sm64pc/src/pc/pc_main.c

192 lines
4.6 KiB
C

#include <stdlib.h>
#ifdef TARGET_WEB
#include <emscripten.h>
#include <emscripten/html5.h>
#endif
#include "sm64.h"
#include "game/memory.h"
#include "audio/external.h"
#include "gfx/gfx_pc.h"
#include "gfx/gfx_opengl.h"
#include "gfx/gfx_sdl.h"
#include "audio/audio_api.h"
#include "audio/audio_sdl.h"
#include "audio/audio_null.h"
#include "pc_main.h"
#include "cliopts.h"
#include "configfile.h"
#include "controller/controller_api.h"
#include "fs/fs.h"
#include "game/main.h"
#include "game/thread6.h"
OSMesg D_80339BEC;
OSMesgQueue gSIEventMesgQueue;
s8 gResetTimer;
s8 D_8032C648;
s8 gDebugLevelSelect;
s8 gShowProfiler;
s8 gShowDebugText;
s32 gRumblePakPfs;
struct RumbleData gRumbleDataQueue[3];
struct StructSH8031D9B0 gCurrRumbleSettings;
static struct AudioAPI *audio_api;
static struct GfxWindowManagerAPI *wm_api;
static struct GfxRenderingAPI *rendering_api;
extern void gfx_run(Gfx *commands);
extern void thread5_game_loop(void *arg);
extern void create_next_audio_buffer(s16 *samples, u32 num_samples);
void game_loop_one_iteration(void);
void dispatch_audio_sptask(struct SPTask *spTask) {
}
void set_vblank_handler(s32 index, struct VblankHandler *handler, OSMesgQueue *queue, OSMesg *msg) {
}
static bool inited = false;
#include "game/display.h" // for gGlobalTimer
void send_display_list(struct SPTask *spTask) {
if (!inited) return;
gfx_run((Gfx *)spTask->task.t.data_ptr);
}
#define printf
void produce_one_frame(void) {
gfx_start_frame();
game_loop_one_iteration();
thread6_rumble_loop(NULL);
int samples_left = audio_api->buffered();
u32 num_audio_samples = samples_left < audio_api->get_desired_buffered() ? 544 : 528;
//printf("Audio samples: %d %u\n", samples_left, num_audio_samples);
s16 audio_buffer[544 * 2 * 2];
for (int i = 0; i < 2; i++) {
/*if (audio_cnt-- == 0) {
audio_cnt = 2;
}
u32 num_audio_samples = audio_cnt < 2 ? 528 : 544;*/
create_next_audio_buffer(audio_buffer + i * (num_audio_samples * 2), num_audio_samples);
}
//printf("Audio samples before submitting: %d\n", audio_api->buffered());
// scale by master volume (0-127)
const s32 mod = (s32)configMasterVolume;
for (u32 i = 0; i < num_audio_samples * 4; ++i)
audio_buffer[i] = ((s32)audio_buffer[i] * mod) >> VOLUME_SHIFT;
audio_api->play((u8*)audio_buffer, 2 * num_audio_samples * 4);
gfx_end_frame();
}
void audio_shutdown(void) {
if (audio_api) {
if (audio_api->shutdown) audio_api->shutdown();
audio_api = NULL;
}
}
void game_deinit(void) {
configfile_save(configfile_name());
controller_shutdown();
audio_shutdown();
gfx_shutdown();
inited = false;
}
void game_exit(void) {
game_deinit();
#ifndef TARGET_WEB
exit(0);
#endif
}
#ifdef TARGET_WEB
static void em_main_loop(void) {
}
static void request_anim_frame(void (*func)(double time)) {
EM_ASM(requestAnimationFrame(function(time) {
dynCall("vd", $0, [time]);
}), func);
}
static void on_anim_frame(double time) {
static double target_time;
time *= 0.03; // milliseconds to frame count (33.333 ms -> 1)
if (time >= target_time + 10.0) {
// We are lagging 10 frames behind, probably due to coming back after inactivity,
// so reset, with a small margin to avoid potential jitter later.
target_time = time - 0.010;
}
for (int i = 0; i < 2; i++) {
// If refresh rate is 15 Hz or something we might need to generate two frames
if (time >= target_time) {
produce_one_frame();
target_time = target_time + 1.0;
}
}
if (inited) // only continue if the init flag is still set
request_anim_frame(on_anim_frame);
}
#endif
void main_func(void) {
static u64 pool[0x165000/8 / 4 * sizeof(void *)];
main_pool_init(pool, pool + sizeof(pool) / sizeof(pool[0]));
gEffectsMemoryPool = mem_pool_init(0x4000, MEMORY_POOL_LEFT);
fs_init(sys_ropaths, FS_BASEDIR, sys_user_path());
configfile_load(configfile_name());
wm_api = &gfx_sdl;
rendering_api = &gfx_opengl_api;
gfx_init(wm_api, rendering_api);
if (audio_api == NULL && audio_sdl.init())
audio_api = &audio_sdl;
if (audio_api == NULL) {
audio_api = &audio_null;
}
audio_init();
sound_init();
thread5_game_loop(NULL);
inited = true;
#ifdef TARGET_WEB
emscripten_set_main_loop(em_main_loop, 0, 0);
request_anim_frame(on_anim_frame);
#else
wm_api->main_loop(produce_one_frame);
#endif
}
int main(int argc, char *argv[]) {
parse_cli_opts(argc, argv);
main_func();
return 0;
}