/* * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include #include #include #include #include #include "tilesheeteditor.hpp" namespace nostalgia::core { TileSheetEditor::TileSheetEditor(Context *ctx, const ox::String &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() { } void TileSheetEditor::copy() { } void TileSheetEditor::paste() { } 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_updated = false; } 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); 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); } 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); m_scrollOffset.x += wheelh * 0.1f; 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 { auto [x, y] = clickPos; 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 = geo::Point(static_cast(x * 2), static_cast(y * 2)); const uint8_t palIdx = 0; m_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; } bool TileSheetEditor::updated() const noexcept { return m_updated; } void TileSheetEditor::ackUpdate() noexcept { m_updated = false; } 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); } } }