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