Merge branch 'main' of https://github.com/dethrace-labs/dethrace into opponent_matching
This commit is contained in:
commit
6af5c19f1b
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -298,6 +298,12 @@ if(DETHRACE_INSTALL)
|
|||
OPTIONAL
|
||||
)
|
||||
endif()
|
||||
if(DETHRACE_PLATFORM_SDL3)
|
||||
install(FILES "$<TARGET_FILE:SDL3::SDL3>"
|
||||
DESTINATION "."
|
||||
OPTIONAL
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -140,8 +140,25 @@ int gAllow_open_to_fail = 1;
|
|||
// GLOBAL: CARM95 0x0050a5c8
|
||||
int gDecode_thing = '@';
|
||||
|
||||
#define DECODE_STRING_SECRET 50
|
||||
|
||||
// GLOBAL: CARM95 0x0050a5d0
|
||||
char gDecode_string[] = { 0x9B, 0x52, 0x93, 0x9F, 0x52, 0x98, 0x9B, 0x96, 0x96, 0x9E, 0x9B, 0xA0, 0x99, 0x0 };
|
||||
char gDecode_string[] = {
|
||||
'i' + DECODE_STRING_SECRET,
|
||||
' ' + DECODE_STRING_SECRET,
|
||||
'a' + DECODE_STRING_SECRET,
|
||||
'm' + DECODE_STRING_SECRET,
|
||||
' ' + DECODE_STRING_SECRET,
|
||||
'f' + DECODE_STRING_SECRET,
|
||||
'i' + DECODE_STRING_SECRET,
|
||||
'd' + DECODE_STRING_SECRET,
|
||||
'd' + DECODE_STRING_SECRET,
|
||||
'l' + DECODE_STRING_SECRET,
|
||||
'i' + DECODE_STRING_SECRET,
|
||||
'n' + DECODE_STRING_SECRET,
|
||||
'g' + DECODE_STRING_SECRET,
|
||||
'\0'
|
||||
};
|
||||
|
||||
// GLOBAL: CARM95 0x00531f00
|
||||
int gFunk_groove_flags[30];
|
||||
|
|
@ -400,7 +417,7 @@ void LoadGeneralParameters(void) {
|
|||
fgets(s, sizeof(s) - 1, f);
|
||||
fclose(f);
|
||||
for (i = 0; i < strlen(gDecode_string); i++) {
|
||||
gDecode_string[i] -= 50;
|
||||
gDecode_string[i] -= DECODE_STRING_SECRET;
|
||||
}
|
||||
|
||||
// trim trailing CRLF etc
|
||||
|
|
@ -413,7 +430,7 @@ void LoadGeneralParameters(void) {
|
|||
}
|
||||
|
||||
for (i = 0; i < strlen(gDecode_string); i++) {
|
||||
gDecode_string[i] += 50;
|
||||
gDecode_string[i] += DECODE_STRING_SECRET;
|
||||
}
|
||||
}
|
||||
PathCat(the_path, gApplication_path, "GENERAL.TXT");
|
||||
|
|
|
|||
|
|
@ -1595,7 +1595,7 @@ void SelectRaceDraw(int pCurrent_choice, int pCurrent_mode) {
|
|||
fputs("*************", f);
|
||||
}
|
||||
}
|
||||
gDecode_thing ^= 0x40u;
|
||||
gDecode_thing ^= '@';
|
||||
fclose(f);
|
||||
EncodeAllFilesInDirectory("");
|
||||
EncodeAllFilesInDirectory("CARS");
|
||||
|
|
|
|||
|
|
@ -98,6 +98,14 @@ void EncodeLine(char* pS) {
|
|||
FILE* test;
|
||||
unsigned char c;
|
||||
|
||||
#ifdef DETHRACE_FIX_BUGS
|
||||
// Demo has its own decryption key + behavior
|
||||
if (harness_game_info.mode == eGame_carmageddon_demo) {
|
||||
EncodeLine_DEMO(pS);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
len = strlen(pS);
|
||||
key = (char*)gLong_key;
|
||||
if (gEncryption_method == 0) {
|
||||
|
|
@ -1441,6 +1449,14 @@ void DecodeLine2(char* pS) {
|
|||
unsigned char c;
|
||||
char* key;
|
||||
|
||||
#ifdef DETHRACE_FIX_BUGS
|
||||
// Demo has its own decryption key + behavior
|
||||
if (harness_game_info.mode == eGame_carmageddon_demo) {
|
||||
DecodeLine2_DEMO(pS);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
len = strlen(pS);
|
||||
key = (char*)gLong_key;
|
||||
#ifdef DETHRACE_FIX_BUGS
|
||||
|
|
@ -1494,6 +1510,14 @@ void EncodeLine2(char* pS) {
|
|||
unsigned char c;
|
||||
char* key;
|
||||
|
||||
#ifdef DETHRACE_FIX_BUGS
|
||||
// Demo has its own decryption key + behavior
|
||||
if (harness_game_info.mode == eGame_carmageddon_demo) {
|
||||
EncodeLine2_DEMO(pS);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
len = strlen(pS);
|
||||
count = 0;
|
||||
key = (char*)gLong_key;
|
||||
|
|
@ -1913,3 +1937,48 @@ void EncodeLine_DEMO(char* pS) {
|
|||
pS[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void EncodeLine2_DEMO(char* pS) {
|
||||
int len;
|
||||
int seed;
|
||||
int i;
|
||||
const char* key;
|
||||
unsigned char c;
|
||||
#if BR_ENDIAN_BIG
|
||||
const tU32 gLong_key_DEMO[] = { 0x58503A76, 0xCBB68565, 0x15CD5B07, 0xB168DE3A };
|
||||
#else
|
||||
const tU32 gLong_key_DEMO[] = { 0x763A5058, 0x6585B6CB, 0x75BCD15, 0x3ADE68B1 };
|
||||
#endif
|
||||
|
||||
len = strlen(pS);
|
||||
key = (char*)gLong_key_DEMO;
|
||||
|
||||
while (len != 0 && (pS[len - 1] == '\r' || pS[len - 1] == '\n')) {
|
||||
pS[len - 1] = 0;
|
||||
len--;
|
||||
}
|
||||
seed = len % 16;
|
||||
for (i = 0; i < len; i++) {
|
||||
c = pS[i];
|
||||
if (c == '\t') {
|
||||
c = 0x9F;
|
||||
}
|
||||
|
||||
c -= 32;
|
||||
c ^= key[seed];
|
||||
c &= 0x7f;
|
||||
c += 32;
|
||||
if (c == 0x9F) {
|
||||
c = '\t';
|
||||
}
|
||||
if (c == '\n' || c == '\r') {
|
||||
c |= 0x80;
|
||||
}
|
||||
seed = (seed + 7) % 16;
|
||||
pS[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
void DecodeLine2_DEMO(char* pS) {
|
||||
EncodeLine_DEMO(pS);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -186,4 +186,10 @@ void BlendifyMaterialPrimitively(br_material* pMaterial, int pPercent);
|
|||
|
||||
void BlendifyMaterial(br_material* pMaterial, int pPercent);
|
||||
|
||||
void EncodeLine_DEMO(char* pS);
|
||||
|
||||
void EncodeLine2_DEMO(char* pS);
|
||||
|
||||
void DecodeLine2_DEMO(char* pS);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ int ReceiveHostResponses(void) {
|
|||
int already_registered;
|
||||
|
||||
char addr_string[32];
|
||||
unsigned int sa_len;
|
||||
socklen_t sa_len;
|
||||
int error;
|
||||
|
||||
sa_len = sizeof(gRemote_addr);
|
||||
|
|
@ -519,7 +519,7 @@ tNet_message* PDNetGetNextMessage(tNet_game_details* pDetails, void** pSender_ad
|
|||
int msg_type;
|
||||
|
||||
char addr_str[32];
|
||||
unsigned int sa_len;
|
||||
socklen_t sa_len;
|
||||
int res;
|
||||
tNet_message* msg;
|
||||
|
||||
|
|
|
|||
|
|
@ -843,6 +843,11 @@ int original_main(int pArgc, char** pArgv) {
|
|||
|
||||
for (i = 1; i < pArgc; i++) {
|
||||
if (strcasecmp(pArgv[i], "-hires") == 0) {
|
||||
#ifdef DETHRACE_FIX_BUGS
|
||||
if (!PDCheckDriveExists("DATA/64X48X8/HEADUP.TXT")) {
|
||||
PDFatalError("No high resolution data (\"DATA/64X48X8\") is available. Run game without -hires.");
|
||||
}
|
||||
#endif
|
||||
gGraf_spec_index = 1;
|
||||
} else if (strcasecmp(pArgv[i], "-yon") == 0 && i < pArgc - 1) {
|
||||
i++;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -180,6 +186,9 @@ static void Harness_DetectGameMode(void) {
|
|||
} else if (strstr(buffer, "NOWA GRA") != NULL) {
|
||||
harness_game_info.localization = eGameLocalization_polish;
|
||||
LOG_INFO2("Language: \"%s\"", "Polish");
|
||||
} else if (strstr(buffer, "NOUVELLE PARTIE") != NULL) {
|
||||
harness_game_info.localization = eGameLocalization_french;
|
||||
LOG_INFO2("Language: \"%s\"", "French");
|
||||
} else {
|
||||
LOG_INFO("Language: unrecognized");
|
||||
}
|
||||
|
|
@ -541,6 +550,14 @@ int Harness_Hook_isalnum(int c) {
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
} if (harness_game_info.localization == eGameLocalization_french) {
|
||||
// French diacritic letters in Windows-1252
|
||||
unsigned char letters[] = { 140, 156, 159, 192, 194, 198, 199, 200, 201, 202, 203, 206, 207, 212, 217, 219, 220, 224, 226, 230, 231, 232, 233, 234, 235, 238, 239, 244, 249, 251, 252, 255 };
|
||||
for (i = 0; i < (int)sizeof(letters); i++) {
|
||||
if ((unsigned char)c == letters[i]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isalnum(c);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ typedef enum {
|
|||
eGameLocalization_none,
|
||||
eGameLocalization_german,
|
||||
eGameLocalization_polish,
|
||||
eGameLocalization_french,
|
||||
} tHarness_game_localization;
|
||||
|
||||
typedef struct tHarness_game_info {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -437,7 +437,7 @@ int OS_GetAdapterAddress(char* name, void* pSockaddr_in) {
|
|||
}
|
||||
|
||||
for (IP_ADAPTER_ADDRESSES* aa = adapter_addrs; aa != NULL; aa = aa->Next) {
|
||||
LOG_DEBUG("name: %s", aa->FriendlyName); // Skip if name is provided and doesn't match FriendlyName
|
||||
LOG_DEBUG2("name: %s", aa->FriendlyName); // Skip if name is provided and doesn't match FriendlyName
|
||||
if (wcslen(wideName) > 0 && wcscmp(aa->FriendlyName, wideName) != 0)
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import enum
|
||||
import sys
|
||||
|
||||
LONG_KEY = (
|
||||
|
|
@ -11,7 +12,15 @@ OTHER_LONG_KEY = (
|
|||
0x67, 0xa8, 0xd6, 0x26, 0xb6, 0xdd, 0x45, 0x1b,
|
||||
0x32, 0x7e, 0x22, 0x13, 0x15, 0xc2, 0x94, 0x37,
|
||||
)
|
||||
DEMO_KEY = (
|
||||
0x58, 0x50, 0x3A, 0x76, 0xCB, 0xB6, 0x85, 0x65,
|
||||
0x15, 0xCD, 0x5B, 0x07, 0xB1, 0x68, 0xDE, 0x3A,
|
||||
)
|
||||
|
||||
class Method(enum.Enum):
|
||||
Method1 = "1"
|
||||
Method2 = "2"
|
||||
Demo = "demo"
|
||||
|
||||
class Byte:
|
||||
def __init__(self, v: int):
|
||||
|
|
@ -52,6 +61,13 @@ class Byte:
|
|||
self.v = (self.v & v) & 0xff
|
||||
return self
|
||||
|
||||
def __or__(self, v: int):
|
||||
return Byte(self.v | v)
|
||||
|
||||
def __ior__(self, v: int):
|
||||
self.v = (self.v | v) & 0xff
|
||||
return self
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, Byte):
|
||||
return self.v == other.v
|
||||
|
|
@ -63,61 +79,20 @@ class Byte:
|
|||
return f"(byte 0x{self.v:02x})"
|
||||
|
||||
|
||||
def decode_line(line: bytes, method: int) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = LONG_KEY
|
||||
seed = len(line) % len(key)
|
||||
dline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
b = Byte(c)
|
||||
if dline[i - 2:i] == b'//':
|
||||
key = OTHER_LONG_KEY
|
||||
if method == 1:
|
||||
if b == ord(b'\t'):
|
||||
b = Byte(0x9f)
|
||||
|
||||
b -= 0x20
|
||||
b ^= key[seed]
|
||||
b &= 0x7f
|
||||
b += 0x20
|
||||
|
||||
seed += 7
|
||||
seed %= len(key)
|
||||
|
||||
if b == 0x9f:
|
||||
b = Byte(ord(b'\t'))
|
||||
else:
|
||||
if b == ord(b'\t'):
|
||||
b = Byte(0x80)
|
||||
|
||||
b -= 0x20
|
||||
if (b & 0x80) == 0:
|
||||
b ^= key[seed] & 0x7f
|
||||
b += 0x20
|
||||
|
||||
seed += 7
|
||||
seed %= len(key)
|
||||
|
||||
if b == 0x80:
|
||||
b = Byte(ord(b'\t'))
|
||||
dline[i] = b.v
|
||||
return dline
|
||||
|
||||
|
||||
def encode_line(line: bytes, method: int) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = LONG_KEY
|
||||
seed = len(line) % len(key)
|
||||
count = 0
|
||||
eline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
if count == 2:
|
||||
key = OTHER_LONG_KEY
|
||||
if c == ord('/'):
|
||||
count += 1
|
||||
else:
|
||||
count = 0
|
||||
if method == 1:
|
||||
class Codec1:
|
||||
def encode_line(self, line: bytes) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = LONG_KEY
|
||||
seed = len(line) % len(key)
|
||||
count = 0
|
||||
eline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
if count == 2:
|
||||
key = OTHER_LONG_KEY
|
||||
if c == ord('/'):
|
||||
count += 1
|
||||
else:
|
||||
count = 0
|
||||
if c == ord('\t'):
|
||||
c = 0x9f
|
||||
|
||||
|
|
@ -132,7 +107,51 @@ def encode_line(line: bytes, method: int) -> bytes:
|
|||
|
||||
if b == 0x9f:
|
||||
b = Byte(ord('\t'))
|
||||
else:
|
||||
eline[i] = b.v
|
||||
return bytes(eline)
|
||||
|
||||
def decode_line(self, line: bytes) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = LONG_KEY
|
||||
seed = len(line) % len(key)
|
||||
dline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
b = Byte(c)
|
||||
if dline[i - 2:i] == b'//':
|
||||
key = OTHER_LONG_KEY
|
||||
|
||||
if b == ord(b'\t'):
|
||||
b = Byte(0x9f)
|
||||
|
||||
b -= 0x20
|
||||
b ^= key[seed]
|
||||
b &= 0x7f
|
||||
b += 0x20
|
||||
|
||||
seed += 7
|
||||
seed %= len(key)
|
||||
|
||||
if b == 0x9f:
|
||||
b = Byte(ord(b'\t'))
|
||||
dline[i] = b.v
|
||||
return dline
|
||||
|
||||
|
||||
class Codec2:
|
||||
def encode_line(self, line: bytes) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = LONG_KEY
|
||||
seed = len(line) % len(key)
|
||||
count = 0
|
||||
eline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
if count == 2:
|
||||
key = OTHER_LONG_KEY
|
||||
if c == ord('/'):
|
||||
count += 1
|
||||
else:
|
||||
count = 0
|
||||
|
||||
if c == ord('\t'):
|
||||
c = 0x80
|
||||
b = Byte(c - 0x20)
|
||||
|
|
@ -145,24 +164,116 @@ def encode_line(line: bytes, method: int) -> bytes:
|
|||
|
||||
if b == 0x80:
|
||||
b = Byte(ord('\t'))
|
||||
eline[i] = b.v
|
||||
return bytes(eline)
|
||||
eline[i] = b.v
|
||||
return bytes(eline)
|
||||
|
||||
def decode_line(self, line: bytes) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = LONG_KEY
|
||||
seed = len(line) % len(key)
|
||||
dline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
b = Byte(c)
|
||||
if dline[i - 2:i] == b'//':
|
||||
key = OTHER_LONG_KEY
|
||||
|
||||
if b == ord(b'\t'):
|
||||
b = Byte(0x80)
|
||||
|
||||
b -= 0x20
|
||||
if (b & 0x80) == 0:
|
||||
b ^= key[seed] & 0x7f
|
||||
b += 0x20
|
||||
|
||||
seed += 7
|
||||
seed %= len(key)
|
||||
|
||||
if b == 0x80:
|
||||
b = Byte(ord(b'\t'))
|
||||
|
||||
dline[i] = b.v
|
||||
return dline
|
||||
|
||||
|
||||
class CodecDemo:
|
||||
def encode_line(self, line: bytes) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = DEMO_KEY
|
||||
seed = len(line) % len(key)
|
||||
dline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
b = Byte(c)
|
||||
|
||||
if b == ord('\t'):
|
||||
b = Byte(0x9f)
|
||||
|
||||
b -= 0x20
|
||||
b ^= key[seed]
|
||||
b &= 0x7f
|
||||
b += 0x20
|
||||
if b == 0x9f:
|
||||
b = Byte(ord('\t'))
|
||||
if b == ord('\n') or b == ord('\r'):
|
||||
b |= 0x80
|
||||
|
||||
seed += 7
|
||||
seed %= len(key)
|
||||
|
||||
dline[i] = b.v
|
||||
return dline
|
||||
|
||||
def decode_line(self, line: bytes) -> bytes:
|
||||
line = line.rstrip(b"\r\n")
|
||||
key = DEMO_KEY
|
||||
seed = len(line) % len(key)
|
||||
dline = bytearray(len(line))
|
||||
for i, c in enumerate(line):
|
||||
b = Byte(c)
|
||||
|
||||
if b == ord('\t'):
|
||||
b = Byte(0x9f)
|
||||
|
||||
b -= 0x20
|
||||
b ^= key[seed]
|
||||
b &= 0x7f
|
||||
b += 0x20
|
||||
|
||||
seed += 7
|
||||
seed %= len(key)
|
||||
|
||||
if b == 0x9f:
|
||||
b = Byte(ord('\t'))
|
||||
|
||||
dline[i] = b.v
|
||||
return dline
|
||||
|
||||
|
||||
CODECS = {
|
||||
Method.Method1: Codec1,
|
||||
Method.Method2: Codec2,
|
||||
Method.Demo: CodecDemo,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
method_choices = tuple(e.value for e in Method.__members__.values())
|
||||
parser = argparse.ArgumentParser(allow_abbrev=False, description="Decode/encode a Carmageddon text file")
|
||||
parser.add_argument("file", metavar="FILE", nargs="?", help="input file (default=stdin)")
|
||||
parser.add_argument("--method", choices=[1, 2], type=int, default=2, help="encryption method to use (default=2)")
|
||||
parser.add_argument("--method", choices=method_choices, default=Method.Method2.value,
|
||||
help=f"encryption method to use (default={Method.Method2.value}, choices={','.join(method_choices)})")
|
||||
args = parser.parse_args()
|
||||
|
||||
method = Method(args.method)
|
||||
codec = CODECS[method]()
|
||||
|
||||
istream = open(args.file, "rb") if args.file else sys.stdin.buffer
|
||||
|
||||
for line in istream.readlines():
|
||||
if line[0] == ord(b'@'):
|
||||
dline = decode_line(line[1:], args.method)
|
||||
if line[0] == ord(b"@"):
|
||||
dline = codec.decode_line(line[1:])
|
||||
sys.stdout.buffer.write(dline)
|
||||
else:
|
||||
eline = b"@" + encode_line(line, args.method)
|
||||
eline = b"@" + codec.encode_line(line)
|
||||
sys.stdout.buffer.write(eline)
|
||||
sys.stdout.buffer.write(b'\n')
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue