From 3352625afe18293bc0d7d87b7be6e019962054d0 Mon Sep 17 00:00:00 2001 From: Gary Talent <gary@drinkingtea.net> Date: Thu, 11 Mar 2021 01:22:43 -0600 Subject: [PATCH] [nostalgia/core] Start port of PC gfx to OpenGL --- src/nostalgia/core/context.hpp | 20 ++- src/nostalgia/core/gfx.cpp | 2 +- src/nostalgia/core/gfx.hpp | 4 +- src/nostalgia/core/sdl/core.cpp | 4 + src/nostalgia/core/sdl/core.hpp | 23 +++ src/nostalgia/core/sdl/gfx.cpp | 136 +++++++---------- src/nostalgia/core/studio/imgconv.cpp | 10 +- src/nostalgia/core/studio/tilesheeteditor.cpp | 32 ++-- src/nostalgia/core/userland/CMakeLists.txt | 12 +- src/nostalgia/core/userland/gfx.hpp | 23 +++ src/nostalgia/core/userland/gfx_opengl.cpp | 139 ++++++++++++++++++ 11 files changed, 289 insertions(+), 116 deletions(-) create mode 100644 src/nostalgia/core/sdl/core.hpp create mode 100644 src/nostalgia/core/userland/gfx.hpp create mode 100644 src/nostalgia/core/userland/gfx_opengl.cpp diff --git a/src/nostalgia/core/context.hpp b/src/nostalgia/core/context.hpp index a422c9f1..6ad84305 100644 --- a/src/nostalgia/core/context.hpp +++ b/src/nostalgia/core/context.hpp @@ -17,16 +17,26 @@ class Context { public: ox::FileSystem *rom = nullptr; private: - void *m_implData = nullptr; + void *m_windowerData = nullptr; + void *m_rendererData = nullptr; public: - constexpr void setImplData(void *implData) noexcept { - m_implData = implData; + constexpr void setWindowerData(void *windowerData) noexcept { + m_windowerData = windowerData; } template<typename T> - constexpr T *implData() noexcept { - return static_cast<T*>(m_implData); + constexpr T *windowerData() noexcept { + return static_cast<T*>(m_windowerData); + } + + constexpr void setRendererData(void *rendererData) noexcept { + m_rendererData = rendererData; + } + + template<typename T> + constexpr T *rendererData() noexcept { + return static_cast<T*>(m_rendererData); } }; diff --git a/src/nostalgia/core/gfx.cpp b/src/nostalgia/core/gfx.cpp index bf32cc53..529ff06d 100644 --- a/src/nostalgia/core/gfx.cpp +++ b/src/nostalgia/core/gfx.cpp @@ -146,7 +146,7 @@ Color32 toColor32(Color16 nc) noexcept { Color32 g = static_cast<Color32>(((nc & 0b0000001111100000) >> 5) * 8); Color32 b = static_cast<Color32>(((nc & 0b0111110000000000) >> 10) * 8); Color32 a = 255; - return a | (b << 8) | (g << 16) | (r << 24); + return r | (g << 8) | (b << 16) | (a << 24); } diff --git a/src/nostalgia/core/gfx.hpp b/src/nostalgia/core/gfx.hpp index 9d2a1801..94fcb31c 100644 --- a/src/nostalgia/core/gfx.hpp +++ b/src/nostalgia/core/gfx.hpp @@ -46,7 +46,7 @@ struct NostalgiaGraphic { int columns = 1; ox::FileAddress defaultPalette; NostalgiaPalette pal; - ox::Vector<uint8_t> tiles; + ox::Vector<uint8_t> pixels; }; template<typename T> @@ -64,7 +64,7 @@ constexpr ox::Error model(T *io, NostalgiaGraphic *ng) { oxReturnError(io->field("columns", &ng->columns)); oxReturnError(io->field("defaultPalette", &ng->defaultPalette)); oxReturnError(io->field("pal", &ng->pal)); - oxReturnError(io->field("tiles", &ng->tiles)); + oxReturnError(io->field("pixels", &ng->pixels)); return OxError(0); } diff --git a/src/nostalgia/core/sdl/core.cpp b/src/nostalgia/core/sdl/core.cpp index 24be503e..918f9354 100644 --- a/src/nostalgia/core/sdl/core.cpp +++ b/src/nostalgia/core/sdl/core.cpp @@ -12,6 +12,8 @@ #include <nostalgia/core/input.hpp> #include <nostalgia/core/core.hpp> +#include "core.hpp" + namespace nostalgia::core { static event_handler g_eventHandler = nullptr; @@ -24,6 +26,7 @@ ox::Error init(Context *ctx) { } ox::Error run(Context *ctx) { + auto id = ctx->windowerData<SdlImplData>(); for (auto running = true; running;) { SDL_Event event; while (SDL_PollEvent(&event)) { @@ -40,6 +43,7 @@ ox::Error run(Context *ctx) { } } draw(ctx); + SDL_GL_SwapWindow(id->window); SDL_Delay(1); } return OxError(0); diff --git a/src/nostalgia/core/sdl/core.hpp b/src/nostalgia/core/sdl/core.hpp new file mode 100644 index 00000000..bd28752a --- /dev/null +++ b/src/nostalgia/core/sdl/core.hpp @@ -0,0 +1,23 @@ +/* + * Copyright 2016 - 2021 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <array> + +#include <SDL.h> + +namespace nostalgia::core { + +struct SdlImplData { + SDL_Window *window = nullptr; + SDL_GLContext renderer = nullptr; + std::array<SDL_Texture*, 4> bgTextures{}; +}; + +} diff --git a/src/nostalgia/core/sdl/gfx.cpp b/src/nostalgia/core/sdl/gfx.cpp index c95fe2b6..8a10f7aa 100644 --- a/src/nostalgia/core/sdl/gfx.cpp +++ b/src/nostalgia/core/sdl/gfx.cpp @@ -10,26 +10,21 @@ #ifdef NOST_FPS_PRINT #include <iostream> #endif +#include <iostream> #include <SDL.h> #include <ox/claw/read.hpp> #include <nostalgia/core/gfx.hpp> +#include <nostalgia/core/userland/gfx.hpp> + +#include "core.hpp" namespace nostalgia::core { using TileMap = std::array<std::array<int, 128>, 128>; -struct SdlImplData { - SDL_Window *window = nullptr; - SDL_Renderer *renderer = nullptr; - std::array<SDL_Texture*, 4> bgTextures{}; - std::array<TileMap, 4> bgTileMaps{}; - int64_t prevFpsCheckTime = 0; - uint64_t draws = 0; -}; - constexpr auto Scale = 5; static ox::Result<ox::Vector<char>> readFile(Context *ctx, const ox::FileAddress &file) { @@ -51,22 +46,32 @@ ox::Result<T> readObj(Context *ctx, const ox::FileAddress &file) { ox::Error initGfx(Context *ctx) { auto id = new SdlImplData; - ctx->setImplData(id); - id->window = SDL_CreateWindow("nostalgia", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 240 * Scale, 160 * Scale, - SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); - id->renderer = SDL_CreateRenderer(id->window, -1, SDL_RENDERER_ACCELERATED); - return OxError(id->window == nullptr); + ctx->setWindowerData(id); + id->window = SDL_CreateWindow("nostalgia", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + 240 * Scale, 160 * Scale, + SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI); + if (id->window == nullptr) { + return OxError(1, SDL_GetError()); + } + id->renderer = SDL_GL_CreateContext(id->window); + if (id->renderer == nullptr) { + return OxError(1, SDL_GetError()); + } + oxReturnError(renderer::init(ctx)); + return OxError(0); } ox::Error shutdownGfx(Context *ctx) { - auto id = ctx->implData<SdlImplData>(); + oxReturnError(renderer::shutdown(ctx)); + auto id = ctx->windowerData<SdlImplData>(); for (auto tex : id->bgTextures) { if (tex) { SDL_DestroyTexture(tex); } } - SDL_DestroyRenderer(id->renderer); + SDL_GL_DeleteContext(id->renderer); SDL_DestroyWindow(id->window); + ctx->setWindowerData(nullptr); delete id; return OxError(0); } @@ -98,8 +103,8 @@ ox::Error loadBgTileSheet(Context *ctx, int section, ox::FileAddress tilesheetPath, ox::FileAddress palettePath) { - auto id = ctx->implData<SdlImplData>(); - auto [tilesheet, tserr] = readObj<NostalgiaGraphic>(ctx, tilesheetPath); + //auto id = ctx->windowerData<SdlImplData>(); + const auto [tilesheet, tserr] = readObj<NostalgiaGraphic>(ctx, tilesheetPath); oxReturnError(tserr); NostalgiaPalette palette; if (!palettePath) { @@ -108,31 +113,36 @@ ox::Error loadBgTileSheet(Context *ctx, oxReturnError(readObj<NostalgiaPalette>(ctx, palettePath).get(&palette)); const unsigned bytesPerTile = tilesheet.bpp == 8 ? 64 : 32; - const auto tiles = tilesheet.tiles.size() / bytesPerTile; + const auto tiles = tilesheet.pixels.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 == 64) { - 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; + //const auto format = SDL_PIXELFORMAT_INDEX8; + //const auto sdlPalette = createSDL_Palette(palette); + std::vector<uint32_t> pixels; + if (bytesPerTile == 64) { // 8 BPP + pixels.resize(tilesheet.pixels.size()); + for (std::size_t i = 0; i < tilesheet.pixels.size(); ++i) { + pixels[i] = toColor32(palette.colors[tilesheet.pixels[i]]); + } + } else { // 4 BPP + pixels.resize(tilesheet.pixels.size() * 2); + for (std::size_t i = 0; i < tilesheet.pixels.size(); ++i) { + pixels[i * 2 + 0] = toColor32(palette.colors[tilesheet.pixels[i] & 0xF]); + pixels[i * 2 + 1] = toColor32(palette.colors[tilesheet.pixels[i] >> 4]); } } - auto texture = SDL_CreateTextureFromSurface(id->renderer, surface); - SDL_FreeSurface(surface); - SDL_FreePalette(sdlPalette); + oxReturnError(renderer::loadTexture(ctx, section, pixels.data(), width, height)); - auto sectionIdx = static_cast<unsigned>(section); - if (id->bgTextures[sectionIdx]) { - SDL_DestroyTexture(id->bgTextures[sectionIdx]); - } - id->bgTextures[sectionIdx] = texture; + //auto texture = SDL_CreateTextureFromSurface(nullptr, surface); + //SDL_FreeSurface(surface); + //SDL_FreePalette(sdlPalette); + + //auto sectionIdx = static_cast<unsigned>(section); + //if (id->bgTextures[sectionIdx]) { + // SDL_DestroyTexture(id->bgTextures[sectionIdx]); + //} + //id->bgTextures[sectionIdx] = texture; return OxError(0); } @@ -144,11 +154,10 @@ ox::Error loadSpriteTileSheet(Context*, return OxError(0); } -void drawBackground(Context *ctx, const TileMap &tm, SDL_Texture *tex) { +void drawBackground(Context*, const TileMap &tm, SDL_Texture *tex) { if (tex) { constexpr auto DstSize = 8 * Scale; - auto id = ctx->implData<SdlImplData>(); - //oxTrace("nostalgia::core::drawBackground") << "Drawing background"; + oxTracef("nostalgia::core::sdl::drawBackground", "Drawing background"); SDL_Rect src = {}, dst = {}; src.x = 0; src.w = 8; @@ -160,7 +169,7 @@ void drawBackground(Context *ctx, const TileMap &tm, SDL_Texture *tex) { for (auto &m : tm) { for (auto t : m) { src.y = t * 8; - SDL_RenderCopy(id->renderer, tex, &src, &dst); + SDL_RenderCopy(nullptr, tex, &src, &dst); dst.x += DstSize; } dst.x = 0; @@ -169,49 +178,4 @@ void drawBackground(Context *ctx, const TileMap &tm, SDL_Texture *tex) { } } -void draw(Context *ctx) { - auto id = ctx->implData<SdlImplData>(); - ++id->draws; - if (id->draws >= 5000) { - using namespace std::chrono; - const auto now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); - const auto duration = static_cast<double>(now - id->prevFpsCheckTime) / 1000.0; - const auto fps = static_cast<int>(static_cast<double>(id->draws) / duration); -#ifdef NOST_FPS_PRINT - std::cout << "FPS: " << fps << '\n'; -#endif - oxTrace("nostalgia::core::gfx::fps") << "FPS:" << fps; - id->prevFpsCheckTime = now; - id->draws = 0; - } - SDL_RenderClear(id->renderer); - for (std::size_t i = 0; i < id->bgTileMaps.size(); i++) { - auto tex = id->bgTextures[i]; - auto &tm = id->bgTileMaps[i]; - drawBackground(ctx, tm, tex); - } - SDL_RenderPresent(id->renderer); -} - -void puts(Context *ctx, int column, int row, const char *str) { - for (int i = 0; str[i]; i++) { - setTile(ctx, 0, column + i, row, static_cast<uint8_t>(charMap[static_cast<uint8_t>(str[i])])); - } -} - -void setTile(Context *ctx, int layer, int column, int row, uint8_t tile) { - auto id = ctx->implData<SdlImplData>(); - auto z = static_cast<unsigned>(layer); - auto y = static_cast<unsigned>(row); - auto x = static_cast<unsigned>(column); - id->bgTileMaps[z][y][x] = tile; -} - -[[maybe_unused]] -void hideSprite(Context*, unsigned) { -} - -void setSprite(Context*, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned, unsigned) { -} - } diff --git a/src/nostalgia/core/studio/imgconv.cpp b/src/nostalgia/core/studio/imgconv.cpp index b7680018..96f31915 100644 --- a/src/nostalgia/core/studio/imgconv.cpp +++ b/src/nostalgia/core/studio/imgconv.cpp @@ -64,9 +64,9 @@ namespace { auto ng = std::make_unique<core::NostalgiaGraphic>(); ng->pal.colors.resize(static_cast<std::size_t>(countColors(src, Tiles))); if (argBpp == 4) { - ng->tiles.resize(static_cast<std::size_t>(Pixels / 2)); + ng->pixels.resize(static_cast<std::size_t>(Pixels / 2)); } else { - ng->tiles.resize(static_cast<std::size_t>(Pixels)); + ng->pixels.resize(static_cast<std::size_t>(Pixels)); } ng->bpp = argBpp; ng->columns = src.width() / TileWidth; @@ -87,12 +87,12 @@ namespace { // set pixel color if (argBpp == 4) { if (destI % 2) { // is odd number pixel - ng->tiles[static_cast<std::size_t>(destI / 2)] |= colors[c] << 4; + ng->pixels[static_cast<std::size_t>(destI / 2)] |= colors[c] << 4; } else { - ng->tiles[static_cast<std::size_t>(destI / 2)] |= colors[c]; + ng->pixels[static_cast<std::size_t>(destI / 2)] |= colors[c]; } } else { - ng->tiles[static_cast<std::size_t>(destI)] = static_cast<std::size_t>(colors[c]); + ng->pixels[static_cast<std::size_t>(destI)] = static_cast<std::size_t>(colors[c]); } } } diff --git a/src/nostalgia/core/studio/tilesheeteditor.cpp b/src/nostalgia/core/studio/tilesheeteditor.cpp index 6edffbc5..c29bae5c 100644 --- a/src/nostalgia/core/studio/tilesheeteditor.cpp +++ b/src/nostalgia/core/studio/tilesheeteditor.cpp @@ -663,18 +663,18 @@ std::unique_ptr<NostalgiaGraphic> SheetData::toNostalgiaGraphic() const { ng->rows = m_rows; auto pixelCount = static_cast<std::size_t>(ng->rows * ng->columns * PixelsPerTile); if (ng->bpp == 4) { - ng->tiles.resize(pixelCount / 2); + ng->pixels.resize(pixelCount / 2); for (std::size_t i = 0; i < pixelCount && i < static_cast<std::size_t>(m_pixels.size()); ++i) { if (i & 1) { - ng->tiles[i / 2] |= static_cast<uint8_t>(m_pixels[i]) << 4; + ng->pixels[i / 2] |= static_cast<uint8_t>(m_pixels[i]) << 4; } else { - ng->tiles[i / 2] = static_cast<uint8_t>(m_pixels[i]); + ng->pixels[i / 2] = static_cast<uint8_t>(m_pixels[i]); } } } else { - ng->tiles.resize(pixelCount); - for (std::size_t i = 0; i < ng->tiles.size(); ++i) { - ng->tiles[i] = static_cast<uint8_t>(m_pixels[i]); + ng->pixels.resize(pixelCount); + for (std::size_t i = 0; i < ng->pixels.size(); ++i) { + ng->pixels[i] = static_cast<uint8_t>(m_pixels[i]); } } return ng; @@ -788,17 +788,17 @@ void SheetData::updatePixels(const NostalgiaGraphic *ng) { m_pixels.clear(); m_pixelSelected.clear(); if (ng->bpp == 8) { - for (std::size_t i = 0; i < ng->tiles.size(); i++) { - m_pixels.push_back(ng->tiles[i]); + for (std::size_t i = 0; i < ng->pixels.size(); i++) { + m_pixels.push_back(ng->pixels[i]); m_pixelSelected.push_back(0); } } else { - for (std::size_t i = 0; i < ng->tiles.size() * 2; i++) { + for (std::size_t i = 0; i < ng->pixels.size() * 2; i++) { uint8_t p; if (i & 1) { - p = ng->tiles[i / 2] >> 4; + p = ng->pixels[i / 2] >> 4; } else { - p = ng->tiles[i / 2] & 0xF; + p = ng->pixels[i / 2] & 0xF; } m_pixels.push_back(p); m_pixelSelected.push_back(0); @@ -1011,15 +1011,15 @@ QImage TileSheetEditor::toQImage(NostalgiaGraphic *ng, NostalgiaPalette *npal) c dst.setPixel(pt.x, pt.y, color); }; if (ng->bpp == 4) { - for (std::size_t i = 0; i < ng->tiles.size(); ++i) { - auto p1 = ng->tiles[i] & 0xF; - auto p2 = ng->tiles[i] >> 4; + for (std::size_t i = 0; i < ng->pixels.size(); ++i) { + auto p1 = ng->pixels[i] & 0xF; + auto p2 = ng->pixels[i] >> 4; setPixel(i * 2 + 0, p1); setPixel(i * 2 + 1, p2); } } else { - for (std::size_t i = 0; i < ng->tiles.size(); i++) { - const auto p = ng->tiles[i]; + for (std::size_t i = 0; i < ng->pixels.size(); i++) { + const auto p = ng->pixels[i]; setPixel(i, p); } } diff --git a/src/nostalgia/core/userland/CMakeLists.txt b/src/nostalgia/core/userland/CMakeLists.txt index 33ba3bf6..5a92b6ca 100644 --- a/src/nostalgia/core/userland/CMakeLists.txt +++ b/src/nostalgia/core/userland/CMakeLists.txt @@ -1,5 +1,6 @@ add_library( - NostalgiaCore-Userspace + NostalgiaCore-Userspace OBJECT + gfx_opengl.cpp media.cpp ) @@ -7,10 +8,19 @@ if(NOT MSVC) target_compile_options(NostalgiaCore-Userspace PRIVATE -Wsign-conversion) endif() +if(APPLE) + find_package(OpenGL REQUIRED) +else() + set(OPENGL_gl_LIBRARY GL) +endif() + target_link_libraries( NostalgiaCore-Userspace PUBLIC OxFS OxStd + NostalgiaCore + #GLESv2 + ${OPENGL_gl_LIBRARY} ) install( diff --git a/src/nostalgia/core/userland/gfx.hpp b/src/nostalgia/core/userland/gfx.hpp new file mode 100644 index 00000000..65b44bb3 --- /dev/null +++ b/src/nostalgia/core/userland/gfx.hpp @@ -0,0 +1,23 @@ +/* + * Copyright 2016 - 2021 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <ox/std/types.hpp> + +#include <nostalgia/core/context.hpp> + +namespace nostalgia::core::renderer { + +ox::Error init(Context *ctx); + +ox::Error shutdown(Context *ctx); + +ox::Error loadTexture(Context *ctx, int section, void *bytes, int w, int h); + +} diff --git a/src/nostalgia/core/userland/gfx_opengl.cpp b/src/nostalgia/core/userland/gfx_opengl.cpp new file mode 100644 index 00000000..42b4cd77 --- /dev/null +++ b/src/nostalgia/core/userland/gfx_opengl.cpp @@ -0,0 +1,139 @@ +/* + * Copyright 2016 - 2021 gary@drinkingtea.net + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <ox/std/fmt.hpp> +#define GL_SILENCE_DEPRECATION + +#include <array> + +#include <ox/std/defines.hpp> +#include <ox/std/defines.hpp> + +#define GL_GLEXT_PROTOTYPES 1 +//#include <GLES2/gl2.h> +#ifdef OX_OS_Darwin +#include <OpenGL/gl.h> +#else +#include <GL/gl.h> +#endif + +#include <nostalgia/core/gfx.hpp> + +namespace nostalgia::core { + +using TileMap = std::array<std::array<int, 128>, 128>; + +struct GlImplData { + std::array<TileMap, 4> bgTileMaps{}; + std::array<GLuint, 4> bgTextures{}; + int64_t prevFpsCheckTime = 0; + uint64_t draws = 0; +}; + + +namespace renderer { + +ox::Error init(Context *ctx) { + const auto id = new GlImplData; + ctx->setRendererData(id); + return OxError(0); +} + +ox::Error shutdown(Context *ctx) { + const auto id = ctx->rendererData<GlImplData>(); + ctx->setRendererData(nullptr); + delete id; + return OxError(0); +} + +ox::Error loadTexture(Context *ctx, int section, void *pixels, int w, int h) { + oxTracef("nostalgia::core::gfx::gl", "loadTexture: { section: {}, w: {}, h: {} }", section, w, h); + const auto &id = ctx->rendererData<GlImplData>(); + auto &texId = id->bgTextures[static_cast<std::size_t>(section)]; + glGenTextures(1, &texId); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texId); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + return OxError(0); +} + +} + + +void draw(Context *ctx) { + const auto id = ctx->rendererData<GlImplData>(); + ++id->draws; + if (id->draws >= 5000) { + using namespace std::chrono; + const auto now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count(); + const auto duration = static_cast<double>(now - id->prevFpsCheckTime) / 1000.0; + const auto fps = static_cast<int>(static_cast<double>(id->draws) / duration); +#ifdef NOST_FPS_PRINT + std::cout << "FPS: " << fps << '\n'; +#endif + oxTracef("nostalgia::core::gfx::gl::fps", "FPS: {}", fps); + id->prevFpsCheckTime = now; + id->draws = 0; + } + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + auto &texId = id->bgTextures[0]; + + glEnable(GL_TEXTURE_2D); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glBindTexture(GL_TEXTURE_2D, texId); + + // Draw a textured quad + glBegin(GL_QUADS); + glTexCoord2f(0, 0); glVertex2f(-0.01, 1); + glTexCoord2f(0, 1); glVertex2f(-0.01, -1); + glTexCoord2f(1, 1); glVertex2f( 0.01, -1); + glTexCoord2f(1, 0); glVertex2f( 0.01, 1); + glEnd(); + + glDisable(GL_TEXTURE_2D); + + for (std::size_t i = 0; i < id->bgTileMaps.size(); i++) { + } +} + +void puts(Context *ctx, int column, int row, const char *str) { + for (int i = 0; str[i]; ++i) { + setTile(ctx, 0, column + i, row, static_cast<uint8_t>(charMap[static_cast<int>(str[i])])); + } +} + +void clearTileLayer(Context*, int) { +} + +void hideSprite(Context*, unsigned) { +} + +void setSprite(Context*, + unsigned, + unsigned, + unsigned, + unsigned, + unsigned, + unsigned, + unsigned) { +} + +void setTile(Context *ctx, int layer, int column, int row, uint8_t tile) { + const auto id = ctx->rendererData<GlImplData>(); + const auto z = static_cast<unsigned>(layer); + const auto y = static_cast<unsigned>(row); + const auto x = static_cast<unsigned>(column); + id->bgTileMaps[z][y][x] = tile; +} + +}