Compare commits
	
		
			38 Commits
		
	
	
		
			release-d2
			...
			dd50bd0249
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 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
 | 
			
		||||
.stfolder
 | 
			
		||||
.stignore
 | 
			
		||||
scripts/__pycache__
 | 
			
		||||
util/scripts/__pycache__
 | 
			
		||||
pyenv
 | 
			
		||||
CMakeLists.txt.user
 | 
			
		||||
ROM.oxfs
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
									
									
									
									
								
							@@ -1,5 +1,6 @@
 | 
			
		||||
BC_VAR_PROJECT_NAME=nostalgia
 | 
			
		||||
BC_VAR_PROJECT_NAME_CAP=Nostalgia
 | 
			
		||||
BC_VAR_DEVENV_ROOT=util
 | 
			
		||||
BUILDCORE_PATH=deps/buildcore
 | 
			
		||||
include ${BUILDCORE_PATH}/base.mk
 | 
			
		||||
 | 
			
		||||
@@ -13,7 +14,7 @@ endif
 | 
			
		||||
 | 
			
		||||
.PHONY: pkg-gba
 | 
			
		||||
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
 | 
			
		||||
run: build
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								deps/glad/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								deps/glad/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +1,11 @@
 | 
			
		||||
add_library(glad OBJECT src/glad.c)
 | 
			
		||||
target_include_directories(glad PUBLIC include)
 | 
			
		||||
add_library(glad src/glad.c)
 | 
			
		||||
 | 
			
		||||
target_include_directories(glad PUBLIC include)
 | 
			
		||||
 | 
			
		||||
install(
 | 
			
		||||
	TARGETS
 | 
			
		||||
		glad
 | 
			
		||||
	DESTINATION
 | 
			
		||||
		LIBRARY DESTINATION lib
 | 
			
		||||
		ARCHIVE DESTINATION lib
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								deps/imgui/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								deps/imgui/CMakeLists.txt
									
									
									
									
										vendored
									
									
								
							@@ -6,7 +6,7 @@ endif()
 | 
			
		||||
# DrinkingTea: end
 | 
			
		||||
 | 
			
		||||
add_library(
 | 
			
		||||
	imgui OBJECT
 | 
			
		||||
	imgui
 | 
			
		||||
		imgui.cpp
 | 
			
		||||
		imgui_demo.cpp
 | 
			
		||||
		imgui_draw.cpp
 | 
			
		||||
@@ -19,4 +19,12 @@ add_library(
 | 
			
		||||
target_include_directories(
 | 
			
		||||
	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);
 | 
			
		||||
	} 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); \
 | 
			
		||||
		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 { \
 | 
			
		||||
			ox::trace::setLogger(&(loggerName)); \
 | 
			
		||||
		} \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								deps/ox/src/ox/std/algorithm.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								deps/ox/src/ox/std/algorithm.hpp
									
									
									
									
										vendored
									
									
								
							@@ -9,13 +9,25 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "def.hpp"
 | 
			
		||||
#include "error.hpp"
 | 
			
		||||
 | 
			
		||||
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
 | 
			
		||||
 | 
			
		||||
namespace ox {
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
		if (*begin == value) {
 | 
			
		||||
			return begin;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								deps/ox/src/ox/std/assert.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								deps/ox/src/ox/std/assert.cpp
									
									
									
									
										vendored
									
									
								
							@@ -20,8 +20,8 @@ void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err)
 | 
			
		||||
		oxErrf("\tError Message:\t{}\n", err.msg);
 | 
			
		||||
	}
 | 
			
		||||
	oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
 | 
			
		||||
	if (err.file != nullptr) {
 | 
			
		||||
		oxErrf("\tError Location:\t{}:{}\n", err.file, err.line);
 | 
			
		||||
	if (err.src.file_name() != nullptr) {
 | 
			
		||||
		oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
 | 
			
		||||
	}
 | 
			
		||||
#ifdef OX_USE_STDLIB
 | 
			
		||||
	printStackTrace(2);
 | 
			
		||||
@@ -56,8 +56,8 @@ void assertFailFuncRuntime(StringViewCR file, int line, [[maybe_unused]] const E
 | 
			
		||||
		msg += sfmt("\tError Message:\t{}\n", err.msg);
 | 
			
		||||
	}
 | 
			
		||||
	msg += sfmt("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
 | 
			
		||||
	if (err.file != nullptr) {
 | 
			
		||||
		msg += sfmt("\tError Location:\t{}:{}\n", err.file, err.line);
 | 
			
		||||
	if (err.src.file_name() != nullptr) {
 | 
			
		||||
		msg += sfmt("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
 | 
			
		||||
	}
 | 
			
		||||
	msg += genStackTrace(2);
 | 
			
		||||
	oxErr(msg);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										40
									
								
								deps/ox/src/ox/std/error.hpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										40
									
								
								deps/ox/src/ox/std/error.hpp
									
									
									
									
										vendored
									
									
								
							@@ -36,28 +36,16 @@ using ErrorCode = uint16_t;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct [[nodiscard]] Error {
 | 
			
		||||
	std::source_location src;
 | 
			
		||||
	ox::CString msg = nullptr;
 | 
			
		||||
	ox::CString file = nullptr;
 | 
			
		||||
	uint16_t line = 0;
 | 
			
		||||
	ErrorCode errCode = 0;
 | 
			
		||||
 | 
			
		||||
	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(
 | 
			
		||||
		ErrorCode const errCode,
 | 
			
		||||
		std::source_location const&src = std::source_location::current()) noexcept:
 | 
			
		||||
		file{src.file_name()},
 | 
			
		||||
		line{static_cast<uint16_t>(src.line())},
 | 
			
		||||
		src{src},
 | 
			
		||||
		errCode{errCode}
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
@@ -65,9 +53,8 @@ struct [[nodiscard]] Error {
 | 
			
		||||
		ErrorCode const errCode,
 | 
			
		||||
		ox::CString msg,
 | 
			
		||||
		std::source_location const&src = std::source_location::current()) noexcept:
 | 
			
		||||
		src{src},
 | 
			
		||||
		msg{msg},
 | 
			
		||||
		file{src.file_name()},
 | 
			
		||||
		line{static_cast<uint16_t>(src.line())},
 | 
			
		||||
		errCode{errCode}
 | 
			
		||||
	{}
 | 
			
		||||
 | 
			
		||||
@@ -89,42 +76,31 @@ constexpr auto toStr(Error const&err) noexcept {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct Exception: public std::exception {
 | 
			
		||||
	std::source_location src;
 | 
			
		||||
	ox::CString msg = nullptr;
 | 
			
		||||
	ox::CString file = nullptr;
 | 
			
		||||
	uint16_t line = 0;
 | 
			
		||||
	ErrorCode errCode = 0;
 | 
			
		||||
 | 
			
		||||
	explicit inline Exception(ox::CString file, uint32_t line, ErrorCode errCode, char const*msg = "") noexcept {
 | 
			
		||||
		this->file = file;
 | 
			
		||||
		this->line = static_cast<uint16_t>(line);
 | 
			
		||||
		this->msg = msg;
 | 
			
		||||
		this->errCode = errCode;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	explicit inline Exception(
 | 
			
		||||
		ErrorCode const errCode,
 | 
			
		||||
		std::source_location const&src = std::source_location::current()) noexcept:
 | 
			
		||||
		file{src.file_name()},
 | 
			
		||||
		line{static_cast<uint16_t>(src.line())},
 | 
			
		||||
		src{src},
 | 
			
		||||
		errCode{errCode} {}
 | 
			
		||||
 | 
			
		||||
	explicit inline Exception(
 | 
			
		||||
		ErrorCode const errCode,
 | 
			
		||||
		ox::CString msg,
 | 
			
		||||
		std::source_location const&src = std::source_location::current()) noexcept:
 | 
			
		||||
		src{src},
 | 
			
		||||
		msg{msg},
 | 
			
		||||
		file{src.file_name()},
 | 
			
		||||
		line{static_cast<uint16_t>(src.line())},
 | 
			
		||||
		errCode{errCode} {}
 | 
			
		||||
 | 
			
		||||
	explicit inline Exception(Error const&err) noexcept:
 | 
			
		||||
		src{err.src},
 | 
			
		||||
		msg{err.msg ? err.msg : ""},
 | 
			
		||||
		file{err.file},
 | 
			
		||||
		line{err.line},
 | 
			
		||||
		errCode{err.errCode} {}
 | 
			
		||||
 | 
			
		||||
	constexpr Error toError() const noexcept {
 | 
			
		||||
		return Error(file, line, errCode, msg);
 | 
			
		||||
		return Error(errCode, msg, src);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[[nodiscard]]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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 {
 | 
			
		||||
	public:
 | 
			
		||||
		virtual constexpr ~Reader_v() noexcept = default;
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		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> tellg() noexcept = 0;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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]]
 | 
			
		||||
		constexpr Vector<K> keys() const noexcept;
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		constexpr Vector<T> values() const noexcept;
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		constexpr K const&key(size_t i) const noexcept;
 | 
			
		||||
 | 
			
		||||
@@ -82,14 +85,22 @@ class SmallMap {
 | 
			
		||||
			return m_pairs;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		constexpr ox::Span<Pair> pairs() noexcept {
 | 
			
		||||
			return m_pairs;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		constexpr void clear();
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		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>
 | 
			
		||||
		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>
 | 
			
		||||
constexpr T &SmallMap<K, T, SmallSz>::operator[](MaybeView_t<K> const&k) {
 | 
			
		||||
	bool isNew{};
 | 
			
		||||
	auto p = &access(m_pairs, k, isNew);
 | 
			
		||||
	auto p = access(m_pairs, k, isNew);
 | 
			
		||||
	if (isNew) {
 | 
			
		||||
		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>
 | 
			
		||||
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) {
 | 
			
		||||
		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>
 | 
			
		||||
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) {
 | 
			
		||||
		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>
 | 
			
		||||
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>
 | 
			
		||||
@@ -186,6 +199,16 @@ constexpr Vector<K> SmallMap<K, T, SmallSz>::keys() const noexcept {
 | 
			
		||||
	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>
 | 
			
		||||
constexpr K const&SmallMap<K, T, SmallSz>::key(size_t i) const noexcept {
 | 
			
		||||
	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 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 {
 | 
			
		||||
	for (auto const&p : pairs) {
 | 
			
		||||
		if (p.key == k) {
 | 
			
		||||
			isNew = false;
 | 
			
		||||
			return p;
 | 
			
		||||
			return &p;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	isNew = true;
 | 
			
		||||
	return pairs.emplace_back();
 | 
			
		||||
	return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template<typename K, typename T, size_t SmallSz>
 | 
			
		||||
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) {
 | 
			
		||||
	for (auto &p : pairs) {
 | 
			
		||||
		if (p.key == k) {
 | 
			
		||||
			isNew = false;
 | 
			
		||||
			return p;
 | 
			
		||||
			return &p;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	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>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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] SmallMap2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest "SmallMap2")
 | 
			
		||||
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] HeapMgr" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/StdTest malloc)
 | 
			
		||||
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);
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		"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",
 | 
			
		||||
		[] {
 | 
			
		||||
@@ -246,7 +290,18 @@ OX_CLANG_NOWARN_END
 | 
			
		||||
			oxExpect(map.size(), 1u);
 | 
			
		||||
			oxExpect(map["aoeu"], "");
 | 
			
		||||
			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 {
 | 
			
		||||
	if (err) {
 | 
			
		||||
		TraceStream trc(file, line, "ox::error");
 | 
			
		||||
		if (err.file != nullptr) {
 | 
			
		||||
			trc << "Error: (" << err.file << ":" << err.line << "):";
 | 
			
		||||
		if (err.src.file_name() != nullptr) {
 | 
			
		||||
			trc << "Error: (" << err.src.file_name() << ":" << err.src.line() << "):";
 | 
			
		||||
		} else {
 | 
			
		||||
			trc <<  "Error:";
 | 
			
		||||
		}
 | 
			
		||||
@@ -282,8 +282,8 @@ inline void logError(const char *file, int line, const Error &err) noexcept {
 | 
			
		||||
	if (err) {
 | 
			
		||||
		TraceStream trc(file, line, "ox::error");
 | 
			
		||||
		trc <<  "Error:" << err;
 | 
			
		||||
		if (err.file != nullptr) {
 | 
			
		||||
			trc << "(" << err.file << ":" << err.line << ")";
 | 
			
		||||
		if (err.src.file_name() != nullptr) {
 | 
			
		||||
			trc << "(" << err.src.file_name() << ":" << err.src.line() << ")";
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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 shrink_to_fit() noexcept(useNoexcept);
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		constexpr void reserveInsert(
 | 
			
		||||
				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>
 | 
			
		||||
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::initializer_list<T> list) noexcept {
 | 
			
		||||
	reserve(list.size());
 | 
			
		||||
	for (auto &item : list) {
 | 
			
		||||
		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>
 | 
			
		||||
constexpr void Vector<T, SmallVectorSize, Allocator>::reserveInsert(
 | 
			
		||||
		std::size_t cap,
 | 
			
		||||
 
 | 
			
		||||
@@ -102,8 +102,6 @@ OX_MODEL_BEGIN(TileSheetSet)
 | 
			
		||||
	OX_MODEL_FIELD(entries)
 | 
			
		||||
OX_MODEL_END()
 | 
			
		||||
 | 
			
		||||
void addEntry(TileSheetSet &set, ox::FileAddress path, int32_t begin = 0, int32_t size = -1) noexcept;
 | 
			
		||||
 | 
			
		||||
[[nodiscard]]
 | 
			
		||||
int tileColumns(Context&) noexcept;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -212,6 +212,10 @@ struct TileSheetV4 {
 | 
			
		||||
				pixels(std::move(pPixels)) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/**
 | 
			
		||||
		 *
 | 
			
		||||
		 * @return the dimensional size of the SubSheet (e.g. width * height)
 | 
			
		||||
		 */
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		constexpr std::size_t size() const noexcept {
 | 
			
		||||
			return static_cast<std::size_t>(columns) * static_cast<std::size_t>(rows);
 | 
			
		||||
@@ -281,7 +285,7 @@ size_t getTileCnt(TileSheet const&ts) noexcept;
 | 
			
		||||
TileSheet::SubSheet const*getSubsheet(TileSheet const&ts, SubSheetId id) noexcept;
 | 
			
		||||
 | 
			
		||||
[[nodiscard]]
 | 
			
		||||
size_t getTileIdx(TileSheet const&ts, SubSheetId id) noexcept;
 | 
			
		||||
ox::Optional<size_t> getTileIdx(TileSheet const&ts, SubSheetId id) noexcept;
 | 
			
		||||
 | 
			
		||||
[[nodiscard]]
 | 
			
		||||
uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
 | 
			
		||||
@@ -400,6 +404,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<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 const&ts, SubSheetId pId) noexcept;
 | 
			
		||||
 
 | 
			
		||||
@@ -48,8 +48,8 @@ OX_ALLOW_UNSAFE_BUFFERS_END
 | 
			
		||||
		oxErrf("\tError Message:\t{}\n", err.msg);
 | 
			
		||||
	}
 | 
			
		||||
	oxErrf("\tError Code:\t{}\n", static_cast<ErrorCode>(err));
 | 
			
		||||
	if (err.file != nullptr) {
 | 
			
		||||
		oxErrf("\tError Location:\t{}:{}\n", err.file, err.line);
 | 
			
		||||
	if (err.src.file_name() != nullptr) {
 | 
			
		||||
		oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
 | 
			
		||||
	}
 | 
			
		||||
	// disable all interrupt handling and IntrWait on no interrupts
 | 
			
		||||
	REG_IE = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -9,24 +9,27 @@ namespace nostalgia::core {
 | 
			
		||||
core::UpdateSubSheetCommand::UpdateSubSheetCommand(
 | 
			
		||||
		TileSheet &img,
 | 
			
		||||
		TileSheet::SubSheetIdx idx,
 | 
			
		||||
		ox::StringParam name,
 | 
			
		||||
		int const cols,
 | 
			
		||||
		int const rows):
 | 
			
		||||
		m_img{img},
 | 
			
		||||
		m_idx{std::move(idx)},
 | 
			
		||||
		m_sheet{getSubSheet(m_img, m_idx)} {
 | 
			
		||||
	m_sheet = getSubSheet(m_img, m_idx);
 | 
			
		||||
	m_sheet.name = std::move(name);
 | 
			
		||||
	OX_THROW_ERROR(resizeSubsheet(m_sheet, m_img.bpp, {cols, rows}));
 | 
			
		||||
		ox::String name,
 | 
			
		||||
		int cols,
 | 
			
		||||
		int rows) noexcept:
 | 
			
		||||
		m_img(img),
 | 
			
		||||
		m_idx(std::move(idx)),
 | 
			
		||||
		m_sheet(getSubSheet(m_img, m_idx)),
 | 
			
		||||
		m_newName(std::move(name)),
 | 
			
		||||
		m_newCols(cols),
 | 
			
		||||
		m_newRows(rows) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::Error UpdateSubSheetCommand::redo() noexcept {
 | 
			
		||||
	std::swap(m_sheet, getSubSheet(m_img, m_idx));
 | 
			
		||||
	auto &sheet = getSubSheet(m_img, m_idx);
 | 
			
		||||
	sheet.name = m_newName;
 | 
			
		||||
	oxLogError(resizeSubsheet(sheet, m_img.bpp, {m_newCols, m_newRows}));
 | 
			
		||||
	return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::Error UpdateSubSheetCommand::undo() noexcept {
 | 
			
		||||
	std::swap(m_sheet, getSubSheet(m_img, m_idx));
 | 
			
		||||
	auto &sheet = getSubSheet(m_img, m_idx);
 | 
			
		||||
	sheet = m_sheet;
 | 
			
		||||
	return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,14 +13,17 @@ class UpdateSubSheetCommand: public TileSheetCommand {
 | 
			
		||||
		TileSheet &m_img;
 | 
			
		||||
		TileSheet::SubSheetIdx m_idx;
 | 
			
		||||
		TileSheet::SubSheet m_sheet;
 | 
			
		||||
		ox::String m_newName;
 | 
			
		||||
		int m_newCols = 0;
 | 
			
		||||
		int m_newRows = 0;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		UpdateSubSheetCommand(
 | 
			
		||||
				TileSheet &img,
 | 
			
		||||
				TileSheet::SubSheetIdx idx,
 | 
			
		||||
				ox::StringParam name,
 | 
			
		||||
				ox::String name,
 | 
			
		||||
				int cols,
 | 
			
		||||
				int rows);
 | 
			
		||||
				int rows) noexcept;
 | 
			
		||||
 | 
			
		||||
		ox::Error redo() noexcept final;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,11 @@
 | 
			
		||||
 | 
			
		||||
namespace nostalgia::core {
 | 
			
		||||
 | 
			
		||||
Palette const TileSheetEditorModel::s_defaultPalette = {
 | 
			
		||||
	.colorNames = {ox::Vector<ox::String>{{}}},
 | 
			
		||||
	.pages = {{"Page 1", ox::Vector<Color16>(128)}},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// delete pixels of all non-leaf nodes
 | 
			
		||||
static void normalizeSubsheets(TileSheet::SubSheet &ss) noexcept {
 | 
			
		||||
	if (ss.subsheets.empty()) {
 | 
			
		||||
@@ -37,14 +42,7 @@ static void normalizeSubsheets(TileSheet::SubSheet &ss) noexcept {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Palette const TileSheetEditorModel::s_defaultPalette = {
 | 
			
		||||
	.colorNames = {ox::Vector<ox::String>{{}}},
 | 
			
		||||
	.pages = {{"Page 1", ox::Vector<Color16>(128)}},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
TileSheetEditorModel::TileSheetEditorModel(
 | 
			
		||||
		studio::StudioContext &sctx, ox::StringViewCR path, studio::UndoStack &undoStack):
 | 
			
		||||
TileSheetEditorModel::TileSheetEditorModel(studio::StudioContext &sctx, ox::StringView path, studio::UndoStack &undoStack):
 | 
			
		||||
	m_sctx(sctx),
 | 
			
		||||
	m_tctx(m_sctx.tctx),
 | 
			
		||||
	m_path(path),
 | 
			
		||||
@@ -64,7 +62,7 @@ void TileSheetEditorModel::cut() {
 | 
			
		||||
	TileSheetClipboard blankCb;
 | 
			
		||||
	auto cb = ox::make_unique<TileSheetClipboard>();
 | 
			
		||||
	auto const&s = activeSubSheet();
 | 
			
		||||
	iterateSelectionRows(*m_selection, [&](int const x, int const y) {
 | 
			
		||||
	iterateSelectionRows(*m_selection, [&](int x, int y) {
 | 
			
		||||
		auto pt = ox::Point{x, y};
 | 
			
		||||
		auto const idx = core::idx(s, pt);
 | 
			
		||||
		auto const c = getPixel(s, m_img.bpp, idx);
 | 
			
		||||
@@ -75,8 +73,7 @@ void TileSheetEditorModel::cut() {
 | 
			
		||||
	auto const pt1 = m_selection->a;
 | 
			
		||||
	auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
 | 
			
		||||
	turbine::setClipboardObject(m_tctx, std::move(cb));
 | 
			
		||||
	pushCommand(ox::make<CutPasteCommand>(
 | 
			
		||||
		CommandId::Cut, m_img, m_activeSubsSheetIdx, pt1, pt2, blankCb));
 | 
			
		||||
	pushCommand(ox::make<CutPasteCommand>(CommandId::Cut, m_img, m_activeSubsSheetIdx, pt1, pt2, blankCb));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TileSheetEditorModel::copy() {
 | 
			
		||||
@@ -84,7 +81,7 @@ void TileSheetEditorModel::copy() {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	auto cb = ox::make_unique<TileSheetClipboard>();
 | 
			
		||||
	iterateSelectionRows(*m_selection, [&](int const x, int const y) {
 | 
			
		||||
	iterateSelectionRows(*m_selection, [&](int x, int y) {
 | 
			
		||||
		auto pt = ox::Point{x, y};
 | 
			
		||||
		const auto&s = activeSubSheet();
 | 
			
		||||
		const auto idx = core::idx(s, pt);
 | 
			
		||||
@@ -108,8 +105,7 @@ void TileSheetEditorModel::paste() {
 | 
			
		||||
	auto const&s = activeSubSheet();
 | 
			
		||||
	auto const pt1 = m_selection->a;
 | 
			
		||||
	auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
 | 
			
		||||
	pushCommand(ox::make<CutPasteCommand>(
 | 
			
		||||
		CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb));
 | 
			
		||||
	pushCommand(ox::make<CutPasteCommand>(CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TileSheetEditorModel::acceptsClipboardPayload() const noexcept {
 | 
			
		||||
@@ -124,8 +120,8 @@ ox::StringView TileSheetEditorModel::palPath() const noexcept {
 | 
			
		||||
	}
 | 
			
		||||
	constexpr ox::StringView uuidPrefix = "uuid://";
 | 
			
		||||
	if (ox::beginsWith(path, uuidPrefix)) {
 | 
			
		||||
		auto const uuid = ox::StringView(&path[uuidPrefix.bytes()], path.bytes() - uuidPrefix.bytes());
 | 
			
		||||
		auto const out = keelCtx(m_tctx).uuidToPath.at(uuid);
 | 
			
		||||
		auto uuid = ox::StringView(&path[uuidPrefix.bytes()], path.bytes() - uuidPrefix.bytes());
 | 
			
		||||
		auto out = keelCtx(m_tctx).uuidToPath.at(uuid);
 | 
			
		||||
		if (out.error) {
 | 
			
		||||
			return {};
 | 
			
		||||
		}
 | 
			
		||||
@@ -135,14 +131,13 @@ ox::StringView TileSheetEditorModel::palPath() const noexcept {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::Error TileSheetEditorModel::setPalette(ox::StringViewCR path) noexcept {
 | 
			
		||||
ox::Error TileSheetEditorModel::setPalette(ox::StringView path) noexcept {
 | 
			
		||||
	OX_REQUIRE(uuid, keelCtx(m_tctx).pathToUuid.at(path));
 | 
			
		||||
	pushCommand(ox::make<PaletteChangeCommand>(
 | 
			
		||||
		activeSubSheetIdx(), m_img, uuid->toString()));
 | 
			
		||||
	pushCommand(ox::make<PaletteChangeCommand>(activeSubSheetIdx(), m_img, uuid->toString()));
 | 
			
		||||
	return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TileSheetEditorModel::setPalettePage(size_t const pg) noexcept {
 | 
			
		||||
void TileSheetEditorModel::setPalettePage(size_t pg) noexcept {
 | 
			
		||||
	m_palettePage = ox::clamp<size_t>(pg, 0, m_pal->pages.size() - 1);
 | 
			
		||||
	m_updated = true;
 | 
			
		||||
}
 | 
			
		||||
@@ -151,7 +146,7 @@ size_t TileSheetEditorModel::palettePage() const noexcept {
 | 
			
		||||
	return m_palettePage;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TileSheetEditorModel::drawCommand(ox::Point const&pt, std::size_t const palIdx) noexcept {
 | 
			
		||||
void TileSheetEditorModel::drawCommand(ox::Point const&pt, std::size_t palIdx) noexcept {
 | 
			
		||||
	const auto &activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx);
 | 
			
		||||
	if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) {
 | 
			
		||||
		return;
 | 
			
		||||
@@ -160,8 +155,7 @@ void TileSheetEditorModel::drawCommand(ox::Point const&pt, std::size_t const pal
 | 
			
		||||
	if (m_ongoingDrawCommand) {
 | 
			
		||||
		m_updated = m_updated || m_ongoingDrawCommand->append(idx);
 | 
			
		||||
	} else if (getPixel(activeSubSheet, m_img.bpp, idx) != palIdx) {
 | 
			
		||||
		pushCommand(ox::make<DrawCommand>(
 | 
			
		||||
			m_img, m_activeSubsSheetIdx, idx, static_cast<int>(palIdx)));
 | 
			
		||||
		pushCommand(ox::make<DrawCommand>(m_img, m_activeSubsSheetIdx, idx, static_cast<int>(palIdx)));
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -177,20 +171,16 @@ void TileSheetEditorModel::rmSubsheet(TileSheet::SubSheetIdx const&idx) noexcept
 | 
			
		||||
	pushCommand(ox::make<RmSubSheetCommand>(m_img, idx));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TileSheetEditorModel::insertTiles(
 | 
			
		||||
	TileSheet::SubSheetIdx const&idx, std::size_t const tileIdx, std::size_t const tileCnt) noexcept {
 | 
			
		||||
void TileSheetEditorModel::insertTiles(TileSheet::SubSheetIdx const&idx, std::size_t tileIdx, std::size_t tileCnt) noexcept {
 | 
			
		||||
	pushCommand(ox::make<InsertTilesCommand>(m_img, idx, tileIdx, tileCnt));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TileSheetEditorModel::deleteTiles(
 | 
			
		||||
	TileSheet::SubSheetIdx const&idx, std::size_t const tileIdx, std::size_t const tileCnt) noexcept {
 | 
			
		||||
void TileSheetEditorModel::deleteTiles(TileSheet::SubSheetIdx const&idx, std::size_t tileIdx, std::size_t tileCnt) noexcept {
 | 
			
		||||
	pushCommand(ox::make<DeleteTilesCommand>(m_img, idx, tileIdx, tileCnt));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ox::Error TileSheetEditorModel::updateSubsheet(
 | 
			
		||||
	TileSheet::SubSheetIdx const&idx, ox::StringViewCR name, int const cols, int const rows) noexcept {
 | 
			
		||||
	OX_REQUIRE(cmd, ox::makeCatch<UpdateSubSheetCommand>(m_img, idx, name, cols, rows));
 | 
			
		||||
	pushCommand(cmd);
 | 
			
		||||
ox::Error TileSheetEditorModel::updateSubsheet(TileSheet::SubSheetIdx const&idx, ox::StringView const&name, int cols, int rows) noexcept {
 | 
			
		||||
	pushCommand(ox::make<UpdateSubSheetCommand>(m_img, idx, ox::String(name), cols, rows));
 | 
			
		||||
	return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -199,7 +189,7 @@ void TileSheetEditorModel::setActiveSubsheet(TileSheet::SubSheetIdx const&idx) n
 | 
			
		||||
	this->activeSubsheetChanged.emit(m_activeSubsSheetIdx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TileSheetEditorModel::fill(ox::Point const&pt, int const palIdx) noexcept {
 | 
			
		||||
void TileSheetEditorModel::fill(ox::Point const&pt, int palIdx) noexcept {
 | 
			
		||||
	auto const&activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx);
 | 
			
		||||
	// build idx list
 | 
			
		||||
	if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) {
 | 
			
		||||
@@ -207,10 +197,10 @@ void TileSheetEditorModel::fill(ox::Point const&pt, int const palIdx) noexcept {
 | 
			
		||||
	}
 | 
			
		||||
	ox::Array<bool, PixelsPerTile> updateMap = {};
 | 
			
		||||
	auto const oldColor = getPixel(activeSubSheet, m_img.bpp, pt);
 | 
			
		||||
	getFillPixels(activeSubSheet, updateMap, pt, oldColor);
 | 
			
		||||
	getFillPixels(updateMap, pt, oldColor);
 | 
			
		||||
	ox::Vector<std::size_t> idxList;
 | 
			
		||||
	auto i = core::idx(activeSubSheet, pt) / PixelsPerTile * PixelsPerTile;
 | 
			
		||||
	for (auto const u : updateMap) {
 | 
			
		||||
	for (auto u : updateMap) {
 | 
			
		||||
		if (u) {
 | 
			
		||||
			idxList.emplace_back(i);
 | 
			
		||||
		}
 | 
			
		||||
@@ -240,7 +230,7 @@ void TileSheetEditorModel::completeSelection() noexcept {
 | 
			
		||||
		m_selTracker.finishSelection();
 | 
			
		||||
		m_selection.emplace(m_selTracker.selection());
 | 
			
		||||
		auto&pt = m_selection->b;
 | 
			
		||||
		auto const&s = activeSubSheet();
 | 
			
		||||
		auto&s = activeSubSheet();
 | 
			
		||||
		pt.x = ox::min(s.columns * TileWidth - 1, pt.x);
 | 
			
		||||
		pt.y = ox::min(s.rows * TileHeight - 1, pt.y);
 | 
			
		||||
	}
 | 
			
		||||
@@ -285,44 +275,47 @@ ox::Error TileSheetEditorModel::saveFile() noexcept {
 | 
			
		||||
	return m_sctx.project->writeObj(m_path, m_img, ox::ClawFormat::Metal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TileSheetEditorModel::pixelSelected(std::size_t const idx) const noexcept {
 | 
			
		||||
bool TileSheetEditorModel::pixelSelected(std::size_t idx) const noexcept {
 | 
			
		||||
	auto const&s = activeSubSheet();
 | 
			
		||||
	auto const pt = idxToPt(static_cast<int>(idx), s.columns);
 | 
			
		||||
	return m_selection && m_selection->contains(pt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TileSheetEditorModel::getFillPixels(
 | 
			
		||||
		TileSheet::SubSheet const&activeSubSheet,
 | 
			
		||||
		ox::Span<bool> pixels,
 | 
			
		||||
		ox::Point const&pt,
 | 
			
		||||
		int const oldColor) const noexcept {
 | 
			
		||||
	auto const idx = ptToIdx(pt, activeSubSheet.columns);
 | 
			
		||||
	auto const relIdx = idx % PixelsPerTile;
 | 
			
		||||
	if (pixels[relIdx] || getPixel(activeSubSheet, m_img.bpp, idx) != oldColor) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
void TileSheetEditorModel::getFillPixels(ox::Span<bool> pixels, ox::Point const&pt, int oldColor) const noexcept {
 | 
			
		||||
	const auto &activeSubSheet = this->activeSubSheet();
 | 
			
		||||
	const auto tileIdx = [activeSubSheet](const ox::Point &pt) noexcept {
 | 
			
		||||
		return ptToIdx(pt, activeSubSheet.columns) / PixelsPerTile;
 | 
			
		||||
	};
 | 
			
		||||
	// get points
 | 
			
		||||
	const auto leftPt = pt + ox::Point(-1, 0);
 | 
			
		||||
	const auto rightPt = pt + ox::Point(1, 0);
 | 
			
		||||
	const auto topPt = pt + ox::Point(0, -1);
 | 
			
		||||
	const auto bottomPt = pt + ox::Point(0, 1);
 | 
			
		||||
	// calculate indices
 | 
			
		||||
	const auto idx = ptToIdx(pt, activeSubSheet.columns);
 | 
			
		||||
	const auto leftIdx = ptToIdx(leftPt, activeSubSheet.columns);
 | 
			
		||||
	const auto rightIdx = ptToIdx(rightPt, activeSubSheet.columns);
 | 
			
		||||
	const auto topIdx = ptToIdx(topPt, activeSubSheet.columns);
 | 
			
		||||
	const auto bottomIdx = ptToIdx(bottomPt, activeSubSheet.columns);
 | 
			
		||||
	const auto tile = tileIdx(pt);
 | 
			
		||||
	// mark pixels to update
 | 
			
		||||
	pixels[relIdx] = true;
 | 
			
		||||
	if (pt.x % TileWidth != 0) {
 | 
			
		||||
		auto const leftPt = pt + ox::Point{-1, 0};
 | 
			
		||||
		getFillPixels(activeSubSheet, pixels, leftPt, oldColor);
 | 
			
		||||
	pixels[idx % PixelsPerTile] = true;
 | 
			
		||||
	if (!pixels[leftIdx % PixelsPerTile] && tile == tileIdx(leftPt) && getPixel(activeSubSheet, m_img.bpp, leftIdx) == oldColor) {
 | 
			
		||||
		getFillPixels(pixels, leftPt, oldColor);
 | 
			
		||||
	}
 | 
			
		||||
	if (pt.x % TileWidth != TileWidth - 1) {
 | 
			
		||||
		auto const rightPt = pt + ox::Point{1, 0};
 | 
			
		||||
		getFillPixels(activeSubSheet, pixels, rightPt, oldColor);
 | 
			
		||||
	if (!pixels[rightIdx % PixelsPerTile] && tile == tileIdx(rightPt) && getPixel(activeSubSheet, m_img.bpp, rightIdx) == oldColor) {
 | 
			
		||||
		getFillPixels(pixels, rightPt, oldColor);
 | 
			
		||||
	}
 | 
			
		||||
	if (pt.y % TileHeight != 0) {
 | 
			
		||||
		auto const topPt = pt + ox::Point{0, -1};
 | 
			
		||||
		getFillPixels(activeSubSheet, pixels, topPt, oldColor);
 | 
			
		||||
	if (!pixels[topIdx % PixelsPerTile] && tile == tileIdx(topPt) && getPixel(activeSubSheet, m_img.bpp, topIdx) == oldColor) {
 | 
			
		||||
		getFillPixels(pixels, topPt, oldColor);
 | 
			
		||||
	}
 | 
			
		||||
	if (pt.y % TileHeight != TileHeight - 1) {
 | 
			
		||||
		auto const bottomPt = pt + ox::Point{0, 1};
 | 
			
		||||
		getFillPixels(activeSubSheet, pixels, bottomPt, oldColor);
 | 
			
		||||
	if (!pixels[bottomIdx % PixelsPerTile] && tile == tileIdx(bottomPt) && getPixel(activeSubSheet, m_img.bpp, bottomIdx) == oldColor) {
 | 
			
		||||
		getFillPixels(pixels, bottomPt, oldColor);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TileSheetEditorModel::pushCommand(studio::UndoCommand *cmd) noexcept {
 | 
			
		||||
	std::ignore = m_undoStack.push(ox::UPtr<studio::UndoCommand>{cmd});
 | 
			
		||||
	std::ignore = m_undoStack.push(ox::UPtr<studio::UndoCommand>(cmd));
 | 
			
		||||
	m_ongoingDrawCommand = dynamic_cast<DrawCommand*>(cmd);
 | 
			
		||||
	m_updated = true;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,9 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <ox/std/bounds.hpp>
 | 
			
		||||
#include <ox/std/point.hpp>
 | 
			
		||||
#include <ox/std/trace.hpp>
 | 
			
		||||
#include <ox/std/string.hpp>
 | 
			
		||||
 | 
			
		||||
#include <studio/studio.hpp>
 | 
			
		||||
@@ -36,7 +38,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
 | 
			
		||||
		bool m_updated = false;
 | 
			
		||||
 | 
			
		||||
	public:
 | 
			
		||||
		TileSheetEditorModel(studio::StudioContext &sctx, ox::StringViewCR path, studio::UndoStack &undoStack);
 | 
			
		||||
		TileSheetEditorModel(studio::StudioContext &sctx, ox::StringView path, studio::UndoStack &undoStack);
 | 
			
		||||
 | 
			
		||||
		~TileSheetEditorModel() override = default;
 | 
			
		||||
 | 
			
		||||
@@ -61,7 +63,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
 | 
			
		||||
		[[nodiscard]]
 | 
			
		||||
		ox::StringView palPath() const noexcept;
 | 
			
		||||
 | 
			
		||||
		ox::Error setPalette(ox::StringViewCR path) noexcept;
 | 
			
		||||
		ox::Error setPalette(ox::StringView path) noexcept;
 | 
			
		||||
 | 
			
		||||
		void setPalettePage(size_t pg) noexcept;
 | 
			
		||||
 | 
			
		||||
@@ -126,11 +128,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
 | 
			
		||||
		bool pixelSelected(std::size_t idx) const noexcept;
 | 
			
		||||
 | 
			
		||||
	private:
 | 
			
		||||
		void getFillPixels(
 | 
			
		||||
			TileSheet::SubSheet const&activeSubSheet,
 | 
			
		||||
			ox::Span<bool> pixels,
 | 
			
		||||
			ox::Point const&pt,
 | 
			
		||||
			int oldColor) const noexcept;
 | 
			
		||||
		void getFillPixels(ox::Span<bool> pixels, ox::Point const&pt, int oldColor) const noexcept;
 | 
			
		||||
 | 
			
		||||
		void pushCommand(studio::UndoCommand *cmd) noexcept;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -66,10 +66,10 @@ static ox::Optional<size_t> getPixelIdx(
 | 
			
		||||
	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{};
 | 
			
		||||
	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 {
 | 
			
		||||
@@ -355,12 +355,12 @@ ox::Result<SubSheetId> getIdFor(TileSheet const&ts, ox::StringViewCR path) noexc
 | 
			
		||||
/**
 | 
			
		||||
 * Gets the offset in tiles of the desired subsheet.
 | 
			
		||||
 */
 | 
			
		||||
static ox::Result<unsigned> getTileOffset(
 | 
			
		||||
static ox::Result<uint32_t> getTileOffset(
 | 
			
		||||
		TileSheet::SubSheet const&ss,
 | 
			
		||||
		ox::SpanView<ox::StringView> const&pNamePath,
 | 
			
		||||
		int8_t pBpp,
 | 
			
		||||
		std::size_t pIt = 0,
 | 
			
		||||
		unsigned pCurrentTotal = 0) noexcept {
 | 
			
		||||
		uint32_t pCurrentTotal = 0) noexcept {
 | 
			
		||||
	// pIt == pNamePath.size() - 1 &&
 | 
			
		||||
	if (ss.name != pNamePath[pIt]) {
 | 
			
		||||
		return ox::Error(2, "Wrong branch");
 | 
			
		||||
@@ -374,12 +374,14 @@ static ox::Result<unsigned> getTileOffset(
 | 
			
		||||
		if (!err) {
 | 
			
		||||
			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;
 | 
			
		||||
	}
 | 
			
		||||
	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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ target_link_libraries(
 | 
			
		||||
 | 
			
		||||
target_compile_definitions(
 | 
			
		||||
	NostalgiaStudio PUBLIC
 | 
			
		||||
		OLYMPIC_APP_VERSION="d2024.12.3"
 | 
			
		||||
		OLYMPIC_APP_VERSION="dev build"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
install(
 | 
			
		||||
 
 | 
			
		||||
@@ -196,15 +196,15 @@ class AssetManager {
 | 
			
		||||
		template<typename T>
 | 
			
		||||
		class AssetTypeManager: public AssetTypeManagerBase {
 | 
			
		||||
			public:
 | 
			
		||||
				using Loader = std::function<ox::Result<T>(ox::StringView assetId)>;
 | 
			
		||||
				using Loader = std::function<ox::Result<T>(ox::StringViewCR assetId)>;
 | 
			
		||||
			private:
 | 
			
		||||
				Loader m_loader{};
 | 
			
		||||
				ox::HashMap<ox::String, ox::UPtr<AssetContainer<T>>> m_cache;
 | 
			
		||||
 | 
			
		||||
			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));
 | 
			
		||||
					if (!out || !*out) {
 | 
			
		||||
						return ox::Error(1, "asset is null");
 | 
			
		||||
@@ -212,7 +212,7 @@ class AssetManager {
 | 
			
		||||
					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];
 | 
			
		||||
					OX_REQUIRE_M(obj, m_loader(assetId));
 | 
			
		||||
					if (!p) {
 | 
			
		||||
@@ -224,7 +224,7 @@ class AssetManager {
 | 
			
		||||
					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];
 | 
			
		||||
					OX_REQUIRE_M(obj, m_loader(assetId));
 | 
			
		||||
					if (!p) {
 | 
			
		||||
@@ -247,7 +247,7 @@ class AssetManager {
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		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>
 | 
			
		||||
		ox::Result<AssetTypeManager<T>*> getTypeManager() noexcept {
 | 
			
		||||
@@ -273,18 +273,18 @@ class AssetManager {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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>());
 | 
			
		||||
			return m->getAsset(assetId);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ox::Error reloadAsset(ox::StringView assetId) noexcept {
 | 
			
		||||
		ox::Error reloadAsset(ox::StringViewCR assetId) noexcept {
 | 
			
		||||
			m_fileUpdated[assetId].emit(assetId);
 | 
			
		||||
			return {};
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		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(out, m->loadAsset(assetId));
 | 
			
		||||
			m_fileUpdated[assetId].connect(m, &AssetTypeManager<T>::reloadAsset);
 | 
			
		||||
 
 | 
			
		||||
@@ -77,12 +77,12 @@ StudioUI::StudioUI(turbine::Context &ctx, ox::StringParam projectDataDir) noexce
 | 
			
		||||
		} else {
 | 
			
		||||
			oxErrf(
 | 
			
		||||
					"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) {
 | 
			
		||||
		if (p->isOpen()) {
 | 
			
		||||
			if (key == turbine::Key::Escape) {
 | 
			
		||||
@@ -168,7 +168,7 @@ void StudioUI::drawMenu() noexcept {
 | 
			
		||||
			ImGui::EndMenu();
 | 
			
		||||
		}
 | 
			
		||||
		if (ImGui::BeginMenu("View")) {
 | 
			
		||||
			if (ImGui::MenuItem("Project Explorer", "Ctrl+1", m_showProjectExplorer)) {
 | 
			
		||||
			if (ImGui::MenuItem("Project Explorer", "Ctrl+Shift+1", m_showProjectExplorer)) {
 | 
			
		||||
				toggleProjectExplorer();
 | 
			
		||||
			}
 | 
			
		||||
			ImGui::EndMenu();
 | 
			
		||||
@@ -227,7 +227,7 @@ void StudioUI::drawTabs() noexcept {
 | 
			
		||||
			try {
 | 
			
		||||
				OX_THROW_ERROR(m_editors.erase(it).moveTo(it));
 | 
			
		||||
			} 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) {
 | 
			
		||||
				oxErrf("Editor tab deletion failed: {}\n", ex.what());
 | 
			
		||||
			}
 | 
			
		||||
@@ -317,8 +317,22 @@ void StudioUI::handleKeyInput() noexcept {
 | 
			
		||||
		} else if (ImGui::IsKeyPressed(ImGuiKey_Z)) {
 | 
			
		||||
			auto const undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
 | 
			
		||||
			if (undoStack) { oxLogError(undoStack->undo()); }
 | 
			
		||||
		} else if (ImGui::IsKeyPressed(ImGuiKey_1)) {
 | 
			
		||||
		} else if (ImGui::IsKeyPressed(ImGuiKey_1) && ImGui::IsKeyPressed(ImGuiKey_ModShift)) {
 | 
			
		||||
			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;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -379,7 +393,7 @@ ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool makeActiveTab)
 | 
			
		||||
		if constexpr(!ox::defines::Debug) {
 | 
			
		||||
			oxErrf("Could not open Editor: {}\n", toStr(err));
 | 
			
		||||
		} 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;
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@ namespace studio {
 | 
			
		||||
class NoChangesException: public ox::Exception {
 | 
			
		||||
	public:
 | 
			
		||||
		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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ void BaseEditor::save() noexcept {
 | 
			
		||||
		setUnsavedChanges(false);
 | 
			
		||||
	} else {
 | 
			
		||||
		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 {
 | 
			
		||||
			oxErrorf("Could not save file {}: {}", itemPath(), toStr(err));
 | 
			
		||||
		}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ target_include_directories(
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
target_sources(
 | 
			
		||||
	Turbine PUBLIC
 | 
			
		||||
	Turbine PRIVATE
 | 
			
		||||
		turbine.cpp
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
FROM fedora:36
 | 
			
		||||
FROM fedora:41
 | 
			
		||||
 | 
			
		||||
RUN dnf update -y
 | 
			
		||||
 | 
			
		||||
@@ -28,11 +28,11 @@ project_name = sys.argv[2]
 | 
			
		||||
bin = f'./build/{host_env}-{current_build}/bin/'
 | 
			
		||||
project_bin = f'build/gba-release/bin/{project_name}.bin'
 | 
			
		||||
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)
 | 
			
		||||
subprocess.run([
 | 
			
		||||
    f'{bin}/{project_name}-pack',
 | 
			
		||||
    f'{bin}/{project_name.lower()}-pack',
 | 
			
		||||
        '-src', project_dir,
 | 
			
		||||
        '-rom-bin', project_gba,
 | 
			
		||||
        '-manifest', project_manifest])
 | 
			
		||||
		Reference in New Issue
	
	Block a user