From 8774f1c062fa15706e4069d3314009f20cfdb395 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Sun, 13 Feb 2022 11:17:57 -0600 Subject: [PATCH] [nostalgia/core/studio] Break out TileSheetEditor application logic --- src/nostalgia/core/studio/CMakeLists.txt | 1 + .../core/studio/tilesheeteditor-imgui.cpp | 2 +- .../core/studio/tilesheeteditor-imgui.hpp | 2 +- src/nostalgia/core/studio/tilesheeteditor.cpp | 66 ++------ src/nostalgia/core/studio/tilesheeteditor.hpp | 105 ++---------- .../core/studio/tilesheeteditormodel.cpp | 50 ++++++ .../core/studio/tilesheeteditormodel.hpp | 159 ++++++++++++++++++ .../core/studio/tilesheetpixelgrid.cpp | 4 +- src/nostalgia/core/studio/tilesheetpixels.cpp | 4 +- src/nostalgia/core/studio/tilesheetpixels.hpp | 2 +- 10 files changed, 246 insertions(+), 149 deletions(-) create mode 100644 src/nostalgia/core/studio/tilesheeteditormodel.cpp create mode 100644 src/nostalgia/core/studio/tilesheeteditormodel.hpp diff --git a/src/nostalgia/core/studio/CMakeLists.txt b/src/nostalgia/core/studio/CMakeLists.txt index 9490feee..c0a36a7f 100644 --- a/src/nostalgia/core/studio/CMakeLists.txt +++ b/src/nostalgia/core/studio/CMakeLists.txt @@ -7,6 +7,7 @@ add_library( #paletteeditor.cpp tilesheeteditor-imgui.cpp tilesheeteditor.cpp + tilesheeteditormodel.cpp tilesheetpixelgrid.cpp tilesheetpixels.cpp ) diff --git a/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp b/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp index 28e659b2..8c2f06f7 100644 --- a/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp +++ b/src/nostalgia/core/studio/tilesheeteditor-imgui.cpp @@ -96,7 +96,7 @@ void TileSheetEditorImGui::drawTileSheet(const geo::Vec2 &fbSize) noexcept { } } -void TileSheetEditorImGui::drawPalettePicker() noexcept { +void TileSheetEditorImGui::drawPalettePicker() const noexcept { // header ImGui::BeginTable("PaletteTable", 2); ImGui::TableSetupColumn("No.", 0, 0.35); diff --git a/src/nostalgia/core/studio/tilesheeteditor-imgui.hpp b/src/nostalgia/core/studio/tilesheeteditor-imgui.hpp index 4d7b372b..c2120e14 100644 --- a/src/nostalgia/core/studio/tilesheeteditor-imgui.hpp +++ b/src/nostalgia/core/studio/tilesheeteditor-imgui.hpp @@ -64,7 +64,7 @@ class TileSheetEditorImGui: public studio::Editor { void drawTileSheet(const geo::Vec2 &fbSize) noexcept; - void drawPalettePicker() noexcept; + void drawPalettePicker() const noexcept; // slots public: diff --git a/src/nostalgia/core/studio/tilesheeteditor.cpp b/src/nostalgia/core/studio/tilesheeteditor.cpp index 99aed085..8dc7d1f0 100644 --- a/src/nostalgia/core/studio/tilesheeteditor.cpp +++ b/src/nostalgia/core/studio/tilesheeteditor.cpp @@ -4,22 +4,19 @@ #include -#include #include #include #include +#include #include "tilesheeteditor.hpp" namespace nostalgia::core { -TileSheetEditor::TileSheetEditor(Context *ctx, const ox::String &path) { +TileSheetEditor::TileSheetEditor(Context *ctx, const ox::String &path): m_model(ctx, path) { // build shaders oxThrowError(m_pixelsDrawer.buildShader()); oxThrowError(m_pixelGridDrawer.buildShader()); - oxRequireT(img, readObj(ctx, path.c_str())); - m_img = std::move(*img); - oxThrowError(readObj(ctx, m_img.defaultPalette).moveTo(&m_pal)); } void TileSheetEditor::cut() { @@ -37,13 +34,12 @@ void TileSheetEditor::draw() noexcept { glClear(GL_COLOR_BUFFER_BIT); m_pixelsDrawer.draw(m_updated, m_scrollOffset); m_pixelGridDrawer.draw(m_updated, m_scrollOffset); - m_updated = false; } -void TileSheetEditor::scrollV(const geo::Vec2 paneSz, float wheel, bool zoomMod) noexcept { +void TileSheetEditor::scrollV(const geo::Vec2 &paneSz, float wheel, bool zoomMod) noexcept { const auto pixelSize = m_pixelsDrawer.pixelSize(paneSz); - const ImVec2 sheetSize(pixelSize.x * static_cast(m_img.columns) * TileWidth, - pixelSize.y * static_cast(m_img.rows) * TileHeight); + const ImVec2 sheetSize(pixelSize.x * static_cast(img().columns) * TileWidth, + pixelSize.y * static_cast(img().rows) * TileHeight); if (zoomMod) { m_pixelSizeMod = ox::clamp(m_pixelSizeMod + wheel * 0.02f, 0.55f, 2.f); m_pixelsDrawer.setPixelSizeMod(m_pixelSizeMod); @@ -57,10 +53,10 @@ void TileSheetEditor::scrollV(const geo::Vec2 paneSz, float wheel, bool zoomMod) m_scrollOffset.y = ox::clamp(m_scrollOffset.y, 0.f, sheetSize.y / 2); } -void TileSheetEditor::scrollH(const geo::Vec2 paneSz, float wheelh) noexcept { +void TileSheetEditor::scrollH(const geo::Vec2 &paneSz, float wheelh) noexcept { const auto pixelSize = m_pixelsDrawer.pixelSize(paneSz); - const ImVec2 sheetSize(pixelSize.x * static_cast(m_img.columns) * TileWidth, - pixelSize.y * static_cast(m_img.rows) * TileHeight); + const ImVec2 sheetSize(pixelSize.x * static_cast(img().columns) * TileWidth, + pixelSize.y * static_cast(img().rows) * TileHeight); m_scrollOffset.x += wheelh * 0.1f; m_scrollOffset.x = ox::clamp(m_scrollOffset.x, -(sheetSize.x / 2), 0.f); } @@ -76,21 +72,13 @@ void TileSheetEditor::clickPixel(const geo::Vec2 &paneSize, const geo::Vec2 &cli y /= pixDrawSz.y; const auto pt = geo::Point(static_cast(x * 2), static_cast(y * 2)); const uint8_t palIdx = 0; - m_img.setPixel(pt, palIdx); + m_model.img().setPixel(pt, palIdx); m_updated = true; } void TileSheetEditor::resize(const geo::Vec2 &sz) noexcept { - m_pixelsDrawer.initBufferSet(sz, m_img, *m_pal); - m_pixelGridDrawer.initBufferSet(sz, m_img); -} - -const NostalgiaGraphic &TileSheetEditor::img() const { - return m_img; -} - -const NostalgiaPalette &TileSheetEditor::pal() const { - return *m_pal; + m_pixelsDrawer.initBufferSet(sz, img(), pal()); + m_pixelGridDrawer.initBufferSet(sz, img()); } bool TileSheetEditor::updated() const noexcept { @@ -104,36 +92,4 @@ void TileSheetEditor::ackUpdate() noexcept { void TileSheetEditor::saveItem() { } -void TileSheetEditor::getFillPixels(bool *pixels, geo::Point pt, int oldColor) const { - const auto tileIdx = [this](const geo::Point &pt) noexcept { - return ptToIdx(pt, m_img.columns) / PixelsPerTile; - }; - // get points - const auto leftPt = pt + geo::Point(-1, 0); - const auto rightPt = pt + geo::Point(1, 0); - const auto topPt = pt + geo::Point(0, -1); - const auto bottomPt = pt + geo::Point(0, 1); - // calculate indices - const auto idx = ptToIdx(pt, m_img.columns); - const auto leftIdx = ptToIdx(leftPt, m_img.columns); - const auto rightIdx = ptToIdx(rightPt, m_img.columns); - const auto topIdx = ptToIdx(topPt, m_img.columns); - const auto bottomIdx = ptToIdx(bottomPt, m_img.columns); - const auto tile = tileIdx(pt); - // mark pixels to update - pixels[idx % PixelsPerTile] = true; - if (!pixels[leftIdx % PixelsPerTile] && tile == tileIdx(leftPt) && m_img.pixels[leftIdx] == oldColor) { - getFillPixels(pixels, leftPt, oldColor); - } - if (!pixels[rightIdx % PixelsPerTile] && tile == tileIdx(rightPt) && m_img.pixels[rightIdx] == oldColor) { - getFillPixels(pixels, rightPt, oldColor); - } - if (!pixels[topIdx % PixelsPerTile] && tile == tileIdx(topPt) && m_img.pixels[topIdx] == oldColor) { - getFillPixels(pixels, topPt, oldColor); - } - if (!pixels[bottomIdx % PixelsPerTile] && tile == tileIdx(bottomPt) && m_img.pixels[bottomIdx] == oldColor) { - getFillPixels(pixels, bottomPt, oldColor); - } -} - } diff --git a/src/nostalgia/core/studio/tilesheeteditor.hpp b/src/nostalgia/core/studio/tilesheeteditor.hpp index 53b76892..3a167dcc 100644 --- a/src/nostalgia/core/studio/tilesheeteditor.hpp +++ b/src/nostalgia/core/studio/tilesheeteditor.hpp @@ -6,103 +6,25 @@ #include +#include #include #include -#include #include #include +#include "tilesheeteditormodel.hpp" #include "tilesheetpixelgrid.hpp" #include "tilesheetpixels.hpp" namespace nostalgia::core { -// Command IDs to use with QUndoCommand::id() -enum class CommandId { - UpdatePixel = 1, - ModPixel = 2, - UpdateDimension = 3, - InsertTile = 4, - ClipboardPaste = 5, -}; - -enum class TileSheetTool: int { - Select, - Draw, - Fill, -}; - -[[nodiscard]] -constexpr auto toString(TileSheetTool t) noexcept { - switch (t) { - case TileSheetTool::Select: - return "Select"; - case TileSheetTool::Draw: - return "Draw"; - case TileSheetTool::Fill: - return "Fill"; - } - return ""; -} - -struct PixelChunk { - static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.PixelChunk"; - static constexpr auto TypeVersion = 1; - geo::Point pt; - int size = 0; -}; - -oxModelBegin(PixelChunk) - oxModelField(pt) - oxModelField(size) -oxModelEnd() - -struct TileSheetClipboard { - static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard"; - static constexpr auto TypeVersion = 1; - - oxModelFriend(TileSheetClipboard); - - protected: - ox::Vector m_pixels; - geo::Point m_p1; - geo::Point m_p2; - - public: - void addPixel(int color); - - [[nodiscard]] - bool empty() const; - - void pastePixels(const geo::Point &pt, ox::Vector *tgt, int tgtColumns) const; - - void setPoints(const geo::Point &p1, const geo::Point &p2); - - [[nodiscard]] - geo::Point point1() const; - - [[nodiscard]] - geo::Point point2() const; - -}; - -template -constexpr ox::Error model(T *io, TileSheetClipboard *b) noexcept { - io->template setTypeInfo(); - oxReturnError(io->field("pixels", &b->m_pixels)); - oxReturnError(io->field("p1", &b->m_p1)); - oxReturnError(io->field("p2", &b->m_p2)); - return OxError(0); -} - class TileSheetEditor { private: + TileSheetEditorModel m_model; TileSheetGrid m_pixelGridDrawer; TileSheetPixels m_pixelsDrawer; bool m_updated = false; - NostalgiaGraphic m_img; - AssetRef m_pal; float m_pixelSizeMod = 1; geo::Vec2 m_scrollOffset; @@ -121,16 +43,19 @@ class TileSheetEditor { void clickPixel(const geo::Vec2 &paneSize, const geo::Vec2 &clickPos) noexcept; - void scrollV(const geo::Vec2 paneSz, float wheel, bool zoomMod) noexcept; + void scrollV(const geo::Vec2 &paneSz, float wheel, bool zoomMod) noexcept; - void scrollH(const geo::Vec2 paneSz, float wheel) noexcept; + void scrollH(const geo::Vec2 &paneSz, float wheel) noexcept; void resize(const geo::Vec2 &sz) noexcept; - const NostalgiaGraphic &img() const; + [[nodiscard]] + constexpr const NostalgiaGraphic &img() const noexcept; - const NostalgiaPalette &pal() const; + [[nodiscard]] + constexpr const NostalgiaPalette &pal() const noexcept; + [[nodiscard]] bool updated() const noexcept; void ackUpdate() noexcept; @@ -138,8 +63,6 @@ class TileSheetEditor { protected: void saveItem(); - void getFillPixels(bool *pixels, geo::Point pt, int oldColor) const; - private: void setPalette(); @@ -161,4 +84,12 @@ class TileSheetEditor { }; +constexpr const NostalgiaGraphic &TileSheetEditor::img() const noexcept { + return m_model.img(); +} + +constexpr const NostalgiaPalette &TileSheetEditor::pal() const noexcept { + return m_model.pal(); +} + } diff --git a/src/nostalgia/core/studio/tilesheeteditormodel.cpp b/src/nostalgia/core/studio/tilesheeteditormodel.cpp new file mode 100644 index 00000000..09f3aa91 --- /dev/null +++ b/src/nostalgia/core/studio/tilesheeteditormodel.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include + +#include "tilesheeteditormodel.hpp" + +namespace nostalgia::core { + +TileSheetEditorModel::TileSheetEditorModel(Context *ctx, const ox::String &path) { + // build shaders + oxRequireT(img, readObj(ctx, path.c_str())); + m_img = std::move(*img); + oxThrowError(readObj(ctx, m_img.defaultPalette).moveTo(&m_pal)); +} + +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; + }; + // get points + const auto leftPt = pt + geo::Point(-1, 0); + const auto rightPt = pt + geo::Point(1, 0); + const auto topPt = pt + geo::Point(0, -1); + const auto bottomPt = pt + geo::Point(0, 1); + // calculate indices + const auto idx = ptToIdx(pt, m_img.columns); + const auto leftIdx = ptToIdx(leftPt, m_img.columns); + const auto rightIdx = ptToIdx(rightPt, m_img.columns); + const auto topIdx = ptToIdx(topPt, m_img.columns); + const auto bottomIdx = ptToIdx(bottomPt, m_img.columns); + const auto tile = tileIdx(pt); + // mark pixels to update + pixels[idx % PixelsPerTile] = true; + if (!pixels[leftIdx % PixelsPerTile] && tile == tileIdx(leftPt) && m_img.pixels[leftIdx] == oldColor) { + getFillPixels(pixels, leftPt, oldColor); + } + if (!pixels[rightIdx % PixelsPerTile] && tile == tileIdx(rightPt) && m_img.pixels[rightIdx] == oldColor) { + getFillPixels(pixels, rightPt, oldColor); + } + if (!pixels[topIdx % PixelsPerTile] && tile == tileIdx(topPt) && m_img.pixels[topIdx] == oldColor) { + getFillPixels(pixels, topPt, oldColor); + } + if (!pixels[bottomIdx % PixelsPerTile] && tile == tileIdx(bottomPt) && m_img.pixels[bottomIdx] == oldColor) { + getFillPixels(pixels, bottomPt, oldColor); + } +} + +} \ No newline at end of file diff --git a/src/nostalgia/core/studio/tilesheeteditormodel.hpp b/src/nostalgia/core/studio/tilesheeteditormodel.hpp new file mode 100644 index 00000000..141c169c --- /dev/null +++ b/src/nostalgia/core/studio/tilesheeteditormodel.hpp @@ -0,0 +1,159 @@ +/* + * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include + +#include +#include +#include +#include +#include + +namespace nostalgia::core { + +// Command IDs to use with QUndoCommand::id() +enum class CommandId { + UpdatePixel = 1, + ModPixel = 2, + UpdateDimension = 3, + InsertTile = 4, + ClipboardPaste = 5, +}; + +enum class TileSheetTool: int { + Select, + Draw, + Fill, +}; + +[[nodiscard]] +constexpr auto toString(TileSheetTool t) noexcept { + switch (t) { + case TileSheetTool::Select: + return "Select"; + case TileSheetTool::Draw: + return "Draw"; + case TileSheetTool::Fill: + return "Fill"; + } + return ""; +} + +struct PixelChunk { + static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.PixelChunk"; + static constexpr auto TypeVersion = 1; + geo::Point pt; + int size = 0; +}; + +oxModelBegin(PixelChunk) + oxModelField(pt) + oxModelField(size) +oxModelEnd() + +struct TileSheetClipboard { + static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.studio.TileSheetClipboard"; + static constexpr auto TypeVersion = 1; + + oxModelFriend(TileSheetClipboard); + + protected: + ox::Vector m_pixels; + geo::Point m_p1; + geo::Point m_p2; + + public: + void addPixel(int color); + + [[nodiscard]] + bool empty() const; + + void pastePixels(const geo::Point &pt, ox::Vector *tgt, int tgtColumns) const; + + void setPoints(const geo::Point &p1, const geo::Point &p2); + + [[nodiscard]] + geo::Point point1() const; + + [[nodiscard]] + geo::Point point2() const; + +}; + +template +constexpr ox::Error model(T *io, TileSheetClipboard *b) noexcept { + io->template setTypeInfo(); + oxReturnError(io->field("pixels", &b->m_pixels)); + oxReturnError(io->field("p1", &b->m_p1)); + oxReturnError(io->field("p2", &b->m_p2)); + return OxError(0); +} + +class TileSheetEditorModel { + + private: + NostalgiaGraphic m_img; + AssetRef m_pal; + + public: + TileSheetEditorModel(Context *ctx, const ox::String &path); + + ~TileSheetEditorModel() = default; + + void cut(); + + void copy(); + + void paste(); + + [[nodiscard]] + constexpr const NostalgiaGraphic &img() const noexcept; + + [[nodiscard]] + constexpr NostalgiaGraphic &img() noexcept; + + [[nodiscard]] + constexpr const NostalgiaPalette &pal() const noexcept; + + protected: + void saveItem(); + + void getFillPixels(bool *pixels, geo::Point pt, int oldColor) const noexcept; + + private: + void setPalette(); + + void saveState(); + + void restoreState(); + + [[nodiscard]] + ox::String paletteName(const ox::String &palettePath) const; + + [[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 { + return m_img; +} + +constexpr NostalgiaGraphic &TileSheetEditorModel::img() noexcept { + return m_img; +} + +constexpr const NostalgiaPalette &TileSheetEditorModel::pal() const noexcept { + return *m_pal; +} + +} \ No newline at end of file diff --git a/src/nostalgia/core/studio/tilesheetpixelgrid.cpp b/src/nostalgia/core/studio/tilesheetpixelgrid.cpp index abedf1d8..d629b58f 100644 --- a/src/nostalgia/core/studio/tilesheetpixelgrid.cpp +++ b/src/nostalgia/core/studio/tilesheetpixelgrid.cpp @@ -25,9 +25,9 @@ void TileSheetGrid::draw(bool update, const geo::Vec2 &scroll) noexcept { if (update) { glutils::sendVbo(m_bufferSet); } - const auto uniformScroll = static_cast(glGetUniformLocation(m_shader, "gScroll")); + const auto uniformScroll = glGetUniformLocation(m_shader, "gScroll"); glUniform2f(uniformScroll, scroll.x, scroll.y); - glDrawArrays(GL_POINTS, 0, m_bufferSet.vertices.size() / VertexVboRowLength); + glDrawArrays(GL_POINTS, 0, static_cast(m_bufferSet.vertices.size() / VertexVboRowLength)); } void TileSheetGrid::initBufferSet(const geo::Vec2 &paneSize, const NostalgiaGraphic &img) noexcept { diff --git a/src/nostalgia/core/studio/tilesheetpixels.cpp b/src/nostalgia/core/studio/tilesheetpixels.cpp index 0b3a61a6..e2ad28e0 100644 --- a/src/nostalgia/core/studio/tilesheetpixels.cpp +++ b/src/nostalgia/core/studio/tilesheetpixels.cpp @@ -24,7 +24,7 @@ void TileSheetPixels::draw(bool update, const geo::Vec2 &scroll) noexcept { if (update) { glutils::sendVbo(m_bufferSet); } - const auto uniformScroll = static_cast(glGetUniformLocation(m_shader, "vScroll")); + const auto uniformScroll = glGetUniformLocation(m_shader, "vScroll"); glUniform2f(uniformScroll, scroll.x, scroll.y); glDrawElements(GL_TRIANGLES, static_cast(m_bufferSet.elements.size()), GL_UNSIGNED_INT, nullptr); } @@ -56,7 +56,7 @@ geo::Vec2 TileSheetPixels::pixelSize(const geo::Vec2 &paneSize) const noexcept { return {xmod * m_pixelSizeMod, ymod * m_pixelSizeMod}; } -void TileSheetPixels::setPixelBufferObject(const geo::Vec2 &paneSize, unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) noexcept { +void TileSheetPixels::setPixelBufferObject(const geo::Vec2 &paneSize, unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) const noexcept { const auto [xmod, ymod] = pixelSize(paneSize); x *= xmod; y *= -ymod; diff --git a/src/nostalgia/core/studio/tilesheetpixels.hpp b/src/nostalgia/core/studio/tilesheetpixels.hpp index 7a2c5053..a8750913 100644 --- a/src/nostalgia/core/studio/tilesheetpixels.hpp +++ b/src/nostalgia/core/studio/tilesheetpixels.hpp @@ -54,7 +54,7 @@ class TileSheetPixels { geo::Vec2 pixelSize(const geo::Vec2 &paneSize) const noexcept; private: - void setPixelBufferObject(const geo::Vec2 &paneS, unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) noexcept; + void setPixelBufferObject(const geo::Vec2 &paneS, unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) const noexcept; void setBufferObjects(const geo::Vec2 &paneS, const NostalgiaGraphic &img, const NostalgiaPalette &pal, glutils::BufferSet *bg) noexcept;