[jasper/world] Rework World system
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
95587f664f
commit
fc184258c9
@ -18,7 +18,7 @@ class ObjectCache {
|
||||
struct Obj {
|
||||
ObjectId id{};
|
||||
uint16_t palBank{};
|
||||
size_t tileIdx{};
|
||||
size_t tilesheetIdx{};
|
||||
};
|
||||
private:
|
||||
struct ObjSet {
|
||||
@ -40,13 +40,15 @@ class ObjectCache {
|
||||
[[nodiscard]]
|
||||
ox::Optional<Obj> obj(uint64_t setId, ObjectId objId) const noexcept;
|
||||
[[nodiscard]]
|
||||
ncore::TileSheetSet const&tilesheets() const noexcept;
|
||||
ncore::TileSheetSet const&tilesheetSet() const noexcept;
|
||||
[[nodiscard]]
|
||||
ox::Vector<ox::FileAddress> const&tilesheets() const noexcept;
|
||||
[[nodiscard]]
|
||||
ox::Vector<ox::FileAddress> const&palettes() const noexcept;
|
||||
private:
|
||||
void addTileSheet(ox::FileAddress path, int32_t tiles) noexcept;
|
||||
void addTileSheetSetEntry(ox::FileAddress path, int32_t tiles) noexcept;
|
||||
};
|
||||
|
||||
ox::Result<ObjectCache> buildObjCache(keel::Context &kctx, WorldDoc const&doc) noexcept;
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,6 @@
|
||||
|
||||
#include <nostalgia/core/context.hpp>
|
||||
|
||||
#include "consts.hpp"
|
||||
#include "worldobject.hpp"
|
||||
#include "worldstatic.hpp"
|
||||
|
||||
namespace jasper::world {
|
||||
@ -18,6 +16,7 @@ class World {
|
||||
private:
|
||||
ncore::Context &m_nctx;
|
||||
WorldStatic const&m_worldStatic;
|
||||
ox::Vector<keel::AssetRef<ncore::CompactTileSheet>, 32> m_tilesheets;
|
||||
#ifndef OX_OS_BareMetal
|
||||
//turbine::TimeMs m_prevUpdateTime{};
|
||||
turbine::TimeMs m_nextUpdateTime{};
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include <ox/fs/fs.hpp>
|
||||
#include <ox/std/error.hpp>
|
||||
#include <ox/std/hash.hpp>
|
||||
#include <ox/std/size.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
@ -31,11 +32,19 @@ struct DocObjRef {
|
||||
constexpr static auto TypeVersion = 1;
|
||||
uint64_t worldObjectSetId{};
|
||||
ObjectId worldObjectId{};
|
||||
bool unique{};
|
||||
};
|
||||
|
||||
constexpr bool operator==(DocObjRef const&a, DocObjRef const&b) noexcept {
|
||||
return a.worldObjectSetId == b.worldObjectSetId
|
||||
&& a.worldObjectId == b.worldObjectId
|
||||
&& a.unique == b.unique;
|
||||
}
|
||||
|
||||
OX_MODEL_BEGIN(DocObjRef)
|
||||
OX_MODEL_FIELD_RENAME(worldObjectSetId, world_object_set_id)
|
||||
OX_MODEL_FIELD_RENAME(worldObjectId, world_object_id)
|
||||
OX_MODEL_FIELD(unique)
|
||||
OX_MODEL_END()
|
||||
|
||||
struct TileDoc {
|
||||
@ -82,25 +91,29 @@ struct WorldDoc {
|
||||
constexpr static auto TypeVersion = 1;
|
||||
ox::Vector<ObjectSetEntry> objSets; // paths
|
||||
uint64_t objSetIdIdx{};
|
||||
int columns{};
|
||||
int rows{};
|
||||
int32_t columns{};
|
||||
int32_t rows{};
|
||||
TileMap tiles;
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr ox::Result<ox::String> objectSetPath(WorldDoc const&wd, uint64_t setId) noexcept {
|
||||
auto const obj = ox::find_if(wd.objSets.begin(), wd.objSets.end(), [setId](ObjectSetEntry const&e) {
|
||||
return e.id == setId;
|
||||
});
|
||||
constexpr ox::Result<ox::String> objectSetPath(
|
||||
WorldDoc const&wd, uint64_t setId) noexcept {
|
||||
auto const obj = ox::find_if(wd.objSets.begin(), wd.objSets.end(),
|
||||
[setId](ObjectSetEntry const&e) {
|
||||
return e.id == setId;
|
||||
});
|
||||
OX_RETURN_ERROR(ox::Error(obj == wd.objSets.end(), "Obj set not found"));
|
||||
return obj->path;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr ox::Result<uint64_t> objectSetId(WorldDoc const&wd, ox::StringView setPath) noexcept {
|
||||
auto const obj = ox::find_if(wd.objSets.begin(), wd.objSets.end(), [setPath](ObjectSetEntry const&e) {
|
||||
return e.path == setPath;
|
||||
});
|
||||
constexpr ox::Result<uint64_t> objectSetId(
|
||||
WorldDoc const&wd, ox::StringViewCR setPath) noexcept {
|
||||
auto const obj = ox::find_if(wd.objSets.begin(), wd.objSets.end(),
|
||||
[setPath](ObjectSetEntry const&e) {
|
||||
return e.path == setPath;
|
||||
});
|
||||
OX_RETURN_ERROR(ox::Error(obj == wd.objSets.end(), "Obj set not found"));
|
||||
return obj->id;
|
||||
}
|
||||
@ -151,3 +164,13 @@ auto &tile(
|
||||
void resize(WorldDoc &doc, ox::Size const&sz) noexcept;
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct std::hash<jasper::world::DocObjRef> {
|
||||
[[nodiscard]]
|
||||
constexpr size_t operator()(jasper::world::DocObjRef const&v) const noexcept {
|
||||
return static_cast<uint32_t>(v.worldObjectSetId)
|
||||
| (static_cast<uint32_t>(v.worldObjectId) << 15)
|
||||
| (static_cast<uint32_t>(v.unique) << 31);
|
||||
}
|
||||
};
|
||||
|
@ -10,31 +10,28 @@
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
|
||||
#include <nostalgia/core/tilesheet.hpp>
|
||||
|
||||
#include <jasper/world/objectcache.hpp>
|
||||
|
||||
#include "worlddoc.hpp"
|
||||
#include "worldobject.hpp"
|
||||
|
||||
namespace jasper::world {
|
||||
|
||||
namespace ncore = nostalgia::core;
|
||||
|
||||
constexpr void setTopEdge(uint8_t &layerAttachments, unsigned val) noexcept {
|
||||
const auto val8 = static_cast<uint8_t>(val);
|
||||
constexpr void setTopEdge(uint8_t &layerAttachments, unsigned const val) noexcept {
|
||||
auto const val8 = static_cast<uint8_t>(val);
|
||||
layerAttachments = (layerAttachments & 0b11111100) | val8;
|
||||
}
|
||||
constexpr void setBottomEdge(uint8_t &layerAttachments, unsigned val) noexcept {
|
||||
const auto val8 = static_cast<uint8_t>(val);
|
||||
constexpr void setBottomEdge(uint8_t &layerAttachments, unsigned const val) noexcept {
|
||||
auto const val8 = static_cast<uint8_t>(val);
|
||||
layerAttachments = (layerAttachments & 0b11110011) | static_cast<uint8_t>(val8 << 2);
|
||||
}
|
||||
constexpr void setLeftEdge(uint8_t &layerAttachments, unsigned val) noexcept {
|
||||
const auto val8 = static_cast<uint8_t>(val);
|
||||
constexpr void setLeftEdge(uint8_t &layerAttachments, unsigned const val) noexcept {
|
||||
auto const val8 = static_cast<uint8_t>(val);
|
||||
layerAttachments = (layerAttachments & 0b11001111) | static_cast<uint8_t>(val8 << 4);
|
||||
}
|
||||
constexpr void setRightEdge(uint8_t &layerAttachments, unsigned val) noexcept {
|
||||
const auto val8 = static_cast<uint8_t>(val);
|
||||
constexpr void setRightEdge(uint8_t &layerAttachments, unsigned const val) noexcept {
|
||||
auto const val8 = static_cast<uint8_t>(val);
|
||||
layerAttachments = (layerAttachments & 0b00111111) | static_cast<uint8_t>(val8 << 6);
|
||||
}
|
||||
|
||||
@ -57,25 +54,23 @@ constexpr unsigned rightEdge(uint8_t layerAttachments) noexcept {
|
||||
|
||||
|
||||
struct TileStatic {
|
||||
constexpr static auto TypeName = "net.drinkingtea.jasper.world.TileStatic";
|
||||
constexpr static auto TypeVersion = 1;
|
||||
uint16_t tileIdx{};
|
||||
uint8_t palBank{};
|
||||
static constexpr auto TypeName = "net.drinkingtea.jasper.world.TileStatic";
|
||||
static constexpr auto TypeVersion = 1;
|
||||
uint8_t objIdxRefSet{};
|
||||
uint8_t tileType{};
|
||||
uint8_t layerAttachments{};
|
||||
};
|
||||
|
||||
OX_MODEL_BEGIN(TileStatic)
|
||||
OX_MODEL_FIELD(tileIdx)
|
||||
OX_MODEL_FIELD(palBank)
|
||||
OX_MODEL_FIELD(objIdxRefSet)
|
||||
OX_MODEL_FIELD(tileType)
|
||||
OX_MODEL_FIELD(layerAttachments)
|
||||
OX_MODEL_END()
|
||||
|
||||
|
||||
struct BgLayer {
|
||||
constexpr static auto TypeName = "net.drinkingtea.jasper.world.BgLayer";
|
||||
constexpr static auto TypeVersion = 1;
|
||||
static constexpr auto TypeName = "net.drinkingtea.jasper.world.BgLayer";
|
||||
static constexpr auto TypeVersion = 1;
|
||||
uint8_t cbb{};
|
||||
ox::Vector<TileStatic> tiles;
|
||||
};
|
||||
@ -86,11 +81,47 @@ OX_MODEL_BEGIN(BgLayer)
|
||||
OX_MODEL_END()
|
||||
|
||||
|
||||
struct ObjTileRefSet {
|
||||
static constexpr auto TypeName = "net.drinkingtea.jasper.world.ObjTileRefSet";
|
||||
static constexpr auto TypeVersion = 1;
|
||||
uint16_t palBank{};
|
||||
uint16_t tilesheetIdx{};
|
||||
uint16_t cbbIdx{};
|
||||
uint8_t cbb{};
|
||||
// which tilesheet to use
|
||||
uint8_t tilesheetId{};
|
||||
uint8_t tileCnt{};
|
||||
// each successive frame will use tileIdx[i] + tileCnt * frameNo for the tileIdx
|
||||
uint8_t frames{};
|
||||
};
|
||||
|
||||
OX_MODEL_BEGIN(ObjTileRefSet)
|
||||
OX_MODEL_FIELD(palBank)
|
||||
OX_MODEL_FIELD(tilesheetIdx)
|
||||
OX_MODEL_FIELD(cbbIdx)
|
||||
OX_MODEL_FIELD(cbb)
|
||||
OX_MODEL_FIELD(tilesheetId)
|
||||
OX_MODEL_FIELD(tileCnt)
|
||||
OX_MODEL_FIELD(frames)
|
||||
OX_MODEL_END()
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr bool operator==(ObjTileRefSet const&a, ObjTileRefSet const&b) noexcept {
|
||||
return
|
||||
a.tilesheetId == b.tilesheetId &&
|
||||
a.tileCnt == b.tileCnt &&
|
||||
a.frames == b.frames &&
|
||||
a.tilesheetIdx == b.tilesheetIdx;
|
||||
}
|
||||
|
||||
|
||||
struct WorldStatic {
|
||||
constexpr static auto TypeName = "net.drinkingtea.jasper.world.WorldStatic";
|
||||
constexpr static auto TypeVersion = 1;
|
||||
constexpr static auto Preloadable = true;
|
||||
ncore::TileSheetSet tilesheets;
|
||||
static constexpr auto TypeName = "net.drinkingtea.jasper.world.WorldStatic";
|
||||
static constexpr auto TypeVersion = 1;
|
||||
static constexpr auto Preloadable = true;
|
||||
ncore::TileSheetSet tilesheetSet;
|
||||
ox::Vector<ObjTileRefSet> objTileRefSets;
|
||||
ox::Vector<ox::FileAddress> tilesheets;
|
||||
ox::Vector<ox::FileAddress> palettes;
|
||||
int16_t columns{};
|
||||
int16_t rows{};
|
||||
@ -98,6 +129,8 @@ struct WorldStatic {
|
||||
};
|
||||
|
||||
OX_MODEL_BEGIN(WorldStatic)
|
||||
OX_MODEL_FIELD(tilesheetSet)
|
||||
OX_MODEL_FIELD(objTileRefSets)
|
||||
OX_MODEL_FIELD(tilesheets)
|
||||
OX_MODEL_FIELD(palettes)
|
||||
OX_MODEL_FIELD(columns)
|
||||
@ -105,9 +138,22 @@ OX_MODEL_BEGIN(WorldStatic)
|
||||
OX_MODEL_FIELD(map)
|
||||
OX_MODEL_END()
|
||||
|
||||
void loadTile(ObjectCache const&objCache, TileStatic &dst, TileDoc const&src) noexcept;
|
||||
[[nodiscard]]
|
||||
constexpr bool valid(WorldStatic const&ws) noexcept {
|
||||
auto const tileCnt = static_cast<size_t>(ws.columns * ws.rows);
|
||||
return ox::all_of(ws.map.begin(), ws.map.end(), [tileCnt](BgLayer const&v) {
|
||||
return v.tiles.size() == tileCnt;
|
||||
});
|
||||
}
|
||||
|
||||
ox::Result<WorldStatic> loadWorldStatic(ObjectCache const&objCache, WorldDoc const&doc) noexcept;
|
||||
void loadTile(TileStatic &dst, TileDoc const&src) noexcept;
|
||||
|
||||
ox::Result<WorldStatic> loadWorldStatic(keel::Context &kctx, ObjectCache const&objCache, WorldDoc const&doc) noexcept;
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr size_t layers(WorldStatic const&ws) noexcept {
|
||||
return ws.map.size();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
auto &tile(
|
||||
@ -124,7 +170,4 @@ auto &cbb(ox::CommonRefWith<WorldStatic> auto&ws, size_t lyr) noexcept {
|
||||
return ws.map[lyr].cbb;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool isValid(WorldStatic const&ws) noexcept;
|
||||
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ ox::Error WorldDocToWorldStaticConverter::convert(
|
||||
WorldDoc &src,
|
||||
WorldStatic &dst) const noexcept {
|
||||
OX_REQUIRE(oc, buildObjCache(kctx, src));
|
||||
return loadWorldStatic(oc, src).moveTo(dst);
|
||||
return loadWorldStatic(kctx, oc, src).moveTo(dst);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,25 +20,28 @@ void ObjectCache::clear() noexcept {
|
||||
|
||||
ox::Error ObjectCache::indexSet(
|
||||
keel::Context &kctx,
|
||||
uint64_t setId,
|
||||
uint64_t const setId,
|
||||
WorldObjectSet const&objSet) noexcept {
|
||||
auto &set = m_objSets.emplace_back(ObjSet{
|
||||
.setId = setId,
|
||||
.objects = {},
|
||||
});
|
||||
OX_REQUIRE(ts, readObj<ncore::TileSheet>(kctx, objSet.tilesheet));
|
||||
auto tsId = ox::find(m_tilesheets.begin(), m_tilesheets.end(), objSet.tilesheet);
|
||||
if (tsId == m_tilesheets.end()) {
|
||||
m_tilesheets.emplace_back(objSet.tilesheet);
|
||||
}
|
||||
for (auto const&obj : objSet.objects) {
|
||||
set.objects.emplace_back(Obj{
|
||||
.id = obj.id,
|
||||
.palBank = static_cast<uint16_t>(obj.palBank + m_palBank),
|
||||
.tileIdx = getTileIdx(*ts, obj.subsheetId) + m_tileIdx,
|
||||
.tilesheetIdx = getTileIdx(*ts, obj.subsheetId).or_value(0) + m_tileIdx,
|
||||
});
|
||||
}
|
||||
auto const tileCnt = getTileCnt(*ts);
|
||||
m_tileIdx += tileCnt;
|
||||
m_tilesheets.emplace_back(objSet.tilesheet);
|
||||
m_tilesheetSet.bpp = 4;
|
||||
addTileSheet(objSet.tilesheet, static_cast<int32_t>(tileCnt));
|
||||
addTileSheetSetEntry(objSet.tilesheet, static_cast<int32_t>(tileCnt));
|
||||
for (auto const&pal : objSet.palettes) {
|
||||
m_palettes.emplace_back(pal);
|
||||
OX_REQUIRE(p, readObj<ncore::Palette>(kctx, pal));
|
||||
@ -61,15 +64,19 @@ ox::Optional<ObjectCache::Obj> ObjectCache::obj(uint64_t setId, ObjectId objId)
|
||||
return {};
|
||||
}
|
||||
|
||||
ncore::TileSheetSet const&ObjectCache::tilesheets() const noexcept {
|
||||
ncore::TileSheetSet const&ObjectCache::tilesheetSet() const noexcept {
|
||||
return m_tilesheetSet;
|
||||
}
|
||||
|
||||
ox::Vector<ox::FileAddress> const&ObjectCache::tilesheets() const noexcept {
|
||||
return m_tilesheets;
|
||||
}
|
||||
|
||||
ox::Vector<ox::FileAddress> const&ObjectCache::palettes() const noexcept {
|
||||
return m_palettes;
|
||||
}
|
||||
|
||||
void ObjectCache::addTileSheet(ox::FileAddress path, int32_t tiles) noexcept {
|
||||
void ObjectCache::addTileSheetSetEntry(ox::FileAddress path, int32_t tiles) noexcept {
|
||||
ncore::TileSheetSetEntry entry;
|
||||
entry.tilesheet = std::move(path);
|
||||
entry.sections.push_back({
|
||||
|
@ -8,27 +8,21 @@
|
||||
namespace jasper::world {
|
||||
|
||||
EditWorldSizeCommand::EditWorldSizeCommand(
|
||||
ObjectCache const&objCache,
|
||||
WorldDoc &doc,
|
||||
WorldStatic &worldStatic,
|
||||
ox::Size const&size):
|
||||
m_objCache(objCache),
|
||||
m_doc(doc),
|
||||
m_worldStatic(worldStatic),
|
||||
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);
|
||||
OX_RETURN_ERROR(loadWorldStatic(m_objCache, m_doc).moveTo(m_worldStatic));
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Error EditWorldSizeCommand::undo() noexcept {
|
||||
resize(m_doc, m_oldSize);
|
||||
m_doc.tiles = std::move(m_oldMap);
|
||||
OX_RETURN_ERROR(loadWorldStatic(m_objCache, m_doc).moveTo(m_worldStatic));
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -14,18 +14,14 @@ namespace jasper::world {
|
||||
|
||||
class EditWorldSizeCommand: public studio::UndoCommand {
|
||||
private:
|
||||
ObjectCache const&m_objCache;
|
||||
WorldDoc &m_doc;
|
||||
WorldStatic &m_worldStatic;
|
||||
size_t m_insertIdx{};
|
||||
ox::Size const m_oldSize;
|
||||
WorldDoc::TileMap m_oldMap;
|
||||
ox::Size m_newSize;
|
||||
public:
|
||||
EditWorldSizeCommand(
|
||||
ObjectCache const&objCache,
|
||||
WorldDoc &doc,
|
||||
WorldStatic &worldStatic,
|
||||
ox::Size const&size);
|
||||
ox::Error redo() noexcept override;
|
||||
ox::Error undo() noexcept override;
|
||||
|
@ -47,7 +47,7 @@ void ModifyTilesCommand::swap() noexcept {
|
||||
auto &activeTile = tile(m_worldStatic, mod.layer, mod.tileAddr.x, mod.tileAddr.y);
|
||||
std::swap(docTile.obj.worldObjectId, mod.objId);
|
||||
std::swap(docTile.obj.worldObjectSetId, mod.setId);
|
||||
loadTile(m_objCache, activeTile, docTile);
|
||||
loadTile(activeTile, docTile);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,12 +77,12 @@ constexpr ox::Point fbPtToTileAddr(
|
||||
};
|
||||
}
|
||||
|
||||
WorldEditorImGui::WorldEditorImGui(studio::StudioContext &sctx, ox::StringView path):
|
||||
Editor(path),
|
||||
WorldEditorImGui::WorldEditorImGui(studio::StudioContext &sctx, ox::StringParam path):
|
||||
Editor(std::move(path)),
|
||||
m_sctx(sctx),
|
||||
m_doc(makeValid(*readObj<WorldDoc>(keelCtx(m_sctx), path).unwrapThrow())),
|
||||
m_doc(makeValid(*readObj<WorldDoc>(keelCtx(m_sctx), itemPath()).unwrapThrow())),
|
||||
m_objCache(buildObjCache(keelCtx(m_sctx), m_doc).unwrapThrow()),
|
||||
m_worldStatic(loadWorldStatic(m_objCache, m_doc)),
|
||||
m_worldStatic(loadWorldStatic(keelCtx(m_sctx), m_objCache, m_doc)),
|
||||
m_view(m_sctx, m_worldStatic) {
|
||||
OX_THROW_ERROR(loadObjectSets());
|
||||
m_objSetPicker.filePicked.connect(this, &WorldEditorImGui::addObjSet);
|
||||
@ -249,7 +249,7 @@ void WorldEditorImGui::drawPropEditor() noexcept {
|
||||
if (ig::PopupControlsOkCancel(popupSz.x, m_sizeEditor.show) == ig::PopupResponse::OK) {
|
||||
if (changed) {
|
||||
std::ignore = pushCommand<EditWorldSizeCommand>(
|
||||
m_objCache, m_doc, m_worldStatic, ox::Size{m_sizeEditor.columns, m_sizeEditor.rows});
|
||||
m_doc, ox::Size{m_sizeEditor.columns, m_sizeEditor.rows});
|
||||
}
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
@ -389,7 +389,7 @@ ox::Error WorldEditorImGui::handleDrop(float fbPaneScale) noexcept {
|
||||
m_objCache,
|
||||
std::move(mods));
|
||||
}
|
||||
OX_RETURN_ERROR(loadWorldStatic(m_objCache, m_doc).moveTo(m_worldStatic));
|
||||
OX_RETURN_ERROR(loadWorldStatic(keelCtx(m_sctx), m_objCache, m_doc).moveTo(m_worldStatic));
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -416,7 +416,7 @@ ox::Error WorldEditorImGui::handleDepUpdate(ox::StringView, ox::UUID const&uuid)
|
||||
|| ox::any_of(m_dependencies.pairs().begin(), m_dependencies.pairs().end(), depMatches);
|
||||
if (depUpdated) {
|
||||
OX_RETURN_ERROR(buildObjCache(kctx, m_doc).moveTo(m_objCache));
|
||||
OX_RETURN_ERROR(loadWorldStatic(m_objCache, m_doc).moveTo(m_worldStatic));
|
||||
OX_RETURN_ERROR(loadWorldStatic(keelCtx(m_sctx), m_objCache, m_doc).moveTo(m_worldStatic));
|
||||
OX_RETURN_ERROR(loadObjectSets());
|
||||
}
|
||||
return {};
|
||||
@ -437,8 +437,11 @@ ox::Error WorldEditorImGui::loadObjectSets() noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
ox::Error WorldEditorImGui::undoStackChanged(studio::UndoCommand const*) {
|
||||
ox::Error WorldEditorImGui::undoStackChanged(studio::UndoCommand const*cmd) {
|
||||
OX_RETURN_ERROR(m_view.setupWorld());
|
||||
if (dynamic_cast<EditWorldSizeCommand const*>(cmd)) {
|
||||
OX_RETURN_ERROR(loadWorldStatic(keelCtx(m_sctx), m_objCache, m_doc).moveTo(m_worldStatic));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -8,8 +8,7 @@
|
||||
|
||||
#include <studio/studio.hpp>
|
||||
|
||||
#include <turbine/context.hpp>
|
||||
|
||||
#include <jasper/world/consts.hpp>
|
||||
#include <jasper/world/objectcache.hpp>
|
||||
|
||||
#include "worldeditorview.hpp"
|
||||
@ -23,8 +22,7 @@ class WorldEditorImGui: public studio::Editor {
|
||||
ox::Optional<studio::Selection> m_selection;
|
||||
uint8_t m_activeLayer{};
|
||||
studio::StudioContext &m_sctx;
|
||||
studio::ig::FilePicker m_objSetPicker{
|
||||
m_sctx, ox::String("Choose Object Set"), ox::String(FileExt_jwob)};
|
||||
studio::ig::FilePicker m_objSetPicker{m_sctx, "Choose Object Set", FileExt_jwob};
|
||||
WorldDoc m_doc;
|
||||
ObjectCache m_objCache;
|
||||
struct ObjSetRef {
|
||||
@ -51,7 +49,7 @@ class WorldEditorImGui: public studio::Editor {
|
||||
} m_sizeEditor;
|
||||
|
||||
public:
|
||||
WorldEditorImGui(studio::StudioContext &ctx, ox::StringView path);
|
||||
WorldEditorImGui(studio::StudioContext &ctx, ox::StringParam path);
|
||||
|
||||
void draw(studio::StudioContext&) noexcept final;
|
||||
|
||||
|
@ -140,7 +140,7 @@ void WorldObjectSetEditorImGui::loadObj() noexcept {
|
||||
w = m_subsheet->columns;
|
||||
h = m_subsheet->rows;
|
||||
}
|
||||
auto const idx = getTileIdx(*m_tileSheet, obj.subsheetId);
|
||||
auto const idx = getTileIdx(*m_tileSheet, obj.subsheetId).or_value(0);
|
||||
oxLogError(m_colView.setup(
|
||||
m_doc.tilesheet,
|
||||
m_doc.palettes[obj.palBank],
|
||||
|
@ -15,6 +15,13 @@ World::World(ncore::Context &nctx, WorldStatic const&worldStatic) noexcept:
|
||||
m_worldStatic(worldStatic) {}
|
||||
|
||||
ox::Error World::setupDisplay() noexcept {
|
||||
auto &kctx = keelCtx(m_nctx);
|
||||
if (m_tilesheets.empty()) {
|
||||
for (auto const&tsAddr : m_worldStatic.tilesheets) {
|
||||
OX_REQUIRE_M(ts, keel::readObj<ncore::CompactTileSheet>(kctx, tsAddr));
|
||||
m_tilesheets.emplace_back(std::move(ts));
|
||||
}
|
||||
}
|
||||
if (m_worldStatic.palettes.empty()) {
|
||||
return ox::Error(1, "World has no palettes");
|
||||
}
|
||||
@ -23,7 +30,16 @@ ox::Error World::setupDisplay() noexcept {
|
||||
OX_RETURN_ERROR(ncore::loadBgPalette(m_nctx, i, *pal));
|
||||
++i;
|
||||
}
|
||||
OX_RETURN_ERROR(ncore::loadBgTileSheet(m_nctx, 0, m_worldStatic.tilesheets));
|
||||
OX_RETURN_ERROR(ncore::loadBgTileSheet(m_nctx, 0, m_worldStatic.tilesheetSet));
|
||||
for (auto const&rs : m_worldStatic.objTileRefSets) {
|
||||
OX_RETURN_ERROR(ncore::loadBgTileSheet(
|
||||
m_nctx,
|
||||
rs.cbb,
|
||||
*m_tilesheets[rs.tilesheetId],
|
||||
rs.cbbIdx,
|
||||
rs.tilesheetIdx,
|
||||
rs.tileCnt));
|
||||
}
|
||||
ncore::setBgStatus(m_nctx, 0); // disable all backgrounds
|
||||
for (auto layerNo = 0u; auto const&layer : m_worldStatic.map) {
|
||||
setupLayer(layerNo, layer.cbb);
|
||||
@ -33,8 +49,8 @@ ox::Error World::setupDisplay() noexcept {
|
||||
}
|
||||
|
||||
void World::setupLayer(
|
||||
uint_t lyr,
|
||||
uint_t cbb) const noexcept {
|
||||
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);
|
||||
@ -45,21 +61,22 @@ void World::setupLayer(
|
||||
auto &t = tile(m_worldStatic, lyr, x, 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>(t.tileIdx + 0),
|
||||
.palBank = t.palBank,
|
||||
.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>(t.tileIdx + 1),
|
||||
.palBank = t.palBank,
|
||||
.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>(t.tileIdx + 2),
|
||||
.palBank = t.palBank,
|
||||
.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>(t.tileIdx + 3),
|
||||
.palBank = t.palBank,
|
||||
.tileIdx = static_cast<uint_t>(obj.cbbIdx + 3),
|
||||
.palBank = obj.palBank,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -2,17 +2,18 @@
|
||||
* Copyright 2023 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||
*/
|
||||
|
||||
#include <keel/media.hpp>
|
||||
|
||||
#include <nostalgia/core/gfx.hpp>
|
||||
|
||||
#include <jasper/world/worldobject.hpp>
|
||||
#include <jasper/world/worldstatic.hpp>
|
||||
|
||||
namespace jasper::world {
|
||||
|
||||
void loadTile(ObjectCache const&objCache, TileStatic &dst, TileDoc const&src) noexcept {
|
||||
auto const obj = objCache.obj(src.obj.worldObjectSetId, src.obj.worldObjectId).or_value({});
|
||||
dst.palBank = src.palBank;
|
||||
dst.tileIdx = static_cast<uint16_t>(obj.tileIdx);
|
||||
dst.palBank = static_cast<uint8_t>(obj.palBank);
|
||||
void loadTile(
|
||||
TileStatic &dst,
|
||||
TileDoc const&src) noexcept {
|
||||
dst.tileType = src.type;
|
||||
setTopEdge(dst.layerAttachments, src.topLayerAttachment);
|
||||
setBottomEdge(dst.layerAttachments, src.bottomLayerAttachment);
|
||||
@ -20,41 +21,110 @@ void loadTile(ObjectCache const&objCache, TileStatic &dst, TileDoc const&src) no
|
||||
setRightEdge(dst.layerAttachments, src.rightLayerAttachment);
|
||||
}
|
||||
|
||||
ox::Result<WorldStatic> loadWorldStatic(ObjectCache const&objCache, WorldDoc const&doc) noexcept {
|
||||
auto const tileCnt =
|
||||
static_cast<size_t>(doc.columns) * static_cast<size_t>(doc.rows);
|
||||
WorldStatic out {
|
||||
.tilesheets = {},
|
||||
.palettes = {},
|
||||
.columns = static_cast<int16_t>(doc.columns),
|
||||
.rows = static_cast<int16_t>(doc.rows),
|
||||
.map = {
|
||||
{.tiles = ox::Vector<TileStatic>(tileCnt),},
|
||||
{.tiles = ox::Vector<TileStatic>(tileCnt),},
|
||||
{.tiles = ox::Vector<TileStatic>(tileCnt),},
|
||||
},
|
||||
};
|
||||
// resources
|
||||
out.tilesheets = objCache.tilesheets();
|
||||
out.palettes = objCache.palettes();
|
||||
// tiles
|
||||
for (auto lyr = 0u; lyr < 3; ++lyr) {
|
||||
for (auto x = 0u; x < static_cast<size_t>(out.columns); ++x) {
|
||||
for (auto y = 0u; y < static_cast<size_t>(out.rows); ++y) {
|
||||
auto &dst = tile(out, lyr, x, y);
|
||||
auto &src = tile(doc, lyr, x, y);;
|
||||
loadTile(objCache, dst, src);
|
||||
}
|
||||
/**
|
||||
* Returns the index in rsrcs for the given docObjRef.
|
||||
*/
|
||||
static ox::Result<uint8_t> setupTileResrc(
|
||||
ox::SmallMap<DocObjRef, uint8_t> &cache,
|
||||
keel::Context &kctx,
|
||||
ox::Vector<ox::FileAddress> const&tilesheets,
|
||||
ox::SmallMap<uint64_t, WorldObjectSet> const&objSets,
|
||||
ox::Vector<ObjTileRefSet> &rsrcs,
|
||||
uint16_t &cbbIt,
|
||||
DocObjRef const&docObjRef) noexcept {
|
||||
if (!docObjRef.unique) {
|
||||
auto const [out, err] = cache.at(docObjRef);
|
||||
if (!err) {
|
||||
return *out;
|
||||
}
|
||||
}
|
||||
OX_REQUIRE(objSet, objSets.at(docObjRef.worldObjectSetId));
|
||||
auto const obj = ox::find_if(
|
||||
objSet->objects.begin(), objSet->objects.end(),
|
||||
[&docObjRef](WorldObject const&o) {
|
||||
return o.id == docObjRef.worldObjectId;
|
||||
});
|
||||
if (obj == objSet->objects.end()) {
|
||||
return ox::Error{obj == objSet->objects.end(), "could not find WorldObject in WorldObjectSet"};
|
||||
}
|
||||
OX_REQUIRE(ts, keel::readObj<ncore::TileSheet>(kctx, objSet->tilesheet));
|
||||
OX_REQUIRE(tsIdx, ox::findIdx(
|
||||
tilesheets.begin(), tilesheets.end(), objSet->tilesheet).to<uint8_t>());
|
||||
auto const subsheetOffset = ncore::getTileIdx(*ts, obj->subsheetId);
|
||||
if (!subsheetOffset) {
|
||||
return ox::Error{1, "invalid subsheet idx"};
|
||||
}
|
||||
auto const subsheet = ncore::getSubsheet(*ts, obj->subsheetId);
|
||||
if (!subsheet) {
|
||||
return ox::Error{1, "could not find subsheet"};
|
||||
}
|
||||
auto const out = static_cast<uint8_t>(rsrcs.size());
|
||||
auto const&refSet = rsrcs.emplace_back(ObjTileRefSet{
|
||||
.palBank = obj->palBank,
|
||||
.tilesheetIdx = static_cast<uint16_t>(*subsheetOffset),
|
||||
.cbbIdx = cbbIt,
|
||||
.tilesheetId = tsIdx,
|
||||
.tileCnt = static_cast<uint8_t>(subsheet->size()),
|
||||
});
|
||||
cbbIt += refSet.tileCnt;
|
||||
if (!docObjRef.unique) {
|
||||
cache[docObjRef] = out;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool isValid(WorldStatic const&ws) noexcept {
|
||||
auto const tileCnt = static_cast<size_t>(ws.columns * ws.rows);
|
||||
return ox::all_of(ws.map.begin(), ws.map.end(), [tileCnt](auto &v) {
|
||||
return v.tiles.size() == tileCnt;
|
||||
});
|
||||
ox::Result<WorldStatic> loadWorldStatic(
|
||||
keel::Context &kctx,
|
||||
ObjectCache const&objCache,
|
||||
WorldDoc const&doc) noexcept {
|
||||
auto const tilesPerLayer =
|
||||
static_cast<size_t>(doc.columns) * static_cast<size_t>(doc.rows);
|
||||
ox::SmallMap<uint64_t, WorldObjectSet> objSets;
|
||||
for (auto const&setRef : doc.objSets) {
|
||||
auto [set, err] =
|
||||
keel::readObj<WorldObjectSet>(kctx, setRef.path);
|
||||
if (!err) {
|
||||
objSets[setRef.id] = *set;
|
||||
}
|
||||
}
|
||||
ox::Result<WorldStatic> result = WorldStatic{
|
||||
.tilesheetSet = objCache.tilesheetSet(),
|
||||
.objTileRefSets = {},
|
||||
.tilesheets = objCache.tilesheets(),
|
||||
.palettes = objCache.palettes(),
|
||||
.columns = static_cast<int16_t>(doc.columns),
|
||||
.rows = static_cast<int16_t>(doc.rows),
|
||||
.map = {
|
||||
{.tiles = ox::Vector<TileStatic>{tilesPerLayer},},
|
||||
{.tiles = ox::Vector<TileStatic>{tilesPerLayer},},
|
||||
{.tiles = ox::Vector<TileStatic>{tilesPerLayer},},
|
||||
},
|
||||
};
|
||||
auto &out = result.value;
|
||||
ox::SmallMap<DocObjRef, uint8_t> refSetCache;
|
||||
uint16_t cbbIt = 4;
|
||||
// tiles
|
||||
for (auto lyr = 0u; lyr < layers(out); ++lyr) {
|
||||
for (auto x = 0u; x < static_cast<size_t>(out.columns); ++x) {
|
||||
for (auto y = 0u; y < static_cast<size_t>(out.rows); ++y) {
|
||||
auto &dst = tile(out, lyr, x, y);
|
||||
auto &src = tile(doc, lyr, x, y);;
|
||||
loadTile(dst, src);
|
||||
auto const refSetIdx = setupTileResrc(
|
||||
refSetCache,
|
||||
kctx,
|
||||
out.tilesheets,
|
||||
objSets,
|
||||
out.objTileRefSets,
|
||||
cbbIt,
|
||||
src.obj);
|
||||
if (refSetIdx.ok()) {
|
||||
dst.objIdxRefSet = refSetIdx.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user