Add SDL3 platform driver (#454)
This commit is contained in:
parent
ba41413396
commit
9c82a405bd
|
|
@ -51,7 +51,8 @@ jobs:
|
|||
cmake-generator: Ninja
|
||||
cmake-toolchain-file: ${{ matrix.platform.cmake-toolchain-file }}
|
||||
discriminator: ${{ matrix.platform.arch }}
|
||||
version: 2-latest
|
||||
version: 3-latest
|
||||
version-sdl2-compat: 2-head
|
||||
version-sdl12-compat: 1-head
|
||||
- name: 'Prepare sources for release'
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') }}
|
||||
|
|
@ -71,6 +72,7 @@ jobs:
|
|||
-DCMAKE_TOOLCHAIN_FILE=${{ matrix.platform.cmake-toolchain-file }} \
|
||||
-DDETHRACE_PLATFORM_SDL1=ON \
|
||||
-DDETHRACE_PLATFORM_SDL2=ON \
|
||||
-DDETHRACE_PLATFORM_SDL3=ON \
|
||||
-DDETHRACE_PLATFORM_SDL_DYNAMIC=ON \
|
||||
${{ matrix.platform.cmake-args }}
|
||||
- name: 'Build (CMake)'
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ option(DETHRACE_SOUND_ENABLED "Include audio support" ON)
|
|||
option(DETHRACE_NET_ENABLED "Include net support" ON)
|
||||
option(DETHRACE_PLATFORM_SDL1 "Support SDL 1.2 platform driver" OFF)
|
||||
option(DETHRACE_PLATFORM_SDL2 "Support SDL 2 platform driver" ON)
|
||||
option(DETHRACE_PLATFORM_SDL3 "Support SDL 3 platform driver" OFF)
|
||||
|
||||
option(MSVC_42_FOR_RECCMP "Build with MSVC 4.2 to match assembly" OFF)
|
||||
|
||||
|
|
@ -54,6 +55,7 @@ if(MSVC_42_FOR_RECCMP)
|
|||
set(DETHRACE_NET_ENABLED OFF)
|
||||
set(DETHRACE_PLATFORM_SDL1 OFF)
|
||||
set(DETHRACE_PLATFORM_SDL2 OFF)
|
||||
set(DETHRACE_PLATFORM_SDL3 OFF)
|
||||
set(BRENDER_BUILD_DRIVERS OFF)
|
||||
|
||||
set(CMAKE_C_FLAGS_DEBUG "/Od /Oi /Zi /MLd")
|
||||
|
|
@ -107,6 +109,12 @@ if(DETHRACE_PLATFORM_SDL2)
|
|||
math(EXPR count_sdl_platforms "${count_sdl_platforms} + 1")
|
||||
endif()
|
||||
|
||||
if(DETHRACE_PLATFORM_SDL3)
|
||||
find_package(SDL3 CONFIG REQUIRED)
|
||||
list(APPEND DETHRACE_PLATFORMS SDL3)
|
||||
math(EXPR count_sdl_platforms "${count_sdl_platforms} + 1")
|
||||
endif()
|
||||
|
||||
if(count_sdl_platforms GREATER 1)
|
||||
# Force dynamic SDL when enabling 2 (or more) SDL platform backends
|
||||
set(dynamic_sdl_force TRUE)
|
||||
|
|
|
|||
|
|
@ -295,6 +295,12 @@ if(DETHRACE_INSTALL)
|
|||
OPTIONAL
|
||||
)
|
||||
endif()
|
||||
if(DETHRACE_PLATFORM_SDL3)
|
||||
install(FILES "$<TARGET_FILE:SDL3::SDL3>"
|
||||
DESTINATION "."
|
||||
OPTIONAL
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ endif()
|
|||
if(DETHRACE_PLATFORM_SDL2)
|
||||
target_sources(harness PRIVATE
|
||||
platforms/sdl2.c
|
||||
platforms/sdl_scancode_map.h
|
||||
platforms/sdl2_scancode_map.h
|
||||
platforms/sdl2_syms.h
|
||||
)
|
||||
target_compile_definitions(harness PRIVATE DETHRACE_PLATFORM_SDL2)
|
||||
|
|
@ -112,6 +112,21 @@ if(DETHRACE_PLATFORM_SDL2)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(DETHRACE_PLATFORM_SDL3)
|
||||
target_sources(harness PRIVATE
|
||||
platforms/sdl3.c
|
||||
platforms/sdl2_scancode_map.h
|
||||
platforms/sdl3_syms.h
|
||||
)
|
||||
target_compile_definitions(harness PRIVATE DETHRACE_PLATFORM_SDL3)
|
||||
if(DETHRACE_PLATFORM_SDL_DYNAMIC)
|
||||
set_property(SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/platforms/sdl3.c" APPEND PROPERTY INCLUDE_DIRECTORIES "$<TARGET_PROPERTY:SDL3::SDL3,INTERFACE_INCLUDE_DIRECTORIES>")
|
||||
set_property(GLOBAL APPEND PROPERTY DETHRACE_BUILD_RPATHS "$<TARGET_FILE_DIR:SDL3::SDL3>")
|
||||
else()
|
||||
target_link_libraries(harness PRIVATE SDL3::SDL3)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(DETHRACE_PLATFORM_SDL_DYNAMIC)
|
||||
target_compile_definitions(harness PRIVATE DETHRACE_SDL_DYNAMIC)
|
||||
target_link_libraries(harness PRIVATE ${CMAKE_DL_LIBS})
|
||||
|
|
|
|||
|
|
@ -22,16 +22,22 @@ extern void Harness_Platform_Init(tHarness_platform* platform);
|
|||
|
||||
extern const tPlatform_bootstrap SDL1_bootstrap;
|
||||
extern const tPlatform_bootstrap SDL2_bootstrap;
|
||||
extern const tPlatform_bootstrap SDL3_bootstrap;
|
||||
|
||||
static const tPlatform_bootstrap* platform_bootstraps[] = {
|
||||
#if defined(DETHRACE_PLATFORM_SDL2) && defined(DETHRACE_PLATFORM_SDL1)
|
||||
#if defined(DETHRACE_PLATFORM_SDL2)
|
||||
&SDL2_bootstrap,
|
||||
&SDL1_bootstrap
|
||||
#elif defined(DETHRACE_PLATFORM_SDL2)
|
||||
&SDL2_bootstrap
|
||||
#elif defined(DETHRACE_PLATFORM_SDL1)
|
||||
&SDL1_bootstrap
|
||||
#else
|
||||
#define HAS_PLATFORM_BOOTSTRAP
|
||||
#endif
|
||||
#if defined(DETHRACE_PLATFORM_SDL3)
|
||||
&SDL3_bootstrap,
|
||||
#define HAS_PLATFORM_BOOTSTRAP
|
||||
#endif
|
||||
#if defined(DETHRACE_PLATFORM_SDL1)
|
||||
&SDL1_bootstrap,
|
||||
#define HAS_PLATFORM_BOOTSTRAP
|
||||
#endif
|
||||
#ifndef HAS_PLATFORM_BOOTSTRAP
|
||||
// This is the case for MSVC 4.20 builds
|
||||
NULL
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ void debug_print_matrix4(const char* fmt, const char* fn, char* name, br_matrix4
|
|||
|
||||
#define BLUE
|
||||
|
||||
#if 1 // _MSC_VER == 1020
|
||||
#if _MSC_VER == 1020
|
||||
|
||||
#define LOG_TRACE()
|
||||
#define LOG_TRACE8()
|
||||
|
|
@ -86,6 +86,13 @@ void debug_print_matrix4(const char* fmt, const char* fn, char* name, br_matrix4
|
|||
stub_printed = 1; \
|
||||
}
|
||||
|
||||
#define LOG_INFO2(a, b) LOG_INFO(a, b)
|
||||
#define LOG_INFO3(a, b, c) LOG_INFO(a, b, c)
|
||||
#define LOG_WARN2(a, b) LOG_WARN(a, b)
|
||||
#define LOG_WARN3(a, b, c) LOG_WARN(a, b, c)
|
||||
#define LOG_PANIC2(a, b) LOG_PANIC(a, b)
|
||||
#define LOG_DEBUG2(a, b) LOG_DEBUG(a, b)
|
||||
|
||||
#endif
|
||||
|
||||
#endif // ifdef
|
||||
|
|
|
|||
|
|
@ -49,12 +49,11 @@ static const char* const possible_locations[] = {
|
|||
"libSDL-1.2.so",
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DETHRACE_SDL_DYNAMIC
|
||||
static void* sdl1_so;
|
||||
#endif
|
||||
|
||||
#define SDL_NAME "SDL1"
|
||||
#define OBJECT_NAME sdl1_so
|
||||
#define SYMBOL_PREFIX SDL1_
|
||||
#define FOREACH_SDLX_SYM FOREACH_SDL1_SYM
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
#include "harness/config.h"
|
||||
#include "harness/hooks.h"
|
||||
#include "harness/trace.h"
|
||||
#include "sdl2_scancode_map.h"
|
||||
#include "sdl2_syms.h"
|
||||
#include "sdl_scancode_map.h"
|
||||
|
||||
SDL_COMPILE_TIME_ASSERT(sdl2_platform_requires_SDL2, SDL_MAJOR_VERSION == 2);
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ static int render_width, render_height;
|
|||
|
||||
static Uint32 last_frame_time;
|
||||
|
||||
void (*gKeyHandler_func)(void);
|
||||
static void (*gKeyHandler_func)(void);
|
||||
|
||||
// 32 bytes, 1 bit per key. Matches dos executable behavior
|
||||
static br_uint_32 key_state[8];
|
||||
|
|
@ -59,12 +59,11 @@ static const char* const possible_locations[] = {
|
|||
"libSDL2-2.0.so",
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef DETHRACE_SDL_DYNAMIC
|
||||
static void* sdl2_so;
|
||||
#endif
|
||||
|
||||
#define SDL_NAME "SDL2"
|
||||
#define OBJECT_NAME sdl2_so
|
||||
#define SYMBOL_PREFIX SDL2_
|
||||
#define FOREACH_SDLX_SYM FOREACH_SDL2_SYM
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@
|
|||
#include "dethrace_scancodes.h"
|
||||
#include <SDL.h>
|
||||
|
||||
int sdl_scancode_map[SDL_NUM_SCANCODES] = {
|
||||
SDL_COMPILE_TIME_ASSERT(sdl2_scancode_map_requires_SDL2, SDL_MAJOR_VERSION == 2);
|
||||
|
||||
static int sdl_scancode_map[SDL_NUM_SCANCODES] = {
|
||||
[SDL_SCANCODE_ESCAPE] = SCANCODE_ESCAPE,
|
||||
[SDL_SCANCODE_1] = SCANCODE_1,
|
||||
[SDL_SCANCODE_2] = SCANCODE_2,
|
||||
|
|
@ -42,6 +42,4 @@
|
|||
X(GetPrefPath, char*, (const char* org, const char* app)) \
|
||||
X(free, void, (void*))
|
||||
|
||||
#undef SDL2_SYM
|
||||
|
||||
#endif /* sdl2_syms_h */
|
||||
|
|
|
|||
|
|
@ -0,0 +1,426 @@
|
|||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "harness.h"
|
||||
#include "harness/config.h"
|
||||
#include "harness/hooks.h"
|
||||
#include "harness/trace.h"
|
||||
#include "sdl3_scancode_map.h"
|
||||
#include "sdl3_syms.h"
|
||||
|
||||
SDL_COMPILE_TIME_ASSERT(sdl3_platform_requires_SDL3, SDL_MAJOR_VERSION == 3);
|
||||
|
||||
static SDL_Window* window;
|
||||
static SDL_Renderer* renderer;
|
||||
static SDL_Texture* screen_texture;
|
||||
static uint32_t converted_palette[256];
|
||||
static br_pixelmap* last_screen_src;
|
||||
|
||||
static SDL_GLContext gl_context;
|
||||
|
||||
static int render_width, render_height;
|
||||
|
||||
static Uint32 last_frame_time;
|
||||
|
||||
static void (*gKeyHandler_func)(void);
|
||||
|
||||
// 32 bytes, 1 bit per key. Matches dos executable behavior
|
||||
static br_uint_32 key_state[8];
|
||||
|
||||
static struct {
|
||||
int x, y;
|
||||
float scale_x, scale_y;
|
||||
} viewport;
|
||||
|
||||
// Callbacks back into original game code
|
||||
extern void QuitGame(void);
|
||||
extern br_pixelmap* gBack_screen;
|
||||
|
||||
#ifdef DETHRACE_SDL_DYNAMIC
|
||||
#ifdef _WIN32
|
||||
static const char * const possible_locations[] = {
|
||||
"SDL3.dll",
|
||||
};
|
||||
#elif defined(__APPLE__)
|
||||
#define SHARED_OBJECT_NAME "libSDL3"
|
||||
#define SDL3_LIBNAME "libSDL3.dylib"
|
||||
#define SDL3_FRAMEWORK "SDL3.framework/Versions/A/SDL3"
|
||||
static const char * const possible_locations[] = {
|
||||
"@loader_path/" SDL3_LIBNAME, /* MyApp.app/Contents/MacOS/libSDL3_dylib */
|
||||
"@loader_path/../Frameworks/" SDL3_FRAMEWORK, /* MyApp.app/Contents/Frameworks/SDL3_framework */
|
||||
"@executable_path/" SDL3_LIBNAME, /* MyApp.app/Contents/MacOS/libSDL3_dylib */
|
||||
"@executable_path/../Frameworks/" SDL3_FRAMEWORK, /* MyApp.app/Contents/Frameworks/SDL3_framework */
|
||||
NULL, /* /Users/username/Library/Frameworks/SDL3_framework */
|
||||
"/Library/Frameworks" SDL3_FRAMEWORK, /* /Library/Frameworks/SDL3_framework */
|
||||
SDL3_LIBNAME /* oh well, anywhere the system can see the .dylib (/usr/local/lib or whatever) */
|
||||
};
|
||||
#else
|
||||
static const char * const possible_locations[] = {
|
||||
"libSDL3.so.0",
|
||||
"libSDL3.so",
|
||||
};
|
||||
#endif
|
||||
|
||||
static void *sdl3_so;
|
||||
#endif
|
||||
|
||||
#define SDL_NAME "SDL3"
|
||||
#define OBJECT_NAME sdl3_so
|
||||
#define SYMBOL_PREFIX SDL3_
|
||||
#define FOREACH_SDLX_SYM FOREACH_SDL3_SYM
|
||||
|
||||
#include "sdl_dyn_common.h"
|
||||
|
||||
static void calculate_viewport(int window_width, int window_height) {
|
||||
int vp_width, vp_height;
|
||||
float target_aspect_ratio;
|
||||
float aspect_ratio;
|
||||
|
||||
aspect_ratio = (float)window_width / window_height;
|
||||
target_aspect_ratio = (float)gBack_screen->width / gBack_screen->height;
|
||||
|
||||
vp_width = window_width;
|
||||
vp_height = window_height;
|
||||
if (aspect_ratio != target_aspect_ratio) {
|
||||
if (aspect_ratio > target_aspect_ratio) {
|
||||
vp_width = window_height * target_aspect_ratio + .5f;
|
||||
} else {
|
||||
vp_height = window_width / target_aspect_ratio + .5f;
|
||||
}
|
||||
}
|
||||
viewport.x = (window_width - vp_width) / 2;
|
||||
viewport.y = (window_height - vp_height) / 2;
|
||||
viewport.scale_x = (float)vp_width / gBack_screen->width;
|
||||
viewport.scale_y = (float)vp_height / gBack_screen->height;
|
||||
}
|
||||
|
||||
static int SDL3_Harness_SetWindowPos(void* hWnd, int x, int y, int nWidth, int nHeight) {
|
||||
// SDL_SetWindowPosition(hWnd, x, y);
|
||||
if (nWidth == 320 && nHeight == 200) {
|
||||
nWidth = 640;
|
||||
nHeight = 400;
|
||||
}
|
||||
SDL3_SetWindowSize(hWnd, nWidth, nHeight);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SDL3_Harness_DestroyWindow(void) {
|
||||
// SDL3_GL_DeleteContext(context);
|
||||
if (window != NULL) {
|
||||
SDL3_DestroyWindow(window);
|
||||
}
|
||||
SDL3_Quit();
|
||||
window = NULL;
|
||||
}
|
||||
|
||||
// Checks whether the `flag_check` is the only modifier applied.
|
||||
// e.g. is_only_modifier(event.key.keysym.mod, KMOD_ALT) returns true when only the ALT key was pressed
|
||||
static int is_only_key_modifier(SDL_Keymod modifier_flags, SDL_Keymod flag_check) {
|
||||
return (modifier_flags & flag_check) && (modifier_flags & (SDL_KMOD_CTRL | SDL_KMOD_SHIFT | SDL_KMOD_ALT | SDL_KMOD_GUI)) == (modifier_flags & flag_check);
|
||||
}
|
||||
|
||||
static void SDL3_Harness_ProcessWindowMessages(void) {
|
||||
SDL_Event event;
|
||||
|
||||
while (SDL3_PollEvent(&event)) {
|
||||
switch (event.type) {
|
||||
case SDL_EVENT_KEY_DOWN:
|
||||
case SDL_EVENT_KEY_UP:
|
||||
if (event.key.windowID != SDL3_GetWindowID(window)) {
|
||||
continue;
|
||||
}
|
||||
if (event.key.key == SDLK_RETURN) {
|
||||
if (event.key.type == SDL_EVENT_KEY_DOWN) {
|
||||
if ((event.key.mod & (SDL_KMOD_CTRL | SDL_KMOD_SHIFT | SDL_KMOD_ALT | SDL_KMOD_GUI))) {
|
||||
// Ignore keydown of RETURN when used together with some modifier
|
||||
return;
|
||||
}
|
||||
} else if (event.key.type == SDL_EVENT_KEY_UP) {
|
||||
if (is_only_key_modifier(event.key.mod, SDL_KMOD_ALT)) {
|
||||
SDL3_SetWindowFullscreen(window, (SDL3_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) ? 0 : SDL_WINDOW_FULLSCREEN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Map incoming SDL scancode to PC scan code as used by game code
|
||||
int dethrace_scancode = sdl_scancode_map[event.key.scancode];
|
||||
if (dethrace_scancode == 0) {
|
||||
LOG_WARN3("unexpected scan code %s (%d)", SDL3_GetScancodeName(event.key.scancode), event.key.scancode);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.type == SDL_EVENT_KEY_DOWN) {
|
||||
key_state[dethrace_scancode >> 5] |= (1 << (dethrace_scancode & 0x1F));
|
||||
} else {
|
||||
key_state[dethrace_scancode >> 5] &= ~(1 << (dethrace_scancode & 0x1F));
|
||||
}
|
||||
gKeyHandler_func();
|
||||
break;
|
||||
|
||||
case SDL_EVENT_WINDOW_RESIZED:
|
||||
calculate_viewport(event.window.data1, event.window.data2);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_QUIT:
|
||||
QuitGame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL3_Harness_SetKeyHandler(void (*handler_func)(void)) {
|
||||
gKeyHandler_func = handler_func;
|
||||
}
|
||||
|
||||
static void SDL3_Harness_GetKeyboardState(br_uint_32* buffer) {
|
||||
memcpy(buffer, key_state, sizeof(key_state));
|
||||
}
|
||||
|
||||
static int SDL3_Harness_GetMouseButtons(int* pButton1, int* pButton2) {
|
||||
if (SDL3_GetMouseFocus() != window) {
|
||||
*pButton1 = 0;
|
||||
*pButton2 = 0;
|
||||
return 0;
|
||||
}
|
||||
int state = SDL3_GetMouseState(NULL, NULL);
|
||||
*pButton1 = state & SDL_BUTTON_LMASK;
|
||||
*pButton2 = state & SDL_BUTTON_RMASK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int SDL3_Harness_GetMousePosition(int* pX, int* pY) {
|
||||
int window_width, window_height;
|
||||
float fWX, fWY;
|
||||
float fX, fY;
|
||||
|
||||
if (SDL3_GetMouseFocus() != window) {
|
||||
return 0;
|
||||
}
|
||||
SDL3_GetWindowSize(window, &window_width, &window_height);
|
||||
|
||||
SDL3_GetMouseState(&fWX, &fWY);
|
||||
if (renderer != NULL) {
|
||||
// software renderer
|
||||
SDL3_RenderCoordinatesFromWindow(renderer, fWX, fWY, &fX, &fY);
|
||||
} else {
|
||||
// hardware renderer
|
||||
// handle case where window is stretched larger than the pixel size
|
||||
fX = fWX * (640.0f / window_width);
|
||||
fY = fWY * (480.0f / window_height);
|
||||
}
|
||||
*pX = (int)fX;
|
||||
*pY = (int)fY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void limit_fps(void) {
|
||||
Uint32 now = SDL3_GetTicks();
|
||||
if (last_frame_time != 0) {
|
||||
unsigned int frame_time = now - last_frame_time;
|
||||
last_frame_time = now;
|
||||
if (frame_time < 100) {
|
||||
int sleep_time = (1000 / harness_game_config.fps) - frame_time;
|
||||
if (sleep_time > 5) {
|
||||
gHarness_platform.Sleep(sleep_time);
|
||||
}
|
||||
}
|
||||
}
|
||||
last_frame_time = SDL3_GetTicks();
|
||||
}
|
||||
|
||||
static int SDL3_Harness_ShowErrorMessage(char* text, char* caption) {
|
||||
fprintf(stderr, "%s", text);
|
||||
SDL3_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, caption, text, window);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void SDL3_Harness_CreateWindow(const char* title, int width, int height, tHarness_window_type window_type) {
|
||||
int window_width, window_height;
|
||||
|
||||
render_width = width;
|
||||
render_height = height;
|
||||
|
||||
window_width = width;
|
||||
window_height = height;
|
||||
|
||||
// special case lores and make a bigger window
|
||||
if (width == 320 && height == 200) {
|
||||
window_width = 640;
|
||||
window_height = 480;
|
||||
}
|
||||
|
||||
if (!SDL3_Init(SDL_INIT_VIDEO)) {
|
||||
LOG_PANIC2("SDL_INIT_VIDEO error: %s", SDL3_GetError());
|
||||
}
|
||||
|
||||
if (window_type == eWindow_type_opengl) {
|
||||
|
||||
window = SDL3_CreateWindow(title,
|
||||
window_width, window_height,
|
||||
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
|
||||
|
||||
if (window == NULL) {
|
||||
LOG_PANIC2("Failed to create window: %s", SDL3_GetError());
|
||||
}
|
||||
|
||||
SDL3_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL3_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL3_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
|
||||
gl_context = SDL3_GL_CreateContext(window);
|
||||
|
||||
if (gl_context == NULL) {
|
||||
LOG_WARN2("Failed to create OpenGL core profile: %s. Trying OpenGLES...", SDL3_GetError());
|
||||
SDL3_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
SDL3_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL3_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
gl_context = SDL3_GL_CreateContext(window);
|
||||
}
|
||||
if (gl_context == NULL) {
|
||||
LOG_PANIC2("Failed to create OpenGL context: %s", SDL3_GetError());
|
||||
}
|
||||
SDL3_GL_SetSwapInterval(1);
|
||||
|
||||
} else {
|
||||
window = SDL3_CreateWindow(title,
|
||||
window_width, window_height,
|
||||
SDL_WINDOW_RESIZABLE);
|
||||
if (window == NULL) {
|
||||
LOG_PANIC2("Failed to create window: %s", SDL3_GetError());
|
||||
}
|
||||
|
||||
renderer = SDL3_CreateRenderer(window, NULL);
|
||||
if (renderer == NULL) {
|
||||
LOG_PANIC2("Failed to create renderer: %s", SDL3_GetError());
|
||||
}
|
||||
SDL3_SetRenderVSync(renderer, 1);
|
||||
SDL3_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
|
||||
SDL3_SetRenderLogicalPresentation(renderer, render_width, render_height, SDL_LOGICAL_PRESENTATION_LETTERBOX);
|
||||
|
||||
screen_texture = SDL3_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, width, height);
|
||||
if (screen_texture == NULL) {
|
||||
const SDL_PixelFormat *renderer_formats = NULL;
|
||||
SDL_PropertiesID renderer_props = SDL3_GetRendererProperties(renderer);
|
||||
if (renderer_props) {
|
||||
renderer_formats = SDL3_GetPointerProperty(renderer_props, SDL_PROP_RENDERER_TEXTURE_FORMATS_POINTER, NULL);
|
||||
if (renderer_formats) {
|
||||
for (Uint32 i = 0; renderer_formats[i] != SDL_PIXELFORMAT_UNKNOWN; i++) {
|
||||
LOG_INFO2("%s\n", SDL3_GetPixelFormatName(renderer_formats[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_PANIC2("Failed to create renderer texture (%s)", SDL3_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
SDL3_ShowCursor();
|
||||
|
||||
viewport.x = 0;
|
||||
viewport.y = 0;
|
||||
viewport.scale_x = 1;
|
||||
viewport.scale_y = 1;
|
||||
|
||||
if (harness_game_config.start_full_screen) {
|
||||
SDL3_SetWindowFullscreen(window, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL3_Harness_Swap(br_pixelmap* back_buffer) {
|
||||
|
||||
SDL3_Harness_ProcessWindowMessages();
|
||||
|
||||
if (gl_context != NULL) {
|
||||
SDL3_GL_SwapWindow(window);
|
||||
} else {
|
||||
uint8_t* src_pixels = back_buffer->pixels;
|
||||
uint32_t* dest_pixels;
|
||||
int dest_pitch;
|
||||
|
||||
SDL3_LockTexture(screen_texture, NULL, (void**)&dest_pixels, &dest_pitch);
|
||||
for (int i = 0; i < back_buffer->height * back_buffer->width; i++) {
|
||||
*dest_pixels = converted_palette[*src_pixels];
|
||||
dest_pixels++;
|
||||
src_pixels++;
|
||||
}
|
||||
SDL3_UnlockTexture(screen_texture);
|
||||
SDL3_RenderClear(renderer);
|
||||
SDL3_RenderTexture(renderer, screen_texture, NULL, NULL);
|
||||
SDL3_RenderPresent(renderer);
|
||||
last_screen_src = back_buffer;
|
||||
}
|
||||
|
||||
if (harness_game_config.fps != 0) {
|
||||
limit_fps();
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL3_Harness_PaletteChanged(br_colour entries[256]) {
|
||||
for (int i = 0; i < 256; i++) {
|
||||
converted_palette[i] = (0xff << 24 | BR_RED(entries[i]) << 16 | BR_GRN(entries[i]) << 8 | BR_BLU(entries[i]));
|
||||
}
|
||||
if (last_screen_src != NULL) {
|
||||
SDL3_Harness_Swap(last_screen_src);
|
||||
}
|
||||
}
|
||||
|
||||
static void SDL3_Harness_GetViewport(int* x, int* y, float* width_multipler, float* height_multiplier) {
|
||||
*x = viewport.x;
|
||||
*y = viewport.y;
|
||||
*width_multipler = viewport.scale_x;
|
||||
*height_multiplier = viewport.scale_y;
|
||||
}
|
||||
|
||||
static void SDL3_Harness_GetPrefPath(char* path, char* app_name) {
|
||||
char* sdl_path = SDL3_GetPrefPath(NULL, app_name);
|
||||
if (sdl_path == NULL) {
|
||||
LOG_PANIC("Failed to get preferences path (%s)", SDL3_GetError());
|
||||
}
|
||||
strcpy(path, sdl_path);
|
||||
SDL3_free(sdl_path);
|
||||
}
|
||||
|
||||
static uint32_t SDL3_Harness_GetTicks(void) {
|
||||
return SDL3_GetTicks();
|
||||
}
|
||||
|
||||
static int SDL3_Harness_ShowCursor(int show) {
|
||||
if (show) {
|
||||
SDL3_ShowCursor();
|
||||
} else {
|
||||
SDL3_HideCursor();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void* SDL3_Harness_GL_GetProcAddress(const char* name) {
|
||||
return SDL3_GL_GetProcAddress(name);
|
||||
}
|
||||
|
||||
static int SDL3_Harness_Platform_Init(tHarness_platform* platform) {
|
||||
if (SDL3_LoadSymbols() != 0) {
|
||||
return 1;
|
||||
}
|
||||
platform->ProcessWindowMessages = SDL3_Harness_ProcessWindowMessages;
|
||||
platform->Sleep = SDL3_Delay;
|
||||
platform->GetTicks = SDL3_Harness_GetTicks;
|
||||
platform->ShowCursor = SDL3_Harness_ShowCursor;
|
||||
platform->SetWindowPos = SDL3_Harness_SetWindowPos;
|
||||
platform->DestroyWindow = SDL3_Harness_DestroyWindow;
|
||||
platform->SetKeyHandler = SDL3_Harness_SetKeyHandler;
|
||||
platform->GetKeyboardState = SDL3_Harness_GetKeyboardState;
|
||||
platform->GetMousePosition = SDL3_Harness_GetMousePosition;
|
||||
platform->GetMouseButtons = SDL3_Harness_GetMouseButtons;
|
||||
platform->ShowErrorMessage = SDL3_Harness_ShowErrorMessage;
|
||||
|
||||
platform->CreateWindow_ = SDL3_Harness_CreateWindow;
|
||||
platform->Swap = SDL3_Harness_Swap;
|
||||
platform->PaletteChanged = SDL3_Harness_PaletteChanged;
|
||||
platform->GL_GetProcAddress = SDL3_Harness_GL_GetProcAddress;
|
||||
platform->GetViewport = SDL3_Harness_GetViewport;
|
||||
platform->GetPrefPath = SDL3_Harness_GetPrefPath;
|
||||
return 0;
|
||||
};
|
||||
|
||||
const tPlatform_bootstrap SDL3_bootstrap = {
|
||||
"sdl3",
|
||||
"SDL3 video backend (libsdl.org)",
|
||||
ePlatform_cap_software | ePlatform_cap_opengl,
|
||||
SDL3_Harness_Platform_Init,
|
||||
};
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
#ifndef SDL_SCANCODE_MAP_H
|
||||
#define SDL_SCANCODE_MAP_H
|
||||
|
||||
#include "dethrace_scancodes.h"
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
SDL_COMPILE_TIME_ASSERT(sdl2_scancode_map_requires_SDL3, SDL_MAJOR_VERSION == 3);
|
||||
|
||||
static int sdl_scancode_map[SDL_SCANCODE_COUNT] = {
|
||||
[SDL_SCANCODE_ESCAPE] = SCANCODE_ESCAPE,
|
||||
[SDL_SCANCODE_1] = SCANCODE_1,
|
||||
[SDL_SCANCODE_2] = SCANCODE_2,
|
||||
[SDL_SCANCODE_3] = SCANCODE_3,
|
||||
[SDL_SCANCODE_4] = SCANCODE_4,
|
||||
[SDL_SCANCODE_5] = SCANCODE_5,
|
||||
[SDL_SCANCODE_6] = SCANCODE_6,
|
||||
[SDL_SCANCODE_7] = SCANCODE_7,
|
||||
[SDL_SCANCODE_8] = SCANCODE_8,
|
||||
[SDL_SCANCODE_9] = SCANCODE_9,
|
||||
[SDL_SCANCODE_0] = SCANCODE_0,
|
||||
[SDL_SCANCODE_MINUS] = SCANCODE_MINUS,
|
||||
[SDL_SCANCODE_EQUALS] = SCANCODE_EQUALS,
|
||||
[SDL_SCANCODE_BACKSPACE] = SCANCODE_BACK,
|
||||
[SDL_SCANCODE_TAB] = SCANCODE_TAB,
|
||||
[SDL_SCANCODE_Q] = SCANCODE_Q,
|
||||
[SDL_SCANCODE_W] = SCANCODE_W,
|
||||
[SDL_SCANCODE_E] = SCANCODE_E,
|
||||
[SDL_SCANCODE_R] = SCANCODE_R,
|
||||
[SDL_SCANCODE_T] = SCANCODE_T,
|
||||
[SDL_SCANCODE_Y] = SCANCODE_Y,
|
||||
[SDL_SCANCODE_U] = SCANCODE_U,
|
||||
[SDL_SCANCODE_I] = SCANCODE_I,
|
||||
[SDL_SCANCODE_O] = SCANCODE_O,
|
||||
[SDL_SCANCODE_P] = SCANCODE_P,
|
||||
[SDL_SCANCODE_LEFTBRACKET] = SCANCODE_LBRACKET,
|
||||
[SDL_SCANCODE_RIGHTBRACKET] = SCANCODE_RBRACKET,
|
||||
[SDL_SCANCODE_RETURN] = SCANCODE_RETURN,
|
||||
[SDL_SCANCODE_LCTRL] = SCANCODE_LCONTROL,
|
||||
[SDL_SCANCODE_A] = SCANCODE_A,
|
||||
[SDL_SCANCODE_S] = SCANCODE_S,
|
||||
[SDL_SCANCODE_D] = SCANCODE_D,
|
||||
[SDL_SCANCODE_F] = SCANCODE_F,
|
||||
[SDL_SCANCODE_G] = SCANCODE_G,
|
||||
[SDL_SCANCODE_H] = SCANCODE_H,
|
||||
[SDL_SCANCODE_J] = SCANCODE_J,
|
||||
[SDL_SCANCODE_K] = SCANCODE_K,
|
||||
[SDL_SCANCODE_L] = SCANCODE_L,
|
||||
[SDL_SCANCODE_SEMICOLON] = SCANCODE_SEMICOLON,
|
||||
[SDL_SCANCODE_APOSTROPHE] = SCANCODE_APOSTROPHE,
|
||||
[SDL_SCANCODE_GRAVE] = SCANCODE_GRAVE,
|
||||
[SDL_SCANCODE_LSHIFT] = SCANCODE_LSHIFT,
|
||||
[SDL_SCANCODE_BACKSLASH] = SCANCODE_BACKSLASH,
|
||||
[SDL_SCANCODE_Z] = SCANCODE_Z,
|
||||
[SDL_SCANCODE_X] = SCANCODE_X,
|
||||
[SDL_SCANCODE_C] = SCANCODE_C,
|
||||
[SDL_SCANCODE_V] = SCANCODE_V,
|
||||
[SDL_SCANCODE_B] = SCANCODE_B,
|
||||
[SDL_SCANCODE_N] = SCANCODE_N,
|
||||
[SDL_SCANCODE_M] = SCANCODE_M,
|
||||
[SDL_SCANCODE_COMMA] = SCANCODE_COMMA,
|
||||
[SDL_SCANCODE_PERIOD] = SCANCODE_PERIOD,
|
||||
[SDL_SCANCODE_SLASH] = SCANCODE_SLASH,
|
||||
[SDL_SCANCODE_RSHIFT] = SCANCODE_RSHIFT,
|
||||
[SDL_SCANCODE_KP_MULTIPLY] = SCANCODE_MULTIPLY,
|
||||
[SDL_SCANCODE_LALT] = SCANCODE_LALT,
|
||||
[SDL_SCANCODE_SPACE] = SCANCODE_SPACE,
|
||||
[SDL_SCANCODE_CAPSLOCK] = SCANCODE_CAPITAL,
|
||||
[SDL_SCANCODE_F1] = SCANCODE_F1,
|
||||
[SDL_SCANCODE_F2] = SCANCODE_F2,
|
||||
[SDL_SCANCODE_F3] = SCANCODE_F3,
|
||||
[SDL_SCANCODE_F4] = SCANCODE_F4,
|
||||
[SDL_SCANCODE_F5] = SCANCODE_F5,
|
||||
[SDL_SCANCODE_F6] = SCANCODE_F6,
|
||||
[SDL_SCANCODE_F7] = SCANCODE_F7,
|
||||
[SDL_SCANCODE_F8] = SCANCODE_F8,
|
||||
[SDL_SCANCODE_F9] = SCANCODE_F9,
|
||||
[SDL_SCANCODE_F10] = SCANCODE_F10,
|
||||
[SDL_SCANCODE_NUMLOCKCLEAR] = SCANCODE_NUMLOCK,
|
||||
[SDL_SCANCODE_SCROLLLOCK] = SCANCODE_SCROLL,
|
||||
[SDL_SCANCODE_KP_7] = SCANCODE_NUMPAD7,
|
||||
[SDL_SCANCODE_KP_8] = SCANCODE_NUMPAD8,
|
||||
[SDL_SCANCODE_KP_9] = SCANCODE_NUMPAD9,
|
||||
[SDL_SCANCODE_KP_MINUS] = SCANCODE_SUBTRACT,
|
||||
[SDL_SCANCODE_KP_4] = SCANCODE_NUMPAD4,
|
||||
[SDL_SCANCODE_KP_5] = SCANCODE_NUMPAD5,
|
||||
[SDL_SCANCODE_KP_6] = SCANCODE_NUMPAD6,
|
||||
[SDL_SCANCODE_KP_PLUS] = SCANCODE_ADD,
|
||||
[SDL_SCANCODE_KP_1] = SCANCODE_NUMPAD1,
|
||||
[SDL_SCANCODE_KP_2] = SCANCODE_NUMPAD2,
|
||||
[SDL_SCANCODE_KP_3] = SCANCODE_NUMPAD3,
|
||||
[SDL_SCANCODE_KP_0] = SCANCODE_NUMPAD0,
|
||||
[SDL_SCANCODE_KP_PERIOD] = SCANCODE_DECIMAL,
|
||||
[SDL_SCANCODE_NONUSBACKSLASH] = SCANCODE_OEM_102,
|
||||
[SDL_SCANCODE_F11] = SCANCODE_F11,
|
||||
[SDL_SCANCODE_F12] = SCANCODE_F12,
|
||||
[SDL_SCANCODE_KP_ENTER] = SCANCODE_NUMPADENTER,
|
||||
[SDL_SCANCODE_RCTRL] = SCANCODE_RCONTROL,
|
||||
[SDL_SCANCODE_KP_DIVIDE] = SCANCODE_DIVIDE,
|
||||
[SDL_SCANCODE_RALT] = SCANCODE_RALT,
|
||||
[SDL_SCANCODE_PAUSE] = SCANCODE_PAUSE,
|
||||
[SDL_SCANCODE_HOME] = SCANCODE_HOME,
|
||||
[SDL_SCANCODE_UP] = SCANCODE_UP,
|
||||
[SDL_SCANCODE_PAGEUP] = SCANCODE_PGUP,
|
||||
[SDL_SCANCODE_LEFT] = SCANCODE_LEFT,
|
||||
[SDL_SCANCODE_RIGHT] = SCANCODE_RIGHT,
|
||||
[SDL_SCANCODE_END] = SCANCODE_END,
|
||||
[SDL_SCANCODE_DOWN] = SCANCODE_DOWN,
|
||||
[SDL_SCANCODE_PAGEDOWN] = SCANCODE_PGDN,
|
||||
[SDL_SCANCODE_INSERT] = SCANCODE_INSERT,
|
||||
[SDL_SCANCODE_DELETE] = SCANCODE_DELETE,
|
||||
};
|
||||
|
||||
#endif /* _SDL2_SCANCODE_TO_DINPUT_H_ */
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef sdl3_syms_h
|
||||
#define sdl3_syms_h
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#define FOREACH_SDL3_SYM(X) \
|
||||
X(free, void, (void *)) \
|
||||
X(Init, bool, (Uint32)) \
|
||||
X(Quit, void, (void)) \
|
||||
X(Delay, void, (Uint32)) \
|
||||
X(GetTicks, Uint64, (void)) \
|
||||
X(GetError, const char*, (void)) \
|
||||
X(GetPointerProperty, void*, (SDL_PropertiesID, const char*, void*)) \
|
||||
X(PollEvent, bool, (SDL_Event*)) \
|
||||
X(ShowSimpleMessageBox, bool, (SDL_MessageBoxFlags flags, const char*, const char *, SDL_Window*)) \
|
||||
X(CreateWindow, SDL_Window*, (const char*, int, int, SDL_WindowFlags)) \
|
||||
X(DestroyWindow, void, (SDL_Window*)) \
|
||||
X(GetWindowFlags, SDL_WindowFlags, (SDL_Window*)) \
|
||||
X(GetPrefPath, char*, (const char *, const char *)) \
|
||||
X(GetWindowID, SDL_WindowID, (SDL_Window*)) \
|
||||
X(GetWindowSize, bool, (SDL_Window*, int*, int*)) \
|
||||
X(HideCursor, bool, (void)) \
|
||||
X(SetWindowFullscreen, bool, (SDL_Window*, bool)) \
|
||||
X(SetWindowSize, bool, (SDL_Window*, int, int)) \
|
||||
X(CreateRenderer, SDL_Renderer*, (SDL_Window*, const char*)) \
|
||||
X(RenderClear, bool, (SDL_Renderer*)) \
|
||||
X(RenderTexture, bool, (SDL_Renderer*, SDL_Texture*, const SDL_FRect*, const SDL_FRect*)) \
|
||||
X(RenderPresent, bool, (SDL_Renderer*)) \
|
||||
X(RenderCoordinatesFromWindow, bool, (SDL_Renderer*, float, float, float*, float*)) \
|
||||
X(GetRendererName, const char*, (SDL_Renderer*)) \
|
||||
X(GetRendererProperties, SDL_PropertiesID, (SDL_Renderer*)) \
|
||||
X(SetRenderLogicalPresentation, bool, (SDL_Renderer*, int, int, SDL_RendererLogicalPresentation)) \
|
||||
X(SetRenderDrawBlendMode, bool, (SDL_Renderer*, SDL_BlendMode)) \
|
||||
X(SetRenderVSync, bool, (SDL_Renderer*, int)) \
|
||||
X(CreateTexture, SDL_Texture*, (SDL_Renderer*, SDL_PixelFormat, SDL_TextureAccess, int, int)) \
|
||||
X(LockTexture, bool, (SDL_Texture*, const SDL_Rect*, void**, int*)) \
|
||||
X(UnlockTexture, void, (SDL_Texture*)) \
|
||||
X(GetMouseFocus, SDL_Window*, (void)) \
|
||||
X(GetMouseState, SDL_MouseButtonFlags, (float*, float*)) \
|
||||
X(ShowCursor, bool, (void)) \
|
||||
X(GetPixelFormatName, const char*, (SDL_PixelFormat)) \
|
||||
X(GetScancodeName, const char *, (SDL_Scancode)) \
|
||||
X(GL_CreateContext, SDL_GLContext, (SDL_Window*)) \
|
||||
X(GL_GetProcAddress, SDL_FunctionPointer, (const char*)) \
|
||||
X(GL_SetAttribute, bool, (SDL_GLAttr, int)) \
|
||||
X(GL_SetSwapInterval, bool, (int)) \
|
||||
X(GL_SwapWindow, bool, (SDL_Window*))
|
||||
|
||||
#endif /* sdl3_syms_h */
|
||||
|
|
@ -16,6 +16,21 @@ static void Harness_UnloadObject(void *obj) {
|
|||
static void *Harness_LoadFunction(void *obj, const char *name) {
|
||||
return GetProcAddress(obj, name);
|
||||
}
|
||||
static const char *Harness_LoadError(void) {
|
||||
static char buffer[512];
|
||||
DWORD cchMsg = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
buffer,
|
||||
sizeof(buffer)-1,
|
||||
NULL);
|
||||
if (cchMsg == 0) {
|
||||
strncpy(buffer, "GetProcAddress failed", sizeof(buffer));
|
||||
buffer[sizeof(buffer)-1] = '\0';
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
static void *Harness_LoadObject(const char *name) {
|
||||
|
|
@ -27,6 +42,9 @@ static void Harness_UnloadObject(void *obj) {
|
|||
static void *Harness_LoadFunction(void *obj, const char *name) {
|
||||
return dlsym(obj, name);
|
||||
}
|
||||
static const char *Harness_LoadError(void) {
|
||||
return dlerror();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
@ -38,7 +56,8 @@ static void *Harness_LoadFunction(void *obj, const char *name) {
|
|||
#ifdef DETHRACE_SDL_DYNAMIC
|
||||
#define X_LOAD_FUNCTION(name, ret, args) \
|
||||
STR_JOIN(SYMBOL_PREFIX, name) = Harness_LoadFunction(OBJECT_NAME, "SDL_" #name); \
|
||||
if (STR_JOIN(SYMBOL_PREFIX, name) == NULL) { \
|
||||
if (STR_JOIN(SYMBOL_PREFIX, name) == NULL) { \
|
||||
fprintf(stderr, "Failed to load %s function: %s (%s)\n", SDL_NAME, "SDL_" #name, Harness_LoadError()); \
|
||||
goto failure; \
|
||||
}
|
||||
#else
|
||||
|
|
@ -57,6 +76,7 @@ static int STR_JOIN(SYMBOL_PREFIX,LoadSymbols)(void) {
|
|||
}
|
||||
}
|
||||
if (OBJECT_NAME == NULL) {
|
||||
fputs("Could not find " SDL_NAME " library\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue