[jasper/world] Rework WorldEditor to use incremental loading
All checks were successful
Build / build (push) Successful in 3m43s
All checks were successful
Build / build (push) Successful in 3m43s
This commit is contained in:
parent
c774b5da70
commit
590b2524e5
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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 {};
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user