From 3a91a526c8853b3284cdc96130f8863513e10355 Mon Sep 17 00:00:00 2001 From: Dethrace Engineering Department <78985374+dethrace-labs@users.noreply.github.com> Date: Sat, 1 Apr 2023 15:40:40 +1300 Subject: [PATCH] Implements quitgame function (#294) * implements quitgame function * updates IOPlatform_* function names --- docs/PORTING.md | 16 +++-- src/DETHRACE/common/main.c | 20 +++++- src/DETHRACE/common/sound.c | 6 +- src/DETHRACE/pc-dos/dossys.c | 9 ++- src/S3/audio.c | 86 ++++++++++++++++++++++++++ src/S3/audio.h | 5 ++ src/S3/include/s3/s3.h | 1 + src/S3/s3cda.c | 16 +---- src/S3/s3cda.h | 1 - src/S3/s3sound.c | 28 ++------- src/S3/s3sound.h | 3 +- src/harness/harness.c | 27 ++++---- src/harness/include/harness/hooks.h | 1 + src/harness/io_platforms/io_platform.h | 18 +++--- src/harness/io_platforms/sdl_gl.c | 27 +++++--- 15 files changed, 182 insertions(+), 82 deletions(-) diff --git a/docs/PORTING.md b/docs/PORTING.md index b9065b83..545f7dc5 100644 --- a/docs/PORTING.md +++ b/docs/PORTING.md @@ -35,13 +35,17 @@ The default IO platform is `SDL_OpenGL`, which uses SDL for windowing and input, To add a new `IOPlatform`: 1. Create `io_platforms/my_platform.c` file and implement the required functions defined in [io_platforms/io_platform.h](https://github.com/dethrace-labs/dethrace/blob/main/src/harness/io_platforms/io_platform.h): -- `Window_Create` -- `Window_PollEvents` -- `Window_Swap` -- `Input_GetKeyMap` -- `Input_IsKeyDown` +- `IOPlatform_Init` +- `IOPlatform_CreateWindow` +- `IOPlatform_PollEvents` +- `IOPlatform_SwapWindow` +- `IOPlatform_GetKeyMap` +- `IOPlatform_IsKeyDown` +- `IOPlatform_GetMousePosition` +- `IOPlatform_GetMouseButtons` +- `IOPlatform_Shutdown` -`Window_Create` returns a `tRenderer*`, which must implement the interface defined in [renderers/renderer.h](https://github.com/dethrace-labs/dethrace/blob/main/src/harness/renderers/renderer.h). See [renderers/gl](https://github.com/dethrace-labs/dethrace/tree/main/src/harness/renderers/gl) for an example. +`IOPlatform_CreateWindow` returns a `tRenderer*`, which must implement the interface defined in [renderers/renderer.h](https://github.com/dethrace-labs/dethrace/blob/main/src/harness/renderers/renderer.h). See [renderers/gl](https://github.com/dethrace-labs/dethrace/tree/main/src/harness/renderers/gl) for an example. 2. Add a new conditional section in `src/harness/CMakeLists.txt` for your new platform diff --git a/src/DETHRACE/common/main.c b/src/DETHRACE/common/main.c index 55440ffb..c16a028a 100644 --- a/src/DETHRACE/common/main.c +++ b/src/DETHRACE/common/main.c @@ -6,6 +6,8 @@ #include "drmem.h" #include "errors.h" #include "globvars.h" +#include "globvrpb.h" +#include "graphics.h" #include "harness/config.h" #include "harness/trace.h" #include "init.h" @@ -27,7 +29,23 @@ void QuitGame() { DoDemoGoodbye(); } - NOT_IMPLEMENTED(); + gProgram_state.racing = 0; + SaveOptions(); + if (gNet_mode != eNet_mode_none) { + NetLeaveGame(gCurrent_net_game); + } + ShutdownNetIfRequired(); + if (gSound_available) { + DRS3ShutDown(); + } + if (gBr_initialized) { + ClearEntireScreen(); + } + PDRevertPalette(); + StopMusic(); + PDShutdownSystem(); + CloseDiagnostics(); + exit(0); } // IDA: tU32 __cdecl TrackCount(br_actor *pActor, tU32 *pCount) diff --git a/src/DETHRACE/common/sound.c b/src/DETHRACE/common/sound.c index 04ffb0a7..6a920c8e 100644 --- a/src/DETHRACE/common/sound.c +++ b/src/DETHRACE/common/sound.c @@ -322,7 +322,11 @@ int DRS3SoundStillPlaying(tS3_sound_tag pSound_tag) { // IDA: void __cdecl DRS3ShutDown() void DRS3ShutDown() { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + if (gSound_enabled) { + gSound_enabled = 0; + S3Shutdown(); + } } // IDA: int __usercall DRS3SetOutletVolume@(tS3_outlet_ptr pOutlet@, tS3_volume pVolume@) diff --git a/src/DETHRACE/pc-dos/dossys.c b/src/DETHRACE/pc-dos/dossys.c index ff177f37..e0ab62c7 100644 --- a/src/DETHRACE/pc-dos/dossys.c +++ b/src/DETHRACE/pc-dos/dossys.c @@ -308,7 +308,11 @@ void PDInitialiseSystem() { // IDA: void __cdecl PDShutdownSystem() void PDShutdownSystem() { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + Harness_Hook_PDShutdownSystem(); + + CloseDiagnostics(); + exit(0); } // IDA: void __cdecl PDSaveOriginalPalette() @@ -320,7 +324,8 @@ void PDSaveOriginalPalette() { // IDA: void __cdecl PDRevertPalette() void PDRevertPalette() { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + // empty function } // IDA: int __usercall PDInitScreenVars@(int pArgc@, char **pArgv@) diff --git a/src/S3/audio.c b/src/S3/audio.c index c787136a..7decdc06 100644 --- a/src/S3/audio.c +++ b/src/S3/audio.c @@ -2,6 +2,7 @@ #include "resource.h" #include "3d.h" +#include "harness/config.h" #include "harness/os.h" #include "harness/trace.h" #include "miniaudio/miniaudio.h" @@ -45,6 +46,9 @@ char gS3_directory_name[8]; int gS3_have_current_dir; char gS3_current_dir[260]; +// dethrace +ma_engine miniaudio_engine; + int dword_5216C0; int S3Init(char* pPath, int pLow_memory_mode) { @@ -85,6 +89,33 @@ int S3Init(char* pPath, int pLow_memory_mode) { return 0; } +void S3Shutdown() { + tS3_outlet* outlet; // [esp+10h] [ebp-10h] + tS3_outlet* next_outlet; // [esp+14h] [ebp-Ch] + tS3_descriptor* next_descriptor; // [esp+18h] [ebp-8h] + tS3_descriptor* descriptor; // [esp+1Ch] [ebp-4h] + + S3StopAllOutletSounds(); + S3DisableMIDI(); + S3DisableCDA(); + if (gS3_enabled) { + S3Disable(); + for (descriptor = gS3_descriptors; descriptor != NULL; descriptor = next_descriptor) { + next_descriptor = descriptor->next; + S3DisposeDescriptor(descriptor->id); + S3MemFree(descriptor); + } + for (outlet = gS3_outlets; outlet != NULL; outlet = next_outlet) { + next_outlet = outlet->next; + S3DisposeOutlet(outlet); + } + S3DisposeUnboundChannels(); + } + if (gS3_opened_output_devices) { + S3CloseDevices(); + } +} + void S3Enable() { gS3_enabled = 1; } @@ -113,6 +144,51 @@ int S3OpenOutputDevices() { return 1; } +int S3OpenSampleDevice() { + ma_result result; + + ma_engine_config engineConfig; + engineConfig = ma_engine_config_init(); + engineConfig.sampleRate = 22050; + + result = ma_engine_init(&engineConfig, &miniaudio_engine); + if (result != MA_SUCCESS) { + printf("Failed to initialize audio engine."); + return 0; + } + + ma_engine_set_volume(&miniaudio_engine, harness_game_config.volume_multiplier); + + S3Enable(); + return 1; +} + +int S3OpenCDADevice() { + // gS3_cda_device.lpstrDeviceType = (LPCSTR)516; + // if (mciSendCommandA(0, 0x803u, 0x3000u, (DWORD_PTR)&gS3_cda_device) + // && mciSendCommandA(0, 0x803u, 0x3100u, (DWORD_PTR)&gS3_cda_device)) { + // return 0; + // } + // stru_550560.dwTimeFormat = 10; // MCI_FORMAT_TMSF + // mciSendCommandA(gS3_cda_device.wDeviceID, 0x80Du, 0x400u, (DWORD_PTR)&stru_550560); + // S3CDAEnable(); + // return 1; + + return 0; +} + +void S3CloseDevices() { + // if (gS3_hardware_info.device_installed) { + // gS3_direct_sound_ptr->lpVtbl->Release(gS3_direct_sound_ptr); + // gS3_direct_sound_ptr = NULL; + // } + // if (gS3_cda_device.wDeviceID) { + // mciSendCommandA(gS3_cda_device.wDeviceID, 0x804u, 0, 0); // MCI_CLOSE + // } + + ma_engine_uninit(&miniaudio_engine); +} + int S3DisposeDescriptor(tS3_sound_id id) { tS3_channel* c; // [esp+Ch] [ebp-10h] tS3_outlet* o; // [esp+10h] [ebp-Ch] @@ -522,6 +598,16 @@ int S3UnbindChannels(tS3_outlet* outlet) { return 1; } +void S3DisposeUnboundChannels() { + tS3_channel* channel; // [esp+Ch] [ebp-8h] + tS3_channel* next_channel; // [esp+10h] [ebp-4h] + + for (channel = gS3_unbound_channels; channel != NULL; channel = next_channel) { + next_channel = channel->next; + S3MemFree(channel); + } +} + tS3_channel* S3AllocateChannel(tS3_outlet* outlet, int priority) { tS3_channel* c; // [esp+Ch] [ebp-10h] int lowest_priority; // [esp+10h] [ebp-Ch] MAPDST diff --git a/src/S3/audio.h b/src/S3/audio.h index 82f5bec2..e875210d 100644 --- a/src/S3/audio.h +++ b/src/S3/audio.h @@ -18,10 +18,15 @@ void S3Disable(); int S3OpenOutputDevices(); int S3OpenSampleDevice(); +int S3OpenCDADevice(); + +int S3OpenSampleDevice(); +void S3CloseDevices(); tS3_outlet* S3CreateOutlet(int unk1, int pChannel_count); int S3CreateOutletChannels(tS3_outlet* outlet, int pChannel_count); void S3DisposeOutlet(tS3_outlet* outlet); int S3UnbindChannels(tS3_outlet* outlet); +void S3DisposeUnboundChannels(); tS3_channel* S3AllocateChannel(tS3_outlet* outlet, int priority); int S3StopChannel(tS3_channel* chan); diff --git a/src/S3/include/s3/s3.h b/src/S3/include/s3/s3.h index 4abdd319..8ad56cf8 100644 --- a/src/S3/include/s3/s3.h +++ b/src/S3/include/s3/s3.h @@ -25,6 +25,7 @@ typedef struct tS3_vector3 { } tS3_vector3; int S3Init(char* path, int low_memory_mode); +void S3Shutdown(); void S3Disable(); void S3Enable(); diff --git a/src/S3/s3cda.c b/src/S3/s3cda.c index aaf09134..ec13b96c 100644 --- a/src/S3/s3cda.c +++ b/src/S3/s3cda.c @@ -12,20 +12,6 @@ void S3StopCDAOutlets() { STUB(); } -int S3OpenCDADevice() { - // gS3_cda_device.lpstrDeviceType = (LPCSTR)516; - // if (mciSendCommandA(0, 0x803u, 0x3000u, (DWORD_PTR)&gS3_cda_device) - // && mciSendCommandA(0, 0x803u, 0x3100u, (DWORD_PTR)&gS3_cda_device)) { - // return 0; - // } - // stru_550560.dwTimeFormat = 10; // MCI_FORMAT_TMSF - // mciSendCommandA(gS3_cda_device.wDeviceID, 0x80Du, 0x400u, (DWORD_PTR)&stru_550560); - // S3CDAEnable(); - // return 1; - - return 0; -} - int S3PlayCDA(tS3_channel* chan) { return 0; } @@ -48,4 +34,4 @@ int S3IsCDAPlaying() { int S3IsCDAPlaying2() { return S3IsCDAPlaying(); -} \ No newline at end of file +} diff --git a/src/S3/s3cda.h b/src/S3/s3cda.h index 58e791fd..d88216c8 100644 --- a/src/S3/s3cda.h +++ b/src/S3/s3cda.h @@ -5,7 +5,6 @@ void S3DisableCDA(); void S3StopCDAOutlets(); -int S3OpenCDADevice(); int S3PlayCDA(tS3_channel* chan); int S3StopCDA(tS3_channel* chan); diff --git a/src/S3/s3sound.c b/src/S3/s3sound.c index 7b2f4bad..452ad200 100644 --- a/src/S3/s3sound.c +++ b/src/S3/s3sound.c @@ -1,9 +1,8 @@ #include "s3sound.h" #include "audio.h" -#include "harness/config.h" +#include "harness/trace.h" #include "miniaudio/miniaudio.h" #include "resource.h" -#include "harness/trace.h" #include #include #include @@ -14,28 +13,9 @@ int gS3_sample_filter_funcs_registered; tS3_sample_filter* gS3_sample_filter_func; tS3_sample_filter* gS3_sample_filter_disable_func; -ma_engine engine; +// dethrace +extern ma_engine miniaudio_engine; -int S3OpenSampleDevice() { - ma_result result; - - ma_engine_config engineConfig; - engineConfig = ma_engine_config_init(); - engineConfig.sampleRate = 22050; - - result = ma_engine_init(&engineConfig, &engine); - if (result != MA_SUCCESS) { - printf("Failed to initialize audio engine."); - return 0; - } - - ma_engine_set_volume(&engine, harness_game_config.volume_multiplier); - - S3Enable(); - return 1; -} - -// Returns 0 if no error int S3LoadSample(tS3_sound_id id) { // LPDIRECTSOUNDBUFFER WavFile; // eax char filename[MAX_PATH_LENGTH]; // [esp+10h] [ebp-5Ch] BYREF @@ -189,7 +169,7 @@ void* S3LoadWavFile(char* pFile_name, tS3_sample* pSample) { ma_sound* sound = malloc(sizeof(ma_sound)); // TOOD: load from memory - we've already read the file data - if (ma_sound_init_from_file(&engine, pFile_name, MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_NO_SPATIALIZATION, NULL, NULL, sound) != MA_SUCCESS) { + if (ma_sound_init_from_file(&miniaudio_engine, pFile_name, MA_SOUND_FLAG_DECODE | MA_SOUND_FLAG_NO_SPATIALIZATION, NULL, NULL, sound) != MA_SUCCESS) { return NULL; // Failed to load sound. } S3MemFree(buf); diff --git a/src/S3/s3sound.h b/src/S3/s3sound.h index 37456fc3..f43ac73d 100644 --- a/src/S3/s3sound.h +++ b/src/S3/s3sound.h @@ -7,7 +7,6 @@ extern int gS3_sample_filter_funcs_registered; extern tS3_sample_filter* gS3_sample_filter_func; extern tS3_sample_filter* gS3_sample_filter_disable_func; -int S3OpenSampleDevice(); int S3LoadSample(tS3_sound_id id); void* S3LoadWavFile(char* pFile_name, tS3_sample* pSample); int S3PlaySample(tS3_channel* chan); @@ -18,4 +17,4 @@ int S3ExecuteSampleFilterFuncs(tS3_channel* chan); int S3SyncSampleVolume(tS3_channel* chan); int S3SyncSampleRate(tS3_channel* chan); -#endif \ No newline at end of file +#endif diff --git a/src/harness/harness.c b/src/harness/harness.c index 25556841..4ce35a5d 100644 --- a/src/harness/harness.c +++ b/src/harness/harness.c @@ -219,12 +219,11 @@ void Harness_Init(int* argc, char* argv[]) { Harness_DetectGameMode(); } - Input_Init(); - int* keymap = Input_GetKeyMap(); + IOPlatform_Init(); + int* keymap = IOPlatform_GetKeyMap(); if (keymap != NULL) { for (int i = 0; i < 123; i++) { gScan_code[i][0] = keymap[i]; - // gScan_code[i][1] = keymap[i]; } } } @@ -314,7 +313,11 @@ void Harness_Hook_GraphicsInit(int render_width, int render_height) { window_width = render_width; window_height = render_height; } - renderer = Window_Create("Dethrace", window_width, window_height, render_width, render_height); + renderer = IOPlatform_CreateWindow("Dethrace", window_width, window_height, render_width, render_height); +} + +void Harness_Hook_PDShutdownSystem() { + IOPlatform_Shutdown(); } // Render 2d back buffer @@ -331,7 +334,7 @@ void Harness_Hook_BrDevPaletteSetOld(br_pixelmap* pm) { if (last_dst) { Harness_RenderScreen(last_dst, last_src); - Window_Swap(0); + IOPlatform_SwapWindow(0); } } @@ -388,23 +391,23 @@ void Harness_Hook_BrPixelmapDoubleBuffer(br_pixelmap* dst, br_pixelmap* src) { Harness_RenderScreen(dst, src); int delay_ms = Harness_CalculateFrameDelay(); - Window_Swap(delay_ms); + IOPlatform_SwapWindow(delay_ms); renderer->ClearBuffers(); - Window_PollEvents(); + IOPlatform_PollEvents(); last_frame_time = GetTotalTime(); } int Harness_Hook_KeyDown(unsigned char pScan_code) { - return Input_IsKeyDown(pScan_code); + return IOPlatform_IsKeyDown(pScan_code); } void Harness_Hook_PDServiceSystem() { - Window_PollEvents(); + IOPlatform_PollEvents(); } void Harness_Hook_PDSetKeyArray() { - Window_PollEvents(); + IOPlatform_PollEvents(); } void Harness_Hook_FlushRenderer() { @@ -429,11 +432,11 @@ void Harness_Hook_BrModelUpdate(br_model* model) { // Input hooks void Harness_Hook_GetMousePosition(int* pX, int* pY) { - Input_GetMousePosition(pX, pY); + IOPlatform_GetMousePosition(pX, pY); } void Harness_Hook_GetMouseButtons(int* pButton1, int* pButton2) { - Input_GetMouseButtons(pButton1, pButton2); + IOPlatform_GetMouseButtons(pButton1, pButton2); } // Sound hooks diff --git a/src/harness/include/harness/hooks.h b/src/harness/include/harness/hooks.h index 7546155c..c66e46fc 100644 --- a/src/harness/include/harness/hooks.h +++ b/src/harness/include/harness/hooks.h @@ -16,6 +16,7 @@ void Harness_Hook_PDSetKeyArray(); // void Harness_Hook_MainGameLoop(); // limit FPS void Harness_Hook_FlushRenderer(); // synchronize in-memory framebuffer and depthbuffer void Harness_Hook_GraphicsInit(int render_width, int render_height); +void Harness_Hook_PDShutdownSystem(); // BRender hooks void Harness_Hook_BrDevPaletteSetOld(br_pixelmap* pm); diff --git a/src/harness/io_platforms/io_platform.h b/src/harness/io_platforms/io_platform.h index 22219714..68ed7e79 100644 --- a/src/harness/io_platforms/io_platform.h +++ b/src/harness/io_platforms/io_platform.h @@ -3,14 +3,14 @@ #include "../renderers/renderer.h" -tRenderer* Window_Create(char* title, int width, int height, int pRender_width, int pRender_height); -void Window_PollEvents(void); -void Window_Swap(int delay_ms_after_swap); - -void Input_Init(); -int* Input_GetKeyMap(void); -int Input_IsKeyDown(unsigned char scan_code); -void Input_GetMousePosition(int* pX, int* pY); -void Input_GetMouseButtons(int* pButton1, int* pButton2); +void IOPlatform_Init(); +tRenderer* IOPlatform_CreateWindow(char* title, int width, int height, int pRender_width, int pRender_height); +void IOPlatform_PollEvents(void); +void IOPlatform_SwapWindow(int delay_ms_after_swap); +int* IOPlatform_GetKeyMap(void); +int IOPlatform_IsKeyDown(unsigned char scan_code); +void IOPlatform_GetMousePosition(int* pX, int* pY); +void IOPlatform_GetMouseButtons(int* pButton1, int* pButton2); +void IOPlatform_Shutdown(); #endif diff --git a/src/harness/io_platforms/sdl_gl.c b/src/harness/io_platforms/sdl_gl.c index eebefdc3..ba62fdc1 100644 --- a/src/harness/io_platforms/sdl_gl.c +++ b/src/harness/io_platforms/sdl_gl.c @@ -14,6 +14,8 @@ #include "grafdata.h" #include "pd/sys.h" +extern void QuitGame(); + #define ARRAY_LEN(array) (sizeof((array)) / sizeof((array)[0])) int scancode_map[123]; @@ -154,7 +156,7 @@ tRenderer gl_renderer = { GLRenderer_GetViewport }; -tRenderer* Window_Create(char* title, int width, int height, int pRender_width, int pRender_height) { +tRenderer* IOPlatform_CreateWindow(char* title, int width, int height, int pRender_width, int pRender_height) { if (SDL_Init(SDL_INIT_VIDEO) != 0) { LOG_PANIC("SDL_INIT_VIDEO error: %s", SDL_GetError()); } @@ -201,13 +203,20 @@ tRenderer* Window_Create(char* title, int width, int height, int pRender_width, return &gl_renderer; } +void IOPlatform_Shutdown() { + SDL_GL_DeleteContext(context); + SDL_DestroyWindow(window); + SDL_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(int modifier_flags, int flag_check) { return (modifier_flags & flag_check) && (modifier_flags & (KMOD_CTRL | KMOD_SHIFT | KMOD_ALT | KMOD_GUI)) == (modifier_flags & flag_check); } -void Window_PollEvents() { +void IOPlatform_PollEvents() { SDL_Event event; int dethrace_key; int w_w, w_h; @@ -257,13 +266,13 @@ void Window_PollEvents() { } break; case SDL_QUIT: - LOG_PANIC("QuitGame"); + QuitGame(); break; } } } -void Window_Swap(int delay_ms_after_swap) { +void IOPlatform_SwapWindow(int delay_ms_after_swap) { SDL_GL_SwapWindow(window); if (delay_ms_after_swap != 0) { @@ -271,7 +280,7 @@ void Window_Swap(int delay_ms_after_swap) { } } -void Input_Init() { +void IOPlatform_Init() { for (size_t i = 0; i < ARRAY_LEN(scancodes_sdl2dethrace); i++) { scancodes_sdl2dethrace[i] = -1; } @@ -285,15 +294,15 @@ void Input_Init() { } } -int* Input_GetKeyMap() { +int* IOPlatform_GetKeyMap() { return (int*)scancode_map; } -int Input_IsKeyDown(unsigned char scan_code) { +int IOPlatform_IsKeyDown(unsigned char scan_code) { return sdl_key_state[scan_code]; } -void Input_GetMousePosition(int* pX, int* pY) { +void IOPlatform_GetMousePosition(int* pX, int* pY) { int vp_x, vp_y, vp_w, vp_h; SDL_GetMouseState(pX, pY); @@ -323,7 +332,7 @@ void Input_GetMousePosition(int* pX, int* pY) { #endif } -void Input_GetMouseButtons(int* pButton1, int* pButton2) { +void IOPlatform_GetMouseButtons(int* pButton1, int* pButton2) { int state = SDL_GetMouseState(NULL, NULL); *pButton1 = state & SDL_BUTTON_LMASK; *pButton2 = state & SDL_BUTTON_RMASK;