Compare commits

..

21 Commits

Author SHA1 Message Date
92d85d1145 Merge commit '9f5f3e26efed6cd27f2a8ff0746f018d75986934'
All checks were successful
Build / build (push) Successful in 2m35s
2024-09-17 23:56:31 -05:00
118fef617f [buildcore] Remove python -m prefix from mypy command 2024-09-17 23:55:15 -05:00
8769305d12 [nostalgia] Allow disabling of BUILD_SHARED_LIBS 2024-09-17 23:51:37 -05:00
c599905000 [nostalgia] Add support for partial tilesheet loading 2024-09-17 23:50:13 -05:00
da23c9304d [ox/std] Add oxModelFwdDecl macro for broken Apple Clang 2024-09-17 23:49:04 -05:00
3ae1d6c897 [ox/std] Make operator[] in Array and Vector nodiscard 2024-09-14 23:45:33 -05:00
a7af6c6660 [keel] Cleanup 2024-09-14 22:35:42 -05:00
0cc6757c57 [keel] Add manifest to pack output 2024-09-14 20:47:54 -05:00
3b8eaef36b [keel] Move vald and repair funcs to their own file, make conversion to validation 2024-09-14 14:16:16 -05:00
b7990ed25b [keel] Make pack file copy logging nest for dir level 2024-09-14 02:52:38 -05:00
71313ed8f4 [ox/std] Cleanup 2024-09-14 02:30:22 -05:00
10531b6ea9 [keel] Cleanup 2024-09-13 23:55:23 -05:00
dfbc298d39 [keel] Add pack file copy status to logging 2024-09-13 23:53:07 -05:00
76760dafb6 [ox/std] Cleanup Defer 2024-09-13 23:51:58 -05:00
5834b9c98d [ox/std] Cleanup logging output 2024-09-13 23:32:42 -05:00
2a58490521 [ox/fs] More cleanup and bug fix from previous cleanup 2024-09-13 23:32:13 -05:00
702b166b8d [ox/fs] Cleanup 2024-09-13 00:17:07 -05:00
8dd837b359 [nostalgia/core] Add a valid function for CompactTileSheet 2024-09-07 23:20:04 -05:00
1d262597a8 [keel] Make default repair return a no repair error 2024-09-07 23:15:15 -05:00
712299faf3 [studio] Cleanup 2024-09-07 02:25:09 -05:00
c45efa6019 [ox/std] Make Result copyTo and moveTo able to convert 2024-09-07 02:24:52 -05:00
43 changed files with 556 additions and 353 deletions

1
.gitignore vendored
View File

@ -20,3 +20,4 @@ imgui.ini
*.sav *.sav
studio_state.json studio_state.json
tags tags
*-manifest.json

View File

@ -28,7 +28,7 @@ set(CMAKE_CXX_STANDARD 23)
if(APPLE) if(APPLE)
set(CMAKE_MACOSX_RPATH OFF) set(CMAKE_MACOSX_RPATH OFF)
else() else()
if(UNIX) if(UNIX AND NOT DEFINED BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS ON) set(BUILD_SHARED_LIBS ON)
endif() endif()
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib") set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")

View File

@ -44,6 +44,9 @@ ifdef BC_VAR_USE_DOCKER_DEVENV
exit 1 exit 1
endif endif
endif endif
ifndef BC_VAR_DEVENV_ROOT
BC_VAR_DEVENV_ROOT="."
endif
else else
BC_CMD_PY3=${BC_CMD_HOST_PY3} BC_CMD_PY3=${BC_CMD_HOST_PY3}
endif endif
@ -90,7 +93,7 @@ purge:
${BC_CMD_RM_RF} compile_commands.json ${BC_CMD_RM_RF} compile_commands.json
.PHONY: test .PHONY: test
test: build test: build
${BC_CMD_ENVRUN} ${BC_CMD_PY3} -m mypy ${BC_VAR_SCRIPTS} ${BC_CMD_ENVRUN} mypy ${BC_VAR_SCRIPTS}
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} test ${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} test
.PHONY: test-verbose .PHONY: test-verbose
test-verbose: build test-verbose: build
@ -102,7 +105,7 @@ test-rerun-verbose: build
ifdef BC_VAR_USE_DOCKER_DEVENV ifdef BC_VAR_USE_DOCKER_DEVENV
.PHONY: devenv-image .PHONY: devenv-image
devenv-image: devenv-image:
docker build . -t ${BC_VAR_DEVENV_IMAGE} docker build ${BC_VAR_DEVENV_ROOT} -t ${BC_VAR_DEVENV_IMAGE}
.PHONY: devenv-create .PHONY: devenv-create
devenv-create: devenv-create:
docker run -d \ docker run -d \

View File

@ -315,7 +315,7 @@ Error FileStoreTemplate<size_t>::remove(uint64_t id) {
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::read(uint64_t id, void *out, FsSize_t outSize, FsSize_t *size) const { Error FileStoreTemplate<size_t>::read(uint64_t id, void *out, FsSize_t outSize, FsSize_t *size) const {
oxTracef("ox.fs.FileStoreTemplate.read", "Attempting to read from inode {}", id); oxTracef("ox.fs.FileStoreTemplate.read", "Attempting to read inode {}", id);
auto src = find(static_cast<size_t>(id)); auto src = find(static_cast<size_t>(id));
// error check // error check
if (!src.valid()) { if (!src.valid()) {
@ -333,7 +333,7 @@ Error FileStoreTemplate<size_t>::read(uint64_t id, void *out, FsSize_t outSize,
oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not read data section of item: {}", id); oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not read data section of item: {}", id);
oxTracef("ox.fs.FileStoreTemplate.read.fail", oxTracef("ox.fs.FileStoreTemplate.read.fail",
"Item data section size: {}, Expected size: {}", srcData.size(), outSize); "Item data section size: {}, Expected size: {}", srcData.size(), outSize);
return OxError(1); return OxError(1, "Invalid inode");
} }
ox::memcpy(out, srcData, srcData.size()); ox::memcpy(out, srcData, srcData.size());
@ -341,7 +341,7 @@ Error FileStoreTemplate<size_t>::read(uint64_t id, void *out, FsSize_t outSize,
*size = src.size(); *size = src.size();
} }
return OxError(0); return {};
} }
template<typename size_t> template<typename size_t>

View File

@ -43,13 +43,15 @@ struct OX_PACKED DirectoryEntry {
public: public:
constexpr DirectoryEntry() noexcept = default; constexpr DirectoryEntry() noexcept = default;
Error init(InodeId_t inode, const char *name, InodeId_t bufferSize) noexcept { Error init(InodeId_t inode, ox::CRStringView name, size_t bufferSize) noexcept {
m_bufferSize = bufferSize; oxTracef("ox.fs.DirectoryEntry.init", "inode: {}, name: {}, bufferSize: {}", inode, name, bufferSize);
m_bufferSize = static_cast<InodeId_t>(bufferSize);
auto d = data(); auto d = data();
if (d.valid()) { if (d.valid()) {
d->inode = inode; d->inode = inode;
ox::strncpy(d->name, name, ox::min(bufferSize, static_cast<InodeId_t>(MaxFileNameLength))); auto const maxStrSz = bufferSize - 1 - sizeof(*this);
return OxError(0); ox::strncpy(d->name, name.data(), ox::min(maxStrSz, name.len()));
return {};
} }
return OxError(1); return OxError(1);
} }
@ -103,23 +105,23 @@ class Directory {
*/ */
Error init() noexcept; Error init() noexcept;
Error mkdir(PathIterator path, bool parents, FileName *nameBuff = nullptr); Error mkdir(PathIterator path, bool parents);
/** /**
* @param parents indicates the operation should create non-existent directories in the path, like mkdir -p * @param parents indicates the operation should create non-existent directories in the path, like mkdir -p
*/ */
Error write(PathIterator path, uint64_t inode64, FileName *nameBuff = nullptr) noexcept; Error write(PathIterator path, uint64_t inode64) noexcept;
Error remove(PathIterator path, FileName *nameBuff = nullptr) noexcept; Error remove(PathIterator path) noexcept;
template<typename F> template<typename F>
Error ls(F cb) noexcept; Error ls(F cb) noexcept;
[[nodiscard]] [[nodiscard]]
Result<typename FileStore::InodeId_t> findEntry(const FileName &name) const noexcept; Result<typename FileStore::InodeId_t> findEntry(const StringView &name) const noexcept;
[[nodiscard]] [[nodiscard]]
Result<typename FileStore::InodeId_t> find(PathIterator name, FileName *nameBuff = nullptr) const noexcept; Result<typename FileStore::InodeId_t> find(PathIterator path) const noexcept;
}; };
@ -145,22 +147,17 @@ Error Directory<FileStore, InodeId_t>::init() noexcept {
} }
new (buff) Buffer(Size); new (buff) Buffer(Size);
m_size = Size; m_size = Size;
return OxError(0); return {};
} }
template<typename FileStore, typename InodeId_t> template<typename FileStore, typename InodeId_t>
Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, FileName *nameBuff) { Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents) {
if (path.valid()) { if (path.valid()) {
oxTrace("ox.fs.Directory.mkdir", path.fullPath()); oxTrace("ox.fs.Directory.mkdir", path.fullPath());
// reuse nameBuff if it has already been allocated, as it is a rather large variable
if (nameBuff == nullptr) {
nameBuff = new (ox_alloca(sizeof(FileName))) FileName;
}
// determine if already exists // determine if already exists
auto name = nameBuff; ox::StringView name;
oxReturnError(path.get(*name)); oxReturnError(path.get(name));
auto childInode = find(PathIterator(*name)); auto childInode = find(PathIterator(name));
if (!childInode.ok()) { if (!childInode.ok()) {
// if this is not the last item in the path and parents is disabled, // if this is not the last item in the path and parents is disabled,
// return an error // return an error
@ -171,12 +168,10 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
oxTracef("ox.fs.Directory.mkdir", "Generated Inode ID: {}", childInode.value); oxTracef("ox.fs.Directory.mkdir", "Generated Inode ID: {}", childInode.value);
oxLogError(childInode.error); oxLogError(childInode.error);
oxReturnError(childInode.error); oxReturnError(childInode.error);
// initialize the directory // initialize the directory
Directory<FileStore, InodeId_t> child(m_fs, childInode.value); Directory<FileStore, InodeId_t> child(m_fs, childInode.value);
oxReturnError(child.init()); oxReturnError(child.init());
auto err = write(PathIterator(name), childInode.value);
auto err = write(PathIterator(*name), childInode.value);
if (err) { if (err) {
oxLogError(err); oxLogError(err);
// could not index the directory, delete it // could not index the directory, delete it
@ -184,46 +179,35 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
return err; return err;
} }
} }
Directory<FileStore, InodeId_t> child(m_fs, childInode.value); Directory<FileStore, InodeId_t> child(m_fs, childInode.value);
if (path.hasNext()) { if (path.hasNext()) {
oxReturnError(child.mkdir(path.next(), parents, nameBuff)); oxReturnError(child.mkdir(path.next(), parents));
} }
} }
return OxError(0); return {};
} }
template<typename FileStore, typename InodeId_t> template<typename FileStore, typename InodeId_t>
Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64, FileName *nameBuff) noexcept { Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64) noexcept {
const auto inode = static_cast<InodeId_t>(inode64); const auto inode = static_cast<InodeId_t>(inode64);
// reuse nameBuff if it has already been allocated, as it is a rather large variable ox::StringView name;
if (nameBuff == nullptr) {
nameBuff = new (ox_alloca(sizeof(FileName))) FileName;
}
auto name = nameBuff;
if (path.next().hasNext()) { // not yet at target directory, recurse to next one if (path.next().hasNext()) { // not yet at target directory, recurse to next one
oxReturnError(path.get(*name));
oxTracef("ox.fs.Directory.write", "Attempting to write to next sub-Directory: {} of {}", oxTracef("ox.fs.Directory.write", "Attempting to write to next sub-Directory: {} of {}",
*name, path.fullPath()); name, path.fullPath());
oxRequire(nextChild, findEntry(*name)); oxReturnError(path.get(name));
oxTracef("ox.fs.Directory.write", "{}: {}", *name, nextChild); oxRequire(nextChild, findEntry(name));
oxTracef("ox.fs.Directory.write", "{}: {}", name, nextChild);
if (nextChild) { if (nextChild) {
// reuse name because it is a rather large variable and will not be used again return Directory(m_fs, nextChild).write(path.next(), inode);
// be attentive that this remains true
name = nullptr;
return Directory(m_fs, nextChild).write(path.next(), inode, nameBuff);
} else { } else {
oxTracef("ox.fs.Directory.write", "{} not found and not allowed to create it.", *name); oxTracef("ox.fs.Directory.write", "{} not found and not allowed to create it.", name);
return OxError(1, "File not found and not allowed to create it."); return OxError(1, "File not found and not allowed to create it.");
} }
} else { } else {
oxTrace("ox.fs.Directory.write", path.fullPath()); oxTrace("ox.fs.Directory.write", path.fullPath());
oxReturnError(path.next(name));
// insert the new entry on this directory // insert the new entry on this directory
// get the name // get the name
oxReturnError(path.next(*name));
// find existing version of directory // find existing version of directory
oxTracef("ox.fs.Directory.write", "Searching for directory inode {}", m_inodeId); oxTracef("ox.fs.Directory.write", "Searching for directory inode {}", m_inodeId);
oxRequire(oldStat, m_fs.stat(m_inodeId)); oxRequire(oldStat, m_fs.stat(m_inodeId));
@ -233,8 +217,7 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64
oxTrace("ox.fs.Directory.write.fail", "Could not read existing version of Directory"); oxTrace("ox.fs.Directory.write.fail", "Could not read existing version of Directory");
return OxError(1, "Could not read existing version of Directory"); return OxError(1, "Could not read existing version of Directory");
} }
const auto pathSize = name.len() + 1;
const auto pathSize = name->len() + 1;
const auto entryDataSize = DirectoryEntry<InodeId_t>::DirectoryEntryData::spaceNeeded(pathSize); const auto entryDataSize = DirectoryEntry<InodeId_t>::DirectoryEntryData::spaceNeeded(pathSize);
const auto newSize = oldStat.size + Buffer::spaceNeeded(entryDataSize); const auto newSize = oldStat.size + Buffer::spaceNeeded(entryDataSize);
auto cpy = ox_malloca(newSize, Buffer, *old, oldStat.size); auto cpy = ox_malloca(newSize, Buffer, *old, oldStat.size);
@ -242,29 +225,22 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64
oxTrace("ox.fs.Directory.write.fail", "Could not allocate memory for copy of Directory"); oxTrace("ox.fs.Directory.write.fail", "Could not allocate memory for copy of Directory");
return OxError(1, "Could not allocate memory for copy of Directory"); return OxError(1, "Could not allocate memory for copy of Directory");
} }
oxReturnError(cpy->setSize(newSize)); oxReturnError(cpy->setSize(newSize));
auto val = cpy->malloc(entryDataSize).value; auto val = cpy->malloc(entryDataSize).value;
if (!val.valid()) { if (!val.valid()) {
oxTrace("ox.fs.Directory.write.fail", "Could not allocate memory for new directory entry"); oxTrace("ox.fs.Directory.write.fail", "Could not allocate memory for new directory entry");
return OxError(1, "Could not allocate memory for new directory entry"); return OxError(1, "Could not allocate memory for new directory entry");
} }
oxTracef("ox.fs.Directory.write", "Attempting to write Directory entry: {}", name);
oxTracef("ox.fs.Directory.write", "Attempting to write Directory entry: {}", name->data()); oxReturnError(val->init(inode, name, val.size()));
oxReturnError(val->init(inode, name->data(), val.size()));
return m_fs.write(m_inodeId, cpy.get(), cpy->size(), static_cast<uint8_t>(FileType::Directory)); return m_fs.write(m_inodeId, cpy.get(), cpy->size(), static_cast<uint8_t>(FileType::Directory));
} }
} }
template<typename FileStore, typename InodeId_t> template<typename FileStore, typename InodeId_t>
Error Directory<FileStore, InodeId_t>::remove(PathIterator path, FileName *nameBuff) noexcept { Error Directory<FileStore, InodeId_t>::remove(PathIterator path) noexcept {
// reuse nameBuff if it has already been allocated, as it is a rather large variable ox::StringView name;
if (nameBuff == nullptr) {
nameBuff = new (ox_alloca(sizeof(FileName))) FileName;
}
auto &name = *nameBuff;
oxReturnError(path.get(name)); oxReturnError(path.get(name));
oxTrace("ox.fs.Directory.remove", name); oxTrace("ox.fs.Directory.remove", name);
auto buff = m_fs.read(m_inodeId).template to<Buffer>(); auto buff = m_fs.read(m_inodeId).template to<Buffer>();
if (buff.valid()) { if (buff.valid()) {
@ -283,7 +259,7 @@ Error Directory<FileStore, InodeId_t>::remove(PathIterator path, FileName *nameB
oxTrace("ox.fs.Directory.remove.fail", "Could not find directory buffer"); oxTrace("ox.fs.Directory.remove.fail", "Could not find directory buffer");
return OxError(1, "Could not find directory buffer"); return OxError(1, "Could not find directory buffer");
} }
return OxError(0); return {};
} }
template<typename FileStore, typename InodeId_t> template<typename FileStore, typename InodeId_t>
@ -295,7 +271,6 @@ Error Directory<FileStore, InodeId_t>::ls(F cb) noexcept {
oxTrace("ox.fs.Directory.ls.fail", "Could not directory buffer"); oxTrace("ox.fs.Directory.ls.fail", "Could not directory buffer");
return OxError(1, "Could not directory buffer"); return OxError(1, "Could not directory buffer");
} }
oxTrace("ox.fs.Directory.ls", "Found directory buffer."); oxTrace("ox.fs.Directory.ls", "Found directory buffer.");
for (auto i = buff->iterator(); i.valid(); i.next()) { for (auto i = buff->iterator(); i.valid(); i.next()) {
auto data = i->data(); auto data = i->data();
@ -305,12 +280,11 @@ Error Directory<FileStore, InodeId_t>::ls(F cb) noexcept {
oxTrace("ox.fs.Directory.ls", "INVALID DIRECTORY ENTRY"); oxTrace("ox.fs.Directory.ls", "INVALID DIRECTORY ENTRY");
} }
} }
return {};
return OxError(0);
} }
template<typename FileStore, typename InodeId_t> template<typename FileStore, typename InodeId_t>
Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry(const FileName &name) const noexcept { Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry(CRStringView name) const noexcept {
oxTrace("ox.fs.Directory.findEntry", name); oxTrace("ox.fs.Directory.findEntry", name);
auto buff = m_fs.read(m_inodeId).template to<Buffer>(); auto buff = m_fs.read(m_inodeId).template to<Buffer>();
if (!buff.valid()) { if (!buff.valid()) {
@ -327,7 +301,7 @@ Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry
return static_cast<InodeId_t>(data->inode); return static_cast<InodeId_t>(data->inode);
} }
} else { } else {
oxTrace("ox.fs.Directory.findEntry") << "INVALID DIRECTORY ENTRY"; oxTrace("ox.fs.Directory.findEntry", "INVALID DIRECTORY ENTRY");
} }
} }
oxTrace("ox.fs.Directory.findEntry.fail", "Entry not present"); oxTrace("ox.fs.Directory.findEntry.fail", "Entry not present");
@ -335,22 +309,15 @@ Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry
} }
template<typename FileStore, typename InodeId_t> template<typename FileStore, typename InodeId_t>
Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::find(PathIterator path, FileName *nameBuff) const noexcept { Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::find(PathIterator path) const noexcept {
// reuse nameBuff if it has already been allocated, as it is a rather large variable
if (nameBuff == nullptr) {
nameBuff = new (ox_alloca(sizeof(FileName))) FileName;
}
// determine if already exists // determine if already exists
auto name = nameBuff; ox::StringView name;
oxReturnError(path.get(*name)); oxReturnError(path.get(name));
oxRequire(v, findEntry(name));
oxRequire(v, findEntry(*name));
// recurse if not at end of path // recurse if not at end of path
if (auto p = path.next(); p.valid()) { if (auto p = path.next(); p.valid()) {
Directory dir(m_fs, v); Directory dir(m_fs, v);
name = nullptr; return dir.find(p);
return dir.find(p, nameBuff);
} }
return v; return v;
} }

View File

@ -323,6 +323,7 @@ Error FileSystemTemplate<FileStore, Directory>::move(CRStringView src, CRStringV
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::readFilePath(CRStringView path, void *buffer, std::size_t buffSize) noexcept { Error FileSystemTemplate<FileStore, Directory>::readFilePath(CRStringView path, void *buffer, std::size_t buffSize) noexcept {
oxTrace("ox.fs.FileSystemTemplate.readFilePath", path);
oxRequire(fd, fileSystemData()); oxRequire(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode); Directory rootDir(m_fs, fd.rootDirInode);
oxRequire(s, stat(path)); oxRequire(s, stat(path));
@ -342,6 +343,7 @@ Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessPath(C
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::readFileInode(uint64_t inode, void *buffer, std::size_t buffSize) noexcept { Error FileSystemTemplate<FileStore, Directory>::readFileInode(uint64_t inode, void *buffer, std::size_t buffSize) noexcept {
oxTracef("ox.fs.FileSystemTemplate.readFileInode", "{}", inode);
oxRequire(s, stat(inode)); oxRequire(s, stat(inode));
if (s.size > buffSize) { if (s.size > buffSize) {
return OxError(1, "Buffer to small to load file"); return OxError(1, "Buffer to small to load file");
@ -409,24 +411,29 @@ Error FileSystemTemplate<FileStore, Directory>::resize() noexcept {
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::resize(uint64_t size, void *buffer) noexcept { Error FileSystemTemplate<FileStore, Directory>::resize(uint64_t size, void *buffer) noexcept {
oxReturnError(m_fs.resize(static_cast<size_t>(size), buffer)); oxReturnError(m_fs.resize(static_cast<size_t>(size), buffer));
return OxError(0); return {};
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::writeFilePath(CRStringView path, const void *buffer, uint64_t size, FileType fileType) noexcept { Error FileSystemTemplate<FileStore, Directory>::writeFilePath(
CRStringView path,
const void *buffer,
uint64_t size,
FileType fileType) noexcept {
oxTrace("ox.fs.FileSystemTemplate.writeFilePath", path);
auto [inode, err] = find(path); auto [inode, err] = find(path);
if (err) { if (err) {
oxRequire(generatedId, m_fs.generateInodeId()); oxReturnError(m_fs.generateInodeId().moveTo(inode));
inode = generatedId;
oxRequireM(rootDir, this->rootDir()); oxRequireM(rootDir, this->rootDir());
oxReturnError(rootDir.write(path, inode)); oxReturnError(rootDir.write(path, inode));
} }
oxReturnError(writeFileInode(inode, buffer, size, fileType)); oxReturnError(writeFileInode(inode, buffer, size, fileType));
return OxError(0); return {};
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept { Error FileSystemTemplate<FileStore, Directory>::writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept {
oxTrace("ox.fs.FileSystemTemplate.writeFileInode", ox::itoa(inode));
return m_fs.write(inode, buffer, static_cast<size_t>(size), static_cast<uint8_t>(fileType)); return m_fs.write(inode, buffer, static_cast<size_t>(size), static_cast<uint8_t>(fileType));
} }

View File

@ -100,7 +100,6 @@ Result<FileStat> PassThroughFS::statPath(CRStringView path) const noexcept {
FileType::Directory : FileType::NormalFile; FileType::Directory : FileType::NormalFile;
oxTracef("ox.fs.PassThroughFS.statInode", "{} {}", ec.message(), path); oxTracef("ox.fs.PassThroughFS.statInode", "{} {}", ec.message(), path);
const uint64_t size = type == FileType::Directory ? 0 : std::filesystem::file_size(p, ec); const uint64_t size = type == FileType::Directory ? 0 : std::filesystem::file_size(p, ec);
oxTracef("ox.fs.PassThroughFS.statInode", "{} {}", ec.message(), path);
oxTracef("ox.fs.PassThroughFS.statInode.size", "{} {}", path, size); oxTracef("ox.fs.PassThroughFS.statInode.size", "{} {}", path, size);
oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: stat failed")); oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: stat failed"));
return FileStat{0, 0, size, type}; return FileStat{0, 0, size, type};

View File

@ -40,30 +40,9 @@ Error PathIterator::dirPath(char *out, std::size_t outSize) {
} }
} }
/**
* @return 0 if no error
*/
Error PathIterator::fileName(char *out, std::size_t outSize) {
auto idx = ox::lastIndexOf(m_path, '/', m_maxSize);
if (idx >= 0) {
idx++; // pass up the preceding /
std::size_t fileNameSize = static_cast<size_t>(ox::strlen(&m_path[idx]));
if (fileNameSize < outSize) {
ox::memcpy(out, &m_path[idx], fileNameSize);
out[fileNameSize] = 0;
return OxError(0);
} else {
return OxError(1);
}
} else {
return OxError(2);
}
}
// Gets the get item in the path // Gets the get item in the path
Error PathIterator::get(IString<MaxFileNameLength> &fileName) { Error PathIterator::get(StringView &fileName) {
std::size_t size = 0; std::size_t size = 0;
std::ignore = fileName.resize(MaxFileNameLength);
if (m_iterator >= m_maxSize) { if (m_iterator >= m_maxSize) {
oxTracef("ox.fs.PathIterator.get", "m_iterator ({}) >= m_maxSize ({})", m_iterator, m_maxSize); oxTracef("ox.fs.PathIterator.get", "m_iterator ({}) >= m_maxSize ({})", m_iterator, m_maxSize);
return OxError(1); return OxError(1);
@ -88,22 +67,21 @@ Error PathIterator::get(IString<MaxFileNameLength> &fileName) {
if (size >= MaxFileNameLength || size == 0) { if (size >= MaxFileNameLength || size == 0) {
return OxError(1); return OxError(1);
} }
ox::memcpy(fileName.data(), &m_path[start], size); fileName = ox::substr(m_path, start, start + size);
// truncate trailing / // truncate trailing /
if (size && fileName[size - 1] == '/') { if (size && fileName[size - 1] == '/') {
size--; fileName = ox::substr(m_path, start, start + size - 1);
} }
oxReturnError(fileName.resize(size)); oxAssert(fileName[fileName.len()-1] != '/', "name ends in /");
return {}; return {};
} }
/** /**
* @return 0 if no error * @return 0 if no error
*/ */
Error PathIterator::next(IString<MaxFileNameLength> &fileName) { Error PathIterator::next(StringView &fileName) {
std::size_t size = 0; std::size_t size = 0;
auto retval = OxError(1); auto retval = OxError(1);
std::ignore = fileName.resize(MaxFileNameLength);
if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) { if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) {
retval = OxError(0); retval = OxError(0);
if (m_path[m_iterator] == '/') { if (m_path[m_iterator] == '/') {
@ -122,15 +100,14 @@ Error PathIterator::next(IString<MaxFileNameLength> &fileName) {
if (size >= MaxFileNameLength) { if (size >= MaxFileNameLength) {
return OxError(1); return OxError(1);
} }
ox::memcpy(fileName.data(), &m_path[start], size); fileName = ox::substr(m_path, start, start + size);
}
// truncate trailing / // truncate trailing /
if (size && fileName[size - 1] == '/') { while (fileName.len() && fileName[fileName.len() - 1] == '/') {
size--; fileName = ox::substr(m_path, start, start + size);
} }
fileName[size] = 0; // end with null terminator
oxReturnError(fileName.resize(size));
m_iterator += size; m_iterator += size;
oxAssert(fileName.len() == 0 || fileName[fileName.len()-1] != '/', "name ends in /");
}
return retval; return retval;
} }

View File

@ -13,7 +13,6 @@
namespace ox { namespace ox {
constexpr std::size_t MaxFileNameLength = 255; constexpr std::size_t MaxFileNameLength = 255;
using FileName = IString<MaxFileNameLength>;
class PathIterator { class PathIterator {
private: private:
@ -28,29 +27,12 @@ class PathIterator {
PathIterator(CRStringView path); PathIterator(CRStringView path);
/**
* @return 0 if no error
*/
Error dirPath(char *pathOut, std::size_t pathOutSize); Error dirPath(char *pathOut, std::size_t pathOutSize);
/** Error next(StringView &fileName);
* @return 0 if no error
*/
Error fileName(char *out, std::size_t outSize);
/** Error get(StringView &fileName);
* @return 0 if no error
*/
Error next(FileName &fileName);
/**
* @return 0 if no error
*/
Error get(FileName &fileName);
/**
* @return 0 if no error
*/
Result<std::size_t> nextSize() const; Result<std::size_t> nextSize() const;
[[nodiscard]] [[nodiscard]]

View File

@ -174,7 +174,7 @@ template<typename size_t, typename Item>
NodeBuffer<size_t, Item>::NodeBuffer(std::size_t size) noexcept { NodeBuffer<size_t, Item>::NodeBuffer(std::size_t size) noexcept {
m_header.size = static_cast<size_t>(size); m_header.size = static_cast<size_t>(size);
ox::memset(this + 1, 0, size - sizeof(*this)); ox::memset(this + 1, 0, size - sizeof(*this));
oxTracef("ox.NodeBuffer.constructor", "{}", m_header.firstItem.get()); oxTracef("ox.ptrarith.NodeBuffer.constructor", "{}", m_header.firstItem.get());
} }
template<typename size_t, typename Item> template<typename size_t, typename Item>

View File

@ -224,7 +224,7 @@ constexpr const Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(s
template<typename T, typename size_t, size_t minOffset> template<typename T, typename size_t, size_t minOffset>
template<typename SubT> template<typename SubT>
constexpr const Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) const noexcept { constexpr const Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) const noexcept {
oxTracef("ox.fs.Ptr.subPtr", "{} {} {} {} {}", m_itemOffset, this->size(), offset, m_itemSize, (m_itemSize - offset)); oxTracef("ox.ptrarith.Ptr.subPtr", "{} {} {} {} {}", m_itemOffset, this->size(), offset, m_itemSize, (m_itemSize - offset));
return subPtr<SubT>(offset, m_itemSize - offset); return subPtr<SubT>(offset, m_itemSize - offset);
} }
@ -237,7 +237,7 @@ constexpr Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t
template<typename T, typename size_t, size_t minOffset> template<typename T, typename size_t, size_t minOffset>
template<typename SubT> template<typename SubT>
constexpr Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) noexcept { constexpr Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) noexcept {
oxTracef("ox.fs.Ptr.subPtr", "{} {} {} {} {}", m_itemOffset, this->size(), offset, m_itemSize, (m_itemSize - offset)); oxTracef("ox.ptrarith.Ptr.subPtr", "{} {} {} {} {}", m_itemOffset, this->size(), offset, m_itemSize, (m_itemSize - offset));
return subPtr<SubT>(offset, m_itemSize - offset); return subPtr<SubT>(offset, m_itemSize - offset);
} }

View File

@ -19,7 +19,6 @@ add_test("[ox/fs] PathIterator::next5" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests
add_test("[ox/fs] PathIterator::hasNext" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::hasNext) add_test("[ox/fs] PathIterator::hasNext" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::hasNext)
add_test("[ox/fs] PathIterator::dirPath" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::dirPath) add_test("[ox/fs] PathIterator::dirPath" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::dirPath)
add_test("[ox/fs] PathIterator::fileName" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::fileName)
add_test("[ox/fs] NodeBuffer::insert" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests "NodeBuffer::insert") add_test("[ox/fs] NodeBuffer::insert" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests "NodeBuffer::insert")
add_test("[ox/fs] FileStore::readWrite" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests "FileStore::readWrite") add_test("[ox/fs] FileStore::readWrite" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests "FileStore::readWrite")

View File

@ -58,9 +58,9 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
{ {
"PathIterator::next1", "PathIterator::next1",
[](ox::StringView) { [](ox::StringView) {
auto const path = ox::String("/usr/share/charset.gbag"); auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
ox::FileName buff; ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "charset.gbag", "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "charset.gbag", "PathIterator shows wrong next");
@ -70,11 +70,13 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
{ {
"PathIterator::next2", "PathIterator::next2",
[](ox::StringView) { [](ox::StringView) {
auto const path = ox::String("/usr/share/"); auto constexpr path = ox::StringView("/usr/share/");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path);
ox::FileName buff; ox::StringView buff;
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff), "PathIterator::next returned error");
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next"); oxExpect(buff, "usr");
oxAssert(it.next(buff), "PathIterator::next returned error");
oxExpect(buff, "share");
return OxError(0); return OxError(0);
} }
}, },
@ -83,20 +85,20 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
[](ox::StringView) { [](ox::StringView) {
auto const path = ox::String("/"); auto const path = ox::String("/");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
ox::FileName buff; ox::StringView buff;
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "\0") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "\0", "PathIterator shows wrong next");
return OxError(0); return OxError(0);
} }
}, },
{ {
"PathIterator::next4", "PathIterator::next4",
[](ox::StringView) { [](ox::StringView) {
auto const path = ox::String("usr/share/charset.gbag"); auto constexpr path = ox::StringLiteral("usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path);
ox::FileName buff; ox::StringView buff;
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "charset.gbag", "PathIterator shows wrong next");
return OxError(0); return OxError(0);
} }
}, },
@ -105,32 +107,22 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
[](ox::StringView) { [](ox::StringView) {
auto const path = ox::String("usr/share/"); auto const path = ox::String("usr/share/");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
ox::FileName buff; ox::StringView buff;
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
return OxError(0); return OxError(0);
} }
}, },
{ {
"PathIterator::dirPath", "PathIterator::dirPath",
[] (ox::StringView) { [] (ox::StringView) {
auto const path = ox::String("/usr/share/charset.gbag"); auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.dirPath(buff, path.len()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path"); oxAssert(it.dirPath(buff, path.len()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
return OxError(0); return OxError(0);
} }
}, },
{
"PathIterator::fileName",
[](ox::StringView) {
auto const path = ox::String("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.fileName(buff, path.len()) == 0 && ox::strcmp(buff, "charset.gbag") == 0, "PathIterator shows incorrect file name");
return OxError(0);
}
},
{ {
"PathIterator::hasNext", "PathIterator::hasNext",
[](ox::StringView) { [](ox::StringView) {
@ -221,7 +213,6 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
oxTrace("ox.fs.test.FileSystem") << "format"; oxTrace("ox.fs.test.FileSystem") << "format";
oxAssert(ox::FileSystem32::format(fsBuff.data(), fsBuff.size()), "FileSystem format failed"); oxAssert(ox::FileSystem32::format(fsBuff.data(), fsBuff.size()), "FileSystem format failed");
ox::FileSystem32 fs(ox::FileStore32(fsBuff.data(), fsBuff.size())); ox::FileSystem32 fs(ox::FileStore32(fsBuff.data(), fsBuff.size()));
oxTrace("ox.fs.test.FileSystem") << "mkdir"; oxTrace("ox.fs.test.FileSystem") << "mkdir";
oxAssert(fs.mkdir("/dir", true), "mkdir failed"); oxAssert(fs.mkdir("/dir", true), "mkdir failed");
oxAssert(fs.stat("/dir").error, "mkdir failed"); oxAssert(fs.stat("/dir").error, "mkdir failed");
@ -229,7 +220,6 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
oxAssert(fs.stat("/l1d1/l2d1/l3d1").error, "mkdir failed"); oxAssert(fs.stat("/l1d1/l2d1/l3d1").error, "mkdir failed");
oxAssert(fs.mkdir("/l1d1/l2d2", true), "mkdir failed"); oxAssert(fs.mkdir("/l1d1/l2d2", true), "mkdir failed");
oxAssert(fs.stat("/l1d1/l2d2").error, "mkdir failed"); oxAssert(fs.stat("/l1d1/l2d2").error, "mkdir failed");
return OxError(0); return OxError(0);
} }
}, },

View File

@ -10,8 +10,10 @@
#include <ox/std/concepts.hpp> #include <ox/std/concepts.hpp>
// oxModelFwdDecl is necessary because Apple-Clang is broken...
#define oxModelFwdDecl(modelName) constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept
#define oxModelBegin(modelName) constexpr ox::Error model(auto *io, [[maybe_unused]] ox::CommonPtrWith<modelName> auto *o) noexcept { oxReturnError(io->template setTypeInfo<modelName>()); #define oxModelBegin(modelName) constexpr ox::Error model(auto *io, [[maybe_unused]] ox::CommonPtrWith<modelName> auto *o) noexcept { oxReturnError(io->template setTypeInfo<modelName>());
#define oxModelEnd() return OxError(0); } #define oxModelEnd() return OxError(0); }
#define oxModelField(fieldName) oxReturnError(io->field(#fieldName, &o->fieldName)); #define oxModelField(fieldName) oxReturnError(io->field(#fieldName, &o->fieldName));
#define oxModelFieldRename(objFieldName, serFieldName) oxReturnError(io->field(#serFieldName, &o->objFieldName)); #define oxModelFieldRename(objFieldName, serFieldName) oxReturnError(io->field(#serFieldName, &o->objFieldName));
#define oxModelFriend(modelName) friend constexpr ox::Error model(auto*, ox::CommonPtrWith<modelName> auto*) noexcept #define oxModelFriend(modelName) friend constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept

View File

@ -41,7 +41,7 @@ class Array {
constexpr Array(Array &&other) noexcept; constexpr Array(Array &&other) noexcept;
~Array() = default; constexpr ~Array() = default;
constexpr iterator<> begin() noexcept { constexpr iterator<> begin() noexcept {
return iterator<>(&m_items[0], 0, ArraySize); return iterator<>(&m_items[0], 0, ArraySize);
@ -81,8 +81,10 @@ class Array {
constexpr Array &operator=(Array &&other) noexcept; constexpr Array &operator=(Array &&other) noexcept;
[[nodiscard]]
constexpr T &operator[](std::size_t i) noexcept; constexpr T &operator[](std::size_t i) noexcept;
[[nodiscard]]
constexpr const T &operator[](std::size_t i) const noexcept; constexpr const T &operator[](std::size_t i) const noexcept;
[[nodiscard]] [[nodiscard]]

View File

@ -36,8 +36,8 @@ constexpr void assertFunc(CRStringView file, int line, bool pass, [[maybe_unused
if (!pass) { if (!pass) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg); auto output = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
printStackTrace(2); output += genStackTrace(2);
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line); oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
std::abort(); std::abort();
#else #else
@ -55,15 +55,16 @@ constexpr void assertFunc(CRStringView file, int line, const Error &err, CRStrin
if (err) { if (err) {
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
#if defined(OX_USE_STDLIB) #if defined(OX_USE_STDLIB)
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg); auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg);
if (err.msg) { if (err.msg) {
oxErrf("\tError Message:\t{}\n", err.msg); msg += sfmt("\tError Message:\t{}\n", err.msg);
} }
oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err)); msg += sfmt("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
if (err.file != nullptr) { if (err.file != nullptr) {
oxErrf("\tError Location:\t{}:{}\n", err.file, err.line); msg += sfmt("\tError Location:\t{}:{}\n", err.file, err.line);
} }
printStackTrace(2); msg += genStackTrace(2);
oxErr(msg);
oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line); oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line);
std::abort(); std::abort();
#else #else

View File

@ -8,8 +8,6 @@
#pragma once #pragma once
#include "error.hpp"
namespace ox { namespace ox {
template<typename T> template<typename T>
@ -18,13 +16,12 @@ class Defer {
T m_deferredFunc; T m_deferredFunc;
public: public:
Defer(T deferredFunc) { constexpr Defer(T deferredFunc) noexcept: m_deferredFunc(deferredFunc) {
m_deferredFunc = deferredFunc;
} }
Defer(const Defer&) = delete; Defer(const Defer&) = delete;
~Defer() { constexpr ~Defer() {
m_deferredFunc(); m_deferredFunc();
} }
@ -34,4 +31,4 @@ class Defer {
} }
#define oxDefer ox::Defer oxConcat(oxDefer_, __LINE__) = [&] #define oxDefer ox::Defer const oxConcat(oxDefer_, __LINE__) =

View File

@ -165,21 +165,24 @@ struct [[nodiscard]] Result {
return error == 0; return error == 0;
} }
constexpr Error copyTo(type &val) const& noexcept { template<typename U>
constexpr Error copyTo(U &val) const& noexcept {
if (!error) [[likely]] { if (!error) [[likely]] {
val = value; val = value;
} }
return error; return error;
} }
constexpr Error copyTo(type &val) && noexcept { template<typename U>
constexpr Error copyTo(U &val) && noexcept {
if (!error) [[likely]] { if (!error) [[likely]] {
val = std::move(value); val = std::move(value);
} }
return error; return error;
} }
constexpr Error moveTo(type &val) noexcept { template<typename U>
constexpr Error moveTo(U &val) noexcept {
if (!error) [[likely]] { if (!error) [[likely]] {
val = std::move(value); val = std::move(value);
} }

View File

@ -57,6 +57,28 @@ static auto symbolicate([[maybe_unused]]void **frames,
} }
#endif // defined(OX_USE_STDLIB) && __has_include(<unistd.h>) #endif // defined(OX_USE_STDLIB) && __has_include(<unistd.h>)
ox::String genStackTrace([[maybe_unused]]unsigned shave) noexcept {
ox::String out;
#if defined(OX_USE_STDLIB) && __has_include(<unistd.h>) && __has_include(<execinfo.h>)
constexpr auto FrameCnt = 100;
Vector<void*, FrameCnt> frames(FrameCnt);
#ifdef OX_OS_FreeBSD
using FrameCnt_t = unsigned;
#else
using FrameCnt_t = signed;
#endif
frames.resize(static_cast<std::size_t>(backtrace(frames.data(), static_cast<FrameCnt_t>(frames.size()))));
if (frames.size() - shave > 2) {
const auto symbolicatedStacktrace = symbolicate(frames.data() + shave, frames.size() - shave, "\t");
out+= "Stacktrace:\n";
for (const auto &s : symbolicatedStacktrace) {
out += sfmt("\t{}\n", s);
}
}
#endif
return out;
}
void printStackTrace([[maybe_unused]]unsigned shave) noexcept { void printStackTrace([[maybe_unused]]unsigned shave) noexcept {
#if defined(OX_USE_STDLIB) && __has_include(<unistd.h>) && __has_include(<execinfo.h>) #if defined(OX_USE_STDLIB) && __has_include(<unistd.h>) && __has_include(<execinfo.h>)
constexpr auto FrameCnt = 100; constexpr auto FrameCnt = 100;

View File

@ -8,8 +8,13 @@
#pragma once #pragma once
#include "string.hpp"
namespace ox { namespace ox {
[[nodiscard]]
ox::String genStackTrace([[maybe_unused]]unsigned shave) noexcept;
/** /**
* Prints a stack trace to stderr. * Prints a stack trace to stderr.
* *

View File

@ -65,23 +65,28 @@ void oxTraceInitHook() {
void oxTraceHook([[maybe_unused]] const char *file, [[maybe_unused]] int line, void oxTraceHook([[maybe_unused]] const char *file, [[maybe_unused]] int line,
[[maybe_unused]] const char *ch, [[maybe_unused]] const char *msg) { [[maybe_unused]] const char *ch, [[maybe_unused]] const char *msg) {
#if defined(OX_USE_STDLIB) #if defined(OX_USE_STDLIB)
auto const chv = ox::StringView{ch};
if (OxPrintTrace) { if (OxPrintTrace) {
auto m = std::string_view{msg};
if (m.ends_with('\n')) {
m = std::string_view{msg, m.size() - 1};
}
std::cout << std::setw(53) << std::left << ch << "| "; std::cout << std::setw(53) << std::left << ch << "| ";
std::cout << std::setw(65) << std::left << msg << '|'; std::cout << std::setw(65) << std::left << m << '|';
std::cout << " " << file << ':' << line << "\n"; std::cout << " " << file << ':' << line << "\n";
} else if (ox::strcmp(ch, "debug") == 0 || ox::strcmp(ch, "info") == 0) { } else if (chv == "debug" || chv == "info") {
printf("%s\n", msg); printf("%s\n", msg);
fflush(stdout); std::ignore = fflush(stdout);
} else if (ox::strcmp(ch, "stdout") == 0) { } else if (chv == "stdout") {
printf("%s", msg); printf("%s", msg);
fflush(stdout); std::ignore = fflush(stdout);
} else if (ox::strcmp(ch, "stderr") == 0) { } else if (chv == "stderr") {
printf("%s", msg); std::ignore = fprintf(stderr, "%s", msg);
fflush(stdout); std::ignore = fflush(stderr);
} else if (ox::strcmp(ch, "error") == 0) { } else if (chv == "error") {
//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); std::ignore = fprintf(stderr, "\033[31;1;1mERROR:\033[0m (%s:%d): %s\n", file, line, msg);
fflush(stderr); std::ignore = fflush(stderr);
} }
#else #else
if (ox::strcmp(ch, "info") == 0) { if (ox::strcmp(ch, "info") == 0) {

View File

@ -222,8 +222,10 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
constexpr Vector &operator=(Vector &&other) noexcept; constexpr Vector &operator=(Vector &&other) noexcept;
[[nodiscard]]
constexpr T &operator[](std::size_t i) noexcept; constexpr T &operator[](std::size_t i) noexcept;
[[nodiscard]]
constexpr const T &operator[](std::size_t i) const noexcept; constexpr const T &operator[](std::size_t i) const noexcept;
[[nodiscard]] [[nodiscard]]

View File

@ -28,8 +28,12 @@ project_name = sys.argv[2]
bin = f'./build/{host_env}-{current_build}/bin/' bin = f'./build/{host_env}-{current_build}/bin/'
project_bin = f'build/gba-release/bin/{project_name}.bin' project_bin = f'build/gba-release/bin/{project_name}.bin'
project_gba = f'{project_name}.gba' project_gba = f'{project_name}.gba'
project_manifest = f'{project_name}-manifest.json'
shutil.copyfile(project_bin, project_gba) shutil.copyfile(project_bin, project_gba)
subprocess.run([ subprocess.run([
f'{bin}/{project_name}-pack', '-src', project_dir, '-rom-bin', project_gba]) f'{bin}/{project_name}-pack',
'-src', project_dir,
'-rom-bin', project_gba,
'-manifest', project_manifest])
subprocess.run(['gbafix', project_gba]) subprocess.run(['gbafix', project_gba])

View File

@ -139,7 +139,15 @@ ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
CompactTileSheet const&ts, CompactTileSheet const&ts,
ox::Optional<unsigned> const&paletteBank) noexcept; size_t dstTileIdx,
size_t srcTileIdx,
size_t tileCnt) noexcept;
ox::Error loadBgTileSheet(
Context &ctx,
unsigned cbb,
CompactTileSheet const&ts,
ox::Optional<unsigned> const&paletteBank = {}) noexcept;
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,

View File

@ -31,6 +31,12 @@ struct TileSheetV1 {
ox::Vector<uint8_t> pixels = {}; ox::Vector<uint8_t> pixels = {};
}; };
[[nodiscard]]
constexpr bool valid(TileSheetV1 const&ts) noexcept {
return ts.bpp == 4 || ts.bpp == 8;
}
struct TileSheetV2 { struct TileSheetV2 {
using SubSheetIdx = ox::Vector<std::size_t, 4>; using SubSheetIdx = ox::Vector<std::size_t, 4>;
@ -43,8 +49,8 @@ struct TileSheetV2 {
ox::Vector<SubSheet> subsheets; ox::Vector<SubSheet> subsheets;
ox::Vector<uint8_t> pixels; ox::Vector<uint8_t> pixels;
constexpr SubSheet() noexcept = default; constexpr SubSheet() noexcept = default;
constexpr SubSheet(ox::CRStringView pName, int pColumns, int pRows, int bpp) noexcept: constexpr SubSheet(ox::StringParam pName, int pColumns, int pRows, int bpp) noexcept:
name(pName), name(std::move(pName)),
columns(pColumns), columns(pColumns),
rows(pRows), rows(pRows),
pixels(static_cast<size_t>(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) { pixels(static_cast<size_t>(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) {
@ -59,6 +65,12 @@ struct TileSheetV2 {
}; };
[[nodiscard]]
constexpr bool valid(TileSheetV2 const&ts) noexcept {
return ts.bpp == 4 || ts.bpp == 8;
}
using SubSheetId = int32_t; using SubSheetId = int32_t;
struct TileSheetV3 { struct TileSheetV3 {
@ -74,14 +86,14 @@ struct TileSheetV3 {
ox::Vector<SubSheet> subsheets; ox::Vector<SubSheet> subsheets;
ox::Vector<uint8_t> pixels; ox::Vector<uint8_t> pixels;
constexpr SubSheet() noexcept = default; constexpr SubSheet() noexcept = default;
inline SubSheet( SubSheet(
SubSheetId pId, SubSheetId pId,
ox::CRStringView pName, ox::StringParam pName,
int pColumns, int pColumns,
int pRows, int pRows,
int bpp) noexcept: int bpp) noexcept:
id(pId), id(pId),
name(pName), name(std::move(pName)),
columns(pColumns), columns(pColumns),
rows(pRows), rows(pRows),
pixels(static_cast<std::size_t>(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) { pixels(static_cast<std::size_t>(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) {
@ -98,7 +110,13 @@ struct TileSheetV3 {
}; };
struct TileSheet { [[nodiscard]]
constexpr bool valid(TileSheetV3 const&ts) noexcept {
return ts.bpp == 4 || ts.bpp == 8;
}
struct TileSheetV4 {
using SubSheetIdx = ox::Vector<std::size_t, 4>; using SubSheetIdx = ox::Vector<std::size_t, 4>;
struct SubSheet { struct SubSheet {
@ -112,26 +130,26 @@ struct TileSheet {
ox::Vector<uint8_t> pixels; ox::Vector<uint8_t> pixels;
constexpr SubSheet() noexcept = default; constexpr SubSheet() noexcept = default;
inline SubSheet( SubSheet(
SubSheetId pId, SubSheetId pId,
ox::CRStringView pName, ox::StringParam pName,
int pColumns, int pColumns,
int pRows, int pRows,
int bpp) noexcept: int bpp) noexcept:
id(pId), id(pId),
name(pName), name(std::move(pName)),
columns(pColumns), columns(pColumns),
rows(pRows), rows(pRows),
pixels(static_cast<std::size_t>(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) { pixels(static_cast<std::size_t>(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) {
} }
inline SubSheet( SubSheet(
SubSheetId pId, SubSheetId pId,
ox::CRStringView pName, ox::StringParam pName,
int pColumns, int pColumns,
int pRows, int pRows,
ox::Vector<uint8_t> pPixels) noexcept: ox::Vector<uint8_t> pPixels) noexcept:
id(pId), id(pId),
name(pName), name(std::move(pName)),
columns(pColumns), columns(pColumns),
rows(pRows), rows(pRows),
pixels(std::move(pPixels)) { pixels(std::move(pPixels)) {
@ -151,10 +169,18 @@ struct TileSheet {
ox::FileAddress defaultPalette; ox::FileAddress defaultPalette;
SubSheet subsheet{0, "Root", 1, 1, bpp}; SubSheet subsheet{0, "Root", 1, 1, bpp};
constexpr TileSheet() noexcept = default; constexpr TileSheetV4() noexcept = default;
}; };
[[nodiscard]]
constexpr bool valid(TileSheetV4 const&ts) noexcept {
return ts.bpp == 4 || ts.bpp == 8;
}
using TileSheet = TileSheetV4;
[[nodiscard]] [[nodiscard]]
std::size_t idx(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept; std::size_t idx(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
@ -286,12 +312,11 @@ ox::Result<unsigned> getTileOffset(TileSheet const&ts, ox::CRStringView pNamePat
ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const&ss, SubSheetId pId) noexcept; ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const&ss, SubSheetId pId) noexcept;
ox::Result<ox::StringView> getNameFor(TileSheet const&ss, SubSheetId pId) noexcept; ox::Result<ox::StringView> getNameFor(TileSheet const&ts, SubSheetId pId) noexcept;
[[nodiscard]] [[nodiscard]]
ox::Vector<uint8_t> pixels(TileSheet &ts) noexcept; ox::Vector<uint8_t> pixels(TileSheet &ts) noexcept;
using TileSheetV4 = TileSheet;
struct CompactTileSheetV1 { struct CompactTileSheetV1 {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.CompactTileSheet"; static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.CompactTileSheet";
@ -302,8 +327,34 @@ struct CompactTileSheetV1 {
ox::Vector<uint8_t> pixels; ox::Vector<uint8_t> pixels;
}; };
[[nodiscard]]
constexpr bool valid(CompactTileSheetV1 const&ts) noexcept {
return ts.bpp == 4 || ts.bpp == 8;
}
using CompactTileSheet = CompactTileSheetV1; using CompactTileSheet = CompactTileSheetV1;
[[nodiscard]]
uint8_t getPixel4Bpp(
CompactTileSheet const&ts,
size_t idx) noexcept;
[[nodiscard]]
uint8_t getPixel8Bpp(
CompactTileSheet const&ts,
size_t idx) noexcept;
[[nodiscard]]
ox::Pair<uint8_t> get2Pixels4Bpp(
CompactTileSheet const&ts,
size_t idx) noexcept;
[[nodiscard]]
ox::Pair<uint8_t> get2Pixels8Bpp(
CompactTileSheet const&ts,
size_t idx) noexcept;
oxModelBegin(TileSheetV1) oxModelBegin(TileSheetV1)
oxModelField(bpp) oxModelField(bpp)
oxModelField(rows) oxModelField(rows)

View File

@ -3,7 +3,6 @@
*/ */
#include <ox/fs/fs.hpp> #include <ox/fs/fs.hpp>
#include <ox/mc/mc.hpp>
#include <ox/std/array.hpp> #include <ox/std/array.hpp>
#include <teagba/addresses.hpp> #include <teagba/addresses.hpp>
@ -11,9 +10,7 @@
#include <teagba/registers.hpp> #include <teagba/registers.hpp>
#include <keel/keel.hpp> #include <keel/keel.hpp>
#include <turbine/turbine.hpp>
#include <nostalgia/core/color.hpp>
#include <nostalgia/core/context.hpp> #include <nostalgia/core/context.hpp>
#include <nostalgia/core/gfx.hpp> #include <nostalgia/core/gfx.hpp>
#include <nostalgia/core/tilesheet.hpp> #include <nostalgia/core/tilesheet.hpp>
@ -22,7 +19,7 @@
namespace nostalgia::core { namespace nostalgia::core {
constexpr auto SpriteCount = 128; static constexpr auto SpriteCount = 128;
ox::Error initGfx(Context&, InitParams const&) noexcept { ox::Error initGfx(Context&, InitParams const&) noexcept {
for (auto bgCtl = &REG_BG0CTL; bgCtl <= &REG_BG3CTL; bgCtl += 2) { for (auto bgCtl = &REG_BG0CTL; bgCtl <= &REG_BG3CTL; bgCtl += 2) {
@ -81,7 +78,7 @@ ox::Error loadSpritePalette(
static ox::Error loadTileSheetSet( static ox::Error loadTileSheetSet(
Context &ctx, Context &ctx,
uint16_t *tileMapTargetMem, ox::Span<uint16_t> tileMapTargetMem,
TileSheetSet const&set) noexcept { TileSheetSet const&set) noexcept {
size_t tileWriteIdx = 0; size_t tileWriteIdx = 0;
size_t const bppMod = set.bpp == 4; size_t const bppMod = set.bpp == 4;
@ -106,6 +103,34 @@ static ox::Error loadTileSheetSet(
return {}; return {};
} }
ox::Error loadBgTileSheet(
Context &ctx,
unsigned const cbb,
CompactTileSheet const&ts,
size_t const dstTileIdx,
size_t const srcTileIdx,
size_t const tileCnt) noexcept {
size_t const bppMod = ts.bpp == 4;
size_t const bytesPerTile = PixelsPerTile >> bppMod;
auto const pixCnt = tileCnt * bytesPerTile;
auto const srcPxIdx = srcTileIdx * bytesPerTile;
auto const dstPxIdx = (dstTileIdx * bytesPerTile) / 2;
for (size_t i = 0; i < pixCnt; ++i) {
auto const srcIdx = srcPxIdx + i * 2;
auto const p1 = static_cast<uint16_t>(ts.pixels[srcIdx]);
auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]);
MEM_BG_TILES[cbb][dstPxIdx + i] = static_cast<uint16_t>(p1 | (p2 << 8));
}
// update bpp of all bgs with the updated cbb
auto const bpp = ctx.cbbData[cbb].bpp;
teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) {
if (teagba::bgCbb(bgCtl) == cbb) {
teagba::bgSetBpp(bgCtl, bpp);
}
});
return {};
}
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned cbb,
@ -142,10 +167,10 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
unsigned cbb, unsigned const cbb,
TileSheetSet const&set) noexcept { TileSheetSet const&set) noexcept {
auto const bpp = static_cast<unsigned>(set.bpp); auto const bpp = static_cast<unsigned>(set.bpp);
oxReturnError(loadTileSheetSet(ctx, MEM_BG_TILES[cbb].data(), set)); oxReturnError(loadTileSheetSet(ctx, MEM_BG_TILES[cbb], set));
// update bpp of all bgs with the updated cbb // update bpp of all bgs with the updated cbb
ctx.cbbData[cbb].bpp = bpp; ctx.cbbData[cbb].bpp = bpp;
teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) { teagba::iterateBgCtl([bpp, cbb](volatile BgCtl &bgCtl) {
@ -193,7 +218,7 @@ ox::Error loadSpriteTileSheet(
Context &ctx, Context &ctx,
TileSheetSet const&set) noexcept { TileSheetSet const&set) noexcept {
auto const bpp = static_cast<unsigned>(set.bpp); auto const bpp = static_cast<unsigned>(set.bpp);
oxReturnError(loadTileSheetSet(ctx, MEM_SPRITE_TILES, set)); oxReturnError(loadTileSheetSet(ctx, {MEM_SPRITE_TILES, 32 * ox::units::KB}, set));
setSpritesBpp(bpp); setSpritesBpp(bpp);
return {}; return {};
} }

View File

@ -22,8 +22,8 @@ namespace nostalgia::core {
namespace renderer { namespace renderer {
constexpr auto Scale = 1; static constexpr auto Scale = 1;
constexpr auto PriorityScale = 0.01f; static constexpr auto PriorityScale = 0.01f;
Drawer::Drawer(Context &ctx) noexcept: m_ctx(ctx) {} Drawer::Drawer(Context &ctx) noexcept: m_ctx(ctx) {}
@ -31,7 +31,7 @@ void Drawer::draw(turbine::Context &tctx) noexcept {
core::gl::draw(m_ctx, turbine::getScreenSize(tctx)); core::gl::draw(m_ctx, turbine::getScreenSize(tctx));
} }
constexpr ox::CStringView bgvshadTmpl = R"glsl( static constexpr ox::CStringView bgvshadTmpl = R"glsl(
{} {}
in vec2 vTexCoord; in vec2 vTexCoord;
in vec3 vPosition; in vec3 vPosition;
@ -55,7 +55,7 @@ constexpr ox::CStringView bgvshadTmpl = R"glsl(
fPalOffset = vPalOffset; fPalOffset = vPalOffset;
})glsl"; })glsl";
constexpr ox::CStringView bgfshadTmpl = R"glsl( static constexpr ox::CStringView bgfshadTmpl = R"glsl(
{} {}
out vec4 outColor; out vec4 outColor;
in float fPalOffset; in float fPalOffset;
@ -71,7 +71,7 @@ constexpr ox::CStringView bgfshadTmpl = R"glsl(
} }
})glsl"; })glsl";
constexpr ox::CStringView spritevshadTmpl = R"glsl( static constexpr ox::CStringView spritevshadTmpl = R"glsl(
{} {}
in float vEnabled; in float vEnabled;
in vec3 vPosition; in vec3 vPosition;
@ -90,7 +90,7 @@ constexpr ox::CStringView spritevshadTmpl = R"glsl(
fTexCoord = vTexCoord * vec2(1, vTileHeight); fTexCoord = vTexCoord * vec2(1, vTileHeight);
})glsl"; })glsl";
constexpr ox::CStringView spritefshadTmpl = R"glsl( static constexpr ox::CStringView spritefshadTmpl = R"glsl(
{} {}
out vec4 outColor; out vec4 outColor;
in vec2 fTexCoord; in vec2 fTexCoord;
@ -279,7 +279,7 @@ static void initBackgroundBufferset(
static glutils::GLTexture createTexture( static glutils::GLTexture createTexture(
GLsizei w, GLsizei w,
GLsizei h, GLsizei h,
const void *pixels) noexcept { void const*pixels) noexcept {
GLuint texId = 0; GLuint texId = 0;
glGenTextures(1, &texId); glGenTextures(1, &texId);
glutils::GLTexture tex(texId); glutils::GLTexture tex(texId);
@ -492,22 +492,22 @@ struct TileSheetData {
}; };
static ox::Result<TileSheetData> normalizeTileSheet( static ox::Result<TileSheetData> normalizeTileSheet(
CompactTileSheet const&tilesheet) noexcept { CompactTileSheet const&ts) noexcept {
const uint_t bytesPerTile = tilesheet.bpp == 8 ? PixelsPerTile : PixelsPerTile / 2; const uint_t bytesPerTile = ts.bpp == 8 ? PixelsPerTile : PixelsPerTile / 2;
const auto tiles = tilesheet.pixels.size() / bytesPerTile; const auto tiles = ts.pixels.size() / bytesPerTile;
constexpr int width = 8; constexpr int width = 8;
const int height = 8 * static_cast<int>(tiles); const int height = 8 * static_cast<int>(tiles);
ox::Vector<uint32_t> pixels; ox::Vector<uint32_t> pixels;
if (bytesPerTile == 64) { // 8 BPP if (bytesPerTile == 64) { // 8 BPP
pixels.resize(tilesheet.pixels.size()); pixels.resize(ts.pixels.size());
for (std::size_t i = 0; i < tilesheet.pixels.size(); ++i) { for (std::size_t i = 0; i < ts.pixels.size(); ++i) {
pixels[i] = tilesheet.pixels[i]; pixels[i] = ts.pixels[i];
} }
} else { // 4 BPP } else { // 4 BPP
pixels.resize(tilesheet.pixels.size() * 2); pixels.resize(ts.pixels.size() * 2);
for (std::size_t i = 0; i < tilesheet.pixels.size(); ++i) { for (std::size_t i = 0; i < ts.pixels.size(); ++i) {
pixels[i * 2 + 0] = tilesheet.pixels[i] & 0xF; pixels[i * 2 + 0] = ts.pixels[i] & 0xF;
pixels[i * 2 + 1] = tilesheet.pixels[i] >> 4; pixels[i * 2 + 1] = ts.pixels[i] >> 4;
} }
} }
return TileSheetData{std::move(pixels), width, height}; return TileSheetData{std::move(pixels), width, height};
@ -572,14 +572,58 @@ static ox::Result<TileSheetData> buildSetTsd(
return setTsd; return setTsd;
} }
static void copyPixels(
CompactTileSheet const&ts,
uint32_t *dst,
size_t const srcPxIdx,
size_t pxlCnt) noexcept {
if (ts.bpp == 4) {
for (size_t i = 0; i < pxlCnt; i += 2) {
auto const [a, b] = get2Pixels4Bpp(ts, i + srcPxIdx);
*(dst++) = a;
*(dst++) = b;
}
} else if (ts.bpp == 8) {
for (size_t i = 0; i < pxlCnt; i += 2) {
auto const [a, b] = get2Pixels8Bpp(ts, i + srcPxIdx);
*(dst++) = a;
*(dst++) = b;
}
}
}
ox::Error loadBgTileSheet(
Context &ctx,
unsigned const cbb,
CompactTileSheet const&ts,
size_t const dstTileIdx,
size_t const srcTileIdx,
size_t const tileCnt) noexcept {
auto &cbbPxls = ctx.cbbs[cbb].pixels;
auto const bytesPerTile = static_cast<uint64_t>(PixelsPerTile / (1 + (ts.bpp == 4)));
auto const pxlCnt = tileCnt * PixelsPerTile;
auto const srcPxIdx = srcTileIdx * PixelsPerTile;
auto const dstPxIdx = dstTileIdx * PixelsPerTile;
if (dstPxIdx + pxlCnt >= cbbPxls.size()) {
return OxError(1, "video mem dst overflow");
}
auto const dst = &cbbPxls[dstPxIdx];
copyPixels(ts, dst, srcPxIdx, pxlCnt);
auto const cbbTiles = cbbPxls.size() / bytesPerTile;
int constexpr cbbWidth = 8;
int const cbbHeight = 8 * static_cast<int>(cbbTiles);
ctx.cbbs[cbb].tex = renderer::createTexture(cbbWidth, cbbHeight, cbbPxls.data());
return {};
}
ox::Error loadBgTileSheet( ox::Error loadBgTileSheet(
Context &ctx, Context &ctx,
uint_t cbb, uint_t cbb,
CompactTileSheet const&ts, CompactTileSheet const&ts,
ox::Optional<unsigned> const&paletteBank) noexcept { ox::Optional<unsigned> const&paletteBank) noexcept {
oxRequire(tsd, normalizeTileSheet(ts)); auto const bytesPerTile = static_cast<uint64_t>(PixelsPerTile / (1 + (ts.bpp == 4)));
oxTracef("nostalgia.core.gfx.gl", "loadBgTexture: { cbbIdx: {}, w: {}, h: {} }", cbb, tsd.width, tsd.height); auto const tiles = ts.pixels.size() / bytesPerTile;
ctx.cbbs[cbb].tex = renderer::createTexture(tsd.width, tsd.height, tsd.pixels.data()); oxReturnError(loadBgTileSheet(ctx, cbb, ts, 0, 0, tiles));
if (paletteBank.has_value() && ts.defaultPalette) { if (paletteBank.has_value() && ts.defaultPalette) {
oxReturnError(loadBgPalette(ctx, *paletteBank, ts.defaultPalette)); oxReturnError(loadBgPalette(ctx, *paletteBank, ts.defaultPalette));
} }

View File

@ -28,6 +28,7 @@ constexpr uint64_t SpriteVertexEboLength = 6;
struct CBB: public glutils::BufferSet { struct CBB: public glutils::BufferSet {
bool updated = false; bool updated = false;
ox::Array<uint32_t, 32768> pixels;
constexpr CBB() noexcept { constexpr CBB() noexcept {
vertices.resize(TileCount * BgVertexVboLength); vertices.resize(TileCount * BgVertexVboLength);
elements.resize(TileCount * BgVertexEboLength); elements.resize(TileCount * BgVertexEboLength);

View File

@ -10,6 +10,8 @@
namespace nostalgia::core { namespace nostalgia::core {
oxModelFwdDecl(class TileSheetClipboard);
class TileSheetClipboard: public turbine::ClipboardObject<TileSheetClipboard> { class TileSheetClipboard: public turbine::ClipboardObject<TileSheetClipboard> {
public: public:
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard"; static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard";

View File

@ -312,9 +312,8 @@ void TileSheetEditorImGui::drawSubsheetSelector(
for (auto i = 0ul; auto &child : subsheet.subsheets) { for (auto i = 0ul; auto &child : subsheet.subsheets) {
path.push_back(i); path.push_back(i);
ImGui::PushID(static_cast<int>(i)); ImGui::PushID(static_cast<int>(i));
ImGui::Indent(-indentReduce); ig::IndentStackItem const indentStackItem{-indentReduce};
drawSubsheetSelector(child, path); drawSubsheetSelector(child, path);
ImGui::Indent(indentReduce);
ImGui::PopID(); ImGui::PopID();
path.pop_back(); path.pop_back();
++i; ++i;
@ -440,7 +439,7 @@ void TileSheetEditorImGui::drawPaletteSelector() noexcept {
} }
auto const pages = m_model.pal().pages.size(); auto const pages = m_model.pal().pages.size();
if (pages > 1) { if (pages > 1) {
ImGui::Indent(20); ig::IndentStackItem const indentStackItem{20};
using Str = ox::IString<55>; using Str = ox::IString<55>;
auto numStr = ox::sfmt<Str>( auto numStr = ox::sfmt<Str>(
"{} - {}", m_model.palettePage() + 1, m_model.pal().pages[m_model.palettePage()].name); "{} - {}", m_model.palettePage() + 1, m_model.pal().pages[m_model.palettePage()].name);
@ -458,7 +457,6 @@ void TileSheetEditorImGui::drawPaletteSelector() noexcept {
} }
ImGui::EndCombo(); ImGui::EndCombo();
} }
ImGui::Indent(-20);
} }
// header // header
if (ImGui::BeginTable( if (ImGui::BeginTable(

View File

@ -280,7 +280,7 @@ uint8_t getPixel4Bpp(
TileSheet::SubSheetIdx const&subsheetIdx) noexcept { TileSheet::SubSheetIdx const&subsheetIdx) noexcept {
oxAssert(ts.bpp == 4, "TileSheet::getPixel4Bpp: wrong bpp"); oxAssert(ts.bpp == 4, "TileSheet::getPixel4Bpp: wrong bpp");
auto &s = getSubSheet(ts, subsheetIdx); auto &s = getSubSheet(ts, subsheetIdx);
const auto idx = ptToIdx(pt, s.columns); auto const idx = ptToIdx(pt, s.columns);
return getPixel4Bpp(s, idx); return getPixel4Bpp(s, idx);
} }
@ -290,10 +290,49 @@ uint8_t getPixel8Bpp(
TileSheet::SubSheetIdx const&subsheetIdx) noexcept { TileSheet::SubSheetIdx const&subsheetIdx) noexcept {
oxAssert(ts.bpp == 8, "TileSheet::getPixel8Bpp: wrong bpp"); oxAssert(ts.bpp == 8, "TileSheet::getPixel8Bpp: wrong bpp");
auto &s = getSubSheet(ts, subsheetIdx); auto &s = getSubSheet(ts, subsheetIdx);
const auto idx = ptToIdx(pt, s.columns); auto const idx = ptToIdx(pt, s.columns);
return getPixel8Bpp(s, idx); return getPixel8Bpp(s, idx);
} }
uint8_t getPixel4Bpp(
CompactTileSheet const&ts,
size_t const idx) noexcept {
oxAssert(ts.bpp == 4, "TileSheet::getPixel4Bpp: wrong bpp");
if (idx & 1) {
return ts.pixels[idx / 2] >> 4;
} else {
return ts.pixels[idx / 2] & 0b0000'1111;
}
}
uint8_t getPixel8Bpp(
CompactTileSheet const&ts,
size_t const idx) noexcept {
oxAssert(ts.bpp == 8, "TileSheet::getPixel8Bpp: wrong bpp");
return ts.pixels[idx];
}
ox::Pair<uint8_t> get2Pixels4Bpp(
CompactTileSheet const&ts,
size_t const idx) noexcept {
oxAssert(ts.bpp == 4, "TileSheet::getPixel4Bpp: wrong bpp");
auto const out = ts.pixels[idx / 2];
return {
static_cast<uint8_t>(out & 0x0f),
static_cast<uint8_t>(out >> 4),
};
}
ox::Pair<uint8_t> get2Pixels8Bpp(
CompactTileSheet const&ts,
size_t const idx) noexcept {
oxAssert(ts.bpp == 8, "TileSheet::getPixel8Bpp: wrong bpp");
return {
static_cast<uint8_t>(ts.pixels[idx]),
static_cast<uint8_t>(ts.pixels[idx + 1]),
};
}
static ox::Result<SubSheetId> getIdFor( static ox::Result<SubSheetId> getIdFor(
TileSheet::SubSheet const&ss, TileSheet::SubSheet const&ss,
ox::SpanView<ox::StringView> const&pNamePath, ox::SpanView<ox::StringView> const&pNamePath,

View File

@ -14,6 +14,8 @@
#include <ox/std/hashmap.hpp> #include <ox/std/hashmap.hpp>
#include <ox/std/utility.hpp> #include <ox/std/utility.hpp>
#include "validation.hpp"
namespace keel { namespace keel {
class AssetManager; class AssetManager;
@ -21,17 +23,6 @@ class AssetManager;
template<typename T> template<typename T>
class AssetRef; class AssetRef;
[[nodiscard]]
constexpr bool valid(auto const&) noexcept {
return true;
}
[[nodiscard]]
constexpr ox::Error repair(auto const&) noexcept {
return {};
}
#ifndef OX_BARE_METAL #ifndef OX_BARE_METAL
template<typename T> template<typename T>
class AssetContainer { class AssetContainer {
@ -226,9 +217,7 @@ class AssetManager {
ox::Result<AssetRef<T>> loadAsset(ox::StringView const assetId) noexcept { ox::Result<AssetRef<T>> loadAsset(ox::StringView const assetId) noexcept {
auto &p = m_cache[assetId]; auto &p = m_cache[assetId];
oxRequireM(obj, m_loader(assetId)); oxRequireM(obj, m_loader(assetId));
if (!valid(obj) && repair(obj)) { oxReturnError(ensureValid(obj));
return OxError(1, "asset is invalid state and could not be repaired");
}
if (!p) { if (!p) {
p = ox::make_unique<AssetContainer<T>>(std::move(obj)); p = ox::make_unique<AssetContainer<T>>(std::move(obj));
} else { } else {

View File

@ -57,8 +57,6 @@ ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::CRStringView uuid) noex
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept; ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept;
ox::Error performPackTransforms(Context &ctx, ox::Buffer &clawData) noexcept;
#ifndef OX_BARE_METAL #ifndef OX_BARE_METAL
namespace detail { namespace detail {

View File

@ -12,6 +12,31 @@
namespace keel { namespace keel {
struct ManifestEntry {
static constexpr auto TypeName = "net.drinkingtea.keel.ManifestEntry";
static constexpr auto TypeVersion = 1;
uint64_t inode{};
bool preloaded{};
ox::String type;
};
oxModelBegin(ManifestEntry)
oxModelField(inode)
oxModelField(preloaded)
oxModelField(type)
oxModelEnd()
struct Manifest {
static constexpr auto TypeName = "net.drinkingtea.keel.Manifest";
static constexpr auto TypeVersion = 1;
ox::HashMap<ox::String, ManifestEntry> files;
};
oxModelBegin(Manifest)
oxModelField(files)
oxModelEnd()
class Context; class Context;
struct GbaPlatSpec { struct GbaPlatSpec {
@ -113,6 +138,7 @@ ox::Error preloadObj(
// transformations need to be done after the copy to the new FS is complete // transformations need to be done after the copy to the new FS is complete
template<typename PlatSpec> template<typename PlatSpec>
ox::Error preloadDir( ox::Error preloadDir(
Manifest &manifest,
ox::TypeStore &ts, ox::TypeStore &ts,
ox::FileSystem &romFs, ox::FileSystem &romFs,
ox::Preloader<PlatSpec> &pl, ox::Preloader<PlatSpec> &pl,
@ -125,13 +151,14 @@ ox::Error preloadDir(
oxRequire(stat, romFs.stat(filePath)); oxRequire(stat, romFs.stat(filePath));
if (stat.fileType == ox::FileType::Directory) { if (stat.fileType == ox::FileType::Directory) {
auto const dir = ox::sfmt("{}{}/", path, name); auto const dir = ox::sfmt("{}{}/", path, name);
oxReturnError(preloadDir(ts, romFs, pl, dir)); oxReturnError(preloadDir(manifest, ts, romFs, pl, dir));
} else { } else {
auto const err = preloadObj(ts, romFs, pl, filePath); auto const err = preloadObj(ts, romFs, pl, filePath);
if (err) { if (err) {
oxErrf("\033[31;1;1mCould not preload {}:\n\t{}\n", filePath, toStr(err)); oxErrf("\033[31;1;1mCould not preload {}:\n\t{}\n", filePath, toStr(err));
return err; return err;
} }
manifest.files[filePath].preloaded = true;
} }
} }
return {}; return {};
@ -162,11 +189,15 @@ ox::Error appendBinary(ox::Buffer &binBuff, ox::SpanView<char> const&fsBuff, ox:
} }
template<typename PlatSpec> template<typename PlatSpec>
ox::Error preload(ox::TypeStore &ts, ox::FileSystem &src, ox::Preloader<PlatSpec> &pl) noexcept { ox::Error preload(
Manifest &manifest,
ox::TypeStore &ts,
ox::FileSystem &src,
ox::Preloader<PlatSpec> &pl) noexcept {
oxOut("Preloading\n"); oxOut("Preloading\n");
return detail::preloadDir(ts, src, pl, "/"); return detail::preloadDir(manifest, ts, src, pl, "/");
} }
ox::Error pack(keel::Context &ctx, ox::TypeStore &ts, ox::FileSystem &dest) noexcept; ox::Error pack(Manifest &manifest, keel::Context &ctx, ox::TypeStore &ts, ox::FileSystem &dest) noexcept;
} }

View File

@ -51,27 +51,27 @@ constexpr T &wrapCast(Wrap &ptr) noexcept {
class BaseConverter { class BaseConverter {
public: public:
virtual ~BaseConverter() noexcept = default; constexpr virtual ~BaseConverter() noexcept = default;
[[nodiscard]] [[nodiscard]]
virtual ox::StringView srcTypeName() const noexcept = 0; constexpr virtual ox::StringView srcTypeName() const noexcept = 0;
[[nodiscard]] [[nodiscard]]
virtual int srcTypeVersion() const noexcept = 0; constexpr virtual int srcTypeVersion() const noexcept = 0;
[[nodiscard]] [[nodiscard]]
virtual bool srcMatches(ox::CRStringView pSrcTypeName, int pSrcTypeVersion) const noexcept = 0; constexpr virtual bool srcMatches(ox::CRStringView pSrcTypeName, int pSrcTypeVersion) const noexcept = 0;
[[nodiscard]] [[nodiscard]]
virtual bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept = 0; constexpr virtual bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept = 0;
virtual ox::Result<ox::UPtr<Wrap>> convertPtrToPtr(keel::Context &ctx, Wrap &src) const noexcept = 0; virtual ox::Result<ox::UPtr<Wrap>> convertPtrToPtr(keel::Context &ctx, Wrap &src) const noexcept = 0;
virtual ox::Result<ox::UPtr<Wrap>> convertBuffToPtr( virtual ox::Result<ox::UPtr<Wrap>> convertBuffToPtr(
keel::Context &ctx, ox::Buffer const&srcBuff) const noexcept = 0; keel::Context &ctx, ox::BufferView const&srcBuff) const noexcept = 0;
[[nodiscard]] [[nodiscard]]
inline bool matches( constexpr bool matches(
ox::CRStringView srcTypeName, int srcTypeVersion, ox::CRStringView srcTypeName, int srcTypeVersion,
ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept { ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept {
return srcMatches(srcTypeName, srcTypeVersion) return srcMatches(srcTypeName, srcTypeVersion)
@ -84,17 +84,17 @@ template<typename SrcType, typename DstType>
class Converter: public BaseConverter { class Converter: public BaseConverter {
public: public:
[[nodiscard]] [[nodiscard]]
ox::StringView srcTypeName() const noexcept final { constexpr ox::StringView srcTypeName() const noexcept final {
return ox::ModelTypeName_v<SrcType>; return ox::ModelTypeName_v<SrcType>;
} }
[[nodiscard]] [[nodiscard]]
int srcTypeVersion() const noexcept final { constexpr int srcTypeVersion() const noexcept final {
return ox::ModelTypeVersion_v<SrcType>; return ox::ModelTypeVersion_v<SrcType>;
} }
[[nodiscard]] [[nodiscard]]
bool srcMatches(ox::CRStringView pSrcTypeName, int pSrcTypeVersion) const noexcept final { constexpr bool srcMatches(ox::CRStringView pSrcTypeName, int pSrcTypeVersion) const noexcept final {
constexpr auto SrcTypeName = ox::requireModelTypeName<SrcType>(); constexpr auto SrcTypeName = ox::requireModelTypeName<SrcType>();
constexpr auto SrcTypeVersion = ox::requireModelTypeVersion<SrcType>(); constexpr auto SrcTypeVersion = ox::requireModelTypeVersion<SrcType>();
return pSrcTypeName == SrcTypeName return pSrcTypeName == SrcTypeName
@ -102,8 +102,8 @@ class Converter: public BaseConverter {
} }
[[nodiscard]] [[nodiscard]]
bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept final { constexpr bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept final {
constexpr auto DstTypeName = ox::StringView(ox::requireModelTypeName<DstType>()); constexpr auto DstTypeName = ox::StringView{ox::requireModelTypeName<DstType>()};
constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>(); constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
return dstTypeName == DstTypeName return dstTypeName == DstTypeName
&& dstTypeVersion == DstTypeVersion; && dstTypeVersion == DstTypeVersion;
@ -117,8 +117,9 @@ class Converter: public BaseConverter {
} }
ox::Result<ox::UPtr<Wrap>> convertBuffToPtr( ox::Result<ox::UPtr<Wrap>> convertBuffToPtr(
keel::Context &ctx, ox::Buffer const&srcBuff) const noexcept final { keel::Context &ctx, ox::BufferView const&srcBuff) const noexcept final {
oxRequireM(src, readAsset<SrcType>(srcBuff)); oxRequireM(src, readAsset<SrcType>(srcBuff));
oxReturnError(ensureValid(src));
auto dst = makeWrap<DstType>(); auto dst = makeWrap<DstType>();
oxReturnError(convert(ctx, src, wrapCast<DstType>(*dst))); oxReturnError(convert(ctx, src, wrapCast<DstType>(*dst)));
return {std::move(dst)}; return {std::move(dst)};
@ -131,12 +132,12 @@ class Converter: public BaseConverter {
ox::Result<ox::UPtr<Wrap>> convert( ox::Result<ox::UPtr<Wrap>> convert(
keel::Context &ctx, keel::Context &ctx,
ox::Buffer const&srcBuffer, ox::BufferView const&srcBuffer,
ox::CRStringView dstTypeName, ox::CRStringView dstTypeName,
int dstTypeVersion) noexcept; int dstTypeVersion) noexcept;
template<typename DstType> template<typename DstType>
ox::Result<DstType> convert(keel::Context &ctx, ox::Buffer const&srcBuffer) noexcept { ox::Result<DstType> convert(keel::Context &ctx, ox::BufferView const&srcBuffer) noexcept {
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>(); static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>(); static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion)); oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion));
@ -144,7 +145,7 @@ ox::Result<DstType> convert(keel::Context &ctx, ox::Buffer const&srcBuffer) noex
} }
template<typename DstType> template<typename DstType>
ox::Error convert(keel::Context &ctx, ox::Buffer const&buff, DstType *outObj) noexcept { ox::Error convert(keel::Context &ctx, ox::BufferView const&buff, DstType *outObj) noexcept {
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>(); static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>(); static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
oxRequire(outPtr, convert(ctx, buff, DstTypeName, DstTypeVersion)); oxRequire(outPtr, convert(ctx, buff, DstTypeName, DstTypeVersion));
@ -154,7 +155,7 @@ ox::Error convert(keel::Context &ctx, ox::Buffer const&buff, DstType *outObj) no
template<typename DstType> template<typename DstType>
ox::Result<ox::Buffer> convertBuffToBuff( ox::Result<ox::Buffer> convertBuffToBuff(
keel::Context &ctx, ox::Buffer const&srcBuffer, ox::ClawFormat fmt) noexcept { keel::Context &ctx, ox::BufferView const&srcBuffer, ox::ClawFormat fmt) noexcept {
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>(); static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>(); static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion)); oxRequire(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion));

View File

@ -0,0 +1,27 @@
/*
* Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/error.hpp>
namespace keel {
[[nodiscard]]
constexpr bool valid(auto const&) noexcept {
return true;
}
constexpr ox::Error repair(auto const&) noexcept {
return OxError(1, "No repair function for this type");
}
constexpr ox::Error ensureValid(auto &o) noexcept {
if (!valid(o)) {
return repair(o);
}
return {};
}
}

View File

@ -154,18 +154,6 @@ ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexce
#endif #endif
} }
ox::Error performPackTransforms(Context &ctx, ox::Buffer &clawData) noexcept {
oxRequireM(typeId, readAssetTypeId(clawData));
for (auto const tr : packTransforms(ctx)) {
bool changed{};
oxReturnError(tr(ctx, clawData, typeId).moveTo(changed));
if (changed) {
oxReturnError(readAssetTypeId(clawData).moveTo(typeId));
}
}
return {};
}
ox::Error reloadAsset(keel::Context &ctx, ox::StringView assetId) noexcept { ox::Error reloadAsset(keel::Context &ctx, ox::StringView assetId) noexcept {
ox::UUIDStr uuidStr; ox::UUIDStr uuidStr;
if (beginsWith(assetId, "uuid://")) { if (beginsWith(assetId, "uuid://")) {

View File

@ -8,6 +8,7 @@
#include <ox/fs/fs.hpp> #include <ox/fs/fs.hpp>
#include <ox/logconn/def.hpp> #include <ox/logconn/def.hpp>
#include <ox/logconn/logconn.hpp> #include <ox/logconn/logconn.hpp>
#include <ox/oc/write.hpp>
#include <keel/keel.hpp> #include <keel/keel.hpp>
@ -48,16 +49,21 @@ static ox::Error generateTypes(ox::TypeStore &ts) noexcept {
return {}; return {};
} }
static ox::Error pack(ox::StringView argSrc, ox::StringView argRomBin, ox::StringView projectDataDir) noexcept { static ox::Error pack(
ox::StringView argSrc,
ox::StringView argRomBin,
ox::StringView argManifest,
ox::StringView projectDataDir) noexcept {
ox::Buffer dstBuff(32 * ox::units::MB); ox::Buffer dstBuff(32 * ox::units::MB);
oxReturnError(ox::FileSystem32::format(dstBuff.data(), dstBuff.size())); oxReturnError(ox::FileSystem32::format(dstBuff.data(), dstBuff.size()));
ox::FileSystem32 dst(dstBuff); ox::FileSystem32 dst(dstBuff);
oxRequire(ctx, keel::init(ox::make_unique<ox::PassThroughFS>(argSrc), "keel-pack")); oxRequire(ctx, keel::init(ox::make_unique<ox::PassThroughFS>(argSrc), "keel-pack"));
keel::TypeStore ts(*ctx->rom, ox::sfmt("{}/type_descriptors", projectDataDir)); keel::TypeStore ts(*ctx->rom, ox::sfmt("{}/type_descriptors", projectDataDir));
oxReturnError(generateTypes(ts)); oxReturnError(generateTypes(ts));
oxReturnError(keel::pack(*ctx, ts, dst)); keel::Manifest manifest;
oxReturnError(keel::pack(manifest, *ctx, ts, dst));
oxRequireM(pl, keel::GbaPreloader::make()); oxRequireM(pl, keel::GbaPreloader::make());
oxReturnError(preload(ts, dst, *pl)); oxReturnError(preload(manifest, ts, dst, *pl));
oxReturnError(dst.resize()); oxReturnError(dst.resize());
// resize buffer // resize buffer
oxRequire(dstSize, dst.size()); oxRequire(dstSize, dst.size());
@ -70,6 +76,8 @@ static ox::Error pack(ox::StringView argSrc, ox::StringView argRomBin, ox::Strin
oxReturnError(appendBinary(romBuff, dstBuff, *pl)); oxReturnError(appendBinary(romBuff, dstBuff, *pl));
oxOutf("Final ROM buff size: {} bytes\n", romBuff.size()); oxOutf("Final ROM buff size: {} bytes\n", romBuff.size());
oxReturnError(writeFileBuff(argRomBin, romBuff)); oxReturnError(writeFileBuff(argRomBin, romBuff));
oxRequire(manifestJson, ox::writeOC(manifest));
oxReturnError(writeFileBuff(argManifest, manifestJson));
return {}; return {};
} }
@ -77,6 +85,7 @@ static ox::Error run(int argc, char const**argv, ox::StringView projectDataDir)
ox::ClArgs const args(argc, argv); ox::ClArgs const args(argc, argv);
auto const argSrc = args.getString("src", ""); auto const argSrc = args.getString("src", "");
auto const argRomBin = args.getString("rom-bin", ""); auto const argRomBin = args.getString("rom-bin", "");
auto const argManifest = args.getString("manifest", "");
if (argSrc == "") { if (argSrc == "") {
oxErr("\033[31;1;1merror:\033[0m must specify a source directory\n"); oxErr("\033[31;1;1merror:\033[0m must specify a source directory\n");
return OxError(1, "must specify a source directory"); return OxError(1, "must specify a source directory");
@ -85,7 +94,7 @@ static ox::Error run(int argc, char const**argv, ox::StringView projectDataDir)
oxErr("\033[31;1;1merror:\033[0m must specify a path for ROM file\n"); oxErr("\033[31;1;1merror:\033[0m must specify a path for ROM file\n");
return OxError(1, "must specify a path for preload file"); return OxError(1, "must specify a path for preload file");
} }
return pack(argSrc, argRomBin, projectDataDir); return pack(argSrc, argRomBin, argManifest, projectDataDir);
} }
namespace olympic { namespace olympic {

View File

@ -6,13 +6,14 @@
#include <ox/model/modelvalue.hpp> #include <ox/model/modelvalue.hpp>
#include <keel/media.hpp> #include <keel/media.hpp>
#include <keel/pack.hpp> #include <keel/pack.hpp>
namespace keel { namespace keel {
static ox::Error pathToInode( static ox::Error pathToInode(
keel::Context &ctx, ox::FileSystem &dest, ox::ModelObject &obj) noexcept { keel::Context &ctx,
ox::FileSystem &dest,
ox::ModelObject &obj) noexcept {
auto &o = obj; auto &o = obj;
auto type = static_cast<ox::FileAddressType>(o.at("type").unwrap()->get<int8_t>()); auto type = static_cast<ox::FileAddressType>(o.at("type").unwrap()->get<int8_t>());
auto &data = o.at("data").unwrap()->get<ox::ModelUnion>(); auto &data = o.at("data").unwrap()->get<ox::ModelUnion>();
@ -85,7 +86,24 @@ static ox::Error transformFileAddressesObj(
return {}; return {};
} }
static ox::Error performPackTransforms(
ManifestEntry &entry,
Context &ctx,
ox::Buffer &clawData) noexcept {
oxRequireM(typeId, readAssetTypeId(clawData));
for (auto const tr : packTransforms(ctx)) {
bool changed{};
oxReturnError(tr(ctx, clawData, typeId).moveTo(changed));
if (changed) {
oxReturnError(readAssetTypeId(clawData).moveTo(typeId));
}
}
entry.type = ox::String{typeId};
return {};
}
static ox::Error doTransformations( static ox::Error doTransformations(
Manifest &manifest,
keel::Context &ctx, keel::Context &ctx,
ox::TypeStore &ts, ox::TypeStore &ts,
ox::FileSystem &dest, ox::FileSystem &dest,
@ -94,7 +112,7 @@ static ox::Error doTransformations(
oxRequire(s, dest.stat(filePath)); oxRequire(s, dest.stat(filePath));
// do transformations // do transformations
oxRequireM(buff, dest.read(s.inode)); oxRequireM(buff, dest.read(s.inode));
oxReturnError(keel::performPackTransforms(ctx, buff)); oxReturnError(keel::performPackTransforms(manifest.files[filePath], ctx, buff));
// transform FileAddresses // transform FileAddresses
oxRequireM(obj, keel::readAsset(ts, buff)); oxRequireM(obj, keel::readAsset(ts, buff));
oxOutf("transforming {}\n", filePath); oxOutf("transforming {}\n", filePath);
@ -108,6 +126,7 @@ static ox::Error doTransformations(
// claw file transformations are broken out from copy because path to inode // claw file transformations are broken out from copy because path to inode
// transformations need to be done after the copy to the new FS is complete // transformations need to be done after the copy to the new FS is complete
static ox::Error transformClaw( static ox::Error transformClaw(
Manifest &manifest,
keel::Context &ctx, keel::Context &ctx,
ox::TypeStore &ts, ox::TypeStore &ts,
ox::FileSystem &dest, ox::FileSystem &dest,
@ -120,9 +139,9 @@ static ox::Error transformClaw(
oxRequire(stat, dest.stat(filePath)); oxRequire(stat, dest.stat(filePath));
if (stat.fileType == ox::FileType::Directory) { if (stat.fileType == ox::FileType::Directory) {
auto const dir = ox::sfmt("{}{}/", path, name); auto const dir = ox::sfmt("{}{}/", path, name);
oxReturnError(transformClaw(ctx, ts, dest, dir)); oxReturnError(transformClaw(manifest, ctx, ts, dest, dir));
} else { } else {
auto const err = doTransformations(ctx, ts, dest, filePath); auto const err = doTransformations(manifest, ctx, ts, dest, filePath);
if (err) { if (err) {
oxErrf("\033[31;1;1mCould not do transformations for {}:\n\t{}\n", filePath, toStr(err)); oxErrf("\033[31;1;1mCould not do transformations for {}:\n\t{}\n", filePath, toStr(err));
return err; return err;
@ -133,10 +152,13 @@ static ox::Error transformClaw(
} }
static ox::Error copy( static ox::Error copy(
Manifest &manifest,
ox::FileSystem &src, ox::FileSystem &src,
ox::FileSystem &dest, ox::FileSystem &dest,
ox::CRStringView path) noexcept { ox::CRStringView path,
oxOutf("copying directory: {}\n", path); ox::CRStringView logPrefix = "") noexcept {
oxOutf("{}copying directory: {}\n", logPrefix, path);
auto const childLogPrefix = ox::sfmt("{}\t", logPrefix);
// copy // copy
oxRequire(fileList, src.ls(path)); oxRequire(fileList, src.ls(path));
for (auto const&name : fileList) { for (auto const&name : fileList) {
@ -147,27 +169,36 @@ static ox::Error copy(
oxRequire(stat, src.stat(currentFile)); oxRequire(stat, src.stat(currentFile));
if (stat.fileType == ox::FileType::Directory) { if (stat.fileType == ox::FileType::Directory) {
oxReturnError(dest.mkdir(currentFile, true)); oxReturnError(dest.mkdir(currentFile, true));
oxReturnError(copy(src, dest, currentFile + '/')); oxReturnError(copy(manifest, src, dest, currentFile + '/', childLogPrefix));
} else { } else {
// load file // load file
oxOutf("copying file: {}\n", currentFile); oxOutf("{}copying file: {}...", childLogPrefix, currentFile);
ox::StringView status = "failed";
oxDefer [&status] {
oxOutf(" {}\n", status);
};
oxRequireM(buff, src.read(currentFile)); oxRequireM(buff, src.read(currentFile));
// write file to dest // write file to dest
oxReturnError(dest.write(currentFile, buff)); oxReturnError(dest.write(currentFile, buff));
status = "OK";
oxRequire(stat, dest.stat(currentFile));
manifest.files[currentFile] = {
.inode = stat.inode,
.type = ox::String{keel::readAssetTypeId(buff).or_value({})},
};
} }
} }
return {}; return {};
} }
static ox::Error copyFS(ox::FileSystem &src, ox::FileSystem &dest) noexcept { ox::Error pack(
oxReturnError(copy(src, dest, "/")); Manifest &manifest,
return {}; keel::Context &ctx,
} ox::TypeStore &ts,
ox::FileSystem &dest) noexcept {
ox::Error pack(keel::Context &ctx, ox::TypeStore &ts, ox::FileSystem &dest) noexcept { oxReturnError(copy(manifest, *ctx.rom, dest, "/"));
oxReturnError(copyFS(*ctx.rom, dest));
oxOut("Doing transforms\n"); oxOut("Doing transforms\n");
oxReturnError(transformClaw(ctx, ts, dest, "/")); oxReturnError(transformClaw(manifest, ctx, ts, dest, "/"));
return {}; return {};
} }

View File

@ -9,7 +9,6 @@
namespace keel { namespace keel {
[[nodiscard]]
static ox::Result<BaseConverter const*> findConverter( static ox::Result<BaseConverter const*> findConverter(
ox::SpanView<BaseConverter const*> const&converters, ox::SpanView<BaseConverter const*> const&converters,
ox::CRStringView srcTypeName, ox::CRStringView srcTypeName,
@ -27,7 +26,7 @@ static ox::Result<BaseConverter const*> findConverter(
static ox::Result<ox::UPtr<Wrap>> convert( static ox::Result<ox::UPtr<Wrap>> convert(
keel::Context &ctx, keel::Context &ctx,
ox::SpanView<BaseConverter const*> const&converters, ox::SpanView<BaseConverter const*> const&converters,
ox::Buffer const&srcBuffer, ox::BufferView const&srcBuffer,
ox::CRStringView srcTypeName, ox::CRStringView srcTypeName,
int srcTypeVersion, int srcTypeVersion,
ox::CRStringView dstTypeName, ox::CRStringView dstTypeName,
@ -55,7 +54,7 @@ static ox::Result<ox::UPtr<Wrap>> convert(
ox::Result<ox::UPtr<Wrap>> convert( ox::Result<ox::UPtr<Wrap>> convert(
keel::Context &ctx, keel::Context &ctx,
ox::Buffer const&srcBuffer, ox::BufferView const&srcBuffer,
ox::CRStringView dstTypeName, ox::CRStringView dstTypeName,
int dstTypeVersion) noexcept { int dstTypeVersion) noexcept {
oxRequire(hdr, readAssetHeader(srcBuffer)); oxRequire(hdr, readAssetHeader(srcBuffer));

View File

@ -8,12 +8,12 @@
namespace studio { namespace studio {
ClawEditor::ClawEditor(ox::CRStringView path, ox::ModelObject obj) noexcept: ClawEditor::ClawEditor(StudioContext &sctx, ox::StringParam path):
Editor(path), Editor(std::move(path)),
m_obj(std::move(obj)) { m_obj(sctx.project->loadObj<ox::ModelObject>(itemPath()).unwrapThrow()) {
} }
void ClawEditor::draw(studio::StudioContext&) noexcept { void ClawEditor::draw(StudioContext&) noexcept {
ImGui::BeginChild("PaletteEditor"); ImGui::BeginChild("PaletteEditor");
static constexpr auto flags = ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; static constexpr auto flags = ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
if (ImGui::BeginTable("ObjTree", 3, flags)) { if (ImGui::BeginTable("ObjTree", 3, flags)) {

View File

@ -11,14 +11,14 @@
namespace studio { namespace studio {
class ClawEditor: public studio::Editor { class ClawEditor: public Editor {
private: private:
using ObjPath = ox::Vector<ox::StringView, 8>; using ObjPath = ox::Vector<ox::StringView, 8>;
ox::ModelObject m_obj; ox::ModelObject m_obj;
public: public:
ClawEditor(ox::CRStringView path, ox::ModelObject obj) noexcept; ClawEditor(StudioContext &sctx, ox::StringParam path);
void draw(studio::StudioContext&) noexcept final; void draw(StudioContext&) noexcept final;
private: private:
static void drawRow(ox::ModelValue const&value) noexcept; static void drawRow(ox::ModelValue const&value) noexcept;

View File

@ -366,15 +366,10 @@ ox::Error StudioUI::openFileActiveTab(ox::CRStringView path, bool makeActiveTab)
} }
oxRequire(ext, studio::fileExt(path)); oxRequire(ext, studio::fileExt(path));
// create Editor // create Editor
studio::BaseEditor *editor = nullptr; BaseEditor *editor = nullptr;
if (!m_editorMakers.contains(ext)) { auto const err = m_editorMakers.contains(ext) ?
auto [obj, err] = m_project->loadObj<ox::ModelObject>(path); m_editorMakers[ext](path).moveTo(editor) :
if (err) { ox::makeCatch<ClawEditor>(m_sctx, path).moveTo(editor);
return OxError(1, "There is no editor for this file extension");
}
editor = ox::make<ClawEditor>(path, std::move(obj));
} else {
auto const err = m_editorMakers[ext](path).moveTo(editor);
if (err) { if (err) {
if constexpr(!ox::defines::Debug) { if constexpr(!ox::defines::Debug) {
oxErrf("Could not open Editor: {}\n", toStr(err)); oxErrf("Could not open Editor: {}\n", toStr(err));
@ -383,7 +378,6 @@ ox::Error StudioUI::openFileActiveTab(ox::CRStringView path, bool makeActiveTab)
} }
return err; return err;
} }
}
editor->closed.connect(this, &StudioUI::closeFile); editor->closed.connect(this, &StudioUI::closeFile);
m_editors.emplace_back(editor); m_editors.emplace_back(editor);
m_openFiles.emplace_back(path); m_openFiles.emplace_back(path);