Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MorsGames
GitHub Repository: MorsGames/sm64plus
Path: blob/master/src/pc/pc_main.c
7857 views
1
#include <stdlib.h>
2
#include <stdio.h>
3
#include <string.h>
4
#include <unistd.h>
5
#ifdef __linux__
6
#include <pwd.h>
7
#elif defined(_WIN32) || defined(_WIN64)
8
#include <windows.h>
9
#include <dirent.h>
10
#endif
11
12
#ifdef TARGET_WEB
13
#include <emscripten.h>
14
#include <emscripten/html5.h>
15
#endif
16
17
#include "sm64.h"
18
19
#include "game/memory.h"
20
#include "audio/external.h"
21
22
#include "gfx/gfx_pc.h"
23
#include "gfx/gfx_opengl.h"
24
#include "gfx/gfx_sdl.h"
25
#include "gfx/gfx_dummy.h"
26
27
#include "audio/audio_api.h"
28
#include "audio/audio_sdl.h"
29
#include "audio/audio_null.h"
30
31
#include "controller/controller_keyboard.h"
32
33
#include "game/hud.h"
34
#include "configfile.h"
35
36
#include "game/rumble_init.h"
37
#include "game/settings.h"
38
#include "colors.h"
39
40
#include "compat.h"
41
42
#define CONFIG_FILE "settings.ini"
43
44
OSMesg gMainReceivedMesg;
45
OSMesgQueue gSIEventMesgQueue;
46
47
s8 gResetTimer;
48
s8 gNmiResetBarsTimer;
49
s8 gDebugLevelSelect;
50
s8 gShowProfiler;
51
s8 gShowDebugText;
52
53
static struct AudioAPI *audio_api;
54
static struct GfxWindowManagerAPI *wm_api;
55
static struct GfxRenderingAPI *rendering_api;
56
57
extern void gfx_run(Gfx *commands);
58
extern void thread5_game_loop(void *arg);
59
extern void create_next_audio_buffer(s16 *samples, u32 num_samples);
60
void game_loop_one_iteration(void);
61
62
void dispatch_audio_sptask(UNUSED struct SPTask *spTask) {
63
}
64
65
void set_vblank_handler(UNUSED s32 index, UNUSED struct VblankHandler *handler, UNUSED OSMesgQueue *queue, UNUSED OSMesg *msg) {
66
}
67
68
static uint8_t inited = 0;
69
70
#include "game/game_init.h" // for gGlobalTimer
71
void exec_display_list(struct SPTask *spTask) {
72
if (!inited) {
73
return;
74
}
75
gfx_run((Gfx *)spTask->task.t.data_ptr);
76
}
77
78
#define printf
79
80
#ifdef VERSION_EU
81
#define SAMPLES_HIGH 656
82
#define SAMPLES_LOW 640
83
#else
84
#define SAMPLES_HIGH 544
85
#define SAMPLES_LOW 528
86
#endif
87
88
static void patch_interpolations(void) {
89
extern void mtx_patch_interpolated(void);
90
extern void patch_screen_transition_interpolated(void);
91
extern void patch_title_screen_scales(void);
92
extern void patch_interpolated_dialog(void);
93
extern void patch_interpolated_hud(void);
94
extern void patch_interpolated_paintings(void);
95
extern void patch_interpolated_bubble_particles(void);
96
extern void patch_interpolated_snow_particles(void);
97
mtx_patch_interpolated();
98
patch_screen_transition_interpolated();
99
patch_title_screen_scales();
100
patch_interpolated_dialog();
101
patch_interpolated_hud();
102
103
if (configStayInCourse)
104
render_you_got_a_star(1);
105
106
patch_interpolated_paintings();
107
patch_interpolated_bubble_particles();
108
patch_interpolated_snow_particles();
109
}
110
111
static void submit_audio_frame(void) {
112
int samples_left = audio_api->buffered();
113
u32 num_audio_samples = samples_left < audio_api->get_desired_buffered() ? SAMPLES_HIGH : SAMPLES_LOW;
114
s16 audio_buffer[SAMPLES_HIGH * 2 * 2];
115
116
for (int i = 0; i < 2; i++) {
117
create_next_audio_buffer(audio_buffer + i * (num_audio_samples * 2), num_audio_samples);
118
}
119
120
audio_api->play((u8 *)audio_buffer, 2 * num_audio_samples * 4);
121
}
122
123
void produce_one_frame(void) {
124
gfx_start_frame();
125
game_loop_one_iteration();
126
127
#if ENABLE_RUMBLE
128
thread6_rumble_loop(NULL);
129
#endif
130
131
submit_audio_frame();
132
133
gfx_end_frame();
134
135
gfx_start_frame();
136
if (configFrameRate) {
137
patch_interpolations();
138
}
139
else if (configStayInCourse) {
140
render_you_got_a_star(3);
141
}
142
exec_display_list(gGfxSPTask);
143
gfx_end_frame();
144
}
145
146
#ifdef TARGET_WEB
147
static void em_main_loop(void) {
148
}
149
150
static void request_anim_frame(void (*func)(double time)) {
151
EM_ASM(requestAnimationFrame(function(time) {
152
dynCall("vd", $0, [time]);
153
}), func);
154
}
155
156
static void on_anim_frame(double time) {
157
static double target_time;
158
159
time *= 0.03; // milliseconds to frame count (33.333 ms -> 1)
160
161
if (time >= target_time + 10.0) {
162
// We are lagging 10 frames behind, probably due to coming back after inactivity,
163
// so reset, with a small margin to avoid potential jitter later.
164
target_time = time - 0.010;
165
}
166
167
for (int i = 0; i < 2; i++) {
168
// If refresh rate is 15 Hz or something we might need to generate two frames
169
if (time >= target_time) {
170
produce_one_frame();
171
target_time = target_time + 1.0;
172
}
173
}
174
175
request_anim_frame(on_anim_frame);
176
}
177
#endif
178
179
static void save_config(void) {
180
configfile_save(CONFIG_FILE);
181
}
182
183
static void on_fullscreen_changed(bool is_now_fullscreen) {
184
configFullscreen = is_now_fullscreen;
185
}
186
187
// used primarily in gfx_pc.c
188
const char* GFX_DIR_PATH = NULL;
189
190
void main_func(const char* gfx_dir) {
191
GFX_DIR_PATH = gfx_dir;
192
#ifdef USE_SYSTEM_MALLOC
193
main_pool_init();
194
gGfxAllocOnlyPool = alloc_only_pool_init();
195
#else
196
static u64 pool[0x165000/8 / 4 * sizeof(void *)];
197
main_pool_init(pool, pool + sizeof(pool) / sizeof(pool[0]));
198
#endif
199
gEffectsMemoryPool = mem_pool_init(0x4000, MEMORY_POOL_LEFT);
200
201
#if defined(_WIN32) || defined(_WIN64)
202
// Set the working directory
203
char *workingdir = malloc(128);
204
strcpy(workingdir, getenv("LOCALAPPDATA"));
205
strcat(workingdir, "\\SM64Plus\\");
206
chdir(workingdir);
207
#endif
208
#ifdef TARGET_LINUX
209
// Set the working directory
210
char *workingdir = malloc(128);
211
const char *homedir;
212
if ((homedir = getenv("HOME")) == NULL) {
213
homedir = getpwuid(getuid())->pw_dir;
214
}
215
strcpy(workingdir, homedir);
216
strcat(workingdir, "/.config/SM64Plus/");
217
chdir(workingdir);
218
#endif
219
220
// Check if the textures exist
221
#if defined(CUSTOM_TEXTURES) && (defined(_WIN32) || defined(_WIN64))
222
DIR* dir = opendir("gfx");
223
if (dir) {
224
closedir(dir);
225
}
226
else {
227
MessageBox(0, "Failed to find the \"gfx\" folder in \"%LOCALAPPDATA%\\SM64Plus\". If you're using the launcher, try reinstalling the game. If not, copy the folder from \"build\\us_pc\".", "ERROR", MB_ICONERROR);
228
exit(1);
229
}
230
231
#endif
232
233
configfile_load(CONFIG_FILE);
234
235
// Set the custom colors
236
set_colors();
237
238
atexit(save_config);
239
240
#ifdef TARGET_WEB
241
emscripten_set_main_loop(em_main_loop, 0, 0);
242
request_anim_frame(on_anim_frame);
243
#endif
244
245
rendering_api = &gfx_opengl_api;
246
wm_api = &gfx_sdl;
247
gfx_init(wm_api, rendering_api, gTitleString, configFullscreen);
248
249
wm_api->set_fullscreen_changed_callback(on_fullscreen_changed);
250
wm_api->set_keyboard_callbacks(keyboard_on_key_down, keyboard_on_key_up, keyboard_on_all_keys_up, keyboard_on_mouse_move, keyboard_on_mouse_press);
251
252
if (audio_sdl.init()) {
253
audio_api = &audio_sdl;
254
}
255
else {
256
audio_api = &audio_null;
257
}
258
259
audio_init();
260
sound_init();
261
262
thread5_game_loop(NULL);
263
#ifdef TARGET_WEB
264
/*for (int i = 0; i < atoi(argv[1]); i++) {
265
game_loop_one_iteration();
266
}*/
267
inited = 1;
268
#else
269
inited = 1;
270
while (1) {
271
wm_api->main_loop(produce_one_frame);
272
}
273
#endif
274
}
275
276
#if defined(_WIN32) || defined(_WIN64)
277
#include <stdbool.h>
278
int WINAPI WinMain(UNUSED HINSTANCE hInstance, UNUSED HINSTANCE hPrevInstance, UNUSED LPSTR pCmdLine, UNUSED int nCmdShow) {
279
AttachConsole(ATTACH_PARENT_PROCESS);
280
281
FILE *fp;
282
freopen_s(&fp, "CONOUT$", "w", stdout);
283
freopen_s(&fp, "CONOUT$", "w", stderr);
284
freopen_s(&fp, "CONIN$", "r", stdin);
285
286
main_func(NULL);
287
288
return 0;
289
}
290
#else
291
int main(int argc, const char *argv[]) {
292
main_func(argc > 1 ? argv[1] : NULL);
293
return 0;
294
}
295
#endif
296