Files
ox/src/nostalgia/core/gfx.hpp
T

298 lines
7.7 KiB
C++

/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#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 {
extern char charMap[128];
class Drawer {
public:
virtual ~Drawer() = default;
virtual void draw(Context*) noexcept = 0;
};
enum class TileSheetSpace {
Background,
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;
};
// 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::BString<32> name;
std::size_t begin = 0;
std::size_t size = 0;
int rows = 1;
int columns = 1;
ox::Vector<SubSheet> subsheets;
};
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet";
static constexpr auto TypeVersion = 1;
int8_t bpp = 0;
ox::FileAddress defaultPalette;
ox::Vector<uint8_t> pixels;
SubSheet subsheet;
[[nodiscard]]
constexpr const auto &getSubSheet(const SubSheetIdx &idx, std::size_t idxIt, const SubSheet *pSubsheet) const 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, std::size_t idxIt, const SubSheet *pSubsheet) noexcept {
if (idxIt == idx.size()) {
return *pSubsheet;
}
return getSubSheet(idx, idxIt + 1, &pSubsheet->subsheets[idx[idxIt]]);
}
[[nodiscard]]
constexpr auto &getSubSheet(const SubSheetIdx &idx) noexcept {
return getSubSheet(idx, 0, &subsheet);
}
[[nodiscard]]
constexpr const auto &columns(const SubSheetIdx &idx = {}) const noexcept {
return getSubSheet(idx).columns;
}
[[nodiscard]]
constexpr const auto &rows(const SubSheetIdx &idx = {}) const noexcept {
return getSubSheet(idx).rows;
}
[[nodiscard]]
constexpr auto &columns(const SubSheetIdx &idx = {}) noexcept {
return getSubSheet(idx).columns;
}
[[nodiscard]]
constexpr auto &rows(const SubSheetIdx &idx = {}) noexcept {
return getSubSheet(idx).rows;
}
[[nodiscard]]
constexpr uint8_t getPixel4Bpp(std::size_t idx) const noexcept {
oxAssert(bpp == 4, "TileSheetV1::getPixel4Bpp: wrong bpp");
if (idx & 1) {
return this->pixels[idx / 2] >> 4;
} else {
return this->pixels[idx / 2] & 0b0000'1111;
}
}
[[nodiscard]]
constexpr uint8_t getPixel8Bpp(std::size_t idx) const noexcept {
oxAssert(bpp == 8, "TileSheetV1::getPixel8Bpp: wrong bpp");
return this->pixels[idx];
}
[[nodiscard]]
constexpr auto getPixel(std::size_t idx) const noexcept {
if (this->bpp == 4) {
return getPixel4Bpp(idx);
} else {
return getPixel8Bpp(idx);
}
}
[[nodiscard]]
constexpr auto getPixel4Bpp(const geo::Point &pt, const SubSheetIdx &subsheetIdx) const noexcept {
oxAssert(bpp == 4, "TileSheetV1::getPixel4Bpp: wrong bpp");
const auto idx = ptToIdx(pt, this->getSubSheet(subsheetIdx).columns);
return getPixel4Bpp(idx);
}
[[nodiscard]]
constexpr auto getPixel8Bpp(const geo::Point &pt, const SubSheetIdx &subsheetIdx) const noexcept {
oxAssert(bpp == 8, "TileSheetV1::getPixel8Bpp: wrong bpp");
const auto idx = ptToIdx(pt, this->getSubSheet(subsheetIdx).columns);
return getPixel8Bpp(idx);
}
[[nodiscard]]
constexpr auto getPixel(const geo::Point &pt, const SubSheetIdx &subsheetIdx) const noexcept {
const auto idx = ptToIdx(pt, this->getSubSheet(subsheetIdx).columns);
return getPixel(idx);
}
constexpr void setPixel(uint64_t idx, uint8_t palIdx) noexcept {
auto &pixel = this->pixels[idx / 2];
if (bpp == 4) {
if (idx & 1) {
pixel = (pixel & 0b0000'1111) | (palIdx << 4);
} else {
pixel = (pixel & 0b1111'0000) | (palIdx);
}
} else {
pixel = palIdx;
}
}
constexpr void setPixel(const SubSheetIdx &subsheetIdx, const geo::Point &pt, uint8_t palIdx) noexcept {
const auto idx = ptToIdx(pt, this->getSubSheet(subsheetIdx).columns);
setPixel(idx, palIdx);
}
};
struct CompactTileSheet {
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(begin);
oxModelField(size);
oxModelField(rows);
oxModelField(columns);
oxModelField(subsheets)
oxModelEnd()
oxModelBegin(TileSheet)
oxModelField(bpp)
oxModelField(defaultPalette)
oxModelField(pixels)
oxModelField(subsheet)
oxModelEnd()
oxModelBegin(CompactTileSheet)
oxModelField(bpp)
oxModelField(defaultPalette)
oxModelField(pixels)
oxModelEnd()
struct Sprite {
unsigned idx = 0;
unsigned x = 0;
unsigned y = 0;
unsigned tileIdx = 0;
unsigned spriteShape = 0;
unsigned spriteSize = 0;
unsigned flipX = 0;
};
ox::Error initGfx(Context *ctx) noexcept;
void addCustomDrawer(Context *ctx, Drawer *cd) noexcept;
void removeCustomDrawer(Context *ctx, Drawer *cd) noexcept;
void setWindowTitle(Context *ctx, const char *title) noexcept;
void focusWindow(Context *ctx) noexcept;
[[nodiscard]]
int getScreenWidth(Context *ctx) noexcept;
[[nodiscard]]
int getScreenHeight(Context *ctx) noexcept;
[[nodiscard]]
geo::Size getScreenSize(Context *ctx) noexcept;
[[nodiscard]]
uint8_t bgStatus(Context *ctx) noexcept;
void setBgStatus(Context *ctx, uint32_t status) noexcept;
bool bgStatus(Context *ctx, unsigned bg) noexcept;
void setBgStatus(Context *ctx, unsigned bg, bool status) noexcept;
ox::Error initConsole(Context *ctx) noexcept;
/**
* @param section describes which section of the selected TileSheetSpace to use (e.g. MEM_PALLETE_BG[section])
*/
ox::Error loadBgTileSheet(Context *ctx, int section, const ox::FileAddress &tilesheet, const ox::FileAddress &palette = nullptr) noexcept;
ox::Error loadSpriteTileSheet(Context *ctx,
int section,
const ox::FileAddress &tilesheetAddr,
const ox::FileAddress &paletteAddr) noexcept;
void puts(Context *ctx, int column, int row, const char *str) noexcept;
void setTile(Context *ctx, int layer, int column, int row, uint8_t tile) noexcept;
void clearTileLayer(Context *ctx, int layer) noexcept;
void hideSprite(Context *ctx, unsigned) noexcept;
void setSprite(Context *ctx, unsigned idx, unsigned x, unsigned y, unsigned tileIdx, unsigned spriteShape = 0, unsigned spriteSize = 0, unsigned flipX = 0) noexcept;
void setSprite(Context *ctx, const Sprite &s) noexcept;
}