From 5a079a2d114f96d4847d1ee305d5b7c16eeec50e Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 27 Dec 2025 12:03:39 -0800 Subject: Initial commit --- contrib/SDL-3.2.8/src/video/n3ds/SDL_n3dsvideo.c | 259 +++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 contrib/SDL-3.2.8/src/video/n3ds/SDL_n3dsvideo.c (limited to 'contrib/SDL-3.2.8/src/video/n3ds/SDL_n3dsvideo.c') diff --git a/contrib/SDL-3.2.8/src/video/n3ds/SDL_n3dsvideo.c b/contrib/SDL-3.2.8/src/video/n3ds/SDL_n3dsvideo.c new file mode 100644 index 0000000..8e925bf --- /dev/null +++ b/contrib/SDL-3.2.8/src/video/n3ds/SDL_n3dsvideo.c @@ -0,0 +1,259 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2025 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_internal.h" + +#ifdef SDL_VIDEO_DRIVER_N3DS + +#include "../SDL_sysvideo.h" +#include "SDL_n3dsevents_c.h" +#include "SDL_n3dsframebuffer_c.h" +#include "SDL_n3dsswkb.h" +#include "SDL_n3dstouch.h" +#include "SDL_n3dsvideo.h" + +#define N3DSVID_DRIVER_NAME "n3ds" + +static bool AddN3DSDisplay(gfxScreen_t screen); + +static bool N3DS_VideoInit(SDL_VideoDevice *_this); +static void N3DS_VideoQuit(SDL_VideoDevice *_this); +static bool N3DS_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display); +static bool N3DS_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode); +static bool N3DS_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect); +static bool N3DS_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props); +static void N3DS_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window); + +struct SDL_DisplayData +{ + gfxScreen_t screen; +}; + +struct SDL_DisplayModeData +{ + GSPGPU_FramebufferFormat fmt; +}; + +static const struct +{ + SDL_PixelFormat pixfmt; + GSPGPU_FramebufferFormat gspfmt; +} format_map[] = { + { SDL_PIXELFORMAT_RGBA8888, GSP_RGBA8_OES }, + { SDL_PIXELFORMAT_BGR24, GSP_BGR8_OES }, + { SDL_PIXELFORMAT_RGB565, GSP_RGB565_OES }, + { SDL_PIXELFORMAT_RGBA5551, GSP_RGB5_A1_OES }, + { SDL_PIXELFORMAT_RGBA4444, GSP_RGBA4_OES } +}; + +// N3DS driver bootstrap functions + +static void N3DS_DeleteDevice(SDL_VideoDevice *device) +{ + SDL_free(device->internal); + SDL_free(device); +} + +static SDL_VideoDevice *N3DS_CreateDevice(void) +{ + SDL_VideoDevice *device; + SDL_VideoData *phdata; + + // Initialize all variables that we clean on shutdown + device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice)); + if (!device) { + return NULL; + } + + // Initialize internal data + phdata = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData)); + if (!phdata) { + SDL_free(device); + return NULL; + } + + device->internal = phdata; + + device->VideoInit = N3DS_VideoInit; + device->VideoQuit = N3DS_VideoQuit; + + device->GetDisplayModes = N3DS_GetDisplayModes; + device->SetDisplayMode = N3DS_SetDisplayMode; + device->GetDisplayBounds = N3DS_GetDisplayBounds; + + device->CreateSDLWindow = N3DS_CreateWindow; + device->DestroyWindow = N3DS_DestroyWindow; + + device->HasScreenKeyboardSupport = N3DS_HasScreenKeyboardSupport; + device->StartTextInput = N3DS_StartTextInput; + device->StopTextInput = N3DS_StopTextInput; + + device->PumpEvents = N3DS_PumpEvents; + + device->CreateWindowFramebuffer = SDL_N3DS_CreateWindowFramebuffer; + device->UpdateWindowFramebuffer = SDL_N3DS_UpdateWindowFramebuffer; + device->DestroyWindowFramebuffer = SDL_N3DS_DestroyWindowFramebuffer; + + device->free = N3DS_DeleteDevice; + + device->device_caps = VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY; + + return device; +} + +VideoBootStrap N3DS_bootstrap = { N3DSVID_DRIVER_NAME, "N3DS Video Driver", N3DS_CreateDevice, NULL, /* no ShowMessageBox implementation */ false }; + +static bool N3DS_VideoInit(SDL_VideoDevice *_this) +{ + SDL_VideoData *internal = (SDL_VideoData *)_this->internal; + + gfxInit(GSP_RGBA8_OES, GSP_RGBA8_OES, false); + hidInit(); + + internal->top_display = AddN3DSDisplay(GFX_TOP); + internal->touch_display = AddN3DSDisplay(GFX_BOTTOM); + + N3DS_InitTouch(); + N3DS_SwkbInit(); + + return true; +} + +static bool AddN3DSDisplay(gfxScreen_t screen) +{ + SDL_DisplayMode mode; + SDL_DisplayModeData *modedata; + SDL_VideoDisplay display; + SDL_DisplayData *display_driver_data = SDL_calloc(1, sizeof(SDL_DisplayData)); + if (!display_driver_data) { + return false; + } + + SDL_zero(mode); + SDL_zero(display); + + display_driver_data->screen = screen; + + modedata = SDL_malloc(sizeof(SDL_DisplayModeData)); + if (!modedata) { + return false; + } + + mode.w = (screen == GFX_TOP) ? GSP_SCREEN_HEIGHT_TOP : GSP_SCREEN_HEIGHT_BOTTOM; + mode.h = GSP_SCREEN_WIDTH; + mode.refresh_rate = 60.0f; + mode.format = SDL_PIXELFORMAT_RGBA8888; + mode.internal = modedata; + modedata->fmt = GSP_RGBA8_OES; + + display.name = (screen == GFX_TOP) ? "N3DS top screen" : "N3DS bottom screen"; + display.desktop_mode = mode; + display.internal = display_driver_data; + + if (SDL_AddVideoDisplay(&display, false) == 0) { + return false; + } + return true; +} + +static void N3DS_VideoQuit(SDL_VideoDevice *_this) +{ + N3DS_SwkbQuit(); + N3DS_QuitTouch(); + + hidExit(); + gfxExit(); +} + +static bool N3DS_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display) +{ + SDL_DisplayData *displaydata = display->internal; + SDL_DisplayModeData *modedata; + SDL_DisplayMode mode; + int i; + + for (i = 0; i < SDL_arraysize(format_map); i++) { + modedata = SDL_malloc(sizeof(SDL_DisplayModeData)); + if (!modedata) + continue; + + SDL_zero(mode); + mode.w = (displaydata->screen == GFX_TOP) ? GSP_SCREEN_HEIGHT_TOP : GSP_SCREEN_HEIGHT_BOTTOM; + mode.h = GSP_SCREEN_WIDTH; + mode.refresh_rate = 60.0f; + mode.format = format_map[i].pixfmt; + mode.internal = modedata; + modedata->fmt = format_map[i].gspfmt; + + if (!SDL_AddFullscreenDisplayMode(display, &mode)) { + SDL_free(modedata); + } + } + + return true; +} + +static bool N3DS_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode) +{ + SDL_DisplayData *displaydata = display->internal; + SDL_DisplayModeData *modedata = mode->internal; + + gfxSetScreenFormat(displaydata->screen, modedata->fmt); + return true; +} + +static bool N3DS_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect) +{ + SDL_DisplayData *driver_data = display->internal; + + if (!driver_data) { + return false; + } + + rect->x = 0; + rect->y = (driver_data->screen == GFX_TOP) ? 0 : GSP_SCREEN_WIDTH; + rect->w = display->current_mode->w; + rect->h = display->current_mode->h; + return true; +} + +static bool N3DS_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) +{ + SDL_DisplayData *display_data; + SDL_WindowData *window_data = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData)); + if (!window_data) { + return false; + } + display_data = SDL_GetDisplayDriverDataForWindow(window); + window_data->screen = display_data->screen; + window->internal = window_data; + SDL_SetKeyboardFocus(window); + return true; +} + +static void N3DS_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) +{ + if (!window) { + return; + } + SDL_free(window->internal); +} + +#endif // SDL_VIDEO_DRIVER_N3DS -- cgit v1.2.3