[nostalgia/core/studio] Add scrolling support to TileSheetEditor
This commit is contained in:
@@ -7,7 +7,9 @@
|
||||
#include <imgui.h>
|
||||
|
||||
#include <nostalgia/common/point.hpp>
|
||||
#include <nostalgia/core/consts.hpp>
|
||||
#include <nostalgia/core/media.hpp>
|
||||
#include <nostalgia/core/ptidxconv.hpp>
|
||||
|
||||
#include "tilesheeteditor.hpp"
|
||||
|
||||
@@ -15,12 +17,11 @@ namespace nostalgia::core {
|
||||
|
||||
TileSheetEditor::TileSheetEditor(Context *ctx, const ox::String &path) {
|
||||
m_itemPath = path;
|
||||
const auto lastSlash = std::find(m_itemPath.crbegin(), m_itemPath.crend(), '/').offset();
|
||||
const auto lastSlash = std::find(m_itemPath.rbegin(), m_itemPath.rend(), '/').offset();
|
||||
m_itemName = m_itemPath.substr(lastSlash + 1);
|
||||
m_ctx = ctx;
|
||||
// build shaders
|
||||
oxThrowError(m_pixels.buildShader());
|
||||
oxThrowError(m_pixelGrid.buildShader());
|
||||
oxThrowError(m_pixelsDrawer.buildShader());
|
||||
oxThrowError(m_pixelGridDrawer.buildShader());
|
||||
oxRequireT(img, readObj<NostalgiaGraphic>(ctx, m_itemPath.c_str()));
|
||||
oxThrowError(readObj<NostalgiaPalette>(ctx, img->defaultPalette).moveTo(&m_pal));
|
||||
m_img = *img;
|
||||
@@ -47,36 +48,56 @@ void TileSheetEditor::paste() {
|
||||
}
|
||||
|
||||
void TileSheetEditor::draw(core::Context*) noexcept {
|
||||
const auto size = ImGui::GetContentRegionAvail();
|
||||
const auto sizei = common::Size(static_cast<int>(size.x), static_cast<int>(size.y));
|
||||
if (m_updated || m_framebuffer.width != sizei.width || m_framebuffer.height != sizei.height) {
|
||||
if (!m_framebuffer) {
|
||||
m_framebuffer = glutils::generateFrameBuffer(sizei.width, sizei.height);
|
||||
}
|
||||
m_pixels.initBufferSet(m_img, *m_pal);
|
||||
m_pixelGrid.initBufferSet(m_img);
|
||||
const auto paneSize = ImGui::GetContentRegionAvail();
|
||||
const auto sizei = common::Size(static_cast<int>(paneSize.x), static_cast<int>(paneSize.y));
|
||||
if (m_framebuffer.width != sizei.width || m_framebuffer.height != sizei.height) {
|
||||
m_framebuffer = glutils::generateFrameBuffer(sizei.width, sizei.height);
|
||||
m_pixelsDrawer.initBufferSet(m_img, *m_pal);
|
||||
m_pixelGridDrawer.initBufferSet(m_img);
|
||||
} else if (m_updated) {
|
||||
m_pixelsDrawer.initBufferSet(m_img, *m_pal);
|
||||
m_pixelGridDrawer.initBufferSet(m_img);
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
|
||||
glViewport(0, 0, sizei.width, sizei.height);
|
||||
glDraw();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
ImGui::Image(reinterpret_cast<void*>(m_framebuffer.color.id), size, ImVec2(0, 1), ImVec2(1, 0));
|
||||
ImGui::Image(reinterpret_cast<void*>(m_framebuffer.color.id), paneSize, ImVec2(0, 1), ImVec2(1, 0));
|
||||
// handle input, this must come after drawing
|
||||
if (ImGui::IsItemHovered()) {
|
||||
const auto &io = ImGui::GetIO();
|
||||
const auto wheel = io.MouseWheel * 0.01f;
|
||||
const auto zoomMod = ox::defines::OS == ox::defines::OS::Darwin ? io.KeySuper : io.KeyCtrl;
|
||||
if (zoomMod && wheel != 0) {
|
||||
m_pixelSizeMod = ox::clamp(m_pixelSizeMod + wheel, 0.55f, 2.f);
|
||||
m_pixels.setPixelSizeMod(m_pixelSizeMod);
|
||||
m_pixelGrid.setPixelSizeMod(m_pixelSizeMod);
|
||||
m_updated = true;
|
||||
const auto wheel = io.MouseWheel;
|
||||
const auto wheelh = io.MouseWheelH;
|
||||
if (wheel != 0) {
|
||||
const auto zoomMod = ox::defines::OS == ox::defines::OS::Darwin ? io.KeySuper : io.KeyCtrl;
|
||||
const auto pixelSize = m_pixelsDrawer.pixelSize(paneSize);
|
||||
const ImVec2 sheetSize(pixelSize.x * static_cast<float>(m_img.columns) * TileWidth,
|
||||
pixelSize.y * static_cast<float>(m_img.rows) * TileHeight);
|
||||
if (zoomMod) {
|
||||
m_pixelSizeMod = ox::clamp(m_pixelSizeMod + wheel * 0.02f, 0.55f, 2.f);
|
||||
m_pixelsDrawer.setPixelSizeMod(m_pixelSizeMod);
|
||||
m_pixelGridDrawer.setPixelSizeMod(m_pixelSizeMod);
|
||||
m_updated = true;
|
||||
} else {
|
||||
m_scrollOffset.y -= wheel * 0.1f;
|
||||
}
|
||||
// adjust scroll offset in both cases because the image can be zoomed
|
||||
// or scrolled off screen
|
||||
m_scrollOffset.y = ox::clamp(m_scrollOffset.y, 0.f, sheetSize.y / 2);
|
||||
}
|
||||
if (io.MouseClicked[0]) {
|
||||
auto clickPos = io.MouseClickedPos[0];
|
||||
if (wheelh != 0) {
|
||||
const auto pixelSize = m_pixelsDrawer.pixelSize(paneSize);
|
||||
const ImVec2 sheetSize(pixelSize.x * static_cast<float>(m_img.columns) * TileWidth,
|
||||
pixelSize.y * static_cast<float>(m_img.rows) * TileHeight);
|
||||
m_scrollOffset.x += wheelh * 0.1f;
|
||||
m_scrollOffset.x = ox::clamp(m_scrollOffset.x, -(sheetSize.x / 2), 0.f);
|
||||
}
|
||||
if (io.MouseDown[0]) {
|
||||
auto clickPos = io.MousePos;
|
||||
const auto &winPos = ImGui::GetWindowPos();
|
||||
clickPos.x -= winPos.x;
|
||||
clickPos.y -= winPos.y;
|
||||
std::cout << clickPos.x - 8 << ", " << clickPos.y - 31 << '\n';
|
||||
clickPos.x -= winPos.x + 8;
|
||||
clickPos.y -= winPos.y + 31;
|
||||
clickPixel(paneSize, clickPos.x, clickPos.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,8 +107,8 @@ void TileSheetEditor::glDraw() noexcept {
|
||||
constexpr Color32 bgColor = 0x717d7e;
|
||||
glClearColor(redf(bgColor), greenf(bgColor), bluef(bgColor), 1.f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
m_pixels.draw(m_updated);
|
||||
m_pixelGrid.draw(m_updated);
|
||||
m_pixelsDrawer.draw(m_updated, m_scrollOffset);
|
||||
m_pixelGridDrawer.draw(m_updated, m_scrollOffset);
|
||||
m_updated = false;
|
||||
//oxAssert(glGetError() == 0, "There was an OpenGL error");
|
||||
}
|
||||
@@ -95,4 +116,50 @@ void TileSheetEditor::glDraw() noexcept {
|
||||
void TileSheetEditor::saveItem() {
|
||||
}
|
||||
|
||||
void TileSheetEditor::getFillPixels(bool *pixels, common::Point pt, int oldColor) const {
|
||||
const auto tileIdx = [this](const common::Point &pt) noexcept {
|
||||
return ptToIdx(pt, m_img.columns) / PixelsPerTile;
|
||||
};
|
||||
// get points
|
||||
const auto leftPt = pt + common::Point(-1, 0);
|
||||
const auto rightPt = pt + common::Point(1, 0);
|
||||
const auto topPt = pt + common::Point(0, -1);
|
||||
const auto bottomPt = pt + common::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);
|
||||
}
|
||||
}
|
||||
|
||||
void TileSheetEditor::clickPixel(const ImVec2 &paneSize, float x, float y) noexcept {
|
||||
const auto pixDrawSz = m_pixelsDrawer.pixelSize(paneSize);
|
||||
x /= paneSize.x;
|
||||
y /= paneSize.y;
|
||||
x += m_scrollOffset.x / 2;
|
||||
y += m_scrollOffset.y / 2;
|
||||
x /= pixDrawSz.x;
|
||||
y /= pixDrawSz.y;
|
||||
const auto pt = common::Point(static_cast<int>(x * 2), static_cast<int>(y * 2));
|
||||
const uint8_t palIdx = 0;
|
||||
m_img.setPixel(pt, palIdx);
|
||||
m_updated = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user