[nostalgia/core] Add support for drawing NostalgiaGraphics in SDL

This commit is contained in:
Gary Talent 2019-10-27 16:24:01 -05:00
parent 79a1a6f896
commit 52c4744242
9 changed files with 181 additions and 22 deletions

View File

@ -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();
}

View File

@ -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);

View 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);
}

View File

@ -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*) {

View File

@ -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;

View File

@ -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()));

View File

@ -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

View File

@ -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) {

View File

@ -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);