Squashed 'deps/nostalgia/' changes from 791b7746..a3d6a58c
a3d6a58c [nostalgia/core/studio] Fix library cpp file ownership e598e7fe [nostalgia,keel] Add ability to types Obj to Obj ba9e720f [ox/model] Fix ModelTypeName_v to use requireModelTypeName 8e816a26 [nostalgia/core/studio] Cleanup, fix possible TileSheet fill tool failure 5b9929ab [keel] Add detail to preload logging ceb54b3f [nostalgia/core/opengl] Cleanup 87644447 [nostalgia/core] Add clearCbb functions ce9a0b1f [nostalgia/core/opengl] Cleanup memcpys f7a468ea [ox/std] Add spancpy 861d177a [studio] Cleanup 3936756b [nostalgia/developer-handbook] Update error handling to reflect the enablement of exceptions for GBA build 3e78ec3f [studio] Cleanup 3c3d53b4 [studio] Ensure Editor tabs do first draw immediately, fix shift key being missed with tab shortcuts 151d7c57 [nostalgia/core/gba] Fix partial tilesheet loading overrun 4e4d8d2c [nostalgia/core/gba] Make panic use standard abort call 03d1fd28 [ox/std] Add and integrate standard abort call 6701decc [gbabuildcore] Enable exceptions 6cff5266 [teagba] Add symbols needed for enabling exceptions dd50bd02 [studio] Remap toggle explorer keyboard shortcut, add Ctrl+1-0 mappings for jumping between tabs 55a16602 [nostalgia/core] Fix TileSheet validation/repair to ensure pixels gets cleared if there are subsheets ed365dfe [studio] Fix new project menu to return an appropriately sized string for name 23a09e4a [nostalgia/core/studio] Fix SubSheet editor to return an appropriately sized string b69e7ebb [nostalgia/core/studio/tilesheeteditor] Fix select all not to go beyond end 418d6e3f [nostalgia/core/studio] Fix crash that occurs when a non-leaf node subsheet is selected c44d8678 [nostalgia/core/studio] Fix tile insert to correct input when inserting past the last tile eb4cd710 [nostalgia/core/studio] Fix tile insert to work on last tile d259770f Merge commit '4ea4a61d542777a270c4e2c283e0e986fc9eec9c' 80bad608 [keel] Fix reloadAsset 2bce9a2b [ox/std] Add non-const SmallMap::pairs git-subtree-dir: deps/nostalgia git-subtree-split: a3d6a58cc898f88434e8901aacb579c819fac3e6
This commit is contained in:
parent
4ea4a61d54
commit
50b1ed33df
4
deps/gbabuildcore/base.cmake
vendored
4
deps/gbabuildcore/base.cmake
vendored
@ -1,8 +1,8 @@
|
|||||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules)
|
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules)
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unwind-tables")
|
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unwind-tables")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
|
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb-interwork")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb-interwork")
|
||||||
|
6
deps/ox/src/ox/model/typenamecatcher.hpp
vendored
6
deps/ox/src/ox/model/typenamecatcher.hpp
vendored
@ -140,16 +140,16 @@ constexpr Str getModelTypeName() noexcept {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename Str = const char*>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
consteval auto requireModelTypeName() noexcept {
|
consteval auto requireModelTypeName() noexcept {
|
||||||
constexpr auto name = getModelTypeName<T>();
|
constexpr auto name = getModelTypeName<T, Str>();
|
||||||
static_assert(ox::StringView{name}.len(), "Type lacks required TypeName");
|
static_assert(ox::StringView{name}.len(), "Type lacks required TypeName");
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename Str = const char*>
|
template<typename T, typename Str = const char*>
|
||||||
constexpr auto ModelTypeName_v = getModelTypeName<T, Str>();
|
constexpr auto ModelTypeName_v = requireModelTypeName<T, Str>();
|
||||||
|
|
||||||
template<typename T, typename Str = const char*>
|
template<typename T, typename Str = const char*>
|
||||||
constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>();
|
constexpr auto ModelTypeVersion_v = requireModelTypeVersion<T>();
|
||||||
|
27
deps/ox/src/ox/std/assert.cpp
vendored
27
deps/ox/src/ox/std/assert.cpp
vendored
@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fmt.hpp"
|
#include "fmt.hpp"
|
||||||
|
#include "realstd.hpp"
|
||||||
#include "stacktrace.hpp"
|
#include "stacktrace.hpp"
|
||||||
#include "trace.hpp"
|
#include "trace.hpp"
|
||||||
|
|
||||||
@ -14,7 +15,7 @@
|
|||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err) noexcept {
|
void panic(StringViewCR file, int const line, StringViewCR panicMsg, Error const&err) noexcept {
|
||||||
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg);
|
oxErrf("\033[31;1;1mPANIC:\033[0m [{}:{}]: {}\n", file, line, panicMsg);
|
||||||
if (err.msg) {
|
if (err.msg) {
|
||||||
oxErrf("\tError Message:\t{}\n", err.msg);
|
oxErrf("\tError Message:\t{}\n", err.msg);
|
||||||
@ -32,16 +33,19 @@ void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void panic(const char *file, int line, const char *panicMsg, const Error &err) noexcept {
|
void panic(const char *file, int const line, char const*panicMsg, Error const&err) noexcept {
|
||||||
panic(StringView{file}, line, StringView{panicMsg}, err);
|
panic(StringView{file}, line, StringView{panicMsg}, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept {
|
void assertFailFuncRuntime(
|
||||||
|
StringViewCR file,
|
||||||
|
int const line,
|
||||||
|
StringViewCR assertTxt,
|
||||||
|
StringViewCR msg) noexcept {
|
||||||
#ifdef OX_USE_STDLIB
|
#ifdef OX_USE_STDLIB
|
||||||
auto output = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
|
auto const st = genStackTrace(2);
|
||||||
output += genStackTrace(2);
|
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]:\n{}", msg, assertTxt, file, line, st);
|
||||||
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
|
abort();
|
||||||
std::abort();
|
|
||||||
#else
|
#else
|
||||||
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
|
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, msg);
|
||||||
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
|
oxTracef("assert", "Failed assert: {} ({}) [{}:{}]", msg, assertTxt, file, line);
|
||||||
@ -49,7 +53,12 @@ void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt,
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void assertFailFuncRuntime(StringViewCR file, int line, [[maybe_unused]] const Error &err, StringViewCR, StringViewCR assertMsg) noexcept {
|
void assertFailFuncRuntime(
|
||||||
|
StringViewCR file,
|
||||||
|
int const line,
|
||||||
|
[[maybe_unused]] Error const&err,
|
||||||
|
StringViewCR,
|
||||||
|
StringViewCR assertMsg) noexcept {
|
||||||
#if defined(OX_USE_STDLIB)
|
#if defined(OX_USE_STDLIB)
|
||||||
auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg);
|
auto msg = sfmt("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg);
|
||||||
if (err.msg) {
|
if (err.msg) {
|
||||||
@ -62,7 +71,7 @@ void assertFailFuncRuntime(StringViewCR file, int line, [[maybe_unused]] const E
|
|||||||
msg += genStackTrace(2);
|
msg += genStackTrace(2);
|
||||||
oxErr(msg);
|
oxErr(msg);
|
||||||
oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line);
|
oxTracef("assert", "Failed assert: {} [{}:{}]", assertMsg, file, line);
|
||||||
std::abort();
|
abort();
|
||||||
#else
|
#else
|
||||||
constexprPanic(file, line, assertMsg);
|
constexprPanic(file, line, assertMsg);
|
||||||
#endif
|
#endif
|
||||||
|
43
deps/ox/src/ox/std/assert.hpp
vendored
43
deps/ox/src/ox/std/assert.hpp
vendored
@ -22,9 +22,15 @@
|
|||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
void panic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err = ox::Error(0)) noexcept;
|
[[noreturn]]
|
||||||
|
void panic(StringViewCR file, int line, StringViewCR panicMsg, Error const&err = {}) noexcept;
|
||||||
|
|
||||||
constexpr void constexprPanic(StringViewCR file, int line, StringViewCR panicMsg, const Error &err = ox::Error(0)) noexcept {
|
[[noreturn]]
|
||||||
|
constexpr void constexprPanic(
|
||||||
|
StringViewCR file,
|
||||||
|
int const line,
|
||||||
|
StringViewCR panicMsg,
|
||||||
|
Error const&err = {}) noexcept {
|
||||||
if (!std::is_constant_evaluated()) {
|
if (!std::is_constant_evaluated()) {
|
||||||
panic(file, line, panicMsg, err);
|
panic(file, line, panicMsg, err);
|
||||||
} else {
|
} else {
|
||||||
@ -32,10 +38,24 @@ constexpr void constexprPanic(StringViewCR file, int line, StringViewCR panicMsg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void assertFailFuncRuntime(StringViewCR file, int line, StringViewCR assertTxt, StringViewCR msg) noexcept;
|
void assertFailFuncRuntime(
|
||||||
void assertFailFuncRuntime(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept;
|
StringViewCR file,
|
||||||
|
int line,
|
||||||
|
StringViewCR assertTxt,
|
||||||
|
StringViewCR msg) noexcept;
|
||||||
|
void assertFailFuncRuntime(
|
||||||
|
StringViewCR file,
|
||||||
|
int line,
|
||||||
|
Error const&err,
|
||||||
|
StringViewCR,
|
||||||
|
StringViewCR assertMsg) noexcept;
|
||||||
|
|
||||||
constexpr void assertFunc(StringViewCR file, int line, bool pass, [[maybe_unused]]StringViewCR assertTxt, [[maybe_unused]]StringViewCR msg) noexcept {
|
constexpr void assertFunc(
|
||||||
|
StringViewCR file,
|
||||||
|
int const line,
|
||||||
|
bool const pass,
|
||||||
|
[[maybe_unused]]StringViewCR assertTxt,
|
||||||
|
[[maybe_unused]]StringViewCR msg) noexcept {
|
||||||
if (!pass) {
|
if (!pass) {
|
||||||
if (!std::is_constant_evaluated()) {
|
if (!std::is_constant_evaluated()) {
|
||||||
assertFailFuncRuntime(file, line, assertTxt, msg);
|
assertFailFuncRuntime(file, line, assertTxt, msg);
|
||||||
@ -45,7 +65,12 @@ constexpr void assertFunc(StringViewCR file, int line, bool pass, [[maybe_unused
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void assertFunc(StringViewCR file, int line, const Error &err, StringViewCR, StringViewCR assertMsg) noexcept {
|
constexpr void assertFunc(
|
||||||
|
StringViewCR file,
|
||||||
|
int const line,
|
||||||
|
Error const&err,
|
||||||
|
StringViewCR,
|
||||||
|
StringViewCR assertMsg) noexcept {
|
||||||
if (err) {
|
if (err) {
|
||||||
if (!std::is_constant_evaluated()) {
|
if (!std::is_constant_evaluated()) {
|
||||||
assertFailFuncRuntime(file, line, err, {}, assertMsg);
|
assertFailFuncRuntime(file, line, err, {}, assertMsg);
|
||||||
@ -55,7 +80,11 @@ constexpr void assertFunc(StringViewCR file, int line, const Error &err, StringV
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void expect(StringViewCR file, int line, const auto &actual, const auto &expected) noexcept {
|
constexpr void expect(
|
||||||
|
StringViewCR file,
|
||||||
|
int const line,
|
||||||
|
auto const&actual,
|
||||||
|
auto const&expected) noexcept {
|
||||||
if (actual != expected) {
|
if (actual != expected) {
|
||||||
if (!std::is_constant_evaluated()) {
|
if (!std::is_constant_evaluated()) {
|
||||||
#if defined(OX_USE_STDLIB)
|
#if defined(OX_USE_STDLIB)
|
||||||
|
7
deps/ox/src/ox/std/error.hpp
vendored
7
deps/ox/src/ox/std/error.hpp
vendored
@ -80,13 +80,13 @@ struct Exception: public std::exception {
|
|||||||
ox::CString msg = nullptr;
|
ox::CString msg = nullptr;
|
||||||
ErrorCode errCode = 0;
|
ErrorCode errCode = 0;
|
||||||
|
|
||||||
explicit inline Exception(
|
explicit 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},
|
src{src},
|
||||||
errCode{errCode} {}
|
errCode{errCode} {}
|
||||||
|
|
||||||
explicit inline Exception(
|
explicit Exception(
|
||||||
ErrorCode const errCode,
|
ErrorCode const errCode,
|
||||||
ox::CString msg,
|
ox::CString msg,
|
||||||
std::source_location const&src = std::source_location::current()) noexcept:
|
std::source_location const&src = std::source_location::current()) noexcept:
|
||||||
@ -94,7 +94,7 @@ struct Exception: public std::exception {
|
|||||||
msg{msg},
|
msg{msg},
|
||||||
errCode{errCode} {}
|
errCode{errCode} {}
|
||||||
|
|
||||||
explicit inline Exception(Error const&err) noexcept:
|
explicit Exception(Error const&err) noexcept:
|
||||||
src{err.src},
|
src{err.src},
|
||||||
msg{err.msg ? err.msg : ""},
|
msg{err.msg ? err.msg : ""},
|
||||||
errCode{err.errCode} {}
|
errCode{err.errCode} {}
|
||||||
@ -109,6 +109,7 @@ struct Exception: public std::exception {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[[noreturn]]
|
||||||
void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept;
|
void panic(char const*file, int line, char const*panicMsg, Error const&err) noexcept;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
9
deps/ox/src/ox/std/realstd.hpp
vendored
9
deps/ox/src/ox/std/realstd.hpp
vendored
@ -13,3 +13,12 @@
|
|||||||
#else
|
#else
|
||||||
#define assert(e) while (!(e));
|
#define assert(e) while (!(e));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __has_include(<cstdlib>)
|
||||||
|
#include <cstdlib>
|
||||||
|
#else
|
||||||
|
extern "C" {
|
||||||
|
[[noreturn]]
|
||||||
|
void abort();
|
||||||
|
}
|
||||||
|
#endif
|
5
deps/ox/src/ox/std/smallmap.hpp
vendored
5
deps/ox/src/ox/std/smallmap.hpp
vendored
@ -85,6 +85,11 @@ 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:
|
||||||
|
20
deps/ox/src/ox/std/span.hpp
vendored
20
deps/ox/src/ox/std/span.hpp
vendored
@ -14,7 +14,7 @@
|
|||||||
#include "iterator.hpp"
|
#include "iterator.hpp"
|
||||||
#include "vector.hpp"
|
#include "vector.hpp"
|
||||||
|
|
||||||
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
|
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
|
||||||
|
|
||||||
namespace ox {
|
namespace ox {
|
||||||
|
|
||||||
@ -133,7 +133,7 @@ class Span {
|
|||||||
return m_items[i];
|
return m_items[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const T &operator[](std::size_t i) const noexcept {
|
constexpr T const&operator[](std::size_t i) const noexcept {
|
||||||
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
|
ox::primitiveAssert(__FILE__, __LINE__, i < size(), "Span access overflow");
|
||||||
return m_items[i];
|
return m_items[i];
|
||||||
}
|
}
|
||||||
@ -168,8 +168,20 @@ class Span {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
using SpanView = Span<const T>;
|
using SpanView = Span<T const>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr void spancpy(ox::Span<T> const dst, ox::SpanView<T> const src) noexcept {
|
||||||
|
auto const sz = ox::min(dst.size(), src.size());
|
||||||
|
if (std::is_constant_evaluated() || std::is_trivially_copyable_v<T>) {
|
||||||
|
for (size_t i{}; i < sz; ++i) {
|
||||||
|
dst.data()[i] = src.data()[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(dst.data(), src.data(), sz * sizeof(T));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OX_CLANG_NOWARN_END
|
OX_ALLOW_UNSAFE_BUFFERS_END
|
||||||
|
10
deps/ox/src/ox/std/typetraits.hpp
vendored
10
deps/ox/src/ox/std/typetraits.hpp
vendored
@ -19,12 +19,15 @@
|
|||||||
namespace std {
|
namespace std {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr bool is_union_v = __is_union(T);
|
inline constexpr bool is_union_v = __is_union(T);
|
||||||
|
|
||||||
constexpr bool is_constant_evaluated() noexcept {
|
inline constexpr bool is_constant_evaluated() noexcept {
|
||||||
return __builtin_is_constant_evaluated();
|
return __builtin_is_constant_evaluated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_trivially_copyable_v = __is_trivially_copyable(T);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@ -156,6 +159,9 @@ static_assert(is_class<int>::value == false);
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr bool is_class_v = is_class<T>();
|
constexpr bool is_class_v = is_class<T>();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_trivially_copyable_v = std::is_trivially_copyable_v<T>;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr bool is_signed_v = integral_constant<bool, T(-1) < T(0)>::value;
|
constexpr bool is_signed_v = integral_constant<bool, T(-1) < T(0)>::value;
|
||||||
|
|
||||||
|
21
deps/teagba/src/cstartup.cpp
vendored
21
deps/teagba/src/cstartup.cpp
vendored
@ -4,17 +4,20 @@
|
|||||||
|
|
||||||
#include <ox/std/heapmgr.hpp>
|
#include <ox/std/heapmgr.hpp>
|
||||||
|
|
||||||
|
#include <teagba/bios.hpp>
|
||||||
|
#include <teagba/registers.hpp>
|
||||||
|
|
||||||
namespace mgba {
|
namespace mgba {
|
||||||
void initConsole();
|
void initConsole();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MEM_EWRAM_BEGIN reinterpret_cast<char*>(0x02000000)
|
#define MEM_HEAP_BEGIN reinterpret_cast<char*>(0x02000000)
|
||||||
#define MEM_EWRAM_END reinterpret_cast<char*>(0x0203FFFF)
|
#define MEM_HEAP_END reinterpret_cast<char*>(0x0203FFFF)
|
||||||
|
|
||||||
#define HEAP_BEGIN reinterpret_cast<char*>(MEM_EWRAM_BEGIN)
|
#define HEAP_BEGIN reinterpret_cast<char*>(MEM_HEAP_BEGIN)
|
||||||
// set size to half of EWRAM
|
// set size to half of EWRAM
|
||||||
#define HEAP_SIZE ((MEM_EWRAM_END - MEM_EWRAM_BEGIN) / 2)
|
#define HEAP_SIZE ((MEM_HEAP_END - MEM_HEAP_BEGIN) / 2)
|
||||||
#define HEAP_END reinterpret_cast<char*>(MEM_EWRAM_BEGIN + HEAP_SIZE)
|
#define HEAP_END reinterpret_cast<char*>(MEM_HEAP_BEGIN + HEAP_SIZE)
|
||||||
|
|
||||||
extern void (*__preinit_array_start[]) (void);
|
extern void (*__preinit_array_start[]) (void);
|
||||||
extern void (*__preinit_array_end[]) (void);
|
extern void (*__preinit_array_end[]) (void);
|
||||||
@ -25,6 +28,14 @@ int main(int argc, const char **argv);
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
void abort() {
|
||||||
|
REG_IE = 0;
|
||||||
|
teagba::intrwait(0, 0);
|
||||||
|
while (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *__gxx_personality_v0{};
|
||||||
|
|
||||||
void __libc_init_array() {
|
void __libc_init_array() {
|
||||||
auto preInits = __preinit_array_end - __preinit_array_start;
|
auto preInits = __preinit_array_end - __preinit_array_start;
|
||||||
for (decltype(preInits) i = 0; i < preInits; i++) {
|
for (decltype(preInits) i = 0; i < preInits; i++) {
|
||||||
|
@ -162,11 +162,9 @@ The Ox way of doing things is the Olympic way of doing things.
|
|||||||
|
|
||||||
### Error Handling
|
### Error Handling
|
||||||
|
|
||||||
The GBA build has exceptions disabled.
|
Instead of throwing exceptions, generally try to use
|
||||||
Instead of throwing exceptions, all engine code should return
|
[ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting,
|
||||||
[ox::Errors](deps/ox/ox-docs.md#error-handling) for error reporting.
|
but exceptions may be used where they make sense.
|
||||||
For the sake of consistency, try to stick to ```ox::Error``` in non-engine code
|
|
||||||
as well, but non-engine code is free to use exceptions when they make sense.
|
|
||||||
|
|
||||||
Exceptions should generally just use ```OxException```, which is bascially an
|
Exceptions should generally just use ```OxException```, which is bascially an
|
||||||
exception form of ```ox::Error```.
|
exception form of ```ox::Error```.
|
||||||
|
@ -142,6 +142,10 @@ ox::Error loadBgTileSheet(
|
|||||||
unsigned cbb,
|
unsigned cbb,
|
||||||
TileSheetSet const&set) noexcept;
|
TileSheetSet const&set) noexcept;
|
||||||
|
|
||||||
|
void clearCbb(Context &ctx, unsigned cbb) noexcept;
|
||||||
|
|
||||||
|
void clearCbbs(Context &ctx) noexcept;
|
||||||
|
|
||||||
ox::Error loadBgTileSheet(
|
ox::Error loadBgTileSheet(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
unsigned cbb,
|
unsigned cbb,
|
||||||
|
11
src/nostalgia/modules/core/include/nostalgia/core/studio.hpp
Normal file
11
src/nostalgia/modules/core/include/nostalgia/core/studio.hpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <studio/studio.hpp>
|
||||||
|
|
||||||
|
namespace nostalgia::core {
|
||||||
|
|
||||||
|
}
|
@ -18,6 +18,23 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
|
struct SubSheetTemplate {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.SubSheetTemplate";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
ox::String name;
|
||||||
|
int32_t width{};
|
||||||
|
int32_t height{};
|
||||||
|
ox::Vector<SubSheetTemplate> subsheets;
|
||||||
|
};
|
||||||
|
|
||||||
|
OX_MODEL_BEGIN(SubSheetTemplate)
|
||||||
|
OX_MODEL_FIELD(name)
|
||||||
|
OX_MODEL_FIELD(width)
|
||||||
|
OX_MODEL_FIELD(height)
|
||||||
|
OX_MODEL_FIELD(subsheets)
|
||||||
|
OX_MODEL_END()
|
||||||
|
|
||||||
|
|
||||||
// Predecessor to TileSheet, kept for backward compatibility
|
// Predecessor to TileSheet, kept for backward compatibility
|
||||||
struct TileSheetV1 {
|
struct TileSheetV1 {
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaGraphic";
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaGraphic";
|
||||||
@ -237,7 +254,9 @@ struct TileSheetV4 {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr bool valid(TileSheetV4::SubSheet const&ss, int bpp) noexcept {
|
constexpr bool valid(TileSheetV4::SubSheet const&ss, int bpp) noexcept {
|
||||||
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
|
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
|
||||||
return ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
|
return
|
||||||
|
(ss.pixels.empty() || ss.subsheets.empty()) &&
|
||||||
|
ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
|
||||||
[bpp, bytes](TileSheetV4::SubSheet const&s) {
|
[bpp, bytes](TileSheetV4::SubSheet const&s) {
|
||||||
return bytes == s.pixels.size() && valid(s, bpp);
|
return bytes == s.pixels.size() && valid(s, bpp);
|
||||||
});
|
});
|
||||||
@ -249,8 +268,14 @@ constexpr bool valid(TileSheetV4 const&ts) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr void repair(TileSheetV4::SubSheet &ss, int bpp) noexcept {
|
constexpr void repair(TileSheetV4::SubSheet &ss, int bpp) noexcept {
|
||||||
|
if (ss.subsheets.empty()) {
|
||||||
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
|
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) / (bpp == 4 ? 2 : 1);
|
||||||
ss.pixels.resize(bytes);
|
ss.pixels.resize(bytes);
|
||||||
|
} else {
|
||||||
|
ss.pixels.clear();
|
||||||
|
ss.columns = -1;
|
||||||
|
ss.rows = -1;
|
||||||
|
}
|
||||||
for (auto &s : ss.subsheets) {
|
for (auto &s : ss.subsheets) {
|
||||||
repair(s, bpp);
|
repair(s, bpp);
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,19 @@ ox::Error loadSpritePalette(
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearCbb(Context&, unsigned const cbb) noexcept {
|
||||||
|
for (auto &v : MEM_BG_TILES[cbb]) {
|
||||||
|
v = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearCbbs(Context &ctx) noexcept {
|
||||||
|
clearCbb(ctx, 0);
|
||||||
|
clearCbb(ctx, 1);
|
||||||
|
clearCbb(ctx, 2);
|
||||||
|
clearCbb(ctx, 3);
|
||||||
|
}
|
||||||
|
|
||||||
static ox::Error loadTileSheetSet(
|
static ox::Error loadTileSheetSet(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
ox::Span<uint16_t> tileMapTargetMem,
|
ox::Span<uint16_t> tileMapTargetMem,
|
||||||
@ -99,10 +112,10 @@ ox::Error loadBgTileSheet(
|
|||||||
size_t const tileCnt) noexcept {
|
size_t const tileCnt) noexcept {
|
||||||
size_t const bppMod = ts.bpp == 4;
|
size_t const bppMod = ts.bpp == 4;
|
||||||
size_t const bytesPerTile = PixelsPerTile >> bppMod;
|
size_t const bytesPerTile = PixelsPerTile >> bppMod;
|
||||||
auto const pixCnt = tileCnt * bytesPerTile;
|
auto const cnt = (tileCnt * bytesPerTile) / 2;
|
||||||
auto const srcPxIdx = srcTileIdx * bytesPerTile;
|
auto const srcPxIdx = srcTileIdx * bytesPerTile;
|
||||||
auto const dstPxIdx = (dstTileIdx * bytesPerTile) / 2;
|
auto const dstPxIdx = (dstTileIdx * bytesPerTile) / 2;
|
||||||
for (size_t i = 0; i < pixCnt; ++i) {
|
for (size_t i = 0; i < cnt; ++i) {
|
||||||
auto const srcIdx = srcPxIdx + i * 2;
|
auto const srcIdx = srcPxIdx + i * 2;
|
||||||
auto const p1 = static_cast<uint16_t>(ts.pixels[srcIdx]);
|
auto const p1 = static_cast<uint16_t>(ts.pixels[srcIdx]);
|
||||||
auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]);
|
auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <ox/std/def.hpp>
|
#include <ox/std/def.hpp>
|
||||||
|
#include <ox/std/realstd.hpp>
|
||||||
|
|
||||||
#include <keel/media.hpp>
|
#include <keel/media.hpp>
|
||||||
#include <turbine/turbine.hpp>
|
#include <turbine/turbine.hpp>
|
||||||
@ -51,9 +52,7 @@ OX_ALLOW_UNSAFE_BUFFERS_END
|
|||||||
if (err.src.file_name() != nullptr) {
|
if (err.src.file_name() != nullptr) {
|
||||||
oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
|
oxErrf("\tError Location:\t{}:{}\n", err.src.file_name(), err.src.line());
|
||||||
}
|
}
|
||||||
// disable all interrupt handling and IntrWait on no interrupts
|
abort();
|
||||||
REG_IE = 0;
|
|
||||||
teagba::intrwait(0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ static class: public keel::Module {
|
|||||||
ox::Vector<keel::PackTransform> packTransforms() const noexcept final {
|
ox::Vector<keel::PackTransform> packTransforms() const noexcept final {
|
||||||
return {
|
return {
|
||||||
// convert tilesheets to CompactTileSheets
|
// convert tilesheets to CompactTileSheets
|
||||||
[](keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) -> ox::Result<bool> {
|
[](keel::Context &ctx, ox::Buffer &buff, ox::StringViewCR typeId) -> ox::Result<bool> {
|
||||||
if (typeId == ox::ModelTypeId_v<TileSheetV1> ||
|
if (typeId == ox::ModelTypeId_v<TileSheetV1> ||
|
||||||
typeId == ox::ModelTypeId_v<TileSheetV2> ||
|
typeId == ox::ModelTypeId_v<TileSheetV2> ||
|
||||||
typeId == ox::ModelTypeId_v<TileSheetV3> ||
|
typeId == ox::ModelTypeId_v<TileSheetV3> ||
|
||||||
@ -78,7 +78,7 @@ static class: public keel::Module {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
[](keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) -> ox::Result<bool> {
|
[](keel::Context &ctx, ox::Buffer &buff, ox::StringViewCR typeId) -> ox::Result<bool> {
|
||||||
if (typeId == ox::ModelTypeId_v<NostalgiaPalette> ||
|
if (typeId == ox::ModelTypeId_v<NostalgiaPalette> ||
|
||||||
typeId == ox::ModelTypeId_v<PaletteV1> ||
|
typeId == ox::ModelTypeId_v<PaletteV1> ||
|
||||||
typeId == ox::ModelTypeId_v<PaletteV2> ||
|
typeId == ox::ModelTypeId_v<PaletteV2> ||
|
||||||
|
@ -111,15 +111,15 @@ static constexpr auto bgVertexRow(uint_t x, uint_t y) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void setSpriteBufferObject(
|
static void setSpriteBufferObject(
|
||||||
uint_t vi,
|
uint_t const vi,
|
||||||
float enabled,
|
float const enabled,
|
||||||
float x,
|
float x,
|
||||||
float y,
|
float y,
|
||||||
uint_t textureRow,
|
uint_t const textureRow,
|
||||||
uint_t flipX,
|
uint_t const flipX,
|
||||||
uint_t priority,
|
uint_t const priority,
|
||||||
float *vbo,
|
ox::Span<float> const vbo,
|
||||||
GLuint *ebo) noexcept {
|
ox::Span<GLuint> const ebo) noexcept {
|
||||||
// don't worry, this memcpy gets optimized to something much more ideal
|
// don't worry, this memcpy gets optimized to something much more ideal
|
||||||
constexpr float xmod = 0.1f;
|
constexpr float xmod = 0.1f;
|
||||||
constexpr float ymod = 0.1f;
|
constexpr float ymod = 0.1f;
|
||||||
@ -138,25 +138,25 @@ static void setSpriteBufferObject(
|
|||||||
enabled, x + xmod, y + ymod, prif, R, textureRowf + 0, // top right
|
enabled, x + xmod, y + ymod, prif, R, textureRowf + 0, // top right
|
||||||
enabled, x, y + ymod, prif, L, textureRowf + 0, // top left
|
enabled, x, y + ymod, prif, L, textureRowf + 0, // top left
|
||||||
};
|
};
|
||||||
memcpy(vbo, vertices.data(), sizeof(vertices));
|
ox::spancpy<float>(vbo, vertices);
|
||||||
ox::Array<GLuint, SpriteVertexEboLength> const elms {
|
ox::Array<GLuint, SpriteVertexEboLength> const elms {
|
||||||
vi + 0, vi + 1, vi + 2,
|
vi + 0, vi + 1, vi + 2,
|
||||||
vi + 2, vi + 3, vi + 0,
|
vi + 2, vi + 3, vi + 0,
|
||||||
};
|
};
|
||||||
memcpy(ebo, elms.data(), sizeof(elms));
|
ox::spancpy<GLuint>(ebo, elms);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setTileBufferObject(
|
static void setTileBufferObject(
|
||||||
uint_t vi,
|
uint_t const vi,
|
||||||
float x,
|
float x,
|
||||||
float y,
|
float y,
|
||||||
float textureTileIdx,
|
float const textureTileIdx,
|
||||||
float priority,
|
float const priority,
|
||||||
float palOffset,
|
float const palOffset,
|
||||||
bool flipX,
|
bool const flipX,
|
||||||
bool flipY,
|
bool const flipY,
|
||||||
float *vbo,
|
ox::Span<float> const vbo,
|
||||||
GLuint *ebo) noexcept {
|
ox::Span<GLuint> const ebo) noexcept {
|
||||||
// don't worry, this memcpy gets optimized to something much more ideal
|
// don't worry, this memcpy gets optimized to something much more ideal
|
||||||
constexpr float ymod = 0.1f;
|
constexpr float ymod = 0.1f;
|
||||||
constexpr float xmod = 0.1f;
|
constexpr float xmod = 0.1f;
|
||||||
@ -175,19 +175,30 @@ static void setTileBufferObject(
|
|||||||
x + xmod, y + ymod, prif, R, T, textureTileIdx, palOffset, // top right
|
x + xmod, y + ymod, prif, R, T, textureTileIdx, palOffset, // top right
|
||||||
x, y + ymod, prif, L, T, textureTileIdx, palOffset, // top left
|
x, y + ymod, prif, L, T, textureTileIdx, palOffset, // top left
|
||||||
};
|
};
|
||||||
memcpy(vbo, vertices.data(), sizeof(vertices));
|
ox::spancpy<float>(vbo, vertices);
|
||||||
ox::Array<GLuint, BgVertexEboLength> const elms {
|
ox::Array<GLuint, BgVertexEboLength> const elms {
|
||||||
vi + 0, vi + 1, vi + 2,
|
vi + 0, vi + 1, vi + 2,
|
||||||
vi + 2, vi + 3, vi + 0,
|
vi + 2, vi + 3, vi + 0,
|
||||||
};
|
};
|
||||||
memcpy(ebo, elms.data(), sizeof(elms));
|
ox::spancpy<GLuint>(ebo, elms);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void initSpriteBufferObjects(Context &ctx, glutils::BufferSet &bs) noexcept {
|
static void initSpriteBufferObjects(Context &ctx, glutils::BufferSet &bs) noexcept {
|
||||||
for (auto i = 0u; i < ctx.spriteCount; ++i) {
|
for (auto i = 0u; i < ctx.spriteCount; ++i) {
|
||||||
auto vbo = &bs.vertices[i * static_cast<std::size_t>(SpriteVertexVboLength)];
|
auto const vbo = ox::Span{bs.vertices}
|
||||||
auto ebo = &bs.elements[i * static_cast<std::size_t>(SpriteVertexEboLength)];
|
+ i * static_cast<std::size_t>(SpriteVertexVboLength);
|
||||||
setSpriteBufferObject(i * static_cast<uint_t>(SpriteVertexVboRows) * ctx.blocksPerSprite, 0, 0, 0, 0, false, 0, vbo, ebo);
|
auto const ebo = ox::Span{bs.elements}
|
||||||
|
+ i * static_cast<std::size_t>(SpriteVertexEboLength);
|
||||||
|
setSpriteBufferObject(
|
||||||
|
i * static_cast<uint_t>(SpriteVertexVboRows) * ctx.blocksPerSprite,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
0,
|
||||||
|
vbo,
|
||||||
|
ebo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,8 +206,10 @@ static void initBackgroundBufferObjects(glutils::BufferSet &bs) noexcept {
|
|||||||
for (auto x = 0u; x < TileColumns; ++x) {
|
for (auto x = 0u; x < TileColumns; ++x) {
|
||||||
for (auto y = 0u; y < TileRows; ++y) {
|
for (auto y = 0u; y < TileRows; ++y) {
|
||||||
const auto i = bgVertexRow(x, y);
|
const auto i = bgVertexRow(x, y);
|
||||||
auto vbo = &bs.vertices[i * static_cast<std::size_t>(BgVertexVboLength)];
|
auto const vbo = ox::Span{bs.vertices}
|
||||||
auto ebo = &bs.elements[i * static_cast<std::size_t>(BgVertexEboLength)];
|
+ i * static_cast<std::size_t>(BgVertexVboLength);
|
||||||
|
auto const ebo = ox::Span{bs.elements}
|
||||||
|
+ i * static_cast<std::size_t>(BgVertexEboLength);
|
||||||
setTileBufferObject(
|
setTileBufferObject(
|
||||||
static_cast<uint_t>(i * BgVertexVboRows),
|
static_cast<uint_t>(i * BgVertexVboRows),
|
||||||
static_cast<float>(x),
|
static_cast<float>(x),
|
||||||
@ -421,8 +434,8 @@ static void setSprite(
|
|||||||
auto const eboIdx = eboBase + renderer::SpriteVertexEboLength * i;
|
auto const eboIdx = eboBase + renderer::SpriteVertexEboLength * i;
|
||||||
oxAssert(vboIdx < ctx.spriteBlocks.vertices.size(), "vbo overflow");
|
oxAssert(vboIdx < ctx.spriteBlocks.vertices.size(), "vbo overflow");
|
||||||
oxAssert(eboIdx < ctx.spriteBlocks.elements.size(), "ebo overflow");
|
oxAssert(eboIdx < ctx.spriteBlocks.elements.size(), "ebo overflow");
|
||||||
auto const vbo = &ctx.spriteBlocks.vertices[vboIdx];
|
auto const vbo = ox::Span{ctx.spriteBlocks.vertices} + vboIdx;
|
||||||
auto const ebo = &ctx.spriteBlocks.elements[eboIdx];
|
auto const ebo = ox::Span{ctx.spriteBlocks.elements} + eboIdx;
|
||||||
renderer::setSpriteBufferObject(
|
renderer::setSpriteBufferObject(
|
||||||
static_cast<uint_t>(vboIdx),
|
static_cast<uint_t>(vboIdx),
|
||||||
enabled,
|
enabled,
|
||||||
@ -556,7 +569,7 @@ static void copyPixels(
|
|||||||
CompactTileSheet const&ts,
|
CompactTileSheet const&ts,
|
||||||
ox::Span<uint32_t> dst,
|
ox::Span<uint32_t> dst,
|
||||||
size_t const srcPxIdx,
|
size_t const srcPxIdx,
|
||||||
size_t pxlCnt) noexcept {
|
size_t const pxlCnt) noexcept {
|
||||||
size_t idx{};
|
size_t idx{};
|
||||||
if (ts.bpp == 4) {
|
if (ts.bpp == 4) {
|
||||||
for (size_t i = 0; i < pxlCnt; i += 2) {
|
for (size_t i = 0; i < pxlCnt; i += 2) {
|
||||||
@ -573,6 +586,18 @@ static void copyPixels(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearCbb(Context &ctx, unsigned const cbb) noexcept {
|
||||||
|
for (auto &v : ctx.cbbs[cbb].pixels) {
|
||||||
|
v = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearCbbs(Context &ctx) noexcept {
|
||||||
|
for (unsigned i = 0 ; i < ctx.cbbs.size(); ++i) {
|
||||||
|
clearCbb(ctx, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ox::Error loadBgTileSheet(
|
ox::Error loadBgTileSheet(
|
||||||
Context &ctx,
|
Context &ctx,
|
||||||
unsigned const cbb,
|
unsigned const cbb,
|
||||||
@ -656,8 +681,8 @@ void setBgTile(
|
|||||||
const auto x = static_cast<uint_t>(column);
|
const auto x = static_cast<uint_t>(column);
|
||||||
const auto i = renderer::bgVertexRow(x, y);
|
const auto i = renderer::bgVertexRow(x, y);
|
||||||
auto &cbb = ctx.cbbs[z];
|
auto &cbb = ctx.cbbs[z];
|
||||||
const auto vbo = &cbb.vertices[i * renderer::BgVertexVboLength];
|
const auto vbo = ox::Span{cbb.vertices} + i * renderer::BgVertexVboLength;
|
||||||
const auto ebo = &cbb.elements[i * renderer::BgVertexEboLength];
|
const auto ebo = ox::Span{cbb.elements} + i * renderer::BgVertexEboLength;
|
||||||
auto &bg = ctx.backgrounds[bgIdx];
|
auto &bg = ctx.backgrounds[bgIdx];
|
||||||
renderer::setTileBufferObject(
|
renderer::setTileBufferObject(
|
||||||
static_cast<uint_t>(i * renderer::BgVertexVboRows),
|
static_cast<uint_t>(i * renderer::BgVertexVboRows),
|
||||||
|
@ -3,7 +3,6 @@ add_library(NostalgiaCore-Studio)
|
|||||||
add_library(
|
add_library(
|
||||||
NostalgiaCore-Studio-ImGui
|
NostalgiaCore-Studio-ImGui
|
||||||
studiomodule.cpp
|
studiomodule.cpp
|
||||||
tilesheeteditor/tilesheeteditor-imgui.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
@ -15,7 +14,6 @@ target_link_libraries(
|
|||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
NostalgiaCore-Studio-ImGui PUBLIC
|
NostalgiaCore-Studio-ImGui PUBLIC
|
||||||
NostalgiaCore-Studio
|
NostalgiaCore-Studio
|
||||||
Studio
|
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
|
@ -9,5 +9,9 @@ target_sources(
|
|||||||
commands/renamepagecommand.cpp
|
commands/renamepagecommand.cpp
|
||||||
commands/updatecolorcommand.cpp
|
commands/updatecolorcommand.cpp
|
||||||
commands/updatecolorinfocommand.cpp
|
commands/updatecolorinfocommand.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_sources(
|
||||||
|
NostalgiaCore-Studio-ImGui PRIVATE
|
||||||
paletteeditor-imgui.cpp
|
paletteeditor-imgui.cpp
|
||||||
)
|
)
|
||||||
|
@ -6,6 +6,11 @@ target_sources(
|
|||||||
tilesheetpixels.cpp
|
tilesheetpixels.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_sources(
|
||||||
|
NostalgiaCore-Studio-ImGui PRIVATE
|
||||||
|
tilesheeteditor-imgui.cpp
|
||||||
|
)
|
||||||
|
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
NostalgiaCore-Studio-ImGui PUBLIC
|
NostalgiaCore-Studio-ImGui PUBLIC
|
||||||
lodepng
|
lodepng
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
core::InsertTilesCommand::InsertTilesCommand(
|
InsertTilesCommand::InsertTilesCommand(
|
||||||
TileSheet &img,
|
TileSheet &img,
|
||||||
TileSheet::SubSheetIdx idx,
|
TileSheet::SubSheetIdx idx,
|
||||||
std::size_t tileIdx,
|
std::size_t tileIdx,
|
||||||
@ -31,9 +31,11 @@ ox::Error InsertTilesCommand::redo() noexcept {
|
|||||||
auto &s = getSubSheet(m_img, m_idx);
|
auto &s = getSubSheet(m_img, m_idx);
|
||||||
auto &p = s.pixels;
|
auto &p = s.pixels;
|
||||||
auto dstPos = m_insertPos + m_insertCnt;
|
auto dstPos = m_insertPos + m_insertCnt;
|
||||||
auto const dst = &p[dstPos];
|
|
||||||
auto const src = &p[m_insertPos];
|
auto const src = &p[m_insertPos];
|
||||||
|
if (dstPos < p.size()) {
|
||||||
|
auto const dst = &p[dstPos];
|
||||||
ox::memmove(dst, src, p.size() - dstPos);
|
ox::memmove(dst, src, p.size() - dstPos);
|
||||||
|
}
|
||||||
ox::memset(src, 0, m_insertCnt * sizeof(decltype(p[0])));
|
ox::memset(src, 0, m_insertCnt * sizeof(decltype(p[0])));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -41,12 +43,14 @@ ox::Error InsertTilesCommand::redo() noexcept {
|
|||||||
ox::Error InsertTilesCommand::undo() noexcept {
|
ox::Error InsertTilesCommand::undo() noexcept {
|
||||||
auto &s = getSubSheet(m_img, m_idx);
|
auto &s = getSubSheet(m_img, m_idx);
|
||||||
auto &p = s.pixels;
|
auto &p = s.pixels;
|
||||||
auto const srcIdx = m_insertPos + m_insertCnt;
|
|
||||||
auto const src = &p[srcIdx];
|
|
||||||
auto const dst1 = &p[m_insertPos];
|
auto const dst1 = &p[m_insertPos];
|
||||||
auto const dst2 = &p[p.size() - m_insertCnt];
|
auto const dst2 = &p[p.size() - m_insertCnt];
|
||||||
|
auto const srcIdx = m_insertPos + m_insertCnt;
|
||||||
|
if (srcIdx < p.size()) {
|
||||||
auto const sz = p.size() - srcIdx;
|
auto const sz = p.size() - srcIdx;
|
||||||
|
auto const src = &p[srcIdx];
|
||||||
ox::memmove(dst1, src, sz);
|
ox::memmove(dst1, src, sz);
|
||||||
|
}
|
||||||
ox::memcpy(dst2, m_deletedPixels.data(), m_deletedPixels.size());
|
ox::memcpy(dst2, m_deletedPixels.data(), m_deletedPixels.size());
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -9,27 +9,24 @@ namespace nostalgia::core {
|
|||||||
core::UpdateSubSheetCommand::UpdateSubSheetCommand(
|
core::UpdateSubSheetCommand::UpdateSubSheetCommand(
|
||||||
TileSheet &img,
|
TileSheet &img,
|
||||||
TileSheet::SubSheetIdx idx,
|
TileSheet::SubSheetIdx idx,
|
||||||
ox::String name,
|
ox::StringParam name,
|
||||||
int cols,
|
int const cols,
|
||||||
int rows) noexcept:
|
int const rows):
|
||||||
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_newName(std::move(name)),
|
m_sheet = getSubSheet(m_img, m_idx);
|
||||||
m_newCols(cols),
|
m_sheet.name = std::move(name);
|
||||||
m_newRows(rows) {
|
OX_THROW_ERROR(resizeSubsheet(m_sheet, m_img.bpp, {cols, rows}));
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error UpdateSubSheetCommand::redo() noexcept {
|
ox::Error UpdateSubSheetCommand::redo() noexcept {
|
||||||
auto &sheet = getSubSheet(m_img, m_idx);
|
std::swap(m_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 {
|
||||||
auto &sheet = getSubSheet(m_img, m_idx);
|
std::swap(m_sheet, getSubSheet(m_img, m_idx));
|
||||||
sheet = m_sheet;
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,17 +13,14 @@ 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::String name,
|
ox::StringParam name,
|
||||||
int cols,
|
int cols,
|
||||||
int rows) noexcept;
|
int rows);
|
||||||
|
|
||||||
ox::Error redo() noexcept final;
|
ox::Error redo() noexcept final;
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ void TileSheetEditorImGui::draw(studio::StudioContext&) noexcept {
|
|||||||
if (ImGui::IsKeyDown(ImGuiKey_ModCtrl)) {
|
if (ImGui::IsKeyDown(ImGuiKey_ModCtrl)) {
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_A)) {
|
if (ImGui::IsKeyPressed(ImGuiKey_A)) {
|
||||||
auto const&img = m_model.activeSubSheet();
|
auto const&img = m_model.activeSubSheet();
|
||||||
m_model.setSelection({{}, {img.columns * TileWidth, img.rows * TileHeight}});
|
m_model.setSelection({{}, {img.columns * TileWidth - 1, img.rows * TileHeight - 1}});
|
||||||
} else if (ImGui::IsKeyPressed(ImGuiKey_G)) {
|
} else if (ImGui::IsKeyPressed(ImGuiKey_G)) {
|
||||||
m_model.clearSelection();
|
m_model.clearSelection();
|
||||||
}
|
}
|
||||||
@ -544,7 +544,7 @@ void TileSheetEditorImGui::SubSheetEditor::draw(turbine::Context &tctx) noexcept
|
|||||||
auto const popupHeight = modSize ? 130.f : 85.f;
|
auto const popupHeight = modSize ? 130.f : 85.f;
|
||||||
auto const popupSz = ImVec2{popupWidth, popupHeight};
|
auto const popupSz = ImVec2{popupWidth, popupHeight};
|
||||||
if (ig::BeginPopup(tctx, popupName, m_show, popupSz)) {
|
if (ig::BeginPopup(tctx, popupName, m_show, popupSz)) {
|
||||||
ImGui::InputText("Name", m_name.data(), m_name.cap());
|
ig::InputText("Name", m_name);
|
||||||
if (modSize) {
|
if (modSize) {
|
||||||
ImGui::InputInt("Columns", &m_cols);
|
ImGui::InputInt("Columns", &m_cols);
|
||||||
ImGui::InputInt("Rows", &m_rows);
|
ImGui::InputInt("Rows", &m_rows);
|
||||||
|
@ -26,11 +26,6 @@
|
|||||||
|
|
||||||
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()) {
|
||||||
@ -42,7 +37,14 @@ 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),
|
||||||
@ -62,7 +64,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 x, int y) {
|
iterateSelectionRows(*m_selection, [&](int const x, int const 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);
|
||||||
@ -73,7 +75,8 @@ 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>(CommandId::Cut, m_img, m_activeSubsSheetIdx, pt1, pt2, blankCb));
|
pushCommand(ox::make<CutPasteCommand>(
|
||||||
|
CommandId::Cut, m_img, m_activeSubsSheetIdx, pt1, pt2, blankCb));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::copy() {
|
void TileSheetEditorModel::copy() {
|
||||||
@ -81,7 +84,7 @@ void TileSheetEditorModel::copy() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto cb = ox::make_unique<TileSheetClipboard>();
|
auto cb = ox::make_unique<TileSheetClipboard>();
|
||||||
iterateSelectionRows(*m_selection, [&](int x, int y) {
|
iterateSelectionRows(*m_selection, [&](int const x, int const 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);
|
||||||
@ -105,7 +108,8 @@ 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>(CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb));
|
pushCommand(ox::make<CutPasteCommand>(
|
||||||
|
CommandId::Paste, m_img, m_activeSubsSheetIdx, pt1, pt2, *cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TileSheetEditorModel::acceptsClipboardPayload() const noexcept {
|
bool TileSheetEditorModel::acceptsClipboardPayload() const noexcept {
|
||||||
@ -120,8 +124,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 uuid = ox::StringView(&path[uuidPrefix.bytes()], path.bytes() - uuidPrefix.bytes());
|
auto const uuid = ox::StringView(&path[uuidPrefix.bytes()], path.bytes() - uuidPrefix.bytes());
|
||||||
auto out = keelCtx(m_tctx).uuidToPath.at(uuid);
|
auto const out = keelCtx(m_tctx).uuidToPath.at(uuid);
|
||||||
if (out.error) {
|
if (out.error) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -131,13 +135,14 @@ ox::StringView TileSheetEditorModel::palPath() const noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error TileSheetEditorModel::setPalette(ox::StringView path) noexcept {
|
ox::Error TileSheetEditorModel::setPalette(ox::StringViewCR path) noexcept {
|
||||||
OX_REQUIRE(uuid, keelCtx(m_tctx).pathToUuid.at(path));
|
OX_REQUIRE(uuid, keelCtx(m_tctx).pathToUuid.at(path));
|
||||||
pushCommand(ox::make<PaletteChangeCommand>(activeSubSheetIdx(), m_img, uuid->toString()));
|
pushCommand(ox::make<PaletteChangeCommand>(
|
||||||
|
activeSubSheetIdx(), m_img, uuid->toString()));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::setPalettePage(size_t pg) noexcept {
|
void TileSheetEditorModel::setPalettePage(size_t const 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;
|
||||||
}
|
}
|
||||||
@ -146,7 +151,7 @@ size_t TileSheetEditorModel::palettePage() const noexcept {
|
|||||||
return m_palettePage;
|
return m_palettePage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorModel::drawCommand(ox::Point const&pt, std::size_t palIdx) noexcept {
|
void TileSheetEditorModel::drawCommand(ox::Point const&pt, std::size_t const 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;
|
||||||
@ -155,7 +160,8 @@ void TileSheetEditorModel::drawCommand(ox::Point const&pt, std::size_t palIdx) n
|
|||||||
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>(m_img, m_activeSubsSheetIdx, idx, static_cast<int>(palIdx)));
|
pushCommand(ox::make<DrawCommand>(
|
||||||
|
m_img, m_activeSubsSheetIdx, idx, static_cast<int>(palIdx)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,16 +177,20 @@ 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(TileSheet::SubSheetIdx const&idx, std::size_t tileIdx, std::size_t tileCnt) noexcept {
|
void TileSheetEditorModel::insertTiles(
|
||||||
|
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(TileSheet::SubSheetIdx const&idx, std::size_t tileIdx, std::size_t tileCnt) noexcept {
|
void TileSheetEditorModel::deleteTiles(
|
||||||
|
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(TileSheet::SubSheetIdx const&idx, ox::StringView const&name, int cols, int rows) noexcept {
|
ox::Error TileSheetEditorModel::updateSubsheet(
|
||||||
pushCommand(ox::make<UpdateSubSheetCommand>(m_img, idx, ox::String(name), cols, rows));
|
TileSheet::SubSheetIdx const&idx, ox::StringViewCR name, int const cols, int const rows) noexcept {
|
||||||
|
OX_REQUIRE(cmd, ox::makeCatch<UpdateSubSheetCommand>(m_img, idx, name, cols, rows));
|
||||||
|
pushCommand(cmd);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +199,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 palIdx) noexcept {
|
void TileSheetEditorModel::fill(ox::Point const&pt, int const 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) {
|
||||||
@ -197,10 +207,10 @@ void TileSheetEditorModel::fill(ox::Point const&pt, int 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(updateMap, pt, oldColor);
|
getFillPixels(activeSubSheet, 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 u : updateMap) {
|
for (auto const u : updateMap) {
|
||||||
if (u) {
|
if (u) {
|
||||||
idxList.emplace_back(i);
|
idxList.emplace_back(i);
|
||||||
}
|
}
|
||||||
@ -230,7 +240,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&s = activeSubSheet();
|
auto const&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);
|
||||||
}
|
}
|
||||||
@ -275,47 +285,44 @@ 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 idx) const noexcept {
|
bool TileSheetEditorModel::pixelSelected(std::size_t const 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(ox::Span<bool> pixels, ox::Point const&pt, int oldColor) const noexcept {
|
void TileSheetEditorModel::getFillPixels(
|
||||||
const auto &activeSubSheet = this->activeSubSheet();
|
TileSheet::SubSheet const&activeSubSheet,
|
||||||
const auto tileIdx = [activeSubSheet](const ox::Point &pt) noexcept {
|
ox::Span<bool> pixels,
|
||||||
return ptToIdx(pt, activeSubSheet.columns) / PixelsPerTile;
|
ox::Point const&pt,
|
||||||
};
|
int const oldColor) const noexcept {
|
||||||
// get points
|
auto const idx = ptToIdx(pt, activeSubSheet.columns);
|
||||||
const auto leftPt = pt + ox::Point(-1, 0);
|
auto const relIdx = idx % PixelsPerTile;
|
||||||
const auto rightPt = pt + ox::Point(1, 0);
|
if (pixels[relIdx] || getPixel(activeSubSheet, m_img.bpp, idx) != oldColor) {
|
||||||
const auto topPt = pt + ox::Point(0, -1);
|
return;
|
||||||
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[idx % PixelsPerTile] = true;
|
pixels[relIdx] = true;
|
||||||
if (!pixels[leftIdx % PixelsPerTile] && tile == tileIdx(leftPt) && getPixel(activeSubSheet, m_img.bpp, leftIdx) == oldColor) {
|
if (pt.x % TileWidth != 0) {
|
||||||
getFillPixels(pixels, leftPt, oldColor);
|
auto const leftPt = pt + ox::Point{-1, 0};
|
||||||
|
getFillPixels(activeSubSheet, pixels, leftPt, oldColor);
|
||||||
}
|
}
|
||||||
if (!pixels[rightIdx % PixelsPerTile] && tile == tileIdx(rightPt) && getPixel(activeSubSheet, m_img.bpp, rightIdx) == oldColor) {
|
if (pt.x % TileWidth != TileWidth - 1) {
|
||||||
getFillPixels(pixels, rightPt, oldColor);
|
auto const rightPt = pt + ox::Point{1, 0};
|
||||||
|
getFillPixels(activeSubSheet, pixels, rightPt, oldColor);
|
||||||
}
|
}
|
||||||
if (!pixels[topIdx % PixelsPerTile] && tile == tileIdx(topPt) && getPixel(activeSubSheet, m_img.bpp, topIdx) == oldColor) {
|
if (pt.y % TileHeight != 0) {
|
||||||
getFillPixels(pixels, topPt, oldColor);
|
auto const topPt = pt + ox::Point{0, -1};
|
||||||
|
getFillPixels(activeSubSheet, pixels, topPt, oldColor);
|
||||||
}
|
}
|
||||||
if (!pixels[bottomIdx % PixelsPerTile] && tile == tileIdx(bottomPt) && getPixel(activeSubSheet, m_img.bpp, bottomIdx) == oldColor) {
|
if (pt.y % TileHeight != TileHeight - 1) {
|
||||||
getFillPixels(pixels, bottomPt, oldColor);
|
auto const bottomPt = pt + ox::Point{0, 1};
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,7 @@
|
|||||||
|
|
||||||
#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>
|
||||||
@ -38,7 +36,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
|||||||
bool m_updated = false;
|
bool m_updated = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TileSheetEditorModel(studio::StudioContext &sctx, ox::StringView path, studio::UndoStack &undoStack);
|
TileSheetEditorModel(studio::StudioContext &sctx, ox::StringViewCR path, studio::UndoStack &undoStack);
|
||||||
|
|
||||||
~TileSheetEditorModel() override = default;
|
~TileSheetEditorModel() override = default;
|
||||||
|
|
||||||
@ -63,7 +61,7 @@ class TileSheetEditorModel: public ox::SignalHandler {
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ox::StringView palPath() const noexcept;
|
ox::StringView palPath() const noexcept;
|
||||||
|
|
||||||
ox::Error setPalette(ox::StringView path) noexcept;
|
ox::Error setPalette(ox::StringViewCR path) noexcept;
|
||||||
|
|
||||||
void setPalettePage(size_t pg) noexcept;
|
void setPalettePage(size_t pg) noexcept;
|
||||||
|
|
||||||
@ -128,7 +126,11 @@ 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(ox::Span<bool> pixels, ox::Point const&pt, int oldColor) const noexcept;
|
void getFillPixels(
|
||||||
|
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;
|
||||||
|
|
||||||
|
@ -56,8 +56,10 @@ void TileSheetEditorView::scrollH(ox::Vec2 const&paneSz, float wheelh) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetEditorView::insertTile(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept {
|
void TileSheetEditorView::insertTile(ox::Vec2 const&paneSize, ox::Vec2 const&clickPos) noexcept {
|
||||||
auto const pt = clickPoint(paneSize, clickPos);
|
auto pt = clickPoint(paneSize, clickPos);
|
||||||
auto const&s = m_model.activeSubSheet();
|
auto const&s = m_model.activeSubSheet();
|
||||||
|
pt.x = ox::min(pt.x, s.columns * TileWidth - 1);
|
||||||
|
pt.y = ox::min(pt.y, s.rows * TileHeight - 1);
|
||||||
auto const tileIdx = ptToIdx(pt, s.columns) / PixelsPerTile;
|
auto const tileIdx = ptToIdx(pt, s.columns) / PixelsPerTile;
|
||||||
m_model.insertTiles(m_model.activeSubSheetIdx(), tileIdx, 1);
|
m_model.insertTiles(m_model.activeSubSheetIdx(), tileIdx, 1);
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,11 @@ void TileSheetGrid::setBufferObject(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetGrid::setBufferObjects(ox::Vec2 const&paneSize, TileSheet::SubSheet const&subsheet) noexcept {
|
void TileSheetGrid::setBufferObjects(ox::Vec2 const&paneSize, TileSheet::SubSheet const&subsheet) noexcept {
|
||||||
|
if (subsheet.columns < 1 || subsheet.rows < 1) {
|
||||||
|
m_bufferSet.elements.clear();
|
||||||
|
m_bufferSet.vertices.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto const pixSize = pixelSize(paneSize);
|
auto const pixSize = pixelSize(paneSize);
|
||||||
auto const set = [&](std::size_t i, ox::Point pt1, ox::Point pt2, Color32 c) {
|
auto const set = [&](std::size_t i, ox::Point pt1, ox::Point pt2, Color32 c) {
|
||||||
auto const vbo = &m_bufferSet.vertices[i * VertexVboLength];
|
auto const vbo = &m_bufferSet.vertices[i * VertexVboLength];
|
||||||
|
@ -51,7 +51,7 @@ ox::Error TileSheetPixels::buildShader() noexcept {
|
|||||||
return glutils::buildShaderProgram(s_programSrc).moveTo(m_shader);
|
return glutils::buildShaderProgram(s_programSrc).moveTo(m_shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TileSheetPixels::draw(bool update, ox::Vec2 const&scroll) noexcept {
|
void TileSheetPixels::draw(bool const update, ox::Vec2 const&scroll) noexcept {
|
||||||
glUseProgram(m_shader);
|
glUseProgram(m_shader);
|
||||||
glBindVertexArray(m_bufferSet.vao);
|
glBindVertexArray(m_bufferSet.vao);
|
||||||
if (update) {
|
if (update) {
|
||||||
@ -117,6 +117,11 @@ void TileSheetPixels::setPixelBufferObject(
|
|||||||
void TileSheetPixels::setBufferObjects(ox::Vec2 const&paneSize) noexcept {
|
void TileSheetPixels::setBufferObjects(ox::Vec2 const&paneSize) noexcept {
|
||||||
// set buffer lengths
|
// set buffer lengths
|
||||||
auto const&subSheet = m_model.activeSubSheet();
|
auto const&subSheet = m_model.activeSubSheet();
|
||||||
|
if (subSheet.columns < 1 || subSheet.rows < 1) {
|
||||||
|
m_bufferSet.vertices.clear();
|
||||||
|
m_bufferSet.elements.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto const&pal = m_model.pal();
|
auto const&pal = m_model.pal();
|
||||||
auto const width = subSheet.columns * TileWidth;
|
auto const width = subSheet.columns * TileWidth;
|
||||||
auto const height = subSheet.rows * TileHeight;
|
auto const height = subSheet.rows * TileHeight;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
namespace keel {
|
namespace keel {
|
||||||
|
|
||||||
class Context;
|
class Context;
|
||||||
using PackTransform = ox::Result<bool>(*)(Context&, ox::Buffer &clawData, ox::StringView);
|
using PackTransform = ox::Result<bool>(*)(Context&, ox::Buffer &clawData, ox::StringViewCR);
|
||||||
|
|
||||||
class Context {
|
class Context {
|
||||||
public:
|
public:
|
||||||
|
@ -70,7 +70,7 @@ constexpr auto makeLoader(Context &ctx) {
|
|||||||
if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
|
if (err != ox::Error_ClawTypeVersionMismatch && err != ox::Error_ClawTypeMismatch) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
OX_RETURN_ERROR(convert<T>(ctx, buff, &obj));
|
OX_RETURN_ERROR(convert<T>(ctx, buff, obj));
|
||||||
}
|
}
|
||||||
return std::move(obj);
|
return std::move(obj);
|
||||||
};
|
};
|
||||||
|
@ -125,7 +125,9 @@ ox::Error preloadObj(
|
|||||||
OX_RETURN_ERROR(err);
|
OX_RETURN_ERROR(err);
|
||||||
keel::PreloadPtr const p{.preloadAddr = a};
|
keel::PreloadPtr const p{.preloadAddr = a};
|
||||||
OX_RETURN_ERROR(ox::writeMC(p).moveTo(buff));
|
OX_RETURN_ERROR(ox::writeMC(p).moveTo(buff));
|
||||||
oxOutf("preloaded {} as a {} @ {} to {}\n", path, obj.type()->typeName, a, a + size);
|
auto const&pbufSz = pl.buff().size();
|
||||||
|
oxOutf("preloaded {} as a {} @ {} to {} / {}, total size: {}\n",
|
||||||
|
path, obj.type()->typeName, a, a + size, pbufSz - 1, pbufSz - a);
|
||||||
} else {
|
} else {
|
||||||
// strip the Claw header (it is not needed after preloading) and write back out to dest fs
|
// strip the Claw header (it is not needed after preloading) and write back out to dest fs
|
||||||
OX_RETURN_ERROR(ox::writeMC(obj).moveTo(buff));
|
OX_RETURN_ERROR(ox::writeMC(obj).moveTo(buff));
|
||||||
|
@ -16,10 +16,43 @@ 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 WrapInline: public Wrap {
|
class WrapT: 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;
|
||||||
|
|
||||||
@ -30,8 +63,15 @@ class WrapInline: public Wrap {
|
|||||||
constexpr explicit WrapInline(Args &&...args): m_obj(ox::forward<Args>(args)...) {
|
constexpr explicit WrapInline(Args &&...args): m_obj(ox::forward<Args>(args)...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
ox::CStringView typeName() const noexcept override {
|
||||||
constexpr T &obj() noexcept {
|
return ox::ModelTypeName_v<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
int typeVersion() const noexcept override {
|
||||||
|
return ox::ModelTypeVersion_v<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr T &obj() noexcept override {
|
||||||
return m_obj;
|
return m_obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +84,7 @@ constexpr ox::UPtr<Wrap> makeWrap(Args &&...args) noexcept {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr T &wrapCast(Wrap &ptr) noexcept {
|
constexpr T &wrapCast(Wrap &ptr) noexcept {
|
||||||
return static_cast<WrapInline<T>&>(ptr).obj();
|
return static_cast<WrapT<T>&>(ptr).obj();
|
||||||
}
|
}
|
||||||
|
|
||||||
class BaseConverter {
|
class BaseConverter {
|
||||||
@ -70,8 +110,8 @@ class BaseConverter {
|
|||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr bool matches(
|
constexpr bool matches(
|
||||||
ox::StringViewCR srcTypeName, int srcTypeVersion,
|
ox::StringViewCR srcTypeName, int const srcTypeVersion,
|
||||||
ox::StringViewCR dstTypeName, int dstTypeVersion) const noexcept {
|
ox::StringViewCR dstTypeName, int const dstTypeVersion) const noexcept {
|
||||||
return srcMatches(srcTypeName, srcTypeVersion)
|
return srcMatches(srcTypeName, srcTypeVersion)
|
||||||
&& dstMatches(dstTypeName, dstTypeVersion);
|
&& dstMatches(dstTypeName, dstTypeVersion);
|
||||||
}
|
}
|
||||||
@ -109,17 +149,17 @@ class Converter: public BaseConverter {
|
|||||||
|
|
||||||
ox::Result<ox::UPtr<Wrap>> convertPtrToPtr(
|
ox::Result<ox::UPtr<Wrap>> convertPtrToPtr(
|
||||||
keel::Context &ctx, Wrap &src) const noexcept final {
|
keel::Context &ctx, Wrap &src) const noexcept final {
|
||||||
auto dst = makeWrap<DstType>();
|
ox::Result<ox::UPtr<Wrap>> dst{makeWrap<DstType>()};
|
||||||
OX_RETURN_ERROR(convert(ctx, wrapCast<SrcType>(src), wrapCast<DstType>(*dst)));
|
OX_RETURN_ERROR(convert(ctx, wrapCast<SrcType>(src), wrapCast<DstType>(*dst.value)));
|
||||||
return {std::move(dst)};
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UPtr<Wrap>> convertBuffToPtr(
|
ox::Result<ox::UPtr<Wrap>> convertBuffToPtr(
|
||||||
keel::Context &ctx, ox::BufferView const&srcBuff) const noexcept final {
|
keel::Context &ctx, ox::BufferView const&srcBuff) const noexcept final {
|
||||||
OX_REQUIRE_M(src, readAsset<SrcType>(srcBuff));
|
OX_REQUIRE_M(src, readAsset<SrcType>(srcBuff));
|
||||||
auto dst = makeWrap<DstType>();
|
ox::Result<ox::UPtr<Wrap>> dst{makeWrap<DstType>()};
|
||||||
OX_RETURN_ERROR(convert(ctx, src, wrapCast<DstType>(*dst)));
|
OX_RETURN_ERROR(convert(ctx, src, wrapCast<DstType>(*dst.value)));
|
||||||
return {std::move(dst)};
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -133,34 +173,57 @@ 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> convert(keel::Context &ctx, ox::BufferView const&srcBuffer) noexcept {
|
ox::Result<DstType> convertObjToObj(
|
||||||
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
|
keel::Context &ctx,
|
||||||
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
|
auto &src) noexcept {
|
||||||
OX_REQUIRE(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion));
|
OX_REQUIRE_M(out, convert(ctx, WrapRef{src}, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
|
||||||
|
return std::move(wrapCast(*out));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename DstType>
|
||||||
|
ox::Result<DstType> convert(keel::Context &ctx, ox::BufferView const&src) noexcept {
|
||||||
|
OX_REQUIRE(out, convert(ctx, src, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
|
||||||
return std::move(wrapCast<DstType>(out));
|
return std::move(wrapCast<DstType>(out));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename DstType>
|
template<typename DstType>
|
||||||
ox::Error convert(keel::Context &ctx, ox::BufferView const&buff, DstType *outObj) noexcept {
|
ox::Error convert(keel::Context &ctx, ox::BufferView const&buff, DstType &outObj) noexcept {
|
||||||
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
|
OX_REQUIRE(out, convert(ctx, buff, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
|
||||||
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
|
outObj = std::move(wrapCast<DstType>(*out));
|
||||||
OX_REQUIRE(outPtr, convert(ctx, buff, DstTypeName, DstTypeVersion));
|
return {};
|
||||||
*outObj = std::move(wrapCast<DstType>(*outPtr));
|
}
|
||||||
|
|
||||||
|
template<typename DstType>
|
||||||
|
ox::Error convertObjToObj(keel::Context &ctx, auto &src, DstType &outObj) noexcept {
|
||||||
|
OX_REQUIRE(outPtr, convert(ctx, src, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
|
||||||
|
outObj = std::move(wrapCast<DstType>(*outPtr));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename DstType>
|
template<typename DstType>
|
||||||
ox::Result<ox::Buffer> convertBuffToBuff(
|
ox::Result<ox::Buffer> convertBuffToBuff(
|
||||||
keel::Context &ctx, ox::BufferView const&srcBuffer, ox::ClawFormat fmt) noexcept {
|
keel::Context &ctx, ox::BufferView const&src, ox::ClawFormat const fmt) noexcept {
|
||||||
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
|
OX_REQUIRE(out, convert(ctx, src, ox::ModelTypeName_v<DstType>, ox::ModelTypeVersion_v<DstType>));
|
||||||
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
|
|
||||||
OX_REQUIRE(out, convert(ctx, srcBuffer, DstTypeName, DstTypeVersion));
|
|
||||||
return ox::writeClaw<DstType>(wrapCast<DstType>(*out), fmt);
|
return ox::writeClaw<DstType>(wrapCast<DstType>(*out), fmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename From, typename To, ox::ClawFormat fmt = ox::ClawFormat::Metal>
|
template<typename From, typename To, ox::ClawFormat fmt = ox::ClawFormat::Metal>
|
||||||
ox::Result<bool> transformRule(keel::Context &ctx, ox::Buffer &buff, ox::StringView typeId) noexcept {
|
ox::Result<bool> transformRule(keel::Context &ctx, ox::Buffer &buff, ox::StringViewCR typeId) noexcept {
|
||||||
if (typeId == ox::ModelTypeId_v<From>) {
|
if (typeId == ox::ModelTypeId_v<From>) {
|
||||||
OX_RETURN_ERROR(keel::convertBuffToBuff<To>(ctx, buff, fmt).moveTo(buff));
|
OX_RETURN_ERROR(keel::convertBuffToBuff<To>(ctx, buff, fmt).moveTo(buff));
|
||||||
return true;
|
return true;
|
||||||
@ -168,5 +231,4 @@ ox::Result<bool> transformRule(keel::Context &ctx, ox::Buffer &buff, ox::StringV
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -154,13 +154,12 @@ ox::Result<ox::CStringView> uuidToPath(Context &ctx, ox::UUID const&uuid) noexce
|
|||||||
}
|
}
|
||||||
|
|
||||||
ox::Error reloadAsset(keel::Context &ctx, ox::StringViewCR assetId) noexcept {
|
ox::Error reloadAsset(keel::Context &ctx, ox::StringViewCR assetId) noexcept {
|
||||||
ox::UUIDStr uuidStr;
|
|
||||||
if (beginsWith(assetId, "uuid://")) {
|
if (beginsWith(assetId, "uuid://")) {
|
||||||
return ctx.assetManager.reloadAsset(substr(assetId, 7));
|
return ctx.assetManager.reloadAsset(substr(assetId, 7));
|
||||||
} else {
|
} else {
|
||||||
auto const [uuid, uuidErr] = getUuid(ctx, assetId);
|
auto const [uuid, uuidErr] = getUuid(ctx, assetId);
|
||||||
if (!uuidErr) {
|
if (!uuidErr) {
|
||||||
return ctx.assetManager.reloadAsset(uuidStr);
|
return ctx.assetManager.reloadAsset(uuid.toString());
|
||||||
} else {
|
} else {
|
||||||
return ctx.assetManager.reloadAsset(assetId);
|
return ctx.assetManager.reloadAsset(assetId);
|
||||||
}
|
}
|
||||||
|
@ -10,30 +10,38 @@ namespace keel {
|
|||||||
static ox::Result<BaseConverter const*> findConverter(
|
static ox::Result<BaseConverter const*> findConverter(
|
||||||
ox::SpanView<BaseConverter const*> const&converters,
|
ox::SpanView<BaseConverter const*> const&converters,
|
||||||
ox::StringViewCR srcTypeName,
|
ox::StringViewCR srcTypeName,
|
||||||
int srcTypeVersion,
|
int const srcTypeVersion,
|
||||||
ox::StringViewCR dstTypeName,
|
ox::StringViewCR dstTypeName,
|
||||||
int dstTypeVersion) noexcept {
|
int const dstTypeVersion) noexcept {
|
||||||
for (auto const&c : converters) {
|
for (auto const&c : converters) {
|
||||||
if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
|
if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ox::Error(1, "Could not find converter");
|
return ox::Error{1, "Could not find converter"};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static ox::Result<ox::UPtr<Wrap>> convert(BaseConverter const&c, Context &ctx, ox::BufferView const&src) noexcept {
|
||||||
|
return c.convertBuffToPtr(ctx, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ox::Result<ox::UPtr<Wrap>> convert(BaseConverter const&c, Context &ctx, Wrap &src) noexcept {
|
||||||
|
return c.convertPtrToPtr(ctx, src);
|
||||||
|
}
|
||||||
|
|
||||||
static ox::Result<ox::UPtr<Wrap>> convert(
|
static ox::Result<ox::UPtr<Wrap>> convert(
|
||||||
keel::Context &ctx,
|
Context &ctx,
|
||||||
ox::SpanView<BaseConverter const*> const&converters,
|
ox::SpanView<BaseConverter const*> const&converters,
|
||||||
ox::BufferView const&srcBuffer,
|
auto &src,
|
||||||
ox::StringViewCR srcTypeName,
|
ox::StringViewCR srcTypeName,
|
||||||
int srcTypeVersion,
|
int const srcTypeVersion,
|
||||||
ox::StringViewCR dstTypeName,
|
ox::StringViewCR dstTypeName,
|
||||||
int dstTypeVersion) noexcept {
|
int const dstTypeVersion) noexcept {
|
||||||
// look for direct converter
|
// look for direct converter
|
||||||
auto [c, err] = findConverter(
|
auto const [c, err] = findConverter(
|
||||||
converters, srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion);
|
converters, srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
return c->convertBuffToPtr(ctx, srcBuffer);
|
return convert(*c, ctx, src);
|
||||||
}
|
}
|
||||||
// try to chain multiple converters
|
// try to chain multiple converters
|
||||||
for (auto const&subConverter : converters) {
|
for (auto const&subConverter : converters) {
|
||||||
@ -41,20 +49,20 @@ static ox::Result<ox::UPtr<Wrap>> convert(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto [intermediate, chainErr] =
|
const auto [intermediate, chainErr] =
|
||||||
convert(ctx, converters, srcBuffer, srcTypeName, srcTypeVersion,
|
convert(ctx, converters, src, srcTypeName, srcTypeVersion,
|
||||||
subConverter->srcTypeName(), subConverter->srcTypeVersion());
|
subConverter->srcTypeName(), subConverter->srcTypeVersion());
|
||||||
if (!chainErr) {
|
if (!chainErr) {
|
||||||
return subConverter->convertPtrToPtr(ctx, *intermediate);
|
return subConverter->convertPtrToPtr(ctx, *intermediate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ox::Error(1, "Could not convert between types");
|
return ox::Error{1, "Could not convert between types"};
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UPtr<Wrap>> convert(
|
ox::Result<ox::UPtr<Wrap>> convert(
|
||||||
keel::Context &ctx,
|
Context &ctx,
|
||||||
ox::BufferView const&srcBuffer,
|
ox::BufferView const&srcBuffer,
|
||||||
ox::StringViewCR dstTypeName,
|
ox::StringViewCR dstTypeName,
|
||||||
int dstTypeVersion) noexcept {
|
int const dstTypeVersion) noexcept {
|
||||||
OX_REQUIRE(hdr, readAssetHeader(srcBuffer));
|
OX_REQUIRE(hdr, readAssetHeader(srcBuffer));
|
||||||
return convert(
|
return convert(
|
||||||
ctx,
|
ctx,
|
||||||
@ -66,4 +74,19 @@ ox::Result<ox::UPtr<Wrap>> convert(
|
|||||||
dstTypeVersion);
|
dstTypeVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ox::Result<ox::UPtr<Wrap>> convert(
|
||||||
|
Context &ctx,
|
||||||
|
Wrap &src,
|
||||||
|
ox::StringViewCR dstTypeName,
|
||||||
|
int const dstTypeVersion) noexcept {
|
||||||
|
return convert(
|
||||||
|
ctx,
|
||||||
|
converters(ctx),
|
||||||
|
src,
|
||||||
|
src.typeName(),
|
||||||
|
src.typeVersion(),
|
||||||
|
dstTypeName,
|
||||||
|
dstTypeVersion);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ void NewProject::draw(studio::StudioContext &ctx) noexcept {
|
|||||||
|
|
||||||
void NewProject::drawNewProjectName(studio::StudioContext &sctx) noexcept {
|
void NewProject::drawNewProjectName(studio::StudioContext &sctx) noexcept {
|
||||||
drawWindow(sctx.tctx, &m_open, [this, &sctx] {
|
drawWindow(sctx.tctx, &m_open, [this, &sctx] {
|
||||||
ImGui::InputText("Name", m_projectName.data(), m_projectName.cap());
|
ig::InputText("Name", m_projectName);
|
||||||
ImGui::Text("Path: %s", m_projectPath.c_str());
|
ImGui::Text("Path: %s", m_projectPath.c_str());
|
||||||
if (ImGui::Button("Browse")) {
|
if (ImGui::Button("Browse")) {
|
||||||
oxLogError(studio::chooseDirectory().moveTo(m_projectPath));
|
oxLogError(studio::chooseDirectory().moveTo(m_projectPath));
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
|
|
||||||
namespace studio {
|
namespace studio {
|
||||||
|
|
||||||
static ox::Vector<studio::Module const*> modules;
|
static ox::Vector<Module const*> modules;
|
||||||
|
|
||||||
void registerModule(studio::Module const*mod) noexcept {
|
void registerModule(Module const*mod) noexcept {
|
||||||
if (mod) {
|
if (mod) {
|
||||||
modules.emplace_back(mod);
|
modules.emplace_back(mod);
|
||||||
}
|
}
|
||||||
@ -45,25 +45,25 @@ OX_MODEL_END()
|
|||||||
|
|
||||||
StudioUI::StudioUI(turbine::Context &ctx, ox::StringParam projectDataDir) noexcept:
|
StudioUI::StudioUI(turbine::Context &ctx, ox::StringParam projectDataDir) noexcept:
|
||||||
m_sctx(*this, ctx),
|
m_sctx(*this, ctx),
|
||||||
m_ctx(ctx),
|
m_tctx(ctx),
|
||||||
m_projectDataDir(std::move(projectDataDir)),
|
m_projectDataDir(std::move(projectDataDir)),
|
||||||
m_projectExplorer(m_ctx),
|
m_projectExplorer(m_tctx),
|
||||||
m_newProject(m_projectDataDir),
|
m_newProject(m_projectDataDir),
|
||||||
m_aboutPopup(m_ctx) {
|
m_aboutPopup(m_tctx) {
|
||||||
turbine::setApplicationData(m_ctx, &m_sctx);
|
turbine::setApplicationData(m_tctx, &m_sctx);
|
||||||
m_projectExplorer.fileChosen.connect(this, &StudioUI::openFile);
|
m_projectExplorer.fileChosen.connect(this, &StudioUI::openFile);
|
||||||
m_newProject.finished.connect(this, &StudioUI::createOpenProject);
|
m_newProject.finished.connect(this, &StudioUI::createOpenProject);
|
||||||
m_newMenu.finished.connect(this, &StudioUI::openFile);
|
m_newMenu.finished.connect(this, &StudioUI::openFile);
|
||||||
ImGui::GetIO().IniFilename = nullptr;
|
ImGui::GetIO().IniFilename = nullptr;
|
||||||
loadModules();
|
loadModules();
|
||||||
// open project and files
|
// open project and files
|
||||||
auto const [config, err] = studio::readConfig<StudioConfig>(keelCtx(m_ctx));
|
auto const [config, err] = studio::readConfig<StudioConfig>(keelCtx(m_tctx));
|
||||||
m_showProjectExplorer = config.showProjectExplorer;
|
m_showProjectExplorer = config.showProjectExplorer;
|
||||||
if (!err) {
|
if (!err) {
|
||||||
auto const openProjErr = openProjectPath(config.projectPath);
|
auto const openProjErr = openProjectPath(config.projectPath);
|
||||||
if (!openProjErr) {
|
if (!openProjErr) {
|
||||||
for (auto const&f: config.openFiles) {
|
for (auto const&f: config.openFiles) {
|
||||||
auto openFileErr = openFileActiveTab(f, config.activeTabItemName == f);
|
auto const openFileErr = openFileActiveTab(f, config.activeTabItemName == f);
|
||||||
if (openFileErr) {
|
if (openFileErr) {
|
||||||
oxErrorf("\nCould not open editor for file:\n\t{}\nReason:\n\t{}\n", f, toStr(openFileErr));
|
oxErrorf("\nCould not open editor for file:\n\t{}\nReason:\n\t{}\n", f, toStr(openFileErr));
|
||||||
continue;
|
continue;
|
||||||
@ -82,8 +82,8 @@ StudioUI::StudioUI(turbine::Context &ctx, ox::StringParam projectDataDir) noexce
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StudioUI::handleKeyEvent(turbine::Key key, bool down) noexcept {
|
void StudioUI::handleKeyEvent(turbine::Key const key, bool const down) noexcept {
|
||||||
for (auto p : m_popups) {
|
for (auto const p : m_popups) {
|
||||||
if (p->isOpen()) {
|
if (p->isOpen()) {
|
||||||
if (key == turbine::Key::Escape) {
|
if (key == turbine::Key::Escape) {
|
||||||
p->close();
|
p->close();
|
||||||
@ -118,13 +118,13 @@ void StudioUI::draw() noexcept {
|
|||||||
for (auto &w: m_widgets) {
|
for (auto &w: m_widgets) {
|
||||||
w->draw(m_sctx);
|
w->draw(m_sctx);
|
||||||
}
|
}
|
||||||
for (auto p: m_popups) {
|
for (auto const p: m_popups) {
|
||||||
p->draw(m_sctx);
|
p->draw(m_sctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
handleKeyInput();
|
handleKeyInput();
|
||||||
m_taskRunner.update(m_ctx);
|
m_taskRunner.update(m_tctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StudioUI::drawMenu() noexcept {
|
void StudioUI::drawMenu() noexcept {
|
||||||
@ -143,7 +143,7 @@ void StudioUI::drawMenu() noexcept {
|
|||||||
m_activeEditor->save();
|
m_activeEditor->save();
|
||||||
}
|
}
|
||||||
if (ImGui::MenuItem("Quit", "Ctrl+Q")) {
|
if (ImGui::MenuItem("Quit", "Ctrl+Q")) {
|
||||||
turbine::requestShutdown(m_ctx);
|
turbine::requestShutdown(m_tctx);
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
@ -168,7 +168,7 @@ void StudioUI::drawMenu() noexcept {
|
|||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
if (ImGui::BeginMenu("View")) {
|
if (ImGui::BeginMenu("View")) {
|
||||||
if (ImGui::MenuItem("Project Explorer", "Ctrl+1", m_showProjectExplorer)) {
|
if (ImGui::MenuItem("Project Explorer", "Ctrl+Shift+1", m_showProjectExplorer)) {
|
||||||
toggleProjectExplorer();
|
toggleProjectExplorer();
|
||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
@ -204,9 +204,10 @@ void StudioUI::drawTabs() noexcept {
|
|||||||
if (ImGui::BeginTabItem(e->itemDisplayName().c_str(), &open, flags)) {
|
if (ImGui::BeginTabItem(e->itemDisplayName().c_str(), &open, flags)) {
|
||||||
if (m_activeEditor != e.get()) [[unlikely]] {
|
if (m_activeEditor != e.get()) [[unlikely]] {
|
||||||
m_activeEditor = e.get();
|
m_activeEditor = e.get();
|
||||||
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
|
studio::editConfig<StudioConfig>(keelCtx(m_tctx), [&](StudioConfig &config) {
|
||||||
config.activeTabItemName = m_activeEditor->itemPath();
|
config.activeTabItemName = m_activeEditor->itemPath();
|
||||||
});
|
});
|
||||||
|
turbine::setRefreshWithin(m_tctx, 0);
|
||||||
} else [[likely]] {
|
} else [[likely]] {
|
||||||
if (m_activeEditorUpdatePending == e.get()) [[unlikely]] {
|
if (m_activeEditorUpdatePending == e.get()) [[unlikely]] {
|
||||||
m_activeEditorUpdatePending = nullptr;
|
m_activeEditorUpdatePending = nullptr;
|
||||||
@ -237,13 +238,13 @@ void StudioUI::drawTabs() noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StudioUI::loadEditorMaker(studio::EditorMaker const&editorMaker) noexcept {
|
void StudioUI::loadEditorMaker(EditorMaker const&editorMaker) noexcept {
|
||||||
for (auto const&ext : editorMaker.fileTypes) {
|
for (auto const&ext : editorMaker.fileTypes) {
|
||||||
m_editorMakers[ext] = editorMaker.make;
|
m_editorMakers[ext] = editorMaker.make;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StudioUI::loadModule(studio::Module const&mod) noexcept {
|
void StudioUI::loadModule(Module const&mod) noexcept {
|
||||||
for (auto const&editorMaker : mod.editors(m_sctx)) {
|
for (auto const&editorMaker : mod.editors(m_sctx)) {
|
||||||
loadEditorMaker(editorMaker);
|
loadEditorMaker(editorMaker);
|
||||||
}
|
}
|
||||||
@ -260,20 +261,20 @@ void StudioUI::loadModules() noexcept {
|
|||||||
|
|
||||||
void StudioUI::toggleProjectExplorer() noexcept {
|
void StudioUI::toggleProjectExplorer() noexcept {
|
||||||
m_showProjectExplorer = !m_showProjectExplorer;
|
m_showProjectExplorer = !m_showProjectExplorer;
|
||||||
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
|
editConfig<StudioConfig>(keelCtx(m_tctx), [&](StudioConfig &config) {
|
||||||
config.showProjectExplorer = m_showProjectExplorer;
|
config.showProjectExplorer = m_showProjectExplorer;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void StudioUI::redo() noexcept {
|
void StudioUI::redo() noexcept {
|
||||||
auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
auto const undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
||||||
if (undoStack && undoStack->canRedo()) {
|
if (undoStack && undoStack->canRedo()) {
|
||||||
oxLogError(m_activeEditor->undoStack()->redo());
|
oxLogError(m_activeEditor->undoStack()->redo());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StudioUI::undo() noexcept {
|
void StudioUI::undo() noexcept {
|
||||||
auto undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
auto const undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
||||||
if (undoStack && undoStack->canUndo()) {
|
if (undoStack && undoStack->canUndo()) {
|
||||||
oxLogError(m_activeEditor->undoStack()->undo());
|
oxLogError(m_activeEditor->undoStack()->undo());
|
||||||
}
|
}
|
||||||
@ -292,7 +293,7 @@ void StudioUI::handleKeyInput() noexcept {
|
|||||||
m_activeEditor->copy();
|
m_activeEditor->copy();
|
||||||
}
|
}
|
||||||
} else if (ImGui::IsKeyPressed(ImGuiKey_N)) {
|
} else if (ImGui::IsKeyPressed(ImGuiKey_N)) {
|
||||||
if (turbine::buttonDown(m_ctx, turbine::Key::Mod_Shift)) {
|
if (turbine::buttonDown(m_tctx, turbine::Key::Mod_Shift)) {
|
||||||
m_newProject.open();
|
m_newProject.open();
|
||||||
} else {
|
} else {
|
||||||
m_newMenu.open();
|
m_newMenu.open();
|
||||||
@ -302,7 +303,7 @@ void StudioUI::handleKeyInput() noexcept {
|
|||||||
} else if (ImGui::IsKeyPressed(ImGuiKey_S)) {
|
} else if (ImGui::IsKeyPressed(ImGuiKey_S)) {
|
||||||
save();
|
save();
|
||||||
} else if (ImGui::IsKeyPressed(ImGuiKey_Q)) {
|
} else if (ImGui::IsKeyPressed(ImGuiKey_Q)) {
|
||||||
turbine::requestShutdown(m_ctx);
|
turbine::requestShutdown(m_tctx);
|
||||||
} else if (ImGui::IsKeyPressed(ImGuiKey_V)) {
|
} else if (ImGui::IsKeyPressed(ImGuiKey_V)) {
|
||||||
if (m_activeEditor && m_activeEditor->pasteEnabled()) {
|
if (m_activeEditor && m_activeEditor->pasteEnabled()) {
|
||||||
m_activeEditor->paste();
|
m_activeEditor->paste();
|
||||||
@ -317,8 +318,22 @@ void StudioUI::handleKeyInput() noexcept {
|
|||||||
} else if (ImGui::IsKeyPressed(ImGuiKey_Z)) {
|
} else if (ImGui::IsKeyPressed(ImGuiKey_Z)) {
|
||||||
auto const undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
auto const undoStack = m_activeEditor ? m_activeEditor->undoStack() : nullptr;
|
||||||
if (undoStack) { oxLogError(undoStack->undo()); }
|
if (undoStack) { oxLogError(undoStack->undo()); }
|
||||||
} else if (ImGui::IsKeyPressed(ImGuiKey_1)) {
|
} else if (ImGui::IsKeyPressed(ImGuiKey_1) && ImGui::IsKeyDown(ImGuiKey_ModShift)) {
|
||||||
toggleProjectExplorer();
|
toggleProjectExplorer();
|
||||||
|
} else {
|
||||||
|
if (!m_editors.empty()) {
|
||||||
|
auto const range = ox::min<size_t>(9u, m_editors.size()) - 1;
|
||||||
|
for (auto i = 0u; i < 9; ++i) {
|
||||||
|
if (ImGui::IsKeyPressed(static_cast<ImGuiKey>(static_cast<int>(ImGuiKey_1) + i))) {
|
||||||
|
m_activeEditor = m_editors[i < m_editors.size() ? i : range].get();
|
||||||
|
m_activeEditorUpdatePending = m_activeEditor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ImGui::IsKeyPressed(ImGuiKey_0)) {
|
||||||
|
m_activeEditor = m_editors[10 < m_editors.size() ? 10 : range].get();
|
||||||
|
m_activeEditorUpdatePending = m_activeEditor;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -333,18 +348,18 @@ ox::Error StudioUI::createOpenProject(ox::StringViewCR path) noexcept {
|
|||||||
|
|
||||||
ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept {
|
ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept {
|
||||||
OX_REQUIRE_M(fs, keel::loadRomFs(path.view()));
|
OX_REQUIRE_M(fs, keel::loadRomFs(path.view()));
|
||||||
OX_RETURN_ERROR(keel::setRomFs(keelCtx(m_ctx), std::move(fs)));
|
OX_RETURN_ERROR(keel::setRomFs(keelCtx(m_tctx), std::move(fs)));
|
||||||
OX_RETURN_ERROR(
|
OX_RETURN_ERROR(
|
||||||
ox::make_unique_catch<studio::Project>(keelCtx(m_ctx), std::move(path), m_projectDataDir)
|
ox::make_unique_catch<Project>(keelCtx(m_tctx), std::move(path), m_projectDataDir)
|
||||||
.moveTo(m_project));
|
.moveTo(m_project));
|
||||||
auto const sctx = applicationData<studio::StudioContext>(m_ctx);
|
auto const sctx = applicationData<StudioContext>(m_tctx);
|
||||||
sctx->project = m_project.get();
|
sctx->project = m_project.get();
|
||||||
turbine::setWindowTitle(m_ctx, ox::sfmt("{} - {}", keelCtx(m_ctx).appName, m_project->projectPath()));
|
turbine::setWindowTitle(m_tctx, ox::sfmt("{} - {}", keelCtx(m_tctx).appName, m_project->projectPath()));
|
||||||
m_project->fileAdded.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
|
m_project->fileAdded.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
|
||||||
m_project->fileDeleted.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
|
m_project->fileDeleted.connect(&m_projectExplorer, &ProjectExplorer::refreshProjectTreeModel);
|
||||||
m_openFiles.clear();
|
m_openFiles.clear();
|
||||||
m_editors.clear();
|
m_editors.clear();
|
||||||
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
|
studio::editConfig<StudioConfig>(keelCtx(m_tctx), [&](StudioConfig &config) {
|
||||||
config.projectPath = ox::String(m_project->projectPath());
|
config.projectPath = ox::String(m_project->projectPath());
|
||||||
config.openFiles.clear();
|
config.openFiles.clear();
|
||||||
});
|
});
|
||||||
@ -355,7 +370,7 @@ ox::Error StudioUI::openFile(ox::StringViewCR path) noexcept {
|
|||||||
return openFileActiveTab(path, true);
|
return openFileActiveTab(path, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool makeActiveTab) noexcept {
|
ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool const makeActiveTab) noexcept {
|
||||||
if (!m_project) {
|
if (!m_project) {
|
||||||
return ox::Error(1, "No project open to open a file from");
|
return ox::Error(1, "No project open to open a file from");
|
||||||
}
|
}
|
||||||
@ -369,7 +384,7 @@ ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool makeActiveTab)
|
|||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
OX_REQUIRE(ext, studio::fileExt(path));
|
OX_REQUIRE(ext, fileExt(path));
|
||||||
// create Editor
|
// create Editor
|
||||||
BaseEditor *editor = nullptr;
|
BaseEditor *editor = nullptr;
|
||||||
auto const err = m_editorMakers.contains(ext) ?
|
auto const err = m_editorMakers.contains(ext) ?
|
||||||
@ -391,7 +406,7 @@ ox::Error StudioUI::openFileActiveTab(ox::StringViewCR path, bool makeActiveTab)
|
|||||||
m_activeEditorUpdatePending = editor;
|
m_activeEditorUpdatePending = editor;
|
||||||
}
|
}
|
||||||
// save to config
|
// save to config
|
||||||
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&path](StudioConfig &config) {
|
studio::editConfig<StudioConfig>(keelCtx(m_tctx), [&path](StudioConfig &config) {
|
||||||
if (!config.openFiles.contains(path)) {
|
if (!config.openFiles.contains(path)) {
|
||||||
config.openFiles.emplace_back(path);
|
config.openFiles.emplace_back(path);
|
||||||
}
|
}
|
||||||
@ -405,7 +420,7 @@ ox::Error StudioUI::closeFile(ox::StringViewCR path) noexcept {
|
|||||||
}
|
}
|
||||||
std::ignore = m_openFiles.erase(std::remove(m_openFiles.begin(), m_openFiles.end(), path));
|
std::ignore = m_openFiles.erase(std::remove(m_openFiles.begin(), m_openFiles.end(), path));
|
||||||
// save to config
|
// save to config
|
||||||
studio::editConfig<StudioConfig>(keelCtx(m_ctx), [&](StudioConfig &config) {
|
studio::editConfig<StudioConfig>(keelCtx(m_tctx), [&](StudioConfig &config) {
|
||||||
std::ignore = config.openFiles.erase(std::remove(config.openFiles.begin(), config.openFiles.end(), path));
|
std::ignore = config.openFiles.erase(std::remove(config.openFiles.begin(), config.openFiles.end(), path));
|
||||||
});
|
});
|
||||||
return {};
|
return {};
|
||||||
|
@ -24,23 +24,23 @@ class StudioUI: public ox::SignalHandler {
|
|||||||
friend class StudioUIDrawer;
|
friend class StudioUIDrawer;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
studio::StudioContext m_sctx;
|
StudioContext m_sctx;
|
||||||
turbine::Context &m_ctx;
|
turbine::Context &m_tctx;
|
||||||
ox::String m_projectDataDir;
|
ox::String m_projectDataDir;
|
||||||
ox::UPtr<studio::Project> m_project;
|
ox::UPtr<Project> m_project;
|
||||||
studio::TaskRunner m_taskRunner;
|
TaskRunner m_taskRunner;
|
||||||
ox::Vector<ox::UPtr<studio::BaseEditor>> m_editors;
|
ox::Vector<ox::UPtr<BaseEditor>> m_editors;
|
||||||
ox::Vector<ox::UPtr<studio::Widget>> m_widgets;
|
ox::Vector<ox::UPtr<Widget>> m_widgets;
|
||||||
ox::HashMap<ox::String, studio::EditorMaker::Func> m_editorMakers;
|
ox::HashMap<ox::String, EditorMaker::Func> m_editorMakers;
|
||||||
ProjectExplorer m_projectExplorer;
|
ProjectExplorer m_projectExplorer;
|
||||||
ox::Vector<ox::String> m_openFiles;
|
ox::Vector<ox::String> m_openFiles;
|
||||||
studio::BaseEditor *m_activeEditorOnLastDraw = nullptr;
|
BaseEditor *m_activeEditorOnLastDraw = nullptr;
|
||||||
studio::BaseEditor *m_activeEditor = nullptr;
|
BaseEditor *m_activeEditor = nullptr;
|
||||||
studio::BaseEditor *m_activeEditorUpdatePending = nullptr;
|
BaseEditor *m_activeEditorUpdatePending = nullptr;
|
||||||
NewMenu m_newMenu;
|
NewMenu m_newMenu;
|
||||||
NewProject m_newProject;
|
NewProject m_newProject;
|
||||||
AboutPopup m_aboutPopup;
|
AboutPopup m_aboutPopup;
|
||||||
ox::Array<studio::Popup*, 3> const m_popups = {
|
ox::Array<Popup*, 3> const m_popups = {
|
||||||
&m_newMenu,
|
&m_newMenu,
|
||||||
&m_newProject,
|
&m_newProject,
|
||||||
&m_aboutPopup
|
&m_aboutPopup
|
||||||
@ -53,7 +53,7 @@ class StudioUI: public ox::SignalHandler {
|
|||||||
void handleKeyEvent(turbine::Key, bool down) noexcept;
|
void handleKeyEvent(turbine::Key, bool down) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
constexpr studio::Project *project() noexcept {
|
constexpr Project *project() noexcept {
|
||||||
return m_project.get();
|
return m_project.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,9 +67,9 @@ class StudioUI: public ox::SignalHandler {
|
|||||||
|
|
||||||
void drawTabs() noexcept;
|
void drawTabs() noexcept;
|
||||||
|
|
||||||
void loadEditorMaker(studio::EditorMaker const&editorMaker) noexcept;
|
void loadEditorMaker(EditorMaker const&editorMaker) noexcept;
|
||||||
|
|
||||||
void loadModule(studio::Module const&mod) noexcept;
|
void loadModule(Module const&mod) noexcept;
|
||||||
|
|
||||||
void loadModules() noexcept;
|
void loadModules() noexcept;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user