/* * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. */ #pragma once #include #include #include #include #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 colors; }; struct Palette { static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.Palette"; static constexpr auto TypeVersion = 1; ox::Vector 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 pixels; }; struct TileSheet { using SubSheetIdx = ox::Vector; struct SubSheet { static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet.SubSheet"; static constexpr auto TypeVersion = 1; ox::BString<32> name; std::size_t begin = 0; std::size_t size = 0; int rows = 1; int columns = 1; ox::Vector subsheets; }; static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.TileSheet"; static constexpr auto TypeVersion = 1; int8_t bpp = 0; ox::FileAddress defaultPalette; ox::Vector 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 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; }