[jasper/world] Remove palette based animation system

This commit is contained in:
2024-06-04 00:25:32 -05:00
parent 97c92cac87
commit 1fc681b23e
26 changed files with 110 additions and 203 deletions

BIN
project/.DS_Store vendored

Binary file not shown.

View File

@ -9,6 +9,10 @@ O1;net.drinkingtea.ox.TypeDescriptor;1;{
"fieldName" : "name", "fieldName" : "name",
"typeId" : "net.drinkingtea.ox.BasicString#8#;1" "typeId" : "net.drinkingtea.ox.BasicString#8#;1"
}, },
{
"fieldName" : "intervalMs",
"typeId" : "B.uint16;0"
},
{ {
"fieldName" : "pal_bank", "fieldName" : "pal_bank",
"typeId" : "B.uint16;0" "typeId" : "B.uint16;0"

View File

@ -18,7 +18,7 @@ O1;net.drinkingtea.ox.TypeDescriptor;1;{
"subscriptType" : 4 "subscriptType" : 4
} }
], ],
"typeId" : "net.drinkingtea.jasper.world.PaletteCycle;1" "typeId" : "net.drinkingtea.ox.FileAddress;1"
}, },
{ {
"fieldName" : "objects", "fieldName" : "objects",

View File

@ -14,7 +14,7 @@ O1;net.drinkingtea.ox.TypeDescriptor;1;{
"subscriptType" : 4 "subscriptType" : 4
} }
], ],
"typeId" : "net.drinkingtea.jasper.world.PaletteCycle;1" "typeId" : "net.drinkingtea.ox.FileAddress;1"
}, },
{ {
"fieldName" : "columns", "fieldName" : "columns",

Binary file not shown.

Binary file not shown.

View File

@ -26,7 +26,7 @@ class ObjectCache {
ox::Vector<Obj> objects; ox::Vector<Obj> objects;
}; };
ox::Vector<ox::FileAddress> m_tilesheets; ox::Vector<ox::FileAddress> m_tilesheets;
ox::Vector<PaletteCycle> m_palettes; ox::Vector<ox::FileAddress> m_palettes;
size_t m_tileIdx{}; size_t m_tileIdx{};
size_t m_palBank{}; size_t m_palBank{};
ox::Vector<ObjSet> m_objSets; ox::Vector<ObjSet> m_objSets;
@ -42,7 +42,7 @@ class ObjectCache {
[[nodiscard]] [[nodiscard]]
ncore::TileSheetSet const&tilesheets() const noexcept; ncore::TileSheetSet const&tilesheets() const noexcept;
[[nodiscard]] [[nodiscard]]
ox::Vector<PaletteCycle> const&palettes() const noexcept; ox::Vector<ox::FileAddress> const&palettes() const noexcept;
private: private:
void addTileSheet(ox::FileAddress path, int32_t tiles) noexcept; void addTileSheet(ox::FileAddress path, int32_t tiles) noexcept;
}; };

View File

@ -16,15 +16,10 @@ namespace ncore = nostalgia::core;
class World { class World {
private: private:
struct PaletteTracker {
keel::AssetRef<ncore::CompactPalette> pal;
int page{};
};
ox::Vector<PaletteTracker, 10> m_palettes;
ncore::Context &m_nctx; ncore::Context &m_nctx;
WorldStatic const&m_worldStatic; WorldStatic const&m_worldStatic;
#ifndef OX_OS_BareMetal #ifndef OX_OS_BareMetal
turbine::TimeMs m_prevUpdateTime{}; //turbine::TimeMs m_prevUpdateTime{};
turbine::TimeMs m_nextUpdateTime{}; turbine::TimeMs m_nextUpdateTime{};
#endif #endif

View File

@ -13,19 +13,6 @@ namespace jasper::world {
namespace ncore = nostalgia::core; namespace ncore = nostalgia::core;
struct PaletteCycle {
static constexpr auto TypeName = "net.drinkingtea.jasper.world.PaletteCycle";
static constexpr auto TypeVersion = 1;
ox::FileAddress palette;
uint16_t intervalMs = 1000;
};
oxModelBegin(PaletteCycle)
oxModelField(palette)
oxModelField(intervalMs)
oxModelEnd()
using CollisionMap = uint32_t; using CollisionMap = uint32_t;
enum class ObjectType: uint8_t { enum class ObjectType: uint8_t {
@ -42,6 +29,7 @@ struct WorldObject {
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
ObjectId id{}; ObjectId id{};
ox::String name; ox::String name;
uint16_t intervalMs{};
uint16_t palBank{}; uint16_t palBank{};
ncore::SubSheetId subsheetId{}; ncore::SubSheetId subsheetId{};
CollisionMap collisionMap{}; CollisionMap collisionMap{};
@ -54,6 +42,7 @@ struct WorldObject {
oxModelBegin(WorldObject) oxModelBegin(WorldObject)
oxModelField(id) oxModelField(id)
oxModelField(name) oxModelField(name)
oxModelFieldRename(intervalMs, interval_ms)
oxModelFieldRename(palBank, pal_bank) oxModelFieldRename(palBank, pal_bank)
oxModelFieldRename(subsheetId, subsheet_id) oxModelFieldRename(subsheetId, subsheet_id)
oxModelFieldRename(collisionMap, collision_map) oxModelFieldRename(collisionMap, collision_map)
@ -80,7 +69,7 @@ struct WorldObjectSet {
// index used to assign unique IDs to objects in the set // index used to assign unique IDs to objects in the set
ObjectId objIdIdx = 0; ObjectId objIdIdx = 0;
ox::FileAddress tilesheet; ox::FileAddress tilesheet;
ox::Vector<PaletteCycle> palettes; ox::Vector<ox::FileAddress> palettes;
ox::Vector<WorldObject> objects; ox::Vector<WorldObject> objects;
}; };

View File

@ -91,7 +91,7 @@ struct WorldStatic {
constexpr static auto TypeVersion = 1; constexpr static auto TypeVersion = 1;
constexpr static auto Preloadable = true; constexpr static auto Preloadable = true;
ncore::TileSheetSet tilesheets; ncore::TileSheetSet tilesheets;
ox::Vector<PaletteCycle> palettes; ox::Vector<ox::FileAddress> palettes;
int16_t columns{}; int16_t columns{};
int16_t rows{}; int16_t rows{};
ox::Array<BgLayer, 3> map; ox::Array<BgLayer, 3> map;

View File

@ -24,7 +24,6 @@ static class: public keel::Module {
[[nodiscard]] [[nodiscard]]
ox::Vector<keel::TypeDescGenerator> types() const noexcept override { ox::Vector<keel::TypeDescGenerator> types() const noexcept override {
return { return {
keel::generateTypeDesc<PaletteCycle>,
keel::generateTypeDesc<WorldObjectSet>, keel::generateTypeDesc<WorldObjectSet>,
keel::generateTypeDesc<WorldDoc>, keel::generateTypeDesc<WorldDoc>,
keel::generateTypeDesc<WorldStatic>, keel::generateTypeDesc<WorldStatic>,

View File

@ -41,7 +41,7 @@ ox::Error ObjectCache::indexSet(
addTileSheet(objSet.tilesheet, static_cast<int32_t>(tileCnt)); addTileSheet(objSet.tilesheet, static_cast<int32_t>(tileCnt));
for (auto const&pal : objSet.palettes) { for (auto const&pal : objSet.palettes) {
m_palettes.emplace_back(pal); m_palettes.emplace_back(pal);
oxRequire(p, readObj<ncore::Palette>(kctx, pal.palette)); oxRequire(p, readObj<ncore::Palette>(kctx, pal));
m_palBank += largestPage(*p); m_palBank += largestPage(*p);
} }
return {}; return {};
@ -65,7 +65,7 @@ ncore::TileSheetSet const&ObjectCache::tilesheets() const noexcept {
return m_tilesheetSet; return m_tilesheetSet;
} }
ox::Vector<PaletteCycle> const&ObjectCache::palettes() const noexcept { ox::Vector<ox::FileAddress> const&ObjectCache::palettes() const noexcept {
return m_palettes; return m_palettes;
} }

View File

@ -431,7 +431,7 @@ ox::Error WorldEditorImGui::loadObjectSets() noexcept {
oxRequireM(os, readObj<WorldObjectSet>(kctx, set.path)); oxRequireM(os, readObj<WorldObjectSet>(kctx, set.path));
oxLogError(addDependency(os->tilesheet)); oxLogError(addDependency(os->tilesheet));
for (auto const&pal : os->palettes) { for (auto const&pal : os->palettes) {
oxLogError(addDependency(pal.palette)); oxLogError(addDependency(pal));
} }
m_objSets.emplace_back(ox::String(set.path), set.id, std::move(os)); m_objSets.emplace_back(ox::String(set.path), set.id, std::move(os));
} }

View File

@ -5,7 +5,6 @@ target_sources(
commands/editobject.cpp commands/editobject.cpp
commands/addpalette.cpp commands/addpalette.cpp
commands/rmpalette.cpp commands/rmpalette.cpp
commands/editpalette.cpp
commands/changetilesheet.cpp commands/changetilesheet.cpp
collisionmapview.cpp collisionmapview.cpp
worldobjectseteditor-imgui.cpp worldobjectseteditor-imgui.cpp

View File

@ -15,18 +15,18 @@ AddPalette::AddPalette(WorldObjectSet &doc, ox::FileAddress palAddr) noexcept:
} }
ox::Error AddPalette::redo() noexcept { ox::Error AddPalette::redo() noexcept {
m_doc.palettes.emplace_back(PaletteCycle{ m_doc.palettes.emplace_back(m_palAddr);
.palette = m_palAddr std::sort(m_doc.palettes.begin(), m_doc.palettes.end(),
}); [](ox::FileAddress const&a, ox::FileAddress const&b) {
std::sort(m_doc.palettes.begin(), m_doc.palettes.end(), [](PaletteCycle const&a, PaletteCycle const&b) { return a.getPath().or_value("") < b.getPath().or_value("");
return a.palette.getPath().or_value("") < b.palette.getPath().or_value("");
}); });
return {}; return {};
} }
ox::Error AddPalette::undo() noexcept { ox::Error AddPalette::undo() noexcept {
auto const idx = std::find_if(m_doc.palettes.begin(), m_doc.palettes.end(), [this](PaletteCycle const&v) { auto const idx = std::find_if(m_doc.palettes.begin(), m_doc.palettes.end(),
return v.palette == m_palAddr; [this](ox::FileAddress const&v) {
return v == m_palAddr;
}); });
return m_doc.palettes.erase(idx).error; return m_doc.palettes.erase(idx).error;
} }

View File

@ -11,12 +11,12 @@ enum class WorldObjCommand {
AddObject, AddObject,
RmObject, RmObject,
EditObjectName, EditObjectName,
EditObjectInterval,
EditObjectPalette, EditObjectPalette,
EditObjectSubSheet, EditObjectSubSheet,
EditObjectCollisionMap, EditObjectCollisionMap,
AddPalette, AddPalette,
RmPalette, RmPalette,
EditPalette,
ChangeTileSheet, ChangeTileSheet,
}; };

View File

@ -43,6 +43,38 @@ bool EditObjectName::mergeWith(UndoCommand const&cmd) noexcept {
} }
EditObjectInterval::EditObjectInterval(WorldObjectSet &doc, size_t objIdx, uint16_t newInterval) noexcept:
m_doc(doc),
m_objIdx(objIdx),
m_oldVal(m_doc.objects[objIdx].intervalMs),
m_newVal(newInterval) {}
ox::Error EditObjectInterval::redo() noexcept {
auto &obj = m_doc.objects[m_objIdx];
obj.intervalMs = m_newVal;
return {};
}
ox::Error EditObjectInterval::undo() noexcept {
auto &obj = m_doc.objects[m_objIdx];
obj.intervalMs = m_oldVal;
return {};
}
int EditObjectInterval::commandId() const noexcept {
return static_cast<int>(WorldObjCommand::EditObjectInterval);
}
bool EditObjectInterval::mergeWith(UndoCommand const&cmd) noexcept {
auto const en = dynamic_cast<EditObjectInterval const*>(&cmd);
if (en && m_objIdx == en->m_objIdx) {
m_newVal = en->m_newVal;
return true;
}
return false;
}
EditObjectSubSheet::EditObjectSubSheet( EditObjectSubSheet::EditObjectSubSheet(
WorldObjectSet &doc, WorldObjectSet &doc,
size_t objIdx, size_t objIdx,

View File

@ -27,6 +27,21 @@ class EditObjectName: public studio::UndoCommand {
bool mergeWith(UndoCommand const&cmd) noexcept override; bool mergeWith(UndoCommand const&cmd) noexcept override;
}; };
class EditObjectInterval: public studio::UndoCommand {
private:
WorldObjectSet &m_doc;
size_t const m_objIdx{};
uint16_t const m_oldVal{};
uint16_t m_newVal{};
public:
EditObjectInterval(WorldObjectSet &doc, size_t objIdx, uint16_t newName) noexcept;
ox::Error redo() noexcept override;
ox::Error undo() noexcept override;
[[nodiscard]]
int commandId() const noexcept override;
bool mergeWith(UndoCommand const&cmd) noexcept override;
};
class EditObjectSubSheet: public studio::UndoCommand { class EditObjectSubSheet: public studio::UndoCommand {
private: private:
WorldObjectSet &m_doc; WorldObjectSet &m_doc;

View File

@ -1,30 +0,0 @@
/*
* Copyright 2023 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "commands.hpp"
#include "editpalette.hpp"
namespace jasper::world {
EditPalette::EditPalette(PaletteCycle &doc, uint16_t interval) noexcept:
m_doc(doc),
m_oldVal(doc.intervalMs),
m_newVal(interval) {
}
ox::Error EditPalette::redo() noexcept {
m_doc.intervalMs = m_newVal;
return {};
}
ox::Error EditPalette::undo() noexcept {
m_doc.intervalMs = m_oldVal;
return {};
}
int EditPalette::commandId() const noexcept {
return static_cast<int>(WorldObjCommand::EditPalette);
}
}

View File

@ -1,28 +0,0 @@
/*
* Copyright 2023 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/fs/fs.hpp>
#include <studio/undostack.hpp>
#include <jasper/world/worldobject.hpp>
namespace jasper::world {
class EditPalette: public studio::UndoCommand {
private:
PaletteCycle &m_doc;
uint16_t const m_oldVal{};
uint16_t const m_newVal{};
public:
EditPalette(PaletteCycle &doc, uint16_t interval) noexcept;
ox::Error redo() noexcept override;
ox::Error undo() noexcept override;
[[nodiscard]]
int commandId() const noexcept override;
};
}

View File

@ -22,8 +22,9 @@ ox::Error RmPalette::redo() noexcept {
ox::Error RmPalette::undo() noexcept { ox::Error RmPalette::undo() noexcept {
m_doc.palettes.emplace_back(std::move(m_pal)); m_doc.palettes.emplace_back(std::move(m_pal));
std::sort(m_doc.palettes.begin(), m_doc.palettes.end(), [](PaletteCycle const&a, PaletteCycle const&b) { std::sort(m_doc.palettes.begin(), m_doc.palettes.end(),
return a.palette.getPath().or_value("") < b.palette.getPath().or_value(""); [](ox::FileAddress const&a, ox::FileAddress const&b) {
return a.getPath().or_value("") < b.getPath().or_value("");
}); });
return {}; return {};
} }

View File

@ -15,7 +15,7 @@ namespace jasper::world {
class RmPalette: public studio::UndoCommand { class RmPalette: public studio::UndoCommand {
private: private:
WorldObjectSet &m_doc; WorldObjectSet &m_doc;
PaletteCycle m_pal; ox::FileAddress m_pal;
size_t const m_rmIdx = 0; size_t const m_rmIdx = 0;
public: public:
RmPalette(WorldObjectSet &doc, size_t rmIdx) noexcept; RmPalette(WorldObjectSet &doc, size_t rmIdx) noexcept;

View File

@ -9,7 +9,6 @@
#include "commands/editobject.hpp" #include "commands/editobject.hpp"
#include "commands/addpalette.hpp" #include "commands/addpalette.hpp"
#include "commands/rmpalette.hpp" #include "commands/rmpalette.hpp"
#include "commands/editpalette.hpp"
#include "commands/changetilesheet.hpp" #include "commands/changetilesheet.hpp"
#include "worldobjectseteditor-imgui.hpp" #include "worldobjectseteditor-imgui.hpp"
@ -26,12 +25,12 @@ WorldObjectSetEditorImGui::WorldObjectSetEditorImGui(
Editor(path), Editor(path),
m_sctx(ctx), m_sctx(ctx),
m_itemPath(path), m_itemPath(path),
m_doc(*readObj<WorldObjectSet>(keelCtx(ctx.tctx), path).unwrapThrow()), m_doc(*readObj<WorldObjectSet>(keelCtx(m_sctx), path).unwrapThrow()),
m_tileSheet(readObj<ncore::TileSheet>(keelCtx(m_sctx.tctx), m_doc.tilesheet).unwrapThrow()) { m_tileSheet(readObj<ncore::TileSheet>(keelCtx(m_sctx), m_doc.tilesheet).unwrapThrow()) {
auto const&tilesheetList = m_sctx.project->fileList(ncore::FileExt_ng); auto const&tilesheetList = m_sctx.project->fileList(ncore::FileExt_ng);
auto &kctx = keelCtx(m_sctx.tctx); auto &kctx = keelCtx(m_sctx);
auto const [tsPath, err] = getPath(kctx, m_doc.tilesheet); auto const [tsPath, err] = getPath(kctx, m_doc.tilesheet);
if (err) { if (!err) {
m_selectedTilesheetIdx = std::find(tilesheetList.begin(), tilesheetList.end(), tsPath).offset(); m_selectedTilesheetIdx = std::find(tilesheetList.begin(), tilesheetList.end(), tsPath).offset();
} }
loadObj(); loadObj();
@ -67,7 +66,6 @@ void WorldObjectSetEditorImGui::draw(studio::StudioContext&) noexcept {
} }
ImGui::EndChild(); ImGui::EndChild();
drawAddPalettePopup(); drawAddPalettePopup();
drawEditPalettePopup();
} }
void WorldObjectSetEditorImGui::onActivated() noexcept { void WorldObjectSetEditorImGui::onActivated() noexcept {
@ -84,8 +82,8 @@ WorldObject &WorldObjectSetEditorImGui::activeObj() noexcept {
void WorldObjectSetEditorImGui::buildPaletteDisplayNameList() noexcept { void WorldObjectSetEditorImGui::buildPaletteDisplayNameList() noexcept {
m_paletteDisplayNames.clear(); m_paletteDisplayNames.clear();
for (auto i = 1u; auto const&pal : m_doc.palettes) { for (auto i = 1u; auto const&pal : m_doc.palettes) {
auto const path = keel::getPath(keelCtx(m_sctx.tctx), pal.palette).or_value("Invalid path"); auto const path = keel::getPath(keelCtx(m_sctx.tctx), pal).or_value("Invalid path");
m_paletteDisplayNames.emplace_back(ox::sfmt("{}: {} - {} ms", i, path, pal.intervalMs)); m_paletteDisplayNames.emplace_back(ox::sfmt("{}: {}", i, path));
++i; ++i;
} }
} }
@ -95,11 +93,11 @@ void WorldObjectSetEditorImGui::drawTileSheetSelector() noexcept {
auto sel = m_selectedTilesheetIdx; auto sel = m_selectedTilesheetIdx;
if (ig::ComboBox("Tile Sheet", tilesheetList, sel)) { if (ig::ComboBox("Tile Sheet", tilesheetList, sel)) {
auto const [uuid, err] = keel::pathToUuid( auto const [uuid, err] = keel::pathToUuid(
keelCtx(m_sctx.tctx), tilesheetList[m_addPalPopup.selectedIdx]); keelCtx(m_sctx.tctx), tilesheetList[sel]);
if (!err) { if (!err) {
auto const uuidUrl = ox::sfmt("uuid://{}", uuid.toString()); auto const uuidUrl = ox::sfmt("uuid://{}", uuid.toString());
std::ignore = undoStack()->push(ox::make_unique<ChangeTileSheet> std::ignore = pushCommand<ChangeTileSheet>
(m_doc, ox::FileAddress(uuidUrl), sel, m_selectedTilesheetIdx)); (m_doc, ox::FileAddress(uuidUrl), sel, m_selectedTilesheetIdx);
loadObj(); loadObj();
} }
} }
@ -115,7 +113,7 @@ void WorldObjectSetEditorImGui::drawObjSelector() noexcept {
} }
ImGui::SameLine(); ImGui::SameLine();
if (ig::PushButton("-", btnSize)) { if (ig::PushButton("-", btnSize)) {
std::ignore = undoStack()->push(ox::make_unique<RmObject>(m_doc, m_selectedObj)); std::ignore = pushCommand<RmObject>(m_doc, m_selectedObj);
} }
if (ig::ListBox("Objects", [this](size_t i) -> ox::CStringView { if (ig::ListBox("Objects", [this](size_t i) -> ox::CStringView {
return m_doc.objects[i].name; return m_doc.objects[i].name;
@ -132,6 +130,7 @@ void WorldObjectSetEditorImGui::loadObj() noexcept {
auto &nameBuff = m_objEditor.nameBuff; auto &nameBuff = m_objEditor.nameBuff;
ox::strncpy(nameBuff.data(), obj.name.data(), nameBuff.size()); ox::strncpy(nameBuff.data(), obj.name.data(), nameBuff.size());
m_objEditor.palette = obj.palBank; m_objEditor.palette = obj.palBank;
m_objEditor.interval = obj.intervalMs;
m_subsheet = getSubsheet(*m_tileSheet, obj.subsheetId); m_subsheet = getSubsheet(*m_tileSheet, obj.subsheetId);
int w = 0; int w = 0;
int h = 0; int h = 0;
@ -142,7 +141,7 @@ void WorldObjectSetEditorImGui::loadObj() noexcept {
auto const idx = getTileIdx(*m_tileSheet, obj.subsheetId); auto const idx = getTileIdx(*m_tileSheet, obj.subsheetId);
oxLogError(m_colView.setup( oxLogError(m_colView.setup(
m_doc.tilesheet, m_doc.tilesheet,
m_doc.palettes[obj.palBank].palette, m_doc.palettes[obj.palBank],
w, w,
h, h,
static_cast<uint_t>(idx), static_cast<uint_t>(idx),
@ -164,17 +163,22 @@ void WorldObjectSetEditorImGui::drawObjEditor() noexcept {
ImGui::NewLine(); ImGui::NewLine();
auto &nameBuff = m_objEditor.nameBuff; auto &nameBuff = m_objEditor.nameBuff;
if (ImGui::InputText("Name", nameBuff.data(), nameBuff.size())) { if (ImGui::InputText("Name", nameBuff.data(), nameBuff.size())) {
std::ignore = undoStack()->push(ox::make_unique<EditObjectName>( std::ignore = pushCommand<EditObjectName>(
m_doc, m_doc,
m_selectedObj, m_selectedObj,
ox::String(nameBuff.data(), ox::strnlen(nameBuff.data(), nameBuff.size())))); ox::String(nameBuff.data(), ox::strnlen(nameBuff.data(), nameBuff.size())));
} }
// SubSheet Selector // SubSheet Selector
{ {
ig::IDStackItem const subsheetSelectorStackItem("SubsheetSelector"); ig::IDStackItem const subsheetSelectorStackItem("SubsheetSelector");
if (ig::ComboBox("Palette", m_paletteDisplayNames, m_objEditor.palette)) { if (ig::ComboBox("Palette", m_paletteDisplayNames, m_objEditor.palette)) {
std::ignore = undoStack()->push(ox::make_unique<EditObjectPalette>( std::ignore = pushCommand<EditObjectPalette>(
m_doc, m_selectedObj, static_cast<uint16_t>(m_objEditor.palette))); m_doc, m_selectedObj, static_cast<uint16_t>(m_objEditor.palette));
}
if (ImGui::InputInt("Interval (ms)", &m_objEditor.interval, 50, 1000)) {
m_objEditor.interval = ox::clamp(m_objEditor.interval, 50, 65535);
std::ignore = pushCommand<EditObjectInterval>(
m_doc, m_selectedObj, static_cast<uint16_t>(m_objEditor.interval));
} }
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Subsheet:"); ImGui::Text("Subsheet:");
@ -213,8 +217,7 @@ void WorldObjectSetEditorImGui::drawObjEditor() noexcept {
auto &obj = activeObj(); auto &obj = activeObj();
auto intermediate = obj.collisionMap; auto intermediate = obj.collisionMap;
if (m_colView.click(mousePos, intermediate)) { if (m_colView.click(mousePos, intermediate)) {
std::ignore = undoStack()->push(ox::make_unique<EditObjectCollisionMap>( std::ignore = pushCommand<EditObjectCollisionMap>(m_doc, m_selectedObj, intermediate);
m_doc, m_selectedObj, intermediate));
} }
} }
} }
@ -234,7 +237,7 @@ void WorldObjectSetEditorImGui::drawSubSheetNode(ncore::TileSheet::SubSheet cons
} }
} else if (ImGui::TreeNodeEx(ss.name.c_str(), ImGuiTreeNodeFlags_Leaf | selected)) { } else if (ImGui::TreeNodeEx(ss.name.c_str(), ImGuiTreeNodeFlags_Leaf | selected)) {
if (ImGui::IsItemClicked()) { if (ImGui::IsItemClicked()) {
std::ignore = undoStack()->push(ox::make_unique<EditObjectSubSheet>(m_doc, m_selectedObj, ss.id)); std::ignore = pushCommand<EditObjectSubSheet>(m_doc, m_selectedObj, ss.id);
} }
ImGui::TreePop(); ImGui::TreePop();
} }
@ -249,14 +252,9 @@ void WorldObjectSetEditorImGui::drawPaletteList() noexcept {
if (ig::PushButton("-", btnSize)) { if (ig::PushButton("-", btnSize)) {
rmPalette(); rmPalette();
} }
ImGui::SameLine();
if (ig::PushButton("Edit")) {
editPalette();
}
constexpr auto flags = ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody; constexpr auto flags = ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
if (ImGui::BeginTable("Subsheets", 2, flags)) { if (ImGui::BeginTable("Subsheets", 1, flags)) {
ImGui::TableSetupColumn("Palette", ImGuiTableColumnFlags_NoHide); ImGui::TableSetupColumn("Palette", ImGuiTableColumnFlags_NoHide);
ImGui::TableSetupColumn("Interval", ImGuiTableColumnFlags_WidthFixed, 100);
ImGui::TableHeadersRow(); ImGui::TableHeadersRow();
drawPaletteListItems(); drawPaletteListItems();
ImGui::EndTable(); ImGui::EndTable();
@ -269,17 +267,12 @@ void WorldObjectSetEditorImGui::drawPaletteListItems() noexcept {
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
auto const path auto const path
= keel::getPath(keelCtx(m_sctx.tctx), pal.palette).or_value("Invalid path"); = keel::getPath(keelCtx(m_sctx.tctx), pal).or_value("Invalid path");
ImGui::Text("%s", path.c_str()); ImGui::Text("%s", path.c_str());
ImGui::TableNextColumn();
ImGui::Text("%d ms", pal.intervalMs);
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Selectable("##PaletteSelection", i == m_selectedPal, ImGuiSelectableFlags_SpanAllColumns)) { if (ImGui::Selectable("##PaletteSelection", i == m_selectedPal, ImGuiSelectableFlags_SpanAllColumns)) {
m_selectedPal = i; m_selectedPal = i;
} }
if (ImGui::IsMouseDoubleClicked(0) && ImGui::IsItemHovered()) {
editPalette();
}
++i; ++i;
} }
} }
@ -299,48 +292,20 @@ void WorldObjectSetEditorImGui::drawAddPalettePopup() noexcept {
keelCtx(m_sctx.tctx), palettes[m_addPalPopup.selectedIdx]); keelCtx(m_sctx.tctx), palettes[m_addPalPopup.selectedIdx]);
if (!err) { if (!err) {
auto const uuidUrl = ox::sfmt("uuid://{}", uuid.toString()); auto const uuidUrl = ox::sfmt("uuid://{}", uuid.toString());
std::ignore = undoStack()->push(ox::make_unique<AddPalette>( std::ignore = pushCommand<AddPalette>(m_doc, ox::FileAddress(uuidUrl));
m_doc, ox::FileAddress(uuidUrl)));
} }
} }
ImGui::EndPopup(); ImGui::EndPopup();
} }
} }
void WorldObjectSetEditorImGui::drawEditPalettePopup() noexcept {
if (!m_editPalPopup.show) {
return;
}
auto constexpr popupName = ox::CStringView("Edit Palette");
auto constexpr popupSz = ImVec2{300.f, 0};
ig::IDStackItem const idStackItem("EditPalette");
if (ig::BeginPopup(m_sctx.tctx, popupName, m_editPalPopup.show, popupSz)) {
auto &pal = m_doc.palettes[m_selectedPal];
ImGui::InputInt("Interval (ms)", &m_editPalPopup.intervalInputVal, 1000);
m_editPalPopup.intervalInputVal =
static_cast<uint16_t>(ox::clamp(m_editPalPopup.intervalInputVal, 0, 60000));
if (ig::PopupControlsOkCancel(popupSz.x, m_editPalPopup.show) == ig::PopupResponse::OK) {
std::ignore = undoStack()->push(ox::make_unique<EditPalette>(
pal, static_cast<uint16_t>(m_editPalPopup.intervalInputVal)));
}
ImGui::EndPopup();
}
}
void WorldObjectSetEditorImGui::addPalette() noexcept { void WorldObjectSetEditorImGui::addPalette() noexcept {
m_addPalPopup.show = true; m_addPalPopup.show = true;
m_addPalPopup.selectedIdx = 0; m_addPalPopup.selectedIdx = 0;
} }
void WorldObjectSetEditorImGui::rmPalette() noexcept { void WorldObjectSetEditorImGui::rmPalette() noexcept {
std::ignore = undoStack()->push(ox::make_unique<RmPalette>( std::ignore = pushCommand<RmPalette>(m_doc, m_selectedPal);
m_doc, m_selectedPal));
}
void WorldObjectSetEditorImGui::editPalette() noexcept {
auto &pal = m_doc.palettes[m_selectedPal];
m_editPalPopup.show = true;
m_editPalPopup.intervalInputVal = pal.intervalMs;
} }
ox::Error WorldObjectSetEditorImGui::handleCmd(studio::UndoCommand const*cmd) noexcept { ox::Error WorldObjectSetEditorImGui::handleCmd(studio::UndoCommand const*cmd) noexcept {
@ -349,8 +314,7 @@ ox::Error WorldObjectSetEditorImGui::handleCmd(studio::UndoCommand const*cmd) no
oxLogError(readObj<ncore::TileSheet>(kctx, m_doc.tilesheet).moveTo(m_tileSheet)); oxLogError(readObj<ncore::TileSheet>(kctx, m_doc.tilesheet).moveTo(m_tileSheet));
} else if ( } else if (
dynamic_cast<AddPalette const*>(cmd) || dynamic_cast<AddPalette const*>(cmd) ||
dynamic_cast<RmPalette const*>(cmd) || dynamic_cast<RmPalette const*>(cmd)) {
dynamic_cast<EditPalette const*>(cmd)) {
buildPaletteDisplayNameList(); buildPaletteDisplayNameList();
} else if (dynamic_cast<EditObjectPalette const*>(cmd)) { } else if (dynamic_cast<EditObjectPalette const*>(cmd)) {
auto const&obj = activeObj(); auto const&obj = activeObj();

View File

@ -29,13 +29,10 @@ class WorldObjectSetEditorImGui: public studio::Editor {
bool show{}; bool show{};
size_t selectedIdx{}; size_t selectedIdx{};
} m_addPalPopup; } m_addPalPopup;
struct {
bool show{};
int intervalInputVal{};
} m_editPalPopup;
CollisionView m_colView{m_sctx}; CollisionView m_colView{m_sctx};
struct { struct {
ox::Buffer nameBuff = ox::Buffer(256); ox::Buffer nameBuff = ox::Buffer(256);
int interval{};
size_t palette{}; size_t palette{};
} m_objEditor; } m_objEditor;
@ -69,14 +66,10 @@ class WorldObjectSetEditorImGui: public studio::Editor {
void drawAddPalettePopup() noexcept; void drawAddPalettePopup() noexcept;
void drawEditPalettePopup() noexcept;
void addPalette() noexcept; void addPalette() noexcept;
void rmPalette() noexcept; void rmPalette() noexcept;
void editPalette() noexcept;
ox::Error handleCmd(studio::UndoCommand const*cmd) noexcept; ox::Error handleCmd(studio::UndoCommand const*cmd) noexcept;
ox::Error saveItem() noexcept final; ox::Error saveItem() noexcept final;

View File

@ -18,11 +18,9 @@ ox::Error World::setupDisplay() noexcept {
if (m_worldStatic.palettes.empty()) { if (m_worldStatic.palettes.empty()) {
return OxError(1, "World has no palettes"); return OxError(1, "World has no palettes");
} }
m_palettes.clear(); for (auto i = 0u; auto const&palAddr : m_worldStatic.palettes) {
for (auto i = 0u; auto const&pal : m_worldStatic.palettes) { oxRequire(pal, readObj<ncore::CompactPalette>(keelCtx(m_nctx), palAddr));
auto &palRef = m_palettes.emplace_back(); oxReturnError(ncore::loadBgPalette(m_nctx, i, *pal));
oxReturnError(readObj<ncore::CompactPalette>(keelCtx(m_nctx), pal.palette).moveTo(palRef.pal));
oxReturnError(ncore::loadBgPalette(m_nctx, i, *palRef.pal));
++i; ++i;
} }
oxReturnError(ncore::loadBgTileSheet(m_nctx, 0, m_worldStatic.tilesheets)); oxReturnError(ncore::loadBgTileSheet(m_nctx, 0, m_worldStatic.tilesheets));
@ -68,15 +66,7 @@ void World::setupLayer(
} }
ox::Result<int> World::update() noexcept { ox::Result<int> World::update() noexcept {
auto const time = ticksMs(turbineCtx(m_nctx));
int expiresIn = 60'000; int expiresIn = 60'000;
for (size_t i = 0; auto const&pal : m_palettes) {
auto const interval = m_worldStatic.palettes[i].intervalMs;
auto const page = (time / interval) % pal.pal->pages.size();
expiresIn = ox::min(expiresIn, static_cast<int>(time % interval));
oxReturnError(ncore::loadBgPalette(m_nctx, i, *pal.pal, static_cast<size_t>(page)));
++i;
}
return expiresIn; return expiresIn;
} }
@ -85,22 +75,6 @@ ox::Result<int> World::editorModeUpdate() noexcept {
auto const time = ticksMs(turbineCtx(m_nctx)); auto const time = ticksMs(turbineCtx(m_nctx));
if (time >= m_nextUpdateTime) { if (time >= m_nextUpdateTime) {
turbine::TimeMs expiresIn = 60'000; turbine::TimeMs expiresIn = 60'000;
bool updated = false;
auto const elapsedSincePrev = time - m_prevUpdateTime;
for (size_t i = 0; auto &pal: m_palettes) {
auto const interval = m_worldStatic.palettes[i].intervalMs;
auto &page = pal.page;
auto const update = (elapsedSincePrev >= interval);
page += update * 1;
page %= static_cast<int>(pal.pal->pages.size());
oxReturnError(ncore::loadBgPalette(m_nctx, i, *pal.pal, static_cast<size_t>(page)));
updated = updated || update;
expiresIn = ox::min<turbine::TimeMs>(expiresIn, interval);
++i;
}
if (updated) {
m_prevUpdateTime = time;
}
m_nextUpdateTime = time + expiresIn; m_nextUpdateTime = time + expiresIn;
} }
return static_cast<int>(m_nextUpdateTime - time); return static_cast<int>(m_nextUpdateTime - time);