[nostalgia/gfx] Move to TileSheetV5
All checks were successful
Build / build (push) Successful in 3m23s

This commit is contained in:
Gary Talent 2025-01-21 02:21:01 -06:00
parent 3c056276c1
commit f987b02c65
11 changed files with 264 additions and 153 deletions

View File

@ -5,10 +5,8 @@
#pragma once
#include <ox/fs/fs.hpp>
#include <ox/std/array.hpp>
#include <ox/std/point.hpp>
#include <ox/std/size.hpp>
#include <ox/std/span.hpp>
#include <ox/std/types.hpp>
#include <ox/model/def.hpp>
@ -290,7 +288,105 @@ constexpr ox::Error repair(TileSheetV4 &ts) noexcept {
}
using TileSheet = TileSheetV4;
struct TileSheetV5 {
using SubSheetIdx = ox::Vector<std::size_t, 4>;
struct SubSheet {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.TileSheet.SubSheet";
static constexpr auto TypeVersion = 5;
SubSheetId id = 0;
ox::String name;
int columns = 0;
int rows = 0;
ox::Vector<SubSheet> subsheets;
ox::Vector<uint8_t> pixels;
constexpr SubSheet() noexcept = default;
SubSheet(
SubSheetId const pId,
ox::StringParam pName,
int const pColumns,
int const pRows) noexcept:
id(pId),
name(std::move(pName)),
columns(pColumns),
rows(pRows),
pixels(static_cast<std::size_t>(columns * rows * PixelsPerTile)) {
}
SubSheet(
SubSheetId const pId,
ox::StringParam pName,
int const pColumns,
int const pRows,
ox::Vector<uint8_t> pPixels) noexcept:
id(pId),
name(std::move(pName)),
columns(pColumns),
rows(pRows),
pixels(std::move(pPixels)) {
}
/**
*
* @return the dimensional size of the SubSheet (e.g. width * height)
*/
[[nodiscard]]
constexpr std::size_t size() const noexcept {
return static_cast<std::size_t>(columns) * static_cast<std::size_t>(rows);
}
};
static constexpr auto TypeName = "net.drinkingtea.nostalgia.gfx.TileSheet";
static constexpr auto TypeVersion = 5;
int8_t bpp = 4;
SubSheetId idIt = 0;
ox::FileAddress defaultPalette;
SubSheet subsheet{0, "Root", 1, 1};
};
[[nodiscard]]
constexpr bool valid(TileSheetV5::SubSheet const&ss) noexcept {
if (ss.subsheets.empty()) {
return static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile) == ss.pixels.size();
} else {
return ss.pixels.empty() && ox::all_of(ss.subsheets.begin(), ss.subsheets.end(),
[](TileSheetV5::SubSheet const&s) {
return valid(s);
});
}
}
[[nodiscard]]
constexpr bool valid(TileSheetV5 const&ts) noexcept {
return (ts.bpp == 4 || ts.bpp == 8) && valid(ts.subsheet);
}
constexpr void repair(TileSheetV5::SubSheet &ss, int const bpp) noexcept {
if (ss.subsheets.empty()) {
auto const bytes = static_cast<size_t>(ss.columns * ss.rows * PixelsPerTile);
ss.pixels.resize(bytes);
} else {
ss.pixels.clear();
ss.columns = -1;
ss.rows = -1;
}
for (auto &s : ss.subsheets) {
repair(s, bpp);
}
}
constexpr ox::Error repair(TileSheetV5 &ts) noexcept {
if (ts.bpp != 4 && ts.bpp != 8) {
return ox::Error{1, "Unable to repair TileSheet"};
}
repair(ts.subsheet, ts.bpp);
return {};
}
using TileSheet = TileSheetV5;
[[nodiscard]]
std::size_t idx(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
@ -311,7 +407,7 @@ uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
uint8_t getPixel8Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
[[nodiscard]]
uint8_t getPixel(TileSheet::SubSheet const&ss, int8_t pBpp, std::size_t idx) noexcept;
uint8_t getPixel(TileSheet::SubSheet const&ss, std::size_t idx) noexcept;
[[nodiscard]]
uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
@ -320,44 +416,24 @@ uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
uint8_t getPixel8Bpp(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
[[nodiscard]]
uint8_t getPixel(TileSheet::SubSheet const&ss, int8_t pBpp, ox::Point const&pt) noexcept;
uint8_t getPixel(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept;
constexpr void walkPixels(TileSheet::SubSheet const&ss, int8_t pBpp, auto callback) noexcept {
if (pBpp == 4) {
const auto pixelCnt = ox::min<std::size_t>(
static_cast<std::size_t>(ss.columns * ss.rows * PixelsPerTile) / 2,
ss.pixels.size());
//oxAssert(pixels.size() == pixelCnt, "Pixel count does not match rows and columns");
for (std::size_t i = 0; i < pixelCnt; ++i) {
const auto colorIdx1 = static_cast<uint8_t>(ss.pixels[i] & 0xF);
const auto colorIdx2 = static_cast<uint8_t>(ss.pixels[i] >> 4);
callback(i * 2 + 0, colorIdx1);
callback(i * 2 + 1, colorIdx2);
}
} else {
const auto pixelCnt = ox::min<std::size_t>(
static_cast<std::size_t>(ss.columns * ss.rows * PixelsPerTile),
ss.pixels.size());
for (std::size_t i = 0; i < pixelCnt; ++i) {
const auto p = ss.pixels[i];
callback(i, p);
}
constexpr void walkPixels(TileSheet::SubSheet const&ss, int8_t, auto callback) noexcept {
for (std::size_t i = 0; i < ss.pixels.size(); ++i) {
callback(i, ss.pixels[i]);
}
}
void setPixel(TileSheet::SubSheet &ss, int8_t pBpp, uint64_t idx, uint8_t palIdx) noexcept;
void setPixel(TileSheet::SubSheet &ss, ox::Point const&pt, uint8_t palIdx) noexcept;
void setPixel(TileSheet::SubSheet &ss, int8_t pBpp, ox::Point const&pt, uint8_t palIdx) noexcept;
ox::Error setPixelCount(TileSheet::SubSheet &ss, int8_t pBpp, std::size_t cnt) noexcept;
ox::Error setPixelCount(TileSheet::SubSheet &ss, std::size_t cnt) noexcept;
/**
* Gets a count of the pixels in this sheet, and not that of its children.
* @param pBpp bits per pixel, need for knowing how to count the pixels
* @return a count of the pixels in this sheet
*/
[[nodiscard]]
unsigned pixelCnt(TileSheet::SubSheet const&ss, int8_t pBpp) noexcept;
unsigned pixelCnt(TileSheet::SubSheet const&ss) noexcept;
/**
*
@ -365,7 +441,7 @@ unsigned pixelCnt(TileSheet::SubSheet const&ss, int8_t pBpp) noexcept;
* @param pBpp
* @param sz size of Subsheet in tiles (not pixels)
*/
ox::Error resizeSubsheet(TileSheet::SubSheet &ss, int8_t pBpp, ox::Size const&sz) noexcept;
ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const&sz) noexcept;
/**
* validateSubSheetIdx takes a SubSheetIdx and moves the index to the
@ -522,6 +598,22 @@ OX_MODEL_BEGIN(TileSheetV4)
OX_MODEL_FIELD(subsheet)
OX_MODEL_END()
OX_MODEL_BEGIN(TileSheetV5::SubSheet)
OX_MODEL_FIELD(id)
OX_MODEL_FIELD(name)
OX_MODEL_FIELD(rows)
OX_MODEL_FIELD(columns)
OX_MODEL_FIELD(subsheets)
OX_MODEL_FIELD(pixels)
OX_MODEL_END()
OX_MODEL_BEGIN(TileSheetV5)
OX_MODEL_FIELD(bpp)
OX_MODEL_FIELD(idIt)
OX_MODEL_FIELD(defaultPalette)
OX_MODEL_FIELD(subsheet)
OX_MODEL_END()
OX_MODEL_BEGIN(CompactTileSheetV1)
OX_MODEL_FIELD(bpp)
OX_MODEL_FIELD(defaultPalette)

View File

@ -23,6 +23,7 @@ static class: public keel::Module {
TileSheetV1ToTileSheetV2Converter m_tileSheetV1ToTileSheetV2Converter;
TileSheetV2ToTileSheetV3Converter m_tileSheetV2ToTileSheetV3Converter;
TileSheetV3ToTileSheetV4Converter m_tileSheetV3ToTileSheetV4Converter;
TileSheetV4ToTileSheetV5Converter m_tileSheetV4ToTileSheetV5Converter;
TileSheetToCompactTileSheetConverter m_tileSheetToCompactTileSheetConverter;
public:
@ -38,6 +39,7 @@ static class: public keel::Module {
keel::generateTypeDesc<TileSheetV2>,
keel::generateTypeDesc<TileSheetV3>,
keel::generateTypeDesc<TileSheetV4>,
keel::generateTypeDesc<TileSheetV5>,
keel::generateTypeDesc<CompactTileSheetV1>,
keel::generateTypeDesc<PaletteV1>,
keel::generateTypeDesc<PaletteV2>,
@ -58,6 +60,7 @@ static class: public keel::Module {
&m_tileSheetV1ToTileSheetV2Converter,
&m_tileSheetV2ToTileSheetV3Converter,
&m_tileSheetV3ToTileSheetV4Converter,
&m_tileSheetV4ToTileSheetV5Converter,
&m_tileSheetToCompactTileSheetConverter,
};
}

View File

@ -133,6 +133,46 @@ ox::Error TileSheetV3ToTileSheetV4Converter::convert(
return {};
}
void TileSheetV4ToTileSheetV5Converter::convertSubsheet(
int const bpp,
TileSheetV4::SubSheet &src,
TileSheetV5::SubSheet &dst,
SubSheetId &idIt) noexcept {
dst.id = idIt;
dst.name = std::move(src.name);
dst.columns = src.columns;
dst.rows = src.rows;
if (bpp == 4) {
dst.pixels.reserve(2 * src.pixels.size());
dst.pixels.resize(0);
for (auto const p : src.pixels) {
dst.pixels.emplace_back(static_cast<uint8_t>(p & 0xf));
dst.pixels.emplace_back(static_cast<uint8_t>(p >> 4));
}
oxAssert(dst.pixels.size() == src.pixels.size() *2, "mismatch");
} else {
dst.pixels = std::move(src.pixels);
}
++idIt;
dst.subsheets.resize(src.subsheets.size());
for (auto i = 0u; i < src.subsheets.size(); ++i) {
convertSubsheet(bpp, src.subsheets[i], dst.subsheets[i], idIt);
}
}
ox::Error TileSheetV4ToTileSheetV5Converter::convert(
keel::Context&,
TileSheetV4 &src,
TileSheetV5 &dst) const noexcept {
dst.bpp = src.bpp;
dst.idIt = src.idIt;
dst.defaultPalette = std::move(src.defaultPalette);
convertSubsheet(dst.bpp, src.subsheet, dst.subsheet, dst.idIt);
return {};
}
ox::Error TileSheetToCompactTileSheetConverter::convert(
keel::Context&,
TileSheet &src,

View File

@ -56,6 +56,15 @@ class TileSheetV3ToTileSheetV4Converter: public keel::Converter<TileSheetV3, Til
ox::Error convert(keel::Context&, TileSheetV3 &src, TileSheetV4 &dst) const noexcept final;
};
class TileSheetV4ToTileSheetV5Converter final: public keel::Converter<TileSheetV4, TileSheetV5> {
static void convertSubsheet(
int bpp,
TileSheetV4::SubSheet &src,
TileSheetV5::SubSheet &dst,
SubSheetId &idIt) noexcept;
ox::Error convert(keel::Context&, TileSheetV4 &src, TileSheetV5 &dst) const noexcept override;
};
class TileSheetToCompactTileSheetConverter: public keel::Converter<TileSheet, CompactTileSheet> {
ox::Error convert(keel::Context&, TileSheet &src, CompactTileSheet &dst) const noexcept final;
};

View File

@ -28,12 +28,12 @@ ox::Error AddSubSheetCommand::redo() noexcept {
auto &parent = getSubSheet(m_img, m_parentIdx);
if (m_addedSheets.size() < 2) {
auto i = parent.subsheets.size();
parent.subsheets.emplace_back(m_img.idIt++, ox::sfmt("Subsheet {}", i), 1, 1, m_img.bpp);
parent.subsheets.emplace_back(m_img.idIt++, ox::sfmt("Subsheet {}", i), 1, 1);
} else {
parent.subsheets.emplace_back(m_img.idIt++, "Subsheet 0", parent.columns, parent.rows, std::move(parent.pixels));
parent.rows = 0;
parent.columns = 0;
parent.subsheets.emplace_back(m_img.idIt++, "Subsheet 1", 1, 1, m_img.bpp);
parent.subsheets.emplace_back(m_img.idIt++, "Subsheet 1", 1, 1);
}
return {};
}

View File

@ -38,7 +38,7 @@ CutPasteCommand::CutPasteCommand(
auto const dstPt = p.pt + dstStart;
if (dstPt.x <= dstEnd.x && dstPt.y <= dstEnd.y) {
auto const idx = gfx::idx(ss, dstPt);
m_changes.emplace_back(static_cast<uint32_t>(idx), p.colorIdx, getPixel(ss, m_img.bpp, idx));
m_changes.emplace_back(static_cast<uint32_t>(idx), p.colorIdx, getPixel(ss, idx));
}
}
}
@ -46,7 +46,7 @@ CutPasteCommand::CutPasteCommand(
ox::Error CutPasteCommand::redo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (const auto &c : m_changes) {
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(c.newPalIdx));
subsheet.pixels[c.idx] = static_cast<uint8_t>(c.newPalIdx);
}
return {};
}
@ -54,7 +54,7 @@ ox::Error CutPasteCommand::redo() noexcept {
ox::Error CutPasteCommand::undo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (const auto &c : m_changes) {
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(c.oldPalIdx));
subsheet.pixels[c.idx] = static_cast<uint8_t>(c.oldPalIdx);
}
return {};
}

View File

@ -15,7 +15,7 @@ DrawCommand::DrawCommand(
m_subSheetIdx(std::move(subSheetIdx)),
m_palIdx(palIdx) {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
m_changes.emplace_back(static_cast<uint32_t>(idx), getPixel(subsheet, m_img.bpp, idx));
m_changes.emplace_back(static_cast<uint32_t>(idx), getPixel(subsheet, idx));
}
DrawCommand::DrawCommand(
@ -28,20 +28,20 @@ DrawCommand::DrawCommand(
m_palIdx(palIdx) {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (auto const idx : idxList) {
m_changes.emplace_back(static_cast<uint32_t>(idx), getPixel(subsheet, m_img.bpp, idx));
m_changes.emplace_back(static_cast<uint32_t>(idx), getPixel(subsheet, idx));
}
}
bool DrawCommand::append(std::size_t idx) noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
if (m_changes.back().value->idx != idx && getPixel(subsheet, m_img.bpp, idx) != m_palIdx) {
if (m_changes.back().value->idx != idx && getPixel(subsheet, idx) != m_palIdx) {
// duplicate entries are bad
auto existing = ox::find_if(m_changes.cbegin(), m_changes.cend(), [idx](auto const&c) {
return c.idx == idx;
});
if (existing == m_changes.cend()) {
m_changes.emplace_back(static_cast<uint32_t>(idx), getPixel(subsheet, m_img.bpp, idx));
setPixel(subsheet, m_img.bpp, idx, static_cast<uint8_t>(m_palIdx));
m_changes.emplace_back(static_cast<uint32_t>(idx), getPixel(subsheet, idx));
subsheet.pixels[idx] = static_cast<uint8_t>(m_palIdx);
return true;
}
}
@ -59,7 +59,7 @@ bool DrawCommand::append(ox::Vector<std::size_t> const&idxList) noexcept {
ox::Error DrawCommand::redo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (auto const&c : m_changes) {
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(m_palIdx));
subsheet.pixels[c.idx] = static_cast<uint8_t>(m_palIdx);
}
return {};
}
@ -67,7 +67,7 @@ ox::Error DrawCommand::redo() noexcept {
ox::Error DrawCommand::undo() noexcept {
auto &subsheet = getSubSheet(m_img, m_subSheetIdx);
for (auto const&c : m_changes) {
setPixel(subsheet, m_img.bpp, c.idx, static_cast<uint8_t>(c.oldPalIdx));
subsheet.pixels[c.idx] = static_cast<uint8_t>(c.oldPalIdx);
}
return {};
}

View File

@ -17,7 +17,7 @@ gfx::UpdateSubSheetCommand::UpdateSubSheetCommand(
m_sheet{getSubSheet(m_img, m_idx)} {
m_sheet = getSubSheet(m_img, m_idx);
m_sheet.name = std::move(name);
OX_THROW_ERROR(resizeSubsheet(m_sheet, m_img.bpp, {cols, rows}));
OX_THROW_ERROR(resizeSubsheet(m_sheet, {cols, rows}));
}
ox::Error UpdateSubSheetCommand::redo() noexcept {

View File

@ -67,7 +67,7 @@ void TileSheetEditorModel::cut() {
iterateSelectionRows(*m_selection, [&](int const x, int const y) {
auto pt = ox::Point{x, y};
auto const idx = gfx::idx(s, pt);
auto const c = getPixel(s, m_img.bpp, idx);
auto const c = getPixel(s, idx);
pt -= m_selection->a;
cb->addPixel(pt, c);
blankCb.addPixel(pt, 0);
@ -88,7 +88,7 @@ void TileSheetEditorModel::copy() {
auto pt = ox::Point{x, y};
const auto&s = activeSubSheet();
const auto idx = gfx::idx(s, pt);
const auto c = getPixel(s, m_img.bpp, idx);
const auto c = getPixel(s, idx);
pt -= m_selection->a;
cb->addPixel(pt, c);
});
@ -159,7 +159,7 @@ void TileSheetEditorModel::drawCommand(ox::Point const&pt, std::size_t const pal
const auto idx = gfx::idx(activeSubSheet, pt);
if (m_ongoingDrawCommand) {
m_updated = m_updated || m_ongoingDrawCommand->append(idx);
} else if (getPixel(activeSubSheet, m_img.bpp, idx) != palIdx) {
} else if (getPixel(activeSubSheet, idx) != palIdx) {
pushCommand(ox::make<DrawCommand>(
m_img, m_activeSubsSheetIdx, idx, static_cast<int>(palIdx)));
}
@ -206,7 +206,7 @@ void TileSheetEditorModel::fill(ox::Point const&pt, int const palIdx) noexcept {
return;
}
ox::Array<bool, PixelsPerTile> updateMap = {};
auto const oldColor = getPixel(activeSubSheet, m_img.bpp, pt);
auto const oldColor = getPixel(activeSubSheet, pt);
getFillPixels(activeSubSheet, updateMap, pt, oldColor);
ox::Vector<std::size_t> idxList;
auto i = gfx::idx(activeSubSheet, pt) / PixelsPerTile * PixelsPerTile;
@ -219,7 +219,7 @@ void TileSheetEditorModel::fill(ox::Point const&pt, int const palIdx) noexcept {
// do updates to sheet
if (m_ongoingDrawCommand) {
m_updated = m_updated || m_ongoingDrawCommand->append(idxList);
} else if (getPixel(activeSubSheet, m_img.bpp, pt) != palIdx) {
} else if (getPixel(activeSubSheet, pt) != palIdx) {
pushCommand(ox::make<DrawCommand>(m_img, m_activeSubsSheetIdx, idxList, palIdx));
}
}
@ -298,7 +298,7 @@ void TileSheetEditorModel::getFillPixels(
int const oldColor) const noexcept {
auto const idx = ptToIdx(pt, activeSubSheet.columns);
auto const relIdx = idx % PixelsPerTile;
if (pixels[relIdx] || getPixel(activeSubSheet, m_img.bpp, idx) != oldColor) {
if (pixels[relIdx] || getPixel(activeSubSheet, idx) != oldColor) {
return;
}
// mark pixels to update

View File

@ -127,6 +127,7 @@ void TileSheetPixels::setBufferObjects(ox::Vec2 const&paneSize) noexcept {
auto const height = subSheet.rows * TileHeight;
auto const pixels = static_cast<size_t>(width) * static_cast<size_t>(height);
auto const vboLen = static_cast<size_t>(s_programSrc.vboLen);
oxAssert(subSheet.pixels.size() == pixels, "incorrect pixels");
m_bufferSet.vertices.resize(pixels * vboLen);
m_bufferSet.elements.resize(pixels * VertexEboLength);
// set pixels

View File

@ -28,21 +28,20 @@ static TileSheet::SubSheet const *getSubsheet(TileSheet::SubSheet const&ss, SubS
}
[[nodiscard]]
static size_t getTileCnt(TileSheet::SubSheet const&ss, int const bpp) noexcept {
static size_t getTileCnt(TileSheet::SubSheet const&ss) noexcept {
if (ss.subsheets.empty()) {
auto const bytesPerTile = bpp == 4 ? 32u : 64u;
return ss.pixels.size() / bytesPerTile;
return ss.pixels.size() / PixelsPerTile;
} else {
size_t out{};
for (auto const&child: ss.subsheets) {
out += getTileCnt(child, bpp);
out += getTileCnt(child);
}
return out;
}
}
size_t getTileCnt(TileSheet const&ts) noexcept {
return getTileCnt(ts.subsheet, ts.bpp);
return getTileCnt(ts.subsheet);
}
TileSheet::SubSheet const *getSubsheet(TileSheet const&ts, SubSheetId const id) noexcept {
@ -52,44 +51,35 @@ TileSheet::SubSheet const *getSubsheet(TileSheet const&ts, SubSheetId const id)
static ox::Optional<size_t> getPixelIdx(
TileSheet::SubSheet const&ss,
SubSheetId const id,
size_t &idx,
int8_t const bpp) noexcept {
size_t &idx) noexcept {
for (auto const&child: ss.subsheets) {
if (child.id == id) {
return ox::Optional<size_t>(ox::in_place, idx);
}
if (auto out = getPixelIdx(child, id, idx, bpp)) {
if (auto out = getPixelIdx(child, id, idx)) {
return out;
}
idx += pixelCnt(child, bpp);
idx += pixelCnt(child);
}
return ox::Optional<size_t>{};
}
ox::Optional<size_t> getTileIdx(TileSheet const&ts, SubSheetId const id) noexcept {
size_t idx{};
auto const out = getPixelIdx(ts.subsheet, id, idx, ts.bpp);
auto const out = getPixelIdx(ts.subsheet, id, idx);
return out ? ox::Optional<size_t>{ox::in_place, *out / PixelsPerTile} : out;
}
uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept {
if (idx & 1) {
return ss.pixels[idx / 2] >> 4;
} else {
return ss.pixels[idx / 2] & 0b0000'1111;
}
}
uint8_t getPixel8Bpp(TileSheet::SubSheet const&ss, std::size_t idx) noexcept {
uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, std::size_t const idx) noexcept {
return ss.pixels[idx];
}
uint8_t getPixel(TileSheet::SubSheet const&ss, int8_t pBpp, std::size_t idx) noexcept {
if (pBpp == 4) {
return getPixel4Bpp(ss, idx);
} else {
return getPixel8Bpp(ss, idx);
uint8_t getPixel8Bpp(TileSheet::SubSheet const&ss, std::size_t const idx) noexcept {
return ss.pixels[idx];
}
uint8_t getPixel(TileSheet::SubSheet const&ss, std::size_t const idx) noexcept {
return ss.pixels[idx];
}
uint8_t getPixel4Bpp(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept {
@ -102,73 +92,48 @@ uint8_t getPixel8Bpp(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept
return getPixel8Bpp(ss, idx);
}
uint8_t getPixel(TileSheet::SubSheet const&ss, int8_t pBpp, ox::Point const&pt) noexcept {
uint8_t getPixel(TileSheet::SubSheet const&ss, ox::Point const&pt) noexcept {
const auto idx = ptToIdx(pt, ss.columns);
return getPixel(ss, pBpp, idx);
return getPixel(ss, idx);
}
static void setPixel(ox::Vector<uint8_t> &pixels, int8_t pBpp, uint64_t idx, uint8_t palIdx) noexcept {
auto &pixel = pixels[static_cast<std::size_t>(idx / 2)];
if (pBpp == 4) {
if (idx & 1) {
pixel = static_cast<uint8_t>((pixel & 0b0000'1111) | (palIdx << 4));
} else {
pixel = (pixel & 0b1111'0000) | (palIdx);
}
} else {
pixel = palIdx;
}
}
void setPixel(TileSheet::SubSheet &ss, int8_t pBpp, uint64_t idx, uint8_t palIdx) noexcept {
setPixel(ss.pixels, pBpp, idx, palIdx);
}
static void setPixel(ox::Vector<uint8_t> &pixels, int columns, int8_t pBpp, ox::Point const&pt, uint8_t palIdx) noexcept {
static void setPixel(
ox::Vector<uint8_t> &pixels,
int const columns,
ox::Point const&pt,
uint8_t const palIdx) noexcept {
const auto idx = ptToIdx(pt, columns);
setPixel(pixels, pBpp, idx, palIdx);
pixels[idx] = palIdx;
}
void setPixel(TileSheet::SubSheet &ss, int8_t pBpp, ox::Point const&pt, uint8_t palIdx) noexcept {
void setPixel(TileSheet::SubSheet &ss, ox::Point const&pt, uint8_t const palIdx) noexcept {
const auto idx = ptToIdx(pt, ss.columns);
setPixel(ss, pBpp, idx, palIdx);
ss.pixels[idx] = palIdx;
}
static ox::Error setPixelCount(ox::Vector<uint8_t> &pixels, int8_t pBpp, std::size_t cnt) noexcept {
size_t sz{};
switch (pBpp) {
case 4:
sz = cnt / 2;
break;
case 8:
sz = cnt;
break;
default:
return ox::Error(1, "Invalid pBpp used for TileSheet::SubSheet::setPixelCount");
}
pixels.reserve(sz);
pixels.resize(sz);
static ox::Error setPixelCount(ox::Vector<uint8_t> &pixels, std::size_t const cnt) noexcept {
pixels.reserve(cnt);
pixels.resize(cnt);
return {};
}
ox::Error setPixelCount(TileSheet::SubSheet &ss, int8_t pBpp, std::size_t cnt) noexcept {
return setPixelCount(ss.pixels, pBpp, cnt);
ox::Error setPixelCount(TileSheet::SubSheet &ss, std::size_t const cnt) noexcept {
return setPixelCount(ss.pixels, cnt);
}
unsigned pixelCnt(TileSheet::SubSheet const&ss, int8_t pBpp) noexcept {
const auto pixelsSize = static_cast<unsigned>(ss.pixels.size());
return pBpp == 4 ? pixelsSize * 2 : pixelsSize;
unsigned pixelCnt(TileSheet::SubSheet const&ss) noexcept {
return static_cast<unsigned>(ss.pixels.size());
}
ox::Error resizeSubsheet(TileSheet::SubSheet &ss, int8_t pBpp, ox::Size const&sz) noexcept {
ox::Error resizeSubsheet(TileSheet::SubSheet &ss, ox::Size const&sz) noexcept {
ox::Vector<uint8_t> out;
OX_RETURN_ERROR(setPixelCount(out, pBpp, static_cast<size_t>(sz.width * sz.height) * PixelsPerTile));
OX_RETURN_ERROR(setPixelCount(out, static_cast<size_t>(sz.width * sz.height) * PixelsPerTile));
auto const w = ox::min<int32_t>(ss.columns, sz.width) * TileWidth;
auto const h = ox::min<int32_t>(ss.rows, sz.height) * TileHeight;
for (auto x = 0; x < w; ++x) {
for (auto y = 0; y < h; ++y) {
auto const palIdx = getPixel(ss, pBpp, {x, y});
setPixel(out, sz.width, pBpp, {x, y}, palIdx);
auto const palIdx = getPixel(ss, {x, y});
setPixel(out, sz.width, {x, y}, palIdx);
}
}
ss.columns = sz.width;
@ -177,7 +142,7 @@ ox::Error resizeSubsheet(TileSheet::SubSheet &ss, int8_t pBpp, ox::Size const&sz
return {};
}
ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const&ss, SubSheetId pId) noexcept {
ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const&ss, SubSheetId const pId) noexcept {
if (ss.id == pId) {
return ox::StringView(ss.name);
}
@ -193,7 +158,7 @@ ox::Result<ox::StringView> getNameFor(TileSheet::SubSheet const&ss, SubSheetId p
TileSheet::SubSheetIdx validateSubSheetIdx(
TileSheet::SubSheetIdx &&pIdx,
std::size_t pIdxIt,
std::size_t const pIdxIt,
TileSheet::SubSheet const&pSubsheet) noexcept {
if (pIdxIt >= pIdx.size()) {
return std::move(pIdx);
@ -216,9 +181,9 @@ TileSheet::SubSheetIdx validateSubSheetIdx(TileSheet const&ts, TileSheet::SubShe
return validateSubSheetIdx(std::move(idx), 0, ts.subsheet);
}
const TileSheet::SubSheet &getSubSheet(
TileSheet::SubSheet const&getSubSheet(
TileSheet::SubSheetIdx const&idx,
std::size_t idxIt,
std::size_t const idxIt,
TileSheet::SubSheet const&pSubsheet) noexcept {
if (idxIt == idx.size()) {
return pSubsheet;
@ -232,7 +197,7 @@ const TileSheet::SubSheet &getSubSheet(
TileSheet::SubSheet &getSubSheet(
TileSheet::SubSheetIdx const&idx,
std::size_t idxIt,
std::size_t const idxIt,
TileSheet::SubSheet &pSubsheet) noexcept {
if (idxIt == idx.size()) {
return pSubsheet;
@ -251,10 +216,10 @@ TileSheet::SubSheet &getSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx
ox::Error addSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept {
auto &parent = getSubSheet(ts, idx);
if (parent.subsheets.size() < 2) {
parent.subsheets.emplace_back(++ts.idIt, ox::sfmt("Subsheet {}", parent.subsheets.size()), 1, 1, ts.bpp);
parent.subsheets.emplace_back(++ts.idIt, ox::sfmt("Subsheet {}", parent.subsheets.size()), 1, 1);
} else {
parent.subsheets.emplace_back(++ts.idIt, "Subsheet 0", parent.columns, parent.rows, ts.bpp);
parent.subsheets.emplace_back(++ts.idIt, "Subsheet 1", 1, 1, ts.bpp);
parent.subsheets.emplace_back(++ts.idIt, "Subsheet 0", parent.columns, parent.rows);
parent.subsheets.emplace_back(++ts.idIt, "Subsheet 1", 1, 1);
}
return ox::Error(0);
}
@ -262,7 +227,7 @@ ox::Error addSubSheet(TileSheet &ts, TileSheet::SubSheetIdx const&idx) noexcept
ox::Error rmSubSheet(
TileSheet &ts,
TileSheet::SubSheetIdx const&idx,
std::size_t idxIt,
std::size_t const idxIt,
TileSheet::SubSheet &pSubsheet) noexcept {
if (idxIt == idx.size() - 1) {
return pSubsheet.subsheets.erase(idx[idxIt]).error;
@ -315,18 +280,12 @@ uint8_t getPixel8Bpp(
ox::Pair<uint8_t> get2Pixels4Bpp(
CompactTileSheet const&ts,
size_t const idx) noexcept {
oxAssert(ts.bpp == 4, "TileSheet::getPixel4Bpp: wrong bpp");
auto const out = ts.pixels[idx / 2];
return {
static_cast<uint8_t>(out & 0x0f),
static_cast<uint8_t>(out >> 4),
};
return get2Pixels8Bpp(ts, idx);
}
ox::Pair<uint8_t> get2Pixels8Bpp(
CompactTileSheet const&ts,
size_t const idx) noexcept {
oxAssert(ts.bpp == 8, "TileSheet::getPixel8Bpp: wrong bpp");
return {
static_cast<uint8_t>(ts.pixels[idx]),
static_cast<uint8_t>(ts.pixels[idx + 1]),
@ -336,7 +295,7 @@ ox::Pair<uint8_t> get2Pixels8Bpp(
static ox::Result<SubSheetId> getIdFor(
TileSheet::SubSheet const&ss,
ox::SpanView<ox::StringView> const&pNamePath,
std::size_t pIt = 0) noexcept {
std::size_t const pIt = 0) noexcept {
for (auto &sub : ss.subsheets) {
if (sub.name == pNamePath[pIt]) {
if (pIt == pNamePath.size()) {
@ -358,8 +317,7 @@ ox::Result<SubSheetId> getIdFor(TileSheet const&ts, ox::StringViewCR path) noexc
static ox::Result<uint32_t> getTileOffset(
TileSheet::SubSheet const&ss,
ox::SpanView<ox::StringView> const&pNamePath,
int8_t pBpp,
std::size_t pIt = 0,
std::size_t const pIt = 0,
uint32_t pCurrentTotal = 0) noexcept {
// pIt == pNamePath.size() - 1 &&
if (ss.name != pNamePath[pIt]) {
@ -370,44 +328,52 @@ static ox::Result<uint32_t> getTileOffset(
}
for (auto &sub : ss.subsheets) {
auto [offset, err] = getTileOffset(
sub, pNamePath, pBpp, pIt + 1, pCurrentTotal);
sub, pNamePath, pIt + 1, pCurrentTotal);
if (!err) {
return offset;
}
// Possible bug? Shoud this be usinga a recursive version of
// Possible bug? Should this be using a recursive version of
// pixelCnt will count pixels in subsheets of sub as well.
pCurrentTotal += pixelCnt(sub, pBpp) / PixelsPerTile;
pCurrentTotal += pixelCnt(sub) / PixelsPerTile;
}
return ox::Error(1, "SubSheet not found");
}
ox::Result<uint32_t> getTileOffset(TileSheet const&ts, ox::StringViewCR pNamePath) noexcept {
return gfx::getTileOffset(ts.subsheet, ox::split<8>(pNamePath, '.'), ts.bpp);
return gfx::getTileOffset(ts.subsheet, ox::split<8>(pNamePath, '.'));
}
ox::Result<ox::StringView> getNameFor(TileSheet &ts, SubSheetId pId) noexcept {
ox::Result<ox::StringView> getNameFor(TileSheet &ts, SubSheetId const pId) noexcept {
return gfx::getNameFor(ts.subsheet, pId);
}
ox::Result<ox::StringView> getNameFor(TileSheet const&ts, SubSheetId pId) noexcept {
ox::Result<ox::StringView> getNameFor(TileSheet const&ts, SubSheetId const pId) noexcept {
return gfx::getNameFor(ts.subsheet, pId);
}
static void readPixelsTo(TileSheet::SubSheet &ss, ox::Vector<uint8_t> &pPixels) noexcept {
static void readPixelsTo(TileSheet::SubSheet &ss, int const pBpp, ox::Vector<uint8_t> &pPixels) noexcept {
if (!ss.subsheets.empty()) {
for (auto &s: ss.subsheets) {
readPixelsTo(s, pPixels);
readPixelsTo(s, pBpp, pPixels);
}
} else {
for (auto p : ss.pixels) {
if (pBpp == 4) {
for (size_t i{}; i < ss.pixels.size() - 1; i += 2) {
auto const p1 = ss.pixels[i];
auto const p2 = ss.pixels[i + 1];
pPixels.emplace_back(static_cast<uint8_t>(p1 | (p2 << 4)));
}
} else {
for (auto const p : ss.pixels) {
pPixels.emplace_back(p);
}
}
}
}
ox::Vector<uint8_t> pixels(TileSheet &ts) noexcept {
ox::Vector<uint8_t> out;
readPixelsTo(ts.subsheet, out);
readPixelsTo(ts.subsheet, ts.bpp, out);
return out;
}
@ -415,7 +381,7 @@ ox::Vector<uint8_t> pixels(TileSheet &ts) noexcept {
ox::Vector<uint32_t> resizeTileSheetData(
ox::Vector<uint32_t> const&srcPixels,
ox::Size const&srcSize,
int scale) noexcept {
int const scale) noexcept {
ox::Vector<uint32_t> dst;
auto dstWidth = srcSize.width * scale;
auto dstHeight = srcSize.height * scale;