[nostalgia/core/studio] Put TileSheetEditor draw command in UndoCommand
This commit is contained in:
parent
4f69f027ef
commit
d792e4c515
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user