trying to use osso-games-startup as gui
[drnoksnes] / platform / sdl.cpp
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/time.h>
4 #include <time.h>
5 #include <SDL.h>
6
7 #include "platform.h"
8 #include "snes9x.h"
9 #include "gfx.h"
10 #include "display.h"
11 #include "memmap.h"
12 #include "soundux.h"
13 #include "hacks.h"
14 #include "hgw.h"
15
16 #define kPollEveryNFrames               5               //Poll input only every this many frames
17 #define kPollHgwEveryNFrames    10              //Poll osso only every this many frames
18
19 #define TRACE printf("trace: %s:%s\n", __FILE__, __func__);
20 #define DIE(format, ...) do { \
21                 fprintf(stderr, "Died at %s:%d: ", __FILE__, __LINE__ ); \
22                 fprintf(stderr, format "\n", ## __VA_ARGS__); \
23                 abort(); \
24         } while (0);
25
26 void S9xMessage(int type, int number, const char * message)
27 {
28         printf("%s\n", message);
29 }
30
31 void S9xLoadSDD1Data()
32 {TRACE
33         Settings.SDD1Pack=FALSE;
34 }
35
36 void S9xAutoSaveSRAM()
37 {
38         Memory.SaveSRAM(S9xGetFilename(".srm"));
39 }
40
41 static void S9xInit() 
42 {
43         if (!Memory.Init () || !S9xInitAPU())
44          DIE("Memory or APU failed");
45
46         if (!S9xInitSound ())
47                 DIE("Sound failed");
48         S9xSetSoundMute (TRUE);
49         
50         // TODO: PAL/NTSC something better than this
51         Settings.PAL = Settings.ForcePAL;
52         
53         Settings.FrameTime = Settings.PAL?Settings.FrameTimePAL:Settings.FrameTimeNTSC;
54         Memory.ROMFramesPerSecond = Settings.PAL?50:60;
55         
56         IPPU.RenderThisFrame = TRUE;
57 }
58
59 static void loadRom()
60 {
61         const char * file = S9xGetFilename(".smc");
62
63         printf("ROM: %s\n", file);
64
65         if (!Memory.LoadROM(file))
66                 DIE("Loading ROM failed");
67         
68         file = S9xGetFilename(".srm");
69         printf("SRAM: %s\n", file);
70         Memory.LoadSRAM(file); 
71 }
72
73 /* This comes nearly straight from snes9x */
74 static void frameSync() {
75         static struct timeval next1 = {0, 0};
76         struct timeval now;
77         
78         if (Settings.TurboMode)
79         {
80                 if(Settings.SkipFrames == AUTO_FRAMERATE || 
81                         ++IPPU.FrameSkip >= Settings.SkipFrames)
82                 {
83                         IPPU.FrameSkip = 0;
84                         IPPU.SkippedFrames = 0;
85                         IPPU.RenderThisFrame = TRUE;
86                 }
87                 else
88                 {
89                         ++IPPU.SkippedFrames;
90                         IPPU.RenderThisFrame = FALSE;
91                 }
92                 return;
93         }
94         
95         /* Normal mode */
96         
97         while (gettimeofday(&now, 0) < 0);
98         
99         /* If there is no known "next" frame, initialize it now */
100         if (next1.tv_sec == 0) { next1 = now; ++next1.tv_usec; }
101         
102     /* If we're on AUTO_FRAMERATE, we'll display frames always
103      * only if there's excess time.
104      * Otherwise we'll display the defined amount of frames.
105      */
106     unsigned limit = Settings.SkipFrames == AUTO_FRAMERATE
107                      ? (timercmp(&next1, &now, <) ? 10 : 1)
108                      : Settings.SkipFrames;
109                      
110     IPPU.RenderThisFrame = ++IPPU.SkippedFrames >= limit;
111     if(IPPU.RenderThisFrame)
112     {
113         IPPU.SkippedFrames = 0;
114     }
115     else
116     {
117         /* If we were behind the schedule, check how much it is */
118         if(timercmp(&next1, &now, <))
119         {
120             unsigned lag =
121                 (now.tv_sec - next1.tv_sec) * 1000000
122                + now.tv_usec - next1.tv_usec;
123             if(lag >= 500000)
124             {
125                 /* More than a half-second behind means probably
126                  * pause. The next line prevents the magic
127                  * fast-forward effect.
128                  */
129                 next1 = now;
130             }
131         }
132     }
133     
134     /* Delay until we're completed this frame */
135
136     /* Can't use setitimer because the sound code already could
137      * be using it. We don't actually need it either.
138      */
139
140     while(timercmp(&next1, &now, >))
141     {
142         /* If we're ahead of time, sleep a while */
143         unsigned timeleft =
144             (next1.tv_sec - now.tv_sec) * 1000000
145            + next1.tv_usec - now.tv_usec;
146
147         usleep(timeleft);
148
149         // XXX : CHECK_SOUND(); S9xProcessEvents(FALSE);
150
151         while (gettimeofday(&now, 0) < 0);
152         /* Continue with a while-loop because usleep()
153          * could be interrupted by a signal
154          */
155     }
156
157     /* Calculate the timestamp of the next frame. */
158     next1.tv_usec += Settings.FrameTime;
159     if (next1.tv_usec >= 1000000)
160     {
161         next1.tv_sec += next1.tv_usec / 1000000;
162         next1.tv_usec %= 1000000;
163     }
164 }
165
166 /** Wraps s9xProcessEvents, taking care of kPollEveryNFrames */
167 static inline void pollEvents() {
168         static int frames = 0;
169         
170         if (++frames > kPollEveryNFrames) {
171                 S9xProcessEvents(FALSE);
172                 frames = 0;
173         }
174 }
175
176 /** Wraps HgwPollEvents, taking care of kPollHgwEveryNFrames */
177 static inline void pollHgwEvents() {
178         static int frames = 0;
179         
180         if (!hgwLaunched) return;
181         
182         if (++frames > kPollHgwEveryNFrames) {
183                 HgwPollEvents();
184                 frames = 0;
185         }
186 }
187
188 int main(int argc, const char ** argv) {        
189         // Initialise SDL
190         if (SDL_Init(0) < 0) 
191                 DIE("SDL_Init: %s", SDL_GetError());
192         
193         // Configure snes9x
194         HgwInit();                                              // Hildon-games-wrapper initialization.
195         S9xLoadConfig(argc, argv);              // Load config files and parse cmd line.
196         HgwConfig();                                    // Apply specific hildon-games config.
197         
198         // S9x initialization
199         S9xInitDisplay(argc, argv);
200         S9xInitAudioOutput();
201         S9xInitInputDevices();
202         S9xInit();
203         S9xReset();
204         
205         // Load rom and related files: state
206         loadRom();
207         
208         // Late initialization
209         sprintf(String, "DrNokSnes - %s", Memory.ROMName);
210         S9xSetTitle(String);
211         S9xHacksLoadFile(Config.hacksFile[0] ? Config.hacksFile : 0);
212         if (!S9xGraphicsInit())
213          DIE("S9xGraphicsInit failed");
214         S9xAudioOutputEnable(true);
215
216         do {
217                 frameSync();                    // May block, or set frameskip to true.
218                 S9xMainLoop();                  // Does CPU things, renders if needed.
219                 pollEvents();
220                 pollHgwEvents();
221         } while (!Config.quitting);
222         
223         // Deinitialization
224         S9xAudioOutputEnable(false);
225         S9xDeinitAudioOutput();
226         S9xDeinitDisplay();
227
228         // Save state
229         Memory.SaveSRAM(S9xGetFilename(".srm"));
230
231         // Late deinitialization
232         S9xGraphicsDeinit();
233         Memory.Deinit();
234         HgwDeinit();
235
236         SDL_Quit();
237
238         return 0;
239 }
240
241 void S9xDoAction(unsigned char action)
242 {
243         if (action & kActionQuit) 
244                 Config.quitting = true;
245                 
246         if (action & kActionToggleFullscreen)
247                 S9xVideoToggleFullscreen();
248 }
249