Implements quitgame function (#294)

* implements quitgame function

* updates IOPlatform_* function names
This commit is contained in:
Dethrace Engineering Department 2023-04-01 15:40:40 +13:00 committed by GitHub
parent 2bdfa07550
commit 3a91a526c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 182 additions and 82 deletions

View File

@ -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

View File

@ -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)

View File

@ -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@<EAX>(tS3_outlet_ptr pOutlet@<EAX>, tS3_volume pVolume@<EDX>)

View File

@ -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@<EAX>(int pArgc@<EAX>, char **pArgv@<EDX>)

View File

@ -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

View File

@ -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);

View File

@ -25,6 +25,7 @@ typedef struct tS3_vector3 {
} tS3_vector3;
int S3Init(char* path, int low_memory_mode);
void S3Shutdown();
void S3Disable();
void S3Enable();

View File

@ -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();
}
}

View File

@ -5,7 +5,6 @@
void S3DisableCDA();
void S3StopCDAOutlets();
int S3OpenCDADevice();
int S3PlayCDA(tS3_channel* chan);
int S3StopCDA(tS3_channel* chan);

View File

@ -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 <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -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);

View File

@ -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
#endif

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;