From 55efa36454f0668366ee6c28cdfa144e050b57bb Mon Sep 17 00:00:00 2001 From: Erik Abair Date: Sun, 3 Oct 2021 22:50:14 -0700 Subject: [PATCH] rendering: Adds SDL_gpu based rendering. --- .gitmodules | 6 ++ 3rdparty/pbgl | 1 + 3rdparty/sdl-gpu | 1 + Includes/font.cpp | 8 ++- Includes/font.h | 8 ++- Includes/menu.cpp | 17 ++++++ Includes/renderer.cpp | 98 ++++++++++++++++++++++++++++--- Includes/renderer.h | 43 +++++++++++--- Includes/sntpClient.cpp | 6 +- Includes/subsystems.cpp | 24 +++++++- Makefile | 31 ++++++++-- nxdk-sdl-gpu/Makefile.inc | 63 ++++++++++++++++++++ nxdk-sdl-gpu/nxdkSDLGPU.cpp | 111 ++++++++++++++++++++++++++++++++++++ nxdk-sdl-gpu/nxdkSDLGPU.h | 14 +++++ 14 files changed, 404 insertions(+), 27 deletions(-) create mode 160000 3rdparty/pbgl create mode 160000 3rdparty/sdl-gpu create mode 100644 nxdk-sdl-gpu/Makefile.inc create mode 100644 nxdk-sdl-gpu/nxdkSDLGPU.cpp create mode 100644 nxdk-sdl-gpu/nxdkSDLGPU.h diff --git a/.gitmodules b/.gitmodules index 8365984..8713e09 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,9 @@ [submodule "3rdparty/NaturalSort"] path = 3rdparty/NaturalSort url = https://github.com/scopeInfinity/NaturalSort.git +[submodule "3rdparty/pbgl"] + path = 3rdparty/pbgl + url = https://github.com/abaire/pbgl.git +[submodule "3rdparty/sdl-gpu"] + path = 3rdparty/sdl-gpu + url = https://github.com/abaire/sdl-gpu.git diff --git a/3rdparty/pbgl b/3rdparty/pbgl new file mode 160000 index 0000000..f47dd37 --- /dev/null +++ b/3rdparty/pbgl @@ -0,0 +1 @@ +Subproject commit f47dd37ec718a72269cf3d8b16965e5b43226dcc diff --git a/3rdparty/sdl-gpu b/3rdparty/sdl-gpu new file mode 160000 index 0000000..c1c3334 --- /dev/null +++ b/3rdparty/sdl-gpu @@ -0,0 +1 @@ +Subproject commit c1c3334fafb3fd3189458f1fe1f870a78b76f937 diff --git a/Includes/font.cpp b/Includes/font.cpp index 57ce35b..61da0c0 100644 --- a/Includes/font.cpp +++ b/Includes/font.cpp @@ -1,13 +1,17 @@ #include "font.h" #include -#include "3rdparty/SDL_FontCache/SDL_FontCache.h" -#include "infoLog.h" + Font::Font(Renderer& renderer, const char* path) : renderer(renderer) { fcFont = FC_CreateFont(); assert(fcFont); +#ifdef FC_USE_SDL_GPU + bool load_success = FC_LoadFont(fcFont, path, 20, FC_MakeColor(250, 250, 250, 255), + TTF_STYLE_NORMAL); +#else bool load_success = FC_LoadFont(fcFont, renderer.getRenderer(), path, 20, FC_MakeColor(250, 250, 250, 255), TTF_STYLE_NORMAL); +#endif assert(load_success); } diff --git a/Includes/font.h b/Includes/font.h index 7977c52..6fa0438 100644 --- a/Includes/font.h +++ b/Includes/font.h @@ -4,9 +4,15 @@ #include #include #include -#include "3rdparty/SDL_FontCache/SDL_FontCache.h" #include "renderer.h" +// clang-format off +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#include "3rdparty/SDL_FontCache/SDL_FontCache.h" +#pragma clang diagnostic pop +// clang-format on + class Font { private: FC_Font* fcFont; diff --git a/Includes/menu.cpp b/Includes/menu.cpp index c12a115..8e22ef4 100644 --- a/Includes/menu.cpp +++ b/Includes/menu.cpp @@ -5,6 +5,16 @@ #include "settingsMenu.hpp" #include "xbeLauncher.h" #include "xbeScanner.h" +#ifdef NXDK +// clang-format off +#ifdef FC_USE_SDL_GPU +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#include "SDL_gpu.h" +#pragma clang diagnostic pop +#endif +// clang-format on +#endif // Character used in the config.json to separate multiple path entries. #define PATH_DELIMITER ',' @@ -384,6 +394,12 @@ void Menu::render(Font& font) { dimensions = font.draw(menutext, coordinates); if (i == this->currentMenu->getSelected()) { +#ifdef FC_USE_SDL_GPU + GPU_Rect rect = { std::get<0>(coordinates) - 10, std::get<1>(coordinates), + std::get<0>(dimensions) + 20, std::get<1>(dimensions) }; + SDL_Color color = { 0xFF, 0xFF, 0xFF, 0xFF }; + GPU_Rectangle2(renderer.getRenderer(), rect, color); +#else SDL_Rect rect; rect.w = std::get<0>(dimensions) + 20; rect.h = std::get<1>(dimensions); @@ -391,6 +407,7 @@ void Menu::render(Font& font) { rect.y = std::get<1>(coordinates); renderer.setDrawColor(0xFF, 0xFF, 0xFF, 0xFF); SDL_RenderDrawRect(renderer.getRenderer(), &rect); +#endif } coordinates = std::pair( diff --git a/Includes/renderer.cpp b/Includes/renderer.cpp index 052e184..011df55 100644 --- a/Includes/renderer.cpp +++ b/Includes/renderer.cpp @@ -6,6 +6,7 @@ #ifdef NXDK #include +#include "nxdk-sdl-gpu/nxdkSDLGPU.h" #endif // One line of text with the default font is 31 pixels high. @@ -18,6 +19,9 @@ Renderer::Renderer() { height = xmode.height; width = xmode.width; windowFlags = SDL_WINDOW_SHOWN; +#ifdef FC_USE_SDL_GPU + windowFlags |= SDL_WINDOW_OPENGL; +#endif #else height = 480; width = 640; @@ -33,14 +37,24 @@ Renderer::Renderer() { Renderer::~Renderer() { if (background != nullptr) { +#ifdef FC_USE_SDL_GPU + GPU_FreeImage(background); +#else SDL_DestroyTexture(background); +#endif } if (renderer != nullptr) { +#ifdef FC_USE_SDL_GPU + GPU_FreeTarget(renderer); +#else SDL_DestroyRenderer(renderer); +#endif } +#ifndef FC_USE_SDL_GPU if (window != nullptr) { SDL_DestroyWindow(window); } +#endif } int Renderer::init() { @@ -49,11 +63,24 @@ int Renderer::init() { if (window == nullptr) { return 1; } + +#ifdef FC_USE_SDL_GPU + GPU_SetInitWindow(SDL_GetWindowID(window)); + renderer = GPU_Init(width, height, GPU_DEFAULT_INIT_FLAGS); + if (!renderer) { + return 1; + } +#else renderer = SDL_CreateRenderer(window, -1, renderFlags); +#endif if (renderer == nullptr) { return 2; } - SDL_SetRenderDrawBlendMode(getRenderer(), SDL_BLENDMODE_BLEND); +#ifdef FC_USE_SDL_GPU + GPU_SetShapeBlendMode(GPU_BLEND_NORMAL); +#else + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); +#endif setDrawColor(); clear(); return 0; @@ -72,7 +99,26 @@ int Renderer::init(const char* bgpath) { InfoLog::outputLine(InfoLog::ERROR, "Creating background surface failed.\n"); return 3; } +#ifdef FC_USE_SDL_GPU + // OpenGL wants the surface in BGR format, but pbgl does not currently implement a + // conversion. Since IMG_Load is only used in this one place, it is converted here + // manually. + auto srcFormat = static_cast(bgsurf->format->format); + switch (srcFormat) { + case SDL_PIXELFORMAT_RGB24: + case SDL_PIXELFORMAT_RGB888: + case SDL_PIXELFORMAT_RGBA32: + case SDL_PIXELFORMAT_RGBA8888: + bgsurf = convertRGBToBGR(bgsurf); + break; + default: + // Ignore surfaces that may already be BGR. + break; + } + background = GPU_CopyImageFromSurface(bgsurf); +#else background = SDL_CreateTextureFromSurface(renderer, bgsurf); +#endif SDL_FreeSurface(bgsurf); if (background == nullptr) { InfoLog::outputLine(InfoLog::ERROR, "Creating background texture failed.\n"); @@ -82,44 +128,80 @@ int Renderer::init(const char* bgpath) { } int Renderer::clear() { +#ifdef FC_USE_SDL_GPU + GPU_ClearColor(renderer, drawColor); + return 0; +#else int ret = SDL_RenderClear(renderer); return ret; +#endif } void Renderer::flip() { +#ifdef FC_USE_SDL_GPU + GPU_Flip(renderer); +#else setDrawColor(0, 0, 0, 0xFF); SDL_RenderDrawRect(renderer, nullptr); setDrawColor(); SDL_RenderPresent(renderer); -#ifdef NXDK - XVideoWaitForVBlank(); #endif } int Renderer::setDrawColor(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { +#ifdef FC_USE_SDL_GPU + drawColor.r = r; + drawColor.g = g; + drawColor.b = b; + drawColor.a = a; + return 0; +#else return SDL_SetRenderDrawColor(renderer, r, g, b, a); +#endif } -void Renderer::drawTexture(SDL_Texture* tex, SDL_Rect& src, SDL_Rect& dst) { +void Renderer::drawTexture(NX_Texture* tex, NX_Rect& src, NX_Rect& dst) { +#ifdef FC_USE_SDL_GPU + GPU_BlitRect(tex, &src, renderer, &dst); +#else SDL_RenderCopy(renderer, tex, &src, &dst); +#endif } -void Renderer::drawTexture(SDL_Texture* tex, SDL_Rect& dst) { +void Renderer::drawTexture(NX_Texture* tex, NX_Rect& dst) { +#ifdef FC_USE_SDL_GPU + GPU_BlitRect(tex, nullptr, renderer, &dst); +#else SDL_RenderCopy(renderer, tex, nullptr, &dst); +#endif } -void Renderer::drawTexture(SDL_Texture* tex, int x, int y) { - SDL_Rect dst = { x, y, 0, 0 }; +void Renderer::drawTexture(NX_Texture* tex, int x, int y) { +#ifdef FC_USE_SDL_GPU + NX_Rect dst = { static_cast(x), static_cast(y), static_cast(tex->w), + static_cast(tex->h) }; +#else + NX_Rect dst = { x, y, 0, 0 }; SDL_QueryTexture(tex, nullptr, nullptr, &dst.w, &dst.h); +#endif drawTexture(tex, dst); } -void Renderer::fillRectangle(const SDL_Rect& dst) { +void Renderer::fillRectangle(const NX_Rect& dst) { +#ifdef FC_USE_SDL_GPU + GPU_RectangleFilled2(renderer, dst, drawColor); +#else SDL_RenderFillRect(renderer, &dst); +#endif } void Renderer::fillRectangle(const SDL_FRect& dst) { +#ifdef FC_USE_SDL_GPU + GPU_Rect rect = { dst.x, dst.y, dst.w, dst.h }; + GPU_RectangleFilled2(renderer, rect, drawColor); +#else SDL_RenderFillRectF(renderer, &dst); +#endif } void Renderer::blitSurface(SDL_Surface* bg, SDL_Surface* fg, int offset) { diff --git a/Includes/renderer.h b/Includes/renderer.h index 5912162..a65574c 100644 --- a/Includes/renderer.h +++ b/Includes/renderer.h @@ -4,8 +4,24 @@ #include #include -int min(int lhs, int rhs); -int max(int lhs, int rhs); +// clang-format off +#ifdef FC_USE_SDL_GPU +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#include "SDL_gpu.h" +#pragma clang diagnostic pop +#endif +// clang-format on + +#ifdef FC_USE_SDL_GPU +typedef GPU_Image NX_Texture; +typedef GPU_Rect NX_Rect; +typedef GPU_Target NX_Target; +#else +typedef SDL_Texture NX_Texture; +typedef SDL_Rect NX_Rect; +typedef SDL_Renderer NX_Target; +#endif class Renderer { public: @@ -17,17 +33,21 @@ class Renderer { int clear(); void flip(); +#ifdef FC_USE_SDL_GPU + GPU_Target* getRenderer() { return renderer; } +#else SDL_Renderer* getRenderer() { return renderer; } +#endif int getWidth() const { return width; } int getHeight() const { return height; } int setDrawColor(uint8_t r = 0x40, uint8_t g = 0x40, uint8_t b = 0xE0, uint8_t a = 0x00); - void drawTexture(SDL_Texture* tex, SDL_Rect& src, SDL_Rect& dst); - void drawTexture(SDL_Texture* tex, SDL_Rect& dst); - void drawTexture(SDL_Texture* tex, int x, int y); + void drawTexture(NX_Texture* tex, NX_Rect& src, NX_Rect& dst); + void drawTexture(NX_Texture* tex, NX_Rect& dst); + void drawTexture(NX_Texture* tex, int x, int y); - void fillRectangle(const SDL_Rect& dst); + void fillRectangle(const NX_Rect& dst); void fillRectangle(const SDL_FRect& dst); void blitSurface(SDL_Surface* bg, SDL_Surface* fg, int offset); @@ -35,10 +55,13 @@ class Renderer { void drawBackground(); private: - SDL_Renderer* renderer = nullptr; + NX_Target* renderer = nullptr; + NX_Texture* background = nullptr; + SDL_Window* window = nullptr; - SDL_Texture* background = nullptr; +#ifndef FC_USE_SDL_GPU Uint32 renderFlags = 0; +#endif Uint32 windowFlags = 0; int height = 0; @@ -48,6 +71,10 @@ class Renderer { size_t menuItemCount = 0; size_t lowerHalf = 0; size_t upperHalf = 0; + +#ifdef FC_USE_SDL_GPU + SDL_Color drawColor; +#endif }; #endif diff --git a/Includes/sntpClient.cpp b/Includes/sntpClient.cpp index 0239596..9673aa9 100644 --- a/Includes/sntpClient.cpp +++ b/Includes/sntpClient.cpp @@ -74,7 +74,8 @@ void sntpClient::updateTime() const { message.originTimestamp.fractionalSeconds = htonl(message.originTimestamp.fractionalSeconds); if (message.originTimestamp.seconds || message.originTimestamp.fractionalSeconds) { - InfoLog::outputLine(InfoLog::INFO, "SNTP: Origin epoch is not 0: %lld\n", message.originTimestamp); + InfoLog::outputLine(InfoLog::INFO, "SNTP: Origin epoch is not 0: %lld\n", + message.originTimestamp); } message.transmitTimestamp.seconds = htonl(message.transmitTimestamp.seconds); @@ -95,7 +96,8 @@ void sntpClient::updateTime() const { } if (delta > allowedDriftSeconds) { - InfoLog::outputLine(InfoLog::DEBUG, "SNTP: Updating system clock (%llu seconds of drift)\n", delta); + InfoLog::outputLine(InfoLog::DEBUG, + "SNTP: Updating system clock (%llu seconds of drift)\n", delta); NTSTATUS status = NtSetSystemTime(&serverTime, nullptr); if (!NT_SUCCESS(status)) { InfoLog::outputLine(InfoLog::INFO, "SNTP: NtSetSystemTime failed: %X\n", status); diff --git a/Includes/subsystems.cpp b/Includes/subsystems.cpp index 4b3621d..33b42f2 100644 --- a/Includes/subsystems.cpp +++ b/Includes/subsystems.cpp @@ -6,7 +6,8 @@ #include #include #include -#include +#include "GL/gl.h" +#include "pbgl.h" #endif #include @@ -16,6 +17,12 @@ #ifdef NXDK #include "networking.h" +// clang-format off +#ifdef FC_USE_SDL_GPU +#include "nxdk-sdl-gpu/nxdkSDLGPU.h" +#endif // FC_USE_SDL_GPU +// clang-format on + void mountHomeDir(const char Letter) { char targetPath[MAX_PATH]; char* finalSeparator; @@ -68,11 +75,26 @@ int init_systems(const Config& config) { InfoLog::outputLine(InfoLog::ERROR, "Mounting warning: Could not mount DVD drive\n"); } #endif + if (SDL_Init(SDL_INIT_VIDEO) != 0) { InfoLog::outputLine(InfoLog::ERROR, "SDL_Init error: %s", SDL_GetError()); return 3; } +#ifdef NXDK + int status = pbgl_init(GL_TRUE); + if (status) { + InfoLog::outputLine(InfoLog::ERROR, "pbgl_init error: %d", status); + return 4; + } + + pbgl_set_swap_interval(1); + +#ifdef FC_USE_SDL_GPU + pbglConfigureSDLVideoDevice(); +#endif +#endif + if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) { InfoLog::outputLine(InfoLog::ERROR, "IMG Init Error: %s!\n", IMG_GetError()); return 2; diff --git a/Makefile b/Makefile index 5576eed..adfba44 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,7 @@ SRCS += \ $(INCDIR)/wipeCache.cpp \ $(INCDIR)/xbeLauncher.cpp \ $(INCDIR)/xbeScanner.cpp \ + $(CURDIR)/nxdk-sdl-gpu/nxdkSDLGPU.cpp \ $(CURDIR)/3rdparty/SDL_FontCache/SDL_FontCache.c NXDK_DIR ?= $(CURDIR)/../nxdk @@ -37,21 +38,41 @@ NXDK_DISABLE_AUTOMOUNT_D = y GEN_XISO = ${XBE_TITLE}.iso -CXXFLAGS += -I$(CURDIR) -I$(INCDIR) -Wall -Wextra -std=gnu++11 -CFLAGS += -std=gnu11 +CXXFLAGS += -I$(CURDIR) -I$(INCDIR) -I$(SDL_GPU_DIR)/include -I$(PBGL_DIR)/include -Wall -Wextra -std=gnu++11 -DFC_USE_SDL_GPU +CFLAGS += -I$(SDL_GPU_DIR)/include -std=gnu11 -DFC_USE_SDL_GPU ifneq ($(DEBUG),y) CFLAGS += -O2 CXXFLAGS += -O2 endif -new_all: copy_resources all +CLEANRULES = clean-resources clean-gl include $(NXDK_DIR)/Makefile -copy_resources: $(OUTPUT_DIR)/config.json - @cp $(RESOURCEDIR)/480.png $(RESOURCEDIR)/720.png $(RESOURCEDIR)/vegur.ttf $(OUTPUT_DIR) +override PBGL_DIR := 3rdparty/pbgl +include 3rdparty/pbgl/Makefile + +override SDL_GPU_DIR := 3rdparty/sdl-gpu +include nxdk-sdl-gpu/Makefile.inc + +RESOURCES = \ + $(OUTPUT_DIR)/config.json \ + $(OUTPUT_DIR)/480.png \ + $(OUTPUT_DIR)/720.png + +TARGET += $(RESOURCES) +$(GEN_XISO): $(RESOURCES) $(OUTPUT_DIR)/config.json: $(CURDIR)/sampleconfig.json @mkdir -p $(OUTPUT_DIR) cp $(CURDIR)/sampleconfig.json $(OUTPUT_DIR)/config.json +$(OUTPUT_DIR)/%: $(RESOURCEDIR)/% + $(VE)cp -r '$<' '$@' + +.PHONY: clean-resources +clean-resources: + $(VE)rm -rf $(OUTPUT_DIR)/NeXThemes + +.PHONY: clean-gl +clean-gl: clean-sdl-gpu clean-pbgl diff --git a/nxdk-sdl-gpu/Makefile.inc b/nxdk-sdl-gpu/Makefile.inc new file mode 100644 index 0000000..fa1511f --- /dev/null +++ b/nxdk-sdl-gpu/Makefile.inc @@ -0,0 +1,63 @@ +# SDL_gpu is a CMake-based project, so for now an nxdk-compatible stub is used. +# This must be kept in sync with the content of the sdl-gpu directory. + +SDL_GPU_DIR := ./ +STB_IMAGE_DIR := $(SDL_GPU_DIR)/src/externals/stb_image +STB_IMAGE_WRITE_DIR := $(SDL_GPU_DIR)/src/externals/stb_image_write +GLEW_DIR := $(SDL_GPU_DIR)/src/externals/glew + +SDL_GPU_SRCS = \ + $(SDL_GPU_DIR)/src/SDL_gpu.c \ + $(SDL_GPU_DIR)/src/SDL_gpu_matrix.c \ + $(SDL_GPU_DIR)/src/SDL_gpu_renderer.c \ + $(SDL_GPU_DIR)/src/SDL_gpu_shapes.c \ + $(SDL_GPU_DIR)/src/renderer_OpenGL_1_BASE.c \ + $(SDL_GPU_DIR)/src/renderer_OpenGL_1.c \ + $(SDL_GPU_DIR)/src/renderer_OpenGL_2.c \ + $(SDL_GPU_DIR)/src/renderer_OpenGL_3.c \ + $(SDL_GPU_DIR)/src/renderer_OpenGL_4.c \ + $(STB_IMAGE_DIR)/stb_image.c \ + $(STB_IMAGE_WRITE_DIR)/stb_image_write.c \ + $(GLEW_DIR)/glew.c + +$(SDL_GPU_DIR)/src/renderer_OpenGL_%.obj: $(SDL_GPU_DIR)/src/renderer_OpenGL_%.c $(SDL_GPU_DIR)/src/renderer_GL_common.inl $(SDL_GPU_DIR)/src/renderer_shapes_GL_common.inl + +SDL_GPU_OBJS = $(addsuffix .obj, $(basename $(SDL_GPU_SRCS))) +LIB_DEPS += $(addsuffix .d, $(SDL_GPU_SRCS)) + +SDL_GPU_CFLAGS := \ + -Wno-inconsistent-dllimport \ + -DXBOX \ + -DAPIENTRY=__cdecl \ + -DSTBI_NO_SIMD \ + -DGLEW_STATIC \ + -DGLEW_NO_GLU \ + -DSDL_GPU_DISABLE_SHADERS \ + -DSDL_GPU_DISABLE_GLES \ + -DSDL_GPU_DISABLE_OPENGL_1_BASE \ + -DSDL_GPU_DISABLE_OPENGL_2 \ + -DSDL_GPU_DISABLE_OPENGL_3 \ + -DSDL_GPU_DISABLE_OPENGL_4 \ + -DSDL_GPU_DISABLE_TEXTURE_GETS \ + -I$(SDL_GPU_DIR)/include \ + -I$(STB_IMAGE_DIR) \ + -I$(STB_IMAGE_WRITE_DIR) \ + -I$(GLEW_DIR)/GL + +ifeq ($(DEBUG),y) + SDL_GPU_CFLAGS += -g -gdwarf-4 +else + SDL_GPU_CFLAGS += -O3 +endif + +$(NXDK_DIR)/lib/libsdl_gpu.lib: CFLAGS += $(SDL_GPU_CFLAGS) +$(NXDK_DIR)/lib/libsdl_gpu.lib: CXXFLAGS += $(SDL_GPU_CFLAGS) +$(NXDK_DIR)/lib/libsdl_gpu.lib: $(SDL_GPU_OBJS) + +main.exe: $(NXDK_DIR)/lib/libsdl_gpu.lib + +CLEANRULES += clean-sdl-gpu + +.PHONY: clean-sdl-gpu +clean-sdl-gpu: + $(VE)rm -f $(SDL_GPU_OBJS) $(NXDK_DIR)/lib/libsdl_gpu.lib diff --git a/nxdk-sdl-gpu/nxdkSDLGPU.cpp b/nxdk-sdl-gpu/nxdkSDLGPU.cpp new file mode 100644 index 0000000..d3ca872 --- /dev/null +++ b/nxdk-sdl-gpu/nxdkSDLGPU.cpp @@ -0,0 +1,111 @@ +#include "nxdkSDLGPU.h" +#include +#include "infoLog.h" +#include "pbgl.h" + +// clang-format off +extern "C" { +#include +}; +// clang-format on + +extern "C" { + +static int PBGL_LoadLibrary(_THIS, const char*) { + // XBOX/pbgl does not support dynamic libraries. + (void)_this; + return 0; +} + +static void* PBGL_GetProcAddress(_THIS, const char*) { + (void)_this; + return nullptr; +} + +static void PBGL_UnloadLibrary(_THIS) { + // XBOX/pbgl does not support dynamic libraries. + (void)_this; +} + +static SDL_GLContext PBGL_CreateContext(_THIS, SDL_Window*) { + (void)_this; + return reinterpret_cast(0xDEADBEEF); +} + +static int PBGL_MakeCurrent(_THIS, SDL_Window*, SDL_GLContext) { + (void)_this; + return 0; +} + +static void PBGL_GetDrawableSize(_THIS, SDL_Window* window, int* w, int* h) { + (void)_this; + SDL_GetWindowSize(window, w, h); +} + +static int PBGL_SetSwapInterval(_THIS, int interval) { + (void)_this; + if (interval < 0) { + return -1; + } + pbgl_set_swap_interval(interval); + return 0; +} + +static int PBGL_GetSwapInterval(_THIS) { + (void)_this; + return pbgl_get_swap_interval(); +} + +static int PBGL_SwapWindow(_THIS, SDL_Window*) { + (void)_this; + pbgl_swap_buffers(); + return 0; +} + +static void PBGL_DeleteContext(_THIS, SDL_GLContext) { + // PBGL has no context, so nothing needs to be done. + (void)_this; +} + +static void GL_DefaultProfileConfig(_THIS, int* mask, int* major, int* minor) { + (void)_this; + *mask = 0; + *major = 1; + *minor = 1; +} + +}; // extern "C" + +void pbglConfigureSDLVideoDevice() { + SDL_VideoDevice* device = SDL_GetVideoDevice(); + if (!device) { + InfoLog::outputLine(InfoLog::ERROR, "No SDL video device!\n"); + return; + } + + device->GL_LoadLibrary = PBGL_LoadLibrary; + device->GL_GetProcAddress = PBGL_GetProcAddress; + device->GL_UnloadLibrary = PBGL_UnloadLibrary; + device->GL_CreateContext = PBGL_CreateContext; + device->GL_MakeCurrent = PBGL_MakeCurrent; + device->GL_GetDrawableSize = PBGL_GetDrawableSize; + device->GL_SetSwapInterval = PBGL_SetSwapInterval; + device->GL_GetSwapInterval = PBGL_GetSwapInterval; + device->GL_SwapWindow = PBGL_SwapWindow; + device->GL_DeleteContext = PBGL_DeleteContext; + device->GL_DefaultProfileConfig = GL_DefaultProfileConfig; +} + + +SDL_Surface* convertRGBToBGR(SDL_Surface* src) { + for (int32_t y = 0; y < src->h; ++y) { + uint8_t* data = reinterpret_cast(src->pixels) + y * src->pitch; + for (int32_t x = 0; x < src->w; ++x, data += src->format->BytesPerPixel) { + uint8_t tmp = *data; + *data = data[2]; + data[2] = tmp; + } + } + + return src; +} \ No newline at end of file diff --git a/nxdk-sdl-gpu/nxdkSDLGPU.h b/nxdk-sdl-gpu/nxdkSDLGPU.h new file mode 100644 index 0000000..9329382 --- /dev/null +++ b/nxdk-sdl-gpu/nxdkSDLGPU.h @@ -0,0 +1,14 @@ +#ifndef NEVOLUTIONX_NXDKSDLGPU_H +#define NEVOLUTIONX_NXDKSDLGPU_H + +#include + +// Patches the active SDL_VideoDevice with OpenGL callbacks that leverage pbgl. +// +// Must be called after SDL_Init. +void pbglConfigureSDLVideoDevice(); + +// Swaps the given SDL_Surface from RGB(A) to BGR(A) in place. +SDL_Surface* convertRGBToBGR(SDL_Surface* src); + +#endif // NEVOLUTIONX_NXDKSDLGPU_H