diff --git a/src/jasper/modules/world/include/jasper/world/worldobject.hpp b/src/jasper/modules/world/include/jasper/world/worldobject.hpp index a95aa48..e9ecf26 100644 --- a/src/jasper/modules/world/include/jasper/world/worldobject.hpp +++ b/src/jasper/modules/world/include/jasper/world/worldobject.hpp @@ -33,6 +33,7 @@ struct WorldObject { uint16_t palBank{}; ncore::SubSheetId subsheetId{}; CollisionMap collisionMap{}; + uint8_t frames{}; uint8_t objectType{}; uint8_t ext1{}; uint8_t ext2{}; @@ -46,6 +47,7 @@ OX_MODEL_BEGIN(WorldObject) OX_MODEL_FIELD_RENAME(palBank, pal_bank) OX_MODEL_FIELD_RENAME(subsheetId, subsheet_id) OX_MODEL_FIELD_RENAME(collisionMap, collision_map) + OX_MODEL_FIELD(frames) OX_MODEL_FIELD_RENAME(objectType, object_type) OX_MODEL_FIELD(ext1) OX_MODEL_FIELD(ext2) diff --git a/src/jasper/modules/world/src/studio/worldobjectseteditor/CMakeLists.txt b/src/jasper/modules/world/src/studio/worldobjectseteditor/CMakeLists.txt index 141a2e7..0771f7d 100644 --- a/src/jasper/modules/world/src/studio/worldobjectseteditor/CMakeLists.txt +++ b/src/jasper/modules/world/src/studio/worldobjectseteditor/CMakeLists.txt @@ -2,7 +2,6 @@ target_sources( JasperWorld-Studio PRIVATE commands/addobject.cpp commands/rmobject.cpp - commands/editobject.cpp commands/addpalette.cpp commands/rmpalette.cpp commands/changetilesheet.cpp diff --git a/src/jasper/modules/world/src/studio/worldobjectseteditor/commands/commands.hpp b/src/jasper/modules/world/src/studio/worldobjectseteditor/commands/commands.hpp index d212146..c0bd3fb 100644 --- a/src/jasper/modules/world/src/studio/worldobjectseteditor/commands/commands.hpp +++ b/src/jasper/modules/world/src/studio/worldobjectseteditor/commands/commands.hpp @@ -11,6 +11,7 @@ enum class WorldObjCommand { AddObject, RmObject, EditObjectName, + EditObjectFrames, EditObjectInterval, EditObjectPalette, EditObjectSubSheet, diff --git a/src/jasper/modules/world/src/studio/worldobjectseteditor/commands/editobject.cpp b/src/jasper/modules/world/src/studio/worldobjectseteditor/commands/editobject.cpp deleted file mode 100644 index 41cf216..0000000 --- a/src/jasper/modules/world/src/studio/worldobjectseteditor/commands/editobject.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2023 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved. - */ - -#include "commands.hpp" -#include "editobject.hpp" - -#include - -namespace jasper::world { - -EditObjectName::EditObjectName(WorldObjectSet &doc, size_t objIdx, ox::String newName) noexcept: - m_doc(doc), - m_objIdx(objIdx), - m_oldVal(m_doc.objects[objIdx].name), - m_newVal(std::move(newName)) { -} - -ox::Error EditObjectName::redo() noexcept { - auto &obj = m_doc.objects[m_objIdx]; - obj.name = std::move(m_newVal); - return {}; -} - -ox::Error EditObjectName::undo() noexcept { - auto &obj = m_doc.objects[m_objIdx]; - m_newVal = std::move(obj.name); - obj.name = m_oldVal; - return {}; -} - -int EditObjectName::commandId() const noexcept { - return static_cast(WorldObjCommand::EditObjectName); -} - -bool EditObjectName::mergeWith(UndoCommand &cmd) noexcept { - auto const en = dynamic_cast(&cmd); - if (en && m_objIdx == en->m_objIdx) { - m_newVal = en->m_newVal; - return true; - } - return false; -} - - -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(WorldObjCommand::EditObjectInterval); -} - -bool EditObjectInterval::mergeWith(UndoCommand &cmd) noexcept { - auto const en = dynamic_cast(&cmd); - if (en && m_objIdx == en->m_objIdx) { - m_newVal = en->m_newVal; - return true; - } - return false; -} - - -EditObjectSubSheet::EditObjectSubSheet( - WorldObjectSet &doc, - size_t objIdx, - ncore::SubSheetId subSheetId) noexcept: - m_doc(doc), - m_objIdx(objIdx), - m_newVal(subSheetId), - m_oldVal(m_doc.objects[m_objIdx].subsheetId) { -} - -ox::Error EditObjectSubSheet::redo() noexcept { - auto &obj = m_doc.objects[m_objIdx]; - obj.subsheetId = m_newVal; - return {}; -} - -ox::Error EditObjectSubSheet::undo() noexcept { - auto &obj = m_doc.objects[m_objIdx]; - obj.subsheetId = m_oldVal; - return {}; -} - -int EditObjectSubSheet::commandId() const noexcept { - return static_cast(WorldObjCommand::EditObjectSubSheet); -} - - -EditObjectPalette::EditObjectPalette(WorldObjectSet &doc, size_t objIdx, uint16_t palBank) noexcept: - m_doc(doc), - m_objIdx(objIdx), - m_oldVal(m_doc.objects[m_objIdx].palBank), - m_newVal(palBank) { -} - -ox::Error EditObjectPalette::redo() noexcept { - auto &obj = m_doc.objects[m_objIdx]; - obj.palBank = m_newVal; - return {}; -} - -ox::Error EditObjectPalette::undo() noexcept { - auto &obj = m_doc.objects[m_objIdx]; - obj.palBank = m_oldVal; - return {}; -} - -[[nodiscard]] -int EditObjectPalette::commandId() const noexcept { - return static_cast(WorldObjCommand::EditObjectPalette); -} - - -EditObjectCollisionMap::EditObjectCollisionMap(WorldObjectSet &doc, size_t objIdx, CollisionMap colMap) noexcept: - m_doc(doc), - m_objIdx(objIdx), - m_oldVal(m_doc.objects[m_objIdx].collisionMap), - m_newVal(colMap) { -} - -ox::Error EditObjectCollisionMap::redo() noexcept { - auto &obj = m_doc.objects[m_objIdx]; - obj.collisionMap = m_newVal; - return {}; -} - -ox::Error EditObjectCollisionMap::undo() noexcept { - auto &obj = m_doc.objects[m_objIdx]; - obj.collisionMap = m_oldVal; - return {}; -} - -[[nodiscard]] -int EditObjectCollisionMap::commandId() const noexcept { - return static_cast(WorldObjCommand::EditObjectCollisionMap); -} - -} diff --git a/src/jasper/modules/world/src/studio/worldobjectseteditor/commands/editobject.hpp b/src/jasper/modules/world/src/studio/worldobjectseteditor/commands/editobject.hpp index 5ce9b3f..fd2393d 100644 --- a/src/jasper/modules/world/src/studio/worldobjectseteditor/commands/editobject.hpp +++ b/src/jasper/modules/world/src/studio/worldobjectseteditor/commands/editobject.hpp @@ -10,78 +10,100 @@ #include +#include "commands.hpp" + namespace jasper::world { -class EditObjectName: public studio::UndoCommand { +template< + WorldObjCommand cmd, auto getVar, auto hasMerge = false, + typename ValType = decltype([] { WorldObject o; return std::move(getVar(o)); }())> +class EditObject: public studio::UndoCommand { private: WorldObjectSet &m_doc; size_t const m_objIdx{}; - ox::String const m_oldVal{}; - ox::String m_newVal{}; + ValType const m_oldVal{}; + ValType m_newVal{}; public: - EditObjectName(WorldObjectSet &doc, size_t objIdx, ox::String newName) noexcept; - ox::Error redo() noexcept override; - ox::Error undo() noexcept override; + EditObject(WorldObjectSet &doc, size_t const objIdx, ValType newVal) noexcept: + m_doc{doc}, + m_objIdx{objIdx}, + m_oldVal{getVar(m_doc.objects[objIdx])}, + m_newVal{std::move(newVal)} {} + + ox::Error redo() noexcept override { + auto &obj = m_doc.objects[m_objIdx]; + if constexpr(!std::is_trivially_copy_assignable_v) { + getVar(obj) = std::move(m_newVal); + } else { + getVar(obj) = m_newVal; + } + return {}; + } + + ox::Error undo() noexcept override { + auto &obj = m_doc.objects[m_objIdx]; + if constexpr(!std::is_trivially_copy_assignable_v) { + m_newVal = std::move(getVar(obj)); + } + getVar(obj) = m_oldVal; + return {}; + } + [[nodiscard]] - int commandId() const noexcept override; - bool mergeWith(UndoCommand &cmd) noexcept override; + int commandId() const noexcept override { + return static_cast(cmd); + } + + bool mergeWith(UndoCommand &undoCmd) noexcept override { + if constexpr(hasMerge) { + auto const c = dynamic_cast(&undoCmd); + if (c && m_objIdx == c->m_objIdx) { + m_newVal = std::move(c->m_newVal); + return true; + } + } + return false; + } + }; -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 &cmd) noexcept override; -}; -class EditObjectSubSheet: public studio::UndoCommand { - private: - WorldObjectSet &m_doc; - size_t const m_objIdx{}; - ncore::SubSheetId const m_newVal{}; - ncore::SubSheetId const m_oldVal{}; - public: - EditObjectSubSheet(WorldObjectSet &doc, size_t objIdx, ncore::SubSheetId subSheetId) noexcept; - ox::Error redo() noexcept override; - ox::Error undo() noexcept override; - [[nodiscard]] - int commandId() const noexcept override; -}; +using EditObjectName = EditObject< + WorldObjCommand::EditObjectName, + [](WorldObject &obj) -> auto& { + return obj.name; + }, + true>; -class EditObjectPalette: public studio::UndoCommand { - private: - WorldObjectSet &m_doc; - size_t const m_objIdx{}; - uint16_t const m_oldVal{}; - uint16_t const m_newVal{}; - public: - EditObjectPalette(WorldObjectSet &doc, size_t objIdx, uint16_t palBank) noexcept; - ox::Error redo() noexcept override; - ox::Error undo() noexcept override; - [[nodiscard]] - int commandId() const noexcept override; -}; +using EditObjectFrames = EditObject< + WorldObjCommand::EditObjectFrames, + [](WorldObject &obj) -> auto& { + return obj.frames; + }>; + +using EditObjectInterval = EditObject< + WorldObjCommand::EditObjectInterval, + [](WorldObject &obj) -> auto& { + return obj.intervalMs; + }>; + +using EditObjectSubSheet = EditObject< + WorldObjCommand::EditObjectSubSheet, + [](WorldObject &obj) -> auto& { + return obj.subsheetId; + }>; + +using EditObjectPalette = EditObject< + WorldObjCommand::EditObjectPalette, + [](WorldObject &obj) -> auto& { + return obj.palBank; + }>; + +using EditObjectCollisionMap = EditObject< + WorldObjCommand::EditObjectCollisionMap, + [](WorldObject &obj) -> auto& { + return obj.collisionMap; + }>; -class EditObjectCollisionMap: public studio::UndoCommand { - private: - WorldObjectSet &m_doc; - size_t const m_objIdx{}; - CollisionMap const m_oldVal{}; - CollisionMap const m_newVal{}; - public: - EditObjectCollisionMap(WorldObjectSet &doc, size_t objIdx, CollisionMap colMap) noexcept; - ox::Error redo() noexcept override; - ox::Error undo() noexcept override; - [[nodiscard]] - int commandId() const noexcept override; -}; } diff --git a/src/jasper/modules/world/src/studio/worldobjectseteditor/worldobjectseteditor-imgui.cpp b/src/jasper/modules/world/src/studio/worldobjectseteditor/worldobjectseteditor-imgui.cpp index c5390f4..1632069 100644 --- a/src/jasper/modules/world/src/studio/worldobjectseteditor/worldobjectseteditor-imgui.cpp +++ b/src/jasper/modules/world/src/studio/worldobjectseteditor/worldobjectseteditor-imgui.cpp @@ -52,17 +52,17 @@ void WorldObjectSetEditorImGui::draw(studio::StudioContext&) noexcept { ImGui::BeginChild("Resources", {0, 0}); { { - ig::IDStackItem const idStackItem("TileSheetSelector"); + ig::IDStackItem const idStackItem{"TileSheetSelector"}; drawTileSheetSelector(); } ImGui::Separator(); { - ig::IDStackItem const idStackItem("ObjSelector"); + ig::IDStackItem const idStackItem{"ObjSelector"}; drawObjSelector(); } ImGui::Separator(); { - ig::IDStackItem const idStackItem("PaletteList"); + ig::IDStackItem const idStackItem{"PaletteList"}; drawPaletteList(); } } @@ -132,6 +132,7 @@ void WorldObjectSetEditorImGui::loadObj() noexcept { auto &nameBuff = m_objEditor.nameBuff; ox::strncpy(nameBuff.data(), obj.name.data(), nameBuff.size()); m_objEditor.palette = obj.palBank; + m_objEditor.frames = obj.frames; m_objEditor.interval = obj.intervalMs; m_subsheet = getSubsheet(*m_tileSheet, obj.subsheetId); int w = 0; @@ -160,8 +161,8 @@ static ox::Vec2 clickPos(ImVec2 const&imgSz, ImVec2 const&offset, ox::Vec2 click } void WorldObjectSetEditorImGui::drawObjEditor() noexcept { - ig::IDStackItem const idStackItem("ObjEditor"); - ig::IndentStackItem const indent1(10); + ig::IDStackItem const idStackItem{"ObjEditor"}; + ig::IndentStackItem const indent1{10}; ImGui::NewLine(); auto &nameBuff = m_objEditor.nameBuff; if (ImGui::InputText("Name", nameBuff.data(), nameBuff.size())) { @@ -177,6 +178,11 @@ void WorldObjectSetEditorImGui::drawObjEditor() noexcept { std::ignore = pushCommand( m_doc, m_selectedObj, static_cast(m_objEditor.palette)); } + if (ImGui::InputInt("Frames", &m_objEditor.frames, 1)) { + m_objEditor.frames = ox::max(m_objEditor.frames, 1); + std::ignore = pushCommand( + m_doc, m_selectedObj, static_cast(m_objEditor.frames)); + } if (ImGui::InputInt("Interval (ms)", &m_objEditor.interval, 50, 1000)) { m_objEditor.interval = ox::clamp(m_objEditor.interval, 50, 65535); std::ignore = pushCommand( @@ -197,7 +203,7 @@ void WorldObjectSetEditorImGui::drawObjEditor() noexcept { if (m_subsheet) { ImGui::NewLine(); ImGui::Text("Collision Map:"); - ig::IndentStackItem const indent2(30); + ig::IndentStackItem const indent2{30}; m_colView.draw(); auto const&fb = m_colView.framebuffer(); uintptr_t const buffId = fb.color.id; @@ -229,7 +235,7 @@ void WorldObjectSetEditorImGui::drawSubSheetNode(ncore::TileSheet::SubSheet cons auto constexpr dirFlags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; auto &obj = activeObj(); auto const selected = ss.id == obj.subsheetId ? ImGuiTreeNodeFlags_Selected : 0; - ig::IDStackItem const idStackItem(ss.name); + ig::IDStackItem const idStackItem{ss.name}; if (!ss.subsheets.empty()) { if (ImGui::TreeNodeEx(ss.name.c_str(), dirFlags)) { for (auto const&child : ss.subsheets) { @@ -246,7 +252,7 @@ void WorldObjectSetEditorImGui::drawSubSheetNode(ncore::TileSheet::SubSheet cons } void WorldObjectSetEditorImGui::drawPaletteList() noexcept { - ig::IDStackItem const idStackItem("PaletteList"); + ig::IDStackItem const idStackItem{"PaletteList"}; if (ig::PushButton("+", btnSize)) { addPalette(); } @@ -265,7 +271,7 @@ void WorldObjectSetEditorImGui::drawPaletteList() noexcept { void WorldObjectSetEditorImGui::drawPaletteListItems() noexcept { for (auto i = 0u; auto const&pal : m_doc.palettes) { - ig::IDStackItem const idStackItem(static_cast(i)); + ig::IDStackItem const idStackItem{static_cast(i)}; ImGui::TableNextRow(); ImGui::TableNextColumn(); auto const path @@ -285,7 +291,7 @@ void WorldObjectSetEditorImGui::drawAddPalettePopup() noexcept { } auto constexpr popupName = ox::CStringView("Add Palette"); auto constexpr popupSz = ImVec2{285.f, 0}; - ig::IDStackItem const idStackItem("AddPalette"); + ig::IDStackItem const idStackItem{"AddPalette"}; if (ig::BeginPopup(m_sctx.tctx, popupName, m_addPalPopup.show, popupSz)) { auto const&palettes = m_sctx.project->fileList(ncore::FileExt_npal); ig::ComboBox("Palette", palettes, m_addPalPopup.selectedIdx); diff --git a/src/jasper/modules/world/src/studio/worldobjectseteditor/worldobjectseteditor-imgui.hpp b/src/jasper/modules/world/src/studio/worldobjectseteditor/worldobjectseteditor-imgui.hpp index 4a6b164..cb24178 100644 --- a/src/jasper/modules/world/src/studio/worldobjectseteditor/worldobjectseteditor-imgui.hpp +++ b/src/jasper/modules/world/src/studio/worldobjectseteditor/worldobjectseteditor-imgui.hpp @@ -4,7 +4,6 @@ #pragma once -#include #include #include @@ -32,6 +31,7 @@ class WorldObjectSetEditorImGui: public studio::Editor { CollisionView m_colView{m_sctx}; struct { ox::Buffer nameBuff = ox::Buffer(256); + int frames{}; int interval{}; size_t palette{}; } m_objEditor; diff --git a/src/jasper/modules/world/src/worldstatic.cpp b/src/jasper/modules/world/src/worldstatic.cpp index 232afbc..d9c8bf4 100644 --- a/src/jasper/modules/world/src/worldstatic.cpp +++ b/src/jasper/modules/world/src/worldstatic.cpp @@ -156,6 +156,7 @@ ox::Result WorldStaticLoader::setupTileResrc(DocObjRef const&docObjRef) .cbbIdx = m_cbbIt, .tilesheetId = tsIdx, .tileCnt = static_cast(subsheet->size()), + .frames = obj->frames, }); m_cbbIt += refSet.tileCnt; m_resourcesChanged = true;