Compare commits

..

6 Commits

Author SHA1 Message Date
b1f912445d Merge commit '1bfb7f99c215e2c74556bd3281f44962b8faaa96'
All checks were successful
Build / build (push) Successful in 1m29s
2025-07-30 00:42:42 -05:00
1bfb7f99c2 Squashed 'deps/nostalgia/' changes from c7bc2a95..e27eee50
e27eee50 [teagba] Add set and scroll background offset functions
fd610454 [nostalgia/gfx] Fix compiler warning
e61d4647 [nostalgia/gfx] Fix BG tilesheet loading, add background offset functions
c275c5f5 [hull] Disable building hull for now
fbf49ba5 [ox/std] Add pre- and post-increment operators to Span
92f74b27 [ox/std] Add null check for deallocating in consteval context Vector
934f0c92 [ox/std] Add beginsWith and endsWith variants that that cingle chars
ee9a3e11 [ox/std] Cleanup
16886cdf [hull] Add start on command interpreter
08b9508d [ox/std] Give std::ignore a named type
69bd968f [nostalgia/player] Fix build
4e7dc666 [nostalgia,olympic] Rename string len() functions to size()
bea0cf5a [ox/std] Rename string len() functions to size()

git-subtree-dir: deps/nostalgia
git-subtree-split: e27eee50f05bb437710313430e0d9cef636a66b1
2025-07-30 00:40:03 -05:00
10db939d62 [nostalgia/gfx/studio] Make editors use Project::loadObj for their primary assets 2025-07-30 00:37:59 -05:00
553797fdbd [studio] Add File -> Reload Project menu item 2025-07-30 00:37:23 -05:00
fb0cd99d8c [keel] Make keel attempt to delete all existing assets when FS is changed 2025-07-30 00:36:56 -05:00
a372814e3c [ox/std] Fix UPtr::reset to conform to unique_ptr::reset 2025-07-30 00:29:34 -05:00
21 changed files with 248 additions and 50 deletions

View File

@@ -16,7 +16,7 @@
namespace std {
inline constexpr struct {
inline constexpr struct ignore_t {
constexpr void operator=(auto&&) const noexcept {}
} ignore;

View File

@@ -213,8 +213,7 @@ class UniquePtr {
return m_t;
}
template<typename U, typename UDeleter>
constexpr void reset(UniquePtr<U, UDeleter> &&other = UniquePtr()) {
constexpr void reset(UniquePtr &&other = UniquePtr()) {
auto t = m_t;
m_t = other.release();
Deleter()(t);

View File

@@ -163,6 +163,24 @@ class Span {
return *this;
}
constexpr Span operator++(int) noexcept {
++m_items;
--m_size;
if (!m_size) [[unlikely]] {
m_items = nullptr;
}
return *this;
}
constexpr Span operator++() noexcept {
++m_items;
--m_size;
if (!m_size) [[unlikely]] {
m_items = nullptr;
}
return *this;
}
[[nodiscard]]
constexpr auto data() const noexcept {
return m_items;

View File

@@ -139,7 +139,7 @@ class BasicString {
constexpr BasicString &operator+=(Integer_c auto i) noexcept;
constexpr BasicString &operator+=(StringView src) noexcept;
constexpr BasicString &operator+=(StringViewCR src) noexcept;
constexpr BasicString &operator+=(BasicString const&src) noexcept;
@@ -185,7 +185,7 @@ class BasicString {
return {};
}
constexpr Error append(ox::StringView sv) noexcept {
constexpr Error append(StringViewCR sv) noexcept {
return append(sv.data(), sv.size());
}
@@ -376,7 +376,7 @@ constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operat
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringView s) noexcept {
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringViewCR s) noexcept {
std::size_t strLen = s.bytes();
std::ignore = append(s.data(), strLen);
return *this;
@@ -456,7 +456,7 @@ constexpr bool BasicString<SmallStringSize_v>::operator==(const char *other) con
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator==(OxString_c auto const&other) const noexcept {
return ox::StringView(*this) == ox::StringView(other);
return StringView(*this) == StringView(other);
}
template<std::size_t SmallStringSize_v>
@@ -548,28 +548,28 @@ using StringCR = String const&;
[[nodiscard]]
constexpr ox::String toString(ox::StringViewCR sv) noexcept {
constexpr String toString(StringViewCR sv) noexcept {
return ox::String(sv);
}
template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]]
constexpr auto sizeOf(const ox::BasicString<SmallStringSize_v>*) noexcept {
constexpr auto sizeOf(BasicString<SmallStringSize_v> const*) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return sizeOf<PlatSpec>(&v);
}
template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]]
constexpr auto alignOf(const ox::BasicString<SmallStringSize_v>&) noexcept {
constexpr auto alignOf(BasicString<SmallStringSize_v> const&) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return alignOf<PlatSpec>(&v);
}
template<size_t sz>
struct MaybeView<ox::BasicString<sz>> {
using type = ox::StringView;
struct MaybeView<BasicString<sz>> {
using type = StringView;
};
}

View File

@@ -21,7 +21,7 @@ OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
[[nodiscard]]
constexpr ox::StringView substr(ox::StringView const&str, std::size_t pos) noexcept {
constexpr StringView substr(StringViewCR str, std::size_t const pos) noexcept {
if (str.size() >= pos) {
return {&str[pos], str.size() - pos};
}
@@ -29,13 +29,23 @@ constexpr ox::StringView substr(ox::StringView const&str, std::size_t pos) noexc
}
[[nodiscard]]
constexpr ox::StringView substr(ox::StringView const&str, std::size_t start, std::size_t end) noexcept {
constexpr StringView substr(StringViewCR str, std::size_t const start, std::size_t const end) noexcept {
if (str.size() >= start && end >= start) {
return {&str[start], end - start};
}
return {};
}
[[nodiscard]]
constexpr bool beginsWith(StringViewCR base, char const beginning) noexcept {
return base.size() && base[0] == beginning;
}
[[nodiscard]]
constexpr bool endsWith(StringViewCR base, char const ending) noexcept {
return base.size() && base[base.size() - 1] == ending;
}
[[nodiscard]]
constexpr bool beginsWith(StringViewCR base, StringViewCR beginning) noexcept {
const auto beginningLen = ox::min(beginning.size(), base.size());
@@ -49,7 +59,7 @@ constexpr bool endsWith(StringViewCR base, StringViewCR ending) noexcept {
}
[[nodiscard]]
constexpr std::size_t find(StringViewCR str, char search) noexcept {
constexpr std::size_t find(StringViewCR str, char const search) noexcept {
std::size_t i = 0;
for (; i < str.size(); ++i) {
if (str[i] == search) {
@@ -72,7 +82,7 @@ constexpr std::size_t find(StringViewCR str, StringViewCR search) noexcept {
template<std::size_t smallSz = 0>
[[nodiscard]]
constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, char del) noexcept {
constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, char const del) noexcept {
ox::Vector<ox::StringView, smallSz> out;
constexpr auto nextSeg = [](StringViewCR current, char del) {
return substr(current, find(current, del) + 1);
@@ -105,7 +115,7 @@ constexpr ox::Vector<ox::StringView, smallSz> split(StringViewCR str, StringView
}
[[nodiscard]]
constexpr ox::Result<std::size_t> lastIndexOf(ox::StringViewCR str, int character) noexcept {
constexpr ox::Result<std::size_t> lastIndexOf(ox::StringViewCR str, int const character) noexcept {
ox::Result<std::size_t> retval = ox::Error(1, "Character not found");
for (auto i = static_cast<int>(str.bytes() - 1); i >= 0; --i) {
if (str[static_cast<std::size_t>(i)] == character) {

View File

@@ -87,7 +87,9 @@ struct VectorAllocator {
constexpr void deallocate(T *items, std::size_t cap) noexcept {
// small vector optimization cannot be done it constexpr, but it doesn't really matter in constexpr
if (std::is_constant_evaluated()) {
Allocator{}.deallocate(items, cap);
if (items) {
Allocator{}.deallocate(items, cap);
}
} else {
if (items && static_cast<void*>(items) != static_cast<void*>(m_data.data())) {
Allocator{}.deallocate(items, cap);

View File

@@ -54,25 +54,41 @@ inline volatile BgCtl &regBgCtl(uintptr_t const bgIdx) noexcept {
}
// background horizontal scrolling registers
#define REG_BG0HOFS (*reinterpret_cast<volatile uint32_t*>(0x0400'0010))
#define REG_BG1HOFS (*reinterpret_cast<volatile uint32_t*>(0x0400'0014))
#define REG_BG2HOFS (*reinterpret_cast<volatile uint32_t*>(0x0400'0018))
#define REG_BG3HOFS (*reinterpret_cast<volatile uint32_t*>(0x0400'001c))
#define REG_BG0HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0010))
#define REG_BG1HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0014))
#define REG_BG2HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0018))
#define REG_BG3HOFS (*reinterpret_cast<volatile int16_t*>(0x0400'001c))
[[nodiscard]]
volatile uint32_t &regBgHofs(auto const bgIdx) noexcept {
return *reinterpret_cast<volatile uint32_t*>(0x0400'0010 + 4 * bgIdx);
volatile int16_t &regBgHofs(auto const bgIdx) noexcept {
return *reinterpret_cast<volatile int16_t*>(0x0400'0010 + 4 * bgIdx);
}
// background vertical scrolling registers
#define REG_BG0VOFS (*reinterpret_cast<volatile uint32_t*>(0x0400'0012))
#define REG_BG1VOFS (*reinterpret_cast<volatile uint32_t*>(0x0400'0016))
#define REG_BG2VOFS (*reinterpret_cast<volatile uint32_t*>(0x0400'001a))
#define REG_BG3VOFS (*reinterpret_cast<volatile uint32_t*>(0x0400'001e))
#define REG_BG0VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0012))
#define REG_BG1VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'0016))
#define REG_BG2VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'001a))
#define REG_BG3VOFS (*reinterpret_cast<volatile int16_t*>(0x0400'001e))
[[nodiscard]]
volatile uint32_t &regBgVofs(auto const bgIdx) noexcept {
return *reinterpret_cast<volatile uint32_t*>(0x0400'0012 + 4 * bgIdx);
volatile int16_t &regBgVofs(auto const bgIdx) noexcept {
return *reinterpret_cast<volatile int16_t*>(0x0400'0012 + 4 * bgIdx);
}
// background scrolling registers
struct OffsetPair {
int16_t x{}, y{};
};
#define REG_BG0OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'0010))
#define REG_BG1OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'0014))
#define REG_BG2OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'0018))
#define REG_BG3OFS (*reinterpret_cast<volatile OffsetPair*>(0x0400'001c))
[[nodiscard]]
volatile OffsetPair &regBgOfs(auto const bgIdx) noexcept {
return *reinterpret_cast<volatile OffsetPair*>(0x0400'0010 + sizeof(OffsetPair) * bgIdx);
}
/////////////////////////////////////////////////////////////////

View File

@@ -41,4 +41,8 @@ void addSpriteUpdate(GbaSpriteAttrUpdate const &upd) noexcept;
void applySpriteUpdates() noexcept;
void setBgOffset(uint16_t bg, int16_t x, int16_t y) noexcept;
void scrollBgOffset(uint16_t bg, int16_t x, int16_t y) noexcept;
}

View File

@@ -12,7 +12,7 @@ namespace teagba {
static ox::Array<GbaSpriteAttrUpdate, 128> g_spriteBuffer;
GbaSpriteAttrUpdate &spriteAttr(size_t i) noexcept {
GbaSpriteAttrUpdate &spriteAttr(size_t const i) noexcept {
return g_spriteBuffer[i];
}
@@ -29,4 +29,16 @@ void applySpriteUpdates() noexcept {
}
}
void setBgOffset(uint16_t const bg, int16_t const x, int16_t const y) noexcept {
auto &o = regBgOfs(bg);
o.x = x;
o.y = y;
}
void scrollBgOffset(uint16_t const bg, int16_t const x, int16_t const y) noexcept {
auto &o = regBgOfs(bg);
o.x = o.x + x;
o.y = o.y + y;
}
}

View File

@@ -238,6 +238,10 @@ void setBgCbb(Context &ctx, unsigned bgIdx, unsigned cbbIdx) noexcept;
void setBgPriority(Context &ctx, uint_t bgIdx, uint_t priority) noexcept;
void setBgOffset(Context &ctx, uint16_t bg, int16_t x, int16_t y) noexcept;
void scrollBgOffset(Context &ctx, uint16_t bg, int16_t x, int16_t y) noexcept;
void hideSprite(Context &ctx, unsigned) noexcept;
void showSprite(Context &ctx, unsigned) noexcept;
@@ -260,8 +264,8 @@ constexpr ox::CStringView GlslVersion = "#version 330";
[[nodiscard]]
ox::Size drawSize(int scale = 5) noexcept;
void draw(gfx::Context &ctx, ox::Size const &renderSz) noexcept;
void draw(Context &ctx, ox::Size const &renderSz) noexcept;
void draw(gfx::Context&, int scale = 5) noexcept;
void draw(Context&, int scale = 5) noexcept;
}

View File

@@ -169,8 +169,8 @@ ox::Error loadBgTileSheet(
unsigned const cbb,
CompactTileSheet const &ts,
ox::Optional<unsigned> const &paletteBank) noexcept {
auto const cnt = (ts.pixels.size() * PixelsPerTile) / (1 + (ts.bpp == 4));
for (size_t i = 0; i < cnt; ++i) {
auto const cnt = ts.pixels.size() >> (ts.bpp == 4);
for (size_t i{}; i < cnt; ++i) {
auto const srcIdx = i * 2;
auto const p1 = static_cast<uint16_t>(ts.pixels[srcIdx]);
auto const p2 = static_cast<uint16_t>(ts.pixels[srcIdx + 1]);
@@ -218,10 +218,11 @@ ox::Error loadSpriteTileSheet(
Context &ctx,
CompactTileSheet const &ts,
bool const loadDefaultPalette) noexcept {
for (size_t i = 0; i < ts.pixels.size(); i += 2) {
uint16_t v = ts.pixels[i];
v |= static_cast<uint16_t>(ts.pixels[i + 1] << 8);
MEM_SPRITE_TILES[i] = v;
for (size_t i{}; i < ts.pixels.size(); i += 2) {
MEM_SPRITE_TILES[i >> 1] =
static_cast<uint16_t>(
ts.pixels[i] |
(static_cast<uint16_t>(ts.pixels[i + 1]) << 8));
}
if (loadDefaultPalette && ts.defaultPalette) {
OX_RETURN_ERROR(loadSpritePalette(ctx, ts.defaultPalette));
@@ -294,6 +295,14 @@ void setBgPriority(Context&, uint_t const bgIdx, uint_t const priority) noexcept
bgCtl = (bgCtl & 0b1111'1111'1111'1100u) | (priority & 0b11);
}
void setBgOffset(Context&, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
teagba::setBgOffset(bg, x, y);
}
void scrollBgOffset(Context&, uint16_t const bg, int16_t const x, int16_t const y) noexcept {
teagba::scrollBgOffset(bg, x, y);
}
void hideSprite(Context&, unsigned const idx) noexcept {
//oxAssert(g_spriteUpdates < config::GbaSpriteBufferLen, "Sprite update buffer overflow");
teagba::addSpriteUpdate({

View File

@@ -249,7 +249,7 @@ void setBgTile(
}
ox::Error initConsole(Context &ctx) noexcept {
constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.ng");
constexpr ox::FileAddress TilesheetAddr = ox::StringLiteral("/TileSheets/Charset.nts");
constexpr ox::FileAddress PaletteAddr = ox::StringLiteral("/Palettes/Charset.npal");
setBgStatus(ctx, 0b0001);
setBgCbb(ctx, 0, 0);

View File

@@ -72,7 +72,7 @@ PaletteEditorImGui::PaletteEditorImGui(studio::Context &sctx, ox::StringParam pa
Editor(sctx, std::move(path)),
m_sctx(sctx),
m_tctx(sctx.tctx),
m_pal(*keel::readObj<Palette>(keelCtx(m_tctx), itemPath()).unwrapThrow()) {
m_pal(m_sctx.project->loadObj<Palette>(itemPath()).unwrapThrow()) {
undoStack()->changeTriggered.connect(this, &PaletteEditorImGui::handleCommand);
m_pageRenameDlg.inputSubmitted.connect(this, &PaletteEditorImGui::renamePage);
}

View File

@@ -49,7 +49,7 @@ TileSheetEditorModel::TileSheetEditorModel(
m_sctx{sctx},
m_tctx{m_sctx.tctx},
m_path{std::move(path)},
m_img{*readObj<TileSheet>(keelCtx(m_tctx), m_path).unwrapThrow()},
m_img{m_sctx.project->loadObj<TileSheet>(m_path).unwrapThrow()},
// ignore failure to load palette
m_pal{readObj<Palette>(keelCtx(m_tctx), m_img.defaultPalette).value},
m_undoStack{undoStack} {

View File

@@ -19,6 +19,9 @@ else()
endif()
add_subdirectory(applib)
#if(NOT APPLE)
# add_subdirectory(hull)
#endif()
add_subdirectory(keel)
add_subdirectory(turbine)
if(${OLYMPIC_BUILD_STUDIO})

View File

@@ -0,0 +1,12 @@
add_library(Hull)
target_sources(
Hull PUBLIC
FILE_SET CXX_MODULES FILES
hull.cpp
)
target_link_libraries(
Hull PUBLIC
OxStd
)

View File

@@ -0,0 +1,98 @@
/*
* Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
module;
#include <ox/std/string.hpp>
export module hull;
namespace hull {
export
template<typename Str = ox::String, size_t SmallVecSz = 0>
constexpr ox::Result<ox::Vector<Str, SmallVecSz>> parseCmd(ox::StringViewCR cmd) noexcept
requires(ox::is_same_v<Str, ox::String> || ox::is_same_v<Str, ox::StringView>) {
auto const tokens = split(cmd, ' ');
ox::Vector<Str, SmallVecSz> args;
char waitingFor{};
auto const handleString = [&waitingFor, &args](
ox::StringViewCR token,
char const delimiter) {
if (endsWith(token, delimiter)) {
args.emplace_back(substr(token, 1, token.size() - 1));
} else {
waitingFor = delimiter;
args.emplace_back(substr(token, 1));
}
};
for (auto const &token : tokens) {
if (waitingFor) {
if (endsWith(token, waitingFor)) {
waitingFor = 0;
}
auto &tgt = *args.back().value;
if constexpr (ox::is_same_v<Str, ox::String>) {
tgt += substr(token, 0, token.size() - 1);
} else {
tgt = {tgt.data(), tgt.size() + token.size() - 1};
}
} else if (beginsWith(token, '"')) {
handleString(token, '"');
} else if (beginsWith(token, '\'')) {
handleString(token, '\'');
} else {
args.emplace_back(token);
}
}
if (waitingFor) {
return ox::Error{1, "unterminated string"};
}
return args;
}
template<typename Str = ox::String>
[[nodiscard]]
static constexpr bool testParse(ox::StringViewCR cmd, std::initializer_list<ox::StringView> const &expected) noexcept {
auto const [args, err] = parseCmd<Str>(cmd);
static constexpr auto equals = [](auto const &a, auto const &b) {
if (a.size() != b.size()) {
return false;
}
for (auto i = 0u; i < a.size(); ++i) {
if (a[i] != b[i]) {
return false;
}
}
return true;
};
return !err && equals(args, ox::Vector(expected));
}
static_assert(testParse("echo asdf", {"echo", "asdf"}));
static_assert(testParse<ox::String>("echo asdf", {"echo", "asdf"}));
static_assert(testParse("echo \"asdf\"", {"echo", "asdf"}));
static_assert(testParse<ox::String>("echo \"asdf\"", {"echo", "asdf"}));
static_assert(testParse("echo 'asdf'", {"echo", "asdf"}));
static_assert(testParse<ox::String>("echo 'asdf'", {"echo", "asdf"}));
static_assert(testParse("echo 'asdf' aoue", {"echo", "asdf", "aoue"}));
static_assert(testParse<ox::String>("echo 'asdf' aoue", {"echo", "asdf", "aoue"}));
export class Prompt {
private:
ox::String m_cmd;
ox::String m_workingDir{"/"};
ox::Vector<ox::String> m_prevCmds;
public:
private:
};
}

View File

@@ -25,12 +25,11 @@ ox::Error writeUuidHeader(ox::Writer_c auto &writer, ox::UUID const&uuid) noexce
template<typename T>
ox::Result<T> readAsset(ox::BufferView buff) noexcept {
std::size_t offset = 0;
auto const err = readUuidHeader(buff).error;
if (!err) {
offset = K1HdrSz; // the size of K1 headers
buff += K1HdrSz; // the size of K1 headers
}
auto out = ox::readClaw<T>(buff + offset);
auto out = ox::readClaw<T>(buff);
OX_RETURN_ERROR(out);
OX_RETURN_ERROR(ensureValid(out.value));
return out;

View File

@@ -261,6 +261,9 @@ namespace keel {
ox::Error setRomFs(Context &ctx, ox::UPtr<ox::FileSystem> &&fs, DuplicateSet &duplicateSet) noexcept {
ctx.rom = std::move(fs);
clearUuidMap(ctx);
#ifndef OX_BARE_METAL
ctx.assetManager.gc();
#endif
return buildUuidMap(ctx, &duplicateSet);
}

View File

@@ -250,6 +250,9 @@ void StudioUI::drawMenu() noexcept {
if (ImGui::MenuItem("Open Project...", STUDIO_CTRL "+O")) {
m_taskRunner.add(*ox::make<FileDialogManager>(this, &StudioUI::openProjectPath));
}
if (ImGui::MenuItem("Reload Project")) {
oxLogError(openProjectPath(m_project->projectPath()));
}
if (ImGui::BeginMenu("Recent Projects", m_recentProjects.size() > 1)) {
for (size_t i = 1; i < m_recentProjects.size(); ++i) {
auto const &p = m_recentProjects[i];
@@ -636,6 +639,9 @@ ox::Error StudioUI::createOpenProject(ox::StringViewCR path) noexcept {
ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept {
OX_REQUIRE_M(fs, keel::loadRomFs(path.view()));
m_project.reset();
m_openFiles.clear();
m_editors.clear();
keel::DuplicateSet ds;
OX_RETURN_ERROR(keel::setRomFs(keelCtx(m_tctx), std::move(fs), ds));
if (ds.size()) {
@@ -649,8 +655,8 @@ ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept {
m_messagePopup.show(msg);
}
OX_RETURN_ERROR(
ox::make_unique_catch<Project>(keelCtx(m_tctx), std::move(path), m_projectDataDir)
.moveTo(m_project));
ox::make_unique_catch<Project>(keelCtx(m_tctx), std::move(path), m_projectDataDir)
.moveTo(m_project));
m_sctx.project = m_project.get();
m_activeEditor = nullptr;
m_activeEditorOnLastDraw = nullptr;
@@ -665,8 +671,6 @@ ox::Error StudioUI::openProjectPath(ox::StringParam path) noexcept {
m_project->dirDeleted.connect(this, &StudioUI::handleDeleteDir);
m_project->fileDeleted.connect(this, &StudioUI::handleDeleteFile);
m_project->fileMoved.connect(this, &StudioUI::handleMoveFile);
m_openFiles.clear();
m_editors.clear();
studio::editConfig<StudioConfig>(keelCtx(m_tctx), [&](StudioConfig &config) {
auto const pcIt = std::find_if(
config.projects.begin(), config.projects.end(),

View File

@@ -185,10 +185,15 @@ ox::Error Project::writeObj(ox::StringViewCR path, T const &obj) noexcept {
template<typename T>
ox::Result<T> Project::loadObj(ox::StringViewCR path) const noexcept {
OX_REQUIRE(buff, loadBuff(path));
OX_REQUIRE_M(buff, loadBuff(path));
if constexpr(ox::is_same_v<T, ox::ModelObject>) {
return keel::readAsset(m_typeStore, buff);
} else {
OX_REQUIRE(typeId, keel::readAssetTypeId(buff));
if (typeId != ox::ModelTypeId_v<T>) {
OX_REQUIRE(ah, keel::readAssetHeader(buff));
OX_RETURN_ERROR(keel::convertBuffToBuff<T>(m_kctx, buff, ah.clawHdr.fmt).moveTo(buff));
}
return keel::readAsset<T>(buff);
}
}