233 lines
5.8 KiB
C
233 lines
5.8 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_direct3d11.h"
|
|
#include "gfx/gfx_direct3d12.h"
|
|
#include "gfx/gfx_dxgi.h"
|
|
#include "gfx/gfx_glx.h"
|
|
#include "gfx/gfx_sdl.h"
|
|
#include "gfx/gfx_dummy.h"
|
|
#include "gfx/gfx_vulkan.h"
|
|
|
|
#include "audio/audio_api.h"
|
|
#include "audio/audio_wasapi.h"
|
|
#include "audio/audio_pulse.h"
|
|
#include "audio/audio_alsa.h"
|
|
#include "audio/audio_sdl.h"
|
|
#include "audio/audio_null.h"
|
|
|
|
#include "controller/controller_keyboard.h"
|
|
|
|
#include "configfile.h"
|
|
|
|
#include "compat.h"
|
|
|
|
#define CONFIG_FILE "sm64config.txt"
|
|
|
|
OSMesg gMainReceivedMesg;
|
|
OSMesgQueue gSIEventMesgQueue;
|
|
|
|
s8 gResetTimer;
|
|
s8 gNmiResetBarsTimer;
|
|
s8 gDebugLevelSelect;
|
|
s8 gShowProfiler;
|
|
s8 gShowDebugText;
|
|
|
|
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(UNUSED struct SPTask *spTask) {
|
|
}
|
|
|
|
void set_vblank_handler(UNUSED s32 index, UNUSED struct VblankHandler *handler, UNUSED OSMesgQueue *queue, UNUSED OSMesg *msg) {
|
|
}
|
|
|
|
static uint8_t inited = 0;
|
|
|
|
#include "game/game_init.h" // for gGlobalTimer
|
|
void exec_display_list(struct SPTask *spTask) {
|
|
if (!inited) {
|
|
return;
|
|
}
|
|
gfx_run((Gfx *)spTask->task.t.data_ptr);
|
|
}
|
|
|
|
#define printf
|
|
|
|
#ifdef VERSION_EU
|
|
#define SAMPLES_HIGH 656
|
|
#define SAMPLES_LOW 640
|
|
#else
|
|
#define SAMPLES_HIGH 544
|
|
#define SAMPLES_LOW 528
|
|
#endif
|
|
|
|
void produce_one_frame(void) {
|
|
gfx_start_frame();
|
|
game_loop_one_iteration();
|
|
|
|
int samples_left = audio_api->buffered();
|
|
u32 num_audio_samples = samples_left < audio_api->get_desired_buffered() ? SAMPLES_HIGH : SAMPLES_LOW;
|
|
//printf("Audio samples: %d %u\n", samples_left, num_audio_samples);
|
|
s16 audio_buffer[SAMPLES_HIGH * 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());
|
|
audio_api->play((u8 *)audio_buffer, 2 * num_audio_samples * 4);
|
|
|
|
gfx_end_frame();
|
|
}
|
|
|
|
#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;
|
|
}
|
|
}
|
|
|
|
request_anim_frame(on_anim_frame);
|
|
}
|
|
#endif
|
|
|
|
static void save_config(void) {
|
|
configfile_save(CONFIG_FILE);
|
|
}
|
|
|
|
static void on_fullscreen_changed(bool is_now_fullscreen) {
|
|
configFullscreen = is_now_fullscreen;
|
|
}
|
|
|
|
void main_func(void) {
|
|
#ifdef USE_SYSTEM_MALLOC
|
|
main_pool_init();
|
|
gGfxAllocOnlyPool = alloc_only_pool_init();
|
|
#else
|
|
static u64 pool[0x165000/8 / 4 * sizeof(void *)];
|
|
main_pool_init(pool, pool + sizeof(pool) / sizeof(pool[0]));
|
|
#endif
|
|
gEffectsMemoryPool = mem_pool_init(0x4000, MEMORY_POOL_LEFT);
|
|
|
|
configfile_load(CONFIG_FILE);
|
|
atexit(save_config);
|
|
|
|
#ifdef TARGET_WEB
|
|
emscripten_set_main_loop(em_main_loop, 0, 0);
|
|
request_anim_frame(on_anim_frame);
|
|
#endif
|
|
|
|
#if defined(ENABLE_DX12)
|
|
rendering_api = &gfx_direct3d12_api;
|
|
wm_api = &gfx_dxgi_api;
|
|
#elif defined(ENABLE_DX11)
|
|
rendering_api = &gfx_direct3d11_api;
|
|
wm_api = &gfx_dxgi_api;
|
|
#elif defined(ENABLE_OPENGL)
|
|
rendering_api = &gfx_opengl_api;
|
|
wm_api = &gfx_sdl;
|
|
#elif defined(ENABLE_GFX_DUMMY)
|
|
rendering_api = &gfx_dummy_renderer_api;
|
|
wm_api = &gfx_dummy_wm_api;
|
|
#endif
|
|
|
|
gfx_init(wm_api, rendering_api, "Super Mario 64 PC-Port", configFullscreen);
|
|
|
|
wm_api->set_fullscreen_changed_callback(on_fullscreen_changed);
|
|
wm_api->set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up);
|
|
|
|
#if HAVE_WASAPI
|
|
if (audio_api == NULL && audio_wasapi.init()) {
|
|
audio_api = &audio_wasapi;
|
|
}
|
|
#endif
|
|
#if HAVE_PULSE_AUDIO
|
|
if (audio_api == NULL && audio_pulse.init()) {
|
|
audio_api = &audio_pulse;
|
|
}
|
|
#endif
|
|
#if HAVE_ALSA
|
|
if (audio_api == NULL && audio_alsa.init()) {
|
|
audio_api = &audio_alsa;
|
|
}
|
|
#endif
|
|
#ifdef TARGET_WEB
|
|
if (audio_api == NULL && audio_sdl.init()) {
|
|
audio_api = &audio_sdl;
|
|
}
|
|
#endif
|
|
if (audio_api == NULL) {
|
|
audio_api = &audio_null;
|
|
}
|
|
|
|
audio_init();
|
|
sound_init();
|
|
|
|
thread5_game_loop(NULL);
|
|
#ifdef TARGET_WEB
|
|
/*for (int i = 0; i < atoi(argv[1]); i++) {
|
|
game_loop_one_iteration();
|
|
}*/
|
|
inited = 1;
|
|
#else
|
|
inited = 1;
|
|
while (1) {
|
|
wm_api->main_loop(produce_one_frame);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if defined(_WIN32) || defined(_WIN64)
|
|
#include <windows.h>
|
|
int WINAPI WinMain(UNUSED HINSTANCE hInstance, UNUSED HINSTANCE hPrevInstance, UNUSED LPSTR pCmdLine, UNUSED int nCmdShow) {
|
|
main_func();
|
|
return 0;
|
|
}
|
|
#else
|
|
int main(UNUSED int argc, UNUSED char *argv[]) {
|
|
main_func();
|
|
return 0;
|
|
}
|
|
#endif
|