Compare commits
21 Commits
e2d5090f44
...
5fa614ab83
Author | SHA1 | Date | |
---|---|---|---|
5fa614ab83 | |||
7a4fbd1160 | |||
bb643bce42 | |||
cf6c05f4c6 | |||
497bbc1a17 | |||
3cd638737a | |||
5508dc5dc0 | |||
03378ebe43 | |||
2669aafe81 | |||
679226ef73 | |||
55ea405a54 | |||
6cfa8dd40d | |||
5a09918b64 | |||
2c2fce2c5a | |||
ca07dc6152 | |||
5cae7cbd24 | |||
887d3b3d13 | |||
b08559b3f3 | |||
c9f1b3aaa3 | |||
907393dfe6 | |||
bd192ba47a |
2
deps/gbastartup/CMakeLists.txt
vendored
2
deps/gbastartup/CMakeLists.txt
vendored
@ -1,4 +1,4 @@
|
|||||||
enable_language(C ASM)
|
enable_language(CXX ASM)
|
||||||
|
|
||||||
add_library(
|
add_library(
|
||||||
GbaStartup OBJECT
|
GbaStartup OBJECT
|
||||||
|
12
deps/ox/src/ox/clargs/clargs.cpp
vendored
12
deps/ox/src/ox/clargs/clargs.cpp
vendored
@ -37,32 +37,32 @@ ClArgs::ClArgs(int argc, const char **args) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClArgs::getBool(const char *arg, bool defaultValue) const noexcept {
|
bool ClArgs::getBool(ox::CRStringView arg, bool defaultValue) const noexcept {
|
||||||
auto [value, err] = m_ints.at(arg);
|
auto [value, err] = m_ints.at(arg);
|
||||||
return !err ? *value : defaultValue;
|
return !err ? *value : defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String ClArgs::getString(const char *arg, const char *defaultValue) const noexcept {
|
String ClArgs::getString(ox::CRStringView arg, const char *defaultValue) const noexcept {
|
||||||
auto [value, err] = m_strings.at(arg);
|
auto [value, err] = m_strings.at(arg);
|
||||||
return !err ? *value : defaultValue;
|
return !err ? *value : defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ClArgs::getInt(const char *arg, int defaultValue) const noexcept {
|
int ClArgs::getInt(ox::CRStringView arg, int defaultValue) const noexcept {
|
||||||
auto [value, err] = m_ints.at(arg);
|
auto [value, err] = m_ints.at(arg);
|
||||||
return !err ? *value : defaultValue;
|
return !err ? *value : defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<bool> ClArgs::getBool(const char *arg) const noexcept {
|
Result<bool> ClArgs::getBool(ox::CRStringView arg) const noexcept {
|
||||||
oxRequire(out, m_bools.at(arg));
|
oxRequire(out, m_bools.at(arg));
|
||||||
return *out;
|
return *out;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<String> ClArgs::getString(const char *argName) const noexcept {
|
Result<String> ClArgs::getString(ox::CRStringView argName) const noexcept {
|
||||||
oxRequire(out, m_strings.at(argName));
|
oxRequire(out, m_strings.at(argName));
|
||||||
return *out;
|
return *out;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<int> ClArgs::getInt(const char *arg) const noexcept {
|
Result<int> ClArgs::getInt(ox::CRStringView arg) const noexcept {
|
||||||
oxRequire(out, m_ints.at(arg));
|
oxRequire(out, m_ints.at(arg));
|
||||||
return *out;
|
return *out;
|
||||||
}
|
}
|
||||||
|
15
deps/ox/src/ox/clargs/clargs.hpp
vendored
15
deps/ox/src/ox/clargs/clargs.hpp
vendored
@ -22,17 +22,20 @@ class ClArgs {
|
|||||||
public:
|
public:
|
||||||
ClArgs(int argc, const char **args) noexcept;
|
ClArgs(int argc, const char **args) noexcept;
|
||||||
|
|
||||||
bool getBool(const char *arg, bool defaultValue) const noexcept;
|
[[nodiscard]]
|
||||||
|
bool getBool(ox::CRStringView arg, bool defaultValue) const noexcept;
|
||||||
|
|
||||||
String getString(const char *argName, const char *defaultArg) const noexcept;
|
[[nodiscard]]
|
||||||
|
String getString(ox::CRStringView argName, const char *defaultArg) const noexcept;
|
||||||
|
|
||||||
int getInt(const char *arg, int defaultValue) const noexcept;
|
[[nodiscard]]
|
||||||
|
int getInt(ox::CRStringView arg, int defaultValue) const noexcept;
|
||||||
|
|
||||||
Result<bool> getBool(const char *arg) const noexcept;
|
Result<bool> getBool(ox::CRStringView arg) const noexcept;
|
||||||
|
|
||||||
Result<String> getString(const char *argName) const noexcept;
|
Result<String> getString(ox::CRStringView argName) const noexcept;
|
||||||
|
|
||||||
Result<int> getInt(const char *arg) const noexcept;
|
Result<int> getInt(ox::CRStringView arg) const noexcept;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
2
deps/ox/src/ox/claw/read.cpp
vendored
2
deps/ox/src/ox/claw/read.cpp
vendored
@ -74,7 +74,7 @@ Result<Buffer> stripClawHeader(const ox::Buffer &buff) noexcept {
|
|||||||
|
|
||||||
Result<ModelObject> readClaw(TypeStore *ts, const Buffer &buff) noexcept {
|
Result<ModelObject> readClaw(TypeStore *ts, const Buffer &buff) noexcept {
|
||||||
oxRequire(header, readClawHeader(buff));
|
oxRequire(header, readClawHeader(buff));
|
||||||
oxRequire(t, ts->template getLoad(header.typeName, header.typeVersion, header.typeParams));
|
oxRequire(t, ts->getLoad(header.typeName, header.typeVersion, header.typeParams));
|
||||||
ModelObject obj;
|
ModelObject obj;
|
||||||
oxReturnError(obj.setType(t));
|
oxReturnError(obj.setType(t));
|
||||||
switch (header.fmt) {
|
switch (header.fmt) {
|
||||||
|
24
deps/ox/src/ox/fs/filesystem/directory.hpp
vendored
24
deps/ox/src/ox/fs/filesystem/directory.hpp
vendored
@ -158,7 +158,7 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
|
|||||||
// determine if already exists
|
// determine if already exists
|
||||||
auto name = nameBuff;
|
auto name = nameBuff;
|
||||||
oxReturnError(path.get(name));
|
oxReturnError(path.get(name));
|
||||||
auto childInode = find(name->c_str());
|
auto childInode = find(PathIterator(*name));
|
||||||
if (!childInode.ok()) {
|
if (!childInode.ok()) {
|
||||||
// if this is not the last item in the path and parents is disabled,
|
// if this is not the last item in the path and parents is disabled,
|
||||||
// return an error
|
// return an error
|
||||||
@ -174,7 +174,7 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
|
|||||||
Directory<FileStore, InodeId_t> child(m_fs, childInode.value);
|
Directory<FileStore, InodeId_t> child(m_fs, childInode.value);
|
||||||
oxReturnError(child.init());
|
oxReturnError(child.init());
|
||||||
|
|
||||||
auto err = write(name->c_str(), childInode.value);
|
auto err = write(PathIterator(*name), childInode.value);
|
||||||
if (err) {
|
if (err) {
|
||||||
oxLogError(err);
|
oxLogError(err);
|
||||||
// could not index the directory, delete it
|
// could not index the directory, delete it
|
||||||
@ -202,16 +202,16 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, InodeId_t inode,
|
|||||||
if (path.next().hasNext()) { // not yet at target directory, recurse to next one
|
if (path.next().hasNext()) { // not yet at target directory, recurse to next one
|
||||||
oxReturnError(path.get(name));
|
oxReturnError(path.get(name));
|
||||||
oxTracef("ox::fs::Directory::write", "Attempting to write to next sub-Directory: {} of {}",
|
oxTracef("ox::fs::Directory::write", "Attempting to write to next sub-Directory: {} of {}",
|
||||||
name->c_str(), path.fullPath());
|
*name, path.fullPath());
|
||||||
oxRequire(nextChild, findEntry(*name));
|
oxRequire(nextChild, findEntry(*name));
|
||||||
oxTracef("ox::fs::Directory::write", "{}: {}", name->c_str(), nextChild);
|
oxTracef("ox::fs::Directory::write", "{}: {}", *name, nextChild);
|
||||||
if (nextChild) {
|
if (nextChild) {
|
||||||
// reuse name because it is a rather large variable and will not be used again
|
// reuse name because it is a rather large variable and will not be used again
|
||||||
// be attentive that this remains true
|
// be attentive that this remains true
|
||||||
name = nullptr;
|
name = nullptr;
|
||||||
return Directory(m_fs, nextChild).write(path.next(), inode, nameBuff);
|
return Directory(m_fs, nextChild).write(path.next(), inode, nameBuff);
|
||||||
} else {
|
} else {
|
||||||
oxTracef("ox::fs::Directory::write", "{} not found and not allowed to create it.", name->c_str());
|
oxTracef("ox::fs::Directory::write", "{} not found and not allowed to create it.", *name);
|
||||||
return OxError(1, "File not found and not allowed to create it.");
|
return OxError(1, "File not found and not allowed to create it.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -262,14 +262,14 @@ Error Directory<FileStore, InodeId_t>::remove(PathIterator path, FileName *nameB
|
|||||||
auto &name = *nameBuff;
|
auto &name = *nameBuff;
|
||||||
oxReturnError(path.get(&name));
|
oxReturnError(path.get(&name));
|
||||||
|
|
||||||
oxTrace("ox::fs::Directory::remove", name.c_str());
|
oxTrace("ox::fs::Directory::remove", name);
|
||||||
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
||||||
if (buff.valid()) {
|
if (buff.valid()) {
|
||||||
oxTrace("ox::fs::Directory::remove", "Found directory buffer.");
|
oxTrace("ox::fs::Directory::remove", "Found directory buffer.");
|
||||||
for (auto i = buff->iterator(); i.valid(); i.next()) {
|
for (auto i = buff->iterator(); i.valid(); i.next()) {
|
||||||
auto data = i->data();
|
auto data = i->data();
|
||||||
if (data.valid()) {
|
if (data.valid()) {
|
||||||
if (ox_strncmp(data->name, name.c_str(), name.len()) == 0) {
|
if (data->name == name) {
|
||||||
oxReturnError(buff->free(i));
|
oxReturnError(buff->free(i));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -308,7 +308,7 @@ Error Directory<FileStore, InodeId_t>::ls(F cb) noexcept {
|
|||||||
|
|
||||||
template<typename FileStore, typename InodeId_t>
|
template<typename FileStore, typename InodeId_t>
|
||||||
Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry(const FileName &name) const noexcept {
|
Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry(const FileName &name) const noexcept {
|
||||||
oxTrace("ox::fs::Directory::findEntry", name.c_str());
|
oxTrace("ox::fs::Directory::findEntry", name);
|
||||||
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
|
||||||
if (!buff.valid()) {
|
if (!buff.valid()) {
|
||||||
oxTrace("ox::fs::Directory::findEntry::fail", "Could not findEntry directory buffer");
|
oxTrace("ox::fs::Directory::findEntry::fail", "Could not findEntry directory buffer");
|
||||||
@ -318,9 +318,9 @@ Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry
|
|||||||
for (auto i = buff->iterator(); i.valid(); i.next()) {
|
for (auto i = buff->iterator(); i.valid(); i.next()) {
|
||||||
auto data = i->data();
|
auto data = i->data();
|
||||||
if (data.valid()) {
|
if (data.valid()) {
|
||||||
oxTracef("ox::fs::Directory::findEntry", "Comparing \"{}\" to \"{}\"", name.c_str(), data->name);
|
oxTracef("ox::fs::Directory::findEntry", "Comparing \"{}\" to \"{}\"", name, data->name);
|
||||||
if (ox_strncmp(data->name, name.c_str(), MaxFileNameLength) == 0) {
|
if (data->name == name) {
|
||||||
oxTracef("ox::fs::Directory::findEntry", "\"{}\" match found.", name.c_str());
|
oxTracef("ox::fs::Directory::findEntry", "\"{}\" match found.", name);
|
||||||
return static_cast<InodeId_t>(data->inode);
|
return static_cast<InodeId_t>(data->inode);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -342,7 +342,7 @@ Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::find(Path
|
|||||||
auto name = nameBuff;
|
auto name = nameBuff;
|
||||||
oxReturnError(path.get(name));
|
oxReturnError(path.get(name));
|
||||||
|
|
||||||
oxRequire(v, findEntry(name->c_str()));
|
oxRequire(v, findEntry(*name));
|
||||||
// recurse if not at end of path
|
// recurse if not at end of path
|
||||||
if (auto p = path.next(); p.valid()) {
|
if (auto p = path.next(); p.valid()) {
|
||||||
Directory dir(m_fs, v);
|
Directory dir(m_fs, v);
|
||||||
|
21
deps/ox/src/ox/fs/filesystem/filelocation.cpp
vendored
21
deps/ox/src/ox/fs/filesystem/filelocation.cpp
vendored
@ -43,15 +43,6 @@ FileAddress::FileAddress(char *path) noexcept {
|
|||||||
m_type = FileAddressType::Path;
|
m_type = FileAddressType::Path;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileAddress::FileAddress(const char *path) noexcept {
|
|
||||||
m_data.constPath = path;
|
|
||||||
m_type = FileAddressType::ConstPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
FileAddress::~FileAddress() noexcept {
|
|
||||||
cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
FileAddress &FileAddress::operator=(const FileAddress &other) noexcept {
|
FileAddress &FileAddress::operator=(const FileAddress &other) noexcept {
|
||||||
if (this == &other) {
|
if (this == &other) {
|
||||||
return *this;
|
return *this;
|
||||||
@ -107,16 +98,4 @@ bool FileAddress::operator==(CRStringView path) const noexcept {
|
|||||||
return path == p;
|
return path == p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileAddress::cleanup() noexcept {
|
|
||||||
if (m_type == FileAddressType::Path) {
|
|
||||||
safeDeleteArray(m_data.path);
|
|
||||||
clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileAddress::clear() noexcept {
|
|
||||||
m_data.path = nullptr;
|
|
||||||
m_type = FileAddressType::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
35
deps/ox/src/ox/fs/filesystem/filelocation.hpp
vendored
35
deps/ox/src/ox/fs/filesystem/filelocation.hpp
vendored
@ -57,17 +57,17 @@ class FileAddress {
|
|||||||
|
|
||||||
FileAddress(uint64_t inode) noexcept;
|
FileAddress(uint64_t inode) noexcept;
|
||||||
|
|
||||||
FileAddress(CRStringView path) noexcept;
|
explicit FileAddress(CRStringView path) noexcept;
|
||||||
|
|
||||||
template<std::size_t SmallStrSz>
|
template<std::size_t SmallStrSz>
|
||||||
FileAddress(const ox::BasicString<SmallStrSz> &path) noexcept: FileAddress(StringView(path)) {
|
explicit FileAddress(const ox::BasicString<SmallStrSz> &path) noexcept: FileAddress(StringView(path)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
FileAddress(char *path) noexcept;
|
explicit FileAddress(char *path) noexcept;
|
||||||
|
|
||||||
FileAddress(const char *path) noexcept;
|
explicit constexpr FileAddress(const char *path) noexcept;
|
||||||
|
|
||||||
~FileAddress() noexcept;
|
constexpr ~FileAddress() noexcept;
|
||||||
|
|
||||||
FileAddress &operator=(const FileAddress &other) noexcept;
|
FileAddress &operator=(const FileAddress &other) noexcept;
|
||||||
|
|
||||||
@ -115,15 +115,24 @@ class FileAddress {
|
|||||||
/**
|
/**
|
||||||
* Cleanup memory allocations.
|
* Cleanup memory allocations.
|
||||||
*/
|
*/
|
||||||
void cleanup() noexcept;
|
constexpr void cleanup() noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears fields, but does not delete allocations.
|
* Clears fields, but does not delete allocations.
|
||||||
*/
|
*/
|
||||||
void clear() noexcept;
|
constexpr void clear() noexcept;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr FileAddress::FileAddress(const char *path) noexcept {
|
||||||
|
m_data.constPath = path;
|
||||||
|
m_type = FileAddressType::ConstPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr FileAddress::~FileAddress() noexcept {
|
||||||
|
cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
constexpr const char *getModelTypeName<FileAddress::Data>() noexcept {
|
constexpr const char *getModelTypeName<FileAddress::Data>() noexcept {
|
||||||
return FileAddress::Data::TypeName;
|
return FileAddress::Data::TypeName;
|
||||||
@ -163,4 +172,16 @@ constexpr Error model(T *io, CommonPtrWith<FileAddress> auto *fa) noexcept {
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr void FileAddress::cleanup() noexcept {
|
||||||
|
if (m_type == FileAddressType::Path) {
|
||||||
|
safeDeleteArray(m_data.path);
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void FileAddress::clear() noexcept {
|
||||||
|
m_data.path = nullptr;
|
||||||
|
m_type = FileAddressType::None;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
23
deps/ox/src/ox/fs/filesystem/filesystem.cpp
vendored
23
deps/ox/src/ox/fs/filesystem/filesystem.cpp
vendored
@ -19,7 +19,7 @@ Result<const char*> FileSystem::directAccess(const FileAddress &addr) noexcept {
|
|||||||
return directAccess(addr.getInode().value);
|
return directAccess(addr.getInode().value);
|
||||||
case FileAddressType::ConstPath:
|
case FileAddressType::ConstPath:
|
||||||
case FileAddressType::Path:
|
case FileAddressType::Path:
|
||||||
return directAccess(addr.getPath().value);
|
return directAccess(StringView(addr.getPath().value));
|
||||||
default:
|
default:
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
@ -31,7 +31,7 @@ Error FileSystem::read(const FileAddress &addr, void *buffer, std::size_t size)
|
|||||||
return read(addr.getInode().value, buffer, size);
|
return read(addr.getInode().value, buffer, size);
|
||||||
case FileAddressType::ConstPath:
|
case FileAddressType::ConstPath:
|
||||||
case FileAddressType::Path:
|
case FileAddressType::Path:
|
||||||
return read(addr.getPath().value, buffer, size);
|
return read(StringView(addr.getPath().value), buffer, size);
|
||||||
default:
|
default:
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
@ -44,29 +44,32 @@ Result<Buffer> FileSystem::read(const FileAddress &addr) noexcept {
|
|||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<Buffer> FileSystem::read(CRStringView path) noexcept {
|
||||||
|
oxRequire(s, stat(path));
|
||||||
|
Buffer buff(s.size);
|
||||||
|
oxReturnError(read(path, buff.data(), buff.size()));
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
Error FileSystem::read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept {
|
Error FileSystem::read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept {
|
||||||
switch (addr.type()) {
|
switch (addr.type()) {
|
||||||
case FileAddressType::Inode:
|
case FileAddressType::Inode:
|
||||||
return read(addr.getInode().value, readStart, readSize, buffer, size);
|
return read(addr.getInode().value, readStart, readSize, buffer, size);
|
||||||
case FileAddressType::ConstPath:
|
case FileAddressType::ConstPath:
|
||||||
case FileAddressType::Path:
|
case FileAddressType::Path:
|
||||||
return read(addr.getPath().value, readStart, readSize, buffer, size);
|
return OxError(2, "Unsupported for path lookups");
|
||||||
default:
|
default:
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Vector<String>> FileSystem::ls(const String &dir) const noexcept {
|
|
||||||
return ls(dir.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
Error FileSystem::remove(const FileAddress &addr, bool recursive) noexcept {
|
Error FileSystem::remove(const FileAddress &addr, bool recursive) noexcept {
|
||||||
switch (addr.type()) {
|
switch (addr.type()) {
|
||||||
case FileAddressType::Inode:
|
case FileAddressType::Inode:
|
||||||
return remove(addr.getInode().value, recursive);
|
return remove(addr.getInode().value, recursive);
|
||||||
case FileAddressType::ConstPath:
|
case FileAddressType::ConstPath:
|
||||||
case FileAddressType::Path:
|
case FileAddressType::Path:
|
||||||
return remove(addr.getPath().value, recursive);
|
return remove(StringView(addr.getPath().value), recursive);
|
||||||
default:
|
default:
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
@ -78,7 +81,7 @@ Error FileSystem::write(const FileAddress &addr, const void *buffer, uint64_t si
|
|||||||
return write(addr.getInode().value, buffer, size, fileType);
|
return write(addr.getInode().value, buffer, size, fileType);
|
||||||
case FileAddressType::ConstPath:
|
case FileAddressType::ConstPath:
|
||||||
case FileAddressType::Path:
|
case FileAddressType::Path:
|
||||||
return write(addr.getPath().value, buffer, size, fileType);
|
return write(StringView(addr.getPath().value), buffer, size, fileType);
|
||||||
default:
|
default:
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
@ -90,7 +93,7 @@ Result<FileStat> FileSystem::stat(const FileAddress &addr) const noexcept {
|
|||||||
return stat(addr.getInode().value);
|
return stat(addr.getInode().value);
|
||||||
case FileAddressType::ConstPath:
|
case FileAddressType::ConstPath:
|
||||||
case FileAddressType::Path:
|
case FileAddressType::Path:
|
||||||
return stat(addr.getPath().value);
|
return stat(StringView(addr.getPath().value));
|
||||||
default:
|
default:
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
|
76
deps/ox/src/ox/fs/filesystem/filesystem.hpp
vendored
76
deps/ox/src/ox/fs/filesystem/filesystem.hpp
vendored
@ -29,18 +29,18 @@ class FileSystem {
|
|||||||
public:
|
public:
|
||||||
virtual ~FileSystem() noexcept = default;
|
virtual ~FileSystem() noexcept = default;
|
||||||
|
|
||||||
virtual Error mkdir(const char *path, bool recursive) noexcept = 0;
|
virtual Error mkdir(CRStringView path, bool recursive) noexcept = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves an entry from one directory to another.
|
* Moves an entry from one directory to another.
|
||||||
* @param src the path to the file
|
* @param src the path to the file
|
||||||
* @param dest the path of the destination directory
|
* @param dest the path of the destination directory
|
||||||
*/
|
*/
|
||||||
virtual Error move(const char *src, const char *dest) noexcept = 0;
|
virtual Error move(CRStringView src, CRStringView dest) noexcept = 0;
|
||||||
|
|
||||||
virtual Error read(const char *path, void *buffer, std::size_t buffSize) noexcept = 0;
|
virtual Error read(CRStringView path, void *buffer, std::size_t buffSize) noexcept = 0;
|
||||||
|
|
||||||
virtual Result<const char*> directAccess(const char *path) noexcept = 0;
|
virtual Result<const char*> directAccess(CRStringView path) noexcept = 0;
|
||||||
|
|
||||||
virtual Error read(uint64_t inode, void *buffer, std::size_t size) noexcept = 0;
|
virtual Error read(uint64_t inode, void *buffer, std::size_t size) noexcept = 0;
|
||||||
|
|
||||||
@ -52,38 +52,48 @@ class FileSystem {
|
|||||||
|
|
||||||
Result<Buffer> read(const FileAddress &addr) noexcept;
|
Result<Buffer> read(const FileAddress &addr) noexcept;
|
||||||
|
|
||||||
|
Result<Buffer> read(CRStringView path) noexcept;
|
||||||
|
|
||||||
Error read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept;
|
Error read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept;
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
Result<const char*> directAccess(const FileAddress &addr) noexcept;
|
Result<const char*> directAccess(const FileAddress &addr) noexcept;
|
||||||
|
|
||||||
Result<Vector<String>> ls(const String &dir) const noexcept;
|
virtual Result<Vector<String>> ls(CRStringView dir) const noexcept = 0;
|
||||||
|
|
||||||
virtual Result<Vector<String>> ls(const char *dir) const noexcept = 0;
|
virtual Error remove(CRStringView path, bool recursive) noexcept = 0;
|
||||||
|
|
||||||
virtual Error remove(const char *path, bool recursive) noexcept = 0;
|
|
||||||
|
|
||||||
Error remove(const FileAddress &addr, bool recursive = false) noexcept;
|
Error remove(const FileAddress &addr, bool recursive = false) noexcept;
|
||||||
|
|
||||||
virtual Error resize(uint64_t size, void *buffer) noexcept = 0;
|
virtual Error resize(uint64_t size, void *buffer) noexcept = 0;
|
||||||
|
|
||||||
virtual Error write(const char *path, const void *buffer, uint64_t size, FileType fileType) noexcept = 0;
|
virtual Error write(CRStringView path, const void *buffer, uint64_t size, FileType fileType) noexcept = 0;
|
||||||
|
|
||||||
virtual Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept = 0;
|
virtual Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept = 0;
|
||||||
|
|
||||||
|
Error write(CRStringView path, const void *buffer, uint64_t size) noexcept {
|
||||||
|
return write(path, buffer, size, FileType::NormalFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
Error write(uint64_t inode, const void *buffer, uint64_t size) noexcept {
|
||||||
|
return write(inode, buffer, size, FileType::NormalFile);
|
||||||
|
}
|
||||||
|
|
||||||
Error write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType = FileType::NormalFile) noexcept;
|
Error write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType = FileType::NormalFile) noexcept;
|
||||||
|
|
||||||
virtual Result<FileStat> stat(uint64_t inode) const noexcept = 0;
|
virtual Result<FileStat> stat(uint64_t inode) const noexcept = 0;
|
||||||
|
|
||||||
virtual Result<FileStat> stat(const char *path) const noexcept = 0;
|
virtual Result<FileStat> stat(CRStringView path) const noexcept = 0;
|
||||||
|
|
||||||
Result<FileStat> stat(const FileAddress &addr) const noexcept;
|
Result<FileStat> stat(const FileAddress &addr) const noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual uint64_t spaceNeeded(uint64_t size) const noexcept = 0;
|
virtual uint64_t spaceNeeded(uint64_t size) const noexcept = 0;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
virtual Result<uint64_t> available() const noexcept = 0;
|
virtual Result<uint64_t> available() const noexcept = 0;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
virtual Result<uint64_t> size() const noexcept = 0;
|
virtual Result<uint64_t> size() const noexcept = 0;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@ -125,13 +135,13 @@ class FileSystemTemplate: public FileSystem {
|
|||||||
|
|
||||||
static Error format(void *buff, uint64_t buffSize) noexcept;
|
static Error format(void *buff, uint64_t buffSize) noexcept;
|
||||||
|
|
||||||
Error mkdir(const char *path, bool recursive) noexcept override;
|
Error mkdir(CRStringView path, bool recursive) noexcept override;
|
||||||
|
|
||||||
Error move(const char *src, const char *dest) noexcept override;
|
Error move(CRStringView src, CRStringView dest) noexcept override;
|
||||||
|
|
||||||
Error read(const char *path, void *buffer, std::size_t buffSize) noexcept override;
|
Error read(CRStringView path, void *buffer, std::size_t buffSize) noexcept override;
|
||||||
|
|
||||||
Result<const char*> directAccess(const char*) noexcept override;
|
Result<const char*> directAccess(CRStringView) noexcept override;
|
||||||
|
|
||||||
Error read(uint64_t inode, void *buffer, std::size_t size) noexcept override;
|
Error read(uint64_t inode, void *buffer, std::size_t size) noexcept override;
|
||||||
|
|
||||||
@ -139,12 +149,12 @@ class FileSystemTemplate: public FileSystem {
|
|||||||
|
|
||||||
Result<const char*> directAccess(uint64_t) noexcept override;
|
Result<const char*> directAccess(uint64_t) noexcept override;
|
||||||
|
|
||||||
Result<Vector<String>> ls(const char *path) const noexcept override;
|
Result<Vector<String>> ls(CRStringView dir) const noexcept override;
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
Error ls(const char *path, F cb) const;
|
Error ls(CRStringView path, F cb) const;
|
||||||
|
|
||||||
Error remove(const char *path, bool recursive) noexcept override;
|
Error remove(CRStringView path, bool recursive) noexcept override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resizes FileSystem to minimum possible size.
|
* Resizes FileSystem to minimum possible size.
|
||||||
@ -153,13 +163,13 @@ class FileSystemTemplate: public FileSystem {
|
|||||||
|
|
||||||
Error resize(uint64_t size, void *buffer) noexcept override;
|
Error resize(uint64_t size, void *buffer) noexcept override;
|
||||||
|
|
||||||
Error write(const char *path, const void *buffer, uint64_t size, FileType fileType) noexcept override;
|
Error write(CRStringView path, const void *buffer, uint64_t size, FileType fileType) noexcept override;
|
||||||
|
|
||||||
Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept override;
|
Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept override;
|
||||||
|
|
||||||
Result<FileStat> stat(uint64_t inode) const noexcept override;
|
Result<FileStat> stat(uint64_t inode) const noexcept override;
|
||||||
|
|
||||||
Result<FileStat> stat(const char *path) const noexcept override;
|
Result<FileStat> stat(CRStringView path) const noexcept override;
|
||||||
|
|
||||||
uint64_t spaceNeeded(uint64_t size) const noexcept override;
|
uint64_t spaceNeeded(uint64_t size) const noexcept override;
|
||||||
|
|
||||||
@ -180,7 +190,7 @@ class FileSystemTemplate: public FileSystem {
|
|||||||
/**
|
/**
|
||||||
* Finds the inode ID at the given path.
|
* Finds the inode ID at the given path.
|
||||||
*/
|
*/
|
||||||
Result<uint64_t> find(const char *path) const noexcept;
|
Result<uint64_t> find(CRStringView path) const noexcept;
|
||||||
|
|
||||||
Result<Directory> rootDir() const noexcept;
|
Result<Directory> rootDir() const noexcept;
|
||||||
|
|
||||||
@ -227,14 +237,14 @@ Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buff
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename FileStore, typename Directory>
|
template<typename FileStore, typename Directory>
|
||||||
Error FileSystemTemplate<FileStore, Directory>::mkdir(const char *path, bool recursive) noexcept {
|
Error FileSystemTemplate<FileStore, Directory>::mkdir(CRStringView path, bool recursive) noexcept {
|
||||||
oxTracef("ox::fs::FileSystemTemplate::mkdir", "path: {}, recursive: {}", path, recursive);
|
oxTracef("ox::fs::FileSystemTemplate::mkdir", "path: {}, recursive: {}", path, recursive);
|
||||||
oxRequireM(rootDir, this->rootDir());
|
oxRequireM(rootDir, this->rootDir());
|
||||||
return rootDir.mkdir(path, recursive);
|
return rootDir.mkdir(path, recursive);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename FileStore, typename Directory>
|
template<typename FileStore, typename Directory>
|
||||||
Error FileSystemTemplate<FileStore, Directory>::move(const char *src, const char *dest) noexcept {
|
Error FileSystemTemplate<FileStore, Directory>::move(CRStringView src, CRStringView dest) noexcept {
|
||||||
oxRequire(fd, fileSystemData());
|
oxRequire(fd, fileSystemData());
|
||||||
Directory rootDir(m_fs, fd.rootDirInode);
|
Directory rootDir(m_fs, fd.rootDirInode);
|
||||||
oxRequireM(inode, rootDir.find(src));
|
oxRequireM(inode, rootDir.find(src));
|
||||||
@ -244,7 +254,7 @@ Error FileSystemTemplate<FileStore, Directory>::move(const char *src, const char
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename FileStore, typename Directory>
|
template<typename FileStore, typename Directory>
|
||||||
Error FileSystemTemplate<FileStore, Directory>::read(const char *path, void *buffer, std::size_t buffSize) noexcept {
|
Error FileSystemTemplate<FileStore, Directory>::read(CRStringView path, void *buffer, std::size_t buffSize) noexcept {
|
||||||
oxRequire(fd, fileSystemData());
|
oxRequire(fd, fileSystemData());
|
||||||
Directory rootDir(m_fs, fd.rootDirInode);
|
Directory rootDir(m_fs, fd.rootDirInode);
|
||||||
oxRequire(inode, rootDir.find(path));
|
oxRequire(inode, rootDir.find(path));
|
||||||
@ -252,7 +262,7 @@ Error FileSystemTemplate<FileStore, Directory>::read(const char *path, void *buf
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename FileStore, typename Directory>
|
template<typename FileStore, typename Directory>
|
||||||
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccess(const char *path) noexcept {
|
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccess(CRStringView path) noexcept {
|
||||||
oxRequire(fd, fileSystemData());
|
oxRequire(fd, fileSystemData());
|
||||||
Directory rootDir(m_fs, fd.rootDirInode);
|
Directory rootDir(m_fs, fd.rootDirInode);
|
||||||
oxRequire(inode, rootDir.find(path));
|
oxRequire(inode, rootDir.find(path));
|
||||||
@ -273,15 +283,15 @@ template<typename FileStore, typename Directory>
|
|||||||
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccess(uint64_t inode) noexcept {
|
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccess(uint64_t inode) noexcept {
|
||||||
auto data = m_fs.read(inode);
|
auto data = m_fs.read(inode);
|
||||||
if (!data.valid()) {
|
if (!data.valid()) {
|
||||||
return OxError(1);
|
return OxError(1, "Data not valid");
|
||||||
}
|
}
|
||||||
return reinterpret_cast<char*>(data.get());
|
return reinterpret_cast<char*>(data.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename FileStore, typename Directory>
|
template<typename FileStore, typename Directory>
|
||||||
Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(const char *path) const noexcept {
|
Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(CRStringView path) const noexcept {
|
||||||
Vector<String> out;
|
Vector<String> out;
|
||||||
oxReturnError(ls(path, [&out](const char *name, typename FileStore::InodeId_t) {
|
oxReturnError(ls(path, [&out](CRStringView name, typename FileStore::InodeId_t) {
|
||||||
out.emplace_back(name);
|
out.emplace_back(name);
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}));
|
}));
|
||||||
@ -290,7 +300,7 @@ Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(const char *
|
|||||||
|
|
||||||
template<typename FileStore, typename Directory>
|
template<typename FileStore, typename Directory>
|
||||||
template<typename F>
|
template<typename F>
|
||||||
Error FileSystemTemplate<FileStore, Directory>::ls(const char *path, F cb) const {
|
Error FileSystemTemplate<FileStore, Directory>::ls(CRStringView path, F cb) const {
|
||||||
oxTracef("ox::fs::FileSystemTemplate::ls", "path: {}", path);
|
oxTracef("ox::fs::FileSystemTemplate::ls", "path: {}", path);
|
||||||
oxRequire(s, stat(path));
|
oxRequire(s, stat(path));
|
||||||
Directory dir(m_fs, s.inode);
|
Directory dir(m_fs, s.inode);
|
||||||
@ -298,7 +308,7 @@ Error FileSystemTemplate<FileStore, Directory>::ls(const char *path, F cb) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename FileStore, typename Directory>
|
template<typename FileStore, typename Directory>
|
||||||
Error FileSystemTemplate<FileStore, Directory>::remove(const char *path, bool recursive) noexcept {
|
Error FileSystemTemplate<FileStore, Directory>::remove(CRStringView path, bool recursive) noexcept {
|
||||||
oxRequire(fd, fileSystemData());
|
oxRequire(fd, fileSystemData());
|
||||||
Directory rootDir(m_fs, fd.rootDirInode);
|
Directory rootDir(m_fs, fd.rootDirInode);
|
||||||
oxRequire(inode, rootDir.find(path));
|
oxRequire(inode, rootDir.find(path));
|
||||||
@ -328,7 +338,7 @@ Error FileSystemTemplate<FileStore, Directory>::resize(uint64_t size, void *buff
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename FileStore, typename Directory>
|
template<typename FileStore, typename Directory>
|
||||||
Error FileSystemTemplate<FileStore, Directory>::write(const char *path, const void *buffer, uint64_t size, FileType fileType) noexcept {
|
Error FileSystemTemplate<FileStore, Directory>::write(CRStringView path, const void *buffer, uint64_t size, FileType fileType) noexcept {
|
||||||
auto [inode, err] = find(path);
|
auto [inode, err] = find(path);
|
||||||
if (err) {
|
if (err) {
|
||||||
oxRequire(generatedId, m_fs.generateInodeId());
|
oxRequire(generatedId, m_fs.generateInodeId());
|
||||||
@ -357,7 +367,7 @@ Result<FileStat> FileSystemTemplate<FileStore, Directory>::stat(uint64_t inode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename FileStore, typename Directory>
|
template<typename FileStore, typename Directory>
|
||||||
Result<FileStat> FileSystemTemplate<FileStore, Directory>::stat(const char *path) const noexcept {
|
Result<FileStat> FileSystemTemplate<FileStore, Directory>::stat(CRStringView path) const noexcept {
|
||||||
oxRequire(inode, find(path));
|
oxRequire(inode, find(path));
|
||||||
return stat(inode);
|
return stat(inode);
|
||||||
}
|
}
|
||||||
@ -400,10 +410,10 @@ Result<typename FileSystemTemplate<FileStore, Directory>::FileSystemData> FileSy
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename FileStore, typename Directory>
|
template<typename FileStore, typename Directory>
|
||||||
Result<uint64_t> FileSystemTemplate<FileStore, Directory>::find(const char *path) const noexcept {
|
Result<uint64_t> FileSystemTemplate<FileStore, Directory>::find(CRStringView path) const noexcept {
|
||||||
oxRequire(fd, fileSystemData());
|
oxRequire(fd, fileSystemData());
|
||||||
// return root as a special case
|
// return root as a special case
|
||||||
if (ox_strcmp(path, "/") == 0) {
|
if (path == "/") {
|
||||||
return static_cast<uint64_t>(fd.rootDirInode);
|
return static_cast<uint64_t>(fd.rootDirInode);
|
||||||
}
|
}
|
||||||
Directory rootDir(m_fs, fd.rootDirInode);
|
Directory rootDir(m_fs, fd.rootDirInode);
|
||||||
|
35
deps/ox/src/ox/fs/filesystem/passthroughfs.cpp
vendored
35
deps/ox/src/ox/fs/filesystem/passthroughfs.cpp
vendored
@ -13,25 +13,25 @@
|
|||||||
#if defined(OX_HAS_PASSTHROUGHFS)
|
#if defined(OX_HAS_PASSTHROUGHFS)
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
PassThroughFS::PassThroughFS(const char *dirPath) {
|
PassThroughFS::PassThroughFS(CRStringView dirPath) {
|
||||||
m_path = dirPath;
|
m_path = std::string_view(dirPath.data(), dirPath.bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
PassThroughFS::~PassThroughFS() noexcept {
|
PassThroughFS::~PassThroughFS() noexcept = default;
|
||||||
}
|
|
||||||
|
|
||||||
String PassThroughFS::basePath() const noexcept {
|
String PassThroughFS::basePath() const noexcept {
|
||||||
return m_path.string().c_str();
|
return m_path.string().c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
Error PassThroughFS::mkdir(const char *path, bool recursive) noexcept {
|
Error PassThroughFS::mkdir(CRStringView path, bool recursive) noexcept {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
const auto p = m_path / stripSlash(path);
|
const auto p = m_path / stripSlash(path);
|
||||||
const auto u8p = p.u8string();
|
const auto u8p = p.u8string();
|
||||||
oxTrace("ox::fs::PassThroughFS::mkdir", u8p.c_str());
|
oxTrace("ox::fs::PassThroughFS::mkdir", std::bit_cast<const char*>(u8p.c_str()));
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
const auto isDir = std::filesystem::is_directory(p, ec);
|
const auto isDir = std::filesystem::is_directory(p, ec);
|
||||||
@ -47,7 +47,6 @@ Error PassThroughFS::mkdir(const char *path, bool recursive) noexcept {
|
|||||||
if (isDir) {
|
if (isDir) {
|
||||||
success = true;
|
success = true;
|
||||||
} else {
|
} else {
|
||||||
std::error_code ec;
|
|
||||||
success = std::filesystem::create_directory(p, ec);
|
success = std::filesystem::create_directory(p, ec);
|
||||||
oxReturnError(OxError(ec.value(), "PassThroughFS: mkdir failed"));
|
oxReturnError(OxError(ec.value(), "PassThroughFS: mkdir failed"));
|
||||||
}
|
}
|
||||||
@ -55,7 +54,7 @@ Error PassThroughFS::mkdir(const char *path, bool recursive) noexcept {
|
|||||||
return OxError(success ? 0 : 1);
|
return OxError(success ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error PassThroughFS::move(const char *src, const char *dest) noexcept {
|
Error PassThroughFS::move(CRStringView src, CRStringView dest) noexcept {
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
std::filesystem::rename(m_path / stripSlash(src), m_path / stripSlash(dest), ec);
|
std::filesystem::rename(m_path / stripSlash(src), m_path / stripSlash(dest), ec);
|
||||||
if (ec.value()) {
|
if (ec.value()) {
|
||||||
@ -64,7 +63,7 @@ Error PassThroughFS::move(const char *src, const char *dest) noexcept {
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error PassThroughFS::read(const char *path, void *buffer, std::size_t buffSize) noexcept {
|
Error PassThroughFS::read(CRStringView path, void *buffer, std::size_t buffSize) noexcept {
|
||||||
try {
|
try {
|
||||||
std::ifstream file((m_path / stripSlash(path)), std::ios::binary | std::ios::ate);
|
std::ifstream file((m_path / stripSlash(path)), std::ios::binary | std::ios::ate);
|
||||||
const std::size_t size = file.tellg();
|
const std::size_t size = file.tellg();
|
||||||
@ -73,7 +72,7 @@ Error PassThroughFS::read(const char *path, void *buffer, std::size_t buffSize)
|
|||||||
oxTracef("ox::fs::PassThroughFS::read::error", "Read failed: Buffer too small: {}", path);
|
oxTracef("ox::fs::PassThroughFS::read::error", "Read failed: Buffer too small: {}", path);
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
file.read(static_cast<char*>(buffer), buffSize);
|
file.read(static_cast<char*>(buffer), static_cast<std::streamsize>(buffSize));
|
||||||
} catch (const std::fstream::failure &f) {
|
} catch (const std::fstream::failure &f) {
|
||||||
oxTracef("ox::fs::PassThroughFS::read::error", "Read of {} failed: {}", path, f.what());
|
oxTracef("ox::fs::PassThroughFS::read::error", "Read of {} failed: {}", path, f.what());
|
||||||
return OxError(2);
|
return OxError(2);
|
||||||
@ -81,7 +80,7 @@ Error PassThroughFS::read(const char *path, void *buffer, std::size_t buffSize)
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<const char*> PassThroughFS::directAccess(const char*) noexcept {
|
Result<const char*> PassThroughFS::directAccess(CRStringView) noexcept {
|
||||||
return OxError(1, "PassThroughFS::directAccess not supported");
|
return OxError(1, "PassThroughFS::directAccess not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +98,7 @@ Result<const char*> PassThroughFS::directAccess(uint64_t) noexcept {
|
|||||||
return OxError(1, "PassThroughFS::directAccess not supported");
|
return OxError(1, "PassThroughFS::directAccess not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Vector<String>> PassThroughFS::ls(const char *dir) const noexcept {
|
Result<Vector<String>> PassThroughFS::ls(CRStringView dir) const noexcept {
|
||||||
Vector<String> out;
|
Vector<String> out;
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
const auto di = std::filesystem::directory_iterator(m_path / stripSlash(dir), ec);
|
const auto di = std::filesystem::directory_iterator(m_path / stripSlash(dir), ec);
|
||||||
@ -111,7 +110,7 @@ Result<Vector<String>> PassThroughFS::ls(const char *dir) const noexcept {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error PassThroughFS::remove(const char *path, bool recursive) noexcept {
|
Error PassThroughFS::remove(CRStringView path, bool recursive) noexcept {
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
return OxError(std::filesystem::remove_all(m_path / stripSlash(path)) != 0);
|
return OxError(std::filesystem::remove_all(m_path / stripSlash(path)) != 0);
|
||||||
} else {
|
} else {
|
||||||
@ -124,7 +123,7 @@ Error PassThroughFS::resize(uint64_t, void*) noexcept {
|
|||||||
return OxError(1, "resize is not supported by PassThroughFS");
|
return OxError(1, "resize is not supported by PassThroughFS");
|
||||||
}
|
}
|
||||||
|
|
||||||
Error PassThroughFS::write(const char *path, const void *buffer, uint64_t size, FileType) noexcept {
|
Error PassThroughFS::write(CRStringView path, const void *buffer, uint64_t size, FileType) noexcept {
|
||||||
const auto p = (m_path / stripSlash(path));
|
const auto p = (m_path / stripSlash(path));
|
||||||
try {
|
try {
|
||||||
std::ofstream f(p, std::ios::binary);
|
std::ofstream f(p, std::ios::binary);
|
||||||
@ -146,7 +145,7 @@ Result<FileStat> PassThroughFS::stat(uint64_t) const noexcept {
|
|||||||
return OxError(1, "stat(uint64_t) is not supported by PassThroughFS");
|
return OxError(1, "stat(uint64_t) is not supported by PassThroughFS");
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<FileStat> PassThroughFS::stat(const char *path) const noexcept {
|
Result<FileStat> PassThroughFS::stat(CRStringView path) const noexcept {
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
const auto p = m_path / stripSlash(path);
|
const auto p = m_path / stripSlash(path);
|
||||||
const FileType type = std::filesystem::is_directory(p, ec) ?
|
const FileType type = std::filesystem::is_directory(p, ec) ?
|
||||||
@ -194,12 +193,12 @@ bool PassThroughFS::valid() const noexcept {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *PassThroughFS::stripSlash(const char *path) noexcept {
|
std::string_view PassThroughFS::stripSlash(StringView path) noexcept {
|
||||||
const auto pathLen = ox_strlen(path);
|
const auto pathLen = ox_strlen(path);
|
||||||
for (auto i = 0u; i < pathLen && path[0] == '/'; i++) {
|
for (auto i = 0u; i < pathLen && path[0] == '/'; i++) {
|
||||||
path++;
|
path = path.substr(1);
|
||||||
}
|
}
|
||||||
return path;
|
return std::string_view(path.data(), path.bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
27
deps/ox/src/ox/fs/filesystem/passthroughfs.hpp
vendored
27
deps/ox/src/ox/fs/filesystem/passthroughfs.hpp
vendored
@ -30,20 +30,20 @@ class PassThroughFS: public FileSystem {
|
|||||||
std::filesystem::path m_path;
|
std::filesystem::path m_path;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PassThroughFS(const char *dirPath);
|
explicit PassThroughFS(CRStringView dirPath);
|
||||||
|
|
||||||
~PassThroughFS() noexcept override;
|
~PassThroughFS() noexcept override;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
String basePath() const noexcept;
|
String basePath() const noexcept;
|
||||||
|
|
||||||
Error mkdir(const char *path, bool recursive = false) noexcept override;
|
Error mkdir(CRStringView path, bool recursive = false) noexcept override;
|
||||||
|
|
||||||
Error move(const char *src, const char *dest) noexcept override;
|
Error move(CRStringView src, CRStringView dest) noexcept override;
|
||||||
|
|
||||||
Error read(const char *path, void *buffer, std::size_t buffSize) noexcept override;
|
Error read(CRStringView path, void *buffer, std::size_t buffSize) noexcept override;
|
||||||
|
|
||||||
Result<const char*> directAccess(const char*) noexcept override;
|
Result<const char*> directAccess(CRStringView) noexcept override;
|
||||||
|
|
||||||
Error read(uint64_t inode, void *buffer, std::size_t size) noexcept override;
|
Error read(uint64_t inode, void *buffer, std::size_t size) noexcept override;
|
||||||
|
|
||||||
@ -51,29 +51,31 @@ class PassThroughFS: public FileSystem {
|
|||||||
|
|
||||||
Result<const char*> directAccess(uint64_t) noexcept override;
|
Result<const char*> directAccess(uint64_t) noexcept override;
|
||||||
|
|
||||||
Result<Vector<String>> ls(const char *dir) const noexcept override;
|
Result<Vector<String>> ls(CRStringView dir) const noexcept override;
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
Error ls(const char *dir, F cb) const noexcept;
|
Error ls(CRStringView dir, F cb) const noexcept;
|
||||||
|
|
||||||
Error remove(const char *path, bool recursive = false) noexcept override;
|
Error remove(CRStringView path, bool recursive = false) noexcept override;
|
||||||
|
|
||||||
Error resize(uint64_t size, void *buffer = nullptr) noexcept override;
|
Error resize(uint64_t size, void *buffer = nullptr) noexcept override;
|
||||||
|
|
||||||
Error write(const char *path, const void *buffer, uint64_t size, FileType fileType = FileType::NormalFile) noexcept override;
|
Error write(CRStringView path, const void *buffer, uint64_t size, FileType fileType = FileType::NormalFile) noexcept override;
|
||||||
|
|
||||||
Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType = FileType::NormalFile) noexcept override;
|
Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType = FileType::NormalFile) noexcept override;
|
||||||
|
|
||||||
Result<FileStat> stat(uint64_t inode) const noexcept override;
|
Result<FileStat> stat(uint64_t inode) const noexcept override;
|
||||||
|
|
||||||
Result<FileStat> stat(const char *path) const noexcept override;
|
Result<FileStat> stat(CRStringView path) const noexcept override;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
uint64_t spaceNeeded(uint64_t size) const noexcept override;
|
uint64_t spaceNeeded(uint64_t size) const noexcept override;
|
||||||
|
|
||||||
Result<uint64_t> available() const noexcept override;
|
Result<uint64_t> available() const noexcept override;
|
||||||
|
|
||||||
Result<uint64_t> size() const noexcept override;
|
Result<uint64_t> size() const noexcept override;
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
char *buff() noexcept override;
|
char *buff() noexcept override;
|
||||||
|
|
||||||
Error walk(Error(*cb)(uint8_t, uint64_t, uint64_t)) noexcept override;
|
Error walk(Error(*cb)(uint8_t, uint64_t, uint64_t)) noexcept override;
|
||||||
@ -85,12 +87,13 @@ class PassThroughFS: public FileSystem {
|
|||||||
/**
|
/**
|
||||||
* Strips the leading slashes from a string.
|
* Strips the leading slashes from a string.
|
||||||
*/
|
*/
|
||||||
static const char *stripSlash(const char *path) noexcept;
|
[[nodiscard]]
|
||||||
|
static std::string_view stripSlash(StringView path) noexcept;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
Error PassThroughFS::ls(const char *dir, F cb) const noexcept {
|
Error PassThroughFS::ls(CRStringView dir, F cb) const noexcept {
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
const auto di = std::filesystem::directory_iterator(m_path / stripSlash(dir), ec);
|
const auto di = std::filesystem::directory_iterator(m_path / stripSlash(dir), ec);
|
||||||
oxReturnError(OxError(ec.value(), "PassThroughFS: ls failed"));
|
oxReturnError(OxError(ec.value(), "PassThroughFS: ls failed"));
|
||||||
|
@ -22,6 +22,9 @@ PathIterator::PathIterator(const char *path, std::size_t maxSize, std::size_t it
|
|||||||
PathIterator::PathIterator(const char *path): PathIterator(path, ox_strlen(path)) {
|
PathIterator::PathIterator(const char *path): PathIterator(path, ox_strlen(path)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PathIterator::PathIterator(CRStringView path): PathIterator(path.data(), path.bytes()) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 0 if no error
|
* @return 0 if no error
|
||||||
*/
|
*/
|
||||||
|
@ -26,6 +26,8 @@ class PathIterator {
|
|||||||
|
|
||||||
PathIterator(const char *path);
|
PathIterator(const char *path);
|
||||||
|
|
||||||
|
PathIterator(CRStringView path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 0 if no error
|
* @return 0 if no error
|
||||||
*/
|
*/
|
||||||
|
2
deps/ox/src/ox/fs/tool.cpp
vendored
2
deps/ox/src/ox/fs/tool.cpp
vendored
@ -56,7 +56,7 @@ static ox::Error runRead(ox::FileSystem *fs, int argc, const char **argv) noexce
|
|||||||
oxErr("Must provide a path to a file to read\n");
|
oxErr("Must provide a path to a file to read\n");
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
oxRequire(buff, fs->read(argv[1]));
|
oxRequire(buff, fs->read(ox::StringView(argv[1])));
|
||||||
fwrite(buff.data(), sizeof(decltype(buff)::value_type), buff.size(), stdout);
|
fwrite(buff.data(), sizeof(decltype(buff)::value_type), buff.size(), stdout);
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
3
deps/ox/src/ox/mc/read.hpp
vendored
3
deps/ox/src/ox/mc/read.hpp
vendored
@ -331,8 +331,7 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, BasicS
|
|||||||
if (m_buffIt + size > m_buffLen) {
|
if (m_buffIt + size > m_buffLen) {
|
||||||
return OxError(MC_BUFFENDED);
|
return OxError(MC_BUFFENDED);
|
||||||
}
|
}
|
||||||
memcpy(data, &m_buff[m_buffIt], size);
|
ox_strncpy(data, &m_buff[m_buffIt], size);
|
||||||
data[size] = 0;
|
|
||||||
m_buffIt += size;
|
m_buffIt += size;
|
||||||
} else {
|
} else {
|
||||||
*val = "";
|
*val = "";
|
||||||
|
13
deps/ox/src/ox/model/fieldcounter.hpp
vendored
13
deps/ox/src/ox/model/fieldcounter.hpp
vendored
@ -57,14 +57,21 @@ class FieldCounter {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr auto ModelFieldCount_v = [] {
|
[[nodiscard]]
|
||||||
|
consteval auto modelFieldCount() noexcept {
|
||||||
auto a = std::allocator<T>();
|
auto a = std::allocator<T>();
|
||||||
auto t = a.allocate(1);
|
auto t = a.allocate(1);
|
||||||
detail::FieldCounter<T> c;
|
detail::FieldCounter<T> c;
|
||||||
oxAssert(model(&c, t), "Count failed");
|
const auto err = model(&c, t);
|
||||||
|
oxAssert(err, "Count failed");
|
||||||
a.deallocate(t, 1);
|
a.deallocate(t, 1);
|
||||||
return c.fields;
|
return c.fields;
|
||||||
}();
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr auto ModelFieldCount_v = detail::modelFieldCount<T>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
1
deps/ox/src/ox/std/CMakeLists.txt
vendored
1
deps/ox/src/ox/std/CMakeLists.txt
vendored
@ -33,6 +33,7 @@ add_library(
|
|||||||
substitutes.cpp
|
substitutes.cpp
|
||||||
stacktrace.cpp
|
stacktrace.cpp
|
||||||
string.cpp
|
string.cpp
|
||||||
|
stringview.cpp
|
||||||
strops.cpp
|
strops.cpp
|
||||||
trace.cpp
|
trace.cpp
|
||||||
typetraits.cpp
|
typetraits.cpp
|
||||||
|
2
deps/ox/src/ox/std/assert.cpp
vendored
2
deps/ox/src/ox/std/assert.cpp
vendored
@ -26,6 +26,8 @@ void panic([[maybe_unused]]const char *file, [[maybe_unused]]int line, [[maybe_u
|
|||||||
printStackTrace(2);
|
printStackTrace(2);
|
||||||
oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << file << ":" << line << ")";
|
oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << file << ":" << line << ")";
|
||||||
std::abort();
|
std::abort();
|
||||||
|
#else
|
||||||
|
while (1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
deps/ox/src/ox/std/assert.hpp
vendored
12
deps/ox/src/ox/std/assert.hpp
vendored
@ -36,12 +36,14 @@ constexpr void assertFunc(const char *file, int line, bool pass, [[maybe_unused]
|
|||||||
if (!pass) {
|
if (!pass) {
|
||||||
if (!std::is_constant_evaluated()) {
|
if (!std::is_constant_evaluated()) {
|
||||||
#ifdef OX_USE_STDLIB
|
#ifdef OX_USE_STDLIB
|
||||||
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
|
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
|
||||||
printStackTrace(2);
|
printStackTrace(2);
|
||||||
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
|
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
|
||||||
std::abort();
|
std::abort();
|
||||||
#else
|
#else
|
||||||
constexprPanic(file, line, msg);
|
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
|
||||||
|
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
|
||||||
|
constexprPanic(file, line, msg);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
while (true);
|
while (true);
|
||||||
|
1
deps/ox/src/ox/std/bstring.hpp
vendored
1
deps/ox/src/ox/std/bstring.hpp
vendored
@ -143,6 +143,7 @@ template<std::size_t size>
|
|||||||
constexpr BString<size> &BString<size>::operator+=(StringView s) noexcept {
|
constexpr BString<size> &BString<size>::operator+=(StringView s) noexcept {
|
||||||
std::size_t strLen = s.bytes();
|
std::size_t strLen = s.bytes();
|
||||||
oxIgnoreError(append(s.data(), strLen));
|
oxIgnoreError(append(s.data(), strLen));
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t size>
|
template<std::size_t size>
|
||||||
|
85
deps/ox/src/ox/std/string.hpp
vendored
85
deps/ox/src/ox/std/string.hpp
vendored
@ -178,18 +178,6 @@ class BasicString {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr BasicString substr(std::size_t begin, std::size_t end) const noexcept;
|
constexpr BasicString substr(std::size_t begin, std::size_t end) const noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr bool beginsWith(const char *ending) const noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr bool beginsWith(const BasicString &ending) const noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr bool endsWith(const char *ending) const noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr bool endsWith(const BasicString &ending) const noexcept;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr const char *data() const noexcept {
|
constexpr const char *data() const noexcept {
|
||||||
return m_buff.data();
|
return m_buff.data();
|
||||||
@ -238,7 +226,7 @@ class BasicString {
|
|||||||
template<std::size_t OtherSize>
|
template<std::size_t OtherSize>
|
||||||
constexpr void set(const BasicString<OtherSize> &src) noexcept;
|
constexpr void set(const BasicString<OtherSize> &src) noexcept;
|
||||||
|
|
||||||
constexpr void set(StringView str) noexcept;
|
constexpr void set(CRStringView str) noexcept;
|
||||||
|
|
||||||
constexpr void set(const char *str) noexcept;
|
constexpr void set(const char *str) noexcept;
|
||||||
|
|
||||||
@ -291,10 +279,10 @@ constexpr BasicString<SmallStringSize_v>::BasicString(const char *str, std::size
|
|||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
constexpr BasicString<SmallStringSize_v>::BasicString(CRStringView str) noexcept {
|
constexpr BasicString<SmallStringSize_v>::BasicString(CRStringView str) noexcept {
|
||||||
if (m_buff.size()) {
|
if (m_buff.empty()) {
|
||||||
m_buff[0] = 0;
|
|
||||||
} else {
|
|
||||||
m_buff.push_back(0);
|
m_buff.push_back(0);
|
||||||
|
} else {
|
||||||
|
m_buff[0] = 0;
|
||||||
}
|
}
|
||||||
set(str);
|
set(str);
|
||||||
}
|
}
|
||||||
@ -520,30 +508,6 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::substr(
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
|
||||||
constexpr bool BasicString<SmallStringSize_v>::beginsWith(const char *beginning) const noexcept {
|
|
||||||
const auto beginningLen = ox::min(ox_strlen(beginning), len());
|
|
||||||
return ox_strncmp(data(), beginning, beginningLen) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
|
||||||
constexpr bool BasicString<SmallStringSize_v>::beginsWith(const BasicString &beginning) const noexcept {
|
|
||||||
const auto sz = ox::min(beginning.len(), len());;
|
|
||||||
return ox_strncmp(data(), beginning.c_str(), sz) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
|
||||||
constexpr bool BasicString<SmallStringSize_v>::endsWith(const char *ending) const noexcept {
|
|
||||||
const auto endingLen = ox_strlen(ending);
|
|
||||||
return len() >= endingLen && ox_strcmp(data() + (len() - endingLen), ending) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
|
||||||
constexpr bool BasicString<SmallStringSize_v>::endsWith(const BasicString &ending) const noexcept {
|
|
||||||
const auto endingLen = ending.len();
|
|
||||||
return len() >= endingLen && ox_strcmp(data() + (len() - endingLen), ending.c_str()) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
constexpr std::size_t BasicString<SmallStringSize_v>::bytes() const noexcept {
|
constexpr std::size_t BasicString<SmallStringSize_v>::bytes() const noexcept {
|
||||||
std::size_t i;
|
std::size_t i;
|
||||||
@ -555,11 +519,10 @@ template<std::size_t SmallStringSize_v>
|
|||||||
constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept {
|
constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept {
|
||||||
std::size_t length = 0;
|
std::size_t length = 0;
|
||||||
for (const auto c : m_buff) {
|
for (const auto c : m_buff) {
|
||||||
auto b = static_cast<uint8_t>(c);
|
const auto b = static_cast<uint8_t>(c);
|
||||||
if (b) {
|
if (b) {
|
||||||
if ((b & 128) == 0) { // normal ASCII character
|
// normal ASCII character or start of UTF-8 character
|
||||||
++length;
|
if ((b & 128) == 0 || (b & (256 << 6)) == (256 << 6)) {
|
||||||
} else if ((b & (256 << 6)) == (256 << 6)) { // start of UTF-8 character
|
|
||||||
++length;
|
++length;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -573,41 +536,33 @@ template<std::size_t SmallStringSize_v>
|
|||||||
template<std::size_t OtherSize>
|
template<std::size_t OtherSize>
|
||||||
constexpr void BasicString<SmallStringSize_v>::set(const BasicString<OtherSize> &src) noexcept {
|
constexpr void BasicString<SmallStringSize_v>::set(const BasicString<OtherSize> &src) noexcept {
|
||||||
std::size_t strBytes = src.bytes();
|
std::size_t strBytes = src.bytes();
|
||||||
if (strBytes > 1) {
|
m_buff.resize(strBytes);
|
||||||
m_buff.resize(strBytes);
|
copy_n(src.begin(), strBytes, m_buff.data());
|
||||||
copy_n(src.begin(), strBytes, m_buff.data());
|
m_buff.back().value = 0;
|
||||||
m_buff.back().value = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
constexpr void BasicString<SmallStringSize_v>::set(StringView str) noexcept {
|
constexpr void BasicString<SmallStringSize_v>::set(CRStringView str) noexcept {
|
||||||
std::size_t strBytes = str.bytes();
|
std::size_t strBytes = str.bytes();
|
||||||
if (strBytes > 1) {
|
m_buff.resize(strBytes + 1);
|
||||||
m_buff.resize(strBytes + 1);
|
copy_n(str.data(), strBytes, m_buff.data());
|
||||||
copy_n(str.data(), strBytes, m_buff.data());
|
m_buff.back().value = 0;
|
||||||
m_buff.back().value = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
constexpr void BasicString<SmallStringSize_v>::set(const char *str) noexcept {
|
constexpr void BasicString<SmallStringSize_v>::set(const char *str) noexcept {
|
||||||
std::size_t strBytes = ox_strlen(str) + 1;
|
std::size_t strBytes = ox_strlen(str) + 1;
|
||||||
if (strBytes > 1) {
|
m_buff.resize(strBytes);
|
||||||
m_buff.resize(strBytes);
|
copy_n(str, strBytes, m_buff.data());
|
||||||
copy_n(str, strBytes, m_buff.data());
|
m_buff.back().value = 0;
|
||||||
m_buff.back().value = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<std::size_t SmallStringSize_v>
|
template<std::size_t SmallStringSize_v>
|
||||||
constexpr void BasicString<SmallStringSize_v>::set(const char8_t *str) noexcept {
|
constexpr void BasicString<SmallStringSize_v>::set(const char8_t *str) noexcept {
|
||||||
std::size_t strBytes = ox_strlen(str) + 1;
|
std::size_t strBytes = ox_strlen(str) + 1;
|
||||||
if (strBytes > 1) {
|
m_buff.resize(strBytes);
|
||||||
m_buff.resize(strBytes);
|
memcpy(m_buff.data(), str, strBytes);
|
||||||
memcpy(m_buff.data(), str, strBytes);
|
m_buff.back().value = 0;
|
||||||
m_buff.back().value = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern template class BasicString<8>;
|
extern template class BasicString<8>;
|
||||||
|
20
deps/ox/src/ox/std/stringview.cpp
vendored
Normal file
20
deps/ox/src/ox/std/stringview.cpp
vendored
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 - 2022 gary@drinkingtea.net
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stringview.hpp"
|
||||||
|
|
||||||
|
static_assert(ox::StringView("Read").bytes() == 4);
|
||||||
|
static_assert(ox::StringView("Read") == ox::StringView("Read"));
|
||||||
|
static_assert(ox::StringView("Read") != ox::StringView("Write"));
|
||||||
|
static_assert(ox::StringView("Write") != ox::StringView("Read"));
|
||||||
|
static_assert(ox::StringView("Write") != ox::StringView(""));
|
||||||
|
static_assert(ox::StringView("") != ox::StringView("Read"));
|
||||||
|
static_assert(ox::StringView("") == ox::StringView(""));
|
||||||
|
static_assert(ox::StringView("") == "");
|
||||||
|
static_assert("Read" == ox::StringView("Read"));
|
||||||
|
static_assert(ox::StringView("Read") == ox::StringView("Read"));
|
39
deps/ox/src/ox/std/stringview.hpp
vendored
39
deps/ox/src/ox/std/stringview.hpp
vendored
@ -8,6 +8,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef OX_USE_STDLIB
|
||||||
|
#include <string_view>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "iterator.hpp"
|
#include "iterator.hpp"
|
||||||
#include "strops.hpp"
|
#include "strops.hpp"
|
||||||
#include "types.hpp"
|
#include "types.hpp"
|
||||||
@ -133,8 +137,11 @@ class StringView {
|
|||||||
public:
|
public:
|
||||||
constexpr StringView() noexcept = default;
|
constexpr StringView() noexcept = default;
|
||||||
|
|
||||||
constexpr StringView(const StringView &sv) noexcept: m_str(sv.m_str), m_len(sv.m_len) {
|
constexpr StringView(const StringView &sv) noexcept = default;
|
||||||
}
|
|
||||||
|
#ifdef OX_USE_STDLIB
|
||||||
|
constexpr StringView(const std::string_view &sv) noexcept: m_str(sv.data()), m_len(sv.size()) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
template<std::size_t SmallStrSz>
|
template<std::size_t SmallStrSz>
|
||||||
constexpr StringView(const BasicString<SmallStrSz> &str) noexcept: m_str(str.c_str()), m_len(str.len()) {}
|
constexpr StringView(const BasicString<SmallStrSz> &str) noexcept: m_str(str.c_str()), m_len(str.len()) {}
|
||||||
@ -259,16 +266,22 @@ class StringView {
|
|||||||
|
|
||||||
using CRStringView = const StringView&;
|
using CRStringView = const StringView&;
|
||||||
|
|
||||||
static_assert(StringView("Read").bytes() == 4);
|
[[nodiscard]]
|
||||||
static_assert(StringView("Read") == StringView("Read"));
|
constexpr bool beginsWith(CRStringView base, CRStringView beginning) noexcept {
|
||||||
static_assert(StringView("Read") != StringView("Write"));
|
const auto beginningLen = ox::min(beginning.len(), base.len());
|
||||||
static_assert(StringView("Write") != StringView("Read"));
|
return ox_strncmp(base.data(), beginning, beginningLen) == 0;
|
||||||
static_assert(StringView("Write") != StringView(""));
|
|
||||||
static_assert(StringView("") != StringView("Read"));
|
|
||||||
static_assert(StringView("") == StringView(""));
|
|
||||||
static_assert(StringView("") == "");
|
|
||||||
static_assert("Read" == StringView("Read"));
|
|
||||||
static_assert(StringView("Read") == StringView("Read"));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr bool endsWith(CRStringView base, CRStringView ending) noexcept {
|
||||||
|
const auto endingLen = ending.len();
|
||||||
|
return base.len() >= endingLen && ox_strcmp(base.data() + (base.len() - endingLen), ending) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OX_USE_STDLIB
|
||||||
|
constexpr auto toStdStringView(CRStringView sv) noexcept {
|
||||||
|
return std::string_view(sv.data(), sv.bytes());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
19
deps/ox/src/ox/std/strops.hpp
vendored
19
deps/ox/src/ox/std/strops.hpp
vendored
@ -15,9 +15,10 @@
|
|||||||
|
|
||||||
template<typename T1, typename T2>
|
template<typename T1, typename T2>
|
||||||
constexpr char *ox_strcpy(T1 dest, T2 src) noexcept {
|
constexpr char *ox_strcpy(T1 dest, T2 src) noexcept {
|
||||||
|
using T1Type = typename ox::remove_reference<decltype(dest[0])>::type;
|
||||||
std::size_t i = 0;
|
std::size_t i = 0;
|
||||||
while (src[i]) {
|
while (src[i]) {
|
||||||
dest[i] = src[i];
|
dest[i] = static_cast<T1Type>(src[i]);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
// set null terminator
|
// set null terminator
|
||||||
@ -27,9 +28,10 @@ constexpr char *ox_strcpy(T1 dest, T2 src) noexcept {
|
|||||||
|
|
||||||
template<typename T1, typename T2>
|
template<typename T1, typename T2>
|
||||||
constexpr char *ox_strncpy(T1 dest, T2 src, std::size_t maxLen) noexcept {
|
constexpr char *ox_strncpy(T1 dest, T2 src, std::size_t maxLen) noexcept {
|
||||||
|
using T1Type = typename ox::remove_reference<decltype(dest[0])>::type;
|
||||||
std::size_t i = 0;
|
std::size_t i = 0;
|
||||||
while (i < maxLen && src[i]) {
|
while (i < maxLen && src[i]) {
|
||||||
dest[i] = src[i];
|
dest[i] = static_cast<T1Type>(src[i]);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
// set null terminator
|
// set null terminator
|
||||||
@ -113,18 +115,7 @@ constexpr char *ox_strchr(char *str, int character, std::size_t maxLen = 0xFFFFF
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr int ox_lastIndexOf(const char *str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept {
|
constexpr int ox_lastIndexOf(const auto &str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept {
|
||||||
int retval = -1;
|
|
||||||
for (std::size_t i = 0; i < maxLen && str[i]; i++) {
|
|
||||||
if (str[i] == character) {
|
|
||||||
retval = static_cast<int>(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
constexpr int ox_lastIndexOf(char *str, int character, std::size_t maxLen = 0xFFFFFFFF) noexcept {
|
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
for (std::size_t i = 0; i < maxLen && str[i]; i++) {
|
for (std::size_t i = 0; i < maxLen && str[i]; i++) {
|
||||||
if (str[i] == character) {
|
if (str[i] == character) {
|
||||||
|
22
deps/ox/src/ox/std/test/tests.cpp
vendored
22
deps/ox/src/ox/std/test/tests.cpp
vendored
@ -75,17 +75,17 @@ static std::map<ox::String, ox::Error(*)()> tests = {
|
|||||||
oxAssert(s == "asdf", "String assign broken");
|
oxAssert(s == "asdf", "String assign broken");
|
||||||
s += "aoeu";
|
s += "aoeu";
|
||||||
oxAssert(s == "asdfaoeu", "String append broken");
|
oxAssert(s == "asdfaoeu", "String append broken");
|
||||||
ox::String ending = "asdf";
|
const ox::StringView str = "asdf";
|
||||||
oxAssert(ending.beginsWith("as"), "String::beginsWith is broken");
|
oxAssert(beginsWith(str, "as"), "String beginsWith is broken");
|
||||||
oxAssert(ending.beginsWith("asd"), "String::beginsWith is broken");
|
oxAssert(beginsWith(str, "asd"), "String beginsWith is broken");
|
||||||
oxAssert(ending.beginsWith("asdf"), "String::beginsWith is broken");
|
oxAssert(beginsWith(str, "asdf"), "String beginsWith is broken");
|
||||||
oxAssert(!ending.beginsWith("aa"), "String::beginsWith is broken");
|
oxAssert(!beginsWith(str, "aa"), "String beginsWith is broken");
|
||||||
oxAssert(!ending.beginsWith("aaaaaaa"), "String::beginsWith is broken");
|
oxAssert(!beginsWith(str, "aaaaaaa"), "String beginsWith is broken");
|
||||||
oxAssert(!ending.beginsWith("li"), "String::beginsWith is broken");
|
oxAssert(!beginsWith(str, "li"), "String beginsWith is broken");
|
||||||
oxAssert(!ending.beginsWith("afoif"), "String::beginsWith is broken");
|
oxAssert(!beginsWith(str, "afoif"), "String beginsWith is broken");
|
||||||
oxAssert(ending.endsWith("df"), "String::endsWith is broken");
|
oxAssert(endsWith(str, "df"), "String endsWith is broken");
|
||||||
oxAssert(!ending.endsWith("awefawe"), "String::endsWith is broken");
|
oxAssert(!endsWith(str, "awefawe"), "String endsWith is broken");
|
||||||
oxAssert(!ending.endsWith("eu"), "String::endsWith is broken");
|
oxAssert(!endsWith(str, "eu"), "String endsWith is broken");
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
6
deps/ox/src/ox/std/trace.hpp
vendored
6
deps/ox/src/ox/std/trace.hpp
vendored
@ -59,11 +59,11 @@ class OutStream {
|
|||||||
TraceMsg m_msg;
|
TraceMsg m_msg;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr OutStream(const char *file, int line, const char *ch, const String &msg) noexcept {
|
constexpr OutStream(const char *file, int line, const char *ch, const StringView &msg) noexcept {
|
||||||
m_msg.file = file;
|
m_msg.file = file;
|
||||||
m_msg.line = line;
|
m_msg.line = line;
|
||||||
m_msg.ch = ch;
|
m_msg.ch = ch;
|
||||||
m_msg.msg = msg.c_str();
|
m_msg.msg = msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr OutStream(const char *file, int line, const char *ch, const char *msg = "") noexcept {
|
constexpr OutStream(const char *file, int line, const char *ch, const char *msg = "") noexcept {
|
||||||
@ -182,7 +182,7 @@ constexpr OutStream &OutStream::operator<<(Integer_c auto v) noexcept {
|
|||||||
class NullStream {
|
class NullStream {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr NullStream(const char*, int, const char*, const String&) noexcept {
|
constexpr NullStream(const char*, int, const char*, const StringView&) noexcept {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr NullStream(const char*, int, const char*, const char* = "") noexcept {
|
constexpr NullStream(const char*, int, const char*, const char* = "") noexcept {
|
||||||
|
11
deps/ox/src/ox/std/tracehook.cpp
vendored
11
deps/ox/src/ox/std/tracehook.cpp
vendored
@ -43,7 +43,7 @@ void initConsole() {
|
|||||||
if (REG_MGBA_DEBUG_ENABLE == 0x1DEA) {
|
if (REG_MGBA_DEBUG_ENABLE == 0x1DEA) {
|
||||||
infoLog = log<LogChan::Info>;
|
infoLog = log<LogChan::Info>;
|
||||||
debugLog = log<LogChan::Info>; // use INFO because mGBA disables DEBUG on start
|
debugLog = log<LogChan::Info>; // use INFO because mGBA disables DEBUG on start
|
||||||
errorLog = log<LogChan::Error>;
|
errorLog = log<LogChan::Info>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,13 +71,14 @@ void oxTraceHook([[maybe_unused]] const char *file, [[maybe_unused]] int line,
|
|||||||
std::cout << std::setw(65) << std::left << msg << '|';
|
std::cout << std::setw(65) << std::left << msg << '|';
|
||||||
std::cout << " " << file << ':' << line << "\n";
|
std::cout << " " << file << ':' << line << "\n";
|
||||||
} else if (ox_strcmp(ch, "debug") == 0 || ox_strcmp(ch, "info") == 0) {
|
} else if (ox_strcmp(ch, "debug") == 0 || ox_strcmp(ch, "info") == 0) {
|
||||||
std::cout << msg << '\n';
|
printf("%s\n", msg);
|
||||||
} else if (ox_strcmp(ch, "stdout") == 0) {
|
} else if (ox_strcmp(ch, "stdout") == 0) {
|
||||||
std::cout << msg;
|
printf("%s", msg);
|
||||||
} else if (ox_strcmp(ch, "stderr") == 0) {
|
} else if (ox_strcmp(ch, "stderr") == 0) {
|
||||||
std::cerr << msg;
|
printf("%s", msg);
|
||||||
} else if (ox_strcmp(ch, "error") == 0) {
|
} else if (ox_strcmp(ch, "error") == 0) {
|
||||||
std::cerr << "\033[31;1;1mERROR:\033[0m (" << file << ':' << line << "): " << msg << '\n';
|
//std::cerr << "\033[31;1;1mERROR:\033[0m (" << file << ':' << line << "): " << msg << '\n';
|
||||||
|
fprintf(stderr, "\033[31;1;1mERROR:\033[0m (%s:%d): %s\n", file, line, msg);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (ox_strcmp(ch, "info") == 0) {
|
if (ox_strcmp(ch, "info") == 0) {
|
||||||
|
Binary file not shown.
1
sample_project/Palettes/Logo.npal
Normal file
1
sample_project/Palettes/Logo.npal
Normal file
@ -0,0 +1 @@
|
|||||||
|
M2;net.drinkingtea.nostalgia.core.Palette;1;PÛ{³ÖCˆ
|
BIN
sample_project/TileSheets/Logo.ng
Normal file
BIN
sample_project/TileSheets/Logo.ng
Normal file
Binary file not shown.
BIN
sample_project/TileSheets/NS_Logo.ng
Normal file
BIN
sample_project/TileSheets/NS_Logo.ng
Normal file
Binary file not shown.
@ -14,7 +14,7 @@ namespace nostalgia::core {
|
|||||||
|
|
||||||
ox::String getClipboardText(class Context *ctx) noexcept;
|
ox::String getClipboardText(class Context *ctx) noexcept;
|
||||||
|
|
||||||
void setClipboardText(class Context *ctx, const ox::String &text) noexcept;
|
void setClipboardText(class Context *ctx, ox::CRStringView text) noexcept;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void setClipboardObject([[maybe_unused]] class Context *ctx, [[maybe_unused]] ox::UniquePtr<T> obj) noexcept {
|
void setClipboardObject([[maybe_unused]] class Context *ctx, [[maybe_unused]] ox::UniquePtr<T> obj) noexcept {
|
||||||
|
@ -61,9 +61,14 @@ class Context {
|
|||||||
unsigned cbb,
|
unsigned cbb,
|
||||||
const ox::FileAddress &tilesheetPath,
|
const ox::FileAddress &tilesheetPath,
|
||||||
const ox::FileAddress &palettePath) noexcept;
|
const ox::FileAddress &palettePath) noexcept;
|
||||||
|
friend ox::Error loadSpriteTileSheet(Context *ctx,
|
||||||
|
const ox::FileAddress &tilesheetAddr,
|
||||||
|
const ox::FileAddress &paletteAddr) noexcept;
|
||||||
|
friend ox::Result<struct TileSheetData> loadTileSheet(Context *ctx,
|
||||||
|
const struct CompactTileSheet &tilesheetAddr) noexcept;
|
||||||
friend ox::Error run(Context *ctx) noexcept;
|
friend ox::Error run(Context *ctx) noexcept;
|
||||||
friend void shutdown(Context *ctx) noexcept;
|
friend void shutdown(Context *ctx) noexcept;
|
||||||
friend ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem> fs, const char *appName) noexcept;
|
friend ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem> fs, ox::CRStringView appName) noexcept;
|
||||||
friend ox::String getClipboardText(Context *ctx) noexcept;
|
friend ox::String getClipboardText(Context *ctx) noexcept;
|
||||||
friend uint64_t ticksMs(Context *ctx) noexcept;
|
friend uint64_t ticksMs(Context *ctx) noexcept;
|
||||||
friend uint8_t bgStatus(Context *ctx) noexcept;
|
friend uint8_t bgStatus(Context *ctx) noexcept;
|
||||||
@ -73,17 +78,24 @@ class Context {
|
|||||||
friend void setBgCbb(Context *ctx, unsigned bgIdx, unsigned cbb) noexcept;
|
friend void setBgCbb(Context *ctx, unsigned bgIdx, unsigned cbb) noexcept;
|
||||||
friend void setBgStatus(Context *ctx, uint32_t status) noexcept;
|
friend void setBgStatus(Context *ctx, uint32_t status) noexcept;
|
||||||
friend void setBgStatus(Context *ctx, unsigned bg, bool status) noexcept;
|
friend void setBgStatus(Context *ctx, unsigned bg, bool status) noexcept;
|
||||||
friend void setClipboardText(Context *ctx, const ox::String &text) noexcept;
|
|
||||||
friend void setUpdateHandler(Context *ctx, UpdateHandler h) noexcept;
|
friend void setUpdateHandler(Context *ctx, UpdateHandler h) noexcept;
|
||||||
friend constexpr void setKeyEventHandler(Context *ctx, KeyEventHandler h) noexcept;
|
friend constexpr void setKeyEventHandler(Context *ctx, KeyEventHandler h) noexcept;
|
||||||
friend constexpr KeyEventHandler keyEventHandler(Context *ctx) noexcept;
|
friend constexpr KeyEventHandler keyEventHandler(Context *ctx) noexcept;
|
||||||
friend void setTile(Context *ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept;
|
friend void setTile(Context *ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept;
|
||||||
friend void setWindowTitle(Context *ctx, const char *title) noexcept;
|
friend void setSprite(Context *ctx,
|
||||||
|
unsigned idx,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
unsigned tileIdx,
|
||||||
|
unsigned spriteShape,
|
||||||
|
unsigned spriteSize,
|
||||||
|
unsigned flipX) noexcept;
|
||||||
|
friend void hideSprite(Context *ctx, unsigned idx) noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ox::UniquePtr<ox::FileSystem> rom;
|
ox::UniquePtr<ox::FileSystem> rom;
|
||||||
ox::Vector<Drawer*, 5> drawers;
|
ox::Vector<Drawer*, 5> drawers;
|
||||||
const char *appName = "Nostalgia";
|
ox::StringView appName = "Nostalgia";
|
||||||
|
|
||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
AssetManager assetManager;
|
AssetManager assetManager;
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem> fs, const char *appName = "Nostalgia") noexcept;
|
ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem> fs, ox::CRStringView appName = "Nostalgia") noexcept;
|
||||||
|
|
||||||
ox::Error run(Context *ctx) noexcept;
|
ox::Error run(Context *ctx) noexcept;
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ static ox::Result<std::size_t> findPreloadSection() noexcept {
|
|||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem> fs, const char *appName) noexcept {
|
ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem> fs, ox::CRStringView appName) noexcept {
|
||||||
auto ctx = ox::make_unique<Context>();
|
auto ctx = ox::make_unique<Context>();
|
||||||
ctx->rom = std::move(fs);
|
ctx->rom = std::move(fs);
|
||||||
ctx->appName = appName;
|
ctx->appName = appName;
|
||||||
@ -74,7 +74,7 @@ uint64_t ticksMs(Context*) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool buttonDown(Context*, Key k) noexcept {
|
bool buttonDown(Context*, Key k) noexcept {
|
||||||
return !(REG_GAMEPAD & (1 << static_cast<int>(k)));
|
return k <= Key::GamePad_L && !(REG_GAMEPAD & (1 << static_cast<int>(k)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void shutdown(Context *ctx) noexcept {
|
void shutdown(Context *ctx) noexcept {
|
||||||
|
@ -85,7 +85,7 @@ ox::Error shutdownGfx(Context*) noexcept {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void setWindowTitle(Context*, const char*) noexcept {
|
void setWindowTitle(Context*, ox::CRStringView) noexcept {
|
||||||
}
|
}
|
||||||
|
|
||||||
void focusWindow(Context*) noexcept {
|
void focusWindow(Context*) noexcept {
|
||||||
@ -124,8 +124,8 @@ void setBgStatus(Context*, unsigned bg, bool status) noexcept {
|
|||||||
|
|
||||||
// Do NOT rely on Context in the GBA version of this function.
|
// Do NOT rely on Context in the GBA version of this function.
|
||||||
ox::Error initConsole(Context *ctx) noexcept {
|
ox::Error initConsole(Context *ctx) noexcept {
|
||||||
constexpr auto TilesheetAddr = "/TileSheets/Charset.ng";
|
constexpr ox::FileAddress TilesheetAddr("/TileSheets/Charset.ng");
|
||||||
constexpr auto PaletteAddr = "/Palettes/Charset.npal";
|
constexpr ox::FileAddress PaletteAddr("/Palettes/Charset.npal");
|
||||||
setBgStatus(ctx, 0b0001);
|
setBgStatus(ctx, 0b0001);
|
||||||
if (!ctx) {
|
if (!ctx) {
|
||||||
ctx = new (ox_alloca(sizeof(Context))) Context();
|
ctx = new (ox_alloca(sizeof(Context))) Context();
|
||||||
@ -174,14 +174,13 @@ ox::Error loadBgTileSheet(Context *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ox::Error loadSpriteTileSheet(Context *ctx,
|
ox::Error loadSpriteTileSheet(Context *ctx,
|
||||||
unsigned cbb,
|
|
||||||
const ox::FileAddress &tilesheetAddr,
|
const ox::FileAddress &tilesheetAddr,
|
||||||
const ox::FileAddress &paletteAddr) noexcept {
|
const ox::FileAddress &paletteAddr) noexcept {
|
||||||
oxRequire(tsStat, ctx->rom->stat(tilesheetAddr));
|
oxRequire(tsStat, ctx->rom->stat(tilesheetAddr));
|
||||||
oxRequire(ts, ctx->rom->directAccess(tilesheetAddr));
|
oxRequire(ts, ctx->rom->directAccess(tilesheetAddr));
|
||||||
GbaTileMapTarget target;
|
GbaTileMapTarget target;
|
||||||
target.pal.palette = &MEM_SPRITE_PALETTE[cbb];
|
target.pal.palette = MEM_SPRITE_PALETTE;
|
||||||
target.tileMap = &reinterpret_cast<uint16_t*>(MEM_SPRITE_TILES)[cbb * 512];
|
target.tileMap = MEM_SPRITE_TILES;
|
||||||
oxReturnError(ox::readMC(ts, tsStat.size, &target));
|
oxReturnError(ox::readMC(ts, tsStat.size, &target));
|
||||||
// load external palette if available
|
// load external palette if available
|
||||||
if (paletteAddr) {
|
if (paletteAddr) {
|
||||||
@ -211,10 +210,11 @@ ox::Error loadSpritePalette(Context *ctx, unsigned cbb, const ox::FileAddress &p
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do NOT use Context in the GBA version of this function.
|
// Do NOT use Context in the GBA version of this function.
|
||||||
void puts(Context *ctx, int column, int row, const char *str) noexcept {
|
void puts(Context *ctx, int column, int row, ox::CRStringView str) noexcept {
|
||||||
for (int i = 0; str[i]; i++) {
|
const auto col = static_cast<unsigned>(column);
|
||||||
|
for (auto i = 0u; i < str.bytes(); i++) {
|
||||||
const auto c = charMap[static_cast<unsigned>(str[i])];
|
const auto c = charMap[static_cast<unsigned>(str[i])];
|
||||||
setTile(ctx, 0, column + i, row, static_cast<uint8_t>(c));
|
setTile(ctx, 0, static_cast<int>(col + i), row, static_cast<uint8_t>(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,15 +253,15 @@ void hideSprite(Context*, unsigned idx) noexcept {
|
|||||||
|
|
||||||
void setSprite(Context*,
|
void setSprite(Context*,
|
||||||
unsigned idx,
|
unsigned idx,
|
||||||
unsigned x,
|
int x,
|
||||||
unsigned y,
|
int y,
|
||||||
unsigned tileIdx,
|
unsigned tileIdx,
|
||||||
unsigned spriteShape,
|
unsigned spriteShape,
|
||||||
unsigned spriteSize,
|
unsigned spriteSize,
|
||||||
unsigned flipX) noexcept {
|
unsigned flipX) noexcept {
|
||||||
oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
|
||||||
GbaSpriteAttrUpdate oa;
|
GbaSpriteAttrUpdate oa;
|
||||||
oa.attr0 = static_cast<uint16_t>(y & ox::onMask<uint8_t>(7))
|
oa.attr0 = static_cast<uint16_t>(y & ox::onMask<uint8_t>(0b111'1111))
|
||||||
| (static_cast<uint16_t>(1) << 10) // enable alpha
|
| (static_cast<uint16_t>(1) << 10) // enable alpha
|
||||||
| (static_cast<uint16_t>(spriteShape) << 14);
|
| (static_cast<uint16_t>(spriteShape) << 14);
|
||||||
oa.attr1 = (static_cast<uint16_t>(x) & ox::onMask<uint8_t>(8))
|
oa.attr1 = (static_cast<uint16_t>(x) & ox::onMask<uint8_t>(8))
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
ox::Result<char*> loadRom(const char*) noexcept {
|
ox::Result<char*> loadRom(ox::CRStringView) noexcept {
|
||||||
// put the header in the wrong order to prevent mistaking this code for the
|
// put the header in the wrong order to prevent mistaking this code for the
|
||||||
// media section
|
// media section
|
||||||
constexpr auto headerP2 = "HEADER__________";
|
constexpr auto headerP2 = "HEADER__________";
|
||||||
@ -31,6 +31,14 @@ ox::Result<char*> loadRom(const char*) noexcept {
|
|||||||
void unloadRom(char*) noexcept {
|
void unloadRom(char*) noexcept {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ox::Result<std::size_t> getPreloadAddr(Context *ctx, ox::CRStringView path) noexcept {
|
||||||
|
oxRequire(stat, ctx->rom->stat(path));
|
||||||
|
oxRequire(buff, ctx->rom->directAccess(path));
|
||||||
|
PreloadPtr p;
|
||||||
|
oxReturnError(ox::readMC(buff, stat.size, &p));
|
||||||
|
return p.preloadAddr + ctx->preloadSectionOffset;
|
||||||
|
}
|
||||||
|
|
||||||
ox::Result<std::size_t> getPreloadAddr(Context *ctx, const ox::FileAddress &file) noexcept {
|
ox::Result<std::size_t> getPreloadAddr(Context *ctx, const ox::FileAddress &file) noexcept {
|
||||||
oxRequire(stat, ctx->rom->stat(file));
|
oxRequire(stat, ctx->rom->stat(file));
|
||||||
oxRequire(buff, ctx->rom->directAccess(file));
|
oxRequire(buff, ctx->rom->directAccess(file));
|
||||||
|
@ -27,7 +27,7 @@ void panic(const char*, int, const char *msg, const ox::Error &err) noexcept {
|
|||||||
puts(nullptr, 32 + 1, 4, "UNEXPECTED STATE:");
|
puts(nullptr, 32 + 1, 4, "UNEXPECTED STATE:");
|
||||||
puts(nullptr, 32 + 2, 6, msg);
|
puts(nullptr, 32 + 2, 6, msg);
|
||||||
if (err) {
|
if (err) {
|
||||||
puts(nullptr, 32 + 2, 8, serr.c_str());
|
puts(nullptr, 32 + 2, 8, serr);
|
||||||
}
|
}
|
||||||
puts(nullptr, 32 + 1, 15, "PLEASE RESTART THE SYSTEM");
|
puts(nullptr, 32 + 1, 15, "PLEASE RESTART THE SYSTEM");
|
||||||
// disable all interrupt handling and IntrWait on no interrupts
|
// disable all interrupt handling and IntrWait on no interrupts
|
||||||
|
@ -93,11 +93,11 @@ struct TileSheet {
|
|||||||
other.columns = 0;
|
other.columns = 0;
|
||||||
other.rows = 0;
|
other.rows = 0;
|
||||||
}
|
}
|
||||||
constexpr SubSheet(const char *pName, int pColumns, int pRows, int bpp) noexcept:
|
constexpr SubSheet(ox::CRStringView pName, int pColumns, int pRows, int bpp) noexcept:
|
||||||
name(pName), columns(pColumns), rows(pRows),
|
name(pName), columns(pColumns), rows(pRows),
|
||||||
pixels(static_cast<std::size_t>(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) {
|
pixels(static_cast<std::size_t>(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) {
|
||||||
}
|
}
|
||||||
constexpr SubSheet(const char *pName, int pColumns, int pRows, ox::Vector<uint8_t> pPixels) noexcept:
|
constexpr SubSheet(ox::CRStringView pName, int pColumns, int pRows, ox::Vector<uint8_t> pPixels) noexcept:
|
||||||
name(pName), columns(pColumns), rows(pRows), pixels(std::move(pPixels)) {
|
name(pName), columns(pColumns), rows(pRows), pixels(std::move(pPixels)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ struct TileSheet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
auto idx(const geo::Point &pt) const noexcept {
|
constexpr auto idx(const geo::Point &pt) const noexcept {
|
||||||
return ptToIdx(pt, columns);
|
return ptToIdx(pt, columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,6 +275,7 @@ struct TileSheet {
|
|||||||
* @param pBpp bits per pixel, need for knowing how to count the pixels
|
* @param pBpp bits per pixel, need for knowing how to count the pixels
|
||||||
* @return a count of the pixels in this sheet
|
* @return a count of the pixels in this sheet
|
||||||
*/
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
constexpr auto pixelCnt(int8_t pBpp) const noexcept {
|
constexpr auto pixelCnt(int8_t pBpp) const noexcept {
|
||||||
return pBpp == 4 ? pixels.size() * 2 : pixels.size();
|
return pBpp == 4 ? pixels.size() * 2 : pixels.size();
|
||||||
}
|
}
|
||||||
@ -287,13 +288,9 @@ struct TileSheet {
|
|||||||
SubSheet subsheet{"Root", 1, 1, bpp};
|
SubSheet subsheet{"Root", 1, 1, bpp};
|
||||||
|
|
||||||
constexpr TileSheet() noexcept = default;
|
constexpr TileSheet() noexcept = default;
|
||||||
inline TileSheet(const TileSheet &other) noexcept:
|
TileSheet(const TileSheet &other) noexcept = default;
|
||||||
bpp(other.bpp),
|
|
||||||
defaultPalette(other.defaultPalette),
|
|
||||||
subsheet(other.subsheet) {
|
|
||||||
}
|
|
||||||
inline TileSheet(TileSheet &&other) noexcept:
|
inline TileSheet(TileSheet &&other) noexcept:
|
||||||
bpp(std::move(other.bpp)),
|
bpp(other.bpp),
|
||||||
defaultPalette(std::move(other.defaultPalette)),
|
defaultPalette(std::move(other.defaultPalette)),
|
||||||
subsheet(std::move(other.subsheet)) {
|
subsheet(std::move(other.subsheet)) {
|
||||||
}
|
}
|
||||||
@ -375,7 +372,7 @@ struct TileSheet {
|
|||||||
constexpr ox::Error addSubSheet(const SubSheetIdx &idx) noexcept {
|
constexpr ox::Error addSubSheet(const SubSheetIdx &idx) noexcept {
|
||||||
auto &parent = getSubSheet(idx);
|
auto &parent = getSubSheet(idx);
|
||||||
if (parent.subsheets.size() < 2) {
|
if (parent.subsheets.size() < 2) {
|
||||||
parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", parent.subsheets.size()).c_str(), 1, 1, bpp);
|
parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", parent.subsheets.size()), 1, 1, bpp);
|
||||||
} else {
|
} else {
|
||||||
parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows, bpp);
|
parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows, bpp);
|
||||||
parent.subsheets.emplace_back("Subsheet 1", 1, 1, bpp);
|
parent.subsheets.emplace_back("Subsheet 1", 1, 1, bpp);
|
||||||
@ -468,21 +465,31 @@ oxModelEnd()
|
|||||||
|
|
||||||
struct Sprite {
|
struct Sprite {
|
||||||
unsigned idx = 0;
|
unsigned idx = 0;
|
||||||
unsigned x = 0;
|
int x = 0;
|
||||||
unsigned y = 0;
|
int y = 0;
|
||||||
unsigned tileIdx = 0;
|
unsigned tileIdx = 0;
|
||||||
unsigned spriteShape = 0;
|
unsigned spriteShape = 0;
|
||||||
unsigned spriteSize = 0;
|
unsigned spriteSize = 0;
|
||||||
unsigned flipX = 0;
|
unsigned flipX = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
oxModelBegin(Sprite)
|
||||||
|
oxModelField(idx)
|
||||||
|
oxModelField(x)
|
||||||
|
oxModelField(y)
|
||||||
|
oxModelField(tileIdx)
|
||||||
|
oxModelField(spriteShape)
|
||||||
|
oxModelField(spriteSize)
|
||||||
|
oxModelField(flipX)
|
||||||
|
oxModelEnd()
|
||||||
|
|
||||||
ox::Error initGfx(Context *ctx) noexcept;
|
ox::Error initGfx(Context *ctx) noexcept;
|
||||||
|
|
||||||
void addCustomDrawer(Context *ctx, Drawer *cd) noexcept;
|
void addCustomDrawer(Context *ctx, Drawer *cd) noexcept;
|
||||||
|
|
||||||
void removeCustomDrawer(Context *ctx, Drawer *cd) noexcept;
|
void removeCustomDrawer(Context *ctx, Drawer *cd) noexcept;
|
||||||
|
|
||||||
void setWindowTitle(Context *ctx, const char *title) noexcept;
|
void setWindowTitle(Context *ctx, ox::CRStringView title) noexcept;
|
||||||
|
|
||||||
void focusWindow(Context *ctx) noexcept;
|
void focusWindow(Context *ctx) noexcept;
|
||||||
|
|
||||||
@ -515,11 +522,10 @@ ox::Error loadBgTileSheet(Context *ctx, unsigned cbb, const ox::FileAddress &til
|
|||||||
const ox::FileAddress &palette = nullptr) noexcept;
|
const ox::FileAddress &palette = nullptr) noexcept;
|
||||||
|
|
||||||
ox::Error loadSpriteTileSheet(Context *ctx,
|
ox::Error loadSpriteTileSheet(Context *ctx,
|
||||||
unsigned section,
|
|
||||||
const ox::FileAddress &tilesheetAddr,
|
const ox::FileAddress &tilesheetAddr,
|
||||||
const ox::FileAddress &paletteAddr) noexcept;
|
const ox::FileAddress &paletteAddr) noexcept;
|
||||||
|
|
||||||
void puts(Context *ctx, int column, int row, const char *str) noexcept;
|
void puts(Context *ctx, int column, int row, ox::CRStringView str) noexcept;
|
||||||
|
|
||||||
void setTile(Context *ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept;
|
void setTile(Context *ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept;
|
||||||
|
|
||||||
@ -527,7 +533,7 @@ void clearTileLayer(Context *ctx, unsigned bgIdx) noexcept;
|
|||||||
|
|
||||||
void hideSprite(Context *ctx, unsigned) noexcept;
|
void hideSprite(Context *ctx, unsigned) noexcept;
|
||||||
|
|
||||||
void setSprite(Context *ctx, unsigned idx, unsigned x, unsigned y, unsigned tileIdx,
|
void setSprite(Context *ctx, unsigned idx, int x, int y, unsigned tileIdx,
|
||||||
unsigned spriteShape = 0, unsigned spriteSize = 0, unsigned flipX = 0) noexcept;
|
unsigned spriteShape = 0, unsigned spriteSize = 0, unsigned flipX = 0) noexcept;
|
||||||
|
|
||||||
void setSprite(Context *ctx, const Sprite &s) noexcept;
|
void setSprite(Context *ctx, const Sprite &s) noexcept;
|
||||||
|
@ -17,9 +17,11 @@ ox::String getClipboardText(Context *ctx) noexcept {
|
|||||||
return glfwGetClipboardString(id->window);
|
return glfwGetClipboardString(id->window);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setClipboardText(Context *ctx, const ox::String &text) noexcept {
|
void setClipboardText(Context *ctx, ox::CRStringView text) noexcept {
|
||||||
const auto id = ctx->windowerData<GlfwImplData>();
|
const auto id = ctx->windowerData<GlfwImplData>();
|
||||||
glfwSetClipboardString(id->window, text.c_str());
|
auto cstr = ox_malloca(text.bytes() + 1, char);
|
||||||
|
ox_strncpy(cstr.get(), text.data(), text.bytes());
|
||||||
|
glfwSetClipboardString(id->window, cstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem> fs, const char *appName) noexcept {
|
ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem> fs, ox::CRStringView appName) noexcept {
|
||||||
auto ctx = ox::make_unique<Context>();
|
auto ctx = ox::make_unique<Context>();
|
||||||
ctx->rom = std::move(fs);
|
ctx->rom = std::move(fs);
|
||||||
ctx->appName = appName;
|
ctx->appName = appName;
|
||||||
@ -32,15 +32,13 @@ ox::Error run(Context *ctx) noexcept {
|
|||||||
while (!glfwWindowShouldClose(id->window)) {
|
while (!glfwWindowShouldClose(id->window)) {
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
const auto ticks = ticksMs(ctx);
|
const auto ticks = ticksMs(ctx);
|
||||||
if (id->eventHandler) {
|
if (id->wakeupTime <= ticks) {
|
||||||
if (id->wakeupTime <= ticks) {
|
sleepTime = id->eventHandler(ctx);
|
||||||
sleepTime = id->eventHandler(ctx);
|
if (sleepTime >= 0) {
|
||||||
if (sleepTime >= 0) {
|
id->wakeupTime = ticks + static_cast<unsigned>(sleepTime);
|
||||||
id->wakeupTime = ticks + static_cast<unsigned>(sleepTime);
|
} else {
|
||||||
} else {
|
id->wakeupTime = ~uint64_t(0);
|
||||||
id->wakeupTime = ~uint64_t(0);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
sleepTime = 10;
|
sleepTime = 10;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ namespace nostalgia::core {
|
|||||||
struct GlfwImplData {
|
struct GlfwImplData {
|
||||||
struct GLFWwindow *window = nullptr;
|
struct GLFWwindow *window = nullptr;
|
||||||
int64_t startTime = 0;
|
int64_t startTime = 0;
|
||||||
UpdateHandler eventHandler = nullptr;
|
UpdateHandler eventHandler = [](Context*) -> int {return 0;};
|
||||||
KeyEventHandler keyEventHandler = nullptr;
|
KeyEventHandler keyEventHandler = nullptr;
|
||||||
uint64_t wakeupTime = 0;
|
uint64_t wakeupTime = 0;
|
||||||
uint64_t keysDown = 0;
|
uint64_t keysDown = 0;
|
||||||
|
@ -192,7 +192,9 @@ ox::Error initGfx(Context *ctx) noexcept {
|
|||||||
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
|
||||||
}
|
}
|
||||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
|
||||||
id->window = glfwCreateWindow(240 * Scale, 160 * Scale, ctx->appName, nullptr, nullptr);
|
auto cstr = ox_malloca(ctx->appName.bytes() + 1, char);
|
||||||
|
ox_strncpy(cstr.get(), ctx->appName.data(), ctx->appName.bytes());
|
||||||
|
id->window = glfwCreateWindow(240 * Scale, 160 * Scale, cstr, nullptr, nullptr);
|
||||||
if (id->window == nullptr) {
|
if (id->window == nullptr) {
|
||||||
return OxError(1, "Could not open GLFW window");
|
return OxError(1, "Could not open GLFW window");
|
||||||
}
|
}
|
||||||
@ -220,9 +222,11 @@ ox::Error initGfx(Context *ctx) noexcept {
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setWindowTitle(Context *ctx, const char *title) noexcept {
|
void setWindowTitle(Context *ctx, ox::CRStringView title) noexcept {
|
||||||
const auto id = ctx->windowerData<GlfwImplData>();
|
const auto id = ctx->windowerData<GlfwImplData>();
|
||||||
glfwSetWindowTitle(id->window, title);
|
auto cstr = ox_malloca(title.bytes() + 1, char);
|
||||||
|
ox_strncpy(cstr.get(), title.data(), title.bytes());
|
||||||
|
glfwSetWindowTitle(id->window, cstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void focusWindow(Context *ctx) noexcept {
|
void focusWindow(Context *ctx) noexcept {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem>, const char*) noexcept {
|
ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem>, ox::CRStringView) noexcept {
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ ox::Error shutdownGfx(Context*) noexcept {
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setWindowTitle(Context*, const char*) noexcept {
|
void setWindowTitle(Context*, ox::CRStringView) noexcept {
|
||||||
}
|
}
|
||||||
|
|
||||||
void focusWindow(Context*) noexcept {
|
void focusWindow(Context*) noexcept {
|
||||||
@ -60,7 +60,6 @@ ox::Error loadBgTileSheet(Context*,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ox::Error loadSpriteTileSheet(Context*,
|
ox::Error loadSpriteTileSheet(Context*,
|
||||||
int,
|
|
||||||
const ox::FileAddress&,
|
const ox::FileAddress&,
|
||||||
const ox::FileAddress&) noexcept {
|
const ox::FileAddress&) noexcept {
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
@ -75,7 +74,7 @@ ox::Error loadSpritePalette(Context*, int, const ox::FileAddress&) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Do NOT use Context in the GBA version of this function.
|
// Do NOT use Context in the GBA version of this function.
|
||||||
void puts(Context*, int, int, const char*) noexcept {
|
void puts(Context*, int, int, ox::CRStringView) noexcept {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTile(Context*, int, int, int, uint8_t) noexcept {
|
void setTile(Context*, int, int, int, uint8_t) noexcept {
|
||||||
@ -91,8 +90,8 @@ void hideSprite(Context*, unsigned) noexcept {
|
|||||||
|
|
||||||
void setSprite(Context*,
|
void setSprite(Context*,
|
||||||
unsigned,
|
unsigned,
|
||||||
unsigned,
|
int,
|
||||||
unsigned,
|
int,
|
||||||
unsigned,
|
unsigned,
|
||||||
unsigned,
|
unsigned,
|
||||||
unsigned,
|
unsigned,
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
ox::Result<char*> loadRom(const char*) noexcept {
|
ox::Result<char*> loadRom(ox::CRStringView) noexcept {
|
||||||
return OxError(1);
|
return OxError(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(const char *path) noexcept {
|
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(ox::CRStringView path) noexcept {
|
||||||
const auto lastDot = ox_lastIndexOf(path, '.');
|
const auto lastDot = ox_lastIndexOf(path, '.');
|
||||||
const auto fsExt = lastDot != -1 ? path + lastDot : "";
|
const auto fsExt = lastDot != -1 ? path.substr(static_cast<std::size_t>(lastDot)) : "";
|
||||||
if (ox_strcmp(fsExt, ".oxfs") == 0) {
|
if (ox_strcmp(fsExt, ".oxfs") == 0) {
|
||||||
oxRequire(rom, core::loadRom(path));
|
oxRequire(rom, core::loadRom(path));
|
||||||
return {ox::make_unique<ox::FileSystem32>(rom, 32 * ox::units::MB, unloadRom)};
|
return {ox::make_unique<ox::FileSystem32>(rom, 32 * ox::units::MB, unloadRom)};
|
||||||
|
@ -26,9 +26,10 @@ oxModelBegin(PreloadPtr)
|
|||||||
oxModelEnd()
|
oxModelEnd()
|
||||||
|
|
||||||
ox::Result<std::size_t> getPreloadAddr(Context *ctx, const ox::FileAddress &file) noexcept;
|
ox::Result<std::size_t> getPreloadAddr(Context *ctx, const ox::FileAddress &file) noexcept;
|
||||||
|
ox::Result<std::size_t> getPreloadAddr(Context *ctx, ox::CRStringView file) noexcept;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<AssetRef<T>> readObj(Context *ctx, const ox::FileAddress &file,
|
ox::Result<AssetRef<T>> readObj([[maybe_unused]] Context *ctx, [[maybe_unused]] ox::CRStringView path,
|
||||||
[[maybe_unused]] bool forceLoad = false) noexcept {
|
[[maybe_unused]] bool forceLoad = false) noexcept {
|
||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
constexpr auto readConvert = [](const ox::Buffer &buff) -> ox::Result<T> {
|
constexpr auto readConvert = [](const ox::Buffer &buff) -> ox::Result<T> {
|
||||||
@ -41,21 +42,36 @@ ox::Result<AssetRef<T>> readObj(Context *ctx, const ox::FileAddress &file,
|
|||||||
}
|
}
|
||||||
return std::move(obj);
|
return std::move(obj);
|
||||||
};
|
};
|
||||||
oxRequire(path, file.getPath());
|
|
||||||
if (forceLoad) {
|
if (forceLoad) {
|
||||||
oxRequire(buff, ctx->rom->read(file));
|
oxRequire(buff, ctx->rom->read(path));
|
||||||
oxRequire(obj, readConvert(buff));
|
oxRequire(obj, readConvert(buff));
|
||||||
oxRequire(cached, ctx->assetManager.setAsset(path, obj));
|
oxRequire(cached, ctx->assetManager.setAsset(path, obj));
|
||||||
return std::move(cached);
|
return std::move(cached);
|
||||||
} else {
|
} else {
|
||||||
auto [cached, err] = ctx->assetManager.getAsset<T>(path);
|
auto [cached, err] = ctx->assetManager.getAsset<T>(path);
|
||||||
if (err) {
|
if (err) {
|
||||||
oxRequire(buff, ctx->rom->read(file));
|
oxRequire(buff, ctx->rom->read(path));
|
||||||
oxRequire(obj, readConvert(buff));
|
oxRequire(obj, readConvert(buff));
|
||||||
oxReturnError(ctx->assetManager.setAsset(path, obj).moveTo(&cached));
|
oxReturnError(ctx->assetManager.setAsset(path, obj).moveTo(&cached));
|
||||||
}
|
}
|
||||||
return std::move(cached);
|
return std::move(cached);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
if constexpr(ox::preloadable<T>::value) {
|
||||||
|
oxRequire(addr, getPreloadAddr(ctx, path));
|
||||||
|
return AssetRef<T>(reinterpret_cast<const T*>(addr));
|
||||||
|
} else {
|
||||||
|
return OxError(1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
ox::Result<AssetRef<T>> readObj(Context *ctx, const ox::FileAddress &file,
|
||||||
|
[[maybe_unused]] bool forceLoad = false) noexcept {
|
||||||
|
#ifndef OX_BARE_METAL
|
||||||
|
oxRequire(path, file.getPath());
|
||||||
|
return readObj<T>(ctx, ox::StringView(path), forceLoad);
|
||||||
#else
|
#else
|
||||||
if constexpr(ox::preloadable<T>::value) {
|
if constexpr(ox::preloadable<T>::value) {
|
||||||
oxRequire(addr, getPreloadAddr(ctx, file));
|
oxRequire(addr, getPreloadAddr(ctx, file));
|
||||||
@ -73,9 +89,9 @@ ox::Error writeObj(Context *ctx, const ox::FileAddress &file, const T &obj,
|
|||||||
return ctx->rom->write(file, objBuff.data(), objBuff.size());
|
return ctx->rom->write(file, objBuff.data(), objBuff.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(const char *path) noexcept;
|
ox::Result<ox::UniquePtr<ox::FileSystem>> loadRomFs(ox::CRStringView path) noexcept;
|
||||||
|
|
||||||
ox::Result<char*> loadRom(const char *path = "") noexcept;
|
ox::Result<char*> loadRom(ox::CRStringView path = "") noexcept;
|
||||||
|
|
||||||
void unloadRom(char*) noexcept;
|
void unloadRom(char*) noexcept;
|
||||||
|
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ox/std/memory.hpp"
|
#include <ox/std/memory.hpp>
|
||||||
|
|
||||||
#include "paletteeditor-imgui.hpp"
|
#include "paletteeditor-imgui.hpp"
|
||||||
#include "tilesheeteditor-imgui.hpp"
|
#include "tilesheeteditor-imgui.hpp"
|
||||||
|
|
||||||
@ -14,7 +15,7 @@ ox::Vector<studio::EditorMaker> Module::editors(core::Context *ctx) noexcept {
|
|||||||
return {
|
return {
|
||||||
{
|
{
|
||||||
{"ng"},
|
{"ng"},
|
||||||
[ctx](const ox::String &path) -> ox::Result<studio::BaseEditor*> {
|
[ctx](ox::CRStringView path) -> ox::Result<studio::BaseEditor*> {
|
||||||
try {
|
try {
|
||||||
return ox::make<TileSheetEditorImGui>(ctx, path);
|
return ox::make<TileSheetEditorImGui>(ctx, path);
|
||||||
} catch (const ox::Exception &ex) {
|
} catch (const ox::Exception &ex) {
|
||||||
@ -24,7 +25,7 @@ ox::Vector<studio::EditorMaker> Module::editors(core::Context *ctx) noexcept {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
{"npal"},
|
{"npal"},
|
||||||
[ctx](const ox::String &path) -> ox::Result<studio::BaseEditor*> {
|
[ctx](ox::CRStringView path) -> ox::Result<studio::BaseEditor*> {
|
||||||
return PaletteEditorImGui::make(ctx, path);
|
return PaletteEditorImGui::make(ctx, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,13 +13,13 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
ox::Result<PaletteEditorImGui*> PaletteEditorImGui::make(Context *ctx, const ox::String &path) noexcept {
|
ox::Result<PaletteEditorImGui*> PaletteEditorImGui::make(Context *ctx, ox::CRStringView path) noexcept {
|
||||||
auto out = ox::UniquePtr<PaletteEditorImGui>(new PaletteEditorImGui);
|
auto out = ox::UniquePtr<PaletteEditorImGui>(new PaletteEditorImGui);
|
||||||
out->m_ctx = ctx;
|
out->m_ctx = ctx;
|
||||||
out->m_itemPath = path;
|
out->m_itemPath = path;
|
||||||
const auto lastSlash = std::find(out->m_itemPath.rbegin(), out->m_itemPath.rend(), '/').offset();
|
const auto lastSlash = std::find(out->m_itemPath.rbegin(), out->m_itemPath.rend(), '/').offset();
|
||||||
out->m_itemName = out->m_itemPath.substr(lastSlash + 1);
|
out->m_itemName = out->m_itemPath.substr(lastSlash + 1);
|
||||||
oxRequire(pal, core::readObj<Palette>(out->m_ctx, out->m_itemPath));
|
oxRequire(pal, core::readObj<Palette>(out->m_ctx, ox::FileAddress(out->m_itemPath.c_str())));
|
||||||
out->m_pal = *pal;
|
out->m_pal = *pal;
|
||||||
return out.release();
|
return out.release();
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ class PaletteEditorImGui: public studio::Editor {
|
|||||||
PaletteEditorImGui() noexcept = default;
|
PaletteEditorImGui() noexcept = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static ox::Result<PaletteEditorImGui*> make(Context *ctx, const ox::String &path) noexcept;
|
static ox::Result<PaletteEditorImGui*> make(Context *ctx, ox::CRStringView path) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of item being edited.
|
* Returns the name of item being edited.
|
||||||
|
@ -38,7 +38,7 @@ ox::Error toPngFile(const ox::String &path, const TileSheet::SubSheet &s, const
|
|||||||
return OxError(lodepng_encode_file(path.c_str(), outData.data(), width, height, fmt, 8));
|
return OxError(lodepng_encode_file(path.c_str(), outData.data(), width, height, fmt, 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
TileSheetEditorImGui::TileSheetEditorImGui(Context *ctx, const ox::String &path): m_tileSheetEditor(ctx, path) {
|
TileSheetEditorImGui::TileSheetEditorImGui(Context *ctx, ox::CRStringView path): m_tileSheetEditor(ctx, path) {
|
||||||
m_ctx = ctx;
|
m_ctx = ctx;
|
||||||
m_itemPath = path;
|
m_itemPath = path;
|
||||||
const auto lastSlash = ox::find(m_itemPath.rbegin(), m_itemPath.rend(), '/').offset();
|
const auto lastSlash = ox::find(m_itemPath.rbegin(), m_itemPath.rend(), '/').offset();
|
||||||
@ -416,7 +416,7 @@ void TileSheetEditorImGui::SubSheetEditor::draw() noexcept {
|
|||||||
if (ImGui::Button("OK")) {
|
if (ImGui::Button("OK")) {
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
m_show = false;
|
m_show = false;
|
||||||
inputSubmitted.emit(m_name.c_str(), m_cols, m_rows);
|
inputSubmitted.emit(m_name, m_cols, m_rows);
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Cancel")) {
|
if (ImGui::Button("Cancel")) {
|
||||||
|
@ -32,7 +32,7 @@ class TileSheetEditorImGui: public studio::BaseEditor {
|
|||||||
int m_rows = 0;
|
int m_rows = 0;
|
||||||
bool m_show = false;
|
bool m_show = false;
|
||||||
public:
|
public:
|
||||||
ox::Signal<ox::Error(const ox::String &name, int cols, int rows)> inputSubmitted;
|
ox::Signal<ox::Error(const ox::StringView &name, int cols, int rows)> inputSubmitted;
|
||||||
constexpr void show(const ox::String &name, int cols, int rows) noexcept {
|
constexpr void show(const ox::String &name, int cols, int rows) noexcept {
|
||||||
m_show = true;
|
m_show = true;
|
||||||
m_name = name.c_str();
|
m_name = name.c_str();
|
||||||
@ -54,7 +54,7 @@ class TileSheetEditorImGui: public studio::BaseEditor {
|
|||||||
Tool m_tool = Tool::Draw;
|
Tool m_tool = Tool::Draw;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TileSheetEditorImGui(Context *ctx, const ox::String &path);
|
TileSheetEditorImGui(Context *ctx, ox::CRStringView path);
|
||||||
|
|
||||||
~TileSheetEditorImGui() override = default;
|
~TileSheetEditorImGui() override = default;
|
||||||
|
|
||||||
|
@ -256,7 +256,7 @@ class AddSubSheetCommand: public TileSheetCommand {
|
|||||||
auto &parent = m_img->getSubSheet(m_parentIdx);
|
auto &parent = m_img->getSubSheet(m_parentIdx);
|
||||||
if (m_addedSheets.size() < 2) {
|
if (m_addedSheets.size() < 2) {
|
||||||
auto i = parent.subsheets.size();
|
auto i = parent.subsheets.size();
|
||||||
parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", i).c_str(), 1, 1, m_img->bpp);
|
parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", i), 1, 1, m_img->bpp);
|
||||||
} else {
|
} else {
|
||||||
parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows, std::move(parent.pixels));
|
parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows, std::move(parent.pixels));
|
||||||
parent.rows = 0;
|
parent.rows = 0;
|
||||||
@ -511,7 +511,7 @@ class PaletteChangeCommand: public TileSheetCommand {
|
|||||||
m_idx = idx;
|
m_idx = idx;
|
||||||
m_img = img;
|
m_img = img;
|
||||||
m_oldPalette = m_img->defaultPalette;
|
m_oldPalette = m_img->defaultPalette;
|
||||||
m_newPalette = newPalette;
|
m_newPalette = ox::FileAddress(newPalette);
|
||||||
}
|
}
|
||||||
|
|
||||||
void redo() noexcept final {
|
void redo() noexcept final {
|
||||||
@ -538,7 +538,7 @@ class PaletteChangeCommand: public TileSheetCommand {
|
|||||||
TileSheetEditorModel::TileSheetEditorModel(Context *ctx, ox::String path) {
|
TileSheetEditorModel::TileSheetEditorModel(Context *ctx, ox::String path) {
|
||||||
m_ctx = ctx;
|
m_ctx = ctx;
|
||||||
m_path = std::move(path);
|
m_path = std::move(path);
|
||||||
oxRequireT(img, readObj<TileSheet>(ctx, m_path.c_str()));
|
oxRequireT(img, readObj<TileSheet>(ctx, m_path));
|
||||||
m_img = *img;
|
m_img = *img;
|
||||||
if (m_img.defaultPalette) {
|
if (m_img.defaultPalette) {
|
||||||
oxThrowError(readObj<Palette>(ctx, m_img.defaultPalette).moveTo(&m_pal));
|
oxThrowError(readObj<Palette>(ctx, m_img.defaultPalette).moveTo(&m_pal));
|
||||||
@ -709,7 +709,7 @@ ox::Error TileSheetEditorModel::markUpdatedCmdId(const studio::UndoCommand *cmd)
|
|||||||
m_updated = true;
|
m_updated = true;
|
||||||
const auto cmdId = cmd->commandId();
|
const auto cmdId = cmd->commandId();
|
||||||
if (static_cast<CommandId>(cmdId) == CommandId::PaletteChange) {
|
if (static_cast<CommandId>(cmdId) == CommandId::PaletteChange) {
|
||||||
oxReturnError(readObj<Palette>(m_ctx, m_img.defaultPalette.getPath().value).moveTo(&m_pal));
|
oxReturnError(readObj<Palette>(m_ctx, ox::StringView(m_img.defaultPalette.getPath().value)).moveTo(&m_pal));
|
||||||
}
|
}
|
||||||
auto tsCmd = dynamic_cast<const TileSheetCommand*>(cmd);
|
auto tsCmd = dynamic_cast<const TileSheetCommand*>(cmd);
|
||||||
auto idx = m_img.validateSubSheetIdx(tsCmd->subsheetIdx());
|
auto idx = m_img.validateSubSheetIdx(tsCmd->subsheetIdx());
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
TileSheetEditorView::TileSheetEditorView(Context *ctx, const ox::String &path): m_model(ctx, path), m_pixelsDrawer(&m_model) {
|
TileSheetEditorView::TileSheetEditorView(Context *ctx, ox::CRStringView path): m_model(ctx, path), m_pixelsDrawer(&m_model) {
|
||||||
// build shaders
|
// build shaders
|
||||||
oxThrowError(m_pixelsDrawer.buildShader());
|
oxThrowError(m_pixelsDrawer.buildShader());
|
||||||
oxThrowError(m_pixelGridDrawer.buildShader());
|
oxThrowError(m_pixelGridDrawer.buildShader());
|
||||||
|
@ -49,7 +49,7 @@ class TileSheetEditorView: public ox::SignalHandler {
|
|||||||
std::size_t m_palIdx = 0;
|
std::size_t m_palIdx = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TileSheetEditorView(Context *ctx, const ox::String &path);
|
TileSheetEditorView(Context *ctx, ox::CRStringView path);
|
||||||
|
|
||||||
~TileSheetEditorView() override = default;
|
~TileSheetEditorView() override = default;
|
||||||
|
|
||||||
|
@ -49,8 +49,8 @@ static const auto converters = [] {
|
|||||||
}();
|
}();
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static auto findConverter(const char *srcTypeName, int srcTypeVersion,
|
static auto findConverter(ox::CRStringView srcTypeName, int srcTypeVersion,
|
||||||
const char *dstTypeName, int dstTypeVersion) noexcept -> ox::Result<BaseConverter*> {
|
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept -> ox::Result<BaseConverter*> {
|
||||||
for (auto &c : converters) {
|
for (auto &c : converters) {
|
||||||
if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
|
if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
|
||||||
return c.get();
|
return c.get();
|
||||||
@ -60,8 +60,8 @@ static auto findConverter(const char *srcTypeName, int srcTypeVersion,
|
|||||||
};
|
};
|
||||||
|
|
||||||
static ox::Result<ox::UniquePtr<Wrap>> convert(const ox::Buffer &srcBuffer,
|
static ox::Result<ox::UniquePtr<Wrap>> convert(const ox::Buffer &srcBuffer,
|
||||||
const char *srcTypeName, int srcTypeVersion,
|
ox::CRStringView srcTypeName, int srcTypeVersion,
|
||||||
const char *dstTypeName, int dstTypeVersion) noexcept {
|
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept {
|
||||||
// look for direct converter
|
// look for direct converter
|
||||||
auto [c, err] = findConverter(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion);
|
auto [c, err] = findConverter(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
@ -82,9 +82,9 @@ static ox::Result<ox::UniquePtr<Wrap>> convert(const ox::Buffer &srcBuffer,
|
|||||||
return OxError(1, "Could not convert between types");
|
return OxError(1, "Could not convert between types");
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Wrap>> convert(const ox::Buffer &srcBuffer, const char *dstTypeName, int dstTypeVersion) noexcept {
|
ox::Result<ox::UniquePtr<Wrap>> convert(const ox::Buffer &srcBuffer, ox::CRStringView dstTypeName, int dstTypeVersion) noexcept {
|
||||||
oxRequire(hdr, ox::readClawHeader(srcBuffer));
|
oxRequire(hdr, ox::readClawHeader(srcBuffer));
|
||||||
return convert(srcBuffer, hdr.typeName.c_str(), hdr.typeVersion, dstTypeName, dstTypeVersion);
|
return convert(srcBuffer, hdr.typeName, hdr.typeVersion, dstTypeName, dstTypeVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -51,24 +51,24 @@ struct BaseConverter {
|
|||||||
virtual ~BaseConverter() noexcept = default;
|
virtual ~BaseConverter() noexcept = default;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual const char *srcTypeName() noexcept = 0;
|
virtual ox::StringView srcTypeName() noexcept = 0;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual int srcTypeVersion() noexcept = 0;
|
virtual int srcTypeVersion() noexcept = 0;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual bool srcMatches(const char *srcTypeName, int srcTypeVersion) const noexcept = 0;
|
virtual bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept = 0;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual bool dstMatches(const char *dstTypeName, int dstTypeVersion) const noexcept = 0;
|
virtual bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept = 0;
|
||||||
|
|
||||||
virtual ox::Result<ox::UniquePtr<Wrap>> convertPtrToPtr(Wrap *src) noexcept = 0;
|
virtual ox::Result<ox::UniquePtr<Wrap>> convertPtrToPtr(Wrap *src) noexcept = 0;
|
||||||
|
|
||||||
virtual ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(const ox::Buffer &srcBuff) noexcept = 0;
|
virtual ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(const ox::Buffer &srcBuff) noexcept = 0;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline bool matches(const char *srcTypeName, int srcTypeVersion,
|
inline bool matches(ox::CRStringView srcTypeName, int srcTypeVersion,
|
||||||
const char *dstTypeName, int dstTypeVersion) const noexcept {
|
ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept {
|
||||||
return srcMatches(srcTypeName, srcTypeVersion)
|
return srcMatches(srcTypeName, srcTypeVersion)
|
||||||
&& dstMatches(dstTypeName, dstTypeVersion);
|
&& dstMatches(dstTypeName, dstTypeVersion);
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ struct Converter: public BaseConverter {
|
|||||||
virtual ox::Error convert(SrcType*, DstType*) noexcept = 0;
|
virtual ox::Error convert(SrcType*, DstType*) noexcept = 0;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
const char *srcTypeName() noexcept final {
|
ox::StringView srcTypeName() noexcept final {
|
||||||
return ox::requireModelTypeName<SrcType>();
|
return ox::requireModelTypeName<SrcType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ struct Converter: public BaseConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool srcMatches(const char *srcTypeName, int srcTypeVersion) const noexcept final {
|
bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept final {
|
||||||
static constexpr auto SrcTypeName = ox::requireModelTypeName<SrcType>();
|
static constexpr auto SrcTypeName = ox::requireModelTypeName<SrcType>();
|
||||||
static constexpr auto SrcTypeVersion = ox::requireModelTypeVersion<SrcType>();
|
static constexpr auto SrcTypeVersion = ox::requireModelTypeVersion<SrcType>();
|
||||||
return ox_strcmp(srcTypeName, SrcTypeName) == 0
|
return ox_strcmp(srcTypeName, SrcTypeName) == 0
|
||||||
@ -99,7 +99,7 @@ struct Converter: public BaseConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool dstMatches(const char *dstTypeName, int dstTypeVersion) const noexcept final {
|
bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept final {
|
||||||
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
|
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
|
||||||
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
|
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
|
||||||
return ox_strcmp(dstTypeName, DstTypeName) == 0
|
return ox_strcmp(dstTypeName, DstTypeName) == 0
|
||||||
@ -122,7 +122,7 @@ struct Converter: public BaseConverter {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Wrap>> convert(const ox::Buffer &srcBuffer,
|
ox::Result<ox::UniquePtr<Wrap>> convert(const ox::Buffer &srcBuffer,
|
||||||
const char *dstTypeName, int dstTypeVersion) noexcept;
|
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept;
|
||||||
|
|
||||||
template<typename DstType>
|
template<typename DstType>
|
||||||
ox::Result<DstType> convert(const ox::Buffer &srcBuffer) noexcept {
|
ox::Result<DstType> convert(const ox::Buffer &srcBuffer) noexcept {
|
||||||
|
@ -10,52 +10,71 @@
|
|||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
ox::Error initConsole(Context *ctx) noexcept {
|
ox::Error initConsole(Context *ctx) noexcept {
|
||||||
constexpr auto TilesheetAddr = "/TileSheets/Charset.ng";
|
constexpr ox::FileAddress TilesheetAddr("/TileSheets/Charset.ng");
|
||||||
constexpr auto PaletteAddr = "/Palettes/Charset.npal";
|
constexpr ox::FileAddress PaletteAddr("/Palettes/Charset.npal");
|
||||||
setBgStatus(ctx, 0b0001);
|
setBgStatus(ctx, 0b0001);
|
||||||
setBgCbb(ctx, 0, 0);
|
setBgCbb(ctx, 0, 0);
|
||||||
return loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr);
|
return loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error loadSpriteTileSheet(Context*,
|
struct TileSheetData {
|
||||||
unsigned,
|
ox::Vector<uint32_t> pixels;
|
||||||
const ox::FileAddress&,
|
int width = 0;
|
||||||
const ox::FileAddress&) noexcept {
|
int height = 0;
|
||||||
return OxError(0);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
ox::Error loadBgTileSheet(Context *ctx,
|
ox::Result<TileSheetData> loadTileSheet(Context *ctx, const CompactTileSheet &tilesheet) noexcept {
|
||||||
unsigned cbb,
|
const unsigned bytesPerTile = tilesheet.bpp == 8 ? 64 : 32;
|
||||||
const ox::FileAddress &tilesheetPath,
|
const auto tiles = tilesheet.pixels.size() / bytesPerTile;
|
||||||
const ox::FileAddress &palettePath) noexcept {
|
|
||||||
oxRequire(tilesheet, readObj<CompactTileSheet>(ctx, tilesheetPath));
|
|
||||||
oxRequire(palette, readObj<Palette>(ctx, palettePath ? palettePath : tilesheet->defaultPalette));
|
|
||||||
const unsigned bytesPerTile = tilesheet->bpp == 8 ? 64 : 32;
|
|
||||||
const auto tiles = tilesheet->pixels.size() / bytesPerTile;
|
|
||||||
constexpr int width = 8;
|
constexpr int width = 8;
|
||||||
const int height = 8 * static_cast<int>(tiles);
|
const int height = 8 * static_cast<int>(tiles);
|
||||||
ox::Vector<uint32_t> pixels;
|
ox::Vector<uint32_t> pixels;
|
||||||
if (bytesPerTile == 64) { // 8 BPP
|
if (bytesPerTile == 64) { // 8 BPP
|
||||||
pixels.resize(tilesheet->pixels.size());
|
pixels.resize(tilesheet.pixels.size());
|
||||||
for (std::size_t i = 0; i < tilesheet->pixels.size(); ++i) {
|
for (std::size_t i = 0; i < tilesheet.pixels.size(); ++i) {
|
||||||
pixels[i] = tilesheet->pixels[i];
|
pixels[i] = tilesheet.pixels[i];
|
||||||
}
|
}
|
||||||
} else { // 4 BPP
|
} else { // 4 BPP
|
||||||
pixels.resize(tilesheet->pixels.size() * 2);
|
pixels.resize(tilesheet.pixels.size() * 2);
|
||||||
for (std::size_t i = 0; i < tilesheet->pixels.size(); ++i) {
|
for (std::size_t i = 0; i < tilesheet.pixels.size(); ++i) {
|
||||||
pixels[i * 2 + 0] = tilesheet->pixels[i] & 0xF;
|
pixels[i * 2 + 0] = tilesheet.pixels[i] & 0xF;
|
||||||
pixels[i * 2 + 1] = tilesheet->pixels[i] >> 4;
|
pixels[i * 2 + 1] = tilesheet.pixels[i] >> 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const auto rd = ctx->rendererData<void>();
|
const auto rd = ctx->rendererData<void>();
|
||||||
renderer::loadBgTexture(rd, cbb, pixels.data(), width, height);
|
renderer::loadSpriteTexture(rd, pixels.data(), width, height);
|
||||||
renderer::loadBgPalette(rd, *palette);
|
return TileSheetData{std::move(pixels), width, height};
|
||||||
return OxError(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void puts(Context *ctx, int column, int row, const char *str) noexcept {
|
ox::Error loadBgTileSheet(Context *ctx,
|
||||||
for (int i = 0; str[i]; ++i) {
|
unsigned cbb,
|
||||||
setTile(ctx, 0, column + i, row, static_cast<uint8_t>(charMap[static_cast<uint8_t>(str[i])]));
|
const ox::FileAddress &tilesheetAddr,
|
||||||
|
const ox::FileAddress &paletteAddr) noexcept {
|
||||||
|
oxRequire(tilesheet, readObj<CompactTileSheet>(ctx, tilesheetAddr));
|
||||||
|
oxRequire(palette, readObj<Palette>(ctx, paletteAddr ? paletteAddr : tilesheet->defaultPalette));
|
||||||
|
oxRequire(tsd, loadTileSheet(ctx, *tilesheet));
|
||||||
|
const auto rd = ctx->rendererData<void>();
|
||||||
|
renderer::loadBgTexture(rd, cbb, tsd.pixels.data(), tsd.width, tsd.height);
|
||||||
|
renderer::loadBgPalette(rd, *palette);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ox::Error loadSpriteTileSheet(Context *ctx,
|
||||||
|
const ox::FileAddress &tilesheetAddr,
|
||||||
|
const ox::FileAddress &paletteAddr) noexcept {
|
||||||
|
oxRequire(tilesheet, readObj<CompactTileSheet>(ctx, tilesheetAddr));
|
||||||
|
oxRequire(palette, readObj<Palette>(ctx, paletteAddr ? paletteAddr : tilesheet->defaultPalette));
|
||||||
|
oxRequire(tsd, loadTileSheet(ctx, *tilesheet));
|
||||||
|
const auto rd = ctx->rendererData<void>();
|
||||||
|
renderer::loadSpriteTexture(rd, tsd.pixels.data(), tsd.width, tsd.height);
|
||||||
|
renderer::loadSpritePalette(rd, *palette);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void puts(Context *ctx, int column, int row, ox::CRStringView str) noexcept {
|
||||||
|
const auto col = static_cast<unsigned>(column);
|
||||||
|
for (auto i = 0u; i < str.bytes(); ++i) {
|
||||||
|
setTile(ctx, 0, static_cast<int>(col + i), row, static_cast<uint8_t>(charMap[static_cast<uint8_t>(str[i])]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,10 @@ void shutdown(Context *ctx, void *rendererData) noexcept;
|
|||||||
|
|
||||||
void loadBgPalette(void *rendererData, const Palette &pal) noexcept;
|
void loadBgPalette(void *rendererData, const Palette &pal) noexcept;
|
||||||
|
|
||||||
void loadBgTexture(void *rendererData, unsigned cbb, void *pixels, int w, int h) noexcept;
|
void loadBgTexture(void *rendererData, unsigned cbb, const void *pixels, int w, int h) noexcept;
|
||||||
|
|
||||||
|
void loadSpritePalette(void *rendererData, const Palette &pal) noexcept;
|
||||||
|
|
||||||
|
void loadSpriteTexture(void *rendererData, const void *pixels, int w, int h) noexcept;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,55 +22,96 @@ namespace renderer {
|
|||||||
constexpr uint64_t TileRows = 128;
|
constexpr uint64_t TileRows = 128;
|
||||||
constexpr uint64_t TileColumns = 128;
|
constexpr uint64_t TileColumns = 128;
|
||||||
constexpr uint64_t TileCount = TileRows * TileColumns;
|
constexpr uint64_t TileCount = TileRows * TileColumns;
|
||||||
|
constexpr uint64_t SpriteCount = 128;
|
||||||
constexpr uint64_t BgVertexVboRows = 4;
|
constexpr uint64_t BgVertexVboRows = 4;
|
||||||
constexpr uint64_t BgVertexVboRowLength = 4;
|
constexpr uint64_t BgVertexVboRowLength = 4;
|
||||||
constexpr uint64_t BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength;
|
constexpr uint64_t BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength;
|
||||||
constexpr uint64_t BgVertexEboLength = 6;
|
constexpr uint64_t BgVertexEboLength = 6;
|
||||||
|
constexpr uint64_t SpriteVertexVboRows = 4;
|
||||||
|
constexpr uint64_t SpriteVertexVboRowLength = 5;
|
||||||
|
constexpr uint64_t SpriteVertexVboLength = SpriteVertexVboRows * SpriteVertexVboRowLength;
|
||||||
|
constexpr uint64_t SpriteVertexEboLength = 6;
|
||||||
|
|
||||||
struct CBB: public glutils::BufferSet {
|
struct CBB: public glutils::BufferSet {
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
|
constexpr CBB() noexcept {
|
||||||
CBB() noexcept {
|
|
||||||
vertices.resize(TileCount * BgVertexVboLength);
|
vertices.resize(TileCount * BgVertexVboLength);
|
||||||
elements.resize(TileCount * BgVertexEboLength);
|
elements.resize(TileCount * BgVertexEboLength);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SpriteBlockset: public glutils::BufferSet {
|
||||||
|
bool updated = false;
|
||||||
|
constexpr SpriteBlockset() noexcept {
|
||||||
|
vertices.resize(SpriteCount * SpriteVertexVboLength);
|
||||||
|
elements.resize(SpriteCount * SpriteVertexEboLength);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct Background {
|
struct Background {
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
unsigned cbbIdx = 0;
|
unsigned cbbIdx = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Sprite {
|
||||||
|
bool enabled = false;
|
||||||
|
};
|
||||||
|
|
||||||
struct GlImplData {
|
struct GlImplData {
|
||||||
glutils::GLProgram bgShader;
|
glutils::GLProgram bgShader;
|
||||||
|
glutils::GLProgram spriteShader;
|
||||||
int64_t prevFpsCheckTime = 0;
|
int64_t prevFpsCheckTime = 0;
|
||||||
uint64_t draws = 0;
|
uint64_t draws = 0;
|
||||||
ox::Array<CBB, 4> cbbs;
|
ox::Array<CBB, 4> cbbs;
|
||||||
|
SpriteBlockset spriteBlocks;
|
||||||
|
ox::Array<Sprite, 128> spriteStates;
|
||||||
ox::Array<Background, 4> backgrounds;
|
ox::Array<Background, 4> backgrounds;
|
||||||
static constexpr std::size_t ColorCnt = 256;
|
|
||||||
ox::Array<GLfloat, ColorCnt * 3> palette{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr const GLchar *bgvshad = R"(
|
constexpr ox::StringView bgvshadTmpl = R"(
|
||||||
{}
|
{}
|
||||||
in vec2 vTexCoord;
|
in vec2 vTexCoord;
|
||||||
in vec2 vPosition;
|
in vec2 vPosition;
|
||||||
out vec2 fTexCoord;
|
out vec2 fTexCoord;
|
||||||
uniform float vTileHeight;
|
uniform float vTileHeight;
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = vec4(vPosition, 0.0, 1.0);
|
gl_Position = vec4(vPosition, 0.0, 1.0);
|
||||||
fTexCoord = vTexCoord * vec2(1, vTileHeight);
|
fTexCoord = vTexCoord * vec2(1, vTileHeight);
|
||||||
})";
|
})";
|
||||||
|
|
||||||
constexpr const GLchar *bgfshad = R"(
|
constexpr ox::StringView bgfshadTmpl = R"(
|
||||||
{}
|
{}
|
||||||
out vec4 outColor;
|
out vec4 outColor;
|
||||||
in vec2 fTexCoord;
|
in vec2 fTexCoord;
|
||||||
uniform sampler2D image;
|
uniform sampler2D image;
|
||||||
uniform vec3 fPalette[256];
|
uniform vec4 fPalette[256];
|
||||||
void main() {
|
void main() {
|
||||||
int idx = int(texture(image, fTexCoord).rgb.r * 256);
|
int idx = int(texture(image, fTexCoord).rgb.r * 256);
|
||||||
outColor = vec4(fPalette[idx], 1.0);
|
outColor = fPalette[idx];
|
||||||
|
//outColor = vec4(0.0, 0.7, 1.0, 1.0);
|
||||||
|
})";
|
||||||
|
|
||||||
|
constexpr ox::StringView spritevshadTmpl = R"(
|
||||||
|
{}
|
||||||
|
in float vEnabled;
|
||||||
|
in vec2 vTexCoord;
|
||||||
|
in vec2 vPosition;
|
||||||
|
out vec2 fTexCoord;
|
||||||
|
uniform float vTileHeight;
|
||||||
|
void main() {
|
||||||
|
gl_Position = vec4(vPosition, 0.0, 1.0);
|
||||||
|
fTexCoord = vTexCoord * vec2(1, vTileHeight) * vec2(vEnabled, vEnabled);
|
||||||
|
})";
|
||||||
|
|
||||||
|
constexpr ox::StringView spritefshadTmpl = R"(
|
||||||
|
{}
|
||||||
|
out vec4 outColor;
|
||||||
|
in vec2 fTexCoord;
|
||||||
|
uniform sampler2D image;
|
||||||
|
uniform vec4 fPalette[256];
|
||||||
|
void main() {
|
||||||
|
int idx = int(texture(image, fTexCoord).rgb.r * 256);
|
||||||
|
outColor = fPalette[idx];
|
||||||
//outColor = vec4(0.0, 0.7, 1.0, 1.0);
|
//outColor = vec4(0.0, 0.7, 1.0, 1.0);
|
||||||
})";
|
})";
|
||||||
|
|
||||||
@ -79,8 +120,46 @@ static constexpr auto bgVertexRow(unsigned x, unsigned y) noexcept {
|
|||||||
return y * TileRows + x;
|
return y * TileRows + x;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void setSpriteBufferObject(Context *ctx,
|
||||||
setTileBufferObject(Context *ctx, unsigned vi, float x, float y, int textureRow, float *vbo, GLuint *ebo) noexcept {
|
unsigned vi,
|
||||||
|
float enabled,
|
||||||
|
float x, float y,
|
||||||
|
unsigned textureRow,
|
||||||
|
unsigned flipX,
|
||||||
|
float *vbo,
|
||||||
|
GLuint *ebo) noexcept {
|
||||||
|
// don't worry, this memcpy gets optimized to something much more ideal
|
||||||
|
const auto [sw, sh] = getScreenSize(ctx);
|
||||||
|
constexpr float ymod = 0.1f;
|
||||||
|
const auto xmod = ymod * static_cast<float>(sh) / static_cast<float>(sw);
|
||||||
|
x *= xmod;
|
||||||
|
y *= -ymod;
|
||||||
|
x -= 1.f;
|
||||||
|
y += 1.f - ymod;
|
||||||
|
const auto textureRowf = static_cast<float>(textureRow);
|
||||||
|
const float L = flipX ? 1 : 0;
|
||||||
|
const float R = flipX ? 0 : 1;
|
||||||
|
const ox::Array<float, SpriteVertexVboLength> vertices {
|
||||||
|
enabled, x, y, L, textureRowf + 1, // bottom left
|
||||||
|
enabled, x + xmod, y, R, textureRowf + 1, // bottom right
|
||||||
|
enabled, x + xmod, y + ymod, R, textureRowf + 0, // top right
|
||||||
|
enabled, x, y + ymod, L, textureRowf + 0, // top left
|
||||||
|
};
|
||||||
|
memcpy(vbo, vertices.data(), sizeof(vertices));
|
||||||
|
const ox::Array<GLuint, SpriteVertexEboLength> elms {
|
||||||
|
vi + 0, vi + 1, vi + 2,
|
||||||
|
vi + 2, vi + 3, vi + 0,
|
||||||
|
};
|
||||||
|
memcpy(ebo, elms.data(), sizeof(elms));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setTileBufferObject(Context *ctx,
|
||||||
|
unsigned vi,
|
||||||
|
float x,
|
||||||
|
float y,
|
||||||
|
unsigned textureRow,
|
||||||
|
float *vbo,
|
||||||
|
GLuint *ebo) noexcept {
|
||||||
// don't worry, this memcpy gets optimized to something much more ideal
|
// don't worry, this memcpy gets optimized to something much more ideal
|
||||||
const auto [sw, sh] = getScreenSize(ctx);
|
const auto [sw, sh] = getScreenSize(ctx);
|
||||||
constexpr float ymod = 2.0f / 20.0f;
|
constexpr float ymod = 2.0f / 20.0f;
|
||||||
@ -89,11 +168,12 @@ setTileBufferObject(Context *ctx, unsigned vi, float x, float y, int textureRow,
|
|||||||
y *= -ymod;
|
y *= -ymod;
|
||||||
x -= 1.0f;
|
x -= 1.0f;
|
||||||
y += 1.0f - ymod;
|
y += 1.0f - ymod;
|
||||||
|
const auto textureRowf = static_cast<float>(textureRow);
|
||||||
const ox::Array<float, BgVertexVboLength> vertices {
|
const ox::Array<float, BgVertexVboLength> vertices {
|
||||||
x, y, 0, static_cast<float>(textureRow + 1), // bottom left
|
x, y, 0, textureRowf + 1, // bottom left
|
||||||
x + xmod, y, 1, static_cast<float>(textureRow + 1), // bottom right
|
x + xmod, y, 1, textureRowf + 1, // bottom right
|
||||||
x + xmod, y + ymod, 1, static_cast<float>(textureRow + 0), // top right
|
x + xmod, y + ymod, 1, textureRowf + 0, // top right
|
||||||
x, y + ymod, 0, static_cast<float>(textureRow + 0), // top left
|
x, y + ymod, 0, textureRowf + 0, // top left
|
||||||
};
|
};
|
||||||
memcpy(vbo, vertices.data(), sizeof(vertices));
|
memcpy(vbo, vertices.data(), sizeof(vertices));
|
||||||
const ox::Array<GLuint, BgVertexEboLength> elms {
|
const ox::Array<GLuint, BgVertexEboLength> elms {
|
||||||
@ -103,6 +183,14 @@ setTileBufferObject(Context *ctx, unsigned vi, float x, float y, int textureRow,
|
|||||||
memcpy(ebo, elms.data(), sizeof(elms));
|
memcpy(ebo, elms.data(), sizeof(elms));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void initSpriteBufferObjects(Context *ctx, glutils::BufferSet *bs) noexcept {
|
||||||
|
for (auto i = 0u; i < SpriteCount; ++i) {
|
||||||
|
auto vbo = &bs->vertices[i * static_cast<std::size_t>(SpriteVertexVboLength)];
|
||||||
|
auto ebo = &bs->elements[i * static_cast<std::size_t>(SpriteVertexEboLength)];
|
||||||
|
setSpriteBufferObject(ctx, i * SpriteVertexVboRows, 0, 0, 0, 0, false, vbo, ebo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void initBackgroundBufferObjects(Context *ctx, glutils::BufferSet *bg) noexcept {
|
static void initBackgroundBufferObjects(Context *ctx, glutils::BufferSet *bg) noexcept {
|
||||||
for (auto x = 0u; x < TileColumns; ++x) {
|
for (auto x = 0u; x < TileColumns; ++x) {
|
||||||
for (auto y = 0u; y < TileRows; ++y) {
|
for (auto y = 0u; y < TileRows; ++y) {
|
||||||
@ -114,6 +202,30 @@ static void initBackgroundBufferObjects(Context *ctx, glutils::BufferSet *bg) no
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void initSpritesBufferset(Context *ctx, GLuint shader, glutils::BufferSet *bs) noexcept {
|
||||||
|
// vao
|
||||||
|
bs->vao = glutils::generateVertexArrayObject();
|
||||||
|
glBindVertexArray(bs->vao);
|
||||||
|
// vbo & ebo
|
||||||
|
bs->vbo = glutils::generateBuffer();
|
||||||
|
bs->ebo = glutils::generateBuffer();
|
||||||
|
initSpriteBufferObjects(ctx, bs);
|
||||||
|
glutils::sendVbo(*bs);
|
||||||
|
glutils::sendEbo(*bs);
|
||||||
|
// vbo layout
|
||||||
|
auto enabledAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vEnabled"));
|
||||||
|
glEnableVertexAttribArray(enabledAttr);
|
||||||
|
glVertexAttribPointer(enabledAttr, 1, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float), nullptr);
|
||||||
|
auto posAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vPosition"));
|
||||||
|
glEnableVertexAttribArray(posAttr);
|
||||||
|
glVertexAttribPointer(posAttr, 2, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float),
|
||||||
|
reinterpret_cast<void*>(1 * sizeof(float)));
|
||||||
|
auto texCoordAttr = static_cast<GLuint>(glGetAttribLocation(shader, "vTexCoord"));
|
||||||
|
glEnableVertexAttribArray(texCoordAttr);
|
||||||
|
glVertexAttribPointer(texCoordAttr, 2, GL_FLOAT, GL_FALSE, SpriteVertexVboRowLength * sizeof(float),
|
||||||
|
reinterpret_cast<void*>(3 * sizeof(float)));
|
||||||
|
}
|
||||||
|
|
||||||
static void initBackgroundBufferset(Context *ctx, GLuint shader, glutils::BufferSet *bg) noexcept {
|
static void initBackgroundBufferset(Context *ctx, GLuint shader, glutils::BufferSet *bg) noexcept {
|
||||||
// vao
|
// vao
|
||||||
bg->vao = glutils::generateVertexArrayObject();
|
bg->vao = glutils::generateVertexArrayObject();
|
||||||
@ -134,7 +246,7 @@ static void initBackgroundBufferset(Context *ctx, GLuint shader, glutils::Buffer
|
|||||||
reinterpret_cast<void*>(2 * sizeof(float)));
|
reinterpret_cast<void*>(2 * sizeof(float)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static glutils::GLTexture loadTexture(GLsizei w, GLsizei h, void *pixels) noexcept {
|
static glutils::GLTexture loadTexture(GLsizei w, GLsizei h, const void *pixels) noexcept {
|
||||||
GLuint texId = 0;
|
GLuint texId = 0;
|
||||||
glGenTextures(1, &texId);
|
glGenTextures(1, &texId);
|
||||||
glutils::GLTexture tex(texId);
|
glutils::GLTexture tex(texId);
|
||||||
@ -179,10 +291,9 @@ static void drawBackground(CBB *cbb) noexcept {
|
|||||||
static void drawBackgrounds(GlImplData *id) noexcept {
|
static void drawBackgrounds(GlImplData *id) noexcept {
|
||||||
// load background shader and its uniforms
|
// load background shader and its uniforms
|
||||||
glUseProgram(id->bgShader);
|
glUseProgram(id->bgShader);
|
||||||
const auto uniformPalette = static_cast<GLint>(glGetUniformLocation(id->bgShader, "fPalette"));
|
|
||||||
const auto uniformTileHeight = static_cast<GLint>(glGetUniformLocation(id->bgShader, "vTileHeight"));
|
const auto uniformTileHeight = static_cast<GLint>(glGetUniformLocation(id->bgShader, "vTileHeight"));
|
||||||
glUniform3fv(uniformPalette, GlImplData::ColorCnt, id->palette.data());
|
//glUniform3fv(uniformPalette, GlImplData::ColorCnt, id->palette.data());
|
||||||
for (auto &bg : id->backgrounds) {
|
for (const auto &bg : id->backgrounds) {
|
||||||
if (bg.enabled) {
|
if (bg.enabled) {
|
||||||
auto &cbb = id->cbbs[bg.cbbIdx];
|
auto &cbb = id->cbbs[bg.cbbIdx];
|
||||||
const auto tileRows = cbb.tex.height / TileHeight;
|
const auto tileRows = cbb.tex.height / TileHeight;
|
||||||
@ -192,16 +303,39 @@ static void drawBackgrounds(GlImplData *id) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void drawSprites(GlImplData *id) noexcept {
|
||||||
|
glUseProgram(id->spriteShader);
|
||||||
|
auto &sb = id->spriteBlocks;
|
||||||
|
const auto uniformTileHeight = static_cast<GLint>(glGetUniformLocation(id->spriteShader, "vTileHeight"));
|
||||||
|
// update vbo
|
||||||
|
glBindVertexArray(sb.vao);
|
||||||
|
if (sb.updated) {
|
||||||
|
sb.updated = false;
|
||||||
|
glutils::sendVbo(sb);
|
||||||
|
}
|
||||||
|
// set vTileHeight uniform
|
||||||
|
const auto tileRows = sb.tex.height / TileHeight;
|
||||||
|
glUniform1f(uniformTileHeight, 1.0f / static_cast<float>(tileRows));
|
||||||
|
// draw
|
||||||
|
glBindTexture(GL_TEXTURE_2D, sb.tex);
|
||||||
|
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(sb.elements.size()), GL_UNSIGNED_INT, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
ox::Error init(Context *ctx, void **rendererData) noexcept {
|
ox::Error init(Context *ctx, void **rendererData) noexcept {
|
||||||
const auto vshad = ox::sfmt(bgvshad, glutils::GlslVersion);
|
glEnable(GL_BLEND);
|
||||||
const auto fshad = ox::sfmt(bgfshad, glutils::GlslVersion);
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
oxRequireM(bgShader, glutils::buildShaderProgram(vshad.c_str(), fshad.c_str()));
|
const auto bgVshad = ox::sfmt(bgvshadTmpl, glutils::GlslVersion);
|
||||||
const auto id = new GlImplData;
|
const auto bgFshad = ox::sfmt(bgfshadTmpl, glutils::GlslVersion);
|
||||||
|
const auto spriteVshad = ox::sfmt(spritevshadTmpl, glutils::GlslVersion);
|
||||||
|
const auto spriteFshad = ox::sfmt(spritefshadTmpl, glutils::GlslVersion);
|
||||||
|
const auto id = ox::make<GlImplData>();
|
||||||
*rendererData = id;
|
*rendererData = id;
|
||||||
id->bgShader = std::move(bgShader);
|
oxReturnError(glutils::buildShaderProgram(bgVshad.c_str(), bgFshad.c_str()).moveTo(&id->bgShader));
|
||||||
|
oxReturnError(glutils::buildShaderProgram(spriteVshad.c_str(), spriteFshad.c_str()).moveTo(&id->spriteShader));
|
||||||
for (auto &bg : id->cbbs) {
|
for (auto &bg : id->cbbs) {
|
||||||
initBackgroundBufferset(ctx, id->bgShader, &bg);
|
initBackgroundBufferset(ctx, id->bgShader, &bg);
|
||||||
}
|
}
|
||||||
|
initSpritesBufferset(ctx, id->spriteShader, &id->spriteBlocks);
|
||||||
ImGui_ImplOpenGL3_Init(glutils::GlslVersion);
|
ImGui_ImplOpenGL3_Init(glutils::GlslVersion);
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
@ -211,20 +345,43 @@ void shutdown(Context*, void *rendererData) noexcept {
|
|||||||
ox::safeDelete(id);
|
ox::safeDelete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadBgPalette(void *rendererData, const Palette &pal) noexcept {
|
static void loadPalette(GLuint shaderPgrm, const Palette &pal, bool firstIsTransparent = false) noexcept {
|
||||||
const auto id = static_cast<GlImplData*>(rendererData);
|
static constexpr std::size_t ColorCnt = 256;
|
||||||
|
ox::Array<GLfloat, ColorCnt * 4> palette{};
|
||||||
for (auto i = 0u; const auto c : pal.colors) {
|
for (auto i = 0u; const auto c : pal.colors) {
|
||||||
id->palette[i++] = redf(c);
|
palette[i++] = redf(c);
|
||||||
id->palette[i++] = greenf(c);
|
palette[i++] = greenf(c);
|
||||||
id->palette[i++] = bluef(c);
|
palette[i++] = bluef(c);
|
||||||
|
palette[i++] = 255;
|
||||||
}
|
}
|
||||||
|
if (firstIsTransparent) {
|
||||||
|
palette[3] = 0;
|
||||||
|
}
|
||||||
|
glUseProgram(shaderPgrm);
|
||||||
|
const auto uniformPalette = static_cast<GLint>(glGetUniformLocation(shaderPgrm, "fPalette"));
|
||||||
|
glUniform4fv(uniformPalette, ColorCnt, palette.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadBgTexture(void *rendererData, unsigned cbbIdx, void *pixels, int w, int h) noexcept {
|
void loadBgPalette(void *rendererData, const Palette &pal) noexcept {
|
||||||
|
const auto id = static_cast<GlImplData*>(rendererData);
|
||||||
|
loadPalette(id->bgShader, pal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadSpritePalette(void *rendererData, const Palette &pal) noexcept {
|
||||||
|
const auto id = static_cast<GlImplData*>(rendererData);
|
||||||
|
loadPalette(id->spriteShader, pal, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadBgTexture(void *rendererData, unsigned cbbIdx, const void *pixels, int w, int h) noexcept {
|
||||||
oxTracef("nostalgia::core::gfx::gl", "loadBgTexture: { cbbIdx: {}, w: {}, h: {} }", cbbIdx, w, h);
|
oxTracef("nostalgia::core::gfx::gl", "loadBgTexture: { cbbIdx: {}, w: {}, h: {} }", cbbIdx, w, h);
|
||||||
const auto id = static_cast<GlImplData*>(rendererData);
|
const auto id = static_cast<GlImplData*>(rendererData);
|
||||||
auto &tex = id->cbbs[cbbIdx].tex;
|
id->cbbs[cbbIdx].tex = loadTexture(w, h, pixels);
|
||||||
tex = loadTexture(w, h, pixels);
|
}
|
||||||
|
|
||||||
|
void loadSpriteTexture(void *rendererData, const void *pixels, int w, int h) noexcept {
|
||||||
|
oxTracef("nostalgia::core::gfx::gl", "loadSpriteTexture: { w: {}, h: {} }", w, h);
|
||||||
|
const auto id = static_cast<GlImplData*>(rendererData);
|
||||||
|
id->spriteBlocks.tex = loadTexture(w, h, pixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -275,6 +432,7 @@ void draw(Context *ctx) noexcept {
|
|||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
// render
|
// render
|
||||||
renderer::drawBackgrounds(id);
|
renderer::drawBackgrounds(id);
|
||||||
|
renderer::drawSprites(id);
|
||||||
for (const auto cd : ctx->drawers) {
|
for (const auto cd : ctx->drawers) {
|
||||||
cd->draw(ctx);
|
cd->draw(ctx);
|
||||||
}
|
}
|
||||||
@ -291,17 +449,31 @@ void clearTileLayer(Context *ctx, unsigned bgIdx) noexcept {
|
|||||||
bg.updated = true;
|
bg.updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hideSprite(Context*, unsigned) noexcept {
|
void hideSprite(Context *ctx, unsigned idx) noexcept {
|
||||||
|
auto &id = *ctx->rendererData<renderer::GlImplData>();
|
||||||
|
auto vbo = &id.spriteBlocks.vertices[idx * renderer::SpriteVertexVboLength];
|
||||||
|
auto ebo = &id.spriteBlocks.elements[idx * renderer::SpriteVertexEboLength];
|
||||||
|
renderer::setSpriteBufferObject(ctx, idx * renderer::SpriteVertexVboRows, 0,
|
||||||
|
0, 0, 0, false, vbo, ebo);
|
||||||
|
id.spriteBlocks.updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSprite(Context*,
|
void setSprite(Context *ctx,
|
||||||
unsigned,
|
unsigned idx,
|
||||||
unsigned,
|
int x,
|
||||||
unsigned,
|
int y,
|
||||||
unsigned,
|
unsigned tileIdx,
|
||||||
unsigned,
|
[[maybe_unused]] unsigned spriteShape,
|
||||||
unsigned,
|
[[maybe_unused]] unsigned spriteSize,
|
||||||
unsigned) noexcept {
|
unsigned flipX) noexcept {
|
||||||
|
const auto uX = static_cast<unsigned>(x) % 255;
|
||||||
|
const auto uY = static_cast<unsigned>(y) % 127;
|
||||||
|
auto &id = *ctx->rendererData<renderer::GlImplData>();
|
||||||
|
auto vbo = &id.spriteBlocks.vertices[idx * renderer::SpriteVertexVboLength];
|
||||||
|
auto ebo = &id.spriteBlocks.elements[idx * renderer::SpriteVertexEboLength];
|
||||||
|
renderer::setSpriteBufferObject(ctx, idx * renderer::SpriteVertexVboRows, 1,
|
||||||
|
static_cast<float>(uX) / 8, static_cast<float>(uY) / 8, tileIdx, flipX, vbo, ebo);
|
||||||
|
id.spriteBlocks.updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setTile(Context *ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept {
|
void setTile(Context *ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept {
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
ox::Result<char*> loadRom(const char *path) noexcept {
|
ox::Result<char*> loadRom(ox::CRStringView path) noexcept {
|
||||||
std::ifstream file(path, std::ios::binary | std::ios::ate);
|
std::ifstream file(std::string(toStdStringView(path)), std::ios::binary | std::ios::ate);
|
||||||
if (!file.good()) {
|
if (!file.good()) {
|
||||||
oxErrorf("Could not find ROM file: {}", path);
|
oxErrorf("Could not find ROM file: {}", path);
|
||||||
return OxError(1, "Could not find ROM file");
|
return OxError(1, "Could not find ROM file");
|
||||||
|
@ -47,7 +47,7 @@ template struct GLObject<deleteProgram>;
|
|||||||
template struct GLObject<deleteShader>;
|
template struct GLObject<deleteShader>;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static ox::Result<GLShader> buildShader(GLuint shaderType, const GLchar *src, const char *shaderName) noexcept {
|
static ox::Result<GLShader> buildShader(GLuint shaderType, const GLchar *src, ox::CRStringView shaderName) noexcept {
|
||||||
GLShader shader(glCreateShader(shaderType));
|
GLShader shader(glCreateShader(shaderType));
|
||||||
glShaderSource(shader, 1, &src, nullptr);
|
glShaderSource(shader, 1, &src, nullptr);
|
||||||
glCompileShader(shader);
|
glCompileShader(shader);
|
||||||
|
@ -12,14 +12,14 @@ static int spriteY = 64;
|
|||||||
static int updateHandler(core::Context *ctx) noexcept {
|
static int updateHandler(core::Context *ctx) noexcept {
|
||||||
int xmod = 0;
|
int xmod = 0;
|
||||||
int ymod = 0;
|
int ymod = 0;
|
||||||
if (core::buttonDown(ctx, core::GamePad_Right)) {
|
if (core::buttonDown(ctx, core::Alpha_D) || core::buttonDown(ctx, core::GamePad_Right)) {
|
||||||
xmod = 2;
|
xmod = 2;
|
||||||
} else if (core::buttonDown(ctx, core::GamePad_Left)) {
|
} else if (core::buttonDown(ctx, core::Alpha_A) || core::buttonDown(ctx, core::GamePad_Left)) {
|
||||||
xmod = -2;
|
xmod = -2;
|
||||||
}
|
}
|
||||||
if (core::buttonDown(ctx, core::GamePad_Down)) {
|
if (core::buttonDown(ctx, core::Alpha_S) || core::buttonDown(ctx, core::GamePad_Down)) {
|
||||||
ymod = 2;
|
ymod = 2;
|
||||||
} else if (core::buttonDown(ctx, core::GamePad_Up)) {
|
} else if (core::buttonDown(ctx, core::Alpha_W) || core::buttonDown(ctx, core::GamePad_Up)) {
|
||||||
ymod = -2;
|
ymod = -2;
|
||||||
}
|
}
|
||||||
if (!xmod && !ymod) {
|
if (!xmod && !ymod) {
|
||||||
@ -27,10 +27,10 @@ static int updateHandler(core::Context *ctx) noexcept {
|
|||||||
}
|
}
|
||||||
spriteX += xmod;
|
spriteX += xmod;
|
||||||
spriteY += ymod;
|
spriteY += ymod;
|
||||||
constexpr auto s = "nostalgia";
|
constexpr ox::StringView s = "nostalgia";
|
||||||
for (unsigned i = 0; s[i]; ++i) {
|
for (unsigned i = 0; s[i]; ++i) {
|
||||||
const auto c = static_cast<unsigned>(s[i] - ('a' - 1));
|
const auto c = static_cast<unsigned>(s[i] - ('a' - 1));
|
||||||
core::setSprite(ctx, i, static_cast<unsigned>(spriteX) + 8 * (i + 1), static_cast<unsigned>(spriteY), c);
|
core::setSprite(ctx, i, spriteX + 8 * (static_cast<int>(i) + 1), spriteY, c);
|
||||||
}
|
}
|
||||||
return 16;
|
return 16;
|
||||||
}
|
}
|
||||||
@ -42,15 +42,15 @@ static void keyEventHandler(core::Context *ctx, core::Key key, bool down) noexce
|
|||||||
}
|
}
|
||||||
|
|
||||||
ox::Error run(ox::UniquePtr<ox::FileSystem> fs) noexcept {
|
ox::Error run(ox::UniquePtr<ox::FileSystem> fs) noexcept {
|
||||||
|
oxTraceInitHook();
|
||||||
oxRequireM(ctx, core::init(std::move(fs)));
|
oxRequireM(ctx, core::init(std::move(fs)));
|
||||||
constexpr auto TileSheetAddr = "/TileSheets/Charset.ng";
|
constexpr ox::FileAddress TileSheetAddr("/TileSheets/Charset.ng");
|
||||||
constexpr auto PaletteAddr = "/Palettes/Charset.npal";
|
constexpr ox::FileAddress PaletteAddr("/Palettes/Charset.npal");
|
||||||
oxRequire(tsStat, ctx->rom->stat(PaletteAddr));
|
oxRequire(tsStat, ctx->rom->stat(PaletteAddr));
|
||||||
oxReturnError(core::loadSpriteTileSheet(ctx.get(), 0, TileSheetAddr, PaletteAddr));
|
oxReturnError(core::loadSpriteTileSheet(ctx.get(), TileSheetAddr, PaletteAddr));
|
||||||
oxReturnError(core::initConsole(ctx.get()));
|
oxReturnError(core::initConsole(ctx.get()));
|
||||||
core::puts(ctx.get(), 10, 9, "DOPENESS!!!");
|
core::puts(ctx.get(), 10, 9, "DOPENESS!!!");
|
||||||
core::setUpdateHandler(ctx.get(), updateHandler);
|
core::setUpdateHandler(ctx.get(), updateHandler);
|
||||||
core::setKeyEventHandler(ctx.get(), keyEventHandler);
|
core::setKeyEventHandler(ctx.get(), keyEventHandler);
|
||||||
return core::run(ctx.get());
|
return core::run(ctx.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,13 @@ install(
|
|||||||
${NOSTALGIA_DIST_RESOURCES}
|
${NOSTALGIA_DIST_RESOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
ns_logo128.png
|
||||||
|
DESTINATION
|
||||||
|
${NOSTALGIA_DIST_RESOURCES}/icons
|
||||||
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
TARGETS
|
TARGETS
|
||||||
nostalgia-studio
|
nostalgia-studio
|
||||||
|
@ -38,7 +38,7 @@ constexpr auto ConfigDir = [] {
|
|||||||
}();
|
}();
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<T> readConfig(core::Context *ctx, const char *name) noexcept {
|
ox::Result<T> readConfig(core::Context *ctx, ox::CRStringView name) noexcept {
|
||||||
oxAssert(ox_strcmp(name, ""), "Config type has no TypeName");
|
oxAssert(ox_strcmp(name, ""), "Config type has no TypeName");
|
||||||
const auto homeDir = std::getenv(ox::defines::OS == ox::OS::Windows ? "USERPROFILE" : "HOME");
|
const auto homeDir = std::getenv(ox::defines::OS == ox::OS::Windows ? "USERPROFILE" : "HOME");
|
||||||
const auto configPath = ox::sfmt(ConfigDir, homeDir, ctx->appName).toStdString();
|
const auto configPath = ox::sfmt(ConfigDir, homeDir, ctx->appName).toStdString();
|
||||||
@ -70,16 +70,16 @@ template<typename T>
|
|||||||
ox::Error writeConfig(core::Context *ctx, const auto &name, T *data) noexcept {
|
ox::Error writeConfig(core::Context *ctx, const auto &name, T *data) noexcept {
|
||||||
oxAssert(ox_strcmp(name, ""), "Config type has no TypeName");
|
oxAssert(ox_strcmp(name, ""), "Config type has no TypeName");
|
||||||
const auto homeDir = std::getenv(ox::defines::OS == ox::OS::Windows ? "USERPROFILE" : "HOME");
|
const auto homeDir = std::getenv(ox::defines::OS == ox::OS::Windows ? "USERPROFILE" : "HOME");
|
||||||
const auto configPath = ox::sfmt(ConfigDir, homeDir, ctx->appName).toStdString();
|
const auto configPath = ox::sfmt(ConfigDir, homeDir, ctx->appName);
|
||||||
const auto path = ox::sfmt("{}.json", name).toStdString();
|
const auto path = ox::sfmt("{}.json", name);
|
||||||
ox::PassThroughFS fs(configPath.c_str());
|
ox::PassThroughFS fs(configPath);
|
||||||
if (auto err = fs.mkdir("/", true)) {
|
if (auto err = fs.mkdir("/", true)) {
|
||||||
oxErrf("Could not create config directory: {}\n", toStr(err));
|
oxErrf("Could not create config directory: {}\n", toStr(err));
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
oxRequireM(buff, ox::writeOC(data));
|
oxRequireM(buff, ox::writeOC(data));
|
||||||
buff.back().value = '\n';
|
buff.back().value = '\n';
|
||||||
if (auto err = fs.write(path.c_str(), buff.data(), buff.size())) {
|
if (auto err = fs.write(path, buff.data(), buff.size())) {
|
||||||
oxErrf("Could not read config file: {}\n", toStr(err));
|
oxErrf("Could not read config file: {}\n", toStr(err));
|
||||||
return OxError(2, "Could not read config file");
|
return OxError(2, "Could not read config file");
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <ox/std/string.hpp>
|
#include <ox/std/string.hpp>
|
||||||
|
|
||||||
#include "editor.hpp"
|
#include "editor.hpp"
|
||||||
@ -93,6 +95,11 @@ ox::Error BaseEditor::saveItem() noexcept {
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ox::StringView BaseEditor::pathToItemName(ox::CRStringView path) noexcept {
|
||||||
|
const auto lastSlash = std::find(path.rbegin(), path.rend(), '/').offset();
|
||||||
|
return path.substr(lastSlash + 1);
|
||||||
|
}
|
||||||
|
|
||||||
Editor::Editor() noexcept {
|
Editor::Editor() noexcept {
|
||||||
m_undoStack.changeTriggered.connect(this, &Editor::markUnsavedChanges);
|
m_undoStack.changeTriggered.connect(this, &Editor::markUnsavedChanges);
|
||||||
}
|
}
|
||||||
|
@ -100,10 +100,7 @@ class NOSTALGIASTUDIO_EXPORT BaseEditor: public Widget {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr auto pathToItemName(ox::CRStringView path) noexcept {
|
static ox::StringView pathToItemName(ox::CRStringView path) noexcept;
|
||||||
const auto lastSlash = std::find(path.rbegin(), path.rend(), '/').offset();
|
|
||||||
return path.substr(lastSlash + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// signals
|
// signals
|
||||||
public:
|
public:
|
||||||
|
@ -10,12 +10,14 @@ namespace nostalgia::studio {
|
|||||||
|
|
||||||
struct FDFilterItem {
|
struct FDFilterItem {
|
||||||
#ifdef OX_OS_Windows
|
#ifdef OX_OS_Windows
|
||||||
using String = ox::BasicString<8, wchar_t>;
|
using String = ox::Vector<wchar_t>;
|
||||||
#else
|
#else
|
||||||
using String = ox::String;
|
using String = ox::Vector<char>;
|
||||||
#endif
|
#endif
|
||||||
String name;
|
String name{};
|
||||||
String spec;
|
String spec{};
|
||||||
|
constexpr FDFilterItem() noexcept = default;
|
||||||
|
FDFilterItem(ox::CRStringView pName, ox::CRStringView pSpec) noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
ox::Result<ox::String> saveFile(const ox::Vector<FDFilterItem> &exts) noexcept;
|
ox::Result<ox::String> saveFile(const ox::Vector<FDFilterItem> &exts) noexcept;
|
||||||
|
@ -6,12 +6,18 @@
|
|||||||
|
|
||||||
#include <ox/std/error.hpp>
|
#include <ox/std/error.hpp>
|
||||||
#include <ox/std/string.hpp>
|
#include <ox/std/string.hpp>
|
||||||
#include <ox/std/trace.hpp>
|
|
||||||
|
|
||||||
#include "filedialog.hpp"
|
#include "filedialog.hpp"
|
||||||
|
|
||||||
namespace nostalgia::studio {
|
namespace nostalgia::studio {
|
||||||
|
|
||||||
|
FDFilterItem::FDFilterItem(ox::CRStringView pName, ox::CRStringView pSpec) noexcept {
|
||||||
|
name.resize(pName.len() + 1);
|
||||||
|
ox_strncpy(name.data(), pName.data(), pName.len());
|
||||||
|
spec.resize(pSpec.len() + 1);
|
||||||
|
ox_strncpy(spec.data(), pSpec.data(), pSpec.len());
|
||||||
|
}
|
||||||
|
|
||||||
static ox::Result<ox::String> toResult(nfdresult_t r, const NFD::UniquePathN &path) noexcept {
|
static ox::Result<ox::String> toResult(nfdresult_t r, const NFD::UniquePathN &path) noexcept {
|
||||||
switch (r) {
|
switch (r) {
|
||||||
case NFD_OKAY: {
|
case NFD_OKAY: {
|
||||||
@ -30,19 +36,19 @@ static ox::Result<ox::String> toResult(nfdresult_t r, const NFD::UniquePathN &pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::String> saveFile(const ox::Vector<FDFilterItem> &filters) noexcept {
|
ox::Result<ox::String> saveFile(const ox::Vector<FDFilterItem> &filters) noexcept {
|
||||||
NFD::Guard guard;
|
const NFD::Guard guard;
|
||||||
NFD::UniquePathN path;
|
NFD::UniquePathN path;
|
||||||
ox::Vector<nfdnfilteritem_t, 5> filterItems(filters.size());
|
ox::Vector<nfdnfilteritem_t, 5> filterItems(filters.size());
|
||||||
for (auto i = 0u; const auto &f : filters) {
|
for (auto i = 0u; const auto &f : filters) {
|
||||||
filterItems[i].name = f.name.c_str();
|
filterItems[i].name = f.name.data();
|
||||||
filterItems[i].spec = f.spec.c_str();
|
filterItems[i].spec = f.spec.data();
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
return toResult(NFD::SaveDialog(path, filterItems.data(), filterItems.size()), path);
|
return toResult(NFD::SaveDialog(path, filterItems.data(), filterItems.size()), path);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::String> chooseDirectory() noexcept {
|
ox::Result<ox::String> chooseDirectory() noexcept {
|
||||||
NFD::Guard guard;
|
const NFD::Guard guard;
|
||||||
NFD::UniquePathN path;
|
NFD::UniquePathN path;
|
||||||
return toResult(NFD::PickFolder(path), path);
|
return toResult(NFD::PickFolder(path), path);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ class ItemMaker {
|
|||||||
fileExt(std::move(pFileExt)) {
|
fileExt(std::move(pFileExt)) {
|
||||||
}
|
}
|
||||||
virtual ~ItemMaker() noexcept = default;
|
virtual ~ItemMaker() noexcept = default;
|
||||||
virtual ox::Error write(core::Context *ctx, const char *pName) const noexcept = 0;
|
virtual ox::Error write(core::Context *ctx, ox::CRStringView pName) const noexcept = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -44,7 +44,7 @@ class ItemMakerT: public ItemMaker {
|
|||||||
item(std::forward(pItem)),
|
item(std::forward(pItem)),
|
||||||
fmt(pFmt) {
|
fmt(pFmt) {
|
||||||
}
|
}
|
||||||
ox::Error write(core::Context *ctx, const char *pName) const noexcept override {
|
ox::Error write(core::Context *ctx, ox::CRStringView pName) const noexcept override {
|
||||||
const auto path = ox::sfmt("{}/{}.{}", parentDir, pName, fileExt);
|
const auto path = ox::sfmt("{}/{}.{}", parentDir, pName, fileExt);
|
||||||
auto sctx = core::applicationData<studio::StudioContext>(ctx);
|
auto sctx = core::applicationData<studio::StudioContext>(ctx);
|
||||||
return sctx->project->writeObj(path, &item, fmt);
|
return sctx->project->writeObj(path, &item, fmt);
|
||||||
|
@ -17,7 +17,7 @@ namespace nostalgia::studio {
|
|||||||
class ItemMaker;
|
class ItemMaker;
|
||||||
|
|
||||||
struct EditorMaker {
|
struct EditorMaker {
|
||||||
using Func = std::function<ox::Result<class BaseEditor*>(const ox::String&)>;
|
using Func = std::function<ox::Result<class BaseEditor*>(ox::CRStringView)>;
|
||||||
ox::Vector<ox::String> fileTypes;
|
ox::Vector<ox::String> fileTypes;
|
||||||
Func make;
|
Func make;
|
||||||
};
|
};
|
||||||
|
@ -26,21 +26,21 @@ ox::FileSystem *Project::romFs() noexcept {
|
|||||||
return m_fs;
|
return m_fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error Project::mkdir(const ox::String &path) const noexcept {
|
ox::Error Project::mkdir(ox::CRStringView path) const noexcept {
|
||||||
oxReturnError(m_fs->mkdir(path.c_str(), true));
|
oxReturnError(m_fs->mkdir(path, true));
|
||||||
fileUpdated.emit(path);
|
fileUpdated.emit(path);
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::FileStat> Project::stat(const ox::String &path) const noexcept {
|
ox::Result<ox::FileStat> Project::stat(ox::CRStringView path) const noexcept {
|
||||||
return m_fs->stat(path.c_str());
|
return m_fs->stat(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Project::exists(const ox::String &path) const noexcept {
|
bool Project::exists(ox::CRStringView path) const noexcept {
|
||||||
return m_fs->stat(path.c_str()).error == 0;
|
return m_fs->stat(path).error == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ox::Vector<ox::String> &Project::fileList(const char *ext) noexcept {
|
const ox::Vector<ox::String> &Project::fileList(ox::CRStringView ext) noexcept {
|
||||||
return m_fileExtFileMap[ext];
|
return m_fileExtFileMap[ext];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,13 +53,13 @@ void Project::buildFileIndex() noexcept {
|
|||||||
m_fileExtFileMap.clear();
|
m_fileExtFileMap.clear();
|
||||||
std::sort(files.begin(), files.end());
|
std::sort(files.begin(), files.end());
|
||||||
for (const auto &file : files) {
|
for (const auto &file : files) {
|
||||||
if (!file.beginsWith("/.nostalgia/")) {
|
if (!beginsWith(file, "/.nostalgia/")) {
|
||||||
indexFile(file);
|
indexFile(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Project::indexFile(const ox::String &path) noexcept {
|
void Project::indexFile(ox::CRStringView path) noexcept {
|
||||||
const auto [ext, err] = fileExt(path);
|
const auto [ext, err] = fileExt(path);
|
||||||
if (err) {
|
if (err) {
|
||||||
return;
|
return;
|
||||||
@ -67,9 +67,9 @@ void Project::indexFile(const ox::String &path) noexcept {
|
|||||||
m_fileExtFileMap[ext].emplace_back(path);
|
m_fileExtFileMap[ext].emplace_back(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error Project::writeBuff(const ox::String &path, const ox::Buffer &buff) noexcept {
|
ox::Error Project::writeBuff(const ox::StringView &path, const ox::Buffer &buff) noexcept {
|
||||||
const auto newFile = m_fs->stat(path.c_str()).error != 0;
|
const auto newFile = m_fs->stat(path).error != 0;
|
||||||
oxReturnError(m_fs->write(path.c_str(), buff.data(), buff.size()));
|
oxReturnError(m_fs->write(path, buff.data(), buff.size(), ox::FileType::NormalFile));
|
||||||
if (newFile) {
|
if (newFile) {
|
||||||
fileAdded.emit(path);
|
fileAdded.emit(path);
|
||||||
indexFile(path);
|
indexFile(path);
|
||||||
@ -80,17 +80,17 @@ ox::Error Project::writeBuff(const ox::String &path, const ox::Buffer &buff) noe
|
|||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::Buffer> Project::loadBuff(const ox::String &path) const noexcept {
|
ox::Result<ox::Buffer> Project::loadBuff(const ox::String &path) const noexcept {
|
||||||
return m_fs->read(path.c_str());
|
return m_fs->read(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error Project::lsProcDir(ox::Vector<ox::String> *paths, const ox::String &path) const noexcept {
|
ox::Error Project::lsProcDir(ox::Vector<ox::String> *paths, ox::CRStringView path) const noexcept {
|
||||||
oxRequire(files, m_fs->ls(path.c_str()));
|
oxRequire(files, m_fs->ls(path));
|
||||||
for (const auto &name : files) {
|
for (const auto &name : files) {
|
||||||
const auto fullPath = path + "/" + name.c_str();
|
auto fullPath = ox::sfmt("{}/{}", path, name);
|
||||||
oxRequire(stat, m_fs->stat(fullPath.c_str()));
|
oxRequire(stat, m_fs->stat(ox::StringView(fullPath)));
|
||||||
switch (stat.fileType) {
|
switch (stat.fileType) {
|
||||||
case ox::FileType::NormalFile:
|
case ox::FileType::NormalFile:
|
||||||
paths->push_back(fullPath);
|
paths->emplace_back(std::move(fullPath));
|
||||||
break;
|
break;
|
||||||
case ox::FileType::Directory:
|
case ox::FileType::Directory:
|
||||||
oxReturnError(lsProcDir(paths, fullPath));
|
oxReturnError(lsProcDir(paths, fullPath));
|
||||||
@ -102,7 +102,7 @@ ox::Error Project::lsProcDir(ox::Vector<ox::String> *paths, const ox::String &pa
|
|||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::Vector<ox::String>> Project::listFiles(const ox::String &path) const noexcept {
|
ox::Result<ox::Vector<ox::String>> Project::listFiles(ox::CRStringView path) const noexcept {
|
||||||
ox::Vector<ox::String> paths;
|
ox::Vector<ox::String> paths;
|
||||||
oxReturnError(lsProcDir(&paths, path));
|
oxReturnError(lsProcDir(&paths, path));
|
||||||
return paths;
|
return paths;
|
||||||
|
@ -29,7 +29,7 @@ enum class ProjectEvent {
|
|||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr ox::Result<ox::String> fileExt(const ox::String &path) noexcept {
|
constexpr ox::Result<ox::StringView> fileExt(ox::CRStringView path) noexcept {
|
||||||
const auto extStart = ox::find(path.crbegin(), path.crend(), '.').offset();
|
const auto extStart = ox::find(path.crbegin(), path.crend(), '.').offset();
|
||||||
if (!extStart) {
|
if (!extStart) {
|
||||||
return OxError(1, "Cannot open a file without valid extension.");
|
return OxError(1, "Cannot open a file without valid extension.");
|
||||||
@ -52,7 +52,7 @@ class NOSTALGIASTUDIO_EXPORT Project {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ox::FileSystem *romFs() noexcept;
|
ox::FileSystem *romFs() noexcept;
|
||||||
|
|
||||||
ox::Error mkdir(const ox::String &path) const noexcept;
|
ox::Error mkdir(ox::CRStringView path) const noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a MetalClaw object to the project at the given path.
|
* Writes a MetalClaw object to the project at the given path.
|
||||||
@ -63,40 +63,40 @@ class NOSTALGIASTUDIO_EXPORT Project {
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
ox::Result<T> loadObj(const ox::String &path) const noexcept;
|
ox::Result<T> loadObj(const ox::String &path) const noexcept;
|
||||||
|
|
||||||
ox::Result<ox::FileStat> stat(const ox::String &path) const noexcept;
|
ox::Result<ox::FileStat> stat(ox::CRStringView path) const noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool exists(const ox::String& path) const noexcept;
|
bool exists(ox::CRStringView path) const noexcept;
|
||||||
|
|
||||||
template<typename Functor>
|
template<typename Functor>
|
||||||
ox::Error subscribe(ProjectEvent e, ox::SignalHandler *tgt, Functor &&slot) const noexcept;
|
ox::Error subscribe(ProjectEvent e, ox::SignalHandler *tgt, Functor &&slot) const noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
const ox::Vector<ox::String> &fileList(const char *ng) noexcept;
|
const ox::Vector<ox::String> &fileList(ox::CRStringView ext) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void buildFileIndex() noexcept;
|
void buildFileIndex() noexcept;
|
||||||
|
|
||||||
void indexFile(const ox::String &path) noexcept;
|
void indexFile(ox::CRStringView path) noexcept;
|
||||||
|
|
||||||
ox::Error writeBuff(const ox::String &path, const ox::Buffer &buff) noexcept;
|
ox::Error writeBuff(const ox::StringView &path, const ox::Buffer &buff) noexcept;
|
||||||
|
|
||||||
ox::Result<ox::Buffer> loadBuff(const ox::String &path) const noexcept;
|
ox::Result<ox::Buffer> loadBuff(const ox::String &path) const noexcept;
|
||||||
|
|
||||||
ox::Error lsProcDir(ox::Vector<ox::String> *paths, const ox::String &path) const noexcept;
|
ox::Error lsProcDir(ox::Vector<ox::String> *paths, ox::CRStringView path) const noexcept;
|
||||||
|
|
||||||
ox::Result<ox::Vector<ox::String>> listFiles(const ox::String &path = "") const noexcept;
|
ox::Result<ox::Vector<ox::String>> listFiles(ox::CRStringView path = "") const noexcept;
|
||||||
|
|
||||||
// signals
|
// signals
|
||||||
public:
|
public:
|
||||||
ox::Signal<ox::Error(ProjectEvent, const ox::String&)> fileEvent;
|
ox::Signal<ox::Error(ProjectEvent, const ox::String&)> fileEvent;
|
||||||
ox::Signal<ox::Error(const ox::String&)> fileAdded;
|
ox::Signal<ox::Error(ox::CRStringView)> fileAdded;
|
||||||
// FileRecognized is triggered for all matching files upon a new
|
// FileRecognized is triggered for all matching files upon a new
|
||||||
// subscription to a section of the project and upon the addition of a
|
// subscription to a section of the project and upon the addition of a
|
||||||
// file.
|
// file.
|
||||||
ox::Signal<ox::Error(const ox::String&)> fileRecognized;
|
ox::Signal<ox::Error(ox::StringView)> fileRecognized;
|
||||||
ox::Signal<ox::Error(const ox::String&)> fileDeleted;
|
ox::Signal<ox::Error(ox::StringView)> fileDeleted;
|
||||||
ox::Signal<ox::Error(const ox::String&)> fileUpdated;
|
ox::Signal<ox::Error(ox::StringView)> fileUpdated;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ void NewMenu::drawLastPageButtons(core::Context *ctx) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void NewMenu::finish(core::Context *ctx) noexcept {
|
void NewMenu::finish(core::Context *ctx) noexcept {
|
||||||
const auto err = m_types[static_cast<std::size_t>(m_selectedType)]->write(ctx, m_itemName.c_str());
|
const auto err = m_types[static_cast<std::size_t>(m_selectedType)]->write(ctx, m_itemName);
|
||||||
if (err) {
|
if (err) {
|
||||||
oxLogError(err);
|
oxLogError(err);
|
||||||
return;
|
return;
|
||||||
|
BIN
src/nostalgia/studio/ns_logo128.png
Normal file
BIN
src/nostalgia/studio/ns_logo128.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
@ -13,9 +13,9 @@
|
|||||||
namespace nostalgia {
|
namespace nostalgia {
|
||||||
|
|
||||||
static ox::Result<ox::UniquePtr<ProjectTreeModel>>
|
static ox::Result<ox::UniquePtr<ProjectTreeModel>>
|
||||||
buildProjectTreeModel(ProjectExplorer *explorer, const ox::String &name, const ox::String &path, ProjectTreeModel *parent) noexcept {
|
buildProjectTreeModel(ProjectExplorer *explorer, ox::CRStringView name, ox::CRStringView path, ProjectTreeModel *parent) noexcept {
|
||||||
const auto fs = explorer->romFs();
|
const auto fs = explorer->romFs();
|
||||||
oxRequire(stat, fs->stat(path.c_str()));
|
oxRequire(stat, fs->stat(path));
|
||||||
auto out = ox::make_unique<ProjectTreeModel>(explorer, name, parent);
|
auto out = ox::make_unique<ProjectTreeModel>(explorer, name, parent);
|
||||||
if (stat.fileType == ox::FileType::Directory) {
|
if (stat.fileType == ox::FileType::Directory) {
|
||||||
oxRequireM(children, fs->ls(path));
|
oxRequireM(children, fs->ls(path));
|
||||||
@ -58,7 +58,7 @@ void ProjectExplorer::setModel(ox::UniquePtr<ProjectTreeModel> model) noexcept {
|
|||||||
m_treeModel = std::move(model);
|
m_treeModel = std::move(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error ProjectExplorer::refreshProjectTreeModel(const ox::String&) noexcept {
|
ox::Error ProjectExplorer::refreshProjectTreeModel(ox::CRStringView) noexcept {
|
||||||
oxRequireM(model, buildProjectTreeModel(this, "Project", "/", nullptr));
|
oxRequireM(model, buildProjectTreeModel(this, "Project", "/", nullptr));
|
||||||
setModel(std::move(model));
|
setModel(std::move(model));
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
|
@ -23,7 +23,7 @@ class ProjectExplorer: public studio::Widget {
|
|||||||
|
|
||||||
void setModel(ox::UniquePtr<ProjectTreeModel> model) noexcept;
|
void setModel(ox::UniquePtr<ProjectTreeModel> model) noexcept;
|
||||||
|
|
||||||
ox::Error refreshProjectTreeModel(const ox::String& = {}) noexcept;
|
ox::Error refreshProjectTreeModel(ox::CRStringView = {}) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr ox::FileSystem *romFs() noexcept {
|
constexpr ox::FileSystem *romFs() noexcept {
|
||||||
@ -32,7 +32,7 @@ class ProjectExplorer: public studio::Widget {
|
|||||||
|
|
||||||
// slots
|
// slots
|
||||||
public:
|
public:
|
||||||
ox::Signal<ox::Error(const ox::String&)> fileChosen;
|
ox::Signal<ox::Error(const ox::StringView&)> fileChosen;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
@ -9,32 +9,38 @@
|
|||||||
|
|
||||||
namespace nostalgia {
|
namespace nostalgia {
|
||||||
|
|
||||||
ProjectTreeModel::ProjectTreeModel(ProjectExplorer *explorer, const ox::String &name,
|
ProjectTreeModel::ProjectTreeModel(ProjectExplorer *explorer, ox::String name,
|
||||||
ProjectTreeModel *parent) noexcept {
|
ProjectTreeModel *parent) noexcept:
|
||||||
m_explorer = explorer;
|
m_explorer(explorer),
|
||||||
m_name = name;
|
m_parent(parent),
|
||||||
m_parent = parent;
|
m_name(std::move(name)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ProjectTreeModel::ProjectTreeModel(ProjectTreeModel &&other) noexcept {
|
ProjectTreeModel::ProjectTreeModel(ProjectTreeModel &&other) noexcept:
|
||||||
m_name = std::move(other.m_name);
|
m_explorer(other.m_explorer),
|
||||||
m_children = std::move(other.m_children);
|
m_parent(other.m_parent),
|
||||||
|
m_name(std::move(other.m_name)),
|
||||||
|
m_children(std::move(other.m_children)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectTreeModel::draw(core::Context *ctx) noexcept {
|
void ProjectTreeModel::draw(core::Context *ctx) const noexcept {
|
||||||
constexpr auto dirFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
|
constexpr auto dirFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
|
||||||
if (m_children.size()) {
|
if (!m_children.empty()) {
|
||||||
if (ImGui::TreeNodeEx(m_name.c_str(), dirFlags)) {
|
if (ImGui::TreeNodeEx(m_name.c_str(), dirFlags)) {
|
||||||
for (auto &child : m_children) {
|
for (const auto &child : m_children) {
|
||||||
child->draw(ctx);
|
child->draw(ctx);
|
||||||
}
|
}
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
} else if (auto path = fullPath(); ImGui::TreeNodeEx(ox::sfmt("{}##{}", m_name, path).c_str(), ImGuiTreeNodeFlags_Leaf)) {
|
} else {
|
||||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) {
|
const auto path = fullPath();
|
||||||
m_explorer->fileChosen.emit(path);
|
const auto name = ox::sfmt<ox::BasicString<255>>("{}##{}", m_name, path);
|
||||||
|
if (ImGui::TreeNodeEx(name.c_str(), ImGuiTreeNodeFlags_Leaf)) {
|
||||||
|
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) {
|
||||||
|
m_explorer->fileChosen.emit(path);
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
ImGui::TreePop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,9 +48,9 @@ void ProjectTreeModel::setChildren(ox::Vector<ox::UniquePtr<ProjectTreeModel>> c
|
|||||||
m_children = std::move(children);
|
m_children = std::move(children);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::String ProjectTreeModel::fullPath() noexcept {
|
ox::BasicString<255> ProjectTreeModel::fullPath() const noexcept {
|
||||||
if (m_parent) {
|
if (m_parent) {
|
||||||
return m_parent->fullPath() + "/" + m_name;
|
return m_parent->fullPath() + "/" + ox::StringView(m_name);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -18,18 +18,18 @@ class ProjectTreeModel {
|
|||||||
ox::String m_name;
|
ox::String m_name;
|
||||||
ox::Vector<ox::UniquePtr<ProjectTreeModel>> m_children;
|
ox::Vector<ox::UniquePtr<ProjectTreeModel>> m_children;
|
||||||
public:
|
public:
|
||||||
explicit ProjectTreeModel(class ProjectExplorer *explorer, const ox::String &name,
|
explicit ProjectTreeModel(class ProjectExplorer *explorer, ox::String name,
|
||||||
ProjectTreeModel *parent = nullptr) noexcept;
|
ProjectTreeModel *parent = nullptr) noexcept;
|
||||||
|
|
||||||
ProjectTreeModel(ProjectTreeModel &&other) noexcept;
|
ProjectTreeModel(ProjectTreeModel &&other) noexcept;
|
||||||
|
|
||||||
void draw(core::Context *ctx) noexcept;
|
void draw(core::Context *ctx) const noexcept;
|
||||||
|
|
||||||
void setChildren(ox::Vector<ox::UniquePtr<ProjectTreeModel>> children) noexcept;
|
void setChildren(ox::Vector<ox::UniquePtr<ProjectTreeModel>> children) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ox::String fullPath() noexcept;
|
ox::BasicString<255> fullPath() const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
@ -283,10 +283,10 @@ void StudioUI::save() noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error StudioUI::openProject(const ox::String &path) noexcept {
|
ox::Error StudioUI::openProject(ox::CRStringView path) noexcept {
|
||||||
oxRequireM(fs, core::loadRomFs(path.c_str()));
|
oxRequireM(fs, core::loadRomFs(path));
|
||||||
m_ctx->rom = std::move(fs);
|
m_ctx->rom = std::move(fs);
|
||||||
core::setWindowTitle(m_ctx, ox::sfmt("Nostalgia Studio - {}", path).c_str());
|
core::setWindowTitle(m_ctx, ox::sfmt("Nostalgia Studio - {}", path));
|
||||||
m_project = ox::make_unique<studio::Project>(m_ctx->rom.get(), path);
|
m_project = ox::make_unique<studio::Project>(m_ctx->rom.get(), path);
|
||||||
auto sctx = applicationData<studio::StudioContext>(m_ctx);
|
auto sctx = applicationData<studio::StudioContext>(m_ctx);
|
||||||
sctx->project = m_project.get();
|
sctx->project = m_project.get();
|
||||||
|
@ -77,7 +77,7 @@ class StudioUI: public ox::SignalHandler {
|
|||||||
|
|
||||||
void save() noexcept;
|
void save() noexcept;
|
||||||
|
|
||||||
ox::Error openProject(const ox::String &path) noexcept;
|
ox::Error openProject(ox::CRStringView path) noexcept;
|
||||||
|
|
||||||
ox::Error openFile(ox::CRStringView path) noexcept;
|
ox::Error openFile(ox::CRStringView path) noexcept;
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@
|
|||||||
|
|
||||||
using namespace nostalgia;
|
using namespace nostalgia;
|
||||||
|
|
||||||
static ox::Error writeFileBuff(ox::CRString path, const ox::Buffer &buff) noexcept {
|
static ox::Error writeFileBuff(ox::CRStringView path, const ox::Buffer &buff) noexcept {
|
||||||
try {
|
try {
|
||||||
std::ofstream f(path.c_str(), std::ios::binary);
|
std::ofstream f(std::string(toStdStringView(path)), std::ios::binary);
|
||||||
f.write(buff.data(), static_cast<intptr_t>(buff.size()));
|
f.write(buff.data(), static_cast<intptr_t>(buff.size()));
|
||||||
} catch (const std::fstream::failure&) {
|
} catch (const std::fstream::failure&) {
|
||||||
return OxError(2, "failed to write file");
|
return OxError(2, "failed to write file");
|
||||||
@ -23,8 +23,8 @@ static ox::Error writeFileBuff(ox::CRString path, const ox::Buffer &buff) noexce
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static ox::Result<ox::Buffer> readFileBuff(const char *path) noexcept {
|
static ox::Result<ox::Buffer> readFileBuff(ox::CRStringView path) noexcept {
|
||||||
std::ifstream file(path, std::ios::binary | std::ios::ate);
|
std::ifstream file(std::string(toStdStringView(path)), std::ios::binary | std::ios::ate);
|
||||||
if (!file.good()) {
|
if (!file.good()) {
|
||||||
oxErrorf("Could not find OxFS file: {}", path);
|
oxErrorf("Could not find OxFS file: {}", path);
|
||||||
return OxError(1, "Could not find OxFS file");
|
return OxError(1, "Could not find OxFS file");
|
||||||
@ -55,7 +55,7 @@ static ox::Error run(const ox::ClArgs &args) noexcept {
|
|||||||
}
|
}
|
||||||
ox::Buffer dstBuff(32 * ox::units::MB);
|
ox::Buffer dstBuff(32 * ox::units::MB);
|
||||||
oxReturnError(ox::FileSystem32::format(dstBuff.data(), dstBuff.size()));
|
oxReturnError(ox::FileSystem32::format(dstBuff.data(), dstBuff.size()));
|
||||||
ox::PassThroughFS src(argSrc.c_str());
|
ox::PassThroughFS src(argSrc);
|
||||||
ox::FileSystem32 dst(ox::FileStore32(dstBuff.data(), dstBuff.size()));
|
ox::FileSystem32 dst(ox::FileStore32(dstBuff.data(), dstBuff.size()));
|
||||||
core::TypeStore ts(&src);
|
core::TypeStore ts(&src);
|
||||||
oxReturnError(pack(&ts, &src, &dst));
|
oxReturnError(pack(&ts, &src, &dst));
|
||||||
@ -66,7 +66,7 @@ static ox::Error run(const ox::ClArgs &args) noexcept {
|
|||||||
oxRequire(dstSize, dst.size());
|
oxRequire(dstSize, dst.size());
|
||||||
dstBuff.resize(dstSize);
|
dstBuff.resize(dstSize);
|
||||||
|
|
||||||
oxRequireM(romBuff, readFileBuff(argRomBin.c_str()));
|
oxRequireM(romBuff, readFileBuff(argRomBin));
|
||||||
oxReturnError(appendBinary(&romBuff, &dstBuff, pl.get()));
|
oxReturnError(appendBinary(&romBuff, &dstBuff, pl.get()));
|
||||||
|
|
||||||
oxOutf("Dest FS size: {} bytes\n", dstSize);
|
oxOutf("Dest FS size: {} bytes\n", dstSize);
|
||||||
|
@ -32,7 +32,7 @@ static ox::Error pathToInode(ox::FileSystem *dest, ox::ModelObject *obj) noexcep
|
|||||||
case ox::FileAddressType::None:
|
case ox::FileAddressType::None:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
oxRequire(s, dest->stat(path.c_str()));
|
oxRequire(s, dest->stat(ox::StringView(path)));
|
||||||
oxReturnError(o["type"].set(static_cast<int8_t>(ox::FileAddressType::Inode)));
|
oxReturnError(o["type"].set(static_cast<int8_t>(ox::FileAddressType::Inode)));
|
||||||
return data.set(2, s.inode);
|
return data.set(2, s.inode);
|
||||||
}
|
}
|
||||||
@ -58,12 +58,12 @@ static ox::Error transformObj(ox::FileSystem *dest, ox::ModelObject *obj) noexce
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static ox::Error doTransformations(core::TypeStore *ts, ox::FileSystem *dest, ox::CRString filePath) noexcept {
|
static ox::Error doTransformations(core::TypeStore *ts, ox::FileSystem *dest, ox::CRStringView filePath) noexcept {
|
||||||
if (filePath.endsWith(".ng") || filePath.endsWith(".npal")) {
|
if (endsWith(filePath, ".ng") || endsWith(filePath, ".npal")) {
|
||||||
// load file
|
// load file
|
||||||
oxRequire(s, dest->stat(filePath.c_str()));
|
oxRequire(s, dest->stat(filePath));
|
||||||
oxRequireM(buff, dest->read(s.inode));
|
oxRequireM(buff, dest->read(s.inode));
|
||||||
if (filePath.endsWith(".ng")) {
|
if (endsWith(filePath, ".ng")) {
|
||||||
oxReturnError(core::convertBuffToBuff<core::CompactTileSheet>(buff, ox::ClawFormat::Metal).moveTo(&buff));
|
oxReturnError(core::convertBuffToBuff<core::CompactTileSheet>(buff, ox::ClawFormat::Metal).moveTo(&buff));
|
||||||
}
|
}
|
||||||
oxRequireM(obj, ox::readClaw(ts, buff));
|
oxRequireM(obj, ox::readClaw(ts, buff));
|
||||||
@ -78,15 +78,15 @@ static ox::Error doTransformations(core::TypeStore *ts, ox::FileSystem *dest, ox
|
|||||||
|
|
||||||
// claw file transformations are broken out because path to inode
|
// claw file transformations are broken out because path to inode
|
||||||
// transformations need to be done after the copy to the new FS is complete
|
// transformations need to be done after the copy to the new FS is complete
|
||||||
static ox::Error transformClaw(core::TypeStore *ts, ox::FileSystem *dest, ox::CRString path) noexcept {
|
static ox::Error transformClaw(core::TypeStore *ts, ox::FileSystem *dest, ox::CRStringView path) noexcept {
|
||||||
// copy
|
// copy
|
||||||
oxTracef("pack::transformClaw", "path: {}", path);
|
oxTracef("pack::transformClaw", "path: {}", path);
|
||||||
oxRequire(fileList, dest->ls(path));
|
oxRequire(fileList, dest->ls(path));
|
||||||
for (const auto &name : fileList) {
|
for (const auto &name : fileList) {
|
||||||
const auto filePath = path + name;
|
const auto filePath = ox::sfmt("{}{}", path, name);
|
||||||
oxRequire(stat, dest->stat(filePath.c_str()));
|
oxRequire(stat, dest->stat(filePath));
|
||||||
if (stat.fileType == ox::FileType::Directory) {
|
if (stat.fileType == ox::FileType::Directory) {
|
||||||
const auto dir = path + name + '/';
|
const auto dir = ox::sfmt("{}{}/", path, name);
|
||||||
oxReturnError(transformClaw(ts, dest, dir));
|
oxReturnError(transformClaw(ts, dest, dir));
|
||||||
} else {
|
} else {
|
||||||
oxReturnError(doTransformations(ts, dest, filePath));
|
oxReturnError(doTransformations(ts, dest, filePath));
|
||||||
@ -95,9 +95,9 @@ static ox::Error transformClaw(core::TypeStore *ts, ox::FileSystem *dest, ox::CR
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static ox::Error verifyFile(ox::FileSystem *fs, ox::CRString path, const ox::Buffer &expected) noexcept {
|
static ox::Error verifyFile(ox::FileSystem *fs, ox::CRStringView path, const ox::Buffer &expected) noexcept {
|
||||||
ox::Buffer buff(expected.size());
|
ox::Buffer buff(expected.size());
|
||||||
oxReturnError(fs->read(path.c_str(), buff.data(), buff.size()));
|
oxReturnError(fs->read(path, buff.data(), buff.size()));
|
||||||
return OxError(buff == expected ? 0 : 1);
|
return OxError(buff == expected ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ struct VerificationPair {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static ox::Error copy(ox::FileSystem *src, ox::FileSystem *dest, ox::CRString path) noexcept {
|
static ox::Error copy(ox::FileSystem *src, ox::FileSystem *dest, ox::CRStringView path) noexcept {
|
||||||
oxOutf("copying directory: {}\n", path);
|
oxOutf("copying directory: {}\n", path);
|
||||||
ox::Vector<VerificationPair> verificationPairs;
|
ox::Vector<VerificationPair> verificationPairs;
|
||||||
// copy
|
// copy
|
||||||
@ -121,16 +121,16 @@ static ox::Error copy(ox::FileSystem *src, ox::FileSystem *dest, ox::CRString pa
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
oxOutf("reading {}\n", currentFile);
|
oxOutf("reading {}\n", currentFile);
|
||||||
oxRequire(stat, src->stat(currentFile.c_str()));
|
oxRequire(stat, src->stat(ox::StringView(currentFile)));
|
||||||
if (stat.fileType == ox::FileType::Directory) {
|
if (stat.fileType == ox::FileType::Directory) {
|
||||||
oxReturnError(dest->mkdir(currentFile.c_str(), true));
|
oxReturnError(dest->mkdir(currentFile, true));
|
||||||
oxReturnError(copy(src, dest, currentFile + '/'));
|
oxReturnError(copy(src, dest, currentFile + '/'));
|
||||||
} else {
|
} else {
|
||||||
// load file
|
// load file
|
||||||
oxRequireM(buff, src->read(currentFile.c_str()));
|
oxRequireM(buff, src->read(currentFile));
|
||||||
// write file to dest
|
// write file to dest
|
||||||
oxOutf("writing {}\n", currentFile);
|
oxOutf("writing {}\n", currentFile);
|
||||||
oxReturnError(dest->write(currentFile.c_str(), buff.data(), buff.size()));
|
oxReturnError(dest->write(currentFile, buff.data(), buff.size()));
|
||||||
oxReturnError(verifyFile(dest, currentFile, buff));
|
oxReturnError(verifyFile(dest, currentFile, buff));
|
||||||
verificationPairs.emplace_back(std::move(currentFile), std::move(buff));
|
verificationPairs.emplace_back(std::move(currentFile), std::move(buff));
|
||||||
}
|
}
|
||||||
@ -143,9 +143,9 @@ static ox::Error copy(ox::FileSystem *src, ox::FileSystem *dest, ox::CRString pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
// transformations need to be done after the copy to the new FS is complete
|
// transformations need to be done after the copy to the new FS is complete
|
||||||
static ox::Error preloadObj(core::TypeStore *ts, ox::FileSystem *romFs, GbaPreloader *pl, ox::CRString path) noexcept {
|
static ox::Error preloadObj(core::TypeStore *ts, ox::FileSystem *romFs, GbaPreloader *pl, ox::CRStringView path) noexcept {
|
||||||
// load file
|
// load file
|
||||||
oxRequireM(buff, romFs->read(path.c_str()));
|
oxRequireM(buff, romFs->read(path));
|
||||||
oxRequireM(obj, ox::readClaw(ts, buff));
|
oxRequireM(obj, ox::readClaw(ts, buff));
|
||||||
if (obj.type()->preloadable) {
|
if (obj.type()->preloadable) {
|
||||||
// preload
|
// preload
|
||||||
@ -159,21 +159,21 @@ static ox::Error preloadObj(core::TypeStore *ts, ox::FileSystem *romFs, GbaPrelo
|
|||||||
// strip the Claw header (it is not needed after preloading) and write back out to dest fs
|
// strip the Claw header (it is not needed after preloading) and write back out to dest fs
|
||||||
oxReturnError(ox::writeMC(&obj).moveTo(&buff));
|
oxReturnError(ox::writeMC(&obj).moveTo(&buff));
|
||||||
}
|
}
|
||||||
oxReturnError(romFs->write(path.c_str(), buff.data(), buff.size()));
|
oxReturnError(romFs->write(path, buff.data(), buff.size()));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// claw file transformations are broken out because path to inode
|
// claw file transformations are broken out because path to inode
|
||||||
// transformations need to be done after the copy to the new FS is complete
|
// transformations need to be done after the copy to the new FS is complete
|
||||||
static ox::Error preloadDir(core::TypeStore *ts, ox::FileSystem *romFs, GbaPreloader *pl, ox::CRString path) noexcept {
|
static ox::Error preloadDir(core::TypeStore *ts, ox::FileSystem *romFs, GbaPreloader *pl, ox::CRStringView path) noexcept {
|
||||||
// copy
|
// copy
|
||||||
oxTracef("pack::preload", "path: {}", path);
|
oxTracef("pack::preload", "path: {}", path);
|
||||||
oxRequire(fileList, romFs->ls(path));
|
oxRequire(fileList, romFs->ls(path));
|
||||||
for (const auto &name : fileList) {
|
for (const auto &name : fileList) {
|
||||||
const auto filePath = path + name;
|
const auto filePath = ox::sfmt("{}{}", path, name);
|
||||||
oxRequire(stat, romFs->stat(filePath.c_str()));
|
oxRequire(stat, romFs->stat(ox::StringView(filePath)));
|
||||||
if (stat.fileType == ox::FileType::Directory) {
|
if (stat.fileType == ox::FileType::Directory) {
|
||||||
const auto dir = path + name + '/';
|
const auto dir = ox::sfmt("{}{}/", path, name);
|
||||||
oxReturnError(preloadDir(ts, romFs, pl, dir));
|
oxReturnError(preloadDir(ts, romFs, pl, dir));
|
||||||
} else {
|
} else {
|
||||||
oxReturnError(preloadObj(ts, romFs, pl, filePath));
|
oxReturnError(preloadObj(ts, romFs, pl, filePath));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user