[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"
|
||||
}
|
||||
],
|
||||
"preloadable" : true,
|
||||
"primitiveType" : 6,
|
||||
"typeName" : "net.drinkingtea.ox.FileAddress.Data",
|
||||
"typeVersion" : 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
|
||||
|
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
|
||||
gfx.cpp
|
||||
module.cpp
|
||||
tilesheet.cpp
|
||||
typeconv.cpp
|
||||
typestore.cpp
|
||||
)
|
||||
|
||||
|
@ -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<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 {
|
||||
unsigned idx = 0;
|
||||
int x = 0;
|
||||
|
@ -15,11 +15,12 @@ namespace nostalgia::core {
|
||||
|
||||
CoreModule CoreModule::mod;
|
||||
|
||||
ox::Vector<foundation::BaseConverter*> CoreModule::converters() const noexcept {
|
||||
ox::Vector<const foundation::BaseConverter*> CoreModule::converters() const noexcept {
|
||||
return {
|
||||
&nostalgiaPaletteToPaletteConverter,
|
||||
&nostalgiaGraphicToTileSheetConverter,
|
||||
&tileSheetToCompactTileSheetConverter,
|
||||
&tileSheetV2ToTileSheetConverter,
|
||||
};
|
||||
}
|
||||
|
||||
@ -28,9 +29,10 @@ ox::Vector<foundation::PackTransform> 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<TileSheet>() ||
|
||||
typeId == ox::buildTypeId<NostalgiaGraphic>()) {
|
||||
const auto typeId = ox::buildTypeId(hdr.typeName, hdr.typeVersion, hdr.typeParams);
|
||||
if (typeId == ox::buildTypeId<TileSheetV1>() ||
|
||||
typeId == ox::buildTypeId<TileSheetV2>() ||
|
||||
typeId == ox::buildTypeId<TileSheet>()) {
|
||||
oxReturnError(foundation::convertBuffToBuff<core::CompactTileSheet>(ctx, *buff, ox::ClawFormat::Metal).moveTo(buff));
|
||||
}
|
||||
return {};
|
||||
|
@ -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<foundation::BaseConverter*> converters() const noexcept override;
|
||||
ox::Vector<const foundation::BaseConverter*> converters() const noexcept override;
|
||||
[[nodiscard]]
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
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
|
||||
|
||||
struct NostalgiaPaletteToPaletteConverter: public foundation::Converter<NostalgiaPalette, Palette> {
|
||||
ox::Error convert(foundation::Context*, NostalgiaPalette *src, Palette *dst) noexcept final {
|
||||
dst->colors = std::move(src->colors);
|
||||
return {};
|
||||
}
|
||||
class NostalgiaPaletteToPaletteConverter: public foundation::Converter<NostalgiaPalette, Palette> {
|
||||
ox::Error convert(foundation::Context*, NostalgiaPalette *src, Palette *dst) const noexcept final;
|
||||
};
|
||||
|
||||
struct NostalgiaGraphicToTileSheetConverter: public foundation::Converter<NostalgiaGraphic, TileSheet> {
|
||||
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<TileSheetV1, TileSheet> {
|
||||
ox::Error convert(foundation::Context*, TileSheetV1 *src, TileSheet *dst) const noexcept final;
|
||||
};
|
||||
|
||||
struct TileSheetToCompactTileSheetConverter: public foundation::Converter<TileSheet, CompactTileSheet> {
|
||||
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<TileSheet, CompactTileSheet> {
|
||||
ox::Error convert(foundation::Context*, TileSheet *src, CompactTileSheet *dst) const noexcept final;
|
||||
};
|
||||
|
||||
class TileSheetV2ToTileSheetConverter: public foundation::Converter<TileSheetV2, TileSheet> {
|
||||
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 {
|
||||
//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 z = static_cast<unsigned>(bgIdx);
|
||||
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 vbo = &bg.vertices[i * renderer::BgVertexVboLength];
|
||||
auto ebo = &bg.elements[i * renderer::BgVertexEboLength];
|
||||
renderer::setTileBufferObject(ctx, i * renderer::BgVertexVboRows,
|
||||
static_cast<float>(x), static_cast<float>(y), tile, vbo, ebo);
|
||||
renderer::setTileBufferObject(
|
||||
ctx, i * renderer::BgVertexVboRows,
|
||||
static_cast<float>(x), static_cast<float>(y),
|
||||
tile, vbo, ebo);
|
||||
bg.updated = true;
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ class Context {
|
||||
ox::StringView appName = "Nostalgia Foundation App";
|
||||
#ifndef OX_BARE_METAL
|
||||
AssetManager assetManager;
|
||||
ox::Vector<class BaseConverter*> converters;
|
||||
ox::Vector<const class BaseConverter*> converters;
|
||||
ox::Vector<PackTransform> packTransforms;
|
||||
#else
|
||||
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 {};
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ class Module {
|
||||
Module &operator=(Module&&) noexcept = delete;
|
||||
constexpr virtual ~Module() noexcept = default;
|
||||
[[nodiscard]]
|
||||
virtual ox::Vector<foundation::BaseConverter*> converters() const noexcept;
|
||||
virtual ox::Vector<const foundation::BaseConverter*> converters() const noexcept;
|
||||
[[nodiscard]]
|
||||
virtual ox::Vector<PackTransform> packTransforms() const noexcept;
|
||||
};
|
||||
|
@ -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<BaseConverter*> {
|
||||
static ox::Result<const BaseConverter*> 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<ox::UniquePtr<Wrap>> convert(foundation::Context *ctx, const ox::Buffer &srcBuffer,
|
||||
ox::CRStringView srcTypeName, int srcTypeVersion,
|
||||
ox::CRStringView dstTypeName, int dstTypeVersion) noexcept {
|
||||
static ox::Result<ox::UniquePtr<Wrap>> 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<ox::UniquePtr<Wrap>> convert(foundation::Context *ctx, const o
|
||||
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));
|
||||
return convert(ctx, srcBuffer, hdr.typeName, hdr.typeVersion, dstTypeName, dstTypeVersion);
|
||||
}
|
||||
|
@ -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<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]]
|
||||
inline bool matches(ox::CRStringView srcTypeName, int srcTypeVersion,
|
||||
@ -80,47 +80,48 @@ class BaseConverter {
|
||||
template<typename SrcType, typename DstType>
|
||||
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<SrcType>();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
int srcTypeVersion() noexcept final {
|
||||
int srcTypeVersion() const noexcept final {
|
||||
return ox::requireModelTypeVersion<SrcType>();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool srcMatches(ox::CRStringView srcTypeName, int srcTypeVersion) const noexcept final {
|
||||
static constexpr auto SrcTypeName = ox::requireModelTypeName<SrcType>();
|
||||
static constexpr auto SrcTypeVersion = ox::requireModelTypeVersion<SrcType>();
|
||||
return ox_strcmp(srcTypeName, SrcTypeName) == 0
|
||||
&& srcTypeVersion == SrcTypeVersion;
|
||||
bool srcMatches(ox::CRStringView pSrcTypeName, int pSrcTypeVersion) const noexcept final {
|
||||
static const auto SrcTypeName = ox::requireModelTypeName<SrcType>();
|
||||
static const auto SrcTypeVersion = ox::requireModelTypeVersion<SrcType>();
|
||||
return pSrcTypeName == SrcTypeName
|
||||
&& pSrcTypeVersion == SrcTypeVersion;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool dstMatches(ox::CRStringView dstTypeName, int dstTypeVersion) const noexcept final {
|
||||
static constexpr auto DstTypeName = ox::requireModelTypeName<DstType>();
|
||||
static constexpr auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
|
||||
return ox_strcmp(dstTypeName, DstTypeName) == 0
|
||||
static const auto DstTypeName = ox::StringView(ox::requireModelTypeName<DstType>());
|
||||
static const auto DstTypeVersion = ox::requireModelTypeVersion<DstType>();
|
||||
return dstTypeName == DstTypeName
|
||||
&& 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>();
|
||||
oxReturnError(convert(ctx, wrapCast<SrcType>(src), wrapCast<DstType>(dst.get())));
|
||||
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));
|
||||
auto dst = makeWrap<DstType>();
|
||||
oxReturnError(convert(ctx, &src, wrapCast<DstType>(dst.get())));
|
||||
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,
|
||||
|
@ -4,41 +4,19 @@
|
||||
|
||||
#include <nostalgia/core/core.hpp>
|
||||
#include <nostalgia/foundation/media.hpp>
|
||||
#include <nostalgia/scene/scene.hpp>
|
||||
|
||||
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<scene::Scene> 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<unsigned>(sprites[i] - ('a' - 1));
|
||||
core::setSprite(ctx, i, spriteX + 8 * (static_cast<int>(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<ox::FileSystem> 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<scene::SceneStatic>(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());
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
||||
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
|
||||
|
||||
#include <ox/fs/fs.hpp>
|
||||
#include <ox/std/error.hpp>
|
||||
#include <ox/std/types.hpp>
|
||||
#include <ox/std/vector.hpp>
|
||||
#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<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;
|
||||
|
||||
ox::Vector<foundation::BaseConverter*> SceneModule::converters() const noexcept {
|
||||
ox::Vector<const foundation::BaseConverter*> SceneModule::converters() const noexcept {
|
||||
return {
|
||||
&sceneToSceneInstaceConverter,
|
||||
&sceneDocToSceneStaticConverter,
|
||||
};
|
||||
}
|
||||
|
||||
ox::Vector<foundation::PackTransform> SceneModule::packTransforms() const noexcept {
|
||||
return {
|
||||
foundation::transformRule<SceneDoc, Scene>,
|
||||
foundation::transformRule<SceneDoc, SceneStatic>,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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<foundation::BaseConverter*> converters() const noexcept override;
|
||||
ox::Vector<const foundation::BaseConverter*> converters() const noexcept override;
|
||||
[[nodiscard]]
|
||||
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.
|
||||
*/
|
||||
|
||||
#include <nostalgia/core/gfx.hpp>
|
||||
#include <nostalgia/foundation/media.hpp>
|
||||
|
||||
#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<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 {};
|
||||
}
|
||||
|
||||
|
@ -6,12 +6,12 @@
|
||||
|
||||
#include <nostalgia/foundation/typeconv.hpp>
|
||||
|
||||
#include "scene.hpp"
|
||||
#include "scenestatic.hpp"
|
||||
|
||||
namespace nostalgia::scene {
|
||||
|
||||
struct SceneDocToSceneConverter: public foundation::Converter<SceneDoc, Scene> {
|
||||
ox::Error convert(foundation::Context*, SceneDoc *src, Scene *dst) noexcept final;
|
||||
class SceneDocToSceneStaticConverter: public foundation::Converter<SceneDoc, SceneStatic> {
|
||||
ox::Error convert(foundation::Context*, SceneDoc *src, SceneStatic *dst) const noexcept final;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user