[jasper/world] Rework WorldEditor to use incremental loading
All checks were successful
Build / build (push) Successful in 3m43s

This commit is contained in:
Gary Talent 2025-01-11 22:20:29 -06:00
parent c774b5da70
commit 590b2524e5
10 changed files with 87 additions and 50 deletions

View File

@ -33,6 +33,10 @@ class World {
ox::Result<int> editorModeUpdate() noexcept;
#endif
void setupTiles() noexcept;
void setupTile(uint32_t lyr, uint32_t x, uint32_t y) const noexcept;
private:
void setupLayer(uint_t lyr, uint_t cbb) const noexcept;

View File

@ -166,6 +166,9 @@ auto &cbb(ox::CommonRefWith<WorldStatic> auto&ws, size_t const lyr) noexcept {
class WorldStaticLoader {
public:
ox::Signal<ox::Error(uint32_t layer, uint32_t x, uint32_t y)> tileUpdated;
ox::Signal<ox::Error()> resourcesUpdated;
private:
keel::Context &m_kctx;
WorldStatic &m_worldStatic;
@ -177,7 +180,8 @@ class WorldStaticLoader {
ox::SmallMap<DocObjRef, CacheEntry> m_cache;
ox::SmallMap<uint64_t, WorldObjectSet> m_objSets;
uint16_t m_cbbIt{4};
bool m_loaded = false;
bool m_resourcesChanged{};
bool m_loaded{};
public:
WorldStaticLoader(keel::Context &kctx, WorldStatic &worldStatic, WorldDoc const&doc);

View File

@ -23,10 +23,6 @@ class AddObjectSet: public studio::UndoCommand {
ox::Error undo() noexcept override;
[[nodiscard]]
int commandId() const noexcept override;
[[nodiscard]]
inline size_t insertIdx() const noexcept {
return m_insertIdx;
}
};
class RmObjectSet: public studio::UndoCommand {

View File

@ -8,22 +8,24 @@
namespace jasper::world {
EditWorldSizeCommand::EditWorldSizeCommand(
WorldStaticLoader &loader,
WorldDoc &doc,
ox::Size const&size):
m_doc(doc),
m_oldSize(m_doc.columns, m_doc.rows),
m_newSize(size) {}
m_loader{loader},
m_doc{doc},
m_oldSize{m_doc.columns, m_doc.rows},
m_newSize{size} {}
ox::Error EditWorldSizeCommand::redo() noexcept {
m_oldMap = m_doc.tiles;
resize(m_doc, m_newSize);
return {};
return m_loader.loadWorldStatic();
}
ox::Error EditWorldSizeCommand::undo() noexcept {
resize(m_doc, m_oldSize);
m_doc.tiles = std::move(m_oldMap);
return {};
return m_loader.loadWorldStatic();
}
int EditWorldSizeCommand::commandId() const noexcept {

View File

@ -4,8 +4,6 @@
#pragma once
#include <ox/fs/fs.hpp>
#include <studio/undostack.hpp>
#include <jasper/world/world.hpp>
@ -14,23 +12,20 @@ namespace jasper::world {
class EditWorldSizeCommand: public studio::UndoCommand {
private:
WorldStaticLoader &m_loader;
WorldDoc &m_doc;
size_t m_insertIdx{};
ox::Size const m_oldSize;
WorldDoc::TileMap m_oldMap;
ox::Size m_newSize;
ox::Size const m_newSize;
public:
EditWorldSizeCommand(
WorldStaticLoader &loader,
WorldDoc &doc,
ox::Size const&size);
ox::Error redo() noexcept override;
ox::Error undo() noexcept override;
[[nodiscard]]
int commandId() const noexcept override;
[[nodiscard]]
inline size_t insertIdx() const noexcept {
return m_insertIdx;
}
private:
enum class Dimension {
X, Y, Both, Neither,

View File

@ -77,10 +77,13 @@ WorldEditorImGui::WorldEditorImGui(studio::StudioContext &sctx, ox::StringParam
m_sctx{sctx},
m_doc{*keel::readObj<WorldDoc>(keelCtx(m_sctx), itemPath()).unwrapThrow()} {
OX_THROW_ERROR(m_loader.loadWorldStatic());
OX_THROW_ERROR(m_view.setupWorld());
OX_THROW_ERROR(loadObjectSets());
m_objSetPicker.filePicked.connect(this, &WorldEditorImGui::addObjSet);
m_sctx.project->fileUpdated.connect(this, &WorldEditorImGui::handleDepUpdate);
studio::Editor::undoStack()->changeTriggered.connect(this, &WorldEditorImGui::undoStackChanged);
m_loader.resourcesUpdated.connect(&m_view, &WorldEditorView::setupWorld);
m_loader.tileUpdated.connect(&m_view, &WorldEditorView::setupTile);
Editor::undoStack()->changeTriggered.connect(this, &WorldEditorImGui::undoStackChanged);
studio::openConfig<WorldEditorConfig>(
keelCtx(m_sctx), itemPath(), [this](WorldEditorConfig const&config) {
m_view.setAnimate(config.animateBg);
@ -106,7 +109,6 @@ void WorldEditorImGui::draw(studio::StudioContext&) noexcept {
}
void WorldEditorImGui::onActivated() noexcept {
oxLogError(m_view.setupWorld());
}
void WorldEditorImGui::copy() {
@ -240,7 +242,7 @@ void WorldEditorImGui::drawPropEditor() noexcept {
if (ig::PopupControlsOkCancel(popupSz.x, m_sizeEditor.show) == ig::PopupResponse::OK) {
if (changed) {
std::ignore = pushCommand<EditWorldSizeCommand>(
m_doc, ox::Size{m_sizeEditor.columns, m_sizeEditor.rows});
m_loader, m_doc, ox::Size{m_sizeEditor.columns, m_sizeEditor.rows});
}
}
ImGui::EndPopup();
@ -379,7 +381,6 @@ ox::Error WorldEditorImGui::handleDrop(float const fbPaneScale) noexcept {
m_doc,
std::move(mods));
}
OX_RETURN_ERROR(m_loader.loadWorldStatic());
return {};
}
@ -430,7 +431,6 @@ ox::Error WorldEditorImGui::undoStackChanged(studio::UndoCommand const*cmd) {
if (dynamic_cast<EditWorldSizeCommand const*>(cmd)) {
OX_RETURN_ERROR(m_loader.loadWorldStatic());
}
OX_RETURN_ERROR(m_view.setupWorld());
return {};
}

View File

@ -9,10 +9,21 @@
namespace jasper::world {
WorldEditorView::WorldEditorView(studio::StudioContext &sctx, WorldStatic const&worldStatic):
m_sctx(sctx),
m_cctx(ncore::init(m_sctx.tctx, {.glInstallDrawer = false}).unwrapThrow()),
m_worldStatic(worldStatic),
m_world(*m_cctx, m_worldStatic) {
m_sctx{sctx},
m_cctx{ncore::init(m_sctx.tctx, {.glInstallDrawer = false}).unwrapThrow()},
m_worldStatic{worldStatic},
m_world{*m_cctx, m_worldStatic} {}
ox::Error WorldEditorView::setupTile(
uint32_t const lyr,
uint32_t const x,
uint32_t const y) const noexcept {
m_world.setupTile(lyr, x, y);
return {};
}
void WorldEditorView::setupTiles() noexcept {
m_world.setupTiles();
}
ox::Error WorldEditorView::setupWorld() noexcept {

View File

@ -19,7 +19,7 @@ namespace jasper::world {
namespace ncore = nostalgia::core;
class WorldEditorView {
class WorldEditorView: public ox::SignalHandler {
private:
studio::StudioContext &m_sctx;
@ -37,6 +37,10 @@ class WorldEditorView {
public:
WorldEditorView(studio::StudioContext &ctx, WorldStatic const&worldStatic);
ox::Error setupTile(uint32_t lyr, uint32_t x, uint32_t y) const noexcept;
void setupTiles() noexcept;
ox::Error setupWorld() noexcept;
void draw(ox::Size const&targetSz) noexcept;

View File

@ -42,27 +42,25 @@ ox::Error World::setupDisplay() noexcept {
rs.tilesheetIdx,
rs.tileCnt));
}
setupTiles();
return {};
}
void World::setupTiles() noexcept {
ncore::setBgStatus(m_nctx, 0); // disable all backgrounds
for (auto layerNo = 0u; auto const&layer : m_worldStatic.map) {
setupLayer(layerNo, layer.cbb);
++layerNo;
}
return {};
}
void World::setupLayer(
uint_t const lyr,
uint_t const cbb) const noexcept {
ncore::clearBg(m_nctx, lyr);
ncore::setBgStatus(m_nctx, lyr, true);
ncore::setBgCbb(m_nctx, lyr, cbb);
auto const rows = ox::min<int>(m_worldStatic.rows, ncore::tileRows(m_nctx) / 2);
auto const columns = ox::min<int>(m_worldStatic.columns, ncore::tileColumns(m_nctx) / 2);
for (auto y = 0; y < rows; ++y) {
for (auto x = 0; x < columns; ++x) {
void World::setupTile(
uint32_t const lyr,
uint32_t const x,
uint32_t const y) const noexcept {
auto &t = tile(m_worldStatic, lyr, x, y);
auto const tx = x * 2;
auto const ty = y * 2;
auto const tx = static_cast<int>(x) * 2;
auto const ty = static_cast<int>(y) * 2;
auto const &obj = m_worldStatic.objTileRefSets[t.objIdxRefSet];;
ncore::setBgTile(m_nctx, lyr, tx + 0, ty + 0, {
.tileIdx = static_cast<uint_t>(obj.cbbIdx + 0),
@ -80,6 +78,19 @@ void World::setupLayer(
.tileIdx = static_cast<uint_t>(obj.cbbIdx + 3),
.palBank = obj.palBank,
});
}
void World::setupLayer(
uint_t const lyr,
uint_t const cbb) const noexcept {
ncore::clearBg(m_nctx, lyr);
ncore::setBgStatus(m_nctx, lyr, true);
ncore::setBgCbb(m_nctx, lyr, cbb);
auto const rows = ox::min<int>(m_worldStatic.rows, ncore::tileRows(m_nctx) / 2);
auto const columns = ox::min<int>(m_worldStatic.columns, ncore::tileColumns(m_nctx) / 2);
for (auto y = 0; y < rows; ++y) {
for (auto x = 0; x < columns; ++x) {
setupTile(lyr, static_cast<uint32_t>(x), static_cast<uint32_t>(y));
}
}
}

View File

@ -56,7 +56,9 @@ ox::Error WorldStaticLoader::loadWorldStatic() noexcept {
}
}
m_loaded = true;
return keel::ensureValid(m_worldStatic);
OX_RETURN_ERROR(keel::ensureValid(m_worldStatic));
resourcesUpdated.emit();
return {};
}
ox::Error WorldStaticLoader::updateTile(
@ -79,6 +81,12 @@ ox::Error WorldStaticLoader::updateTile(
}
}
loadTile(dst, newSrc);
if (m_resourcesChanged) {
m_resourcesChanged = false;
resourcesUpdated.emit();
} else {
tileUpdated.emit(layer, col, row);
}
return {};
}
@ -150,6 +158,7 @@ ox::Result<uint8_t> WorldStaticLoader::setupTileResrc(DocObjRef const&docObjRef)
.tileCnt = static_cast<uint8_t>(subsheet->size()),
});
m_cbbIt += refSet.tileCnt;
m_resourcesChanged = true;
if (!docObjRef.unique) {
m_cache[docObjRef] = {.value = out, .refCnt = 1};
}
@ -180,6 +189,7 @@ void WorldStaticLoader::deleteRefSet(uint8_t const refIdx, DocObjRef const&oldOb
}
std::ignore = m_worldStatic.objTileRefSets.erase(refIdx);
m_cache.erase(oldObjRef);
m_resourcesChanged = true;
}
}