ref: f5b3b2e0d08ccbcf62aa04e836307142230ada59
parent: 49027c4ab789f2ed367bf6b16e5cc8a9f019e40f
author: Clownacy <Clownacy@users.noreply.github.com>
date: Sat Oct 10 20:09:22 EDT 2020
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
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,7 +26,7 @@
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 @@
"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 "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()
--- /dev/null
+++ b/src/Backends/Platform/3DS.cpp
@@ -1,0 +1,147 @@
+#include "../Misc.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <string>
+
+#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);
+}
--- /dev/null
+++ b/src/Backends/Rendering/Window/Software/3DS.cpp
@@ -1,0 +1,75 @@
+#include "../Software.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#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;
+}