From f5b3b2e0d08ccbcf62aa04e836307142230ada59 Mon Sep 17 00:00:00 2001 From: Clownacy Date: Sun, 11 Oct 2020 00:09:22 +0100 Subject: [PATCH] Add a basic 3DS port Was a lot easier than I expected. The software renderer is such a godsend for quick-and-dirty ports. Oddly enough, even on an old3DS, this actually almost runs at full speed (hits around 40FPS in Mimiga Village). There's a lot of work left to do before this is actually useable: * There's no audio * You can't save * A proper hardware-accelerated renderer is needed --- CMakeLists.txt | 9 +- src/Backends/Platform/3DS.cpp | 147 ++++++++++++++++++ .../Rendering/Window/Software/3DS.cpp | 75 +++++++++ 3 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 src/Backends/Platform/3DS.cpp create mode 100644 src/Backends/Rendering/Window/Software/3DS.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 98d70409..cbab1a1a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ option(FREETYPE_FONTS "Use FreeType2 to render the DejaVu Mono (English) or Migu set(BACKEND_RENDERER "SDLTexture" CACHE STRING "Which renderer the game should use: 'OpenGL3' for an OpenGL 3.2 renderer, 'OpenGLES2' for an OpenGL ES 2.0 renderer, 'SDLTexture' for SDL2's hardware-accelerated Texture API, 'SDLSurface' for SDL2's software-rendered Surface API, 'Wii U' for the Wii U's hardware-accelerated GX2 API, or 'Software' for a handwritten software renderer") set(BACKEND_AUDIO "SDL2" CACHE STRING "Which audio backend the game should use: 'SDL2', 'miniaudio', 'WiiU-Hardware', 'WiiU-Software', or 'Null'") -set(BACKEND_PLATFORM "SDL2" CACHE STRING "Which platform backend the game should use: 'SDL2', 'GLFW3', 'WiiU', or 'Null'") +set(BACKEND_PLATFORM "SDL2" CACHE STRING "Which platform backend the game should use: 'SDL2', 'GLFW3', 'WiiU', '3DS', or 'Null'") option(LTO "Enable link-time optimisation" OFF) option(PKG_CONFIG_STATIC_LIBS "On platforms with pkg-config, static-link the dependencies (good for Windows builds, so you don't need to bundle DLL files)" OFF) @@ -393,6 +393,11 @@ elseif(BACKEND_PLATFORM MATCHES "WiiU") "src/Backends/Controller/WiiU.cpp" "src/Backends/Platform/WiiU.cpp" ) +elseif(BACKEND_PLATFORM MATCHES "3DS") + target_sources(CSE2 PRIVATE + "src/Backends/Controller/Null.cpp" + "src/Backends/Platform/3DS.cpp" + ) elseif(BACKEND_PLATFORM MATCHES "Null") target_sources(CSE2 PRIVATE "src/Backends/Controller/Null.cpp" @@ -417,6 +422,8 @@ elseif(BACKEND_PLATFORM MATCHES "GLFW3" AND BACKEND_RENDERER MATCHES "Software") elseif(BACKEND_PLATFORM MATCHES "WiiU" AND BACKEND_RENDERER MATCHES "WiiU") elseif(BACKEND_PLATFORM MATCHES "WiiU" AND BACKEND_RENDERER MATCHES "Software") target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/WiiU.cpp") +elseif(BACKEND_PLATFORM MATCHES "3DS" AND BACKEND_RENDERER MATCHES "Software") + target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/3DS.cpp") elseif(BACKEND_PLATFORM MATCHES "Null" AND BACKEND_RENDERER MATCHES "Software") target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/Null.cpp") else() diff --git a/src/Backends/Platform/3DS.cpp b/src/Backends/Platform/3DS.cpp new file mode 100644 index 00000000..591ddd4c --- /dev/null +++ b/src/Backends/Platform/3DS.cpp @@ -0,0 +1,147 @@ +#include "../Misc.h" + +#include +#include +#include +#include + +#include <3ds.h> + +bool Backend_Init(void (*drag_and_drop_callback)(const char *path), void (*window_focus_callback)(bool focus)) +{ + (void)drag_and_drop_callback; + (void)window_focus_callback; + + hidInit(); + + gfxInitDefault(); + consoleInit(GFX_TOP, NULL); + + Result rc = romfsInit(); + + if (rc == 0) + { + return true; + } + else + { + Backend_PrintError("Could not initialise romfs"); + } + + return false; +} + +void Backend_Deinit(void) +{ + romfsExit(); + + gfxExit(); + + hidExit(); +} + +void Backend_PostWindowCreation(void) +{ + +} + +bool Backend_GetBasePath(std::string *string_buffer) +{ + *string_buffer = "romfs:"; + + return true; +} + +void Backend_HideMouse(void) +{ + +} + +void Backend_SetWindowIcon(const unsigned char *rgb_pixels, size_t width, size_t height) +{ + (void)rgb_pixels; + (void)width; + (void)height; +} + +void Backend_SetCursor(const unsigned char *rgba_pixels, size_t width, size_t height) +{ + (void)rgba_pixels; + (void)width; + (void)height; +} + +void Backend_EnableDragAndDrop(void) +{ + +} + +bool Backend_SystemTask(bool active) +{ + (void)active; + + return aptMainLoop(); +} + +void Backend_GetKeyboardState(bool *keyboard_state) +{ + memset(keyboard_state, 0, sizeof(bool) * BACKEND_KEYBOARD_TOTAL); + + // Read controller + hidScanInput(); + + u32 buttons = hidKeysHeld(); + + keyboard_state[BACKEND_KEYBOARD_UP] |= buttons & KEY_UP; + keyboard_state[BACKEND_KEYBOARD_DOWN] |= buttons & KEY_DOWN; + keyboard_state[BACKEND_KEYBOARD_LEFT] |= buttons & KEY_LEFT; + keyboard_state[BACKEND_KEYBOARD_RIGHT] |= buttons & KEY_RIGHT; + keyboard_state[BACKEND_KEYBOARD_Z] |= buttons & KEY_B; // Jump + keyboard_state[BACKEND_KEYBOARD_X] |= buttons & KEY_Y; // Shoot + keyboard_state[BACKEND_KEYBOARD_Q] |= buttons & (KEY_A | KEY_START); // Inventory + keyboard_state[BACKEND_KEYBOARD_W] |= buttons & (KEY_X | KEY_SELECT); // Map + keyboard_state[BACKEND_KEYBOARD_A] |= buttons & (KEY_L | KEY_ZL | KEY_CSTICK_LEFT); // Weapon left + keyboard_state[BACKEND_KEYBOARD_S] |= buttons & (KEY_R | KEY_ZR | KEY_CSTICK_RIGHT); // Weapon right +} + +void Backend_ShowMessageBox(const char *title, const char *message) +{ + Backend_PrintInfo("ShowMessageBox - %s - %s", title, message); +} + +ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintError(const char *format, ...) +{ + char message_buffer[0x100]; + + va_list argument_list; + va_start(argument_list, format); + vsnprintf(message_buffer, sizeof(message_buffer), format, argument_list); + va_end(argument_list); + + printf("ERROR:"); + printf(message_buffer); +} + +ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintInfo(const char *format, ...) +{ + char message_buffer[0x100]; + + va_list argument_list; + va_start(argument_list, format); + vsnprintf(message_buffer, sizeof(message_buffer), format, argument_list); + va_end(argument_list); + + printf("INFO:"); + printf(message_buffer); +} + +unsigned long Backend_GetTicks(void) +{ + return svcGetSystemTick() / CPU_TICKS_PER_MSEC; +} + +void Backend_Delay(unsigned int ticks) +{ + // svcSleepThread measures in nanoseconds + svcSleepThread(ticks * 1000000); +} diff --git a/src/Backends/Rendering/Window/Software/3DS.cpp b/src/Backends/Rendering/Window/Software/3DS.cpp new file mode 100644 index 00000000..906505bb --- /dev/null +++ b/src/Backends/Rendering/Window/Software/3DS.cpp @@ -0,0 +1,75 @@ +#include "../Software.h" + +#include +#include + +#include <3ds.h> + +static unsigned char *framebuffer; +static size_t framebuffer_pitch; +static size_t framebuffer_width; +static size_t framebuffer_height; + +bool WindowBackend_Software_CreateWindow(const char *window_title, size_t screen_width, size_t screen_height, bool fullscreen) +{ + (void)window_title; + (void)fullscreen; + + gfxSetDoubleBuffering(GFX_TOP, true); + + gfxSetScreenFormat(GFX_TOP, GSP_BGR8_OES); + + framebuffer = (unsigned char*)malloc(screen_width * screen_height * 3); + + if (framebuffer != NULL) + { + framebuffer_pitch = screen_width * 3; + framebuffer_width = screen_width; + framebuffer_height = screen_height; + + return true; + } + + return false; +} + +void WindowBackend_Software_DestroyWindow(void) +{ + free(framebuffer); +} + +unsigned char* WindowBackend_Software_GetFramebuffer(size_t *pitch) +{ + *pitch = framebuffer_pitch; + + return framebuffer; +} + +void WindowBackend_Software_Display(void) +{ + // Absolutely disgusting + unsigned char *actual_framebuffer = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL); + + unsigned char *framebuffer_pointer = framebuffer; + + const size_t offset = ((400 - framebuffer_width) / 2) * 240; + + for (unsigned int h = framebuffer_height - 1; h-- != 0;) + { + for (unsigned int w = 0; w < framebuffer_width * 240; w += 240) + { + actual_framebuffer[(offset + w + h) * 3 + 2] = *framebuffer_pointer++; + actual_framebuffer[(offset + w + h) * 3 + 1] = *framebuffer_pointer++; + actual_framebuffer[(offset + w + h) * 3 + 0] = *framebuffer_pointer++; + } + } + + gfxFlushBuffers(); + gfxSwapBuffers(); +} + +void WindowBackend_Software_HandleWindowResize(size_t width, size_t height) +{ + (void)width; + (void)height; +}