From 8077aaf0ae0fd830312686375777de89c61c33f9 Mon Sep 17 00:00:00 2001 From: Gary Talent Date: Tue, 7 Feb 2023 23:17:58 -0600 Subject: [PATCH] [nostalgia] Fill out basic Scene system functionality --- .../.nostalgia/type_descriptors/B.bool;0 | 4 + ...ingtea.nostalgia.core.TileSheet.SubSheet;3 | 42 ++ ...net.drinkingtea.nostalgia.core.TileSheet;3 | 24 + .../net.drinkingtea.ox.FileAddress.Data;1 | 1 + .../net.drinkingtea.ox.FileAddress;1 | 1 + sample_project/Palettes/Chester.npal | 1 + sample_project/Scenes/Chester.nscn | Bin 0 -> 1207 bytes sample_project/TileSheets/Chester.ng | Bin 0 -> 255 bytes src/nostalgia/core/CMakeLists.txt | 2 + src/nostalgia/core/gfx.hpp | 426 +------------ src/nostalgia/core/module.cpp | 10 +- src/nostalgia/core/module.hpp | 9 +- src/nostalgia/core/palette.hpp | 47 ++ .../core/studio/tilesheeteditormodel.cpp | 6 +- src/nostalgia/core/tilesheet.cpp | 9 + src/nostalgia/core/tilesheet.hpp | 566 ++++++++++++++++++ src/nostalgia/core/typeconv.cpp | 67 +++ src/nostalgia/core/typeconv.hpp | 38 +- src/nostalgia/core/userland/gfx_opengl.cpp | 11 +- src/nostalgia/foundation/context.hpp | 2 +- src/nostalgia/foundation/module.cpp | 2 +- src/nostalgia/foundation/module.hpp | 2 +- src/nostalgia/foundation/typeconv.cpp | 22 +- src/nostalgia/foundation/typeconv.hpp | 39 +- src/nostalgia/player/app.cpp | 46 +- src/nostalgia/scene/CMakeLists.txt | 4 +- src/nostalgia/scene/scene.cpp | 37 +- src/nostalgia/scene/scene.hpp | 99 +-- src/nostalgia/scene/scenemodule.cpp | 6 +- src/nostalgia/scene/scenemodule.hpp | 4 +- src/nostalgia/scene/scenestatic.cpp | 11 + src/nostalgia/scene/scenestatic.hpp | 164 +++++ src/nostalgia/scene/typeconv.cpp | 34 +- src/nostalgia/scene/typeconv.hpp | 6 +- 34 files changed, 1111 insertions(+), 631 deletions(-) create mode 100644 sample_project/.nostalgia/type_descriptors/B.bool;0 create mode 100644 sample_project/.nostalgia/type_descriptors/net.drinkingtea.nostalgia.core.TileSheet.SubSheet;3 create mode 100644 sample_project/.nostalgia/type_descriptors/net.drinkingtea.nostalgia.core.TileSheet;3 create mode 100644 sample_project/Palettes/Chester.npal create mode 100644 sample_project/Scenes/Chester.nscn create mode 100644 sample_project/TileSheets/Chester.ng create mode 100644 src/nostalgia/core/palette.hpp create mode 100644 src/nostalgia/core/tilesheet.cpp create mode 100644 src/nostalgia/core/tilesheet.hpp create mode 100644 src/nostalgia/core/typeconv.cpp create mode 100644 src/nostalgia/scene/scenestatic.cpp create mode 100644 src/nostalgia/scene/scenestatic.hpp diff --git a/sample_project/.nostalgia/type_descriptors/B.bool;0 b/sample_project/.nostalgia/type_descriptors/B.bool;0 new file mode 100644 index 00000000..0f93c256 --- /dev/null +++ b/sample_project/.nostalgia/type_descriptors/B.bool;0 @@ -0,0 +1,4 @@ +O1;net.drinkingtea.ox.TypeDescriptor;1;{ + "primitiveType" : 2, + "typeName" : "B.bool" +} diff --git a/sample_project/.nostalgia/type_descriptors/net.drinkingtea.nostalgia.core.TileSheet.SubSheet;3 b/sample_project/.nostalgia/type_descriptors/net.drinkingtea.nostalgia.core.TileSheet.SubSheet;3 new file mode 100644 index 00000000..01125bb1 --- /dev/null +++ b/sample_project/.nostalgia/type_descriptors/net.drinkingtea.nostalgia.core.TileSheet.SubSheet;3 @@ -0,0 +1,42 @@ +O1;net.drinkingtea.ox.TypeDescriptor;1;{ + "fieldList" : + [ + { + "fieldName" : "name", + "typeId" : "net.drinkingtea.ox.BasicString#8#;1" + }, + { + "fieldName" : "rows", + "typeId" : "B.int32;0" + }, + { + "fieldName" : "columns", + "typeId" : "B.int32;0" + }, + { + "fieldName" : "subsheets", + "subscriptLevels" : 1, + "subscriptStack" : + [ + { + "subscriptType" : 4 + } + ], + "typeId" : "net.drinkingtea.nostalgia.core.TileSheet.SubSheet;3" + }, + { + "fieldName" : "pixels", + "subscriptLevels" : 1, + "subscriptStack" : + [ + { + "subscriptType" : 4 + } + ], + "typeId" : "B.uint8;0" + } + ], + "primitiveType" : 5, + "typeName" : "net.drinkingtea.nostalgia.core.TileSheet.SubSheet", + "typeVersion" : 3 +} diff --git a/sample_project/.nostalgia/type_descriptors/net.drinkingtea.nostalgia.core.TileSheet;3 b/sample_project/.nostalgia/type_descriptors/net.drinkingtea.nostalgia.core.TileSheet;3 new file mode 100644 index 00000000..3bb34484 --- /dev/null +++ b/sample_project/.nostalgia/type_descriptors/net.drinkingtea.nostalgia.core.TileSheet;3 @@ -0,0 +1,24 @@ +O1;net.drinkingtea.ox.TypeDescriptor;1;{ + "fieldList" : + [ + { + "fieldName" : "bpp", + "typeId" : "B.int8;0" + }, + { + "fieldName" : "idIt", + "typeId" : "B.int32;0" + }, + { + "fieldName" : "defaultPalette", + "typeId" : "net.drinkingtea.ox.FileAddress;1" + }, + { + "fieldName" : "subsheet", + "typeId" : "net.drinkingtea.nostalgia.core.TileSheet.SubSheet;3" + } + ], + "primitiveType" : 5, + "typeName" : "net.drinkingtea.nostalgia.core.TileSheet", + "typeVersion" : 3 +} diff --git a/sample_project/.nostalgia/type_descriptors/net.drinkingtea.ox.FileAddress.Data;1 b/sample_project/.nostalgia/type_descriptors/net.drinkingtea.ox.FileAddress.Data;1 index cb981fac..5ba7e2c1 100644 --- a/sample_project/.nostalgia/type_descriptors/net.drinkingtea.ox.FileAddress.Data;1 +++ b/sample_project/.nostalgia/type_descriptors/net.drinkingtea.ox.FileAddress.Data;1 @@ -14,6 +14,7 @@ O1;net.drinkingtea.ox.TypeDescriptor;1;{ "typeId" : "B.uint64;0" } ], + "preloadable" : true, "primitiveType" : 6, "typeName" : "net.drinkingtea.ox.FileAddress.Data", "typeVersion" : 1 diff --git a/sample_project/.nostalgia/type_descriptors/net.drinkingtea.ox.FileAddress;1 b/sample_project/.nostalgia/type_descriptors/net.drinkingtea.ox.FileAddress;1 index 43361af1..878acc0f 100644 --- a/sample_project/.nostalgia/type_descriptors/net.drinkingtea.ox.FileAddress;1 +++ b/sample_project/.nostalgia/type_descriptors/net.drinkingtea.ox.FileAddress;1 @@ -10,6 +10,7 @@ O1;net.drinkingtea.ox.TypeDescriptor;1;{ "typeId" : "net.drinkingtea.ox.FileAddress.Data" } ], + "preloadable" : true, "primitiveType" : 5, "typeName" : "net.drinkingtea.ox.FileAddress", "typeVersion" : 1 diff --git a/sample_project/Palettes/Chester.npal b/sample_project/Palettes/Chester.npal new file mode 100644 index 00000000..e818a266 --- /dev/null +++ b/sample_project/Palettes/Chester.npal @@ -0,0 +1 @@ +M2;net.drinkingtea.nostalgia.core.Palette;1;ûÿ³Ö \ No newline at end of file diff --git a/sample_project/Scenes/Chester.nscn b/sample_project/Scenes/Chester.nscn new file mode 100644 index 0000000000000000000000000000000000000000..535b35f0e8d00a67ba9ea22c2d376de983d5b7a4 GIT binary patch literal 1207 zcmeHG!3x4K4E5T6#pqc&cXda1SDd#oq|UGvM?2Pd5ZS+*bOS%Y)4BXcg{#HE=euY%PUCCk>m)<&o5zN7Uy!xNzBV;Vsc;r0&xzP%%Tz& o7DlH3Xg~=BRKO$>;iTk*!~-+Y1W>uCJS^%VHlW%A=7F6D08)EFNB{r; literal 0 HcmV?d00001 diff --git a/src/nostalgia/core/CMakeLists.txt b/src/nostalgia/core/CMakeLists.txt index b0695bf0..e2ca53b1 100644 --- a/src/nostalgia/core/CMakeLists.txt +++ b/src/nostalgia/core/CMakeLists.txt @@ -2,6 +2,8 @@ add_library( NostalgiaCore-Common OBJECT gfx.cpp module.cpp + tilesheet.cpp + typeconv.cpp typestore.cpp ) diff --git a/src/nostalgia/core/gfx.hpp b/src/nostalgia/core/gfx.hpp index 7e8a2edf..cb9c2eda 100644 --- a/src/nostalgia/core/gfx.hpp +++ b/src/nostalgia/core/gfx.hpp @@ -14,6 +14,7 @@ #include "color.hpp" #include "context.hpp" #include "ptidxconv.hpp" +#include "tilesheet.hpp" namespace nostalgia::core { @@ -31,431 +32,6 @@ enum class TileSheetSpace { Sprite }; -struct NostalgiaPalette { - static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaPalette"; - static constexpr auto TypeVersion = 1; - ox::Vector colors = {}; -}; - -struct Palette { - static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.Palette"; - static constexpr auto TypeVersion = 1; - ox::Vector colors = {}; - [[nodiscard]] - constexpr Color16 color(auto idx) const noexcept { - if (idx < colors.size()) [[likely]] { - return colors[idx]; - } - return 0; - } -}; - -// Predecessor to TileSheet, kept for backward compatibility -struct NostalgiaGraphic { - static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaGraphic"; - static constexpr auto TypeVersion = 1; - int8_t bpp = 0; - // rows and columns are really only used by TileSheetEditor - int rows = 1; - int columns = 1; - ox::FileAddress defaultPalette; - Palette pal; - ox::Vector pixels = {}; -}; - -struct TileSheet { - using SubSheetIdx = ox::Vector; - - struct SubSheet { - static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet.SubSheet"; - static constexpr auto TypeVersion = 1; - ox::String name; - int columns = 0; - int rows = 0; - ox::Vector subsheets; - ox::Vector pixels; - - constexpr SubSheet() noexcept = default; - 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(ox::CRStringView pName, int pColumns, int pRows, int bpp) noexcept: - name(pName), columns(pColumns), rows(pRows), - pixels(static_cast(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) { - } - constexpr SubSheet(ox::CRStringView pName, int pColumns, int pRows, ox::Vector pPixels) noexcept: - name(pName), columns(pColumns), rows(pRows), pixels(std::move(pPixels)) { - } - - constexpr SubSheet &operator=(const SubSheet &other) noexcept = default; - - 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; - } - - [[nodiscard]] - constexpr auto idx(const geo::Point &pt) const noexcept { - return ptToIdx(pt, columns); - } - - /** - * Reads all pixels of this sheet or its children into the given pixel list - * @param pixels - */ - constexpr void readPixelsTo(ox::Vector *pPixels, int8_t bpp) const noexcept { - if (subsheets.size()) { - for (auto &s: subsheets) { - s.readPixelsTo(pPixels); - } - } else { - if (bpp == 4) { - for (auto p: this->pixels) { - pPixels->emplace_back(p & 0b1111); - pPixels->emplace_back(p >> 4); - } - } else { - for (auto p: this->pixels) { - pPixels->emplace_back(p); - } - } - } - } - - /** - * Reads all pixels of this sheet or its children into the given pixel list - * @param pixels - */ - constexpr void readPixelsTo(ox::Vector *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(columns) * static_cast(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 pBpp, std::size_t idx) const noexcept { - if (pBpp == 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 pBpp, const geo::Point &pt) const noexcept { - const auto idx = ptToIdx(pt, columns); - return getPixel(pBpp, idx); - } - - constexpr auto walkPixels(int8_t pBpp, auto callback) const noexcept { - if (pBpp == 4) { - const auto pixelCnt = ox::min(static_cast(columns * rows * PixelsPerTile) / 2, - 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 = pixels[i] & 0xF; - const auto colorIdx2 = pixels[i] >> 4; - callback(i * 2 + 0, colorIdx1); - callback(i * 2 + 1, colorIdx2); - } - } else { - const auto pixelCnt = ox::min(static_cast(columns * rows * PixelsPerTile), - pixels.size()); - for (std::size_t i = 0; i < pixelCnt; ++i) { - const auto p = pixels[i]; - callback(i, p); - } - } - } - - constexpr void setPixel(int8_t pBpp, uint64_t idx, uint8_t palIdx) noexcept { - auto &pixel = this->pixels[idx / 2]; - if (pBpp == 4) { - if (idx & 1) { - pixel = (pixel & 0b0000'1111) | (palIdx << 4); - } else { - pixel = (pixel & 0b1111'0000) | (palIdx); - } - } else { - pixel = palIdx; - } - } - - constexpr void setPixel(int8_t pBpp, const geo::Point &pt, uint8_t palIdx) noexcept { - const auto idx = ptToIdx(pt, columns); - setPixel(pBpp, idx, palIdx); - } - - constexpr auto setPixelCount(int8_t pBpp, std::size_t cnt) noexcept { - switch (pBpp) { - case 4: - pixels.resize(cnt / 2); - return OxError(0); - case 8: - pixels.resize(cnt); - return OxError(0); - default: - return OxError(1, "Invalid pBpp used for TileSheet::SubSheet::setPixelCount"); - } - } - - /** - * 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]] - constexpr auto pixelCnt(int8_t pBpp) const noexcept { - return pBpp == 4 ? pixels.size() * 2 : pixels.size(); - } - }; - - static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet"; - static constexpr auto TypeVersion = 2; - int8_t bpp = 4; - ox::FileAddress defaultPalette; - SubSheet subsheet{"Root", 1, 1, bpp}; - - constexpr TileSheet() noexcept = default; - TileSheet(const TileSheet &other) noexcept = default; - 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 { - if (this != &other) { - 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; - if (pSubsheet->subsheets.size()) { - out.back().value = pSubsheet->subsheets.size() - 1; - } else { - out.pop_back(); - } - 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; - } - const auto currentIdx = idx[idxIt]; - if (pSubsheet->subsheets.size() < currentIdx) { - return *pSubsheet; - } - return getSubSheet(idx, idxIt + 1, &pSubsheet->subsheets[currentIdx]); - } - - [[nodiscard]] - constexpr static auto &getSubSheet(const SubSheetIdx &idx, std::size_t idxIt, SubSheet *pSubsheet) noexcept { - if (idxIt == idx.size()) { - return *pSubsheet; - } - return getSubSheet(idx, idxIt + 1, &pSubsheet->subsheets[idx[idxIt]]); - } - - [[nodiscard]] - constexpr const auto &getSubSheet(const SubSheetIdx &idx) const noexcept { - return getSubSheet(idx, 0, &subsheet); - } - - [[nodiscard]] - constexpr auto &getSubSheet(const SubSheetIdx &idx) noexcept { - 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()), 1, 1, bpp); - } else { - parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows, bpp); - parent.subsheets.emplace_back("Subsheet 1", 1, 1, bpp); - } - return OxError(0); - } - - [[nodiscard]] - constexpr static auto rmSubSheet(const SubSheetIdx &idx, std::size_t idxIt, SubSheet *pSubsheet) noexcept { - if (idxIt == idx.size() - 1) { - return pSubsheet->subsheets.erase(idx[idxIt]).error; - } - return rmSubSheet(idx, idxIt + 1, &pSubsheet->subsheets[idx[idxIt]]); - } - - [[nodiscard]] - constexpr auto rmSubSheet(const SubSheetIdx &idx) noexcept { - return rmSubSheet(idx, 0, &subsheet); - } - - [[nodiscard]] - constexpr auto getPixel4Bpp(const geo::Point &pt, const SubSheetIdx &subsheetIdx) const noexcept { - oxAssert(bpp == 4, "TileSheetV1::getPixel4Bpp: wrong bpp"); - 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"); - auto &s = this->getSubSheet(subsheetIdx); - const auto idx = ptToIdx(pt, s.columns); - return s.getPixel8Bpp(idx); - } - - [[nodiscard]] - auto pixels() const noexcept { - ox::Vector out; - subsheet.readPixelsTo(&out); - return out; - } - -}; - -struct CompactTileSheet { - static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.CompactTileSheet"; - static constexpr auto TypeVersion = 1; - int8_t bpp = 0; - ox::FileAddress defaultPalette; - ox::Vector pixels = {}; -}; - -oxModelBegin(NostalgiaPalette) - oxModelField(colors) -oxModelEnd() - -oxModelBegin(Palette) - oxModelField(colors) -oxModelEnd() - -oxModelBegin(NostalgiaGraphic) - oxModelField(bpp) - oxModelField(rows) - oxModelField(columns) - oxModelField(defaultPalette) - oxModelField(pal) - oxModelField(pixels) -oxModelEnd() - -oxModelBegin(TileSheet::SubSheet) - oxModelField(name); - oxModelField(rows); - oxModelField(columns); - oxModelField(subsheets) - oxModelField(pixels) -oxModelEnd() - -oxModelBegin(TileSheet) - oxModelField(bpp) - oxModelField(defaultPalette) - oxModelField(subsheet) -oxModelEnd() - -oxModelBegin(CompactTileSheet) - oxModelField(bpp) - oxModelField(defaultPalette) - oxModelField(pixels) -oxModelEnd() - struct Sprite { unsigned idx = 0; int x = 0; diff --git a/src/nostalgia/core/module.cpp b/src/nostalgia/core/module.cpp index fe93aaf9..02f2b0e0 100644 --- a/src/nostalgia/core/module.cpp +++ b/src/nostalgia/core/module.cpp @@ -15,11 +15,12 @@ namespace nostalgia::core { CoreModule CoreModule::mod; -ox::Vector CoreModule::converters() const noexcept { +ox::Vector CoreModule::converters() const noexcept { return { &nostalgiaPaletteToPaletteConverter, &nostalgiaGraphicToTileSheetConverter, &tileSheetToCompactTileSheetConverter, + &tileSheetV2ToTileSheetConverter, }; } @@ -28,9 +29,10 @@ ox::Vector CoreModule::packTransforms() const noexcep // convert tilesheets to CompactTileSheets [](foundation::Context *ctx, ox::Buffer *buff) -> ox::Error { oxRequire(hdr, ox::readClawHeader(*buff)); - const auto typeId = ox::buildTypeId(hdr.typeName, hdr.typeVersion); - if (typeId == ox::buildTypeId() || - typeId == ox::buildTypeId()) { + const auto typeId = ox::buildTypeId(hdr.typeName, hdr.typeVersion, hdr.typeParams); + if (typeId == ox::buildTypeId() || + typeId == ox::buildTypeId() || + typeId == ox::buildTypeId()) { oxReturnError(foundation::convertBuffToBuff(ctx, *buff, ox::ClawFormat::Metal).moveTo(buff)); } return {}; diff --git a/src/nostalgia/core/module.hpp b/src/nostalgia/core/module.hpp index 712351fa..7c3859cd 100644 --- a/src/nostalgia/core/module.hpp +++ b/src/nostalgia/core/module.hpp @@ -12,14 +12,15 @@ namespace nostalgia::core { class CoreModule: public foundation::Module { private: - mutable NostalgiaPaletteToPaletteConverter nostalgiaPaletteToPaletteConverter; - mutable NostalgiaGraphicToTileSheetConverter nostalgiaGraphicToTileSheetConverter; - mutable TileSheetToCompactTileSheetConverter tileSheetToCompactTileSheetConverter; + NostalgiaPaletteToPaletteConverter nostalgiaPaletteToPaletteConverter; + TileSheetV1ToTileSheetConverter nostalgiaGraphicToTileSheetConverter; + TileSheetToCompactTileSheetConverter tileSheetToCompactTileSheetConverter; + TileSheetV2ToTileSheetConverter tileSheetV2ToTileSheetConverter; public: static CoreModule mod; [[nodiscard]] - ox::Vector converters() const noexcept override; + ox::Vector converters() const noexcept override; [[nodiscard]] ox::Vector packTransforms() const noexcept override; }; diff --git a/src/nostalgia/core/palette.hpp b/src/nostalgia/core/palette.hpp new file mode 100644 index 00000000..10c06982 --- /dev/null +++ b/src/nostalgia/core/palette.hpp @@ -0,0 +1,47 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include +#include + +#include +#include + +#include "color.hpp" +#include "context.hpp" +#include "ptidxconv.hpp" + +namespace nostalgia::core { + +struct NostalgiaPalette { + static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaPalette"; + static constexpr auto TypeVersion = 1; + ox::Vector colors = {}; +}; + +struct Palette { + static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.Palette"; + static constexpr auto TypeVersion = 1; + ox::Vector colors = {}; + [[nodiscard]] + constexpr Color16 color(auto idx) const noexcept { + if (idx < colors.size()) [[likely]] { + return colors[idx]; + } + return 0; + } +}; + +oxModelBegin(NostalgiaPalette) + oxModelField(colors) +oxModelEnd() + +oxModelBegin(Palette) + oxModelField(colors) +oxModelEnd() + +} diff --git a/src/nostalgia/core/studio/tilesheeteditormodel.cpp b/src/nostalgia/core/studio/tilesheeteditormodel.cpp index 4a820fe0..f9592e6f 100644 --- a/src/nostalgia/core/studio/tilesheeteditormodel.cpp +++ b/src/nostalgia/core/studio/tilesheeteditormodel.cpp @@ -256,12 +256,12 @@ class AddSubSheetCommand: public TileSheetCommand { auto &parent = m_img->getSubSheet(m_parentIdx); if (m_addedSheets.size() < 2) { auto i = parent.subsheets.size(); - parent.subsheets.emplace_back(ox::sfmt("Subsheet {}", i), 1, 1, m_img->bpp); + parent.subsheets.emplace_back(m_img->idIt++, ox::sfmt("Subsheet {}", i), 1, 1, m_img->bpp); } else { - parent.subsheets.emplace_back("Subsheet 0", parent.columns, parent.rows, std::move(parent.pixels)); + 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("Subsheet 1", 1, 1, m_img->bpp); + parent.subsheets.emplace_back(m_img->idIt++, "Subsheet 1", 1, 1, m_img->bpp); } } diff --git a/src/nostalgia/core/tilesheet.cpp b/src/nostalgia/core/tilesheet.cpp new file mode 100644 index 00000000..464c9da8 --- /dev/null +++ b/src/nostalgia/core/tilesheet.cpp @@ -0,0 +1,9 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include "tilesheet.hpp" + +namespace nostalgia::core { + +} diff --git a/src/nostalgia/core/tilesheet.hpp b/src/nostalgia/core/tilesheet.hpp new file mode 100644 index 00000000..ddcddf0d --- /dev/null +++ b/src/nostalgia/core/tilesheet.hpp @@ -0,0 +1,566 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include +#include + +#include +#include + +#include "color.hpp" +#include "context.hpp" +#include "ptidxconv.hpp" +#include "palette.hpp" + +namespace nostalgia::core { + +// Predecessor to TileSheet, kept for backward compatibility +struct TileSheetV1 { + static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaGraphic"; + static constexpr auto TypeVersion = 1; + int8_t bpp = 0; + // rows and columns are really only used by TileSheetEditor + int rows = 1; + int columns = 1; + ox::FileAddress defaultPalette; + Palette pal; + ox::Vector pixels = {}; +}; + +struct TileSheetV2 { + using SubSheetIdx = ox::Vector; + + struct SubSheet { + static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet.SubSheet"; + static constexpr auto TypeVersion = 1; + ox::String name; + int columns = 0; + int rows = 0; + ox::Vector subsheets; + ox::Vector pixels; + constexpr SubSheet() noexcept = default; + constexpr SubSheet(ox::CRStringView pName, int pColumns, int pRows, int bpp) noexcept: + name(pName), columns(pColumns), rows(pRows), + pixels(static_cast(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) { + } + }; + + static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet"; + static constexpr auto TypeVersion = 2; + int8_t bpp = 4; + ox::FileAddress defaultPalette; + SubSheet subsheet{"Root", 1, 1, bpp}; + +}; + +using SubSheetId = int32_t; + +struct TileSheet { + using SubSheetIdx = ox::Vector; + + struct SubSheet { + static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet.SubSheet"; + static constexpr auto TypeVersion = 3; + SubSheetId id = 0; + ox::String name; + int columns = 0; + int rows = 0; + ox::Vector subsheets; + ox::Vector pixels; + + constexpr SubSheet() noexcept = default; + constexpr SubSheet(const SubSheet &other) noexcept { + id = other.id; + name = other.name; + columns = other.columns; + rows = other.rows; + subsheets = other.subsheets; + pixels = other.pixels; + } + constexpr SubSheet(SubSheet &&other) noexcept { + id = other.id; + 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( + SubSheetId pId, + ox::CRStringView pName, + int pColumns, + int pRows, + int bpp) noexcept: + id(pId), name(pName), columns(pColumns), rows(pRows), + pixels(static_cast(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) { + } + constexpr SubSheet( + SubSheetId pId, + ox::CRStringView pName, + int pColumns, + int pRows, + ox::Vector pPixels) noexcept: + id(pId), name(pName), columns(pColumns), rows(pRows), pixels(std::move(pPixels)) { + } + + constexpr SubSheet &operator=(const SubSheet &other) noexcept = default; + + 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; + } + + [[nodiscard]] + constexpr auto idx(const geo::Point &pt) const noexcept { + return ptToIdx(pt, columns); + } + + /** + * Reads all pixels of this sheet or its children into the given pixel list + * @param pixels + */ + constexpr void readPixelsTo(ox::Vector *pPixels, int8_t bpp) const noexcept { + if (subsheets.size()) { + for (auto &s: subsheets) { + s.readPixelsTo(pPixels); + } + } else { + if (bpp == 4) { + for (auto p: this->pixels) { + pPixels->emplace_back(p & 0b1111); + pPixels->emplace_back(p >> 4); + } + } else { + for (auto p: this->pixels) { + pPixels->emplace_back(p); + } + } + } + } + + /** + * Reads all pixels of this sheet or its children into the given pixel list + * @param pixels + */ + constexpr void readPixelsTo(ox::Vector *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(columns) * static_cast(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 pBpp, std::size_t idx) const noexcept { + if (pBpp == 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 pBpp, const geo::Point &pt) const noexcept { + const auto idx = ptToIdx(pt, columns); + return getPixel(pBpp, idx); + } + + constexpr auto walkPixels(int8_t pBpp, auto callback) const noexcept { + if (pBpp == 4) { + const auto pixelCnt = ox::min(static_cast(columns * rows * PixelsPerTile) / 2, + 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 = pixels[i] & 0xF; + const auto colorIdx2 = pixels[i] >> 4; + callback(i * 2 + 0, colorIdx1); + callback(i * 2 + 1, colorIdx2); + } + } else { + const auto pixelCnt = ox::min(static_cast(columns * rows * PixelsPerTile), + pixels.size()); + for (std::size_t i = 0; i < pixelCnt; ++i) { + const auto p = pixels[i]; + callback(i, p); + } + } + } + + constexpr void setPixel(int8_t pBpp, uint64_t idx, uint8_t palIdx) noexcept { + auto &pixel = this->pixels[idx / 2]; + if (pBpp == 4) { + if (idx & 1) { + pixel = (pixel & 0b0000'1111) | (palIdx << 4); + } else { + pixel = (pixel & 0b1111'0000) | (palIdx); + } + } else { + pixel = palIdx; + } + } + + constexpr void setPixel(int8_t pBpp, const geo::Point &pt, uint8_t palIdx) noexcept { + const auto idx = ptToIdx(pt, columns); + setPixel(pBpp, idx, palIdx); + } + + constexpr auto setPixelCount(int8_t pBpp, std::size_t cnt) noexcept { + switch (pBpp) { + case 4: + pixels.resize(cnt / 2); + return OxError(0); + case 8: + pixels.resize(cnt); + return OxError(0); + default: + return OxError(1, "Invalid pBpp used for TileSheet::SubSheet::setPixelCount"); + } + } + + /** + * 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]] + constexpr unsigned pixelCnt(int8_t pBpp) const noexcept { + return pBpp == 4 ? pixels.size() * 2 : pixels.size(); + } + + /** + * Gets the offset in tiles of the desired subsheet. + */ + [[nodiscard]] + constexpr ox::Result getTileOffset( + const auto &pNamePath, + int8_t pBpp, + std::size_t pIt = 0, + unsigned pCurrentTotal = 0) const noexcept { + // pIt == pNamePath.size() - 1 && + if (name != pNamePath[pIt]) { + return OxError(2, "Wrong branch"); + } + if (pIt == pNamePath.size() - 1) { + return pCurrentTotal; + } + for (auto &sub : subsheets) { + auto [offset, err] = sub.getTileOffset( + pNamePath, pBpp, pIt + 1, pCurrentTotal); + if (!err) { + return offset; + } + pCurrentTotal += sub.pixelCnt(pBpp) / PixelsPerTile; + } + return OxError(1, "SubSheet not found"); + } + + [[nodiscard]] + constexpr ox::Result getIdFor( + const auto &pNamePath, + std::size_t pIt = 0) const noexcept { + for (auto &sub : subsheets) { + if (sub.name == pNamePath[pIt]) { + if (pIt == pNamePath.size()) { + return id; + } + return getIdFor(pNamePath, pIt + 1); + } + } + return OxError(1, "SubSheet not found"); + } + + [[nodiscard]] + constexpr ox::Result getNameFor(SubSheetId pId) const noexcept { + if (id == pId) { + return ox::StringView(name); + } + for (const auto &sub : subsheets) { + const auto [name, err] = sub.getNameFor(pId); + if (!err) { + return name; + } + } + return OxError(1, "SubSheet not found"); + } + + }; + + static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet"; + static constexpr auto TypeVersion = 3; + int8_t bpp = 4; + SubSheetId idIt = 0; + ox::FileAddress defaultPalette; + SubSheet subsheet{0, "Root", 1, 1, bpp}; + + constexpr TileSheet() noexcept = default; + TileSheet(const TileSheet &other) noexcept = default; + inline TileSheet(TileSheet &&other) noexcept: + bpp(other.bpp), + idIt(other.idIt), + defaultPalette(std::move(other.defaultPalette)), + subsheet(std::move(other.subsheet)) { + } + + inline auto &operator=(const TileSheet &other) noexcept { + if (this != &other) { + bpp = other.bpp; + idIt = other.idIt; + defaultPalette = other.defaultPalette; + subsheet = other.subsheet; + } + return *this; + } + inline auto &operator=(TileSheet &&other) noexcept { + bpp = other.bpp; + idIt = other.idIt; + 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; + if (pSubsheet->subsheets.size()) { + out.back().value = pSubsheet->subsheets.size() - 1; + } else { + out.pop_back(); + } + 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 SubSheet &getSubSheet( + const SubSheetIdx &idx, + std::size_t idxIt, + const SubSheet *pSubsheet) noexcept { + if (idxIt == idx.size()) { + return *pSubsheet; + } + const auto currentIdx = idx[idxIt]; + if (pSubsheet->subsheets.size() < currentIdx) { + return *pSubsheet; + } + return getSubSheet(idx, idxIt + 1, &pSubsheet->subsheets[currentIdx]); + } + + [[nodiscard]] + constexpr static SubSheet &getSubSheet( + const SubSheetIdx &idx, + std::size_t idxIt, + SubSheet *pSubsheet) noexcept { + if (idxIt == idx.size()) { + return *pSubsheet; + } + return getSubSheet(idx, idxIt + 1, &pSubsheet->subsheets[idx[idxIt]]); + } + + [[nodiscard]] + constexpr const SubSheet &getSubSheet(const SubSheetIdx &idx) const noexcept { + return getSubSheet(idx, 0, &subsheet); + } + + [[nodiscard]] + constexpr SubSheet &getSubSheet(const SubSheetIdx &idx) noexcept { + 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(idIt++, ox::sfmt("Subsheet {}", parent.subsheets.size()), 1, 1, bpp); + } else { + parent.subsheets.emplace_back(idIt++, "Subsheet 0", parent.columns, parent.rows, bpp); + parent.subsheets.emplace_back(idIt++, "Subsheet 1", 1, 1, bpp); + } + return OxError(0); + } + + [[nodiscard]] + constexpr static auto rmSubSheet( + const SubSheetIdx &idx, + std::size_t idxIt, + SubSheet *pSubsheet) noexcept { + if (idxIt == idx.size() - 1) { + return pSubsheet->subsheets.erase(idx[idxIt]).error; + } + return rmSubSheet(idx, idxIt + 1, &pSubsheet->subsheets[idx[idxIt]]); + } + + [[nodiscard]] + constexpr auto rmSubSheet(const SubSheetIdx &idx) noexcept { + return rmSubSheet(idx, 0, &subsheet); + } + + [[nodiscard]] + constexpr auto getPixel4Bpp( + const geo::Point &pt, + const SubSheetIdx &subsheetIdx) const noexcept { + oxAssert(bpp == 4, "TileSheet::getPixel4Bpp: wrong bpp"); + 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, "TileSheet::getPixel8Bpp: wrong bpp"); + auto &s = this->getSubSheet(subsheetIdx); + const auto idx = ptToIdx(pt, s.columns); + return s.getPixel8Bpp(idx); + } + + [[nodiscard]] + constexpr auto getIdFor(ox::CRStringView path) const noexcept { + return subsheet.getIdFor(ox::split<8>(path, '.')); + } + + constexpr ox::Result getTileOffset(const auto &pNamePath) const noexcept { + return subsheet.getTileOffset(ox::split<8>(pNamePath, '.'), bpp); + } + + constexpr ox::Result getNameFor(SubSheetId pId) const noexcept { + return subsheet.getNameFor(pId); + } + + [[nodiscard]] + auto pixels() const noexcept { + ox::Vector out; + subsheet.readPixelsTo(&out); + return out; + } + +}; + +struct CompactTileSheet { + static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.CompactTileSheet"; + static constexpr auto TypeVersion = 1; + int8_t bpp = 0; + ox::FileAddress defaultPalette; + ox::Vector pixels = {}; +}; + +oxModelBegin(TileSheetV1) + oxModelField(bpp) + oxModelField(rows) + oxModelField(columns) + oxModelField(defaultPalette) + oxModelField(pal) + oxModelField(pixels) +oxModelEnd() + +oxModelBegin(TileSheetV2::SubSheet) + oxModelField(name); + oxModelField(rows); + oxModelField(columns); + oxModelField(subsheets) + oxModelField(pixels) +oxModelEnd() + +oxModelBegin(TileSheetV2) + oxModelField(bpp) + oxModelField(defaultPalette) + oxModelField(subsheet) +oxModelEnd() + +oxModelBegin(TileSheet::SubSheet) + oxModelField(name); + oxModelField(rows); + oxModelField(columns); + oxModelField(subsheets) + oxModelField(pixels) +oxModelEnd() + +oxModelBegin(TileSheet) + oxModelField(bpp) + oxModelField(idIt) + oxModelField(defaultPalette) + oxModelField(subsheet) +oxModelEnd() + +oxModelBegin(CompactTileSheet) + oxModelField(bpp) + oxModelField(defaultPalette) + oxModelField(pixels) +oxModelEnd() + +} diff --git a/src/nostalgia/core/typeconv.cpp b/src/nostalgia/core/typeconv.cpp new file mode 100644 index 00000000..461b0275 --- /dev/null +++ b/src/nostalgia/core/typeconv.cpp @@ -0,0 +1,67 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include "typeconv.hpp" + +namespace nostalgia::core { + +ox::Error NostalgiaPaletteToPaletteConverter::convert( + foundation::Context*, + NostalgiaPalette *src, + Palette *dst) const noexcept { + dst->colors = std::move(src->colors); + return {}; +} + +ox::Error TileSheetV1ToTileSheetConverter::convert( + foundation::Context*, + TileSheetV1 *src, + TileSheet *dst) const noexcept { + dst->bpp = src->bpp; + dst->defaultPalette = std::move(src->defaultPalette); + dst->subsheet.name = "Root"; + dst->subsheet.rows = src->rows; + dst->subsheet.columns = src->columns; + dst->subsheet.pixels = std::move(src->pixels); + return {}; +} + +ox::Error TileSheetToCompactTileSheetConverter::convert( + foundation::Context*, + TileSheet *src, + CompactTileSheet *dst) const noexcept { + dst->bpp = src->bpp; + dst->defaultPalette = std::move(src->defaultPalette); + dst->pixels = src->pixels(); + return {}; +} + + +void TileSheetV2ToTileSheetConverter::convertSubsheet( + TileSheetV2::SubSheet *src, + TileSheet::SubSheet *dst, + SubSheetId *idIt) noexcept { + dst->id = *idIt; + dst->name = std::move(src->name); + dst->columns = src->columns; + dst->rows = src->rows; + dst->pixels = std::move(src->pixels); + ++*idIt; + dst->subsheets.resize(src->subsheets.size()); + for (auto i = 0u; i < src->subsheets.size(); ++i) { + convertSubsheet(&src->subsheets[i], &dst->subsheets[i], idIt); + } +} + +ox::Error TileSheetV2ToTileSheetConverter::convert( + foundation::Context*, + TileSheetV2 *src, + TileSheet *dst) const noexcept { + dst->bpp = src->bpp; + dst->defaultPalette = std::move(src->defaultPalette); + convertSubsheet(&src->subsheet, &dst->subsheet, &dst->idIt); + return {}; +} + +} diff --git a/src/nostalgia/core/typeconv.hpp b/src/nostalgia/core/typeconv.hpp index 50bfdc22..3c65f399 100644 --- a/src/nostalgia/core/typeconv.hpp +++ b/src/nostalgia/core/typeconv.hpp @@ -15,32 +15,26 @@ namespace nostalgia::core { // Type converters -struct NostalgiaPaletteToPaletteConverter: public foundation::Converter { - ox::Error convert(foundation::Context*, NostalgiaPalette *src, Palette *dst) noexcept final { - dst->colors = std::move(src->colors); - return {}; - } +class NostalgiaPaletteToPaletteConverter: public foundation::Converter { + ox::Error convert(foundation::Context*, NostalgiaPalette *src, Palette *dst) const noexcept final; }; -struct NostalgiaGraphicToTileSheetConverter: public foundation::Converter { - ox::Error convert(foundation::Context*, NostalgiaGraphic *src, TileSheet *dst) noexcept final { - dst->bpp = src->bpp; - dst->subsheet.name = "Root"; - dst->subsheet.rows = src->rows; - dst->subsheet.columns = src->columns; - dst->defaultPalette = std::move(src->defaultPalette); - dst->subsheet.pixels = std::move(src->pixels); - return {}; - } +class TileSheetV1ToTileSheetConverter: public foundation::Converter { + ox::Error convert(foundation::Context*, TileSheetV1 *src, TileSheet *dst) const noexcept final; }; -struct TileSheetToCompactTileSheetConverter: public foundation::Converter { - ox::Error convert(foundation::Context*, TileSheet *src, CompactTileSheet *dst) noexcept final { - dst->bpp = src->bpp; - dst->defaultPalette = std::move(src->defaultPalette); - dst->pixels = src->pixels(); - return {}; - } +class TileSheetToCompactTileSheetConverter: public foundation::Converter { + ox::Error convert(foundation::Context*, TileSheet *src, CompactTileSheet *dst) const noexcept final; +}; + +class TileSheetV2ToTileSheetConverter: public foundation::Converter { + static void convertSubsheet( + TileSheetV2::SubSheet *src, + TileSheet::SubSheet *dst, + SubSheetId *idIt) noexcept; + + ox::Error convert(foundation::Context*, TileSheetV2 *src, TileSheet *dst) const noexcept final; + }; } diff --git a/src/nostalgia/core/userland/gfx_opengl.cpp b/src/nostalgia/core/userland/gfx_opengl.cpp index 95fbb9d7..1e6cd9d1 100644 --- a/src/nostalgia/core/userland/gfx_opengl.cpp +++ b/src/nostalgia/core/userland/gfx_opengl.cpp @@ -511,7 +511,10 @@ void setSprite(Context *ctx, } void setTile(Context *ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept { - //oxTracef("nostalgia::core::gfx::gl", "setTile(ctx, {}, {}, {}, {})", bgIdx, column, row, tile); + oxTracef( + "nostalgia::core::gfx::setTile", + "bgIdx: {}, column: {}, row: {}, tile: {}", + bgIdx, column, row, tile); const auto id = ctx->rendererData(); const auto z = static_cast(bgIdx); const auto y = static_cast(row); @@ -520,8 +523,10 @@ void setTile(Context *ctx, unsigned bgIdx, int column, int row, uint8_t tile) no auto &bg = id->cbbs[z]; auto vbo = &bg.vertices[i * renderer::BgVertexVboLength]; auto ebo = &bg.elements[i * renderer::BgVertexEboLength]; - renderer::setTileBufferObject(ctx, i * renderer::BgVertexVboRows, - static_cast(x), static_cast(y), tile, vbo, ebo); + renderer::setTileBufferObject( + ctx, i * renderer::BgVertexVboRows, + static_cast(x), static_cast(y), + tile, vbo, ebo); bg.updated = true; } diff --git a/src/nostalgia/foundation/context.hpp b/src/nostalgia/foundation/context.hpp index e2c0a695..24add52d 100644 --- a/src/nostalgia/foundation/context.hpp +++ b/src/nostalgia/foundation/context.hpp @@ -21,7 +21,7 @@ class Context { ox::StringView appName = "Nostalgia Foundation App"; #ifndef OX_BARE_METAL AssetManager assetManager; - ox::Vector converters; + ox::Vector converters; ox::Vector packTransforms; #else std::size_t preloadSectionOffset = 0; diff --git a/src/nostalgia/foundation/module.cpp b/src/nostalgia/foundation/module.cpp index 9fe570e8..aeb8353e 100644 --- a/src/nostalgia/foundation/module.cpp +++ b/src/nostalgia/foundation/module.cpp @@ -18,7 +18,7 @@ const ox::Vector *modules() noexcept { } -ox::Vector Module::converters() const noexcept { +ox::Vector Module::converters() const noexcept { return {}; } diff --git a/src/nostalgia/foundation/module.hpp b/src/nostalgia/foundation/module.hpp index 6687f262..642cbe89 100644 --- a/src/nostalgia/foundation/module.hpp +++ b/src/nostalgia/foundation/module.hpp @@ -19,7 +19,7 @@ class Module { Module &operator=(Module&&) noexcept = delete; constexpr virtual ~Module() noexcept = default; [[nodiscard]] - virtual ox::Vector converters() const noexcept; + virtual ox::Vector converters() const noexcept; [[nodiscard]] virtual ox::Vector packTransforms() const noexcept; }; diff --git a/src/nostalgia/foundation/typeconv.cpp b/src/nostalgia/foundation/typeconv.cpp index 8f281abc..a32ba101 100644 --- a/src/nostalgia/foundation/typeconv.cpp +++ b/src/nostalgia/foundation/typeconv.cpp @@ -11,9 +11,10 @@ namespace nostalgia::foundation { #ifndef OX_BARE_METAL [[nodiscard]] -static auto findConverter(foundation::Context *ctx, - ox::CRStringView srcTypeName, int srcTypeVersion, - ox::CRStringView dstTypeName, int dstTypeVersion) noexcept -> ox::Result { +static ox::Result findConverter( + foundation::Context *ctx, + ox::CRStringView srcTypeName, int srcTypeVersion, + ox::CRStringView dstTypeName, int dstTypeVersion) noexcept { for (auto &c : ctx->converters) { if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) { return c; @@ -22,13 +23,14 @@ static auto findConverter(foundation::Context *ctx, return OxError(1, "Could not find converter"); }; -static ox::Result> convert(foundation::Context *ctx, const ox::Buffer &srcBuffer, - ox::CRStringView srcTypeName, int srcTypeVersion, - ox::CRStringView dstTypeName, int dstTypeVersion) noexcept { +static ox::Result> convert( + foundation::Context *ctx, const ox::Buffer &srcBuffer, + ox::CRStringView srcTypeName, int srcTypeVersion, + ox::CRStringView dstTypeName, int dstTypeVersion) noexcept { // look for direct converter auto [c, err] = findConverter(ctx, srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion); if (!err) { - return c->convertBuffToPtr(nullptr, srcBuffer); + return c->convertBuffToPtr(ctx, srcBuffer); } // try to chain multiple converters for (const auto &subConverter : ctx->converters) { @@ -45,7 +47,11 @@ static ox::Result> convert(foundation::Context *ctx, const o return OxError(1, "Could not convert between types"); } -ox::Result> convert(foundation::Context *ctx, const ox::Buffer &srcBuffer, ox::CRStringView dstTypeName, int dstTypeVersion) noexcept { +ox::Result> convert( + foundation::Context *ctx, + const ox::Buffer &srcBuffer, + ox::CRStringView dstTypeName, + int dstTypeVersion) noexcept { oxRequire(hdr, ox::readClawHeader(srcBuffer)); return convert(ctx, srcBuffer, hdr.typeName, hdr.typeVersion, dstTypeName, dstTypeVersion); } diff --git a/src/nostalgia/foundation/typeconv.hpp b/src/nostalgia/foundation/typeconv.hpp index fad5e612..b2da2acb 100644 --- a/src/nostalgia/foundation/typeconv.hpp +++ b/src/nostalgia/foundation/typeconv.hpp @@ -53,20 +53,20 @@ class BaseConverter { virtual ~BaseConverter() noexcept = default; [[nodiscard]] - virtual ox::StringView srcTypeName() noexcept = 0; + virtual ox::StringView srcTypeName() const noexcept = 0; [[nodiscard]] - virtual int srcTypeVersion() noexcept = 0; + virtual int srcTypeVersion() const noexcept = 0; [[nodiscard]] - virtual bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept = 0; + virtual bool srcMatches(ox::CRStringView pSrcTypeName, int pSrcTypeVersion) const noexcept = 0; [[nodiscard]] virtual bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept = 0; - virtual ox::Result> convertPtrToPtr(foundation::Context *ctx, Wrap *src) noexcept = 0; + virtual ox::Result> convertPtrToPtr(foundation::Context *ctx, Wrap *src) const noexcept = 0; - virtual ox::Result> convertBuffToPtr(foundation::Context *ctx, const ox::Buffer &srcBuff) noexcept = 0; + virtual ox::Result> convertBuffToPtr(foundation::Context *ctx, const ox::Buffer &srcBuff) const noexcept = 0; [[nodiscard]] inline bool matches(ox::CRStringView srcTypeName, int srcTypeVersion, @@ -80,47 +80,48 @@ class BaseConverter { template class Converter: public BaseConverter { public: - virtual ox::Error convert(foundation::Context *ctx, SrcType*, DstType*) noexcept = 0; - [[nodiscard]] - ox::StringView srcTypeName() noexcept final { + ox::StringView srcTypeName() const noexcept final { return ox::requireModelTypeName(); } [[nodiscard]] - int srcTypeVersion() noexcept final { + int srcTypeVersion() const noexcept final { return ox::requireModelTypeVersion(); } [[nodiscard]] - bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept final { - static constexpr auto SrcTypeName = ox::requireModelTypeName(); - static constexpr auto SrcTypeVersion = ox::requireModelTypeVersion(); - return ox_strcmp(srcTypeName, SrcTypeName) == 0 - && srcTypeVersion == SrcTypeVersion; + bool srcMatches(ox::CRStringView pSrcTypeName, int pSrcTypeVersion) const noexcept final { + static const auto SrcTypeName = ox::requireModelTypeName(); + static const auto SrcTypeVersion = ox::requireModelTypeVersion(); + return pSrcTypeName == SrcTypeName + && pSrcTypeVersion == SrcTypeVersion; } [[nodiscard]] bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept final { - static constexpr auto DstTypeName = ox::requireModelTypeName(); - static constexpr auto DstTypeVersion = ox::requireModelTypeVersion(); - return ox_strcmp(dstTypeName, DstTypeName) == 0 + static const auto DstTypeName = ox::StringView(ox::requireModelTypeName()); + static const auto DstTypeVersion = ox::requireModelTypeVersion(); + return dstTypeName == DstTypeName && dstTypeVersion == DstTypeVersion; } - ox::Result> convertPtrToPtr(foundation::Context *ctx, Wrap *src) noexcept final { + ox::Result> convertPtrToPtr(foundation::Context *ctx, Wrap *src) const noexcept final { auto dst = makeWrap(); oxReturnError(convert(ctx, wrapCast(src), wrapCast(dst.get()))); return ox::Result>(std::move(dst)); } - ox::Result> convertBuffToPtr(foundation::Context *ctx, const ox::Buffer &srcBuff) noexcept final { + ox::Result> convertBuffToPtr(foundation::Context *ctx, const ox::Buffer &srcBuff) const noexcept final { oxRequireM(src, ox::readClaw(srcBuff)); auto dst = makeWrap(); oxReturnError(convert(ctx, &src, wrapCast(dst.get()))); return ox::Result>(std::move(dst)); } + protected: + virtual ox::Error convert(foundation::Context *ctx, SrcType*, DstType*) const noexcept = 0; + }; ox::Result> convert(foundation::Context *ctx, const ox::Buffer &srcBuffer, diff --git a/src/nostalgia/player/app.cpp b/src/nostalgia/player/app.cpp index c4ee6652..2655ab77 100644 --- a/src/nostalgia/player/app.cpp +++ b/src/nostalgia/player/app.cpp @@ -4,41 +4,19 @@ #include #include +#include using namespace nostalgia; -static int spriteX = 72; -static int spriteY = 64; -static ox::StringView sprites = "nostalgia"; -static bool paused = false; +static bool s_paused = false; +static ox::Optional s_scene; -static int updateHandler(core::Context *ctx) noexcept { +static int updateHandler(core::Context*) noexcept { constexpr auto sleepTime = 16; - if (paused) { + if (s_paused) { return sleepTime; } - int xmod = 0; - int ymod = 0; - if (buttonDown(ctx, core::Alpha_D) || buttonDown(ctx, core::GamePad_Right)) { - xmod = 2; - } else if (buttonDown(ctx, core::Alpha_A) || buttonDown(ctx, core::GamePad_Left)) { - xmod = -2; - } - if (buttonDown(ctx, core::Alpha_S) || buttonDown(ctx, core::GamePad_Down)) { - ymod = 2; - } else if (buttonDown(ctx, core::Alpha_W) || buttonDown(ctx, core::GamePad_Up)) { - ymod = -2; - } - if (!xmod && !ymod) { - spriteX += 1; - } - spriteX += xmod; - spriteY += ymod; - //constexpr ox::StringView sprites = "nostalgia"; - for (unsigned i = 0; i < sprites.len(); ++i) { - const auto c = static_cast(sprites[i] - ('a' - 1)); - core::setSprite(ctx, i, spriteX + 8 * (static_cast(i) + 1), spriteY, c, 0, 0, 0); - } + // do stuff return sleepTime; } @@ -47,7 +25,7 @@ static void keyEventHandler(core::Context *ctx, core::Key key, bool down) noexce if (key == core::Key::Alpha_Q) { core::shutdown(ctx); } else if (key == core::Key::Alpha_P) { - paused = !paused; + s_paused = !s_paused; } } } @@ -55,13 +33,11 @@ static void keyEventHandler(core::Context *ctx, core::Key key, bool down) noexce ox::Error run(ox::UniquePtr fs) noexcept { oxTraceInitHook(); oxRequireM(ctx, core::init(std::move(fs))); - constexpr ox::FileAddress TileSheetAddr("/TileSheets/Charset.ng"); - constexpr ox::FileAddress PaletteAddr("/Palettes/Charset.npal"); - oxRequire(tsStat, ctx->rom->stat(PaletteAddr)); - oxReturnError(core::loadSpriteTileSheet(ctx.get(), TileSheetAddr, PaletteAddr)); - oxReturnError(core::initConsole(ctx.get())); - core::puts(ctx.get(), 10, 9, "DOPENESS!!!"); + constexpr ox::FileAddress SceneAddr("/Scenes/Chester.nscn"); + oxRequire(scn, foundation::readObj(ctx.get(), SceneAddr)); core::setUpdateHandler(ctx.get(), updateHandler); core::setKeyEventHandler(ctx.get(), keyEventHandler); + s_scene.emplace(scn.get()); + oxReturnError(s_scene->setupDisplay(ctx.get())); return core::run(ctx.get()); } diff --git a/src/nostalgia/scene/CMakeLists.txt b/src/nostalgia/scene/CMakeLists.txt index 128036b0..610736da 100644 --- a/src/nostalgia/scene/CMakeLists.txt +++ b/src/nostalgia/scene/CMakeLists.txt @@ -2,6 +2,7 @@ add_library( NostalgiaScene scene.cpp + scenestatic.cpp scenemodule.cpp typeconv.cpp ) @@ -9,11 +10,12 @@ add_library( target_link_libraries( NostalgiaScene PUBLIC NostalgiaCore + NostalgiaGeo ) install( FILES - scene.hpp + scenestatic.hpp scenemodule.hpp typeconv.hpp DESTINATION diff --git a/src/nostalgia/scene/scene.cpp b/src/nostalgia/scene/scene.cpp index 9e440fd6..e80564e5 100644 --- a/src/nostalgia/scene/scene.cpp +++ b/src/nostalgia/scene/scene.cpp @@ -1,11 +1,46 @@ /* - * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ +#include + #include "scene.hpp" namespace nostalgia::scene { +Scene::Scene(const SceneStatic *sceneStatic) noexcept: + m_sceneStatic(sceneStatic) { +} +ox::Error Scene::setupDisplay(core::Context *ctx) noexcept { + if (m_sceneStatic->palettes.empty()) { + return OxError(1, "Scene has no palettes"); + } + const auto &palette = m_sceneStatic->palettes[0]; + oxReturnError(core::loadBgTileSheet( + ctx, 0, m_sceneStatic->tilesheet, palette)); + // disable all backgrounds + core::setBgStatus(ctx, 0); + for (auto layerNo = 0u; const auto &layer : m_sceneStatic->tileMapIdx) { + core::setBgStatus(ctx, layerNo, true); + core::setBgCbb(ctx, layerNo, 0); + auto x = 0; + auto y = 0; + auto width = m_sceneStatic->rows[layerNo]; + for (const auto &tile : layer) { + core::setTile(ctx, layerNo, x, y, tile); + core::setTile(ctx, layerNo, x + 1, y, tile + 1); + core::setTile(ctx, layerNo, x, y + 1, tile + 2); + core::setTile(ctx, layerNo, x + 1, y + 1, tile + 3); + x += 2; + if (x >= width * 2) { + x = 0; + y += 2; + } + } + ++layerNo; + } + return {}; +} } diff --git a/src/nostalgia/scene/scene.hpp b/src/nostalgia/scene/scene.hpp index 64ffbf56..6189103f 100644 --- a/src/nostalgia/scene/scene.hpp +++ b/src/nostalgia/scene/scene.hpp @@ -4,104 +4,19 @@ #pragma once -#include -#include -#include -#include +#include "scenestatic.hpp" namespace nostalgia::scene { -struct TileDoc { +class Scene { + private: + const SceneStatic *m_sceneStatic = nullptr; - constexpr static auto TypeName = "net.drinkingtea.nostalgia.scene.TileDoc"; - constexpr static auto TypeVersion = 1; - constexpr static auto Preloadable = true; + public: + explicit Scene(const SceneStatic *sceneStatic) noexcept; - ox::String sheetIdx; - uint8_t type = 0; + ox::Error setupDisplay(core::Context *ctx) noexcept; }; -oxModelBegin(TileDoc) - oxModelFieldRename(sheet_idx, sheetIdx); - oxModelField(type); -oxModelEnd() - -struct SceneDoc { - - using TileMapRow = ox::Vector; - using TileMapLayer = ox::Vector; - using TileMap = ox::Vector; - - constexpr static auto TypeName = "net.drinkingtea.nostalgia.scene.SceneDoc"; - constexpr static auto TypeVersion = 1; - constexpr static auto Preloadable = true; - - ox::FileAddress tilesheet; - ox::FileAddress palette; - TileMap tiles; - -}; - -oxModelBegin(SceneDoc) - oxModelField(tilesheet) - oxModelField(palette) - oxModelField(tiles) -oxModelEnd() - -struct Scene { - - constexpr static auto TypeName = "net.drinkingtea.nostalgia.scene.Scene"; - constexpr static auto TypeVersion = 1; - constexpr static auto Preloadable = true; - - struct Tile { - uint16_t &tileMapIdx; - uint8_t &tileType; - constexpr Tile(uint16_t &pTileMapIdx, uint8_t &pTileType) noexcept: - tileMapIdx(pTileMapIdx), - tileType(pTileType) { - } - }; - struct Layer { - uint16_t &columns; - uint16_t &rows; - uint16_t *tileMapIdx = nullptr; - uint8_t *tileType = nullptr; - constexpr Layer(uint16_t &pColumns, - uint16_t &pRows, - uint16_t *pTileMapIdx, - uint8_t *pTileType) noexcept: - columns(pColumns), - rows(pRows), - tileMapIdx(pTileMapIdx), - tileType(pTileType) { - } - [[nodiscard]] - constexpr Tile tile(std::size_t i) const noexcept { - return {tileMapIdx[i], tileType[i]}; - } - }; - - uint16_t layers = 0; - ox::Vector columns; - ox::Vector rows; - ox::Vector> tileMapIdx; - ox::Vector> tileType; - - [[nodiscard]] - constexpr Layer layer(std::size_t i) noexcept { - return {columns[i], rows[i], tileMapIdx[i].data(), tileType[i].data()}; - } - -}; - -oxModelBegin(Scene) - oxModelField(layers) - oxModelField(columns) - oxModelField(rows) - oxModelFieldRename(tile_map_idx, tileMapIdx) - oxModelFieldRename(tile_type, tileType) -oxModelEnd() - } diff --git a/src/nostalgia/scene/scenemodule.cpp b/src/nostalgia/scene/scenemodule.cpp index 328c263f..8f4533cd 100644 --- a/src/nostalgia/scene/scenemodule.cpp +++ b/src/nostalgia/scene/scenemodule.cpp @@ -10,15 +10,15 @@ namespace nostalgia::scene { SceneModule SceneModule::mod; -ox::Vector SceneModule::converters() const noexcept { +ox::Vector SceneModule::converters() const noexcept { return { - &sceneToSceneInstaceConverter, + &sceneDocToSceneStaticConverter, }; } ox::Vector SceneModule::packTransforms() const noexcept { return { - foundation::transformRule, + foundation::transformRule, }; } diff --git a/src/nostalgia/scene/scenemodule.hpp b/src/nostalgia/scene/scenemodule.hpp index 9c6e62fa..30c4c8cc 100644 --- a/src/nostalgia/scene/scenemodule.hpp +++ b/src/nostalgia/scene/scenemodule.hpp @@ -12,12 +12,12 @@ namespace nostalgia::scene { class SceneModule: public foundation::Module { private: - mutable SceneDocToSceneConverter sceneToSceneInstaceConverter; + SceneDocToSceneStaticConverter sceneDocToSceneStaticConverter; public: static SceneModule mod; [[nodiscard]] - ox::Vector converters() const noexcept override; + ox::Vector converters() const noexcept override; [[nodiscard]] ox::Vector packTransforms() const noexcept override; }; diff --git a/src/nostalgia/scene/scenestatic.cpp b/src/nostalgia/scene/scenestatic.cpp new file mode 100644 index 00000000..3f9b653a --- /dev/null +++ b/src/nostalgia/scene/scenestatic.cpp @@ -0,0 +1,11 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#include "scenestatic.hpp" + +namespace nostalgia::scene { + + + +} diff --git a/src/nostalgia/scene/scenestatic.hpp b/src/nostalgia/scene/scenestatic.hpp new file mode 100644 index 00000000..794d3f3c --- /dev/null +++ b/src/nostalgia/scene/scenestatic.hpp @@ -0,0 +1,164 @@ +/* + * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace nostalgia::scene { + +struct TileDoc { + + constexpr static auto TypeName = "net.drinkingtea.nostalgia.scene.TileDoc"; + constexpr static auto TypeVersion = 1; + constexpr static auto Preloadable = true; + + core::SubSheetId subsheetId = -1; + ox::String subsheetPath; + uint8_t type = 0; + + [[nodiscard]] + constexpr ox::Result getSubsheetId(const core::TileSheet &ts) const noexcept { + // prefer the already present ID + if (subsheetId > -1) { + return subsheetId; + } + return ts.getIdFor(subsheetPath); + } + + [[nodiscard]] + constexpr ox::Result getSubsheetPath( + const core::TileSheet &ts) const noexcept { + // prefer the already present path + if (!subsheetPath.len()) { + return ts.getNameFor(subsheetId); + } + return ox::StringView(subsheetPath); + } + +}; + +oxModelBegin(TileDoc) + oxModelFieldRename(subsheet_id, subsheetId); + oxModelFieldRename(subsheet_path, subsheetPath); + oxModelField(type); +oxModelEnd() + +struct SceneDoc { + + using TileMapRow = ox::Vector; + using TileMapLayer = ox::Vector; + using TileMap = ox::Vector; + + constexpr static auto TypeName = "net.drinkingtea.nostalgia.scene.SceneDoc"; + constexpr static auto TypeVersion = 1; + constexpr static auto Preloadable = true; + + ox::String tilesheet; // path + ox::Vector palettes; // paths + TileMap tiles; + + [[nodiscard]] + constexpr geo::Size size(std::size_t layerIdx) const noexcept { + const auto &layer = this->tiles[layerIdx]; + const auto rowCnt = static_cast(layer.size()); + if (!rowCnt) { + return {}; + } + auto colCnt = layer[0].size(); + // find shortest row (they should all be the same, but you know this data + // could come from a file) + for (const auto &row : layer) { + colCnt = ox::min(colCnt, row.size()); + } + return {static_cast(colCnt), rowCnt}; + } +}; + +oxModelBegin(SceneDoc) + oxModelField(tilesheet) + oxModelField(palettes) + oxModelField(tiles) +oxModelEnd() + +struct SceneStatic { + + constexpr static auto TypeName = "net.drinkingtea.nostalgia.scene.SceneStatic"; + constexpr static auto TypeVersion = 1; + constexpr static auto Preloadable = true; + + struct Tile { + uint16_t &tileMapIdx; + uint8_t &tileType; + constexpr Tile(uint16_t *pTileMapIdx, uint8_t *pTileType) noexcept: + tileMapIdx(*pTileMapIdx), + tileType(*pTileType) { + } + }; + struct Layer { + uint16_t &columns; + uint16_t &rows; + ox::Vector &tileMapIdx; + ox::Vector &tileType; + constexpr Layer( + uint16_t *pColumns, + uint16_t *pRows, + ox::Vector *pTileMapIdx, + ox::Vector *pTileType) noexcept: + columns(*pColumns), + rows(*pRows), + tileMapIdx(*pTileMapIdx), + tileType(*pTileType) { + } + [[nodiscard]] + constexpr Tile tile(std::size_t i) noexcept { + return {&tileMapIdx[i], &tileType[i]}; + } + constexpr auto setDimensions(geo::Size dim) noexcept { + columns = dim.width; + rows = dim.height; + const auto tileCnt = static_cast(columns * rows); + tileMapIdx.resize(tileCnt); + tileType.resize(tileCnt); + } + }; + + ox::FileAddress tilesheet; + ox::Vector palettes; + // tile layer data + ox::Vector columns; + ox::Vector rows; + ox::Vector> tileMapIdx; + ox::Vector> tileType; + + [[nodiscard]] + constexpr Layer layer(std::size_t i) noexcept { + return {&columns[i], &rows[i], &tileMapIdx[i], &tileType[i]}; + } + + constexpr auto setLayerCnt(std::size_t layerCnt) noexcept { + this->columns.resize(layerCnt); + this->rows.resize(layerCnt); + this->tileMapIdx.resize(layerCnt); + this->tileType.resize(layerCnt); + } + +}; + +oxModelBegin(SceneStatic) + oxModelField(tilesheet) + oxModelField(palettes) + oxModelField(columns) + oxModelField(rows) + oxModelFieldRename(tile_map_idx, tileMapIdx) + oxModelFieldRename(tile_type, tileType) +oxModelEnd() + +} diff --git a/src/nostalgia/scene/typeconv.cpp b/src/nostalgia/scene/typeconv.cpp index 3dbf4e10..517736f8 100644 --- a/src/nostalgia/scene/typeconv.cpp +++ b/src/nostalgia/scene/typeconv.cpp @@ -2,13 +2,41 @@ * Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. */ +#include +#include + #include "typeconv.hpp" namespace nostalgia::scene { -// Type converters - -ox::Error SceneDocToSceneConverter::convert(foundation::Context*, SceneDoc *, Scene *) noexcept { +ox::Error SceneDocToSceneStaticConverter::convert( + foundation::Context *ctx, + SceneDoc *src, + SceneStatic *dst) const noexcept { + oxRequire(ts, foundation::readObj(ctx, src->tilesheet)); + const auto layerCnt = src->tiles.size(); + dst->setLayerCnt(layerCnt); + dst->tilesheet = ox::FileAddress(src->tilesheet); + dst->palettes.reserve(src->palettes.size()); + for (const auto &pal : src->palettes) { + dst->palettes.emplace_back(pal); + } + for (auto layerIdx = 0u; const auto &layer : src->tiles) { + const auto layerDim = src->size(layerIdx); + auto dstLayer = dst->layer(layerIdx); + dstLayer.setDimensions(layerDim); + for (auto tileIdx = 0u; const auto &row : layer) { + for (const auto &srcTile : row) { + auto dstTile = dstLayer.tile(tileIdx); + dstTile.tileType = srcTile.type; + oxRequire(path, srcTile.getSubsheetPath(*ts)); + oxRequire(mapIdx, ts->getTileOffset(path)); + dstTile.tileMapIdx = static_cast(mapIdx); + ++tileIdx; + } + } + ++layerIdx; + } return {}; } diff --git a/src/nostalgia/scene/typeconv.hpp b/src/nostalgia/scene/typeconv.hpp index d10fa917..5a8c60e2 100644 --- a/src/nostalgia/scene/typeconv.hpp +++ b/src/nostalgia/scene/typeconv.hpp @@ -6,12 +6,12 @@ #include -#include "scene.hpp" +#include "scenestatic.hpp" namespace nostalgia::scene { -struct SceneDocToSceneConverter: public foundation::Converter { - ox::Error convert(foundation::Context*, SceneDoc *src, Scene *dst) noexcept final; +class SceneDocToSceneStaticConverter: public foundation::Converter { + ox::Error convert(foundation::Context*, SceneDoc *src, SceneStatic *dst) const noexcept final; }; }