Compare commits

..

34 Commits

Author SHA1 Message Date
7477ede222 [ox/std] Cleanup some enable_ifs
All checks were successful
Build / build (push) Successful in 1m7s
2026-01-21 23:35:19 -06:00
65e3153dda [ox/std] Add Union_c concept 2026-01-21 23:35:02 -06:00
53a224cf8f [ox/std] Cleanup 2026-01-21 23:34:36 -06:00
592e641ba9 [ox/std] Fix writeItoa to work with max length 64 bit ints
All checks were successful
Build / build (push) Successful in 1m8s
2026-01-21 23:28:13 -06:00
689da4a019 [ox] Update docs
All checks were successful
Build / build (push) Successful in 1m10s
2026-01-21 21:04:17 -06:00
bdf7755ee2 [nostalgia/developer-handbook] Update developer handbook 2026-01-21 21:03:47 -06:00
63f627377d [ox/std] Remove excess char from intToStr return
All checks were successful
Build / build (push) Successful in 1m9s
2026-01-20 01:29:37 -06:00
ff9002ad9a [nostalgia/developer-handbook] Update error handling section
All checks were successful
Build / build (push) Successful in 1m8s
2026-01-20 01:22:05 -06:00
4d0da022cf [ox] Update error handling docs
All checks were successful
Build / build (push) Successful in 1m8s
2026-01-20 00:47:51 -06:00
02332d99b5 [ox] Fix issues in String Types section of docs
All checks were successful
Build / build (push) Successful in 1m8s
2026-01-20 00:26:38 -06:00
a566ed2a8b [ox/std] Fix writeItoa to work with negatives
All checks were successful
Build / build (push) Successful in 1m9s
2026-01-19 23:00:16 -06:00
815c3d19bf [ox/std] Make StringLiteral constructors non-explicit
All checks were successful
Build / build (push) Successful in 1m8s
2026-01-19 21:00:58 -06:00
522bb14f18 [ox/std] Fix intToStr to have room for negatives 2026-01-19 21:00:12 -06:00
f40d5515f9 [ox] Add strings section to docs
All checks were successful
Build / build (push) Successful in 1m11s
2026-01-18 19:00:24 -06:00
941d1d90dc [ox/std] Add Vector::reserveResize
All checks were successful
Build / build (push) Successful in 1m15s
2026-01-07 21:48:04 -06:00
3e880dcdcc [nostalgia/gfx/studio] Remove unused EBO management
All checks were successful
Build / build (push) Successful in 1m16s
2026-01-07 21:33:16 -06:00
03328ac10f [turbine/glfw] Fix to handle null click handler
All checks were successful
Build / build (push) Successful in 1m9s
2025-12-03 20:44:01 -06:00
63d0abaa3c [nostalgia/gfx/gba] Remove teagba scroll bg function call
All checks were successful
Build / build (push) Successful in 1m15s
2025-11-22 23:53:18 -06:00
ef2a8cda77 [teagba] Remove bg scroll, cleanup 2025-11-22 23:53:04 -06:00
671fa54f6f [ox/std] Make ox::Vector::push_back comply with std::vector::push_back
All checks were successful
Build / build (push) Successful in 1m12s
2025-09-10 23:47:36 -05:00
517432679b [nostalgia/gfx/studio] Cleanup includes
All checks were successful
Build / build (push) Successful in 1m15s
2025-09-04 22:40:58 -05:00
b31c01f724 [keel,studio] Cleanup 2025-09-04 22:37:01 -05:00
f41213f13f [ox/std] Fix channel format for oxLogError
All checks were successful
Build / build (push) Successful in 1m8s
2025-09-04 21:11:52 -05:00
28be7c4650 [ox/fs] Fix write functions to take SpanViews 2025-09-04 21:11:52 -05:00
2f340b13b2 [ox/std] Fix Windows GCC build
All checks were successful
Build / build (push) Successful in 1m15s
2025-09-04 01:21:13 -05:00
312c818866 [nostalgia/gfx/studio] Remove unused variable
All checks were successful
Build / build (push) Successful in 1m10s
2025-08-29 22:18:37 -05:00
0d69d0c4a2 [ox/std] Remove oxDebug line
All checks were successful
Build / build (push) Successful in 1m18s
2025-08-19 21:02:13 -05:00
81a0b8c820 [ox/mc] Remove an oxDebug line
Some checks failed
Build / build (push) Failing after 22s
2025-08-19 20:59:51 -05:00
172b5aee90 [ox/oc] Remove an oxDebug line
Some checks failed
Build / build (push) Failing after 17s
2025-08-19 20:58:32 -05:00
2b5338a9df [nostalgia] Improve Makefile dependency handling
Some checks failed
Build / build (push) Failing after 9s
2025-08-17 14:10:45 -05:00
8a430faf4c [keel] Cleanup
All checks were successful
Build / build (push) Successful in 1m19s
2025-08-12 22:57:13 -05:00
e59382dd60 [keel] Address undefined behavior 2025-08-12 22:39:08 -05:00
3006e77ef3 [ox/std] Add and integrate std::launder
All checks were successful
Build / build (push) Successful in 1m30s
2025-08-12 22:37:21 -05:00
59c112a69c [studio] Fix navigate back not to iterate on the first item twice
All checks were successful
Build / build (push) Successful in 1m55s
2025-08-09 15:15:34 -05:00
48 changed files with 516 additions and 229 deletions

View File

@@ -14,7 +14,7 @@ endif
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP} PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-gba .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} ${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-mac .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/olympic/studio/applib/src/rsrc.json
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/nostalgia/studio/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 .PHONY: build-player
build-player: build-player:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP} ${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 .PHONY: run
run: build-player run: build-player
${PROJECT_PLAYER} sample_project ${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 .PHONY: run-studio
run-studio: build run-studio: build-studio
${PROJECT_STUDIO} ${PROJECT_STUDIO}
.PHONY: gba-run .PHONY: gba-run
gba-run: pkg-gba gba-run: pkg-gba
${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba ${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba
.PHONY: debug .PHONY: debug
debug: build debug: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project ${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project
.PHONY: debug-studio .PHONY: debug-studio
debug-studio: build debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO} ${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO}
.PHONY: configure-gba .PHONY: configure-gba
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} ${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}

217
deps/ox/ox-docs.md vendored
View File

@@ -28,10 +28,7 @@ All components have a platform indicator next to them:
Ox provides ```ox::Error``` to report errors. Ox provides ```ox::Error``` to report errors.
```ox::Error``` is a struct that has overloaded operators to behave like an ```ox::Error``` is a struct that has overloaded operators to behave like an
integer error code, plus some extra fields to enhance debuggability. integer error code, plus some extra fields to enhance debuggability.
If instantiated through the ```OxError(x)``` macro, it will also include the ```ox::Error```s will also include the file and line of the error.
file and line of the error.
The ```OxError(x)``` macro should only be used for the initial instantiation of
an ```ox::Error```.
In addition to ```ox::Error``` there is also the template ```ox::Result<T>```. In addition to ```ox::Error``` there is also the template ```ox::Result<T>```.
```ox::Result``` simply wraps the type T value in a struct that also includes ```ox::Result``` simply wraps the type T value in a struct that also includes
@@ -49,7 +46,7 @@ ox::Result<int> foo(int i) noexcept {
if (i < 10) { if (i < 10) {
return i + 1; // implicitly calls ox::Result<T>::Result(T) return i + 1; // implicitly calls ox::Result<T>::Result(T)
} }
return OxError(1); // implicitly calls ox::Result<T>::Result(ox::Error) return ox::Error(1); // implicitly calls ox::Result<T>::Result(ox::Error)
} }
int caller1() { int caller1() {
@@ -181,6 +178,216 @@ variant for creating a non-const value.
* ```OX_REQUIRE_M``` - OX_REQUIRE Mutable * ```OX_REQUIRE_M``` - OX_REQUIRE Mutable
### Ox String Types
Ox has six different major string types.
These types are divided into two categories: store types and view types.
String stores maintain a copy of the string data, whereas view types only
maintain a reference to the data.
Views should be used where you otherwise might use a const reference to a
string store type.
Having all of these different string types may sound like an interoperability
nightmare, but taking string view types extensively where applicable makes the
imagined interoperability issues virtually non-existent.
#### String Store Types
##### String / BasicString
```ox::String```, or really ```ox::BasicString```, is Ox's version of
```std::string```.
Like ```std::string```, ```String``` allocates to store the string data.
Also like ```std::string```, ```String``` allows for small string
optimization for strings under 8 bytes.
Unlike ```std::string```, the template that ```String``` is based on,
```BasicString```, takes a parameter that allows adjusting to different size
small string buffers.
```ox::String``` is an alias to ```ox::BasicString<8>```.
```cpp
// s can hold up to 100 bytes, plus one for a null terminator before allocating
ox::BasicString<100> s;
```
Also unlike ```std::string```, ```ox::String``` has an explicit C-string conversion
constructor.
This prevents accidental instantiations of ```String```.
Consider the following:
```cpp
void fStd(std::string const&);
void fOx(ox::String const&);
int main() {
// implicit and silent instantiation of std::string, which includes an
// allocation
fStd("123456789");
// Will fail to compile:
fOx("123456789");
// But explicit String instantiation will work:
fOx(ox::String{"123456789"});
}
```
##### IString
```IString```, or "inline string", is like ```BasicString```, but it will cut
off strings that exceed that limit.
```cpp
ox::IString<5> s; // s can hold up to 5 characters, plus a null terminator
s = "12345"; // valid
s = "123456"; // will compile and run, but will get cut off at '5'
```
This is useful for certain string categories that have fixed lengths, like UUID
strings or for numbers.
Ox makes use of ```IString``` in the following ways:
```cpp
using UUIDStr = ox::IString<36>;
// and
template<Integer_c Integer>
[[nodiscard]]
constexpr auto intToStr(Integer v) noexcept {
constexpr auto Cap = [] {
auto out = 0;
switch (sizeof(Integer)) {
case 1:
out = 3;
break;
case 2:
out = 5;
break;
case 4:
out = 10;
break;
case 8:
out = 21;
break;
}
return out + ox::is_signed_v<Integer>;
}();
ox::IString<Cap> out;
std::ignore = out.resize(out.cap());
ox::CharBuffWriter w{{out.data(), out.cap()}};
std::ignore = writeItoa(v, w);
std::ignore = out.resize(w.tellp());
return out;
}
```
##### StringParam
```StringParam``` is a weird type.
Because ```String::String(const char*)``` is explicit, it becomes a pain for
functions to take ```String```s.
```cpp
struct Type {
ox::String m_s;
explicit Type(ox::String p): m_s(std::move(p)) {
}
};
void f() {
ox::String s{"asdf"};
Type t1{"asdf"}; // invalid - will not compile
Type t2{s}; // invalid - will not compile
Type t3{std::move(s)}; // valid
Type t4{ox::String{"asdf"}}; // valid
}
```
```StringParam``` has implicit conversion constructors, and will appropriately
move from r-value ```String```s or create a ```String``` if not passed
ownership of an existing ```String```.
Think of ```StringParam``` as a way to opt-in to implicit instantiation with
strings.
```StringParam``` can access the string as a view through the ```view()```
function, and the ```String``` inside can be accessed by moving from the
```StringParam```.
```cpp
struct Type {
ox::String m_s;
explicit Type(ox::StringParam p): m_s(std::move(p)) {
}
};
void f() {
ox::String s{"asdf"};
Type t1{"asdf"}; // valid
Type t2{s}; // valid
Type t3{std::move(s)}; // valid
Type t4{ox::String{"asdf"}}; // valid
}
```
#### String View Types
##### StringView
```ox::StringView``` is Ox's version of ```std::string_view```.
```StringView``` contains a pointer to a string, along with its size.
This should be the normal type taken when a function needs a string that will
exist until it returns.
##### CStringView
```CStringView``` is like ```StringView```, but it comes with the promise that
the string ends with a null terminator.
Accordingly, it has a ```c_str()``` function in addition to the ```data()```
function that ```StringView``` has.
```CStringView``` should be used when wrapping a C API that only takes C
strings.
##### StringLiteral
```StringLiteral``` is a string view type, but it kind of straddles the line
between view and store types.
Creating a ```StringLiteral``` is a promise that you are passing a string
literal into the constructor.
This means you can treat it like a store, that can be safely used as a copy of
the data.
Functions that take ```StringLiteral```s are allowed to assume that the data
will have no lifetime concerns and hold onto it without any need to make a
copy.
It has a consteval constructor to enforce the promise that it is a compile time
string.
```cpp
void f(ox::StringLiteral const&);
int main() {
f("123456789"); // valid
f(ox::String{"123456789"}.c_str()); // invalid - will not compile
}
```
#### Other Variants
There are a few convenience aliases as well.
* StringCR = String const&
* StringViewCR = StringView const&
* CStringViewCR = CStringView const&
* CString = const char*
String views do not generally need const references, but it does make debugging
easier, as we can skip the constructor call if a string view already exists.
These kind of aliases probably should not exist for most types, but strings are
fundamental and ease of use is desirable.
### Logging and Output ### Logging and Output
Ox provides for logging and debug prints via the ```oxTrace```, ```oxDebug```, and ```oxError``` macros. Ox provides for logging and debug prints via the ```oxTrace```, ```oxDebug```, and ```oxError``` macros.

View File

@@ -87,7 +87,7 @@ class FileSystem {
return writeFilePath(path, buffer, size, FileType::NormalFile); 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); return write(path, buff.data(), buff.size(), FileType::NormalFile);
} }
@@ -95,7 +95,7 @@ class FileSystem {
return write(inode, buffer, size, FileType::NormalFile); 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); return write(inode, buff.data(), buff.size(), FileType::NormalFile);
} }

View File

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

View File

@@ -181,7 +181,6 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
} }
} }
} catch (Json::LogicError const&e) { } catch (Json::LogicError const&e) {
oxDebugf("JSON error: {}", e.what());
err = ox::Error(1, "error reading JSON data"); err = ox::Error(1, "error reading JSON data");
} }
++m_fieldIt; ++m_fieldIt;

View File

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

View File

@@ -17,19 +17,19 @@ namespace ox {
template<typename T> template<typename T>
[[nodiscard]] [[nodiscard]]
constexpr T byteSwap(typename enable_if<sizeof(T) == 1, T>::type i) noexcept { constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 1) {
return i; return i;
} }
template<typename T> template<typename T>
[[nodiscard]] [[nodiscard]]
constexpr T byteSwap(typename enable_if<sizeof(T) == 2, T>::type i) noexcept { constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 2) {
return static_cast<T>(i << 8) | static_cast<T>(i >> 8); return static_cast<T>(i << 8) | static_cast<T>(i >> 8);
} }
template<typename T> template<typename T>
[[nodiscard]] [[nodiscard]]
constexpr T byteSwap(typename enable_if<sizeof(T) == 4, T>::type i) noexcept { constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 4) {
return ((i >> 24) & 0x000000ff) | return ((i >> 24) & 0x000000ff) |
((i >> 8) & 0x0000ff00) | ((i >> 8) & 0x0000ff00) |
((i << 8) & 0x00ff0000) | ((i << 8) & 0x00ff0000) |
@@ -38,7 +38,7 @@ constexpr T byteSwap(typename enable_if<sizeof(T) == 4, T>::type i) noexcept {
template<typename T> template<typename T>
[[nodiscard]] [[nodiscard]]
constexpr T byteSwap(typename enable_if<sizeof(T) == 8, T>::type i) noexcept { constexpr T byteSwap(T const i) noexcept requires(sizeof(T) == 8) {
return ((i >> 56) & 0x00000000000000ff) | return ((i >> 56) & 0x00000000000000ff) |
((i >> 40) & 0x000000000000ff00) | ((i >> 40) & 0x000000000000ff00) |
((i >> 24) & 0x0000000000ff0000) | ((i >> 24) & 0x0000000000ff0000) |

View File

@@ -32,4 +32,8 @@ concept Integral_c = ox::is_integral_v<T>;
template<typename T, size_t max> template<typename T, size_t max>
concept IntegerRange_c = ox::is_integer_v<T> && ox::MaxValue<T> >= max; concept IntegerRange_c = ox::is_integer_v<T> && ox::MaxValue<T> >= max;
template<typename Union>
concept Union_c = is_union_v<Union>;
} }

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 { constexpr void *operator new[](std::size_t, void *addr) noexcept {
return addr; 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 #endif
namespace ox { 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> template<typename T, typename U = T, typename ...Args>
[[nodiscard]] [[nodiscard]]
constexpr U *make(Args &&...args) noexcept { constexpr U *make(Args &&...args) noexcept {

View File

@@ -18,34 +18,34 @@ namespace ox {
template<Integer_c Integer> template<Integer_c Integer>
constexpr ox::Error writeItoa(Integer v, ox::Writer_c auto &writer) noexcept { constexpr ox::Error writeItoa(Integer v, ox::Writer_c auto &writer) noexcept {
if (v) { if (v) {
ox::ResizedInt_t<Integer, 64> mod = 1000000000000000000; ox::ResizedInt_t<Integer, 64> mod = 1000000000000000000;
ox::ResizedInt_t<Integer, 64> val = v; ox::ResizedInt_t<Integer, 64> val = v;
constexpr auto base = 10; constexpr auto base = 10;
auto it = 0; auto it = 0;
if (val < 0) { if (val < 0) {
OX_RETURN_ERROR(writer.put('-')); OX_RETURN_ERROR(writer.put('-'));
val = ~val + 1;
}
while (mod) {
auto digit = val / mod;
val %= mod;
mod /= base;
if (it || digit) {
constexpr auto start = '0';
if (digit >= 10) [[unlikely]] {
digit -= 10;
OX_RETURN_ERROR(writer.put('1'));
}
OX_RETURN_ERROR(writer.put(static_cast<char>(start + digit)));
++it; ++it;
} }
while (mod) {
auto digit = val / mod;
val %= mod;
mod /= base;
if (it || digit) {
ox::ResizedInt_t<Integer, 64> start = '0';
if (digit >= 10) {
start = 'a';
digit -= 10;
}
OX_RETURN_ERROR(writer.put(static_cast<char>(start + digit)));
++it;
}
}
} else {
// 0 is a special case
OX_RETURN_ERROR(writer.put('0'));
} }
return {}; } else {
// 0 is a special case
OX_RETURN_ERROR(writer.put('0'));
}
return {};
} }
} }

View File

@@ -23,12 +23,12 @@ class StringLiteral: public detail::BaseStringView {
constexpr StringLiteral(StringLiteral const &sv) noexcept = default; constexpr StringLiteral(StringLiteral const &sv) noexcept = default;
consteval explicit StringLiteral(std::nullptr_t) noexcept {} consteval StringLiteral(std::nullptr_t) noexcept {}
consteval explicit StringLiteral(char const *str, std::size_t const len) noexcept: BaseStringView{str, len} {} consteval StringLiteral(char const *str, std::size_t const len) noexcept: BaseStringView{str, len} {}
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_ALLOW_UNSAFE_BUFFERS_BEGIN
consteval explicit StringLiteral(char const *str) noexcept: StringLiteral{str, ox::strlen(str)} {} consteval StringLiteral(char const *str) noexcept: StringLiteral{str, ox::strlen(str)} {}
OX_ALLOW_UNSAFE_BUFFERS_END OX_ALLOW_UNSAFE_BUFFERS_END
constexpr StringLiteral &operator=(StringLiteral const &other) noexcept { constexpr StringLiteral &operator=(StringLiteral const &other) noexcept {

View File

@@ -28,3 +28,4 @@ add_test("[ox/std] FromHex" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "FromHex")
add_test("[ox/std] ToHex" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ToHex") add_test("[ox/std] ToHex" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "ToHex")
add_test("[ox/std] UUID" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID") add_test("[ox/std] UUID" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID")
add_test("[ox/std] UUID::generate" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID::generate") add_test("[ox/std] UUID::generate" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "UUID::generate")
add_test("[ox/std] intToStr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "intToStr")

View File

@@ -337,7 +337,6 @@ OX_CLANG_NOWARN_END
oxExpect(si["asdf"], 0); oxExpect(si["asdf"], 0);
oxAssert(si["aoeu"] == 100, "aoeu != 100"); oxAssert(si["aoeu"] == 100, "aoeu != 100");
auto si2 = si; auto si2 = si;
oxDebugf("{}", si2["asdf"]);
oxExpect(si2["asdf"], 0); oxExpect(si2["asdf"], 0);
oxAssert(si2["aoeu"] == 100, "aoeu != 100"); oxAssert(si2["aoeu"] == 100, "aoeu != 100");
ox::HashMap<int, int> ii; ox::HashMap<int, int> ii;
@@ -537,6 +536,33 @@ OX_CLANG_NOWARN_END
return ox::Error(0); return ox::Error(0);
} }
}, },
{
"intToStr",
[] {
oxExpect(ox::intToStr(static_cast<int8_t>(127)), "127");
oxExpect(ox::intToStr(static_cast<int8_t>(-128)), "-128");
oxExpect(ox::intToStr(static_cast<uint8_t>(255)), "255");
oxExpect(ox::intToStr(static_cast<uint16_t>(65535)), "65535");
oxExpect(ox::intToStr(static_cast<int16_t>(32767)), "32767");
oxExpect(ox::intToStr(static_cast<int16_t>(-32768)), "-32768");
oxExpect(ox::intToStr(static_cast<uint32_t>(4294967295)), "4294967295");
oxExpect(ox::intToStr(static_cast<int32_t>(2147483647)), "2147483647");
oxExpect(ox::intToStr(static_cast<int32_t>(-2147483648)), "-2147483648");
oxExpect(ox::intToStr(static_cast<uint64_t>(18446744073709551615u)), "18446744073709551615");
oxExpect(ox::intToStr(static_cast<int64_t>(9223372036854775807)), "9223372036854775807");
oxExpect(ox::intToStr(static_cast<int64_t>(-9223372036854775807)), "-9223372036854775807");
oxExpect(ox::intToStr(0), "0");
oxExpect(ox::intToStr(5), "5");
oxExpect(ox::intToStr(5000), "5000");
oxExpect(ox::intToStr(50000), "50000");
oxExpect(ox::intToStr(500000), "500000");
oxExpect(ox::intToStr(-5), "-5");
oxExpect(ox::intToStr(-5000), "-5000");
oxExpect(ox::intToStr(-50000), "-50000");
oxExpect(ox::intToStr(-500000), "-500000");
return ox::Error{};
}
},
}; };
int main(int argc, const char **argv) { int main(int argc, const char **argv) {

View File

@@ -268,7 +268,7 @@ using TraceStream = NullStream;
inline void logError(const char *file, int line, const char *fmt, const Error &err) noexcept { inline void logError(const char *file, int line, const char *fmt, const Error &err) noexcept {
if (err) { if (err) {
TraceStream trc(file, line, "ox::error"); TraceStream trc(file, line, "ox.error");
if (err.src.file_name() != nullptr) { if (err.src.file_name() != nullptr) {
trc << "Error: (" << err.src.file_name() << ":" << err.src.line() << "):"; trc << "Error: (" << err.src.file_name() << ":" << err.src.line() << "):";
} else { } 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 { inline void logError(const char *file, int line, const Error &err) noexcept {
if (err) { if (err) {
TraceStream trc(file, line, "ox::error"); TraceStream trc(file, line, "ox.error");
trc << "Error:" << err; trc << "Error:" << err;
if (err.src.file_name() != nullptr) { if (err.src.file_name() != nullptr) {
trc << "(" << err.src.file_name() << ":" << err.src.line() << ")"; trc << "(" << err.src.file_name() << ":" << err.src.line() << ")";

View File

@@ -63,25 +63,6 @@ namespace ox {
using CString = char const*; 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> template<std::size_t sz>
struct SignedType { struct SignedType {
}; };

View File

@@ -34,10 +34,10 @@ struct VectorAllocator {
ox::Array<AllocAlias<T>, Size> m_data = {}; ox::Array<AllocAlias<T>, Size> m_data = {};
protected: protected:
constexpr VectorAllocator() noexcept = default; constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(const VectorAllocator&) noexcept = default; constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) 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 // small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated() || cap > Size) { if (std::is_constant_evaluated() || cap > Size) {
*items = Allocator{}.allocate(cap); *items = Allocator{}.allocate(cap);
@@ -49,42 +49,26 @@ struct VectorAllocator {
constexpr void moveConstructItemsFrom( constexpr void moveConstructItemsFrom(
T **items, T **items,
VectorAllocator *src, VectorAllocator *src,
const std::size_t count, std::size_t const count,
const std::size_t cap) noexcept { std::size_t const cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM, // this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later // try removing it later
if (!std::is_constant_evaluated()) { if (!std::is_constant_evaluated()) {
if (cap <= m_data.size() && count <= m_data.size()) { if (cap <= m_data.size() && count <= m_data.size()) {
for (auto i = 0u; i < count; ++i) { for (auto i = 0u; i < count; ++i) {
const auto dstItem = reinterpret_cast<T *>(&m_data[i]); auto const srcItem = std::launder(reinterpret_cast<T*>(&src->m_data[i]));
const auto srcItem = reinterpret_cast<T *>(&src->m_data[i]); new (&m_data[i]) T(std::move(*srcItem));
std::construct_at<T>(dstItem, std::move(*srcItem)); }
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( constexpr void deallocate(T *const items, std::size_t const cap) noexcept {
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 {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr // small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
if (items) { if (items) {
@@ -103,10 +87,10 @@ template<typename T, typename Allocator>
struct VectorAllocator<T, Allocator, 0> { struct VectorAllocator<T, Allocator, 0> {
protected: protected:
constexpr VectorAllocator() noexcept = default; constexpr VectorAllocator() noexcept = default;
constexpr VectorAllocator(const VectorAllocator&) noexcept = default; constexpr VectorAllocator(VectorAllocator const&) noexcept = default;
constexpr VectorAllocator(VectorAllocator&&) 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); *items = Allocator{}.allocate(cap);
} }
@@ -114,15 +98,15 @@ struct VectorAllocator<T, Allocator, 0> {
constexpr void moveConstructItemsFrom( constexpr void moveConstructItemsFrom(
T**, T**,
VectorAllocator*, VectorAllocator*,
const std::size_t, std::size_t const,
const std::size_t) noexcept { std::size_t const) noexcept {
} }
[[maybe_unused]] [[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) { if (items) {
Allocator{}.deallocate(items, cap); Allocator{}.deallocate(items, cap);
} }
@@ -263,6 +247,8 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
constexpr void resize(std::size_t size) noexcept(useNoexcept); constexpr void resize(std::size_t size) noexcept(useNoexcept);
constexpr void reserveResize(std::size_t size) noexcept(useNoexcept);
[[nodiscard]] [[nodiscard]]
constexpr T *data() noexcept { constexpr T *data() noexcept {
return m_items; return m_items;
@@ -287,7 +273,9 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
template<typename... Args> template<typename... Args>
constexpr T &emplace_back(Args&&... args) noexcept(useNoexcept); 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); constexpr void pop_back() noexcept(useNoexcept);
@@ -421,7 +409,7 @@ constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allo
m_size = other.m_size; m_size = other.m_size;
m_cap = other.m_cap; m_cap = other.m_cap;
m_items = other.m_items; 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_size = 0;
other.m_cap = 0; other.m_cap = 0;
other.m_items = nullptr; other.m_items = nullptr;
@@ -531,6 +519,12 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::resize(std::size_t size) n
m_size = size; m_size = size;
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveResize(std::size_t const size) noexcept(useNoexcept) {
reserve(size);
resize(size);
}
template<typename T, std::size_t SmallVectorSize, typename Allocator> template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const&v) const noexcept { constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(MaybeView_t<T> const&v) const noexcept {
for (std::size_t i = 0; i < m_size; ++i) { for (std::size_t i = 0; i < m_size; ++i) {
@@ -617,7 +611,16 @@ constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args)
} }
template<typename T, std::size_t SmallVectorSize, typename Allocator> 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) { if (m_size == m_cap) {
reserve(m_cap ? m_cap * 2 : initialCap); reserve(m_cap ? m_cap * 2 : initialCap);
} }

View File

@@ -99,23 +99,23 @@ volatile OffsetPair &regBgOfs(auto const bgIdx) noexcept {
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// Memory Addresses // Memory Addresses
#define MEM_EWRAM (*reinterpret_cast<ox::Array<uint16_t, 0x0203'FFFF - 0x0200'0000>*>(0x0200'0000)) #define MEM_EWRAM (*(reinterpret_cast<ox::Array<uint16_t, 0x0203'FFFF - 0x0200'0000>*>(0x0200'0000)))
#define MEM_IWRAM (*reinterpret_cast<ox::Array<uint8_t, 0x0300'7FFF - 0x0300'0000>*>(0x0300'0000)) #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))
using Palette = ox::Array<uint16_t, 128>; using Palette = ox::Array<uint16_t, 128>;
#define MEM_BG_PALETTE (*reinterpret_cast<::Palette*>(0x0500'0000)) #define MEM_BG_PALETTE (*(reinterpret_cast<::Palette*>(0x0500'0000)))
#define MEM_SPRITE_PALETTE (*reinterpret_cast<::Palette*>(0x0500'0200)) #define MEM_SPRITE_PALETTE (*(reinterpret_cast<::Palette*>(0x0500'0200)))
using BgMapTile = ox::Array<uint16_t, 8192>; using BgMapTile = ox::Array<uint16_t, 8192>;
#define MEM_BG_TILES (*reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'0000)) #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_BG_MAP (*(reinterpret_cast<ox::Array<BgMapTile, 4>*>(0x0600'e000)))
#define MEM_SPRITE_TILES (*reinterpret_cast<ox::Array<uint16_t, 32 * ox::units::KB>*>(0x0601'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_OAM (*(reinterpret_cast<ox::Array<uint64_t, 64>*>(0x0700'0000)))
#define MEM_ROM (*reinterpret_cast<ox::Array<char, 32 * ox::units::MB>*>(0x0700'0000)) #define MEM_ROM (*(reinterpret_cast<ox::Array<char, 32 * ox::units::MB>*>(0x0700'0000)))
#define MEM_SRAM (*reinterpret_cast<ox::Array<char, 64 * ox::units::KB>*>(0x0e00'0000)) #define MEM_SRAM (*(reinterpret_cast<ox::Array<char, 64 * ox::units::KB>*>(0x0e00'0000)))

View File

@@ -43,6 +43,4 @@ void applySpriteUpdates() noexcept;
void setBgOffset(uint16_t bg, int16_t x, int16_t y) 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

@@ -18,7 +18,7 @@ GbaSpriteAttrUpdate &spriteAttr(size_t const i) noexcept {
void addSpriteUpdate(GbaSpriteAttrUpdate const &upd) noexcept { void addSpriteUpdate(GbaSpriteAttrUpdate const &upd) noexcept {
const auto ie = REG_IE; // disable vblank interrupt handler const auto ie = REG_IE; // disable vblank interrupt handler
REG_IE = REG_IE & static_cast<uint16_t>(~teagba::Int_vblank); // disable vblank interrupt handler REG_IE = REG_IE & static_cast<uint16_t>(~Int_vblank); // disable vblank interrupt handler
g_spriteBuffer[upd.idx] = upd; g_spriteBuffer[upd.idx] = upd;
REG_IE = ie; // enable vblank interrupt handler REG_IE = ie; // enable vblank interrupt handler
} }
@@ -35,10 +35,4 @@ void setBgOffset(uint16_t const bg, int16_t const x, int16_t const y) noexcept {
o.y = y; 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

@@ -27,9 +27,9 @@ All components have a platform indicator next to them:
* opengl - OpenGL implementation (P-) * opengl - OpenGL implementation (P-)
* studio - studio plugin for core (P-) * studio - studio plugin for core (P-)
* keel - keel plugin for core (PG) * keel - keel plugin for core (PG)
* scene - defines & processes map data (PG) * sound - sound system for Nostalgia (PG)
* studio - studio plugin for scene (P-) * studio - studio plugin for sound (P-)
* keel - keel plugin for scene (PG) * keel - keel plugin for sound (PG)
* player - plays the games (PG) * player - plays the games (PG)
* studio - makes the games (P-) * studio - makes the games (P-)
* tools - command line tools (P-) * tools - command line tools (P-)
@@ -48,7 +48,7 @@ All components have a platform indicator next to them:
Not really that external... (PG) Not really that external... (PG)
* GlUtils - OpenGL helpers (P-) * GlUtils - OpenGL helpers (P-)
* teagba - GBA assembly startup code (mostly pulled from devkitPro under MPL * teagba - GBA assembly startup code (mostly pulled from devkitPro under MPL
2.0), and custom GBA hardware interop code (-G) 2.0), and custom GBA hardware interop code (-G)
Most GBA code is built on PC because it is small and helps to work on both Most GBA code is built on PC because it is small and helps to work on both
projects with the same CMake build dir, but GBA code is never linked with any projects with the same CMake build dir, but GBA code is never linked with any
@@ -89,7 +89,8 @@ The GBA has two major resources for learning about its hardware:
On the surface, it seems like C++ changes the way we do things from C for no On the surface, it seems like C++ changes the way we do things from C for no
reason, but there are reasons for many of these duplications of functionality. reason, but there are reasons for many of these duplications of functionality.
The C++ language designers aren't stupid. Question them, but don't ignore them. The C++ language designers aren't stupid.
Question them, but don't ignore them.
#### Casting #### Casting
@@ -163,10 +164,11 @@ The Ox way of doing things is the Olympic way of doing things.
### Error Handling ### Error Handling
Instead of throwing exceptions, generally try to use Instead of throwing exceptions, generally try to use
[ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting, [ox::Error](deps/ox/ox-docs.md#error-handling) for error reporting.
but exceptions may be used where they make sense. Exceptions may be used where errors-as-values will not work, but catch them and
convert them to ```ox::Error``` as soon as possible.
Exceptions should generally just use ```OxException```, which is bascially an Exceptions should generally just use ```ox::Exception```, which is basically an
exception form of ```ox::Error```. exception form of ```ox::Error```.
### File I/O ### File I/O

View File

@@ -23,17 +23,15 @@ struct BgCbbData {
unsigned bpp = 4; unsigned bpp = 4;
}; };
class Context { class Context final {
public: public:
turbine::Context &turbineCtx; turbine::Context &turbineCtx;
ox::Array<BgCbbData, 4> cbbData; ox::Array<BgCbbData, 4> cbbData;
ox::Array<OffsetPair, 4> bgOffsets;
explicit Context(turbine::Context &tctx) noexcept: turbineCtx{tctx} {} explicit Context(turbine::Context &tctx) noexcept: turbineCtx{tctx} {}
Context(Context &other) noexcept = delete;
Context(Context const &other) noexcept = delete; Context(Context const &other) noexcept = delete;
Context(Context const &&other) noexcept = delete;
virtual ~Context() noexcept = default;
}; };
@@ -295,12 +293,16 @@ void setBgPriority(Context&, uint_t const bgIdx, uint_t const priority) noexcept
bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11); bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11);
} }
void setBgOffset(Context&, uint16_t const bg, int16_t const x, int16_t const y) noexcept { void setBgOffset(Context &ctx, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
ctx.bgOffsets[bg] = {.x = x, .y = y};
teagba::setBgOffset(bg, x, y); teagba::setBgOffset(bg, x, y);
} }
void scrollBgOffset(Context&, uint16_t const bg, int16_t const x, int16_t const y) noexcept { void scrollBgOffset(Context &ctx, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
teagba::scrollBgOffset(bg, x, y); auto &o = ctx.bgOffsets[bg];
o.x += x;
o.y += y;
teagba::setBgOffset(bg, o.x, o.y);
} }
void hideSprite(Context&, unsigned const idx) noexcept { void hideSprite(Context&, unsigned const idx) noexcept {

View File

@@ -87,9 +87,7 @@ class Context {
blocksPerSprite{params.glBlocksPerSprite} { blocksPerSprite{params.glBlocksPerSprite} {
} }
Context(Context const&) = delete; Context(Context const&) = delete;
Context(Context&&) = delete;
Context &operator=(Context const&) = delete; Context &operator=(Context const&) = delete;
Context &operator=(Context&&) = delete;
~Context() noexcept { ~Context() noexcept {
turbine::gl::removeDrawer(turbineCtx, &drawer); turbine::gl::removeDrawer(turbineCtx, &drawer);
} }
@@ -113,7 +111,7 @@ namespace renderer {
static constexpr auto Scale = 1; static constexpr auto Scale = 1;
static constexpr auto PriorityScale = 0.01f; static constexpr auto PriorityScale = 0.01f;
static constexpr ox::CStringView bgvshadTmpl = R"glsl( static constexpr ox::StringLiteral bgvshadTmpl{R"glsl(
{} {}
in vec2 vTexCoord; in vec2 vTexCoord;
in vec3 vPosition; in vec3 vPosition;
@@ -135,9 +133,9 @@ static constexpr ox::CStringView bgvshadTmpl = R"glsl(
vTexCoord.x, vTexCoord.x,
vTexCoord.y * vTileHeight + vTileIdx * vTileHeight); vTexCoord.y * vTileHeight + vTileIdx * vTileHeight);
fPalOffset = vPalOffset; fPalOffset = vPalOffset;
})glsl"; })glsl"};
static constexpr ox::CStringView bgfshadTmpl = R"glsl( static constexpr ox::StringLiteral bgfshadTmpl{R"glsl(
{} {}
out vec4 outColor; out vec4 outColor;
in float fPalOffset; in float fPalOffset;
@@ -151,9 +149,9 @@ static constexpr ox::CStringView bgfshadTmpl = R"glsl(
if (outColor.a == 0) { if (outColor.a == 0) {
discard; discard;
} }
})glsl"; })glsl"};
static constexpr ox::CStringView spritevshadTmpl = R"glsl( static constexpr ox::StringLiteral spritevshadTmpl{R"glsl(
{} {}
in float vEnabled; in float vEnabled;
in vec3 vPosition; in vec3 vPosition;
@@ -170,9 +168,9 @@ static constexpr ox::CStringView spritevshadTmpl = R"glsl(
vPosition.z - 0.004, vPosition.z - 0.004,
1.0) * vEnabled; 1.0) * vEnabled;
fTexCoord = vTexCoord * vec2(1, vTileHeight); fTexCoord = vTexCoord * vec2(1, vTileHeight);
})glsl"; })glsl"};
static constexpr ox::CStringView spritefshadTmpl = R"glsl( static constexpr ox::StringLiteral spritefshadTmpl{R"glsl(
{} {}
out vec4 outColor; out vec4 outColor;
in vec2 fTexCoord; in vec2 fTexCoord;
@@ -185,7 +183,7 @@ static constexpr ox::CStringView spritefshadTmpl = R"glsl(
if (outColor.a == 0) { if (outColor.a == 0) {
discard; discard;
} }
})glsl"; })glsl"};
[[nodiscard]] [[nodiscard]]
static constexpr auto bgVertexRow(uint_t const x, uint_t const y) noexcept { static constexpr auto bgVertexRow(uint_t const x, uint_t const y) noexcept {
@@ -841,6 +839,12 @@ void setBgPriority(Context &ctx, uint_t const bgIdx, uint_t const priority) noex
bg.priority = static_cast<float>(priority & 0b11); bg.priority = static_cast<float>(priority & 0b11);
} }
void setBgOffset(Context&, uint16_t const, int16_t const, int16_t const) noexcept {
}
void scrollBgOffset(Context&, uint16_t const, int16_t const, int16_t const) noexcept {
}
void hideSprite(Context &ctx, uint_t const idx) noexcept { void hideSprite(Context &ctx, uint_t const idx) noexcept {
auto &s = ctx.spriteStates[idx]; auto &s = ctx.spriteStates[idx];
s.enabled = false; s.enabled = false;

View File

@@ -5,6 +5,13 @@
#pragma once #pragma once
#include <ox/std/error.hpp> #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 { namespace nostalgia::gfx {

View File

@@ -3,7 +3,6 @@
*/ */
#include <imgui.h> #include <imgui.h>
#include <lodepng.h>
#include <ox/std/point.hpp> #include <ox/std/point.hpp>
#include <keel/media.hpp> #include <keel/media.hpp>

View File

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

View File

@@ -69,7 +69,7 @@ void TileSheetGrid::update(ox::Vec2 const &paneSize, TileSheet::SubSheet const &
glBindVertexArray(m_bufferSet.vao); glBindVertexArray(m_bufferSet.vao);
setBufferObjects(paneSize, subsheet); setBufferObjects(paneSize, subsheet);
glutils::sendVbo(m_bufferSet); glutils::sendVbo(m_bufferSet);
glutils::sendEbo(m_bufferSet); //glutils::sendEbo(m_bufferSet);
} }
void TileSheetGrid::setBufferObject( void TileSheetGrid::setBufferObject(
@@ -89,7 +89,6 @@ void TileSheetGrid::setBufferObject(
void TileSheetGrid::setBufferObjects(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept { void TileSheetGrid::setBufferObjects(ox::Vec2 const &paneSize, TileSheet::SubSheet const &subsheet) noexcept {
if (subsheet.columns < 1 || subsheet.rows < 1) { if (subsheet.columns < 1 || subsheet.rows < 1) {
m_bufferSet.elements.clear();
m_bufferSet.vertices.clear(); m_bufferSet.vertices.clear();
return; return;
} }

View File

@@ -15,7 +15,7 @@ target_link_libraries(
target_compile_definitions( target_compile_definitions(
NostalgiaStudio PUBLIC NostalgiaStudio PUBLIC
OLYMPIC_APP_VERSION="d2025.07.0" OLYMPIC_APP_VERSION="dev build"
) )
install( install(

View File

@@ -18,7 +18,7 @@
<string>APPL</string> <string>APPL</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>d2025.07.0</string> <string>dev build</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>12.0.0</string> <string>12.0.0</string>

View File

@@ -13,11 +13,11 @@ namespace keel {
constexpr auto K1HdrSz = 40; 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::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(write(writer, "K1;"));
OX_RETURN_ERROR(uuid.toString(writer)); OX_RETURN_ERROR(uuid.toString(writer));
return writer.put(';'); return writer.put(';');
@@ -35,15 +35,15 @@ ox::Result<T> readAsset(ox::BufferView buff) noexcept {
return out; 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 { struct AssetHdr {
ox::UUID uuid; ox::UUID uuid;
ox::ClawHeader clawHdr; 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

@@ -351,23 +351,23 @@ class AssetManager {
template<typename T> template<typename T>
class AssetRef { class AssetRef {
private: private:
T const* m_obj = nullptr; T const *m_obj = nullptr;
public: public:
constexpr AssetRef() noexcept = default; 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; return m_obj;
} }
constexpr T const&operator*() const & noexcept { constexpr T const &operator*() const & noexcept {
return *m_obj; return *m_obj;
} }
constexpr T const*operator->() const noexcept { constexpr T const *operator->() const noexcept {
return m_obj; return m_obj;
} }

View File

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

View File

@@ -29,22 +29,22 @@ OX_MODEL_BEGIN(PreloadPtr)
OX_MODEL_FIELD(preloadAddr) OX_MODEL_FIELD(preloadAddr)
OX_MODEL_END() 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; 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 // map of UUIDs to paths
using DuplicateSet = ox::HashMap<ox::UUID, ox::Vector<ox::String>>; 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> 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::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; 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::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]] [[nodiscard]]
constexpr bool isUuidUrl(ox::StringViewCR path) noexcept { constexpr bool isUuidUrl(ox::StringViewCR path) noexcept {
@@ -147,7 +147,7 @@ template<typename T>
ox::Result<AssetRef<T>> readObj( ox::Result<AssetRef<T>> readObj(
Context &ctx, Context &ctx,
ox::StringViewCR assetId, ox::StringViewCR assetId,
[[maybe_unused]] bool forceLoad = false) noexcept { [[maybe_unused]] bool const forceLoad = false) noexcept {
#ifndef OX_BARE_METAL #ifndef OX_BARE_METAL
return readObjFile<T>(ctx, assetId, forceLoad); return readObjFile<T>(ctx, assetId, forceLoad);
#else #else
@@ -158,8 +158,8 @@ ox::Result<AssetRef<T>> readObj(
template<typename T> template<typename T>
ox::Result<AssetRef<T>> readObj( ox::Result<AssetRef<T>> readObj(
Context &ctx, Context &ctx,
ox::FileAddress const&file, ox::FileAddress const &file,
[[maybe_unused]] bool forceLoad = false) noexcept { [[maybe_unused]] bool const forceLoad = false) noexcept {
#ifndef OX_BARE_METAL #ifndef OX_BARE_METAL
OX_REQUIRE(assetId, file.getPath()); OX_REQUIRE(assetId, file.getPath());
return readObj<T>(ctx, ox::StringView(assetId), forceLoad); return readObj<T>(ctx, ox::StringView(assetId), forceLoad);
@@ -176,9 +176,9 @@ ox::Result<AssetRef<T>> readObj(
template<typename T> template<typename T>
ox::Error writeObj( ox::Error writeObj(
Context &ctx, Context &ctx,
ox::FileAddress const&file, ox::FileAddress const &file,
T const&obj, T const &obj,
ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept { ox::ClawFormat const fmt = ox::ClawFormat::Metal) noexcept {
OX_REQUIRE(objBuff, ox::writeClaw(obj, fmt)); OX_REQUIRE(objBuff, ox::writeClaw(obj, fmt));
return ctx.rom->write(file, objBuff.data(), objBuff.size()); return ctx.rom->write(file, objBuff.data(), objBuff.size());
} }

View File

@@ -40,6 +40,6 @@ class Module {
void registerModule(Module const*mod) noexcept; void registerModule(Module const*mod) noexcept;
[[nodiscard]] [[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); OX_RETURN_ERROR(err);
keel::PreloadPtr const p{.preloadAddr = a}; keel::PreloadPtr const p{.preloadAddr = a};
OX_RETURN_ERROR(ox::writeMC(p).moveTo(buff)); 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", oxOutf("preloaded {} as a {} @ {} to {} / {}, total size: {}\n",
path, obj.type()->typeName, a, a + size, pbufSz - 1, pbufSz - a); path, obj.type()->typeName, a, a + size, pbufSz - 1, pbufSz - a);
} else { } else {
@@ -148,7 +148,7 @@ ox::Error preloadDir(
// copy // copy
oxTracef("pack.preload", "path: {}", path); oxTracef("pack.preload", "path: {}", path);
OX_REQUIRE(fileList, romFs.ls(path)); OX_REQUIRE(fileList, romFs.ls(path));
for (auto const&name : fileList) { for (auto const &name : fileList) {
auto const filePath = ox::sfmt("{}{}", path, name); auto const filePath = ox::sfmt("{}{}", path, name);
OX_REQUIRE(stat, romFs.stat(filePath)); OX_REQUIRE(stat, romFs.stat(filePath));
if (stat.fileType == ox::FileType::Directory) { if (stat.fileType == ox::FileType::Directory) {
@@ -169,7 +169,7 @@ ox::Error preloadDir(
} }
template<typename PlatSpec> 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 { constexpr auto padbin = [](ox::BufferWriter &w, unsigned factor) noexcept -> ox::Error {
return w.write(nullptr, factor - w.buff().size() % factor); 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(padbin(w, hdrSize));
OX_RETURN_ERROR(w.write(preloadHdr.data(), preloadHdr.bytes())); OX_RETURN_ERROR(w.write(preloadHdr.data(), preloadHdr.bytes()));
OX_RETURN_ERROR(pl.offsetPtrs(binBuff.size())); 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())); OX_RETURN_ERROR(w.write(plBuff.data(), plBuff.size()));
return {}; 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>> convertPtrToPtr(keel::Context &ctx, Wrap &src) const noexcept = 0;
virtual ox::Result<ox::UPtr<Wrap>> convertBuffToPtr( 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]] [[nodiscard]]
constexpr bool matches( constexpr bool matches(
@@ -187,7 +187,7 @@ class ConverterFunc final: public BaseConverter {
} }
ox::Result<ox::UPtr<Wrap>> convertBuffToPtr( 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_REQUIRE_M(src, readAsset<SrcType>(srcBuff));
ox::Result<ox::UPtr<Wrap>> dst{makeWrap<DstType>()}; ox::Result<ox::UPtr<Wrap>> dst{makeWrap<DstType>()};
OX_RETURN_ERROR(convert(ctx, src, wrapCast<DstType>(*dst.value))); OX_RETURN_ERROR(convert(ctx, src, wrapCast<DstType>(*dst.value)));
@@ -214,13 +214,13 @@ class Converter {
} }
[[nodiscard]] [[nodiscard]]
BaseConverter const &converter() const noexcept { BaseConverter const &converter() const noexcept {
return *m_buff.data(); return *std::launder(m_buff.data());
} }
}; };
ox::Result<ox::UPtr<Wrap>> convert( ox::Result<ox::UPtr<Wrap>> convert(
Context &ctx, Context &ctx,
ox::BufferView const&srcBuffer, ox::BufferView const &srcBuffer,
ox::StringViewCR dstTypeName, ox::StringViewCR dstTypeName,
int dstTypeVersion) noexcept; int dstTypeVersion) noexcept;
@@ -241,7 +241,7 @@ ox::Result<ox::UPtr<Wrap>> convert(
ox::Result<ox::UPtr<Wrap>> convert( ox::Result<ox::UPtr<Wrap>> convert(
Context &ctx, Context &ctx,
auto const&src, auto const &src,
ox::StringViewCR dstTypeName, ox::StringViewCR dstTypeName,
int const dstTypeVersion) noexcept { int const dstTypeVersion) noexcept {
auto srcCpy = src; auto srcCpy = src;
@@ -258,13 +258,13 @@ ox::Result<DstType> convertObjToObj(
} }
template<typename DstType> 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>)); OX_REQUIRE(out, convert(ctx, src, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
return std::move(wrapCast<DstType>(*out)); return std::move(wrapCast<DstType>(*out));
} }
template<typename DstType> 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>)); OX_REQUIRE(out, convert(ctx, buff, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
outObj = std::move(wrapCast<DstType>(*out)); outObj = std::move(wrapCast<DstType>(*out));
return {}; return {};
@@ -279,7 +279,7 @@ ox::Error convertObjToObj(Context &ctx, auto &src, DstType &outObj) noexcept {
template<typename DstType> template<typename DstType>
ox::Result<ox::Buffer> convertBuffToBuff( 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>)); OX_REQUIRE(out, convert(ctx, src, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
return ox::writeClaw<DstType>(wrapCast<DstType>(*out), fmt); return ox::writeClaw<DstType>(wrapCast<DstType>(*out), fmt);
} }

View File

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

View File

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

View File

@@ -16,7 +16,7 @@ static ox::Error init(
setRomFs(ctx, std::move(fs), *duplicateSet) : setRomFs(ctx, std::move(fs), *duplicateSet) :
setRomFs(ctx, std::move(fs)); setRomFs(ctx, std::move(fs));
#ifndef OX_BARE_METAL #ifndef OX_BARE_METAL
auto const&mods = modules(); auto const &mods = modules();
for (auto &mod : mods) { for (auto &mod : mods) {
// register type converters // register type converters
for (auto const c : mod->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)]; auto buff = new char[static_cast<std::size_t>(size)];
file.read(buff, size); file.read(buff, size);
return buff; 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()); oxErrorf("Could not read ROM file due to file IO failure: {}", e.what());
return ox::Error(2, "Could not read ROM file"); 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()); oxErrorf("Could not read ROM file due to new failure: {}", e.what());
return ox::Error(2, "Could not allocate memory for ROM file"); return ox::Error(2, "Could not allocate memory for ROM file");
} }
@@ -42,14 +42,14 @@ static void clearUuidMap(Context &ctx) noexcept {
ctx.pathToUuid.clear(); 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.pathToUuid[filePath] = uuid;
ctx.uuidToPath[uuid.toString()] = filePath; ctx.uuidToPath[uuid.toString()] = filePath;
} }
static ox::Error buildUuidMap(Context &ctx, ox::StringViewCR path, DuplicateSet *duplicates) noexcept { static ox::Error buildUuidMap(Context &ctx, ox::StringViewCR path, DuplicateSet *duplicates) noexcept {
OX_REQUIRE(files, ctx.rom->ls(path)); 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_M(filePath, ox::join("/", ox::Array<ox::StringView, 2>{path, f}));
OX_REQUIRE(stat, ctx.rom->stat(filePath)); OX_REQUIRE(stat, ctx.rom->stat(filePath));
if (stat.fileType == ox::FileType::NormalFile) { if (stat.fileType == ox::FileType::NormalFile) {
@@ -97,7 +97,7 @@ ox::Result<ox::UUID> pathToUuid(Context &ctx, ox::StringViewCR path) noexcept {
#endif #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()); OX_REQUIRE(path, fileAddr.getPath());
return getUuid(ctx, path); 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()); OX_REQUIRE(path, fileAddr.getPath());
if (beginsWith(path, "uuid://")) { if (beginsWith(path, "uuid://")) {
auto const uuid = substr(path, 7); auto const uuid = substr(path, 7);
@@ -173,7 +173,7 @@ ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::StringViewCR uuid) noex
#endif #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 #ifndef OX_BARE_METAL
OX_REQUIRE_M(out, ctx.uuidToPath.at(uuid.toString())); OX_REQUIRE_M(out, ctx.uuidToPath.at(uuid.toString()));
return ox::CStringView(*out); 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; 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(stat, ctx.rom->stat(addr));
OX_REQUIRE(buff, static_cast<ox::MemFS&>(*ctx.rom).directAccess(addr)); OX_REQUIRE(buff, static_cast<ox::MemFS&>(*ctx.rom).directAccess(addr));
PreloadPtr p; PreloadPtr p;

View File

@@ -8,14 +8,14 @@ namespace keel {
static ox::Vector<Module const*> mods; static ox::Vector<Module const*> mods;
void registerModule(Module const*mod) noexcept { void registerModule(Module const *mod) noexcept {
if (mod) { if (mod) {
mods.emplace_back(mod); mods.emplace_back(mod);
} }
} }
[[nodiscard]] [[nodiscard]]
ox::Vector<Module const*> const&modules() noexcept { ox::Vector<Module const*> const &modules() noexcept {
return mods; 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.seekg(0, std::ios::beg);
file.read(buff.data(), static_cast<std::streamsize>(buff.size())); file.read(buff.data(), static_cast<std::streamsize>(buff.size()));
return buff; return buff;
} catch (std::ios_base::failure const&e) { } catch (std::ios_base::failure const &e) {
oxErrorf("Could not read OxFS file: {}", e.what()); oxErrorf("Could not read OxFS file: {}", e.what());
return ox::Error(2, "Could not read OxFS file"); return ox::Error(2, "Could not read OxFS file");
} }

View File

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

View File

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

View File

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

View File

@@ -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; int retval = -1;
if (argc > 0) { if (argc > 0) {
auto const args = ox::Span{argv, static_cast<size_t>(argc)}; auto const args = ox::Span{argv, static_cast<size_t>(argc)};

View File

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

View File

@@ -8,13 +8,18 @@ namespace studio {
void navigateTo(Context &ctx, ox::StringParam filePath, ox::StringParam navArgs) noexcept { void navigateTo(Context &ctx, ox::StringParam filePath, ox::StringParam navArgs) noexcept {
ox::String path = std::move(filePath); ox::String path = std::move(filePath);
if (beginsWith(path, "uuid://")) { if (keel::isUuidUrl(path)) {
auto const [p, err] = keel::uuidUrlToPath(keelCtx(ctx), path); auto const [p, err] = keel::uuidUrlToPath(keelCtx(ctx), path);
if (err) { if (err) {
return; return;
} }
path = p; path = p;
} }
//if (
// auto const [np, err] = ctx.navStack.back();
// !err && np->filePath == path && np->navArgs == navArgs.view()) {
// return;
//}
ctx.navStack.resize(ctx.navIdx + 1); ctx.navStack.resize(ctx.navIdx + 1);
ctx.navStack.emplace_back(ox::String{path}, ox::String{navArgs.view()}); ctx.navStack.emplace_back(ox::String{path}, ox::String{navArgs.view()});
try { try {
@@ -49,8 +54,9 @@ void navigateBack(Context &ctx) noexcept {
} }
void navigateForward(Context &ctx) noexcept { void navigateForward(Context &ctx) noexcept {
while (ctx.navIdx < ctx.navStack.size()) { auto const nextIdx = ctx.navIdx + 1;
auto const &n = ctx.navStack[ctx.navIdx]; while (nextIdx < ctx.navStack.size()) {
auto const &n = ctx.navStack[nextIdx];
try { try {
ctx.navCallback(n.filePath, n.navArgs); ctx.navCallback(n.filePath, n.navArgs);
} catch (std::exception const &e) { } catch (std::exception const &e) {
@@ -58,7 +64,7 @@ void navigateForward(Context &ctx) noexcept {
oxErrf("navigateForward failed: {}", e.what()); oxErrf("navigateForward failed: {}", e.what());
} }
if (!ctx.project->exists(n.filePath)) { if (!ctx.project->exists(n.filePath)) {
std::ignore = ctx.navStack.erase(ctx.navIdx); std::ignore = ctx.navStack.erase(nextIdx);
continue; continue;
} }
++ctx.navIdx; ++ctx.navIdx;

View File

@@ -285,11 +285,11 @@ static void handleKeyPress(Context &ctx, int const key, bool const down) noexcep
map[GLFW_KEY_ESCAPE] = Key::Escape; map[GLFW_KEY_ESCAPE] = Key::Escape;
return map; return map;
}(); }();
auto const eventHandler = keyEventHandler(ctx);
auto const keyIdx = static_cast<std::size_t>(key); auto const keyIdx = static_cast<std::size_t>(key);
if (keyIdx < keyMap.size()) { if (keyIdx < keyMap.size()) {
auto const k = keyMap[keyIdx]; auto const k = keyMap[keyIdx];
setKeyDownStatus(ctx, k, down); setKeyDownStatus(ctx, k, down);
auto const eventHandler = keyEventHandler(ctx);
if (eventHandler) { if (eventHandler) {
eventHandler(ctx, k, down); eventHandler(ctx, k, down);
} }
@@ -306,7 +306,9 @@ static void handleGlfwMouseButtonEvent(
int) noexcept { int) noexcept {
auto &ctx = *static_cast<Context*>(glfwGetWindowUserPointer(window)); auto &ctx = *static_cast<Context*>(glfwGetWindowUserPointer(window));
setMandatoryRefreshPeriod(ctx, ticksMs(ctx) + config::MandatoryRefreshPeriod); setMandatoryRefreshPeriod(ctx, ticksMs(ctx) + config::MandatoryRefreshPeriod);
ctx.mouseButtonEventHandler(ctx, btn, action == 1); if (ctx.mouseButtonEventHandler) {
ctx.mouseButtonEventHandler(ctx, btn, action == 1);
}
} }
static void handleGlfwKeyEvent(GLFWwindow *window, int const key, int, int const action, int) noexcept { static void handleGlfwKeyEvent(GLFWwindow *window, int const key, int, int const action, int) noexcept {