[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;
|
ox::Result<int> editorModeUpdate() noexcept;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void setupTiles() noexcept;
|
||||||
|
|
||||||
|
void setupTile(uint32_t lyr, uint32_t x, uint32_t y) const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupLayer(uint_t lyr, uint_t cbb) const noexcept;
|
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 {
|
class WorldStaticLoader {
|
||||||
|
public:
|
||||||
|
ox::Signal<ox::Error(uint32_t layer, uint32_t x, uint32_t y)> tileUpdated;
|
||||||
|
ox::Signal<ox::Error()> resourcesUpdated;
|
||||||
private:
|
private:
|
||||||
keel::Context &m_kctx;
|
keel::Context &m_kctx;
|
||||||
WorldStatic &m_worldStatic;
|
WorldStatic &m_worldStatic;
|
||||||
@ -177,7 +180,8 @@ class WorldStaticLoader {
|
|||||||
ox::SmallMap<DocObjRef, CacheEntry> m_cache;
|
ox::SmallMap<DocObjRef, CacheEntry> m_cache;
|
||||||
ox::SmallMap<uint64_t, WorldObjectSet> m_objSets;
|
ox::SmallMap<uint64_t, WorldObjectSet> m_objSets;
|
||||||
uint16_t m_cbbIt{4};
|
uint16_t m_cbbIt{4};
|
||||||
bool m_loaded = false;
|
bool m_resourcesChanged{};
|
||||||
|
bool m_loaded{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WorldStaticLoader(keel::Context &kctx, WorldStatic &worldStatic, WorldDoc const&doc);
|
WorldStaticLoader(keel::Context &kctx, WorldStatic &worldStatic, WorldDoc const&doc);
|
||||||
|
@ -23,10 +23,6 @@ class AddObjectSet: public studio::UndoCommand {
|
|||||||
ox::Error undo() noexcept override;
|
ox::Error undo() noexcept override;
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept override;
|
int commandId() const noexcept override;
|
||||||
[[nodiscard]]
|
|
||||||
inline size_t insertIdx() const noexcept {
|
|
||||||
return m_insertIdx;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RmObjectSet: public studio::UndoCommand {
|
class RmObjectSet: public studio::UndoCommand {
|
||||||
|
@ -8,22 +8,24 @@
|
|||||||
namespace jasper::world {
|
namespace jasper::world {
|
||||||
|
|
||||||
EditWorldSizeCommand::EditWorldSizeCommand(
|
EditWorldSizeCommand::EditWorldSizeCommand(
|
||||||
|
WorldStaticLoader &loader,
|
||||||
WorldDoc &doc,
|
WorldDoc &doc,
|
||||||
ox::Size const&size):
|
ox::Size const&size):
|
||||||
m_doc(doc),
|
m_loader{loader},
|
||||||
m_oldSize(m_doc.columns, m_doc.rows),
|
m_doc{doc},
|
||||||
m_newSize(size) {}
|
m_oldSize{m_doc.columns, m_doc.rows},
|
||||||
|
m_newSize{size} {}
|
||||||
|
|
||||||
ox::Error EditWorldSizeCommand::redo() noexcept {
|
ox::Error EditWorldSizeCommand::redo() noexcept {
|
||||||
m_oldMap = m_doc.tiles;
|
m_oldMap = m_doc.tiles;
|
||||||
resize(m_doc, m_newSize);
|
resize(m_doc, m_newSize);
|
||||||
return {};
|
return m_loader.loadWorldStatic();
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error EditWorldSizeCommand::undo() noexcept {
|
ox::Error EditWorldSizeCommand::undo() noexcept {
|
||||||
resize(m_doc, m_oldSize);
|
resize(m_doc, m_oldSize);
|
||||||
m_doc.tiles = std::move(m_oldMap);
|
m_doc.tiles = std::move(m_oldMap);
|
||||||
return {};
|
return m_loader.loadWorldStatic();
|
||||||
}
|
}
|
||||||
|
|
||||||
int EditWorldSizeCommand::commandId() const noexcept {
|
int EditWorldSizeCommand::commandId() const noexcept {
|
||||||
|
@ -4,8 +4,6 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ox/fs/fs.hpp>
|
|
||||||
|
|
||||||
#include <studio/undostack.hpp>
|
#include <studio/undostack.hpp>
|
||||||
|
|
||||||
#include <jasper/world/world.hpp>
|
#include <jasper/world/world.hpp>
|
||||||
@ -14,23 +12,20 @@ namespace jasper::world {
|
|||||||
|
|
||||||
class EditWorldSizeCommand: public studio::UndoCommand {
|
class EditWorldSizeCommand: public studio::UndoCommand {
|
||||||
private:
|
private:
|
||||||
|
WorldStaticLoader &m_loader;
|
||||||
WorldDoc &m_doc;
|
WorldDoc &m_doc;
|
||||||
size_t m_insertIdx{};
|
|
||||||
ox::Size const m_oldSize;
|
ox::Size const m_oldSize;
|
||||||
WorldDoc::TileMap m_oldMap;
|
WorldDoc::TileMap m_oldMap;
|
||||||
ox::Size m_newSize;
|
ox::Size const m_newSize;
|
||||||
public:
|
public:
|
||||||
EditWorldSizeCommand(
|
EditWorldSizeCommand(
|
||||||
|
WorldStaticLoader &loader,
|
||||||
WorldDoc &doc,
|
WorldDoc &doc,
|
||||||
ox::Size const&size);
|
ox::Size const&size);
|
||||||
ox::Error redo() noexcept override;
|
ox::Error redo() noexcept override;
|
||||||
ox::Error undo() noexcept override;
|
ox::Error undo() noexcept override;
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int commandId() const noexcept override;
|
int commandId() const noexcept override;
|
||||||
[[nodiscard]]
|
|
||||||
inline size_t insertIdx() const noexcept {
|
|
||||||
return m_insertIdx;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
enum class Dimension {
|
enum class Dimension {
|
||||||
X, Y, Both, Neither,
|
X, Y, Both, Neither,
|
||||||
|
@ -77,10 +77,13 @@ WorldEditorImGui::WorldEditorImGui(studio::StudioContext &sctx, ox::StringParam
|
|||||||
m_sctx{sctx},
|
m_sctx{sctx},
|
||||||
m_doc{*keel::readObj<WorldDoc>(keelCtx(m_sctx), itemPath()).unwrapThrow()} {
|
m_doc{*keel::readObj<WorldDoc>(keelCtx(m_sctx), itemPath()).unwrapThrow()} {
|
||||||
OX_THROW_ERROR(m_loader.loadWorldStatic());
|
OX_THROW_ERROR(m_loader.loadWorldStatic());
|
||||||
|
OX_THROW_ERROR(m_view.setupWorld());
|
||||||
OX_THROW_ERROR(loadObjectSets());
|
OX_THROW_ERROR(loadObjectSets());
|
||||||
m_objSetPicker.filePicked.connect(this, &WorldEditorImGui::addObjSet);
|
m_objSetPicker.filePicked.connect(this, &WorldEditorImGui::addObjSet);
|
||||||
m_sctx.project->fileUpdated.connect(this, &WorldEditorImGui::handleDepUpdate);
|
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>(
|
studio::openConfig<WorldEditorConfig>(
|
||||||
keelCtx(m_sctx), itemPath(), [this](WorldEditorConfig const&config) {
|
keelCtx(m_sctx), itemPath(), [this](WorldEditorConfig const&config) {
|
||||||
m_view.setAnimate(config.animateBg);
|
m_view.setAnimate(config.animateBg);
|
||||||
@ -106,7 +109,6 @@ void WorldEditorImGui::draw(studio::StudioContext&) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WorldEditorImGui::onActivated() noexcept {
|
void WorldEditorImGui::onActivated() noexcept {
|
||||||
oxLogError(m_view.setupWorld());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldEditorImGui::copy() {
|
void WorldEditorImGui::copy() {
|
||||||
@ -240,7 +242,7 @@ void WorldEditorImGui::drawPropEditor() noexcept {
|
|||||||
if (ig::PopupControlsOkCancel(popupSz.x, m_sizeEditor.show) == ig::PopupResponse::OK) {
|
if (ig::PopupControlsOkCancel(popupSz.x, m_sizeEditor.show) == ig::PopupResponse::OK) {
|
||||||
if (changed) {
|
if (changed) {
|
||||||
std::ignore = pushCommand<EditWorldSizeCommand>(
|
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();
|
ImGui::EndPopup();
|
||||||
@ -379,7 +381,6 @@ ox::Error WorldEditorImGui::handleDrop(float const fbPaneScale) noexcept {
|
|||||||
m_doc,
|
m_doc,
|
||||||
std::move(mods));
|
std::move(mods));
|
||||||
}
|
}
|
||||||
OX_RETURN_ERROR(m_loader.loadWorldStatic());
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,7 +431,6 @@ ox::Error WorldEditorImGui::undoStackChanged(studio::UndoCommand const*cmd) {
|
|||||||
if (dynamic_cast<EditWorldSizeCommand const*>(cmd)) {
|
if (dynamic_cast<EditWorldSizeCommand const*>(cmd)) {
|
||||||
OX_RETURN_ERROR(m_loader.loadWorldStatic());
|
OX_RETURN_ERROR(m_loader.loadWorldStatic());
|
||||||
}
|
}
|
||||||
OX_RETURN_ERROR(m_view.setupWorld());
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,10 +9,21 @@
|
|||||||
namespace jasper::world {
|
namespace jasper::world {
|
||||||
|
|
||||||
WorldEditorView::WorldEditorView(studio::StudioContext &sctx, WorldStatic const&worldStatic):
|
WorldEditorView::WorldEditorView(studio::StudioContext &sctx, WorldStatic const&worldStatic):
|
||||||
m_sctx(sctx),
|
m_sctx{sctx},
|
||||||
m_cctx(ncore::init(m_sctx.tctx, {.glInstallDrawer = false}).unwrapThrow()),
|
m_cctx{ncore::init(m_sctx.tctx, {.glInstallDrawer = false}).unwrapThrow()},
|
||||||
m_worldStatic(worldStatic),
|
m_worldStatic{worldStatic},
|
||||||
m_world(*m_cctx, m_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 {
|
ox::Error WorldEditorView::setupWorld() noexcept {
|
||||||
|
@ -19,7 +19,7 @@ namespace jasper::world {
|
|||||||
|
|
||||||
namespace ncore = nostalgia::core;
|
namespace ncore = nostalgia::core;
|
||||||
|
|
||||||
class WorldEditorView {
|
class WorldEditorView: public ox::SignalHandler {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
studio::StudioContext &m_sctx;
|
studio::StudioContext &m_sctx;
|
||||||
@ -37,6 +37,10 @@ class WorldEditorView {
|
|||||||
public:
|
public:
|
||||||
WorldEditorView(studio::StudioContext &ctx, WorldStatic const&worldStatic);
|
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;
|
ox::Error setupWorld() noexcept;
|
||||||
|
|
||||||
void draw(ox::Size const&targetSz) noexcept;
|
void draw(ox::Size const&targetSz) noexcept;
|
||||||
|
@ -42,12 +42,42 @@ ox::Error World::setupDisplay() noexcept {
|
|||||||
rs.tilesheetIdx,
|
rs.tilesheetIdx,
|
||||||
rs.tileCnt));
|
rs.tileCnt));
|
||||||
}
|
}
|
||||||
|
setupTiles();
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::setupTiles() noexcept {
|
||||||
ncore::setBgStatus(m_nctx, 0); // disable all backgrounds
|
ncore::setBgStatus(m_nctx, 0); // disable all backgrounds
|
||||||
for (auto layerNo = 0u; auto const&layer : m_worldStatic.map) {
|
for (auto layerNo = 0u; auto const&layer : m_worldStatic.map) {
|
||||||
setupLayer(layerNo, layer.cbb);
|
setupLayer(layerNo, layer.cbb);
|
||||||
++layerNo;
|
++layerNo;
|
||||||
}
|
}
|
||||||
return {};
|
}
|
||||||
|
|
||||||
|
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 = 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),
|
||||||
|
.palBank = obj.palBank,
|
||||||
|
});
|
||||||
|
ncore::setBgTile(m_nctx, lyr, tx + 1, ty + 0, {
|
||||||
|
.tileIdx = static_cast<uint_t>(obj.cbbIdx + 1),
|
||||||
|
.palBank = obj.palBank,
|
||||||
|
});
|
||||||
|
ncore::setBgTile(m_nctx, lyr, tx + 0, ty + 1, {
|
||||||
|
.tileIdx = static_cast<uint_t>(obj.cbbIdx + 2),
|
||||||
|
.palBank = obj.palBank,
|
||||||
|
});
|
||||||
|
ncore::setBgTile(m_nctx, lyr, tx + 1, ty + 1, {
|
||||||
|
.tileIdx = static_cast<uint_t>(obj.cbbIdx + 3),
|
||||||
|
.palBank = obj.palBank,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::setupLayer(
|
void World::setupLayer(
|
||||||
@ -60,26 +90,7 @@ void World::setupLayer(
|
|||||||
auto const columns = ox::min<int>(m_worldStatic.columns, ncore::tileColumns(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 y = 0; y < rows; ++y) {
|
||||||
for (auto x = 0; x < columns; ++x) {
|
for (auto x = 0; x < columns; ++x) {
|
||||||
auto &t = tile(m_worldStatic, lyr, x, y);
|
setupTile(lyr, static_cast<uint32_t>(x), static_cast<uint32_t>(y));
|
||||||
auto const tx = x * 2;
|
|
||||||
auto const ty = 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),
|
|
||||||
.palBank = obj.palBank,
|
|
||||||
});
|
|
||||||
ncore::setBgTile(m_nctx, lyr, tx + 1, ty + 0, {
|
|
||||||
.tileIdx = static_cast<uint_t>(obj.cbbIdx + 1),
|
|
||||||
.palBank = obj.palBank,
|
|
||||||
});
|
|
||||||
ncore::setBgTile(m_nctx, lyr, tx + 0, ty + 1, {
|
|
||||||
.tileIdx = static_cast<uint_t>(obj.cbbIdx + 2),
|
|
||||||
.palBank = obj.palBank,
|
|
||||||
});
|
|
||||||
ncore::setBgTile(m_nctx, lyr, tx + 1, ty + 1, {
|
|
||||||
.tileIdx = static_cast<uint_t>(obj.cbbIdx + 3),
|
|
||||||
.palBank = obj.palBank,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,9 @@ ox::Error WorldStaticLoader::loadWorldStatic() noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_loaded = true;
|
m_loaded = true;
|
||||||
return keel::ensureValid(m_worldStatic);
|
OX_RETURN_ERROR(keel::ensureValid(m_worldStatic));
|
||||||
|
resourcesUpdated.emit();
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error WorldStaticLoader::updateTile(
|
ox::Error WorldStaticLoader::updateTile(
|
||||||
@ -79,6 +81,12 @@ ox::Error WorldStaticLoader::updateTile(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
loadTile(dst, newSrc);
|
loadTile(dst, newSrc);
|
||||||
|
if (m_resourcesChanged) {
|
||||||
|
m_resourcesChanged = false;
|
||||||
|
resourcesUpdated.emit();
|
||||||
|
} else {
|
||||||
|
tileUpdated.emit(layer, col, row);
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,6 +158,7 @@ ox::Result<uint8_t> WorldStaticLoader::setupTileResrc(DocObjRef const&docObjRef)
|
|||||||
.tileCnt = static_cast<uint8_t>(subsheet->size()),
|
.tileCnt = static_cast<uint8_t>(subsheet->size()),
|
||||||
});
|
});
|
||||||
m_cbbIt += refSet.tileCnt;
|
m_cbbIt += refSet.tileCnt;
|
||||||
|
m_resourcesChanged = true;
|
||||||
if (!docObjRef.unique) {
|
if (!docObjRef.unique) {
|
||||||
m_cache[docObjRef] = {.value = out, .refCnt = 1};
|
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);
|
std::ignore = m_worldStatic.objTileRefSets.erase(refIdx);
|
||||||
m_cache.erase(oldObjRef);
|
m_cache.erase(oldObjRef);
|
||||||
|
m_resourcesChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user