[nostalgia/core/studio] Put TileSheetEditor draw command in UndoCommand

This commit is contained in:
Gary Talent 2022-02-13 23:23:59 -06:00
parent 4f69f027ef
commit d792e4c515
7 changed files with 123 additions and 43 deletions

View File

@ -28,7 +28,7 @@ struct AssetContainer {
public:
template<class... Args>
explicit AssetContainer(Args&&... args): m_obj(ox::forward<Args>(args)...) {
explicit constexpr AssetContainer(Args&&... args): m_obj(ox::forward<Args>(args)...) {
}
constexpr T *get() noexcept {
@ -60,17 +60,17 @@ class AssetRef {
const AssetContainer<T> *m_ctr = nullptr;
public:
explicit AssetRef(const AssetContainer<T> *c = nullptr) noexcept: m_ctr(c) {
explicit constexpr AssetRef(const AssetContainer<T> *c = nullptr) noexcept: m_ctr(c) {
}
AssetRef(const AssetRef &h) noexcept {
constexpr AssetRef(const AssetRef &h) noexcept {
m_ctr = h.m_ctr;
if (m_ctr) {
m_ctr->incRefs();
}
}
AssetRef(AssetRef &&h) noexcept {
constexpr AssetRef(AssetRef &&h) noexcept {
m_ctr = h.m_ctr;
h.m_ctr = nullptr;
}

View File

@ -73,8 +73,7 @@ struct NostalgiaGraphic {
}
}
constexpr void setPixel(const geo::Point &pt, uint8_t palIdx) noexcept {
const auto idx = ptToIdx(pt, this->columns);
constexpr void setPixel(uint64_t idx, uint8_t palIdx) noexcept {
if (bpp == 4) {
if (idx & 1) {
pixels[idx / 2] &= 0b0000'1111 | (palIdx << 4);
@ -85,6 +84,11 @@ struct NostalgiaGraphic {
this->pixels[idx] = palIdx;
}
}
constexpr void setPixel(const geo::Point &pt, uint8_t palIdx) noexcept {
const auto idx = ptToIdx(pt, this->columns);
setPixel(idx, palIdx);
}
};
oxModelBegin(NostalgiaPalette)

View File

@ -46,7 +46,7 @@ void TileSheetEditorImGui::draw(core::Context*) noexcept {
const auto paneSize = ImGui::GetContentRegionAvail();
const auto tileSheetParentSize = ImVec2(paneSize.x - m_palViewWidth, paneSize.y);
const auto fbSize = geo::Vec2(tileSheetParentSize.x - 16, tileSheetParentSize.y - 16);
ImGui::BeginChild("child1", ImVec2(tileSheetParentSize.x, tileSheetParentSize.y), true);
ImGui::BeginChild("child1", tileSheetParentSize, true);
drawTileSheet(fbSize);
ImGui::EndChild();
ImGui::SameLine();
@ -75,8 +75,9 @@ void TileSheetEditorImGui::drawTileSheet(const geo::Vec2 &fbSize) noexcept {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
ImGui::Image(reinterpret_cast<void*>(m_framebuffer.color.id), static_cast<ImVec2>(fbSize), ImVec2(0, 1), ImVec2(1, 0));
// handle input, this must come after drawing
const auto &io = ImGui::GetIO();
const auto mousePos = geo::Vec2(io.MousePos);
if (ImGui::IsItemHovered()) {
const auto &io = ImGui::GetIO();
const auto wheel = io.MouseWheel;
const auto wheelh = io.MouseWheelH;
if (wheel != 0) {
@ -87,13 +88,16 @@ void TileSheetEditorImGui::drawTileSheet(const geo::Vec2 &fbSize) noexcept {
m_tileSheetEditor.scrollH(fbSize, wheelh);
}
if (io.MouseDown[0]) {
auto clickPos = geo::Vec2(io.MousePos);
auto clickPos = mousePos;
const auto &winPos = ImGui::GetWindowPos();
clickPos.x -= winPos.x + 10;
clickPos.y -= winPos.y + 10;
m_tileSheetEditor.clickPixel(fbSize, clickPos);
m_tileSheetEditor.hitPixel(fbSize, clickPos);
}
}
if (io.MouseReleased[0]) {
m_tileSheetEditor.releaseMouseButton();
}
}
void TileSheetEditorImGui::drawPalettePicker() const noexcept {

View File

@ -6,7 +6,6 @@
#include <nostalgia/core/consts.hpp>
#include <nostalgia/core/media.hpp>
#include <nostalgia/core/ptidxconv.hpp>
#include <nostalgia/geo/point.hpp>
#include "tilesheeteditor.hpp"
@ -32,8 +31,8 @@ void TileSheetEditor::draw() noexcept {
constexpr Color32 bgColor = 0x717d7e;
glClearColor(redf(bgColor), greenf(bgColor), bluef(bgColor), 1.f);
glClear(GL_COLOR_BUFFER_BIT);
m_pixelsDrawer.draw(m_updated, m_scrollOffset);
m_pixelGridDrawer.draw(m_updated, m_scrollOffset);
m_pixelsDrawer.draw(updated(), m_scrollOffset);
m_pixelGridDrawer.draw(updated(), m_scrollOffset);
}
void TileSheetEditor::scrollV(const geo::Vec2 &paneSz, float wheel, bool zoomMod) noexcept {
@ -61,7 +60,7 @@ void TileSheetEditor::scrollH(const geo::Vec2 &paneSz, float wheelh) noexcept {
m_scrollOffset.x = ox::clamp(m_scrollOffset.x, -(sheetSize.x / 2), 0.f);
}
void TileSheetEditor::clickPixel(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept {
void TileSheetEditor::hitPixel(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept {
auto [x, y] = clickPos;
const auto pixDrawSz = m_pixelsDrawer.pixelSize(paneSize);
x /= paneSize.x;
@ -72,8 +71,11 @@ void TileSheetEditor::clickPixel(const geo::Vec2 &paneSize, const geo::Vec2 &cli
y /= pixDrawSz.y;
const auto pt = geo::Point(static_cast<int>(x * 2), static_cast<int>(y * 2));
const uint8_t palIdx = 0;
m_model.img().setPixel(pt, palIdx);
m_updated = true;
m_model.draw(pt, palIdx);
}
void TileSheetEditor::releaseMouseButton() noexcept {
m_model.endDraw();
}
void TileSheetEditor::resize(const geo::Vec2 &sz) noexcept {
@ -82,11 +84,12 @@ void TileSheetEditor::resize(const geo::Vec2 &sz) noexcept {
}
bool TileSheetEditor::updated() const noexcept {
return m_updated;
return m_updated || m_model.updated();
}
void TileSheetEditor::ackUpdate() noexcept {
m_updated = false;
m_model.ackUpdate();
}
void TileSheetEditor::saveItem() {

View File

@ -7,7 +7,6 @@
#include <ox/model/def.hpp>
#include <nostalgia/core/gfx.hpp>
#include <nostalgia/geo/bounds.hpp>
#include <nostalgia/geo/vec.hpp>
#include <nostalgia/glutils/glutils.hpp>
#include <nostalgia/studio/studio.hpp>
@ -24,8 +23,8 @@ class TileSheetEditor {
TileSheetEditorModel m_model;
TileSheetGrid m_pixelGridDrawer;
TileSheetPixels m_pixelsDrawer;
bool m_updated = false;
float m_pixelSizeMod = 1;
bool m_updated = false;
geo::Vec2 m_scrollOffset;
public:
@ -41,7 +40,9 @@ class TileSheetEditor {
void draw() noexcept;
void clickPixel(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept;
void hitPixel(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept;
void releaseMouseButton() noexcept;
void scrollV(const geo::Vec2 &paneSz, float wheel, bool zoomMod) noexcept;

View File

@ -9,12 +9,33 @@
namespace nostalgia::core {
TileSheetEditorModel::TileSheetEditorModel(Context *ctx, const ox::String &path) {
// build shaders
oxRequireT(img, readObj<NostalgiaGraphic>(ctx, path.c_str()));
m_img = std::move(*img);
m_img = *img;
oxThrowError(readObj<NostalgiaPalette>(ctx, m_img.defaultPalette).moveTo(&m_pal));
}
void TileSheetEditorModel::draw(const geo::Point &pt, std::size_t palIdx) noexcept {
if (!m_ongoingDrawCommand) {
m_ongoingDrawCommand = new DrawCommand(&m_img, ptToIdx(pt, m_img.columns), palIdx);
m_undoStack.push(m_ongoingDrawCommand);
m_updated = true;
} else {
m_updated = m_ongoingDrawCommand->append(ptToIdx(pt, m_img.columns));
}
}
void TileSheetEditorModel::endDraw() noexcept {
m_ongoingDrawCommand = nullptr;
}
bool TileSheetEditorModel::updated() const noexcept {
return m_updated;
}
void TileSheetEditorModel::ackUpdate() noexcept {
m_updated = false;
}
void TileSheetEditorModel::getFillPixels(bool *pixels, geo::Point pt, int oldColor) const noexcept {
const auto tileIdx = [this](const geo::Point &pt) noexcept {
return ptToIdx(pt, img().columns) / PixelsPerTile;

View File

@ -6,9 +6,9 @@
#include <ox/std/string.hpp>
#include <nostalgia/geo/bounds.hpp>
#include <nostalgia/geo/vec.hpp>
#include <nostalgia/core/gfx.hpp>
#include <nostalgia/geo/point.hpp>
#include <nostalgia/geo/vec.hpp>
#include <nostalgia/glutils/glutils.hpp>
#include <nostalgia/studio/studio.hpp>
@ -49,16 +49,56 @@ struct PixelChunk {
int size = 0;
};
struct DrawCommand: public studio::UndoCommand {
private:
struct Change {
uint32_t idx = 0;
uint16_t oldPalIdx = 0;
};
NostalgiaGraphic *m_img = nullptr;
ox::Vector<Change, 8> m_changes;
int m_palIdx = 0;
public:
constexpr DrawCommand(NostalgiaGraphic *img, std::size_t idx, int palIdx) noexcept {
m_img = img;
m_changes.emplace_back(idx, m_img->pixels[idx]);
m_palIdx = palIdx;
}
constexpr bool append(std::size_t idx) noexcept {
if (m_changes.back().value.idx != idx) {
m_changes.emplace_back(idx, m_img->pixels[idx]);
m_img->setPixel(idx, m_palIdx);
return true;
}
return false;
}
void redo() noexcept override {
for (auto c : m_changes) {
m_img->setPixel(c.idx, m_palIdx);
}
}
void undo() noexcept override {
for (auto c : m_changes) {
m_img->setPixel(c.idx, c.oldPalIdx);
}
}
};
oxModelBegin(PixelChunk)
oxModelField(pt)
oxModelField(size)
oxModelEnd()
struct TileSheetClipboard {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard";
static constexpr auto TypeVersion = 1;
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard";
static constexpr auto TypeVersion = 1;
oxModelFriend(TileSheetClipboard);
oxModelFriend(TileSheetClipboard);
protected:
ox::Vector<int> m_pixels;
@ -76,27 +116,31 @@ struct TileSheetClipboard {
void setPoints(const geo::Point &p1, const geo::Point &p2);
[[nodiscard]]
geo::Point point1() const;
constexpr geo::Point point1() const noexcept {
return m_p1;
}
[[nodiscard]]
geo::Point point2() const;
constexpr geo::Point point2() const noexcept {
return m_p2;
}
};
template<typename T>
constexpr ox::Error model(T *io, TileSheetClipboard *b) noexcept {
io->template setTypeInfo<TileSheetClipboard>();
oxReturnError(io->field("pixels", &b->m_pixels));
oxReturnError(io->field("p1", &b->m_p1));
oxReturnError(io->field("p2", &b->m_p2));
return OxError(0);
}
oxModelBegin(TileSheetClipboard)
oxModelFieldRename(pixels, m_pixels)
oxModelFieldRename(p1, m_p1)
oxModelFieldRename(p2, m_p2)
oxModelEnd()
class TileSheetEditorModel {
private:
NostalgiaGraphic m_img;
AssetRef<NostalgiaPalette> m_pal;
studio::UndoStack m_undoStack;
DrawCommand *m_ongoingDrawCommand = nullptr;
bool m_updated = false;
public:
TileSheetEditorModel(Context *ctx, const ox::String &path);
@ -118,6 +162,15 @@ class TileSheetEditorModel {
[[nodiscard]]
constexpr const NostalgiaPalette &pal() const noexcept;
void draw(const geo::Point &pt, std::size_t palIdx) noexcept;
void endDraw() noexcept;
[[nodiscard]]
bool updated() const noexcept;
void ackUpdate() noexcept;
protected:
void saveItem();
@ -136,12 +189,6 @@ class TileSheetEditorModel {
[[nodiscard]]
ox::String palettePath(const ox::String &palettePath) const;
// slots
public:
ox::Error colorSelected() noexcept;
ox::Error setColorTable() noexcept;
};
constexpr const NostalgiaGraphic &TileSheetEditorModel::img() const noexcept {