[nostalgia] Add basic support for subsheets
This commit is contained in:
+219
-77
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user