Compare commits

...

21 Commits

Author SHA1 Message Date
5fa614ab83 [nostalgia/sample_project] Add Studio logo source to sample_project 2023-01-03 03:40:59 -06:00
7a4fbd1160 [gbastartup] Correct enabled languages in CMake 2023-01-03 03:39:53 -06:00
bb643bce42 [nostalgia] Add implementation of single tile sprites on OpenGL 2023-01-03 03:37:51 -06:00
cf6c05f4c6 [nostalgia/tools/pack] Fix for a non-compliant implementation of fstream 2023-01-03 03:33:54 -06:00
497bbc1a17 [nostalgia/studio] Update for new String beginsWith API 2023-01-03 03:32:16 -06:00
3cd638737a [ox] Update more C strings to StringViews 2023-01-03 03:31:22 -06:00
5508dc5dc0 [ox/std] Make String::beginsWtih and endsWith functions that take StringViews 2023-01-03 03:30:33 -06:00
03378ebe43 [nostalgia/core/gba] Fix buttonDown to return false for non-gamepad buttons 2023-01-03 00:13:40 -06:00
2669aafe81 [nostalgia] Cleanup frequent allocations and const correctness in project explorer 2023-01-01 15:27:28 -06:00
679226ef73 [nostalgia] Replace C strings with ox::StringView 2022-12-31 17:14:43 -06:00
55ea405a54 [ox/std] Add toStdStringView and endsWith functions 2022-12-31 17:14:09 -06:00
6cfa8dd40d [nostalgia] Replace unnecessary ox::Strings with ox::StringViews 2022-12-31 15:48:47 -06:00
5a09918b64 [nostalgia/studio] Add logo 2022-12-31 15:28:04 -06:00
2c2fce2c5a [nostalgia] Replace C strings with StringViews 2022-12-31 15:03:04 -06:00
ca07dc6152 [ox] Replace C strings in FS with StringView 2022-12-31 14:58:35 -06:00
5cae7cbd24 [nostalgia/studio] Cleanup 2022-12-30 18:19:39 -06:00
887d3b3d13 [ox/std] Remove some unnecessary/breaking checks in BasicString::set functions 2022-12-29 02:12:11 -06:00
b08559b3f3 [ox/model] MSVC fix 2022-12-19 00:19:28 -06:00
c9f1b3aaa3 [ox/claw] MSVC fix 2022-12-18 23:27:59 -06:00
907393dfe6 [nostalgia/studio] Fix MSVC issue 2022-12-18 23:18:24 -06:00
bd192ba47a [nostalgia/studio] Fix FDFilterItem to work on Windows 2022-12-18 21:56:30 -06:00
84 changed files with 828 additions and 546 deletions

View File

@ -1,4 +1,4 @@
enable_language(C ASM)
enable_language(CXX ASM)
add_library(
GbaStartup OBJECT

View File

@ -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);
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);
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);
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));
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));
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));
return *out;
}

View File

@ -22,17 +22,20 @@ class ClArgs {
public:
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;
};

View File

@ -74,7 +74,7 @@ Result<Buffer> stripClawHeader(const ox::Buffer &buff) noexcept {
Result<ModelObject> readClaw(TypeStore *ts, const Buffer &buff) noexcept {
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;
oxReturnError(obj.setType(t));
switch (header.fmt) {

View File

@ -158,7 +158,7 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
// determine if already exists
auto name = nameBuff;
oxReturnError(path.get(name));
auto childInode = find(name->c_str());
auto childInode = find(PathIterator(*name));
if (!childInode.ok()) {
// if this is not the last item in the path and parents is disabled,
// 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);
oxReturnError(child.init());
auto err = write(name->c_str(), childInode.value);
auto err = write(PathIterator(*name), childInode.value);
if (err) {
oxLogError(err);
// 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
oxReturnError(path.get(name));
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));
oxTracef("ox::fs::Directory::write", "{}: {}", name->c_str(), nextChild);
oxTracef("ox::fs::Directory::write", "{}: {}", *name, nextChild);
if (nextChild) {
// reuse name because it is a rather large variable and will not be used again
// be attentive that this remains true
name = nullptr;
return Directory(m_fs, nextChild).write(path.next(), inode, nameBuff);
} 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.");
}
} else {
@ -262,14 +262,14 @@ Error Directory<FileStore, InodeId_t>::remove(PathIterator path, FileName *nameB
auto &name = *nameBuff;
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>();
if (buff.valid()) {
oxTrace("ox::fs::Directory::remove", "Found directory buffer.");
for (auto i = buff->iterator(); i.valid(); i.next()) {
auto data = i->data();
if (data.valid()) {
if (ox_strncmp(data->name, name.c_str(), name.len()) == 0) {
if (data->name == name) {
oxReturnError(buff->free(i));
}
} else {
@ -308,7 +308,7 @@ Error Directory<FileStore, InodeId_t>::ls(F cb) noexcept {
template<typename FileStore, typename InodeId_t>
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>();
if (!buff.valid()) {
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()) {
auto data = i->data();
if (data.valid()) {
oxTracef("ox::fs::Directory::findEntry", "Comparing \"{}\" to \"{}\"", name.c_str(), data->name);
if (ox_strncmp(data->name, name.c_str(), MaxFileNameLength) == 0) {
oxTracef("ox::fs::Directory::findEntry", "\"{}\" match found.", name.c_str());
oxTracef("ox::fs::Directory::findEntry", "Comparing \"{}\" to \"{}\"", name, data->name);
if (data->name == name) {
oxTracef("ox::fs::Directory::findEntry", "\"{}\" match found.", name);
return static_cast<InodeId_t>(data->inode);
}
} else {
@ -342,7 +342,7 @@ Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::find(Path
auto name = nameBuff;
oxReturnError(path.get(name));
oxRequire(v, findEntry(name->c_str()));
oxRequire(v, findEntry(*name));
// recurse if not at end of path
if (auto p = path.next(); p.valid()) {
Directory dir(m_fs, v);

View File

@ -43,15 +43,6 @@ FileAddress::FileAddress(char *path) noexcept {
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 {
if (this == &other) {
return *this;
@ -107,16 +98,4 @@ bool FileAddress::operator==(CRStringView path) const noexcept {
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;
}
}

View File

@ -57,17 +57,17 @@ class FileAddress {
FileAddress(uint64_t inode) noexcept;
FileAddress(CRStringView path) noexcept;
explicit FileAddress(CRStringView path) noexcept;
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;
@ -115,15 +115,24 @@ class FileAddress {
/**
* Cleanup memory allocations.
*/
void cleanup() noexcept;
constexpr void cleanup() noexcept;
/**
* 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<>
constexpr const char *getModelTypeName<FileAddress::Data>() noexcept {
return FileAddress::Data::TypeName;
@ -163,4 +172,16 @@ constexpr Error model(T *io, CommonPtrWith<FileAddress> auto *fa) noexcept {
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;
}
}

View File

@ -19,7 +19,7 @@ Result<const char*> FileSystem::directAccess(const FileAddress &addr) noexcept {
return directAccess(addr.getInode().value);
case FileAddressType::ConstPath:
case FileAddressType::Path:
return directAccess(addr.getPath().value);
return directAccess(StringView(addr.getPath().value));
default:
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);
case FileAddressType::ConstPath:
case FileAddressType::Path:
return read(addr.getPath().value, buffer, size);
return read(StringView(addr.getPath().value), buffer, size);
default:
return OxError(1);
}
@ -44,29 +44,32 @@ Result<Buffer> FileSystem::read(const FileAddress &addr) noexcept {
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 {
switch (addr.type()) {
case FileAddressType::Inode:
return read(addr.getInode().value, readStart, readSize, buffer, size);
case FileAddressType::ConstPath:
case FileAddressType::Path:
return read(addr.getPath().value, readStart, readSize, buffer, size);
return OxError(2, "Unsupported for path lookups");
default:
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 {
switch (addr.type()) {
case FileAddressType::Inode:
return remove(addr.getInode().value, recursive);
case FileAddressType::ConstPath:
case FileAddressType::Path:
return remove(addr.getPath().value, recursive);
return remove(StringView(addr.getPath().value), recursive);
default:
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);
case FileAddressType::ConstPath:
case FileAddressType::Path:
return write(addr.getPath().value, buffer, size, fileType);
return write(StringView(addr.getPath().value), buffer, size, fileType);
default:
return OxError(1);
}
@ -90,7 +93,7 @@ Result<FileStat> FileSystem::stat(const FileAddress &addr) const noexcept {
return stat(addr.getInode().value);
case FileAddressType::ConstPath:
case FileAddressType::Path:
return stat(addr.getPath().value);
return stat(StringView(addr.getPath().value));
default:
return OxError(1);
}

View File

@ -29,18 +29,18 @@ class FileSystem {
public:
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.
* @param src the path to the file
* @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;
@ -52,38 +52,48 @@ class FileSystem {
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;
[[maybe_unused]]
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(const char *path, bool recursive) noexcept = 0;
virtual Error remove(CRStringView path, bool recursive) noexcept = 0;
Error remove(const FileAddress &addr, bool recursive = false) noexcept;
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;
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;
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;
[[nodiscard]]
virtual uint64_t spaceNeeded(uint64_t size) const noexcept = 0;
[[nodiscard]]
virtual Result<uint64_t> available() const noexcept = 0;
[[nodiscard]]
virtual Result<uint64_t> size() const noexcept = 0;
[[nodiscard]]
@ -125,13 +135,13 @@ class FileSystemTemplate: public FileSystem {
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;
@ -139,12 +149,12 @@ class FileSystemTemplate: public FileSystem {
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>
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.
@ -153,13 +163,13 @@ class FileSystemTemplate: public FileSystem {
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;
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;
@ -180,7 +190,7 @@ class FileSystemTemplate: public FileSystem {
/**
* 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;
@ -227,14 +237,14 @@ Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buff
}
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);
oxRequireM(rootDir, this->rootDir());
return rootDir.mkdir(path, recursive);
}
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());
Directory rootDir(m_fs, fd.rootDirInode);
oxRequireM(inode, rootDir.find(src));
@ -244,7 +254,7 @@ Error FileSystemTemplate<FileStore, Directory>::move(const char *src, const char
}
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());
Directory rootDir(m_fs, fd.rootDirInode);
oxRequire(inode, rootDir.find(path));
@ -252,7 +262,7 @@ Error FileSystemTemplate<FileStore, Directory>::read(const char *path, void *buf
}
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());
Directory rootDir(m_fs, fd.rootDirInode);
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 {
auto data = m_fs.read(inode);
if (!data.valid()) {
return OxError(1);
return OxError(1, "Data not valid");
}
return reinterpret_cast<char*>(data.get());
}
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;
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);
return OxError(0);
}));
@ -290,7 +300,7 @@ Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(const char *
template<typename FileStore, typename Directory>
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);
oxRequire(s, stat(path));
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>
Error FileSystemTemplate<FileStore, Directory>::remove(const char *path, bool recursive) noexcept {
Error FileSystemTemplate<FileStore, Directory>::remove(CRStringView path, bool recursive) noexcept {
oxRequire(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode);
oxRequire(inode, rootDir.find(path));
@ -328,7 +338,7 @@ Error FileSystemTemplate<FileStore, Directory>::resize(uint64_t size, void *buff
}
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);
if (err) {
oxRequire(generatedId, m_fs.generateInodeId());
@ -357,7 +367,7 @@ Result<FileStat> FileSystemTemplate<FileStore, Directory>::stat(uint64_t inode)
}
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));
return stat(inode);
}
@ -400,10 +410,10 @@ Result<typename FileSystemTemplate<FileStore, Directory>::FileSystemData> FileSy
}
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());
// return root as a special case
if (ox_strcmp(path, "/") == 0) {
if (path == "/") {
return static_cast<uint64_t>(fd.rootDirInode);
}
Directory rootDir(m_fs, fd.rootDirInode);

View File

@ -13,25 +13,25 @@
#if defined(OX_HAS_PASSTHROUGHFS)
#include <fstream>
#include <string_view>
namespace ox {
PassThroughFS::PassThroughFS(const char *dirPath) {
m_path = dirPath;
PassThroughFS::PassThroughFS(CRStringView dirPath) {
m_path = std::string_view(dirPath.data(), dirPath.bytes());
}
PassThroughFS::~PassThroughFS() noexcept {
}
PassThroughFS::~PassThroughFS() noexcept = default;
String PassThroughFS::basePath() const noexcept {
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;
const auto p = m_path / stripSlash(path);
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) {
std::error_code 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) {
success = true;
} else {
std::error_code ec;
success = std::filesystem::create_directory(p, ec);
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);
}
Error PassThroughFS::move(const char *src, const char *dest) noexcept {
Error PassThroughFS::move(CRStringView src, CRStringView dest) noexcept {
std::error_code ec;
std::filesystem::rename(m_path / stripSlash(src), m_path / stripSlash(dest), ec);
if (ec.value()) {
@ -64,7 +63,7 @@ Error PassThroughFS::move(const char *src, const char *dest) noexcept {
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 {
std::ifstream file((m_path / stripSlash(path)), std::ios::binary | std::ios::ate);
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);
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) {
oxTracef("ox::fs::PassThroughFS::read::error", "Read of {} failed: {}", path, f.what());
return OxError(2);
@ -81,7 +80,7 @@ Error PassThroughFS::read(const char *path, void *buffer, std::size_t buffSize)
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");
}
@ -99,7 +98,7 @@ Result<const char*> PassThroughFS::directAccess(uint64_t) noexcept {
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;
std::error_code 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;
}
Error PassThroughFS::remove(const char *path, bool recursive) noexcept {
Error PassThroughFS::remove(CRStringView path, bool recursive) noexcept {
if (recursive) {
return OxError(std::filesystem::remove_all(m_path / stripSlash(path)) != 0);
} else {
@ -124,7 +123,7 @@ Error PassThroughFS::resize(uint64_t, void*) noexcept {
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));
try {
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");
}
Result<FileStat> PassThroughFS::stat(const char *path) const noexcept {
Result<FileStat> PassThroughFS::stat(CRStringView path) const noexcept {
std::error_code ec;
const auto p = m_path / stripSlash(path);
const FileType type = std::filesystem::is_directory(p, ec) ?
@ -194,12 +193,12 @@ bool PassThroughFS::valid() const noexcept {
return false;
}
const char *PassThroughFS::stripSlash(const char *path) noexcept {
std::string_view PassThroughFS::stripSlash(StringView path) noexcept {
const auto pathLen = ox_strlen(path);
for (auto i = 0u; i < pathLen && path[0] == '/'; i++) {
path++;
path = path.substr(1);
}
return path;
return std::string_view(path.data(), path.bytes());
}
}

View File

@ -30,20 +30,20 @@ class PassThroughFS: public FileSystem {
std::filesystem::path m_path;
public:
explicit PassThroughFS(const char *dirPath);
explicit PassThroughFS(CRStringView dirPath);
~PassThroughFS() noexcept override;
[[nodiscard]]
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;
@ -51,29 +51,31 @@ class PassThroughFS: public FileSystem {
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>
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 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;
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;
Result<uint64_t> available() const noexcept override;
Result<uint64_t> size() const noexcept override;
[[nodiscard]]
char *buff() 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.
*/
static const char *stripSlash(const char *path) noexcept;
[[nodiscard]]
static std::string_view stripSlash(StringView path) noexcept;
};
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;
const auto di = std::filesystem::directory_iterator(m_path / stripSlash(dir), ec);
oxReturnError(OxError(ec.value(), "PassThroughFS: ls failed"));

View File

@ -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(CRStringView path): PathIterator(path.data(), path.bytes()) {
}
/**
* @return 0 if no error
*/

View File

@ -26,6 +26,8 @@ class PathIterator {
PathIterator(const char *path);
PathIterator(CRStringView path);
/**
* @return 0 if no error
*/

View File

@ -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");
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);
return OxError(0);
}

View File

@ -331,8 +331,7 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, BasicS
if (m_buffIt + size > m_buffLen) {
return OxError(MC_BUFFENDED);
}
memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
ox_strncpy(data, &m_buff[m_buffIt], size);
m_buffIt += size;
} else {
*val = "";

View File

@ -57,14 +57,21 @@ class FieldCounter {
}
namespace detail {
template<typename T>
constexpr auto ModelFieldCount_v = [] {
[[nodiscard]]
consteval auto modelFieldCount() noexcept {
auto a = std::allocator<T>();
auto t = a.allocate(1);
detail::FieldCounter<T> c;
oxAssert(model(&c, t), "Count failed");
const auto err = model(&c, t);
oxAssert(err, "Count failed");
a.deallocate(t, 1);
return c.fields;
}();
}
}
template<typename T>
constexpr auto ModelFieldCount_v = detail::modelFieldCount<T>();
}

View File

@ -33,6 +33,7 @@ add_library(
substitutes.cpp
stacktrace.cpp
string.cpp
stringview.cpp
strops.cpp
trace.cpp
typetraits.cpp

View File

@ -26,6 +26,8 @@ void panic([[maybe_unused]]const char *file, [[maybe_unused]]int line, [[maybe_u
printStackTrace(2);
oxTrace("panic").del("") << "Panic: " << panicMsg << " (" << file << ":" << line << ")";
std::abort();
#else
while (1);
#endif
}

View File

@ -41,6 +41,8 @@ constexpr void assertFunc(const char *file, int line, bool pass, [[maybe_unused]
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
std::abort();
#else
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
} else {

View File

@ -143,6 +143,7 @@ template<std::size_t size>
constexpr BString<size> &BString<size>::operator+=(StringView s) noexcept {
std::size_t strLen = s.bytes();
oxIgnoreError(append(s.data(), strLen));
return *this;
}
template<std::size_t size>

View File

@ -178,18 +178,6 @@ class BasicString {
[[nodiscard]]
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]]
constexpr const char *data() const noexcept {
return m_buff.data();
@ -238,7 +226,7 @@ class BasicString {
template<std::size_t OtherSize>
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;
@ -291,10 +279,10 @@ constexpr BasicString<SmallStringSize_v>::BasicString(const char *str, std::size
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(CRStringView str) noexcept {
if (m_buff.size()) {
m_buff[0] = 0;
} else {
if (m_buff.empty()) {
m_buff.push_back(0);
} else {
m_buff[0] = 0;
}
set(str);
}
@ -520,30 +508,6 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::substr(
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>
constexpr std::size_t BasicString<SmallStringSize_v>::bytes() const noexcept {
std::size_t i;
@ -555,11 +519,10 @@ template<std::size_t SmallStringSize_v>
constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept {
std::size_t length = 0;
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 & 128) == 0) { // normal ASCII character
++length;
} else if ((b & (256 << 6)) == (256 << 6)) { // start of UTF-8 character
// normal ASCII character or start of UTF-8 character
if ((b & 128) == 0 || (b & (256 << 6)) == (256 << 6)) {
++length;
}
} else {
@ -573,41 +536,33 @@ template<std::size_t SmallStringSize_v>
template<std::size_t OtherSize>
constexpr void BasicString<SmallStringSize_v>::set(const BasicString<OtherSize> &src) noexcept {
std::size_t strBytes = src.bytes();
if (strBytes > 1) {
m_buff.resize(strBytes);
copy_n(src.begin(), strBytes, m_buff.data());
m_buff.back().value = 0;
}
}
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();
if (strBytes > 1) {
m_buff.resize(strBytes + 1);
copy_n(str.data(), strBytes, m_buff.data());
m_buff.back().value = 0;
}
}
template<std::size_t SmallStringSize_v>
constexpr void BasicString<SmallStringSize_v>::set(const char *str) noexcept {
std::size_t strBytes = ox_strlen(str) + 1;
if (strBytes > 1) {
m_buff.resize(strBytes);
copy_n(str, strBytes, m_buff.data());
m_buff.back().value = 0;
}
}
template<std::size_t SmallStringSize_v>
constexpr void BasicString<SmallStringSize_v>::set(const char8_t *str) noexcept {
std::size_t strBytes = ox_strlen(str) + 1;
if (strBytes > 1) {
m_buff.resize(strBytes);
memcpy(m_buff.data(), str, strBytes);
m_buff.back().value = 0;
}
}
extern template class BasicString<8>;

20
deps/ox/src/ox/std/stringview.cpp vendored Normal file
View 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"));

View File

@ -8,6 +8,10 @@
#pragma once
#ifdef OX_USE_STDLIB
#include <string_view>
#endif
#include "iterator.hpp"
#include "strops.hpp"
#include "types.hpp"
@ -133,8 +137,11 @@ class StringView {
public:
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>
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&;
static_assert(StringView("Read").bytes() == 4);
static_assert(StringView("Read") == StringView("Read"));
static_assert(StringView("Read") != StringView("Write"));
static_assert(StringView("Write") != StringView("Read"));
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 beginsWith(CRStringView base, CRStringView beginning) noexcept {
const auto beginningLen = ox::min(beginning.len(), base.len());
return ox_strncmp(base.data(), beginning, beginningLen) == 0;
}
[[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
}

View File

@ -15,9 +15,10 @@
template<typename T1, typename T2>
constexpr char *ox_strcpy(T1 dest, T2 src) noexcept {
using T1Type = typename ox::remove_reference<decltype(dest[0])>::type;
std::size_t i = 0;
while (src[i]) {
dest[i] = src[i];
dest[i] = static_cast<T1Type>(src[i]);
++i;
}
// set null terminator
@ -27,9 +28,10 @@ constexpr char *ox_strcpy(T1 dest, T2 src) noexcept {
template<typename T1, typename T2>
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;
while (i < maxLen && src[i]) {
dest[i] = src[i];
dest[i] = static_cast<T1Type>(src[i]);
++i;
}
// set null terminator
@ -113,18 +115,7 @@ constexpr char *ox_strchr(char *str, int character, std::size_t maxLen = 0xFFFFF
}
[[nodiscard]]
constexpr int ox_lastIndexOf(const char *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 {
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) {

View File

@ -75,17 +75,17 @@ static std::map<ox::String, ox::Error(*)()> tests = {
oxAssert(s == "asdf", "String assign broken");
s += "aoeu";
oxAssert(s == "asdfaoeu", "String append broken");
ox::String ending = "asdf";
oxAssert(ending.beginsWith("as"), "String::beginsWith is broken");
oxAssert(ending.beginsWith("asd"), "String::beginsWith is broken");
oxAssert(ending.beginsWith("asdf"), "String::beginsWith is broken");
oxAssert(!ending.beginsWith("aa"), "String::beginsWith is broken");
oxAssert(!ending.beginsWith("aaaaaaa"), "String::beginsWith is broken");
oxAssert(!ending.beginsWith("li"), "String::beginsWith is broken");
oxAssert(!ending.beginsWith("afoif"), "String::beginsWith is broken");
oxAssert(ending.endsWith("df"), "String::endsWith is broken");
oxAssert(!ending.endsWith("awefawe"), "String::endsWith is broken");
oxAssert(!ending.endsWith("eu"), "String::endsWith is broken");
const ox::StringView str = "asdf";
oxAssert(beginsWith(str, "as"), "String beginsWith is broken");
oxAssert(beginsWith(str, "asd"), "String beginsWith is broken");
oxAssert(beginsWith(str, "asdf"), "String beginsWith is broken");
oxAssert(!beginsWith(str, "aa"), "String beginsWith is broken");
oxAssert(!beginsWith(str, "aaaaaaa"), "String beginsWith is broken");
oxAssert(!beginsWith(str, "li"), "String beginsWith is broken");
oxAssert(!beginsWith(str, "afoif"), "String beginsWith is broken");
oxAssert(endsWith(str, "df"), "String endsWith is broken");
oxAssert(!endsWith(str, "awefawe"), "String endsWith is broken");
oxAssert(!endsWith(str, "eu"), "String endsWith is broken");
return OxError(0);
}
},

View File

@ -59,11 +59,11 @@ class OutStream {
TraceMsg m_msg;
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.line = line;
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 {
@ -182,7 +182,7 @@ constexpr OutStream &OutStream::operator<<(Integer_c auto v) noexcept {
class NullStream {
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 {

View File

@ -43,7 +43,7 @@ void initConsole() {
if (REG_MGBA_DEBUG_ENABLE == 0x1DEA) {
infoLog = log<LogChan::Info>;
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 << " " << file << ':' << line << "\n";
} 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) {
std::cout << msg;
printf("%s", msg);
} else if (ox_strcmp(ch, "stderr") == 0) {
std::cerr << msg;
printf("%s", msg);
} 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
if (ox_strcmp(ch, "info") == 0) {

Binary file not shown.

View File

@ -0,0 +1 @@
M2;net.drinkingtea.nostalgia.core.Palette;1;PÛ{³ÖCˆ

Binary file not shown.

Binary file not shown.

View File

@ -14,7 +14,7 @@ namespace nostalgia::core {
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>
void setClipboardObject([[maybe_unused]] class Context *ctx, [[maybe_unused]] ox::UniquePtr<T> obj) noexcept {

View File

@ -61,9 +61,14 @@ class Context {
unsigned cbb,
const ox::FileAddress &tilesheetPath,
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 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 uint64_t ticksMs(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 setBgStatus(Context *ctx, uint32_t 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 constexpr void setKeyEventHandler(Context *ctx, KeyEventHandler h) 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 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:
ox::UniquePtr<ox::FileSystem> rom;
ox::Vector<Drawer*, 5> drawers;
const char *appName = "Nostalgia";
ox::StringView appName = "Nostalgia";
#ifndef OX_BARE_METAL
AssetManager assetManager;

View File

@ -17,7 +17,7 @@
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;

View File

@ -54,7 +54,7 @@ static ox::Result<std::size_t> findPreloadSection() noexcept {
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>();
ctx->rom = std::move(fs);
ctx->appName = appName;
@ -74,7 +74,7 @@ uint64_t ticksMs(Context*) 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 {

View File

@ -85,7 +85,7 @@ ox::Error shutdownGfx(Context*) noexcept {
return {};
}
void setWindowTitle(Context*, const char*) noexcept {
void setWindowTitle(Context*, ox::CRStringView) 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.
ox::Error initConsole(Context *ctx) noexcept {
constexpr auto TilesheetAddr = "/TileSheets/Charset.ng";
constexpr auto PaletteAddr = "/Palettes/Charset.npal";
constexpr ox::FileAddress TilesheetAddr("/TileSheets/Charset.ng");
constexpr ox::FileAddress PaletteAddr("/Palettes/Charset.npal");
setBgStatus(ctx, 0b0001);
if (!ctx) {
ctx = new (ox_alloca(sizeof(Context))) Context();
@ -174,14 +174,13 @@ ox::Error loadBgTileSheet(Context *ctx,
}
ox::Error loadSpriteTileSheet(Context *ctx,
unsigned cbb,
const ox::FileAddress &tilesheetAddr,
const ox::FileAddress &paletteAddr) noexcept {
oxRequire(tsStat, ctx->rom->stat(tilesheetAddr));
oxRequire(ts, ctx->rom->directAccess(tilesheetAddr));
GbaTileMapTarget target;
target.pal.palette = &MEM_SPRITE_PALETTE[cbb];
target.tileMap = &reinterpret_cast<uint16_t*>(MEM_SPRITE_TILES)[cbb * 512];
target.pal.palette = MEM_SPRITE_PALETTE;
target.tileMap = MEM_SPRITE_TILES;
oxReturnError(ox::readMC(ts, tsStat.size, &target));
// load external palette if available
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.
void puts(Context *ctx, int column, int row, const char *str) noexcept {
for (int i = 0; str[i]; i++) {
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++) {
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*,
unsigned idx,
unsigned x,
unsigned y,
int x,
int y,
unsigned tileIdx,
unsigned spriteShape,
unsigned spriteSize,
unsigned flipX) noexcept {
oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
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>(spriteShape) << 14);
oa.attr1 = (static_cast<uint16_t>(x) & ox::onMask<uint8_t>(8))

View File

@ -11,7 +11,7 @@
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
// media section
constexpr auto headerP2 = "HEADER__________";
@ -31,6 +31,14 @@ ox::Result<char*> loadRom(const 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 {
oxRequire(stat, ctx->rom->stat(file));
oxRequire(buff, ctx->rom->directAccess(file));

View 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 + 2, 6, msg);
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");
// disable all interrupt handling and IntrWait on no interrupts

View File

@ -93,11 +93,11 @@ struct TileSheet {
other.columns = 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),
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)) {
}
@ -120,7 +120,7 @@ struct TileSheet {
}
[[nodiscard]]
auto idx(const geo::Point &pt) const noexcept {
constexpr auto idx(const geo::Point &pt) const noexcept {
return ptToIdx(pt, columns);
}
@ -275,6 +275,7 @@ struct TileSheet {
* @param pBpp bits per pixel, need for knowing how to count the pixels
* @return a count of the pixels in this sheet
*/
[[nodiscard]]
constexpr auto pixelCnt(int8_t pBpp) const noexcept {
return pBpp == 4 ? pixels.size() * 2 : pixels.size();
}
@ -287,13 +288,9 @@ struct TileSheet {
SubSheet subsheet{"Root", 1, 1, bpp};
constexpr TileSheet() noexcept = default;
inline TileSheet(const TileSheet &other) noexcept:
bpp(other.bpp),
defaultPalette(other.defaultPalette),
subsheet(other.subsheet) {
}
TileSheet(const TileSheet &other) noexcept = default;
inline TileSheet(TileSheet &&other) noexcept:
bpp(std::move(other.bpp)),
bpp(other.bpp),
defaultPalette(std::move(other.defaultPalette)),
subsheet(std::move(other.subsheet)) {
}
@ -375,7 +372,7 @@ struct TileSheet {
constexpr ox::Error addSubSheet(const SubSheetIdx &idx) noexcept {
auto &parent = getSubSheet(idx);
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 {
parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows, bpp);
parent.subsheets.emplace_back("Subsheet 1", 1, 1, bpp);
@ -468,21 +465,31 @@ oxModelEnd()
struct Sprite {
unsigned idx = 0;
unsigned x = 0;
unsigned y = 0;
int x = 0;
int y = 0;
unsigned tileIdx = 0;
unsigned spriteShape = 0;
unsigned spriteSize = 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;
void addCustomDrawer(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;
@ -515,11 +522,10 @@ ox::Error loadBgTileSheet(Context *ctx, unsigned cbb, const ox::FileAddress &til
const ox::FileAddress &palette = nullptr) noexcept;
ox::Error loadSpriteTileSheet(Context *ctx,
unsigned section,
const ox::FileAddress &tilesheetAddr,
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;
@ -527,7 +533,7 @@ void clearTileLayer(Context *ctx, unsigned bgIdx) 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;
void setSprite(Context *ctx, const Sprite &s) noexcept;

View File

@ -17,9 +17,11 @@ ox::String getClipboardText(Context *ctx) noexcept {
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>();
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);
}
}

View File

@ -13,7 +13,7 @@
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>();
ctx->rom = std::move(fs);
ctx->appName = appName;
@ -32,7 +32,6 @@ ox::Error run(Context *ctx) noexcept {
while (!glfwWindowShouldClose(id->window)) {
glfwPollEvents();
const auto ticks = ticksMs(ctx);
if (id->eventHandler) {
if (id->wakeupTime <= ticks) {
sleepTime = id->eventHandler(ctx);
if (sleepTime >= 0) {
@ -40,7 +39,6 @@ ox::Error run(Context *ctx) noexcept {
} else {
id->wakeupTime = ~uint64_t(0);
}
}
} else {
sleepTime = 10;
}

View File

@ -11,7 +11,7 @@ namespace nostalgia::core {
struct GlfwImplData {
struct GLFWwindow *window = nullptr;
int64_t startTime = 0;
UpdateHandler eventHandler = nullptr;
UpdateHandler eventHandler = [](Context*) -> int {return 0;};
KeyEventHandler keyEventHandler = nullptr;
uint64_t wakeupTime = 0;
uint64_t keysDown = 0;

View File

@ -192,7 +192,9 @@ ox::Error initGfx(Context *ctx) noexcept {
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 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) {
return OxError(1, "Could not open GLFW window");
}
@ -220,9 +222,11 @@ ox::Error initGfx(Context *ctx) noexcept {
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>();
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 {

View File

@ -7,7 +7,7 @@
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);
}

View File

@ -15,7 +15,7 @@ ox::Error shutdownGfx(Context*) noexcept {
return OxError(0);
}
void setWindowTitle(Context*, const char*) noexcept {
void setWindowTitle(Context*, ox::CRStringView) noexcept {
}
void focusWindow(Context*) noexcept {
@ -60,7 +60,6 @@ ox::Error loadBgTileSheet(Context*,
}
ox::Error loadSpriteTileSheet(Context*,
int,
const ox::FileAddress&,
const ox::FileAddress&) noexcept {
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.
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 {
@ -91,8 +90,8 @@ void hideSprite(Context*, unsigned) noexcept {
void setSprite(Context*,
unsigned,
unsigned,
unsigned,
int,
int,
unsigned,
unsigned,
unsigned,

View File

@ -8,7 +8,7 @@
namespace nostalgia::core {
ox::Result<char*> loadRom(const char*) noexcept {
ox::Result<char*> loadRom(ox::CRStringView) noexcept {
return OxError(1);
}

View File

@ -6,9 +6,9 @@
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 fsExt = lastDot != -1 ? path + lastDot : "";
const auto fsExt = lastDot != -1 ? path.substr(static_cast<std::size_t>(lastDot)) : "";
if (ox_strcmp(fsExt, ".oxfs") == 0) {
oxRequire(rom, core::loadRom(path));
return {ox::make_unique<ox::FileSystem32>(rom, 32 * ox::units::MB, unloadRom)};

View File

@ -26,9 +26,10 @@ oxModelBegin(PreloadPtr)
oxModelEnd()
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>
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 {
#ifndef OX_BARE_METAL
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);
};
oxRequire(path, file.getPath());
if (forceLoad) {
oxRequire(buff, ctx->rom->read(file));
oxRequire(buff, ctx->rom->read(path));
oxRequire(obj, readConvert(buff));
oxRequire(cached, ctx->assetManager.setAsset(path, obj));
return std::move(cached);
} else {
auto [cached, err] = ctx->assetManager.getAsset<T>(path);
if (err) {
oxRequire(buff, ctx->rom->read(file));
oxRequire(buff, ctx->rom->read(path));
oxRequire(obj, readConvert(buff));
oxReturnError(ctx->assetManager.setAsset(path, obj).moveTo(&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
if constexpr(ox::preloadable<T>::value) {
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());
}
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;

View File

@ -2,7 +2,8 @@
* 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 "tilesheeteditor-imgui.hpp"
@ -14,7 +15,7 @@ ox::Vector<studio::EditorMaker> Module::editors(core::Context *ctx) noexcept {
return {
{
{"ng"},
[ctx](const ox::String &path) -> ox::Result<studio::BaseEditor*> {
[ctx](ox::CRStringView path) -> ox::Result<studio::BaseEditor*> {
try {
return ox::make<TileSheetEditorImGui>(ctx, path);
} catch (const ox::Exception &ex) {
@ -24,7 +25,7 @@ ox::Vector<studio::EditorMaker> Module::editors(core::Context *ctx) noexcept {
},
{
{"npal"},
[ctx](const ox::String &path) -> ox::Result<studio::BaseEditor*> {
[ctx](ox::CRStringView path) -> ox::Result<studio::BaseEditor*> {
return PaletteEditorImGui::make(ctx, path);
}
}

View File

@ -13,13 +13,13 @@
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);
out->m_ctx = ctx;
out->m_itemPath = path;
const auto lastSlash = std::find(out->m_itemPath.rbegin(), out->m_itemPath.rend(), '/').offset();
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;
return out.release();
}

View File

@ -21,7 +21,7 @@ class PaletteEditorImGui: public studio::Editor {
PaletteEditorImGui() noexcept = default;
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.

View File

@ -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));
}
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_itemPath = path;
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")) {
ImGui::CloseCurrentPopup();
m_show = false;
inputSubmitted.emit(m_name.c_str(), m_cols, m_rows);
inputSubmitted.emit(m_name, m_cols, m_rows);
}
ImGui::SameLine();
if (ImGui::Button("Cancel")) {

View File

@ -32,7 +32,7 @@ class TileSheetEditorImGui: public studio::BaseEditor {
int m_rows = 0;
bool m_show = false;
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 {
m_show = true;
m_name = name.c_str();
@ -54,7 +54,7 @@ class TileSheetEditorImGui: public studio::BaseEditor {
Tool m_tool = Tool::Draw;
public:
TileSheetEditorImGui(Context *ctx, const ox::String &path);
TileSheetEditorImGui(Context *ctx, ox::CRStringView path);
~TileSheetEditorImGui() override = default;

View File

@ -256,7 +256,7 @@ class AddSubSheetCommand: public TileSheetCommand {
auto &parent = m_img->getSubSheet(m_parentIdx);
if (m_addedSheets.size() < 2) {
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 {
parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows, std::move(parent.pixels));
parent.rows = 0;
@ -511,7 +511,7 @@ class PaletteChangeCommand: public TileSheetCommand {
m_idx = idx;
m_img = img;
m_oldPalette = m_img->defaultPalette;
m_newPalette = newPalette;
m_newPalette = ox::FileAddress(newPalette);
}
void redo() noexcept final {
@ -538,7 +538,7 @@ class PaletteChangeCommand: public TileSheetCommand {
TileSheetEditorModel::TileSheetEditorModel(Context *ctx, ox::String path) {
m_ctx = ctx;
m_path = std::move(path);
oxRequireT(img, readObj<TileSheet>(ctx, m_path.c_str()));
oxRequireT(img, readObj<TileSheet>(ctx, m_path));
m_img = *img;
if (m_img.defaultPalette) {
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;
const auto cmdId = cmd->commandId();
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 idx = m_img.validateSubSheetIdx(tsCmd->subsheetIdx());

View File

@ -10,7 +10,7 @@
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
oxThrowError(m_pixelsDrawer.buildShader());
oxThrowError(m_pixelGridDrawer.buildShader());

View File

@ -49,7 +49,7 @@ class TileSheetEditorView: public ox::SignalHandler {
std::size_t m_palIdx = 0;
public:
TileSheetEditorView(Context *ctx, const ox::String &path);
TileSheetEditorView(Context *ctx, ox::CRStringView path);
~TileSheetEditorView() override = default;

View File

@ -49,8 +49,8 @@ static const auto converters = [] {
}();
[[nodiscard]]
static auto findConverter(const char *srcTypeName, int srcTypeVersion,
const char *dstTypeName, int dstTypeVersion) noexcept -> ox::Result<BaseConverter*> {
static auto findConverter(ox::CRStringView srcTypeName, int srcTypeVersion,
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept -> ox::Result<BaseConverter*> {
for (auto &c : converters) {
if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
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,
const char *srcTypeName, int srcTypeVersion,
const char *dstTypeName, int dstTypeVersion) noexcept {
ox::CRStringView srcTypeName, int srcTypeVersion,
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept {
// look for direct converter
auto [c, err] = findConverter(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion);
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");
}
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));
return convert(srcBuffer, hdr.typeName.c_str(), hdr.typeVersion, dstTypeName, dstTypeVersion);
return convert(srcBuffer, hdr.typeName, hdr.typeVersion, dstTypeName, dstTypeVersion);
}
#endif

View File

@ -51,24 +51,24 @@ struct BaseConverter {
virtual ~BaseConverter() noexcept = default;
[[nodiscard]]
virtual const char *srcTypeName() noexcept = 0;
virtual ox::StringView srcTypeName() noexcept = 0;
[[nodiscard]]
virtual int srcTypeVersion() noexcept = 0;
[[nodiscard]]
virtual bool srcMatches(const char *srcTypeName, int srcTypeVersion) const noexcept = 0;
virtual bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept = 0;
[[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>> convertBuffToPtr(const ox::Buffer &srcBuff) noexcept = 0;
[[nodiscard]]
inline bool matches(const char *srcTypeName, int srcTypeVersion,
const char *dstTypeName, int dstTypeVersion) const noexcept {
inline bool matches(ox::CRStringView srcTypeName, int srcTypeVersion,
ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept {
return srcMatches(srcTypeName, srcTypeVersion)
&& dstMatches(dstTypeName, dstTypeVersion);
}
@ -81,7 +81,7 @@ struct Converter: public BaseConverter {
virtual ox::Error convert(SrcType*, DstType*) noexcept = 0;
[[nodiscard]]
const char *srcTypeName() noexcept final {
ox::StringView srcTypeName() noexcept final {
return ox::requireModelTypeName<SrcType>();
}
@ -91,7 +91,7 @@ struct Converter: public BaseConverter {
}
[[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 SrcTypeVersion = ox::requireModelTypeVersion<SrcType>();
return ox_strcmp(srcTypeName, SrcTypeName) == 0
@ -99,7 +99,7 @@ struct Converter: public BaseConverter {
}
[[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 DstTypeVersion = ox::requireModelTypeVersion<DstType>();
return ox_strcmp(dstTypeName, DstTypeName) == 0
@ -122,7 +122,7 @@ struct Converter: public BaseConverter {
};
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>
ox::Result<DstType> convert(const ox::Buffer &srcBuffer) noexcept {

View File

@ -10,52 +10,71 @@
namespace nostalgia::core {
ox::Error initConsole(Context *ctx) noexcept {
constexpr auto TilesheetAddr = "/TileSheets/Charset.ng";
constexpr auto PaletteAddr = "/Palettes/Charset.npal";
constexpr ox::FileAddress TilesheetAddr("/TileSheets/Charset.ng");
constexpr ox::FileAddress PaletteAddr("/Palettes/Charset.npal");
setBgStatus(ctx, 0b0001);
setBgCbb(ctx, 0, 0);
return loadBgTileSheet(ctx, 0, TilesheetAddr, PaletteAddr);
}
ox::Error loadSpriteTileSheet(Context*,
unsigned,
const ox::FileAddress&,
const ox::FileAddress&) noexcept {
return OxError(0);
}
struct TileSheetData {
ox::Vector<uint32_t> pixels;
int width = 0;
int height = 0;
};
ox::Error loadBgTileSheet(Context *ctx,
unsigned cbb,
const ox::FileAddress &tilesheetPath,
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;
ox::Result<TileSheetData> loadTileSheet(Context *ctx, const CompactTileSheet &tilesheet) noexcept {
const unsigned bytesPerTile = tilesheet.bpp == 8 ? 64 : 32;
const auto tiles = tilesheet.pixels.size() / bytesPerTile;
constexpr int width = 8;
const int height = 8 * static_cast<int>(tiles);
ox::Vector<uint32_t> pixels;
if (bytesPerTile == 64) { // 8 BPP
pixels.resize(tilesheet->pixels.size());
for (std::size_t i = 0; i < tilesheet->pixels.size(); ++i) {
pixels[i] = tilesheet->pixels[i];
pixels.resize(tilesheet.pixels.size());
for (std::size_t i = 0; i < tilesheet.pixels.size(); ++i) {
pixels[i] = tilesheet.pixels[i];
}
} else { // 4 BPP
pixels.resize(tilesheet->pixels.size() * 2);
for (std::size_t i = 0; i < tilesheet->pixels.size(); ++i) {
pixels[i * 2 + 0] = tilesheet->pixels[i] & 0xF;
pixels[i * 2 + 1] = tilesheet->pixels[i] >> 4;
pixels.resize(tilesheet.pixels.size() * 2);
for (std::size_t i = 0; i < tilesheet.pixels.size(); ++i) {
pixels[i * 2 + 0] = tilesheet.pixels[i] & 0xF;
pixels[i * 2 + 1] = tilesheet.pixels[i] >> 4;
}
}
const auto rd = ctx->rendererData<void>();
renderer::loadBgTexture(rd, cbb, pixels.data(), width, height);
renderer::loadBgPalette(rd, *palette);
return OxError(0);
renderer::loadSpriteTexture(rd, pixels.data(), width, height);
return TileSheetData{std::move(pixels), width, height};
}
void puts(Context *ctx, int column, int row, const char *str) noexcept {
for (int i = 0; str[i]; ++i) {
setTile(ctx, 0, column + i, row, static_cast<uint8_t>(charMap[static_cast<uint8_t>(str[i])]));
ox::Error loadBgTileSheet(Context *ctx,
unsigned cbb,
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])]));
}
}

View File

@ -20,6 +20,10 @@ void shutdown(Context *ctx, void *rendererData) 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;
}

View File

@ -22,36 +22,53 @@ namespace renderer {
constexpr uint64_t TileRows = 128;
constexpr uint64_t TileColumns = 128;
constexpr uint64_t TileCount = TileRows * TileColumns;
constexpr uint64_t SpriteCount = 128;
constexpr uint64_t BgVertexVboRows = 4;
constexpr uint64_t BgVertexVboRowLength = 4;
constexpr uint64_t BgVertexVboLength = BgVertexVboRows * BgVertexVboRowLength;
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 {
bool updated = false;
CBB() noexcept {
constexpr CBB() noexcept {
vertices.resize(TileCount * BgVertexVboLength);
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 {
bool enabled = false;
unsigned cbbIdx = 0;
};
struct Sprite {
bool enabled = false;
};
struct GlImplData {
glutils::GLProgram bgShader;
glutils::GLProgram spriteShader;
int64_t prevFpsCheckTime = 0;
uint64_t draws = 0;
ox::Array<CBB, 4> cbbs;
SpriteBlockset spriteBlocks;
ox::Array<Sprite, 128> spriteStates;
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 vPosition;
@ -62,15 +79,39 @@ constexpr const GLchar *bgvshad = R"(
fTexCoord = vTexCoord * vec2(1, vTileHeight);
})";
constexpr const GLchar *bgfshad = R"(
constexpr ox::StringView bgfshadTmpl = R"(
{}
out vec4 outColor;
in vec2 fTexCoord;
uniform sampler2D image;
uniform vec3 fPalette[256];
uniform vec4 fPalette[256];
void main() {
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);
})";
@ -79,8 +120,46 @@ static constexpr auto bgVertexRow(unsigned x, unsigned y) noexcept {
return y * TileRows + x;
}
static void
setTileBufferObject(Context *ctx, unsigned vi, float x, float y, int textureRow, float *vbo, GLuint *ebo) noexcept {
static void setSpriteBufferObject(Context *ctx,
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
const auto [sw, sh] = getScreenSize(ctx);
constexpr float ymod = 2.0f / 20.0f;
@ -89,11 +168,12 @@ setTileBufferObject(Context *ctx, unsigned vi, float x, float y, int textureRow,
y *= -ymod;
x -= 1.0f;
y += 1.0f - ymod;
const auto textureRowf = static_cast<float>(textureRow);
const ox::Array<float, BgVertexVboLength> vertices {
x, y, 0, static_cast<float>(textureRow + 1), // bottom left
x + xmod, y, 1, static_cast<float>(textureRow + 1), // bottom right
x + xmod, y + ymod, 1, static_cast<float>(textureRow + 0), // top right
x, y + ymod, 0, static_cast<float>(textureRow + 0), // top left
x, y, 0, textureRowf + 1, // bottom left
x + xmod, y, 1, textureRowf + 1, // bottom right
x + xmod, y + ymod, 1, textureRowf + 0, // top right
x, y + ymod, 0, textureRowf + 0, // top left
};
memcpy(vbo, vertices.data(), sizeof(vertices));
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));
}
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 {
for (auto x = 0u; x < TileColumns; ++x) {
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 {
// vao
bg->vao = glutils::generateVertexArrayObject();
@ -134,7 +246,7 @@ static void initBackgroundBufferset(Context *ctx, GLuint shader, glutils::Buffer
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;
glGenTextures(1, &texId);
glutils::GLTexture tex(texId);
@ -179,10 +291,9 @@ static void drawBackground(CBB *cbb) noexcept {
static void drawBackgrounds(GlImplData *id) noexcept {
// load background shader and its uniforms
glUseProgram(id->bgShader);
const auto uniformPalette = static_cast<GLint>(glGetUniformLocation(id->bgShader, "fPalette"));
const auto uniformTileHeight = static_cast<GLint>(glGetUniformLocation(id->bgShader, "vTileHeight"));
glUniform3fv(uniformPalette, GlImplData::ColorCnt, id->palette.data());
for (auto &bg : id->backgrounds) {
//glUniform3fv(uniformPalette, GlImplData::ColorCnt, id->palette.data());
for (const auto &bg : id->backgrounds) {
if (bg.enabled) {
auto &cbb = id->cbbs[bg.cbbIdx];
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 {
const auto vshad = ox::sfmt(bgvshad, glutils::GlslVersion);
const auto fshad = ox::sfmt(bgfshad, glutils::GlslVersion);
oxRequireM(bgShader, glutils::buildShaderProgram(vshad.c_str(), fshad.c_str()));
const auto id = new GlImplData;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
const auto bgVshad = ox::sfmt(bgvshadTmpl, glutils::GlslVersion);
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;
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) {
initBackgroundBufferset(ctx, id->bgShader, &bg);
}
initSpritesBufferset(ctx, id->spriteShader, &id->spriteBlocks);
ImGui_ImplOpenGL3_Init(glutils::GlslVersion);
return OxError(0);
}
@ -211,20 +345,43 @@ void shutdown(Context*, void *rendererData) noexcept {
ox::safeDelete(id);
}
void loadBgPalette(void *rendererData, const Palette &pal) noexcept {
const auto id = static_cast<GlImplData*>(rendererData);
static void loadPalette(GLuint shaderPgrm, const Palette &pal, bool firstIsTransparent = false) noexcept {
static constexpr std::size_t ColorCnt = 256;
ox::Array<GLfloat, ColorCnt * 4> palette{};
for (auto i = 0u; const auto c : pal.colors) {
id->palette[i++] = redf(c);
id->palette[i++] = greenf(c);
id->palette[i++] = bluef(c);
palette[i++] = redf(c);
palette[i++] = greenf(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);
const auto id = static_cast<GlImplData*>(rendererData);
auto &tex = id->cbbs[cbbIdx].tex;
tex = loadTexture(w, h, pixels);
id->cbbs[cbbIdx].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);
// render
renderer::drawBackgrounds(id);
renderer::drawSprites(id);
for (const auto cd : ctx->drawers) {
cd->draw(ctx);
}
@ -291,17 +449,31 @@ void clearTileLayer(Context *ctx, unsigned bgIdx) noexcept {
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*,
unsigned,
unsigned,
unsigned,
unsigned,
unsigned,
unsigned,
unsigned) noexcept {
void setSprite(Context *ctx,
unsigned idx,
int x,
int y,
unsigned tileIdx,
[[maybe_unused]] unsigned spriteShape,
[[maybe_unused]] unsigned spriteSize,
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 {

View File

@ -10,8 +10,8 @@
namespace nostalgia::core {
ox::Result<char*> loadRom(const char *path) noexcept {
std::ifstream file(path, std::ios::binary | std::ios::ate);
ox::Result<char*> loadRom(ox::CRStringView path) noexcept {
std::ifstream file(std::string(toStdStringView(path)), std::ios::binary | std::ios::ate);
if (!file.good()) {
oxErrorf("Could not find ROM file: {}", path);
return OxError(1, "Could not find ROM file");

View File

@ -47,7 +47,7 @@ template struct GLObject<deleteProgram>;
template struct GLObject<deleteShader>;
[[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));
glShaderSource(shader, 1, &src, nullptr);
glCompileShader(shader);

View File

@ -12,14 +12,14 @@ static int spriteY = 64;
static int updateHandler(core::Context *ctx) noexcept {
int xmod = 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;
} else if (core::buttonDown(ctx, core::GamePad_Left)) {
} else if (core::buttonDown(ctx, core::Alpha_A) || core::buttonDown(ctx, core::GamePad_Left)) {
xmod = -2;
}
if (core::buttonDown(ctx, core::GamePad_Down)) {
if (core::buttonDown(ctx, core::Alpha_S) || core::buttonDown(ctx, core::GamePad_Down)) {
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;
}
if (!xmod && !ymod) {
@ -27,10 +27,10 @@ static int updateHandler(core::Context *ctx) noexcept {
}
spriteX += xmod;
spriteY += ymod;
constexpr auto s = "nostalgia";
constexpr ox::StringView s = "nostalgia";
for (unsigned i = 0; s[i]; ++i) {
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;
}
@ -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 {
oxTraceInitHook();
oxRequireM(ctx, core::init(std::move(fs)));
constexpr auto TileSheetAddr = "/TileSheets/Charset.ng";
constexpr auto PaletteAddr = "/Palettes/Charset.npal";
constexpr ox::FileAddress TileSheetAddr("/TileSheets/Charset.ng");
constexpr ox::FileAddress PaletteAddr("/Palettes/Charset.npal");
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()));
core::puts(ctx.get(), 10, 9, "DOPENESS!!!");
core::setUpdateHandler(ctx.get(), updateHandler);
core::setKeyEventHandler(ctx.get(), keyEventHandler);
return core::run(ctx.get());
}

View File

@ -35,6 +35,13 @@ install(
${NOSTALGIA_DIST_RESOURCES}
)
install(
FILES
ns_logo128.png
DESTINATION
${NOSTALGIA_DIST_RESOURCES}/icons
)
install(
TARGETS
nostalgia-studio

View File

@ -38,7 +38,7 @@ constexpr auto ConfigDir = [] {
}();
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");
const auto homeDir = std::getenv(ox::defines::OS == ox::OS::Windows ? "USERPROFILE" : "HOME");
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 {
oxAssert(ox_strcmp(name, ""), "Config type has no TypeName");
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 path = ox::sfmt("{}.json", name).toStdString();
ox::PassThroughFS fs(configPath.c_str());
const auto configPath = ox::sfmt(ConfigDir, homeDir, ctx->appName);
const auto path = ox::sfmt("{}.json", name);
ox::PassThroughFS fs(configPath);
if (auto err = fs.mkdir("/", true)) {
oxErrf("Could not create config directory: {}\n", toStr(err));
return err;
}
oxRequireM(buff, ox::writeOC(data));
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));
return OxError(2, "Could not read config file");
}

View File

@ -2,6 +2,8 @@
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <algorithm>
#include <ox/std/string.hpp>
#include "editor.hpp"
@ -93,6 +95,11 @@ ox::Error BaseEditor::saveItem() noexcept {
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 {
m_undoStack.changeTriggered.connect(this, &Editor::markUnsavedChanges);
}

View File

@ -100,10 +100,7 @@ class NOSTALGIASTUDIO_EXPORT BaseEditor: public Widget {
return nullptr;
}
static constexpr auto pathToItemName(ox::CRStringView path) noexcept {
const auto lastSlash = std::find(path.rbegin(), path.rend(), '/').offset();
return path.substr(lastSlash + 1);
}
static ox::StringView pathToItemName(ox::CRStringView path) noexcept;
// signals
public:

View File

@ -10,12 +10,14 @@ namespace nostalgia::studio {
struct FDFilterItem {
#ifdef OX_OS_Windows
using String = ox::BasicString<8, wchar_t>;
using String = ox::Vector<wchar_t>;
#else
using String = ox::String;
using String = ox::Vector<char>;
#endif
String name;
String spec;
String name{};
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;

View File

@ -6,12 +6,18 @@
#include <ox/std/error.hpp>
#include <ox/std/string.hpp>
#include <ox/std/trace.hpp>
#include "filedialog.hpp"
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 {
switch (r) {
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 {
NFD::Guard guard;
const NFD::Guard guard;
NFD::UniquePathN path;
ox::Vector<nfdnfilteritem_t, 5> filterItems(filters.size());
for (auto i = 0u; const auto &f : filters) {
filterItems[i].name = f.name.c_str();
filterItems[i].spec = f.spec.c_str();
filterItems[i].name = f.name.data();
filterItems[i].spec = f.spec.data();
++i;
}
return toResult(NFD::SaveDialog(path, filterItems.data(), filterItems.size()), path);
}
ox::Result<ox::String> chooseDirectory() noexcept {
NFD::Guard guard;
const NFD::Guard guard;
NFD::UniquePathN path;
return toResult(NFD::PickFolder(path), path);
}

View File

@ -21,7 +21,7 @@ class ItemMaker {
fileExt(std::move(pFileExt)) {
}
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>
@ -44,7 +44,7 @@ class ItemMakerT: public ItemMaker {
item(std::forward(pItem)),
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);
auto sctx = core::applicationData<studio::StudioContext>(ctx);
return sctx->project->writeObj(path, &item, fmt);

View File

@ -17,7 +17,7 @@ namespace nostalgia::studio {
class ItemMaker;
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;
Func make;
};

View File

@ -26,21 +26,21 @@ ox::FileSystem *Project::romFs() noexcept {
return m_fs;
}
ox::Error Project::mkdir(const ox::String &path) const noexcept {
oxReturnError(m_fs->mkdir(path.c_str(), true));
ox::Error Project::mkdir(ox::CRStringView path) const noexcept {
oxReturnError(m_fs->mkdir(path, true));
fileUpdated.emit(path);
return OxError(0);
}
ox::Result<ox::FileStat> Project::stat(const ox::String &path) const noexcept {
return m_fs->stat(path.c_str());
ox::Result<ox::FileStat> Project::stat(ox::CRStringView path) const noexcept {
return m_fs->stat(path);
}
bool Project::exists(const ox::String &path) const noexcept {
return m_fs->stat(path.c_str()).error == 0;
bool Project::exists(ox::CRStringView path) const noexcept {
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];
}
@ -53,13 +53,13 @@ void Project::buildFileIndex() noexcept {
m_fileExtFileMap.clear();
std::sort(files.begin(), files.end());
for (const auto &file : files) {
if (!file.beginsWith("/.nostalgia/")) {
if (!beginsWith(file, "/.nostalgia/")) {
indexFile(file);
}
}
}
void Project::indexFile(const ox::String &path) noexcept {
void Project::indexFile(ox::CRStringView path) noexcept {
const auto [ext, err] = fileExt(path);
if (err) {
return;
@ -67,9 +67,9 @@ void Project::indexFile(const ox::String &path) noexcept {
m_fileExtFileMap[ext].emplace_back(path);
}
ox::Error Project::writeBuff(const ox::String &path, const ox::Buffer &buff) noexcept {
const auto newFile = m_fs->stat(path.c_str()).error != 0;
oxReturnError(m_fs->write(path.c_str(), buff.data(), buff.size()));
ox::Error Project::writeBuff(const ox::StringView &path, const ox::Buffer &buff) noexcept {
const auto newFile = m_fs->stat(path).error != 0;
oxReturnError(m_fs->write(path, buff.data(), buff.size(), ox::FileType::NormalFile));
if (newFile) {
fileAdded.emit(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 {
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 {
oxRequire(files, m_fs->ls(path.c_str()));
ox::Error Project::lsProcDir(ox::Vector<ox::String> *paths, ox::CRStringView path) const noexcept {
oxRequire(files, m_fs->ls(path));
for (const auto &name : files) {
const auto fullPath = path + "/" + name.c_str();
oxRequire(stat, m_fs->stat(fullPath.c_str()));
auto fullPath = ox::sfmt("{}/{}", path, name);
oxRequire(stat, m_fs->stat(ox::StringView(fullPath)));
switch (stat.fileType) {
case ox::FileType::NormalFile:
paths->push_back(fullPath);
paths->emplace_back(std::move(fullPath));
break;
case ox::FileType::Directory:
oxReturnError(lsProcDir(paths, fullPath));
@ -102,7 +102,7 @@ ox::Error Project::lsProcDir(ox::Vector<ox::String> *paths, const ox::String &pa
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;
oxReturnError(lsProcDir(&paths, path));
return paths;

View File

@ -29,7 +29,7 @@ enum class ProjectEvent {
};
[[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();
if (!extStart) {
return OxError(1, "Cannot open a file without valid extension.");
@ -52,7 +52,7 @@ class NOSTALGIASTUDIO_EXPORT Project {
[[nodiscard]]
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.
@ -63,40 +63,40 @@ class NOSTALGIASTUDIO_EXPORT Project {
template<typename T>
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]]
bool exists(const ox::String& path) const noexcept;
bool exists(ox::CRStringView path) const noexcept;
template<typename Functor>
ox::Error subscribe(ProjectEvent e, ox::SignalHandler *tgt, Functor &&slot) const noexcept;
[[nodiscard]]
const ox::Vector<ox::String> &fileList(const char *ng) noexcept;
const ox::Vector<ox::String> &fileList(ox::CRStringView ext) noexcept;
private:
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::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
public:
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
// subscription to a section of the project and upon the addition of a
// file.
ox::Signal<ox::Error(const ox::String&)> fileRecognized;
ox::Signal<ox::Error(const ox::String&)> fileDeleted;
ox::Signal<ox::Error(const ox::String&)> fileUpdated;
ox::Signal<ox::Error(ox::StringView)> fileRecognized;
ox::Signal<ox::Error(ox::StringView)> fileDeleted;
ox::Signal<ox::Error(ox::StringView)> fileUpdated;
};

View File

@ -108,7 +108,7 @@ void NewMenu::drawLastPageButtons(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) {
oxLogError(err);
return;

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

View File

@ -13,9 +13,9 @@
namespace nostalgia {
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();
oxRequire(stat, fs->stat(path.c_str()));
oxRequire(stat, fs->stat(path));
auto out = ox::make_unique<ProjectTreeModel>(explorer, name, parent);
if (stat.fileType == ox::FileType::Directory) {
oxRequireM(children, fs->ls(path));
@ -58,7 +58,7 @@ void ProjectExplorer::setModel(ox::UniquePtr<ProjectTreeModel> model) noexcept {
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));
setModel(std::move(model));
return OxError(0);

View File

@ -23,7 +23,7 @@ class ProjectExplorer: public studio::Widget {
void setModel(ox::UniquePtr<ProjectTreeModel> model) noexcept;
ox::Error refreshProjectTreeModel(const ox::String& = {}) noexcept;
ox::Error refreshProjectTreeModel(ox::CRStringView = {}) noexcept;
[[nodiscard]]
constexpr ox::FileSystem *romFs() noexcept {
@ -32,7 +32,7 @@ class ProjectExplorer: public studio::Widget {
// slots
public:
ox::Signal<ox::Error(const ox::String&)> fileChosen;
ox::Signal<ox::Error(const ox::StringView&)> fileChosen;
};
}

View File

@ -9,42 +9,48 @@
namespace nostalgia {
ProjectTreeModel::ProjectTreeModel(ProjectExplorer *explorer, const ox::String &name,
ProjectTreeModel *parent) noexcept {
m_explorer = explorer;
m_name = name;
m_parent = parent;
ProjectTreeModel::ProjectTreeModel(ProjectExplorer *explorer, ox::String name,
ProjectTreeModel *parent) noexcept:
m_explorer(explorer),
m_parent(parent),
m_name(std::move(name)) {
}
ProjectTreeModel::ProjectTreeModel(ProjectTreeModel &&other) noexcept {
m_name = std::move(other.m_name);
m_children = std::move(other.m_children);
ProjectTreeModel::ProjectTreeModel(ProjectTreeModel &&other) noexcept:
m_explorer(other.m_explorer),
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;
if (m_children.size()) {
if (!m_children.empty()) {
if (ImGui::TreeNodeEx(m_name.c_str(), dirFlags)) {
for (auto &child : m_children) {
for (const auto &child : m_children) {
child->draw(ctx);
}
ImGui::TreePop();
}
} else if (auto path = fullPath(); ImGui::TreeNodeEx(ox::sfmt("{}##{}", m_name, path).c_str(), ImGuiTreeNodeFlags_Leaf)) {
} else {
const auto path = fullPath();
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();
}
}
}
void ProjectTreeModel::setChildren(ox::Vector<ox::UniquePtr<ProjectTreeModel>> children) noexcept {
m_children = std::move(children);
}
ox::String ProjectTreeModel::fullPath() noexcept {
ox::BasicString<255> ProjectTreeModel::fullPath() const noexcept {
if (m_parent) {
return m_parent->fullPath() + "/" + m_name;
return m_parent->fullPath() + "/" + ox::StringView(m_name);
}
return "";
}

View File

@ -18,18 +18,18 @@ class ProjectTreeModel {
ox::String m_name;
ox::Vector<ox::UniquePtr<ProjectTreeModel>> m_children;
public:
explicit ProjectTreeModel(class ProjectExplorer *explorer, const ox::String &name,
explicit ProjectTreeModel(class ProjectExplorer *explorer, ox::String name,
ProjectTreeModel *parent = nullptr) 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;
private:
[[nodiscard]]
ox::String fullPath() noexcept;
ox::BasicString<255> fullPath() const noexcept;
};
}

View File

@ -283,10 +283,10 @@ void StudioUI::save() noexcept {
}
}
ox::Error StudioUI::openProject(const ox::String &path) noexcept {
oxRequireM(fs, core::loadRomFs(path.c_str()));
ox::Error StudioUI::openProject(ox::CRStringView path) noexcept {
oxRequireM(fs, core::loadRomFs(path));
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);
auto sctx = applicationData<studio::StudioContext>(m_ctx);
sctx->project = m_project.get();

View File

@ -77,7 +77,7 @@ class StudioUI: public ox::SignalHandler {
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;

View File

@ -13,9 +13,9 @@
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 {
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()));
} catch (const std::fstream::failure&) {
return OxError(2, "failed to write file");
@ -23,8 +23,8 @@ static ox::Error writeFileBuff(ox::CRString path, const ox::Buffer &buff) noexce
return {};
}
static ox::Result<ox::Buffer> readFileBuff(const char *path) noexcept {
std::ifstream file(path, std::ios::binary | std::ios::ate);
static ox::Result<ox::Buffer> readFileBuff(ox::CRStringView path) noexcept {
std::ifstream file(std::string(toStdStringView(path)), std::ios::binary | std::ios::ate);
if (!file.good()) {
oxErrorf("Could not find OxFS file: {}", path);
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);
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()));
core::TypeStore ts(&src);
oxReturnError(pack(&ts, &src, &dst));
@ -66,7 +66,7 @@ static ox::Error run(const ox::ClArgs &args) noexcept {
oxRequire(dstSize, dst.size());
dstBuff.resize(dstSize);
oxRequireM(romBuff, readFileBuff(argRomBin.c_str()));
oxRequireM(romBuff, readFileBuff(argRomBin));
oxReturnError(appendBinary(&romBuff, &dstBuff, pl.get()));
oxOutf("Dest FS size: {} bytes\n", dstSize);

View File

@ -32,7 +32,7 @@ static ox::Error pathToInode(ox::FileSystem *dest, ox::ModelObject *obj) noexcep
case ox::FileAddressType::None:
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)));
return data.set(2, s.inode);
}
@ -58,12 +58,12 @@ static ox::Error transformObj(ox::FileSystem *dest, ox::ModelObject *obj) noexce
return {};
}
static ox::Error doTransformations(core::TypeStore *ts, ox::FileSystem *dest, ox::CRString filePath) noexcept {
if (filePath.endsWith(".ng") || filePath.endsWith(".npal")) {
static ox::Error doTransformations(core::TypeStore *ts, ox::FileSystem *dest, ox::CRStringView filePath) noexcept {
if (endsWith(filePath, ".ng") || endsWith(filePath, ".npal")) {
// load file
oxRequire(s, dest->stat(filePath.c_str()));
oxRequire(s, dest->stat(filePath));
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));
}
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
// 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
oxTracef("pack::transformClaw", "path: {}", path);
oxRequire(fileList, dest->ls(path));
for (const auto &name : fileList) {
const auto filePath = path + name;
oxRequire(stat, dest->stat(filePath.c_str()));
const auto filePath = ox::sfmt("{}{}", path, name);
oxRequire(stat, dest->stat(filePath));
if (stat.fileType == ox::FileType::Directory) {
const auto dir = path + name + '/';
const auto dir = ox::sfmt("{}{}/", path, name);
oxReturnError(transformClaw(ts, dest, dir));
} else {
oxReturnError(doTransformations(ts, dest, filePath));
@ -95,9 +95,9 @@ static ox::Error transformClaw(core::TypeStore *ts, ox::FileSystem *dest, ox::CR
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());
oxReturnError(fs->read(path.c_str(), buff.data(), buff.size()));
oxReturnError(fs->read(path, buff.data(), buff.size()));
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);
ox::Vector<VerificationPair> verificationPairs;
// copy
@ -121,16 +121,16 @@ static ox::Error copy(ox::FileSystem *src, ox::FileSystem *dest, ox::CRString pa
continue;
}
oxOutf("reading {}\n", currentFile);
oxRequire(stat, src->stat(currentFile.c_str()));
oxRequire(stat, src->stat(ox::StringView(currentFile)));
if (stat.fileType == ox::FileType::Directory) {
oxReturnError(dest->mkdir(currentFile.c_str(), true));
oxReturnError(dest->mkdir(currentFile, true));
oxReturnError(copy(src, dest, currentFile + '/'));
} else {
// load file
oxRequireM(buff, src->read(currentFile.c_str()));
oxRequireM(buff, src->read(currentFile));
// write file to dest
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));
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
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
oxRequireM(buff, romFs->read(path.c_str()));
oxRequireM(buff, romFs->read(path));
oxRequireM(obj, ox::readClaw(ts, buff));
if (obj.type()->preloadable) {
// 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
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 {};
}
// claw file transformations are broken out because path to inode
// 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
oxTracef("pack::preload", "path: {}", path);
oxRequire(fileList, romFs->ls(path));
for (const auto &name : fileList) {
const auto filePath = path + name;
oxRequire(stat, romFs->stat(filePath.c_str()));
const auto filePath = ox::sfmt("{}{}", path, name);
oxRequire(stat, romFs->stat(ox::StringView(filePath)));
if (stat.fileType == ox::FileType::Directory) {
const auto dir = path + name + '/';
const auto dir = ox::sfmt("{}{}/", path, name);
oxReturnError(preloadDir(ts, romFs, pl, dir));
} else {
oxReturnError(preloadObj(ts, romFs, pl, filePath));