/* * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #include #include #include "tilesheeteditormodel.hpp" namespace nostalgia::core { TileSheetEditorModel::TileSheetEditorModel(Context *ctx, const ox::String &path) { m_ctx = ctx; m_path = path; oxRequireT(img, readObj(ctx, path.c_str())); m_img = *img; oxThrowError(readObj(ctx, m_img.defaultPalette).moveTo(&m_pal)); m_undoStack.changeTriggered.connect(this, &TileSheetEditorModel::markUpdated); } void TileSheetEditorModel::cut() { } void TileSheetEditorModel::copy() { } void TileSheetEditorModel::paste() { } void TileSheetEditorModel::drawCommand(const geo::Point &pt, std::size_t palIdx) noexcept { if (m_ongoingDrawCommand) { m_updated = m_updated || m_ongoingDrawCommand->append(ptToIdx(pt, m_img.columns())); } else { const auto idx = ptToIdx(pt, m_img.columns()); if (m_img.getPixel(idx) != palIdx) { pushCommand(new DrawCommand(&m_img, idx, palIdx)); } } } void TileSheetEditorModel::endDrawCommand() noexcept { m_ongoingDrawCommand = nullptr; } bool TileSheetEditorModel::updated() const noexcept { return m_updated; } ox::Error TileSheetEditorModel::markUpdated() noexcept { m_updated = true; return OxError(0); } void TileSheetEditorModel::ackUpdate() noexcept { m_updated = false; } ox::Error TileSheetEditorModel::saveFile() noexcept { auto sctx = applicationData(m_ctx); oxReturnError(sctx->project->writeObj(m_path, &m_img)); return m_ctx->assetManager.setAsset(m_path, m_img).error; } void TileSheetEditorModel::getFillPixels(bool *pixels, const 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); } } void TileSheetEditorModel::pushCommand(studio::UndoCommand *cmd) noexcept { m_undoStack.push(cmd); m_ongoingDrawCommand = dynamic_cast(cmd); m_updated = true; } }