[jasper/world] Cleanup, add frames to WorldObjectSetEditor
All checks were successful
Build / build (push) Successful in 3m42s

This commit is contained in:
Gary Talent 2025-01-12 01:05:50 -06:00
parent 2b9609e308
commit 953edfa64a
8 changed files with 104 additions and 227 deletions

View File

@ -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)

View File

@ -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

View File

@ -11,6 +11,7 @@ enum class WorldObjCommand {
AddObject,
RmObject,
EditObjectName,
EditObjectFrames,
EditObjectInterval,
EditObjectPalette,
EditObjectSubSheet,

View File

@ -1,154 +0,0 @@
/*
* Copyright 2023 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include "commands.hpp"
#include "editobject.hpp"
#include <utility>
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<int>(WorldObjCommand::EditObjectName);
}
bool EditObjectName::mergeWith(UndoCommand &cmd) noexcept {
auto const en = dynamic_cast<EditObjectName const*>(&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<int>(WorldObjCommand::EditObjectInterval);
}
bool EditObjectInterval::mergeWith(UndoCommand &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(
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<int>(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<int>(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<int>(WorldObjCommand::EditObjectCollisionMap);
}
}

View File

@ -10,78 +10,100 @@
#include <jasper/world/worldobject.hpp>
#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<ValType>) {
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<ValType>) {
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<int>(cmd);
}
bool mergeWith(UndoCommand &undoCmd) noexcept override {
if constexpr(hasMerge) {
auto const c = dynamic_cast<EditObject const*>(&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;
};
}

View File

@ -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<EditObjectPalette>(
m_doc, m_selectedObj, static_cast<uint16_t>(m_objEditor.palette));
}
if (ImGui::InputInt("Frames", &m_objEditor.frames, 1)) {
m_objEditor.frames = ox::max(m_objEditor.frames, 1);
std::ignore = pushCommand<EditObjectFrames>(
m_doc, m_selectedObj, static_cast<uint8_t>(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<EditObjectInterval>(
@ -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<int>(i));
ig::IDStackItem const idStackItem{static_cast<int>(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);

View File

@ -4,7 +4,6 @@
#pragma once
#include <turbine/context.hpp>
#include <studio/studio.hpp>
#include <jasper/world/worldobject.hpp>
@ -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;

View File

@ -156,6 +156,7 @@ ox::Result<uint8_t> WorldStaticLoader::setupTileResrc(DocObjRef const&docObjRef)
.cbbIdx = m_cbbIt,
.tilesheetId = tsIdx,
.tileCnt = static_cast<uint8_t>(subsheet->size()),
.frames = obj->frames,
});
m_cbbIt += refSet.tileCnt;
m_resourcesChanged = true;