1 #if (_MSC_VER == 1600 && _M_IX86_FP >= 0 && (_MSC_FULL_VER < 160040219))
2 #error The version of Visual Studio 2010 you are using generates SSE2 instructions  when /arch:SSE is specified. Please update to Service Pack 1.
3 #endif
4 
5 #ifdef NO_D3D
6 #ifdef NO_OGL
7 #error NO_D3D and NO_OGL must not be defined at the same time.
8 #endif
9 #endif
10 
11 #include "stdafx.h"
12 #include "VBA.h"
13 
14 #include <intrin.h>
15 
16 #include "AVIWrite.h"
17 #include "LangSelect.h"
18 #include "MainWnd.h"
19 #include "Reg.h"
20 #include "resource.h"
21 #include "WavWriter.h"
22 #include "WinResUtil.h"
23 #include "Logging.h"
24 #include "rpi.h"
25 
26 #include "../System.h"
27 #include "../gba/agbprint.h"
28 #include "../gba/cheatSearch.h"
29 #include "../gba/GBA.h"
30 #include "../gba/Globals.h"
31 #include "../gba/RTC.h"
32 #include "../gba/Sound.h"
33 #include "../Util.h"
34 #include "../gb/gbGlobals.h"
35 #include "../gb/gbPrinter.h"
36 #include "../gb/gbSound.h"
37 #include "../common/SoundDriver.h"
38 #include "../common/ConfigManager.h"
39 
40 #include "../version.h"
41 
42 /* Link
43 ---------------------*/
44 #include "../gba/GBALink.h"
45 /* ---------------- */
46 
47 extern void Pixelate(u8*,u32,u8*,u8*,u32,int,int);
48 extern void Pixelate32(u8*,u32,u8*,u8*,u32,int,int);
49 extern void _2xSaI(u8*,u32,u8*,u8*,u32,int,int);
50 extern void _2xSaI32(u8*,u32,u8*,u8*,u32,int,int);
51 extern void Super2xSaI(u8*,u32,u8*,u8*,u32,int,int);
52 extern void Super2xSaI32(u8*,u32,u8*,u8*,u32,int,int);
53 extern void SuperEagle(u8*,u32,u8*,u8*,u32,int,int);
54 extern void SuperEagle32(u8*,u32,u8*,u8*,u32,int,int);
55 extern void AdMame2x(u8*,u32,u8*,u8*,u32,int,int);
56 extern void AdMame2x32(u8*,u32,u8*,u8*,u32,int,int);
57 extern void Bilinear(u8*,u32,u8*,u8*,u32,int,int);
58 extern void Bilinear32(u8*,u32,u8*,u8*,u32,int,int);
59 extern void BilinearPlus(u8*,u32,u8*,u8*,u32,int,int);
60 extern void BilinearPlus32(u8*,u32,u8*,u8*,u32,int,int);
61 extern void Scanlines(u8*,u32,u8*,u8*,u32,int,int);
62 extern void Scanlines32(u8*,u32,u8*,u8*,u32,int,int);
63 extern void ScanlinesTV(u8*,u32,u8*,u8*,u32,int,int);
64 extern void ScanlinesTV32(u8*,u32,u8*,u8*,u32,int,int);
65 extern void hq2x(u8*,u32,u8*,u8*,u32,int,int);
66 extern void hq2x32(u8*,u32,u8*,u8*,u32,int,int);
67 extern void lq2x(u8*,u32,u8*,u8*,u32,int,int);
68 extern void lq2x32(u8*,u32,u8*,u8*,u32,int,int);
69 extern void Simple2x16(u8*,u32,u8*,u8*,u32,int,int);
70 extern void Simple2x32(u8*,u32,u8*,u8*,u32,int,int);
71 extern void Simple3x16(u8*,u32,u8*,u8*,u32,int,int);
72 extern void Simple3x32(u8*,u32,u8*,u8*,u32,int,int);
73 extern void Simple4x16(u8*,u32,u8*,u8*,u32,int,int);
74 extern void Simple4x32(u8*,u32,u8*,u8*,u32,int,int);
75 #ifndef WIN64
76 extern void hq3x16(u8*,u32,u8*,u8*,u32,int,int);
77 extern void hq4x16(u8*,u32,u8*,u8*,u32,int,int);
78 extern void hq3x32(u8*,u32,u8*,u8*,u32,int,int);
79 extern void hq4x32(u8*,u32,u8*,u8*,u32,int,int);
80 #endif
81 extern void xbrz2x32(u8*,u32,u8*,u8*,u32,int,int);
82 extern void xbrz3x32(u8*,u32,u8*,u8*,u32,int,int);
83 extern void xbrz4x32(u8*,u32,u8*,u8*,u32,int,int);
84 extern void xbrz5x32(u8*,u32,u8*,u8*,u32,int,int);
85 extern void xbrz6x32(u8*,u32,u8*,u8*,u32,int,int);
86 
87 extern void SmartIB(u8*,u32,int,int);
88 extern void SmartIB32(u8*,u32,int,int);
89 extern void MotionBlurIB(u8*,u32,int,int);
90 extern void MotionBlurIB32(u8*,u32,int,int);
91 
92 extern IDisplay *newGDIDisplay();
93 extern IDisplay *newDirectDrawDisplay();
94 #ifndef NO_OGL
95 extern IDisplay *newOpenGLDisplay();
96 #endif
97 #ifndef NO_D3D
98 extern IDisplay *newDirect3DDisplay();
99 #endif
100 
101 extern Input *newDirectInput();
102 
103 extern SoundDriver *newDirectSound();
104 #ifndef NO_OAL
105 extern SoundDriver *newOpenAL();
106 #endif
107 #ifndef NO_XAUDIO2
108 extern SoundDriver *newXAudio2_Output();
109 #endif
110 
111 extern void remoteStubSignal(int, int);
112 extern void remoteOutput(char *, u32);
113 extern void remoteStubMain();
114 extern void remoteSetProtocol(int);
115 extern void remoteCleanUp();
116 extern int remoteSocket;
117 
118 extern void InterframeCleanup();
119 
120 void winlog(const char *msg, ...);
121 
122 /* Link
123 ---------------------*/
124 extern char inifile[];
125 /* ------------------- */
126 #ifdef _DEBUG
127 #define new DEBUG_NEW
128 #undef THIS_FILE
129 static char THIS_FILE[] = __FILE__;
130 #endif
131 
132 int emulating = 0;
133 int RGB_LOW_BITS_MASK = 0;
134 bool b16to32Video = false;
135 int systemFrameSkip = 0;
136 int systemSpeed = 0;
137 u32 systemColorMap32[0x10000];
138 u16 systemColorMap16[0x10000];
139 u16 systemGbPalette[24];
140 int systemRedShift = 0;
141 int systemBlueShift = 0;
142 int systemGreenShift = 0;
143 int systemColorDepth = 16;
144 int realsystemRedShift = 0;
145 int realsystemBlueShift = 0;
146 int realsystemGreenShift = 0;
147 int realsystemColorDepth = 16;
148 int systemVerbose = 0;
149 int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
150 bool soundBufferLow = 0;
151 void winSignal(int,int);
152 void winOutput(const char *, u32);
153 
154 #ifdef MMX
155 extern "C" bool cpu_mmx;
156 #endif
157 
158 namespace Sm60FPS
159 {
160   float					K_fCpuSpeed = 100.0f; // was 98.0f before, but why?
161   float					K_fTargetFps = 60.0f * K_fCpuSpeed / 100;
162   float					K_fDT = 1000.0f / K_fTargetFps;
163 
164   u32					dwTimeElapse;
165   u32					dwTime0;
166   u32					dwTime1;
167   u32					nFrameCnt;
168   float					fWantFPS;
169   float					fCurFPS;
170   bool					bLastSkip;
171   int					nCurSpeed;
172   int					bSaveMoreCPU;
173 };
174 
175 #ifdef LOG_PERFORMANCE
176 #ifndef PERFORMANCE_INTERVAL
177 #define PERFORMANCE_INTERVAL 3600
178 #endif
179 int systemSpeedTable[PERFORMANCE_INTERVAL];
180 unsigned int systemSpeedCounter;
181 #endif
182 
directXMessage(const char * msg)183 void directXMessage(const char *msg)
184 {
185   systemMessage(IDS_DIRECTX_7_REQUIRED,
186                 "DirectX 7.0 or greater is required to run.\nDownload at http://www.microsoft.com/directx.\n\nError found at: %s",
187                 msg);
188 }
189 
190 /////////////////////////////////////////////////////////////////////////////
191 // VBA
192 
VBA()193 VBA::VBA()
194 {
195   // COINIT_MULTITHREADED is not supported by SHBrowseForFolder with BIF_USENEWUI
196   // OpenAL also causes trouble when COINIT_MULTITHREADED is used
197   if( S_OK != CoInitializeEx( NULL, COINIT_APARTMENTTHREADED ) ) {
198 	  systemMessage( IDS_COM_FAILURE, NULL );
199   }
200 
201   // ! keep in mind that many of the following values will be really initialized in loadSettings()
202   maxCpuCores = 1;
203   windowPositionX = 0;
204   windowPositionY = 0;
205   filterFunction = NULL;
206   ifbFunction = NULL;
207   ifbType = kIFBNone;
208   filter = FILTER_NONE;
209   filterWidth = 0;
210   filterHeight = 0;
211   filterMT = false;
212   fsAdapter = 0;
213   fsWidth = 0;
214   fsHeight = 0;
215   fsColorDepth = 0;
216   fsFrequency = 0;
217   fsForceChange = false;
218   surfaceSizeX = 0;
219   surfaceSizeY = 0;
220   sizeX = 0;
221   sizeY = 0;
222   videoOption = 0;
223   fullScreenStretch = false;
224   showSpeed = 0;
225   showSpeedTransparent = true;
226   showRenderedFrames = 0;
227   screenMessage = false;
228   screenMessageTime = 0;
229   display = NULL;
230   menu = NULL;
231   popup = NULL;
232   cartridgeType = IMAGE_GBA;
233   soundInitialized = false;
234   useBiosFileGBA = false;
235   useBiosFileGBC = false;
236   useBiosFileGB = false;
237   skipBios = false;
238   biosFileNameGBA = _T("");
239   biosFileNameGBC = _T("");
240   biosFileNameGB = _T("");
241   active = true;
242   paused = false;
243   recentFreeze = false;
244   autoSaveLoadCheatList = true;
245   winout = NULL;
246   autoPatch = true;
247   winGbBorderOn = 0;
248   winFlashSize = 0x20000;
249   rtcEnabled = false;
250   cpuSaveType = 0;
251   rewindMemory = NULL;
252   rewindPos = 0;
253   rewindTopPos = 0;
254   rewindCounter = 0;
255   rewindCount = 0;
256   rewindSaveNeeded = false;
257   rewindTimer = 0;
258   captureFormat = 0;
259   tripleBuffering = true;
260   throttle = 0;
261   autoFrameSkipLastTime = 0;
262   autoFrameSkip = false;
263   vsync = false;
264   changingVideoSize = false;
265   renderMethod = DIRECT_3D;
266   audioAPI = DIRECTSOUND;
267 #ifndef NO_OAL
268   oalDevice = NULL;
269   oalBufferCount = 5;
270 #endif
271 #ifndef NO_XAUDIO2
272   audioAPI = XAUDIO2;
273   xa2Device = 0;
274   xa2BufferCount = 4;
275   xa2Upmixing = false;
276 #endif
277 #ifndef NO_D3D
278   d3dFilter = 0;
279   d3dMotionBlur = false;
280 #endif
281   iconic = false;
282   glFilter = 0;
283   regEnabled = false;
284  pauseWhenInactive = true;
285   speedupToggle = false;
286   winGbPrinterEnabled = false;
287   gdbBreakOnLoad = false;
288   threadPriority = 2;
289   disableMMX = false;
290   languageOption = 0;
291   languageModule = NULL;
292   languageName = "";
293   renderedFrames = 0;
294   input = NULL;
295   joypadDefault = 0;
296   autoFire = 0;
297   autoFireToggle = false;
298   winPauseNextFrame = false;
299   soundRecording = false;
300   soundRecorder = NULL;
301   dsoundDisableHardwareAcceleration = true;
302   aviRecording = false;
303   aviRecorder = NULL;
304   painting = false;
305   skipAudioFrames = 0;
306   movieRecording = false;
307   moviePlaying = false;
308   movieFrame = 0;
309   moviePlayFrame = 0;
310   movieFile = NULL;
311   movieLastJoypad = 0;
312   movieNextJoypad = 0;
313   sensorX = 2047;
314   sensorY = 2047;
315   sunBars = 500;
316   mouseCounter = 0;
317   wasPaused = false;
318   frameskipadjust = 0;
319   autoLoadMostRecent = false;
320   maxScale = 0;
321   romSize = 0;
322   lastWindowed = VIDEO_3X;
323   lastFullscreen = VIDEO_1024x768;
324 
325   updateCount = 0;
326 
327   systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
328 
329   ZeroMemory(&emulator, sizeof(emulator));
330 
331   hAccel = NULL;
332 
333   for(int i = 0; i < 24;) {
334     systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10);
335     systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10);
336     systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10);
337     systemGbPalette[i++] = 0;
338   }
339 }
340 
~VBA()341 VBA::~VBA()
342 {
343   rpiCleanup();
344   InterframeCleanup();
345 
346   char winBuffer[2048];
347 
348   GetModuleFileName(NULL, winBuffer, 2048);
349   char *p = strrchr(winBuffer, '\\');
350   if(p)
351     *p = 0;
352 
353   regInit(winBuffer);
354 #ifndef NO_LINK
355   CloseLink();
356 #endif
357   saveSettings();
358 
359   if(moviePlaying) {
360     if(movieFile != NULL) {
361       fclose(movieFile);
362       movieFile = NULL;
363     }
364     moviePlaying = false;
365     movieLastJoypad = 0;
366   }
367 
368   if(movieRecording) {
369     if(movieFile != NULL) {
370       // record the last joypad change so that the correct time can be
371       // recorded
372       fwrite(&movieFrame, 1, sizeof(int), movieFile);
373       fwrite(&movieLastJoypad, 1, sizeof(u32), movieFile);
374       fclose(movieFile);
375       movieFile = NULL;
376     }
377     movieRecording = false;
378     moviePlaying = false;
379     movieLastJoypad = 0;
380   }
381 
382   soundPause();
383   soundShutdown();
384 
385   if(gbRom != NULL || rom != NULL) {
386     if(autoSaveLoadCheatList)
387       ((MainWnd *)m_pMainWnd)->winSaveCheatListDefault();
388     ((MainWnd *)m_pMainWnd)->writeBatteryFile();
389     cheatSearchCleanup(&cheatSearchData);
390     emulator.emuCleanUp();
391   }
392 
393   if(input)
394     delete input;
395 
396   shutdownDisplay();
397 
398   if(rewindMemory)
399     free(rewindMemory);
400 
401 #ifndef NO_OAL
402   if( oalDevice ) {
403 	  free( oalDevice );
404   }
405 #endif
406 
407   CoUninitialize();
408 }
409 
410 /////////////////////////////////////////////////////////////////////////////
411 // The one and only VBA object
412 
413 VBA theApp;
414 /////////////////////////////////////////////////////////////////////////////
415 // VBA initialization
416 
InitInstance()417 BOOL VBA::InitInstance()
418 {
419 #if _MSC_VER < 1400
420 #ifdef _AFXDLL
421   Enable3dControls();      // Call this when using MFC in a shared DLL
422 #else
423   Enable3dControlsStatic();  // Call this when linking to MFC statically
424 #endif
425 #endif
426 
427   SetRegistryKey(_T("VBA"));
428 
429   remoteSetProtocol(0);
430 
431   systemVerbose = GetPrivateProfileInt("config",
432                                        "verbose",
433                                        0,
434                                        MakeInstanceFilename("vbam.ini"));
435 
436   wndClass = AfxRegisterWndClass(0, LoadCursor(IDC_ARROW), (HBRUSH)GetStockObject(BLACK_BRUSH), LoadIcon(IDI_MAINICON));
437 
438   char winBuffer[2048];
439 
440   GetModuleFileName(NULL, winBuffer, 2048);
441   char *p = strrchr(winBuffer, '\\');
442   if(p)
443     *p = 0;
444 
445   bool force = false;
446 
447   if (m_lpCmdLine[0])
448   {
449     if(__argc > 0) {
450       if( 0 == strcmp( __argv[1], "--configpath" ) ) {
451         if( __argc > 2 ) {
452           strcpy( winBuffer, __argv[2] );
453           force = true;
454           if( __argc > 3 ) {
455             szFile = __argv[3]; filename = szFile;
456             int index = filename.ReverseFind('.');
457             if(index != -1)
458               filename = filename.Left(index);
459           }
460         }
461       } else {
462         szFile = __argv[1]; filename = szFile;
463         int index = filename.ReverseFind('.');
464         if(index != -1)
465           filename = filename.Left(index);
466       }
467     }
468   }
469 
470   regInit(winBuffer, force);
471 
472   loadSettings();
473 
474   if(!initDisplay()) {
475     if(videoOption >= VIDEO_320x240) {
476       regSetDwordValue("video", VIDEO_2X);
477     }
478     return FALSE;
479   }
480 
481   if(!initInput())
482     return FALSE;
483 
484   hAccel = LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCELERATOR));
485 
486   winAccelMgr.Connect((MainWnd *)m_pMainWnd);
487 
488   winAccelMgr.SetRegKey(HKEY_CURRENT_USER, "Software\\Emulators\\VisualBoyAdvance");
489 
490   extern void winAccelAddCommands(CAcceleratorManager&);
491 
492   winAccelAddCommands(winAccelMgr);
493 
494   winAccelMgr.CreateDefaultTable();
495 
496   winAccelMgr.Load();
497 
498   winAccelMgr.UpdateWndTable();
499 
500   winAccelMgr.UpdateMenu(menu);
501 
502   if( !filename.IsEmpty() ) {
503     if(((MainWnd*)m_pMainWnd)->FileRun())
504       emulating = true;
505     else
506       emulating = false;
507   }
508 
509   return TRUE;
510 }
511 
adjustDestRect()512 void VBA::adjustDestRect()
513 {
514   POINT point;
515 
516   point.x = 0;
517   point.y = 0;
518 
519   m_pMainWnd->ClientToScreen(&point);
520   dest.top = point.y;
521   dest.left = point.x;
522 
523   point.x = surfaceSizeX;
524   point.y = surfaceSizeY;
525 
526   m_pMainWnd->ClientToScreen(&point);
527   dest.bottom = point.y;
528   dest.right = point.x;
529 
530   // make sure that dest rect lies in the monitor
531   if(videoOption >= VIDEO_320x240) {
532     dest.top -= windowPositionY;
533     dest.left -= windowPositionX;
534     dest.bottom-= windowPositionY;
535     dest.right -= windowPositionX;
536   }
537 
538   if(videoOption > VIDEO_6X) {
539 	  if(fullScreenStretch) {
540 		  dest.top = 0;
541 		  dest.left = 0;
542 		  dest.right = fsWidth;
543 		  dest.bottom = fsHeight;
544 	  } else {
545 		  int top = (fsHeight - surfaceSizeY) / 2;
546 		  int left = (fsWidth - surfaceSizeX) / 2;
547 		  dest.top += top;
548 		  dest.bottom += top;
549 		  dest.left += left;
550 		  dest.right += left;
551 	  }
552   }
553 }
554 
555 
updateIFB()556 void VBA::updateIFB()
557 {
558   if(systemColorDepth == 16) {
559     switch(ifbType) {
560     case 0:
561     default:
562       ifbFunction = NULL;
563       break;
564     case 1:
565       ifbFunction = MotionBlurIB;
566       break;
567     case 2:
568       ifbFunction = SmartIB;
569       break;
570     }
571   } else if(systemColorDepth == 32) {
572     switch(ifbType) {
573     case 0:
574     default:
575       ifbFunction = NULL;
576       break;
577     case 1:
578       ifbFunction = MotionBlurIB32;
579       break;
580     case 2:
581       ifbFunction = SmartIB32;
582       break;
583     }
584   } else
585     ifbFunction = NULL;
586 }
587 
updateFilter()588 void VBA::updateFilter()
589 {
590 	// BEGIN hacky ugly code
591 
592 	// HQ3X asm wants 16 bit input.  When we switch
593 	// away from 16 bits we need to restore the driver values
594 
595 	// This hack is also necessary for Kega Fusion filter plugins
596 
597 	if ( b16to32Video )
598 	{
599 		b16to32Video = false;
600 		systemColorDepth = realsystemColorDepth;
601 		systemRedShift = realsystemRedShift;
602 		systemGreenShift = realsystemGreenShift;
603 		systemBlueShift = realsystemBlueShift;
604 		utilUpdateSystemColorMaps(theApp.cartridgeType == IMAGE_GBA && gbColorOption == 1);
605 	}
606     // END hacky ugly code
607 
608     filterWidth = sizeX;
609 	filterHeight = sizeY;
610 	filterMagnification = 1;
611 
612 
613 	if ( videoOption == VIDEO_1X || videoOption == VIDEO_320x240 )
614 	{
615 		filterFunction = NULL;
616 		filterMagnification = 1;
617 	}
618 	else
619 	{
620 		if ( systemColorDepth == 16 )
621 		{
622 		switch(filter)
623 		{
624 		default:
625 		case FILTER_NONE:
626 			filterFunction = NULL;
627 			filterMagnification = 1;
628 			break;
629         case FILTER_PLUGIN:
630 			if( rpiInit( pluginName ) ) {
631 				filterFunction = rpiFilter;
632 				filterMagnification = rpiScaleFactor();
633 			} else {
634 				filter = FILTER_NONE;
635 				updateFilter();
636 				return;
637 			}
638 		    break;
639 		case FILTER_TVMODE:
640 			filterFunction = ScanlinesTV;
641 			filterMagnification = 2;
642 			break;
643 		case FILTER_2XSAI:
644 			filterFunction = _2xSaI;
645 			filterMagnification = 2;
646 			break;
647 		case FILTER_SUPER2XSAI:
648 			filterFunction = Super2xSaI;
649 			filterMagnification = 2;
650 			break;
651 		case FILTER_SUPEREAGLE:
652 			filterFunction = SuperEagle;
653 			filterMagnification = 2;
654 			break;
655 		case FILTER_PIXELATE:
656 			filterFunction = Pixelate;
657 			filterMagnification = 2;
658 			break;
659 		case FILTER_MAMESCALE2X:
660 			filterFunction = AdMame2x;
661 			filterMagnification = 2;
662 			break;
663 		case FILTER_SIMPLE2X:
664 			filterFunction = Simple2x16;
665 			filterMagnification = 2;
666 			break;
667 		case FILTER_BILINEAR:
668 			filterFunction = Bilinear;
669 			filterMagnification = 2;
670 			break;
671 		case FILTER_BILINEARPLUS:
672 			filterFunction = BilinearPlus;
673 			filterMagnification = 2;
674 			break;
675 		case FILTER_SCANLINES:
676 			filterFunction = Scanlines;
677 			filterMagnification = 2;
678 			break;
679 		case FILTER_HQ2X:
680 			filterFunction = hq2x;
681 			filterMagnification = 2;
682 			break;
683 		case FILTER_LQ2X:
684 			filterFunction = lq2x;
685 			filterMagnification = 2;
686 			break;
687 		case FILTER_SIMPLE3X:
688 			filterFunction = Simple3x16;
689 			filterMagnification = 3;
690 			break;
691 		case FILTER_SIMPLE4X:
692 			filterFunction = Simple4x16;
693 			filterMagnification = 4;
694 			break;
695 #ifndef WIN64
696 		case FILTER_HQ3X:
697 			filterFunction = hq3x16;
698 			filterMagnification = 3;
699 			break;
700 		case FILTER_HQ4X:
701 			filterFunction = hq4x16;
702 			filterMagnification = 4;
703 			break;
704 #endif
705 		}
706 		}
707 
708 		if ( systemColorDepth == 32 )
709 		{
710 			switch(filter)
711 			{
712 			default:
713 			case FILTER_NONE:
714 				filterFunction = NULL;
715 				filterMagnification = 1;
716 				break;
717             case FILTER_PLUGIN:
718 				if( rpiInit( pluginName ) ) {
719 					filterFunction = rpiFilter;
720 					filterMagnification = rpiScaleFactor();
721 					b16to32Video=true;
722 				} else {
723 					filter = FILTER_NONE;
724 					updateFilter();
725 					return;
726 				}
727 				break;
728 			case FILTER_TVMODE:
729 				filterFunction = ScanlinesTV32;
730 				filterMagnification = 2;
731 				break;
732 			case FILTER_2XSAI:
733 				filterFunction = _2xSaI32;
734 				filterMagnification = 2;
735 				break;
736 			case FILTER_SUPER2XSAI:
737 				filterFunction = Super2xSaI32;
738 				filterMagnification = 2;
739 				break;
740 			case FILTER_SUPEREAGLE:
741 				filterFunction = SuperEagle32;
742 				filterMagnification = 2;
743 				break;
744 			case FILTER_PIXELATE:
745 				filterFunction = Pixelate32;
746 				filterMagnification = 2;
747 				break;
748 			case FILTER_MAMESCALE2X:
749 				filterFunction = AdMame2x32;
750 				filterMagnification = 2;
751 				break;
752 			case FILTER_SIMPLE2X:
753 				filterFunction = Simple2x32;
754 				filterMagnification = 2;
755 				break;
756 			case FILTER_BILINEAR:
757 				filterFunction = Bilinear32;
758 				filterMagnification = 2;
759 				break;
760 			case FILTER_BILINEARPLUS:
761 				filterFunction = BilinearPlus32;
762 				filterMagnification = 2;
763 				break;
764 			case FILTER_SCANLINES:
765 				filterFunction = Scanlines32;
766 				filterMagnification = 2;
767 				break;
768 			case FILTER_HQ2X:
769 				filterFunction = hq2x32;
770 				filterMagnification = 2;
771 				break;
772 			case FILTER_LQ2X:
773 				filterFunction = lq2x32;
774 				filterMagnification = 2;
775 				break;
776 			case FILTER_SIMPLE3X:
777 				filterFunction = Simple3x32;
778 				filterMagnification = 3;
779 				break;
780 			case FILTER_SIMPLE4X:
781 				filterFunction = Simple4x32;
782 				filterMagnification = 4;
783 				break;
784 #ifndef WIN64
785 			case FILTER_HQ3X:
786 				filterFunction = hq3x32;
787 				filterMagnification = 3;
788 #ifndef NO_ASM
789 				b16to32Video=true;
790 #endif
791 				break;
792 			case FILTER_HQ4X:
793 				filterFunction = hq4x32;
794 				filterMagnification = 4;
795 #ifndef NO_ASM
796 				b16to32Video=true;
797 #endif
798 				break;
799 #endif
800 			case FILTER_XBRZ2X:
801 				filterFunction = xbrz2x32;
802 				filterMagnification = 2;
803 				break;
804 			case FILTER_XBRZ3X:
805 				filterFunction = xbrz3x32;
806 				filterMagnification = 3;
807 				break;
808 			case FILTER_XBRZ4X:
809 				filterFunction = xbrz4x32;
810 				filterMagnification = 4;
811 				break;
812 			case FILTER_XBRZ5X:
813 				filterFunction = xbrz5x32;
814 				filterMagnification = 5;
815 				break;
816 			case FILTER_XBRZ6X:
817 				filterFunction = xbrz6x32;
818 				filterMagnification = 6;
819 				break;
820 			}
821 		}
822 	}
823 
824 	rect.right = sizeX * filterMagnification;
825 	rect.bottom = sizeY * filterMagnification;
826 
827 
828 	if( filter != FILTER_NONE )
829 		memset(delta, 0xFF, sizeof(delta));
830 
831 	if( display )
832 		display->changeRenderSize(rect.right, rect.bottom);
833 
834 	if (b16to32Video && systemColorDepth!=16)
835 	{
836 		realsystemColorDepth = systemColorDepth;
837 		systemColorDepth = 16;
838 		realsystemRedShift = systemRedShift;
839 		systemRedShift = 11;
840 		realsystemGreenShift = systemGreenShift;
841 		systemGreenShift = 6;
842 		realsystemBlueShift = systemBlueShift;
843 		systemBlueShift = 0;
844 		utilUpdateSystemColorMaps(theApp.cartridgeType == IMAGE_GBA && gbColorOption == 1);
845 	}
846 
847 #ifdef LOG_PERFORMANCE
848 	memset( systemSpeedTable, 0x00, sizeof(systemSpeedTable) );
849 	systemSpeedCounter = 0;
850 #endif
851 }
852 
853 
updateThrottle(unsigned short _throttle)854 void VBA::updateThrottle( unsigned short _throttle )
855 {
856 	if( _throttle ) {
857 		Sm60FPS::K_fCpuSpeed = (float)_throttle;
858 		Sm60FPS::K_fTargetFps = 60.0f * Sm60FPS::K_fCpuSpeed / 100;
859 		Sm60FPS::K_fDT = 1000.0f / Sm60FPS::K_fTargetFps;
860 		autoFrameSkip = false;
861 		frameSkip = 0;
862 		systemFrameSkip = 0;
863 	}
864 
865 	throttle = _throttle;
866 	soundSetThrottle(_throttle);
867 }
868 
869 
updateMenuBar()870 void VBA::updateMenuBar()
871 {
872   if(menu != NULL) {
873     if(m_pMainWnd)
874       m_pMainWnd->SetMenu(NULL);
875     m_menu.Detach();
876     DestroyMenu(menu);
877   }
878 
879   if(popup != NULL) {
880     // force popup recreation if language changed
881     DestroyMenu(popup);
882     popup = NULL;
883   }
884 
885   if( ( videoOption >= VIDEO_320x240 ) ) {
886 	  return;
887   }
888 
889   m_menu.Attach(winResLoadMenu(MAKEINTRESOURCE(IDR_MENU)));
890   menu = (HMENU)m_menu;
891 
892   if(m_pMainWnd)
893       m_pMainWnd->SetMenu(&m_menu);
894 }
895 
log(const char * msg,...)896 void log(const char *msg, ...)
897 {
898   CString buffer;
899   va_list valist;
900 
901   va_start(valist, msg);
902   buffer.FormatV(msg, valist);
903 
904   toolsLog(buffer);
905 
906   va_end(valist);
907 }
908 
systemReadJoypads()909 bool systemReadJoypads()
910 {
911   if(theApp.input)
912     return theApp.input->readDevices();
913   return false;
914 }
915 
systemReadJoypad(int which)916 u32 systemReadJoypad(int which)
917 {
918   if(theApp.input)
919     return theApp.input->readDevice(which);
920   return 0;
921 }
922 
923 static u8 sensorDarkness = 0xE8; // total darkness (including daylight on rainy days)
924 
925 // TODO: implement
systemCartridgeRumble(bool)926 void systemCartridgeRumble(bool) { }
systemPossibleCartridgeRumble(bool)927 void systemPossibleCartridgeRumble(bool) { }
updateRumbleFrame()928 void updateRumbleFrame() { }
systemGetSensorZ()929 int systemGetSensorZ() { return 0; }
930 
systemGetSensorDarkness()931 u8 systemGetSensorDarkness()
932 {
933 	return sensorDarkness;
934 }
935 
systemDrawScreen()936 void systemDrawScreen()
937 {
938   if(theApp.display == NULL)
939     return;
940 
941   renderedFrames++;
942 
943   if(theApp.updateCount) {
944     POSITION pos = theApp.updateList.GetHeadPosition();
945     while(pos) {
946       IUpdateListener *up = theApp.updateList.GetNext(pos);
947       up->update();
948     }
949   }
950 
951   if (Sm60FPS_CanSkipFrame())
952 	  return;
953 
954   if( aviRecording ) {
955 	  if (theApp.painting) {
956 		  theApp.skipAudioFrames++;
957 	  } else {
958 		  unsigned char *bmp;
959 		  unsigned short srcPitch = sizeX * ( systemColorDepth >> 3 ) + 4;
960 		  switch( systemColorDepth )
961 		  {
962 		  case 16:
963 			  bmp = new unsigned char[ sizeX * sizeY * 2 ];
964 			  cpyImg16bmp( bmp, pix + srcPitch, srcPitch, sizeX, sizeY );
965 			  break;
966 		  case 32:
967 			  // use 24 bit colors to reduce video size
968 			  bmp = new unsigned char[ sizeX * sizeY * 3 ];
969 			  cpyImg32bmp( bmp, pix + srcPitch, srcPitch, sizeX, sizeY );
970 			  break;
971 		  }
972 		  if( false == theApp.aviRecorder->AddVideoFrame( bmp ) ) {
973 			  systemMessage( IDS_AVI_CANNOT_WRITE_VIDEO, "Cannot write video frame to AVI file." );
974 			  delete theApp.aviRecorder;
975 			  theApp.aviRecorder = NULL;
976 			  aviRecording = false;
977 		  }
978 		  delete [] bmp;
979 	  }
980   }
981 
982   if( theApp.ifbFunction ) {
983 	  theApp.ifbFunction( pix + (filterWidth * (systemColorDepth>>3)) + 4,
984 		  (filterWidth * (systemColorDepth>>3)) + 4,
985 		  filterWidth, filterHeight );
986   }
987 
988   if(!soundBufferLow)
989   {
990 	  theApp.display->render();
991       Sm60FPS_Sleep();
992   }
993   else
994 	  soundBufferLow = false;
995 
996 }
997 
systemScreenCapture(int captureNumber)998 void systemScreenCapture(int captureNumber)
999 {
1000   if(theApp.m_pMainWnd)
1001     ((MainWnd *)theApp.m_pMainWnd)->screenCapture(captureNumber);
1002 }
1003 
systemGetClock()1004 u32 systemGetClock()
1005 {
1006   return GetTickCount();
1007 }
1008 
systemMessage(int number,const char * defaultMsg,...)1009 void systemMessage(int number, const char *defaultMsg, ...)
1010 {
1011   CString buffer;
1012   va_list valist;
1013   CString msg = defaultMsg;
1014   if(number)
1015     msg = winResLoadString(number);
1016 
1017   va_start(valist, defaultMsg);
1018   buffer.FormatV(msg, valist);
1019 
1020   CWnd *win = AfxGetApp()->GetMainWnd();
1021   if (win)
1022     win = win->GetLastActivePopup(); // possible modal dialog
1023   if (!win)
1024     win = AfxGetApp()->m_pMainWnd;
1025   win->MessageBox(buffer, winResLoadString(IDS_ERROR), MB_OK|MB_ICONERROR);
1026 
1027   va_end(valist);
1028 }
1029 
systemSetTitle(const char * title)1030 void systemSetTitle(const char *title)
1031 {
1032   if(theApp.m_pMainWnd != NULL) {
1033     AfxGetApp()->m_pMainWnd->SetWindowText(title);
1034   }
1035 }
1036 
systemShowSpeed(int speed)1037 void systemShowSpeed(int speed)
1038 {
1039   systemSpeed = speed;
1040   showRenderedFrames = renderedFrames;
1041   renderedFrames = 0;
1042   if(videoOption <= VIDEO_6X && showSpeed) {
1043     CString buffer;
1044     if(showSpeed == 1)
1045       buffer.Format(VBA_NAME_AND_SUBVERSION "-%3d%%", systemSpeed);
1046     else
1047       buffer.Format(VBA_NAME_AND_SUBVERSION "-%3d%%(%d, %d fps)", systemSpeed,
1048                     systemFrameSkip,
1049                     showRenderedFrames);
1050 
1051     systemSetTitle(buffer);
1052   }
1053 }
1054 
1055 
systemFrame()1056 void systemFrame()
1057 {
1058 	if( movieRecording || moviePlaying ) {
1059 		movieFrame++;
1060 	}
1061 
1062 #ifdef LOG_PERFORMANCE
1063 	systemSpeedTable[systemSpeedCounter++ % PERFORMANCE_INTERVAL] = systemSpeed;
1064 #endif
1065 }
1066 
1067 
system10Frames(int rate)1068 void system10Frames(int rate)
1069 {
1070 
1071 	if( autoFrameSkip )
1072 	{
1073 		u32 time = systemGetClock();
1074 		u32 diff = time - autoFrameSkipLastTime;
1075 		autoFrameSkipLastTime = time;
1076 		if( diff ) {
1077 			// countermeasure against div/0 when debugging
1078 			Sm60FPS::nCurSpeed = (1000000/rate)/diff;
1079 		} else {
1080 			Sm60FPS::nCurSpeed = 100;
1081 		}
1082 	}
1083 
1084 
1085   if(theApp.rewindMemory) {
1086     if(++rewindCounter >= (rewindTimer)) {
1087       rewindSaveNeeded = true;
1088       rewindCounter = 0;
1089     }
1090   }
1091   if(systemSaveUpdateCounter) {
1092     if(--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED) {
1093       ((MainWnd *)theApp.m_pMainWnd)->writeBatteryFile();
1094       systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
1095     }
1096   }
1097 
1098   wasPaused = false;
1099 
1100 //  Old autoframeskip crap... might be useful later. autoframeskip Ifdef above might be useless as well now
1101 //  autoFrameSkipLastTime = time;
1102 
1103 #ifdef LOG_PERFORMANCE
1104   if( systemSpeedCounter >= PERFORMANCE_INTERVAL ) {
1105 	  // log performance every PERFORMANCE_INTERVAL frames
1106 	  float a = 0.0f;
1107 	  for( unsigned short i = 0 ; i < PERFORMANCE_INTERVAL ; i++ ) {
1108 		  a += (float)systemSpeedTable[i];
1109 	  }
1110 	  a /= (float)PERFORMANCE_INTERVAL;
1111 	  log( _T("Speed: %f\n"), a );
1112 	  systemSpeedCounter = 0;
1113   }
1114 #endif
1115 }
1116 
systemScreenMessage(const char * msg)1117 void systemScreenMessage(const char *msg)
1118 {
1119   screenMessage = true;
1120   theApp.screenMessageTime = GetTickCount();
1121   theApp.screenMessageBuffer = msg;
1122 
1123   if(theApp.screenMessageBuffer.GetLength() > 40)
1124     theApp.screenMessageBuffer = theApp.screenMessageBuffer.Left(40);
1125 }
1126 
systemUpdateSolarSensor()1127 void systemUpdateSolarSensor()
1128 {
1129 	u8 sun = 0x0; //sun = 0xE8 - 0xE8 (case 0 and default)
1130 	int level = sunBars / 10;
1131 	switch (level)
1132 	{
1133 	case 1:
1134 		sun = 0xE8 - 0xE0;
1135 		break;
1136 	case 2:
1137 		sun = 0xE8 - 0xDA;
1138 		break;
1139 	case 3:
1140 		sun = 0xE8 - 0xD0;
1141 		break;
1142 	case 4:
1143 		sun = 0xE8 - 0xC8;
1144 		break;
1145 	case 5:
1146 		sun = 0xE8 - 0xC0;
1147 		break;
1148 	case 6:
1149 		sun = 0xE8 - 0xB0;
1150 		break;
1151 	case 7:
1152 		sun = 0xE8 - 0xA0;
1153 		break;
1154 	case 8:
1155 		sun = 0xE8 - 0x88;
1156 		break;
1157 	case 9:
1158 		sun = 0xE8 - 0x70;
1159 		break;
1160 	case 10:
1161 		sun = 0xE8 - 0x50;
1162 		break;
1163 	default:
1164 		break;
1165 	}
1166 	struct tm *newtime;
1167 	time_t long_time;
1168 	// regardless of the weather, there should be no sun at night time!
1169 	time(&long_time); // Get time as long integer.
1170 	newtime = localtime(&long_time); // Convert to local time.
1171 	if (newtime->tm_hour > 21 || newtime->tm_hour < 5)
1172 	{
1173 		sun = 0; // total darkness, 9pm - 5am
1174 	}
1175 	else if (newtime->tm_hour > 20 || newtime->tm_hour < 6)
1176 	{
1177 		sun /= 9; // almost total darkness 8pm-9pm, 5am-6am
1178 	}
1179 	else if (newtime->tm_hour > 18 || newtime->tm_hour < 7)
1180 	{
1181 		sun >>= 1;
1182 	}
1183 	sensorDarkness = 0xE8 - sun;
1184 }
1185 
systemUpdateMotionSensor()1186 void systemUpdateMotionSensor()
1187 {
1188   if(theApp.input)
1189     theApp.input->checkMotionKeys();
1190 
1191   systemUpdateSolarSensor();
1192 }
1193 
systemGetSensorX()1194 int systemGetSensorX()
1195 {
1196   return sensorX;
1197 }
1198 
systemGetSensorY()1199 int systemGetSensorY()
1200 {
1201   return sensorY;
1202 }
1203 
1204 
systemSoundInit()1205 SoundDriver * systemSoundInit()
1206 {
1207 	SoundDriver * drv = 0;
1208 	soundShutdown();
1209 
1210 	switch( theApp.audioAPI )
1211 	{
1212 	case DIRECTSOUND:
1213 		drv = newDirectSound();
1214 		break;
1215 #ifndef NO_OAL
1216 	case OPENAL_SOUND:
1217 		drv = newOpenAL();
1218 		break;
1219 #endif
1220 #ifndef NO_XAUDIO2
1221 	case XAUDIO2:
1222 		drv = newXAudio2_Output();
1223 		break;
1224 #endif
1225 	}
1226 
1227 	if( drv ) {
1228 		if (throttle)
1229 		drv->setThrottle( throttle );
1230 	}
1231 
1232 	return drv;
1233 }
1234 
1235 
systemOnSoundShutdown()1236 void systemOnSoundShutdown()
1237 {
1238 	if( theApp.aviRecorder ) {
1239 		delete theApp.aviRecorder;
1240 		theApp.aviRecorder = NULL;
1241 	}
1242 	aviRecording = false;
1243 
1244 
1245 	if( theApp.soundRecorder ) {
1246 		delete theApp.soundRecorder;
1247 		theApp.soundRecorder = NULL;
1248 	}
1249 	soundRecording = false;
1250 }
1251 
systemOnWriteDataToSoundBuffer(const u16 * finalWave,int length)1252 void systemOnWriteDataToSoundBuffer(const u16 * finalWave, int length)
1253 {
1254 	if( soundRecording ) {
1255 		if( theApp.soundRecorder ) {
1256 			theApp.soundRecorder->AddSound( (const u8 *)finalWave, length );
1257 		} else {
1258 			WAVEFORMATEX format;
1259 			format.cbSize = 0;
1260 			format.wFormatTag = WAVE_FORMAT_PCM;
1261 			format.nChannels = 2;
1262 			format.nSamplesPerSec = soundGetSampleRate();
1263 			format.wBitsPerSample = 16;
1264 			format.nBlockAlign = format.nChannels * ( format.wBitsPerSample >> 3 );
1265 			format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
1266 			theApp.soundRecorder = new WavWriter;
1267 			if( theApp.soundRecorder->Open( theApp.soundRecordName ) ) {
1268 				theApp.soundRecorder->SetFormat( &format );
1269 			}
1270 		}
1271 	}
1272 
1273 	if( aviRecording && theApp.aviRecorder ) {
1274 		if( theApp.skipAudioFrames ) {
1275 			theApp.skipAudioFrames--;
1276 		} else {
1277 			if( false == theApp.aviRecorder->AddAudioFrame( ( u8 *)finalWave ) ) {
1278 				systemMessage( IDS_AVI_CANNOT_WRITE_AUDIO, "Cannot write audio frame to AVI file." );
1279 				delete theApp.aviRecorder;
1280 				theApp.aviRecorder = NULL;
1281 				aviRecording = false;
1282 			}
1283 		}
1284 	}
1285 }
1286 
systemCanChangeSoundQuality()1287 bool systemCanChangeSoundQuality()
1288 {
1289   return true;
1290 }
1291 
systemPauseOnFrame()1292 bool systemPauseOnFrame()
1293 {
1294   if(winPauseNextFrame) {
1295     paused = true;
1296     winPauseNextFrame = false;
1297     return true;
1298   }
1299   return false;
1300 }
1301 
systemGbBorderOn()1302 void systemGbBorderOn()
1303 {
1304   if(emulating && theApp.cartridgeType == IMAGE_GB && gbBorderOn) {
1305     theApp.updateWindowSize(videoOption);
1306   }
1307 }
1308 
OnIdle(LONG lCount)1309 BOOL VBA::OnIdle(LONG lCount)
1310 {
1311   if(emulating && debugger) {
1312     MSG msg;
1313     remoteStubMain();
1314     if(debugger)
1315       return TRUE; // continue loop
1316     return !::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE);
1317   } else if(emulating && active && !paused) {
1318       emulator.emuMain(emulator.emuCount);
1319 
1320       if(rewindSaveNeeded && rewindMemory && emulator.emuWriteMemState) {
1321         rewindCount++;
1322         if(rewindCount > 8)
1323           rewindCount = 8;
1324         long resize;
1325         if(emulator.emuWriteMemState(&rewindMemory[rewindPos*REWIND_SIZE],
1326                                      REWIND_SIZE, resize)) { /* available and actual size */
1327           rewindPos = ++rewindPos & 7;
1328           if(rewindCount == 8)
1329             rewindTopPos = ++rewindTopPos & 7;
1330         }
1331       }
1332 
1333       rewindSaveNeeded = false;
1334 
1335     if(mouseCounter) {
1336       if(--mouseCounter == 0) {
1337         SetCursor(NULL);
1338       }
1339     }
1340     return TRUE;
1341   }
1342   return FALSE;
1343 
1344   //  return CWinApp::OnIdle(lCount);
1345 }
1346 
addRecentFile(CString file)1347 void VBA::addRecentFile(CString file)
1348 {
1349   // Do not change recent list if frozen
1350   if(recentFreeze)
1351     return;
1352   int i = 0;
1353   for(i = 0; i < 10; i++) {
1354     if(recentFiles[i].GetLength() == 0)
1355       break;
1356 
1357     if(recentFiles[i].Compare(file) == 0) {
1358       if(i == 0)
1359         return;
1360       CString p = recentFiles[i];
1361       for(int j = i; j > 0; j--) {
1362         recentFiles[j] = recentFiles[j-1];
1363       }
1364       recentFiles[0] = p;
1365       return;
1366     }
1367   }
1368   int num = 0;
1369   for(i = 0; i < 10; i++) {
1370     if(recentFiles[i].GetLength() != 0)
1371       num++;
1372   }
1373   if(num == 10) {
1374     num--;
1375   }
1376 
1377   for(i = num; i >= 1; i--) {
1378     recentFiles[i] = recentFiles[i-1];
1379   }
1380   recentFiles[0] = file;
1381 }
1382 
loadSettings()1383 void VBA::loadSettings()
1384 {
1385   CString buffer;
1386 
1387   lastFullscreen = (VIDEO_SIZE)regQueryDwordValue("lastFullscreen", VIDEO_1024x768);
1388 
1389   languageOption = regQueryDwordValue("language", 1);
1390   if(languageOption < 0 || languageOption > 2)
1391     languageOption = 1;
1392 
1393   buffer = regQueryStringValue("languageName", "");
1394   if(!buffer.IsEmpty()) {
1395     languageName = buffer.Left(3);
1396   } else
1397     languageName = "";
1398 
1399   winSetLanguageOption(languageOption, true);
1400 
1401   frameSkip = regQueryDwordValue("frameSkip", 0);
1402   if(frameSkip < 0 || frameSkip > 9)
1403     frameSkip = 0;
1404 
1405   gbFrameSkip = regQueryDwordValue("gbFrameSkip", 0);
1406   if(gbFrameSkip < 0 || gbFrameSkip > 9)
1407     gbFrameSkip = 0;
1408 
1409   autoFrameSkip = regQueryDwordValue("autoFrameSkip", FALSE) ? TRUE : FALSE;
1410 
1411   vsync = regQueryDwordValue("vsync", false) ? true : false ;
1412   fullScreenStretch = regQueryDwordValue("stretch", 0) ? true : false;
1413 
1414   videoOption = regQueryDwordValue("video", VIDEO_3X);
1415 
1416   strcpy(pluginName, regQueryStringValue("pluginName", ""));
1417 
1418   if(videoOption < VIDEO_1X || videoOption > VIDEO_OTHER)
1419     videoOption = VIDEO_3X;
1420 
1421   fsAdapter = regQueryDwordValue("fsAdapter", 0);
1422   fsWidth = regQueryDwordValue("fsWidth", 800);
1423   fsHeight = regQueryDwordValue("fsHeight", 600);
1424   fsColorDepth = regQueryDwordValue("fsColorDepth", 32);
1425   fsFrequency = regQueryDwordValue("fsFrequency", 60);
1426 
1427   if(videoOption == VIDEO_OTHER) {
1428     if(fsWidth < 0 || fsWidth > 4095 || fsHeight < 0 || fsHeight > 4095)
1429       videoOption = 0;
1430     if(fsColorDepth != 16 && fsColorDepth != 24 && fsColorDepth != 32)
1431       videoOption = 0;
1432   }
1433 
1434   renderMethod = (DISPLAY_TYPE)regQueryDwordValue("renderMethod", DIRECT_3D);
1435 #ifdef NO_OGL
1436   if( renderMethod == OPENGL ) {
1437 	  renderMethod = DIRECT_3D;
1438   }
1439 #endif
1440 #ifdef NO_D3D
1441   if( renderMethod == DIRECT_3D ) {
1442 	  renderMethod = OPENGL;
1443   }
1444 #endif
1445 #ifndef NO_XAUDIO2
1446   audioAPI = (AUDIO_API)regQueryDwordValue( "audioAPI", XAUDIO2 );
1447 #else
1448   audioAPI = (AUDIO_API)regQueryDwordValue( "audioAPI", DIRECTSOUND );
1449 #endif
1450   if( ( audioAPI != DIRECTSOUND )
1451 #ifndef NO_OAL
1452 	  && ( audioAPI != OPENAL_SOUND )
1453 #endif
1454 #ifndef NO_XAUDIO2
1455 	  && ( audioAPI != XAUDIO2 )
1456 #endif
1457 	  ) {
1458 #ifndef NO_XAUDIO2
1459         audioAPI = XAUDIO2;
1460 #else
1461         audioAPI = DIRECTSOUND;
1462 #endif
1463   }
1464 
1465   windowPositionX = regQueryDwordValue("windowX", 0);
1466   if(windowPositionX < 0)
1467     windowPositionX = 0;
1468   windowPositionY = regQueryDwordValue("windowY", 0);
1469   if(windowPositionY < 0)
1470     windowPositionY = 0;
1471 
1472   maxCpuCores = regQueryDwordValue("maxCpuCores", 0);
1473   if(maxCpuCores == 0) {
1474 	  maxCpuCores = detectCpuCores();
1475   }
1476 
1477   useBiosFileGBA = ( regQueryDwordValue("useBiosGBA", 0) == 1 ) ? true : false;
1478 
1479   useBiosFileGBC = ( regQueryDwordValue("useBiosGBC", 0) == 1 ) ? true : false;
1480 
1481   useBiosFileGB = ( regQueryDwordValue("useBiosGB", 0) == 1 ) ? true : false;
1482 
1483   skipBios = regQueryDwordValue("skipBios", 0) ? true : false;
1484 
1485   buffer = regQueryStringValue("biosFileGBA", "");
1486 
1487   if(!buffer.IsEmpty()) {
1488     biosFileNameGBA = buffer;
1489   }
1490 
1491   buffer = regQueryStringValue("biosFileGBC", "");
1492 
1493   if(!buffer.IsEmpty()) {
1494     biosFileNameGBC = buffer;
1495   }
1496 
1497   buffer = regQueryStringValue("biosFileGB", "");
1498 
1499   if(!buffer.IsEmpty()) {
1500     biosFileNameGB = buffer;
1501   }
1502 
1503   int res = regQueryDwordValue("soundEnable", 0x30f);
1504   soundSetEnable(res);
1505 
1506   long soundQuality = regQueryDwordValue("soundQuality", 1);
1507   soundSetSampleRate(44100 / soundQuality);
1508 
1509   soundSetVolume( (float)(regQueryDwordValue("soundVolume", 100)) / 100.0f );
1510 
1511 	gb_effects_config.enabled = 1 == regQueryDwordValue( "gbSoundEffectsEnabled", 0 );
1512 	gb_effects_config.surround = 1 == regQueryDwordValue( "gbSoundEffectsSurround", 0 );
1513 	gb_effects_config.echo = (float)regQueryDwordValue( "gbSoundEffectsEcho", 20 ) / 100.0f;
1514 	gb_effects_config.stereo = (float)regQueryDwordValue( "gbSoundEffectsStereo", 15 ) / 100.0f;
1515 
1516 	gbSoundSetDeclicking( 1 == regQueryDwordValue( "gbSoundDeclicking", 1 ) );
1517 
1518 	soundInterpolation = 1 == regQueryDwordValue( "gbaSoundInterpolation", 1 );
1519 	soundFiltering = (float)regQueryDwordValue( "gbaSoundFiltering", 50 ) / 100.0f;
1520 
1521   tripleBuffering = regQueryDwordValue("tripleBuffering", false) ? true : false;
1522 
1523 #ifndef NO_D3D
1524   d3dFilter = regQueryDwordValue("d3dFilter", 1);
1525   if(d3dFilter < 0 || d3dFilter > 1)
1526     d3dFilter = 1;
1527 
1528   d3dMotionBlur = ( regQueryDwordValue("d3dMotionBlur", 0) == 1 ) ? true : false;
1529 #endif
1530 
1531   glFilter = regQueryDwordValue("glFilter", 1);
1532   if(glFilter < 0 || glFilter > 1)
1533     glFilter = 1;
1534 
1535 
1536   filter = regQueryDwordValue("filter", 0);
1537   if(filter < FILTER_NONE || filter > FILTER_LAST)
1538     filter = FILTER_NONE;
1539 
1540   filterMT = ( 1 == regQueryDwordValue("filterEnableMultiThreading", 0) );
1541 
1542   disableMMX = regQueryDwordValue("disableMMX", false) ? true: false;
1543 
1544   disableStatusMessages = regQueryDwordValue("disableStatus", 0) ? true : false;
1545 
1546   showSpeed = regQueryDwordValue("showSpeed", 0);
1547   if(showSpeed < 0 || showSpeed > 2)
1548     showSpeed = 0;
1549 
1550   showSpeedTransparent = regQueryDwordValue("showSpeedTransparent", TRUE) ?
1551     TRUE : FALSE;
1552 
1553   winGbPrinterEnabled = regQueryDwordValue("gbPrinter", false) ? true : false;
1554 
1555   if(winGbPrinterEnabled)
1556     gbSerialFunction = gbPrinterSend;
1557   else
1558 #ifndef NO_LINK
1559     gbSerialFunction = gbStartLink;
1560 #else
1561 	gbSerialFunction = NULL;
1562 #endif
1563 
1564   pauseWhenInactive = regQueryDwordValue("pauseWhenInactive", 1) ?
1565     true : false;
1566   captureFormat = regQueryDwordValue("captureFormat", 0);
1567 
1568   recentFreeze = regQueryDwordValue("recentFreeze", false) ? true : false;
1569 
1570   autoPatch = regQueryDwordValue("autoPatch", 1) == 1 ? true : false;
1571 
1572   cpuDisableSfx = regQueryDwordValue("disableSfx", 0) ? true : false;
1573 
1574   cpuSaveType = regQueryDwordValue("saveType", 0);
1575   if(cpuSaveType < 0 || cpuSaveType > 5)
1576     cpuSaveType = 0;
1577 
1578   ifbType = (IFBFilter)regQueryDwordValue("ifbType", 0);
1579   if(ifbType < 0 || ifbType > 2)
1580     ifbType = kIFBNone;
1581 
1582   winFlashSize = regQueryDwordValue("flashSize", 0x10000);
1583   if(winFlashSize != 0x10000 && winFlashSize != 0x20000)
1584     winFlashSize = 0x10000;
1585 
1586   agbPrintEnable(regQueryDwordValue("agbPrint", 0) ? true : false);
1587 
1588   rtcEnabled = regQueryDwordValue("rtcEnabled", 0) ? true : false;
1589   rtcEnable(rtcEnabled);
1590 
1591   switch(videoOption) {
1592   case VIDEO_320x240:
1593     fsWidth = 320;
1594     fsHeight = 240;
1595     fsColorDepth = 16;
1596 	fsFrequency = 60;
1597     break;
1598   case VIDEO_640x480:
1599     fsWidth = 640;
1600     fsHeight = 480;
1601     fsColorDepth = 16;
1602 	fsFrequency = 60;
1603 	break;
1604   case VIDEO_800x600:
1605     fsWidth = 800;
1606     fsHeight = 600;
1607     fsColorDepth = 16;
1608 	fsFrequency = 60;
1609 	break;
1610   case VIDEO_1024x768:
1611     fsWidth = 1024;
1612     fsHeight = 768;
1613     fsColorDepth = 16;
1614 	fsFrequency = 60;
1615 	break;
1616   case VIDEO_1280x1024:
1617     fsWidth = 1280;
1618     fsHeight = 1024;
1619     fsColorDepth = 16;
1620 	fsFrequency = 60;
1621 	break;
1622   }
1623 
1624   winGbBorderOn = regQueryDwordValue("borderOn", 0);
1625   gbBorderAutomatic = regQueryDwordValue("borderAutomatic", 0);
1626   gbEmulatorType = regQueryDwordValue("emulatorType", 1);
1627   if(gbEmulatorType < 0 || gbEmulatorType > 5)
1628     gbEmulatorType = 1;
1629   gbColorOption = regQueryDwordValue("colorOption", 0);
1630 
1631   threadPriority = regQueryDwordValue("priority", 2);
1632 
1633   if(threadPriority < 0 || threadPriority >3)
1634     threadPriority = 2;
1635   updatePriority();
1636 
1637   autoSaveLoadCheatList = ( 1 == regQueryDwordValue( "autoSaveCheatList", 1 ) ) ? true : false;
1638 
1639   gbPaletteOption = regQueryDwordValue("gbPaletteOption", 0);
1640   if(gbPaletteOption < 0)
1641     gbPaletteOption = 0;
1642   if(gbPaletteOption > 2)
1643     gbPaletteOption = 2;
1644 
1645   regQueryBinaryValue("gbPalette", (char *)systemGbPalette,
1646                       24*sizeof(u16));
1647 
1648   rewindTimer = regQueryDwordValue("rewindTimer", 0);
1649 
1650   if(rewindTimer < 0 || rewindTimer > 600)
1651     rewindTimer = 0;
1652 
1653   rewindTimer *= 6; // convert to 10 frames multiple
1654 
1655   if(rewindTimer != 0)
1656     rewindMemory = (char *)malloc(8*REWIND_SIZE);
1657 
1658   for(int i = 0; i < 10; i++) {
1659     buffer.Format("recent%d", i);
1660     char *s = regQueryStringValue(buffer, NULL);
1661     if(s == NULL)
1662       break;
1663     recentFiles[i] = s;
1664   }
1665 
1666   joypadDefault = regQueryDwordValue("joypadDefault", 0);
1667   if(joypadDefault < 0 || joypadDefault > 3)
1668     joypadDefault = 0;
1669 
1670   autoLoadMostRecent = ( 1 == regQueryDwordValue("autoLoadMostRecent", 0) ) ? true : false;
1671 
1672   skipSaveGameBattery = ( 1 == regQueryDwordValue("skipSaveGameBattery", 0) ) ? true : false;
1673 
1674   skipSaveGameCheats = ( 1 == regQueryDwordValue("skipSaveGameCheats", 0) ) ? true : false;
1675 
1676   cheatsEnabled = regQueryDwordValue("cheatsEnabled", false) ? true : false;
1677 
1678   maxScale = regQueryDwordValue("maxScale", 0);
1679 
1680   updateThrottle( (unsigned short)regQueryDwordValue( "throttle", 0 ) );
1681 
1682 #ifndef NO_LINK
1683   linkTimeout = regQueryDwordValue("LinkTimeout", 1);
1684 
1685   linkMode = regQueryDwordValue("LinkMode", LINK_DISCONNECTED);
1686 
1687   linkHostAddr = regQueryStringValue("LinkHostAddr", "localhost");
1688 
1689   linkAuto = regQueryDwordValue("LinkAuto", true);
1690 
1691   linkHacks = regQueryDwordValue("LinkHacks", false);
1692 
1693   linkNumPlayers = regQueryDwordValue("LinkNumPlayers", 2);
1694 #endif
1695 
1696   gdbPort = regQueryDwordValue("gdbPort", 55555);
1697   gdbBreakOnLoad = regQueryDwordValue("gdbBreakOnLoad", false) ? true : false;
1698 
1699   Sm60FPS::bSaveMoreCPU = regQueryDwordValue("saveMoreCPU", 0);
1700 
1701 #ifndef NO_OAL
1702   buffer = regQueryStringValue( "oalDevice", "Generic Software" );
1703   if( oalDevice ) {
1704 	  free( oalDevice );
1705   }
1706   oalDevice = (TCHAR*)malloc( ( buffer.GetLength() + 1 ) * sizeof( TCHAR ) );
1707   _tcscpy( oalDevice, buffer.GetBuffer() );
1708 
1709   oalBufferCount = regQueryDwordValue( "oalBufferCount", 5 );
1710 #endif
1711 
1712 #ifndef NO_XAUDIO2
1713   xa2Device = regQueryDwordValue( "xa2Device", 0 );
1714   xa2BufferCount = regQueryDwordValue( "xa2BufferCount", 4 );
1715   xa2Upmixing = ( 1 == regQueryDwordValue( "xa2Upmixing", 0 ) );
1716 #endif
1717 
1718   if( ( maxCpuCores == 1 ) && filterMT ) {
1719 	  // multi-threading use useless for just one core
1720 	  filterMT = false;
1721   }
1722 }
1723 
updateFrameSkip()1724 void VBA::updateFrameSkip()
1725 {
1726   switch(cartridgeType) {
1727   case 0:
1728     systemFrameSkip = frameSkip;
1729     break;
1730   case 1:
1731     systemFrameSkip = gbFrameSkip;
1732     break;
1733   }
1734 }
1735 
updateVideoSize(UINT id)1736 void VBA::updateVideoSize(UINT id)
1737 {
1738   int value = 0;
1739 
1740   switch(id) {
1741   case ID_OPTIONS_VIDEO_X1:
1742     value = VIDEO_1X;
1743     break;
1744   case ID_OPTIONS_VIDEO_X2:
1745     value = VIDEO_2X;
1746     break;
1747   case ID_OPTIONS_VIDEO_X3:
1748     value = VIDEO_3X;
1749     break;
1750   case ID_OPTIONS_VIDEO_X4:
1751     value = VIDEO_4X;
1752     break;
1753   case ID_OPTIONS_VIDEO_X5:
1754     value = VIDEO_5X;
1755     break;
1756   case ID_OPTIONS_VIDEO_X6:
1757     value = VIDEO_6X;
1758     break;
1759   case ID_OPTIONS_VIDEO_FULLSCREEN320X240:
1760     value = VIDEO_320x240;
1761     fsWidth = 320;
1762     fsHeight = 240;
1763     fsColorDepth = 16;
1764     break;
1765   case ID_OPTIONS_VIDEO_FULLSCREEN640X480:
1766     value = VIDEO_640x480;
1767     fsWidth = 640;
1768     fsHeight = 480;
1769     fsColorDepth = 16;
1770     break;
1771   case ID_OPTIONS_VIDEO_FULLSCREEN800X600:
1772     value = VIDEO_800x600;
1773     fsWidth = 800;
1774     fsHeight = 600;
1775     fsColorDepth = 16;
1776     break;
1777   case ID_OPTIONS_VIDEO_FULLSCREEN1024X768:
1778     value = VIDEO_1024x768;
1779     fsWidth = 1024;
1780     fsHeight = 768;
1781     fsColorDepth = 32;
1782     break;
1783   case ID_OPTIONS_VIDEO_FULLSCREEN1280X1024:
1784     value = VIDEO_1280x1024;
1785     fsWidth = 1280;
1786     fsHeight = 1024;
1787     fsColorDepth = 32;
1788     break;
1789   case ID_OPTIONS_VIDEO_FULLSCREEN:
1790     value = VIDEO_OTHER;
1791     break;
1792   }
1793 
1794   updateWindowSize(value);
1795 }
1796 
1797 
updateWindowSize(int value)1798 void VBA::updateWindowSize(int value)
1799 {
1800   regSetDwordValue("video", value);
1801 
1802   if(value == VIDEO_OTHER) {
1803     regSetDwordValue("fsWidth", fsWidth);
1804     regSetDwordValue("fsHeight", fsHeight);
1805     regSetDwordValue("fsColorDepth", fsColorDepth);
1806   }
1807 
1808   if(((value >= VIDEO_320x240) &&
1809       (videoOption != value)) ||
1810      (videoOption >= VIDEO_320x240 &&
1811       value <= VIDEO_6X) ||
1812      fsForceChange) {
1813     fsForceChange = false;
1814     changingVideoSize = true;
1815 	if( videoOption <= VIDEO_6X ) {
1816 		lastWindowed = (VIDEO_SIZE)videoOption; // save for when leaving full screen
1817 	} else {
1818 		lastFullscreen = (VIDEO_SIZE)videoOption; // save for when using quick switch to fullscreen
1819 	}
1820     shutdownDisplay();
1821     if(input) {
1822       delete input;
1823       input = NULL;
1824     }
1825     m_pMainWnd->DragAcceptFiles(FALSE);
1826     CWnd *pWnd = m_pMainWnd;
1827     m_pMainWnd = NULL;
1828     pWnd->DestroyWindow();
1829     delete pWnd;
1830     videoOption = value;
1831     if(!initDisplay()) {
1832       if(videoOption == VIDEO_320x240 ||
1833          videoOption == VIDEO_640x480 ||
1834          videoOption == VIDEO_800x600 ||
1835          videoOption == VIDEO_1024x768 ||
1836          videoOption == VIDEO_1280x1024 ||
1837          videoOption == VIDEO_OTHER) {
1838         regSetDwordValue("video", VIDEO_1X);
1839       }
1840       changingVideoSize = false;
1841       AfxPostQuitMessage(0);
1842       return;
1843     }
1844     if(!initInput()) {
1845       changingVideoSize = false;
1846       AfxPostQuitMessage(0);
1847       return;
1848     }
1849     input->checkKeys();
1850 
1851 
1852     changingVideoSize = FALSE;
1853     updateWindowSize(videoOption);
1854     return;
1855   }
1856 
1857   sizeX = 240;
1858   sizeY = 160;
1859 
1860   videoOption = value;
1861 
1862   if(cartridgeType == IMAGE_GB) {
1863     if(gbBorderOn) {
1864       sizeX = 256;
1865       sizeY = 224;
1866       gbBorderLineSkip = 256;
1867       gbBorderColumnSkip = 48;
1868       gbBorderRowSkip = 40;
1869     } else {
1870       sizeX = 160;
1871       sizeY = 144;
1872       gbBorderLineSkip = 160;
1873       gbBorderColumnSkip = 0;
1874       gbBorderRowSkip = 0;
1875     }
1876   }
1877 
1878   surfaceSizeX = sizeX;
1879   surfaceSizeY = sizeY;
1880 
1881   switch(videoOption) {
1882   case VIDEO_1X:
1883     surfaceSizeX = sizeX;
1884     surfaceSizeY = sizeY;
1885     break;
1886   case VIDEO_2X:
1887     surfaceSizeX = sizeX * 2;
1888     surfaceSizeY = sizeY * 2;
1889     break;
1890   case VIDEO_3X:
1891     surfaceSizeX = sizeX * 3;
1892     surfaceSizeY = sizeY * 3;
1893     break;
1894   case VIDEO_4X:
1895     surfaceSizeX = sizeX * 4;
1896     surfaceSizeY = sizeY * 4;
1897     break;
1898   case VIDEO_5X:
1899     surfaceSizeX = sizeX * 5;
1900     surfaceSizeY = sizeY * 5;
1901     break;
1902   case VIDEO_6X:
1903     surfaceSizeX = sizeX * 6;
1904     surfaceSizeY = sizeY * 6;
1905     break;
1906   case VIDEO_320x240:
1907   case VIDEO_640x480:
1908   case VIDEO_800x600:
1909   case VIDEO_1024x768:
1910   case VIDEO_1280x1024:
1911   case VIDEO_OTHER:
1912     {
1913       int scaleX = 1;
1914       int scaleY = 1;
1915       scaleX = (fsWidth / sizeX);
1916       scaleY = (fsHeight / sizeY);
1917       int min = scaleX < scaleY ? scaleX : scaleY;
1918       if(maxScale)
1919         min = min > maxScale ? maxScale : min;
1920       surfaceSizeX = min * sizeX;
1921       surfaceSizeY = min * sizeY;
1922       if((fullScreenStretch && (display != NULL &&
1923                                 (display->getType() != DIRECT_3D)))
1924          || (display != NULL && display->getType() >= DIRECT_3D)) {
1925         surfaceSizeX = fsWidth;
1926         surfaceSizeY = fsHeight;
1927       }
1928     }
1929     break;
1930   }
1931 
1932   rect.right = sizeX;
1933   rect.bottom = sizeY;
1934 
1935   int winSizeX = sizeX;
1936   int winSizeY = sizeY;
1937 
1938   if(videoOption <= VIDEO_6X) {
1939     dest.left = 0;
1940     dest.top = 0;
1941     dest.right = surfaceSizeX;
1942     dest.bottom = surfaceSizeY;
1943 
1944     DWORD style = WS_POPUP | WS_VISIBLE;
1945 
1946     style |= WS_OVERLAPPEDWINDOW;
1947 
1948     AdjustWindowRectEx(&dest, style, TRUE, 0); //WS_EX_TOPMOST);
1949 
1950     winSizeX = dest.right-dest.left;
1951     winSizeY = dest.bottom-dest.top;
1952 
1953       m_pMainWnd->SetWindowPos(0, //HWND_TOPMOST,
1954                                windowPositionX,
1955                                windowPositionY,
1956                                winSizeX,
1957                                winSizeY,
1958                                SWP_NOMOVE | SWP_SHOWWINDOW);
1959 
1960 	  // content of old seperate 'winCheckMenuBarInfo' function:
1961       MENUBARINFO info;
1962       info.cbSize = sizeof(MENUBARINFO);
1963 	  GetMenuBarInfo( theApp.m_pMainWnd->GetSafeHwnd(), OBJID_MENU, 0, &info );
1964       int menuHeight = GetSystemMetrics(SM_CYMENU); // includes white line
1965       if((info.rcBar.bottom - info.rcBar.top) > menuHeight) // check for double height menu
1966 	  {
1967         winSizeY += (info.rcBar.bottom - info.rcBar.top) - menuHeight + 1;
1968         m_pMainWnd->SetWindowPos(
1969                                         0, //HWND_TOPMOST,
1970                                         windowPositionX,
1971                                         windowPositionY,
1972                                         winSizeX,
1973                                         winSizeY,
1974                                         SWP_NOMOVE | SWP_SHOWWINDOW);
1975       }
1976   }
1977 
1978   adjustDestRect();
1979 
1980   updateIFB();
1981   updateFilter();
1982 
1983   if(display)
1984     display->resize(theApp.dest.right-theApp.dest.left, theApp.dest.bottom-theApp.dest.top);
1985 
1986   m_pMainWnd->RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
1987 }
1988 
1989 
initDisplay()1990 bool VBA::initDisplay()
1991 {
1992   return updateRenderMethod(false);
1993 }
1994 
1995 
preInitialize()1996 bool VBA::preInitialize()
1997 {
1998 	switch( cartridgeType )
1999 	{
2000 	case IMAGE_GBA:
2001 		sizeX = 240;
2002 		sizeY = 160;
2003 		break;
2004 	case IMAGE_GB:
2005 		if( gbBorderOn ) {
2006 			sizeX = 256;
2007 			sizeY = 224;
2008 		} else {
2009 			sizeX = 160;
2010 			sizeY = 144;
2011 		}
2012 		break;
2013 	}
2014 
2015 	switch( videoOption )
2016 	{
2017 	case VIDEO_1X:
2018 		surfaceSizeX = sizeX;
2019 		surfaceSizeY = sizeY;
2020 		break;
2021 	case VIDEO_2X:
2022 		surfaceSizeX = sizeX * 2;
2023 		surfaceSizeY = sizeY * 2;
2024 		break;
2025 	case VIDEO_3X:
2026 		surfaceSizeX = sizeX * 3;
2027 		surfaceSizeY = sizeY * 3;
2028 		break;
2029 	case VIDEO_4X:
2030 		surfaceSizeX = sizeX * 4;
2031 		surfaceSizeY = sizeY * 4;
2032 		break;
2033 	case VIDEO_5X:
2034 		surfaceSizeX = sizeX * 5;
2035 		surfaceSizeY = sizeY * 5;
2036 		break;
2037 	case VIDEO_6X:
2038 		surfaceSizeX = sizeX * 6;
2039 		surfaceSizeY = sizeY * 6;
2040 		break;
2041 	case VIDEO_320x240:
2042 	case VIDEO_640x480:
2043 	case VIDEO_800x600:
2044 	case VIDEO_1024x768:
2045 	case VIDEO_1280x1024:
2046 	case VIDEO_OTHER:
2047 		float scaleX = (float)fsWidth / sizeX;
2048 		float scaleY = (float)fsHeight / sizeY;
2049 		float min = ( scaleX < scaleY ) ? scaleX : scaleY;
2050 		if( fullScreenStretch ) {
2051 			surfaceSizeX = fsWidth;
2052 			surfaceSizeY = fsHeight;
2053 		} else {
2054 			surfaceSizeX = (int)( sizeX * min );
2055 			surfaceSizeY = (int)( sizeY * min );
2056 		}
2057 		break;
2058 	}
2059 
2060 	rect.left = 0;
2061 	rect.top = 0;
2062 	rect.right = sizeX;
2063 	rect.bottom = sizeY;
2064 
2065 	dest.left = 0;
2066 	dest.top = 0;
2067 	dest.right = surfaceSizeX;
2068 	dest.bottom = surfaceSizeY;
2069 
2070 
2071 	DWORD style = WS_POPUP | WS_VISIBLE;
2072 	DWORD styleEx = 0;
2073 
2074 	if( videoOption <= VIDEO_6X ) {
2075 		style |= WS_OVERLAPPEDWINDOW;
2076 	} else {
2077 		styleEx = 0;
2078 	}
2079 
2080 	if( videoOption <= VIDEO_6X ) {
2081 		AdjustWindowRectEx( &dest, style, TRUE, styleEx );
2082 	} else {
2083 		AdjustWindowRectEx( &dest, style, FALSE, styleEx );
2084 	}
2085 
2086 	int winSizeX = dest.right-dest.left;
2087 	int winSizeY = dest.bottom-dest.top;
2088 
2089 	if( videoOption > VIDEO_6X ) {
2090 		winSizeX = fsWidth;
2091 		winSizeY = fsHeight;
2092 	}
2093 
2094 	int x = 0, y = 0;
2095 
2096 	if( videoOption <= VIDEO_6X ) {
2097 		x = windowPositionX;
2098 		y = windowPositionY;
2099 	}
2100 
2101 
2102 	// Create a window
2103 	MainWnd *pWnd = new MainWnd;
2104 	m_pMainWnd = pWnd;
2105 
2106 	pWnd->CreateEx(
2107 		styleEx,
2108 		wndClass,
2109 		_T(VBA_NAME_AND_SUBVERSION),
2110 		style,
2111 		x, y,
2112 		winSizeX, winSizeY,
2113 		NULL,
2114 		0
2115 		);
2116 
2117 	if( !((HWND)*pWnd) ) {
2118 		winlog( "Error creating Window %08x\n", GetLastError() );
2119 		return false;
2120 	}
2121 	pWnd->DragAcceptFiles( TRUE );
2122 	updateMenuBar();
2123 	adjustDestRect();
2124 
2125 	return true;
2126 }
2127 
2128 
updateRenderMethod(bool force)2129 bool VBA::updateRenderMethod(bool force)
2130 {
2131 	bool ret = true;
2132 
2133 	Sm60FPS_Init();
2134 
2135 	if( !updateRenderMethod0( force ) ) {
2136 		// fall back to safe configuration
2137 		renderMethod = DIRECT_3D;
2138 		fsAdapter = 0;
2139 		videoOption = VIDEO_1X;
2140 		ret = updateRenderMethod( true );
2141 	}
2142 
2143 	return ret;
2144 }
2145 
2146 
updateRenderMethod0(bool force)2147 bool VBA::updateRenderMethod0(bool force)
2148 {
2149   bool initInput = false;
2150   b16to32Video = false;
2151 
2152   if(display) {
2153     if(display->getType() != renderMethod || force) {
2154 	  toolsLoggingClose(); // close log dialog
2155       initInput = true;
2156       changingVideoSize = true;
2157       shutdownDisplay();
2158       if(input) {
2159         delete input;
2160         input = NULL;
2161       }
2162       CWnd *pWnd = m_pMainWnd;
2163 
2164       m_pMainWnd = NULL;
2165       pWnd->DragAcceptFiles(FALSE);
2166       pWnd->DestroyWindow();
2167       delete pWnd;
2168 
2169       display = NULL;
2170       regSetDwordValue("renderMethod", renderMethod);
2171     }
2172   }
2173   if(display == NULL) {
2174     switch(renderMethod) {
2175 #ifndef NO_OGL
2176 	case OPENGL:
2177 		display = newOpenGLDisplay();
2178 		break;
2179 #endif
2180 #ifndef NO_D3D
2181     case DIRECT_3D:
2182 		display = newDirect3DDisplay();
2183 		break;
2184 #endif
2185     }
2186 
2187 	if( preInitialize() ) {
2188 		if( display->initialize() ) {
2189 			if( initInput ) {
2190 				if( !this->initInput() ) {
2191 					changingVideoSize = false;
2192 					AfxPostQuitMessage(0);
2193 					return false;
2194 				}
2195 				input->checkKeys();
2196 				updateMenuBar();
2197 				changingVideoSize = false;
2198 				updateWindowSize(videoOption);
2199 
2200 				m_pMainWnd->ShowWindow(SW_SHOW);
2201 				m_pMainWnd->UpdateWindow();
2202 				m_pMainWnd->SetFocus();
2203 
2204 				return true;
2205 			} else {
2206 				changingVideoSize = false;
2207 				return true;
2208 			}
2209 		}
2210 	}
2211 	changingVideoSize = false;
2212   }
2213   return true;
2214 }
2215 
2216 
shutdownDisplay()2217 void VBA::shutdownDisplay()
2218 {
2219   if(display != NULL) {
2220     display->cleanup();
2221     delete display;
2222     display = NULL;
2223   }
2224 }
2225 
directXMessage(const char * msg)2226 void VBA::directXMessage(const char *msg)
2227 {
2228   systemMessage(IDS_DIRECTX_7_REQUIRED,
2229                 "DirectX 7.0 or greater is required to run.\nDownload at http://www.microsoft.com/directx.\n\nError found at: %s",
2230                 msg);
2231 }
2232 
updatePriority()2233 void VBA::updatePriority()
2234 {
2235   switch(threadPriority) {
2236   case 0:
2237     SetThreadPriority(THREAD_PRIORITY_HIGHEST);
2238     break;
2239   case 1:
2240     SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
2241     break;
2242   case 3:
2243     SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
2244     break;
2245   default:
2246     SetThreadPriority(THREAD_PRIORITY_NORMAL);
2247   }
2248 }
2249 
2250 #ifdef MMX
detectMMX()2251 bool VBA::detectMMX()
2252 {
2253   bool support = false;
2254   char brand[12]; // not zero terminated
2255 
2256   // check for Intel chip
2257   __try {
2258     __asm {
2259       mov eax, 0;
2260       cpuid;
2261       mov [dword ptr brand+0], ebx;
2262       mov [dword ptr brand+4], edx;
2263       mov [dword ptr brand+8], ecx;
2264     }
2265   }
2266   __except(EXCEPTION_EXECUTE_HANDLER) {
2267     if(_exception_code() == STATUS_ILLEGAL_INSTRUCTION) {
2268       return false;
2269     }
2270     return false;
2271   }
2272   // Check for Intel or AMD CPUs
2273   if(strncmp(brand, "GenuineIntel", 12)) {
2274     if(strncmp(brand, "AuthenticAMD", 12)) {
2275       return false;
2276     }
2277   }
2278 
2279   __asm {
2280     mov eax, 1;
2281     cpuid;
2282     test edx, 00800000h;
2283     jz NotFound;
2284     mov [support], 1;
2285   NotFound:
2286   }
2287   return support;
2288 }
2289 #endif
2290 
winSetLanguageOption(int option,bool force)2291 void VBA::winSetLanguageOption(int option, bool force)
2292 {
2293   if(((option == languageOption) && option != 2) && !force)
2294     return;
2295   switch(option) {
2296   case 0:
2297     {
2298       char lbuffer[10];
2299 
2300       if(GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SABBREVLANGNAME,
2301                        lbuffer, 10)) {
2302         HINSTANCE l = winLoadLanguage(lbuffer);
2303         if(l == NULL) {
2304           LCID locIdBase = MAKELCID( MAKELANGID( PRIMARYLANGID( GetSystemDefaultLangID() ), SUBLANG_NEUTRAL ), SORT_DEFAULT );
2305           if(GetLocaleInfo(locIdBase, LOCALE_SABBREVLANGNAME,
2306                            lbuffer, 10)) {
2307             l = winLoadLanguage(lbuffer);
2308             if(l == NULL) {
2309               systemMessage(IDS_FAILED_TO_LOAD_LIBRARY,
2310                             "Failed to load library %s",
2311                             lbuffer);
2312               return;
2313             }
2314           }
2315         }
2316         AfxSetResourceHandle(l);
2317         if(languageModule != NULL)
2318 #ifdef _AFXDLL
2319           AfxFreeLibrary( languageModule );
2320 #else
2321           FreeLibrary( languageModule );
2322 #endif
2323         languageModule = l;
2324       } else {
2325         systemMessage(IDS_FAILED_TO_GET_LOCINFO,
2326                       "Failed to get locale information");
2327         return;
2328       }
2329     }
2330     break;
2331   case 1:
2332     if(languageModule != NULL)
2333 #ifdef _AFXDLL
2334       AfxFreeLibrary( languageModule );
2335 #else
2336       FreeLibrary( languageModule );
2337 #endif
2338     languageModule = NULL;
2339     AfxSetResourceHandle(AfxGetInstanceHandle());
2340     break;
2341   case 2:
2342     {
2343       if(!force) {
2344         LangSelect dlg;
2345         if(dlg.DoModal()) {
2346           HINSTANCE l = winLoadLanguage(languageName);
2347           if(l == NULL) {
2348             systemMessage(IDS_FAILED_TO_LOAD_LIBRARY,
2349                           "Failed to load library %s",
2350                           languageName);
2351             return;
2352           }
2353           AfxSetResourceHandle(l);
2354           if(languageModule != NULL)
2355 		  {
2356 #ifdef _AFXDLL
2357             AfxFreeLibrary( languageModule );
2358 #else
2359             FreeLibrary( languageModule );
2360 #endif
2361 		  }
2362           languageModule = l;
2363         }
2364       } else {
2365         if(languageName.IsEmpty())
2366           return;
2367         HINSTANCE l = winLoadLanguage(languageName);
2368         if(l == NULL) {
2369           systemMessage(IDS_FAILED_TO_LOAD_LIBRARY,
2370                         "Failed to load library %s",
2371                         languageName);
2372           return;
2373         }
2374         AfxSetResourceHandle(l);
2375         if(languageModule != NULL)
2376           FreeLibrary(languageModule);
2377         languageModule = l;
2378       }
2379     }
2380     break;
2381   }
2382   languageOption = option;
2383   updateMenuBar();
2384 }
2385 
winLoadLanguage(const char * name)2386 HINSTANCE VBA::winLoadLanguage(const char *name)
2387 {
2388   CString buffer;
2389 
2390   buffer.Format( _T("vba_%s.dll"), name);
2391 
2392 #ifdef _AFXDLL
2393   HINSTANCE l = AfxLoadLibrary( buffer );
2394 #else
2395   HMODULE l = LoadLibrary( buffer );
2396 #endif
2397 
2398   if(l == NULL) {
2399     if(strlen(name) == 3) {
2400       char buffer2[3];
2401       buffer2[0] = name[0];
2402       buffer2[1] = name[1];
2403       buffer2[2] = 0;
2404       buffer.Format("vba_%s.dll", buffer2);
2405 
2406 #ifdef _AFXDLL
2407 	  return AfxLoadLibrary( buffer );
2408 #else
2409 	  return LoadLibrary( buffer );
2410 #endif
2411     }
2412   }
2413   return l;
2414 }
2415 
2416 
initInput()2417 bool VBA::initInput()
2418 {
2419   if(input)
2420     delete input;
2421   input = newDirectInput();
2422   if(input->initialize()) {
2423     input->loadSettings();
2424     input->checkKeys();
2425     return true;
2426   }
2427   delete input;
2428   return false;
2429 }
2430 
winAddUpdateListener(IUpdateListener * l)2431 void VBA::winAddUpdateListener(IUpdateListener *l)
2432 {
2433   updateList.AddTail(l);
2434   updateCount++;
2435 }
2436 
winRemoveUpdateListener(IUpdateListener * l)2437 void VBA::winRemoveUpdateListener(IUpdateListener *l)
2438 {
2439   POSITION pos = updateList.Find(l);
2440   if(pos) {
2441     updateList.RemoveAt(pos);
2442     updateCount--;
2443     if(updateCount < 0)
2444       updateCount = 0;
2445   }
2446 }
2447 
winLoadFilter(UINT id)2448 CString VBA::winLoadFilter(UINT id)
2449 {
2450   CString res = winResLoadString(id);
2451   res.Replace('_','|');
2452 
2453   return res;
2454 }
2455 
movieReadNext()2456 void VBA::movieReadNext()
2457 {
2458   if(movieFile) {
2459     bool movieEnd = false;
2460 
2461     if(fread(&moviePlayFrame, 1, sizeof(int), movieFile) == sizeof(int)) {
2462       if(fread(&movieNextJoypad, 1, sizeof(u32), movieFile) == sizeof(int)) {
2463         // make sure we don't have spurious entries on the movie that can
2464         // cause us to play it forever
2465         if(moviePlayFrame <= movieFrame)
2466           movieEnd = true;
2467       } else
2468         movieEnd = true;
2469     } else
2470       movieEnd = true;
2471     if(movieEnd) {
2472       CString string = winResLoadString(IDS_END_OF_MOVIE);
2473       systemScreenMessage(string);
2474       moviePlaying = false;
2475       fclose(movieFile);
2476       movieFile = NULL;
2477       return;
2478     }
2479   } else
2480     moviePlaying = false;
2481 }
2482 
saveSettings()2483 void VBA::saveSettings()
2484 {
2485   regSetDwordValue("language", languageOption);
2486 
2487   regSetStringValue("languageName", languageName);
2488 
2489   regSetDwordValue("frameSkip", frameSkip);
2490 
2491   regSetDwordValue("gbFrameSkip", gbFrameSkip);
2492 
2493   regSetDwordValue("autoFrameSkip", autoFrameSkip);
2494   regSetDwordValue("vsync", vsync);
2495   regSetDwordValue("stretch", fullScreenStretch);
2496 
2497   regSetDwordValue("video", videoOption);
2498 
2499   regSetDwordValue("fsAdapter", fsAdapter);
2500   regSetDwordValue("fsWidth", fsWidth);
2501   regSetDwordValue("fsHeight", fsHeight);
2502   regSetDwordValue("fsColorDepth", fsColorDepth);
2503   regSetDwordValue("fsFrequency", fsFrequency);
2504 
2505   regSetDwordValue("renderMethod", renderMethod);
2506   regSetDwordValue( "audioAPI", audioAPI );
2507 
2508   regSetDwordValue("windowX", windowPositionX);
2509   regSetDwordValue("windowY", windowPositionY);
2510 
2511   regSetDwordValue("maxCpuCores", maxCpuCores);
2512 
2513   regSetDwordValue("useBiosGBA", useBiosFileGBA);
2514 
2515   regSetDwordValue("useBiosGBC", useBiosFileGBC);
2516 
2517   regSetDwordValue("useBiosGB", useBiosFileGB);
2518 
2519   regSetDwordValue("skipBios", skipBios);
2520 
2521   if(!biosFileNameGBA.IsEmpty())
2522     regSetStringValue("biosFileGBA", biosFileNameGBA);
2523 
2524   if(!biosFileNameGBC.IsEmpty())
2525     regSetStringValue("biosFileGBC", biosFileNameGBC);
2526 
2527   if(!biosFileNameGB.IsEmpty())
2528     regSetStringValue("biosFileGB", biosFileNameGB);
2529 
2530   regSetDwordValue("soundEnable", soundGetEnable() & 0x30f);
2531 
2532   regSetDwordValue("soundQuality", 44100 / soundGetSampleRate() );
2533 
2534   regSetDwordValue("soundVolume", (DWORD)(soundGetVolume() * 100.0f));
2535 
2536 	regSetDwordValue( "gbSoundEffectsEnabled", gb_effects_config.enabled ? 1 : 0 );
2537 	regSetDwordValue( "gbSoundEffectsSurround", gb_effects_config.surround ? 1 : 0 );
2538 	regSetDwordValue( "gbSoundEffectsEcho", (DWORD)( gb_effects_config.echo * 100.0f ) );
2539 	regSetDwordValue( "gbSoundEffectsStereo", (DWORD)( gb_effects_config.stereo * 100.0f ) );
2540 
2541 	regSetDwordValue( "gbSoundDeclicking", gbSoundGetDeclicking() ? 1 : 0 );
2542 
2543 	regSetDwordValue( "gbaSoundInterpolation", soundInterpolation ? 1 : 0 );
2544 	regSetDwordValue( "gbaSoundFiltering", (DWORD)( soundFiltering * 100.0f ) );
2545 
2546   regSetDwordValue("tripleBuffering", tripleBuffering);
2547 
2548 #ifndef NO_D3D
2549   regSetDwordValue("d3dFilter", d3dFilter);
2550   regSetDwordValue("d3dMotionBlur", d3dMotionBlur ? 1 : 0);
2551 #endif
2552 
2553   regSetDwordValue("glFilter", glFilter);
2554 
2555   regSetDwordValue("filter", filter);
2556 
2557   regSetDwordValue("filterEnableMultiThreading", filterMT ? 1 : 0);
2558 
2559   regSetDwordValue("disableMMX", disableMMX);
2560 
2561   regSetDwordValue("disableStatus", disableStatusMessages);
2562 
2563   regSetDwordValue("showSpeed", showSpeed);
2564 
2565   regSetDwordValue("showSpeedTransparent", showSpeedTransparent);
2566 
2567   regSetDwordValue("gbPrinter", winGbPrinterEnabled);
2568 
2569   regSetDwordValue("captureFormat", captureFormat);
2570 
2571   regSetDwordValue("recentFreeze", recentFreeze);
2572 
2573   regSetDwordValue("autoPatch", autoPatch ? 1 : 0);
2574 
2575   regSetDwordValue("disableSfx", cpuDisableSfx);
2576 
2577   regSetDwordValue("saveType", cpuSaveType);
2578 
2579   regSetDwordValue("ifbType", ifbType);
2580 
2581   regSetDwordValue("flashSize", winFlashSize);
2582 
2583   regSetDwordValue("agbPrint", agbPrintIsEnabled());
2584 
2585   regSetDwordValue("rtcEnabled", rtcEnabled);
2586 
2587   regSetDwordValue("borderOn", winGbBorderOn);
2588   regSetDwordValue("borderAutomatic", gbBorderAutomatic);
2589   regSetDwordValue("emulatorType", gbEmulatorType);
2590   regSetDwordValue("colorOption", gbColorOption);
2591 
2592   regSetDwordValue("priority", threadPriority);
2593 
2594   regSetDwordValue("autoSaveCheatList", autoSaveLoadCheatList);
2595 
2596   regSetDwordValue("gbPaletteOption", gbPaletteOption);
2597 
2598   regSetBinaryValue("gbPalette", (char *)systemGbPalette,
2599                     24*sizeof(u16));
2600 
2601   regSetDwordValue("rewindTimer", rewindTimer/6);
2602 
2603   CString buffer;
2604   for(int i = 0; i < 10; i++) {
2605     buffer.Format("recent%d", i);
2606     regSetStringValue(buffer, recentFiles[i]);
2607   }
2608 
2609   regSetDwordValue("joypadDefault", joypadDefault);
2610   regSetDwordValue("autoLoadMostRecent", autoLoadMostRecent);
2611   regSetDwordValue("skipSaveGameBattery", skipSaveGameBattery);
2612   regSetDwordValue("skipSaveGameCheats", skipSaveGameCheats);
2613   regSetDwordValue("cheatsEnabled", cheatsEnabled);
2614   regSetDwordValue("maxScale", maxScale);
2615   regSetDwordValue("throttle", throttle);
2616   regSetStringValue("pluginName", pluginName);
2617   regSetDwordValue("saveMoreCPU", Sm60FPS::bSaveMoreCPU);
2618 
2619 #ifndef NO_LINK
2620   regSetDwordValue("LinkTimeout", linkTimeout);
2621   regSetDwordValue("LinkMode", linkMode);
2622   regSetStringValue("LinkHostAddr", linkHostAddr);
2623   regSetDwordValue("LinkAuto", linkAuto);
2624   regSetDwordValue("LinkHacks", linkHacks);
2625   regSetDwordValue("LinkNumPlayers", linkNumPlayers);
2626 #endif
2627 
2628   regSetDwordValue("gdbPort", gdbPort);
2629   regSetDwordValue("gdbBreakOnLoad", gdbBreakOnLoad);
2630 
2631   regSetDwordValue("lastFullscreen", lastFullscreen);
2632   regSetDwordValue("pauseWhenInactive", pauseWhenInactive);
2633 
2634 #ifndef NO_OAL
2635   regSetStringValue( "oalDevice", oalDevice );
2636   regSetDwordValue( "oalBufferCount", oalBufferCount );
2637 #endif
2638 
2639 #ifndef NO_XAUDIO2
2640   regSetDwordValue( "xa2Device", xa2Device );
2641   regSetDwordValue( "xa2BufferCount", xa2BufferCount );
2642   regSetDwordValue( "xa2Upmixing", xa2Upmixing ? 1 : 0 );
2643 #endif
2644 }
2645 
detectCpuCores()2646 unsigned int VBA::detectCpuCores()
2647 {
2648 	SYSTEM_INFO info;
2649 
2650 	GetSystemInfo( &info );
2651 
2652 	return info.dwNumberOfProcessors;
2653 }
2654 
winSignal(int,int)2655 void winSignal(int, int)
2656 {
2657 }
2658 
2659 #define CPUReadByteQuick(addr) \
2660   map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]
2661 
winOutput(const char * s,u32 addr)2662 void winOutput(const char *s, u32 addr)
2663 {
2664   if(s) {
2665     toolsLog(s);
2666   } else {
2667     CString str;
2668     char c;
2669 
2670     c = CPUReadByteQuick(addr);
2671     addr++;
2672     while(c) {
2673       str += c;
2674       c = CPUReadByteQuick(addr);
2675       addr++;
2676     }
2677     toolsLog(str);
2678   }
2679 }
2680 
2681 
Sm60FPS_Init()2682 void Sm60FPS_Init()
2683 {
2684 	Sm60FPS::dwTimeElapse = 0;
2685 	Sm60FPS::fWantFPS = 60.f;
2686 	Sm60FPS::fCurFPS = 0.f;
2687 	Sm60FPS::nFrameCnt = 0;
2688 	Sm60FPS::bLastSkip = false;
2689 	Sm60FPS::nCurSpeed = 100;
2690 }
2691 
2692 
Sm60FPS_CanSkipFrame()2693 bool Sm60FPS_CanSkipFrame()
2694 {
2695   if( autoFrameSkip ) {
2696 	  if( Sm60FPS::nFrameCnt == 0 ) {
2697 		  Sm60FPS::nFrameCnt = 0;
2698 		  Sm60FPS::dwTimeElapse = 0;
2699 		  Sm60FPS::dwTime0 = GetTickCount();
2700 	  } else {
2701 		  if( Sm60FPS::nFrameCnt >= 10 ) {
2702 			  Sm60FPS::nFrameCnt = 0;
2703 			  Sm60FPS::dwTimeElapse = 0;
2704 
2705 			  if( Sm60FPS::nCurSpeed > Sm60FPS::K_fCpuSpeed ) {
2706 				  Sm60FPS::fWantFPS += 1;
2707 				  if( Sm60FPS::fWantFPS > Sm60FPS::K_fTargetFps ){
2708 					  Sm60FPS::fWantFPS = Sm60FPS::K_fTargetFps;
2709 				  }
2710 			  } else {
2711 				  if( Sm60FPS::nCurSpeed < (Sm60FPS::K_fCpuSpeed - 5) ) {
2712 					  Sm60FPS::fWantFPS -= 1;
2713 					  if( Sm60FPS::fWantFPS < 30.f ) {
2714 						  Sm60FPS::fWantFPS = 30.f;
2715 					  }
2716 				  }
2717 			  }
2718 		  } else { // between frame 1-10
2719 			  Sm60FPS::dwTime1 = GetTickCount();
2720 			  Sm60FPS::dwTimeElapse += (Sm60FPS::dwTime1 - Sm60FPS::dwTime0);
2721 			  Sm60FPS::dwTime0 = Sm60FPS::dwTime1;
2722 			  if( !Sm60FPS::bLastSkip &&
2723 				  ( (Sm60FPS::fWantFPS < Sm60FPS::K_fTargetFps) || Sm60FPS::bSaveMoreCPU) ) {
2724 					  Sm60FPS::fCurFPS = (float)Sm60FPS::nFrameCnt * 1000 / Sm60FPS::dwTimeElapse;
2725 					  if( (Sm60FPS::fCurFPS < Sm60FPS::K_fTargetFps) || Sm60FPS::bSaveMoreCPU ) {
2726 						  Sm60FPS::bLastSkip = true;
2727 						  Sm60FPS::nFrameCnt++;
2728 						  return true;
2729 					  }
2730 			  }
2731 		  }
2732 	  }
2733 	  Sm60FPS::bLastSkip = false;
2734 	  Sm60FPS::nFrameCnt++;
2735   }
2736   return false;
2737 }
2738 
2739 
Sm60FPS_Sleep()2740 void Sm60FPS_Sleep()
2741 {
2742 	if( autoFrameSkip ) {
2743 		u32 dwTimePass = Sm60FPS::dwTimeElapse + (GetTickCount() - Sm60FPS::dwTime0);
2744 		u32 dwTimeShould = (u32)(Sm60FPS::nFrameCnt * Sm60FPS::K_fDT);
2745 		if (dwTimeShould > dwTimePass && !gba_joybus_active) {
2746 			Sleep(dwTimeShould - dwTimePass);
2747 		}
2748 	}
2749 }
2750