Compare commits

..

19 Commits

Author SHA1 Message Date
144d234d09 [nostalgia/studio] Change version to release-d2024.12
All checks were successful
Build / build (push) Successful in 3m20s
2025-01-12 21:03:34 -06:00
465fb06f76 [nostalgia/core] Fix TileSheet validation/repair to ensure pixels gets cleared if there are subsheets
Some checks failed
Build / build (push) Has been cancelled
2025-01-12 20:58:19 -06:00
db953dd0d1 [studio] Fix new project menu to return an appropriately sized string for name 2025-01-12 20:58:19 -06:00
daab4dc4f5 [nostalgia/core/studio] Fix SubSheet editor to return an appropriately sized string 2025-01-12 20:58:19 -06:00
83cbac5cca [nostalgia/studio] Update version to d2024.12.1
All checks were successful
Build / build (push) Successful in 3m19s
2025-01-11 17:22:02 -06:00
74e518fee0 [nostalgia/core/studio/tilesheeteditor] Fix select all not to go beyond end 2025-01-11 17:07:50 -06:00
6b0ce40c02 [nostalgia/core/studio] Fix crash that occurs when a non-leaf node subsheet is selected 2025-01-11 17:07:50 -06:00
4f55964dd9 [nostalgia/core/studio] Fix tile insert to correct input when inserting past the last tile 2025-01-11 17:07:50 -06:00
cb597cf92e [nostalgia/core/studio] Fix tile insert to work on last tile 2025-01-11 17:07:50 -06:00
6906c66ba7 [keel] Fix reloadAsset 2025-01-11 17:07:50 -06:00
ba00d10dfc [nostalgia] Update liccor file 2025-01-11 17:07:50 -06:00
cdfbfe48b7 [ox] Update liccor file 2025-01-11 17:07:50 -06:00
21ae2a14e9 [ox] Run liccor 2025-01-11 17:07:50 -06:00
81b120b1ce [nostalgia,olympic] Run liccor 2025-01-11 17:07:50 -06:00
40938958de [turbine/glfw] Ensure window opens with a standard mandatory refresh period 2025-01-11 17:07:50 -06:00
df190c05a0 [studio] Make first tab not draw before selected tab when window opens 2025-01-11 17:07:50 -06:00
3fe3b08eca [ox/std] Add hash.hpp to install 2025-01-11 17:07:50 -06:00
ecc5ae6b2f [studio] Make selection tracker not go below 0 2025-01-11 17:07:50 -06:00
a863bfc181 [nostalgia/studio] Update version to d2024.12.0
All checks were successful
Build / build (push) Successful in 3m20s
2024-12-21 19:27:00 -06:00
55 changed files with 345 additions and 725 deletions

2
.gitignore vendored
View File

@ -6,7 +6,7 @@
.mypy_cache .mypy_cache
.stfolder .stfolder
.stignore .stignore
util/scripts/__pycache__ scripts/__pycache__
pyenv pyenv
CMakeLists.txt.user CMakeLists.txt.user
ROM.oxfs ROM.oxfs

View File

@ -1,4 +1,4 @@
FROM fedora:41 FROM fedora:36
RUN dnf update -y RUN dnf update -y

View File

@ -1,6 +1,5 @@
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
@ -14,7 +13,7 @@ endif
.PHONY: pkg-gba .PHONY: pkg-gba
pkg-gba: build pkg-gba: build
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME} ${BC_CMD_ENVRUN} ${BC_PY3} ./scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME}
.PHONY: run .PHONY: run
run: build run: build

View File

@ -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")

View File

@ -1,11 +1,2 @@
add_library(glad src/glad.c) add_library(glad OBJECT 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
)

View File

@ -6,7 +6,7 @@ endif()
# DrinkingTea: end # DrinkingTea: end
add_library( add_library(
imgui imgui OBJECT
imgui.cpp imgui.cpp
imgui_demo.cpp imgui_demo.cpp
imgui_draw.cpp imgui_draw.cpp
@ -19,12 +19,4 @@ add_library(
target_include_directories( target_include_directories(
imgui SYSTEM PUBLIC imgui SYSTEM PUBLIC
. .
) )
install(
TARGETS
imgui
DESTINATION
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)

View File

@ -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.errCode, ex.msg, ex.src); return ox::Error(ex.file, ex.line, ex.errCode, ex.msg);
} }
} }

View File

@ -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.src.file_name(), loggerErr.src.line()); \ oxErrf("Could not connect to logger: {} ({}:{})\n", toStr(loggerErr), loggerErr.file, loggerErr.line); \
} else { \ } else { \
ox::trace::setLogger(&(loggerName)); \ ox::trace::setLogger(&(loggerName)); \
} \ } \

View File

@ -140,16 +140,16 @@ constexpr Str getModelTypeName() noexcept {
return out; return out;
} }
template<typename T, typename Str = const char*> template<typename T>
[[nodiscard]] [[nodiscard]]
consteval auto requireModelTypeName() noexcept { consteval auto requireModelTypeName() noexcept {
constexpr auto name = getModelTypeName<T, Str>(); constexpr auto name = getModelTypeName<T>();
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 = requireModelTypeName<T, Str>(); constexpr auto ModelTypeName_v = getModelTypeName<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>();

View File

@ -9,25 +9,13 @@
#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 ox::Result<size_t> findIdx(It begin, It end, T const&value) { constexpr It find(It begin, It end, const T &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;

View File

@ -7,7 +7,6 @@
*/ */
#include "fmt.hpp" #include "fmt.hpp"
#include "realstd.hpp"
#include "stacktrace.hpp" #include "stacktrace.hpp"
#include "trace.hpp" #include "trace.hpp"
@ -15,14 +14,14 @@
namespace ox { namespace ox {
void panic(StringViewCR file, int const line, StringViewCR panicMsg, Error const&err) noexcept { void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &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.src.file_name() != nullptr) { if (err.file != nullptr) {
oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line()); oxErrf("\tError Location:\t{}:{}\n", err.file, err.line);
} }
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
printStackTrace(2); printStackTrace(2);
@ -33,19 +32,16 @@ void panic(StringViewCR file, int const line, StringViewCR panicMsg, Error const
#endif #endif
} }
void panic(const char *file, int const line, char const*panicMsg, Error const&err) noexcept { void panic(const char *file, int line, const char *panicMsg, const Error &err) noexcept {
panic(StringView{file}, line, StringView{panicMsg}, err); panic(StringView{file}, line, StringView{panicMsg}, err);
} }
void assertFailFuncRuntime( void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept {
StringViewCR file,
int const line,
StringViewCR assertTxt,
StringViewCR msg) noexcept {
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
auto const st = genStackTrace(2); auto output = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]:\n{}", msg, assertTxt, file, line, st); output += genStackTrace(2);
abort(); oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
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);
@ -53,25 +49,20 @@ void assertFailFuncRuntime(
#endif #endif
} }
void assertFailFuncRuntime( void assertFailFuncRuntime(StringViewCR file, int line, [[maybe_unused]] const Error &err, StringViewCR, StringViewCR assertMsg) noexcept {
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.src.file_name() != nullptr) { if (err.file != nullptr) {
msg += sfmt("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line()); msg += sfmt("\tError Location:\t{}:{}\n", err.file, err.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);
abort(); std::abort();
#else #else
constexprPanic(file, line, assertMsg); constexprPanic(file, line, assertMsg);
#endif #endif

View File

@ -22,15 +22,9 @@
namespace ox { namespace ox {
[[noreturn]] void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err = ox::Error(0)) noexcept;
void panic(StringViewCR file, int line, StringViewCR panicMsg, Error const&err = {}) noexcept;
[[noreturn]] constexpr void constexprPanic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err = ox::Error(0)) noexcept {
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 {
@ -38,24 +32,10 @@ constexpr void constexprPanic(
} }
} }
void assertFailFuncRuntime( void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept;
StringViewCR file, void assertFailFuncRuntime(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept;
int line,
StringViewCR assertTxt,
StringViewCR msg) noexcept;
void assertFailFuncRuntime(
StringViewCR file,
int line,
Error const&err,
StringViewCR,
StringViewCR assertMsg) noexcept;
constexpr void assertFunc( constexpr void assertFunc(StringViewCR file, int line, bool pass, [[maybe_unused]]StringViewCR assertTxt, [[maybe_unused]]StringViewCR msg) noexcept {
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);
@ -65,12 +45,7 @@ constexpr void assertFunc(
} }
} }
constexpr void assertFunc( constexpr void assertFunc(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept {
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);
@ -80,11 +55,7 @@ constexpr void assertFunc(
} }
} }
constexpr void expect( constexpr void expect(StringViewCR file, int line, const auto &actual, const auto &expected) noexcept {
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)

View File

@ -36,16 +36,28 @@ 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:
src{src}, file{src.file_name()},
line{static_cast<uint16_t>(src.line())},
errCode{errCode} errCode{errCode}
{} {}
@ -53,8 +65,9 @@ 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}
{} {}
@ -76,31 +89,42 @@ 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 Exception( 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, ErrorCode const errCode,
std::source_location const&src = std::source_location::current()) noexcept: std::source_location const&src = std::source_location::current()) noexcept:
src{src}, file{src.file_name()},
line{static_cast<uint16_t>(src.line())},
errCode{errCode} {} errCode{errCode} {}
explicit Exception( explicit inline 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 Exception(Error const&err) noexcept: explicit inline 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(errCode, msg, src); return Error(file, line, errCode, msg);
} }
[[nodiscard]] [[nodiscard]]
@ -109,7 +133,6 @@ 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>

View File

@ -31,6 +31,7 @@ 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;

View File

@ -12,13 +12,4 @@
#include <cassert> #include <cassert>
#else #else
#define assert(e) while (!(e)); #define assert(e) while (!(e));
#endif
#if __has_include(<cstdlib>)
#include <cstdlib>
#else
extern "C" {
[[noreturn]]
void abort();
}
#endif #endif

View File

@ -62,9 +62,6 @@ 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;
@ -85,22 +82,14 @@ 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);
}; };
@ -140,7 +129,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;
} }
@ -149,7 +138,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 const p = accessNoCreate(m_pairs, k); auto p = access(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")};
} }
@ -158,8 +147,7 @@ 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 {
bool isNew{}; auto p = access(m_pairs, k);
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")};
} }
@ -180,8 +168,7 @@ 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 {
bool isNew{}; return access(m_pairs, k) != nullptr;
return access(m_pairs, k, isNew) != nullptr;
} }
template<typename K, typename T, size_t SmallSz> template<typename K, typename T, size_t SmallSz>
@ -199,16 +186,6 @@ 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;
@ -241,42 +218,30 @@ 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 nullptr; return pairs.emplace_back();
} }
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>

View File

@ -14,7 +14,7 @@
#include "iterator.hpp" #include "iterator.hpp"
#include "vector.hpp" #include "vector.hpp"
OX_ALLOW_UNSAFE_BUFFERS_BEGIN OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox { namespace ox {
@ -133,7 +133,7 @@ class Span {
return m_items[i]; return m_items[i];
} }
constexpr T const&operator[](std::size_t i) const noexcept { constexpr const T &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,20 +168,8 @@ class Span {
}; };
template<typename T> template<typename T>
using SpanView = Span<T const>; using SpanView = Span<const T>;
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_ALLOW_UNSAFE_BUFFERS_END OX_CLANG_NOWARN_END

View File

@ -17,8 +17,6 @@ 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")

View File

@ -237,50 +237,6 @@ 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",
[] { [] {
@ -290,18 +246,7 @@ 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);
ox::SmallMap<ox::String, ox::String> cmap; return ox::Error(0);
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);
} }
}, },
{ {

View File

@ -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.src.file_name() != nullptr) { if (err.file != nullptr) {
trc << "Error: (" << err.src.file_name() << ":" << err.src.line() << "):"; trc << "Error: (" << err.file << ":" << err.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.src.file_name() != nullptr) { if (err.file != nullptr) {
trc << "(" << err.src.file_name() << ":" << err.src.line() << ")"; trc << "(" << err.file << ":" << err.line << ")";
} }
} }
} }

View File

@ -19,15 +19,12 @@
namespace std { namespace std {
template<typename T> template<typename T>
inline constexpr bool is_union_v = __is_union(T); constexpr bool is_union_v = __is_union(T);
inline constexpr bool is_constant_evaluated() noexcept { 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
@ -159,9 +156,6 @@ 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;

View File

@ -313,8 +313,6 @@ 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);
@ -343,7 +341,6 @@ 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));
} }
@ -678,24 +675,6 @@ 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,

View File

@ -4,20 +4,17 @@
#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_HEAP_BEGIN reinterpret_cast<char*>(0x02000000) #define MEM_EWRAM_BEGIN reinterpret_cast<char*>(0x02000000)
#define MEM_HEAP_END reinterpret_cast<char*>(0x0203FFFF) #define MEM_EWRAM_END reinterpret_cast<char*>(0x0203FFFF)
#define HEAP_BEGIN reinterpret_cast<char*>(MEM_HEAP_BEGIN) #define HEAP_BEGIN reinterpret_cast<char*>(MEM_EWRAM_BEGIN)
// set size to half of EWRAM // set size to half of EWRAM
#define HEAP_SIZE ((MEM_HEAP_END - MEM_HEAP_BEGIN) / 2) #define HEAP_SIZE ((MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2)
#define HEAP_END reinterpret_cast<char*>(MEM_HEAP_BEGIN + HEAP_SIZE) #define HEAP_END reinterpret_cast<char*>(MEM_EWRAM_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);
@ -28,14 +25,6 @@ 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++) {

View File

@ -162,9 +162,11 @@ The Ox way of doing things is the Olympic way of doing things.
### Error Handling ### Error Handling
Instead of throwing exceptions, generally try to use The GBA build has exceptions disabled.
[ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting, Instead of throwing exceptions, all engine code should return
but exceptions may be used where they make sense. [ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting.
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```.

View File

@ -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.lower()}-manifest.json' project_manifest = f'{project_name}-manifest.json'
shutil.copyfile(project_bin, project_gba) shutil.copyfile(project_bin, project_gba)
subprocess.run([ subprocess.run([
f'{bin}/{project_name.lower()}-pack', f'{bin}/{project_name}-pack',
'-src', project_dir, '-src', project_dir,
'-rom-bin', project_gba, '-rom-bin', project_gba,
'-manifest', project_manifest]) '-manifest', project_manifest])

View File

@ -102,6 +102,8 @@ 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;
@ -142,10 +144,6 @@ 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,

View File

@ -1,11 +0,0 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <studio/studio.hpp>
namespace nostalgia::core {
}

View File

@ -18,23 +18,6 @@
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";
@ -229,10 +212,6 @@ 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);
@ -302,7 +281,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]]
ox::Optional<size_t> getTileIdx(TileSheet const&ts, SubSheetId id) noexcept; 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;
@ -421,8 +400,6 @@ 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;

View File

@ -63,19 +63,6 @@ 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,
@ -112,10 +99,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 cnt = (tileCnt * bytesPerTile) / 2; auto const pixCnt = tileCnt * bytesPerTile;
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 < cnt; ++i) { for (size_t i = 0; i < pixCnt; ++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]);

View File

@ -4,7 +4,6 @@
#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>
@ -49,10 +48,12 @@ 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.src.file_name() != nullptr) { if (err.file != nullptr) {
oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line()); oxErrf("\tError Location:\t{}:{}\n", err.file, err.line);
} }
abort(); // disable all interrupt handling and IntrWait on no interrupts
REG_IE = 0;
teagba::intrwait(0, 0);
} }
} }

View File

@ -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::StringViewCR typeId) -> ox::Result<bool> { [](keel::Context &ctx, ox::Buffer &buff, ox::StringView 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::StringViewCR typeId) -> ox::Result<bool> { [](keel::Context &ctx, ox::Buffer &buff, ox::StringView 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> ||

View File

@ -111,15 +111,15 @@ static constexpr auto bgVertexRow(uint_t x, uint_t y) noexcept {
} }
static void setSpriteBufferObject( static void setSpriteBufferObject(
uint_t const vi, uint_t vi,
float const enabled, float enabled,
float x, float x,
float y, float y,
uint_t const textureRow, uint_t textureRow,
uint_t const flipX, uint_t flipX,
uint_t const priority, uint_t priority,
ox::Span<float> const vbo, float *vbo,
ox::Span<GLuint> const ebo) noexcept { GLuint *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
}; };
ox::spancpy<float>(vbo, vertices); memcpy(vbo, vertices.data(), sizeof(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,
}; };
ox::spancpy<GLuint>(ebo, elms); memcpy(ebo, elms.data(), sizeof(elms));
} }
static void setTileBufferObject( static void setTileBufferObject(
uint_t const vi, uint_t vi,
float x, float x,
float y, float y,
float const textureTileIdx, float textureTileIdx,
float const priority, float priority,
float const palOffset, float palOffset,
bool const flipX, bool flipX,
bool const flipY, bool flipY,
ox::Span<float> const vbo, float *vbo,
ox::Span<GLuint> const ebo) noexcept { GLuint *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;
@ -170,35 +170,24 @@ static void setTileBufferObject(
float const T = flipY ? 1 : 0; float const T = flipY ? 1 : 0;
float const B = flipY ? 0 : 1; float const B = flipY ? 0 : 1;
ox::Array<float, BgVertexVboLength> const vertices { ox::Array<float, BgVertexVboLength> const vertices {
x, y, prif, L, B, textureTileIdx, palOffset, // bottom left x, y, prif, L, B, textureTileIdx, palOffset, // bottom left
x + xmod, y, prif, R, B, textureTileIdx, palOffset, // bottom right x + xmod, y, prif, R, B, textureTileIdx, palOffset, // bottom right
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
}; };
ox::spancpy<float>(vbo, vertices); memcpy(vbo, vertices.data(), sizeof(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,
}; };
ox::spancpy<GLuint>(ebo, elms); memcpy(ebo, elms.data(), sizeof(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 const vbo = ox::Span{bs.vertices} auto vbo = &bs.vertices[i * static_cast<std::size_t>(SpriteVertexVboLength)];
+ i * static_cast<std::size_t>(SpriteVertexVboLength); auto ebo = &bs.elements[i * static_cast<std::size_t>(SpriteVertexEboLength)];
auto const ebo = ox::Span{bs.elements} setSpriteBufferObject(i * static_cast<uint_t>(SpriteVertexVboRows) * ctx.blocksPerSprite, 0, 0, 0, 0, false, 0, vbo, ebo);
+ i * static_cast<std::size_t>(SpriteVertexEboLength);
setSpriteBufferObject(
i * static_cast<uint_t>(SpriteVertexVboRows) * ctx.blocksPerSprite,
0,
0,
0,
0,
false,
0,
vbo,
ebo);
} }
} }
@ -206,10 +195,8 @@ 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 const vbo = ox::Span{bs.vertices} auto vbo = &bs.vertices[i * static_cast<std::size_t>(BgVertexVboLength)];
+ i * static_cast<std::size_t>(BgVertexVboLength); auto ebo = &bs.elements[i * static_cast<std::size_t>(BgVertexEboLength)];
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),
@ -434,8 +421,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 = ox::Span{ctx.spriteBlocks.vertices} + vboIdx; auto const vbo = &ctx.spriteBlocks.vertices[vboIdx];
auto const ebo = ox::Span{ctx.spriteBlocks.elements} + eboIdx; auto const ebo = &ctx.spriteBlocks.elements[eboIdx];
renderer::setSpriteBufferObject( renderer::setSpriteBufferObject(
static_cast<uint_t>(vboIdx), static_cast<uint_t>(vboIdx),
enabled, enabled,
@ -569,7 +556,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 const pxlCnt) noexcept { size_t 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) {
@ -586,18 +573,6 @@ 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,
@ -681,8 +656,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 = ox::Span{cbb.vertices} + i * renderer::BgVertexVboLength; const auto vbo = &cbb.vertices[i * renderer::BgVertexVboLength];
const auto ebo = ox::Span{cbb.elements} + i * renderer::BgVertexEboLength; const auto ebo = &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),

View File

@ -3,6 +3,7 @@ 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(
@ -14,6 +15,7 @@ target_link_libraries(
target_link_libraries( target_link_libraries(
NostalgiaCore-Studio-ImGui PUBLIC NostalgiaCore-Studio-ImGui PUBLIC
NostalgiaCore-Studio NostalgiaCore-Studio
Studio
) )
install( install(

View File

@ -9,9 +9,5 @@ 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
) )

View File

@ -6,11 +6,6 @@ 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

View File

@ -9,24 +9,27 @@ namespace nostalgia::core {
core::UpdateSubSheetCommand::UpdateSubSheetCommand( core::UpdateSubSheetCommand::UpdateSubSheetCommand(
TileSheet &img, TileSheet &img,
TileSheet::SubSheetIdx idx, TileSheet::SubSheetIdx idx,
ox::StringParam name, ox::String name,
int const cols, int cols,
int const rows): int rows) noexcept:
m_img{img}, m_img(img),
m_idx{std::move(idx)}, m_idx(std::move(idx)),
m_sheet{getSubSheet(m_img, m_idx)} { m_sheet(getSubSheet(m_img, m_idx)),
m_sheet = getSubSheet(m_img, m_idx); m_newName(std::move(name)),
m_sheet.name = std::move(name); m_newCols(cols),
OX_THROW_ERROR(resizeSubsheet(m_sheet, m_img.bpp, {cols, rows})); m_newRows(rows) {
} }
ox::Error UpdateSubSheetCommand::redo() noexcept { 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 {}; return {};
} }
ox::Error UpdateSubSheetCommand::undo() noexcept { 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 {}; return {};
} }

View File

@ -13,14 +13,17 @@ class UpdateSubSheetCommand: public TileSheetCommand {
TileSheet &m_img; TileSheet &m_img;
TileSheet::SubSheetIdx m_idx; TileSheet::SubSheetIdx m_idx;
TileSheet::SubSheet m_sheet; TileSheet::SubSheet m_sheet;
ox::String m_newName;
int m_newCols = 0;
int m_newRows = 0;
public: public:
UpdateSubSheetCommand( UpdateSubSheetCommand(
TileSheet &img, TileSheet &img,
TileSheet::SubSheetIdx idx, TileSheet::SubSheetIdx idx,
ox::StringParam name, ox::String name,
int cols, int cols,
int rows); int rows) noexcept;
ox::Error redo() noexcept final; ox::Error redo() noexcept final;

View File

@ -26,6 +26,11 @@
namespace nostalgia::core { 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 // delete pixels of all non-leaf nodes
static void normalizeSubsheets(TileSheet::SubSheet &ss) noexcept { static void normalizeSubsheets(TileSheet::SubSheet &ss) noexcept {
if (ss.subsheets.empty()) { if (ss.subsheets.empty()) {
@ -37,14 +42,7 @@ static void normalizeSubsheets(TileSheet::SubSheet &ss) noexcept {
} }
} }
TileSheetEditorModel::TileSheetEditorModel(studio::StudioContext &sctx, ox::StringView path, studio::UndoStack &undoStack):
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):
m_sctx(sctx), m_sctx(sctx),
m_tctx(m_sctx.tctx), m_tctx(m_sctx.tctx),
m_path(path), m_path(path),
@ -64,7 +62,7 @@ void TileSheetEditorModel::cut() {
TileSheetClipboard blankCb; TileSheetClipboard blankCb;
auto cb = ox::make_unique<TileSheetClipboard>(); auto cb = ox::make_unique<TileSheetClipboard>();
auto const&s = activeSubSheet(); 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 pt = ox::Point{x, y};
auto const idx = core::idx(s, pt); auto const idx = core::idx(s, pt);
auto const c = getPixel(s, m_img.bpp, idx); auto const c = getPixel(s, m_img.bpp, idx);
@ -75,8 +73,7 @@ void TileSheetEditorModel::cut() {
auto const pt1 = m_selection->a; auto const pt1 = m_selection->a;
auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight}; auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
turbine::setClipboardObject(m_tctx, std::move(cb)); turbine::setClipboardObject(m_tctx, std::move(cb));
pushCommand(ox::make<CutPasteCommand>( pushCommand(ox::make<CutPasteCommand>(CommandId::Cut, m_img, m_activeSubsSheetIdx, pt1, pt2, blankCb));
CommandId::Cut, m_img, m_activeSubsSheetIdx, pt1, pt2, blankCb));
} }
void TileSheetEditorModel::copy() { void TileSheetEditorModel::copy() {
@ -84,7 +81,7 @@ void TileSheetEditorModel::copy() {
return; return;
} }
auto cb = ox::make_unique<TileSheetClipboard>(); 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}; auto pt = ox::Point{x, y};
const auto&s = activeSubSheet(); const auto&s = activeSubSheet();
const auto idx = core::idx(s, pt); const auto idx = core::idx(s, pt);
@ -108,8 +105,7 @@ void TileSheetEditorModel::paste() {
auto const&s = activeSubSheet(); auto const&s = activeSubSheet();
auto const pt1 = m_selection->a; auto const pt1 = m_selection->a;
auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight}; auto const pt2 = ox::Point{s.columns * TileWidth, s.rows * TileHeight};
pushCommand(ox::make<CutPasteCommand>( pushCommand(ox::make<CutPasteCommand>(CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb));
CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb));
} }
bool TileSheetEditorModel::acceptsClipboardPayload() const noexcept { bool TileSheetEditorModel::acceptsClipboardPayload() const noexcept {
@ -124,8 +120,8 @@ ox::StringView TileSheetEditorModel::palPath() const noexcept {
} }
constexpr ox::StringView uuidPrefix = "uuid://"; constexpr ox::StringView uuidPrefix = "uuid://";
if (ox::beginsWith(path, uuidPrefix)) { if (ox::beginsWith(path, uuidPrefix)) {
auto const uuid = ox::StringView(&path[uuidPrefix.bytes()], path.bytes() - uuidPrefix.bytes()); auto uuid = ox::StringView(&path[uuidPrefix.bytes()], path.bytes() - uuidPrefix.bytes());
auto const out = keelCtx(m_tctx).uuidToPath.at(uuid); auto out = keelCtx(m_tctx).uuidToPath.at(uuid);
if (out.error) { if (out.error) {
return {}; 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)); OX_REQUIRE(uuid, keelCtx(m_tctx).pathToUuid.at(path));
pushCommand(ox::make<PaletteChangeCommand>( pushCommand(ox::make<PaletteChangeCommand>(activeSubSheetIdx(), m_img, uuid->toString()));
activeSubSheetIdx(), m_img, uuid->toString()));
return {}; 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_palettePage = ox::clamp<size_t>(pg, 0, m_pal->pages.size() - 1);
m_updated = true; m_updated = true;
} }
@ -151,7 +146,7 @@ size_t TileSheetEditorModel::palettePage() const noexcept {
return m_palettePage; 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); const auto &activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx);
if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) { if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) {
return; return;
@ -160,8 +155,7 @@ void TileSheetEditorModel::drawCommand(ox::Point const&pt, std::size_t const pal
if (m_ongoingDrawCommand) { if (m_ongoingDrawCommand) {
m_updated = m_updated || m_ongoingDrawCommand->append(idx); m_updated = m_updated || m_ongoingDrawCommand->append(idx);
} else if (getPixel(activeSubSheet, m_img.bpp, idx) != palIdx) { } else if (getPixel(activeSubSheet, m_img.bpp, idx) != palIdx) {
pushCommand(ox::make<DrawCommand>( pushCommand(ox::make<DrawCommand>(m_img, m_activeSubsSheetIdx, idx, static_cast<int>(palIdx)));
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)); pushCommand(ox::make<RmSubSheetCommand>(m_img, idx));
} }
void TileSheetEditorModel::insertTiles( void TileSheetEditorModel::insertTiles(TileSheet::SubSheetIdx const&idx, std::size_t tileIdx, std::size_t tileCnt) noexcept {
TileSheet::SubSheetIdx const&idx, std::size_t const tileIdx, std::size_t const tileCnt) noexcept {
pushCommand(ox::make<InsertTilesCommand>(m_img, idx, tileIdx, tileCnt)); pushCommand(ox::make<InsertTilesCommand>(m_img, idx, tileIdx, tileCnt));
} }
void TileSheetEditorModel::deleteTiles( void TileSheetEditorModel::deleteTiles(TileSheet::SubSheetIdx const&idx, std::size_t tileIdx, std::size_t tileCnt) noexcept {
TileSheet::SubSheetIdx const&idx, std::size_t const tileIdx, std::size_t const tileCnt) noexcept {
pushCommand(ox::make<DeleteTilesCommand>(m_img, idx, tileIdx, tileCnt)); pushCommand(ox::make<DeleteTilesCommand>(m_img, idx, tileIdx, tileCnt));
} }
ox::Error TileSheetEditorModel::updateSubsheet( ox::Error TileSheetEditorModel::updateSubsheet(TileSheet::SubSheetIdx const&idx, ox::StringView const&name, int cols, int rows) noexcept {
TileSheet::SubSheetIdx const&idx, ox::StringViewCR name, int const cols, int const rows) noexcept { pushCommand(ox::make<UpdateSubSheetCommand>(m_img, idx, ox::String(name), cols, rows));
OX_REQUIRE(cmd, ox::makeCatch<UpdateSubSheetCommand>(m_img, idx, name, cols, rows));
pushCommand(cmd);
return {}; return {};
} }
@ -199,7 +189,7 @@ void TileSheetEditorModel::setActiveSubsheet(TileSheet::SubSheetIdx const&idx) n
this->activeSubsheetChanged.emit(m_activeSubsSheetIdx); 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); auto const&activeSubSheet = getSubSheet(m_img, m_activeSubsSheetIdx);
// build idx list // build idx list
if (pt.x >= activeSubSheet.columns * TileWidth || pt.y >= activeSubSheet.rows * TileHeight) { 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 = {}; ox::Array<bool, PixelsPerTile> updateMap = {};
auto const oldColor = getPixel(activeSubSheet, m_img.bpp, pt); auto const oldColor = getPixel(activeSubSheet, m_img.bpp, pt);
getFillPixels(activeSubSheet, updateMap, pt, oldColor); getFillPixels(updateMap, pt, oldColor);
ox::Vector<std::size_t> idxList; ox::Vector<std::size_t> idxList;
auto i = core::idx(activeSubSheet, pt) / PixelsPerTile * PixelsPerTile; auto i = core::idx(activeSubSheet, pt) / PixelsPerTile * PixelsPerTile;
for (auto const u : updateMap) { for (auto u : updateMap) {
if (u) { if (u) {
idxList.emplace_back(i); idxList.emplace_back(i);
} }
@ -240,7 +230,7 @@ void TileSheetEditorModel::completeSelection() noexcept {
m_selTracker.finishSelection(); m_selTracker.finishSelection();
m_selection.emplace(m_selTracker.selection()); m_selection.emplace(m_selTracker.selection());
auto&pt = m_selection->b; auto&pt = m_selection->b;
auto const&s = activeSubSheet(); auto&s = activeSubSheet();
pt.x = ox::min(s.columns * TileWidth - 1, pt.x); pt.x = ox::min(s.columns * TileWidth - 1, pt.x);
pt.y = ox::min(s.rows * TileHeight - 1, pt.y); 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); 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&s = activeSubSheet();
auto const pt = idxToPt(static_cast<int>(idx), s.columns); auto const pt = idxToPt(static_cast<int>(idx), s.columns);
return m_selection && m_selection->contains(pt); return m_selection && m_selection->contains(pt);
} }
void TileSheetEditorModel::getFillPixels( void TileSheetEditorModel::getFillPixels(ox::Span<bool> pixels, ox::Point const&pt, int oldColor) const noexcept {
TileSheet::SubSheet const&activeSubSheet, const auto &activeSubSheet = this->activeSubSheet();
ox::Span<bool> pixels, const auto tileIdx = [activeSubSheet](const ox::Point &pt) noexcept {
ox::Point const&pt, return ptToIdx(pt, activeSubSheet.columns) / PixelsPerTile;
int const oldColor) const noexcept { };
auto const idx = ptToIdx(pt, activeSubSheet.columns); // get points
auto const relIdx = idx % PixelsPerTile; const auto leftPt = pt + ox::Point(-1, 0);
if (pixels[relIdx] || getPixel(activeSubSheet, m_img.bpp, idx) != oldColor) { const auto rightPt = pt + ox::Point(1, 0);
return; 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 // mark pixels to update
pixels[relIdx] = true; pixels[idx % PixelsPerTile] = true;
if (pt.x % TileWidth != 0) { if (!pixels[leftIdx % PixelsPerTile] && tile == tileIdx(leftPt) && getPixel(activeSubSheet, m_img.bpp, leftIdx) == oldColor) {
auto const leftPt = pt + ox::Point{-1, 0}; getFillPixels(pixels, leftPt, oldColor);
getFillPixels(activeSubSheet, pixels, leftPt, oldColor);
} }
if (pt.x % TileWidth != TileWidth - 1) { if (!pixels[rightIdx % PixelsPerTile] && tile == tileIdx(rightPt) && getPixel(activeSubSheet, m_img.bpp, rightIdx) == oldColor) {
auto const rightPt = pt + ox::Point{1, 0}; getFillPixels(pixels, rightPt, oldColor);
getFillPixels(activeSubSheet, pixels, rightPt, oldColor);
} }
if (pt.y % TileHeight != 0) { if (!pixels[topIdx % PixelsPerTile] && tile == tileIdx(topPt) && getPixel(activeSubSheet, m_img.bpp, topIdx) == oldColor) {
auto const topPt = pt + ox::Point{0, -1}; getFillPixels(pixels, topPt, oldColor);
getFillPixels(activeSubSheet, pixels, topPt, oldColor);
} }
if (pt.y % TileHeight != TileHeight - 1) { if (!pixels[bottomIdx % PixelsPerTile] && tile == tileIdx(bottomPt) && getPixel(activeSubSheet, m_img.bpp, bottomIdx) == oldColor) {
auto const bottomPt = pt + ox::Point{0, 1}; getFillPixels(pixels, bottomPt, oldColor);
getFillPixels(activeSubSheet, pixels, bottomPt, oldColor);
} }
} }
void TileSheetEditorModel::pushCommand(studio::UndoCommand *cmd) noexcept { 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_ongoingDrawCommand = dynamic_cast<DrawCommand*>(cmd);
m_updated = true; m_updated = true;
} }

View File

@ -4,7 +4,9 @@
#pragma once #pragma once
#include <ox/std/bounds.hpp>
#include <ox/std/point.hpp> #include <ox/std/point.hpp>
#include <ox/std/trace.hpp>
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
#include <studio/studio.hpp> #include <studio/studio.hpp>
@ -36,7 +38,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
bool m_updated = false; bool m_updated = false;
public: public:
TileSheetEditorModel(studio::StudioContext &sctx, ox::StringViewCR path, studio::UndoStack &undoStack); TileSheetEditorModel(studio::StudioContext &sctx, ox::StringView path, studio::UndoStack &undoStack);
~TileSheetEditorModel() override = default; ~TileSheetEditorModel() override = default;
@ -61,7 +63,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
[[nodiscard]] [[nodiscard]]
ox::StringView palPath() const noexcept; 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; void setPalettePage(size_t pg) noexcept;
@ -126,11 +128,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
bool pixelSelected(std::size_t idx) const noexcept; bool pixelSelected(std::size_t idx) const noexcept;
private: private:
void getFillPixels( void getFillPixels(ox::Span<bool> pixels, ox::Point const&pt, int oldColor) const noexcept;
TileSheet::SubSheet const&activeSubSheet,
ox::Span<bool> pixels,
ox::Point const&pt,
int oldColor) const noexcept;
void pushCommand(studio::UndoCommand *cmd) noexcept; void pushCommand(studio::UndoCommand *cmd) noexcept;

View File

@ -66,10 +66,10 @@ static ox::Optional<size_t> getPixelIdx(
return ox::Optional<size_t>{}; return ox::Optional<size_t>{};
} }
ox::Optional<size_t> getTileIdx(TileSheet const&ts, SubSheetId const id) noexcept { 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 ? ox::Optional<size_t>{ox::in_place, *out / PixelsPerTile} : out; return out.or_value(0) / PixelsPerTile;
} }
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<uint32_t> getTileOffset( static ox::Result<unsigned> 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,
uint32_t pCurrentTotal = 0) noexcept { unsigned 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,14 +374,12 @@ static ox::Result<uint32_t> 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<uint32_t> getTileOffset(TileSheet const&ts, ox::StringViewCR pNamePath) noexcept { ox::Result<unsigned> 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);
} }

View File

@ -11,7 +11,7 @@ target_link_libraries(
target_compile_definitions( target_compile_definitions(
NostalgiaStudio PUBLIC NostalgiaStudio PUBLIC
OLYMPIC_APP_VERSION="dev build" OLYMPIC_APP_VERSION="d2024.12.2"
) )
install( install(

View File

@ -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::StringViewCR assetId)>; using Loader = std::function<ox::Result<T>(ox::StringView 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(std::move(loader)) {} AssetTypeManager(Loader loader) noexcept: m_loader(loader) {}
ox::Result<AssetRef<T>> getAsset(ox::StringViewCR assetId) const noexcept { ox::Result<AssetRef<T>> getAsset(ox::StringView const 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::StringViewCR assetId) noexcept { ox::Result<AssetRef<T>> loadAsset(ox::StringView const 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::StringViewCR assetId) noexcept { ox::Error reloadAsset(ox::StringView const 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::StringViewCR assetId)>> m_fileUpdated; ox::HashMap<ox::String, ox::Signal<ox::Error(ox::StringView 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::StringViewCR assetId) noexcept { ox::Result<AssetRef<T>> getAsset(ox::StringView assetId) noexcept {
OX_REQUIRE(m, getTypeManager<T>()); OX_REQUIRE(m, getTypeManager<T>());
return m->getAsset(assetId); return m->getAsset(assetId);
} }
ox::Error reloadAsset(ox::StringViewCR assetId) noexcept { ox::Error reloadAsset(ox::StringView 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::StringViewCR assetId) noexcept { ox::Result<AssetRef<T>> loadAsset(ox::StringView 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);

View File

@ -12,7 +12,7 @@
namespace keel { namespace keel {
class Context; class Context;
using PackTransform = ox::Result<bool>(*)(Context&, ox::Buffer &clawData, ox::StringViewCR); using PackTransform = ox::Result<bool>(*)(Context&, ox::Buffer &clawData, ox::StringView);
class Context { class Context {
public: public:

View File

@ -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);
}; };

View File

@ -125,9 +125,7 @@ ox::Error preloadObj(
OX_RETURN_ERROR(err); OX_RETURN_ERROR(err);
keel::PreloadPtr const p{.preloadAddr = a}; keel::PreloadPtr const p{.preloadAddr = a};
OX_RETURN_ERROR(ox::writeMC(p).moveTo(buff)); OX_RETURN_ERROR(ox::writeMC(p).moveTo(buff));
auto const&pbufSz = pl.buff().size(); oxOutf("preloaded {} as a {} @ {} to {}\n", path, obj.type()->typeName, a, a + 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));

View File

@ -16,43 +16,10 @@ 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;
}; };
template<typename T> template<typename T>
class WrapT: public Wrap { class WrapInline: public Wrap {
public:
[[nodiscard]]
virtual constexpr T &obj() noexcept = 0;
};
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;
@ -63,15 +30,8 @@ class WrapInline final: public WrapT<T> {
constexpr explicit WrapInline(Args &&...args): m_obj(ox::forward<Args>(args)...) { constexpr explicit WrapInline(Args &&...args): m_obj(ox::forward<Args>(args)...) {
} }
ox::CStringView typeName() const noexcept override { [[nodiscard]]
return ox::ModelTypeName_v<T>; constexpr T &obj() noexcept {
}
int typeVersion() const noexcept override {
return ox::ModelTypeVersion_v<T>;
}
constexpr T &obj() noexcept override {
return m_obj; return m_obj;
} }
@ -84,7 +44,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<WrapT<T>&>(ptr).obj(); return static_cast<WrapInline<T>&>(ptr).obj();
} }
class BaseConverter { class BaseConverter {
@ -110,10 +70,10 @@ class BaseConverter {
[[nodiscard]] [[nodiscard]]
constexpr bool matches( constexpr bool matches(
ox::StringViewCR srcTypeName, int const srcTypeVersion, ox::StringViewCR srcTypeName, int srcTypeVersion,
ox::StringViewCR dstTypeName, int const dstTypeVersion) const noexcept { ox::StringViewCR dstTypeName, int dstTypeVersion) const noexcept {
return srcMatches(srcTypeName, srcTypeVersion) return srcMatches(srcTypeName, srcTypeVersion)
&& dstMatches(dstTypeName, dstTypeVersion); && dstMatches(dstTypeName, dstTypeVersion);
} }
}; };
@ -149,17 +109,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 {
ox::Result<ox::UPtr<Wrap>> dst{makeWrap<DstType>()}; auto dst = makeWrap<DstType>();
OX_RETURN_ERROR(convert(ctx, wrapCast<SrcType>(src), wrapCast<DstType>(*dst.value))); OX_RETURN_ERROR(convert(ctx, wrapCast<SrcType>(src), wrapCast<DstType>(*dst)));
return dst; return {std::move(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));
ox::Result<ox::UPtr<Wrap>> dst{makeWrap<DstType>()}; auto dst = makeWrap<DstType>();
OX_RETURN_ERROR(convert(ctx, src, wrapCast<DstType>(*dst.value))); OX_RETURN_ERROR(convert(ctx, src, wrapCast<DstType>(*dst)));
return dst; return {std::move(dst)};
} }
protected: protected:
@ -173,57 +133,34 @@ 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 {
return convert(ctx, WrapRef{src}, dstTypeName, dstTypeVersion);
}
template<typename DstType> template<typename DstType>
ox::Result<DstType> convertObjToObj( ox::Result<DstType> convert(keel::Context &ctx, ox::BufferView const&srcBuffer) noexcept {
keel::Context &ctx, static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
auto &src) noexcept { static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
OX_REQUIRE_M(out, convert(ctx, WrapRef{src}, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>)); OX_REQUIRE(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion));
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 {
OX_REQUIRE(out, convert(ctx, buff, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>)); static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
outObj = std::move(wrapCast<DstType>(*out)); static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
return {}; OX_REQUIRE(outPtr, convert(ctx, buff, DstTypeName, DstTypeVersion));
} *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&src, ox::ClawFormat const fmt) noexcept { keel::Context &ctx, ox::BufferView const&srcBuffer, ox::ClawFormat fmt) noexcept {
OX_REQUIRE(out, convert(ctx, src, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>)); static constexpr auto DstTypeName = ox::requireModelTypeName<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::StringViewCR typeId) noexcept { ox::Result<bool> transformRule(keel::Context &ctx, ox::Buffer &buff, ox::StringView 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;
@ -231,4 +168,5 @@ ox::Result<bool> transformRule(keel::Context &ctx, ox::Buffer &buff, ox::StringV
return false; return false;
}; };
} }

View File

@ -10,38 +10,30 @@ 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 const srcTypeVersion, int srcTypeVersion,
ox::StringViewCR dstTypeName, ox::StringViewCR dstTypeName,
int const dstTypeVersion) noexcept { int 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(
Context &ctx, keel::Context &ctx,
ox::SpanView<BaseConverter const*> const&converters, ox::SpanView<BaseConverter const*> const&converters,
auto &src, ox::BufferView const&srcBuffer,
ox::StringViewCR srcTypeName, ox::StringViewCR srcTypeName,
int const srcTypeVersion, int srcTypeVersion,
ox::StringViewCR dstTypeName, ox::StringViewCR dstTypeName,
int const dstTypeVersion) noexcept { int dstTypeVersion) noexcept {
// look for direct converter // look for direct converter
auto const [c, err] = findConverter( auto [c, err] = findConverter(
converters, srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion); converters, srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion);
if (!err) { if (!err) {
return convert(*c, ctx, src); return c->convertBuffToPtr(ctx, srcBuffer);
} }
// try to chain multiple converters // try to chain multiple converters
for (auto const&subConverter : converters) { for (auto const&subConverter : converters) {
@ -49,20 +41,20 @@ static ox::Result<ox::UPtr<Wrap>> convert(
continue; continue;
} }
const auto [intermediate, chainErr] = const auto [intermediate, chainErr] =
convert(ctx, converters, src, srcTypeName, srcTypeVersion, convert(ctx, converters, srcBuffer, 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(
Context &ctx, keel::Context &ctx,
ox::BufferView const&srcBuffer, ox::BufferView const&srcBuffer,
ox::StringViewCR dstTypeName, ox::StringViewCR dstTypeName,
int const dstTypeVersion) noexcept { int dstTypeVersion) noexcept {
OX_REQUIRE(hdr, readAssetHeader(srcBuffer)); OX_REQUIRE(hdr, readAssetHeader(srcBuffer));
return convert( return convert(
ctx, ctx,
@ -74,19 +66,4 @@ 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);
}
} }

View File

@ -18,9 +18,9 @@
namespace studio { namespace studio {
static ox::Vector<Module const*> modules; static ox::Vector<studio::Module const*> modules;
void registerModule(Module const*mod) noexcept { void registerModule(studio::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_tctx(ctx), m_ctx(ctx),
m_projectDataDir(std::move(projectDataDir)), m_projectDataDir(std::move(projectDataDir)),
m_projectExplorer(m_tctx), m_projectExplorer(m_ctx),
m_newProject(m_projectDataDir), m_newProject(m_projectDataDir),
m_aboutPopup(m_tctx) { m_aboutPopup(m_ctx) {
turbine::setApplicationData(m_tctx, &m_sctx); turbine::setApplicationData(m_ctx, &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_tctx)); auto const [config, err] = studio::readConfig<StudioConfig>(keelCtx(m_ctx));
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 const openFileErr = openFileActiveTab(f, config.activeTabItemName == f); auto 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.src.file_name(), err.src.line()); err.errCode, toStr(err), err.file, err.line);
} }
} }
} }
void StudioUI::handleKeyEvent(turbine::Key const key, bool const down) noexcept { void StudioUI::handleKeyEvent(turbine::Key key, bool down) noexcept {
for (auto const p : m_popups) { for (auto 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 const p: m_popups) { for (auto p: m_popups) {
p->draw(m_sctx); p->draw(m_sctx);
} }
} }
ImGui::End(); ImGui::End();
handleKeyInput(); handleKeyInput();
m_taskRunner.update(m_tctx); m_taskRunner.update(m_ctx);
} }
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_tctx); turbine::requestShutdown(m_ctx);
} }
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+Shift+1", m_showProjectExplorer)) { if (ImGui::MenuItem("Project Explorer", "Ctrl+1", m_showProjectExplorer)) {
toggleProjectExplorer(); toggleProjectExplorer();
} }
ImGui::EndMenu(); ImGui::EndMenu();
@ -204,10 +204,9 @@ 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_tctx), [&](StudioConfig &config) { studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](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;
@ -228,7 +227,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.src.file_name(), ex.src.line()); oxErrf("Editor tab deletion failed: {} ({}:{})\n", ex.what(), ex.file, ex.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());
} }
@ -238,13 +237,13 @@ void StudioUI::drawTabs() noexcept {
} }
} }
void StudioUI::loadEditorMaker(EditorMaker const&editorMaker) noexcept { void StudioUI::loadEditorMaker(studio::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(Module const&mod) noexcept { void StudioUI::loadModule(studio::Module const&mod) noexcept {
for (auto const&editorMaker : mod.editors(m_sctx)) { for (auto const&editorMaker : mod.editors(m_sctx)) {
loadEditorMaker(editorMaker); loadEditorMaker(editorMaker);
} }
@ -261,20 +260,20 @@ void StudioUI::loadModules() noexcept {
void StudioUI::toggleProjectExplorer() noexcept { void StudioUI::toggleProjectExplorer() noexcept {
m_showProjectExplorer = !m_showProjectExplorer; m_showProjectExplorer = !m_showProjectExplorer;
editConfig<StudioConfig>(keelCtx(m_tctx), [&](StudioConfig &config) { studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
config.showProjectExplorer = m_showProjectExplorer; config.showProjectExplorer = m_showProjectExplorer;
}); });
} }
void StudioUI::redo() noexcept { void StudioUI::redo() noexcept {
auto const undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr; auto 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 const undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr; auto 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());
} }
@ -293,7 +292,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_tctx, turbine::Key::Mod_Shift)) { if (turbine::buttonDown(m_ctx, turbine::Key::Mod_Shift)) {
m_newProject.open(); m_newProject.open();
} else { } else {
m_newMenu.open(); m_newMenu.open();
@ -303,7 +302,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_tctx); turbine::requestShutdown(m_ctx);
} 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();
@ -318,22 +317,8 @@ 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) && ImGui::IsKeyDown(ImGuiKey_ModShift)) { } else if (ImGui::IsKeyPressed(ImGuiKey_1)) {
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;
}
}
} }
} }
} }
@ -348,18 +333,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_tctx), std::move(fs))); OX_RETURN_ERROR(keel::setRomFs(keelCtx(m_ctx), std::move(fs)));
OX_RETURN_ERROR( OX_RETURN_ERROR(
ox::make_unique_catch<Project>(keelCtx(m_tctx), std::move(path), m_projectDataDir) ox::make_unique_catch<studio::Project>(keelCtx(m_ctx), std::move(path), m_projectDataDir)
.moveTo(m_project)); .moveTo(m_project));
auto const sctx = applicationData<StudioContext>(m_tctx); auto const sctx = applicationData<studio::StudioContext>(m_ctx);
sctx->project = m_project.get(); sctx->project = m_project.get();
turbine::setWindowTitle(m_tctx, ox::sfmt("{} - {}", keelCtx(m_tctx).appName, m_project->projectPath())); turbine::setWindowTitle(m_ctx, ox::sfmt("{} - {}", keelCtx(m_ctx).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_tctx), [&](StudioConfig &config) { studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
config.projectPath = ox::String(m_project->projectPath()); config.projectPath = ox::String(m_project->projectPath());
config.openFiles.clear(); config.openFiles.clear();
}); });
@ -370,7 +355,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 const makeActiveTab) noexcept { ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool 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");
} }
@ -384,7 +369,7 @@ ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool const makeActi
} }
return {}; return {};
} }
OX_REQUIRE(ext, fileExt(path)); OX_REQUIRE(ext, studio::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) ?
@ -394,7 +379,7 @@ ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool const makeActi
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.src.file_name(), err.src.line()); oxErrf("Could not open Editor: {} ({}:{})\n", err.errCode, err.file, err.line);
} }
return err; return err;
} }
@ -406,7 +391,7 @@ ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool const makeActi
m_activeEditorUpdatePending = editor; m_activeEditorUpdatePending = editor;
} }
// save to config // save to config
studio::editConfig<StudioConfig>(keelCtx(m_tctx), [&path](StudioConfig &config) { studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&path](StudioConfig &config) {
if (!config.openFiles.contains(path)) { if (!config.openFiles.contains(path)) {
config.openFiles.emplace_back(path); config.openFiles.emplace_back(path);
} }
@ -420,7 +405,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_tctx), [&](StudioConfig &config) { studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](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 {};

View File

@ -24,23 +24,23 @@ class StudioUI: public ox::SignalHandler {
friend class StudioUIDrawer; friend class StudioUIDrawer;
private: private:
StudioContext m_sctx; studio::StudioContext m_sctx;
turbine::Context &m_tctx; turbine::Context &m_ctx;
ox::String m_projectDataDir; ox::String m_projectDataDir;
ox::UPtr<Project> m_project; ox::UPtr<studio::Project> m_project;
TaskRunner m_taskRunner; studio::TaskRunner m_taskRunner;
ox::Vector<ox::UPtr<BaseEditor>> m_editors; ox::Vector<ox::UPtr<studio::BaseEditor>> m_editors;
ox::Vector<ox::UPtr<Widget>> m_widgets; ox::Vector<ox::UPtr<studio::Widget>> m_widgets;
ox::HashMap<ox::String, EditorMaker::Func> m_editorMakers; ox::HashMap<ox::String, studio::EditorMaker::Func> m_editorMakers;
ProjectExplorer m_projectExplorer; ProjectExplorer m_projectExplorer;
ox::Vector<ox::String> m_openFiles; ox::Vector<ox::String> m_openFiles;
BaseEditor *m_activeEditorOnLastDraw = nullptr; studio::BaseEditor *m_activeEditorOnLastDraw = nullptr;
BaseEditor *m_activeEditor = nullptr; studio::BaseEditor *m_activeEditor = nullptr;
BaseEditor *m_activeEditorUpdatePending = nullptr; studio::BaseEditor *m_activeEditorUpdatePending = nullptr;
NewMenu m_newMenu; NewMenu m_newMenu;
NewProject m_newProject; NewProject m_newProject;
AboutPopup m_aboutPopup; AboutPopup m_aboutPopup;
ox::Array<Popup*, 3> const m_popups = { ox::Array<studio::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 Project *project() noexcept { constexpr studio::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(EditorMaker const&editorMaker) noexcept; void loadEditorMaker(studio::EditorMaker const&editorMaker) noexcept;
void loadModule(Module const&mod) noexcept; void loadModule(studio::Module const&mod) noexcept;
void loadModules() noexcept; void loadModules() noexcept;

View File

@ -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(1, "Command makes no changes.", sloc) {} ox::Exception(sloc.file_name(), sloc.line(), 1, "Command makes no changes.") {}
}; };
class UndoCommand { class UndoCommand {

View File

@ -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.src.file_name(), err.src.line()); oxErrorf("Could not save file {}: {} ({}:{})", itemPath(), toStr(err), err.file, err.line);
} else { } else {
oxErrorf("Could not save file {}: {}", itemPath(), toStr(err)); oxErrorf("Could not save file {}: {}", itemPath(), toStr(err));
} }

View File

@ -19,7 +19,7 @@ target_include_directories(
) )
target_sources( target_sources(
Turbine PRIVATE Turbine PUBLIC
turbine.cpp turbine.cpp
) )