Compare commits

...

34 Commits

Author SHA1 Message Date
a53d1f87ee [Makefile] Add targets for build-pack and build-gba-player, update pkg-gba target to use them
All checks were successful
Build / build (push) Successful in 1m20s
2025-10-01 00:30:41 -05:00
7b5c760974 [ox/std] Ignore broken GCC warning
All checks were successful
Build / build (push) Successful in 1m24s
2025-09-20 13:57:45 -05:00
53446cfa1d Merge commit '5384d8c83bd449618b0ab318877fd967cb1f034f'
All checks were successful
Build / build (push) Successful in 1m49s
2025-09-10 23:48:49 -05:00
5384d8c83b Squashed 'deps/nostalgia/' changes from 31b39982..671fa54f
671fa54f [ox/std] Make ox::Vector::push_back comply with std::vector::push_back
51743267 [nostalgia/gfx/studio] Cleanup includes
b31c01f7 [keel,studio] Cleanup
f41213f1 [ox/std] Fix channel format for oxLogError
28be7c46 [ox/fs] Fix write functions to take SpanViews
2f340b13 [ox/std] Fix Windows GCC build
312c8188 [nostalgia/gfx/studio] Remove unused variable
0d69d0c4 [ox/std] Remove oxDebug line
81a0b8c8 [ox/mc] Remove an oxDebug line
172b5aee [ox/oc] Remove an oxDebug line
2b5338a9 [nostalgia] Improve Makefile dependency handling
8a430faf [keel] Cleanup
e59382dd [keel] Address undefined behavior
3006e77e [ox/std] Add and integrate std::launder
59c112a6 [studio] Fix navigate back not to iterate on the first item twice

git-subtree-dir: deps/nostalgia
git-subtree-split: 671fa54f6f3f16f4772353bb0b12cfe09dd2fd92
2025-09-10 23:48:49 -05:00
6a0f57994c Merge commit '6b0a56d5d66032c4d150c76c2b6a537930a5c5fa'
All checks were successful
Build / build (push) Successful in 1m31s
2025-08-01 02:53:02 -05:00
6b0a56d5d6 Squashed 'deps/nostalgia/' changes from e38b85b4..31b39982
31b39982 [keel] Fix AssetRef to call incRef on initial creation of ref, not just copy
5476417b [nostalgia] Add release notes for d2025.07.0
e03be694 Merge commit 'b67b95767b7bfcd5f618ebc8e14ddbc83edcbe36'
490c0368 [nostalgia/gfx] Add lists for file extensions
a24fc407 [ox/std] Fix MSVC build

git-subtree-dir: deps/nostalgia
git-subtree-split: 31b39982c5ead87da1727bc1f561b945e4d1e5fb
2025-08-01 02:53:02 -05:00
3aac345637 Merge commit 'b67b95767b7bfcd5f618ebc8e14ddbc83edcbe36'
All checks were successful
Build / build (push) Successful in 1m30s
2025-07-31 00:41:06 -05:00
b67b95767b Squashed 'deps/nostalgia/' changes from f7c3c02c..e38b85b4
e38b85b4 [studio] Eliminate redundant serialization and deserialization

git-subtree-dir: deps/nostalgia
git-subtree-split: e38b85b4f4134af04b9b71caddcd2268f425f5df
2025-07-31 00:41:06 -05:00
8aea7c2ecf [nostalgia/gfx] Add lists for file extensions
All checks were successful
Build / build (push) Successful in 1m31s
2025-07-31 00:39:55 -05:00
e9a7fb1ec8 [ox/std] Fix MSVC build
Some checks failed
Build / build (push) Has been cancelled
2025-07-31 00:38:26 -05:00
375388c0f1 Squashed 'deps/nostalgia/' changes from e27eee50..f7c3c02c
f7c3c02c Merge commit '1bfb7f99c215e2c74556bd3281f44962b8faaa96'
8f0f1fea [nostalgia/gfx/studio] Make editors use Project::loadObj for their primary assets
2f36a3f6 [studio] Add File -> Reload Project menu item
07e5bf90 [keel] Make keel attempt to delete all existing assets when FS is changed
aacff3da [ox/std] Fix UPtr::reset to conform to unique_ptr::reset

git-subtree-dir: deps/nostalgia
git-subtree-split: f7c3c02c4cbe676ea116ea53f1f31b27f668cd98
2025-07-30 01:51:46 -05:00
084baa6005 Merge commit '375388c0f16a0de1b16575578ad49e8318a1c80f'
All checks were successful
Build / build (push) Successful in 1m31s
2025-07-30 01:51:46 -05:00
b1f912445d Merge commit '1bfb7f99c215e2c74556bd3281f44962b8faaa96'
All checks were successful
Build / build (push) Successful in 1m29s
2025-07-30 00:42:42 -05:00
1bfb7f99c2 Squashed 'deps/nostalgia/' changes from c7bc2a95..e27eee50
e27eee50 [teagba] Add set and scroll background offset functions
fd610454 [nostalgia/gfx] Fix compiler warning
e61d4647 [nostalgia/gfx] Fix BG tilesheet loading, add background offset functions
c275c5f5 [hull] Disable building hull for now
fbf49ba5 [ox/std] Add pre- and post-increment operators to Span
92f74b27 [ox/std] Add null check for deallocating in consteval context Vector
934f0c92 [ox/std] Add beginsWith and endsWith variants that that cingle chars
ee9a3e11 [ox/std] Cleanup
16886cdf [hull] Add start on command interpreter
08b9508d [ox/std] Give std::ignore a named type
69bd968f [nostalgia/player] Fix build
4e7dc666 [nostalgia,olympic] Rename string len() functions to size()
bea0cf5a [ox/std] Rename string len() functions to size()

git-subtree-dir: deps/nostalgia
git-subtree-split: e27eee50f05bb437710313430e0d9cef636a66b1
2025-07-30 00:40:03 -05:00
10db939d62 [nostalgia/gfx/studio] Make editors use Project::loadObj for their primary assets 2025-07-30 00:37:59 -05:00
553797fdbd [studio] Add File -> Reload Project menu item 2025-07-30 00:37:23 -05:00
fb0cd99d8c [keel] Make keel attempt to delete all existing assets when FS is changed 2025-07-30 00:36:56 -05:00
a372814e3c [ox/std] Fix UPtr::reset to conform to unique_ptr::reset 2025-07-30 00:29:34 -05:00
ceea6c7b27 [nostalgia/player] Fix build
All checks were successful
Build / build (push) Successful in 1m40s
2025-07-25 22:54:43 -05:00
7f6e734026 [jasper/world/studio] Cleanup
Some checks failed
Build / build (push) Failing after 22s
2025-07-25 22:51:14 -05:00
2863874ae0 [jasper/project] Fill out more facets of player assets 2025-07-25 22:51:02 -05:00
d0277a43fc [jasper/world/studio] Rename string len() functions to size() 2025-07-25 22:49:35 -05:00
aa875e9be2 [nostalgia,olympic] Rename string len() functions to size() 2025-07-25 22:48:08 -05:00
b126a3a859 [ox/std] Rename string len() functions to size() 2025-07-25 22:47:56 -05:00
90613184e0 [jasper] Add make loc command 2025-07-25 22:45:14 -05:00
8a74e044dc Squashed 'deps/nostalgia/' changes from fae1e73e..c7bc2a95
c7bc2a95 [nostalgia/gfx] Style update
7372036a [nostalgia/gfx] Add function missing from header
7461d832 [nostalgia/gfx/studio,studio] Fix CLI tool output to only show usage if no args given
6052798f Merge commit 'dceeaaa9302b7e9ce85fa773fc187bc593f3c93c'
801d35c8 [keel] Make type converters work with functions that take const src arg

git-subtree-dir: deps/nostalgia
git-subtree-split: c7bc2a954fdf435127fb09896f32c5cb23c99f02
2025-07-25 00:32:02 -05:00
f1d4c20c88 Merge commit '8a74e044dc5fa44ba10dbbf7d2812c7070ff4f7c'
All checks were successful
Build / build (push) Successful in 1m30s
2025-07-25 00:32:02 -05:00
6a7226ae68 [jasper/world/studio] Fix build
All checks were successful
Build / build (push) Successful in 1m33s
2025-07-24 02:02:46 -05:00
dceeaaa930 Squashed 'deps/nostalgia/' changes from 671b8eda..fae1e73e
fae1e73e [nostalgia/gfx] Make getSubSheet check root subsheet name
51f2905c [nostalgia/gfx/studio] Make TileSheetEditor use export-tilesheet functions for export, fix exporting Root subsheet
0c866d1b [studio,nostalgia/gfx] Add system for adding sub-commands in Modules, add export-tilesheet command
fdf39d1a [ox/std] Add Result::transformError
a523a75e [ox/std] Add missing include to StringParam
cdaa64ed [ox/clargs] Fix arg parsing for first '-'
37b5fcc0 [teagba] Put parentheses around all registers
f5f2c3be [studio/applib] Make Studio remove files unable to be opened from open file list in config
f6ef2b5a [turbine,nostalgia] Make memory regions cast to bounded ox::Arrays
bf958a4a [teagba] Make memory regions cast to bounded ox::Arrays
6a70e478 [nostalgia/gfx] Cleanup

git-subtree-dir: deps/nostalgia
git-subtree-split: fae1e73e54a420d4b93af67e03144d5442825a11
2025-07-24 01:58:27 -05:00
86860cf27b Merge commit 'dceeaaa9302b7e9ce85fa773fc187bc593f3c93c' 2025-07-24 01:58:27 -05:00
6f80f634b0 [jasper/world/keel] Make convertWorldDocToWorldStatic take a const src
All checks were successful
Build / build (push) Successful in 1m30s
2025-07-23 00:42:41 -05:00
99ee44b838 [keel] Make type converters work with functions that take const src arg 2025-07-23 00:41:33 -05:00
be7dd92971 Merge commit 'b0726568df6aaa37390906ca44ff1eee11735f98'
All checks were successful
Build / build (push) Successful in 1m34s
2025-06-29 17:34:57 -05:00
b0726568df Squashed 'deps/nostalgia/' changes from f847289b..671b8eda
671b8eda [ox/std] Make StringLiteral constructors consteval
952637a1 Merge commit 'cbf4414fcaf00c00a2abf73b5c04a055180ad980'
7569698e [nostalgia,studio] Add FileExts_TileSheet const, and corresponding FilePickerPopup constructor
21713ba9 [ox/std] Fix StringLiteral::operator= to work with DevkitARM
73273b6f [nostalgia/gfx] Add isTileSheet function for checking paths against both file extensions
9f040392 [olympic,nostalgia] Cleanup style
f4f7e5d0 Merge commit '9b5f7886cadc5c3dc826d00fa5b2e71696151dfd'
c27726a4 Merge commit '6bbcae10cc7b21b73171ec0ff196f4baf6304404'
bd24a775 Merge commit '7371df429534f264c179684412f6197f7968ebfa'
4419dff2 Merge commit '7688c05bac8c20bc267cae62ec78d55e5d0c493b'
536999c0 Merge commit '47eee1d56d591e3631d16e95a78ea3629ee312ee'
a5535ef5 Merge commit '08236fc790e711afe886b6ef545511d35e4e5c6c'
a90380f3 Merge commit 'e90dd887477452922f783535edb3d4c55e9a0d2c'
2000b2de [nostalgia/gfx/studio] Cleanup
7d92400f [nostalgia/gfx/studio] Add type specific navigateTo functions

git-subtree-dir: deps/nostalgia
git-subtree-split: 671b8edaadefe1872fb8954ad13d221b24f676c0
2025-06-29 17:33:27 -05:00
124 changed files with 1887 additions and 1277 deletions

View File

@@ -15,16 +15,26 @@ else
endif
.PHONY: pkg-gba
pkg-gba: build
pkg-gba: build-pack build-gba-player
${BC_CMD_ENVRUN} ${BC_PY3} deps/nostalgia/util/scripts/pkg-gba.py project ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-mac
pkg-mac: install
${BC_CMD_ENVRUN} ${BC_PY3} deps/nostalgia/util/scripts/pkg-dmg.py JasperStudio
.PHONY: build-gba-player
build-gba-player:
cmake --build ./build/gba-*
.PHONY: build-player
build-player:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: build-pack
build-pack:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME}-pack
.PHONY: run
run: build-player
${PROJECT_PLAYER} project
@@ -65,3 +75,38 @@ git-push-nostalgia:
.PHONY: generate-studio-rsrc
generate-studio-rsrc:
${BC_CMD_ENVRUN} ${BC_PY3} deps/nostalgia/util/scripts/file-to-cpp.py --rsrc src/jasper/tools/rsrc.json
.PHONY: loc
loc:
${BC_PY3} deps/nostalgia/util/scripts/loc.py \
--search-dirs \
src \
--include-exts \
.cpp \
.hpp \
.py \
.s \
.cmake
.PHONY: loc-full
loc-full:
${BC_PY3} deps/nostalgia/util/scripts/loc.py \
--search-dirs \
src \
deps/nostalgia/src \
deps/nostalgia/deps/ox/src \
deps/nostalgia/deps/buildcore \
deps/nostalgia/deps/gbabuildcore \
deps/nostalgia/deps/glutils \
deps/nostalgia/deps/teagba \
--include-exts \
.cpp \
.hpp \
.py \
.s \
.cmake \
--exclude-paths \
deps/nostalgia/deps/teagba/src/gba_crt0.s \
deps/nostalgia/src/olympic/studio/applib/src/font.cpp \
deps/nostalgia/src/olympic/studio/applib/src/font.hpp \
deps/nostalgia/src/nostalgia/studio/icondata.cpp

View File

@@ -14,7 +14,7 @@ endif
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-gba
pkg-gba: build
pkg-gba: build-pack build-gba-player
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-mac
@@ -26,25 +26,44 @@ generate-studio-rsrc:
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/olympic/studio/applib/src/rsrc.json
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/nostalgia/studio/rsrc.json
.PHONY: build-gba-player
build-gba-player:
cmake --build ./build/gba-*
.PHONY: build-player
build-player:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: build-pack
build-pack:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME}-pack
.PHONY: run
run: build-player
${PROJECT_PLAYER} sample_project
.PHONY: build-studio
build-studio:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME_CAP}Studio
.PHONY: run-studio
run-studio: build
run-studio: build-studio
${PROJECT_STUDIO}
.PHONY: gba-run
gba-run: pkg-gba
${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba
.PHONY: debug
debug: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project
.PHONY: debug-studio
debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO}
.PHONY: configure-gba
configure-gba:
${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=release --build_root=${BC_VAR_BUILD_PATH}

View File

@@ -15,16 +15,16 @@ ClArgs::ClArgs(int argc, const char **args) noexcept: ClArgs({args, static_cast<
ClArgs::ClArgs(ox::SpanView<const char*> args) noexcept {
for (auto i = 0u; i < args.size(); ++i) {
auto arg = StringView(args[i]);
auto arg = StringView{args[i]};
if (arg[0] == '-') {
while (arg[0] == '-' && arg.len()) {
while (arg[0] == '-' && arg.size()) {
arg = substr(arg, 1);
}
m_bools[arg] = true;
// parse additional arguments
if (i < args.size() && args[i + 1]) {
auto val = String(args[i + 1]);
if (val.len() && val[i] != '-') {
auto const val = StringView{args[i + 1]};
if (val.size() && val[0] != '-') {
if (val == "false") {
m_bools[arg] = false;
}
@@ -40,17 +40,17 @@ ClArgs::ClArgs(ox::SpanView<const char*> args) noexcept {
}
bool ClArgs::getBool(ox::StringViewCR arg, bool defaultValue) const noexcept {
auto [value, err] = m_ints.at(arg);
auto const [value, err] = m_ints.at(arg);
return !err ? *value : defaultValue;
}
String ClArgs::getString(ox::StringViewCR arg, ox::StringView defaultValue) const noexcept {
auto [value, err] = m_strings.at(arg);
auto const [value, err] = m_strings.at(arg);
return !err ? ox::String(*value) : ox::String(defaultValue);
}
int ClArgs::getInt(ox::StringViewCR arg, int defaultValue) const noexcept {
auto [value, err] = m_ints.at(arg);
auto const [value, err] = m_ints.at(arg);
return !err ? *value : defaultValue;
}

View File

@@ -109,7 +109,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
"ClawHeaderReader",
[] {
constexpr auto hdr = ox::StringLiteral("O1;com.drinkingtea.ox.claw.test.Header;2;");
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.size() + 1});
oxAssert(err, "Error parsing header");
oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format wrong");
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header", "Type name wrong");
@@ -121,7 +121,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
"ClawHeaderReader2",
[] {
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;");
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.size() + 1});
oxAssert(err, "Error parsing header");
oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong");
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header2", "Type name wrong");
@@ -134,7 +134,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
[] {
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;awefawf");
constexpr auto expected = ox::StringLiteral("com.drinkingtea.ox.claw.test.Header2;3");
OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.len() + 1}));
OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.size() + 1}));
oxExpect(actual, expected);
return ox::Error{};
}

View File

@@ -52,7 +52,7 @@ struct OX_PACKED DirectoryEntry {
if (d.valid()) {
d->inode = inode;
auto const maxStrSz = bufferSize - 1 - sizeof(*this);
ox::strncpy(d->name, name.data(), ox::min(maxStrSz, name.len()));
ox::strncpy(d->name, name.data(), ox::min(maxStrSz, name.size()));
return {};
}
return ox::Error(1);
@@ -219,7 +219,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");
return ox::Error(1, "Could not read existing version of Directory");
}
const auto pathSize = name.len() + 1;
const auto pathSize = name.size() + 1;
const auto entryDataSize = DirectoryEntry<InodeId_t>::DirectoryEntryData::spaceNeeded(pathSize);
const auto newSize = oldStat.size + Buffer::spaceNeeded(entryDataSize);
auto cpy = ox_malloca(newSize, Buffer, *old, oldStat.size);

View File

@@ -87,7 +87,7 @@ class FileSystem {
return writeFilePath(path, buffer, size, FileType::NormalFile);
}
Error write(StringViewCR path, ox::Span<char> const&buff) noexcept {
Error write(StringViewCR path, ox::SpanView<char> const&buff) noexcept {
return write(path, buff.data(), buff.size(), FileType::NormalFile);
}
@@ -95,7 +95,7 @@ class FileSystem {
return write(inode, buffer, size, FileType::NormalFile);
}
Error write(uint64_t inode, ox::Span<char> const&buff) noexcept {
Error write(uint64_t inode, ox::SpanView<char> const&buff) noexcept {
return write(inode, buff.data(), buff.size(), FileType::NormalFile);
}

View File

@@ -206,7 +206,7 @@ Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) n
}
std::string_view PassThroughFS::stripSlash(StringView path) noexcept {
for (auto i = 0u; i < path.len() && path[0] == '/'; i++) {
for (auto i = 0u; i < path.size() && path[0] == '/'; i++) {
path = substr(path, 1);
}
return {path.data(), path.bytes()};

View File

@@ -74,7 +74,7 @@ Error PathIterator::get(StringView &fileName) {
if (size && fileName[size - 1] == '/') {
fileName = ox::substr(m_path, start, start + size - 1);
}
oxAssert(fileName[fileName.len()-1] != '/', "name ends in /");
oxAssert(fileName[fileName.size()-1] != '/', "name ends in /");
return {};
}
@@ -104,11 +104,11 @@ Error PathIterator::next(StringView &fileName) {
}
fileName = ox::substr(m_path, start, start + size);
// truncate trailing /
while (fileName.len() && fileName[fileName.len() - 1] == '/') {
while (fileName.size() && fileName[fileName.size() - 1] == '/') {
fileName = ox::substr(m_path, start, start + size);
}
m_iterator += size;
oxAssert(fileName.len() == 0 || fileName[fileName.len()-1] != '/', "name ends in /");
oxAssert(fileName.size() == 0 || fileName[fileName.size()-1] != '/', "name ends in /");
}
return retval;
}

View File

@@ -59,7 +59,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next1",
[](ox::StringView) {
auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len());
ox::PathIterator it(path.c_str(), path.size());
ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
@@ -84,7 +84,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next3",
[](ox::StringView) {
auto const path = ox::String("/");
ox::PathIterator it(path.c_str(), path.len());
ox::PathIterator it(path.c_str(), path.size());
ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "\0", "PathIterator shows wrong next");
return ox::Error(0);
@@ -106,7 +106,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::next5",
[](ox::StringView) {
auto const path = ox::String("usr/share/");
ox::PathIterator it(path.c_str(), path.len());
ox::PathIterator it(path.c_str(), path.size());
ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
@@ -117,10 +117,10 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
"PathIterator::dirPath",
[] (ox::StringView) {
auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
ox::PathIterator it(path.c_str(), path.size());
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
oxAssert(it.dirPath(buff, path.len()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
oxAssert(it.dirPath(buff, path.size()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
OX_ALLOW_UNSAFE_BUFFERS_END
return ox::Error(0);
}

View File

@@ -157,7 +157,6 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
oxAssert(testIn.String == testOut.String, "String value mismatch");
oxDebugf("{}", testOut.IString.len());
oxExpect(testIn.IString, testOut.IString);
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");

View File

@@ -191,12 +191,12 @@ template<Writer_c Writer>
template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<SmallStringSize> *val) noexcept {
bool fieldSet = false;
if (val->len() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
if (val->size() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
const auto strLen = mc::encodeInteger(val->len());
const auto strLen = mc::encodeInteger(val->size());
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<const char*>(strLen.data.data()), strLen.length));
// write the string
OX_RETURN_ERROR(m_writer.write(val->c_str(), static_cast<std::size_t>(val->len())));
OX_RETURN_ERROR(m_writer.write(val->c_str(), static_cast<std::size_t>(val->size())));
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
@@ -207,7 +207,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<Sm
template<Writer_c Writer>
template<std::size_t L>
constexpr Error MetalClawWriter<Writer>::field(const char *name, const IString<L> *val) noexcept {
return fieldCString(name, val->data(), val->len());
return fieldCString(name, val->data(), val->size());
}
template<Writer_c Writer>
@@ -339,7 +339,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
OX_RETURN_ERROR(handler.setTypeInfo("Map", 0, {}, len * 2));
// this loop body needs to be in a lambda because of the potential alloca call
constexpr auto loopBody = [](auto &handler, auto const&key, auto const&val) -> ox::Error {
const auto keyLen = key.len();
const auto keyLen = key.size();
auto wkey = ox_malloca(keyLen + 1, char, 0);
memcpy(wkey.get(), key.c_str(), keyLen + 1);
OX_RETURN_ERROR(handler.fieldCString("", wkey.get(), keyLen));

View File

@@ -43,7 +43,7 @@ static constexpr auto buildTypeId(
for (const auto &p : typeParams) {
tp += p + ",";
}
tp.resize(tp.len() - 1);
tp.resize(tp.size() - 1);
tp += "#";
}
return ox::sfmt("{}{};{}", name, tp, version);

View File

@@ -144,7 +144,7 @@ template<typename T, typename Str = const char*>
[[nodiscard]]
consteval auto requireModelTypeName() noexcept {
constexpr auto name = getModelTypeName<T, Str>();
static_assert(ox::StringView{name}.len(), "Type lacks required TypeName");
static_assert(ox::StringView{name}.size(), "Type lacks required TypeName");
return name;
}
@@ -159,7 +159,7 @@ constexpr auto ModelTypeId_v = [] {
constexpr auto name = ModelTypeName_v<T, ox::StringView>;
constexpr auto version = ModelTypeVersion_v<T>;
constexpr auto versionStr = ox::sfmt<ox::IString<19>>("{}", version);
return ox::sfmt<ox::IString<name.len() + versionStr.len() + 1>>("{};{}", name, versionStr);
return ox::sfmt<ox::IString<name.size() + versionStr.size() + 1>>("{};{}", name, versionStr);
}();
}

View File

@@ -181,7 +181,6 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
}
}
} catch (Json::LogicError const&e) {
oxDebugf("JSON error: {}", e.what());
err = ox::Error(1, "error reading JSON data");
}
++m_fieldIt;
@@ -307,7 +306,7 @@ Result<T> readOC(BufferView buff) noexcept {
template<typename T>
Result<T> readOC(ox::StringView json) noexcept {
return readOC<T>(ox::BufferView{json.data(), json.len()});
return readOC<T>(ox::BufferView{json.data(), json.size()});
}
}

View File

@@ -32,7 +32,7 @@ Error OrganicClawWriter::fieldCString(const char *key, const char *const*val) no
Error OrganicClawWriter::field(const char *key, const UUID *uuid) noexcept {
const auto uuidStr = uuid->toString();
if (targetValid() && uuidStr.len()) {
if (targetValid() && uuidStr.size()) {
value(key) = uuidStr.c_str();
}
++m_fieldIt;

View File

@@ -138,7 +138,7 @@ class OrganicClawWriter {
template<std::size_t L>
Error field(char const*key, IString<L> const*val) noexcept {
if (targetValid() && val->len()) {
if (targetValid() && val->size()) {
value(key) = val->c_str();
}
++m_fieldIt;
@@ -147,7 +147,7 @@ class OrganicClawWriter {
template<std::size_t L>
Error field(char const*key, BasicString<L> const*val) noexcept {
if (targetValid() && val->len()) {
if (targetValid() && val->size()) {
value(key) = val->c_str();
}
++m_fieldIt;

View File

@@ -33,6 +33,9 @@ void panic(StringViewCR file, int const line, StringViewCR panicMsg, Error const
#endif
}
#if __GNUC__ && !_WIN32
__attribute__((weak))
#endif
void panic(const char *file, int const line, char const*panicMsg, Error const&err) noexcept {
panic(StringView{file}, line, StringView{panicMsg}, err);
}

View File

@@ -185,7 +185,7 @@ class BaseStringView {
}
[[nodiscard]]
constexpr auto len() const noexcept {
constexpr auto size() const noexcept {
return m_len;
}

View File

@@ -21,13 +21,13 @@ class CStringView: public detail::BaseStringView {
constexpr CStringView(CStringView const&sv) noexcept = default;
constexpr CStringView(StringLiteral const&str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr CStringView(StringLiteral const&str) noexcept: BaseStringView(str.data(), str.size()) {}
template<std::size_t SmallStrSz>
constexpr CStringView(BasicString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr CStringView(BasicString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.size()) {}
template<std::size_t SmallStrSz>
constexpr CStringView(IString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr CStringView(IString<SmallStrSz> const&str) noexcept: BaseStringView(str.data(), str.size()) {}
constexpr CStringView(std::nullptr_t) noexcept {}
@@ -37,7 +37,7 @@ class CStringView: public detail::BaseStringView {
constexpr auto &operator=(CStringView const&other) noexcept {
if (&other != this) {
set(other.data(), other.len());
set(other.data(), other.size());
}
return *this;
}

View File

@@ -307,6 +307,13 @@ struct [[nodiscard]] Result {
return std::move(value);
}
constexpr Result transformError(ErrorCode const ec, CString const msg) && {
if (error) {
error = Error{ec, msg};
}
return *this;
}
};
namespace detail {

View File

@@ -16,7 +16,7 @@
namespace std {
inline constexpr struct {
inline constexpr struct ignore_t {
constexpr void operator=(auto&&) const noexcept {}
} ignore;

View File

@@ -72,7 +72,7 @@ class IString {
* Returns the number of characters in this string.
*/
[[nodiscard]]
constexpr std::size_t len() const noexcept;
constexpr std::size_t size() const noexcept;
/**
* Returns the number of bytes used for this string.
@@ -121,7 +121,7 @@ constexpr IString<size> &IString<size>::operator=(Integer_c auto i) noexcept {
template<std::size_t size>
constexpr IString<size> &IString<size>::operator=(ox::StringViewCR str) noexcept {
std::size_t strLen = str.len();
std::size_t strLen = str.size();
if (cap() < strLen) {
strLen = cap();
}
@@ -171,7 +171,7 @@ constexpr char &IString<StrCap>::operator[](std::size_t i) noexcept {
template<std::size_t StrCap>
constexpr Error IString<StrCap>::append(const char *str, std::size_t strLen) noexcept {
Error err{};
auto const currentLen = len();
auto const currentLen = size();
if (cap() < currentLen + strLen) {
strLen = cap() - currentLen;
err = ox::Error(1, "Insufficient space for full string");
@@ -187,7 +187,7 @@ OX_CLANG_NOWARN_END
template<std::size_t StrCap>
constexpr Error IString<StrCap>::append(ox::StringView str) noexcept {
return append(str.data(), str.len());
return append(str.data(), str.size());
}
template<std::size_t StrCap>
@@ -207,7 +207,7 @@ constexpr const char *IString<StrCap>::c_str() const noexcept {
template<std::size_t StrCap>
constexpr std::size_t IString<StrCap>::len() const noexcept {
constexpr std::size_t IString<StrCap>::size() const noexcept {
return m_size;
}

View File

@@ -213,8 +213,7 @@ class UniquePtr {
return m_t;
}
template<typename U, typename UDeleter>
constexpr void reset(UniquePtr<U, UDeleter> &&other = UniquePtr()) {
constexpr void reset(UniquePtr &&other = UniquePtr()) {
auto t = m_t;
m_t = other.release();
Deleter()(t);

View File

@@ -30,11 +30,49 @@ constexpr void *operator new(std::size_t, void *addr) noexcept {
constexpr void *operator new[](std::size_t, void *addr) noexcept {
return addr;
}
namespace std {
template<typename T>
[[nodiscard]]
constexpr T* launder(T* __p) noexcept {
return __builtin_launder(__p);
}
template<typename T, typename... Args, bool noex>
void launder(T(*)(Args...) noexcept(noex)) = delete;
template<typename T, typename... Args, bool noex>
void launder(T(*)(Args......) noexcept(noex)) = delete;
void launder(void*) = delete;
void launder(void const*) = delete;
void launder(volatile void*) = delete;
void launder(volatile void const*) = delete;
}
#endif
namespace ox {
/**
* Aliases type T in size and alignment to allow allocating space for a T
* without running the constructor.
*/
template<typename T, std::size_t sz = sizeof(T)>
struct alignas(alignof(T)) AllocAlias {
char buff[sz];
constexpr AllocAlias() noexcept = default;
[[nodiscard]]
auto data() noexcept {
return reinterpret_cast<T*>(this);
}
[[nodiscard]]
auto data() const noexcept {
return reinterpret_cast<T const*>(this);
}
};
template<typename T, typename U = T, typename ...Args>
[[nodiscard]]
constexpr U *make(Args &&...args) noexcept {

View File

@@ -30,13 +30,15 @@ constexpr std::ios_base::seekdir sdMap(ox::ios_base::seekdir in) noexcept {
ox::Result<char> StreamReader::peek() const noexcept {
try {
if (m_strm.eof()) {
return Error{1, "EOF"};
}
char c{};
m_strm.get(c);
auto const ok = c != EOF;
if (ok && m_strm.unget()) [[unlikely]] {
return ox::Error(1, "Unable to unget character");
if (m_strm.unget()) [[unlikely]] {
return ox::Error{1, "Unable to unget character"};
}
return {static_cast<char>(c), ox::Error(!ok, "File peek failed")};
return static_cast<char>(c);
} catch (std::exception const&) {
return ox::Error(1, "peek failed");
}

View File

@@ -163,6 +163,24 @@ class Span {
return *this;
}
constexpr Span operator++(int) noexcept {
++m_items;
--m_size;
if (!m_size) [[unlikely]] {
m_items = nullptr;
}
return *this;
}
constexpr Span operator++() noexcept {
++m_items;
--m_size;
if (!m_size) [[unlikely]] {
m_items = nullptr;
}
return *this;
}
[[nodiscard]]
constexpr auto data() const noexcept {
return m_items;

View File

@@ -139,7 +139,7 @@ class BasicString {
constexpr BasicString &operator+=(Integer_c auto i) noexcept;
constexpr BasicString &operator+=(StringView src) noexcept;
constexpr BasicString &operator+=(StringViewCR src) noexcept;
constexpr BasicString &operator+=(BasicString const&src) noexcept;
@@ -176,7 +176,7 @@ class BasicString {
constexpr char &operator[](std::size_t i) noexcept;
constexpr Error append(const char *str, std::size_t strLen) noexcept {
auto currentLen = len();
auto currentLen = size();
m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&m_buff[currentLen], str, strLen);
// make sure last element is a null terminator
@@ -185,8 +185,8 @@ class BasicString {
return {};
}
constexpr Error append(ox::StringView sv) noexcept {
return append(sv.data(), sv.len());
constexpr Error append(StringViewCR sv) noexcept {
return append(sv.data(), sv.size());
}
[[nodiscard]]
@@ -237,7 +237,7 @@ class BasicString {
* Returns the number of characters in this string.
*/
[[nodiscard]]
constexpr std::size_t len() const noexcept;
constexpr std::size_t size() const noexcept;
/**
* Returns the number of bytes used for this string.
@@ -277,7 +277,7 @@ constexpr BasicString<SmallStringSize_v>::BasicString(const char *str, std::size
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(StringLiteral const&str) noexcept:
BasicString(StringView{str.data(), str.len()}) {
BasicString(StringView{str.data(), str.size()}) {
}
template<std::size_t SmallStringSize_v>
@@ -376,7 +376,7 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringView s) noexcept {
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringViewCR s) noexcept {
std::size_t strLen = s.bytes();
std::ignore = append(s.data(), strLen);
return *this;
@@ -384,14 +384,14 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(BasicString const&src) noexcept {
std::ignore = append(src.c_str(), src.len());
std::ignore = append(src.c_str(), src.size());
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(const char *str) const noexcept {
const std::size_t strLen = ox::strlen(str);
const auto currentLen = len();
const auto currentLen = size();
BasicString<SmallStringSize_v> cpy;
cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
@@ -420,8 +420,8 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operato
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(StringViewCR src) const noexcept {
const std::size_t strLen = src.len();
const auto currentLen = len();
const std::size_t strLen = src.size();
const auto currentLen = size();
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
@@ -432,8 +432,8 @@ constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operato
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(BasicString const&src) const noexcept {
const std::size_t strLen = src.len();
const auto currentLen = len();
const std::size_t strLen = src.size();
const auto currentLen = size();
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen);
ox::listcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
@@ -456,7 +456,7 @@ constexpr bool BasicString<SmallStringSize_v>::operator==(const char *other) con
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator==(OxString_c auto const&other) const noexcept {
return ox::StringView(*this) == ox::StringView(other);
return StringView(*this) == StringView(other);
}
template<std::size_t SmallStringSize_v>
@@ -521,7 +521,7 @@ constexpr std::size_t BasicString<SmallStringSize_v>::bytes() const noexcept {
}
template<std::size_t SmallStringSize_v>
constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept {
constexpr std::size_t BasicString<SmallStringSize_v>::size() const noexcept {
return m_buff.size() - 1;
}
@@ -548,28 +548,28 @@ using StringCR = String const&;
[[nodiscard]]
constexpr ox::String toString(ox::StringViewCR sv) noexcept {
constexpr String toString(StringViewCR sv) noexcept {
return ox::String(sv);
}
template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]]
constexpr auto sizeOf(const ox::BasicString<SmallStringSize_v>*) noexcept {
constexpr auto sizeOf(BasicString<SmallStringSize_v> const*) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return sizeOf<PlatSpec>(&v);
}
template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]]
constexpr auto alignOf(const ox::BasicString<SmallStringSize_v>&) noexcept {
constexpr auto alignOf(BasicString<SmallStringSize_v> const&) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return alignOf<PlatSpec>(&v);
}
template<size_t sz>
struct MaybeView<ox::BasicString<sz>> {
using type = ox::StringView;
struct MaybeView<BasicString<sz>> {
using type = StringView;
};
}

View File

@@ -16,11 +16,6 @@ namespace ox {
* StringLiteral is used for functions that want to ensure that they are taking
* string literals, and not strings outside of the data section of the program
* that might get deleted.
* This type cannot force you to use it correctly, so don't give it something
* that is not a literal.
* If you do this:
* StringLiteral(str.c_str())
* the resulting segfault is on you.
*/
class StringLiteral: public detail::BaseStringView {
public:
@@ -28,21 +23,21 @@ class StringLiteral: public detail::BaseStringView {
constexpr StringLiteral(StringLiteral const &sv) noexcept = default;
constexpr explicit StringLiteral(std::nullptr_t) noexcept {}
consteval explicit StringLiteral(std::nullptr_t) noexcept {}
constexpr explicit StringLiteral(const char *str, std::size_t len) noexcept: BaseStringView{str, len} {}
consteval explicit StringLiteral(char const *str, std::size_t const len) noexcept: BaseStringView{str, len} {}
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
constexpr explicit StringLiteral(char const *str) noexcept: StringLiteral{str, ox::strlen(str)} {}
consteval explicit StringLiteral(char const *str) noexcept: StringLiteral{str, ox::strlen(str)} {}
OX_ALLOW_UNSAFE_BUFFERS_END
constexpr StringLiteral &operator=(StringLiteral const &other) noexcept {
set(other.data(), other.len());
set(other.data(), other.size());
return *this;
}
[[nodiscard]]
constexpr const char *c_str() const noexcept {
constexpr char const *c_str() const noexcept {
return data();
}

View File

@@ -8,6 +8,7 @@
#pragma once
#include "cstringview.hpp"
#include "string.hpp"
namespace ox {

View File

@@ -40,10 +40,10 @@ class StringView: public detail::BaseStringView {
constexpr StringView(BaseStringView const&str) noexcept: BaseStringView(str.data(), str.bytes()) {}
template<std::size_t SmallStrSz>
constexpr StringView(const BasicString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr StringView(const BasicString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.size()) {}
template<std::size_t SmallStrSz>
constexpr StringView(const IString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.len()) {}
constexpr StringView(const IString<SmallStrSz> &str) noexcept: BaseStringView(str.data(), str.size()) {}
constexpr StringView(std::nullptr_t) noexcept {}
@@ -53,7 +53,7 @@ class StringView: public detail::BaseStringView {
constexpr auto &operator=(StringView const&other) noexcept {
if (&other != this) {
set(other.data(), other.len());
set(other.data(), other.size());
}
return *this;
}
@@ -63,14 +63,14 @@ class StringView: public detail::BaseStringView {
using StringViewCR = StringView const&;
constexpr auto operator==(StringViewCR s1, StringViewCR s2) noexcept {
if (s2.len() != s1.len()) {
if (s2.size() != s1.size()) {
return false;
}
return ox::strncmp(s1.data(), s2.data(), s1.len()) == 0;
return ox::strncmp(s1.data(), s2.data(), s1.size()) == 0;
}
constexpr auto operator<=>(StringViewCR s1, StringViewCR s2) noexcept {
const auto maxLen = ox::min(s1.len(), s2.len());
const auto maxLen = ox::min(s1.size(), s2.size());
const auto a = &s1.front();
const auto b = &s2.front();
for (std::size_t i = 0; i < maxLen && (a[i] || b[i]); ++i) {
@@ -80,9 +80,9 @@ constexpr auto operator<=>(StringViewCR s1, StringViewCR s2) noexcept {
return 1;
}
}
if (s1.len() > s2.len()) {
if (s1.size() > s2.size()) {
return 1;
} else if (s1.len() < s2.len()) {
} else if (s1.size() < s2.size()) {
return -1;
} else {
return 0;
@@ -104,10 +104,10 @@ constexpr ox::Result<int> strToInt(StringViewCR str) noexcept {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
int total = 0;
int multiplier = 1;
if (str.len() == 0) [[unlikely]] {
if (str.size() == 0) [[unlikely]] {
return Error{1, "Empty string passed to strToInt"};
}
for (auto i = static_cast<int64_t>(str.len()) - 1; i != -1; --i) {
for (auto i = static_cast<int64_t>(str.size()) - 1; i != -1; --i) {
auto s = static_cast<std::size_t>(i);
if (str[s] >= '0' && str[s] <= '9') {
total += (str[s] - '0') * multiplier;

View File

@@ -21,37 +21,47 @@ OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
[[nodiscard]]
constexpr ox::StringView substr(ox::StringView const&str, std::size_t pos) noexcept {
if (str.len() >= pos) {
return {&str[pos], str.len() - pos};
constexpr StringView substr(StringViewCR str, std::size_t const pos) noexcept {
if (str.size() >= pos) {
return {&str[pos], str.size() - pos};
}
return {};
}
[[nodiscard]]
constexpr ox::StringView substr(ox::StringView const&str, std::size_t start, std::size_t end) noexcept {
if (str.len() >= start && end >= start) {
constexpr StringView substr(StringViewCR str, std::size_t const start, std::size_t const end) noexcept {
if (str.size() >= start && end >= start) {
return {&str[start], end - start};
}
return {};
}
[[nodiscard]]
constexpr bool beginsWith(StringViewCR base, char const beginning) noexcept {
return base.size() && base[0] == beginning;
}
[[nodiscard]]
constexpr bool endsWith(StringViewCR base, char const ending) noexcept {
return base.size() && base[base.size() - 1] == ending;
}
[[nodiscard]]
constexpr bool beginsWith(StringViewCR base, StringViewCR beginning) noexcept {
const auto beginningLen = ox::min(beginning.len(), base.len());
return base.len() >= beginning.len() && ox::strncmp(base.data(), beginning, beginningLen) == 0;
const auto beginningLen = ox::min(beginning.size(), base.size());
return base.size() >= beginning.size() && ox::strncmp(base.data(), beginning, beginningLen) == 0;
}
[[nodiscard]]
constexpr bool endsWith(StringViewCR base, StringViewCR ending) noexcept {
const auto endingLen = ending.len();
return base.len() >= endingLen && ox::strcmp(base.data() + (base.len() - endingLen), ending) == 0;
const auto endingLen = ending.size();
return base.size() >= endingLen && ox::strcmp(base.data() + (base.size() - endingLen), ending) == 0;
}
[[nodiscard]]
constexpr std::size_t find(StringViewCR str, char search) noexcept {
constexpr std::size_t find(StringViewCR str, char const search) noexcept {
std::size_t i = 0;
for (; i < str.len(); ++i) {
for (; i < str.size(); ++i) {
if (str[i] == search) {
break;
}
@@ -62,7 +72,7 @@ constexpr std::size_t find(StringViewCR str, char search) noexcept {
[[nodiscard]]
constexpr std::size_t find(StringViewCR str, StringViewCR search) noexcept {
std::size_t i = 0;
for (; i < str.len(); ++i) {
for (; i < str.size(); ++i) {
if (beginsWith(substr(str, i), search)) {
break;
}
@@ -72,14 +82,14 @@ constexpr std::size_t find(StringViewCR str, StringViewCR search) noexcept {
template<std::size_t smallSz = 0>
[[nodiscard]]
constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, char del) noexcept {
constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, char const del) noexcept {
ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](StringViewCR current, char del) {
return substr(current, find(current, del) + 1);
};
for (auto current = str; current.len(); current = nextSeg(current, del)) {
for (auto current = str; current.size(); current = nextSeg(current, del)) {
const auto next = find(current, del);
if (const auto s = substr(current, 0, next); s.len()) {
if (const auto s = substr(current, 0, next); s.size()) {
out.emplace_back(s);
}
current = substr(current, next);
@@ -92,11 +102,11 @@ template<std::size_t smallSz = 0>
constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, StringViewCR del) noexcept {
ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](StringViewCR current, StringViewCR del) {
return substr(current, find(current, del) + del.len());
return substr(current, find(current, del) + del.size());
};
for (auto current = str; current.len(); current = nextSeg(current, del)) {
for (auto current = str; current.size(); current = nextSeg(current, del)) {
const auto next = find(current, del);
if (const auto s = substr(current, 0, next); s.len()) {
if (const auto s = substr(current, 0, next); s.size()) {
out.emplace_back(s);
}
current = substr(current, next);
@@ -105,7 +115,7 @@ constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, StringView
}
[[nodiscard]]
constexpr ox::Result<std::size_t> lastIndexOf(ox::StringViewCR str, int character) noexcept {
constexpr ox::Result<std::size_t> lastIndexOf(ox::StringViewCR str, int const character) noexcept {
ox::Result<std::size_t> retval = ox::Error(1, "Character not found");
for (auto i = static_cast<int>(str.bytes() - 1); i >= 0; --i) {
if (str[static_cast<std::size_t>(i)] == character) {

View File

@@ -183,7 +183,7 @@ OX_CLANG_NOWARN_END
s = "asdf";
oxAssert(s == "asdf", "String assign broken");
oxAssert(s != "aoeu", "String assign broken");
oxAssert(s.len() == 4, "String assign broken");
oxAssert(s.size() == 4, "String assign broken");
return ox::Error(0);
}
},
@@ -337,7 +337,6 @@ OX_CLANG_NOWARN_END
oxExpect(si["asdf"], 0);
oxAssert(si["aoeu"] == 100, "aoeu != 100");
auto si2 = si;
oxDebugf("{}", si2["asdf"]);
oxExpect(si2["asdf"], 0);
oxAssert(si2["aoeu"] == 100, "aoeu != 100");
ox::HashMap<int, int> ii;

View File

@@ -166,7 +166,7 @@ class OutStream {
constexpr OutStream &operator<<(Integer_c auto v) noexcept;
constexpr OutStream &operator<<(char v) noexcept {
if (m_msg.msg.len()) {
if (m_msg.msg.size()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += v;
@@ -174,7 +174,7 @@ class OutStream {
}
constexpr OutStream &operator<<(StringViewCR v) noexcept {
if (m_msg.msg.len()) {
if (m_msg.msg.size()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += v;
@@ -209,7 +209,7 @@ class OutStream {
private:
constexpr OutStream &appendSignedInt(int64_t v) noexcept {
if (m_msg.msg.len()) {
if (m_msg.msg.size()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += static_cast<int64_t>(v);
@@ -217,7 +217,7 @@ class OutStream {
}
constexpr OutStream &appendUnsignedInt(uint64_t v) noexcept {
if (m_msg.msg.len()) {
if (m_msg.msg.size()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += static_cast<int64_t>(v);
@@ -227,7 +227,7 @@ class OutStream {
};
constexpr OutStream &OutStream::operator<<(Integer_c auto v) noexcept {
if (m_msg.msg.len()) {
if (m_msg.msg.size()) {
m_msg.msg += m_delimiter;
}
m_msg.msg += v;
@@ -268,7 +268,7 @@ using TraceStream = NullStream;
inline void logError(const char *file, int line, const char *fmt, const Error &err) noexcept {
if (err) {
TraceStream trc(file, line, "ox::error");
TraceStream trc(file, line, "ox.error");
if (err.src.file_name() != nullptr) {
trc << "Error: (" << err.src.file_name() << ":" << err.src.line() << "):";
} else {
@@ -280,7 +280,7 @@ inline void logError(const char *file, int line, const char *fmt, const Error &e
inline void logError(const char *file, int line, const Error &err) noexcept {
if (err) {
TraceStream trc(file, line, "ox::error");
TraceStream trc(file, line, "ox.error");
trc << "Error:" << err;
if (err.src.file_name() != nullptr) {
trc << "(" << err.src.file_name() << ":" << err.src.line() << ")";

View File

@@ -63,25 +63,6 @@ namespace ox {
using CString = char const*;
/**
* Aliases type T in size and alignment to allow allocating space for a T
* without running the constructor.
*/
template<typename T, std::size_t sz = sizeof(T)>
struct alignas(alignof(T)) AllocAlias {
char buff[sz];
constexpr AllocAlias() noexcept = default;
[[nodiscard]]
auto data() noexcept {
return reinterpret_cast<T*>(this);
}
[[nodiscard]]
auto data() const noexcept {
return reinterpret_cast<const T*>(this);
}
};
template<std::size_t sz>
struct SignedType {
};

View File

@@ -58,7 +58,7 @@ constexpr ox::Result<uint8_t> fromHex(ox::StringViewCR v) noexcept {
if (!detail::isHexChar(v[0]) || !detail::isHexChar(v[1])) {
return ox::Error(1, "Invalid UUID");
}
if (v.len() != 2) {
if (v.size() != 2) {
return ox::Error(2);
}
uint8_t out = 0;
@@ -133,18 +133,18 @@ class UUID {
}
static constexpr ox::Result<ox::UUID> fromString(ox::StringViewCR s) noexcept {
if (s.len() < 36) {
if (s.size() < 36) {
return ox::Error(1, "Insufficient data to contain a complete UUID");
}
UUID out;
auto valueI = 0u;
for (size_t i = 0; i < s.len();) {
for (size_t i = 0; i < s.size();) {
if (s[i] == '-') {
++i;
continue;
}
const auto seg = substr(s, i, i + 2);
if (seg.len() != 2) {
if (seg.size() != 2) {
return ox::Error(1, "Invalid UUID");
}
OX_REQUIRE(val, detail::fromHex(seg));
@@ -174,7 +174,7 @@ class UUID {
for (auto i = 0u; i < cnt; ++i) {
const auto v = value[valueI];
const auto h = detail::toHex(v);
std::ignore = writer.write(h.c_str(), h.len());
std::ignore = writer.write(h.c_str(), h.size());
++valueI;
}
};

View File

@@ -34,10 +34,10 @@ struct VectorAllocator {
ox::Array<AllocAlias<T>, Size> m_data = {};
protected:
constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t cap) noexcept {
constexpr void allocate(T **items, std::size_t const cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated() || cap > Size) {
*items = Allocator{}.allocate(cap);
@@ -49,45 +49,38 @@ struct VectorAllocator {
constexpr void moveConstructItemsFrom(
T **items,
VectorAllocator *src,
const std::size_t count,
const std::size_t cap) noexcept {
std::size_t const count,
std::size_t const cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later
if (!std::is_constant_evaluated()) {
if (cap <= m_data.size() && count <= m_data.size()) {
for (auto i = 0u; i < count; ++i) {
const auto dstItem = reinterpret_cast<T *>(&m_data[i]);
const auto srcItem = reinterpret_cast<T *>(&src->m_data[i]);
std::construct_at<T>(dstItem, std::move(*srcItem));
auto const srcItem = std::launder(reinterpret_cast<T*>(&src->m_data[i]));
#if defined(__GNUC__) && __GNUC__ >= 12
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow="
#endif
new (&m_data[i]) T(std::move(*srcItem));
#if defined(__GNUC__) && __GNUC__ >= 12
#pragma GCC diagnostic pop
#endif
}
if (count) {
*items = std::launder(reinterpret_cast<T*>(m_data.data()));
} else {
*items = reinterpret_cast<T*>(m_data.data());
}
*items = reinterpret_cast<T*>(m_data.data());
}
}
}
constexpr void moveItemsFrom(
T **items,
VectorAllocator *src,
const std::size_t count,
const std::size_t cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later
if (!std::is_constant_evaluated()) {
if (cap <= m_data.size() && count <= m_data.size()) {
for (std::size_t i = 0; i < count; ++i) {
const auto dstItem = reinterpret_cast<T *>(&m_data[i]);
const auto srcItem = reinterpret_cast<T *>(&src->m_data[i]);
*dstItem = std::move(*srcItem);
}
*items = reinterpret_cast<T*>(m_data.data());
}
}
}
constexpr void deallocate(T *items, std::size_t cap) noexcept {
constexpr void deallocate(T *const items, std::size_t const cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated()) {
Allocator{}.deallocate(items, cap);
if (items) {
Allocator{}.deallocate(items, cap);
}
} else {
if (items && static_cast<void*>(items) != static_cast<void*>(m_data.data())) {
Allocator{}.deallocate(items, cap);
@@ -101,10 +94,10 @@ template<typename T, typename Allocator>
struct VectorAllocator<T, Allocator, 0> {
protected:
constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(const VectorAllocator&) noexcept = default;
constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) noexcept = default;
constexpr void allocate(T **items, std::size_t cap) noexcept {
constexpr void allocate(T **items, std::size_t const cap) noexcept {
*items = Allocator{}.allocate(cap);
}
@@ -112,15 +105,15 @@ struct VectorAllocator<T, Allocator, 0> {
constexpr void moveConstructItemsFrom(
T**,
VectorAllocator*,
const std::size_t,
const std::size_t) noexcept {
std::size_t const,
std::size_t const) noexcept {
}
[[maybe_unused]]
constexpr void moveItemsFrom(T**, VectorAllocator*, const std::size_t, const std::size_t) noexcept {
constexpr void moveItemsFrom(T**, VectorAllocator*, std::size_t const, std::size_t const) noexcept {
}
constexpr void deallocate(T *items, std::size_t cap) noexcept {
constexpr void deallocate(T *const items, std::size_t const cap) noexcept {
if (items) {
Allocator{}.deallocate(items, cap);
}
@@ -285,7 +278,9 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
template<typename... Args>
constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept);
constexpr void push_back(T item) noexcept(useNoexcept);
constexpr void push_back(T const &item) noexcept(useNoexcept);
constexpr void push_back(T &&item) noexcept(useNoexcept);
constexpr void pop_back() noexcept(useNoexcept);
@@ -419,7 +414,7 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
m_size = other.m_size;
m_cap = other.m_cap;
m_items = other.m_items;
this->moveItemsFrom(&m_items, &other, m_size, m_cap);
this->moveConstructItemsFrom(&m_items, &other, m_size, m_cap);
other.m_size = 0;
other.m_cap = 0;
other.m_items = nullptr;
@@ -615,7 +610,16 @@ constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args)
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T item) noexcept(useNoexcept) {
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T const &item) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap);
}
std::construct_at(&m_items[m_size], item);
++m_size;
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(T &&item) noexcept(useNoexcept) {
if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap);
}

View File

@@ -5,103 +5,117 @@
#pragma once
#include <ox/std/array.hpp>
#include <ox/std/types.hpp>
#include <ox/std/units.hpp>
/////////////////////////////////////////////////////////////////
// Interrupt Handler
using interrupt_handler = void (*)();
#define REG_ISR *reinterpret_cast<interrupt_handler*>(0x0300'7FFC)
#define REG_IE *reinterpret_cast<volatile uint16_t*>(0x0400'0200)
#define REG_IF *reinterpret_cast<volatile uint16_t*>(0x0400'0202)
#define REG_IME *reinterpret_cast<volatile uint16_t*>(0x0400'0208)
using InterruptHandler = void(*)();
#define REG_ISR (*reinterpret_cast<InterruptHandler*>(0x0300'7FFC))
#define REG_IE (*reinterpret_cast<volatile uint16_t*>(0x0400'0200))
#define REG_IF (*reinterpret_cast<volatile uint16_t*>(0x0400'0202))
#define REG_IME (*reinterpret_cast<volatile uint16_t*>(0x0400'0208))
/////////////////////////////////////////////////////////////////
// Display Registers
#define REG_DISPCTL *reinterpret_cast<volatile uint32_t*>(0x0400'0000)
#define REG_DISPSTAT *reinterpret_cast<volatile uint32_t*>(0x0400'0004)
#define REG_VCOUNT *reinterpret_cast<volatile uint32_t*>(0x0400'0006)
#define REG_DISPCTL (*reinterpret_cast<volatile uint32_t*>(0x0400'0000))
#define REG_DISPSTAT (*reinterpret_cast<volatile uint32_t*>(0x0400'0004))
#define REG_VCOUNT (*reinterpret_cast<volatile uint32_t*>(0x0400'0006))
/////////////////////////////////////////////////////////////////
// Timers
#define REG_TIMER0 *reinterpret_cast<volatile uint16_t*>(0x0400'0100)
#define REG_TIMER0CTL *reinterpret_cast<volatile uint16_t*>(0x0400'0102)
#define REG_TIMER0 (*reinterpret_cast<volatile uint16_t*>(0x0400'0100))
#define REG_TIMER0CTL (*reinterpret_cast<volatile uint16_t*>(0x0400'0102))
#define REG_TIMER1 *reinterpret_cast<volatile uint16_t*>(0x0400'0104)
#define REG_TIMER1CTL *reinterpret_cast<volatile uint16_t*>(0x0400'0106)
#define REG_TIMER1 (*reinterpret_cast<volatile uint16_t*>(0x0400'0104))
#define REG_TIMER1CTL (*reinterpret_cast<volatile uint16_t*>(0x0400'0106))
#define REG_TIMER2 *reinterpret_cast<volatile uint16_t*>(0x0400'0108)
#define REG_TIMER2CTL *reinterpret_cast<volatile uint16_t*>(0x0400'010a)
#define REG_TIMER2 (*reinterpret_cast<volatile uint16_t*>(0x0400'0108))
#define REG_TIMER2CTL (*reinterpret_cast<volatile uint16_t*>(0x0400'010a))
#define REG_TIMER3 *reinterpret_cast<volatile uint16_t*>(0x0400'010c)
#define REG_TIMER3CTL *reinterpret_cast<volatile uint16_t*>(0x0400'010e)
#define REG_TIMER3 (*reinterpret_cast<volatile uint16_t*>(0x0400'010c))
#define REG_TIMER3CTL (*reinterpret_cast<volatile uint16_t*>(0x0400'010e))
/////////////////////////////////////////////////////////////////
// background registers
// background control registers
using BgCtl = uint16_t;
#define REG_BG0CTL *reinterpret_cast<volatile BgCtl*>(0x0400'0008)
#define REG_BG1CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000a)
#define REG_BG2CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000c)
#define REG_BG3CTL *reinterpret_cast<volatile BgCtl*>(0x0400'000e)
#define REG_BG0CTL (*reinterpret_cast<volatile BgCtl*>(0x0400'0008))
#define REG_BG1CTL (*reinterpret_cast<volatile BgCtl*>(0x0400'000a))
#define REG_BG2CTL (*reinterpret_cast<volatile BgCtl*>(0x0400'000c))
#define REG_BG3CTL (*reinterpret_cast<volatile BgCtl*>(0x0400'000e))
[[nodiscard]]
inline volatile BgCtl &regBgCtl(uintptr_t bgIdx) noexcept {
inline volatile BgCtl &regBgCtl(uintptr_t const bgIdx) noexcept {
return *reinterpret_cast<volatile BgCtl*>(0x0400'0008 + 2 * bgIdx);
}
// background horizontal scrolling registers
#define REG_BG0HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0010)
#define REG_BG1HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0014)
#define REG_BG2HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0018)
#define REG_BG3HOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001c)
#define REG_BG0HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0010))
#define REG_BG1HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0014))
#define REG_BG2HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0018))
#define REG_BG3HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'001c))
[[nodiscard]]
inline volatile uint32_t &regBgHofs(auto bgIdx) noexcept {
return *reinterpret_cast<volatile uint32_t*>(0x0400'0010 + 4 * bgIdx);
volatile int16_t &regBgHofs(auto const bgIdx) noexcept {
return *reinterpret_cast<volatile int16_t*>(0x0400'0010 + 4 * bgIdx);
}
// background vertical scrolling registers
#define REG_BG0VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0012)
#define REG_BG1VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'0016)
#define REG_BG2VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001a)
#define REG_BG3VOFS *reinterpret_cast<volatile uint32_t*>(0x0400'001e)
#define REG_BG0VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0012))
#define REG_BG1VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0016))
#define REG_BG2VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'001a))
#define REG_BG3VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'001e))
[[nodiscard]]
inline volatile uint32_t &regBgVofs(auto bgIdx) noexcept {
return *reinterpret_cast<volatile uint32_t*>(0x0400'0012 + 4 * bgIdx);
volatile int16_t &regBgVofs(auto const bgIdx) noexcept {
return *reinterpret_cast<volatile int16_t*>(0x0400'0012 + 4 * bgIdx);
}
// background scrolling registers
struct OffsetPair {
int16_t x{}, y{};
};
#define REG_BG0OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'0010))
#define REG_BG1OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'0014))
#define REG_BG2OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'0018))
#define REG_BG3OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'001c))
[[nodiscard]]
volatile OffsetPair &regBgOfs(auto const bgIdx) noexcept {
return *reinterpret_cast<volatile OffsetPair*>(0x0400'0010 + sizeof(OffsetPair) * bgIdx);
}
/////////////////////////////////////////////////////////////////
// User Input
#define REG_GAMEPAD *reinterpret_cast<volatile uint16_t*>(0x0400'0130)
#define REG_GAMEPAD (*reinterpret_cast<volatile uint16_t*>(0x0400'0130))
/////////////////////////////////////////////////////////////////
// Memory Addresses
#define MEM_EWRAM_BEGIN reinterpret_cast<uint8_t*>(0x0200'0000)
#define MEM_EWRAM_END reinterpret_cast<uint8_t*>(0x0203'FFFF)
#define MEM_EWRAM (*reinterpret_cast<ox::Array<uint16_t, 0x0203'FFFF - 0x0200'0000>*>(0x0200'0000))
#define MEM_IWRAM_BEGIN reinterpret_cast<uint8_t*>(0x0300'0000)
#define MEM_IWRAM_END reinterpret_cast<uint8_t*>(0x0300'7FFF)
#define MEM_IWRAM (*reinterpret_cast<ox::Array<uint8_t, 0x0300'7FFF - 0x0300'0000>*>(0x0300'0000))
#define REG_BLNDCTL *reinterpret_cast<uint16_t*>(0x0400'0050)
#define REG_BLNDCTL (*reinterpret_cast<uint16_t*>(0x0400'0050))
#define MEM_BG_PALETTE reinterpret_cast<uint16_t*>(0x0500'0000)
#define MEM_SPRITE_PALETTE reinterpret_cast<uint16_t*>(0x0500'0200)
using Palette = ox::Array<uint16_t, 128>;
#define MEM_BG_PALETTE (*reinterpret_cast<::Palette*>(0x0500'0000))
#define MEM_SPRITE_PALETTE (*reinterpret_cast<::Palette*>(0x0500'0200))
using BgMapTile = ox::Array<uint16_t, 8192>;
#define MEM_BG_TILES reinterpret_cast<BgMapTile*>(0x0600'0000)
#define MEM_BG_MAP reinterpret_cast<BgMapTile*>(0x0600'e000)
#define MEM_BG_TILES (*reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'0000))
#define MEM_BG_MAP (*reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'e000))
#define MEM_SPRITE_TILES reinterpret_cast<uint16_t*>(0x0601'0000)
#define MEM_OAM reinterpret_cast<uint64_t*>(0x0700'0000)
#define MEM_SPRITE_TILES (*reinterpret_cast<ox::Array<uint16_t, 32 * ox::units::KB>*>(0x0601'0000))
#define MEM_OAM (*reinterpret_cast<ox::Array<uint64_t, 64>*>(0x0700'0000))
#define MEM_ROM reinterpret_cast<char*>(0x0800'0000)
#define MEM_ROM (*reinterpret_cast<ox::Array<char, 32 * ox::units::MB>*>(0x0700'0000))
#define MEM_SRAM reinterpret_cast<char*>(0x0e00'0000)
#define MEM_SRAM_SIZE 65535
#define MEM_SRAM (*reinterpret_cast<ox::Array<char, 64 * ox::units::KB>*>(0x0e00'0000))

View File

@@ -41,4 +41,8 @@ void addSpriteUpdate(GbaSpriteAttrUpdate const &upd) noexcept;
void applySpriteUpdates() noexcept;
void setBgOffset(uint16_t bg, int16_t x, int16_t y) noexcept;
void scrollBgOffset(uint16_t bg, int16_t x, int16_t y) noexcept;
}

View File

@@ -12,7 +12,7 @@ namespace teagba {
static ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer;
GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept {
GbaSpriteAttrUpdate &spriteAttr(size_t const i) noexcept {
return g_spriteBuffer[i];
}
@@ -29,4 +29,16 @@ void applySpriteUpdates() noexcept {
}
}
void setBgOffset(uint16_t const bg, int16_t const x, int16_t const y) noexcept {
auto &o = regBgOfs(bg);
o.x = x;
o.y = y;
}
void scrollBgOffset(uint16_t const bg, int16_t const x, int16_t const y) noexcept {
auto &o = regBgOfs(bg);
o.x = o.x + x;
o.y = o.y + y;
}
}

View File

@@ -1,3 +1,9 @@
# d2025.07.0
* Add sub-command for exporting TileSheets as PNG files.
* Add 'Reload Project' menu item under File.
* Fix opening a project to mark an unopenable file as closed in the config file on startup.
# d2025.06.0
* Add ability to remember recent projects in config

View File

@@ -21,9 +21,28 @@ constexpr ox::Array<ox::StringLiteral, 2> FileExts_TileSheet{
FileExt_ng,
};
constexpr ox::Array<ox::StringLiteral, 2> FileExts_Palette{
FileExt_npal,
};
[[nodiscard]]
constexpr bool isTileSheet(ox::StringViewCR path) noexcept {
return endsWith(path, FileExt_nts) || endsWith(path, FileExt_ng);
return ox::any_of(
FileExts_TileSheet.begin(),
FileExts_TileSheet.end(),
[path](ox::StringLiteral const &ext) {
return endsWith(path, ext);
});
}
[[nodiscard]]
constexpr bool isPalette(ox::StringViewCR path) noexcept {
return ox::any_of(
FileExts_Palette.begin(),
FileExts_Palette.end(),
[path](ox::StringLiteral const &ext) {
return endsWith(path, ext);
});
}
}

View File

@@ -114,10 +114,10 @@ struct InitParams {
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const &params = {}) noexcept;
[[nodiscard]]
int tileColumns(Context&) noexcept;
int tileColumns(Context const&) noexcept;
[[nodiscard]]
int tileRows(Context&) noexcept;
int tileRows(Context const&) noexcept;
ox::Error loadBgPalette(
Context &ctx,
@@ -238,6 +238,10 @@ void setBgCbb(Context &ctx, unsigned bgIdx, unsigned cbbIdx) noexcept;
void setBgPriority(Context &ctx, uint_t bgIdx, uint_t priority) noexcept;
void setBgOffset(Context &ctx, uint16_t bg, int16_t x, int16_t y) noexcept;
void scrollBgOffset(Context &ctx, uint16_t bg, int16_t x, int16_t y) noexcept;
void hideSprite(Context &ctx, unsigned) noexcept;
void showSprite(Context &ctx, unsigned) noexcept;
@@ -260,8 +264,8 @@ constexpr ox::CStringView GlslVersion = "#version 330";
[[nodiscard]]
ox::Size drawSize(int scale = 5) noexcept;
void draw(gfx::Context &ctx, ox::Size const &renderSz) noexcept;
void draw(Context &ctx, ox::Size const &renderSz) noexcept;
void draw(gfx::Context&, int scale = 5) noexcept;
void draw(Context&, int scale = 5) noexcept;
}

View File

@@ -168,9 +168,9 @@ OX_MODEL_BEGIN(PaletteV3)
OX_MODEL_END()
[[nodiscard]]
constexpr bool valid(PaletteV3 const&p) noexcept {
constexpr bool valid(PaletteV3 const &p) noexcept {
auto const colors = p.colorInfo.size();
return ox::all_of(p.pages.begin(), p.pages.end(), [colors](auto const&page) {
return ox::all_of(p.pages.begin(), p.pages.end(), [colors](auto const &page) {
return page.size() == colors;
});
}
@@ -198,9 +198,9 @@ OX_MODEL_BEGIN(PaletteV4)
OX_MODEL_END()
[[nodiscard]]
constexpr bool valid(PaletteV4 const&p) noexcept {
constexpr bool valid(PaletteV4 const &p) noexcept {
auto const colors = p.colorNames.size();
return ox::all_of(p.pages.begin(), p.pages.end(), [colors](PalettePageV1 const&page) {
return ox::all_of(p.pages.begin(), p.pages.end(), [colors](PalettePageV1 const &page) {
return page.colors.size() == colors;
});
}

View File

@@ -11,7 +11,7 @@
namespace nostalgia::gfx {
[[nodiscard]]
constexpr std::size_t ptToIdx(int x, int y, int c, int scale = 1) noexcept {
constexpr std::size_t ptToIdx(int const x, int const y, int const c, int const scale = 1) noexcept {
auto const tileWidth = TileWidth * scale;
auto const tileHeight = TileHeight * scale;
auto const pixelsPerTile = tileWidth * tileHeight;
@@ -25,12 +25,12 @@ constexpr std::size_t ptToIdx(int x, int y, int c, int scale = 1) noexcept {
}
[[nodiscard]]
constexpr std::size_t ptToIdx(const ox::Point &pt, int c, int scale = 1) noexcept {
constexpr std::size_t ptToIdx(ox::Point const &pt, int const c, int const scale = 1) noexcept {
return ptToIdx(pt.x, pt.y, c * TileWidth, scale);
}
[[nodiscard]]
constexpr ox::Point idxToPt(int i, int c, int scale = 1) noexcept {
constexpr ox::Point idxToPt(int const i, int c, int const scale = 1) noexcept {
auto const tileWidth = TileWidth * scale;
auto const tileHeight = TileHeight * scale;
auto const pixelsPerTile = tileWidth * tileHeight;

View File

@@ -30,7 +30,7 @@ struct TileSheetV1 {
};
[[nodiscard]]
constexpr bool valid(TileSheetV1 const&ts) noexcept {
constexpr bool valid(TileSheetV1 const &ts) noexcept {
auto const bytes = static_cast<size_t>(ts.columns * ts.rows * PixelsPerTile) / (ts.bpp == 4 ? 2 : 1);
return (ts.bpp == 4 || ts.bpp == 8) && ts.pixels.size() == bytes;
}
@@ -71,16 +71,16 @@ struct TileSheetV2 {
};
[[nodiscard]]
constexpr bool valid(TileSheetV2::SubSheet const&ss, int bpp) noexcept {
constexpr bool valid(TileSheetV2::SubSheet const &ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[bpp, bytes](TileSheetV2::SubSheet const&s) {
[bpp, bytes](TileSheetV2::SubSheet const &s) {
return bytes == s.pixels.size() && valid(s, bpp);
});
}
[[nodiscard]]
constexpr bool valid(TileSheetV2 const&ts) noexcept {
constexpr bool valid(TileSheetV2 const &ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp);
}
@@ -141,16 +141,16 @@ struct TileSheetV3 {
};
[[nodiscard]]
constexpr bool valid(TileSheetV3::SubSheet const&ss, int bpp) noexcept {
constexpr bool valid(TileSheetV3::SubSheet const &ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[bpp, bytes](TileSheetV3::SubSheet const&s) {
[bpp, bytes](TileSheetV3::SubSheet const &s) {
return bytes == s.pixels.size() && valid(s, bpp);
});
}
[[nodiscard]]
constexpr bool valid(TileSheetV3 const&ts) noexcept {
constexpr bool valid(TileSheetV3 const &ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp);
}
@@ -233,18 +233,18 @@ struct TileSheetV4 {
};
[[nodiscard]]
constexpr bool valid(TileSheetV4::SubSheet const&ss, int bpp) noexcept {
constexpr bool valid(TileSheetV4::SubSheet const &ss, int bpp) noexcept {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
return
(ss.pixels.empty() || ss.subsheets.empty()) &&
ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[bpp, bytes](TileSheetV4::SubSheet const&s) {
[bpp, bytes](TileSheetV4::SubSheet const &s) {
return bytes == s.pixels.size() && valid(s, bpp);
});
}
[[nodiscard]]
constexpr bool valid(TileSheetV4 const&ts) noexcept {
constexpr bool valid(TileSheetV4 const &ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet, ts.bpp);
}
@@ -334,19 +334,19 @@ struct TileSheetV5 {
};
[[nodiscard]]
constexpr bool valid(TileSheetV5::SubSheet const&ss) noexcept {
constexpr bool valid(TileSheetV5::SubSheet const &ss) noexcept {
if (ss.subsheets.empty()) {
return std::cmp_equal(ss.columns * ss.rows * PixelsPerTile, ss.pixels.size());
} else {
return ss.pixels.empty() && ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[](TileSheetV5::SubSheet const&s) {
[](TileSheetV5::SubSheet const &s) {
return valid(s);
});
}
}
[[nodiscard]]
constexpr bool valid(TileSheetV5 const&ts) noexcept {
constexpr bool valid(TileSheetV5 const &ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet);
}
@@ -376,24 +376,24 @@ constexpr ox::Error repair(TileSheetV5 &ts) noexcept {
using TileSheet = TileSheetV5;
[[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;
[[nodiscard]]
size_t getTileCnt(TileSheet const&ts) noexcept;
size_t getTileCnt(TileSheet const &ts) noexcept;
[[nodiscard]]
TileSheet::SubSheet const*getSubsheet(TileSheet const&ts, SubSheetId id) noexcept;
TileSheet::SubSheet const*getSubsheet(TileSheet const &ts, SubSheetId id) noexcept;
[[nodiscard]]
ox::Optional<size_t> getTileIdx(TileSheet const&ts, SubSheetId id) noexcept;
ox::Optional<size_t> getTileIdx(TileSheet const &ts, SubSheetId id) noexcept;
[[nodiscard]]
uint8_t getPixel(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
uint8_t getPixel(TileSheet::SubSheet const &ss, std::size_t idx) noexcept;
[[nodiscard]]
uint8_t getPixel(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
uint8_t getPixel(TileSheet::SubSheet const &ss, ox::Point const &pt) noexcept;
void setPixel(TileSheet::SubSheet &ss, ox::Point const&pt, uint8_t palIdx) noexcept;
void setPixel(TileSheet::SubSheet &ss, ox::Point const &pt, uint8_t palIdx) noexcept;
ox::Error setPixelCount(TileSheet::SubSheet &ss, std::size_t cnt) noexcept;
@@ -406,14 +406,14 @@ void flipY(TileSheet::SubSheet &ss, ox::Point const &a, ox::Point const &b) noex
* @return a count of the pixels in this sheet
*/
[[nodiscard]]
unsigned pixelCnt(TileSheet::SubSheet const&ss) noexcept;
unsigned pixelCnt(TileSheet::SubSheet const &ss) noexcept;
/**
*
* @param ss
* @param sz size of Subsheet in tiles (not pixels)
*/
ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const&sz) noexcept;
ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const &sz) noexcept;
/**
* validateSubSheetIdx takes a SubSheetIdx and moves the index to the
@@ -424,13 +424,21 @@ ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const&sz) noexcept;
* @return a valid version of idx
*/
[[nodiscard]]
TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const&ts, TileSheet::SubSheetIdx idx) noexcept;
TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const &ts, TileSheet::SubSheetIdx idx) noexcept;
ox::Result<TileSheet::SubSheetIdx> getSubSheetIdx(TileSheet const &ts, SubSheetId pId) noexcept;
ox::Result<TileSheet::SubSheet*> getSubSheet(
ox::SpanView<ox::StringView> const &idx,
TileSheet &ts) noexcept;
ox::Result<TileSheet::SubSheet const*> getSubSheet(
ox::SpanView<ox::StringView> const &idx,
TileSheet const &ts) noexcept;
[[nodiscard]]
TileSheet::SubSheet &getSubSheet(
ox::SpanView<uint32_t> const&idx,
ox::SpanView<uint32_t> const &idx,
std::size_t idxIt,
TileSheet::SubSheet &pSubsheet) noexcept;
@@ -439,7 +447,7 @@ TileSheet::SubSheet &getSubSheet(
#pragma GCC diagnostic ignored "-Wdangling-reference"
#endif
[[nodiscard]]
TileSheet::SubSheet const&getSubSheet(TileSheet const&ts, ox::SpanView<uint32_t> const &idx) noexcept;
TileSheet::SubSheet const &getSubSheet(TileSheet const &ts, ox::SpanView<uint32_t> const &idx) noexcept;
[[nodiscard]]
TileSheet::SubSheet &getSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const &idx) noexcept;
@@ -453,27 +461,29 @@ ox::Error insertSubSheet(TileSheet &ts, ox::SpanView<uint32_t> const &idx, TileS
ox::Error rmSubSheet(
TileSheet &ts,
TileSheet::SubSheetIdx const&idx,
TileSheet::SubSheetIdx const &idx,
std::size_t idxIt,
TileSheet::SubSheet &pSubsheet) noexcept;
ox::Error rmSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept;
ox::Error rmSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const &idx) noexcept;
[[nodiscard]]
uint8_t getPixel(
TileSheet const&ts,
ox::Point const&pt,
TileSheet::SubSheetIdx const&subsheetIdx) noexcept;
TileSheet const &ts,
ox::Point const &pt,
TileSheet::SubSheetIdx const &subsheetIdx) noexcept;
ox::Result<SubSheetId> getIdFor(TileSheet const&ts, ox::StringViewCR path) noexcept;
ox::Result<SubSheetId> getIdFor(TileSheet const &ts, ox::StringViewCR path) noexcept;
ox::Result<unsigned> getTileOffset(TileSheet const&ts, ox::StringViewCR pNamePath) noexcept;
ox::Result<unsigned> getTileOffset(TileSheet const &ts, ox::StringViewCR pNamePath) noexcept;
ox::Result<uint32_t> getTileOffset(TileSheet const&ts, SubSheetId pId) noexcept;
ox::Result<uint32_t> getTileOffset(TileSheet const &ts, SubSheetId pId) noexcept;
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&ts, SubSheetId pId) noexcept;
ox::Result<ox::StringView> getNameFor(TileSheet &ts, SubSheetId pId) noexcept;
ox::Result<ox::StringView> getNameFor(TileSheet const &ts, SubSheetId pId) noexcept;
[[nodiscard]]
ox::Vector<uint8_t> pixels(TileSheet &ts) noexcept;
@@ -489,7 +499,7 @@ struct CompactTileSheetV1 {
};
[[nodiscard]]
constexpr bool valid(CompactTileSheetV1 const&ts) noexcept {
constexpr bool valid(CompactTileSheetV1 const &ts) noexcept {
return ts.bpp == 4 || ts.bpp == 8;
}
@@ -498,22 +508,22 @@ using CompactTileSheet = CompactTileSheetV1;
[[nodiscard]]
uint8_t getPixel4Bpp(
CompactTileSheet const&ts,
CompactTileSheet const &ts,
size_t idx) noexcept;
[[nodiscard]]
uint8_t getPixel8Bpp(
CompactTileSheet const&ts,
CompactTileSheet const &ts,
size_t idx) noexcept;
[[nodiscard]]
ox::Pair<uint8_t> get2Pixels4Bpp(
CompactTileSheet const&ts,
CompactTileSheet const &ts,
size_t idx) noexcept;
[[nodiscard]]
ox::Pair<uint8_t> get2Pixels8Bpp(
CompactTileSheet const&ts,
CompactTileSheet const &ts,
size_t idx) noexcept;
OX_MODEL_BEGIN(TileSheetV1)
@@ -593,8 +603,8 @@ OX_MODEL_BEGIN(CompactTileSheetV1)
OX_MODEL_END()
ox::Vector<uint32_t> resizeTileSheetData(
ox::Vector<uint32_t> const&srcPixels,
ox::Size const&srcSize,
ox::Vector<uint32_t> const &srcPixels,
ox::Size const &srcSize,
int scale = 2) noexcept;
}

View File

@@ -35,11 +35,6 @@ class Context {
Context(Context const &&other) noexcept = delete;
virtual ~Context() noexcept = default;
[[nodiscard]]
ox::MemFS const &rom() const noexcept {
return static_cast<ox::MemFS const&>(*turbine::rom(turbineCtx));
}
};
void safeDelete(Context *ctx) noexcept {
@@ -81,7 +76,7 @@ ox::Error loadBgPalette(
if (palette.pages.empty()) {
return {};
}
auto const paletteMem = MEM_BG_PALETTE + palBank * 16;
auto const paletteMem = ox::Span{MEM_BG_PALETTE} + palBank * 16;
for (auto i = 0u; i < colorCnt(palette, page); ++i) {
paletteMem[i] = color(palette, page, i);
}
@@ -95,9 +90,8 @@ ox::Error loadSpritePalette(
if (palette.pages.empty()) {
return {};
}
auto const paletteMem = MEM_SPRITE_PALETTE;
for (auto i = 0u; i < colorCnt(palette, page); ++i) {
paletteMem[i] = color(palette, page, i);
MEM_SPRITE_PALETTE[i] = color(palette, page, i);
}
return {};
}
@@ -175,8 +169,8 @@ ox::Error loadBgTileSheet(
unsigned const cbb,
CompactTileSheet const &ts,
ox::Optional<unsigned> const &paletteBank) noexcept {
auto const cnt = (ts.pixels.size() * PixelsPerTile) / (1 + (ts.bpp == 4));
for (size_t i = 0; i < cnt; ++i) {
auto const cnt = ts.pixels.size() >> (ts.bpp == 4);
for (size_t i{}; i < cnt; ++i) {
auto const srcIdx = i * 2;
auto const p1 = static_cast<uint16_t>(ts.pixels[srcIdx]);
auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]);
@@ -224,10 +218,11 @@ ox::Error loadSpriteTileSheet(
Context &ctx,
CompactTileSheet const &ts,
bool const loadDefaultPalette) noexcept {
for (size_t i = 0; i < ts.pixels.size(); i += 2) {
uint16_t v = ts.pixels[i];
v |= static_cast<uint16_t>(ts.pixels[i + 1] << 8);
MEM_SPRITE_TILES[i] = v;
for (size_t i{}; i < ts.pixels.size(); i += 2) {
MEM_SPRITE_TILES[i >> 1] =
static_cast<uint16_t>(
ts.pixels[i] |
(static_cast<uint16_t>(ts.pixels[i + 1]) << 8));
}
if (loadDefaultPalette && ts.defaultPalette) {
OX_RETURN_ERROR(loadSpritePalette(ctx, ts.defaultPalette));
@@ -240,7 +235,7 @@ ox::Error loadSpriteTileSheet(
Context &ctx,
TileSheetSet const &set) noexcept {
auto const bpp = static_cast<unsigned>(set.bpp);
OX_RETURN_ERROR(loadTileSheetSet(ctx, {MEM_SPRITE_TILES, 32 * ox::units::KB}, set));
OX_RETURN_ERROR(loadTileSheetSet(ctx, MEM_SPRITE_TILES, set));
setSpritesBpp(bpp);
return {};
}
@@ -300,6 +295,14 @@ void setBgPriority(Context&, uint_t const bgIdx, uint_t const priority) noexcept
bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11);
}
void setBgOffset(Context&, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
teagba::setBgOffset(bg, x, y);
}
void scrollBgOffset(Context&, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
teagba::scrollBgOffset(bg, x, y);
}
void hideSprite(Context&, unsigned const idx) noexcept {
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
teagba::addSpriteUpdate({
@@ -349,9 +352,9 @@ void panic(char const *file, int line, char const *panicMsg, ox::Error const &er
using namespace nostalgia::gfx;
// reset heap to make sure we have enough memory to allocate context data
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
auto const heapBegin = reinterpret_cast<char*>(MEM_EWRAM_BEGIN);
auto const heapSz = (MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2;
auto const heapEnd = reinterpret_cast<char*>(MEM_EWRAM_BEGIN + heapSz);
auto const heapBegin = reinterpret_cast<char*>(MEM_EWRAM.data());
auto const heapSz = MEM_EWRAM.size() / 2;
auto const heapEnd = reinterpret_cast<char*>(MEM_EWRAM.data() + heapSz);
ox::heapmgr::initHeap(heapBegin, heapEnd);
OX_ALLOW_UNSAFE_BUFFERS_END
auto tctx = turbine::init(keel::loadRomFs("").unwrap(), "Nostalgia").unwrap();

View File

@@ -453,7 +453,7 @@ static void drawBackgrounds(
}
}
static void drawSprites(Context &ctx, ox::Size const&renderSz) noexcept {
static void drawSprites(Context &ctx, ox::Size const &renderSz) noexcept {
glUseProgram(ctx.spriteShader);
auto &sb = ctx.spriteBlocks;
auto const uniformXScale = glGetUniformLocation(ctx.bgShader, "vXScale");
@@ -481,7 +481,7 @@ static void loadPalette(
ox::Array<GLfloat, 1024> &palette,
size_t const palOffset,
GLuint const shaderPgrm,
CompactPalette const&pal,
CompactPalette const &pal,
size_t const page = 0) noexcept {
static constexpr std::size_t ColorCnt = 256;
for (auto i = palOffset; auto const c : pal.pages[page]) {
@@ -500,7 +500,7 @@ static void loadPalette(
static void setSprite(
Context &ctx,
uint_t const idx,
Sprite const&s) noexcept {
Sprite const &s) noexcept {
// Tonc Table 8.4
struct Sz { uint_t x{}, y{}; };
static constexpr ox::Array<Sz, 12> dimensions{
@@ -574,7 +574,7 @@ static void setSprite(
}
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const&params) noexcept {
ox::Result<ox::UPtr<Context>> init(turbine::Context &tctx, InitParams const &params) noexcept {
auto ctx = ox::make_unique<Context>(tctx, params);
auto const bgVshad = ox::sfmt(renderer::bgvshadTmpl, gl::GlslVersion);
auto const bgFshad = ox::sfmt(renderer::bgfshadTmpl, gl::GlslVersion);
@@ -604,7 +604,7 @@ struct TileSheetData {
};
static ox::Result<TileSheetData> normalizeTileSheet
(CompactTileSheet const&ts) noexcept {
(CompactTileSheet const &ts) noexcept {
const uint_t bytesPerTile = ts.bpp == 8 ? PixelsPerTile : PixelsPerTile / 2;
auto const tiles = ts.pixels.size() / bytesPerTile;
constexpr int width = 8;
@@ -632,7 +632,7 @@ static ox::Result<TileSheetData> normalizeTileSheet
ox::Error loadBgPalette(
Context &ctx,
size_t const palBank,
CompactPalette const&palette,
CompactPalette const &palette,
size_t const page) noexcept {
renderer::loadPalette(ctx.bgPalette, palBank * 16 * 4, ctx.bgShader, palette, page);
return {};
@@ -640,7 +640,7 @@ ox::Error loadBgPalette(
ox::Error loadSpritePalette(
Context &ctx,
CompactPalette const&palette,
CompactPalette const &palette,
size_t const page) noexcept {
ox::Array<GLfloat, 1024> pal;
renderer::loadPalette(pal, 0, ctx.spriteShader, palette, page);
@@ -649,14 +649,14 @@ ox::Error loadSpritePalette(
static ox::Result<TileSheetData> buildSetTsd(
Context const &ctx,
TileSheetSet const&set) noexcept {
TileSheetSet const &set) noexcept {
auto &kctx = keelCtx(ctx.turbineCtx);
TileSheetData setTsd;
setTsd.width = TileWidth;
for (auto const&entry : set.entries) {
for (auto const &entry : set.entries) {
OX_REQUIRE(tilesheet, readObj<CompactTileSheet>(kctx, entry.tilesheet));
OX_REQUIRE(tsd, normalizeTileSheet(*tilesheet));
for (auto const&s : entry.sections) {
for (auto const &s : entry.sections) {
auto const size = s.tiles * PixelsPerTile;
for (auto i = 0; i < size; ++i) {
auto const srcIdx = static_cast<size_t>(i) + static_cast<size_t>(s.begin * PixelsPerTile);
@@ -669,7 +669,7 @@ static ox::Result<TileSheetData> buildSetTsd(
}
static void copyPixels(
CompactTileSheet const&ts,
CompactTileSheet const &ts,
ox::Span<uint32_t> const dst,
size_t const srcPxIdx,
size_t const pxlCnt) noexcept {
@@ -704,7 +704,7 @@ void clearCbbs(Context &ctx) noexcept {
ox::Error loadBgTileSheet(
Context &ctx,
unsigned const cbb,
CompactTileSheet const&ts,
CompactTileSheet const &ts,
size_t const dstTileIdx,
size_t const srcTileIdx,
size_t const tileCnt) noexcept {
@@ -728,8 +728,8 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet(
Context &ctx,
uint_t const cbb,
CompactTileSheet const&ts,
ox::Optional<unsigned> const&paletteBank) noexcept {
CompactTileSheet const &ts,
ox::Optional<unsigned> const &paletteBank) noexcept {
auto const bytesPerTile = static_cast<uint64_t>(PixelsPerTile / (1 + (ts.bpp == 4)));
auto const tiles = ts.pixels.size() / bytesPerTile;
OX_RETURN_ERROR(loadBgTileSheet(ctx, cbb, ts, 0, 0, tiles));
@@ -742,7 +742,7 @@ ox::Error loadBgTileSheet(
ox::Error loadBgTileSheet(
Context &ctx,
unsigned const cbb,
TileSheetSet const&set) noexcept {
TileSheetSet const &set) noexcept {
OX_REQUIRE(setTsd, buildSetTsd(ctx, set));
ctx.cbbs[cbb].tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data());
return {};
@@ -750,7 +750,7 @@ ox::Error loadBgTileSheet(
ox::Error loadSpriteTileSheet(
Context &ctx,
CompactTileSheet const&ts,
CompactTileSheet const &ts,
bool const loadDefaultPalette) noexcept {
OX_REQUIRE(tsd, normalizeTileSheet(ts));
oxTracef("nostalgia.gfx.gl", "loadSpriteTexture: { w: {}, h: {} }", tsd.width, tsd.height);
@@ -763,7 +763,7 @@ ox::Error loadSpriteTileSheet(
ox::Error loadSpriteTileSheet(
Context &ctx,
TileSheetSet const&set) noexcept {
TileSheetSet const &set) noexcept {
OX_REQUIRE(setTsd, buildSetTsd(ctx, set));
ctx.spriteBlocks.tex = renderer::createTexture(setTsd.width, setTsd.height, setTsd.pixels.data());
return {};
@@ -774,7 +774,7 @@ void setBgTile(
uint_t const bgIdx,
int const column,
int const row,
BgTile const&tile) noexcept {
BgTile const &tile) noexcept {
oxTracef(
"nostalgia.gfx.setBgTile",
"bgIdx: {}, column: {}, row: {}, tile: {}, palBank: {}",
@@ -853,7 +853,7 @@ void showSprite(Context &ctx, uint_t const idx) noexcept {
renderer::setSprite(ctx, idx, s);
}
void setSprite(Context &ctx, uint_t const idx, Sprite const&sprite) noexcept {
void setSprite(Context &ctx, uint_t const idx, Sprite const &sprite) noexcept {
auto &s = ctx.spriteStates[idx];
s = sprite;
renderer::setSprite(ctx, idx, s);
@@ -869,7 +869,7 @@ ox::Size drawSize(int const scale) noexcept {
return {240 * scale, 160 * scale};
}
void draw(Context &ctx, ox::Size const&renderSz) noexcept {
void draw(Context &ctx, ox::Size const &renderSz) noexcept {
glViewport(0, 0, renderSz.width, renderSz.height);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);

View File

@@ -10,11 +10,11 @@ namespace nostalgia::gfx {
constexpr auto GbaTileColumns = 32;
constexpr auto GbaTileRows = 32;
int tileColumns(Context&) noexcept {
int tileColumns(Context const&) noexcept {
return GbaTileColumns;
}
int tileRows(Context&) noexcept {
int tileRows(Context const&) noexcept {
return GbaTileRows;
}
@@ -249,7 +249,7 @@ void setBgTile(
}
ox::Error initConsole(Context &ctx) noexcept {
constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.nts");
constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
setBgStatus(ctx, 0b0001);
setBgCbb(ctx, 0, 0);

View File

@@ -26,3 +26,4 @@ install(
add_subdirectory(paletteeditor)
add_subdirectory(tilesheeteditor)
add_subdirectory(subcommands)

View File

@@ -72,7 +72,7 @@ PaletteEditorImGui::PaletteEditorImGui(studio::Context &sctx, ox::StringParam pa
Editor(sctx, std::move(path)),
m_sctx(sctx),
m_tctx(sctx.tctx),
m_pal(*keel::readObj<Palette>(keelCtx(m_tctx), itemPath()).unwrapThrow()) {
m_pal(m_sctx.project->loadObj<Palette>(itemPath()).unwrapThrow()) {
undoStack()->changeTriggered.connect(this, &PaletteEditorImGui::handleCommand);
m_pageRenameDlg.inputSubmitted.connect(this, &PaletteEditorImGui::renamePage);
}

View File

@@ -8,10 +8,25 @@
#include "paletteeditor/paletteeditor-imgui.hpp"
#include "tilesheeteditor/tilesheeteditor-imgui.hpp"
#include "subcommands/export-tilesheet/export-tilesheet.hpp"
namespace nostalgia::gfx {
static class: public studio::Module {
static struct: studio::Module {
ox::String id() const noexcept final {
return ox::String{"net.drinkingtea.nostalgia.gfx"};
}
ox::Vector<studio::Command> commands() const final {
return {
{
"export-tilesheet",
cmdExportTilesheet,
}
};
}
ox::Vector<studio::EditorMaker> editors(studio::Context &ctx) const noexcept final {
return {
studio::editorMaker<TileSheetEditorImGui>(ctx, {FileExt_ng, FileExt_nts}),
@@ -28,6 +43,7 @@ static class: public studio::Module {
}, ox::ClawFormat::Organic));
return out;
}
} const mod;
studio::Module const *studioModule() noexcept {

View File

@@ -0,0 +1,10 @@
target_sources(
NostalgiaGfx-Studio PRIVATE
export-tilesheet/export-tilesheet.cpp
)
target_link_libraries(
NostalgiaGfx-Studio PUBLIC
OxClArgs
)

View File

@@ -0,0 +1,161 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <lodepng.h>
#include <ox/clargs/clargs.hpp>
#include <ox/std/trace.hpp>
#include <studio/project.hpp>
#include <nostalgia/gfx/palette.hpp>
#include <nostalgia/gfx/tilesheet.hpp>
#include "export-tilesheet.hpp"
#include "nostalgia/gfx/tilesheet.hpp"
#include "studio/context.hpp"
namespace nostalgia::gfx {
static ox::Vector<uint32_t> normalizePixelSizes(
ox::Vector<uint8_t> const &inPixels) noexcept {
ox::Vector<uint32_t> outPixels;
outPixels.reserve(inPixels.size());
outPixels.resize(inPixels.size());
for (size_t i{}; i < inPixels.size(); ++i) {
outPixels[i] = inPixels[i];
}
return outPixels;
}
static ox::Vector<uint32_t> normalizePixelArrangement(
ox::Vector<uint32_t> const &inPixels,
int const cols,
int const scale) {
auto const scalePt = ox::Point{scale, scale};
auto const width = cols * TileWidth;
auto const height = static_cast<int>(inPixels.size()) / width;
auto const dstWidth = width * scale;
ox::Vector<uint32_t> outPixels(static_cast<size_t>((width * scale) * (height * scale)));
for (size_t dstIdx{}; dstIdx < outPixels.size(); ++dstIdx) {
auto const dstPt = ox::Point{
static_cast<int>(dstIdx) % dstWidth,
static_cast<int>(dstIdx) / dstWidth};
auto const srcPt = dstPt / scalePt;
auto const srcIdx = ptToIdx(srcPt, cols);
outPixels[dstIdx] = inPixels[srcIdx];
}
return outPixels;
}
static ox::Error toPngFile(
ox::CStringViewCR path,
ox::Vector<uint32_t> &&pixels,
Palette const &pal,
size_t const page,
unsigned const width,
unsigned const height) noexcept {
for (auto &c : pixels) {
c = color32(color(pal, page, c)) | static_cast<Color32>(0XFF << 24);
}
constexpr auto fmt = LCT_RGBA;
return ox::Error(static_cast<ox::ErrorCode>(
lodepng_encode_file(
path.c_str(),
reinterpret_cast<uint8_t const*>(pixels.data()),
width,
height,
fmt,
8)));
}
ox::Error exportSubsheetToPng(
TileSheet::SubSheet const &s,
Palette const &pal,
size_t const palPage,
ox::CStringViewCR dstPath,
int const scale) noexcept {
// subsheet to png
auto const width = s.columns * TileWidth;
auto const height = s.rows * TileHeight;
auto const err = toPngFile(
dstPath,
normalizePixelArrangement(
normalizePixelSizes(s.pixels),
s.columns,
scale),
pal,
palPage,
static_cast<unsigned>(width * scale),
static_cast<unsigned>(height * scale));
if (err) {
oxErrorf("TileSheet export failed: {}", toStr(err));
return ox::Error{7, "TileSheet export failed"};
}
return {};
}
ox::Error exportSubsheetToPng(
TileSheet const &src,
Palette const &pal,
ox::StringViewCR subsheetPath,
size_t const palPage,
ox::CStringViewCR dstPath,
int const scale) noexcept {
// subsheet to png
auto const [s, ssErr] = getSubSheet(
ox::split(subsheetPath, '.'), src);
if (ssErr) {
return ox::Error{6, "failed to find SubSheet"};
}
return exportSubsheetToPng(
*s,
pal,
palPage,
dstPath,
scale);
}
ox::Error cmdExportTilesheet(studio::Project &project, ox::SpanView<ox::CString> const args) noexcept {
// parse args
ox::ClArgs const clargs{args};
bool showUsage = true;
OX_DEFER [&showUsage] {
if (showUsage) {
oxErr("usage: export-tilesheet "
"-src-path <path> "
"-dst-path <path> "
"[-pal-path <path>] "
"[-subsheet-path <path>] "
"[-scale <int>]\n");
}
};
if (args.empty()) {
return {};
}
OX_REQUIRE(srcPath, clargs.getString("src-path").transformError(1, "no src path specified"));
OX_REQUIRE(dstPath, clargs.getString("dst-path").transformError(2, "no dst path specified"));
auto const palPath = clargs.getString("pal-path", "");
auto const subsheetPath = clargs.getString("subsheet-path").or_value(ox::String{"Root"});
auto const palPage = static_cast<size_t>(clargs.getInt("pal-page", 0));
auto const scale = clargs.getInt("scale", 1);
showUsage = false;
// load objects
auto &kctx = project.kctx();
OX_REQUIRE(ts, keel::readObj<TileSheet>(kctx, srcPath).transformError(4, "could not load TileSheet"));
OX_REQUIRE(pal, keel::readObj<Palette>(kctx, palPath.size() ? palPath : ts->defaultPalette)
.transformError(5, "could not load Palette"));
// export to the destination file
return exportSubsheetToPng(
*ts,
*pal,
subsheetPath,
palPage,
dstPath,
scale);
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/error.hpp>
#include <ox/std/span.hpp>
#include <ox/std/stringview.hpp>
#include <studio/project.hpp>
#include <nostalgia/gfx/palette.hpp>
#include <nostalgia/gfx/tilesheet.hpp>
namespace nostalgia::gfx {
ox::Error exportSubsheetToPng(
TileSheet::SubSheet const &s,
Palette const &pal,
size_t palPage,
ox::CStringViewCR dstPath,
int scale) noexcept;
ox::Error exportSubsheetToPng(
TileSheet const &src,
Palette const &pal,
ox::StringViewCR subsheetPath,
size_t palPage,
ox::CStringViewCR dstPath,
int scale) noexcept;
ox::Error cmdExportTilesheet(studio::Project& project, ox::SpanView<ox::CString> args) noexcept;
}

View File

@@ -3,7 +3,6 @@
*/
#include <imgui.h>
#include <lodepng.h>
#include <ox/std/point.hpp>
#include <keel/media.hpp>
@@ -11,6 +10,7 @@
#include <nostalgia/gfx/studio.hpp>
#include "../subcommands/export-tilesheet/export-tilesheet.hpp"
#include "tilesheeteditor-imgui.hpp"
namespace nostalgia::gfx {
@@ -37,58 +37,6 @@ OX_MODEL_BEGIN(TileSheetEditorConfig)
OX_MODEL_FIELD_RENAME(activeSubsheet, active_subsheet)
OX_MODEL_END()
static ox::Vector<uint32_t> normalizePixelSizes(
ox::Vector<uint8_t> const &inPixels) noexcept {
ox::Vector<uint32_t> outPixels;
outPixels.reserve(inPixels.size());
outPixels.resize(inPixels.size());
for (std::size_t i = 0; i < inPixels.size(); ++i) {
outPixels[i] = inPixels[i];
}
return outPixels;
}
static ox::Vector<uint32_t> normalizePixelArrangement(
ox::Vector<uint32_t> const &inPixels,
int const cols,
int const scale) {
auto const scalePt = ox::Point{scale, scale};
auto const width = cols * TileWidth;
auto const height = static_cast<int>(inPixels.size()) / width;
auto const dstWidth = width * scale;
ox::Vector<uint32_t> outPixels(static_cast<size_t>((width * scale) * (height * scale)));
for (std::size_t dstIdx = 0; dstIdx < outPixels.size(); ++dstIdx) {
auto const dstPt = ox::Point{
static_cast<int>(dstIdx) % dstWidth,
static_cast<int>(dstIdx) / dstWidth};
auto const srcPt = dstPt / scalePt;
auto const srcIdx = ptToIdx(srcPt, cols);
outPixels[dstIdx] = inPixels[srcIdx];
}
return outPixels;
}
static ox::Error toPngFile(
ox::CStringViewCR path,
ox::Vector<uint32_t> &&pixels,
Palette const &pal,
size_t const page,
unsigned const width,
unsigned const height) noexcept {
for (auto &c : pixels) {
c = color32(color(pal, page, c)) | static_cast<Color32>(0XFF << 24);
}
constexpr auto fmt = LCT_RGBA;
return ox::Error(static_cast<ox::ErrorCode>(
lodepng_encode_file(
path.c_str(),
reinterpret_cast<uint8_t const*>(pixels.data()),
width,
height,
fmt,
8)));
}
TileSheetEditorImGui::TileSheetEditorImGui(studio::Context &sctx, ox::StringParam path):
Editor{sctx, std::move(path)},
m_sctx{sctx},
@@ -421,21 +369,7 @@ ox::Error TileSheetEditorImGui::exportSubsheetToPng(int const scale) const noexc
// subsheet to png
auto const &s = m_model.activeSubSheet();
auto const &pal = m_model.pal();
auto const width = s.columns * TileWidth;
auto const height = s.rows * TileHeight;
auto pixels = normalizePixelSizes(s.pixels);
pixels = normalizePixelArrangement(pixels, s.columns, scale);
auto const err = toPngFile(
path,
std::move(pixels),
pal,
m_model.palettePage(),
static_cast<unsigned>(width * scale),
static_cast<unsigned>(height * scale));
if (err) {
oxErrorf("TileSheet export failed: {}", toStr(err));
}
return err;
return gfx::exportSubsheetToPng(s, pal, m_model.palettePage(), path, scale);
}
void TileSheetEditorImGui::drawTileSheet(ox::Vec2 const &fbSize) noexcept {

View File

@@ -57,7 +57,6 @@ class TileSheetEditorImGui: public studio::Editor {
ox::Vec2 m_prevMouseDownPos;
TileSheetTool m_tool = TileSheetTool::Draw;
bool m_palPathFocused{};
ox::Vector<ox::UPtr<studio::UndoCommand>, 1> m_deferredCmds;
public:
TileSheetEditorImGui(studio::Context &sctx, ox::StringParam path);

View File

@@ -49,7 +49,7 @@ TileSheetEditorModel::TileSheetEditorModel(
m_sctx{sctx},
m_tctx{m_sctx.tctx},
m_path{std::move(path)},
m_img{*readObj<TileSheet>(keelCtx(m_tctx), m_path).unwrapThrow()},
m_img{m_sctx.project->loadObj<TileSheet>(m_path).unwrapThrow()},
// ignore failure to load palette
m_pal{readObj<Palette>(keelCtx(m_tctx), m_img.defaultPalette).value},
m_undoStack{undoStack} {

View File

@@ -211,6 +211,47 @@ ox::Result<TileSheet::SubSheetIdx> getSubSheetIdx(TileSheet const &ts, SubSheetI
return out;
}
template<typename SubSheet>
static ox::Result<SubSheet*> getSubSheet(
ox::SpanView<ox::StringView> const &idx,
std::size_t const idxIt,
SubSheet &pSubSheet) noexcept {
if (idxIt == idx.size()) {
return &pSubSheet;
}
auto const &currentIdx = idx[idxIt];
auto const next = ox::find_if(
pSubSheet.subsheets.begin(),
pSubSheet.subsheets.end(),
[&currentIdx](TileSheet::SubSheet const &ss) {
return ss.name == currentIdx;
});
if (next == pSubSheet.subsheets.end()) {
return ox::Error{1, "SubSheet not found"};
}
return getSubSheet(idx, idxIt + 1, *next);
}
ox::Result<TileSheet::SubSheet const*> getSubSheet(
ox::SpanView<ox::StringView> const &idx,
TileSheet const &ts) noexcept {
if (!idx.empty() && idx[0] == ts.subsheet.name) {
return getSubSheet<TileSheet::SubSheet const>(idx, 1, ts.subsheet);
}
return ox::Error{1, "SubSheet not found"};
}
ox::Result<TileSheet::SubSheet*> getSubSheet(
ox::SpanView<ox::StringView> const &idx,
TileSheet &ts) noexcept {
if (!idx.empty() && idx[0] == ts.subsheet.name) {
return getSubSheet<TileSheet::SubSheet>(idx, 1, ts.subsheet);
}
return ox::Error{1, "SubSheet not found"};
}
#if defined(__GNUC__) && __GNUC__ >= 13
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdangling-reference"

View File

@@ -10,6 +10,10 @@ namespace nostalgia::sound {
static struct: studio::Module {
ox::String id() const noexcept final {
return ox::String{"net.drinkingtea.nostalgia.sound"};
}
ox::Vector<studio::EditorMaker> editors(studio::Context&) const noexcept final {
return {
};
@@ -22,7 +26,7 @@ static struct: studio::Module {
} const mod;
const studio::Module *studioModule() noexcept {
studio::Module const *studioModule() noexcept {
return &mod;
}

View File

@@ -38,7 +38,7 @@ static int testUpdateHandler(turbine::Context &tctx) noexcept {
spriteX += xmod;
spriteY += ymod;
constexpr ox::StringView sprites = "nostalgia";
for (unsigned i = 0; i < sprites.len(); ++i) {
for (unsigned i = 0; i < sprites.size(); ++i) {
auto const c = static_cast<unsigned>(sprites[i] - ('a' - 1));
gfx::setSprite(cctx, i, {
.enabled = true,

View File

@@ -19,6 +19,9 @@ else()
endif()
add_subdirectory(applib)
#if(NOT APPLE)
# add_subdirectory(hull)
#endif()
add_subdirectory(keel)
add_subdirectory(turbine)
if(${OLYMPIC_BUILD_STUDIO})

View File

@@ -3,6 +3,11 @@ add_library(
OlympicApplib INTERFACE
)
target_link_libraries(
OlympicApplib INTERFACE
OxLogConn
)
target_sources(
OlympicApplib INTERFACE
applib.cpp

View File

@@ -0,0 +1,12 @@
add_library(Hull)
target_sources(
Hull PUBLIC
FILE_SET CXX_MODULES FILES
hull.cpp
)
target_link_libraries(
Hull PUBLIC
OxStd
)

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
module;
#include <ox/std/string.hpp>
export module hull;
namespace hull {
export
template<typename Str = ox::String, size_t SmallVecSz = 0>
constexpr ox::Result<ox::Vector<Str, SmallVecSz>> parseCmd(ox::StringViewCR cmd) noexcept
requires(ox::is_same_v<Str, ox::String> || ox::is_same_v<Str, ox::StringView>) {
auto const tokens = split(cmd, ' ');
ox::Vector<Str, SmallVecSz> args;
char waitingFor{};
auto const handleString = [&waitingFor, &args](
ox::StringViewCR token,
char const delimiter) {
if (endsWith(token, delimiter)) {
args.emplace_back(substr(token, 1, token.size() - 1));
} else {
waitingFor = delimiter;
args.emplace_back(substr(token, 1));
}
};
for (auto const &token : tokens) {
if (waitingFor) {
if (endsWith(token, waitingFor)) {
waitingFor = 0;
}
auto &tgt = *args.back().value;
if constexpr (ox::is_same_v<Str, ox::String>) {
tgt += substr(token, 0, token.size() - 1);
} else {
tgt = {tgt.data(), tgt.size() + token.size() - 1};
}
} else if (beginsWith(token, '"')) {
handleString(token, '"');
} else if (beginsWith(token, '\'')) {
handleString(token, '\'');
} else {
args.emplace_back(token);
}
}
if (waitingFor) {
return ox::Error{1, "unterminated string"};
}
return args;
}
template<typename Str = ox::String>
[[nodiscard]]
static constexpr bool testParse(ox::StringViewCR cmd, std::initializer_list<ox::StringView> const &expected) noexcept {
auto const [args, err] = parseCmd<Str>(cmd);
static constexpr auto equals = [](auto const &a, auto const &b) {
if (a.size() != b.size()) {
return false;
}
for (auto i = 0u; i < a.size(); ++i) {
if (a[i] != b[i]) {
return false;
}
}
return true;
};
return !err && equals(args, ox::Vector(expected));
}
static_assert(testParse("echo asdf", {"echo", "asdf"}));
static_assert(testParse<ox::String>("echo asdf", {"echo", "asdf"}));
static_assert(testParse("echo \"asdf\"", {"echo", "asdf"}));
static_assert(testParse<ox::String>("echo \"asdf\"", {"echo", "asdf"}));
static_assert(testParse("echo 'asdf'", {"echo", "asdf"}));
static_assert(testParse<ox::String>("echo 'asdf'", {"echo", "asdf"}));
static_assert(testParse("echo 'asdf' aoue", {"echo", "asdf", "aoue"}));
static_assert(testParse<ox::String>("echo 'asdf' aoue", {"echo", "asdf", "aoue"}));
export class Prompt {
private:
ox::String m_cmd;
ox::String m_workingDir{"/"};
ox::Vector<ox::String> m_prevCmds;
public:
private:
};
}

View File

@@ -13,11 +13,11 @@ namespace keel {
constexpr auto K1HdrSz = 40;
ox::Result<ox::UUID> readUuidHeader(ox::BufferView buff) noexcept;
ox::Result<ox::UUID> readUuidHeader(ox::BufferView const &buff) noexcept;
ox::Result<ox::UUID> regenerateUuidHeader(ox::Buffer &buff) noexcept;
ox::Error writeUuidHeader(ox::Writer_c auto &writer, ox::UUID const&uuid) noexcept {
ox::Error writeUuidHeader(ox::Writer_c auto &writer, ox::UUID const &uuid) noexcept {
OX_RETURN_ERROR(write(writer, "K1;"));
OX_RETURN_ERROR(uuid.toString(writer));
return writer.put(';');
@@ -25,26 +25,25 @@ ox::Error writeUuidHeader(ox::Writer_c auto &writer, ox::UUID const&uuid) noexce
template<typename T>
ox::Result<T> readAsset(ox::BufferView buff) noexcept {
std::size_t offset = 0;
auto const err = readUuidHeader(buff).error;
if (!err) {
offset = K1HdrSz; // the size of K1 headers
buff += K1HdrSz; // the size of K1 headers
}
auto out = ox::readClaw<T>(buff + offset);
auto out = ox::readClaw<T>(buff);
OX_RETURN_ERROR(out);
OX_RETURN_ERROR(ensureValid(out.value));
return out;
}
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::BufferView buff) noexcept;
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::BufferView const &buff) noexcept;
struct AssetHdr {
ox::UUID uuid;
ox::ClawHeader clawHdr;
};
ox::Result<ox::StringView> readAssetTypeId(ox::BufferView buff) noexcept;
ox::Result<ox::StringView> readAssetTypeId(ox::BufferView const &buff) noexcept;
ox::Result<AssetHdr> readAssetHeader(ox::BufferView buff) noexcept;
ox::Result<AssetHdr> readAssetHeader(ox::BufferView const &buff) noexcept;
}

View File

@@ -64,11 +64,13 @@ class AssetContainer {
protected:
constexpr void incRefs() const noexcept {
oxAssert(m_references < ox::MaxValue<decltype(m_references)>, "reference count exceeds maximum");
++m_references;
}
constexpr void decRefs() const noexcept {
--m_references;
oxAssert(m_references >= 0, "negative references");
}
[[nodiscard]]
@@ -162,6 +164,7 @@ template<typename T>
constexpr AssetRef<T>::AssetRef(AssetContainer<T> const*c) noexcept: m_ctr(c) {
if (m_ctr) {
m_ctr->updated.connect(this, &AssetRef::emitUpdated);
m_ctr->incRefs();
}
}
@@ -348,23 +351,23 @@ class AssetManager {
template<typename T>
class AssetRef {
private:
T const* m_obj = nullptr;
T const *m_obj = nullptr;
public:
constexpr AssetRef() noexcept = default;
explicit constexpr AssetRef(T const*obj) noexcept: m_obj(obj) {
explicit constexpr AssetRef(T const *obj) noexcept: m_obj(obj) {
}
constexpr T const*get() const noexcept {
constexpr T const *get() const noexcept {
return m_obj;
}
constexpr T const&operator*() const & noexcept {
constexpr T const &operator*() const & noexcept {
return *m_obj;
}
constexpr T const*operator->() const noexcept {
constexpr T const *operator->() const noexcept {
return m_obj;
}

View File

@@ -35,7 +35,7 @@ class Context {
};
constexpr ox::SpanView<PackTransform> packTransforms(
[[maybe_unused]] Context const&ctx) noexcept {
[[maybe_unused]] Context const &ctx) noexcept {
#ifndef OX_BARE_METAL
return ctx.packTransforms;
#else
@@ -44,7 +44,7 @@ constexpr ox::SpanView<PackTransform> packTransforms(
}
constexpr ox::SpanView<Converter> converters(
[[maybe_unused]] Context const&ctx) noexcept {
[[maybe_unused]] Context const &ctx) noexcept {
#ifndef OX_BARE_METAL
return ctx.converters;
#else

View File

@@ -29,22 +29,22 @@ OX_MODEL_BEGIN(PreloadPtr)
OX_MODEL_FIELD(preloadAddr)
OX_MODEL_END()
ox::Result<std::size_t> getPreloadAddr(Context &ctx, ox::FileAddress const&addr) noexcept;
ox::Result<std::size_t> getPreloadAddr(Context &ctx, ox::FileAddress const &addr) noexcept;
ox::Result<std::size_t> getPreloadAddr(Context &ctx, ox::StringViewCR path) noexcept;
void createUuidMapping(Context &ctx, ox::StringViewCR filePath, ox::UUID const&uuid) noexcept;
void createUuidMapping(Context &ctx, ox::StringViewCR filePath, ox::UUID const &uuid) noexcept;
// map of UUIDs to paths
using DuplicateSet = ox::HashMap<ox::UUID, ox::Vector<ox::String>>;
ox::Result<ox::UUID> pathToUuid(Context &ctx, ox::StringViewCR path) noexcept;
ox::Result<ox::UUID> getUuid(Context &ctx, ox::FileAddress const&fileAddr) noexcept;
ox::Result<ox::UUID> getUuid(Context &ctx, ox::FileAddress const &fileAddr) noexcept;
ox::Result<ox::UUID> getUuid(Context &ctx, ox::StringViewCR path) noexcept;
ox::Result<ox::CStringView> getPath(Context &ctx, ox::FileAddress const&fileAddr) noexcept;
ox::Result<ox::CStringView> getPath(Context &ctx, ox::FileAddress const &fileAddr) noexcept;
ox::Result<ox::CStringView> getPath(Context &ctx, ox::CStringViewCR fileId) noexcept;
@@ -58,7 +58,7 @@ ox::Result<ox::CStringView> uuidUrlToPath(Context &ctx, ox::StringViewCR uuid) n
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::StringViewCR uuid) noexcept;
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept;
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const &uuid) noexcept;
[[nodiscard]]
constexpr bool isUuidUrl(ox::StringViewCR path) noexcept {
@@ -147,7 +147,7 @@ template<typename T>
ox::Result<AssetRef<T>> readObj(
Context &ctx,
ox::StringViewCR assetId,
[[maybe_unused]] bool forceLoad = false) noexcept {
[[maybe_unused]] bool const forceLoad = false) noexcept {
#ifndef OX_BARE_METAL
return readObjFile<T>(ctx, assetId, forceLoad);
#else
@@ -158,8 +158,8 @@ ox::Result<AssetRef<T>> readObj(
template<typename T>
ox::Result<AssetRef<T>> readObj(
Context &ctx,
ox::FileAddress const&file,
[[maybe_unused]] bool forceLoad = false) noexcept {
ox::FileAddress const &file,
[[maybe_unused]] bool const forceLoad = false) noexcept {
#ifndef OX_BARE_METAL
OX_REQUIRE(assetId, file.getPath());
return readObj<T>(ctx, ox::StringView(assetId), forceLoad);
@@ -176,9 +176,9 @@ ox::Result<AssetRef<T>> readObj(
template<typename T>
ox::Error writeObj(
Context &ctx,
ox::FileAddress const&file,
T const&obj,
ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept {
ox::FileAddress const &file,
T const &obj,
ox::ClawFormat const fmt = ox::ClawFormat::Metal) noexcept {
OX_REQUIRE(objBuff, ox::writeClaw(obj, fmt));
return ctx.rom->write(file, objBuff.data(), objBuff.size());
}

View File

@@ -40,6 +40,6 @@ class Module {
void registerModule(Module const*mod) noexcept;
[[nodiscard]]
ox::Vector<keel::Module const*> const&modules() noexcept;
ox::Vector<keel::Module const*> const &modules() noexcept;
}

View File

@@ -125,7 +125,7 @@ ox::Error preloadObj(
OX_RETURN_ERROR(err);
keel::PreloadPtr const p{.preloadAddr = a};
OX_RETURN_ERROR(ox::writeMC(p).moveTo(buff));
auto const&pbufSz = pl.buff().size();
auto const &pbufSz = pl.buff().size();
oxOutf("preloaded {} as a {} @ {} to {} / {}, total size: {}\n",
path, obj.type()->typeName, a, a + size, pbufSz - 1, pbufSz - a);
} else {
@@ -148,7 +148,7 @@ ox::Error preloadDir(
// copy
oxTracef("pack.preload", "path: {}", path);
OX_REQUIRE(fileList, romFs.ls(path));
for (auto const&name : fileList) {
for (auto const &name : fileList) {
auto const filePath = ox::sfmt("{}{}", path, name);
OX_REQUIRE(stat, romFs.stat(filePath));
if (stat.fileType == ox::FileType::Directory) {
@@ -169,7 +169,7 @@ ox::Error preloadDir(
}
template<typename PlatSpec>
ox::Error appendBinary(ox::Buffer &binBuff, ox::SpanView<char> const&fsBuff, ox::Preloader<PlatSpec> &pl) noexcept {
ox::Error appendBinary(ox::Buffer &binBuff, ox::SpanView<char> const &fsBuff, ox::Preloader<PlatSpec> &pl) noexcept {
constexpr auto padbin = [](ox::BufferWriter &w, unsigned factor) noexcept -> ox::Error {
return w.write(nullptr, factor - w.buff().size() % factor);
};
@@ -185,7 +185,7 @@ ox::Error appendBinary(ox::Buffer &binBuff, ox::SpanView<char> const&fsBuff, ox:
OX_RETURN_ERROR(padbin(w, hdrSize));
OX_RETURN_ERROR(w.write(preloadHdr.data(), preloadHdr.bytes()));
OX_RETURN_ERROR(pl.offsetPtrs(binBuff.size()));
auto const&plBuff = pl.buff();
auto const &plBuff = pl.buff();
OX_RETURN_ERROR(w.write(plBuff.data(), plBuff.size()));
return {};
}

View File

@@ -122,7 +122,7 @@ class BaseConverter {
virtual ox::Result<ox::UPtr<Wrap>> convertPtrToPtr(keel::Context &ctx, Wrap &src) const noexcept = 0;
virtual ox::Result<ox::UPtr<Wrap>> convertBuffToPtr(
Context &ctx, ox::BufferView const&srcBuff) const noexcept = 0;
Context &ctx, ox::BufferView const &srcBuff) const noexcept = 0;
[[nodiscard]]
constexpr bool matches(
@@ -140,7 +140,7 @@ class ConverterFunc final: public BaseConverter {
private:
template<typename SrcType, typename DstType>
struct ParamPack {
using Src = SrcType;
using Src = ox::remove_const_t<SrcType>;
using Dst = DstType;
};
@@ -187,7 +187,7 @@ class ConverterFunc final: public BaseConverter {
}
ox::Result<ox::UPtr<Wrap>> convertBuffToPtr(
Context &ctx, ox::BufferView const&srcBuff) const noexcept override {
Context &ctx, ox::BufferView const &srcBuff) const noexcept override {
OX_REQUIRE_M(src, readAsset<SrcType>(srcBuff));
ox::Result<ox::UPtr<Wrap>> dst{makeWrap<DstType>()};
OX_RETURN_ERROR(convert(ctx, src, wrapCast<DstType>(*dst.value)));
@@ -214,13 +214,13 @@ class Converter {
}
[[nodiscard]]
BaseConverter const &converter() const noexcept {
return *m_buff.data();
return *std::launder(m_buff.data());
}
};
ox::Result<ox::UPtr<Wrap>> convert(
Context &ctx,
ox::BufferView const&srcBuffer,
ox::BufferView const &srcBuffer,
ox::StringViewCR dstTypeName,
int dstTypeVersion) noexcept;
@@ -241,7 +241,7 @@ ox::Result<ox::UPtr<Wrap>> convert(
ox::Result<ox::UPtr<Wrap>> convert(
Context &ctx,
auto const&src,
auto const &src,
ox::StringViewCR dstTypeName,
int const dstTypeVersion) noexcept {
auto srcCpy = src;
@@ -258,13 +258,13 @@ ox::Result<DstType> convertObjToObj(
}
template<typename DstType>
ox::Result<DstType> convert(Context &ctx, ox::BufferView const&src) noexcept {
ox::Result<DstType> convert(Context &ctx, ox::BufferView const &src) noexcept {
OX_REQUIRE(out, convert(ctx, src, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
return std::move(wrapCast<DstType>(*out));
}
template<typename DstType>
ox::Error convert(Context &ctx, ox::BufferView const&buff, DstType &outObj) noexcept {
ox::Error convert(Context &ctx, ox::BufferView const &buff, DstType &outObj) noexcept {
OX_REQUIRE(out, convert(ctx, buff, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
outObj = std::move(wrapCast<DstType>(*out));
return {};
@@ -279,7 +279,7 @@ ox::Error convertObjToObj(Context &ctx, auto &src, DstType &outObj) noexcept {
template<typename DstType>
ox::Result<ox::Buffer> convertBuffToBuff(
Context &ctx, ox::BufferView const&src, ox::ClawFormat const fmt) noexcept {
Context &ctx, ox::BufferView const &src, ox::ClawFormat const fmt) noexcept {
OX_REQUIRE(out, convert(ctx, src, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
return ox::writeClaw<DstType>(wrapCast<DstType>(*out), fmt);
}

View File

@@ -16,7 +16,7 @@ class TypeStore: public ox::TypeStore {
ox::String m_descPath;
public:
explicit TypeStore(ox::FileSystem &fs, ox::StringView descPath) noexcept;
explicit TypeStore(ox::FileSystem &fs, ox::StringViewCR descPath) noexcept;
protected:
ox::Result<ox::UPtr<ox::DescriptorType>> loadDescriptor(ox::StringView typeId) noexcept override;

View File

@@ -6,7 +6,7 @@
namespace keel {
ox::Result<ox::UUID> readUuidHeader(ox::BufferView buff) noexcept {
ox::Result<ox::UUID> readUuidHeader(ox::BufferView const &buff) noexcept {
if (buff.size() < K1HdrSz) [[unlikely]] {
return ox::Error{1, "Insufficient data to contain complete Keel header"};
}
@@ -27,16 +27,15 @@ ox::Result<ox::UUID> regenerateUuidHeader(ox::Buffer &buff) noexcept {
return id;
}
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::BufferView buff) noexcept {
ox::Result<ox::ModelObject> readAsset(ox::TypeStore &ts, ox::BufferView const &buff) noexcept {
std::size_t offset = 0;
if (!readUuidHeader(buff).error) {
offset = K1HdrSz;
}
buff += offset;
return ox::readClaw(ts, buff);
return ox::readClaw(ts, buff + offset);
}
ox::Result<ox::StringView> readAssetTypeId(ox::BufferView const buff) noexcept {
ox::Result<ox::StringView> readAssetTypeId(ox::BufferView const &buff) noexcept {
auto const err = readUuidHeader(buff).error;
auto const offset = err ? 0u : K1HdrSz;
if (offset >= buff.size()) [[unlikely]] {
@@ -45,15 +44,14 @@ ox::Result<ox::StringView> readAssetTypeId(ox::BufferView const buff) noexcept {
return ox::readClawTypeId(buff + offset);
}
ox::Result<AssetHdr> readAssetHeader(ox::BufferView buff) noexcept {
ox::Result<AssetHdr> readAssetHeader(ox::BufferView const &buff) noexcept {
ox::Result<AssetHdr> out;
auto const err = readUuidHeader(buff).moveTo(out.value.uuid);
auto const offset = err ? 0u : K1HdrSz;
if (offset >= buff.size()) [[unlikely]] {
return ox::Error(1, "Buffer too small for expected data");
}
buff += offset;
OX_RETURN_ERROR(ox::readClawHeader(buff).moveTo(out.value.clawHdr));
OX_RETURN_ERROR(ox::readClawHeader(buff + offset).moveTo(out.value.clawHdr));
return out;
}

View File

@@ -16,7 +16,7 @@ static ox::Error init(
setRomFs(ctx, std::move(fs), *duplicateSet) :
setRomFs(ctx, std::move(fs));
#ifndef OX_BARE_METAL
auto const&mods = modules();
auto const &mods = modules();
for (auto &mod : mods) {
// register type converters
for (auto const c : mod->converters()) {

View File

@@ -24,10 +24,10 @@ ox::Result<char*> loadRom(ox::StringViewCR path) noexcept {
auto buff = new char[static_cast<std::size_t>(size)];
file.read(buff, size);
return buff;
} catch (std::ios_base::failure const&e) {
} catch (std::ios_base::failure const &e) {
oxErrorf("Could not read ROM file due to file IO failure: {}", e.what());
return ox::Error(2, "Could not read ROM file");
} catch (std::bad_alloc const&e) {
} catch (std::bad_alloc const &e) {
oxErrorf("Could not read ROM file due to new failure: {}", e.what());
return ox::Error(2, "Could not allocate memory for ROM file");
}
@@ -42,14 +42,14 @@ static void clearUuidMap(Context &ctx) noexcept {
ctx.pathToUuid.clear();
}
void createUuidMapping(Context &ctx, ox::StringViewCR filePath, ox::UUID const&uuid) noexcept {
void createUuidMapping(Context &ctx, ox::StringViewCR filePath, ox::UUID const &uuid) noexcept {
ctx.pathToUuid[filePath] = uuid;
ctx.uuidToPath[uuid.toString()] = filePath;
}
static ox::Error buildUuidMap(Context &ctx, ox::StringViewCR path, DuplicateSet *duplicates) noexcept {
OX_REQUIRE(files, ctx.rom->ls(path));
for (auto const&f : files) {
for (auto const &f : files) {
OX_REQUIRE_M(filePath, ox::join("/", ox::Array<ox::StringView, 2>{path, f}));
OX_REQUIRE(stat, ctx.rom->stat(filePath));
if (stat.fileType == ox::FileType::NormalFile) {
@@ -59,7 +59,7 @@ static ox::Error buildUuidMap(Context &ctx, ox::StringViewCR path, DuplicateSet
auto const [uuid, err] = readUuidHeader(buff);
if (!err) {
// check for duplication
if (duplicates && ctx.uuidToPath[uuid.toString()].len()) {
if (duplicates && ctx.uuidToPath[uuid.toString()].size()) {
auto &dl = (*duplicates)[uuid];
if (dl.empty()) {
dl.emplace_back(ctx.uuidToPath[uuid.toString()]);
@@ -97,7 +97,7 @@ ox::Result<ox::UUID> pathToUuid(Context &ctx, ox::StringViewCR path) noexcept {
#endif
}
ox::Result<ox::UUID> getUuid(Context &ctx, ox::FileAddress const&fileAddr) noexcept {
ox::Result<ox::UUID> getUuid(Context &ctx, ox::FileAddress const &fileAddr) noexcept {
OX_REQUIRE(path, fileAddr.getPath());
return getUuid(ctx, path);
}
@@ -111,7 +111,7 @@ ox::Result<ox::UUID> getUuid(Context &ctx, ox::StringViewCR path) noexcept {
}
}
ox::Result<ox::CStringView> getPath(Context &ctx, ox::FileAddress const&fileAddr) noexcept {
ox::Result<ox::CStringView> getPath(Context &ctx, ox::FileAddress const &fileAddr) noexcept {
OX_REQUIRE(path, fileAddr.getPath());
if (beginsWith(path, "uuid://")) {
auto const uuid = substr(path, 7);
@@ -173,7 +173,7 @@ ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::StringViewCR uuid) noex
#endif
}
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexcept {
ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const &uuid) noexcept {
#ifndef OX_BARE_METAL
OX_REQUIRE_M(out, ctx.uuidToPath.at(uuid.toString()));
return ox::CStringView(*out);
@@ -240,7 +240,7 @@ ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::StringViewCR path
return static_cast<std::size_t>(p.preloadAddr) + ctx.preloadSectionOffset;
}
ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::FileAddress const&addr) noexcept {
ox::Result<std::size_t> getPreloadAddr(keel::Context &ctx, ox::FileAddress const &addr) noexcept {
OX_REQUIRE(stat, ctx.rom->stat(addr));
OX_REQUIRE(buff, static_cast<ox::MemFS&>(*ctx.rom).directAccess(addr));
PreloadPtr p;
@@ -261,6 +261,9 @@ namespace keel {
ox::Error setRomFs(Context &ctx, ox::UPtr<ox::FileSystem> &&fs, DuplicateSet &duplicateSet) noexcept {
ctx.rom = std::move(fs);
clearUuidMap(ctx);
#ifndef OX_BARE_METAL
ctx.assetManager.gc();
#endif
return buildUuidMap(ctx, &duplicateSet);
}

View File

@@ -8,14 +8,14 @@ namespace keel {
static ox::Vector<Module const*> mods;
void registerModule(Module const*mod) noexcept {
void registerModule(Module const *mod) noexcept {
if (mod) {
mods.emplace_back(mod);
}
}
[[nodiscard]]
ox::Vector<Module const*> const&modules() noexcept {
ox::Vector<Module const*> const &modules() noexcept {
return mods;
}

View File

@@ -32,7 +32,7 @@ static ox::Result<ox::Buffer> readFileBuff(ox::StringViewCR path) noexcept {
file.seekg(0, std::ios::beg);
file.read(buff.data(), static_cast<std::streamsize>(buff.size()));
return buff;
} catch (std::ios_base::failure const&e) {
} catch (std::ios_base::failure const &e) {
oxErrorf("Could not read OxFS file: {}", e.what());
return ox::Error(2, "Could not read OxFS file");
}
@@ -88,7 +88,7 @@ static ox::Error pack(
oxOutf("Final ROM buff size: {} bytes\n", romBuff.size());
OX_RETURN_ERROR(writeFileBuff(argRomBin, romBuff));
OX_REQUIRE(manifestJson, ox::writeOCString(manifest));
OX_RETURN_ERROR(writeFileBuff(argManifest, {manifestJson.data(), manifestJson.len()}));
OX_RETURN_ERROR(writeFileBuff(argManifest, {manifestJson.data(), manifestJson.size()}));
return {};
}

View File

@@ -144,7 +144,7 @@ static ox::Error transformClaw(
// copy
oxTracef("pack.transformClaw", "path: {}", path);
OX_REQUIRE(fileList, dest.ls(path));
for (auto const&name : fileList) {
for (auto const &name : fileList) {
auto const filePath = ox::sfmt("{}{}", path, name);
OX_REQUIRE(stat, dest.stat(filePath));
if (stat.fileType == ox::FileType::Directory) {
@@ -171,7 +171,7 @@ static ox::Error copy(
auto const childLogPrefix = ox::sfmt("{}\t", logPrefix);
// copy
OX_REQUIRE(fileList, src.ls(path));
for (auto const&name : fileList) {
for (auto const &name : fileList) {
auto const currentFile = ox::sfmt("{}{}", path, name);
if (beginsWith(name, ".")) {
continue;
@@ -187,7 +187,7 @@ static ox::Error copy(
OX_DEFER [&status] {
oxOutf(" {}\n", status);
};
OX_REQUIRE_M(buff, src.read(currentFile));
OX_REQUIRE(buff, src.read(currentFile));
// write file to dest
OX_RETURN_ERROR(dest.write(currentFile, buff));
status = "OK";

View File

@@ -9,12 +9,12 @@
namespace keel {
static ox::Result<BaseConverter const*> findConverter(
ox::SpanView<Converter> const&converters,
ox::SpanView<Converter> const &converters,
ox::StringViewCR srcTypeName,
int const srcTypeVersion,
ox::StringViewCR dstTypeName,
int const dstTypeVersion) noexcept {
for (auto const&c : converters) {
for (auto const &c : converters) {
if (c.converter().matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
return &c.converter();
}
@@ -22,17 +22,17 @@ static ox::Result<BaseConverter const*> findConverter(
return ox::Error{1, "Could not find converter"};
};
static ox::Result<ox::UPtr<Wrap>> convert(BaseConverter const&c, Context &ctx, ox::BufferView const&src) noexcept {
static ox::Result<ox::UPtr<Wrap>> convert(BaseConverter const &c, Context &ctx, ox::BufferView const &src) noexcept {
return c.convertBuffToPtr(ctx, src);
}
static ox::Result<ox::UPtr<Wrap>> convert(BaseConverter const&c, Context &ctx, Wrap &src) noexcept {
static ox::Result<ox::UPtr<Wrap>> convert(BaseConverter const &c, Context &ctx, Wrap &src) noexcept {
return c.convertPtrToPtr(ctx, src);
}
static ox::Result<ox::UPtr<Wrap>> convert(
Context &ctx,
ox::SpanView<Converter> const&converters,
ox::SpanView<Converter> const &converters,
auto &src,
ox::StringViewCR srcTypeName,
int const srcTypeVersion,
@@ -45,7 +45,7 @@ static ox::Result<ox::UPtr<Wrap>> convert(
return convert(*c, ctx, src);
}
// try to chain multiple converters
for (auto const&subConverter : converters) {
for (auto const &subConverter : converters) {
if (!subConverter.converter().dstMatches(dstTypeName, dstTypeVersion)) {
continue;
}
@@ -61,7 +61,7 @@ static ox::Result<ox::UPtr<Wrap>> convert(
ox::Result<ox::UPtr<Wrap>> convert(
Context &ctx,
ox::BufferView const&srcBuffer,
ox::BufferView const &srcBuffer,
ox::StringViewCR dstTypeName,
int const dstTypeVersion) noexcept {
OX_REQUIRE(hdr, readAssetHeader(srcBuffer));

View File

@@ -6,7 +6,7 @@
namespace keel {
TypeStore::TypeStore(ox::FileSystem &fs, ox::StringView descPath) noexcept:
TypeStore::TypeStore(ox::FileSystem &fs, ox::StringViewCR descPath) noexcept:
m_fs(fs),
m_descPath(descPath) {
}

View File

@@ -16,7 +16,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
constexpr ox::StringView uuidStr = "8d814442-f46e-4cc3-8edc-ca3c01cc86db";
constexpr ox::StringView hdr = "K1;8d814442-f46e-4cc3-8edc-ca3c01cc86db;";
OX_REQUIRE(uuid, ox::UUID::fromString(uuidStr));
ox::Array<char, hdr.len()> buff;
ox::Array<char, hdr.size()> buff;
ox::CharBuffWriter bw(buff);
OX_RETURN_ERROR(keel::writeUuidHeader(bw, uuid));
oxExpect(ox::StringView(buff.data(), buff.size()), hdr);
@@ -25,7 +25,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
},
};
int main(int argc, char const **argv) {
int main(int const argc, char const **argv) {
int retval = -1;
if (argc > 0) {
auto const args = ox::Span{argv, static_cast<size_t>(argc)};

View File

@@ -10,6 +10,9 @@
namespace studio {
[[nodiscard]]
ox::Vector<Module const*> const &modules() noexcept;
void registerModule(Module const*) noexcept;
}

View File

@@ -2,15 +2,18 @@
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <complex>
#include <ctime>
#include <ox/logconn/logconn.hpp>
#include <ox/std/trace.hpp>
#include <ox/std/uuid.hpp>
#include <keel/media.hpp>
#include <keel/keel.hpp>
#include <turbine/turbine.hpp>
#include <studio/context.hpp>
#include <studioapp/studioapp.hpp>
#include "studioui.hpp"
namespace studio {
@@ -40,7 +43,7 @@ static void mouseButtonEventHandler(turbine::Context &ctx, int const btn, bool c
[[nodiscard]]
ox::Vector<ox::SpanView<uint8_t>> WindowIcons() noexcept;
static ox::Error runApp(
static ox::Error runStudio(
ox::StringViewCR appName,
ox::StringViewCR projectDataDir,
ox::UPtr<ox::FileSystem> &&fs) noexcept {
@@ -61,17 +64,49 @@ static ox::Error runApp(
static ox::Error run(
ox::StringViewCR appName,
ox::StringViewCR projectDataDir,
ox::SpanView<ox::CString>) {
ox::SpanView<ox::CString> const &args) {
// seed UUID generator
auto const time = std::time(nullptr);
ox::UUID::seedGenerator({
static_cast<uint64_t>(time),
static_cast<uint64_t>(time << 1)
});
// run app
auto const err = runApp(appName, projectDataDir, ox::UPtr<ox::FileSystem>{});
oxAssert(err, "Something went wrong...");
return err;
if (args.size() > 1 && ox::StringView{args[1]} == "cmd") {
if (args.size() < 5) {
return ox::Error{1, "insufficient arguments for sub-command"};
}
auto constexpr numCmdArgs = 5;
ox::StringView const projectDir = args[2];
ox::StringView const moduleId = args[3];
ox::StringView const subCmd = args[4];
for (auto const m : modules()) {
if (m->id() == moduleId) {
for (auto const &c : m->commands()) {
if (c.name == subCmd) {
auto kctx = keel::init(
ox::make_unique<ox::PassThroughFS>(projectDir),
c.name);
if (kctx.error) {
return ox::Error{2, "failed to load project directory"};
}
Project project{*kctx.value, projectDir, projectDataDir};
return c.func(
project,
args.size() > numCmdArgs ?
args + numCmdArgs : ox::SpanView<ox::CString>{});
}
}
return ox::Error{1, "command not found"};
}
}
return ox::Error{1, "module not found"};
} else {
// run app
auto const err = runStudio(appName, projectDataDir, ox::UPtr<ox::FileSystem>{});
oxAssert(err, "Something went wrong...");
return err;
}
return {};
}
}

View File

@@ -28,7 +28,7 @@ void ClawEditor::draw(Context&) noexcept {
ImGui::EndChild();
}
void ClawEditor::drawRow(ox::ModelValue const&value) noexcept {
void ClawEditor::drawRow(ox::ModelValue const &value) noexcept {
using Str = ox::BasicString<100>;
Str val, type;
switch (value.type()) {
@@ -93,13 +93,13 @@ void ClawEditor::drawRow(ox::ModelValue const&value) noexcept {
ImGui::Text("%s", val.c_str());
}
void ClawEditor::drawVar(ObjPath &path, ox::StringViewCR name, ox::ModelValue const&value) noexcept {
void ClawEditor::drawVar(ObjPath &path, ox::StringViewCR name, ox::ModelValue const &value) noexcept {
using Str = ox::BasicString<100>;
path.push_back(name);
if (value.type() == ox::ModelValue::Type::Object) {
drawTree(path, value.get<ox::ModelObject>());
} else if (value.type() == ox::ModelValue::Type::Vector) {
auto const&vec = value.get<ox::ModelValueVector>();
auto const &vec = value.get<ox::ModelValueVector>();
auto const pathStr = ox::join<Str>("##", path).unwrap();
auto const lbl = ox::sfmt<Str>("{}##{}", name, pathStr);
auto const flags = ImGuiTreeNodeFlags_SpanFullWidth
@@ -110,7 +110,7 @@ void ClawEditor::drawVar(ObjPath &path, ox::StringViewCR name, ox::ModelValue co
ImGui::SameLine();
drawRow(value);
if (open) {
for (auto i = 0lu; auto const&e: vec) {
for (auto i = 0lu; auto const &e: vec) {
auto const iStr = ox::sfmt<Str>("{}", i);
path.push_back(iStr);
ImGui::TableNextRow(0, 5);
@@ -138,7 +138,7 @@ void ClawEditor::drawVar(ObjPath &path, ox::StringViewCR name, ox::ModelValue co
path.pop_back();
}
void ClawEditor::drawTree(ObjPath &path, ox::ModelObject const&obj) noexcept {
void ClawEditor::drawTree(ObjPath &path, ox::ModelObject const &obj) noexcept {
using Str = ox::BasicString<100>;
for (auto const &c : obj) {
ImGui::TableNextRow(0, 5);

View File

@@ -21,11 +21,11 @@ class ClawEditor: public Editor {
void draw(Context&) noexcept final;
private:
static void drawRow(ox::ModelValue const&value) noexcept;
static void drawRow(ox::ModelValue const &value) noexcept;
void drawVar(ObjPath &path, ox::StringViewCR name, ox::ModelValue const&value) noexcept;
void drawVar(ObjPath &path, ox::StringViewCR name, ox::ModelValue const &value) noexcept;
void drawTree(ObjPath &path, ox::ModelObject const&obj) noexcept;
void drawTree(ObjPath &path, ox::ModelObject const &obj) noexcept;
};
}

View File

@@ -24,7 +24,7 @@ void NewMenu::open() noexcept {
m_useDefaultPath = true;
m_explorer.setModel(buildFileTreeModel(
m_explorer,
[](ox::StringViewCR, ox::FileStat const&s) {
[](ox::StringViewCR, ox::FileStat const &s) {
return s.fileType == ox::FileType::Directory;
}).or_value(ox::UPtr<FileTreeModel>{}));
}
@@ -75,26 +75,26 @@ void NewMenu::addItemMaker(ox::UPtr<ItemMaker> &&im) noexcept {
m_types.emplace_back(std::move(im));
std::sort(
m_types.begin(), m_types.end(),
[](ox::UPtr<ItemMaker> const&im1, ox::UPtr<ItemMaker> const&im2) {
[](ox::UPtr<ItemMaker> const &im1, ox::UPtr<ItemMaker> const &im2) {
return im1->typeDisplayName() < im2->typeDisplayName();
});
}
void NewMenu::installItemTemplate(ox::UPtr<ItemTemplate> &&tmplt) noexcept {
for (auto const&im : m_types) {
for (auto const &im : m_types) {
if (im->installTemplate(std::move(tmplt))) {
break;
}
}
}
void NewMenu::drawNewItemType(Context const&sctx) noexcept {
void NewMenu::drawNewItemType(Context const &sctx) noexcept {
setSize({280, 180});
drawWindow(sctx.tctx, m_open, [this] {
ig::ListBox("Item Type", [&](size_t const i) -> ox::CStringView {
return m_types[i]->typeDisplayName();
}, m_types.size(), m_selectedType, {200, 100});
auto const&im = *m_types[m_selectedType];
auto const &im = *m_types[m_selectedType];
drawFirstPageButtons(im.itemTemplates().size() == 1 ?
Stage::NewItemTransitioningToPath : Stage::NewItemTemplate);
if (m_stage == Stage::NewItemTransitioningToPath || m_stage == Stage::NewItemTemplate) {
@@ -105,10 +105,10 @@ void NewMenu::drawNewItemType(Context const&sctx) noexcept {
});
}
void NewMenu::drawNewItemTemplate(Context const&sctx) noexcept {
void NewMenu::drawNewItemTemplate(Context const &sctx) noexcept {
setSize({280, 180});
drawWindow(sctx.tctx, m_open, [this] {
auto const&templates =
auto const &templates =
m_types[m_selectedType]->itemTemplates();
ig::ListBox("Template", [&](size_t const i) -> ox::CStringView {
return templates[i]->name();
@@ -192,7 +192,7 @@ void NewMenu::drawLastPageButtons(Context &sctx) noexcept {
}
void NewMenu::finish(Context &sctx) noexcept {
if (m_itemName.len() == 0) {
if (m_itemName.size() == 0) {
oxLogError(ox::Error{1, "New file error: no file name"});
return;
}

View File

@@ -75,7 +75,7 @@ class NewMenu final: public Popup {
void installItemTemplate(ox::UPtr<ItemTemplate> &&tmplt) noexcept;
private:
void drawNewItemType(Context const&sctx) noexcept;
void drawNewItemType(Context const &sctx) noexcept;
void drawNewItemPath(Context &sctx) noexcept;

View File

@@ -13,7 +13,7 @@
namespace studio {
class NewProject: public studio::Popup {
class NewProject: public Popup {
public:
enum class Stage {
Closed,

View File

@@ -57,7 +57,7 @@ void ProjectExplorer::dirContextMenu(ox::StringViewCR path) const noexcept {
if (ImGui::MenuItem("Add Directory")) {
addDir.emit(path);
}
if (path.len() && ImGui::MenuItem("Delete")) {
if (path.size() && ImGui::MenuItem("Delete")) {
deleteItem.emit(path);
}
ImGui::EndPopup();

View File

@@ -37,11 +37,15 @@ static bool shutdownHandler(turbine::Context &ctx) {
namespace ig {
extern bool s_mainWinHasFocus;
}
static ox::Vector<Module const*> modules;
static ox::Vector<Module const*> g_modules;
ox::Vector<Module const*> const &modules() noexcept {
return g_modules;
}
void registerModule(Module const*mod) noexcept {
if (mod) {
modules.emplace_back(mod);
g_modules.emplace_back(mod);
}
}
@@ -246,6 +250,9 @@ void StudioUI::drawMenu() noexcept {
if (ImGui::MenuItem("Open Project...", STUDIO_CTRL "+O")) {
m_taskRunner.add(*ox::make<FileDialogManager>(this, &StudioUI::openProjectPath));
}
if (ImGui::MenuItem("Reload Project")) {
oxLogError(openProjectPath(m_project->projectPath()));
}
if (ImGui::BeginMenu("Recent Projects", m_recentProjects.size() > 1)) {
for (size_t i = 1; i < m_recentProjects.size(); ++i) {
auto const &p = m_recentProjects[i];
@@ -443,7 +450,7 @@ void StudioUI::loadModule(Module const &mod) noexcept {
}
void StudioUI::loadModules() noexcept {
for (auto const mod : modules) {
for (auto const mod : g_modules) {
loadModule(*mod);
}
}
@@ -632,6 +639,9 @@ ox::Error StudioUI::createOpenProject(ox::StringViewCR path) noexcept {
ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept {
OX_REQUIRE_M(fs, keel::loadRomFs(path.view()));
m_project.reset();
m_openFiles.clear();
m_editors.clear();
keel::DuplicateSet ds;
OX_RETURN_ERROR(keel::setRomFs(keelCtx(m_tctx), std::move(fs), ds));
if (ds.size()) {
@@ -645,8 +655,8 @@ ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept {
m_messagePopup.show(msg);
}
OX_RETURN_ERROR(
ox::make_unique_catch<Project>(keelCtx(m_tctx), std::move(path), m_projectDataDir)
.moveTo(m_project));
ox::make_unique_catch<Project>(keelCtx(m_tctx), std::move(path), m_projectDataDir)
.moveTo(m_project));
m_sctx.project = m_project.get();
m_activeEditor = nullptr;
m_activeEditorOnLastDraw = nullptr;
@@ -661,8 +671,6 @@ ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept {
m_project->dirDeleted.connect(this, &StudioUI::handleDeleteDir);
m_project->fileDeleted.connect(this, &StudioUI::handleDeleteFile);
m_project->fileMoved.connect(this, &StudioUI::handleMoveFile);
m_openFiles.clear();
m_editors.clear();
studio::editConfig<StudioConfig>(keelCtx(m_tctx), [&](StudioConfig &config) {
auto const pcIt = std::find_if(
config.projects.begin(), config.projects.end(),
@@ -673,14 +681,18 @@ ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept {
auto p = std::move(*pcIt);
std::ignore = config.projects.erase(pcIt);
auto &pc = *config.projects.emplace(0, std::move(p));
for (auto const &f: pc.openFiles) {
auto const openFileErr = openFileActiveTab(f, pc.activeTabItemName == f);
if (openFileErr) {
oxErrorf("\nCould not open editor for file:\n\t{}\nReason:\n\t{}\n", f, toStr(openFileErr));
continue;
}
m_activeEditor = m_editors.back().value->get();
}
std::ignore = pc.openFiles.erase(
std::remove_if(
pc.openFiles.begin(), pc.openFiles.end(),
[&](ox::String const &f) {
auto const openFileErr = openFileActiveTab(f, pc.activeTabItemName == f);
if (openFileErr) {
oxErrorf("\nCould not open editor for file:\n\t{}\nReason:\n\t{}\n", f, toStr(openFileErr));
return true;
}
m_activeEditor = m_editors.back().value->get();
return false;
}));
} else {
config.projects.emplace(0, StudioConfig::ProjectConfig{
.projectPath = ox::String{m_project->projectPath()},

View File

@@ -140,7 +140,7 @@ class Editor: public studio::BaseEditor {
ox::Error pushCommand(Args&&... args) noexcept {
try {
return m_undoStack.push(ox::make_unique<UC>(ox::forward<Args>(args)...));
} catch (ox::Exception const&ex) {
} catch (ox::Exception const &ex) {
return ex.toError();
}
}
@@ -148,7 +148,7 @@ class Editor: public studio::BaseEditor {
private:
ox::Error markUnsavedChanges(UndoCommand const*) noexcept;
ox::Error handleRename(ox::StringViewCR oldPath, ox::StringViewCR newPath, ox::UUID const&id) noexcept;
ox::Error handleRename(ox::StringViewCR oldPath, ox::StringViewCR newPath, ox::UUID const &id) noexcept;
};

View File

@@ -21,7 +21,7 @@ struct FDFilterItem {
FDFilterItem(ox::StringViewCR pName, ox::StringViewCR pSpec) noexcept;
};
ox::Result<ox::String> saveFile(ox::Vector<FDFilterItem> const&exts) noexcept;
ox::Result<ox::String> saveFile(ox::Vector<FDFilterItem> const &exts) noexcept;
ox::Result<ox::String> chooseDirectory() noexcept;

View File

@@ -78,7 +78,7 @@ class FileExplorer: public ox::SignalHandler {
}
private:
ox::Result<bool> setSelectedPath(ox::StringViewCR path, FileTreeModel const&node) noexcept;
ox::Result<bool> setSelectedPath(ox::StringViewCR path, FileTreeModel const &node) noexcept;
};
@@ -106,7 +106,7 @@ class FileTreeModel {
void setChildren(ox::Vector<ox::UPtr<FileTreeModel>> children) noexcept;
[[nodiscard]]
ox::Vector<ox::UPtr<FileTreeModel>> const&children() const noexcept {
ox::Vector<ox::UPtr<FileTreeModel>> const &children() const noexcept {
return m_children;
}
@@ -129,13 +129,13 @@ ox::Result<ox::UPtr<FileTreeModel>> buildFileTreeModel(
ox::StringParam name,
ox::StringViewCR path,
FileTreeModel *parent = nullptr,
std::function<bool(ox::StringViewCR, ox::FileStat const&)> const&filter =
std::function<bool(ox::StringViewCR, ox::FileStat const&)> const &filter =
[](ox::StringViewCR, ox::FileStat const&) {return true;},
bool showEmptyDirs = true) noexcept;
ox::Result<ox::UPtr<FileTreeModel>> buildFileTreeModel(
FileExplorer &explorer,
std::function<bool(ox::StringViewCR, ox::FileStat const&)> const&filter =
std::function<bool(ox::StringViewCR, ox::FileStat const&)> const &filter =
[](ox::StringViewCR, ox::FileStat const&) {return true;},
bool showEmptyDirs = true) noexcept;

View File

@@ -31,7 +31,7 @@ ox::Result<T> getDragDropPayload(ox::CStringViewCR name) noexcept {
return ox::Error(1, "No drag/drop payload");
}
return ox::readClaw<T>({
reinterpret_cast<char const*>(payload->Data),
std::launder(reinterpret_cast<char const*>(payload->Data)),
static_cast<size_t>(payload->DataSize)});
}

View File

@@ -27,11 +27,11 @@ class ItemTemplate {
virtual ~ItemTemplate() = default;
[[nodiscard]]
constexpr ox::String const&name() const noexcept {
constexpr ox::String const &name() const noexcept {
return m_name;
}
constexpr bool operator<=>(ItemTemplate const&other) const noexcept {
constexpr bool operator<=>(ItemTemplate const &other) const noexcept {
return m_name != other.name() ? (m_name < other.name() ? -1 : 1) : 0;
}
@@ -105,7 +105,7 @@ class ItemMaker {
virtual ~ItemMaker() noexcept = default;
[[nodiscard]]
ox::String const&typeDisplayName() const noexcept {
ox::String const &typeDisplayName() const noexcept {
return m_typeDisplayName;
}
@@ -120,17 +120,17 @@ class ItemMaker {
return false;
}
constexpr ox::Vector<ox::UPtr<ItemTemplate>> const&itemTemplates() const noexcept {
constexpr ox::Vector<ox::UPtr<ItemTemplate>> const &itemTemplates() const noexcept {
return m_templates;
}
[[nodiscard]]
ox::String const&fileExt() const noexcept {
ox::String const &fileExt() const noexcept {
return m_fileExt;
}
[[nodiscard]]
ox::String const&defaultPath() const noexcept {
ox::String const &defaultPath() const noexcept {
return m_parentDir;
}
@@ -212,7 +212,7 @@ class ItemMakerT final: public ItemMaker {
ox::StringParam pDisplayName,
ox::StringViewCR pParentDir,
ox::StringParam fileExt,
T const&pItem,
T const &pItem,
ox::ClawFormat const pFmt) noexcept:
ItemMaker(
std::move(pDisplayName),
@@ -249,7 +249,7 @@ class ItemMakerT final: public ItemMaker {
ox::StringViewCR pPath,
size_t const pTemplateIdx) const noexcept override {
createUuidMapping(keelCtx(ctx.tctx), pPath, ox::UUID::generate().unwrap());
auto const&templates = itemTemplates();
auto const &templates = itemTemplates();
auto const tmplIdx = pTemplateIdx < templates.size() ? pTemplateIdx : 0;
OX_REQUIRE_M(tmpl, templates[tmplIdx]->getItem(
keelCtx(ctx), typeName(), typeVersion()));

View File

@@ -23,15 +23,34 @@ struct EditorMaker {
Func make;
};
struct Command {
ox::String name;
std::function<ox::Error(Project&, ox::SpanView<ox::CString>)> func;
Command(
ox::StringParam name,
std::function<ox::Error(Project&, ox::SpanView<ox::CString>)> func) noexcept:
name(std::move(name)),
func(std::move(func)) {}
};
class Module {
public:
virtual ~Module() noexcept = default;
virtual ox::Vector<EditorMaker> editors(studio::Context &ctx) const;
[[nodiscard]]
virtual ox::String id() const noexcept = 0;
virtual ox::Vector<ox::UPtr<ItemMaker>> itemMakers(studio::Context&) const;
[[nodiscard]]
virtual ox::Vector<Command> commands() const;
virtual ox::Vector<ox::UPtr<ItemTemplate>> itemTemplates(studio::Context&) const;
[[nodiscard]]
virtual ox::Vector<EditorMaker> editors(Context &ctx) const;
[[nodiscard]]
virtual ox::Vector<ox::UPtr<ItemMaker>> itemMakers(Context&) const;
[[nodiscard]]
virtual ox::Vector<ox::UPtr<ItemTemplate>> itemTemplates(Context&) const;
};

View File

@@ -43,11 +43,11 @@ class Popup: public Widget {
m_title = std::move(title);
}
constexpr ox::String const&title() const noexcept {
constexpr ox::String const &title() const noexcept {
return m_title;
}
void drawWindow(turbine::Context &ctx, bool &open, std::function<void()> const&drawContents);
void drawWindow(turbine::Context &ctx, bool &open, std::function<void()> const &drawContents);
};

View File

@@ -40,8 +40,8 @@ constexpr ox::Result<ox::StringView> fileExt(ox::StringViewCR path) noexcept {
[[nodiscard]]
constexpr ox::StringView parentDir(ox::StringView path) noexcept {
if (path.len() && path[path.len() - 1] == '/') {
path = substr(path, 0, path.len() - 1);
if (path.size() && path[path.size() - 1] == '/') {
path = substr(path, 0, path.size() - 1);
}
auto const extStart = ox::find(path.crbegin(), path.crend(), '/').offset();
return substr(path, 0, extStart);
@@ -59,12 +59,12 @@ class Project: public ox::SignalHandler {
ox::HashMap<ox::String, ox::Vector<ox::String>> m_fileExtFileMap;
public:
explicit Project(keel::Context &ctx, ox::String path, ox::StringViewCR projectDataDir);
explicit Project(keel::Context &ctx, ox::StringParam path, ox::StringViewCR projectDataDir);
ox::Error create() noexcept;
[[nodiscard]]
ox::String const&projectPath() const noexcept;
ox::String const &projectPath() const noexcept;
[[nodiscard]]
ox::FileSystem &romFs() noexcept;
@@ -77,7 +77,7 @@ class Project: public ox::SignalHandler {
template<typename T>
ox::Error writeObj(
ox::StringViewCR path,
T const&obj,
T const &obj,
ox::ClawFormat fmt) noexcept;
/**
@@ -86,7 +86,7 @@ class Project: public ox::SignalHandler {
template<typename T>
ox::Error writeObj(
ox::StringViewCR path,
T const&obj) noexcept;
T const &obj) noexcept;
template<typename T>
ox::Result<T> loadObj(ox::StringViewCR path) const noexcept;
@@ -101,6 +101,16 @@ class Project: public ox::SignalHandler {
ox::Error deleteItem(ox::StringViewCR path) noexcept;
[[nodiscard]]
keel::Context &kctx() noexcept {
return m_kctx;
}
[[nodiscard]]
keel::Context const &kctx() const noexcept {
return m_kctx;
}
[[nodiscard]]
bool exists(ox::StringViewCR path) const noexcept;
@@ -108,7 +118,7 @@ class Project: public ox::SignalHandler {
ox::Error subscribe(ProjectEvent e, ox::SignalHandler *tgt, Functor &&slot) const noexcept;
[[nodiscard]]
ox::Vector<ox::String> const&fileList(ox::StringViewCR ext) noexcept;
ox::Vector<ox::String> const &fileList(ox::StringViewCR ext) noexcept;
ox::Error writeTypeStore() noexcept;
@@ -117,7 +127,7 @@ class Project: public ox::SignalHandler {
void indexFile(ox::StringViewCR path) noexcept;
ox::Error writeBuff(ox::StringViewCR path, ox::BufferView const&buff) noexcept;
ox::Error writeBuff(ox::StringViewCR path, ox::BufferView const &buff) noexcept;
ox::Result<ox::Buffer> loadBuff(ox::StringViewCR path) const noexcept;
@@ -136,13 +146,13 @@ class Project: public ox::SignalHandler {
ox::Signal<ox::Error(ox::StringViewCR)> fileRecognized;
ox::Signal<ox::Error(ox::StringViewCR)> fileDeleted;
ox::Signal<ox::Error(ox::StringViewCR)> dirDeleted;
ox::Signal<ox::Error(ox::StringViewCR path, ox::UUID const&id)> fileUpdated;
ox::Signal<ox::Error(ox::StringViewCR oldPath, ox::StringViewCR newPath, ox::UUID const&id)> fileMoved;
ox::Signal<ox::Error(ox::StringViewCR path, ox::UUID const &id)> fileUpdated;
ox::Signal<ox::Error(ox::StringViewCR oldPath, ox::StringViewCR newPath, ox::UUID const &id)> fileMoved;
};
template<typename T>
ox::Error Project::writeObj(ox::StringViewCR path, T const&obj, ox::ClawFormat fmt) noexcept {
ox::Error Project::writeObj(ox::StringViewCR path, T const &obj, ox::ClawFormat fmt) noexcept {
OX_REQUIRE_M(buff, ox::writeClaw(obj, fmt));
if (fmt == ox::ClawFormat::Organic) {
buff.pop_back();
@@ -167,7 +177,7 @@ ox::Error Project::writeObj(ox::StringViewCR path, T const&obj, ox::ClawFormat f
}
template<typename T>
ox::Error Project::writeObj(ox::StringViewCR path, T const&obj) noexcept {
ox::Error Project::writeObj(ox::StringViewCR path, T const &obj) noexcept {
OX_REQUIRE(ext, fileExt(path));
auto const fmt = m_typeFmt[ext].or_value(ox::ClawFormat::Metal);
return writeObj(path, obj, fmt);
@@ -179,6 +189,10 @@ ox::Result<T> Project::loadObj(ox::StringViewCR path) const noexcept {
if constexpr(ox::is_same_v<T, ox::ModelObject>) {
return keel::readAsset(m_typeStore, buff);
} else {
OX_REQUIRE(typeId, keel::readAssetTypeId(buff));
if (typeId != ox::ModelTypeId_v<T>) {
return keel::convert<T>(m_kctx, buff);
}
return keel::readAsset<T>(buff);
}
}
@@ -197,7 +211,7 @@ ox::Error Project::subscribe(ProjectEvent e, ox::SignalHandler *tgt, Functor &&s
case ProjectEvent::FileRecognized:
{
OX_REQUIRE(files, listFiles());
for (auto const&f : files) {
for (auto const &f : files) {
slot(f);
}
connect(this, &Project::fileRecognized, tgt, slot);

View File

@@ -16,19 +16,19 @@ namespace studio {
struct Selection {
ox::Point a, b;
constexpr Selection() noexcept = default;
constexpr Selection(ox::Point const&pA, ox::Point const&pB) noexcept: a(pA), b(pB) {}
constexpr Selection(ox::Point const &pA, ox::Point const &pB) noexcept: a(pA), b(pB) {}
[[nodiscard]]
constexpr ox::Size size() const noexcept {
return {b.x - a.x, b.y - a.y};
}
[[nodiscard]]
constexpr bool contains(ox::Point const&pt) const noexcept {
constexpr bool contains(ox::Point const &pt) const noexcept {
return a.x <= pt.x && a.y <= pt.y
&& b.x >= pt.x && b.y >= pt.y;
}
};
constexpr auto iterateSelection(studio::Selection const&sel, auto const&cb) {
constexpr auto iterateSelection(Selection const &sel, auto const &cb) {
constexpr auto retErr = ox::is_same_v<decltype(cb(0, 0)), ox::Error>;
for (auto x = sel.a.x; x <= sel.b.x; ++x) {
for (auto y = sel.a.y; y <= sel.b.y; ++y) {
@@ -44,7 +44,7 @@ constexpr auto iterateSelection(studio::Selection const&sel, auto const&cb) {
}
};
constexpr auto iterateSelectionRows(studio::Selection const&sel, auto const&cb) {
constexpr auto iterateSelectionRows(Selection const &sel, auto const &cb) {
constexpr auto retErr = ox::is_same_v<decltype(cb(0, 0)), ox::Error>;
for (auto y = sel.a.y; y <= sel.b.y; ++y) {
for (auto x = sel.a.x; x <= sel.b.x; ++x) {

View File

@@ -12,7 +12,7 @@ namespace studio {
class NoChangesException: public ox::Exception {
public:
inline NoChangesException(std::source_location sloc = std::source_location::current()):
explicit NoChangesException(std::source_location sloc = std::source_location::current()):
ox::Exception(1, "Command makes no changes.", sloc) {}
};

Some files were not shown because too many files have changed in this diff Show More