[nostalgia] Add basic support for subsheets

This commit is contained in:
2022-02-26 22:48:18 -06:00
parent 329ecb3266
commit e8a046c2dc
20 changed files with 630 additions and 238 deletions
+219 -77
View File
@@ -60,30 +60,221 @@ struct TileSheet {
struct SubSheet {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet.SubSheet";
static constexpr auto TypeVersion = 1;
ox::BString<32> name;
uint64_t begin = 0;
ox::String name;
int columns = 1;
int rows = 1;
ox::Vector<SubSheet> subsheets;
ox::Vector<uint8_t> pixels;
constexpr SubSheet() noexcept = default;
constexpr SubSheet(const char *pName, int pColumns, int pRows) noexcept: name(pName), columns(pColumns), rows(pRows) {
constexpr SubSheet(const SubSheet &other) noexcept {
name = other.name;
columns = other.columns;
rows = other.rows;
subsheets = other.subsheets;
pixels = other.pixels;
}
constexpr SubSheet(SubSheet &&other) noexcept {
name = std::move(other.name);
columns = other.columns;
rows = other.rows;
subsheets = std::move(other.subsheets);
pixels = std::move(other.pixels);
other.name = "";
other.columns = 0;
other.rows = 0;
}
constexpr SubSheet(const char *pName, int pColumns, int pRows) noexcept:
name(pName), columns(pColumns), rows(pRows), pixels(static_cast<std::size_t>(columns * rows * PixelsPerTile)) {
}
constexpr SubSheet(const char *pName, int pColumns, int pRows, ox::Vector<uint8_t> pPixels) noexcept:
name(pName), columns(pColumns), rows(pRows), pixels(std::move(pPixels)) {
}
constexpr SubSheet &operator=(const SubSheet &other) noexcept {
name = other.name;
columns = other.columns;
rows = other.rows;
subsheets = other.subsheets;
pixels = other.pixels;
return *this;
}
constexpr SubSheet &operator=(SubSheet &&other) noexcept {
name = std::move(other.name);
columns = other.columns;
rows = other.rows;
subsheets = std::move(other.subsheets);
pixels = std::move(other.pixels);
return *this;
}
/**
* Reads all pixels of this sheet or its children into the given pixel list
* @param pixels
*/
void readPixelsTo(ox::Vector<uint8_t> *pPixels) const noexcept {
if (subsheets.size()) {
for (auto &s: subsheets) {
s.readPixelsTo(pPixels);
}
} else {
for (auto p : this->pixels) {
pPixels->emplace_back(p);
}
}
}
[[nodiscard]]
constexpr std::size_t size() const noexcept {
return static_cast<std::size_t>(columns) * static_cast<std::size_t>(rows);
}
[[nodiscard]]
constexpr std::size_t unusedPixels() const noexcept {
std::size_t childrenSize = 0;
for (auto &c : subsheets) {
childrenSize += c.size();
}
return size() - childrenSize;
}
[[nodiscard]]
constexpr uint8_t getPixel4Bpp(std::size_t idx) const noexcept {
if (idx & 1) {
return this->pixels[idx / 2] >> 4;
} else {
return this->pixels[idx / 2] & 0b0000'1111;
}
}
[[nodiscard]]
constexpr uint8_t getPixel8Bpp(std::size_t idx) const noexcept {
return this->pixels[idx];
}
[[nodiscard]]
constexpr auto getPixel(int8_t bpp, std::size_t idx) const noexcept {
if (bpp == 4) {
return getPixel4Bpp(idx);
} else {
return getPixel8Bpp(idx);
}
}
[[nodiscard]]
constexpr auto getPixel4Bpp(const geo::Point &pt) const noexcept {
const auto idx = ptToIdx(pt, columns);
return getPixel4Bpp(idx);
}
[[nodiscard]]
constexpr auto getPixel8Bpp(const geo::Point &pt) const noexcept {
const auto idx = ptToIdx(pt, columns);
return getPixel8Bpp(idx);
}
[[nodiscard]]
constexpr auto getPixel(int8_t bpp, const geo::Point &pt) const noexcept {
const auto idx = ptToIdx(pt, columns);
return getPixel(bpp, idx);
}
constexpr void setPixel(int8_t bpp, uint64_t idx, uint8_t palIdx) noexcept {
auto &pixel = this->pixels[idx / 2];
if (bpp == 4) {
if (idx & 1) {
pixel = (pixel & 0b0000'1111) | (palIdx << 4);
} else {
pixel = (pixel & 0b1111'0000) | (palIdx);
}
} else {
pixel = palIdx;
}
}
constexpr void setPixel(int8_t bpp, const geo::Point &pt, uint8_t palIdx) noexcept {
const auto idx = ptToIdx(pt, columns);
setPixel(bpp, idx, palIdx);
}
/**
* Gets a count of the pixels in this sheet, and not that of its children.
* @param bpp bits per pixel, need for knowing how to count the pixels
* @return a count of the pixels in this sheet
*/
constexpr auto pixelCnt(int8_t bpp) const noexcept {
return bpp == 4 ? pixels.size() * 2 : pixels.size();
}
};
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet";
static constexpr auto TypeVersion = 1;
static constexpr auto TypeVersion = 2;
int8_t bpp = 0;
ox::FileAddress defaultPalette;
ox::Vector<uint8_t> pixels;
SubSheet subsheet;
constexpr TileSheet() noexcept = default;
inline TileSheet(const TileSheet &other) noexcept {
bpp = other.bpp;
defaultPalette = other.defaultPalette;
subsheet = other.subsheet;
}
inline TileSheet(TileSheet &&other) noexcept {
bpp = other.bpp;
defaultPalette = std::move(other.defaultPalette);
subsheet = std::move(other.subsheet);
}
inline auto &operator=(const TileSheet &other) noexcept {
bpp = other.bpp;
defaultPalette = other.defaultPalette;
subsheet = other.subsheet;
return *this;
}
inline auto &operator=(TileSheet &&other) noexcept {
bpp = other.bpp;
defaultPalette = std::move(other.defaultPalette);
subsheet = std::move(other.subsheet);
return *this;
}
[[nodiscard]]
constexpr auto validateSubSheetIdx(const SubSheetIdx &pIdx, std::size_t pIdxIt, const SubSheet *pSubsheet) noexcept {
if (pIdxIt == pIdx.size()) {
return pIdx;
}
const auto currentIdx = pIdx[pIdxIt];
if (pSubsheet->subsheets.size() <= currentIdx) {
auto out = pIdx;
out.back().value = pSubsheet->subsheets.size() - 1;
return out;
}
return validateSubSheetIdx(pIdx, pIdxIt + 1, &pSubsheet->subsheets[pIdx[pIdxIt]]);
}
/**
* validateSubSheetIdx takes a SubSheetIdx and moves the index to the
* preceding or parent sheet if the current corresponding sheet does
* not exist.
* @param idx SubSheetIdx to validate and correct
* @return a valid version of idx
*/
[[nodiscard]]
constexpr auto validateSubSheetIdx(const SubSheetIdx &idx) noexcept {
return validateSubSheetIdx(idx, 0, &subsheet);
}
[[nodiscard]]
constexpr static const auto &getSubSheet(const SubSheetIdx &idx, std::size_t idxIt, const SubSheet *pSubsheet) noexcept {
if (idxIt == idx.size()) {
return *pSubsheet;
}
return getSubSheet(idx, idxIt + 1, &pSubsheet->subsheets[idx[idxIt]]);
const auto currentIdx = idx[idxIt];
if (pSubsheet->subsheets.size() < currentIdx) {
return *pSubsheet;
}
return getSubSheet(idx, idxIt + 1, &pSubsheet->subsheets[currentIdx]);
}
[[nodiscard]]
@@ -104,6 +295,17 @@ struct TileSheet {
return getSubSheet(idx, 0, &subsheet);
}
constexpr ox::Error addSubSheet(const SubSheetIdx &idx) noexcept {
auto &parent = getSubSheet(idx);
if (parent.subsheets.size() < 2) {
parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", parent.subsheets.size()).c_str(), 1, 1);
} else {
parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows);
parent.subsheets.emplace_back("Subsheet 1", 1, 1);
}
return OxError(0);
}
[[nodiscard]]
constexpr static auto rmSubSheet(const SubSheetIdx &idx, std::size_t idxIt, SubSheet *pSubsheet) noexcept {
if (idxIt == idx.size() - 1) {
@@ -117,88 +319,29 @@ struct TileSheet {
return rmSubSheet(idx, 0, &subsheet);
}
[[nodiscard]]
constexpr const auto &columns(const SubSheetIdx &idx = {}) const noexcept {
return getSubSheet(idx).columns;
}
[[nodiscard]]
constexpr const auto &rows(const SubSheetIdx &idx = {}) const noexcept {
return getSubSheet(idx).rows;
}
[[nodiscard]]
constexpr auto &columns(const SubSheetIdx &idx = {}) noexcept {
return getSubSheet(idx).columns;
}
[[nodiscard]]
constexpr auto &rows(const SubSheetIdx &idx = {}) noexcept {
return getSubSheet(idx).rows;
}
[[nodiscard]]
constexpr uint8_t getPixel4Bpp(std::size_t idx) const noexcept {
oxAssert(bpp == 4, "TileSheetV1::getPixel4Bpp: wrong bpp");
if (idx & 1) {
return this->pixels[idx / 2] >> 4;
} else {
return this->pixels[idx / 2] & 0b0000'1111;
}
}
[[nodiscard]]
constexpr uint8_t getPixel8Bpp(std::size_t idx) const noexcept {
oxAssert(bpp == 8, "TileSheetV1::getPixel8Bpp: wrong bpp");
return this->pixels[idx];
}
[[nodiscard]]
constexpr auto getPixel(std::size_t idx) const noexcept {
if (this->bpp == 4) {
return getPixel4Bpp(idx);
} else {
return getPixel8Bpp(idx);
}
}
[[nodiscard]]
constexpr auto getPixel4Bpp(const geo::Point &pt, const SubSheetIdx &subsheetIdx) const noexcept {
oxAssert(bpp == 4, "TileSheetV1::getPixel4Bpp: wrong bpp");
const auto idx = ptToIdx(pt, this->getSubSheet(subsheetIdx).columns);
return getPixel4Bpp(idx);
auto &s = this->getSubSheet(subsheetIdx);
const auto idx = ptToIdx(pt, s.columns);
return s.getPixel4Bpp(idx);
}
[[nodiscard]]
constexpr auto getPixel8Bpp(const geo::Point &pt, const SubSheetIdx &subsheetIdx) const noexcept {
oxAssert(bpp == 8, "TileSheetV1::getPixel8Bpp: wrong bpp");
const auto idx = ptToIdx(pt, this->getSubSheet(subsheetIdx).columns);
return getPixel8Bpp(idx);
auto &s = this->getSubSheet(subsheetIdx);
const auto idx = ptToIdx(pt, s.columns);
return s.getPixel8Bpp(idx);
}
[[nodiscard]]
constexpr auto getPixel(const geo::Point &pt, const SubSheetIdx &subsheetIdx) const noexcept {
const auto idx = ptToIdx(pt, this->getSubSheet(subsheetIdx).columns);
return getPixel(idx);
auto pixels() const noexcept {
ox::Vector<uint8_t> out;
subsheet.readPixelsTo(&out);
return out;
}
constexpr void setPixel(uint64_t idx, uint8_t palIdx) noexcept {
auto &pixel = this->pixels[idx / 2];
if (bpp == 4) {
if (idx & 1) {
pixel = (pixel & 0b0000'1111) | (palIdx << 4);
} else {
pixel = (pixel & 0b1111'0000) | (palIdx);
}
} else {
pixel = palIdx;
}
}
constexpr void setPixel(const SubSheetIdx &subsheetIdx, const geo::Point &pt, uint8_t palIdx) noexcept {
const auto idx = ptToIdx(pt, this->getSubSheet(subsheetIdx).columns);
setPixel(idx, palIdx);
}
};
struct CompactTileSheet {
@@ -228,16 +371,15 @@ oxModelEnd()
oxModelBegin(TileSheet::SubSheet)
oxModelField(name);
oxModelField(begin);
oxModelField(rows);
oxModelField(columns);
oxModelField(subsheets)
oxModelField(pixels)
oxModelEnd()
oxModelBegin(TileSheet)
oxModelField(bpp)
oxModelField(defaultPalette)
oxModelField(pixels)
oxModelField(subsheet)
oxModelEnd()