1 // Run module
2 #include "burner.h"
3 #ifdef BUILD_SDL2
4 #include "sdl2_gui_common.h"
5 #endif
6 #include <sys/time.h>
7
8 static unsigned int nDoFPS = 0;
9 bool bAltPause = 0;
10
11 int bAlwaysDrawFrames = 0;
12
13 int counter; // General purpose variable used when debugging
14
15 static unsigned int nNormalLast = 0; // Last value of GetTime()
16 static int nNormalFrac = 0; // Extra fraction we did
17
18 static bool bAppDoStep = 0;
19 bool bAppDoFast = 0;
20 bool bAppShowFPS = 0;
21 static int nFastSpeed = 6;
22 static bool bscreenshot = 0;
23
24 UINT32 messageFrames = 0;
25 char lastMessage[MESSAGE_MAX_LENGTH];
26
27 #ifdef BUILD_SDL2
28 static Uint32 starting_stick;
29 /// Ingame gui
30 extern SDL_Renderer* sdlRenderer;
31 extern void ingame_gui_start(SDL_Renderer* renderer);
32 /// Save States
33 static char* szSDLSavePath = NULL;
34 static char Windowtitle[512];
35 #endif
36
37 int bDrvSaveAll = 0;
38
39 // The automatic save
StatedAuto(int bSave)40 int StatedAuto(int bSave)
41 {
42 static TCHAR szName[MAX_PATH] = _T("");
43 int nRet;
44
45 #if defined(BUILD_SDL2) && !defined(SDL_WINDOWS)
46 if (szSDLSavePath == NULL)
47 {
48 szSDLSavePath = SDL_GetPrefPath("fbneo", "states");
49 }
50
51 snprintf(szName, MAX_PATH, "%s%s.fs", szSDLSavePath, BurnDrvGetText(DRV_NAME));
52
53 #else
54
55 _stprintf(szName, _T("config/games/%s.fs"), BurnDrvGetText(DRV_NAME));
56
57 #endif
58
59 if (bSave == 0)
60 {
61 printf("loading state %i %s\n", bDrvSaveAll, szName);
62 nRet = BurnStateLoad(szName, bDrvSaveAll, NULL); // Load ram
63 if (nRet && bDrvSaveAll)
64 {
65 nRet = BurnStateLoad(szName, 0, NULL); // Couldn't get all - okay just try the nvram
66 }
67 }
68 else
69 {
70 printf("saving state %i %s\n", bDrvSaveAll, szName);
71 nRet = BurnStateSave(szName, bDrvSaveAll); // Save ram
72 }
73
74 return nRet;
75 }
76
77
78 /// End Save States
79
80 char fpsstring[20];
81
82 static time_t fpstimer;
83 static unsigned int nPreviousFrames;
84
DisplayFPSInit()85 static void DisplayFPSInit()
86 {
87 nDoFPS = 0;
88 fpstimer = 0;
89 nPreviousFrames = nFramesRendered;
90 }
91
DisplayFPS()92 static void DisplayFPS()
93 {
94 time_t temptime = clock();
95 double fps = (double)(nFramesRendered - nPreviousFrames) * CLOCKS_PER_SEC / (temptime - fpstimer);
96 if (bAppDoFast) {
97 fps *= nFastSpeed + 1;
98 }
99 if (fpstimer && temptime - fpstimer > 0) { // avoid strange fps values
100 sprintf(fpsstring, "%2.2lf", fps);
101 }
102
103 fpstimer = temptime;
104 nPreviousFrames = nFramesRendered;
105 }
106
107
108 //crappy message system
UpdateMessage(char * message)109 void UpdateMessage(char* message)
110 {
111 snprintf(lastMessage, MESSAGE_MAX_LENGTH, "%s", message);
112 messageFrames = MESSAGE_MAX_FRAMES;
113 }
114
115 // define this function somewhere above RunMessageLoop()
ToggleLayer(unsigned char thisLayer)116 void ToggleLayer(unsigned char thisLayer)
117 {
118 nBurnLayer ^= thisLayer; // xor with thisLayer
119 VidRedraw();
120 VidPaint(0);
121 }
122
123
124 struct timeval start;
125
GetTime(void)126 unsigned int GetTime(void)
127 {
128 unsigned int ticks;
129 struct timeval now;
130 gettimeofday(&now, NULL);
131 ticks = (now.tv_sec - start.tv_sec) * 1000000 + now.tv_usec - start.tv_usec;
132 return ticks;
133 }
134
135 // With or without sound, run one frame.
136 // If bDraw is true, it's the last frame before we are up to date, and so we should draw the screen
RunFrame(int bDraw,int bPause)137 static int RunFrame(int bDraw, int bPause)
138 {
139 if (!bDrvOkay)
140 {
141 return 1;
142 }
143
144 if (bPause)
145 {
146 InputMake(false);
147 VidPaint(0);
148 }
149 else
150 {
151 nFramesEmulated++;
152 nCurrentFrame++;
153 InputMake(true);
154 }
155
156 if (bDraw)
157 {
158 nFramesRendered++;
159
160 if (!bRunAhead || bAppDoFast) { // Run-Ahead feature -dink aug 02, 2021
161 if (VidFrame()) { // Do one frame w/o RunAhead or if FFWD is pressed.
162 AudBlankSound();
163 }
164 } else {
165 pBurnDraw = NULL; // Do one frame w/RunAhead
166 BurnDrvFrame();
167 StateRunAheadSave();
168 pBurnSoundOut = NULL;
169 VidFrame();
170 StateRunAheadLoad();
171 }
172
173 VidPaint(0); // paint the screen (no need to validate)
174 }
175 else
176 { // frame skipping
177 pBurnDraw = NULL; // Make sure no image is drawn
178 BurnDrvFrame();
179 }
180
181 if (bAppShowFPS) {
182 if (nDoFPS < nFramesRendered) {
183 DisplayFPS();
184 nDoFPS = nFramesRendered + 30;
185 }
186 }
187
188 return 0;
189 }
190
191 // Callback used when DSound needs more sound
RunGetNextSound(int bDraw)192 static int RunGetNextSound(int bDraw)
193 {
194 if (nAudNextSound == NULL)
195 {
196 return 1;
197 }
198
199 if (bRunPause)
200 {
201 if (bAppDoStep)
202 {
203 RunFrame(bDraw, 0);
204 memset(nAudNextSound, 0, nAudSegLen << 2); // Write silence into the buffer
205 }
206 else
207 {
208 RunFrame(bDraw, 1);
209 }
210
211 bAppDoStep = 0; // done one step
212 return 0;
213 }
214
215 if (bAppDoFast)
216 { // do more frames
217 for (int i = 0; i < nFastSpeed; i++)
218 {
219 RunFrame(0, 0);
220 }
221 }
222
223 // Render frame with sound
224 pBurnSoundOut = nAudNextSound;
225 RunFrame(bDraw, 0);
226 if (bAppDoStep)
227 {
228 memset(nAudNextSound, 0, nAudSegLen << 2); // Write silence into the buffer
229 }
230 bAppDoStep = 0; // done one step
231
232 return 0;
233 }
234
delay_ticks(int ticks)235 int delay_ticks(int ticks)
236 {
237 //sdl_delay can take up to 10 - 15 ticks it doesnt guarentee below this
238 int startTicks = 0;
239 int endTicks = 0;
240 int checkTicks = 0;
241
242 startTicks=SDL_GetTicks();
243
244 while (checkTicks <= ticks)
245 {
246 endTicks=SDL_GetTicks();
247 checkTicks = endTicks - startTicks;
248 }
249
250 return ticks;
251 }
RunIdle()252 int RunIdle()
253 {
254 int nTime, nCount;
255
256 if (bAudPlaying)
257 {
258 // Run with sound
259 AudSoundCheck();
260 return 0;
261 }
262
263 // Run without sound
264 nTime = GetTime() - nNormalLast;
265 nCount = (nTime * nAppVirtualFps - nNormalFrac) / 100000;
266 if (nCount <= 0) { // No need to do anything for a bit
267 //delay_ticks(2);
268 return 0;
269 }
270
271 nNormalFrac += nCount * 100000;
272 nNormalLast += nNormalFrac / nAppVirtualFps;
273 nNormalFrac %= nAppVirtualFps;
274
275 if (nCount > 100) { // Limit frame skipping
276 nCount = 100;
277 }
278 if (bRunPause) {
279 if (bAppDoStep) { // Step one frame
280 nCount = 10;
281 }
282 else {
283 RunFrame(1, 1); // Paused
284 return 0;
285 }
286 }
287 bAppDoStep = 0;
288
289
290 if (bAppDoFast)
291 { // do more frames
292 for (int i = 0; i < nFastSpeed; i++)
293 {
294 RunFrame(0, 0);
295 }
296 }
297
298 if (!bAlwaysDrawFrames)
299 {
300 for (int i = nCount / 10; i > 0; i--)
301 { // Mid-frames
302 RunFrame(0, 0);
303 }
304 }
305 RunFrame(1, 0); // End-frame
306 // temp added for SDLFBA
307 //VidPaint(0);
308 return 0;
309 }
310
RunReset()311 int RunReset()
312 {
313 // Reset the speed throttling code
314 nNormalLast = 0; nNormalFrac = 0;
315 if (!bAudPlaying)
316 {
317 // run without sound
318 nNormalLast = GetTime();
319 }
320 return 0;
321 }
322
RunInit()323 int RunInit()
324 {
325 gettimeofday(&start, NULL);
326 DisplayFPSInit();
327 // Try to run with sound
328 AudSetCallback(RunGetNextSound);
329 AudSoundPlay();
330
331 RunReset();
332 StatedAuto(0);
333 return 0;
334 }
335
RunExit()336 int RunExit()
337 {
338 nNormalLast = 0;
339 StatedAuto(1);
340 return 0;
341 }
342
343 #ifdef BUILD_SDL2
pause_game()344 void pause_game()
345 {
346 AudSoundStop();
347
348 if(nVidSelect) {
349 // no Text in OpenGL...
350 SDL_GL_SwapWindow(sdlWindow);
351 }else{
352 inprint_shadowed(sdlRenderer, "PAUSE", 10, 10);
353 SDL_RenderPresent(sdlRenderer);
354 }
355
356 int finished = 0;
357 while (!finished)
358 {
359 starting_stick = SDL_GetTicks();
360
361 SDL_Event e;
362
363 while (SDL_PollEvent(&e))
364 {
365 if (e.type == SDL_QUIT)
366 {
367 finished=1;
368 }
369 if (e.type == SDL_KEYDOWN)
370 {
371 switch (e.key.keysym.sym)
372 {
373 case SDLK_TAB:
374 case SDLK_p:
375 finished=1;
376 break;
377 default:
378 break;
379 }
380 }
381 if (e.type == SDL_WINDOWEVENT)
382 { // Window Event
383 switch (e.window.event)
384 {
385 //case SDL_WINDOWEVENT_RESTORED: // keep pause when restore window
386 case SDL_WINDOWEVENT_FOCUS_GAINED:
387 finished=1;
388 break;
389 case SDL_WINDOWEVENT_CLOSE:
390 finished=1;
391 RunExit();
392 break;
393 default:
394 break;
395 }
396 }
397 }
398
399 // limit 5 FPS (free CPU usage)
400 if ( ( 1000 / 5 ) > SDL_GetTicks() - starting_stick) {
401 SDL_Delay( 1000 / 5 - ( SDL_GetTicks() - starting_stick ) );
402 }
403
404 }
405
406 AudSoundPlay();
407 }
408 #endif
409
410 #ifndef BUILD_MACOS
411 // The main message loop
RunMessageLoop()412 int RunMessageLoop()
413 {
414 int quit = 0;
415
416 RunInit();
417 GameInpCheckMouse(); // Hide the cursor
418
419 while (!quit)
420 {
421
422 SDL_Event event;
423 while (SDL_PollEvent(&event))
424 {
425 switch (event.type)
426 {
427 case SDL_QUIT: /* Windows was closed */
428 quit = 1;
429 break;
430
431 #ifdef BUILD_SDL2
432 case SDL_WINDOWEVENT: // Window Event
433 switch (event.window.event)
434 {
435 case SDL_WINDOWEVENT_MINIMIZED:
436 case SDL_WINDOWEVENT_FOCUS_LOST:
437 pause_game();
438 break;
439 }
440 break;
441 #endif
442
443 case SDL_KEYDOWN: // need to find a nicer way of doing this...
444 switch (event.key.keysym.sym)
445 {
446 case SDLK_F1:
447 bAppDoFast = 1;
448 break;
449 case SDLK_F9:
450 QuickState(0);
451 break;
452 case SDLK_F10:
453 QuickState(1);
454 break;
455 case SDLK_F11:
456 bAppShowFPS = !bAppShowFPS;
457 #ifdef BUILD_SDL2
458 if (!bAppShowFPS)
459 {
460 sprintf(Windowtitle, "FBNeo - %s - %s", BurnDrvGetTextA(DRV_NAME), BurnDrvGetTextA(DRV_FULLNAME));
461 SDL_SetWindowTitle(sdlWindow, Windowtitle);
462 }
463 #endif
464 break;
465 #ifdef BUILD_SDL2
466 case SDLK_TAB:
467 if(!nVidSelect) {
468 ingame_gui_start(sdlRenderer);
469 } else {
470 // Pause with SDL2 OpenGL mode
471 pause_game();
472 }
473 break;
474
475 case SDLK_RETURN:
476 if (event.key.keysym.mod & KMOD_ALT)
477 {
478 SetFullscreen(!GetFullscreen());
479 }
480 break;
481 #endif
482 case SDLK_F6: // screeenshot
483 if (!bscreenshot) {
484 MakeScreenShot();
485 bscreenshot = 1;
486 }
487 break;
488 case SDLK_KP_MINUS: // volumme -
489 nAudVolume -= 500;
490 if (nAudVolume < 0) {
491 nAudVolume = 0;
492 }
493 if (AudSoundSetVolume() == 0) {
494 }
495 break;
496 case SDLK_KP_PLUS: // volume -+
497 nAudVolume += 500;
498 if (nAudVolume > 10000) {
499 nAudVolume = 10000;
500 }
501 if (AudSoundSetVolume() == 0) {
502 }
503 break;
504 default:
505 break;
506 }
507 break;
508
509 case SDL_KEYUP: // need to find a nicer way of doing this...
510 switch (event.key.keysym.sym)
511 {
512 case SDLK_F1:
513 bAppDoFast = 0;
514 break;
515 case SDLK_F6:
516 bscreenshot = 0;
517 break;
518 case SDLK_F12:
519 quit = 1;
520 break;
521
522 default:
523 break;
524 }
525 break;
526 }
527 }
528
529 RunIdle();
530
531 }
532
533 RunExit();
534
535 return 0;
536 }
537
538 #endif
539