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
This commit is contained in:
parent
49027c4ab7
commit
f5b3b2e0d0
3 changed files with 230 additions and 1 deletions
|
@ -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_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_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(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)
|
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/Controller/WiiU.cpp"
|
||||||
"src/Backends/Platform/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")
|
elseif(BACKEND_PLATFORM MATCHES "Null")
|
||||||
target_sources(CSE2 PRIVATE
|
target_sources(CSE2 PRIVATE
|
||||||
"src/Backends/Controller/Null.cpp"
|
"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 "WiiU")
|
||||||
elseif(BACKEND_PLATFORM MATCHES "WiiU" AND BACKEND_RENDERER MATCHES "Software")
|
elseif(BACKEND_PLATFORM MATCHES "WiiU" AND BACKEND_RENDERER MATCHES "Software")
|
||||||
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/WiiU.cpp")
|
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")
|
elseif(BACKEND_PLATFORM MATCHES "Null" AND BACKEND_RENDERER MATCHES "Software")
|
||||||
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/Null.cpp")
|
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/Null.cpp")
|
||||||
else()
|
else()
|
||||||
|
|
147
src/Backends/Platform/3DS.cpp
Normal file
147
src/Backends/Platform/3DS.cpp
Normal file
|
@ -0,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);
|
||||||
|
}
|
75
src/Backends/Rendering/Window/Software/3DS.cpp
Normal file
75
src/Backends/Rendering/Window/Software/3DS.cpp
Normal file
|
@ -0,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;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue