17 #define kPollEveryNFrames 5 //Poll input only every this many frames
18 #define kPollHgwEveryNFrames 10 //Poll dbus only every this many frames
20 #define TRACE printf("trace: %s:%s\n", __FILE__, __func__);
21 #define DIE(format, ...) do { \
22 fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \
23 fprintf(stderr, format "\n", ## __VA_ARGS__); \
27 void S9xMessage(int type, int number, const char * message)
29 printf("%s\n", message);
32 void S9xLoadSDD1Data()
34 Settings.SDD1Pack=FALSE;
37 void S9xAutoSaveSRAM()
39 Memory.SaveSRAM(S9xGetFilename(FILE_SRAM));
44 if (!Memory.Init () || !S9xInitAPU())
45 DIE("Memory or APU failed");
49 S9xSetSoundMute (TRUE);
51 // TODO: PAL/NTSC something better than this
52 Settings.PAL = Settings.ForcePAL;
54 Settings.FrameTime = Settings.PAL?Settings.FrameTimePAL:Settings.FrameTimeNTSC;
55 Memory.ROMFramesPerSecond = Settings.PAL?50:60;
57 IPPU.RenderThisFrame = TRUE;
62 const char * file = S9xGetFilename(FILE_ROM);
64 printf("ROM: %s\n", file);
66 if (!Memory.LoadROM(file))
67 DIE("Loading ROM failed");
69 file = S9xGetFilename(FILE_SRAM);
70 printf("SRAM: %s\n", file);
71 Memory.LoadSRAM(file);
74 static void resumeGame()
76 if (!Config.snapshotLoad) return;
78 const char * file = S9xGetFilename(FILE_FREEZE);
79 int result = S9xUnfreezeGame(file);
81 printf("Unfreeze: %s", file);
85 FILE* fp = fopen(file, "rb");
87 if (Config.snapshotSave) {
88 puts(", but the file exists, so I'm not going to overwrite it");
89 Config.snapshotSave = false;
95 puts(" (file does not exist)");
102 static void pauseGame()
104 if (!Config.snapshotSave) return;
106 const char * file = S9xGetFilename(FILE_FREEZE);
107 int result = S9xFreezeGame(file);
109 printf("Freeze: %s", file);
112 Config.snapshotSave = false; // Serves as a flag to Hgw
119 /* This comes nearly straight from snes9x */
120 static void frameSync() {
121 static struct timeval next1 = {0, 0};
124 if (Settings.TurboMode)
126 if(Settings.SkipFrames == AUTO_FRAMERATE ||
127 ++IPPU.FrameSkip >= Settings.SkipFrames)
130 IPPU.SkippedFrames = 0;
131 IPPU.RenderThisFrame = TRUE;
135 ++IPPU.SkippedFrames;
136 IPPU.RenderThisFrame = FALSE;
143 while (gettimeofday(&now, 0) < 0);
145 /* If there is no known "next" frame, initialize it now */
146 if (next1.tv_sec == 0) { next1 = now; ++next1.tv_usec; }
148 /* If we're on AUTO_FRAMERATE, we'll display frames always
149 * only if there's excess time.
150 * Otherwise we'll display the defined amount of frames.
152 unsigned limit = Settings.SkipFrames == AUTO_FRAMERATE
153 ? (timercmp(&next1, &now, <) ? 10 : 1)
154 : Settings.SkipFrames;
156 IPPU.RenderThisFrame = ++IPPU.SkippedFrames >= limit;
157 if(IPPU.RenderThisFrame)
159 IPPU.SkippedFrames = 0;
163 /* If we were behind the schedule, check how much it is */
164 if(timercmp(&next1, &now, <))
167 (now.tv_sec - next1.tv_sec) * 1000000
168 + now.tv_usec - next1.tv_usec;
171 /* More than a half-second behind means probably
172 * pause. The next line prevents the magic
173 * fast-forward effect.
180 /* Delay until we're completed this frame */
182 /* Can't use setitimer because the sound code already could
183 * be using it. We don't actually need it either.
186 while(timercmp(&next1, &now, >))
188 /* If we're ahead of time, sleep a while */
190 (next1.tv_sec - now.tv_sec) * 1000000
191 + next1.tv_usec - now.tv_usec;
195 // XXX : CHECK_SOUND(); S9xProcessEvents(FALSE);
197 while (gettimeofday(&now, 0) < 0);
198 /* Continue with a while-loop because usleep()
199 * could be interrupted by a signal
203 /* Calculate the timestamp of the next frame. */
204 next1.tv_usec += Settings.FrameTime;
205 if (next1.tv_usec >= 1000000)
207 next1.tv_sec += next1.tv_usec / 1000000;
208 next1.tv_usec %= 1000000;
212 /** Wraps s9xProcessEvents, taking care of kPollEveryNFrames */
213 static inline void pollEvents() {
214 static int frames = 0;
216 if (++frames > kPollEveryNFrames) {
217 S9xProcessEvents(FALSE);
222 /** Wraps HgwPollEvents, taking care of kPollHgwEveryNFrames */
223 static inline void pollHgwEvents() {
224 static int frames = 0;
226 if (!hgwLaunched) return;
228 if (++frames > kPollHgwEveryNFrames) {
234 int main(int argc, const char ** argv) {
237 DIE("SDL_Init: %s", SDL_GetError());
240 HgwInit(); // Hildon-games-wrapper initialization.
241 S9xLoadConfig(argc, argv); // Load config files and parse cmd line.
242 HgwConfig(); // Apply specific hildon-games config.
244 // S9x initialization
245 S9xInitDisplay(argc, argv);
246 S9xInitAudioOutput();
247 S9xInitInputDevices();
251 // Load rom and related files: state, unfreeze if needed
255 // Late initialization
256 sprintf(String, "DrNokSnes - %s", Memory.ROMName);
258 S9xHacksLoadFile(Config.hacksFile[0] ? Config.hacksFile : 0);
259 if (!S9xGraphicsInit())
260 DIE("S9xGraphicsInit failed");
261 S9xAudioOutputEnable(true);
264 frameSync(); // May block, or set frameskip to true.
265 S9xMainLoop(); // Does CPU things, renders if needed.
268 } while (!Config.quitting);
271 S9xAudioOutputEnable(false);
272 S9xDeinitAudioOutput();
276 Memory.SaveSRAM(S9xGetFilename(FILE_SRAM));
279 // Late deinitialization
290 void S9xDoAction(unsigned char action)
292 if (action & kActionQuit)
293 Config.quitting = true;
295 if (action & kActionToggleFullscreen)
296 S9xVideoToggleFullscreen();