-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.cpp
148 lines (119 loc) · 3.5 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#include <cstdlib>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <emscripten/html5.h>
#endif
#include "frontend.h"
#ifdef __EMSCRIPTEN__
static double next_time;
static double time_delta;
static void Terminate()
{
Frontend::Deinitialise();
emscripten_cancel_main_loop();
// Deinitialise persistent storage.
EM_ASM({
FS.syncfs(false, function (err) {});
}, 0);
}
static void FrameRateCallback(const bool pal_mode)
{
time_delta = pal_mode ? Frontend::DivideByPALFramerate(1000.0) : Frontend::DivideByNTSCFramerate(1000.0);
}
static int EventFilter(void* /*const userdata*/, SDL_Event* const event)
{
// The event loop will never have time to catch this, so we
// must use this callback to intercept it as soon as possible.
if (event->type == SDL_APP_TERMINATING)
Terminate();
return 0;
}
extern "C" EMSCRIPTEN_KEEPALIVE void StorageLoaded()
{
const auto callback = []()
{
const double current_time = emscripten_get_now();
if (current_time >= next_time)
{
// If massively delayed, resynchronise to avoid fast-forwarding.
if (current_time >= next_time + 100.0)
next_time = current_time;
next_time += time_delta / (Frontend::IsFastForwarding() ? 4 : 1);
SDL_Event event;
while (SDL_PollEvent(&event))
Frontend::HandleEvent(event);
Frontend::Update();
if (Frontend::WantsToQuit())
Terminate();
}
};
next_time = emscripten_get_now();
emscripten_set_main_loop(callback, 0, 0);
if (Frontend::Initialise(0, nullptr, FrameRateCallback))
SDL_AddEventWatch(EventFilter, nullptr);
}
#else
// 300 is the magic number that prevents the frame delta calculations from ever dipping into
// numbers smaller than 1 (technically it's only required by the NTSC framerate: PAL doesn't need it).
#define FRAME_DELTA_MULTIPLIER 300
static Uint32 frame_rate_delta;
static void FrameRateCallback(const bool pal_mode)
{
if (pal_mode)
{
// Run at 50FPS
frame_rate_delta = Frontend::DivideByPALFramerate(1000ul * FRAME_DELTA_MULTIPLIER);
}
else
{
// Run at roughly 59.94FPS (60 divided by 1.001)
frame_rate_delta = Frontend::DivideByNTSCFramerate(1000ul * FRAME_DELTA_MULTIPLIER);
}
}
#endif
int main(const int argc, char** const argv)
{
#ifdef __EMSCRIPTEN__
static_cast<void>(argc);
static_cast<void>(argv);
// Initialise persistent storage.
EM_ASM({
FS.mkdir('/clownmdemu-frontend');
FS.mount(IDBFS, {}, '/clownmdemu-frontend');
FS.chdir('/clownmdemu-frontend');
FS.syncfs(true, function (err) {
Module._StorageLoaded();
});
}, 0);
#else
if (Frontend::Initialise(argc, argv, FrameRateCallback))
{
while (!Frontend::WantsToQuit())
{
// This loop processes events and manages the framerate.
for (;;)
{
static Uint64 next_time;
const Uint64 current_time = SDL_GetTicks64() * FRAME_DELTA_MULTIPLIER;
int timeout = 0;
if (current_time < next_time)
timeout = (next_time - current_time) / FRAME_DELTA_MULTIPLIER;
else if (current_time > next_time + 100 * FRAME_DELTA_MULTIPLIER) // If we're way past our deadline, then resync to the current tick instead of fast-forwarding
next_time = current_time;
// Obtain an event
SDL_Event event;
if (!SDL_WaitEventTimeout(&event, timeout)) // If the timeout has expired and there are no more events, exit this loop
{
// Calculate when the next frame will be
next_time += frame_rate_delta >> (Frontend::IsFastForwarding() ? 2 : 0);
break;
}
Frontend::HandleEvent(event);
}
Frontend::Update();
}
Frontend::Deinitialise();
}
#endif
return EXIT_SUCCESS;
}