Compare commits

..

13 Commits

Author SHA1 Message Date
17c9f673bd [studio] Fix navigate back not to iterate on the first item twice
All checks were successful
Build / build (push) Successful in 1m29s
2025-08-09 15:15:54 -05:00
870fb9c6e3 [nostalgia/studio] Set version to d2025.07.0
All checks were successful
Build / build (push) Successful in 1m17s
2025-07-31 22:07:22 -05:00
31b39982c5 [keel] Fix AssetRef to call incRef on initial creation of ref, not just copy
All checks were successful
Build / build (push) Successful in 1m18s
2025-07-31 22:06:52 -05:00
5476417be2 [nostalgia] Add release notes for d2025.07.0
All checks were successful
Build / build (push) Successful in 1m18s
2025-07-31 01:05:29 -05:00
e03be694c2 Merge commit 'b67b95767b7bfcd5f618ebc8e14ddbc83edcbe36'
All checks were successful
Build / build (push) Successful in 1m37s
2025-07-31 00:41:06 -05:00
490c0368bc [nostalgia/gfx] Add lists for file extensions 2025-07-31 00:39:55 -05:00
a24fc407c5 [ox/std] Fix MSVC build 2025-07-31 00:38:26 -05:00
e38b85b4f4 [studio] Eliminate redundant serialization and deserialization
All checks were successful
Build / build (push) Successful in 1m42s
2025-07-30 21:48:44 -05:00
f7c3c02c4c Merge commit '1bfb7f99c215e2c74556bd3281f44962b8faaa96'
All checks were successful
Build / build (push) Successful in 1m35s
2025-07-30 00:42:42 -05:00
8f0f1fea39 [nostalgia/gfx/studio] Make editors use Project::loadObj for their primary assets 2025-07-30 00:37:59 -05:00
2f36a3f6f0 [studio] Add File -> Reload Project menu item 2025-07-30 00:37:23 -05:00
07e5bf9054 [keel] Make keel attempt to delete all existing assets when FS is changed 2025-07-30 00:36:56 -05:00
aacff3daf9 [ox/std] Fix UPtr::reset to conform to unique_ptr::reset 2025-07-30 00:29:34 -05:00
14 changed files with 62 additions and 19 deletions

View File

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

View File

@@ -19,7 +19,7 @@ namespace ox {
*/ */
class StringLiteral: public detail::BaseStringView { class StringLiteral: public detail::BaseStringView {
public: public:
consteval StringLiteral() noexcept = default; constexpr StringLiteral() noexcept = default;
constexpr StringLiteral(StringLiteral const &sv) noexcept = default; constexpr StringLiteral(StringLiteral const &sv) noexcept = default;

View File

@@ -1,3 +1,9 @@
# d2025.07.0
* Add sub-command for exporting TileSheets as PNG files.
* Add 'Reload Project' menu item under File.
* Fix opening a project to mark an unopenable file as closed in the config file on startup.
# d2025.06.0 # d2025.06.0
* Add ability to remember recent projects in config * Add ability to remember recent projects in config

View File

@@ -21,9 +21,28 @@ constexpr ox::Array<ox::StringLiteral, 2> FileExts_TileSheet{
FileExt_ng, FileExt_ng,
}; };
constexpr ox::Array<ox::StringLiteral, 2> FileExts_Palette{
FileExt_npal,
};
[[nodiscard]] [[nodiscard]]
constexpr bool isTileSheet(ox::StringViewCR path) noexcept { constexpr bool isTileSheet(ox::StringViewCR path) noexcept {
return endsWith(path, FileExt_nts) || endsWith(path, FileExt_ng); return ox::any_of(
FileExts_TileSheet.begin(),
FileExts_TileSheet.end(),
[path](ox::StringLiteral const &ext) {
return endsWith(path, ext);
});
}
[[nodiscard]]
constexpr bool isPalette(ox::StringViewCR path) noexcept {
return ox::any_of(
FileExts_Palette.begin(),
FileExts_Palette.end(),
[path](ox::StringLiteral const &ext) {
return endsWith(path, ext);
});
} }
} }

View File

@@ -72,7 +72,7 @@ PaletteEditorImGui::PaletteEditorImGui(studio::Context &sctx, ox::StringParam pa
Editor(sctx, std::move(path)), Editor(sctx, std::move(path)),
m_sctx(sctx), m_sctx(sctx),
m_tctx(sctx.tctx), 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); undoStack()->changeTriggered.connect(this, &PaletteEditorImGui::handleCommand);
m_pageRenameDlg.inputSubmitted.connect(this, &PaletteEditorImGui::renamePage); m_pageRenameDlg.inputSubmitted.connect(this, &PaletteEditorImGui::renamePage);
} }

View File

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

View File

@@ -15,7 +15,7 @@ target_link_libraries(
target_compile_definitions( target_compile_definitions(
NostalgiaStudio PUBLIC NostalgiaStudio PUBLIC
OLYMPIC_APP_VERSION="dev build" OLYMPIC_APP_VERSION="d2025.07.0"
) )
install( install(

View File

@@ -18,7 +18,7 @@
<string>APPL</string> <string>APPL</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>dev build</string> <string>d2025.07.0</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
<string>12.0.0</string> <string>12.0.0</string>

View File

@@ -25,12 +25,11 @@ ox::Error writeUuidHeader(ox::Writer_c auto &writer, ox::UUID const&uuid) noexce
template<typename T> template<typename T>
ox::Result<T> readAsset(ox::BufferView buff) noexcept { ox::Result<T> readAsset(ox::BufferView buff) noexcept {
std::size_t offset = 0;
auto const err = readUuidHeader(buff).error; auto const err = readUuidHeader(buff).error;
if (!err) { 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(out);
OX_RETURN_ERROR(ensureValid(out.value)); OX_RETURN_ERROR(ensureValid(out.value));
return out; return out;

View File

@@ -64,11 +64,13 @@ class AssetContainer {
protected: protected:
constexpr void incRefs() const noexcept { constexpr void incRefs() const noexcept {
oxAssert(m_references < ox::MaxValue<decltype(m_references)>, "reference count exceeds maximum");
++m_references; ++m_references;
} }
constexpr void decRefs() const noexcept { constexpr void decRefs() const noexcept {
--m_references; --m_references;
oxAssert(m_references >= 0, "negative references");
} }
[[nodiscard]] [[nodiscard]]
@@ -162,6 +164,7 @@ template<typename T>
constexpr AssetRef<T>::AssetRef(AssetContainer<T> const*c) noexcept: m_ctr(c) { constexpr AssetRef<T>::AssetRef(AssetContainer<T> const*c) noexcept: m_ctr(c) {
if (m_ctr) { if (m_ctr) {
m_ctr->updated.connect(this, &AssetRef::emitUpdated); m_ctr->updated.connect(this, &AssetRef::emitUpdated);
m_ctr->incRefs();
} }
} }

View File

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

View File

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

View File

@@ -189,6 +189,10 @@ ox::Result<T> Project::loadObj(ox::StringViewCR path) const noexcept {
if constexpr(ox::is_same_v<T, ox::ModelObject>) { if constexpr(ox::is_same_v<T, ox::ModelObject>) {
return keel::readAsset(m_typeStore, buff); return keel::readAsset(m_typeStore, buff);
} else { } else {
OX_REQUIRE(typeId, keel::readAssetTypeId(buff));
if (typeId != ox::ModelTypeId_v<T>) {
return keel::convert<T>(m_kctx, buff);
}
return keel::readAsset<T>(buff); return keel::readAsset<T>(buff);
} }
} }

View File

@@ -8,13 +8,18 @@ namespace studio {
void navigateTo(Context &ctx, ox::StringParam filePath, ox::StringParam navArgs) noexcept { void navigateTo(Context &ctx, ox::StringParam filePath, ox::StringParam navArgs) noexcept {
ox::String path = std::move(filePath); ox::String path = std::move(filePath);
if (beginsWith(path, "uuid://")) { if (keel::isUuidUrl(path)) {
auto const [p, err] = keel::uuidUrlToPath(keelCtx(ctx), path); auto const [p, err] = keel::uuidUrlToPath(keelCtx(ctx), path);
if (err) { if (err) {
return; return;
} }
path = p; path = p;
} }
//if (
// auto const [np, err] = ctx.navStack.back();
// !err && np->filePath == path && np->navArgs == navArgs.view()) {
// return;
//}
ctx.navStack.resize(ctx.navIdx + 1); ctx.navStack.resize(ctx.navIdx + 1);
ctx.navStack.emplace_back(ox::String{path}, ox::String{navArgs.view()}); ctx.navStack.emplace_back(ox::String{path}, ox::String{navArgs.view()});
try { try {
@@ -49,8 +54,9 @@ void navigateBack(Context &ctx) noexcept {
} }
void navigateForward(Context &ctx) noexcept { void navigateForward(Context &ctx) noexcept {
while (ctx.navIdx < ctx.navStack.size()) { auto const nextIdx = ctx.navIdx + 1;
auto const &n = ctx.navStack[ctx.navIdx]; while (nextIdx < ctx.navStack.size()) {
auto const &n = ctx.navStack[nextIdx];
try { try {
ctx.navCallback(n.filePath, n.navArgs); ctx.navCallback(n.filePath, n.navArgs);
} catch (std::exception const &e) { } catch (std::exception const &e) {
@@ -58,7 +64,7 @@ void navigateForward(Context &ctx) noexcept {
oxErrf("navigateForward failed: {}", e.what()); oxErrf("navigateForward failed: {}", e.what());
} }
if (!ctx.project->exists(n.filePath)) { if (!ctx.project->exists(n.filePath)) {
std::ignore = ctx.navStack.erase(ctx.navIdx); std::ignore = ctx.navStack.erase(nextIdx);
continue; continue;
} }
++ctx.navIdx; ++ctx.navIdx;