shithub: cstory

Download patch

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;
+}