[nostalgia] Fill out basic Scene system functionality
This commit is contained in:
parent
eb55144211
commit
8077aaf0ae
4
sample_project/.nostalgia/type_descriptors/B.bool;0
Normal file
4
sample_project/.nostalgia/type_descriptors/B.bool;0
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
O1;net.drinkingtea.ox.TypeDescriptor;1;{
|
||||||
|
"primitiveType" : 2,
|
||||||
|
"typeName" : "B.bool"
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
@ -14,6 +14,7 @@ O1;net.drinkingtea.ox.TypeDescriptor;1;{
|
|||||||
"typeId" : "B.uint64;0"
|
"typeId" : "B.uint64;0"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"preloadable" : true,
|
||||||
"primitiveType" : 6,
|
"primitiveType" : 6,
|
||||||
"typeName" : "net.drinkingtea.ox.FileAddress.Data",
|
"typeName" : "net.drinkingtea.ox.FileAddress.Data",
|
||||||
"typeVersion" : 1
|
"typeVersion" : 1
|
||||||
|
@ -10,6 +10,7 @@ O1;net.drinkingtea.ox.TypeDescriptor;1;{
|
|||||||
"typeId" : "net.drinkingtea.ox.FileAddress.Data"
|
"typeId" : "net.drinkingtea.ox.FileAddress.Data"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"preloadable" : true,
|
||||||
"primitiveType" : 5,
|
"primitiveType" : 5,
|
||||||
"typeName" : "net.drinkingtea.ox.FileAddress",
|
"typeName" : "net.drinkingtea.ox.FileAddress",
|
||||||
"typeVersion" : 1
|
"typeVersion" : 1
|
||||||
|
1
sample_project/Palettes/Chester.npal
Normal file
1
sample_project/Palettes/Chester.npal
Normal file
@ -0,0 +1 @@
|
|||||||
|
M2;net.drinkingtea.nostalgia.core.Palette;1;ûÿ³Ö
|
BIN
sample_project/Scenes/Chester.nscn
Normal file
BIN
sample_project/Scenes/Chester.nscn
Normal file
Binary file not shown.
BIN
sample_project/TileSheets/Chester.ng
Normal file
BIN
sample_project/TileSheets/Chester.ng
Normal file
Binary file not shown.
@ -2,6 +2,8 @@ add_library(
|
|||||||
NostalgiaCore-Common OBJECT
|
NostalgiaCore-Common OBJECT
|
||||||
gfx.cpp
|
gfx.cpp
|
||||||
module.cpp
|
module.cpp
|
||||||
|
tilesheet.cpp
|
||||||
|
typeconv.cpp
|
||||||
typestore.cpp
|
typestore.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "color.hpp"
|
#include "color.hpp"
|
||||||
#include "context.hpp"
|
#include "context.hpp"
|
||||||
#include "ptidxconv.hpp"
|
#include "ptidxconv.hpp"
|
||||||
|
#include "tilesheet.hpp"
|
||||||
|
|
||||||
namespace nostalgia::core {
|
namespace nostalgia::core {
|
||||||
|
|
||||||
@ -31,431 +32,6 @@ enum class TileSheetSpace {
|
|||||||
Sprite
|
Sprite
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NostalgiaPalette {
|
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaPalette";
|
|
||||||
static constexpr auto TypeVersion = 1;
|
|
||||||
ox::Vector<Color16> colors = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Palette {
|
|
||||||
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.Palette";
|
|
||||||
static constexpr auto TypeVersion = 1;
|
|
||||||
ox::Vector<Color16> 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<uint8_t> pixels = {};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TileSheet {
|
|
||||||
using SubSheetIdx = ox::Vector<std::size_t, 4>;
|
|
||||||
|
|
||||||
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<SubSheet> subsheets;
|
|
||||||
ox::Vector<uint8_t> 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<std::size_t>(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) {
|
|
||||||
}
|
|
||||||
constexpr SubSheet(ox::CRStringView 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 = 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<uint8_t> *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<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 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<std::size_t>(static_cast<std::size_t>(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<std::size_t>(static_cast<std::size_t>(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<uint8_t> 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<uint8_t> 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 {
|
struct Sprite {
|
||||||
unsigned idx = 0;
|
unsigned idx = 0;
|
||||||
int x = 0;
|
int x = 0;
|
||||||
|
@ -15,11 +15,12 @@ namespace nostalgia::core {
|
|||||||
|
|
||||||
CoreModule CoreModule::mod;
|
CoreModule CoreModule::mod;
|
||||||
|
|
||||||
ox::Vector<foundation::BaseConverter*> CoreModule::converters() const noexcept {
|
ox::Vector<const foundation::BaseConverter*> CoreModule::converters() const noexcept {
|
||||||
return {
|
return {
|
||||||
&nostalgiaPaletteToPaletteConverter,
|
&nostalgiaPaletteToPaletteConverter,
|
||||||
&nostalgiaGraphicToTileSheetConverter,
|
&nostalgiaGraphicToTileSheetConverter,
|
||||||
&tileSheetToCompactTileSheetConverter,
|
&tileSheetToCompactTileSheetConverter,
|
||||||
|
&tileSheetV2ToTileSheetConverter,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,9 +29,10 @@ ox::Vector<foundation::PackTransform> CoreModule::packTransforms() const noexcep
|
|||||||
// convert tilesheets to CompactTileSheets
|
// convert tilesheets to CompactTileSheets
|
||||||
[](foundation::Context *ctx, ox::Buffer *buff) -> ox::Error {
|
[](foundation::Context *ctx, ox::Buffer *buff) -> ox::Error {
|
||||||
oxRequire(hdr, ox::readClawHeader(*buff));
|
oxRequire(hdr, ox::readClawHeader(*buff));
|
||||||
const auto typeId = ox::buildTypeId(hdr.typeName, hdr.typeVersion);
|
const auto typeId = ox::buildTypeId(hdr.typeName, hdr.typeVersion, hdr.typeParams);
|
||||||
if (typeId == ox::buildTypeId<TileSheet>() ||
|
if (typeId == ox::buildTypeId<TileSheetV1>() ||
|
||||||
typeId == ox::buildTypeId<NostalgiaGraphic>()) {
|
typeId == ox::buildTypeId<TileSheetV2>() ||
|
||||||
|
typeId == ox::buildTypeId<TileSheet>()) {
|
||||||
oxReturnError(foundation::convertBuffToBuff<core::CompactTileSheet>(ctx, *buff, ox::ClawFormat::Metal).moveTo(buff));
|
oxReturnError(foundation::convertBuffToBuff<core::CompactTileSheet>(ctx, *buff, ox::ClawFormat::Metal).moveTo(buff));
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
@ -12,14 +12,15 @@ namespace nostalgia::core {
|
|||||||
|
|
||||||
class CoreModule: public foundation::Module {
|
class CoreModule: public foundation::Module {
|
||||||
private:
|
private:
|
||||||
mutable NostalgiaPaletteToPaletteConverter nostalgiaPaletteToPaletteConverter;
|
NostalgiaPaletteToPaletteConverter nostalgiaPaletteToPaletteConverter;
|
||||||
mutable NostalgiaGraphicToTileSheetConverter nostalgiaGraphicToTileSheetConverter;
|
TileSheetV1ToTileSheetConverter nostalgiaGraphicToTileSheetConverter;
|
||||||
mutable TileSheetToCompactTileSheetConverter tileSheetToCompactTileSheetConverter;
|
TileSheetToCompactTileSheetConverter tileSheetToCompactTileSheetConverter;
|
||||||
|
TileSheetV2ToTileSheetConverter tileSheetV2ToTileSheetConverter;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static CoreModule mod;
|
static CoreModule mod;
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ox::Vector<foundation::BaseConverter*> converters() const noexcept override;
|
ox::Vector<const foundation::BaseConverter*> converters() const noexcept override;
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ox::Vector<foundation::PackTransform> packTransforms() const noexcept override;
|
ox::Vector<foundation::PackTransform> packTransforms() const noexcept override;
|
||||||
};
|
};
|
||||||
|
47
src/nostalgia/core/palette.hpp
Normal file
47
src/nostalgia/core/palette.hpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ox/std/array.hpp>
|
||||||
|
#include <ox/std/types.hpp>
|
||||||
|
#include <ox/model/def.hpp>
|
||||||
|
|
||||||
|
#include <nostalgia/geo/point.hpp>
|
||||||
|
#include <nostalgia/geo/size.hpp>
|
||||||
|
|
||||||
|
#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<Color16> colors = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Palette {
|
||||||
|
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.Palette";
|
||||||
|
static constexpr auto TypeVersion = 1;
|
||||||
|
ox::Vector<Color16> 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()
|
||||||
|
|
||||||
|
}
|
@ -256,12 +256,12 @@ class AddSubSheetCommand: public TileSheetCommand {
|
|||||||
auto &parent = m_img->getSubSheet(m_parentIdx);
|
auto &parent = m_img->getSubSheet(m_parentIdx);
|
||||||
if (m_addedSheets.size() < 2) {
|
if (m_addedSheets.size() < 2) {
|
||||||
auto i = parent.subsheets.size();
|
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 {
|
} 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.rows = 0;
|
||||||
parent.columns = 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
9
src/nostalgia/core/tilesheet.cpp
Normal file
9
src/nostalgia/core/tilesheet.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tilesheet.hpp"
|
||||||
|
|
||||||
|
namespace nostalgia::core {
|
||||||
|
|
||||||
|
}
|
566
src/nostalgia/core/tilesheet.hpp
Normal file
566
src/nostalgia/core/tilesheet.hpp
Normal file
@ -0,0 +1,566 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ox/std/array.hpp>
|
||||||
|
#include <ox/std/types.hpp>
|
||||||
|
#include <ox/model/def.hpp>
|
||||||
|
|
||||||
|
#include <nostalgia/geo/point.hpp>
|
||||||
|
#include <nostalgia/geo/size.hpp>
|
||||||
|
|
||||||
|
#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<uint8_t> pixels = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TileSheetV2 {
|
||||||
|
using SubSheetIdx = ox::Vector<std::size_t, 4>;
|
||||||
|
|
||||||
|
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<SubSheet> subsheets;
|
||||||
|
ox::Vector<uint8_t> 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<std::size_t>(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<std::size_t, 4>;
|
||||||
|
|
||||||
|
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<SubSheet> subsheets;
|
||||||
|
ox::Vector<uint8_t> 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<std::size_t>(columns * rows * PixelsPerTile) / (bpp == 4 ? 2u : 1u)) {
|
||||||
|
}
|
||||||
|
constexpr SubSheet(
|
||||||
|
SubSheetId pId,
|
||||||
|
ox::CRStringView pName,
|
||||||
|
int pColumns,
|
||||||
|
int pRows,
|
||||||
|
ox::Vector<uint8_t> 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<uint8_t> *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<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 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<std::size_t>(static_cast<std::size_t>(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<std::size_t>(static_cast<std::size_t>(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<unsigned> 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<SubSheetId> 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<ox::StringView> 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<unsigned> getTileOffset(const auto &pNamePath) const noexcept {
|
||||||
|
return subsheet.getTileOffset(ox::split<8>(pNamePath, '.'), bpp);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ox::Result<ox::StringView> getNameFor(SubSheetId pId) const noexcept {
|
||||||
|
return subsheet.getNameFor(pId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
auto pixels() const noexcept {
|
||||||
|
ox::Vector<uint8_t> 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<uint8_t> 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()
|
||||||
|
|
||||||
|
}
|
67
src/nostalgia/core/typeconv.cpp
Normal file
67
src/nostalgia/core/typeconv.cpp
Normal file
@ -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 {};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,32 +15,26 @@ namespace nostalgia::core {
|
|||||||
|
|
||||||
// Type converters
|
// Type converters
|
||||||
|
|
||||||
struct NostalgiaPaletteToPaletteConverter: public foundation::Converter<NostalgiaPalette, Palette> {
|
class NostalgiaPaletteToPaletteConverter: public foundation::Converter<NostalgiaPalette, Palette> {
|
||||||
ox::Error convert(foundation::Context*, NostalgiaPalette *src, Palette *dst) noexcept final {
|
ox::Error convert(foundation::Context*, NostalgiaPalette *src, Palette *dst) const noexcept final;
|
||||||
dst->colors = std::move(src->colors);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NostalgiaGraphicToTileSheetConverter: public foundation::Converter<NostalgiaGraphic, TileSheet> {
|
class TileSheetV1ToTileSheetConverter: public foundation::Converter<TileSheetV1, TileSheet> {
|
||||||
ox::Error convert(foundation::Context*, NostalgiaGraphic *src, TileSheet *dst) noexcept final {
|
ox::Error convert(foundation::Context*, TileSheetV1 *src, TileSheet *dst) const 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 {};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TileSheetToCompactTileSheetConverter: public foundation::Converter<TileSheet, CompactTileSheet> {
|
class TileSheetToCompactTileSheetConverter: public foundation::Converter<TileSheet, CompactTileSheet> {
|
||||||
ox::Error convert(foundation::Context*, TileSheet *src, CompactTileSheet *dst) noexcept final {
|
ox::Error convert(foundation::Context*, TileSheet *src, CompactTileSheet *dst) const noexcept final;
|
||||||
dst->bpp = src->bpp;
|
};
|
||||||
dst->defaultPalette = std::move(src->defaultPalette);
|
|
||||||
dst->pixels = src->pixels();
|
class TileSheetV2ToTileSheetConverter: public foundation::Converter<TileSheetV2, TileSheet> {
|
||||||
return {};
|
static void convertSubsheet(
|
||||||
}
|
TileSheetV2::SubSheet *src,
|
||||||
|
TileSheet::SubSheet *dst,
|
||||||
|
SubSheetId *idIt) noexcept;
|
||||||
|
|
||||||
|
ox::Error convert(foundation::Context*, TileSheetV2 *src, TileSheet *dst) const noexcept final;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -511,7 +511,10 @@ void setSprite(Context *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setTile(Context *ctx, unsigned bgIdx, int column, int row, uint8_t tile) noexcept {
|
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<renderer::GlImplData>();
|
const auto id = ctx->rendererData<renderer::GlImplData>();
|
||||||
const auto z = static_cast<unsigned>(bgIdx);
|
const auto z = static_cast<unsigned>(bgIdx);
|
||||||
const auto y = static_cast<unsigned>(row);
|
const auto y = static_cast<unsigned>(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 &bg = id->cbbs[z];
|
||||||
auto vbo = &bg.vertices[i * renderer::BgVertexVboLength];
|
auto vbo = &bg.vertices[i * renderer::BgVertexVboLength];
|
||||||
auto ebo = &bg.elements[i * renderer::BgVertexEboLength];
|
auto ebo = &bg.elements[i * renderer::BgVertexEboLength];
|
||||||
renderer::setTileBufferObject(ctx, i * renderer::BgVertexVboRows,
|
renderer::setTileBufferObject(
|
||||||
static_cast<float>(x), static_cast<float>(y), tile, vbo, ebo);
|
ctx, i * renderer::BgVertexVboRows,
|
||||||
|
static_cast<float>(x), static_cast<float>(y),
|
||||||
|
tile, vbo, ebo);
|
||||||
bg.updated = true;
|
bg.updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ class Context {
|
|||||||
ox::StringView appName = "Nostalgia Foundation App";
|
ox::StringView appName = "Nostalgia Foundation App";
|
||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
AssetManager assetManager;
|
AssetManager assetManager;
|
||||||
ox::Vector<class BaseConverter*> converters;
|
ox::Vector<const class BaseConverter*> converters;
|
||||||
ox::Vector<PackTransform> packTransforms;
|
ox::Vector<PackTransform> packTransforms;
|
||||||
#else
|
#else
|
||||||
std::size_t preloadSectionOffset = 0;
|
std::size_t preloadSectionOffset = 0;
|
||||||
|
@ -18,7 +18,7 @@ const ox::Vector<const Module*> *modules() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ox::Vector<foundation::BaseConverter*> Module::converters() const noexcept {
|
ox::Vector<const foundation::BaseConverter*> Module::converters() const noexcept {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ class Module {
|
|||||||
Module &operator=(Module&&) noexcept = delete;
|
Module &operator=(Module&&) noexcept = delete;
|
||||||
constexpr virtual ~Module() noexcept = default;
|
constexpr virtual ~Module() noexcept = default;
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual ox::Vector<foundation::BaseConverter*> converters() const noexcept;
|
virtual ox::Vector<const foundation::BaseConverter*> converters() const noexcept;
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual ox::Vector<PackTransform> packTransforms() const noexcept;
|
virtual ox::Vector<PackTransform> packTransforms() const noexcept;
|
||||||
};
|
};
|
||||||
|
@ -11,9 +11,10 @@ namespace nostalgia::foundation {
|
|||||||
#ifndef OX_BARE_METAL
|
#ifndef OX_BARE_METAL
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static auto findConverter(foundation::Context *ctx,
|
static ox::Result<const BaseConverter*> findConverter(
|
||||||
ox::CRStringView srcTypeName, int srcTypeVersion,
|
foundation::Context *ctx,
|
||||||
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept -> ox::Result<BaseConverter*> {
|
ox::CRStringView srcTypeName, int srcTypeVersion,
|
||||||
|
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept {
|
||||||
for (auto &c : ctx->converters) {
|
for (auto &c : ctx->converters) {
|
||||||
if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
|
if (c->matches(srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion)) {
|
||||||
return c;
|
return c;
|
||||||
@ -22,13 +23,14 @@ static auto findConverter(foundation::Context *ctx,
|
|||||||
return OxError(1, "Could not find converter");
|
return OxError(1, "Could not find converter");
|
||||||
};
|
};
|
||||||
|
|
||||||
static ox::Result<ox::UniquePtr<Wrap>> convert(foundation::Context *ctx, const ox::Buffer &srcBuffer,
|
static ox::Result<ox::UniquePtr<Wrap>> convert(
|
||||||
ox::CRStringView srcTypeName, int srcTypeVersion,
|
foundation::Context *ctx, const ox::Buffer &srcBuffer,
|
||||||
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept {
|
ox::CRStringView srcTypeName, int srcTypeVersion,
|
||||||
|
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept {
|
||||||
// look for direct converter
|
// look for direct converter
|
||||||
auto [c, err] = findConverter(ctx, srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion);
|
auto [c, err] = findConverter(ctx, srcTypeName, srcTypeVersion, dstTypeName, dstTypeVersion);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
return c->convertBuffToPtr(nullptr, srcBuffer);
|
return c->convertBuffToPtr(ctx, srcBuffer);
|
||||||
}
|
}
|
||||||
// try to chain multiple converters
|
// try to chain multiple converters
|
||||||
for (const auto &subConverter : ctx->converters) {
|
for (const auto &subConverter : ctx->converters) {
|
||||||
@ -45,7 +47,11 @@ static ox::Result<ox::UniquePtr<Wrap>> convert(foundation::Context *ctx, const o
|
|||||||
return OxError(1, "Could not convert between types");
|
return OxError(1, "Could not convert between types");
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Wrap>> convert(foundation::Context *ctx, const ox::Buffer &srcBuffer, ox::CRStringView dstTypeName, int dstTypeVersion) noexcept {
|
ox::Result<ox::UniquePtr<Wrap>> convert(
|
||||||
|
foundation::Context *ctx,
|
||||||
|
const ox::Buffer &srcBuffer,
|
||||||
|
ox::CRStringView dstTypeName,
|
||||||
|
int dstTypeVersion) noexcept {
|
||||||
oxRequire(hdr, ox::readClawHeader(srcBuffer));
|
oxRequire(hdr, ox::readClawHeader(srcBuffer));
|
||||||
return convert(ctx, srcBuffer, hdr.typeName, hdr.typeVersion, dstTypeName, dstTypeVersion);
|
return convert(ctx, srcBuffer, hdr.typeName, hdr.typeVersion, dstTypeName, dstTypeVersion);
|
||||||
}
|
}
|
||||||
|
@ -53,20 +53,20 @@ class BaseConverter {
|
|||||||
virtual ~BaseConverter() noexcept = default;
|
virtual ~BaseConverter() noexcept = default;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual ox::StringView srcTypeName() noexcept = 0;
|
virtual ox::StringView srcTypeName() const noexcept = 0;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual int srcTypeVersion() noexcept = 0;
|
virtual int srcTypeVersion() const noexcept = 0;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept = 0;
|
virtual bool srcMatches(ox::CRStringView pSrcTypeName, int pSrcTypeVersion) const noexcept = 0;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
virtual bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept = 0;
|
virtual bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept = 0;
|
||||||
|
|
||||||
virtual ox::Result<ox::UniquePtr<Wrap>> convertPtrToPtr(foundation::Context *ctx, Wrap *src) noexcept = 0;
|
virtual ox::Result<ox::UniquePtr<Wrap>> convertPtrToPtr(foundation::Context *ctx, Wrap *src) const noexcept = 0;
|
||||||
|
|
||||||
virtual ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(foundation::Context *ctx, const ox::Buffer &srcBuff) noexcept = 0;
|
virtual ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(foundation::Context *ctx, const ox::Buffer &srcBuff) const noexcept = 0;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline bool matches(ox::CRStringView srcTypeName, int srcTypeVersion,
|
inline bool matches(ox::CRStringView srcTypeName, int srcTypeVersion,
|
||||||
@ -80,47 +80,48 @@ class BaseConverter {
|
|||||||
template<typename SrcType, typename DstType>
|
template<typename SrcType, typename DstType>
|
||||||
class Converter: public BaseConverter {
|
class Converter: public BaseConverter {
|
||||||
public:
|
public:
|
||||||
virtual ox::Error convert(foundation::Context *ctx, SrcType*, DstType*) noexcept = 0;
|
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ox::StringView srcTypeName() noexcept final {
|
ox::StringView srcTypeName() const noexcept final {
|
||||||
return ox::requireModelTypeName<SrcType>();
|
return ox::requireModelTypeName<SrcType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
int srcTypeVersion() noexcept final {
|
int srcTypeVersion() const noexcept final {
|
||||||
return ox::requireModelTypeVersion<SrcType>();
|
return ox::requireModelTypeVersion<SrcType>();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept final {
|
bool srcMatches(ox::CRStringView pSrcTypeName, int pSrcTypeVersion) const noexcept final {
|
||||||
static constexpr auto SrcTypeName = ox::requireModelTypeName<SrcType>();
|
static const auto SrcTypeName = ox::requireModelTypeName<SrcType>();
|
||||||
static constexpr auto SrcTypeVersion = ox::requireModelTypeVersion<SrcType>();
|
static const auto SrcTypeVersion = ox::requireModelTypeVersion<SrcType>();
|
||||||
return ox_strcmp(srcTypeName, SrcTypeName) == 0
|
return pSrcTypeName == SrcTypeName
|
||||||
&& srcTypeVersion == SrcTypeVersion;
|
&& pSrcTypeVersion == SrcTypeVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept final {
|
bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept final {
|
||||||
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
|
static const auto DstTypeName = ox::StringView(ox::requireModelTypeName<DstType>());
|
||||||
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
|
static const auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
|
||||||
return ox_strcmp(dstTypeName, DstTypeName) == 0
|
return dstTypeName == DstTypeName
|
||||||
&& dstTypeVersion == DstTypeVersion;
|
&& dstTypeVersion == DstTypeVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Wrap>> convertPtrToPtr(foundation::Context *ctx, Wrap *src) noexcept final {
|
ox::Result<ox::UniquePtr<Wrap>> convertPtrToPtr(foundation::Context *ctx, Wrap *src) const noexcept final {
|
||||||
auto dst = makeWrap<DstType>();
|
auto dst = makeWrap<DstType>();
|
||||||
oxReturnError(convert(ctx, wrapCast<SrcType>(src), wrapCast<DstType>(dst.get())));
|
oxReturnError(convert(ctx, wrapCast<SrcType>(src), wrapCast<DstType>(dst.get())));
|
||||||
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
|
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(foundation::Context *ctx, const ox::Buffer &srcBuff) noexcept final {
|
ox::Result<ox::UniquePtr<Wrap>> convertBuffToPtr(foundation::Context *ctx, const ox::Buffer &srcBuff) const noexcept final {
|
||||||
oxRequireM(src, ox::readClaw<SrcType>(srcBuff));
|
oxRequireM(src, ox::readClaw<SrcType>(srcBuff));
|
||||||
auto dst = makeWrap<DstType>();
|
auto dst = makeWrap<DstType>();
|
||||||
oxReturnError(convert(ctx, &src, wrapCast<DstType>(dst.get())));
|
oxReturnError(convert(ctx, &src, wrapCast<DstType>(dst.get())));
|
||||||
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
|
return ox::Result<ox::UniquePtr<Wrap>>(std::move(dst));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ox::Error convert(foundation::Context *ctx, SrcType*, DstType*) const noexcept = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ox::Result<ox::UniquePtr<Wrap>> convert(foundation::Context *ctx, const ox::Buffer &srcBuffer,
|
ox::Result<ox::UniquePtr<Wrap>> convert(foundation::Context *ctx, const ox::Buffer &srcBuffer,
|
||||||
|
@ -4,41 +4,19 @@
|
|||||||
|
|
||||||
#include <nostalgia/core/core.hpp>
|
#include <nostalgia/core/core.hpp>
|
||||||
#include <nostalgia/foundation/media.hpp>
|
#include <nostalgia/foundation/media.hpp>
|
||||||
|
#include <nostalgia/scene/scene.hpp>
|
||||||
|
|
||||||
using namespace nostalgia;
|
using namespace nostalgia;
|
||||||
|
|
||||||
static int spriteX = 72;
|
static bool s_paused = false;
|
||||||
static int spriteY = 64;
|
static ox::Optional<scene::Scene> s_scene;
|
||||||
static ox::StringView sprites = "nostalgia";
|
|
||||||
static bool paused = false;
|
|
||||||
|
|
||||||
static int updateHandler(core::Context *ctx) noexcept {
|
static int updateHandler(core::Context*) noexcept {
|
||||||
constexpr auto sleepTime = 16;
|
constexpr auto sleepTime = 16;
|
||||||
if (paused) {
|
if (s_paused) {
|
||||||
return sleepTime;
|
return sleepTime;
|
||||||
}
|
}
|
||||||
int xmod = 0;
|
// do stuff
|
||||||
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<unsigned>(sprites[i] - ('a' - 1));
|
|
||||||
core::setSprite(ctx, i, spriteX + 8 * (static_cast<int>(i) + 1), spriteY, c, 0, 0, 0);
|
|
||||||
}
|
|
||||||
return sleepTime;
|
return sleepTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +25,7 @@ static void keyEventHandler(core::Context *ctx, core::Key key, bool down) noexce
|
|||||||
if (key == core::Key::Alpha_Q) {
|
if (key == core::Key::Alpha_Q) {
|
||||||
core::shutdown(ctx);
|
core::shutdown(ctx);
|
||||||
} else if (key == core::Key::Alpha_P) {
|
} 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<ox::FileSystem> fs) noexcept {
|
ox::Error run(ox::UniquePtr<ox::FileSystem> fs) noexcept {
|
||||||
oxTraceInitHook();
|
oxTraceInitHook();
|
||||||
oxRequireM(ctx, core::init(std::move(fs)));
|
oxRequireM(ctx, core::init(std::move(fs)));
|
||||||
constexpr ox::FileAddress TileSheetAddr("/TileSheets/Charset.ng");
|
constexpr ox::FileAddress SceneAddr("/Scenes/Chester.nscn");
|
||||||
constexpr ox::FileAddress PaletteAddr("/Palettes/Charset.npal");
|
oxRequire(scn, foundation::readObj<scene::SceneStatic>(ctx.get(), SceneAddr));
|
||||||
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!!!");
|
|
||||||
core::setUpdateHandler(ctx.get(), updateHandler);
|
core::setUpdateHandler(ctx.get(), updateHandler);
|
||||||
core::setKeyEventHandler(ctx.get(), keyEventHandler);
|
core::setKeyEventHandler(ctx.get(), keyEventHandler);
|
||||||
|
s_scene.emplace(scn.get());
|
||||||
|
oxReturnError(s_scene->setupDisplay(ctx.get()));
|
||||||
return core::run(ctx.get());
|
return core::run(ctx.get());
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
add_library(
|
add_library(
|
||||||
NostalgiaScene
|
NostalgiaScene
|
||||||
scene.cpp
|
scene.cpp
|
||||||
|
scenestatic.cpp
|
||||||
scenemodule.cpp
|
scenemodule.cpp
|
||||||
typeconv.cpp
|
typeconv.cpp
|
||||||
)
|
)
|
||||||
@ -9,11 +10,12 @@ add_library(
|
|||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
NostalgiaScene PUBLIC
|
NostalgiaScene PUBLIC
|
||||||
NostalgiaCore
|
NostalgiaCore
|
||||||
|
NostalgiaGeo
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
FILES
|
FILES
|
||||||
scene.hpp
|
scenestatic.hpp
|
||||||
scenemodule.hpp
|
scenemodule.hpp
|
||||||
typeconv.hpp
|
typeconv.hpp
|
||||||
DESTINATION
|
DESTINATION
|
||||||
|
@ -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 <nostalgia/core/gfx.hpp>
|
||||||
|
|
||||||
#include "scene.hpp"
|
#include "scene.hpp"
|
||||||
|
|
||||||
namespace nostalgia::scene {
|
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 {};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,104 +4,19 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <ox/fs/fs.hpp>
|
#include "scenestatic.hpp"
|
||||||
#include <ox/std/error.hpp>
|
|
||||||
#include <ox/std/types.hpp>
|
|
||||||
#include <ox/std/vector.hpp>
|
|
||||||
|
|
||||||
namespace nostalgia::scene {
|
namespace nostalgia::scene {
|
||||||
|
|
||||||
struct TileDoc {
|
class Scene {
|
||||||
|
private:
|
||||||
|
const SceneStatic *m_sceneStatic = nullptr;
|
||||||
|
|
||||||
constexpr static auto TypeName = "net.drinkingtea.nostalgia.scene.TileDoc";
|
public:
|
||||||
constexpr static auto TypeVersion = 1;
|
explicit Scene(const SceneStatic *sceneStatic) noexcept;
|
||||||
constexpr static auto Preloadable = true;
|
|
||||||
|
|
||||||
ox::String sheetIdx;
|
ox::Error setupDisplay(core::Context *ctx) noexcept;
|
||||||
uint8_t type = 0;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
oxModelBegin(TileDoc)
|
|
||||||
oxModelFieldRename(sheet_idx, sheetIdx);
|
|
||||||
oxModelField(type);
|
|
||||||
oxModelEnd()
|
|
||||||
|
|
||||||
struct SceneDoc {
|
|
||||||
|
|
||||||
using TileMapRow = ox::Vector<TileDoc>;
|
|
||||||
using TileMapLayer = ox::Vector<TileMapRow>;
|
|
||||||
using TileMap = ox::Vector<TileMapLayer>;
|
|
||||||
|
|
||||||
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<uint16_t> columns;
|
|
||||||
ox::Vector<uint16_t> rows;
|
|
||||||
ox::Vector<ox::Vector<uint16_t>> tileMapIdx;
|
|
||||||
ox::Vector<ox::Vector<uint8_t>> 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()
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -10,15 +10,15 @@ namespace nostalgia::scene {
|
|||||||
|
|
||||||
SceneModule SceneModule::mod;
|
SceneModule SceneModule::mod;
|
||||||
|
|
||||||
ox::Vector<foundation::BaseConverter*> SceneModule::converters() const noexcept {
|
ox::Vector<const foundation::BaseConverter*> SceneModule::converters() const noexcept {
|
||||||
return {
|
return {
|
||||||
&sceneToSceneInstaceConverter,
|
&sceneDocToSceneStaticConverter,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Vector<foundation::PackTransform> SceneModule::packTransforms() const noexcept {
|
ox::Vector<foundation::PackTransform> SceneModule::packTransforms() const noexcept {
|
||||||
return {
|
return {
|
||||||
foundation::transformRule<SceneDoc, Scene>,
|
foundation::transformRule<SceneDoc, SceneStatic>,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,12 +12,12 @@ namespace nostalgia::scene {
|
|||||||
|
|
||||||
class SceneModule: public foundation::Module {
|
class SceneModule: public foundation::Module {
|
||||||
private:
|
private:
|
||||||
mutable SceneDocToSceneConverter sceneToSceneInstaceConverter;
|
SceneDocToSceneStaticConverter sceneDocToSceneStaticConverter;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static SceneModule mod;
|
static SceneModule mod;
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ox::Vector<foundation::BaseConverter*> converters() const noexcept override;
|
ox::Vector<const foundation::BaseConverter*> converters() const noexcept override;
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ox::Vector<foundation::PackTransform> packTransforms() const noexcept override;
|
ox::Vector<foundation::PackTransform> packTransforms() const noexcept override;
|
||||||
};
|
};
|
||||||
|
11
src/nostalgia/scene/scenestatic.cpp
Normal file
11
src/nostalgia/scene/scenestatic.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "scenestatic.hpp"
|
||||||
|
|
||||||
|
namespace nostalgia::scene {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
164
src/nostalgia/scene/scenestatic.hpp
Normal file
164
src/nostalgia/scene/scenestatic.hpp
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ox/fs/fs.hpp>
|
||||||
|
#include <ox/std/error.hpp>
|
||||||
|
#include <ox/std/types.hpp>
|
||||||
|
#include <ox/std/vector.hpp>
|
||||||
|
|
||||||
|
#include <nostalgia/core/tilesheet.hpp>
|
||||||
|
#include <nostalgia/geo/size.hpp>
|
||||||
|
|
||||||
|
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<core::SubSheetId> 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<ox::StringView> 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<TileDoc>;
|
||||||
|
using TileMapLayer = ox::Vector<TileMapRow>;
|
||||||
|
using TileMap = ox::Vector<TileMapLayer>;
|
||||||
|
|
||||||
|
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<ox::String> 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<int>(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<int>(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<uint16_t> &tileMapIdx;
|
||||||
|
ox::Vector<uint8_t> &tileType;
|
||||||
|
constexpr Layer(
|
||||||
|
uint16_t *pColumns,
|
||||||
|
uint16_t *pRows,
|
||||||
|
ox::Vector<uint16_t> *pTileMapIdx,
|
||||||
|
ox::Vector<uint8_t> *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<unsigned>(columns * rows);
|
||||||
|
tileMapIdx.resize(tileCnt);
|
||||||
|
tileType.resize(tileCnt);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ox::FileAddress tilesheet;
|
||||||
|
ox::Vector<ox::FileAddress> palettes;
|
||||||
|
// tile layer data
|
||||||
|
ox::Vector<uint16_t> columns;
|
||||||
|
ox::Vector<uint16_t> rows;
|
||||||
|
ox::Vector<ox::Vector<uint16_t>> tileMapIdx;
|
||||||
|
ox::Vector<ox::Vector<uint8_t>> 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()
|
||||||
|
|
||||||
|
}
|
@ -2,13 +2,41 @@
|
|||||||
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <nostalgia/core/gfx.hpp>
|
||||||
|
#include <nostalgia/foundation/media.hpp>
|
||||||
|
|
||||||
#include "typeconv.hpp"
|
#include "typeconv.hpp"
|
||||||
|
|
||||||
namespace nostalgia::scene {
|
namespace nostalgia::scene {
|
||||||
|
|
||||||
// Type converters
|
ox::Error SceneDocToSceneStaticConverter::convert(
|
||||||
|
foundation::Context *ctx,
|
||||||
ox::Error SceneDocToSceneConverter::convert(foundation::Context*, SceneDoc *, Scene *) noexcept {
|
SceneDoc *src,
|
||||||
|
SceneStatic *dst) const noexcept {
|
||||||
|
oxRequire(ts, foundation::readObj<core::TileSheet>(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<uint16_t>(mapIdx);
|
||||||
|
++tileIdx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++layerIdx;
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,12 +6,12 @@
|
|||||||
|
|
||||||
#include <nostalgia/foundation/typeconv.hpp>
|
#include <nostalgia/foundation/typeconv.hpp>
|
||||||
|
|
||||||
#include "scene.hpp"
|
#include "scenestatic.hpp"
|
||||||
|
|
||||||
namespace nostalgia::scene {
|
namespace nostalgia::scene {
|
||||||
|
|
||||||
struct SceneDocToSceneConverter: public foundation::Converter<SceneDoc, Scene> {
|
class SceneDocToSceneStaticConverter: public foundation::Converter<SceneDoc, SceneStatic> {
|
||||||
ox::Error convert(foundation::Context*, SceneDoc *src, Scene *dst) noexcept final;
|
ox::Error convert(foundation::Context*, SceneDoc *src, SceneStatic *dst) const noexcept final;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user