diff --git a/src/nostalgia/core/studio/CMakeLists.txt b/src/nostalgia/core/studio/CMakeLists.txt index 7bf32750..a0b4e724 100644 --- a/src/nostalgia/core/studio/CMakeLists.txt +++ b/src/nostalgia/core/studio/CMakeLists.txt @@ -1,6 +1,5 @@ add_library( NostalgiaCore-Studio OBJECT - #imgconv.cpp #import_tilesheet_wizard.cpp module.cpp #new_tilesheet_wizard.cpp @@ -9,8 +8,6 @@ add_library( tilesheeteditor.cpp tilesheetpixelgrid.cpp tilesheetpixels.cpp - #util.cpp - #rsrc.qrc ) if(NOT MSVC) diff --git a/src/nostalgia/core/studio/core-studio.json b/src/nostalgia/core/studio/core-studio.json deleted file mode 100644 index 98df762c..00000000 --- a/src/nostalgia/core/studio/core-studio.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "module_name": "Nostalgia Core" -} diff --git a/src/nostalgia/core/studio/tilesheeteditor.cpp b/src/nostalgia/core/studio/tilesheeteditor.cpp index c67895db..59f667f6 100644 --- a/src/nostalgia/core/studio/tilesheeteditor.cpp +++ b/src/nostalgia/core/studio/tilesheeteditor.cpp @@ -23,8 +23,8 @@ TileSheetEditor::TileSheetEditor(Context *ctx, const ox::String &path) { oxThrowError(m_pixelsDrawer.buildShader()); oxThrowError(m_pixelGridDrawer.buildShader()); oxRequireT(img, readObj(ctx, m_itemPath.c_str())); - oxThrowError(readObj(ctx, img->defaultPalette).moveTo(&m_pal)); - m_img = *img; + m_img = std::move(*img); + oxThrowError(readObj(ctx, m_img.defaultPalette).moveTo(&m_pal)); } ox::String TileSheetEditor::itemName() const noexcept { @@ -49,57 +49,16 @@ void TileSheetEditor::paste() { void TileSheetEditor::draw(core::Context*) noexcept { const auto paneSize = ImGui::GetContentRegionAvail(); - const auto sizei = common::Size(static_cast(paneSize.x), static_cast(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(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; - const auto wheelh = io.MouseWheelH; - if (wheel != 0) { - const auto zoomMod = ox::defines::OS == ox::OS::Darwin ? io.KeySuper : io.KeyCtrl; - const auto pixelSize = m_pixelsDrawer.pixelSize(paneSize); - const ImVec2 sheetSize(pixelSize.x * static_cast(m_img.columns) * TileWidth, - pixelSize.y * static_cast(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 (wheelh != 0) { - const auto pixelSize = m_pixelsDrawer.pixelSize(paneSize); - const ImVec2 sheetSize(pixelSize.x * static_cast(m_img.columns) * TileWidth, - pixelSize.y * static_cast(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 + 8; - clickPos.y -= winPos.y + 31; - clickPixel(paneSize, clickPos.x, clickPos.y); - } - } + const auto tileSheetParentSize = ImVec2(paneSize.x - m_palViewWidth, paneSize.y); + const auto fbSize = common::Vec2(tileSheetParentSize.x - 16, tileSheetParentSize.y - 16); + ImGui::BeginChild("child1", ImVec2(tileSheetParentSize.x, tileSheetParentSize.y), true); + drawTileSheet(fbSize); + ImGui::EndChild(); + ImGui::SameLine(); + // draw palette/color picker + ImGui::BeginChild("child2", ImVec2(m_palViewWidth - 8, paneSize.y), true); + drawPalettePicker(); + ImGui::EndChild(); } void TileSheetEditor::glDraw() noexcept { @@ -148,11 +107,82 @@ void TileSheetEditor::getFillPixels(bool *pixels, common::Point pt, int oldColor } } -void TileSheetEditor::clickPixel(const ImVec2 &paneSize, float x, float y) noexcept { +void TileSheetEditor::drawTileSheet(const common::Vec2 &fbSize) noexcept { + const auto fbSizei = common::Size(static_cast(fbSize.x), static_cast(fbSize.y)); + if (m_framebuffer.width != fbSizei.width || m_framebuffer.height != fbSizei.height) { + m_framebuffer = glutils::generateFrameBuffer(fbSizei.width, fbSizei.height); + m_pixelsDrawer.initBufferSet(common::Vec2(fbSize), m_img, *m_pal); + m_pixelGridDrawer.initBufferSet(common::Vec2(fbSize), m_img); + } else if (m_updated) { + m_pixelsDrawer.initBufferSet(common::Vec2(fbSize), m_img, *m_pal); + m_pixelGridDrawer.initBufferSet(common::Vec2(fbSize), m_img); + } + glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); + glViewport(0, 0, fbSizei.width, fbSizei.height); + glDraw(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + ImGui::Image(reinterpret_cast(m_framebuffer.color.id), static_cast(fbSize), 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; + const auto wheelh = io.MouseWheelH; + if (wheel != 0) { + const auto zoomMod = ox::defines::OS == ox::OS::Darwin ? io.KeySuper : io.KeyCtrl; + const auto pixelSize = m_pixelsDrawer.pixelSize(common::Vec2(fbSize)); + const ImVec2 sheetSize(pixelSize.x * static_cast(m_img.columns) * TileWidth, + pixelSize.y * static_cast(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 (wheelh != 0) { + const auto pixelSize = m_pixelsDrawer.pixelSize(common::Vec2(fbSize)); + const ImVec2 sheetSize(pixelSize.x * static_cast(m_img.columns) * TileWidth, + pixelSize.y * static_cast(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 = common::Vec2(io.MousePos); + const auto &winPos = ImGui::GetWindowPos(); + clickPos.x -= winPos.x + 10; + clickPos.y -= winPos.y + 10; + clickPixel(fbSize, clickPos); + } + } +} + +void TileSheetEditor::drawPalettePicker() noexcept { + // header + ImGui::BeginTable("PaletteTable", 2); + ImGui::TableSetupColumn("No.", 0, 0.35); + ImGui::TableSetupColumn("Color16", 0, 3); + ImGui::TableHeadersRow(); + for (auto i = 1; auto c : m_pal->colors) { + ImGui::TableNextColumn(); + ImGui::Text("%d", i); + ImGui::TableNextColumn(); + ImGui::Text("(%d, %d, %d)", red16(c), green16(c), blue16(c)); + ++i; + } + ImGui::EndTable(); +} + +void TileSheetEditor::clickPixel(const common::Vec2 &paneSize, const common::Vec2 &clickPos) noexcept { + auto [x, y] = clickPos; const auto pixDrawSz = m_pixelsDrawer.pixelSize(paneSize); x /= paneSize.x; y /= paneSize.y; - x += m_scrollOffset.x / 2; + x += -m_scrollOffset.x / 2; y += m_scrollOffset.y / 2; x /= pixDrawSz.x; y /= pixDrawSz.y; diff --git a/src/nostalgia/core/studio/tilesheeteditor.hpp b/src/nostalgia/core/studio/tilesheeteditor.hpp index 7e3e7891..8b153c9b 100644 --- a/src/nostalgia/core/studio/tilesheeteditor.hpp +++ b/src/nostalgia/core/studio/tilesheeteditor.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -106,7 +107,8 @@ class TileSheetEditor: public studio::Editor { NostalgiaGraphic m_img; AssetRef m_pal; float m_pixelSizeMod = 1; - ImVec2 m_scrollOffset; + common::Vec2 m_scrollOffset; + float m_palViewWidth = 200; public: TileSheetEditor(Context *ctx, const ox::String &path); @@ -147,7 +149,11 @@ class TileSheetEditor: public studio::Editor { [[nodiscard]] ox::String palettePath(const ox::String &palettePath) const; - void clickPixel(const ImVec2 &paneSize, float x, float y) noexcept; + void drawTileSheet(const common::Vec2 &fbSize) noexcept; + + void drawPalettePicker() noexcept; + + void clickPixel(const common::Vec2 &paneSize, const common::Vec2 &clickPos) noexcept; // slots public: diff --git a/src/nostalgia/core/studio/tilesheetpixelgrid.cpp b/src/nostalgia/core/studio/tilesheetpixelgrid.cpp index 6fe7aed6..f9b4e572 100644 --- a/src/nostalgia/core/studio/tilesheetpixelgrid.cpp +++ b/src/nostalgia/core/studio/tilesheetpixelgrid.cpp @@ -18,7 +18,7 @@ ox::Error TileSheetGrid::buildShader() noexcept { return glutils::buildShaderProgram(pixelLineVshad, pixelLineFshad, pixelLineGshad).moveTo(&m_shader); } -void TileSheetGrid::draw(bool update, const ImVec2 &scroll) noexcept { +void TileSheetGrid::draw(bool update, const common::Vec2 &scroll) noexcept { glLineWidth(3 * m_pixelSizeMod * 0.5f); glUseProgram(m_shader); glBindVertexArray(m_bufferSet.vao); @@ -30,13 +30,13 @@ void TileSheetGrid::draw(bool update, const ImVec2 &scroll) noexcept { glDrawArrays(GL_POINTS, 0, m_bufferSet.vertices.size() / VertexVboRowLength); } -void TileSheetGrid::initBufferSet(const NostalgiaGraphic &img) noexcept { +void TileSheetGrid::initBufferSet(const common::Vec2 &paneSize, const NostalgiaGraphic &img) noexcept { // vao m_bufferSet.vao = glutils::generateVertexArrayObject(); glBindVertexArray(m_bufferSet.vao); // vbo m_bufferSet.vbo = glutils::generateBuffer(); - setBufferObjects(img, &m_bufferSet); + setBufferObjects(paneSize, img, &m_bufferSet); glutils::sendVbo(m_bufferSet); // vbo layout const auto pt1Attr = static_cast(glGetAttribLocation(m_shader, "vPt1")); @@ -52,7 +52,7 @@ void TileSheetGrid::initBufferSet(const NostalgiaGraphic &img) noexcept { reinterpret_cast(4 * sizeof(float))); } -void TileSheetGrid::setBufferObject(common::Point pt1, common::Point pt2, Color32 c, float *vbo, const ImVec2 &pixSize) noexcept { +void TileSheetGrid::setBufferObject(common::Point pt1, common::Point pt2, Color32 c, float *vbo, const common::Vec2 &pixSize) noexcept { const auto x1 = static_cast(pt1.x) * pixSize.x - 1.f; const auto y1 = 1.f - static_cast(pt1.y) * pixSize.y; const auto x2 = static_cast(pt2.x) * pixSize.x - 1.f; @@ -62,8 +62,8 @@ void TileSheetGrid::setBufferObject(common::Point pt1, common::Point pt2, Color3 memcpy(vbo, vertices, sizeof(vertices)); } -void TileSheetGrid::setBufferObjects(const NostalgiaGraphic &img, glutils::BufferSet *bg) noexcept { - const auto pixSize = pixelSize(); +void TileSheetGrid::setBufferObjects(const common::Vec2 &paneSize, const NostalgiaGraphic &img, glutils::BufferSet *bg) noexcept { + const auto pixSize = pixelSize(paneSize); const auto set = [bg, pixSize](unsigned i, common::Point pt1, common::Point pt2, Color32 c) { const auto vbo = &bg->vertices[i * VertexVboLength]; setBufferObject(pt1, pt2, c, vbo, pixSize); @@ -98,7 +98,7 @@ void TileSheetGrid::setBufferObjects(const NostalgiaGraphic &img, glutils::Buffe } } -ImVec2 TileSheetGrid::pixelSize(const ImVec2 &paneSize) const noexcept { +common::Vec2 TileSheetGrid::pixelSize(const common::Vec2 &paneSize) const noexcept { const auto [sw, sh] = paneSize; constexpr float ymod = 0.35f / 10.0f; const auto xmod = ymod * sh / sw; diff --git a/src/nostalgia/core/studio/tilesheetpixelgrid.hpp b/src/nostalgia/core/studio/tilesheetpixelgrid.hpp index 3bc474a9..7e12a0a9 100644 --- a/src/nostalgia/core/studio/tilesheetpixelgrid.hpp +++ b/src/nostalgia/core/studio/tilesheetpixelgrid.hpp @@ -4,9 +4,8 @@ #pragma once -#include - #include +#include #include #include #include @@ -45,7 +44,7 @@ class TileSheetGrid { static constexpr auto GShad = R"glsl( {} layout(points) in; - layout(line_strip, max_vertices = 9) out; + layout(line_strip, max_vertices = 2) out; in vec3 gColor[]; in vec2 gPt2[]; out vec3 fColor; @@ -68,17 +67,17 @@ class TileSheetGrid { ox::Error buildShader() noexcept; - void draw(bool update, const ImVec2 &scroll) noexcept; + void draw(bool update, const common::Vec2 &scroll) noexcept; - void initBufferSet(const NostalgiaGraphic &img) noexcept; + void initBufferSet(const common::Vec2 &paneSize, const NostalgiaGraphic &img) noexcept; private: - static void setBufferObject(common::Point pt1, common::Point pt2, Color32 c, float *vbo, const ImVec2 &pixSize) noexcept; + static void setBufferObject(common::Point pt1, common::Point pt2, Color32 c, float *vbo, const common::Vec2 &pixSize) noexcept; - void setBufferObjects(const NostalgiaGraphic &img, glutils::BufferSet *bg) noexcept; + void setBufferObjects(const common::Vec2 &paneSize, const NostalgiaGraphic &img, glutils::BufferSet *bg) noexcept; [[nodiscard]] - class ImVec2 pixelSize(const ImVec2 &paneSize = ImGui::GetContentRegionAvail()) const noexcept; + common::Vec2 pixelSize(const common::Vec2 &paneSize) const noexcept; }; diff --git a/src/nostalgia/core/studio/tilesheetpixels.cpp b/src/nostalgia/core/studio/tilesheetpixels.cpp index 457b22d8..089b1c25 100644 --- a/src/nostalgia/core/studio/tilesheetpixels.cpp +++ b/src/nostalgia/core/studio/tilesheetpixels.cpp @@ -18,7 +18,7 @@ ox::Error TileSheetPixels::buildShader() noexcept { return glutils::buildShaderProgram(Vshad, Fshad).moveTo(&m_shader); } -void TileSheetPixels::draw(bool update, const ImVec2 &scroll) noexcept { +void TileSheetPixels::draw(bool update, const common::Vec2 &scroll) noexcept { glUseProgram(m_shader); glBindVertexArray(m_bufferSet.vao); if (update) { @@ -29,14 +29,14 @@ void TileSheetPixels::draw(bool update, const ImVec2 &scroll) noexcept { glDrawElements(GL_TRIANGLES, static_cast(m_bufferSet.elements.size()), GL_UNSIGNED_INT, nullptr); } -void TileSheetPixels::initBufferSet(const NostalgiaGraphic &img, const NostalgiaPalette &pal) noexcept { +void TileSheetPixels::initBufferSet(const common::Vec2 &paneSize, const NostalgiaGraphic &img, const NostalgiaPalette &pal) noexcept { // vao m_bufferSet.vao = glutils::generateVertexArrayObject(); glBindVertexArray(m_bufferSet.vao); // vbo & ebo m_bufferSet.vbo = glutils::generateBuffer(); m_bufferSet.ebo = glutils::generateBuffer(); - setBufferObjects(img, pal, &m_bufferSet); + setBufferObjects(paneSize, img, pal, &m_bufferSet); glutils::sendVbo(m_bufferSet); glutils::sendEbo(m_bufferSet); // vbo layout @@ -49,20 +49,19 @@ void TileSheetPixels::initBufferSet(const NostalgiaGraphic &img, const Nostalgia reinterpret_cast(2 * sizeof(float))); } -ImVec2 TileSheetPixels::pixelSize(const ImVec2 &paneSize) const noexcept { +common::Vec2 TileSheetPixels::pixelSize(const common::Vec2 &paneSize) const noexcept { const auto [sw, sh] = paneSize; constexpr float ymod = 0.35f / 10.0f; const auto xmod = ymod * sh / sw; return {xmod * m_pixelSizeMod, ymod * m_pixelSizeMod}; } -void TileSheetPixels::setPixelBufferObject(unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) noexcept { - const auto [xmod, ymod] = pixelSize(); +void TileSheetPixels::setPixelBufferObject(const common::Vec2 &paneSize, unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) noexcept { + const auto [xmod, ymod] = pixelSize(paneSize); x *= xmod; y *= -ymod; x -= 1.0f; y += 1.0f - ymod; - //std::cout << x << ", " << y << ", " << (x + xmod) << ", " << (y + ymod) << '\n'; const auto r = redf(color), g = greenf(color), b = bluef(color); // don't worry, these memcpys gets optimized to something much more ideal const float vertices[VertexVboLength] = { @@ -79,15 +78,15 @@ void TileSheetPixels::setPixelBufferObject(unsigned vertexRow, float x, float y, memcpy(ebo, elms, sizeof(elms)); } -void TileSheetPixels::setBufferObjects(const NostalgiaGraphic &img, const NostalgiaPalette &pal, glutils::BufferSet *bg) noexcept { - const auto setPixel = [this, bg, img, pal](std::size_t i, uint8_t p) { +void TileSheetPixels::setBufferObjects(const common::Vec2 &paneSize, const NostalgiaGraphic &img, const NostalgiaPalette &pal, glutils::BufferSet *bg) noexcept { + const auto setPixel = [this, paneSize, bg, img, pal](std::size_t i, uint8_t p) { const auto color = pal.colors[p]; - const auto pt = idxToPt(i, img.columns); + const auto pt = idxToPt(static_cast(i), img.columns); const auto fx = static_cast(pt.x); const auto fy = static_cast(pt.y); const auto vbo = &bg->vertices[i * VertexVboLength]; const auto ebo = &bg->elements[i * VertexEboLength]; - setPixelBufferObject(i * VertexVboRows, fx, fy, color, vbo, ebo); + setPixelBufferObject(paneSize, i * VertexVboRows, fx, fy, color, vbo, ebo); }; // set buffer lengths const auto width = img.columns * TileWidth; diff --git a/src/nostalgia/core/studio/tilesheetpixels.hpp b/src/nostalgia/core/studio/tilesheetpixels.hpp index d99858f5..82727c14 100644 --- a/src/nostalgia/core/studio/tilesheetpixels.hpp +++ b/src/nostalgia/core/studio/tilesheetpixels.hpp @@ -4,8 +4,7 @@ #pragma once -#include - +#include #include #include #include @@ -47,17 +46,17 @@ class TileSheetPixels { ox::Error buildShader() noexcept; - void draw(bool update, const ImVec2 &scroll) noexcept; + void draw(bool update, const common::Vec2 &scroll) noexcept; - void initBufferSet(const NostalgiaGraphic &img, const NostalgiaPalette &pal) noexcept; + void initBufferSet(const common::Vec2 &paneSize, const NostalgiaGraphic &img, const NostalgiaPalette &pal) noexcept; [[nodiscard]] - ImVec2 pixelSize(const ImVec2 &paneSize = ImGui::GetContentRegionAvail()) const noexcept; + common::Vec2 pixelSize(const common::Vec2 &paneSize) const noexcept; private: - void setPixelBufferObject(unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) noexcept; + void setPixelBufferObject(const common::Vec2 &paneS, unsigned vertexRow, float x, float y, Color16 color, float *vbo, GLuint *ebo) noexcept; - void setBufferObjects(const NostalgiaGraphic &img, const NostalgiaPalette &pal, glutils::BufferSet *bg) noexcept; + void setBufferObjects(const common::Vec2 &paneS, const NostalgiaGraphic &img, const NostalgiaPalette &pal, glutils::BufferSet *bg) noexcept; }; diff --git a/src/nostalgia/core/studio/util.cpp b/src/nostalgia/core/studio/util.cpp deleted file mode 100644 index 17cbbb1a..00000000 --- a/src/nostalgia/core/studio/util.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. - */ - -#include "util.hpp" - -namespace nostalgia::core { - -QColor toQColor(Color16 nc) { - const auto r = red32(nc); - const auto g = green32(nc); - const auto b = blue32(nc); - const auto a = alpha32(nc); - return QColor(r, g, b, a); -} - -} diff --git a/src/nostalgia/core/studio/util.hpp b/src/nostalgia/core/studio/util.hpp deleted file mode 100644 index ead7e0e8..00000000 --- a/src/nostalgia/core/studio/util.hpp +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. - */ - -#pragma once - -#include - -#include - -namespace nostalgia::core { - -[[nodiscard]] QColor toQColor(Color16 nc); - -}