[nostalgia/core] Add support for drawing NostalgiaGraphics in SDL
This commit is contained in:
parent
79a1a6f896
commit
52c4744242
@ -17,8 +17,8 @@
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
ox::Error init(Context *ctx);
|
||||
[[nodiscard]] ox::Error init(Context *ctx);
|
||||
|
||||
ox::Error run();
|
||||
[[nodiscard]] ox::Error run();
|
||||
|
||||
}
|
||||
|
@ -15,6 +15,11 @@
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
enum class TileSheetSpace {
|
||||
Background,
|
||||
Sprite
|
||||
};
|
||||
|
||||
using Color = uint16_t;
|
||||
|
||||
struct NostalgiaPalette {
|
||||
@ -26,7 +31,7 @@ struct NostalgiaGraphic {
|
||||
static constexpr auto Fields = 4;
|
||||
uint8_t bpp = 0;
|
||||
ox::FileAddress defaultPalette;
|
||||
ox::Vector<Color> pal;
|
||||
NostalgiaPalette pal;
|
||||
ox::Vector<uint8_t> tiles;
|
||||
};
|
||||
|
||||
@ -47,9 +52,16 @@ ox::Error model(T *io, NostalgiaPalette *pal) {
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
ox::Error initGfx(Context *ctx);
|
||||
[[nodiscard]] ox::Error initGfx(Context *ctx);
|
||||
|
||||
ox::Error initConsole(Context *ctx);
|
||||
[[nodiscard]] ox::Error shutdownGfx();
|
||||
|
||||
[[nodiscard]] ox::Error initConsole(Context *ctx);
|
||||
|
||||
/**
|
||||
* @param section describes which section of the selected TileSheetSpace to use (e.g. MEM_PALLETE_BG[section])
|
||||
*/
|
||||
[[nodiscard]] ox::Error loadTileSheet(Context *ctx, TileSheetSpace tss, int section, ox::FileAddress tilesheet, ox::FileAddress palette = nullptr);
|
||||
|
||||
ox::Error loadTileSheet(Context *ctx, ox::FileAddress file);
|
||||
|
||||
|
@ -12,6 +12,8 @@
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
void draw();
|
||||
|
||||
ox::Error run() {
|
||||
for (auto running = true; running;) {
|
||||
SDL_Event event;
|
||||
@ -28,7 +30,7 @@ ox::Error run() {
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_Delay(1);
|
||||
draw();
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
@ -6,25 +6,153 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "../gfx.hpp"
|
||||
#include <ox/mc/read.hpp>
|
||||
|
||||
#include <nostalgia/core/gfx.hpp>
|
||||
|
||||
namespace nostalgia::core {
|
||||
|
||||
static SDL_Window *window = nullptr;
|
||||
static SDL_Renderer *renderer = nullptr;
|
||||
|
||||
static std::array<SDL_Texture*, 4> bgTextures;
|
||||
static std::vector<std::vector<int>> bgTileMaps(128, std::vector<int>(128, 0));
|
||||
|
||||
[[nodiscard]] static ox::ValErr<ox::Vector<uint8_t>> readFile(Context *ctx, const ox::FileAddress &file) {
|
||||
auto [stat, err] = ctx->rom->stat(file);
|
||||
oxReturnError(err);
|
||||
ox::Vector<uint8_t> buff(stat.size);
|
||||
oxReturnError(ctx->rom->read(file, buff.data(), buff.size()));
|
||||
return buff;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] ox::ValErr<T> readMC(Context *ctx, const ox::FileAddress &file) {
|
||||
auto [buff, err] = readFile(ctx, file);
|
||||
oxReturnError(err);
|
||||
T t;
|
||||
oxReturnError(ox::readMC(buff.data(), buff.size(), &t));
|
||||
return t;
|
||||
}
|
||||
|
||||
ox::Error initGfx(Context*) {
|
||||
window = SDL_CreateWindow("nostalgia", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1024, 768, SDL_WINDOW_SHOWN);
|
||||
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
|
||||
return OxError(window == nullptr);
|
||||
}
|
||||
|
||||
ox::Error shutdownGfx() {
|
||||
for (auto tex : bgTextures) {
|
||||
SDL_DestroyTexture(tex);
|
||||
}
|
||||
SDL_DestroyRenderer(renderer);
|
||||
SDL_DestroyWindow(window);
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
ox::Error initConsole(Context*) {
|
||||
return OxError(1);
|
||||
}
|
||||
|
||||
ox::Error loadTileSheet(Context*, ox::FileAddress) {
|
||||
return OxError(1);
|
||||
SDL_Color createSDL_Color(Color nc) {
|
||||
SDL_Color c;
|
||||
// extract the color chanels and scale them up for a 24 bit color
|
||||
c.r = ((nc & 0b0000000000011111) >> 0) * 8;
|
||||
c.g = ((nc & 0b0000001111100000) >> 5) * 8;
|
||||
c.b = ((nc & 0b0111110000000000) >> 10) * 8;
|
||||
c.a = 1;
|
||||
return c;
|
||||
}
|
||||
|
||||
SDL_Palette *createSDL_Palette(const NostalgiaPalette &npal) {
|
||||
auto pal = SDL_AllocPalette(npal.colors.size());
|
||||
for (std::size_t i = 0; i < npal.colors.size(); ++i) {
|
||||
pal->colors[i] = createSDL_Color(npal.colors[i]);
|
||||
}
|
||||
return pal;
|
||||
}
|
||||
|
||||
ox::Error loadTileSheet(Context *ctx,
|
||||
TileSheetSpace tss,
|
||||
int section,
|
||||
ox::FileAddress tilesheetPath,
|
||||
ox::FileAddress palettePath) {
|
||||
auto [tilesheet, tserr] = readMC<NostalgiaGraphic>(ctx, tilesheetPath);
|
||||
oxReturnError(tserr);
|
||||
NostalgiaPalette palette;
|
||||
if (palettePath) {
|
||||
oxReturnError(readMC<NostalgiaPalette>(ctx, palettePath).get(&palette));
|
||||
} else {
|
||||
palette = tilesheet.pal;
|
||||
}
|
||||
|
||||
const auto bytesPerTile = tilesheet.bpp == 8 ? 64 : 32;
|
||||
const auto tiles = tilesheet.tiles.size() / bytesPerTile;
|
||||
const int width = 8;
|
||||
const int height = 8 * tiles;
|
||||
const auto format = SDL_PIXELFORMAT_INDEX8;
|
||||
auto surface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 16, format);
|
||||
auto sdlPalette = createSDL_Palette(palette);
|
||||
SDL_SetSurfacePalette(surface, sdlPalette);
|
||||
if (bytesPerTile == 1) {
|
||||
SDL_memcpy(surface->pixels, tilesheet.tiles.data(), bytesPerTile * tiles);
|
||||
} else {
|
||||
for (std::size_t i = 0; i < tilesheet.tiles.size(); ++i) {
|
||||
static_cast<uint8_t*>(surface->pixels)[i * 2 + 0] = tilesheet.tiles[i] & 0xF;
|
||||
static_cast<uint8_t*>(surface->pixels)[i * 2 + 1] = tilesheet.tiles[i] >> 4;
|
||||
}
|
||||
}
|
||||
|
||||
auto texture = SDL_CreateTextureFromSurface(renderer, surface);
|
||||
SDL_FreeSurface(surface);
|
||||
SDL_FreePalette(sdlPalette);
|
||||
|
||||
if (tss == TileSheetSpace::Background) {
|
||||
if (bgTextures[section]) {
|
||||
SDL_DestroyTexture(bgTextures[section]);
|
||||
}
|
||||
bgTextures[section] = texture;
|
||||
}
|
||||
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
void drawBackground(std::size_t bg) {
|
||||
//oxTrace("nostalgia::core::drawBackground") << "Drawing background";
|
||||
SDL_Rect src = {}, dst = {};
|
||||
src.x = 0;
|
||||
src.w = 8;
|
||||
src.h = 8;
|
||||
dst.x = 0;
|
||||
dst.y = 0;
|
||||
dst.w = 64;
|
||||
dst.h = 64;
|
||||
const auto tex = bgTextures[bg];
|
||||
if (tex) {
|
||||
for (auto &m : bgTileMaps) {
|
||||
for (auto t : m) {
|
||||
src.y = t * 8;
|
||||
SDL_RenderCopy(renderer, tex, &src, &dst);
|
||||
dst.y += 64;
|
||||
}
|
||||
dst.x += 64;
|
||||
dst.y = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
SDL_RenderClear(renderer);
|
||||
drawBackground(0);
|
||||
drawBackground(1);
|
||||
drawBackground(2);
|
||||
drawBackground(3);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
|
||||
void puts(Context*, int, const char*) {
|
||||
|
@ -75,7 +75,7 @@ namespace {
|
||||
|
||||
QMap<QRgb, int> colors;
|
||||
auto ng = std::make_unique<core::NostalgiaGraphic>();
|
||||
ng->pal.resize(countColors(src, argTiles));
|
||||
ng->pal.colors.resize(countColors(src, argTiles));
|
||||
if (argBpp == 4) {
|
||||
ng->tiles.resize(Pixels / 2);
|
||||
} else {
|
||||
@ -112,7 +112,7 @@ namespace {
|
||||
// store colors in palette with the corresponding color id
|
||||
for (auto key : colors.keys()) {
|
||||
auto colorId = colors[key];
|
||||
ng->pal[colorId] = toGbaColor(key);
|
||||
ng->pal.colors[colorId] = toGbaColor(key);
|
||||
}
|
||||
|
||||
return ng;
|
||||
|
@ -73,7 +73,7 @@ int ImportTilesheetWizardPalettePage::accept() {
|
||||
if (palette != PaletteOptions.indexOf(PaletteOption_Bundle)) {
|
||||
const auto outPath = PaletteDir + paletteName + FileExt_npal;
|
||||
core::NostalgiaPalette pal;
|
||||
pal.colors = std::move(ng->pal);
|
||||
pal = std::move(ng->pal);
|
||||
auto [buff, err] = toBuffer(&pal);
|
||||
oxReturnError(err);
|
||||
oxReturnError(m_ctx->project->write(outPath, buff.data(), buff.size()));
|
||||
|
@ -6,6 +6,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include <ox/fs/fs.hpp>
|
||||
#include <ox/std/units.hpp>
|
||||
#include <nostalgia/world/world.hpp>
|
||||
|
||||
@ -13,14 +14,16 @@ using namespace nostalgia::common;
|
||||
using namespace nostalgia::core;
|
||||
using namespace nostalgia::world;
|
||||
|
||||
int run(ox::FileSystem *fs) {
|
||||
ox::Error run(ox::FileSystem *fs) {
|
||||
Context ctx;
|
||||
init(&ctx);
|
||||
oxReturnError(init(&ctx));
|
||||
ctx.rom = fs;
|
||||
Zone zone(&ctx, Bounds{0, 0, 40, 40}, "/TileSheets/GeneralWorld");
|
||||
Zone zone;
|
||||
oxReturnError(zone.init(&ctx, Bounds{0, 0, 40, 40}, "/TileSheets/Charset.ng", "/Palettes/Charset.npal"));
|
||||
zone.draw(&ctx);
|
||||
run();
|
||||
return 0;
|
||||
oxReturnError(run());
|
||||
oxReturnError(shutdownGfx());
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
#ifndef OX_USE_STDLIB
|
||||
@ -32,8 +35,14 @@ extern "C" void _start() {
|
||||
|
||||
#else
|
||||
|
||||
int main() {
|
||||
return run(nullptr);
|
||||
int main(int argc, const char **argv) {
|
||||
if (argc > 1) {
|
||||
ox::PassThroughFS fs(argv[1]);
|
||||
auto err = run(&fs);
|
||||
oxAssert(err, "Something went wrong...");
|
||||
return err;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -13,11 +13,15 @@ namespace nostalgia::world {
|
||||
using namespace common;
|
||||
using namespace core;
|
||||
|
||||
Zone::Zone(Context *ctx, Bounds bnds, ox::FileAddress tileSheet) {
|
||||
ox::Error Zone::init(Context *ctx, Bounds bnds, ox::FileAddress tileSheet, ox::FileAddress palette) {
|
||||
const auto size = bnds.width * bnds.height;
|
||||
m_tiles = new Tile[size];
|
||||
m_bounds = bnds;
|
||||
core::loadTileSheet(ctx, tileSheet);
|
||||
return core::loadTileSheet(ctx, core::TileSheetSpace::Background, 0, tileSheet, palette);
|
||||
}
|
||||
|
||||
Zone::~Zone() {
|
||||
delete[] m_tiles;
|
||||
}
|
||||
|
||||
void Zone::draw(Context *ctx) {
|
||||
|
@ -47,7 +47,11 @@ struct Zone {
|
||||
Tile *m_tiles = nullptr;
|
||||
|
||||
public:
|
||||
Zone(core::Context *ctx, common::Bounds bnds, ox::FileAddress tileSheet);
|
||||
Zone() = default;
|
||||
|
||||
~Zone();
|
||||
|
||||
[[nodiscard]] ox::Error init(core::Context *ctx, common::Bounds bnds, ox::FileAddress tileSheet, ox::FileAddress palette = {});
|
||||
|
||||
void draw(core::Context *ctx);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user