Compare commits
	
		
			59 Commits
		
	
	
		
			release-d2
			...
			92e9d9cbfc
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 92e9d9cbfc | |||
| b29b9a9b3a | |||
| 721f844214 | |||
| a3d6a58cc8 | |||
| e598e7fe27 | |||
| ba9e720f9f | |||
| 8e816a261f | |||
| 5b9929ab3d | |||
| ceb54b3f1b | |||
| 8764444758 | |||
| ce9a0b1fdb | |||
| f7a468ea1e | |||
| 861d177a27 | |||
| 3936756b36 | |||
| 3e78ec3fe5 | |||
| 3c3d53b40c | |||
| 151d7c5736 | |||
| 4e4d8d2c3f | |||
| 03d1fd2857 | |||
| 6701decc91 | |||
| 6cff526647 | |||
| dd50bd0249 | |||
| 55a1660242 | |||
| ed365dfef5 | |||
| 23a09e4a13 | |||
| b69e7ebb98 | |||
| 418d6e3f22 | |||
| c44d8678cb | |||
| eb4cd7106d | |||
| d259770f32 | |||
| 80bad608f7 | |||
| 2bce9a2baf | |||
| 791b7746f3 | |||
| 842e3587fd | |||
| 318e79004b | |||
| 9f338a7429 | |||
| 645e48af7b | |||
| ef92c8df13 | |||
| 849d50be8e | |||
| 845092f114 | |||
| 75819a1797 | |||
| d66da85753 | |||
| 98ddb08abd | |||
| 8d1701b0bb | |||
| 1048e522fd | |||
| ee59da4aa3 | |||
| 1ba64cb5d8 | |||
| 462bebf6dd | |||
| e3f84c4e75 | |||
| 6837a0556d | |||
| ede2c8ca37 | |||
| f50367f7d5 | |||
| e758e03d2b | |||
| 835e3270ce | |||
| 480dd5ece4 | |||
| dba6bb5800 | |||
| 40a456e54a | |||
| bf5be00c12 | |||
| dc7c2559d6 | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -6,7 +6,7 @@
 | 
				
			|||||||
.mypy_cache
 | 
					.mypy_cache
 | 
				
			||||||
.stfolder
 | 
					.stfolder
 | 
				
			||||||
.stignore
 | 
					.stignore
 | 
				
			||||||
scripts/__pycache__
 | 
					util/scripts/__pycache__
 | 
				
			||||||
pyenv
 | 
					pyenv
 | 
				
			||||||
CMakeLists.txt.user
 | 
					CMakeLists.txt.user
 | 
				
			||||||
ROM.oxfs
 | 
					ROM.oxfs
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
									
									
									
									
								
							@@ -1,5 +1,6 @@
 | 
				
			|||||||
BC_VAR_PROJECT_NAME=nostalgia
 | 
					BC_VAR_PROJECT_NAME=nostalgia
 | 
				
			||||||
BC_VAR_PROJECT_NAME_CAP=Nostalgia
 | 
					BC_VAR_PROJECT_NAME_CAP=Nostalgia
 | 
				
			||||||
 | 
					BC_VAR_DEVENV_ROOT=util
 | 
				
			||||||
BUILDCORE_PATH=deps/buildcore
 | 
					BUILDCORE_PATH=deps/buildcore
 | 
				
			||||||
include ${BUILDCORE_PATH}/base.mk
 | 
					include ${BUILDCORE_PATH}/base.mk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -13,7 +14,7 @@ endif
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
.PHONY: pkg-gba
 | 
					.PHONY: pkg-gba
 | 
				
			||||||
pkg-gba: build
 | 
					pkg-gba: build
 | 
				
			||||||
	${BC_CMD_ENVRUN} ${BC_PY3} ./scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME}
 | 
						${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.PHONY: run
 | 
					.PHONY: run
 | 
				
			||||||
run: build
 | 
					run: build
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								deps/gbabuildcore/base.cmake
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								deps/gbabuildcore/base.cmake
									
									
									
									
										vendored
									
									
								
							@@ -1,8 +1,8 @@
 | 
				
			|||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules)
 | 
					list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules)
 | 
				
			||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib")
 | 
					set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib")
 | 
				
			||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++")
 | 
					set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++")
 | 
				
			||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unwind-tables")
 | 
					#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unwind-tables")
 | 
				
			||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
 | 
					#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
 | 
				
			||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
 | 
					set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
 | 
				
			||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
 | 
					set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
 | 
				
			||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb-interwork")
 | 
					set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb-interwork")
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								deps/glad/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								deps/glad/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +1,11 @@
 | 
				
			|||||||
add_library(glad OBJECT src/glad.c)
 | 
					add_library(glad src/glad.c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_include_directories(glad PUBLIC include)
 | 
					target_include_directories(glad PUBLIC include)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					install(
 | 
				
			||||||
 | 
						TARGETS
 | 
				
			||||||
 | 
							glad
 | 
				
			||||||
 | 
						DESTINATION
 | 
				
			||||||
 | 
							LIBRARY DESTINATION lib
 | 
				
			||||||
 | 
							ARCHIVE DESTINATION lib
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								deps/imgui/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								deps/imgui/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							@@ -6,7 +6,7 @@ endif()
 | 
				
			|||||||
# DrinkingTea: end
 | 
					# DrinkingTea: end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_library(
 | 
					add_library(
 | 
				
			||||||
	imgui OBJECT
 | 
						imgui
 | 
				
			||||||
		imgui.cpp
 | 
							imgui.cpp
 | 
				
			||||||
		imgui_demo.cpp
 | 
							imgui_demo.cpp
 | 
				
			||||||
		imgui_draw.cpp
 | 
							imgui_draw.cpp
 | 
				
			||||||
@@ -20,3 +20,11 @@ target_include_directories(
 | 
				
			|||||||
	imgui SYSTEM PUBLIC
 | 
						imgui SYSTEM PUBLIC
 | 
				
			||||||
		.
 | 
							.
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					install(
 | 
				
			||||||
 | 
						TARGETS
 | 
				
			||||||
 | 
							imgui
 | 
				
			||||||
 | 
						DESTINATION
 | 
				
			||||||
 | 
							LIBRARY DESTINATION lib
 | 
				
			||||||
 | 
							ARCHIVE DESTINATION lib
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								deps/ox/src/ox/event/signal.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								deps/ox/src/ox/event/signal.hpp
									
									
									
									
										vendored
									
									
								
							@@ -215,7 +215,7 @@ Error Signal<Args...>::emitCheckError(Args... args) const noexcept {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		return ox::Error(0);
 | 
							return ox::Error(0);
 | 
				
			||||||
	} catch (const ox::Exception &ex) {
 | 
						} catch (const ox::Exception &ex) {
 | 
				
			||||||
		return ox::Error(ex.file, ex.line, ex.errCode, ex.msg);
 | 
							return ox::Error(ex.errCode, ex.msg, ex.src);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								deps/ox/src/ox/logconn/def.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								deps/ox/src/ox/logconn/def.hpp
									
									
									
									
										vendored
									
									
								
							@@ -14,7 +14,7 @@
 | 
				
			|||||||
    { \
 | 
					    { \
 | 
				
			||||||
		const auto loggerErr = (loggerName).initConn(appName); \
 | 
							const auto loggerErr = (loggerName).initConn(appName); \
 | 
				
			||||||
		if (loggerErr) { \
 | 
							if (loggerErr) { \
 | 
				
			||||||
			oxErrf("Could not connect to logger: {} ({}:{})\n", toStr(loggerErr), loggerErr.file, loggerErr.line); \
 | 
								oxErrf("Could not connect to logger: {} ({}:{})\n", toStr(loggerErr), loggerErr.src.file_name(), loggerErr.src.line()); \
 | 
				
			||||||
		} else { \
 | 
							} else { \
 | 
				
			||||||
			ox::trace::setLogger(&(loggerName)); \
 | 
								ox::trace::setLogger(&(loggerName)); \
 | 
				
			||||||
		} \
 | 
							} \
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								deps/ox/src/ox/model/typenamecatcher.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								deps/ox/src/ox/model/typenamecatcher.hpp
									
									
									
									
										vendored
									
									
								
							@@ -140,16 +140,16 @@ constexpr Str getModelTypeName() noexcept {
 | 
				
			|||||||
	return out;
 | 
						return out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T, typename Str = const char*>
 | 
				
			||||||
[[nodiscard]]
 | 
					[[nodiscard]]
 | 
				
			||||||
consteval auto requireModelTypeName() noexcept {
 | 
					consteval auto requireModelTypeName() noexcept {
 | 
				
			||||||
	constexpr auto name = getModelTypeName<T>();
 | 
						constexpr auto name = getModelTypeName<T, Str>();
 | 
				
			||||||
	static_assert(ox::StringView{name}.len(), "Type lacks required TypeName");
 | 
						static_assert(ox::StringView{name}.len(), "Type lacks required TypeName");
 | 
				
			||||||
	return name;
 | 
						return name;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T, typename Str = const char*>
 | 
					template<typename T, typename Str = const char*>
 | 
				
			||||||
constexpr auto ModelTypeName_v = getModelTypeName<T, Str>();
 | 
					constexpr auto ModelTypeName_v = requireModelTypeName<T, Str>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T, typename Str = const char*>
 | 
					template<typename T, typename Str = const char*>
 | 
				
			||||||
constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>();
 | 
					constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>();
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										14
									
								
								deps/ox/src/ox/std/algorithm.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								deps/ox/src/ox/std/algorithm.hpp
									
									
									
									
										vendored
									
									
								
							@@ -9,13 +9,25 @@
 | 
				
			|||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "def.hpp"
 | 
					#include "def.hpp"
 | 
				
			||||||
 | 
					#include "error.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
 | 
					OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ox {
 | 
					namespace ox {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename It, typename T>
 | 
					template<typename It, typename T>
 | 
				
			||||||
constexpr It find(It begin, It end, const T &value) {
 | 
					constexpr ox::Result<size_t> findIdx(It begin, It end, T const&value) {
 | 
				
			||||||
 | 
						auto it = begin;
 | 
				
			||||||
 | 
						for (; it != end; ++it) {
 | 
				
			||||||
 | 
							if (*it == value) {
 | 
				
			||||||
 | 
								return it.offset();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ox::Error{1, "item not found"};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename It, typename T>
 | 
				
			||||||
 | 
					constexpr It find(It begin, It end, T const&value) {
 | 
				
			||||||
	for (; begin != end; ++begin) {
 | 
						for (; begin != end; ++begin) {
 | 
				
			||||||
		if (*begin == value) {
 | 
							if (*begin == value) {
 | 
				
			||||||
			return begin;
 | 
								return begin;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										85
									
								
								deps/ox/src/ox/std/anyptr.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										85
									
								
								deps/ox/src/ox/std/anyptr.hpp
									
									
									
									
										vendored
									
									
								
							@@ -15,16 +15,20 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace ox {
 | 
					namespace ox {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AnyPtr {
 | 
					namespace detail {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<bool unique>
 | 
				
			||||||
 | 
					class AnyPtrT {
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		struct WrapBase {
 | 
							struct WrapBase {
 | 
				
			||||||
			virtual constexpr ~WrapBase() = default;
 | 
								virtual constexpr ~WrapBase() = default;
 | 
				
			||||||
			virtual constexpr WrapBase *copyTo(ox::Span<char> s) noexcept = 0;
 | 
								virtual constexpr WrapBase *copyTo(ox::Span<char> s) noexcept = 0;
 | 
				
			||||||
			virtual constexpr operator bool() const noexcept = 0;
 | 
								virtual constexpr operator bool() const noexcept = 0;
 | 
				
			||||||
 | 
								virtual void free() noexcept = 0;
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		struct Wrap: public WrapBase {
 | 
							struct Wrap final: WrapBase {
 | 
				
			||||||
			T *data{};
 | 
								T *data{};
 | 
				
			||||||
			constexpr Wrap(T *pData) noexcept: data(pData) {
 | 
								constexpr Wrap(T *pData) noexcept: data(pData) {
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -39,16 +43,20 @@ class AnyPtr {
 | 
				
			|||||||
			constexpr operator bool() const noexcept override {
 | 
								constexpr operator bool() const noexcept override {
 | 
				
			||||||
				return data != nullptr;
 | 
									return data != nullptr;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								constexpr void free() noexcept override {
 | 
				
			||||||
 | 
									ox::safeDelete(data);
 | 
				
			||||||
 | 
									data = {};
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		WrapBase *m_wrapPtr{};
 | 
							WrapBase *m_wrapPtr{};
 | 
				
			||||||
		ox::Array<char, sizeof(Wrap<void*>)> m_wrapData;
 | 
							ox::Array<char, sizeof(Wrap<void*>)> m_wrapData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		constexpr AnyPtr() noexcept = default;
 | 
							constexpr AnyPtrT() noexcept = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		constexpr AnyPtr(T *ptr) noexcept {
 | 
							constexpr AnyPtrT(T *ptr) noexcept {
 | 
				
			||||||
			if (std::is_constant_evaluated()) {
 | 
								if (std::is_constant_evaluated()) {
 | 
				
			||||||
				m_wrapPtr = new Wrap(ptr);
 | 
									m_wrapPtr = new Wrap(ptr);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
@@ -56,22 +64,39 @@ class AnyPtr {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr AnyPtr(AnyPtr const&other) noexcept {
 | 
							constexpr AnyPtrT(AnyPtrT const&other) noexcept {
 | 
				
			||||||
			if (other) {
 | 
								if (other) {
 | 
				
			||||||
				m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData);
 | 
									m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr ~AnyPtr() noexcept {
 | 
							constexpr AnyPtrT(AnyPtrT &&other) noexcept {
 | 
				
			||||||
 | 
								if (other) {
 | 
				
			||||||
 | 
									m_wrapPtr = other.m_wrapPtr->copyTo(m_wrapData);
 | 
				
			||||||
 | 
									if (std::is_constant_evaluated()) {
 | 
				
			||||||
 | 
										ox::safeDelete(m_wrapPtr);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									other.m_wrapPtr = {};
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							constexpr ~AnyPtrT() noexcept {
 | 
				
			||||||
 | 
								if constexpr(unique) {
 | 
				
			||||||
 | 
									free();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			if (std::is_constant_evaluated()) {
 | 
								if (std::is_constant_evaluated()) {
 | 
				
			||||||
				ox::safeDelete(m_wrapPtr);
 | 
									ox::safeDelete(m_wrapPtr);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		constexpr AnyPtr &operator=(T *ptr) noexcept {
 | 
							constexpr AnyPtrT &operator=(T *ptr) noexcept {
 | 
				
			||||||
			if (std::is_constant_evaluated()) {
 | 
								if constexpr(unique) {
 | 
				
			||||||
 | 
									free();
 | 
				
			||||||
 | 
								} else if (std::is_constant_evaluated()) {
 | 
				
			||||||
				ox::safeDelete(m_wrapPtr);
 | 
									ox::safeDelete(m_wrapPtr);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (std::is_constant_evaluated()) {
 | 
				
			||||||
				m_wrapPtr = new Wrap(ptr);
 | 
									m_wrapPtr = new Wrap(ptr);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				m_wrapPtr = new(m_wrapData.data()) Wrap(ptr);
 | 
									m_wrapPtr = new(m_wrapData.data()) Wrap(ptr);
 | 
				
			||||||
@@ -79,10 +104,14 @@ class AnyPtr {
 | 
				
			|||||||
			return *this;
 | 
								return *this;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr AnyPtr &operator=(AnyPtr const&ptr) noexcept {
 | 
							constexpr AnyPtrT &operator=(AnyPtrT const&ptr) noexcept {
 | 
				
			||||||
			if (this != &ptr) {
 | 
								if (this != &ptr) {
 | 
				
			||||||
				if (ptr) {
 | 
									if constexpr(unique) {
 | 
				
			||||||
 | 
										free();
 | 
				
			||||||
 | 
									} else if (std::is_constant_evaluated()) {
 | 
				
			||||||
					ox::safeDelete(m_wrapPtr);
 | 
										ox::safeDelete(m_wrapPtr);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (ptr) {
 | 
				
			||||||
					m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData);
 | 
										m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData);
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					m_wrapPtr = nullptr;
 | 
										m_wrapPtr = nullptr;
 | 
				
			||||||
@@ -91,10 +120,40 @@ class AnyPtr {
 | 
				
			|||||||
			return *this;
 | 
								return *this;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							constexpr AnyPtrT &operator=(AnyPtrT &&ptr) noexcept {
 | 
				
			||||||
 | 
								if (this != &ptr) {
 | 
				
			||||||
 | 
									if constexpr(unique) {
 | 
				
			||||||
 | 
										free();
 | 
				
			||||||
 | 
									} else if (std::is_constant_evaluated()) {
 | 
				
			||||||
 | 
										ox::safeDelete(m_wrapPtr);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (ptr) {
 | 
				
			||||||
 | 
										m_wrapPtr = ptr.m_wrapPtr->copyTo(m_wrapData);
 | 
				
			||||||
 | 
										if (std::is_constant_evaluated()) {
 | 
				
			||||||
 | 
											ox::safeDelete(ptr.m_wrapPtr);
 | 
				
			||||||
 | 
											ptr.m_wrapPtr = nullptr;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										m_wrapPtr = nullptr;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return *this;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr operator bool() const noexcept {
 | 
							constexpr operator bool() const noexcept {
 | 
				
			||||||
			return m_wrapPtr && *m_wrapPtr;
 | 
								return m_wrapPtr && *m_wrapPtr;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							constexpr void free() noexcept {
 | 
				
			||||||
 | 
								if (m_wrapPtr) {
 | 
				
			||||||
 | 
									m_wrapPtr->free();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (std::is_constant_evaluated()) {
 | 
				
			||||||
 | 
									ox::safeDelete(m_wrapPtr);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								m_wrapPtr = nullptr;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		[[nodiscard]]
 | 
							[[nodiscard]]
 | 
				
			||||||
		constexpr T *get() const noexcept {
 | 
							constexpr T *get() const noexcept {
 | 
				
			||||||
@@ -104,6 +163,12 @@ class AnyPtr {
 | 
				
			|||||||
			return dynamic_cast<Wrap<T>*>(m_wrapPtr)->data;
 | 
								return dynamic_cast<Wrap<T>*>(m_wrapPtr)->data;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using AnyPtr = detail::AnyPtrT<false>;
 | 
				
			||||||
 | 
					using UAnyPtr = detail::AnyPtrT<true>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										35
									
								
								deps/ox/src/ox/std/assert.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										35
									
								
								deps/ox/src/ox/std/assert.cpp
									
									
									
									
										vendored
									
									
								
							@@ -7,6 +7,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "fmt.hpp"
 | 
					#include "fmt.hpp"
 | 
				
			||||||
 | 
					#include "realstd.hpp"
 | 
				
			||||||
#include "stacktrace.hpp"
 | 
					#include "stacktrace.hpp"
 | 
				
			||||||
#include "trace.hpp"
 | 
					#include "trace.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -14,14 +15,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace ox {
 | 
					namespace ox {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err) noexcept {
 | 
					void panic(StringViewCR file, int const line, StringViewCR panicMsg, Error const&err) noexcept {
 | 
				
			||||||
	oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg);
 | 
						oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg);
 | 
				
			||||||
	if (err.msg) {
 | 
						if (err.msg) {
 | 
				
			||||||
		oxErrf("\tError Message:\t{}\n", err.msg);
 | 
							oxErrf("\tError Message:\t{}\n", err.msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
 | 
						oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
 | 
				
			||||||
	if (err.file != nullptr) {
 | 
						if (err.src.file_name() != nullptr) {
 | 
				
			||||||
		oxErrf("\tError Location:\t{}:{}\n", err.file, err.line);
 | 
							oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#ifdef OX_USE_STDLIB
 | 
					#ifdef OX_USE_STDLIB
 | 
				
			||||||
	printStackTrace(2);
 | 
						printStackTrace(2);
 | 
				
			||||||
@@ -32,16 +33,19 @@ void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err)
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void panic(const char *file, int line, const char *panicMsg, const Error &err) noexcept {
 | 
					void panic(const char *file, int const line, char const*panicMsg, Error const&err) noexcept {
 | 
				
			||||||
	panic(StringView{file}, line, StringView{panicMsg}, err);
 | 
						panic(StringView{file}, line, StringView{panicMsg}, err);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept {
 | 
					void assertFailFuncRuntime(
 | 
				
			||||||
 | 
						StringViewCR file,
 | 
				
			||||||
 | 
						int const line,
 | 
				
			||||||
 | 
						StringViewCR assertTxt,
 | 
				
			||||||
 | 
						StringViewCR msg) noexcept {
 | 
				
			||||||
#ifdef OX_USE_STDLIB
 | 
					#ifdef OX_USE_STDLIB
 | 
				
			||||||
	auto output = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
 | 
						auto const st = genStackTrace(2);
 | 
				
			||||||
	output += genStackTrace(2);
 | 
						oxTracef("assert", "Failed assert: {} ({}) [{}:{}]:\n{}", msg, assertTxt, file, line, st);
 | 
				
			||||||
	oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
 | 
						abort();
 | 
				
			||||||
	std::abort();
 | 
					 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
 | 
						oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
 | 
				
			||||||
	oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
 | 
						oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
 | 
				
			||||||
@@ -49,20 +53,25 @@ void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt,
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void assertFailFuncRuntime(StringViewCR file, int line, [[maybe_unused]] const Error &err, StringViewCR, StringViewCR assertMsg) noexcept {
 | 
					void assertFailFuncRuntime(
 | 
				
			||||||
 | 
						StringViewCR file,
 | 
				
			||||||
 | 
						int const line,
 | 
				
			||||||
 | 
						[[maybe_unused]] Error const&err,
 | 
				
			||||||
 | 
						StringViewCR,
 | 
				
			||||||
 | 
						StringViewCR assertMsg) noexcept {
 | 
				
			||||||
#if defined(OX_USE_STDLIB)
 | 
					#if defined(OX_USE_STDLIB)
 | 
				
			||||||
	auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg);
 | 
						auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg);
 | 
				
			||||||
	if (err.msg) {
 | 
						if (err.msg) {
 | 
				
			||||||
		msg += sfmt("\tError Message:\t{}\n", err.msg);
 | 
							msg += sfmt("\tError Message:\t{}\n", err.msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	msg += sfmt("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
 | 
						msg += sfmt("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
 | 
				
			||||||
	if (err.file != nullptr) {
 | 
						if (err.src.file_name() != nullptr) {
 | 
				
			||||||
		msg += sfmt("\tError Location:\t{}:{}\n", err.file, err.line);
 | 
							msg += sfmt("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	msg += genStackTrace(2);
 | 
						msg += genStackTrace(2);
 | 
				
			||||||
	oxErr(msg);
 | 
						oxErr(msg);
 | 
				
			||||||
	oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line);
 | 
						oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line);
 | 
				
			||||||
	std::abort();
 | 
						abort();
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
	constexprPanic(file, line, assertMsg);
 | 
						constexprPanic(file, line, assertMsg);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										43
									
								
								deps/ox/src/ox/std/assert.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										43
									
								
								deps/ox/src/ox/std/assert.hpp
									
									
									
									
										vendored
									
									
								
							@@ -22,9 +22,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace ox {
 | 
					namespace ox {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err = ox::Error(0)) noexcept;
 | 
					[[noreturn]]
 | 
				
			||||||
 | 
					void panic(StringViewCR file, int line, StringViewCR panicMsg, Error const&err = {}) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
constexpr void constexprPanic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err = ox::Error(0)) noexcept {
 | 
					[[noreturn]]
 | 
				
			||||||
 | 
					constexpr void constexprPanic(
 | 
				
			||||||
 | 
						StringViewCR file,
 | 
				
			||||||
 | 
						int const line,
 | 
				
			||||||
 | 
						StringViewCR panicMsg,
 | 
				
			||||||
 | 
						Error const&err = {}) noexcept {
 | 
				
			||||||
	if (!std::is_constant_evaluated()) {
 | 
						if (!std::is_constant_evaluated()) {
 | 
				
			||||||
		panic(file, line, panicMsg, err);
 | 
							panic(file, line, panicMsg, err);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@@ -32,10 +38,24 @@ constexpr void constexprPanic(StringViewCR file, int line, StringViewCR panicMsg
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept;
 | 
					void assertFailFuncRuntime(
 | 
				
			||||||
void assertFailFuncRuntime(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept;
 | 
						StringViewCR file,
 | 
				
			||||||
 | 
						int line,
 | 
				
			||||||
 | 
						StringViewCR assertTxt,
 | 
				
			||||||
 | 
						StringViewCR msg) noexcept;
 | 
				
			||||||
 | 
					void assertFailFuncRuntime(
 | 
				
			||||||
 | 
						StringViewCR file,
 | 
				
			||||||
 | 
						int line,
 | 
				
			||||||
 | 
						Error const&err,
 | 
				
			||||||
 | 
						StringViewCR,
 | 
				
			||||||
 | 
						StringViewCR assertMsg) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
constexpr void assertFunc(StringViewCR file, int line, bool pass, [[maybe_unused]]StringViewCR assertTxt, [[maybe_unused]]StringViewCR msg) noexcept {
 | 
					constexpr void assertFunc(
 | 
				
			||||||
 | 
						StringViewCR file,
 | 
				
			||||||
 | 
						int const line,
 | 
				
			||||||
 | 
						bool const pass,
 | 
				
			||||||
 | 
						[[maybe_unused]]StringViewCR assertTxt,
 | 
				
			||||||
 | 
						[[maybe_unused]]StringViewCR msg) noexcept {
 | 
				
			||||||
	if (!pass) {
 | 
						if (!pass) {
 | 
				
			||||||
		if (!std::is_constant_evaluated()) {
 | 
							if (!std::is_constant_evaluated()) {
 | 
				
			||||||
			assertFailFuncRuntime(file, line, assertTxt, msg);
 | 
								assertFailFuncRuntime(file, line, assertTxt, msg);
 | 
				
			||||||
@@ -45,7 +65,12 @@ constexpr void assertFunc(StringViewCR file, int line, bool pass, [[maybe_unused
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
constexpr void assertFunc(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept {
 | 
					constexpr void assertFunc(
 | 
				
			||||||
 | 
						StringViewCR file,
 | 
				
			||||||
 | 
						int const line,
 | 
				
			||||||
 | 
						Error const&err,
 | 
				
			||||||
 | 
						StringViewCR,
 | 
				
			||||||
 | 
						StringViewCR assertMsg) noexcept {
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
		if (!std::is_constant_evaluated()) {
 | 
							if (!std::is_constant_evaluated()) {
 | 
				
			||||||
			assertFailFuncRuntime(file, line, err, {}, assertMsg);
 | 
								assertFailFuncRuntime(file, line, err, {}, assertMsg);
 | 
				
			||||||
@@ -55,7 +80,11 @@ constexpr void assertFunc(StringViewCR file, int line, const Error &err, StringV
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
constexpr void expect(StringViewCR file, int line, const auto &actual, const auto &expected) noexcept {
 | 
					constexpr void expect(
 | 
				
			||||||
 | 
						StringViewCR file,
 | 
				
			||||||
 | 
						int const line,
 | 
				
			||||||
 | 
						auto const&actual,
 | 
				
			||||||
 | 
						auto const&expected) noexcept {
 | 
				
			||||||
	if (actual != expected) {
 | 
						if (actual != expected) {
 | 
				
			||||||
		 if (!std::is_constant_evaluated()) {
 | 
							 if (!std::is_constant_evaluated()) {
 | 
				
			||||||
#if defined(OX_USE_STDLIB)
 | 
					#if defined(OX_USE_STDLIB)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								deps/ox/src/ox/std/error.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										47
									
								
								deps/ox/src/ox/std/error.hpp
									
									
									
									
										vendored
									
									
								
							@@ -36,28 +36,16 @@ using ErrorCode = uint16_t;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct [[nodiscard]] Error {
 | 
					struct [[nodiscard]] Error {
 | 
				
			||||||
 | 
						std::source_location src;
 | 
				
			||||||
	ox::CString msg = nullptr;
 | 
						ox::CString msg = nullptr;
 | 
				
			||||||
	ox::CString file = nullptr;
 | 
					 | 
				
			||||||
	uint16_t line = 0;
 | 
					 | 
				
			||||||
	ErrorCode errCode = 0;
 | 
						ErrorCode errCode = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	constexpr Error() noexcept = default;
 | 
						constexpr Error() noexcept = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	explicit constexpr Error(
 | 
					 | 
				
			||||||
		ox::CString file,
 | 
					 | 
				
			||||||
		uint32_t const line,
 | 
					 | 
				
			||||||
		ErrorCode const errCode,
 | 
					 | 
				
			||||||
		ox::CString msg = nullptr) noexcept:
 | 
					 | 
				
			||||||
		msg{msg},
 | 
					 | 
				
			||||||
		file{file},
 | 
					 | 
				
			||||||
		line{static_cast<uint16_t>(line)},
 | 
					 | 
				
			||||||
		errCode{errCode} {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	explicit constexpr Error(
 | 
						explicit constexpr Error(
 | 
				
			||||||
		ErrorCode const errCode,
 | 
							ErrorCode const errCode,
 | 
				
			||||||
		std::source_location const&src = std::source_location::current()) noexcept:
 | 
							std::source_location const&src = std::source_location::current()) noexcept:
 | 
				
			||||||
		file{src.file_name()},
 | 
							src{src},
 | 
				
			||||||
		line{static_cast<uint16_t>(src.line())},
 | 
					 | 
				
			||||||
		errCode{errCode}
 | 
							errCode{errCode}
 | 
				
			||||||
	{}
 | 
						{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -65,9 +53,8 @@ struct [[nodiscard]] Error {
 | 
				
			|||||||
		ErrorCode const errCode,
 | 
							ErrorCode const errCode,
 | 
				
			||||||
		ox::CString msg,
 | 
							ox::CString msg,
 | 
				
			||||||
		std::source_location const&src = std::source_location::current()) noexcept:
 | 
							std::source_location const&src = std::source_location::current()) noexcept:
 | 
				
			||||||
 | 
							src{src},
 | 
				
			||||||
		msg{msg},
 | 
							msg{msg},
 | 
				
			||||||
		file{src.file_name()},
 | 
					 | 
				
			||||||
		line{static_cast<uint16_t>(src.line())},
 | 
					 | 
				
			||||||
		errCode{errCode}
 | 
							errCode{errCode}
 | 
				
			||||||
	{}
 | 
						{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -89,42 +76,31 @@ constexpr auto toStr(Error const&err) noexcept {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct Exception: public std::exception {
 | 
					struct Exception: public std::exception {
 | 
				
			||||||
 | 
						std::source_location src;
 | 
				
			||||||
	ox::CString msg = nullptr;
 | 
						ox::CString msg = nullptr;
 | 
				
			||||||
	ox::CString file = nullptr;
 | 
					 | 
				
			||||||
	uint16_t line = 0;
 | 
					 | 
				
			||||||
	ErrorCode errCode = 0;
 | 
						ErrorCode errCode = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	explicit inline Exception(ox::CString file, uint32_t line, ErrorCode errCode, char const*msg = "") noexcept {
 | 
						explicit Exception(
 | 
				
			||||||
		this->file = file;
 | 
					 | 
				
			||||||
		this->line = static_cast<uint16_t>(line);
 | 
					 | 
				
			||||||
		this->msg = msg;
 | 
					 | 
				
			||||||
		this->errCode = errCode;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	explicit inline Exception(
 | 
					 | 
				
			||||||
		ErrorCode const errCode,
 | 
							ErrorCode const errCode,
 | 
				
			||||||
		std::source_location const&src = std::source_location::current()) noexcept:
 | 
							std::source_location const&src = std::source_location::current()) noexcept:
 | 
				
			||||||
		file{src.file_name()},
 | 
							src{src},
 | 
				
			||||||
		line{static_cast<uint16_t>(src.line())},
 | 
					 | 
				
			||||||
		errCode{errCode} {}
 | 
							errCode{errCode} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	explicit inline Exception(
 | 
						explicit Exception(
 | 
				
			||||||
		ErrorCode const errCode,
 | 
							ErrorCode const errCode,
 | 
				
			||||||
		ox::CString msg,
 | 
							ox::CString msg,
 | 
				
			||||||
		std::source_location const&src = std::source_location::current()) noexcept:
 | 
							std::source_location const&src = std::source_location::current()) noexcept:
 | 
				
			||||||
 | 
							src{src},
 | 
				
			||||||
		msg{msg},
 | 
							msg{msg},
 | 
				
			||||||
		file{src.file_name()},
 | 
					 | 
				
			||||||
		line{static_cast<uint16_t>(src.line())},
 | 
					 | 
				
			||||||
		errCode{errCode} {}
 | 
							errCode{errCode} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	explicit inline Exception(Error const&err) noexcept:
 | 
						explicit Exception(Error const&err) noexcept:
 | 
				
			||||||
 | 
							src{err.src},
 | 
				
			||||||
		msg{err.msg ? err.msg : ""},
 | 
							msg{err.msg ? err.msg : ""},
 | 
				
			||||||
		file{err.file},
 | 
					 | 
				
			||||||
		line{err.line},
 | 
					 | 
				
			||||||
		errCode{err.errCode} {}
 | 
							errCode{err.errCode} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	constexpr Error toError() const noexcept {
 | 
						constexpr Error toError() const noexcept {
 | 
				
			||||||
		return Error(file, line, errCode, msg);
 | 
							return Error(errCode, msg, src);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	[[nodiscard]]
 | 
						[[nodiscard]]
 | 
				
			||||||
@@ -133,6 +109,7 @@ struct Exception: public std::exception {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[noreturn]]
 | 
				
			||||||
void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept;
 | 
					void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								deps/ox/src/ox/std/reader.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								deps/ox/src/ox/std/reader.hpp
									
									
									
									
										vendored
									
									
								
							@@ -31,7 +31,6 @@ concept Reader_c = requires(T v) {
 | 
				
			|||||||
class Reader_v {
 | 
					class Reader_v {
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		virtual constexpr ~Reader_v() noexcept = default;
 | 
							virtual constexpr ~Reader_v() noexcept = default;
 | 
				
			||||||
		[[nodiscard]]
 | 
					 | 
				
			||||||
		virtual constexpr ox::Result<char> peek() const noexcept = 0;
 | 
							virtual constexpr ox::Result<char> peek() const noexcept = 0;
 | 
				
			||||||
		virtual constexpr ox::Result<std::size_t> read(char*, std::size_t) noexcept = 0;
 | 
							virtual constexpr ox::Result<std::size_t> read(char*, std::size_t) noexcept = 0;
 | 
				
			||||||
		virtual constexpr ox::Result<std::size_t> tellg() noexcept = 0;
 | 
							virtual constexpr ox::Result<std::size_t> tellg() noexcept = 0;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								deps/ox/src/ox/std/realstd.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								deps/ox/src/ox/std/realstd.hpp
									
									
									
									
										vendored
									
									
								
							@@ -13,3 +13,12 @@
 | 
				
			|||||||
#else
 | 
					#else
 | 
				
			||||||
#define	assert(e) while (!(e));
 | 
					#define	assert(e) while (!(e));
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if __has_include(<cstdlib>)
 | 
				
			||||||
 | 
					#include <cstdlib>
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					[[noreturn]]
 | 
				
			||||||
 | 
					void abort();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										59
									
								
								deps/ox/src/ox/std/smallmap.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										59
									
								
								deps/ox/src/ox/std/smallmap.hpp
									
									
									
									
										vendored
									
									
								
							@@ -62,6 +62,9 @@ class SmallMap {
 | 
				
			|||||||
		[[nodiscard]]
 | 
							[[nodiscard]]
 | 
				
			||||||
		constexpr Vector<K> keys() const noexcept;
 | 
							constexpr Vector<K> keys() const noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							constexpr Vector<T> values() const noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		[[nodiscard]]
 | 
							[[nodiscard]]
 | 
				
			||||||
		constexpr K const&key(size_t i) const noexcept;
 | 
							constexpr K const&key(size_t i) const noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -82,14 +85,22 @@ class SmallMap {
 | 
				
			|||||||
			return m_pairs;
 | 
								return m_pairs;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							constexpr ox::Span<Pair> pairs() noexcept {
 | 
				
			||||||
 | 
								return m_pairs;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr void clear();
 | 
							constexpr void clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		template<typename KK>
 | 
							template<typename KK>
 | 
				
			||||||
		constexpr Pair const&access(PairVector const&pairs, KK const&key, bool &isNew) const;
 | 
							constexpr Pair const*access(PairVector const&pairs, KK const&key, bool &isNew) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename KK>
 | 
							template<typename KK>
 | 
				
			||||||
		constexpr Pair &access(PairVector &pairs, KK const&key, bool &isNew);
 | 
							constexpr Pair *access(PairVector &pairs, KK const&key, bool &isNew);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							template<typename KK>
 | 
				
			||||||
 | 
							constexpr Pair *accessNoCreate(PairVector &pairs, KK const&key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -129,7 +140,7 @@ constexpr SmallMap<K, T, SmallSz> &SmallMap<K, T, SmallSz>::operator=(SmallMap<K
 | 
				
			|||||||
template<typename K, typename T, size_t SmallSz>
 | 
					template<typename K, typename T, size_t SmallSz>
 | 
				
			||||||
constexpr T &SmallMap<K, T, SmallSz>::operator[](MaybeView_t<K> const&k) {
 | 
					constexpr T &SmallMap<K, T, SmallSz>::operator[](MaybeView_t<K> const&k) {
 | 
				
			||||||
	bool isNew{};
 | 
						bool isNew{};
 | 
				
			||||||
	auto p = &access(m_pairs, k, isNew);
 | 
						auto p = access(m_pairs, k, isNew);
 | 
				
			||||||
	if (isNew) {
 | 
						if (isNew) {
 | 
				
			||||||
		p->key = k;
 | 
							p->key = k;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -138,7 +149,7 @@ constexpr T &SmallMap<K, T, SmallSz>::operator[](MaybeView_t<K> const&k) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template<typename K, typename T, size_t SmallSz>
 | 
					template<typename K, typename T, size_t SmallSz>
 | 
				
			||||||
constexpr Result<T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) noexcept {
 | 
					constexpr Result<T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) noexcept {
 | 
				
			||||||
	auto p = access(m_pairs, k);
 | 
						auto const p = accessNoCreate(m_pairs, k);
 | 
				
			||||||
	if (!p) {
 | 
						if (!p) {
 | 
				
			||||||
		return {nullptr, ox::Error(1, "value not found for given key")};
 | 
							return {nullptr, ox::Error(1, "value not found for given key")};
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -147,7 +158,8 @@ constexpr Result<T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) noexcep
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template<typename K, typename T, size_t SmallSz>
 | 
					template<typename K, typename T, size_t SmallSz>
 | 
				
			||||||
constexpr Result<const T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) const noexcept {
 | 
					constexpr Result<const T*> SmallMap<K, T, SmallSz>::at(MaybeView_t<K> const&k) const noexcept {
 | 
				
			||||||
	auto p = access(m_pairs, k);
 | 
						bool isNew{};
 | 
				
			||||||
 | 
						auto p = access(m_pairs, k, isNew);
 | 
				
			||||||
	if (!p) {
 | 
						if (!p) {
 | 
				
			||||||
		return {nullptr, ox::Error(1, "value not found for given key")};
 | 
							return {nullptr, ox::Error(1, "value not found for given key")};
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -168,7 +180,8 @@ constexpr void SmallMap<K, T, SmallSz>::erase(MaybeView_t<K> const&k) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template<typename K, typename T, size_t SmallSz>
 | 
					template<typename K, typename T, size_t SmallSz>
 | 
				
			||||||
constexpr bool SmallMap<K, T, SmallSz>::contains(MaybeView_t<K> const&k) const noexcept {
 | 
					constexpr bool SmallMap<K, T, SmallSz>::contains(MaybeView_t<K> const&k) const noexcept {
 | 
				
			||||||
	return access(m_pairs, k) != nullptr;
 | 
						bool isNew{};
 | 
				
			||||||
 | 
						return access(m_pairs, k, isNew) != nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename K, typename T, size_t SmallSz>
 | 
					template<typename K, typename T, size_t SmallSz>
 | 
				
			||||||
@@ -186,6 +199,16 @@ constexpr Vector<K> SmallMap<K, T, SmallSz>::keys() const noexcept {
 | 
				
			|||||||
	return keys;
 | 
						return keys;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename K, typename T, size_t SmallSz>
 | 
				
			||||||
 | 
					constexpr Vector<T> SmallMap<K, T, SmallSz>::values() const noexcept {
 | 
				
			||||||
 | 
						ox::Vector<T> keys;
 | 
				
			||||||
 | 
						keys.reserve(m_pairs.size());
 | 
				
			||||||
 | 
						for (auto const&p : m_pairs) {
 | 
				
			||||||
 | 
							keys.emplace_back(p.key);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return keys;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename K, typename T, size_t SmallSz>
 | 
					template<typename K, typename T, size_t SmallSz>
 | 
				
			||||||
constexpr K const&SmallMap<K, T, SmallSz>::key(size_t i) const noexcept {
 | 
					constexpr K const&SmallMap<K, T, SmallSz>::key(size_t i) const noexcept {
 | 
				
			||||||
	return m_pairs[i].key;
 | 
						return m_pairs[i].key;
 | 
				
			||||||
@@ -218,30 +241,42 @@ constexpr void SmallMap<K, T, SmallSz>::clear() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template<typename K, typename T, size_t SmallSz>
 | 
					template<typename K, typename T, size_t SmallSz>
 | 
				
			||||||
template<typename KK>
 | 
					template<typename KK>
 | 
				
			||||||
constexpr typename SmallMap<K, T, SmallSz>::Pair const&SmallMap<K, T, SmallSz>::access(
 | 
					constexpr typename SmallMap<K, T, SmallSz>::Pair const*SmallMap<K, T, SmallSz>::access(
 | 
				
			||||||
		PairVector const&pairs, KK const&k, bool &isNew) const {
 | 
							PairVector const&pairs, KK const&k, bool &isNew) const {
 | 
				
			||||||
	for (auto const&p : pairs) {
 | 
						for (auto const&p : pairs) {
 | 
				
			||||||
		if (p.key == k) {
 | 
							if (p.key == k) {
 | 
				
			||||||
			isNew = false;
 | 
								isNew = false;
 | 
				
			||||||
			return p;
 | 
								return &p;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	isNew = true;
 | 
						isNew = true;
 | 
				
			||||||
	return pairs.emplace_back();
 | 
						return nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename K, typename T, size_t SmallSz>
 | 
					template<typename K, typename T, size_t SmallSz>
 | 
				
			||||||
template<typename KK>
 | 
					template<typename KK>
 | 
				
			||||||
constexpr typename SmallMap<K, T, SmallSz>::Pair &SmallMap<K, T, SmallSz>::access(
 | 
					constexpr typename SmallMap<K, T, SmallSz>::Pair *SmallMap<K, T, SmallSz>::access(
 | 
				
			||||||
		PairVector &pairs, KK const&k, bool &isNew) {
 | 
							PairVector &pairs, KK const&k, bool &isNew) {
 | 
				
			||||||
	for (auto &p : pairs) {
 | 
						for (auto &p : pairs) {
 | 
				
			||||||
		if (p.key == k) {
 | 
							if (p.key == k) {
 | 
				
			||||||
			isNew = false;
 | 
								isNew = false;
 | 
				
			||||||
			return p;
 | 
								return &p;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	isNew = true;
 | 
						isNew = true;
 | 
				
			||||||
	return pairs.emplace_back();
 | 
						return &pairs.emplace_back();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename K, typename T, size_t SmallSz>
 | 
				
			||||||
 | 
					template<typename KK>
 | 
				
			||||||
 | 
					constexpr typename SmallMap<K, T, SmallSz>::Pair *SmallMap<K, T, SmallSz>::accessNoCreate(
 | 
				
			||||||
 | 
							PairVector &pairs, KK const&k) {
 | 
				
			||||||
 | 
						for (auto &p : pairs) {
 | 
				
			||||||
 | 
							if (p.key == k) {
 | 
				
			||||||
 | 
								return &p;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T, typename K, typename V, size_t SmallSz>
 | 
					template<typename T, typename K, typename V, size_t SmallSz>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										20
									
								
								deps/ox/src/ox/std/span.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								deps/ox/src/ox/std/span.hpp
									
									
									
									
										vendored
									
									
								
							@@ -14,7 +14,7 @@
 | 
				
			|||||||
#include "iterator.hpp"
 | 
					#include "iterator.hpp"
 | 
				
			||||||
#include "vector.hpp"
 | 
					#include "vector.hpp"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
 | 
					OX_ALLOW_UNSAFE_BUFFERS_BEGIN
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace ox {
 | 
					namespace ox {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -133,7 +133,7 @@ class Span {
 | 
				
			|||||||
			return m_items[i];
 | 
								return m_items[i];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr const T &operator[](std::size_t i) const noexcept {
 | 
							constexpr T const&operator[](std::size_t i) const noexcept {
 | 
				
			||||||
			ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
 | 
								ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
 | 
				
			||||||
			return m_items[i];
 | 
								return m_items[i];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -168,8 +168,20 @@ class Span {
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
using SpanView = Span<const T>;
 | 
					using SpanView = Span<T const>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					constexpr void spancpy(ox::Span<T> const dst, ox::SpanView<T> const src) noexcept {
 | 
				
			||||||
 | 
						auto const sz = ox::min(dst.size(), src.size());
 | 
				
			||||||
 | 
						if (std::is_constant_evaluated() || std::is_trivially_copyable_v<T>) {
 | 
				
			||||||
 | 
							for (size_t i{}; i < sz; ++i) {
 | 
				
			||||||
 | 
								dst.data()[i] = src.data()[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							memcpy(dst.data(), src.data(), sz * sizeof(T));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OX_CLANG_NOWARN_END
 | 
					OX_ALLOW_UNSAFE_BUFFERS_END
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								deps/ox/src/ox/std/test/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								deps/ox/src/ox/std/test/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							@@ -17,6 +17,8 @@ add_test("[ox/std] String" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "String")
 | 
				
			|||||||
add_test("[ox/std] SmallMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap")
 | 
					add_test("[ox/std] SmallMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap")
 | 
				
			||||||
add_test("[ox/std] SmallMap2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap2")
 | 
					add_test("[ox/std] SmallMap2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap2")
 | 
				
			||||||
add_test("[ox/std] Vector" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Vector")
 | 
					add_test("[ox/std] Vector" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Vector")
 | 
				
			||||||
 | 
					add_test("[ox/std] Vector::shrink_to_fit" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Vector::shrink_to_fit")
 | 
				
			||||||
 | 
					add_test("[ox/std] findIdx" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "findIdx")
 | 
				
			||||||
add_test("[ox/std] HashMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "HashMap")
 | 
					add_test("[ox/std] HashMap" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "HashMap")
 | 
				
			||||||
add_test("[ox/std] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc)
 | 
					add_test("[ox/std] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc)
 | 
				
			||||||
add_test("[ox/std] Serialize-Int" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Serialize-Int")
 | 
					add_test("[ox/std] Serialize-Int" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "Serialize-Int")
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										57
									
								
								deps/ox/src/ox/std/test/tests.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										57
									
								
								deps/ox/src/ox/std/test/tests.cpp
									
									
									
									
										vendored
									
									
								
							@@ -237,6 +237,50 @@ OX_CLANG_NOWARN_END
 | 
				
			|||||||
			return ox::Error(0);
 | 
								return ox::Error(0);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							"Vector::shrink_to_fit",
 | 
				
			||||||
 | 
							[] {
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									ox::Vector<ox::IString<8>> v;
 | 
				
			||||||
 | 
									v.reserve(50);
 | 
				
			||||||
 | 
									v.emplace_back("asdf");
 | 
				
			||||||
 | 
									v.emplace_back("aoeu");
 | 
				
			||||||
 | 
									auto const origData = v.data();
 | 
				
			||||||
 | 
									v.shrink_to_fit();
 | 
				
			||||||
 | 
									oxExpect(v[0], "asdf");
 | 
				
			||||||
 | 
									oxExpect(v[1], "aoeu");
 | 
				
			||||||
 | 
									oxExpect(v.capacity(), 2u);
 | 
				
			||||||
 | 
									oxAssert(origData != v.data(), "shrink_to_fit did not create a new allocation");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									ox::Vector<ox::IString<8>> v;
 | 
				
			||||||
 | 
									v.reserve(2);
 | 
				
			||||||
 | 
									v.emplace_back("asdf");
 | 
				
			||||||
 | 
									v.emplace_back("aoeu");
 | 
				
			||||||
 | 
									auto const origData = v.data();
 | 
				
			||||||
 | 
									v.shrink_to_fit();
 | 
				
			||||||
 | 
									oxExpect(v[0], "asdf");
 | 
				
			||||||
 | 
									oxExpect(v[1], "aoeu");
 | 
				
			||||||
 | 
									oxExpect(v.capacity(), 2u);
 | 
				
			||||||
 | 
									oxAssert(origData == v.data(), "shrink_to_fit inappropriately created a new allocation");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return ox::Error{};
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							"findIdx",
 | 
				
			||||||
 | 
							[] {
 | 
				
			||||||
 | 
								ox::Vector<ox::IString<8>> const v {"zero", "one", "two", "three", "four"};
 | 
				
			||||||
 | 
								oxExpect(ox::findIdx(v.begin(), v.end(), "zero").or_value(5), 0u);
 | 
				
			||||||
 | 
								oxExpect(ox::findIdx(v.begin(), v.end(), "one").or_value(5), 1u);
 | 
				
			||||||
 | 
								oxExpect(ox::findIdx(v.begin(), v.end(), "two").or_value(5), 2u);
 | 
				
			||||||
 | 
								oxExpect(ox::findIdx(v.begin(), v.end(), "three").or_value(5), 3u);
 | 
				
			||||||
 | 
								oxExpect(ox::findIdx(v.begin(), v.end(), "four").or_value(5), 4u);
 | 
				
			||||||
 | 
								oxExpect(ox::findIdx(v.begin(), v.end(), "five").or_value(5), 5u);
 | 
				
			||||||
 | 
								oxExpect(ox::findIdx(v.begin(), v.end(), "six").or_value(6), 6u);
 | 
				
			||||||
 | 
								return ox::Error{};
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		"SmallMap",
 | 
							"SmallMap",
 | 
				
			||||||
		[] {
 | 
							[] {
 | 
				
			||||||
@@ -246,7 +290,18 @@ OX_CLANG_NOWARN_END
 | 
				
			|||||||
			oxExpect(map.size(), 1u);
 | 
								oxExpect(map.size(), 1u);
 | 
				
			||||||
			oxExpect(map["aoeu"], "");
 | 
								oxExpect(map["aoeu"], "");
 | 
				
			||||||
			oxExpect(map.size(), 2u);
 | 
								oxExpect(map.size(), 2u);
 | 
				
			||||||
			return ox::Error(0);
 | 
								ox::SmallMap<ox::String, ox::String> cmap;
 | 
				
			||||||
 | 
								cmap["asdf"] = "aoeu";
 | 
				
			||||||
 | 
								auto constexpr constTest = [](ox::SmallMap<ox::String, ox::String> const&map) {
 | 
				
			||||||
 | 
									OX_REQUIRE(asdf, map.at("asdf"));
 | 
				
			||||||
 | 
									oxExpect(*asdf, "aoeu");
 | 
				
			||||||
 | 
									oxExpect(map.size(), 1u);
 | 
				
			||||||
 | 
									auto const aoeu = map.at("aoeu");
 | 
				
			||||||
 | 
									oxExpect(aoeu.ok(), false);
 | 
				
			||||||
 | 
									oxExpect(map.size(), 1u);
 | 
				
			||||||
 | 
									return ox::Error{};
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								return constTest(cmap);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										8
									
								
								deps/ox/src/ox/std/trace.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								deps/ox/src/ox/std/trace.hpp
									
									
									
									
										vendored
									
									
								
							@@ -269,8 +269,8 @@ 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.file != nullptr) {
 | 
							if (err.src.file_name() != nullptr) {
 | 
				
			||||||
			trc << "Error: (" << err.file << ":" << err.line << "):";
 | 
								trc << "Error: (" << err.src.file_name() << ":" << err.src.line() << "):";
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			trc <<  "Error:";
 | 
								trc <<  "Error:";
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -282,8 +282,8 @@ 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.file != nullptr) {
 | 
							if (err.src.file_name() != nullptr) {
 | 
				
			||||||
			trc << "(" << err.file << ":" << err.line << ")";
 | 
								trc << "(" << err.src.file_name() << ":" << err.src.line() << ")";
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								deps/ox/src/ox/std/typetraits.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								deps/ox/src/ox/std/typetraits.hpp
									
									
									
									
										vendored
									
									
								
							@@ -19,12 +19,15 @@
 | 
				
			|||||||
namespace std {
 | 
					namespace std {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
constexpr bool is_union_v = __is_union(T);
 | 
					inline constexpr bool is_union_v = __is_union(T);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
constexpr bool is_constant_evaluated() noexcept {
 | 
					inline constexpr bool is_constant_evaluated() noexcept {
 | 
				
			||||||
	return __builtin_is_constant_evaluated();
 | 
						return __builtin_is_constant_evaluated();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					inline constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@@ -156,6 +159,9 @@ static_assert(is_class<int>::value == false);
 | 
				
			|||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
constexpr bool is_class_v = is_class<T>();
 | 
					constexpr bool is_class_v = is_class<T>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					inline constexpr bool is_trivially_copyable_v = std::is_trivially_copyable_v<T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
constexpr bool is_signed_v = integral_constant<bool, T(-1) < T(0)>::value;
 | 
					constexpr bool is_signed_v = integral_constant<bool, T(-1) < T(0)>::value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								deps/ox/src/ox/std/vector.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								deps/ox/src/ox/std/vector.hpp
									
									
									
									
										vendored
									
									
								
							@@ -313,6 +313,8 @@ class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		constexpr void reserve(std::size_t cap) noexcept(useNoexcept);
 | 
							constexpr void reserve(std::size_t cap) noexcept(useNoexcept);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							constexpr void shrink_to_fit() noexcept(useNoexcept);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		constexpr void reserveInsert(
 | 
							constexpr void reserveInsert(
 | 
				
			||||||
				std::size_t cap, std::size_t pos, std::size_t offset = 1) noexcept(useNoexcept);
 | 
									std::size_t cap, std::size_t pos, std::size_t offset = 1) noexcept(useNoexcept);
 | 
				
			||||||
@@ -341,6 +343,7 @@ constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::size_t size) noexce
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template<typename T, std::size_t SmallVectorSize, typename Allocator>
 | 
					template<typename T, std::size_t SmallVectorSize, typename Allocator>
 | 
				
			||||||
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept {
 | 
					constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept {
 | 
				
			||||||
 | 
						reserve(list.size());
 | 
				
			||||||
	for (auto &item : list) {
 | 
						for (auto &item : list) {
 | 
				
			||||||
		emplace_back(std::move(item));
 | 
							emplace_back(std::move(item));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -675,6 +678,24 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::reserve(std::size_t cap) n
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename T, std::size_t SmallVectorSize, typename Allocator>
 | 
				
			||||||
 | 
					constexpr void Vector<T, SmallVectorSize, Allocator>::shrink_to_fit() noexcept(useNoexcept)  {
 | 
				
			||||||
 | 
						if (m_size == m_cap) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						const auto oldItems = m_items;
 | 
				
			||||||
 | 
						const auto oldCap = m_cap;
 | 
				
			||||||
 | 
						m_cap = m_size;
 | 
				
			||||||
 | 
						this->allocate(&m_items, m_size);
 | 
				
			||||||
 | 
						if (oldItems) { // move over old items
 | 
				
			||||||
 | 
							for (std::size_t i = 0; i < m_size; ++i) {
 | 
				
			||||||
 | 
								std::construct_at(&m_items[i], std::move(oldItems[i]));
 | 
				
			||||||
 | 
								oldItems[i].~T();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							this->deallocate(oldItems, oldCap);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T, std::size_t SmallVectorSize, typename Allocator>
 | 
					template<typename T, std::size_t SmallVectorSize, typename Allocator>
 | 
				
			||||||
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveInsert(
 | 
					constexpr void Vector<T, SmallVectorSize, Allocator>::reserveInsert(
 | 
				
			||||||
		std::size_t cap,
 | 
							std::size_t cap,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								deps/teagba/src/cstartup.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								deps/teagba/src/cstartup.cpp
									
									
									
									
										vendored
									
									
								
							@@ -4,17 +4,20 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <ox/std/heapmgr.hpp>
 | 
					#include <ox/std/heapmgr.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <teagba/bios.hpp>
 | 
				
			||||||
 | 
					#include <teagba/registers.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mgba {
 | 
					namespace mgba {
 | 
				
			||||||
void initConsole();
 | 
					void initConsole();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MEM_EWRAM_BEGIN reinterpret_cast<char*>(0x02000000)
 | 
					#define MEM_HEAP_BEGIN reinterpret_cast<char*>(0x02000000)
 | 
				
			||||||
#define MEM_EWRAM_END   reinterpret_cast<char*>(0x0203FFFF)
 | 
					#define MEM_HEAP_END   reinterpret_cast<char*>(0x0203FFFF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define HEAP_BEGIN reinterpret_cast<char*>(MEM_EWRAM_BEGIN)
 | 
					#define HEAP_BEGIN reinterpret_cast<char*>(MEM_HEAP_BEGIN)
 | 
				
			||||||
// set size to half of EWRAM
 | 
					// set size to half of EWRAM
 | 
				
			||||||
#define HEAP_SIZE ((MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2)
 | 
					#define HEAP_SIZE ((MEM_HEAP_END - MEM_HEAP_BEGIN) / 2)
 | 
				
			||||||
#define HEAP_END  reinterpret_cast<char*>(MEM_EWRAM_BEGIN + HEAP_SIZE)
 | 
					#define HEAP_END  reinterpret_cast<char*>(MEM_HEAP_BEGIN + HEAP_SIZE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void (*__preinit_array_start[]) (void);
 | 
					extern void (*__preinit_array_start[]) (void);
 | 
				
			||||||
extern void (*__preinit_array_end[]) (void);
 | 
					extern void (*__preinit_array_end[]) (void);
 | 
				
			||||||
@@ -25,6 +28,14 @@ int main(int argc, const char **argv);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extern "C" {
 | 
					extern "C" {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void abort() {
 | 
				
			||||||
 | 
						REG_IE = 0;
 | 
				
			||||||
 | 
						teagba::intrwait(0, 0);
 | 
				
			||||||
 | 
						while (true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *__gxx_personality_v0{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void __libc_init_array() {
 | 
					void __libc_init_array() {
 | 
				
			||||||
	auto preInits = __preinit_array_end - __preinit_array_start;
 | 
						auto preInits = __preinit_array_end - __preinit_array_start;
 | 
				
			||||||
	for (decltype(preInits) i = 0; i < preInits; i++) {
 | 
						for (decltype(preInits) i = 0; i < preInits; i++) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -162,11 +162,9 @@ The Ox way of doing things is the Olympic way of doing things.
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### Error Handling
 | 
					### Error Handling
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The GBA build has exceptions disabled.
 | 
					Instead of throwing exceptions, generally try to use
 | 
				
			||||||
Instead of throwing exceptions, all engine code should return
 | 
					[ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting,
 | 
				
			||||||
[ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting.
 | 
					but exceptions may be used where they make sense.
 | 
				
			||||||
For the sake of consistency, try to stick to ```ox::Error``` in non-engine code
 | 
					 | 
				
			||||||
as well, but non-engine code is free to use exceptions when they make sense.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Exceptions should generally just use ```OxException```, which is bascially an
 | 
					Exceptions should generally just use ```OxException```, which is bascially an
 | 
				
			||||||
exception form of ```ox::Error```.
 | 
					exception form of ```ox::Error```.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -102,8 +102,6 @@ OX_MODEL_BEGIN(TileSheetSet)
 | 
				
			|||||||
	OX_MODEL_FIELD(entries)
 | 
						OX_MODEL_FIELD(entries)
 | 
				
			||||||
OX_MODEL_END()
 | 
					OX_MODEL_END()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void addEntry(TileSheetSet &set, ox::FileAddress path, int32_t begin = 0, int32_t size = -1) noexcept;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[[nodiscard]]
 | 
					[[nodiscard]]
 | 
				
			||||||
int tileColumns(Context&) noexcept;
 | 
					int tileColumns(Context&) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -144,6 +142,10 @@ ox::Error loadBgTileSheet(
 | 
				
			|||||||
		unsigned cbb,
 | 
							unsigned cbb,
 | 
				
			||||||
		TileSheetSet const&set) noexcept;
 | 
							TileSheetSet const&set) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void clearCbb(Context &ctx, unsigned cbb) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void clearCbbs(Context &ctx) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ox::Error loadBgTileSheet(
 | 
					ox::Error loadBgTileSheet(
 | 
				
			||||||
		Context &ctx,
 | 
							Context &ctx,
 | 
				
			||||||
		unsigned cbb,
 | 
							unsigned cbb,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								src/nostalgia/modules/core/include/nostalgia/core/studio.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/nostalgia/modules/core/include/nostalgia/core/studio.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <studio/studio.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace nostalgia::core {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -18,6 +18,23 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace nostalgia::core {
 | 
					namespace nostalgia::core {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct SubSheetTemplate {
 | 
				
			||||||
 | 
						static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.SubSheetTemplate";
 | 
				
			||||||
 | 
						static constexpr auto TypeVersion = 1;
 | 
				
			||||||
 | 
						ox::String name;
 | 
				
			||||||
 | 
						int32_t width{};
 | 
				
			||||||
 | 
						int32_t height{};
 | 
				
			||||||
 | 
						ox::Vector<SubSheetTemplate> subsheets;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OX_MODEL_BEGIN(SubSheetTemplate)
 | 
				
			||||||
 | 
						OX_MODEL_FIELD(name)
 | 
				
			||||||
 | 
						OX_MODEL_FIELD(width)
 | 
				
			||||||
 | 
						OX_MODEL_FIELD(height)
 | 
				
			||||||
 | 
						OX_MODEL_FIELD(subsheets)
 | 
				
			||||||
 | 
					OX_MODEL_END()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Predecessor to TileSheet, kept for backward compatibility
 | 
					// Predecessor to TileSheet, kept for backward compatibility
 | 
				
			||||||
struct TileSheetV1 {
 | 
					struct TileSheetV1 {
 | 
				
			||||||
	static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaGraphic";
 | 
						static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaGraphic";
 | 
				
			||||||
@@ -212,6 +229,10 @@ struct TileSheetV4 {
 | 
				
			|||||||
				pixels(std::move(pPixels)) {
 | 
									pixels(std::move(pPixels)) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/**
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * @return the dimensional size of the SubSheet (e.g. width * height)
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
		[[nodiscard]]
 | 
							[[nodiscard]]
 | 
				
			||||||
		constexpr std::size_t size() const noexcept {
 | 
							constexpr std::size_t size() const noexcept {
 | 
				
			||||||
			return static_cast<std::size_t>(columns) * static_cast<std::size_t>(rows);
 | 
								return static_cast<std::size_t>(columns) * static_cast<std::size_t>(rows);
 | 
				
			||||||
@@ -281,7 +302,7 @@ size_t getTileCnt(TileSheet const&ts) noexcept;
 | 
				
			|||||||
TileSheet::SubSheet const*getSubsheet(TileSheet const&ts, SubSheetId id) noexcept;
 | 
					TileSheet::SubSheet const*getSubsheet(TileSheet const&ts, SubSheetId id) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[nodiscard]]
 | 
					[[nodiscard]]
 | 
				
			||||||
size_t getTileIdx(TileSheet const&ts, SubSheetId id) noexcept;
 | 
					ox::Optional<size_t> getTileIdx(TileSheet const&ts, SubSheetId id) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[nodiscard]]
 | 
					[[nodiscard]]
 | 
				
			||||||
uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
 | 
					uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
 | 
				
			||||||
@@ -400,6 +421,8 @@ ox::Result<SubSheetId> getIdFor(TileSheet const&ts, ox::StringViewCR path) noexc
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
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<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 const&ts, SubSheetId pId) noexcept;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -63,6 +63,19 @@ ox::Error loadSpritePalette(
 | 
				
			|||||||
	return {};
 | 
						return {};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void clearCbb(Context&, unsigned const cbb) noexcept {
 | 
				
			||||||
 | 
						for (auto &v : MEM_BG_TILES[cbb]) {
 | 
				
			||||||
 | 
							v = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void clearCbbs(Context &ctx) noexcept {
 | 
				
			||||||
 | 
						clearCbb(ctx, 0);
 | 
				
			||||||
 | 
						clearCbb(ctx, 1);
 | 
				
			||||||
 | 
						clearCbb(ctx, 2);
 | 
				
			||||||
 | 
						clearCbb(ctx, 3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ox::Error loadTileSheetSet(
 | 
					static ox::Error loadTileSheetSet(
 | 
				
			||||||
		Context &ctx,
 | 
							Context &ctx,
 | 
				
			||||||
		ox::Span<uint16_t> tileMapTargetMem,
 | 
							ox::Span<uint16_t> tileMapTargetMem,
 | 
				
			||||||
@@ -99,10 +112,10 @@ ox::Error loadBgTileSheet(
 | 
				
			|||||||
		size_t const tileCnt) noexcept {
 | 
							size_t const tileCnt) noexcept {
 | 
				
			||||||
	size_t const bppMod = ts.bpp == 4;
 | 
						size_t const bppMod = ts.bpp == 4;
 | 
				
			||||||
	size_t const bytesPerTile = PixelsPerTile >> bppMod;
 | 
						size_t const bytesPerTile = PixelsPerTile >> bppMod;
 | 
				
			||||||
	auto const pixCnt = tileCnt * bytesPerTile;
 | 
						auto const cnt = (tileCnt * bytesPerTile) / 2;
 | 
				
			||||||
	auto const srcPxIdx = srcTileIdx * bytesPerTile;
 | 
						auto const srcPxIdx = srcTileIdx * bytesPerTile;
 | 
				
			||||||
	auto const dstPxIdx = (dstTileIdx * bytesPerTile) / 2;
 | 
						auto const dstPxIdx = (dstTileIdx * bytesPerTile) / 2;
 | 
				
			||||||
	for (size_t i = 0; i < pixCnt; ++i) {
 | 
						for (size_t i = 0; i < cnt; ++i) {
 | 
				
			||||||
		auto const srcIdx = srcPxIdx + i * 2;
 | 
							auto const srcIdx = srcPxIdx + i * 2;
 | 
				
			||||||
		auto const p1 = static_cast<uint16_t>(ts.pixels[srcIdx]);
 | 
							auto const p1 = static_cast<uint16_t>(ts.pixels[srcIdx]);
 | 
				
			||||||
		auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]);
 | 
							auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ox/std/def.hpp>
 | 
					#include <ox/std/def.hpp>
 | 
				
			||||||
 | 
					#include <ox/std/realstd.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <keel/media.hpp>
 | 
					#include <keel/media.hpp>
 | 
				
			||||||
#include <turbine/turbine.hpp>
 | 
					#include <turbine/turbine.hpp>
 | 
				
			||||||
@@ -48,12 +49,10 @@ OX_ALLOW_UNSAFE_BUFFERS_END
 | 
				
			|||||||
		oxErrf("\tError Message:\t{}\n", err.msg);
 | 
							oxErrf("\tError Message:\t{}\n", err.msg);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
 | 
						oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
 | 
				
			||||||
	if (err.file != nullptr) {
 | 
						if (err.src.file_name() != nullptr) {
 | 
				
			||||||
		oxErrf("\tError Location:\t{}:{}\n", err.file, err.line);
 | 
							oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// disable all interrupt handling and IntrWait on no interrupts
 | 
						abort();
 | 
				
			||||||
	REG_IE = 0;
 | 
					 | 
				
			||||||
	teagba::intrwait(0, 0);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,7 +67,7 @@ static class: public keel::Module {
 | 
				
			|||||||
		ox::Vector<keel::PackTransform> packTransforms() const noexcept final {
 | 
							ox::Vector<keel::PackTransform> packTransforms() const noexcept final {
 | 
				
			||||||
			return {
 | 
								return {
 | 
				
			||||||
				// convert tilesheets to CompactTileSheets
 | 
									// convert tilesheets to CompactTileSheets
 | 
				
			||||||
				[](keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) -> ox::Result<bool> {
 | 
									[](keel::Context &ctx, ox::Buffer &buff, ox::StringViewCR typeId) -> ox::Result<bool> {
 | 
				
			||||||
					if (typeId == ox::ModelTypeId_v<TileSheetV1> ||
 | 
										if (typeId == ox::ModelTypeId_v<TileSheetV1> ||
 | 
				
			||||||
					    typeId == ox::ModelTypeId_v<TileSheetV2> ||
 | 
										    typeId == ox::ModelTypeId_v<TileSheetV2> ||
 | 
				
			||||||
					    typeId == ox::ModelTypeId_v<TileSheetV3> ||
 | 
										    typeId == ox::ModelTypeId_v<TileSheetV3> ||
 | 
				
			||||||
@@ -78,7 +78,7 @@ static class: public keel::Module {
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
					return false;
 | 
										return false;
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				[](keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) -> ox::Result<bool> {
 | 
									[](keel::Context &ctx, ox::Buffer &buff, ox::StringViewCR typeId) -> ox::Result<bool> {
 | 
				
			||||||
					if (typeId == ox::ModelTypeId_v<NostalgiaPalette> ||
 | 
										if (typeId == ox::ModelTypeId_v<NostalgiaPalette> ||
 | 
				
			||||||
					    typeId == ox::ModelTypeId_v<PaletteV1> ||
 | 
										    typeId == ox::ModelTypeId_v<PaletteV1> ||
 | 
				
			||||||
					    typeId == ox::ModelTypeId_v<PaletteV2> ||
 | 
										    typeId == ox::ModelTypeId_v<PaletteV2> ||
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -111,15 +111,15 @@ static constexpr auto bgVertexRow(uint_t x, uint_t y) noexcept {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void setSpriteBufferObject(
 | 
					static void setSpriteBufferObject(
 | 
				
			||||||
		uint_t vi,
 | 
							uint_t const vi,
 | 
				
			||||||
		float enabled,
 | 
							float const enabled,
 | 
				
			||||||
		float x,
 | 
							float x,
 | 
				
			||||||
		float y,
 | 
							float y,
 | 
				
			||||||
		uint_t textureRow,
 | 
							uint_t const textureRow,
 | 
				
			||||||
		uint_t flipX,
 | 
							uint_t const flipX,
 | 
				
			||||||
		uint_t priority,
 | 
							uint_t const priority,
 | 
				
			||||||
		float *vbo,
 | 
							ox::Span<float> const vbo,
 | 
				
			||||||
		GLuint *ebo) noexcept {
 | 
							ox::Span<GLuint> const ebo) noexcept {
 | 
				
			||||||
	// don't worry, this memcpy gets optimized to something much more ideal
 | 
						// don't worry, this memcpy gets optimized to something much more ideal
 | 
				
			||||||
	constexpr float xmod = 0.1f;
 | 
						constexpr float xmod = 0.1f;
 | 
				
			||||||
	constexpr float ymod = 0.1f;
 | 
						constexpr float ymod = 0.1f;
 | 
				
			||||||
@@ -138,25 +138,25 @@ static void setSpriteBufferObject(
 | 
				
			|||||||
	    enabled, x + xmod, y + ymod, prif, R, textureRowf + 0, // top right
 | 
						    enabled, x + xmod, y + ymod, prif, R, textureRowf + 0, // top right
 | 
				
			||||||
	    enabled,        x, y + ymod, prif, L, textureRowf + 0, // top left
 | 
						    enabled,        x, y + ymod, prif, L, textureRowf + 0, // top left
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	memcpy(vbo, vertices.data(), sizeof(vertices));
 | 
						ox::spancpy<float>(vbo, vertices);
 | 
				
			||||||
	ox::Array<GLuint, SpriteVertexEboLength> const elms {
 | 
						ox::Array<GLuint, SpriteVertexEboLength> const elms {
 | 
				
			||||||
		vi + 0, vi + 1, vi + 2,
 | 
							vi + 0, vi + 1, vi + 2,
 | 
				
			||||||
		vi + 2, vi + 3, vi + 0,
 | 
							vi + 2, vi + 3, vi + 0,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	memcpy(ebo, elms.data(), sizeof(elms));
 | 
						ox::spancpy<GLuint>(ebo, elms);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void setTileBufferObject(
 | 
					static void setTileBufferObject(
 | 
				
			||||||
		uint_t vi,
 | 
							uint_t const vi,
 | 
				
			||||||
		float x,
 | 
							float x,
 | 
				
			||||||
		float y,
 | 
							float y,
 | 
				
			||||||
		float textureTileIdx,
 | 
							float const textureTileIdx,
 | 
				
			||||||
		float priority,
 | 
							float const priority,
 | 
				
			||||||
		float palOffset,
 | 
							float const palOffset,
 | 
				
			||||||
		bool flipX,
 | 
							bool const flipX,
 | 
				
			||||||
		bool flipY,
 | 
							bool const flipY,
 | 
				
			||||||
		float *vbo,
 | 
							ox::Span<float> const vbo,
 | 
				
			||||||
		GLuint *ebo) noexcept {
 | 
							ox::Span<GLuint> const ebo) noexcept {
 | 
				
			||||||
	// don't worry, this memcpy gets optimized to something much more ideal
 | 
						// don't worry, this memcpy gets optimized to something much more ideal
 | 
				
			||||||
	constexpr float ymod = 0.1f;
 | 
						constexpr float ymod = 0.1f;
 | 
				
			||||||
	constexpr float xmod = 0.1f;
 | 
						constexpr float xmod = 0.1f;
 | 
				
			||||||
@@ -175,19 +175,30 @@ static void setTileBufferObject(
 | 
				
			|||||||
		x + xmod, y + ymod, prif, R, T, textureTileIdx, palOffset, // top right
 | 
							x + xmod, y + ymod, prif, R, T, textureTileIdx, palOffset, // top right
 | 
				
			||||||
		       x, y + ymod, prif, L, T, textureTileIdx, palOffset, // top left
 | 
							       x, y + ymod, prif, L, T, textureTileIdx, palOffset, // top left
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	memcpy(vbo, vertices.data(), sizeof(vertices));
 | 
						ox::spancpy<float>(vbo, vertices);
 | 
				
			||||||
	ox::Array<GLuint, BgVertexEboLength> const elms {
 | 
						ox::Array<GLuint, BgVertexEboLength> const elms {
 | 
				
			||||||
		vi + 0, vi + 1, vi + 2,
 | 
							vi + 0, vi + 1, vi + 2,
 | 
				
			||||||
		vi + 2, vi + 3, vi + 0,
 | 
							vi + 2, vi + 3, vi + 0,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	memcpy(ebo, elms.data(), sizeof(elms));
 | 
						ox::spancpy<GLuint>(ebo, elms);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void initSpriteBufferObjects(Context &ctx, glutils::BufferSet &bs) noexcept {
 | 
					static void initSpriteBufferObjects(Context &ctx, glutils::BufferSet &bs) noexcept {
 | 
				
			||||||
	for (auto i = 0u; i < ctx.spriteCount; ++i) {
 | 
						for (auto i = 0u; i < ctx.spriteCount; ++i) {
 | 
				
			||||||
		auto vbo = &bs.vertices[i * static_cast<std::size_t>(SpriteVertexVboLength)];
 | 
							auto const vbo = ox::Span{bs.vertices}
 | 
				
			||||||
		auto ebo = &bs.elements[i * static_cast<std::size_t>(SpriteVertexEboLength)];
 | 
								+ i * static_cast<std::size_t>(SpriteVertexVboLength);
 | 
				
			||||||
		setSpriteBufferObject(i * static_cast<uint_t>(SpriteVertexVboRows) * ctx.blocksPerSprite, 0, 0, 0, 0, false, 0, vbo, ebo);
 | 
							auto const ebo = ox::Span{bs.elements}
 | 
				
			||||||
 | 
								+ i * static_cast<std::size_t>(SpriteVertexEboLength);
 | 
				
			||||||
 | 
							setSpriteBufferObject(
 | 
				
			||||||
 | 
								i * static_cast<uint_t>(SpriteVertexVboRows) * ctx.blocksPerSprite,
 | 
				
			||||||
 | 
								0,
 | 
				
			||||||
 | 
								0,
 | 
				
			||||||
 | 
								0,
 | 
				
			||||||
 | 
								0,
 | 
				
			||||||
 | 
								false,
 | 
				
			||||||
 | 
								0,
 | 
				
			||||||
 | 
								vbo,
 | 
				
			||||||
 | 
								ebo);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -195,8 +206,10 @@ static void initBackgroundBufferObjects(glutils::BufferSet &bs) noexcept {
 | 
				
			|||||||
	for (auto x = 0u; x < TileColumns; ++x) {
 | 
						for (auto x = 0u; x < TileColumns; ++x) {
 | 
				
			||||||
		for (auto y = 0u; y < TileRows; ++y) {
 | 
							for (auto y = 0u; y < TileRows; ++y) {
 | 
				
			||||||
			const auto i = bgVertexRow(x, y);
 | 
								const auto i = bgVertexRow(x, y);
 | 
				
			||||||
			auto vbo = &bs.vertices[i * static_cast<std::size_t>(BgVertexVboLength)];
 | 
								auto const vbo = ox::Span{bs.vertices}
 | 
				
			||||||
			auto ebo = &bs.elements[i * static_cast<std::size_t>(BgVertexEboLength)];
 | 
									+ i * static_cast<std::size_t>(BgVertexVboLength);
 | 
				
			||||||
 | 
								auto const ebo = ox::Span{bs.elements}
 | 
				
			||||||
 | 
									+ i * static_cast<std::size_t>(BgVertexEboLength);
 | 
				
			||||||
			setTileBufferObject(
 | 
								setTileBufferObject(
 | 
				
			||||||
				static_cast<uint_t>(i * BgVertexVboRows),
 | 
									static_cast<uint_t>(i * BgVertexVboRows),
 | 
				
			||||||
				static_cast<float>(x),
 | 
									static_cast<float>(x),
 | 
				
			||||||
@@ -421,8 +434,8 @@ static void setSprite(
 | 
				
			|||||||
		auto const eboIdx = eboBase + renderer::SpriteVertexEboLength * i;
 | 
							auto const eboIdx = eboBase + renderer::SpriteVertexEboLength * i;
 | 
				
			||||||
		oxAssert(vboIdx < ctx.spriteBlocks.vertices.size(), "vbo overflow");
 | 
							oxAssert(vboIdx < ctx.spriteBlocks.vertices.size(), "vbo overflow");
 | 
				
			||||||
		oxAssert(eboIdx < ctx.spriteBlocks.elements.size(), "ebo overflow");
 | 
							oxAssert(eboIdx < ctx.spriteBlocks.elements.size(), "ebo overflow");
 | 
				
			||||||
		auto const vbo = &ctx.spriteBlocks.vertices[vboIdx];
 | 
							auto const vbo = ox::Span{ctx.spriteBlocks.vertices} + vboIdx;
 | 
				
			||||||
		auto const ebo = &ctx.spriteBlocks.elements[eboIdx];
 | 
							auto const ebo = ox::Span{ctx.spriteBlocks.elements} + eboIdx;
 | 
				
			||||||
		renderer::setSpriteBufferObject(
 | 
							renderer::setSpriteBufferObject(
 | 
				
			||||||
				static_cast<uint_t>(vboIdx),
 | 
									static_cast<uint_t>(vboIdx),
 | 
				
			||||||
				enabled,
 | 
									enabled,
 | 
				
			||||||
@@ -556,7 +569,7 @@ static void copyPixels(
 | 
				
			|||||||
		CompactTileSheet const&ts,
 | 
							CompactTileSheet const&ts,
 | 
				
			||||||
		ox::Span<uint32_t> dst,
 | 
							ox::Span<uint32_t> dst,
 | 
				
			||||||
		size_t const srcPxIdx,
 | 
							size_t const srcPxIdx,
 | 
				
			||||||
		size_t pxlCnt) noexcept {
 | 
							size_t const pxlCnt) noexcept {
 | 
				
			||||||
	size_t idx{};
 | 
						size_t idx{};
 | 
				
			||||||
	if (ts.bpp == 4) {
 | 
						if (ts.bpp == 4) {
 | 
				
			||||||
		for (size_t i = 0; i < pxlCnt; i += 2) {
 | 
							for (size_t i = 0; i < pxlCnt; i += 2) {
 | 
				
			||||||
@@ -573,6 +586,18 @@ static void copyPixels(
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void clearCbb(Context &ctx, unsigned const cbb) noexcept {
 | 
				
			||||||
 | 
						for (auto &v : ctx.cbbs[cbb].pixels) {
 | 
				
			||||||
 | 
							v = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void clearCbbs(Context &ctx) noexcept {
 | 
				
			||||||
 | 
						for (unsigned i = 0 ; i < ctx.cbbs.size(); ++i) {
 | 
				
			||||||
 | 
							clearCbb(ctx, i);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ox::Error loadBgTileSheet(
 | 
					ox::Error loadBgTileSheet(
 | 
				
			||||||
		Context &ctx,
 | 
							Context &ctx,
 | 
				
			||||||
		unsigned const cbb,
 | 
							unsigned const cbb,
 | 
				
			||||||
@@ -656,8 +681,8 @@ void setBgTile(
 | 
				
			|||||||
	const auto x = static_cast<uint_t>(column);
 | 
						const auto x = static_cast<uint_t>(column);
 | 
				
			||||||
	const auto i = renderer::bgVertexRow(x, y);
 | 
						const auto i = renderer::bgVertexRow(x, y);
 | 
				
			||||||
	auto &cbb = ctx.cbbs[z];
 | 
						auto &cbb = ctx.cbbs[z];
 | 
				
			||||||
	const auto vbo = &cbb.vertices[i * renderer::BgVertexVboLength];
 | 
						const auto vbo = ox::Span{cbb.vertices} + i * renderer::BgVertexVboLength;
 | 
				
			||||||
	const auto ebo = &cbb.elements[i * renderer::BgVertexEboLength];
 | 
						const auto ebo = ox::Span{cbb.elements} + i * renderer::BgVertexEboLength;
 | 
				
			||||||
	auto &bg = ctx.backgrounds[bgIdx];
 | 
						auto &bg = ctx.backgrounds[bgIdx];
 | 
				
			||||||
	renderer::setTileBufferObject(
 | 
						renderer::setTileBufferObject(
 | 
				
			||||||
			static_cast<uint_t>(i * renderer::BgVertexVboRows),
 | 
								static_cast<uint_t>(i * renderer::BgVertexVboRows),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,7 +3,6 @@ add_library(NostalgiaCore-Studio)
 | 
				
			|||||||
add_library(
 | 
					add_library(
 | 
				
			||||||
	NostalgiaCore-Studio-ImGui
 | 
						NostalgiaCore-Studio-ImGui
 | 
				
			||||||
		studiomodule.cpp
 | 
							studiomodule.cpp
 | 
				
			||||||
		tilesheeteditor/tilesheeteditor-imgui.cpp
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_link_libraries(
 | 
					target_link_libraries(
 | 
				
			||||||
@@ -15,7 +14,6 @@ target_link_libraries(
 | 
				
			|||||||
target_link_libraries(
 | 
					target_link_libraries(
 | 
				
			||||||
	NostalgiaCore-Studio-ImGui PUBLIC
 | 
						NostalgiaCore-Studio-ImGui PUBLIC
 | 
				
			||||||
		NostalgiaCore-Studio
 | 
							NostalgiaCore-Studio
 | 
				
			||||||
		Studio
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install(
 | 
					install(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,5 +9,9 @@ target_sources(
 | 
				
			|||||||
		commands/renamepagecommand.cpp
 | 
							commands/renamepagecommand.cpp
 | 
				
			||||||
		commands/updatecolorcommand.cpp
 | 
							commands/updatecolorcommand.cpp
 | 
				
			||||||
		commands/updatecolorinfocommand.cpp
 | 
							commands/updatecolorinfocommand.cpp
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					target_sources(
 | 
				
			||||||
 | 
						NostalgiaCore-Studio-ImGui PRIVATE
 | 
				
			||||||
		paletteeditor-imgui.cpp
 | 
							paletteeditor-imgui.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,11 @@ target_sources(
 | 
				
			|||||||
		tilesheetpixels.cpp
 | 
							tilesheetpixels.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					target_sources(
 | 
				
			||||||
 | 
						NostalgiaCore-Studio-ImGui PRIVATE
 | 
				
			||||||
 | 
							tilesheeteditor-imgui.cpp
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_link_libraries(
 | 
					target_link_libraries(
 | 
				
			||||||
	NostalgiaCore-Studio-ImGui PUBLIC
 | 
						NostalgiaCore-Studio-ImGui PUBLIC
 | 
				
			||||||
		lodepng
 | 
							lodepng
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -234,7 +234,7 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept {
 | 
				
			|||||||
		ImGui::BeginChild("SubSheets", {s_palViewWidth - 24, ySize / 2.f}, true);
 | 
							ImGui::BeginChild("SubSheets", {s_palViewWidth - 24, ySize / 2.f}, true);
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			static constexpr auto btnHeight = ig::BtnSz.y;
 | 
								static constexpr auto btnHeight = ig::BtnSz.y;
 | 
				
			||||||
			auto const btnSize = ImVec2{btnHeight, btnHeight};
 | 
								auto constexpr btnSize = ImVec2{btnHeight, btnHeight};
 | 
				
			||||||
			if (ig::PushButton("+", btnSize)) {
 | 
								if (ig::PushButton("+", btnSize)) {
 | 
				
			||||||
				auto insertOnIdx = m_model.activeSubSheetIdx();
 | 
									auto insertOnIdx = m_model.activeSubSheetIdx();
 | 
				
			||||||
				auto const&parent = m_model.activeSubSheet();
 | 
									auto const&parent = m_model.activeSubSheet();
 | 
				
			||||||
@@ -258,7 +258,10 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept {
 | 
				
			|||||||
				m_exportMenu.show();
 | 
									m_exportMenu.show();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			TileSheet::SubSheetIdx path;
 | 
								TileSheet::SubSheetIdx path;
 | 
				
			||||||
			static constexpr auto flags = ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
 | 
								static constexpr auto flags =
 | 
				
			||||||
 | 
									ImGuiTableFlags_RowBg |
 | 
				
			||||||
 | 
					                ImGuiTableFlags_NoBordersInBody |
 | 
				
			||||||
 | 
					                ImGuiTableFlags_ScrollY;
 | 
				
			||||||
            if (ImGui::BeginTable("Subsheets", 4, flags)) {
 | 
					            if (ImGui::BeginTable("Subsheets", 4, flags)) {
 | 
				
			||||||
                ImGui::TableSetupColumn("Subsheet", ImGuiTableColumnFlags_NoHide);
 | 
					                ImGui::TableSetupColumn("Subsheet", ImGuiTableColumnFlags_NoHide);
 | 
				
			||||||
                ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed, 25);
 | 
					                ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed, 25);
 | 
				
			||||||
@@ -462,8 +465,12 @@ void TileSheetEditorImGui::drawPaletteMenu() noexcept {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// header
 | 
						// header
 | 
				
			||||||
 | 
						auto constexpr palTblFlags =
 | 
				
			||||||
 | 
							ImGuiTableFlags_RowBg |
 | 
				
			||||||
 | 
					        ImGuiTableFlags_SizingStretchProp |
 | 
				
			||||||
 | 
					        ImGuiTableFlags_ScrollY;
 | 
				
			||||||
	if (ImGui::BeginTable(
 | 
						if (ImGui::BeginTable(
 | 
				
			||||||
			"PaletteTable", 4, ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp)) {
 | 
								"PaletteTable", 4, palTblFlags)) {
 | 
				
			||||||
		ImGui::TableSetupColumn("Idx", 0, 0.6f);
 | 
							ImGui::TableSetupColumn("Idx", 0, 0.6f);
 | 
				
			||||||
		ImGui::TableSetupColumn("", 0, 0.22f);
 | 
							ImGui::TableSetupColumn("", 0, 0.22f);
 | 
				
			||||||
		ImGui::TableSetupColumn("Name", 0, 3);
 | 
							ImGui::TableSetupColumn("Name", 0, 3);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,10 +66,10 @@ static ox::Optional<size_t> getPixelIdx(
 | 
				
			|||||||
	return ox::Optional<size_t>{};
 | 
						return ox::Optional<size_t>{};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t getTileIdx(TileSheet const&ts, SubSheetId const id) noexcept {
 | 
					ox::Optional<size_t> getTileIdx(TileSheet const&ts, SubSheetId const id) noexcept {
 | 
				
			||||||
	size_t idx{};
 | 
						size_t idx{};
 | 
				
			||||||
	auto const out = getPixelIdx(ts.subsheet, id, idx, ts.bpp);
 | 
						auto const out = getPixelIdx(ts.subsheet, id, idx, ts.bpp);
 | 
				
			||||||
	return out.or_value(0) / PixelsPerTile;
 | 
						return out ? ox::Optional<size_t>{ox::in_place, *out / PixelsPerTile} : out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept {
 | 
					uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept {
 | 
				
			||||||
@@ -355,12 +355,12 @@ ox::Result<SubSheetId> getIdFor(TileSheet const&ts, ox::StringViewCR path) noexc
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Gets the offset in tiles of the desired subsheet.
 | 
					 * Gets the offset in tiles of the desired subsheet.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static ox::Result<unsigned> getTileOffset(
 | 
					static ox::Result<uint32_t> getTileOffset(
 | 
				
			||||||
		TileSheet::SubSheet const&ss,
 | 
							TileSheet::SubSheet const&ss,
 | 
				
			||||||
		ox::SpanView<ox::StringView> const&pNamePath,
 | 
							ox::SpanView<ox::StringView> const&pNamePath,
 | 
				
			||||||
		int8_t pBpp,
 | 
							int8_t pBpp,
 | 
				
			||||||
		std::size_t pIt = 0,
 | 
							std::size_t pIt = 0,
 | 
				
			||||||
		unsigned pCurrentTotal = 0) noexcept {
 | 
							uint32_t pCurrentTotal = 0) noexcept {
 | 
				
			||||||
	// pIt == pNamePath.size() - 1 &&
 | 
						// pIt == pNamePath.size() - 1 &&
 | 
				
			||||||
	if (ss.name != pNamePath[pIt]) {
 | 
						if (ss.name != pNamePath[pIt]) {
 | 
				
			||||||
		return ox::Error(2, "Wrong branch");
 | 
							return ox::Error(2, "Wrong branch");
 | 
				
			||||||
@@ -374,12 +374,14 @@ static ox::Result<unsigned> getTileOffset(
 | 
				
			|||||||
		if (!err) {
 | 
							if (!err) {
 | 
				
			||||||
			return offset;
 | 
								return offset;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							// Possible bug? Shoud this be usinga a recursive version of
 | 
				
			||||||
 | 
							// pixelCnt will count pixels in subsheets of sub as well.
 | 
				
			||||||
		pCurrentTotal += pixelCnt(sub, pBpp) / PixelsPerTile;
 | 
							pCurrentTotal += pixelCnt(sub, pBpp) / PixelsPerTile;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return ox::Error(1, "SubSheet not found");
 | 
						return ox::Error(1, "SubSheet not found");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ox::Result<unsigned> getTileOffset(TileSheet const&ts, ox::StringViewCR pNamePath) noexcept {
 | 
					ox::Result<uint32_t> getTileOffset(TileSheet const&ts, ox::StringViewCR pNamePath) noexcept {
 | 
				
			||||||
	return core::getTileOffset(ts.subsheet, ox::split<8>(pNamePath, '.'), ts.bpp);
 | 
						return core::getTileOffset(ts.subsheet, ox::split<8>(pNamePath, '.'), ts.bpp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@ target_link_libraries(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
target_compile_definitions(
 | 
					target_compile_definitions(
 | 
				
			||||||
	NostalgiaStudio PUBLIC
 | 
						NostalgiaStudio PUBLIC
 | 
				
			||||||
		OLYMPIC_APP_VERSION="d2024.12.3"
 | 
							OLYMPIC_APP_VERSION="dev build"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
install(
 | 
					install(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -196,15 +196,15 @@ class AssetManager {
 | 
				
			|||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		class AssetTypeManager: public AssetTypeManagerBase {
 | 
							class AssetTypeManager: public AssetTypeManagerBase {
 | 
				
			||||||
			public:
 | 
								public:
 | 
				
			||||||
				using Loader = std::function<ox::Result<T>(ox::StringView assetId)>;
 | 
									using Loader = std::function<ox::Result<T>(ox::StringViewCR assetId)>;
 | 
				
			||||||
			private:
 | 
								private:
 | 
				
			||||||
				Loader m_loader{};
 | 
									Loader m_loader{};
 | 
				
			||||||
				ox::HashMap<ox::String, ox::UPtr<AssetContainer<T>>> m_cache;
 | 
									ox::HashMap<ox::String, ox::UPtr<AssetContainer<T>>> m_cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			public:
 | 
								public:
 | 
				
			||||||
				AssetTypeManager(Loader loader) noexcept: m_loader(loader) {}
 | 
									AssetTypeManager(Loader &&loader) noexcept: m_loader(std::move(loader)) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				ox::Result<AssetRef<T>> getAsset(ox::StringView const assetId) const noexcept {
 | 
									ox::Result<AssetRef<T>> getAsset(ox::StringViewCR assetId) const noexcept {
 | 
				
			||||||
					OX_REQUIRE(out, m_cache.at(assetId));
 | 
										OX_REQUIRE(out, m_cache.at(assetId));
 | 
				
			||||||
					if (!out || !*out) {
 | 
										if (!out || !*out) {
 | 
				
			||||||
						return ox::Error(1, "asset is null");
 | 
											return ox::Error(1, "asset is null");
 | 
				
			||||||
@@ -212,7 +212,7 @@ class AssetManager {
 | 
				
			|||||||
					return AssetRef<T>(out->get());
 | 
										return AssetRef<T>(out->get());
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				ox::Result<AssetRef<T>> loadAsset(ox::StringView const assetId) noexcept {
 | 
									ox::Result<AssetRef<T>> loadAsset(ox::StringViewCR assetId) noexcept {
 | 
				
			||||||
					auto &p = m_cache[assetId];
 | 
										auto &p = m_cache[assetId];
 | 
				
			||||||
					OX_REQUIRE_M(obj, m_loader(assetId));
 | 
										OX_REQUIRE_M(obj, m_loader(assetId));
 | 
				
			||||||
					if (!p) {
 | 
										if (!p) {
 | 
				
			||||||
@@ -224,7 +224,7 @@ class AssetManager {
 | 
				
			|||||||
					return AssetRef<T>(p.get());
 | 
										return AssetRef<T>(p.get());
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				ox::Error reloadAsset(ox::StringView const assetId) noexcept {
 | 
									ox::Error reloadAsset(ox::StringViewCR assetId) noexcept {
 | 
				
			||||||
					auto &p = m_cache[assetId];
 | 
										auto &p = m_cache[assetId];
 | 
				
			||||||
					OX_REQUIRE_M(obj, m_loader(assetId));
 | 
										OX_REQUIRE_M(obj, m_loader(assetId));
 | 
				
			||||||
					if (!p) {
 | 
										if (!p) {
 | 
				
			||||||
@@ -247,7 +247,7 @@ class AssetManager {
 | 
				
			|||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ox::HashMap<ox::String, ox::UPtr<AssetTypeManagerBase>> m_assetTypeManagers;
 | 
							ox::HashMap<ox::String, ox::UPtr<AssetTypeManagerBase>> m_assetTypeManagers;
 | 
				
			||||||
		ox::HashMap<ox::String, ox::Signal<ox::Error(ox::StringView assetId)>> m_fileUpdated;
 | 
							ox::HashMap<ox::String, ox::Signal<ox::Error(ox::StringViewCR assetId)>> m_fileUpdated;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		ox::Result<AssetTypeManager<T>*> getTypeManager() noexcept {
 | 
							ox::Result<AssetTypeManager<T>*> getTypeManager() noexcept {
 | 
				
			||||||
@@ -273,18 +273,18 @@ class AssetManager {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		ox::Result<AssetRef<T>> getAsset(ox::StringView assetId) noexcept {
 | 
							ox::Result<AssetRef<T>> getAsset(ox::StringViewCR assetId) noexcept {
 | 
				
			||||||
			OX_REQUIRE(m, getTypeManager<T>());
 | 
								OX_REQUIRE(m, getTypeManager<T>());
 | 
				
			||||||
			return m->getAsset(assetId);
 | 
								return m->getAsset(assetId);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ox::Error reloadAsset(ox::StringView assetId) noexcept {
 | 
							ox::Error reloadAsset(ox::StringViewCR assetId) noexcept {
 | 
				
			||||||
			m_fileUpdated[assetId].emit(assetId);
 | 
								m_fileUpdated[assetId].emit(assetId);
 | 
				
			||||||
			return {};
 | 
								return {};
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		ox::Result<AssetRef<T>> loadAsset(ox::StringView assetId) noexcept {
 | 
							ox::Result<AssetRef<T>> loadAsset(ox::StringViewCR assetId) noexcept {
 | 
				
			||||||
			OX_REQUIRE(m, getTypeManager<T>());
 | 
								OX_REQUIRE(m, getTypeManager<T>());
 | 
				
			||||||
			OX_REQUIRE(out, m->loadAsset(assetId));
 | 
								OX_REQUIRE(out, m->loadAsset(assetId));
 | 
				
			||||||
			m_fileUpdated[assetId].connect(m, &AssetTypeManager<T>::reloadAsset);
 | 
								m_fileUpdated[assetId].connect(m, &AssetTypeManager<T>::reloadAsset);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@
 | 
				
			|||||||
namespace keel {
 | 
					namespace keel {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Context;
 | 
					class Context;
 | 
				
			||||||
using PackTransform = ox::Result<bool>(*)(Context&, ox::Buffer &clawData, ox::StringView);
 | 
					using PackTransform = ox::Result<bool>(*)(Context&, ox::Buffer &clawData, ox::StringViewCR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Context {
 | 
					class Context {
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -70,7 +70,7 @@ constexpr auto makeLoader(Context &ctx) {
 | 
				
			|||||||
			if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
 | 
								if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
 | 
				
			||||||
				return err;
 | 
									return err;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			OX_RETURN_ERROR(convert<T>(ctx, buff, &obj));
 | 
								OX_RETURN_ERROR(convert<T>(ctx, buff, obj));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return std::move(obj);
 | 
							return std::move(obj);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -125,7 +125,9 @@ 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));
 | 
				
			||||||
		oxOutf("preloaded {} as a {} @ {} to {}\n", path, obj.type()->typeName, a, a + 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 {
 | 
						} else {
 | 
				
			||||||
		// strip the Claw header (it is not needed after preloading) and write back out to dest fs
 | 
							// strip the Claw header (it is not needed after preloading) and write back out to dest fs
 | 
				
			||||||
		OX_RETURN_ERROR(ox::writeMC(obj).moveTo(buff));
 | 
							OX_RETURN_ERROR(ox::writeMC(obj).moveTo(buff));
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,10 +16,50 @@ namespace keel {
 | 
				
			|||||||
class Wrap {
 | 
					class Wrap {
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		virtual ~Wrap() = default;
 | 
							virtual ~Wrap() = default;
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							virtual ox::CStringView typeName() const noexcept = 0;
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							virtual int typeVersion() const noexcept = 0;
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							virtual ox::UAnyPtr moveToCopy() noexcept = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
class WrapInline: public Wrap {
 | 
					class WrapT: public Wrap {
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							virtual constexpr T &obj() noexcept = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ox::UAnyPtr moveToCopy() noexcept final {
 | 
				
			||||||
 | 
								return new T{std::move(obj())};
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					class WrapRef final: public WrapT<T> {
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							T &m_obj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							constexpr explicit WrapRef(T &obj): m_obj{obj} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ox::CStringView typeName() const noexcept override {
 | 
				
			||||||
 | 
								return ox::ModelTypeName_v<T>;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int typeVersion() const noexcept override {
 | 
				
			||||||
 | 
								return ox::ModelTypeVersion_v<T>;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							constexpr T &obj() noexcept override {
 | 
				
			||||||
 | 
								return m_obj;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					class WrapInline final: public WrapT<T> {
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		T m_obj;
 | 
							T m_obj;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,8 +70,15 @@ class WrapInline: public Wrap {
 | 
				
			|||||||
		constexpr explicit WrapInline(Args &&...args): m_obj(ox::forward<Args>(args)...) {
 | 
							constexpr explicit WrapInline(Args &&...args): m_obj(ox::forward<Args>(args)...) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		[[nodiscard]]
 | 
							ox::CStringView typeName() const noexcept override {
 | 
				
			||||||
		constexpr T &obj() noexcept {
 | 
								return ox::ModelTypeName_v<T>;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int typeVersion() const noexcept override {
 | 
				
			||||||
 | 
								return ox::ModelTypeVersion_v<T>;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							constexpr T &obj() noexcept override {
 | 
				
			||||||
			return m_obj;
 | 
								return m_obj;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -44,7 +91,7 @@ constexpr ox::UPtr<Wrap> makeWrap(Args &&...args) noexcept {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
constexpr T &wrapCast(Wrap &ptr) noexcept {
 | 
					constexpr T &wrapCast(Wrap &ptr) noexcept {
 | 
				
			||||||
	return static_cast<WrapInline<T>&>(ptr).obj();
 | 
						return static_cast<WrapT<T>&>(ptr).obj();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BaseConverter {
 | 
					class BaseConverter {
 | 
				
			||||||
@@ -70,8 +117,8 @@ class BaseConverter {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		[[nodiscard]]
 | 
							[[nodiscard]]
 | 
				
			||||||
		constexpr bool matches(
 | 
							constexpr bool matches(
 | 
				
			||||||
				ox::StringViewCR srcTypeName, int srcTypeVersion,
 | 
									ox::StringViewCR srcTypeName, int const srcTypeVersion,
 | 
				
			||||||
				ox::StringViewCR dstTypeName, int dstTypeVersion) const noexcept {
 | 
									ox::StringViewCR dstTypeName, int const dstTypeVersion) const noexcept {
 | 
				
			||||||
			return srcMatches(srcTypeName, srcTypeVersion)
 | 
								return srcMatches(srcTypeName, srcTypeVersion)
 | 
				
			||||||
			    && dstMatches(dstTypeName, dstTypeVersion);
 | 
								    && dstMatches(dstTypeName, dstTypeVersion);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -109,17 +156,17 @@ class Converter: public BaseConverter {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		ox::Result<ox::UPtr<Wrap>> convertPtrToPtr(
 | 
							ox::Result<ox::UPtr<Wrap>> convertPtrToPtr(
 | 
				
			||||||
				keel::Context &ctx, Wrap &src) const noexcept final {
 | 
									keel::Context &ctx, Wrap &src) const noexcept final {
 | 
				
			||||||
			auto dst = makeWrap<DstType>();
 | 
								ox::Result<ox::UPtr<Wrap>> dst{makeWrap<DstType>()};
 | 
				
			||||||
			OX_RETURN_ERROR(convert(ctx, wrapCast<SrcType>(src), wrapCast<DstType>(*dst)));
 | 
								OX_RETURN_ERROR(convert(ctx, wrapCast<SrcType>(src), wrapCast<DstType>(*dst.value)));
 | 
				
			||||||
			return {std::move(dst)};
 | 
								return dst;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ox::Result<ox::UPtr<Wrap>> convertBuffToPtr(
 | 
							ox::Result<ox::UPtr<Wrap>> convertBuffToPtr(
 | 
				
			||||||
				keel::Context &ctx, ox::BufferView const&srcBuff) const noexcept final {
 | 
									keel::Context &ctx, ox::BufferView const&srcBuff) const noexcept final {
 | 
				
			||||||
			OX_REQUIRE_M(src, readAsset<SrcType>(srcBuff));
 | 
								OX_REQUIRE_M(src, readAsset<SrcType>(srcBuff));
 | 
				
			||||||
			auto dst = makeWrap<DstType>();
 | 
								ox::Result<ox::UPtr<Wrap>> dst{makeWrap<DstType>()};
 | 
				
			||||||
			OX_RETURN_ERROR(convert(ctx, src, wrapCast<DstType>(*dst)));
 | 
								OX_RETURN_ERROR(convert(ctx, src, wrapCast<DstType>(*dst.value)));
 | 
				
			||||||
			return {std::move(dst)};
 | 
								return dst;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected:
 | 
						protected:
 | 
				
			||||||
@@ -133,34 +180,68 @@ ox::Result<ox::UPtr<Wrap>> convert(
 | 
				
			|||||||
		ox::StringViewCR dstTypeName,
 | 
							ox::StringViewCR dstTypeName,
 | 
				
			||||||
		int dstTypeVersion) noexcept;
 | 
							int dstTypeVersion) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ox::Result<ox::UPtr<Wrap>> convert(
 | 
				
			||||||
 | 
							keel::Context &ctx,
 | 
				
			||||||
 | 
							Wrap &src,
 | 
				
			||||||
 | 
							ox::StringViewCR dstTypeName,
 | 
				
			||||||
 | 
							int dstTypeVersion) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ox::Result<ox::UPtr<Wrap>> convert(
 | 
				
			||||||
 | 
							keel::Context &ctx,
 | 
				
			||||||
 | 
							auto &src,
 | 
				
			||||||
 | 
							ox::StringViewCR dstTypeName,
 | 
				
			||||||
 | 
							int const dstTypeVersion) noexcept {
 | 
				
			||||||
 | 
						WrapRef ref{src};
 | 
				
			||||||
 | 
						return convert(ctx, static_cast<Wrap&>(ref), dstTypeName, dstTypeVersion);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ox::Result<ox::UPtr<Wrap>> convert(
 | 
				
			||||||
 | 
							keel::Context &ctx,
 | 
				
			||||||
 | 
							auto const&src,
 | 
				
			||||||
 | 
							ox::StringViewCR dstTypeName,
 | 
				
			||||||
 | 
							int const dstTypeVersion) noexcept {
 | 
				
			||||||
 | 
						auto srcCpy = src;
 | 
				
			||||||
 | 
						WrapRef ref{srcCpy};
 | 
				
			||||||
 | 
						return convert(ctx, ref, dstTypeName, dstTypeVersion);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename DstType>
 | 
					template<typename DstType>
 | 
				
			||||||
ox::Result<DstType> convert(keel::Context &ctx, ox::BufferView const&srcBuffer) noexcept {
 | 
					ox::Result<DstType> convertObjToObj(
 | 
				
			||||||
	static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
 | 
							keel::Context &ctx,
 | 
				
			||||||
	static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
 | 
							auto &src) noexcept {
 | 
				
			||||||
	OX_REQUIRE(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion));
 | 
						OX_REQUIRE_M(out, convert(ctx, WrapRef{src}, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
 | 
				
			||||||
 | 
						return std::move(wrapCast(*out));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename DstType>
 | 
				
			||||||
 | 
					ox::Result<DstType> convert(keel::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));
 | 
						return std::move(wrapCast<DstType>(out));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename DstType>
 | 
					template<typename DstType>
 | 
				
			||||||
ox::Error convert(keel::Context &ctx, ox::BufferView const&buff, DstType *outObj) noexcept {
 | 
					ox::Error convert(keel::Context &ctx, ox::BufferView const&buff, DstType &outObj) noexcept {
 | 
				
			||||||
	static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
 | 
						OX_REQUIRE(out, convert(ctx, buff, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
 | 
				
			||||||
	static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
 | 
						outObj = std::move(wrapCast<DstType>(*out));
 | 
				
			||||||
	OX_REQUIRE(outPtr, convert(ctx, buff, DstTypeName, DstTypeVersion));
 | 
						return {};
 | 
				
			||||||
	*outObj = std::move(wrapCast<DstType>(*outPtr));
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename DstType>
 | 
				
			||||||
 | 
					ox::Error convertObjToObj(keel::Context &ctx, auto &src, DstType &outObj) noexcept {
 | 
				
			||||||
 | 
						OX_REQUIRE(outPtr, convert(ctx, src, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
 | 
				
			||||||
 | 
						outObj = std::move(wrapCast<DstType>(*outPtr));
 | 
				
			||||||
	return {};
 | 
						return {};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename DstType>
 | 
					template<typename DstType>
 | 
				
			||||||
ox::Result<ox::Buffer> convertBuffToBuff(
 | 
					ox::Result<ox::Buffer> convertBuffToBuff(
 | 
				
			||||||
		keel::Context &ctx, ox::BufferView const&srcBuffer, ox::ClawFormat fmt) noexcept {
 | 
							keel::Context &ctx, ox::BufferView const&src, ox::ClawFormat const fmt) noexcept {
 | 
				
			||||||
	static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
 | 
						OX_REQUIRE(out, convert(ctx, src, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
 | 
				
			||||||
	static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
 | 
					 | 
				
			||||||
	OX_REQUIRE(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion));
 | 
					 | 
				
			||||||
	return ox::writeClaw<DstType>(wrapCast<DstType>(*out), fmt);
 | 
						return ox::writeClaw<DstType>(wrapCast<DstType>(*out), fmt);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename From, typename To, ox::ClawFormat fmt = ox::ClawFormat::Metal>
 | 
					template<typename From, typename To, ox::ClawFormat fmt = ox::ClawFormat::Metal>
 | 
				
			||||||
ox::Result<bool> transformRule(keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) noexcept {
 | 
					ox::Result<bool> transformRule(keel::Context &ctx, ox::Buffer &buff, ox::StringViewCR typeId) noexcept {
 | 
				
			||||||
	if (typeId == ox::ModelTypeId_v<From>) {
 | 
						if (typeId == ox::ModelTypeId_v<From>) {
 | 
				
			||||||
		OX_RETURN_ERROR(keel::convertBuffToBuff<To>(ctx, buff, fmt).moveTo(buff));
 | 
							OX_RETURN_ERROR(keel::convertBuffToBuff<To>(ctx, buff, fmt).moveTo(buff));
 | 
				
			||||||
		return true;
 | 
							return true;
 | 
				
			||||||
@@ -168,5 +249,4 @@ ox::Result<bool> transformRule(keel::Context &ctx, ox::Buffer &buff, ox::StringV
 | 
				
			|||||||
	return false;
 | 
						return false;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,30 +10,38 @@ namespace keel {
 | 
				
			|||||||
static ox::Result<BaseConverter const*> findConverter(
 | 
					static ox::Result<BaseConverter const*> findConverter(
 | 
				
			||||||
		ox::SpanView<BaseConverter const*> const&converters,
 | 
							ox::SpanView<BaseConverter const*> const&converters,
 | 
				
			||||||
		ox::StringViewCR srcTypeName,
 | 
							ox::StringViewCR srcTypeName,
 | 
				
			||||||
		int srcTypeVersion,
 | 
							int const srcTypeVersion,
 | 
				
			||||||
		ox::StringViewCR dstTypeName,
 | 
							ox::StringViewCR dstTypeName,
 | 
				
			||||||
		int dstTypeVersion) noexcept {
 | 
							int const dstTypeVersion) noexcept {
 | 
				
			||||||
	for (auto const&c : converters) {
 | 
						for (auto const&c : converters) {
 | 
				
			||||||
		if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
 | 
							if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
 | 
				
			||||||
			return c;
 | 
								return c;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	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 {
 | 
				
			||||||
 | 
						return c.convertBuffToPtr(ctx, src);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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(
 | 
					static ox::Result<ox::UPtr<Wrap>> convert(
 | 
				
			||||||
		keel::Context &ctx,
 | 
							Context &ctx,
 | 
				
			||||||
		ox::SpanView<BaseConverter const*> const&converters,
 | 
							ox::SpanView<BaseConverter const*> const&converters,
 | 
				
			||||||
		ox::BufferView const&srcBuffer,
 | 
							auto &src,
 | 
				
			||||||
		ox::StringViewCR srcTypeName,
 | 
							ox::StringViewCR srcTypeName,
 | 
				
			||||||
		int srcTypeVersion,
 | 
							int const srcTypeVersion,
 | 
				
			||||||
		ox::StringViewCR dstTypeName,
 | 
							ox::StringViewCR dstTypeName,
 | 
				
			||||||
		int dstTypeVersion) noexcept {
 | 
							int const dstTypeVersion) noexcept {
 | 
				
			||||||
	// look for direct converter
 | 
						// look for direct converter
 | 
				
			||||||
	auto [c, err] = findConverter(
 | 
						auto const [c, err] = findConverter(
 | 
				
			||||||
			converters, srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion);
 | 
								converters, srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion);
 | 
				
			||||||
	if (!err) {
 | 
						if (!err) {
 | 
				
			||||||
		return c->convertBuffToPtr(ctx, srcBuffer);
 | 
							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) {
 | 
				
			||||||
@@ -41,20 +49,20 @@ static ox::Result<ox::UPtr<Wrap>> convert(
 | 
				
			|||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		const auto [intermediate, chainErr] =
 | 
							const auto [intermediate, chainErr] =
 | 
				
			||||||
			convert(ctx, converters, srcBuffer, srcTypeName, srcTypeVersion,
 | 
								convert(ctx, converters, src, srcTypeName, srcTypeVersion,
 | 
				
			||||||
			        subConverter->srcTypeName(), subConverter->srcTypeVersion());
 | 
								        subConverter->srcTypeName(), subConverter->srcTypeVersion());
 | 
				
			||||||
		if (!chainErr) {
 | 
							if (!chainErr) {
 | 
				
			||||||
			return subConverter->convertPtrToPtr(ctx, *intermediate);
 | 
								return subConverter->convertPtrToPtr(ctx, *intermediate);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return ox::Error(1, "Could not convert between types");
 | 
						return ox::Error{1, "Could not convert between types"};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ox::Result<ox::UPtr<Wrap>> convert(
 | 
					ox::Result<ox::UPtr<Wrap>> convert(
 | 
				
			||||||
		keel::Context &ctx,
 | 
							Context &ctx,
 | 
				
			||||||
		ox::BufferView const&srcBuffer,
 | 
							ox::BufferView const&srcBuffer,
 | 
				
			||||||
		ox::StringViewCR dstTypeName,
 | 
							ox::StringViewCR dstTypeName,
 | 
				
			||||||
		int dstTypeVersion) noexcept {
 | 
							int const dstTypeVersion) noexcept {
 | 
				
			||||||
	OX_REQUIRE(hdr, readAssetHeader(srcBuffer));
 | 
						OX_REQUIRE(hdr, readAssetHeader(srcBuffer));
 | 
				
			||||||
	return convert(
 | 
						return convert(
 | 
				
			||||||
			ctx,
 | 
								ctx,
 | 
				
			||||||
@@ -66,4 +74,19 @@ ox::Result<ox::UPtr<Wrap>> convert(
 | 
				
			|||||||
			dstTypeVersion);
 | 
								dstTypeVersion);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ox::Result<ox::UPtr<Wrap>> convert(
 | 
				
			||||||
 | 
							Context &ctx,
 | 
				
			||||||
 | 
							Wrap &src,
 | 
				
			||||||
 | 
							ox::StringViewCR dstTypeName,
 | 
				
			||||||
 | 
							int const dstTypeVersion) noexcept {
 | 
				
			||||||
 | 
						return convert(
 | 
				
			||||||
 | 
								ctx,
 | 
				
			||||||
 | 
								converters(ctx),
 | 
				
			||||||
 | 
								src,
 | 
				
			||||||
 | 
								src.typeName(),
 | 
				
			||||||
 | 
								src.typeVersion(),
 | 
				
			||||||
 | 
								dstTypeName,
 | 
				
			||||||
 | 
								dstTypeVersion);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,7 +14,7 @@ namespace studio {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
NewMenu::NewMenu() noexcept {
 | 
					NewMenu::NewMenu() noexcept {
 | 
				
			||||||
	setTitle("New Item");
 | 
						setTitle("New Item");
 | 
				
			||||||
	setSize({230, 140});
 | 
						setSize({280, 180});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::open() noexcept {
 | 
					void NewMenu::open() noexcept {
 | 
				
			||||||
@@ -33,7 +33,7 @@ bool NewMenu::isOpen() const noexcept {
 | 
				
			|||||||
	return m_open;
 | 
						return m_open;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::draw(studio::StudioContext &sctx) noexcept {
 | 
					void NewMenu::draw(StudioContext &sctx) noexcept {
 | 
				
			||||||
	switch (m_stage) {
 | 
						switch (m_stage) {
 | 
				
			||||||
		case Stage::Opening:
 | 
							case Stage::Opening:
 | 
				
			||||||
			ImGui::OpenPopup(title().c_str());
 | 
								ImGui::OpenPopup(title().c_str());
 | 
				
			||||||
@@ -46,51 +46,73 @@ void NewMenu::draw(studio::StudioContext &sctx) noexcept {
 | 
				
			|||||||
		case Stage::NewItemName:
 | 
							case Stage::NewItemName:
 | 
				
			||||||
			drawNewItemName(sctx);
 | 
								drawNewItemName(sctx);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							case Stage::NewItemTemplate:
 | 
				
			||||||
 | 
								drawNewItemTemplate(sctx);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		case Stage::Closed:
 | 
							case Stage::Closed:
 | 
				
			||||||
			m_open = false;
 | 
								m_open = false;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::addItemMaker(ox::UniquePtr<studio::ItemMaker> &&im) noexcept {
 | 
					void NewMenu::addItemMaker(ox::UPtr<ItemMaker> &&im) noexcept {
 | 
				
			||||||
	m_types.emplace_back(std::move(im));
 | 
						m_types.emplace_back(std::move(im));
 | 
				
			||||||
	std::sort(
 | 
						std::sort(
 | 
				
			||||||
			m_types.begin(), m_types.end(),
 | 
								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->typeName < im2->typeName;
 | 
									 return im1->typeDisplayName() < im2->typeDisplayName();
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::drawNewItemType(studio::StudioContext &sctx) noexcept {
 | 
					void NewMenu::installItemTemplate(ox::UPtr<ItemTemplate> &tmplt) noexcept {
 | 
				
			||||||
	drawWindow(sctx.tctx, &m_open, [this] {
 | 
						for (auto const&im : m_types) {
 | 
				
			||||||
		auto const allocSz = m_types.size() * sizeof(char const*);
 | 
							if (im->installTemplate(tmplt)) {
 | 
				
			||||||
		auto mem = ox_malloca(allocSz, char const*, nullptr);
 | 
								break;
 | 
				
			||||||
		auto items = ox::Span{mem.get(), allocSz};
 | 
					 | 
				
			||||||
		for (auto i = 0u; auto const&im : m_types) {
 | 
					 | 
				
			||||||
			items[i] = im->typeName.c_str();
 | 
					 | 
				
			||||||
			++i;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ImGui::ListBox("Item Type", &m_selectedType, items.data(), static_cast<int>(m_types.size()));
 | 
						}
 | 
				
			||||||
		drawFirstPageButtons();
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void NewMenu::drawNewItemType(StudioContext const&sctx) noexcept {
 | 
				
			||||||
 | 
						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];
 | 
				
			||||||
 | 
							drawFirstPageButtons(im.itemTemplates().size() == 1 ?
 | 
				
			||||||
 | 
								Stage::NewItemName : Stage::NewItemTemplate);
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::drawNewItemName(studio::StudioContext &sctx) noexcept {
 | 
					void NewMenu::drawNewItemTemplate(StudioContext &sctx) noexcept {
 | 
				
			||||||
	drawWindow(sctx.tctx, &m_open, [this, &sctx] {
 | 
						drawWindow(sctx.tctx, m_open, [this] {
 | 
				
			||||||
		auto const typeIdx = static_cast<std::size_t>(m_selectedType);
 | 
							auto const&templates =
 | 
				
			||||||
		if (typeIdx < m_types.size()) {
 | 
								m_types[m_selectedType]->itemTemplates();
 | 
				
			||||||
 | 
							ig::ListBox("Template", [&](size_t const i) -> ox::CStringView {
 | 
				
			||||||
 | 
								return templates[i]->name();
 | 
				
			||||||
 | 
							}, templates.size(), m_selectedTemplate, {200, 100});
 | 
				
			||||||
 | 
							drawButtons(Stage::NewItemType, Stage::NewItemName);
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void NewMenu::drawNewItemName(StudioContext &sctx) noexcept {
 | 
				
			||||||
 | 
						drawWindow(sctx.tctx, m_open, [this, &sctx] {
 | 
				
			||||||
 | 
							if (m_selectedType < m_types.size()) {
 | 
				
			||||||
			ig::InputText("Name", m_itemName);
 | 
								ig::InputText("Name", m_itemName);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		drawLastPageButtons(sctx);
 | 
							drawLastPageButtons(sctx);
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::drawFirstPageButtons() noexcept {
 | 
					void NewMenu::drawButtons(Stage const prev, Stage const next) noexcept {
 | 
				
			||||||
	ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 130);
 | 
						ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 198);
 | 
				
			||||||
	ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
 | 
						ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
 | 
				
			||||||
	auto const btnSz = ImVec2(60, 20);
 | 
						constexpr ImVec2 btnSz{60, 20};
 | 
				
			||||||
 | 
						if (ImGui::Button("Back", btnSz)) {
 | 
				
			||||||
 | 
							m_stage = prev;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ImGui::SameLine();
 | 
				
			||||||
	if (ImGui::Button("Next", btnSz)) {
 | 
						if (ImGui::Button("Next", btnSz)) {
 | 
				
			||||||
		m_stage = Stage::NewItemName;
 | 
							m_stage = next;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ImGui::SameLine();
 | 
						ImGui::SameLine();
 | 
				
			||||||
	if (ImGui::Button("Cancel", btnSz)) {
 | 
						if (ImGui::Button("Cancel", btnSz)) {
 | 
				
			||||||
@@ -99,34 +121,50 @@ void NewMenu::drawFirstPageButtons() noexcept {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::drawLastPageButtons(studio::StudioContext &sctx) noexcept {
 | 
					void NewMenu::drawFirstPageButtons(Stage const next) noexcept {
 | 
				
			||||||
	ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 138);
 | 
						ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 130);
 | 
				
			||||||
	ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
 | 
						ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
 | 
				
			||||||
	if (ImGui::Button("Back")) {
 | 
						constexpr ImVec2 btnSz{60, 20};
 | 
				
			||||||
		m_stage = Stage::NewItemType;
 | 
						if (ImGui::Button("Next", btnSz)) {
 | 
				
			||||||
 | 
							m_stage = next;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ImGui::SameLine();
 | 
						ImGui::SameLine();
 | 
				
			||||||
	if (ImGui::Button("Finish")) {
 | 
						if (ImGui::Button("Cancel", btnSz)) {
 | 
				
			||||||
		finish(sctx);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ImGui::SameLine();
 | 
					 | 
				
			||||||
	if (ImGui::Button("Quit")) {
 | 
					 | 
				
			||||||
		ImGui::CloseCurrentPopup();
 | 
							ImGui::CloseCurrentPopup();
 | 
				
			||||||
		m_stage = Stage::Closed;
 | 
							m_stage = Stage::Closed;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewMenu::finish(studio::StudioContext &sctx) noexcept {
 | 
					void NewMenu::drawLastPageButtons(StudioContext &sctx) noexcept {
 | 
				
			||||||
 | 
						ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 198);
 | 
				
			||||||
 | 
						ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetContentRegionAvail().y - 20);
 | 
				
			||||||
 | 
						constexpr ImVec2 btnSz{60, 20};
 | 
				
			||||||
 | 
						if (ImGui::Button("Back", btnSz)) {
 | 
				
			||||||
 | 
							m_stage = Stage::NewItemType;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ImGui::SameLine();
 | 
				
			||||||
 | 
						if (ImGui::Button("Finish", btnSz)) {
 | 
				
			||||||
 | 
							finish(sctx);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						ImGui::SameLine();
 | 
				
			||||||
 | 
						if (ImGui::Button("Quit", btnSz)) {
 | 
				
			||||||
 | 
							ImGui::CloseCurrentPopup();
 | 
				
			||||||
 | 
							m_stage = Stage::Closed;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void NewMenu::finish(StudioContext &sctx) noexcept {
 | 
				
			||||||
	if (m_itemName.len() == 0) {
 | 
						if (m_itemName.len() == 0) {
 | 
				
			||||||
		oxLogError(ox::Error(1, "New file error: no file name"));
 | 
							oxLogError(ox::Error{1, "New file error: no file name"});
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	auto const&typeMaker = *m_types[static_cast<std::size_t>(m_selectedType)];
 | 
						auto const&im = *m_types[static_cast<std::size_t>(m_selectedType)];
 | 
				
			||||||
	if (sctx.project->exists(typeMaker.itemPath(m_itemName))) {
 | 
						if (sctx.project->exists(im.itemPath(m_itemName))) {
 | 
				
			||||||
		oxLogError(ox::Error(1, "New file error: file already exists"));
 | 
							oxLogError(ox::Error{1, "New file error: file already exists"});
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	auto const [path, err] = typeMaker.write(sctx, m_itemName);
 | 
						auto const [path, err] =
 | 
				
			||||||
 | 
							im.write(sctx, m_itemName, m_selectedTemplate);
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
		oxLogError(err);
 | 
							oxLogError(err);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,13 +13,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace studio {
 | 
					namespace studio {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NewMenu: public studio::Popup {
 | 
					class NewMenu final: public Popup {
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		enum class Stage {
 | 
							enum class Stage {
 | 
				
			||||||
			Closed,
 | 
								Closed,
 | 
				
			||||||
			Opening,
 | 
								Opening,
 | 
				
			||||||
			NewItemType,
 | 
								NewItemType,
 | 
				
			||||||
			NewItemName,
 | 
								NewItemName,
 | 
				
			||||||
 | 
								NewItemTemplate,
 | 
				
			||||||
		};
 | 
							};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// emits path parameter
 | 
							// emits path parameter
 | 
				
			||||||
@@ -29,8 +30,9 @@ class NewMenu: public studio::Popup {
 | 
				
			|||||||
		Stage m_stage = Stage::Closed;
 | 
							Stage m_stage = Stage::Closed;
 | 
				
			||||||
		ox::String m_typeName;
 | 
							ox::String m_typeName;
 | 
				
			||||||
		ox::IString<255> m_itemName;
 | 
							ox::IString<255> m_itemName;
 | 
				
			||||||
		ox::Vector<ox::UniquePtr<studio::ItemMaker>> m_types;
 | 
							ox::Vector<ox::UPtr<studio::ItemMaker>> m_types;
 | 
				
			||||||
		int m_selectedType = 0;
 | 
							size_t m_selectedType = 0;
 | 
				
			||||||
 | 
							size_t m_selectedTemplate = 0;
 | 
				
			||||||
		bool m_open = false;
 | 
							bool m_open = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
@@ -43,37 +45,70 @@ class NewMenu: public studio::Popup {
 | 
				
			|||||||
		[[nodiscard]]
 | 
							[[nodiscard]]
 | 
				
			||||||
		bool isOpen() const noexcept override;
 | 
							bool isOpen() const noexcept override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void draw(studio::StudioContext &sctx) noexcept override;
 | 
							void draw(StudioContext &sctx) noexcept override;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		void addItemType(ox::String name, ox::String parentDir, ox::String fileExt, T itemTempl, ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept;
 | 
							void addItemType(
 | 
				
			||||||
 | 
								ox::StringParam displayName,
 | 
				
			||||||
 | 
								ox::StringParam parentDir,
 | 
				
			||||||
 | 
								ox::StringParam fileExt,
 | 
				
			||||||
 | 
								T itemTempl,
 | 
				
			||||||
 | 
								ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		template<typename T>
 | 
							template<typename T>
 | 
				
			||||||
		void addItemType(ox::String name, ox::String parentDir, ox::String fileExt, ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept;
 | 
							void addItemType(
 | 
				
			||||||
 | 
								ox::StringParam displayName,
 | 
				
			||||||
 | 
								ox::StringParam parentDir,
 | 
				
			||||||
 | 
								ox::StringParam fileExt,
 | 
				
			||||||
 | 
								ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void addItemMaker(ox::UniquePtr<studio::ItemMaker> &&im) noexcept;
 | 
							void addItemMaker(ox::UPtr<ItemMaker> &&im) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void installItemTemplate(ox::UPtr<ItemTemplate> &tmplt) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		void drawNewItemType(studio::StudioContext &sctx) noexcept;
 | 
							void drawNewItemType(StudioContext const&sctx) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void drawNewItemName(studio::StudioContext &sctx) noexcept;
 | 
							void drawNewItemName(StudioContext &sctx) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void drawFirstPageButtons() noexcept;
 | 
							void drawNewItemTemplate(StudioContext &sctx) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void drawLastPageButtons(studio::StudioContext &sctx) noexcept;
 | 
							void drawButtons(Stage prev, Stage next) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void finish(studio::StudioContext &sctx) noexcept;
 | 
							void drawFirstPageButtons(Stage next) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void drawLastPageButtons(StudioContext &sctx) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							void finish(StudioContext &sctx) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
void NewMenu::addItemType(ox::String displayName, ox::String parentDir, ox::String fileExt, T itemTempl, ox::ClawFormat pFmt) noexcept {
 | 
					void NewMenu::addItemType(
 | 
				
			||||||
	m_types.emplace_back(ox::make<studio::ItemMakerT<T>>(std::move(displayName), std::move(parentDir), std::move(fileExt), std::move(itemTempl), pFmt));
 | 
						ox::StringParam displayName,
 | 
				
			||||||
 | 
						ox::StringParam parentDir,
 | 
				
			||||||
 | 
						ox::StringParam fileExt,
 | 
				
			||||||
 | 
						T itemTempl,
 | 
				
			||||||
 | 
						ox::ClawFormat const pFmt) noexcept {
 | 
				
			||||||
 | 
						m_types.emplace_back(ox::make<ItemMakerT<T>>(
 | 
				
			||||||
 | 
							std::move(displayName),
 | 
				
			||||||
 | 
							std::move(parentDir),
 | 
				
			||||||
 | 
							std::move(fileExt),
 | 
				
			||||||
 | 
							std::move(itemTempl),
 | 
				
			||||||
 | 
							pFmt));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
void NewMenu::addItemType(ox::String displayName, ox::String parentDir, ox::String fileExt, ox::ClawFormat pFmt) noexcept {
 | 
					void NewMenu::addItemType(
 | 
				
			||||||
	m_types.emplace_back(ox::make<studio::ItemMakerT<T>>(std::move(displayName), std::move(parentDir), std::move(fileExt), pFmt));
 | 
						ox::StringParam displayName,
 | 
				
			||||||
 | 
						ox::StringParam parentDir,
 | 
				
			||||||
 | 
						ox::StringParam fileExt,
 | 
				
			||||||
 | 
						ox::ClawFormat const pFmt) noexcept {
 | 
				
			||||||
 | 
						m_types.emplace_back(ox::make<ItemMakerT<T>>(
 | 
				
			||||||
 | 
							std::move(displayName),
 | 
				
			||||||
 | 
							std::move(parentDir),
 | 
				
			||||||
 | 
							std::move(fileExt),
 | 
				
			||||||
 | 
							pFmt));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,7 +49,7 @@ void NewProject::draw(studio::StudioContext &ctx) noexcept {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void NewProject::drawNewProjectName(studio::StudioContext &sctx) noexcept {
 | 
					void NewProject::drawNewProjectName(studio::StudioContext &sctx) noexcept {
 | 
				
			||||||
	drawWindow(sctx.tctx, &m_open, [this, &sctx] {
 | 
						drawWindow(sctx.tctx, m_open, [this, &sctx] {
 | 
				
			||||||
		ig::InputText("Name", m_projectName);
 | 
							ig::InputText("Name", m_projectName);
 | 
				
			||||||
		ImGui::Text("Path: %s", m_projectPath.c_str());
 | 
							ImGui::Text("Path: %s", m_projectPath.c_str());
 | 
				
			||||||
		if (ImGui::Button("Browse")) {
 | 
							if (ImGui::Button("Browse")) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,9 +18,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace studio {
 | 
					namespace studio {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ox::Vector<studio::Module const*> modules;
 | 
					static ox::Vector<Module const*> modules;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void registerModule(studio::Module const*mod) noexcept {
 | 
					void registerModule(Module const*mod) noexcept {
 | 
				
			||||||
	if (mod) {
 | 
						if (mod) {
 | 
				
			||||||
		modules.emplace_back(mod);
 | 
							modules.emplace_back(mod);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -45,25 +45,25 @@ OX_MODEL_END()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
StudioUI::StudioUI(turbine::Context &ctx, ox::StringParam projectDataDir) noexcept:
 | 
					StudioUI::StudioUI(turbine::Context &ctx, ox::StringParam projectDataDir) noexcept:
 | 
				
			||||||
		m_sctx(*this, ctx),
 | 
							m_sctx(*this, ctx),
 | 
				
			||||||
		m_ctx(ctx),
 | 
							m_tctx(ctx),
 | 
				
			||||||
		m_projectDataDir(std::move(projectDataDir)),
 | 
							m_projectDataDir(std::move(projectDataDir)),
 | 
				
			||||||
		m_projectExplorer(m_ctx),
 | 
							m_projectExplorer(m_tctx),
 | 
				
			||||||
		m_newProject(m_projectDataDir),
 | 
							m_newProject(m_projectDataDir),
 | 
				
			||||||
		m_aboutPopup(m_ctx) {
 | 
							m_aboutPopup(m_tctx) {
 | 
				
			||||||
	turbine::setApplicationData(m_ctx, &m_sctx);
 | 
						turbine::setApplicationData(m_tctx, &m_sctx);
 | 
				
			||||||
	m_projectExplorer.fileChosen.connect(this, &StudioUI::openFile);
 | 
						m_projectExplorer.fileChosen.connect(this, &StudioUI::openFile);
 | 
				
			||||||
	m_newProject.finished.connect(this, &StudioUI::createOpenProject);
 | 
						m_newProject.finished.connect(this, &StudioUI::createOpenProject);
 | 
				
			||||||
	m_newMenu.finished.connect(this, &StudioUI::openFile);
 | 
						m_newMenu.finished.connect(this, &StudioUI::openFile);
 | 
				
			||||||
	ImGui::GetIO().IniFilename = nullptr;
 | 
						ImGui::GetIO().IniFilename = nullptr;
 | 
				
			||||||
	loadModules();
 | 
						loadModules();
 | 
				
			||||||
	// open project and files
 | 
						// open project and files
 | 
				
			||||||
	auto const [config, err] = studio::readConfig<StudioConfig>(keelCtx(m_ctx));
 | 
						auto const [config, err] = studio::readConfig<StudioConfig>(keelCtx(m_tctx));
 | 
				
			||||||
	m_showProjectExplorer = config.showProjectExplorer;
 | 
						m_showProjectExplorer = config.showProjectExplorer;
 | 
				
			||||||
	if (!err) {
 | 
						if (!err) {
 | 
				
			||||||
		auto const openProjErr = openProjectPath(config.projectPath);
 | 
							auto const openProjErr = openProjectPath(config.projectPath);
 | 
				
			||||||
		if (!openProjErr) {
 | 
							if (!openProjErr) {
 | 
				
			||||||
			for (auto const&f: config.openFiles) {
 | 
								for (auto const&f: config.openFiles) {
 | 
				
			||||||
				auto openFileErr = openFileActiveTab(f, config.activeTabItemName == f);
 | 
									auto const openFileErr = openFileActiveTab(f, config.activeTabItemName == f);
 | 
				
			||||||
				if (openFileErr) {
 | 
									if (openFileErr) {
 | 
				
			||||||
					oxErrorf("\nCould not open editor for file:\n\t{}\nReason:\n\t{}\n", f, toStr(openFileErr));
 | 
										oxErrorf("\nCould not open editor for file:\n\t{}\nReason:\n\t{}\n", f, toStr(openFileErr));
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
@@ -77,13 +77,13 @@ StudioUI::StudioUI(turbine::Context &ctx, ox::StringParam projectDataDir) noexce
 | 
				
			|||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			oxErrf(
 | 
								oxErrf(
 | 
				
			||||||
					"Could not open studio config file: {}: {} ({}:{})\n",
 | 
										"Could not open studio config file: {}: {} ({}:{})\n",
 | 
				
			||||||
					err.errCode, toStr(err), err.file, err.line);
 | 
										err.errCode, toStr(err), err.src.file_name(), err.src.line());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void StudioUI::handleKeyEvent(turbine::Key key, bool down) noexcept {
 | 
					void StudioUI::handleKeyEvent(turbine::Key const key, bool const down) noexcept {
 | 
				
			||||||
	for (auto p : m_popups) {
 | 
						for (auto const p : m_popups) {
 | 
				
			||||||
		if (p->isOpen()) {
 | 
							if (p->isOpen()) {
 | 
				
			||||||
			if (key == turbine::Key::Escape) {
 | 
								if (key == turbine::Key::Escape) {
 | 
				
			||||||
				p->close();
 | 
									p->close();
 | 
				
			||||||
@@ -118,13 +118,13 @@ void StudioUI::draw() noexcept {
 | 
				
			|||||||
		for (auto &w: m_widgets) {
 | 
							for (auto &w: m_widgets) {
 | 
				
			||||||
			w->draw(m_sctx);
 | 
								w->draw(m_sctx);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for (auto p: m_popups) {
 | 
							for (auto const p: m_popups) {
 | 
				
			||||||
			p->draw(m_sctx);
 | 
								p->draw(m_sctx);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	ImGui::End();
 | 
						ImGui::End();
 | 
				
			||||||
	handleKeyInput();
 | 
						handleKeyInput();
 | 
				
			||||||
	m_taskRunner.update(m_ctx);
 | 
						m_taskRunner.update(m_tctx);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void StudioUI::drawMenu() noexcept {
 | 
					void StudioUI::drawMenu() noexcept {
 | 
				
			||||||
@@ -143,7 +143,7 @@ void StudioUI::drawMenu() noexcept {
 | 
				
			|||||||
				m_activeEditor->save();
 | 
									m_activeEditor->save();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (ImGui::MenuItem("Quit", "Ctrl+Q")) {
 | 
								if (ImGui::MenuItem("Quit", "Ctrl+Q")) {
 | 
				
			||||||
				turbine::requestShutdown(m_ctx);
 | 
									turbine::requestShutdown(m_tctx);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			ImGui::EndMenu();
 | 
								ImGui::EndMenu();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -168,7 +168,7 @@ void StudioUI::drawMenu() noexcept {
 | 
				
			|||||||
			ImGui::EndMenu();
 | 
								ImGui::EndMenu();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (ImGui::BeginMenu("View")) {
 | 
							if (ImGui::BeginMenu("View")) {
 | 
				
			||||||
			if (ImGui::MenuItem("Project Explorer", "Ctrl+1", m_showProjectExplorer)) {
 | 
								if (ImGui::MenuItem("Project Explorer", "Ctrl+Shift+1", m_showProjectExplorer)) {
 | 
				
			||||||
				toggleProjectExplorer();
 | 
									toggleProjectExplorer();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			ImGui::EndMenu();
 | 
								ImGui::EndMenu();
 | 
				
			||||||
@@ -204,9 +204,10 @@ void StudioUI::drawTabs() noexcept {
 | 
				
			|||||||
		if (ImGui::BeginTabItem(e->itemDisplayName().c_str(), &open, flags)) {
 | 
							if (ImGui::BeginTabItem(e->itemDisplayName().c_str(), &open, flags)) {
 | 
				
			||||||
			if (m_activeEditor != e.get()) [[unlikely]] {
 | 
								if (m_activeEditor != e.get()) [[unlikely]] {
 | 
				
			||||||
				m_activeEditor = e.get();
 | 
									m_activeEditor = e.get();
 | 
				
			||||||
				studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
 | 
									studio::editConfig<StudioConfig>(keelCtx(m_tctx), [&](StudioConfig &config) {
 | 
				
			||||||
					config.activeTabItemName = m_activeEditor->itemPath();
 | 
										config.activeTabItemName = m_activeEditor->itemPath();
 | 
				
			||||||
				});
 | 
									});
 | 
				
			||||||
 | 
									turbine::setRefreshWithin(m_tctx, 0);
 | 
				
			||||||
			} else [[likely]] {
 | 
								} else [[likely]] {
 | 
				
			||||||
				if (m_activeEditorUpdatePending == e.get()) [[unlikely]] {
 | 
									if (m_activeEditorUpdatePending == e.get()) [[unlikely]] {
 | 
				
			||||||
					m_activeEditorUpdatePending = nullptr;
 | 
										m_activeEditorUpdatePending = nullptr;
 | 
				
			||||||
@@ -227,7 +228,7 @@ void StudioUI::drawTabs() noexcept {
 | 
				
			|||||||
			try {
 | 
								try {
 | 
				
			||||||
				OX_THROW_ERROR(m_editors.erase(it).moveTo(it));
 | 
									OX_THROW_ERROR(m_editors.erase(it).moveTo(it));
 | 
				
			||||||
			} catch (ox::Exception const&ex) {
 | 
								} catch (ox::Exception const&ex) {
 | 
				
			||||||
				oxErrf("Editor tab deletion failed: {} ({}:{})\n", ex.what(), ex.file, ex.line);
 | 
									oxErrf("Editor tab deletion failed: {} ({}:{})\n", ex.what(), ex.src.file_name(), ex.src.line());
 | 
				
			||||||
			} catch (std::exception const&ex) {
 | 
								} catch (std::exception const&ex) {
 | 
				
			||||||
				oxErrf("Editor tab deletion failed: {}\n", ex.what());
 | 
									oxErrf("Editor tab deletion failed: {}\n", ex.what());
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -237,19 +238,23 @@ void StudioUI::drawTabs() noexcept {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void StudioUI::loadEditorMaker(studio::EditorMaker const&editorMaker) noexcept {
 | 
					void StudioUI::loadEditorMaker(EditorMaker const&editorMaker) noexcept {
 | 
				
			||||||
	for (auto const&ext : editorMaker.fileTypes) {
 | 
						for (auto const&ext : editorMaker.fileTypes) {
 | 
				
			||||||
		m_editorMakers[ext] = editorMaker.make;
 | 
							m_editorMakers[ext] = editorMaker.make;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void StudioUI::loadModule(studio::Module const&mod) noexcept {
 | 
					void StudioUI::loadModule(Module const&mod) noexcept {
 | 
				
			||||||
	for (auto const&editorMaker : mod.editors(m_sctx)) {
 | 
						for (auto const&editorMaker : mod.editors(m_sctx)) {
 | 
				
			||||||
		loadEditorMaker(editorMaker);
 | 
							loadEditorMaker(editorMaker);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (auto &im : mod.itemMakers(m_sctx)) {
 | 
						for (auto &im : mod.itemMakers(m_sctx)) {
 | 
				
			||||||
		m_newMenu.addItemMaker(std::move(im));
 | 
							m_newMenu.addItemMaker(std::move(im));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						auto tmplts = mod.itemTemplates(m_sctx);
 | 
				
			||||||
 | 
						for (auto &t : tmplts) {
 | 
				
			||||||
 | 
							m_newMenu.installItemTemplate(t);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void StudioUI::loadModules() noexcept {
 | 
					void StudioUI::loadModules() noexcept {
 | 
				
			||||||
@@ -260,20 +265,20 @@ void StudioUI::loadModules() noexcept {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void StudioUI::toggleProjectExplorer() noexcept {
 | 
					void StudioUI::toggleProjectExplorer() noexcept {
 | 
				
			||||||
	m_showProjectExplorer = !m_showProjectExplorer;
 | 
						m_showProjectExplorer = !m_showProjectExplorer;
 | 
				
			||||||
	studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
 | 
						editConfig<StudioConfig>(keelCtx(m_tctx), [&](StudioConfig &config) {
 | 
				
			||||||
		config.showProjectExplorer = m_showProjectExplorer;
 | 
							config.showProjectExplorer = m_showProjectExplorer;
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void StudioUI::redo() noexcept {
 | 
					void StudioUI::redo() noexcept {
 | 
				
			||||||
	auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
 | 
						auto const undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
 | 
				
			||||||
	if (undoStack && undoStack->canRedo()) {
 | 
						if (undoStack && undoStack->canRedo()) {
 | 
				
			||||||
		 oxLogError(m_activeEditor->undoStack()->redo());
 | 
							 oxLogError(m_activeEditor->undoStack()->redo());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void StudioUI::undo() noexcept {
 | 
					void StudioUI::undo() noexcept {
 | 
				
			||||||
	auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
 | 
						auto const undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
 | 
				
			||||||
	if (undoStack && undoStack->canUndo()) {
 | 
						if (undoStack && undoStack->canUndo()) {
 | 
				
			||||||
		 oxLogError(m_activeEditor->undoStack()->undo());
 | 
							 oxLogError(m_activeEditor->undoStack()->undo());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -292,7 +297,7 @@ void StudioUI::handleKeyInput() noexcept {
 | 
				
			|||||||
				m_activeEditor->copy();
 | 
									m_activeEditor->copy();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else if (ImGui::IsKeyPressed(ImGuiKey_N)) {
 | 
							} else if (ImGui::IsKeyPressed(ImGuiKey_N)) {
 | 
				
			||||||
			if (turbine::buttonDown(m_ctx, turbine::Key::Mod_Shift)) {
 | 
								if (turbine::buttonDown(m_tctx, turbine::Key::Mod_Shift)) {
 | 
				
			||||||
				m_newProject.open();
 | 
									m_newProject.open();
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				m_newMenu.open();
 | 
									m_newMenu.open();
 | 
				
			||||||
@@ -302,7 +307,7 @@ void StudioUI::handleKeyInput() noexcept {
 | 
				
			|||||||
		} else if (ImGui::IsKeyPressed(ImGuiKey_S)) {
 | 
							} else if (ImGui::IsKeyPressed(ImGuiKey_S)) {
 | 
				
			||||||
			save();
 | 
								save();
 | 
				
			||||||
		} else if (ImGui::IsKeyPressed(ImGuiKey_Q)) {
 | 
							} else if (ImGui::IsKeyPressed(ImGuiKey_Q)) {
 | 
				
			||||||
			turbine::requestShutdown(m_ctx);
 | 
								turbine::requestShutdown(m_tctx);
 | 
				
			||||||
		} else if (ImGui::IsKeyPressed(ImGuiKey_V)) {
 | 
							} else if (ImGui::IsKeyPressed(ImGuiKey_V)) {
 | 
				
			||||||
			if (m_activeEditor && m_activeEditor->pasteEnabled()) {
 | 
								if (m_activeEditor && m_activeEditor->pasteEnabled()) {
 | 
				
			||||||
				m_activeEditor->paste();
 | 
									m_activeEditor->paste();
 | 
				
			||||||
@@ -317,8 +322,22 @@ void StudioUI::handleKeyInput() noexcept {
 | 
				
			|||||||
		} else if (ImGui::IsKeyPressed(ImGuiKey_Z)) {
 | 
							} else if (ImGui::IsKeyPressed(ImGuiKey_Z)) {
 | 
				
			||||||
			auto const undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
 | 
								auto const undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
 | 
				
			||||||
			if (undoStack) { oxLogError(undoStack->undo()); }
 | 
								if (undoStack) { oxLogError(undoStack->undo()); }
 | 
				
			||||||
		} else if (ImGui::IsKeyPressed(ImGuiKey_1)) {
 | 
							} else if (ImGui::IsKeyPressed(ImGuiKey_1) && ImGui::IsKeyDown(ImGuiKey_ModShift)) {
 | 
				
			||||||
			toggleProjectExplorer();
 | 
								toggleProjectExplorer();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (!m_editors.empty()) {
 | 
				
			||||||
 | 
									auto const range = ox::min<size_t>(9u, m_editors.size()) - 1;
 | 
				
			||||||
 | 
									for (auto i = 0u; i < 9; ++i) {
 | 
				
			||||||
 | 
										if (ImGui::IsKeyPressed(static_cast<ImGuiKey>(static_cast<int>(ImGuiKey_1) + i))) {
 | 
				
			||||||
 | 
											m_activeEditor = m_editors[i < m_editors.size() ? i : range].get();
 | 
				
			||||||
 | 
											m_activeEditorUpdatePending = m_activeEditor;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if (ImGui::IsKeyPressed(ImGuiKey_0)) {
 | 
				
			||||||
 | 
										m_activeEditor = m_editors[10 < m_editors.size() ? 10 : range].get();
 | 
				
			||||||
 | 
										m_activeEditorUpdatePending = m_activeEditor;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -333,18 +352,18 @@ ox::Error StudioUI::createOpenProject(ox::StringViewCR path) noexcept {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept {
 | 
					ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept {
 | 
				
			||||||
	OX_REQUIRE_M(fs, keel::loadRomFs(path.view()));
 | 
						OX_REQUIRE_M(fs, keel::loadRomFs(path.view()));
 | 
				
			||||||
	OX_RETURN_ERROR(keel::setRomFs(keelCtx(m_ctx), std::move(fs)));
 | 
						OX_RETURN_ERROR(keel::setRomFs(keelCtx(m_tctx), std::move(fs)));
 | 
				
			||||||
	OX_RETURN_ERROR(
 | 
						OX_RETURN_ERROR(
 | 
				
			||||||
			ox::make_unique_catch<studio::Project>(keelCtx(m_ctx), std::move(path), m_projectDataDir)
 | 
								ox::make_unique_catch<Project>(keelCtx(m_tctx), std::move(path), m_projectDataDir)
 | 
				
			||||||
			        .moveTo(m_project));
 | 
								        .moveTo(m_project));
 | 
				
			||||||
	auto const sctx = applicationData<studio::StudioContext>(m_ctx);
 | 
						auto const sctx = applicationData<StudioContext>(m_tctx);
 | 
				
			||||||
	sctx->project = m_project.get();
 | 
						sctx->project = m_project.get();
 | 
				
			||||||
	turbine::setWindowTitle(m_ctx, ox::sfmt("{} - {}", keelCtx(m_ctx).appName, m_project->projectPath()));
 | 
						turbine::setWindowTitle(m_tctx, ox::sfmt("{} - {}", keelCtx(m_tctx).appName, m_project->projectPath()));
 | 
				
			||||||
	m_project->fileAdded.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
 | 
						m_project->fileAdded.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
 | 
				
			||||||
	m_project->fileDeleted.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
 | 
						m_project->fileDeleted.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
 | 
				
			||||||
	m_openFiles.clear();
 | 
						m_openFiles.clear();
 | 
				
			||||||
	m_editors.clear();
 | 
						m_editors.clear();
 | 
				
			||||||
	studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
 | 
						studio::editConfig<StudioConfig>(keelCtx(m_tctx), [&](StudioConfig &config) {
 | 
				
			||||||
		config.projectPath = ox::String(m_project->projectPath());
 | 
							config.projectPath = ox::String(m_project->projectPath());
 | 
				
			||||||
		config.openFiles.clear();
 | 
							config.openFiles.clear();
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
@@ -355,7 +374,7 @@ ox::Error StudioUI::openFile(ox::StringViewCR path) noexcept {
 | 
				
			|||||||
	return openFileActiveTab(path, true);
 | 
						return openFileActiveTab(path, true);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool makeActiveTab) noexcept {
 | 
					ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool const makeActiveTab) noexcept {
 | 
				
			||||||
	if (!m_project) {
 | 
						if (!m_project) {
 | 
				
			||||||
		return ox::Error(1, "No project open to open a file from");
 | 
							return ox::Error(1, "No project open to open a file from");
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -369,7 +388,7 @@ ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool makeActiveTab)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		return {};
 | 
							return {};
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	OX_REQUIRE(ext, studio::fileExt(path));
 | 
						OX_REQUIRE(ext, fileExt(path));
 | 
				
			||||||
	// create Editor
 | 
						// create Editor
 | 
				
			||||||
	BaseEditor *editor = nullptr;
 | 
						BaseEditor *editor = nullptr;
 | 
				
			||||||
	auto const err = m_editorMakers.contains(ext) ?
 | 
						auto const err = m_editorMakers.contains(ext) ?
 | 
				
			||||||
@@ -379,7 +398,7 @@ ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool makeActiveTab)
 | 
				
			|||||||
		if constexpr(!ox::defines::Debug) {
 | 
							if constexpr(!ox::defines::Debug) {
 | 
				
			||||||
			oxErrf("Could not open Editor: {}\n", toStr(err));
 | 
								oxErrf("Could not open Editor: {}\n", toStr(err));
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			oxErrf("Could not open Editor: {} ({}:{})\n", err.errCode, err.file, err.line);
 | 
								oxErrf("Could not open Editor: {} ({}:{})\n", err.errCode, err.src.file_name(), err.src.line());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -391,7 +410,7 @@ ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool makeActiveTab)
 | 
				
			|||||||
		m_activeEditorUpdatePending = editor;
 | 
							m_activeEditorUpdatePending = editor;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// save to config
 | 
						// save to config
 | 
				
			||||||
	studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&path](StudioConfig &config) {
 | 
						studio::editConfig<StudioConfig>(keelCtx(m_tctx), [&path](StudioConfig &config) {
 | 
				
			||||||
		if (!config.openFiles.contains(path)) {
 | 
							if (!config.openFiles.contains(path)) {
 | 
				
			||||||
			config.openFiles.emplace_back(path);
 | 
								config.openFiles.emplace_back(path);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -405,7 +424,7 @@ ox::Error StudioUI::closeFile(ox::StringViewCR path) noexcept {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	std::ignore = m_openFiles.erase(std::remove(m_openFiles.begin(), m_openFiles.end(), path));
 | 
						std::ignore = m_openFiles.erase(std::remove(m_openFiles.begin(), m_openFiles.end(), path));
 | 
				
			||||||
	// save to config
 | 
						// save to config
 | 
				
			||||||
	studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
 | 
						studio::editConfig<StudioConfig>(keelCtx(m_tctx), [&](StudioConfig &config) {
 | 
				
			||||||
		std::ignore = config.openFiles.erase(std::remove(config.openFiles.begin(), config.openFiles.end(), path));
 | 
							std::ignore = config.openFiles.erase(std::remove(config.openFiles.begin(), config.openFiles.end(), path));
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
	return {};
 | 
						return {};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,23 +24,23 @@ class StudioUI: public ox::SignalHandler {
 | 
				
			|||||||
	friend class StudioUIDrawer;
 | 
						friend class StudioUIDrawer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		studio::StudioContext m_sctx;
 | 
							StudioContext m_sctx;
 | 
				
			||||||
		turbine::Context &m_ctx;
 | 
							turbine::Context &m_tctx;
 | 
				
			||||||
		ox::String m_projectDataDir;
 | 
							ox::String m_projectDataDir;
 | 
				
			||||||
		ox::UPtr<studio::Project> m_project;
 | 
							ox::UPtr<Project> m_project;
 | 
				
			||||||
		studio::TaskRunner m_taskRunner;
 | 
							TaskRunner m_taskRunner;
 | 
				
			||||||
		ox::Vector<ox::UPtr<studio::BaseEditor>> m_editors;
 | 
							ox::Vector<ox::UPtr<BaseEditor>> m_editors;
 | 
				
			||||||
		ox::Vector<ox::UPtr<studio::Widget>> m_widgets;
 | 
							ox::Vector<ox::UPtr<Widget>> m_widgets;
 | 
				
			||||||
		ox::HashMap<ox::String, studio::EditorMaker::Func> m_editorMakers;
 | 
							ox::HashMap<ox::String, EditorMaker::Func> m_editorMakers;
 | 
				
			||||||
		ProjectExplorer m_projectExplorer;
 | 
							ProjectExplorer m_projectExplorer;
 | 
				
			||||||
		ox::Vector<ox::String> m_openFiles;
 | 
							ox::Vector<ox::String> m_openFiles;
 | 
				
			||||||
		studio::BaseEditor *m_activeEditorOnLastDraw = nullptr;
 | 
							BaseEditor *m_activeEditorOnLastDraw = nullptr;
 | 
				
			||||||
		studio::BaseEditor *m_activeEditor = nullptr;
 | 
							BaseEditor *m_activeEditor = nullptr;
 | 
				
			||||||
		studio::BaseEditor *m_activeEditorUpdatePending = nullptr;
 | 
							BaseEditor *m_activeEditorUpdatePending = nullptr;
 | 
				
			||||||
		NewMenu m_newMenu;
 | 
							NewMenu m_newMenu;
 | 
				
			||||||
		NewProject m_newProject;
 | 
							NewProject m_newProject;
 | 
				
			||||||
		AboutPopup m_aboutPopup;
 | 
							AboutPopup m_aboutPopup;
 | 
				
			||||||
		ox::Array<studio::Popup*, 3> const m_popups = {
 | 
							ox::Array<Popup*, 3> const m_popups = {
 | 
				
			||||||
			&m_newMenu,
 | 
								&m_newMenu,
 | 
				
			||||||
			&m_newProject,
 | 
								&m_newProject,
 | 
				
			||||||
			&m_aboutPopup
 | 
								&m_aboutPopup
 | 
				
			||||||
@@ -53,7 +53,7 @@ class StudioUI: public ox::SignalHandler {
 | 
				
			|||||||
		void handleKeyEvent(turbine::Key, bool down) noexcept;
 | 
							void handleKeyEvent(turbine::Key, bool down) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		[[nodiscard]]
 | 
							[[nodiscard]]
 | 
				
			||||||
		constexpr studio::Project *project() noexcept {
 | 
							constexpr Project *project() noexcept {
 | 
				
			||||||
			return m_project.get();
 | 
								return m_project.get();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -67,9 +67,9 @@ class StudioUI: public ox::SignalHandler {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		void drawTabs() noexcept;
 | 
							void drawTabs() noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void loadEditorMaker(studio::EditorMaker const&editorMaker) noexcept;
 | 
							void loadEditorMaker(EditorMaker const&editorMaker) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void loadModule(studio::Module const&mod) noexcept;
 | 
							void loadModule(Module const&mod) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		void loadModules() noexcept;
 | 
							void loadModules() noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -214,7 +214,8 @@ bool ListBox(
 | 
				
			|||||||
		ox::CStringViewCR name,
 | 
							ox::CStringViewCR name,
 | 
				
			||||||
		std::function<ox::CStringView(size_t)> const&f,
 | 
							std::function<ox::CStringView(size_t)> const&f,
 | 
				
			||||||
		size_t strCnt,
 | 
							size_t strCnt,
 | 
				
			||||||
		size_t &selIdx) noexcept;
 | 
							size_t &selIdx,
 | 
				
			||||||
 | 
							ImVec2 const&sz = {0, 0}) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ox/claw/claw.hpp>
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <ox/model/typenamecatcher.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <keel/media.hpp>
 | 
					#include <keel/media.hpp>
 | 
				
			||||||
#include <turbine/context.hpp>
 | 
					#include <turbine/context.hpp>
 | 
				
			||||||
@@ -13,75 +15,212 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace studio {
 | 
					namespace studio {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ItemMaker {
 | 
					class ItemTemplate {
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							ox::String const m_name{"Default"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		ox::String const typeName;
 | 
							explicit ItemTemplate() noexcept = default;
 | 
				
			||||||
		ox::String const parentDir;
 | 
					
 | 
				
			||||||
		ox::String const fileExt;
 | 
							explicit ItemTemplate(ox::StringParam name) noexcept: m_name{std::move(name)} {}
 | 
				
			||||||
		constexpr explicit ItemMaker(
 | 
					
 | 
				
			||||||
 | 
							virtual ~ItemTemplate() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							constexpr ox::String const&name() const noexcept {
 | 
				
			||||||
 | 
								return m_name;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							constexpr bool operator<=>(ItemTemplate const&other) const noexcept {
 | 
				
			||||||
 | 
								return m_name != other.name() ? (m_name < other.name() ? -1 : 1) : 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							ox::CStringView displayName() const noexcept {
 | 
				
			||||||
 | 
								return m_name;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							virtual ox::CStringView typeName() const noexcept = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							virtual int typeVersion() const noexcept = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual ox::Result<ox::UAnyPtr> getItem(
 | 
				
			||||||
 | 
								keel::Context &ctx, ox::StringViewCR name, int version) noexcept = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					template<typename T>
 | 
				
			||||||
 | 
					class ItemTemplateT: public ItemTemplate {
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							T const m_item;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							constexpr ItemTemplateT() noexcept = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							explicit ItemTemplateT(ox::StringParam name, T item) noexcept:
 | 
				
			||||||
 | 
								ItemTemplate{std::move(name)}, m_item{std::move(item)} {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							ox::CStringView typeName() const noexcept final {
 | 
				
			||||||
 | 
								return ox::ModelTypeName_v<T>;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							int typeVersion() const noexcept final {
 | 
				
			||||||
 | 
								return ox::ModelTypeVersion_v<T>;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ox::Result<ox::UAnyPtr> getItem(
 | 
				
			||||||
 | 
									keel::Context &kctx, ox::StringViewCR name, int const version) noexcept final {
 | 
				
			||||||
 | 
								if (ox::ModelTypeVersion_v<T> != version || ox::ModelTypeName_v<T> != name) {
 | 
				
			||||||
 | 
									OX_REQUIRE_M(item, keel::convert(kctx, m_item, name, version));
 | 
				
			||||||
 | 
									auto out = ox::Result<ox::UAnyPtr>{item->moveToCopy()};
 | 
				
			||||||
 | 
									ox::safeDelete(item.release());
 | 
				
			||||||
 | 
									return out;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return ox::UAnyPtr{new T{m_item}};
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ItemMaker {
 | 
				
			||||||
 | 
						private:
 | 
				
			||||||
 | 
							ox::Vector<ox::UPtr<ItemTemplate>> m_templates;
 | 
				
			||||||
 | 
							ox::String const m_parentDir;
 | 
				
			||||||
 | 
							ox::String const m_fileExt;
 | 
				
			||||||
 | 
							ox::String const m_typeDisplayName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public:
 | 
				
			||||||
 | 
							constexpr ItemMaker(
 | 
				
			||||||
				ox::StringParam pName,
 | 
									ox::StringParam pName,
 | 
				
			||||||
				ox::StringParam pParentDir,
 | 
									ox::StringParam pParentDir,
 | 
				
			||||||
				ox::StringParam pFileExt) noexcept:
 | 
									ox::StringParam pFileExt) noexcept:
 | 
				
			||||||
			typeName{std::move(pName)},
 | 
								m_parentDir{std::move(pParentDir)},
 | 
				
			||||||
			parentDir{std::move(pParentDir)},
 | 
								m_fileExt{std::move(pFileExt)},
 | 
				
			||||||
			fileExt{std::move(pFileExt)} {
 | 
								m_typeDisplayName{std::move(pName)} {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		virtual ~ItemMaker() noexcept = default;
 | 
							virtual ~ItemMaker() noexcept = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		[[nodiscard]]
 | 
							[[nodiscard]]
 | 
				
			||||||
		virtual ox::String itemPath(ox::StringView pName) const noexcept {
 | 
							ox::String const&typeDisplayName() const noexcept {
 | 
				
			||||||
			return ox::sfmt("/{}/{}.{}", parentDir, pName, fileExt);
 | 
								return m_typeDisplayName;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool installTemplate(ox::UPtr<ItemTemplate> &tmpl) {
 | 
				
			||||||
 | 
								if (typeName() == tmpl->typeName() &&
 | 
				
			||||||
 | 
								    typeVersion() <= tmpl->typeVersion()) {
 | 
				
			||||||
 | 
					                m_templates.emplace_back(std::move(tmpl));
 | 
				
			||||||
 | 
									// begin() + 1 because 'Default' should always be first
 | 
				
			||||||
 | 
					                std::sort(m_templates.begin() + 1, m_templates.end());
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bool installTemplate(ox::UPtr<ItemTemplate> &&tmpl) {
 | 
				
			||||||
 | 
								return installTemplate(tmpl);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							constexpr ox::Vector<ox::UPtr<ItemTemplate>> const&itemTemplates() const noexcept {
 | 
				
			||||||
 | 
								return m_templates;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							ox::String itemPath(ox::StringViewCR pName) const noexcept {
 | 
				
			||||||
 | 
								return ox::sfmt("/{}/{}.{}", m_parentDir, pName, m_fileExt);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							virtual ox::StringView typeName() const noexcept = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							[[nodiscard]]
 | 
				
			||||||
 | 
							virtual int typeVersion() const noexcept = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/**
 | 
							/**
 | 
				
			||||||
		 * Returns path of the file created.
 | 
							 * Returns path of the file created.
 | 
				
			||||||
		 * @param ctx
 | 
							 * @param ctx
 | 
				
			||||||
		 * @param pName
 | 
							 * @param pName
 | 
				
			||||||
 | 
							 * @param pTemplateIdx
 | 
				
			||||||
		 * @return path of file or error in Result
 | 
							 * @return path of file or error in Result
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		virtual ox::Result<ox::String> write(StudioContext &ctx, ox::StringView pName) const noexcept = 0;
 | 
							virtual ox::Result<ox::String> write(
 | 
				
			||||||
 | 
								StudioContext &ctx, ox::StringViewCR pName, size_t pTemplateIdx) const noexcept = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename T>
 | 
					template<typename T>
 | 
				
			||||||
class ItemMakerT: public ItemMaker {
 | 
					class ItemMakerT final: public ItemMaker {
 | 
				
			||||||
	private:
 | 
						private:
 | 
				
			||||||
		T const m_item;
 | 
					 | 
				
			||||||
		ox::ClawFormat const m_fmt;
 | 
							ox::ClawFormat const m_fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		constexpr ItemMakerT(
 | 
							constexpr ItemMakerT(
 | 
				
			||||||
				ox::StringParam pDisplayName,
 | 
									ox::StringParam pDisplayName,
 | 
				
			||||||
				ox::StringParam pParentDir,
 | 
									ox::StringParam pParentDir,
 | 
				
			||||||
				ox::StringParam fileExt,
 | 
									ox::StringParam fileExt,
 | 
				
			||||||
				ox::ClawFormat pFmt = ox::ClawFormat::Metal) noexcept:
 | 
									ox::ClawFormat const pFmt = ox::ClawFormat::Metal) noexcept:
 | 
				
			||||||
			ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)),
 | 
									ItemMaker(
 | 
				
			||||||
			m_fmt(pFmt) {
 | 
										std::move(pDisplayName),
 | 
				
			||||||
 | 
										std::move(pParentDir),
 | 
				
			||||||
 | 
										std::move(fileExt)),
 | 
				
			||||||
 | 
									m_fmt{pFmt} {
 | 
				
			||||||
 | 
								installTemplate(ox::make_unique<ItemTemplateT<T>>());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr ItemMakerT(
 | 
							constexpr ItemMakerT(
 | 
				
			||||||
				ox::StringParam pDisplayName,
 | 
									ox::StringParam pDisplayName,
 | 
				
			||||||
				ox::StringParam pParentDir,
 | 
									ox::StringParam pParentDir,
 | 
				
			||||||
				ox::StringParam fileExt,
 | 
									ox::StringParam fileExt,
 | 
				
			||||||
				T pItem,
 | 
									T const&pItem,
 | 
				
			||||||
				ox::ClawFormat pFmt) noexcept:
 | 
									ox::ClawFormat const pFmt) noexcept:
 | 
				
			||||||
			ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)),
 | 
									ItemMaker(
 | 
				
			||||||
			m_item(std::move(pItem)),
 | 
										std::move(pDisplayName),
 | 
				
			||||||
			m_fmt(pFmt) {
 | 
										std::move(pParentDir),
 | 
				
			||||||
 | 
										std::move(fileExt)),
 | 
				
			||||||
 | 
									m_fmt{pFmt} {
 | 
				
			||||||
 | 
								installTemplate(ox::make_unique<ItemTemplateT<T>>(std::move(pItem)));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		constexpr ItemMakerT(
 | 
							constexpr ItemMakerT(
 | 
				
			||||||
				ox::StringParam pDisplayName,
 | 
									ox::StringParam pDisplayName,
 | 
				
			||||||
				ox::StringParam pParentDir,
 | 
									ox::StringParam pParentDir,
 | 
				
			||||||
				ox::StringParam fileExt,
 | 
									ox::StringParam fileExt,
 | 
				
			||||||
				T &&pItem,
 | 
									T &&pItem,
 | 
				
			||||||
				ox::ClawFormat pFmt) noexcept:
 | 
									ox::ClawFormat const pFmt) noexcept:
 | 
				
			||||||
			ItemMaker(std::move(pDisplayName), std::move(pParentDir), std::move(fileExt)),
 | 
									ItemMaker(
 | 
				
			||||||
			m_item(std::move(pItem)),
 | 
										std::move(pDisplayName),
 | 
				
			||||||
			m_fmt(pFmt) {
 | 
										std::move(pParentDir),
 | 
				
			||||||
 | 
										std::move(fileExt)),
 | 
				
			||||||
 | 
									m_fmt{pFmt} {
 | 
				
			||||||
 | 
								installTemplate(ox::make_unique<ItemTemplateT<T>>(std::move(pItem)));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ox::Result<ox::String> write(studio::StudioContext &sctx, ox::StringView const pName) const noexcept override {
 | 
					
 | 
				
			||||||
 | 
							ox::StringView typeName() const noexcept override {
 | 
				
			||||||
 | 
								return ox::ModelTypeName_v<T>;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							int typeVersion() const noexcept override {
 | 
				
			||||||
 | 
								return ox::ModelTypeVersion_v<T>;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ox::Result<ox::String> write(
 | 
				
			||||||
 | 
								StudioContext &sctx,
 | 
				
			||||||
 | 
								ox::StringViewCR pName,
 | 
				
			||||||
 | 
								size_t const pTemplateIdx) const noexcept override {
 | 
				
			||||||
			auto const path = itemPath(pName);
 | 
								auto const path = itemPath(pName);
 | 
				
			||||||
			createUuidMapping(keelCtx(sctx.tctx), path, ox::UUID::generate().unwrap());
 | 
								createUuidMapping(keelCtx(sctx.tctx), path, ox::UUID::generate().unwrap());
 | 
				
			||||||
			OX_RETURN_ERROR(sctx.project->writeObj(path, m_item, m_fmt));
 | 
								auto const&templates = itemTemplates();
 | 
				
			||||||
 | 
								auto const tmplIdx = pTemplateIdx < templates.size() ? pTemplateIdx : 0;
 | 
				
			||||||
 | 
								OX_REQUIRE_M(tmpl, templates[tmplIdx]->getItem(
 | 
				
			||||||
 | 
									keelCtx(sctx), typeName(), typeVersion()));
 | 
				
			||||||
 | 
								auto item = tmpl.template get<T>();
 | 
				
			||||||
 | 
								OX_RETURN_ERROR(sctx.project->writeObj(path, *item, m_fmt));
 | 
				
			||||||
 | 
								tmpl.free();
 | 
				
			||||||
			return path;
 | 
								return path;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,8 @@ class Module {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		virtual ox::Vector<ox::UPtr<ItemMaker>> itemMakers(studio::StudioContext&) const;
 | 
							virtual ox::Vector<ox::UPtr<ItemMaker>> itemMakers(studio::StudioContext&) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							virtual ox::Vector<ox::UPtr<ItemTemplate>> itemTemplates(studio::StudioContext&) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
template<typename Editor>
 | 
					template<typename Editor>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -47,7 +47,7 @@ class Popup {
 | 
				
			|||||||
			return m_title;
 | 
								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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,7 @@ namespace studio {
 | 
				
			|||||||
class NoChangesException: public ox::Exception {
 | 
					class NoChangesException: public ox::Exception {
 | 
				
			||||||
	public:
 | 
						public:
 | 
				
			||||||
		inline NoChangesException(std::source_location sloc = std::source_location::current()):
 | 
							inline NoChangesException(std::source_location sloc = std::source_location::current()):
 | 
				
			||||||
				ox::Exception(sloc.file_name(), sloc.line(), 1, "Command makes no changes.") {}
 | 
									ox::Exception(1, "Command makes no changes.", sloc) {}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UndoCommand {
 | 
					class UndoCommand {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,7 +46,7 @@ void BaseEditor::save() noexcept {
 | 
				
			|||||||
		setUnsavedChanges(false);
 | 
							setUnsavedChanges(false);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if constexpr(ox::defines::Debug) {
 | 
							if constexpr(ox::defines::Debug) {
 | 
				
			||||||
			oxErrorf("Could not save file {}: {} ({}:{})", itemPath(), toStr(err), err.file, err.line);
 | 
								oxErrorf("Could not save file {}: {} ({}:{})", itemPath(), toStr(err), err.src.file_name(), err.src.line());
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			oxErrorf("Could not save file {}: {}", itemPath(), toStr(err));
 | 
								oxErrorf("Could not save file {}: {}", itemPath(), toStr(err));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -136,11 +136,12 @@ bool FileComboBox(
 | 
				
			|||||||
bool ListBox(
 | 
					bool ListBox(
 | 
				
			||||||
		ox::CStringViewCR name,
 | 
							ox::CStringViewCR name,
 | 
				
			||||||
		std::function<ox::CStringView(size_t)> const&f,
 | 
							std::function<ox::CStringView(size_t)> const&f,
 | 
				
			||||||
		size_t strCnt,
 | 
							size_t const strCnt,
 | 
				
			||||||
		size_t &selIdx) noexcept {
 | 
							size_t &selIdx,
 | 
				
			||||||
 | 
							ImVec2 const&sz) noexcept {
 | 
				
			||||||
	auto out = false;
 | 
						auto out = false;
 | 
				
			||||||
	if (ImGui::BeginListBox(name.c_str())) {
 | 
						if (ImGui::BeginListBox(name.c_str(), sz)) {
 | 
				
			||||||
		for (auto i = 0u; i < strCnt; ++i) {
 | 
							for (size_t i = 0; i < strCnt; ++i) {
 | 
				
			||||||
			auto str = f(i);
 | 
								auto str = f(i);
 | 
				
			||||||
			ig::IDStackItem const idStackItem2(static_cast<int>(i));
 | 
								ig::IDStackItem const idStackItem2(static_cast<int>(i));
 | 
				
			||||||
			if (ImGui::Selectable(str.c_str(), selIdx == i)) {
 | 
								if (ImGui::Selectable(str.c_str(), selIdx == i)) {
 | 
				
			||||||
@@ -161,6 +162,12 @@ bool ListBox(ox::CStringViewCR name, ox::SpanView<ox::String> const&list, size_t
 | 
				
			|||||||
	}, list.size(), selIdx);
 | 
						}, list.size(), selIdx);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool ListBox(ox::CStringViewCR name, ox::SpanView<ox::CStringView> const&list, size_t &selIdx) noexcept {
 | 
				
			||||||
 | 
						return ListBox(name, [list](size_t i) -> ox::CStringView {
 | 
				
			||||||
 | 
							return list[i];
 | 
				
			||||||
 | 
						}, list.size(), selIdx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FilePicker::FilePicker(
 | 
					FilePicker::FilePicker(
 | 
				
			||||||
		StudioContext &sctx,
 | 
							StudioContext &sctx,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,11 +6,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace studio {
 | 
					namespace studio {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ox::Vector<EditorMaker> Module::editors(studio::StudioContext&) const {
 | 
					ox::Vector<EditorMaker> Module::editors(StudioContext&) const {
 | 
				
			||||||
	return {};
 | 
						return {};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ox::Vector<ox::UPtr<ItemMaker>> Module::itemMakers(studio::StudioContext&) const {
 | 
					ox::Vector<ox::UPtr<ItemMaker>> Module::itemMakers(StudioContext&) const {
 | 
				
			||||||
 | 
						return {};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ox::Vector<ox::UPtr<ItemTemplate>> Module::itemTemplates(StudioContext&) const {
 | 
				
			||||||
	return {};
 | 
						return {};
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,11 +7,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace studio {
 | 
					namespace studio {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Popup::drawWindow(turbine::Context &ctx, bool *open, std::function<void()> const&drawContents) {
 | 
					void Popup::drawWindow(turbine::Context &ctx, bool &open, std::function<void()> const&drawContents) {
 | 
				
			||||||
	studio::ig::centerNextWindow(ctx);
 | 
						studio::ig::centerNextWindow(ctx);
 | 
				
			||||||
	ImGui::SetNextWindowSize(static_cast<ImVec2>(m_size));
 | 
						ImGui::SetNextWindowSize(static_cast<ImVec2>(m_size));
 | 
				
			||||||
	constexpr auto modalFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
 | 
						constexpr auto modalFlags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
 | 
				
			||||||
	if (ImGui::BeginPopupModal(m_title.c_str(), open, modalFlags)) {
 | 
						if (ImGui::BeginPopupModal(m_title.c_str(), &open, modalFlags)) {
 | 
				
			||||||
		drawContents();
 | 
							drawContents();
 | 
				
			||||||
		ImGui::EndPopup();
 | 
							ImGui::EndPopup();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,7 @@ target_include_directories(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
target_sources(
 | 
					target_sources(
 | 
				
			||||||
	Turbine PUBLIC
 | 
						Turbine PRIVATE
 | 
				
			||||||
		turbine.cpp
 | 
							turbine.cpp
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
FROM fedora:36
 | 
					FROM fedora:41
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN dnf update -y
 | 
					RUN dnf update -y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -28,11 +28,11 @@ project_name = sys.argv[2]
 | 
				
			|||||||
bin = f'./build/{host_env}-{current_build}/bin/'
 | 
					bin = f'./build/{host_env}-{current_build}/bin/'
 | 
				
			||||||
project_bin = f'build/gba-release/bin/{project_name}.bin'
 | 
					project_bin = f'build/gba-release/bin/{project_name}.bin'
 | 
				
			||||||
project_gba = f'{project_name}.gba'
 | 
					project_gba = f'{project_name}.gba'
 | 
				
			||||||
project_manifest = f'{project_name}-manifest.json'
 | 
					project_manifest = f'{project_name.lower()}-manifest.json'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
shutil.copyfile(project_bin, project_gba)
 | 
					shutil.copyfile(project_bin, project_gba)
 | 
				
			||||||
subprocess.run([
 | 
					subprocess.run([
 | 
				
			||||||
    f'{bin}/{project_name}-pack',
 | 
					    f'{bin}/{project_name.lower()}-pack',
 | 
				
			||||||
        '-src', project_dir,
 | 
					        '-src', project_dir,
 | 
				
			||||||
        '-rom-bin', project_gba,
 | 
					        '-rom-bin', project_gba,
 | 
				
			||||||
        '-manifest', project_manifest])
 | 
					        '-manifest', project_manifest])
 | 
				
			||||||
		Reference in New Issue
	
	Block a user