From cf8789f8879dc2e6ade1a273088a4b861de5ef86 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Mon, 11 May 2020 23:30:44 +0100 Subject: [PATCH 1/8] Initial SDL 1.2 backend --- CMakeLists.txt | 46 +++- src/Backends/Controller/{SDL2.cpp => SDL.cpp} | 4 + src/Backends/Platform/SDL1.cpp | 254 ++++++++++++++++++ .../Rendering/Window/Software/SDL1.cpp | 76 ++++++ 4 files changed, 378 insertions(+), 2 deletions(-) rename src/Backends/Controller/{SDL2.cpp => SDL.cpp} (98%) create mode 100644 src/Backends/Platform/SDL1.cpp create mode 100644 src/Backends/Rendering/Window/Software/SDL1.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9980f348..f2498895 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, '3DS' for the 3DS's hardware accelerated Citro2D/Citro3D 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', '3DS-Hardware', '3DS-Software', or 'Null'") -set(BACKEND_PLATFORM "SDL2" CACHE STRING "Which platform backend the game should use: 'SDL2', 'GLFW3', 'WiiU', '3DS', or 'Null'") +set(BACKEND_PLATFORM "SDL2" CACHE STRING "Which platform backend the game should use: 'SDL2', 'SDL1', '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,10 +393,15 @@ endif() if(BACKEND_PLATFORM MATCHES "SDL2") target_sources(CSE2 PRIVATE - "src/Backends/Controller/SDL2.cpp" + "src/Backends/Controller/SDL.cpp" "src/Backends/Platform/SDL2.cpp" "src/Backends/Shared/SDL2.h" ) +elseif(BACKEND_PLATFORM MATCHES "SDL1") + target_sources(CSE2 PRIVATE + "src/Backends/Controller/SDL.cpp" + "src/Backends/Platform/SDL1.cpp" + ) elseif(BACKEND_PLATFORM MATCHES "GLFW3") target_sources(CSE2 PRIVATE "src/Backends/Controller/GLFW3.cpp" @@ -428,6 +433,8 @@ elseif(BACKEND_PLATFORM MATCHES "SDL2" AND BACKEND_RENDERER MATCHES "SDLTexture" elseif(BACKEND_PLATFORM MATCHES "SDL2" AND BACKEND_RENDERER MATCHES "SDLSurface") elseif(BACKEND_PLATFORM MATCHES "SDL2" AND BACKEND_RENDERER MATCHES "Software") target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/SDL2.cpp") +elseif(BACKEND_PLATFORM MATCHES "SDL1" AND BACKEND_RENDERER MATCHES "Software") + target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/SDL1.cpp") elseif(BACKEND_PLATFORM MATCHES "GLFW3" AND BACKEND_RENDERER MATCHES "OpenGL3") target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/OpenGL3/GLFW3.cpp") elseif(BACKEND_PLATFORM MATCHES "GLFW3" AND BACKEND_RENDERER MATCHES "OpenGLES2") @@ -599,6 +606,41 @@ if(BACKEND_PLATFORM MATCHES "SDL2" OR BACKEND_AUDIO MATCHES "SDL2") endif() endif() +if(BACKEND_PLATFORM MATCHES "SDL1") + find_package(SDL 1.2.15) + + if (PKG_CONFIG_FOUND) + pkg_check_modules(sdl QUIET IMPORTED_TARGET sdl) + endif() + + if(TARGET PkgConfig::sdl) + # pkg-config + if (PKG_CONFIG_STATIC_LIBS) + message(STATUS "Using system SDL1 (pkg-config, static)") + # Do not link libSDLmain.a, otherwise we get weird linker errors about SDL_main not being found. + # We don't need SDL's WinMain->main shim anyway, so we can just ignore it. + list(REMOVE_ITEM sdl_STATIC_CFLAGS "-Dmain=SDL_main") + list(REMOVE_ITEM sdl_STATIC_LDFLAGS "-lSDLmain") + target_compile_options(CSE2 PRIVATE ${sdl_STATIC_CFLAGS}) + target_link_libraries(CSE2 PRIVATE ${sdl_STATIC_LDFLAGS}) + else() + message(STATUS "Using system SDL1 (pkg-config, dynamic)") + # Do not link libSDLmain.a, otherwise we get weird linker errors about SDL_main not being found. + # We don't need SDL's WinMain->main shim anyway, so we can just ignore it. + list(REMOVE_ITEM sdl_CFLAGS "-Dmain=SDL_main") + list(REMOVE_ITEM sdl_LDFLAGS "-lSDLmain") + target_compile_options(CSE2 PRIVATE ${sdl_CFLAGS}) + target_link_libraries(CSE2 PRIVATE ${sdl_LDFLAGS}) + endif() + elseif(SDL_FOUND) + message(STATUS "Using system SDL1 (CMake)") + target_include_directories(CSE2 PRIVATE ${SDL_INCLUDE_DIR}) + target_link_libraries(CSE2 PRIVATE ${SDL_LIBRARY}) + else() + message(FATAL_ERROR "SDL1 not installed!") + endif() +endif() + if(FREETYPE_FONTS) if(NOT FORCE_LOCAL_LIBS) find_package(Freetype) diff --git a/src/Backends/Controller/SDL2.cpp b/src/Backends/Controller/SDL.cpp similarity index 98% rename from src/Backends/Controller/SDL2.cpp rename to src/Backends/Controller/SDL.cpp index 87aea8d1..0d55c239 100644 --- a/src/Backends/Controller/SDL2.cpp +++ b/src/Backends/Controller/SDL.cpp @@ -6,7 +6,9 @@ #include "SDL.h" #include "../Misc.h" +#if SDL_VERSION_ATLEAST(2, 0, 0) #include "../Shared/SDL2.h" +#endif #define DEADZONE 10000 @@ -126,6 +128,7 @@ bool ControllerBackend_GetJoystickStatus(bool **buttons, unsigned int *button_co return true; } +#if SDL_VERSION_ATLEAST(2, 0, 0) void ControllerBackend_JoystickConnect(Sint32 joystick_id) { const char *joystick_name = SDL_JoystickNameForIndex(joystick_id); @@ -199,3 +202,4 @@ void ControllerBackend_JoystickDisconnect(Sint32 joystick_id) free(axis_neutrals); } } +#endif diff --git a/src/Backends/Platform/SDL1.cpp b/src/Backends/Platform/SDL1.cpp new file mode 100644 index 00000000..110f6b1a --- /dev/null +++ b/src/Backends/Platform/SDL1.cpp @@ -0,0 +1,254 @@ +#include "../Misc.h" + +#include +#include +#include +#include + +#include "SDL.h" + +#include "../Rendering.h" +#include "../../Main.h" +#include "../../Organya.h" +#include "../../Profile.h" +#include "../../Resource.h" + +#define DO_KEY(SDL_KEY, BACKEND_KEY) \ + case SDL_KEY: \ + keyboard_state[BACKEND_KEY] = event.key.type == SDL_KEYDOWN; \ + break; + +static bool keyboard_state[BACKEND_KEYBOARD_TOTAL]; + +bool Backend_Init(void) +{ + if (SDL_Init(SDL_INIT_VIDEO) == 0) + { + char driver[20]; + if (SDL_VideoDriverName(driver, 20) != NULL) + { + Backend_PrintInfo("Selected SDL video driver: %s", driver); + + return true; + } + else + { + Backend_PrintError("No SDL video driver initialized!"); + SDL_Quit(); + } + } + else + { + std::string error_message = std::string("Could not initialise SDL: ") + SDL_GetError(); + Backend_ShowMessageBox("Fatal error", error_message.c_str()); + } + + return false; +} + +void Backend_Deinit(void) +{ + SDL_Quit(); +} + +void Backend_PostWindowCreation(void) +{ +} + +bool Backend_GetBasePath(char *string_buffer) +{ + return false; +} + +void Backend_HideMouse(void) +{ + SDL_ShowCursor(SDL_DISABLE); +} + +void Backend_SetWindowIcon(const unsigned char *rgb_pixels, unsigned int width, unsigned int height) +{ + SDL_Surface *surface = SDL_CreateRGBSurfaceFrom((void*)rgb_pixels, width, height, 24, width * 3, 0x0000FF, 0x00FF00, 0xFF0000, 0); + + if (surface != NULL) + { + SDL_WM_SetIcon(surface, NULL); + SDL_FreeSurface(surface); + } + else + { + Backend_PrintError("Couldn't create RGB surface for window icon: %s", SDL_GetError()); + } +} + +void Backend_SetCursor(const unsigned char *rgb_pixels, unsigned int width, unsigned int height) +{ + (void)rgb_pixels; + (void)width; + (void)height; + // SDL1 only supports black and white cursors +} + +void PlaybackBackend_EnableDragAndDrop(void) +{ +} + +bool Backend_SystemTask(bool active) +{ + if (SDL_PollEvent(NULL) || !active) + { + SDL_Event event; + + if (!SDL_WaitEvent(&event)) + return false; + + switch (event.type) + { + case SDL_KEYUP: + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + DO_KEY(SDLK_a, BACKEND_KEYBOARD_A) + DO_KEY(SDLK_b, BACKEND_KEYBOARD_B) + DO_KEY(SDLK_c, BACKEND_KEYBOARD_C) + DO_KEY(SDLK_d, BACKEND_KEYBOARD_D) + DO_KEY(SDLK_e, BACKEND_KEYBOARD_E) + DO_KEY(SDLK_f, BACKEND_KEYBOARD_F) + DO_KEY(SDLK_g, BACKEND_KEYBOARD_G) + DO_KEY(SDLK_h, BACKEND_KEYBOARD_H) + DO_KEY(SDLK_i, BACKEND_KEYBOARD_I) + DO_KEY(SDLK_j, BACKEND_KEYBOARD_J) + DO_KEY(SDLK_k, BACKEND_KEYBOARD_K) + DO_KEY(SDLK_l, BACKEND_KEYBOARD_L) + DO_KEY(SDLK_m, BACKEND_KEYBOARD_M) + DO_KEY(SDLK_n, BACKEND_KEYBOARD_N) + DO_KEY(SDLK_o, BACKEND_KEYBOARD_O) + DO_KEY(SDLK_p, BACKEND_KEYBOARD_P) + DO_KEY(SDLK_q, BACKEND_KEYBOARD_Q) + DO_KEY(SDLK_r, BACKEND_KEYBOARD_R) + DO_KEY(SDLK_s, BACKEND_KEYBOARD_S) + DO_KEY(SDLK_t, BACKEND_KEYBOARD_T) + DO_KEY(SDLK_u, BACKEND_KEYBOARD_U) + DO_KEY(SDLK_v, BACKEND_KEYBOARD_V) + DO_KEY(SDLK_w, BACKEND_KEYBOARD_W) + DO_KEY(SDLK_x, BACKEND_KEYBOARD_X) + DO_KEY(SDLK_y, BACKEND_KEYBOARD_Y) + DO_KEY(SDLK_z, BACKEND_KEYBOARD_Z) + DO_KEY(SDLK_0, BACKEND_KEYBOARD_0) + DO_KEY(SDLK_1, BACKEND_KEYBOARD_1) + DO_KEY(SDLK_2, BACKEND_KEYBOARD_2) + DO_KEY(SDLK_3, BACKEND_KEYBOARD_3) + DO_KEY(SDLK_4, BACKEND_KEYBOARD_4) + DO_KEY(SDLK_5, BACKEND_KEYBOARD_5) + DO_KEY(SDLK_6, BACKEND_KEYBOARD_6) + DO_KEY(SDLK_7, BACKEND_KEYBOARD_7) + DO_KEY(SDLK_8, BACKEND_KEYBOARD_8) + DO_KEY(SDLK_9, BACKEND_KEYBOARD_9) + DO_KEY(SDLK_F1, BACKEND_KEYBOARD_F1) + DO_KEY(SDLK_F2, BACKEND_KEYBOARD_F2) + DO_KEY(SDLK_F3, BACKEND_KEYBOARD_F3) + DO_KEY(SDLK_F4, BACKEND_KEYBOARD_F4) + DO_KEY(SDLK_F5, BACKEND_KEYBOARD_F5) + DO_KEY(SDLK_F6, BACKEND_KEYBOARD_F6) + DO_KEY(SDLK_F7, BACKEND_KEYBOARD_F7) + DO_KEY(SDLK_F8, BACKEND_KEYBOARD_F8) + DO_KEY(SDLK_F9, BACKEND_KEYBOARD_F9) + DO_KEY(SDLK_F10, BACKEND_KEYBOARD_F10) + DO_KEY(SDLK_F11, BACKEND_KEYBOARD_F11) + DO_KEY(SDLK_F12, BACKEND_KEYBOARD_F12) + DO_KEY(SDLK_UP, BACKEND_KEYBOARD_UP) + DO_KEY(SDLK_DOWN, BACKEND_KEYBOARD_DOWN) + DO_KEY(SDLK_LEFT, BACKEND_KEYBOARD_LEFT) + DO_KEY(SDLK_RIGHT, BACKEND_KEYBOARD_RIGHT) + DO_KEY(SDLK_ESCAPE, BACKEND_KEYBOARD_ESCAPE) + DO_KEY(SDLK_BACKQUOTE, BACKEND_KEYBOARD_BACK_QUOTE) + DO_KEY(SDLK_TAB, BACKEND_KEYBOARD_TAB) + DO_KEY(SDLK_CAPSLOCK, BACKEND_KEYBOARD_CAPS_LOCK) + DO_KEY(SDLK_LSHIFT, BACKEND_KEYBOARD_LEFT_SHIFT) + DO_KEY(SDLK_LCTRL, BACKEND_KEYBOARD_LEFT_CTRL) + DO_KEY(SDLK_LALT, BACKEND_KEYBOARD_LEFT_ALT) + DO_KEY(SDLK_SPACE, BACKEND_KEYBOARD_SPACE) + DO_KEY(SDLK_RALT, BACKEND_KEYBOARD_RIGHT_ALT) + DO_KEY(SDLK_RCTRL, BACKEND_KEYBOARD_RIGHT_CTRL) + DO_KEY(SDLK_RSHIFT, BACKEND_KEYBOARD_RIGHT_SHIFT) + DO_KEY(SDLK_RETURN, BACKEND_KEYBOARD_ENTER) + DO_KEY(SDLK_BACKSPACE, BACKEND_KEYBOARD_BACKSPACE) + DO_KEY(SDLK_MINUS, BACKEND_KEYBOARD_MINUS) + DO_KEY(SDLK_EQUALS, BACKEND_KEYBOARD_EQUALS) + DO_KEY(SDLK_LEFTBRACKET, BACKEND_KEYBOARD_LEFT_BRACKET) + DO_KEY(SDLK_RIGHTBRACKET, BACKEND_KEYBOARD_RIGHT_BRACKET) + DO_KEY(SDLK_BACKSLASH, BACKEND_KEYBOARD_BACK_SLASH) + DO_KEY(SDLK_SEMICOLON, BACKEND_KEYBOARD_SEMICOLON) + DO_KEY(SDLK_QUOTE, BACKEND_KEYBOARD_APOSTROPHE) + DO_KEY(SDLK_COMMA, BACKEND_KEYBOARD_COMMA) + DO_KEY(SDLK_PERIOD, BACKEND_KEYBOARD_PERIOD) + DO_KEY(SDLK_SLASH, BACKEND_KEYBOARD_FORWARD_SLASH) + + default: + break; + } + + break; + + case SDL_ACTIVEEVENT: + if (event.active.state & SDL_APPINPUTFOCUS) + { + if (event.active.gain) + ActiveWindow(); + else + InactiveWindow(); + } + + break; + + case SDL_VIDEORESIZE: + RenderBackend_HandleWindowResize(event.resize.w, event.resize.h); + break; + + case SDL_QUIT: + StopOrganyaMusic(); + return false; + } + } + + return true; +} + +void Backend_GetKeyboardState(bool *out_keyboard_state) +{ + memcpy(out_keyboard_state, keyboard_state, sizeof(keyboard_state)); +} + +void Backend_ShowMessageBox(const char *title, const char *message) +{ + fprintf(stderr, "ShowMessageBox - '%s' - '%s'\n", title, message); +} + +ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintError(const char *format, ...) +{ + va_list argumentList; + va_start(argumentList, format); + fputs("ERROR: ", stderr); + vfprintf(stderr, format, argumentList); + fputc('\n', stderr); + va_end(argumentList); +} + +ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintInfo(const char *format, ...) +{ + va_list argumentList; + va_start(argumentList, format); + fputs("INFO: ", stdout); + vprintf(format, argumentList); + putchar('\n'); + va_end(argumentList); +} + +unsigned long Backend_GetTicks(void) +{ + return SDL_GetTicks(); +} + +void Backend_Delay(unsigned int ticks) +{ + SDL_Delay(ticks); +} diff --git a/src/Backends/Rendering/Window/Software/SDL1.cpp b/src/Backends/Rendering/Window/Software/SDL1.cpp new file mode 100644 index 00000000..142d2109 --- /dev/null +++ b/src/Backends/Rendering/Window/Software/SDL1.cpp @@ -0,0 +1,76 @@ +#include "../Software.h" + +#include +#include +#include + +#include "SDL.h" + +#include "../../../Misc.h" + +static Uint32 window_flags = SDL_HWSURFACE | SDL_DOUBLEBUF; + +static SDL_Surface *window_sdlsurface; +static SDL_Surface *framebuffer_sdlsurface; + +bool WindowBackend_Software_CreateWindow(const char *window_title, int screen_width, int screen_height, bool fullscreen) +{ + if (fullscreen) + window_flags |= SDL_FULLSCREEN; + else + window_flags &= ~SDL_FULLSCREEN; + + window_sdlsurface = SDL_SetVideoMode(screen_width, screen_height, 24, window_flags); + if (window_sdlsurface != NULL) + { + SDL_WM_SetCaption(window_title, NULL); + framebuffer_sdlsurface = SDL_CreateRGBSurface(SDL_SWSURFACE, window_sdlsurface->w, window_sdlsurface->h, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0); + + if (framebuffer_sdlsurface != NULL) + { + Backend_PostWindowCreation(); + + return true; + } + else + { + std::string error_message = std::string("Couldn't create framebuffer surface: ") + SDL_GetError(); + Backend_ShowMessageBox("Fatal error (software rendering backend)", error_message.c_str()); + } + } + else + { + std::string error_message = std::string("Couldn't create window: ") + SDL_GetError(); + Backend_ShowMessageBox("Fatal error (software rendering backend)", error_message.c_str()); + } + + return false; +} + +void WindowBackend_Software_DestroyWindow(void) +{ + SDL_FreeSurface(framebuffer_sdlsurface); +} + +unsigned char* WindowBackend_Software_GetFramebuffer(size_t *pitch) +{ + *pitch = framebuffer_sdlsurface->pitch; + + return (unsigned char*)framebuffer_sdlsurface->pixels; +} + +void WindowBackend_Software_Display(void) +{ + if (SDL_BlitSurface(framebuffer_sdlsurface, NULL, window_sdlsurface, NULL) < 0) + Backend_PrintError("Couldn't blit framebuffer surface to window surface: %s", SDL_GetError()); + + if (SDL_Flip(window_sdlsurface) < 0) + Backend_PrintError("Couldn't copy window surface to the screen: %s", SDL_GetError()); +} + +void WindowBackend_Software_HandleWindowResize(unsigned int width, unsigned int height) +{ + window_sdlsurface = SDL_SetVideoMode(width, height, 24, window_flags); + if (window_sdlsurface == NULL) + Backend_PrintError("Couldn't get SDL surface associated with window: %s", SDL_GetError()); +} From d5f12b2f2b2efd126c4b9b0ae8bc0b1b0acadd72 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Mon, 18 May 2020 22:57:47 +0100 Subject: [PATCH 2/8] Add a fallback for when 24bpp screen modes are unsupported --- src/Backends/Rendering/Window/Software/SDL1.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Backends/Rendering/Window/Software/SDL1.cpp b/src/Backends/Rendering/Window/Software/SDL1.cpp index 142d2109..e10603e4 100644 --- a/src/Backends/Rendering/Window/Software/SDL1.cpp +++ b/src/Backends/Rendering/Window/Software/SDL1.cpp @@ -8,7 +8,8 @@ #include "../../../Misc.h" -static Uint32 window_flags = SDL_HWSURFACE | SDL_DOUBLEBUF; +static int bits_per_pixel = 24; +static Uint32 window_flags = SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_ANYFORMAT; static SDL_Surface *window_sdlsurface; static SDL_Surface *framebuffer_sdlsurface; @@ -20,7 +21,13 @@ bool WindowBackend_Software_CreateWindow(const char *window_title, int screen_wi else window_flags &= ~SDL_FULLSCREEN; - window_sdlsurface = SDL_SetVideoMode(screen_width, screen_height, 24, window_flags); + window_sdlsurface = SDL_SetVideoMode(screen_width, screen_height, bits_per_pixel, window_flags); + if (window_sdlsurface == NULL) { + Backend_PrintError("Couldn't create 24bpp window: %s", SDL_GetError()); + bits_per_pixel = 32; + window_sdlsurface = SDL_SetVideoMode(screen_width, screen_height, bits_per_pixel, window_flags); + } + if (window_sdlsurface != NULL) { SDL_WM_SetCaption(window_title, NULL); @@ -70,7 +77,7 @@ void WindowBackend_Software_Display(void) void WindowBackend_Software_HandleWindowResize(unsigned int width, unsigned int height) { - window_sdlsurface = SDL_SetVideoMode(width, height, 24, window_flags); + window_sdlsurface = SDL_SetVideoMode(width, height, bits_per_pixel, window_flags); if (window_sdlsurface == NULL) Backend_PrintError("Couldn't get SDL surface associated with window: %s", SDL_GetError()); } From 72a5f366547e12cab97eca00df1a09d4e178033e Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Thu, 25 Jun 2020 16:28:08 +0100 Subject: [PATCH 3/8] Always use the first available joystick with SDL 1.2 --- CMakeLists.txt | 3 ++- src/Backends/Controller/SDL.cpp | 17 ++++++++++++----- src/Backends/Platform/SDL2.cpp | 2 +- src/Backends/Rendering/SDLSurface.cpp | 2 +- src/Backends/Rendering/SDLTexture.cpp | 2 +- src/Backends/Rendering/Window/OpenGL3/SDL2.cpp | 2 +- src/Backends/Rendering/Window/Software/SDL2.cpp | 2 +- src/Backends/Shared/{SDL2.h => SDL.h} | 2 ++ 8 files changed, 21 insertions(+), 11 deletions(-) rename src/Backends/Shared/{SDL2.h => SDL.h} (82%) diff --git a/CMakeLists.txt b/CMakeLists.txt index f2498895..b062ccd3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -395,12 +395,13 @@ if(BACKEND_PLATFORM MATCHES "SDL2") target_sources(CSE2 PRIVATE "src/Backends/Controller/SDL.cpp" "src/Backends/Platform/SDL2.cpp" - "src/Backends/Shared/SDL2.h" + "src/Backends/Shared/SDL.h" ) elseif(BACKEND_PLATFORM MATCHES "SDL1") target_sources(CSE2 PRIVATE "src/Backends/Controller/SDL.cpp" "src/Backends/Platform/SDL1.cpp" + "src/Backends/Shared/SDL.h" ) elseif(BACKEND_PLATFORM MATCHES "GLFW3") target_sources(CSE2 PRIVATE diff --git a/src/Backends/Controller/SDL.cpp b/src/Backends/Controller/SDL.cpp index 0d55c239..8d281ff4 100644 --- a/src/Backends/Controller/SDL.cpp +++ b/src/Backends/Controller/SDL.cpp @@ -6,9 +6,7 @@ #include "SDL.h" #include "../Misc.h" -#if SDL_VERSION_ATLEAST(2, 0, 0) -#include "../Shared/SDL2.h" -#endif +#include "../Shared/SDL.h" #define DEADZONE 10000 @@ -24,6 +22,11 @@ bool ControllerBackend_Init(void) return false; } +#if !SDL_VERSION_ATLEAST(2, 0, 0) + if (SDL_NumJoysticks() > 0) + ControllerBackend_JoystickConnect(0); +#endif + return true; } @@ -128,10 +131,13 @@ bool ControllerBackend_GetJoystickStatus(bool **buttons, unsigned int *button_co return true; } -#if SDL_VERSION_ATLEAST(2, 0, 0) void ControllerBackend_JoystickConnect(Sint32 joystick_id) { +#if SDL_VERSION_ATLEAST(2, 0, 0) const char *joystick_name = SDL_JoystickNameForIndex(joystick_id); +#else + const char *joystick_name = SDL_JoystickName(joystick_id); +#endif if (joystick_name != NULL) { @@ -189,6 +195,7 @@ void ControllerBackend_JoystickConnect(Sint32 joystick_id) void ControllerBackend_JoystickDisconnect(Sint32 joystick_id) { +#if SDL_VERSION_ATLEAST(2, 0, 0) SDL_JoystickID current_joystick_id = SDL_JoystickInstanceID(joystick); if (current_joystick_id < 0) Backend_PrintError("Couldn't get instance ID for current joystick: %s", SDL_GetError()); @@ -201,5 +208,5 @@ void ControllerBackend_JoystickDisconnect(Sint32 joystick_id) free(axis_neutrals); } -} #endif +} diff --git a/src/Backends/Platform/SDL2.cpp b/src/Backends/Platform/SDL2.cpp index 1ab1dcbb..5e25cf45 100644 --- a/src/Backends/Platform/SDL2.cpp +++ b/src/Backends/Platform/SDL2.cpp @@ -10,7 +10,7 @@ #include "SDL.h" #include "../Rendering.h" -#include "../Shared/SDL2.h" +#include "../Shared/SDL.h" #include "../../Attributes.h" #define DO_KEY(SDL_KEY, BACKEND_KEY) \ diff --git a/src/Backends/Rendering/SDLSurface.cpp b/src/Backends/Rendering/SDLSurface.cpp index 41c4c0ef..2fba59dd 100644 --- a/src/Backends/Rendering/SDLSurface.cpp +++ b/src/Backends/Rendering/SDLSurface.cpp @@ -8,7 +8,7 @@ #include "SDL.h" #include "../Misc.h" -#include "../Shared/SDL2.h" +#include "../Shared/SDL.h" typedef struct RenderBackend_Surface { diff --git a/src/Backends/Rendering/SDLTexture.cpp b/src/Backends/Rendering/SDLTexture.cpp index 4995e50d..7a155775 100644 --- a/src/Backends/Rendering/SDLTexture.cpp +++ b/src/Backends/Rendering/SDLTexture.cpp @@ -10,7 +10,7 @@ #include "../../WindowsWrapper.h" #include "../Misc.h" -#include "../Shared/SDL2.h" +#include "../Shared/SDL.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) diff --git a/src/Backends/Rendering/Window/OpenGL3/SDL2.cpp b/src/Backends/Rendering/Window/OpenGL3/SDL2.cpp index 8046a463..d96cecdb 100644 --- a/src/Backends/Rendering/Window/OpenGL3/SDL2.cpp +++ b/src/Backends/Rendering/Window/OpenGL3/SDL2.cpp @@ -9,7 +9,7 @@ #include "SDL.h" #include "../../../Misc.h" -#include "../../../Shared/SDL2.h" +#include "../../../Shared/SDL.h" SDL_Window *window; diff --git a/src/Backends/Rendering/Window/Software/SDL2.cpp b/src/Backends/Rendering/Window/Software/SDL2.cpp index bc630a75..1c267641 100644 --- a/src/Backends/Rendering/Window/Software/SDL2.cpp +++ b/src/Backends/Rendering/Window/Software/SDL2.cpp @@ -6,7 +6,7 @@ #include "SDL.h" #include "../../../Misc.h" -#include "../../../Shared/SDL2.h" +#include "../../../Shared/SDL.h" SDL_Window *window; diff --git a/src/Backends/Shared/SDL2.h b/src/Backends/Shared/SDL.h similarity index 82% rename from src/Backends/Shared/SDL2.h rename to src/Backends/Shared/SDL.h index 264c847c..c540be14 100644 --- a/src/Backends/Shared/SDL2.h +++ b/src/Backends/Shared/SDL.h @@ -2,7 +2,9 @@ #include "SDL.h" +#if SDL_VERSION_ATLEAST(2, 0, 0) extern SDL_Window *window; +#endif void ControllerBackend_JoystickConnect(Sint32 joystick_id); void ControllerBackend_JoystickDisconnect(Sint32 joystick_id); From 9b81f453813dfcd78ef17c04243cf3e517416bfd Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Thu, 25 Jun 2020 17:12:12 +0100 Subject: [PATCH 4/8] Add an SDL 1.2 audio backend --- CMakeLists.txt | 14 ++- src/Backends/Audio/SDL1.cpp | 243 ++++++++++++++++++++++++++++++++++++ 2 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 src/Backends/Audio/SDL1.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index b062ccd3..229b60b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ option(LANCZOS_RESAMPLER "Use Lanczos filtering for audio resampling instead of option(FREETYPE_FONTS "Use FreeType2 to render the DejaVu Mono (English) or Migu1M (Japanese) fonts, instead of using pre-rendered copies of Courier New (English) and MS Gothic (Japanese)" OFF) 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, '3DS' for the 3DS's hardware accelerated Citro2D/Citro3D 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', '3DS-Hardware', '3DS-Software', or 'Null'") +set(BACKEND_AUDIO "SDL2" CACHE STRING "Which audio backend the game should use: 'SDL2', 'SDL1', 'miniaudio', 'WiiU-Hardware', 'WiiU-Software', '3DS-Hardware', '3DS-Software', or 'Null'") set(BACKEND_PLATFORM "SDL2" CACHE STRING "Which platform backend the game should use: 'SDL2', 'SDL1', 'GLFW3', 'WiiU', '3DS', or 'Null'") option(LTO "Enable link-time optimisation" OFF) @@ -336,6 +336,12 @@ if(BACKEND_AUDIO MATCHES "SDL2") "src/Backends/Audio/SoftwareMixer/Backend.h" "src/Backends/Audio/SoftwareMixer/SDL2.cpp" ) +elseif(BACKEND_AUDIO MATCHES "SDL1") + target_sources(CSE2 PRIVATE + "src/Backends/Audio/SDL1.cpp" + "src/Backends/Audio/SoftwareMixer.cpp" + "src/Backends/Audio/SoftwareMixer.h" + ) elseif(BACKEND_AUDIO MATCHES "miniaudio") target_sources(CSE2 PRIVATE "src/Backends/Audio/SoftwareMixer.cpp" @@ -607,7 +613,11 @@ if(BACKEND_PLATFORM MATCHES "SDL2" OR BACKEND_AUDIO MATCHES "SDL2") endif() endif() -if(BACKEND_PLATFORM MATCHES "SDL1") +if(BACKEND_PLATFORM MATCHES "SDL1" OR BACKEND_AUDIO MATCHES "SDL1") + if(BACKEND_PLATFORM MATCHES "SDL2" OR BACKEND_AUDIO MATCHES "SDL2") + message(FATAL_ERROR "SDL1 and SDL2 cannot be used simultaneously!") + endif() + find_package(SDL 1.2.15) if (PKG_CONFIG_FOUND) diff --git a/src/Backends/Audio/SDL1.cpp b/src/Backends/Audio/SDL1.cpp new file mode 100644 index 00000000..b750a4c2 --- /dev/null +++ b/src/Backends/Audio/SDL1.cpp @@ -0,0 +1,243 @@ +#include "../Audio.h" + +#include +#include +#include +#include + +#include "SDL.h" + +#include "../Misc.h" + +#include "SoftwareMixer.h" + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static unsigned long output_frequency; + +static void (*organya_callback)(void); +static unsigned int organya_callback_milliseconds; + +static void MixSoundsAndUpdateOrganya(long *stream, size_t frames_total) +{ + if (organya_callback_milliseconds == 0) + { + Mixer_MixSounds(stream, frames_total); + } + else + { + // Synchronise audio generation with Organya. + // In the original game, Organya ran asynchronously in a separate thread, + // firing off commands to DirectSound in realtime. To match that, we'd + // need a very low-latency buffer, otherwise we'd get mistimed instruments. + // Instead, we can just do this. + unsigned int frames_done = 0; + + while (frames_done != frames_total) + { + static unsigned long organya_countdown; + + if (organya_countdown == 0) + { + organya_countdown = (organya_callback_milliseconds * output_frequency) / 1000; // organya_timer is in milliseconds, so convert it to audio frames + organya_callback(); + } + + const unsigned int frames_to_do = MIN(organya_countdown, frames_total - frames_done); + + Mixer_MixSounds(stream + frames_done * 2, frames_to_do); + + frames_done += frames_to_do; + organya_countdown -= frames_to_do; + } + } +} + +static void Callback(void *user_data, Uint8 *stream_uint8, int len) +{ + (void)user_data; + + short *stream = (short*)stream_uint8; + const size_t frames_total = len / sizeof(short) / 2; + + size_t frames_done = 0; + + while (frames_done != frames_total) + { + long mix_buffer[0x800 * 2]; // 2 because stereo + + size_t subframes = MIN(0x800, frames_total - frames_done); + + memset(mix_buffer, 0, subframes * sizeof(long) * 2); + + MixSoundsAndUpdateOrganya(mix_buffer, subframes); + + for (size_t i = 0; i < subframes * 2; ++i) + { + if (mix_buffer[i] > 0x7FFF) + *stream++ = 0x7FFF; + else if (mix_buffer[i] < -0x7FFF) + *stream++ = -0x7FFF; + else + *stream++ = mix_buffer[i]; + } + + frames_done += subframes; + } +} + +bool AudioBackend_Init(void) +{ + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) + { + std::string errorMessage = std::string("'SDL_InitSubSystem(SDL_INIT_AUDIO)' failed: ") + SDL_GetError(); + Backend_ShowMessageBox("Fatal error (SDL1 audio backend)", errorMessage.c_str()); + return false; + } + + SDL_AudioSpec specification; + specification.freq = 48000; + specification.format = AUDIO_S16; + specification.channels = 2; + specification.samples = 0x400; // Roughly 10 milliseconds for 48000Hz + specification.callback = Callback; + specification.userdata = NULL; + + SDL_AudioSpec obtained_specification; + if (SDL_OpenAudio(&specification, &obtained_specification) != 0) + { + std::string error_message = std::string("'SDL_OpenAudio' failed: ") + SDL_GetError(); + Backend_ShowMessageBox("Fatal error (SDL1 audio backend)", error_message.c_str()); + return false; + } + + output_frequency = obtained_specification.freq; + Mixer_Init(obtained_specification.freq); + + SDL_PauseAudio(0); + + char driver[20]; + Backend_PrintInfo("Selected SDL audio driver: %s", SDL_AudioDriverName(driver, 20)); + + return true; +} + +void AudioBackend_Deinit(void) +{ + SDL_CloseAudio(); + + SDL_QuitSubSystem(SDL_INIT_AUDIO); +} + +AudioBackend_Sound* AudioBackend_CreateSound(unsigned int frequency, const unsigned char *samples, size_t length) +{ + SDL_LockAudio(); + + Mixer_Sound *sound = Mixer_CreateSound(frequency, samples, length); + + SDL_UnlockAudio(); + + return (AudioBackend_Sound*)sound; +} + +void AudioBackend_DestroySound(AudioBackend_Sound *sound) +{ + if (sound == NULL) + return; + + SDL_LockAudio(); + + Mixer_DestroySound((Mixer_Sound*)sound); + + SDL_UnlockAudio(); +} + +void AudioBackend_PlaySound(AudioBackend_Sound *sound, bool looping) +{ + if (sound == NULL) + return; + + SDL_LockAudio(); + + Mixer_PlaySound((Mixer_Sound*)sound, looping); + + SDL_UnlockAudio(); +} + +void AudioBackend_StopSound(AudioBackend_Sound *sound) +{ + if (sound == NULL) + return; + + SDL_LockAudio(); + + Mixer_StopSound((Mixer_Sound*)sound); + + SDL_UnlockAudio(); +} + +void AudioBackend_RewindSound(AudioBackend_Sound *sound) +{ + if (sound == NULL) + return; + + SDL_LockAudio(); + + Mixer_RewindSound((Mixer_Sound*)sound); + + SDL_UnlockAudio(); +} + +void AudioBackend_SetSoundFrequency(AudioBackend_Sound *sound, unsigned int frequency) +{ + if (sound == NULL) + return; + + SDL_LockAudio(); + + Mixer_SetSoundFrequency((Mixer_Sound*)sound, frequency); + + SDL_UnlockAudio(); +} + +void AudioBackend_SetSoundVolume(AudioBackend_Sound *sound, long volume) +{ + if (sound == NULL) + return; + + SDL_LockAudio(); + + Mixer_SetSoundVolume((Mixer_Sound*)sound, volume); + + SDL_UnlockAudio(); +} + +void AudioBackend_SetSoundPan(AudioBackend_Sound *sound, long pan) +{ + if (sound == NULL) + return; + + SDL_LockAudio(); + + Mixer_SetSoundPan((Mixer_Sound*)sound, pan); + + SDL_UnlockAudio(); +} + +void AudioBackend_SetOrganyaCallback(void (*callback)(void)) +{ + SDL_LockAudio(); + + organya_callback = callback; + + SDL_UnlockAudio(); +} + +void AudioBackend_SetOrganyaTimer(unsigned int milliseconds) +{ + SDL_LockAudio(); + + organya_callback_milliseconds = milliseconds; + + SDL_UnlockAudio(); +} From 5328426b4b04fa0473afa8b0f009037a9a890264 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Thu, 25 Jun 2020 17:12:50 +0100 Subject: [PATCH 5/8] Support using the OpenGL3 renderer with SDL 1.2 --- CMakeLists.txt | 2 + .../Rendering/Window/OpenGL3/SDL1.cpp | 52 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/Backends/Rendering/Window/OpenGL3/SDL1.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 229b60b9..cc6cf6f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -440,6 +440,8 @@ elseif(BACKEND_PLATFORM MATCHES "SDL2" AND BACKEND_RENDERER MATCHES "SDLTexture" elseif(BACKEND_PLATFORM MATCHES "SDL2" AND BACKEND_RENDERER MATCHES "SDLSurface") elseif(BACKEND_PLATFORM MATCHES "SDL2" AND BACKEND_RENDERER MATCHES "Software") target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/SDL2.cpp") +elseif(BACKEND_PLATFORM MATCHES "SDL1" AND BACKEND_RENDERER MATCHES "OpenGL3") + target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/OpenGL3/SDL1.cpp") elseif(BACKEND_PLATFORM MATCHES "SDL1" AND BACKEND_RENDERER MATCHES "Software") target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/SDL1.cpp") elseif(BACKEND_PLATFORM MATCHES "GLFW3" AND BACKEND_RENDERER MATCHES "OpenGL3") diff --git a/src/Backends/Rendering/Window/OpenGL3/SDL1.cpp b/src/Backends/Rendering/Window/OpenGL3/SDL1.cpp new file mode 100644 index 00000000..44a7d867 --- /dev/null +++ b/src/Backends/Rendering/Window/OpenGL3/SDL1.cpp @@ -0,0 +1,52 @@ +#include "../OpenGL.h" + +#include +#include + +#include +#include "SDL.h" + +#include "../../../Misc.h" + +bool WindowBackend_OpenGL_CreateWindow(const char *window_title, int *screen_width, int *screen_height, bool fullscreen) +{ + if (SDL_SetVideoMode(*screen_width, *screen_height, 0, SDL_RESIZABLE | SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0)) != NULL) + { + SDL_WM_SetCaption(window_title, NULL); + + if (gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) + { + // Check if the platform supports OpenGL 3.2 + if (GLAD_GL_VERSION_3_2) + { + Backend_PostWindowCreation(); + + return true; + } + else + { + Backend_ShowMessageBox("Fatal error (OpenGL rendering backend)", "Your system does not support OpenGL 3.2"); + } + } + else + { + Backend_ShowMessageBox("Fatal error (OpenGL rendering backend)", "Couldn't load OpenGL functions"); + } + } + else + { + std::string error_message = std::string("Could not create window: ") + SDL_GetError(); + Backend_ShowMessageBox("Fatal error (OpenGL rendering backend)", error_message.c_str()); + } + + return false; +} + +void WindowBackend_OpenGL_DestroyWindow(void) +{ +} + +void WindowBackend_OpenGL_Display(void) +{ + SDL_GL_SwapBuffers(); +} From 11fb3911a6ddb8073dd658a31f53f749098bb6aa Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Sat, 8 Aug 2020 20:58:11 +0100 Subject: [PATCH 6/8] Update SDL 1.2 backend to reflect recent changes --- src/Backends/Audio/SDL1.cpp | 1 - src/Backends/Platform/SDL1.cpp | 19 ++++++++++++------- .../Rendering/Window/Software/SDL1.cpp | 1 - 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Backends/Audio/SDL1.cpp b/src/Backends/Audio/SDL1.cpp index b750a4c2..791c801f 100644 --- a/src/Backends/Audio/SDL1.cpp +++ b/src/Backends/Audio/SDL1.cpp @@ -1,7 +1,6 @@ #include "../Audio.h" #include -#include #include #include diff --git a/src/Backends/Platform/SDL1.cpp b/src/Backends/Platform/SDL1.cpp index 110f6b1a..75e0fc46 100644 --- a/src/Backends/Platform/SDL1.cpp +++ b/src/Backends/Platform/SDL1.cpp @@ -1,6 +1,8 @@ #include "../Misc.h" +#include #include +#include #include #include #include @@ -8,10 +10,10 @@ #include "SDL.h" #include "../Rendering.h" +#include "../../Attributes.h" #include "../../Main.h" #include "../../Organya.h" #include "../../Profile.h" -#include "../../Resource.h" #define DO_KEY(SDL_KEY, BACKEND_KEY) \ case SDL_KEY: \ @@ -55,8 +57,10 @@ void Backend_PostWindowCreation(void) { } -bool Backend_GetBasePath(char *string_buffer) +bool Backend_GetBasePath(std::string *string_buffer) { + (void)string_buffer; + return false; } @@ -94,13 +98,14 @@ void PlaybackBackend_EnableDragAndDrop(void) bool Backend_SystemTask(bool active) { - if (SDL_PollEvent(NULL) || !active) - { - SDL_Event event; - - if (!SDL_WaitEvent(&event)) + if (!active) + if (!SDL_WaitEvent(NULL)) return false; + SDL_Event event; + + while (SDL_PollEvent(&event)) + { switch (event.type) { case SDL_KEYUP: diff --git a/src/Backends/Rendering/Window/Software/SDL1.cpp b/src/Backends/Rendering/Window/Software/SDL1.cpp index e10603e4..cce2f798 100644 --- a/src/Backends/Rendering/Window/Software/SDL1.cpp +++ b/src/Backends/Rendering/Window/Software/SDL1.cpp @@ -1,7 +1,6 @@ #include "../Software.h" #include -#include #include #include "SDL.h" From 131a8decc0b71253b41f65e76a712e3eef76fb7d Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Thu, 3 Sep 2020 20:48:03 +0100 Subject: [PATCH 7/8] Update SDL 1.2 backend to reflect recent changes --- CMakeLists.txt | 6 +- src/Backends/Audio/SDL1.cpp | 242 ------------------ src/Backends/Audio/SoftwareMixer/SDL1.cpp | 113 ++++++++ src/Backends/Platform/SDL1.cpp | 32 ++- .../Rendering/Window/OpenGL3/SDL1.cpp | 2 +- .../Rendering/Window/Software/SDL1.cpp | 10 +- 6 files changed, 141 insertions(+), 264 deletions(-) delete mode 100644 src/Backends/Audio/SDL1.cpp create mode 100644 src/Backends/Audio/SoftwareMixer/SDL1.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cc6cf6f0..63ad6011 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -338,9 +338,11 @@ if(BACKEND_AUDIO MATCHES "SDL2") ) elseif(BACKEND_AUDIO MATCHES "SDL1") target_sources(CSE2 PRIVATE - "src/Backends/Audio/SDL1.cpp" "src/Backends/Audio/SoftwareMixer.cpp" - "src/Backends/Audio/SoftwareMixer.h" + "src/Backends/Audio/SoftwareMixer/Mixer.cpp" + "src/Backends/Audio/SoftwareMixer/Mixer.h" + "src/Backends/Audio/SoftwareMixer/Backend.h" + "src/Backends/Audio/SoftwareMixer/SDL1.cpp" ) elseif(BACKEND_AUDIO MATCHES "miniaudio") target_sources(CSE2 PRIVATE diff --git a/src/Backends/Audio/SDL1.cpp b/src/Backends/Audio/SDL1.cpp deleted file mode 100644 index 791c801f..00000000 --- a/src/Backends/Audio/SDL1.cpp +++ /dev/null @@ -1,242 +0,0 @@ -#include "../Audio.h" - -#include -#include -#include - -#include "SDL.h" - -#include "../Misc.h" - -#include "SoftwareMixer.h" - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -static unsigned long output_frequency; - -static void (*organya_callback)(void); -static unsigned int organya_callback_milliseconds; - -static void MixSoundsAndUpdateOrganya(long *stream, size_t frames_total) -{ - if (organya_callback_milliseconds == 0) - { - Mixer_MixSounds(stream, frames_total); - } - else - { - // Synchronise audio generation with Organya. - // In the original game, Organya ran asynchronously in a separate thread, - // firing off commands to DirectSound in realtime. To match that, we'd - // need a very low-latency buffer, otherwise we'd get mistimed instruments. - // Instead, we can just do this. - unsigned int frames_done = 0; - - while (frames_done != frames_total) - { - static unsigned long organya_countdown; - - if (organya_countdown == 0) - { - organya_countdown = (organya_callback_milliseconds * output_frequency) / 1000; // organya_timer is in milliseconds, so convert it to audio frames - organya_callback(); - } - - const unsigned int frames_to_do = MIN(organya_countdown, frames_total - frames_done); - - Mixer_MixSounds(stream + frames_done * 2, frames_to_do); - - frames_done += frames_to_do; - organya_countdown -= frames_to_do; - } - } -} - -static void Callback(void *user_data, Uint8 *stream_uint8, int len) -{ - (void)user_data; - - short *stream = (short*)stream_uint8; - const size_t frames_total = len / sizeof(short) / 2; - - size_t frames_done = 0; - - while (frames_done != frames_total) - { - long mix_buffer[0x800 * 2]; // 2 because stereo - - size_t subframes = MIN(0x800, frames_total - frames_done); - - memset(mix_buffer, 0, subframes * sizeof(long) * 2); - - MixSoundsAndUpdateOrganya(mix_buffer, subframes); - - for (size_t i = 0; i < subframes * 2; ++i) - { - if (mix_buffer[i] > 0x7FFF) - *stream++ = 0x7FFF; - else if (mix_buffer[i] < -0x7FFF) - *stream++ = -0x7FFF; - else - *stream++ = mix_buffer[i]; - } - - frames_done += subframes; - } -} - -bool AudioBackend_Init(void) -{ - if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) - { - std::string errorMessage = std::string("'SDL_InitSubSystem(SDL_INIT_AUDIO)' failed: ") + SDL_GetError(); - Backend_ShowMessageBox("Fatal error (SDL1 audio backend)", errorMessage.c_str()); - return false; - } - - SDL_AudioSpec specification; - specification.freq = 48000; - specification.format = AUDIO_S16; - specification.channels = 2; - specification.samples = 0x400; // Roughly 10 milliseconds for 48000Hz - specification.callback = Callback; - specification.userdata = NULL; - - SDL_AudioSpec obtained_specification; - if (SDL_OpenAudio(&specification, &obtained_specification) != 0) - { - std::string error_message = std::string("'SDL_OpenAudio' failed: ") + SDL_GetError(); - Backend_ShowMessageBox("Fatal error (SDL1 audio backend)", error_message.c_str()); - return false; - } - - output_frequency = obtained_specification.freq; - Mixer_Init(obtained_specification.freq); - - SDL_PauseAudio(0); - - char driver[20]; - Backend_PrintInfo("Selected SDL audio driver: %s", SDL_AudioDriverName(driver, 20)); - - return true; -} - -void AudioBackend_Deinit(void) -{ - SDL_CloseAudio(); - - SDL_QuitSubSystem(SDL_INIT_AUDIO); -} - -AudioBackend_Sound* AudioBackend_CreateSound(unsigned int frequency, const unsigned char *samples, size_t length) -{ - SDL_LockAudio(); - - Mixer_Sound *sound = Mixer_CreateSound(frequency, samples, length); - - SDL_UnlockAudio(); - - return (AudioBackend_Sound*)sound; -} - -void AudioBackend_DestroySound(AudioBackend_Sound *sound) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_DestroySound((Mixer_Sound*)sound); - - SDL_UnlockAudio(); -} - -void AudioBackend_PlaySound(AudioBackend_Sound *sound, bool looping) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_PlaySound((Mixer_Sound*)sound, looping); - - SDL_UnlockAudio(); -} - -void AudioBackend_StopSound(AudioBackend_Sound *sound) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_StopSound((Mixer_Sound*)sound); - - SDL_UnlockAudio(); -} - -void AudioBackend_RewindSound(AudioBackend_Sound *sound) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_RewindSound((Mixer_Sound*)sound); - - SDL_UnlockAudio(); -} - -void AudioBackend_SetSoundFrequency(AudioBackend_Sound *sound, unsigned int frequency) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_SetSoundFrequency((Mixer_Sound*)sound, frequency); - - SDL_UnlockAudio(); -} - -void AudioBackend_SetSoundVolume(AudioBackend_Sound *sound, long volume) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_SetSoundVolume((Mixer_Sound*)sound, volume); - - SDL_UnlockAudio(); -} - -void AudioBackend_SetSoundPan(AudioBackend_Sound *sound, long pan) -{ - if (sound == NULL) - return; - - SDL_LockAudio(); - - Mixer_SetSoundPan((Mixer_Sound*)sound, pan); - - SDL_UnlockAudio(); -} - -void AudioBackend_SetOrganyaCallback(void (*callback)(void)) -{ - SDL_LockAudio(); - - organya_callback = callback; - - SDL_UnlockAudio(); -} - -void AudioBackend_SetOrganyaTimer(unsigned int milliseconds) -{ - SDL_LockAudio(); - - organya_callback_milliseconds = milliseconds; - - SDL_UnlockAudio(); -} diff --git a/src/Backends/Audio/SoftwareMixer/SDL1.cpp b/src/Backends/Audio/SoftwareMixer/SDL1.cpp new file mode 100644 index 00000000..0f99165c --- /dev/null +++ b/src/Backends/Audio/SoftwareMixer/SDL1.cpp @@ -0,0 +1,113 @@ +#include "Backend.h" + +#include +#include +#include + +#include "SDL.h" + +#include "../../Misc.h" + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static void (*parent_callback)(long *stream, size_t frames_total); + +static void Callback(void *user_data, Uint8 *stream_uint8, int len) +{ + (void)user_data; + + short *stream = (short*)stream_uint8; + const size_t frames_total = len / sizeof(short) / 2; + + size_t frames_done = 0; + + while (frames_done != frames_total) + { + long mix_buffer[0x800 * 2]; // 2 because stereo + + size_t subframes = MIN(0x800, frames_total - frames_done); + + memset(mix_buffer, 0, subframes * sizeof(long) * 2); + + parent_callback(mix_buffer, subframes); + + for (size_t i = 0; i < subframes * 2; ++i) + { + if (mix_buffer[i] > 0x7FFF) + *stream++ = 0x7FFF; + else if (mix_buffer[i] < -0x7FFF) + *stream++ = -0x7FFF; + else + *stream++ = mix_buffer[i]; + } + + frames_done += subframes; + } +} + +unsigned long SoftwareMixerBackend_Init(void (*callback)(long *stream, size_t frames_total)) +{ + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) + { + std::string errorMessage = std::string("'SDL_InitSubSystem(SDL_INIT_AUDIO)' failed: ") + SDL_GetError(); + Backend_ShowMessageBox("Fatal error (SDL1 audio backend)", errorMessage.c_str()); + return false; + } + + SDL_AudioSpec specification; + specification.freq = 48000; + specification.format = AUDIO_S16; + specification.channels = 2; + specification.samples = 0x400; // Roughly 10 milliseconds for 48000Hz + specification.callback = Callback; + specification.userdata = NULL; + + SDL_AudioSpec obtained_specification; + if (SDL_OpenAudio(&specification, &obtained_specification) != 0) + { + std::string error_message = std::string("'SDL_OpenAudio' failed: ") + SDL_GetError(); + Backend_ShowMessageBox("Fatal error (SDL1 audio backend)", error_message.c_str()); + return false; + } + + char driver[20]; + Backend_PrintInfo("Selected SDL audio driver: %s", SDL_AudioDriverName(driver, 20)); + + parent_callback = callback; + + return obtained_specification.freq; +} + +void SoftwareMixerBackend_Deinit(void) +{ + SDL_CloseAudio(); + + SDL_QuitSubSystem(SDL_INIT_AUDIO); +} + +bool SoftwareMixerBackend_Start(void) +{ + SDL_PauseAudio(0); + + return true; +} + +void SoftwareMixerBackend_LockMixerMutex(void) +{ + SDL_LockAudio(); +} + +void SoftwareMixerBackend_UnlockMixerMutex(void) +{ + SDL_UnlockAudio(); +} + +void SoftwareMixerBackend_LockOrganyaMutex(void) +{ + SDL_LockAudio(); +} + +void SoftwareMixerBackend_UnlockOrganyaMutex(void) +{ + SDL_UnlockAudio(); +} diff --git a/src/Backends/Platform/SDL1.cpp b/src/Backends/Platform/SDL1.cpp index 75e0fc46..b8b3d8ea 100644 --- a/src/Backends/Platform/SDL1.cpp +++ b/src/Backends/Platform/SDL1.cpp @@ -11,9 +11,6 @@ #include "../Rendering.h" #include "../../Attributes.h" -#include "../../Main.h" -#include "../../Organya.h" -#include "../../Profile.h" #define DO_KEY(SDL_KEY, BACKEND_KEY) \ case SDL_KEY: \ @@ -22,8 +19,12 @@ static bool keyboard_state[BACKEND_KEYBOARD_TOTAL]; -bool Backend_Init(void) +static void (*window_focus_callback)(bool focus); + +bool Backend_Init(void (*drag_and_drop_callback_param)(const char *path), void (*window_focus_callback_param)(bool focus)) { + window_focus_callback = window_focus_callback_param; + if (SDL_Init(SDL_INIT_VIDEO) == 0) { char driver[20]; @@ -57,9 +58,10 @@ void Backend_PostWindowCreation(void) { } -bool Backend_GetBasePath(std::string *string_buffer) +bool Backend_GetPaths(std::string *module_path, std::string *data_path) { - (void)string_buffer; + (void)module_path; + (void)data_path; return false; } @@ -69,7 +71,7 @@ void Backend_HideMouse(void) SDL_ShowCursor(SDL_DISABLE); } -void Backend_SetWindowIcon(const unsigned char *rgb_pixels, unsigned int width, unsigned int height) +void Backend_SetWindowIcon(const unsigned char *rgb_pixels, size_t width, size_t height) { SDL_Surface *surface = SDL_CreateRGBSurfaceFrom((void*)rgb_pixels, width, height, 24, width * 3, 0x0000FF, 0x00FF00, 0xFF0000, 0); @@ -84,7 +86,7 @@ void Backend_SetWindowIcon(const unsigned char *rgb_pixels, unsigned int width, } } -void Backend_SetCursor(const unsigned char *rgb_pixels, unsigned int width, unsigned int height) +void Backend_SetCursor(const unsigned char *rgb_pixels, size_t width, size_t height) { (void)rgb_pixels; (void)width; @@ -92,7 +94,7 @@ void Backend_SetCursor(const unsigned char *rgb_pixels, unsigned int width, unsi // SDL1 only supports black and white cursors } -void PlaybackBackend_EnableDragAndDrop(void) +void Backend_EnableDragAndDrop(void) { } @@ -197,10 +199,7 @@ bool Backend_SystemTask(bool active) case SDL_ACTIVEEVENT: if (event.active.state & SDL_APPINPUTFOCUS) { - if (event.active.gain) - ActiveWindow(); - else - InactiveWindow(); + window_focus_callback(event.active.gain); } break; @@ -210,7 +209,6 @@ bool Backend_SystemTask(bool active) break; case SDL_QUIT: - StopOrganyaMusic(); return false; } } @@ -225,7 +223,7 @@ void Backend_GetKeyboardState(bool *out_keyboard_state) void Backend_ShowMessageBox(const char *title, const char *message) { - fprintf(stderr, "ShowMessageBox - '%s' - '%s'\n", title, message); + Backend_PrintInfo("ShowMessageBox - '%s' - '%s'\n", title, message); } ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintError(const char *format, ...) @@ -243,8 +241,8 @@ ATTRIBUTE_FORMAT_PRINTF(1, 2) void Backend_PrintInfo(const char *format, ...) va_list argumentList; va_start(argumentList, format); fputs("INFO: ", stdout); - vprintf(format, argumentList); - putchar('\n'); + vfprintf(stdout, format, argumentList); + fputc('\n', stdout); va_end(argumentList); } diff --git a/src/Backends/Rendering/Window/OpenGL3/SDL1.cpp b/src/Backends/Rendering/Window/OpenGL3/SDL1.cpp index 44a7d867..efcfac23 100644 --- a/src/Backends/Rendering/Window/OpenGL3/SDL1.cpp +++ b/src/Backends/Rendering/Window/OpenGL3/SDL1.cpp @@ -8,7 +8,7 @@ #include "../../../Misc.h" -bool WindowBackend_OpenGL_CreateWindow(const char *window_title, int *screen_width, int *screen_height, bool fullscreen) +bool WindowBackend_OpenGL_CreateWindow(const char *window_title, size_t *screen_width, size_t *screen_height, bool fullscreen) { if (SDL_SetVideoMode(*screen_width, *screen_height, 0, SDL_RESIZABLE | SDL_OPENGL | (fullscreen ? SDL_FULLSCREEN : 0)) != NULL) { diff --git a/src/Backends/Rendering/Window/Software/SDL1.cpp b/src/Backends/Rendering/Window/Software/SDL1.cpp index cce2f798..84267274 100644 --- a/src/Backends/Rendering/Window/Software/SDL1.cpp +++ b/src/Backends/Rendering/Window/Software/SDL1.cpp @@ -13,7 +13,7 @@ static Uint32 window_flags = SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_ANYFORMAT; static SDL_Surface *window_sdlsurface; static SDL_Surface *framebuffer_sdlsurface; -bool WindowBackend_Software_CreateWindow(const char *window_title, int screen_width, int screen_height, bool fullscreen) +bool WindowBackend_Software_CreateWindow(const char *window_title, size_t screen_width, size_t screen_height, bool fullscreen) { if (fullscreen) window_flags |= SDL_FULLSCREEN; @@ -34,6 +34,8 @@ bool WindowBackend_Software_CreateWindow(const char *window_title, int screen_wi if (framebuffer_sdlsurface != NULL) { + SDL_LockSurface(framebuffer_sdlsurface); // If this errors then oh dear + Backend_PostWindowCreation(); return true; @@ -67,14 +69,18 @@ unsigned char* WindowBackend_Software_GetFramebuffer(size_t *pitch) void WindowBackend_Software_Display(void) { + SDL_UnlockSurface(framebuffer_sdlsurface); + if (SDL_BlitSurface(framebuffer_sdlsurface, NULL, window_sdlsurface, NULL) < 0) Backend_PrintError("Couldn't blit framebuffer surface to window surface: %s", SDL_GetError()); + SDL_LockSurface(framebuffer_sdlsurface); // If this errors then oh dear + if (SDL_Flip(window_sdlsurface) < 0) Backend_PrintError("Couldn't copy window surface to the screen: %s", SDL_GetError()); } -void WindowBackend_Software_HandleWindowResize(unsigned int width, unsigned int height) +void WindowBackend_Software_HandleWindowResize(size_t width, size_t height) { window_sdlsurface = SDL_SetVideoMode(width, height, bits_per_pixel, window_flags); if (window_sdlsurface == NULL) From 44544a65d23de1c3d618c65198a22fc3b51ea107 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Tue, 20 Oct 2020 17:33:36 +0100 Subject: [PATCH 8/8] RISC OS port --- .gitignore | 7 +++---- CMakeLists.txt | 4 ++++ assets/riscos/!Boot,feb | 2 ++ assets/riscos/!Run,feb | 2 ++ assets/riscos/!Sprites,ff9 | Bin 0 -> 996 bytes cmake/RISCOSApp.cmake | 22 ++++++++++++++++++++++ src/Config.cpp | 2 ++ 7 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 assets/riscos/!Boot,feb create mode 100644 assets/riscos/!Run,feb create mode 100644 assets/riscos/!Sprites,ff9 create mode 100644 cmake/RISCOSApp.cmake diff --git a/.gitignore b/.gitignore index 89807ac3..3d053adb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ /obj # Exclude the (recommended) CMake build directory -/build +/build* # Exclude executables /game_english/CSE2_debug.exe @@ -15,6 +15,7 @@ /game_english/DoConfig /game_english/CSE2_debug.rpx /game_english/CSE2.rpx +/game_english/\!CSE2 /game_japanese/CSE2_debug.exe /game_japanese/DoConfig_debug.exe /game_japanese/CSE2.exe @@ -25,6 +26,7 @@ /game_japanese/DoConfig /game_japanese/CSE2_debug.rpx /game_japanese/CSE2.rpx +/game_japanese/\!CSE2 # Exclude MSVC debug data /game_english/CSE2_debug.ilk @@ -97,8 +99,5 @@ # Portable branch # ################### -# Exclude Wii U build directory -/buildwiiu - # Exclude converted resource files /src/Resource diff --git a/CMakeLists.txt b/CMakeLists.txt index 63ad6011..1d075d49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -775,3 +775,7 @@ if(DOCONFIG) RUNTIME_OUTPUT_DIRECTORY_DEBUG ${BUILD_DIRECTORY} ) endif() + +if(RISCOS) + include(RISCOSApp) +endif() diff --git a/assets/riscos/!Boot,feb b/assets/riscos/!Boot,feb new file mode 100644 index 00000000..c156edab --- /dev/null +++ b/assets/riscos/!Boot,feb @@ -0,0 +1,2 @@ +Set CSE2$Dir +IconSprites .!Sprites diff --git a/assets/riscos/!Run,feb b/assets/riscos/!Run,feb new file mode 100644 index 00000000..9cab7e0b --- /dev/null +++ b/assets/riscos/!Run,feb @@ -0,0 +1,2 @@ +Set CSE2$Dir +Run .CSE2 >.Log 2>&1 diff --git a/assets/riscos/!Sprites,ff9 b/assets/riscos/!Sprites,ff9 new file mode 100644 index 0000000000000000000000000000000000000000..631ddd2a51c9191bf547f5890b45d5c52fd4d063 GIT binary patch literal 996 zcmd5)%}T>S5FQ(YM?F}2ET#l69!i$Qt03Za+wJND6pw;6%3Sk6eTY1cZ&AOQ-82aZ zo&<+XX1@7$e%PG}5nVvPGNS#2=xSTPRKOw#(OkV~_wYq8Q!JSVwxI+5qD|ANc7e8S zN%R0R>H$_x{;hgz? dNFd5dOVln_I*ZVBmWx{@7DeQXDq13>e*+)d#o+(| literal 0 HcmV?d00001 diff --git a/cmake/RISCOSApp.cmake b/cmake/RISCOSApp.cmake new file mode 100644 index 00000000..803df9b7 --- /dev/null +++ b/cmake/RISCOSApp.cmake @@ -0,0 +1,22 @@ +# Use the following commands to build for RISC OS: +# cmake -B build-riscos -DCMAKE_BUILD_TYPE=Release -DBACKEND_PLATFORM=SDL1 -DBACKEND_RENDERER=Software -DBACKEND_AUDIO=SDL1 -DDOCONFIG=OFF -DCMAKE_TOOLCHAIN_FILE=$GCCSDK_INSTALL_ENV/toolchain-riscos.cmake -DRISCOS=ON -DPKG_CONFIG_STATIC_LIBS=ON +# cmake --build build-riscos +# (cd game_english && $GCCSDK_INSTALL_ENV/bin/zip -,9r cse2-riscos.zip \!CSE2) + +function(elf_to_aif) + cmake_parse_arguments(ELFTOAIF "" "TARGET;OUTPUT" "" ${ARGN}) + get_filename_component(ELFTOAIF_OUTPUT_DIR "${ELFTOAIF_OUTPUT}" DIRECTORY) + add_custom_command(OUTPUT "${ELFTOAIF_OUTPUT}" + COMMAND ${CMAKE_COMMAND} -E make_directory ${ELFTOAIF_OUTPUT_DIR} + COMMAND elf2aif $ ${ELFTOAIF_OUTPUT} + DEPENDS ${ELFTOAIF_TARGET}) + add_custom_target(${ELFTOAIF_TARGET}-aif ALL DEPENDS ${ELFTOAIF_OUTPUT}) +endfunction(elf_to_aif) + +elf_to_aif(TARGET CSE2 OUTPUT ${BUILD_DIRECTORY}/!CSE2/CSE2,ff8) + +configure_file(${ASSETS_DIRECTORY}/riscos/!Boot,feb ${BUILD_DIRECTORY}/!CSE2/!Boot,feb COPYONLY) +configure_file(${ASSETS_DIRECTORY}/riscos/!Run,feb ${BUILD_DIRECTORY}/!CSE2/!Run,feb COPYONLY) +configure_file(${ASSETS_DIRECTORY}/riscos/!Sprites,ff9 ${BUILD_DIRECTORY}/!CSE2/!Sprites,ff9 COPYONLY) +configure_file(${BUILD_DIRECTORY}/licence.txt ${BUILD_DIRECTORY}/!CSE2/Licence COPYONLY) +file(COPY ${BUILD_DIRECTORY}/data DESTINATION ${BUILD_DIRECTORY}/!CSE2) diff --git a/src/Config.cpp b/src/Config.cpp index 4e355d80..c85a62bd 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -65,6 +65,8 @@ void DefaultConfigData(CONFIGDATA *conf) #ifdef _3DS conf->display_mode = 1; +#elif defined(__riscos__) + conf->display_mode = 2; #endif // Reset joystick settings (as these can't simply be set to 0)