1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
4 
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 
19 // VBA.cpp : Defines the class behaviors for the application.
20 //
21 #include "stdafx.h"
22 #include <mmsystem.h>
23 
24 #include "AVIWrite.h"
25 #include "LangSelect.h"
26 #include "MainWnd.h"
27 #include "Reg.h"
28 #include "resource.h"
29 #include "skin.h"
30 #include "WavWriter.h"
31 #include "WinResUtil.h"
32 
33 #include "../System.h"
34 #include "../agbprint.h"
35 #include "../cheatSearch.h"
36 #include "../GBA.h"
37 #include "../Globals.h"
38 #include "../RTC.h"
39 #include "../Sound.h"
40 #include "../Util.h"
41 #include "../gb/gbGlobals.h"
42 #include "../gb/gbPrinter.h"
43 
44 extern void Pixelate(u8*,u32,u8*,u8*,u32,int,int);
45 extern void Pixelate32(u8*,u32,u8*,u8*,u32,int,int);
46 extern void MotionBlur(u8*,u32,u8*,u8*,u32,int,int);
47 extern void MotionBlur32(u8*,u32,u8*,u8*,u32,int,int);
48 extern void _2xSaI(u8*,u32,u8*,u8*,u32,int,int);
49 extern void _2xSaI32(u8*,u32,u8*,u8*,u32,int,int);
50 extern void Super2xSaI(u8*,u32,u8*,u8*,u32,int,int);
51 extern void Super2xSaI32(u8*,u32,u8*,u8*,u32,int,int);
52 extern void SuperEagle(u8*,u32,u8*,u8*,u32,int,int);
53 extern void SuperEagle32(u8*,u32,u8*,u8*,u32,int,int);
54 extern void AdMame2x(u8*,u32,u8*,u8*,u32,int,int);
55 extern void AdMame2x32(u8*,u32,u8*,u8*,u32,int,int);
56 extern void Simple2x(u8*,u32,u8*,u8*,u32,int,int);
57 extern void Simple2x32(u8*,u32,u8*,u8*,u32,int,int);
58 extern void Bilinear(u8*,u32,u8*,u8*,u32,int,int);
59 extern void Bilinear32(u8*,u32,u8*,u8*,u32,int,int);
60 extern void BilinearPlus(u8*,u32,u8*,u8*,u32,int,int);
61 extern void BilinearPlus32(u8*,u32,u8*,u8*,u32,int,int);
62 extern void Scanlines(u8*,u32,u8*,u8*,u32,int,int);
63 extern void Scanlines32(u8*,u32,u8*,u8*,u32,int,int);
64 extern void ScanlinesTV(u8*,u32,u8*,u8*,u32,int,int);
65 extern void ScanlinesTV32(u8*,u32,u8*,u8*,u32,int,int);
66 extern void hq2x(u8*,u32,u8*,u8*,u32,int,int);
67 extern void hq2x32(u8*,u32,u8*,u8*,u32,int,int);
68 extern void lq2x(u8*,u32,u8*,u8*,u32,int,int);
69 extern void lq2x32(u8*,u32,u8*,u8*,u32,int,int);
70 
71 extern void SmartIB(u8*,u32,int,int);
72 extern void SmartIB32(u8*,u32,int,int);
73 extern void MotionBlurIB(u8*,u32,int,int);
74 extern void InterlaceIB(u8*,u32,int,int);
75 extern void MotionBlurIB32(u8*,u32,int,int);
76 
77 extern void toolsLog(const char *);
78 
79 extern IDisplay *newGDIDisplay();
80 extern IDisplay *newDirectDrawDisplay();
81 extern IDisplay *newDirect3DDisplay();
82 extern IDisplay *newOpenGLDisplay();
83 
84 extern Input *newDirectInput();
85 
86 extern ISound *newDirectSound();
87 
88 extern void remoteStubSignal(int, int);
89 extern void remoteOutput(char *, u32);
90 extern void remoteStubMain();
91 extern void remoteSetProtocol(int);
92 extern void remoteCleanUp();
93 extern int remoteSocket;
94 
95 extern void InterframeCleanup();
96 
97 void winlog(const char *msg, ...);
98 
99 #ifdef _DEBUG
100 #define new DEBUG_NEW
101 #undef THIS_FILE
102 static char THIS_FILE[] = __FILE__;
103 #endif
104 
105 int emulating = 0;
106 bool debugger = false;
107 int RGB_LOW_BITS_MASK = 0;
108 
109 int systemFrameSkip = 0;
110 int systemSpeed = 0;
111 bool systemSoundOn = false;
112 u32 systemColorMap32[0x10000];
113 u16 systemColorMap16[0x10000];
114 u16 systemGbPalette[24];
115 int systemRedShift = 0;
116 int systemBlueShift = 0;
117 int systemGreenShift = 0;
118 int systemColorDepth = 16;
119 int systemVerbose = 0;
120 int systemDebug = 0;
121 int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
122 
123 void winSignal(int,int);
124 void winOutput(char *, u32);
125 
126 void (*dbgSignal)(int,int) = winSignal;
127 void (*dbgOutput)(char *, u32) = winOutput;
128 
129 #ifdef MMX
130 extern "C" bool cpu_mmx;
131 #endif
132 
directXMessage(const char * msg)133 void directXMessage(const char *msg)
134 {
135   systemMessage(IDS_DIRECTX_7_REQUIRED,
136                 "DirectX 7.0 or greater is required to run.\nDownload at http://www.microsoft.com/directx.\n\nError found at: %s",
137                 msg);
138 }
139 
140 /////////////////////////////////////////////////////////////////////////////
141 // VBA
142 
BEGIN_MESSAGE_MAP(VBA,CWinApp)143 BEGIN_MESSAGE_MAP(VBA, CWinApp)
144   //{{AFX_MSG_MAP(VBA)
145   // NOTE - the ClassWizard will add and remove mapping macros here.
146   //    DO NOT EDIT what you see in these blocks of generated code!
147   //}}AFX_MSG_MAP
148   END_MESSAGE_MAP()
149 
150   /////////////////////////////////////////////////////////////////////////////
151 // VBA construction
152 
153 VBA::VBA()
154 {
155   mode320Available = false;
156   mode640Available = false;
157   mode800Available = false;
158   windowPositionX = 0;
159   windowPositionY = 0;
160   filterFunction = NULL;
161   ifbFunction = NULL;
162   ifbType = 0;
163   filterType = 0;
164   filterWidth = 0;
165   filterHeight = 0;
166   fsWidth = 0;
167   fsHeight = 0;
168   fsColorDepth = 0;
169   fsForceChange = false;
170   surfaceSizeX = 0;
171   surfaceSizeY = 0;
172   sizeX = 0;
173   sizeY = 0;
174   videoOption = 0;
175   fullScreenStretch = false;
176   disableStatusMessage = false;
177   showSpeed = 1;
178   showSpeedTransparent = true;
179   showRenderedFrames = 0;
180   screenMessage = false;
181   screenMessageTime = 0;
182   menuToggle = true;
183   display = NULL;
184   menu = NULL;
185   popup = NULL;
186   cartridgeType = 0;
187   soundInitialized = false;
188   useBiosFile = false;
189   skipBiosFile = false;
190   active = true;
191   paused = false;
192   recentFreeze = false;
193   autoSaveLoadCheatList = false;
194   winout = NULL;
195   removeIntros = false;
196   autoIPS = true;
197   winGbBorderOn = 0;
198   winFlashSize = 0x10000;
199   winRtcEnable = false;
200   winSaveType = 0;
201   rewindMemory = NULL;
202   rewindPos = 0;
203   rewindTopPos = 0;
204   rewindCounter = 0;
205   rewindCount = 0;
206   rewindSaveNeeded = false;
207   rewindTimer = 0;
208   captureFormat = 0;
209   tripleBuffering = true;
210   autoHideMenu = false;
211   throttle = 0;
212   throttleLastTime = 0;
213   autoFrameSkipLastTime = 0;
214   autoFrameSkip = false;
215   vsync = false;
216   changingVideoSize = false;
217   pVideoDriverGUID = NULL;
218   renderMethod = DIRECT_DRAW;
219   iconic = false;
220   ddrawEmulationOnly = false;
221   ddrawUsingEmulationOnly = false;
222   ddrawDebug = false;
223   ddrawUseVideoMemory = false;
224   d3dFilter = 0;
225   glFilter = 0;
226   glType = 0;
227   skin = NULL;
228   skinName = "";
229   skinEnabled = false;
230   skinButtons = 0;
231   regEnabled = false;
232   pauseWhenInactive = true;
233   speedupToggle = false;
234   useOldSync = false;
235   winGbPrinterEnabled = false;
236   threadPriority = 2;
237   disableMMX = false;
238   languageOption = 0;
239   languageModule = NULL;
240   languageName = "";
241   renderedFrames = 0;
242   input = NULL;
243   joypadDefault = 0;
244   autoFire = 0;
245   autoFireToggle = false;
246   winPauseNextFrame = false;
247   soundRecording = false;
248   soundRecorder = NULL;
249   sound = NULL;
250   aviRecording = false;
251   aviRecorder = NULL;
252   aviFrameNumber = 0;
253   painting = false;
254   movieRecording = false;
255   moviePlaying = false;
256   movieFrame = 0;
257   moviePlayFrame = 0;
258   movieFile = NULL;
259   movieLastJoypad = 0;
260   movieNextJoypad = 0;
261   sensorX = 2047;
262   sensorY = 2047;
263   mouseCounter = 0;
264   wasPaused = false;
265   frameskipadjust = 0;
266   autoLoadMostRecent = false;
267   fsMaxScale = 0;
268   romSize = 0;
269 
270   updateCount = 0;
271 
272   systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
273 
274   ZeroMemory(&emulator, sizeof(emulator));
275 
276   hAccel = NULL;
277 
278   for(int i = 0; i < 24;) {
279     systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10);
280     systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10);
281     systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10);
282     systemGbPalette[i++] = 0;
283   }
284 }
285 
~VBA()286 VBA::~VBA()
287 {
288   InterframeCleanup();
289 
290   saveSettings();
291 
292   if(moviePlaying) {
293     if(movieFile != NULL) {
294       fclose(movieFile);
295       movieFile = NULL;
296     }
297     moviePlaying = false;
298     movieLastJoypad = 0;
299   }
300 
301   if(movieRecording) {
302     if(movieFile != NULL) {
303       // record the last joypad change so that the correct time can be
304       // recorded
305       fwrite(&movieFrame, 1, sizeof(int), movieFile);
306       fwrite(&movieLastJoypad, 1, sizeof(u32), movieFile);
307       fclose(movieFile);
308       movieFile = NULL;
309     }
310     movieRecording = false;
311     moviePlaying = false;
312     movieLastJoypad = 0;
313   }
314 
315   if(aviRecorder) {
316     delete aviRecorder;
317     aviRecording = false;
318   }
319 
320   if(soundRecorder) {
321     delete soundRecorder;
322     soundRecorder = NULL;
323   }
324   soundRecording = false;
325   soundPause();
326   soundShutdown();
327 
328   if(gbRom != NULL || rom != NULL) {
329     if(autoSaveLoadCheatList)
330       ((MainWnd *)m_pMainWnd)->winSaveCheatListDefault();
331     ((MainWnd *)m_pMainWnd)->writeBatteryFile();
332     cheatSearchCleanup(&cheatSearchData);
333     emulator.emuCleanUp();
334   }
335 
336   if(input)
337     delete input;
338 
339   shutdownDisplay();
340 
341   if(skin) {
342     delete skin;
343   }
344 
345   if(rewindMemory)
346     free(rewindMemory);
347 }
348 
349 /////////////////////////////////////////////////////////////////////////////
350 // The one and only VBA object
351 
352 VBA theApp;
353 #include <afxdisp.h>
354 /////////////////////////////////////////////////////////////////////////////
355 // VBA initialization
356 
357 // code from SDL_main.c for Windows
358 /* Parse a command line buffer into arguments */
parseCommandLine(char * cmdline,char ** argv)359 static int parseCommandLine(char *cmdline, char **argv)
360 {
361   char *bufp;
362   int argc;
363 
364   argc = 0;
365   for ( bufp = cmdline; *bufp; ) {
366     /* Skip leading whitespace */
367     while ( isspace(*bufp) ) {
368       ++bufp;
369     }
370     /* Skip over argument */
371     if ( *bufp == '"' ) {
372       ++bufp;
373       if ( *bufp ) {
374         if ( argv ) {
375           argv[argc] = bufp;
376         }
377         ++argc;
378       }
379       /* Skip over word */
380       while ( *bufp && (*bufp != '"') ) {
381         ++bufp;
382       }
383     } else {
384       if ( *bufp ) {
385         if ( argv ) {
386           argv[argc] = bufp;
387         }
388         ++argc;
389       }
390       /* Skip over word */
391       while ( *bufp && ! isspace(*bufp) ) {
392         ++bufp;
393       }
394     }
395     if ( *bufp ) {
396       if ( argv ) {
397         *bufp = '\0';
398       }
399       ++bufp;
400     }
401   }
402   if ( argv ) {
403     argv[argc] = NULL;
404   }
405   return(argc);
406 }
407 
InitInstance()408 BOOL VBA::InitInstance()
409 {
410   AfxEnableControlContainer();
411   // Standard initialization
412   // If you are not using these features and wish to reduce the size
413   //  of your final executable, you should remove from the following
414   //  the specific initialization routines you do not need.
415 
416 #ifdef _AFXDLL
417   Enable3dControls();      // Call this when using MFC in a shared DLL
418 #else
419   Enable3dControlsStatic();  // Call this when linking to MFC statically
420 #endif
421 
422   SetRegistryKey(_T("VBA"));
423 
424   remoteSetProtocol(0);
425 
426   systemVerbose = GetPrivateProfileInt("config",
427                                        "verbose",
428                                        0,
429                                        "VBA.ini");
430 
431   systemDebug = GetPrivateProfileInt("config",
432                                      "debug",
433                                      0,
434                                      "VBA.ini");
435   ddrawDebug = GetPrivateProfileInt("config",
436                                     "ddrawDebug",
437                                     0,
438                                     "VBA.ini") ? true : false;
439 
440   wndClass = AfxRegisterWndClass(0, LoadCursor(IDC_ARROW), (HBRUSH)GetStockObject(BLACK_BRUSH), LoadIcon(IDI_ICON));
441 
442   char winBuffer[2048];
443 
444   GetModuleFileName(NULL, winBuffer, 2048);
445   char *p = strrchr(winBuffer, '\\');
446   if(p)
447     *p = 0;
448 
449   regInit(winBuffer);
450 
451   loadSettings();
452 
453   if(!initInput())
454     return FALSE;
455 
456   if(!initDisplay()) {
457     if(videoOption >= VIDEO_320x240) {
458       regSetDwordValue("video", VIDEO_1X);
459       if(pVideoDriverGUID)
460         regSetDwordValue("defaultVideoDriver", TRUE);
461     }
462     return FALSE;
463   }
464 
465   hAccel = LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCELERATOR));
466 
467   winAccelMgr.Connect((MainWnd *)m_pMainWnd);
468 
469   winAccelMgr.SetRegKey(HKEY_CURRENT_USER, "Software\\Emulators\\VisualBoyAdvance");
470 
471   extern void winAccelAddCommands(CAcceleratorManager&);
472 
473   winAccelAddCommands(winAccelMgr);
474 
475   winAccelMgr.CreateDefaultTable();
476 
477   winAccelMgr.Load();
478 
479   winAccelMgr.UpdateWndTable();
480 
481   winAccelMgr.UpdateMenu(menu);
482 
483   if (m_lpCmdLine[0])
484     {
485       int argc = parseCommandLine(m_lpCmdLine, NULL);
486       char **argv = (char **)malloc((argc+1)*sizeof(char *));
487       parseCommandLine(m_lpCmdLine, argv);
488       if(argc > 0) {
489         szFile = argv[0];
490         filename = szFile;
491       }
492       int index = filename.ReverseFind('.');
493 
494       if(index != -1)
495         filename = filename.Left(index);
496 
497       if(((MainWnd*)m_pMainWnd)->FileRun())
498         emulating = true;
499       else
500         emulating = false;
501       free(argv);
502     }
503 
504   return TRUE;
505 }
506 
adjustDestRect()507 void VBA::adjustDestRect()
508 {
509   POINT point;
510   RECT skinRect;
511   if(skin)
512     skinRect = skin->GetBlitRect();
513 
514   point.x = 0;
515   point.y = 0;
516 
517   if(skin) {
518     point.x = skinRect.left;
519     point.y = skinRect.top;
520   }
521 
522   m_pMainWnd->ClientToScreen(&point);
523   dest.top = point.y;
524   dest.left = point.x;
525 
526   point.x = surfaceSizeX;
527   point.y = surfaceSizeY;
528 
529   if(skin) {
530     point.x = skinRect.right;
531     point.y = skinRect.bottom;
532   }
533 
534   m_pMainWnd->ClientToScreen(&point);
535   dest.bottom = point.y;
536   dest.right = point.x;
537 
538   // make sure that dest rect lies in the monitor
539   if(videoOption >= VIDEO_320x240) {
540     dest.top -= windowPositionY;
541     dest.left -= windowPositionX;
542     dest.bottom-= windowPositionY;
543     dest.right -= windowPositionX;
544   }
545 
546   if(skin)
547     return;
548 
549   int menuSkip = 0;
550 
551   if(videoOption >= VIDEO_320x240 && menuToggle) {
552     int m = GetSystemMetrics(SM_CYMENU);
553     menuSkip = m;
554     dest.bottom -=m;
555   }
556 
557   if(videoOption > VIDEO_4X) {
558     int top = (fsHeight - surfaceSizeY) / 2;
559     int left = (fsWidth - surfaceSizeX) / 2;
560     dest.top += top;
561     dest.bottom += top;
562     dest.left += left;
563     dest.right += left;
564     if(fullScreenStretch) {
565       dest.top = 0+menuSkip;
566       dest.left = 0;
567       dest.right = fsWidth;
568       dest.bottom = fsHeight;
569     }
570   }
571 }
572 
updateIFB()573 void VBA::updateIFB()
574 {
575   if(systemColorDepth == 16) {
576     switch(ifbType) {
577     case 0:
578     default:
579       ifbFunction = NULL;
580       break;
581     case 1:
582       ifbFunction = MotionBlurIB;
583       break;
584     case 2:
585       ifbFunction = SmartIB;
586       break;
587     }
588   } else if(systemColorDepth == 32) {
589     switch(ifbType) {
590     case 0:
591     default:
592       ifbFunction = NULL;
593       break;
594     case 1:
595       ifbFunction = MotionBlurIB32;
596       break;
597     case 2:
598       ifbFunction = SmartIB32;
599       break;
600     }
601   } else
602     ifbFunction = NULL;
603 }
604 
updateFilter()605 void VBA::updateFilter()
606 {
607   filterWidth = sizeX;
608   filterHeight = sizeY;
609 
610   if(systemColorDepth == 16 && (videoOption > VIDEO_1X &&
611                                 videoOption != VIDEO_320x240)) {
612     switch(filterType) {
613     default:
614     case 0:
615       filterFunction = NULL;
616       break;
617     case 1:
618       filterFunction = ScanlinesTV;
619       break;
620     case 2:
621       filterFunction = _2xSaI;
622       break;
623     case 3:
624       filterFunction = Super2xSaI;
625       break;
626     case 4:
627       filterFunction = SuperEagle;
628       break;
629     case 5:
630       filterFunction = Pixelate;
631       break;
632     case 6:
633       filterFunction = MotionBlur;
634       break;
635     case 7:
636       filterFunction = AdMame2x;
637       break;
638     case 8:
639       filterFunction = Simple2x;
640       break;
641     case 9:
642       filterFunction = Bilinear;
643       break;
644     case 10:
645       filterFunction = BilinearPlus;
646       break;
647     case 11:
648       filterFunction = Scanlines;
649       break;
650     case 12:
651       filterFunction = hq2x;
652       break;
653     case 13:
654       filterFunction = lq2x;
655       break;
656     }
657 
658     if(filterType != 0) {
659       rect.right = sizeX*2;
660       rect.bottom = sizeY*2;
661       memset(delta,255,sizeof(delta));
662     } else {
663       rect.right = sizeX;
664       rect.bottom = sizeY;
665     }
666   } else {
667     if(systemColorDepth == 32 && videoOption > VIDEO_1X &&
668        videoOption != VIDEO_320x240) {
669       switch(filterType) {
670       default:
671       case 0:
672         filterFunction = NULL;
673         break;
674       case 1:
675         filterFunction = ScanlinesTV32;
676         break;
677       case 2:
678         filterFunction = _2xSaI32;
679         break;
680       case 3:
681         filterFunction = Super2xSaI32;
682         break;
683       case 4:
684         filterFunction = SuperEagle32;
685         break;
686       case 5:
687         filterFunction = Pixelate32;
688         break;
689       case 6:
690         filterFunction = MotionBlur32;
691         break;
692       case 7:
693         filterFunction = AdMame2x32;
694         break;
695       case 8:
696         filterFunction = Simple2x32;
697         break;
698       case 9:
699         filterFunction = Bilinear32;
700         break;
701       case 10:
702         filterFunction = BilinearPlus32;
703         break;
704       case 11:
705         filterFunction = Scanlines32;
706         break;
707       case 12:
708         filterFunction = hq2x32;
709         break;
710       case 13:
711         filterFunction = lq2x32;
712         break;
713       }
714       if(filterType != 0) {
715         rect.right = sizeX*2;
716         rect.bottom = sizeY*2;
717         memset(delta,255,sizeof(delta));
718       } else {
719         rect.right = sizeX;
720         rect.bottom = sizeY;
721       }
722     } else
723       filterFunction = NULL;
724   }
725 
726   if(display)
727     display->changeRenderSize(rect.right, rect.bottom);
728 }
729 
updateMenuBar()730 void VBA::updateMenuBar()
731 {
732   if(menu != NULL) {
733     if(m_pMainWnd)
734       m_pMainWnd->SetMenu(NULL);
735     m_menu.Detach();
736     DestroyMenu(menu);
737   }
738 
739   if(popup != NULL) {
740     // force popup recreation if language changed
741     DestroyMenu(popup);
742     popup = NULL;
743   }
744 
745   m_menu.Attach(winResLoadMenu(MAKEINTRESOURCE(IDR_MENU)));
746   menu = (HMENU)m_menu;
747 
748   // don't set a menu if skin is active
749   if(skin == NULL)
750     if(m_pMainWnd)
751       m_pMainWnd->SetMenu(&m_menu);
752 }
753 
winlog(const char * msg,...)754 void winlog(const char *msg, ...)
755 {
756   CString buffer;
757   va_list valist;
758 
759   va_start(valist, msg);
760   buffer.FormatV(msg, valist);
761 
762   if(theApp.winout == NULL) {
763     theApp.winout = fopen("vba-trace.log","w");
764   }
765 
766   fputs(buffer, theApp.winout);
767 
768   va_end(valist);
769 }
770 
log(const char * msg,...)771 void log(const char *msg, ...)
772 {
773   CString buffer;
774   va_list valist;
775 
776   va_start(valist, msg);
777   buffer.FormatV(msg, valist);
778 
779   toolsLog(buffer);
780 
781   va_end(valist);
782 }
783 
systemReadJoypads()784 bool systemReadJoypads()
785 {
786   if(theApp.input)
787     return theApp.input->readDevices();
788   return false;
789 }
790 
systemReadJoypad(int which)791 u32 systemReadJoypad(int which)
792 {
793   if(theApp.input)
794     return theApp.input->readDevice(which);
795   return 0;
796 }
797 
systemDrawScreen()798 void systemDrawScreen()
799 {
800   if(theApp.display == NULL)
801     return;
802 
803   theApp.renderedFrames++;
804 
805   if(theApp.updateCount) {
806     POSITION pos = theApp.updateList.GetHeadPosition();
807     while(pos) {
808       IUpdateListener *up = theApp.updateList.GetNext(pos);
809       up->update();
810     }
811   }
812 
813   if(theApp.aviRecording && !theApp.painting) {
814     int width = 240;
815     int height = 160;
816     switch(theApp.cartridgeType) {
817     case 0:
818       width = 240;
819       height = 160;
820       break;
821     case 1:
822       if(gbBorderOn) {
823         width = 256;
824         height = 224;
825       } else {
826         width = 160;
827         height = 144;
828       }
829       break;
830     }
831 
832     if(theApp.aviRecorder == NULL) {
833       theApp.aviRecorder = new AVIWrite();
834       theApp.aviFrameNumber = 0;
835 
836       theApp.aviRecorder->SetFPS(60);
837 
838       BITMAPINFOHEADER bi;
839       memset(&bi, 0, sizeof(bi));
840       bi.biSize = 0x28;
841       bi.biPlanes = 1;
842       bi.biBitCount = 24;
843       bi.biWidth = width;
844       bi.biHeight = height;
845       bi.biSizeImage = 3*width*height;
846       theApp.aviRecorder->SetVideoFormat(&bi);
847       theApp.aviRecorder->Open(theApp.aviRecordName);
848     }
849 
850     char *bmp = new char[width*height*3];
851 
852     utilWriteBMP(bmp, width, height, pix);
853     theApp.aviRecorder->AddFrame(theApp.aviFrameNumber, bmp);
854 
855     delete bmp;
856   }
857 
858   if(theApp.ifbFunction) {
859     if(systemColorDepth == 16)
860       theApp.ifbFunction(pix+theApp.filterWidth*2+4, theApp.filterWidth*2+4,
861                          theApp.filterWidth, theApp.filterHeight);
862     else
863       theApp.ifbFunction(pix+theApp.filterWidth*4+4, theApp.filterWidth*4+4,
864                          theApp.filterWidth, theApp.filterHeight);
865   }
866 
867   theApp.display->render();
868 }
869 
systemScreenCapture(int captureNumber)870 void systemScreenCapture(int captureNumber)
871 {
872   if(theApp.m_pMainWnd)
873     ((MainWnd *)theApp.m_pMainWnd)->screenCapture(captureNumber);
874 }
875 
systemGetClock()876 u32 systemGetClock()
877 {
878   return timeGetTime();
879 }
880 
systemMessage(int number,const char * defaultMsg,...)881 void systemMessage(int number, const char *defaultMsg, ...)
882 {
883   CString buffer;
884   va_list valist;
885   CString msg = defaultMsg;
886   if(number)
887     msg = winResLoadString(number);
888 
889   va_start(valist, defaultMsg);
890   buffer.FormatV(msg, valist);
891 
892   theApp.winCheckFullscreen();
893 
894   AfxGetApp()->m_pMainWnd->MessageBox(buffer, winResLoadString(IDS_ERROR), MB_OK|MB_ICONERROR);
895 
896   va_end(valist);
897 }
898 
systemSetTitle(const char * title)899 void systemSetTitle(const char *title)
900 {
901   if(theApp.m_pMainWnd != NULL) {
902     AfxGetApp()->m_pMainWnd->SetWindowText(title);
903   }
904 }
905 
systemShowSpeed(int speed)906 void systemShowSpeed(int speed)
907 {
908   systemSpeed = speed;
909   theApp.showRenderedFrames = theApp.renderedFrames;
910   theApp.renderedFrames = 0;
911   if(theApp.videoOption <= VIDEO_4X && theApp.showSpeed) {
912     CString buffer;
913     if(theApp.showSpeed == 1)
914       buffer.Format("VisualBoyAdvance-%3d%%", systemSpeed);
915     else
916       buffer.Format("VisualBoyAdvance-%3d%%(%d, %d fps)", systemSpeed,
917                     systemFrameSkip,
918                     theApp.showRenderedFrames);
919 
920     systemSetTitle(buffer);
921   }
922 }
923 
systemFrame()924 void systemFrame()
925 {
926   if(theApp.aviRecording)
927     theApp.aviFrameNumber++;
928   if(theApp.movieRecording || theApp.moviePlaying)
929     theApp.movieFrame++;
930 }
931 
system10Frames(int rate)932 void system10Frames(int rate)
933 {
934   u32 time = systemGetClock();
935   if(!theApp.wasPaused && theApp.autoFrameSkip && !theApp.throttle) {
936     u32 diff = time - theApp.autoFrameSkipLastTime;
937     int speed = 100;
938 
939     if(diff)
940       speed = (1000000/rate)/diff;
941 
942     if(speed >= 98) {
943       theApp.frameskipadjust++;
944 
945       if(theApp.frameskipadjust >= 3) {
946         theApp.frameskipadjust=0;
947         if(systemFrameSkip > 0)
948           systemFrameSkip--;
949       }
950     } else {
951       if(speed  < 80)
952         theApp.frameskipadjust -= (90 - speed)/5;
953       else if(systemFrameSkip < 9)
954         theApp.frameskipadjust--;
955 
956       if(theApp.frameskipadjust <= -2) {
957         theApp.frameskipadjust += 2;
958         if(systemFrameSkip < 9)
959           systemFrameSkip++;
960       }
961     }
962   }
963   if(!theApp.wasPaused && theApp.throttle) {
964     if(!speedup) {
965       u32 diff = time - theApp.throttleLastTime;
966 
967       int target = (1000000/(rate*theApp.throttle));
968       int d = (target - diff);
969 
970       if(d > 0) {
971         Sleep(d);
972       }
973     }
974     theApp.throttleLastTime = systemGetClock();
975   }
976   if(theApp.rewindMemory) {
977     if(++theApp.rewindCounter >= (theApp.rewindTimer)) {
978       theApp.rewindSaveNeeded = true;
979       theApp.rewindCounter = 0;
980     }
981   }
982   if(systemSaveUpdateCounter) {
983     if(--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED) {
984       ((MainWnd *)theApp.m_pMainWnd)->writeBatteryFile();
985       systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
986     }
987   }
988 
989   theApp.wasPaused = false;
990   theApp.autoFrameSkipLastTime = time;
991 }
992 
systemScreenMessage(const char * msg)993 void systemScreenMessage(const char *msg)
994 {
995   theApp.screenMessage = true;
996   theApp.screenMessageTime = GetTickCount();
997   theApp.screenMessageBuffer = msg;
998 
999   if(theApp.screenMessageBuffer.GetLength() > 40)
1000     theApp.screenMessageBuffer = theApp.screenMessageBuffer.Left(40);
1001 }
1002 
systemUpdateMotionSensor()1003 void systemUpdateMotionSensor()
1004 {
1005   if(theApp.input)
1006     theApp.input->checkMotionKeys();
1007 }
1008 
systemGetSensorX()1009 int systemGetSensorX()
1010 {
1011   return theApp.sensorX;
1012 }
1013 
systemGetSensorY()1014 int systemGetSensorY()
1015 {
1016   return theApp.sensorY;
1017 }
1018 
systemSoundInit()1019 bool systemSoundInit()
1020 {
1021   if(theApp.sound)
1022     delete theApp.sound;
1023 
1024   theApp.sound = newDirectSound();
1025   return theApp.sound->init();
1026 }
1027 
1028 
systemSoundShutdown()1029 void systemSoundShutdown()
1030 {
1031   if(theApp.sound)
1032     delete theApp.sound;
1033   theApp.sound = NULL;
1034 }
1035 
systemSoundPause()1036 void systemSoundPause()
1037 {
1038   if(theApp.sound)
1039     theApp.sound->pause();
1040 }
1041 
systemSoundReset()1042 void systemSoundReset()
1043 {
1044   if(theApp.sound)
1045     theApp.sound->reset();
1046 }
1047 
systemSoundResume()1048 void systemSoundResume()
1049 {
1050   if(theApp.sound)
1051     theApp.sound->resume();
1052 }
1053 
systemWriteDataToSoundBuffer()1054 void systemWriteDataToSoundBuffer()
1055 {
1056   if(theApp.sound)
1057     theApp.sound->write();
1058 }
1059 
systemCanChangeSoundQuality()1060 bool systemCanChangeSoundQuality()
1061 {
1062   return true;
1063 }
1064 
systemPauseOnFrame()1065 bool systemPauseOnFrame()
1066 {
1067   if(theApp.winPauseNextFrame) {
1068     theApp.paused = true;
1069     theApp.winPauseNextFrame = false;
1070     return true;
1071   }
1072   return false;
1073 }
1074 
systemGbBorderOn()1075 void systemGbBorderOn()
1076 {
1077   if(emulating && theApp.cartridgeType == 1 && gbBorderOn) {
1078     theApp.updateWindowSize(theApp.videoOption);
1079   }
1080 }
1081 
OnIdle(LONG lCount)1082 BOOL VBA::OnIdle(LONG lCount)
1083 {
1084   if(emulating && debugger) {
1085     MSG msg;
1086     remoteStubMain();
1087     if(debugger)
1088       return TRUE; // continue loop
1089     return !::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE);
1090   } else if(emulating && active && !paused) {
1091     for(int i = 0; i < 2; i++) {
1092       emulator.emuMain(emulator.emuCount);
1093 
1094       if(rewindSaveNeeded && rewindMemory && emulator.emuWriteMemState) {
1095         rewindCount++;
1096         if(rewindCount > 8)
1097           rewindCount = 8;
1098         if(emulator.emuWriteMemState(&rewindMemory[rewindPos*REWIND_SIZE],
1099                                      REWIND_SIZE)) {
1100           rewindPos = ++rewindPos & 7;
1101           if(rewindCount == 8)
1102             rewindTopPos = ++rewindTopPos & 7;
1103         }
1104       }
1105 
1106       rewindSaveNeeded = false;
1107     }
1108 
1109     if(mouseCounter) {
1110       if(--mouseCounter == 0) {
1111         SetCursor(NULL);
1112       }
1113     }
1114     return TRUE;
1115   }
1116   return FALSE;
1117 
1118   //  return CWinApp::OnIdle(lCount);
1119 }
1120 
addRecentFile(CString file)1121 void VBA::addRecentFile(CString file)
1122 {
1123   // Do not change recent list if frozen
1124   if(recentFreeze)
1125     return;
1126   int i = 0;
1127   for(i = 0; i < 10; i++) {
1128     if(recentFiles[i].GetLength() == 0)
1129       break;
1130 
1131     if(recentFiles[i].Compare(file) == 0) {
1132       if(i == 0)
1133         return;
1134       CString p = recentFiles[i];
1135       for(int j = i; j > 0; j--) {
1136         recentFiles[j] = recentFiles[j-1];
1137       }
1138       recentFiles[0] = p;
1139       return;
1140     }
1141   }
1142   int num = 0;
1143   for(i = 0; i < 10; i++) {
1144     if(recentFiles[i].GetLength() != 0)
1145       num++;
1146   }
1147   if(num == 10) {
1148     num--;
1149   }
1150 
1151   for(i = num; i >= 1; i--) {
1152     recentFiles[i] = recentFiles[i-1];
1153   }
1154   recentFiles[0] = file;
1155 }
1156 
loadSettings()1157 void VBA::loadSettings()
1158 {
1159   CString buffer;
1160 
1161   languageOption = regQueryDwordValue("language", 1);
1162   if(languageOption < 0 || languageOption > 2)
1163     languageOption = 1;
1164 
1165   buffer = regQueryStringValue("languageName", "");
1166   if(!buffer.IsEmpty()) {
1167     languageName = buffer.Left(3);
1168   } else
1169     languageName = "";
1170 
1171   winSetLanguageOption(languageOption, true);
1172 
1173   frameSkip = regQueryDwordValue("frameSkip", 2);
1174   if(frameSkip < 0 || frameSkip > 9)
1175     frameSkip = 2;
1176 
1177   gbFrameSkip = regQueryDwordValue("gbFrameSkip", 0);
1178   if(gbFrameSkip < 0 || gbFrameSkip > 9)
1179     gbFrameSkip = 0;
1180 
1181   autoFrameSkip = regQueryDwordValue("autoFrameSkip", FALSE) ? TRUE : FALSE;
1182 
1183   vsync = regQueryDwordValue("vsync", false) ? true : false ;
1184   synchronize = regQueryDwordValue("synchronize", 1) ? true : false;
1185   fullScreenStretch = regQueryDwordValue("stretch", 0) ? true : false;
1186 
1187   videoOption = regQueryDwordValue("video", 0);
1188 
1189   if(videoOption < 0 || videoOption > VIDEO_OTHER)
1190     videoOption = 0;
1191 
1192   bool defaultVideoDriver = regQueryDwordValue("defaultVideoDriver", true) ?
1193     true : false;
1194 
1195   if(!regQueryBinaryValue("videoDriverGUID", (char *)&videoDriverGUID,
1196                           sizeof(GUID))) {
1197     defaultVideoDriver = TRUE;
1198   }
1199 
1200   if(defaultVideoDriver)
1201     pVideoDriverGUID = NULL;
1202   else
1203     pVideoDriverGUID = &videoDriverGUID;
1204 
1205   fsWidth = regQueryDwordValue("fsWidth", 0);
1206   fsHeight = regQueryDwordValue("fsHeight", 0);
1207   fsColorDepth = regQueryDwordValue("fsColorDepth", 0);
1208 
1209   if(videoOption == VIDEO_OTHER) {
1210     if(fsWidth < 0 || fsWidth > 4095 || fsHeight < 0 || fsHeight > 4095)
1211       videoOption = 0;
1212     if(fsColorDepth != 16 && fsColorDepth != 24 && fsColorDepth != 32)
1213       videoOption = 0;
1214   }
1215 
1216   renderMethod = (DISPLAY_TYPE)regQueryDwordValue("renderMethod", DIRECT_DRAW);
1217 
1218   if(renderMethod < GDI || renderMethod > OPENGL)
1219     renderMethod = DIRECT_DRAW;
1220 
1221   windowPositionX = regQueryDwordValue("windowX", 0);
1222   if(windowPositionX < 0)
1223     windowPositionX = 0;
1224   windowPositionY = regQueryDwordValue("windowY", 0);
1225   if(windowPositionY < 0)
1226     windowPositionY = 0;
1227 
1228   useBiosFile = regQueryDwordValue("useBios", 0) ? true: false;
1229 
1230   skipBiosFile = regQueryDwordValue("skipBios", 0) ? true : false;
1231 
1232   buffer = regQueryStringValue("biosFile", "");
1233 
1234   if(!buffer.IsEmpty()) {
1235     biosFileName = buffer;
1236   }
1237 
1238   int res = regQueryDwordValue("soundEnable", 0x30f);
1239 
1240   soundEnable(res);
1241   soundDisable(~res);
1242 
1243   soundOffFlag = (regQueryDwordValue("soundOff", 0)) ? true : false;
1244 
1245   soundQuality = regQueryDwordValue("soundQuality", 2);
1246 
1247   soundEcho = regQueryDwordValue("soundEcho", 0) ? true : false;
1248 
1249   soundLowPass = regQueryDwordValue("soundLowPass", 0) ? true : false;
1250 
1251   soundReverse = regQueryDwordValue("soundReverse", 0) ? true : false;
1252 
1253   soundVolume = regQueryDwordValue("soundVolume", 0);
1254   if(soundVolume < 0 || soundVolume > 5)
1255     soundVolume = 0;
1256 
1257   ddrawEmulationOnly = regQueryDwordValue("ddrawEmulationOnly", false) ? true : false;
1258   ddrawUseVideoMemory = regQueryDwordValue("ddrawUseVideoMemory", false) ? true : false;
1259   tripleBuffering = regQueryDwordValue("tripleBuffering", true) ? true : false;
1260 
1261   d3dFilter = regQueryDwordValue("d3dFilter", 0);
1262   if(d3dFilter < 0 || d3dFilter > 1)
1263     d3dFilter = 0;
1264   glFilter = regQueryDwordValue("glFilter", 0);
1265   if(glFilter < 0 || glFilter > 1)
1266     glFilter = 0;
1267   glType = regQueryDwordValue("glType", 0);
1268   if(glType < 0 || glType > 1)
1269     glType = 0;
1270 
1271   filterType = regQueryDwordValue("filter", 0);
1272   if(filterType < 0 || filterType > 13)
1273     filterType = 0;
1274 
1275   disableMMX = regQueryDwordValue("disableMMX", 0) ? true: false;
1276 
1277   disableStatusMessage = regQueryDwordValue("disableStatus", 0) ? true : false;
1278 
1279   showSpeed = regQueryDwordValue("showSpeed", 1);
1280   if(showSpeed < 0 || showSpeed > 2)
1281     showSpeed = 1;
1282 
1283   showSpeedTransparent = regQueryDwordValue("showSpeedTransparent", TRUE) ?
1284     TRUE : FALSE;
1285 
1286   winGbPrinterEnabled = regQueryDwordValue("gbPrinter", false) ? true : false;
1287 
1288   if(winGbPrinterEnabled)
1289     gbSerialFunction = gbPrinterSend;
1290   else
1291     gbSerialFunction = NULL;
1292 
1293   pauseWhenInactive = regQueryDwordValue("pauseWhenInactive", 1) ?
1294     true : false;
1295 
1296   useOldSync = regQueryDwordValue("useOldSync", 0) ?
1297     TRUE : FALSE;
1298 
1299   captureFormat = regQueryDwordValue("captureFormat", 0);
1300 
1301   removeIntros = regQueryDwordValue("removeIntros", false) ? true : false;
1302 
1303   recentFreeze = regQueryDwordValue("recentFreeze", false) ? true : false;
1304 
1305   autoIPS = regQueryDwordValue("autoIPS", true) ? true : false;
1306 
1307   cpuDisableSfx = regQueryDwordValue("disableSfx", 0) ? true : false;
1308 
1309   winSaveType = regQueryDwordValue("saveType", 0);
1310   if(winSaveType < 0 || winSaveType > 5)
1311     winSaveType = 0;
1312 
1313   cpuEnhancedDetection = regQueryDwordValue("enhancedDetection", 1) ? true :
1314     false;
1315 
1316   ifbType = regQueryDwordValue("ifbType", 0);
1317   if(ifbType < 0 || ifbType > 2)
1318     ifbType = 0;
1319 
1320   winFlashSize = regQueryDwordValue("flashSize", 0x10000);
1321   if(winFlashSize != 0x10000 && winFlashSize != 0x20000)
1322     winFlashSize = 0x10000;
1323 
1324   agbPrintEnable(regQueryDwordValue("agbPrint", 0) ? true : false);
1325 
1326   winRtcEnable = regQueryDwordValue("rtcEnabled", 0) ? true : false;
1327   rtcEnable(winRtcEnable);
1328 
1329   autoHideMenu = regQueryDwordValue("autoHideMenu", 0) ? true : false;
1330 
1331   skinEnabled = regQueryDwordValue("skinEnabled", 0) ? true : false;
1332 
1333   skinName = regQueryStringValue("skinName", "");
1334 
1335   switch(videoOption) {
1336   case VIDEO_320x240:
1337     fsWidth = 320;
1338     fsHeight = 240;
1339     fsColorDepth = 16;
1340     break;
1341   case VIDEO_640x480:
1342     fsWidth = 640;
1343     fsHeight = 480;
1344     fsColorDepth = 16;
1345     break;
1346   case VIDEO_800x600:
1347     fsWidth = 800;
1348     fsHeight = 600;
1349     fsColorDepth = 16;
1350     break;
1351   }
1352 
1353   winGbBorderOn = regQueryDwordValue("borderOn", 0);
1354   gbBorderAutomatic = regQueryDwordValue("borderAutomatic", 0);
1355   gbEmulatorType = regQueryDwordValue("emulatorType", 1);
1356   if(gbEmulatorType < 0 || gbEmulatorType > 5)
1357     gbEmulatorType = 1;
1358   gbColorOption = regQueryDwordValue("colorOption", 0);
1359 
1360   threadPriority = regQueryDwordValue("priority", 2);
1361 
1362   if(threadPriority < 0 || threadPriority >3)
1363     threadPriority = 2;
1364   updatePriority();
1365 
1366   autoSaveLoadCheatList = regQueryDwordValue("autoSaveCheatList", 0) ?
1367     true : false;
1368 
1369   gbPaletteOption = regQueryDwordValue("gbPaletteOption", 0);
1370   if(gbPaletteOption < 0)
1371     gbPaletteOption = 0;
1372   if(gbPaletteOption > 2)
1373     gbPaletteOption = 2;
1374 
1375   regQueryBinaryValue("gbPalette", (char *)systemGbPalette,
1376                       24*sizeof(u16));
1377 
1378   rewindTimer = regQueryDwordValue("rewindTimer", 0);
1379 
1380   if(rewindTimer < 0 || rewindTimer > 600)
1381     rewindTimer = 0;
1382 
1383   rewindTimer *= 6; // convert to 10 frames multiple
1384 
1385   if(rewindTimer != 0)
1386     rewindMemory = (char *)malloc(8*REWIND_SIZE);
1387 
1388   for(int i = 0; i < 10; i++) {
1389     buffer.Format("recent%d", i);
1390     char *s = regQueryStringValue(buffer, NULL);
1391     if(s == NULL)
1392       break;
1393     recentFiles[i] = s;
1394   }
1395 
1396   joypadDefault = regQueryDwordValue("joypadDefault", 0);
1397   if(joypadDefault < 0 || joypadDefault > 3)
1398     joypadDefault = 0;
1399 
1400   autoLoadMostRecent = regQueryDwordValue("autoLoadMostRecent", false) ? true :
1401     false;
1402 
1403   cheatsEnabled = regQueryDwordValue("cheatsEnabled", true) ? true : false;
1404 
1405   fsMaxScale = regQueryDwordValue("fsMaxScale", 0);
1406 
1407   throttle = regQueryDwordValue("throttle", 0);
1408   if(throttle < 5 || throttle > 1000)
1409     throttle = 0;
1410 }
1411 
updateFrameSkip()1412 void VBA::updateFrameSkip()
1413 {
1414   switch(cartridgeType) {
1415   case 0:
1416     systemFrameSkip = frameSkip;
1417     break;
1418   case 1:
1419     systemFrameSkip = gbFrameSkip;
1420     break;
1421   }
1422 }
1423 
updateVideoSize(UINT id)1424 void VBA::updateVideoSize(UINT id)
1425 {
1426   int value = 0;
1427 
1428   switch(id) {
1429   case ID_OPTIONS_VIDEO_X1:
1430     value = VIDEO_1X;
1431     break;
1432   case ID_OPTIONS_VIDEO_X2:
1433     value = VIDEO_2X;
1434     break;
1435   case ID_OPTIONS_VIDEO_X3:
1436     value = VIDEO_3X;
1437     break;
1438   case ID_OPTIONS_VIDEO_X4:
1439     value = VIDEO_4X;
1440     break;
1441   case ID_OPTIONS_VIDEO_FULLSCREEN320X240:
1442     value = VIDEO_320x240;
1443     fsWidth = 320;
1444     fsHeight = 240;
1445     fsColorDepth = 16;
1446     break;
1447   case ID_OPTIONS_VIDEO_FULLSCREEN640X480:
1448     value = VIDEO_640x480;
1449     fsWidth = 640;
1450     fsHeight = 480;
1451     fsColorDepth = 16;
1452     break;
1453   case ID_OPTIONS_VIDEO_FULLSCREEN800X600:
1454     value = VIDEO_800x600;
1455     fsWidth = 800;
1456     fsHeight = 600;
1457     fsColorDepth = 16;
1458     break;
1459   case ID_OPTIONS_VIDEO_FULLSCREEN:
1460     value = VIDEO_OTHER;
1461     break;
1462   }
1463 
1464   if(videoOption == value && value != VIDEO_OTHER)
1465     return;
1466 
1467   updateWindowSize(value);
1468 }
1469 
1470 typedef BOOL (WINAPI *GETMENUBARINFO)(HWND, LONG, LONG, PMENUBARINFO);
1471 
winCheckMenuBarInfo(int & winSizeX,int & winSizeY)1472 static void winCheckMenuBarInfo(int& winSizeX, int& winSizeY)
1473 {
1474   HINSTANCE hinstDll;
1475   DWORD dwVersion = 0;
1476 
1477   hinstDll = AfxLoadLibrary("USER32.DLL");
1478 
1479   if(hinstDll) {
1480     GETMENUBARINFO func = (GETMENUBARINFO)GetProcAddress(hinstDll,
1481                                                          "GetMenuBarInfo");
1482 
1483     if(func) {
1484       MENUBARINFO info;
1485       info.cbSize = sizeof(info);
1486 
1487       func(AfxGetMainWnd()->GetSafeHwnd(), OBJID_MENU, 0, &info);
1488 
1489       int menuHeight = GetSystemMetrics(SM_CYMENU);
1490 
1491       if((info.rcBar.bottom - info.rcBar.top) > menuHeight) {
1492         winSizeY += (info.rcBar.bottom - info.rcBar.top) - menuHeight + 1;
1493         theApp.m_pMainWnd->SetWindowPos(
1494                                         0, //HWND_TOPMOST,
1495                                         theApp.windowPositionX,
1496                                         theApp.windowPositionY,
1497                                         winSizeX,
1498                                         winSizeY,
1499                                         SWP_NOMOVE | SWP_SHOWWINDOW);
1500       }
1501     }
1502     AfxFreeLibrary(hinstDll);
1503   }
1504 }
1505 
updateWindowSize(int value)1506 void VBA::updateWindowSize(int value)
1507 {
1508   regSetDwordValue("video", value);
1509 
1510   if(value == VIDEO_OTHER) {
1511     regSetDwordValue("fsWidth", fsWidth);
1512     regSetDwordValue("fsHeight", fsHeight);
1513     regSetDwordValue("fsColorDepth", fsColorDepth);
1514   }
1515 
1516   if(((value >= VIDEO_320x240) &&
1517       (videoOption != value)) ||
1518      (videoOption >= VIDEO_320x240 &&
1519       value <= VIDEO_4X) ||
1520      fsForceChange) {
1521     fsForceChange = false;
1522     changingVideoSize = true;
1523     shutdownDisplay();
1524     if(input) {
1525       delete input;
1526       input = NULL;
1527     }
1528     m_pMainWnd->DragAcceptFiles(FALSE);
1529     CWnd *pWnd = m_pMainWnd;
1530     m_pMainWnd = NULL;
1531     pWnd->DestroyWindow();
1532     delete pWnd;
1533     videoOption = value;
1534     if(!initDisplay()) {
1535       if(videoOption == VIDEO_320x240 ||
1536          videoOption == VIDEO_640x480 ||
1537          videoOption == VIDEO_800x600 ||
1538          videoOption == VIDEO_OTHER) {
1539         regSetDwordValue("video", VIDEO_1X);
1540         if(pVideoDriverGUID)
1541           regSetDwordValue("defaultVideoDriver", TRUE);
1542       }
1543       changingVideoSize = false;
1544       AfxPostQuitMessage(0);
1545       return;
1546     }
1547     if(!initInput()) {
1548       changingVideoSize = false;
1549       AfxPostQuitMessage(0);
1550       return;
1551     }
1552     input->checkKeys();
1553     updateMenuBar();
1554     changingVideoSize = FALSE;
1555     updateWindowSize(videoOption);
1556     return;
1557   }
1558 
1559   sizeX = 240;
1560   sizeY = 160;
1561 
1562   videoOption = value;
1563 
1564   if(cartridgeType == 1) {
1565     if(gbBorderOn) {
1566       sizeX = 256;
1567       sizeY = 224;
1568       gbBorderLineSkip = 256;
1569       gbBorderColumnSkip = 48;
1570       gbBorderRowSkip = 40;
1571     } else {
1572       sizeX = 160;
1573       sizeY = 144;
1574       gbBorderLineSkip = 160;
1575       gbBorderColumnSkip = 0;
1576       gbBorderRowSkip = 0;
1577     }
1578   }
1579 
1580   surfaceSizeX = sizeX;
1581   surfaceSizeY = sizeY;
1582 
1583   switch(videoOption) {
1584   case VIDEO_1X:
1585     surfaceSizeX = sizeX;
1586     surfaceSizeY = sizeY;
1587     break;
1588   case VIDEO_2X:
1589     surfaceSizeX = sizeX * 2;
1590     surfaceSizeY = sizeY * 2;
1591     break;
1592   case VIDEO_3X:
1593     surfaceSizeX = sizeX * 3;
1594     surfaceSizeY = sizeY * 3;
1595     break;
1596   case VIDEO_4X:
1597     surfaceSizeX = sizeX * 4;
1598     surfaceSizeY = sizeY * 4;
1599     break;
1600   case VIDEO_320x240:
1601   case VIDEO_640x480:
1602   case VIDEO_800x600:
1603   case VIDEO_OTHER:
1604     {
1605       int scaleX = 1;
1606       int scaleY = 1;
1607       scaleX = (fsWidth / sizeX);
1608       scaleY = (fsHeight / sizeY);
1609       int min = scaleX < scaleY ? scaleX : scaleY;
1610       if(fsMaxScale)
1611         min = min > fsMaxScale ? fsMaxScale : min;
1612       surfaceSizeX = min * sizeX;
1613       surfaceSizeY = min * sizeY;
1614       if((fullScreenStretch && (display != NULL &&
1615                                 (display->getType() != DIRECT_3D)))
1616          || (display != NULL && display->getType() >= DIRECT_3D)) {
1617         surfaceSizeX = fsWidth;
1618         surfaceSizeY = fsHeight;
1619       }
1620     }
1621     break;
1622   }
1623 
1624   rect.right = sizeX;
1625   rect.bottom = sizeY;
1626 
1627   int winSizeX = sizeX;
1628   int winSizeY = sizeY;
1629 
1630   if(videoOption <= VIDEO_4X) {
1631     dest.left = 0;
1632     dest.top = 0;
1633     dest.right = surfaceSizeX;
1634     dest.bottom = surfaceSizeY;
1635 
1636     DWORD style = WS_POPUP | WS_VISIBLE;
1637 
1638     style |= WS_OVERLAPPEDWINDOW;
1639 
1640     menuToggle = TRUE;
1641     AdjustWindowRectEx(&dest, style, TRUE, 0); //WS_EX_TOPMOST);
1642 
1643     winSizeX = dest.right-dest.left;
1644     winSizeY = dest.bottom-dest.top;
1645 
1646     if(skin == NULL) {
1647       m_pMainWnd->SetWindowPos(0, //HWND_TOPMOST,
1648                                windowPositionX,
1649                                windowPositionY,
1650                                winSizeX,
1651                                winSizeY,
1652                                SWP_NOMOVE | SWP_SHOWWINDOW);
1653 
1654       winCheckMenuBarInfo(winSizeX, winSizeY);
1655     }
1656   }
1657 
1658   adjustDestRect();
1659 
1660   updateIFB();
1661   updateFilter();
1662 
1663   m_pMainWnd->RedrawWindow(NULL,NULL,RDW_INVALIDATE|RDW_ERASE|RDW_ALLCHILDREN);
1664 }
1665 
initDisplay()1666 bool VBA::initDisplay()
1667 {
1668   return updateRenderMethod(false);
1669 }
1670 
updateRenderMethod(bool force)1671 bool VBA::updateRenderMethod(bool force)
1672 {
1673   bool res = updateRenderMethod0(force);
1674 
1675   while(!res && renderMethod > 0) {
1676     if(renderMethod == OPENGL)
1677       renderMethod = DIRECT_3D;
1678     else if(renderMethod == DIRECT_3D)
1679       renderMethod = DIRECT_DRAW;
1680     else if(renderMethod == DIRECT_DRAW) {
1681       if(videoOption > VIDEO_4X) {
1682         videoOption = VIDEO_2X;
1683         force = true;
1684       } else
1685         renderMethod = GDI;
1686     }
1687 
1688     res = updateRenderMethod(force);
1689   }
1690   return res;
1691 }
1692 
updateRenderMethod0(bool force)1693 bool VBA::updateRenderMethod0(bool force)
1694 {
1695   bool initInput = false;
1696 
1697   if(display) {
1698     if(display->getType() != renderMethod || force) {
1699       if(skin) {
1700         delete skin;
1701         skin = NULL;
1702       }
1703       initInput = true;
1704       changingVideoSize = true;
1705       shutdownDisplay();
1706       if(input) {
1707         delete input;
1708         input = NULL;
1709       }
1710       CWnd *pWnd = m_pMainWnd;
1711 
1712       m_pMainWnd = NULL;
1713       pWnd->DragAcceptFiles(FALSE);
1714       pWnd->DestroyWindow();
1715       delete pWnd;
1716 
1717       display = NULL;
1718       regSetDwordValue("renderMethod", renderMethod);
1719     }
1720   }
1721   if(display == NULL) {
1722     switch(renderMethod) {
1723     case GDI:
1724       display = newGDIDisplay();
1725       break;
1726     case DIRECT_DRAW:
1727       display = newDirectDrawDisplay();
1728       break;
1729     case DIRECT_3D:
1730       display = newDirect3DDisplay();
1731       break;
1732     case OPENGL:
1733       display = newOpenGLDisplay();
1734       break;
1735     }
1736 
1737     if(display->initialize()) {
1738       winUpdateSkin();
1739       if(initInput) {
1740         if(!this->initInput()) {
1741           changingVideoSize = false;
1742           AfxPostQuitMessage(0);
1743           return false;
1744         }
1745         input->checkKeys();
1746         updateMenuBar();
1747         changingVideoSize = false;
1748         updateWindowSize(videoOption);
1749 
1750         m_pMainWnd->ShowWindow(SW_SHOW);
1751         m_pMainWnd->UpdateWindow();
1752         m_pMainWnd->SetFocus();
1753 
1754         return true;
1755       } else {
1756         changingVideoSize = false;
1757         return true;
1758       }
1759     }
1760     changingVideoSize = false;
1761   }
1762   return true;
1763 }
1764 
winCheckFullscreen()1765 void VBA::winCheckFullscreen()
1766 {
1767   if(videoOption > VIDEO_4X && tripleBuffering) {
1768     if(display)
1769       display->checkFullScreen();
1770   }
1771 }
1772 
shutdownDisplay()1773 void VBA::shutdownDisplay()
1774 {
1775   if(display != NULL) {
1776     display->cleanup();
1777     delete display;
1778     display = NULL;
1779   }
1780 }
1781 
directXMessage(const char * msg)1782 void VBA::directXMessage(const char *msg)
1783 {
1784   systemMessage(IDS_DIRECTX_7_REQUIRED,
1785                 "DirectX 7.0 or greater is required to run.\nDownload at http://www.microsoft.com/directx.\n\nError found at: %s",
1786                 msg);
1787 }
1788 
winUpdateSkin()1789 void VBA::winUpdateSkin()
1790 {
1791   skinButtons = 0;
1792   if(skin) {
1793     delete skin;
1794     skin = NULL;
1795   }
1796 
1797   if(!skinName.IsEmpty() && skinEnabled && display->isSkinSupported()) {
1798     skin = new CSkin();
1799     if(skin->Initialize(skinName)) {
1800       skin->Hook(m_pMainWnd);
1801       skin->Enable(true);
1802     } else {
1803       delete skin;
1804       skin = NULL;
1805     }
1806   }
1807 
1808   if(!skin) {
1809     adjustDestRect();
1810     updateMenuBar();
1811   }
1812 }
1813 
updatePriority()1814 void VBA::updatePriority()
1815 {
1816   switch(threadPriority) {
1817   case 0:
1818     SetThreadPriority(THREAD_PRIORITY_HIGHEST);
1819     break;
1820   case 1:
1821     SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
1822     break;
1823   case 3:
1824     SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
1825     break;
1826   default:
1827     SetThreadPriority(THREAD_PRIORITY_NORMAL);
1828   }
1829 }
1830 
1831 #ifdef MMX
detectMMX()1832 bool VBA::detectMMX()
1833 {
1834   bool support = false;
1835   char brand[13];
1836 
1837   // check for Intel chip
1838   __try {
1839     __asm {
1840       mov eax, 0;
1841       cpuid;
1842       mov [dword ptr brand+0], ebx;
1843       mov [dword ptr brand+4], edx;
1844       mov [dword ptr brand+8], ecx;
1845     }
1846   }
1847   __except(EXCEPTION_EXECUTE_HANDLER) {
1848     if(_exception_code() == STATUS_ILLEGAL_INSTRUCTION) {
1849       return false;
1850     }
1851     return false;
1852   }
1853   // Check for Intel or AMD CPUs
1854   if(strncmp(brand, "GenuineIntel", 12)) {
1855     if(strncmp(brand, "AuthenticAMD", 12)) {
1856       return false;
1857     }
1858   }
1859 
1860   __asm {
1861     mov eax, 1;
1862     cpuid;
1863     test edx, 00800000h;
1864     jz NotFound;
1865     mov [support], 1;
1866   NotFound:
1867   }
1868   return support;
1869 }
1870 #endif
1871 
winSetLanguageOption(int option,bool force)1872 void VBA::winSetLanguageOption(int option, bool force)
1873 {
1874   if(((option == languageOption) && option != 2) && !force)
1875     return;
1876   switch(option) {
1877   case 0:
1878     {
1879       char lbuffer[10];
1880 
1881       if(GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SABBREVLANGNAME,
1882                        lbuffer, 10)) {
1883         HINSTANCE l = winLoadLanguage(lbuffer);
1884         if(l == NULL) {
1885           LCID locIdBase = MAKELCID( MAKELANGID( PRIMARYLANGID( GetSystemDefaultLangID() ), SUBLANG_NEUTRAL ), SORT_DEFAULT );
1886           if(GetLocaleInfo(locIdBase, LOCALE_SABBREVLANGNAME,
1887                            lbuffer, 10)) {
1888             l = winLoadLanguage(lbuffer);
1889             if(l == NULL) {
1890               systemMessage(IDS_FAILED_TO_LOAD_LIBRARY,
1891                             "Failed to load library %s",
1892                             lbuffer);
1893               return;
1894             }
1895           }
1896         }
1897         AfxSetResourceHandle(l);
1898         if(languageModule != NULL)
1899           AfxFreeLibrary(languageModule);
1900         languageModule = l;
1901       } else {
1902         systemMessage(IDS_FAILED_TO_GET_LOCINFO,
1903                       "Failed to get locale information");
1904         return;
1905       }
1906     }
1907     break;
1908   case 1:
1909     if(languageModule != NULL)
1910       AfxFreeLibrary(languageModule);
1911     languageModule = NULL;
1912     AfxSetResourceHandle(AfxGetInstanceHandle());
1913     break;
1914   case 2:
1915     {
1916       if(!force) {
1917         LangSelect dlg;
1918         if(dlg.DoModal()) {
1919           HINSTANCE l = winLoadLanguage(languageName);
1920           if(l == NULL) {
1921             systemMessage(IDS_FAILED_TO_LOAD_LIBRARY,
1922                           "Failed to load library %s",
1923                           languageName);
1924             return;
1925           }
1926           AfxSetResourceHandle(l);
1927           if(languageModule != NULL)
1928             AfxFreeLibrary(languageModule);
1929           languageModule = l;
1930         }
1931       } else {
1932         if(languageName.IsEmpty())
1933           return;
1934         HINSTANCE l = winLoadLanguage(languageName);
1935         if(l == NULL) {
1936           systemMessage(IDS_FAILED_TO_LOAD_LIBRARY,
1937                         "Failed to load library %s",
1938                         languageName);
1939           return;
1940         }
1941         AfxSetResourceHandle(l);
1942         if(languageModule != NULL)
1943           FreeLibrary(languageModule);
1944         languageModule = l;
1945       }
1946     }
1947     break;
1948   }
1949   languageOption = option;
1950   updateMenuBar();
1951 }
1952 
winLoadLanguage(const char * name)1953 HINSTANCE VBA::winLoadLanguage(const char *name)
1954 {
1955   CString buffer;
1956 
1957   buffer.Format("vba_%s.dll", name);
1958 
1959   HINSTANCE l = AfxLoadLibrary(buffer);
1960 
1961   if(l == NULL) {
1962     if(strlen(name) == 3) {
1963       char buffer2[3];
1964       buffer2[0] = name[0];
1965       buffer2[1] = name[1];
1966       buffer2[2] = 0;
1967       buffer.Format("vba_%s.dll", buffer2);
1968 
1969       return AfxLoadLibrary(buffer);
1970     }
1971   }
1972   return l;
1973 }
1974 
1975 
initInput()1976 bool VBA::initInput()
1977 {
1978   if(input)
1979     delete input;
1980   input = newDirectInput();
1981   if(input->initialize()) {
1982     input->loadSettings();
1983     input->checkKeys();
1984     return true;
1985   }
1986   delete input;
1987   return false;
1988 }
1989 
winAddUpdateListener(IUpdateListener * l)1990 void VBA::winAddUpdateListener(IUpdateListener *l)
1991 {
1992   updateList.AddTail(l);
1993   updateCount++;
1994 }
1995 
winRemoveUpdateListener(IUpdateListener * l)1996 void VBA::winRemoveUpdateListener(IUpdateListener *l)
1997 {
1998   POSITION pos = updateList.Find(l);
1999   if(pos) {
2000     updateList.RemoveAt(pos);
2001     updateCount--;
2002     if(updateCount < 0)
2003       updateCount = 0;
2004   }
2005 }
2006 
winLoadFilter(UINT id)2007 CString VBA::winLoadFilter(UINT id)
2008 {
2009   CString res = winResLoadString(id);
2010   res.Replace('_','|');
2011 
2012   return res;
2013 }
2014 
movieReadNext()2015 void VBA::movieReadNext()
2016 {
2017   if(movieFile) {
2018     bool movieEnd = false;
2019 
2020     if(fread(&moviePlayFrame, 1, sizeof(int), movieFile) == sizeof(int)) {
2021       if(fread(&movieNextJoypad, 1, sizeof(u32), movieFile) == sizeof(int)) {
2022         // make sure we don't have spurious entries on the movie that can
2023         // cause us to play it forever
2024         if(moviePlayFrame <= movieFrame)
2025           movieEnd = true;
2026       } else
2027         movieEnd = true;
2028     } else
2029       movieEnd = true;
2030     if(movieEnd) {
2031       CString string = winResLoadString(IDS_END_OF_MOVIE);
2032       systemScreenMessage(string);
2033       moviePlaying = false;
2034       fclose(movieFile);
2035       movieFile = NULL;
2036       return;
2037     }
2038   } else
2039     moviePlaying = false;
2040 }
2041 
saveSettings()2042 void VBA::saveSettings()
2043 {
2044   regSetDwordValue("language", languageOption);
2045 
2046   regSetStringValue("languageName", languageName);
2047 
2048   regSetDwordValue("frameSkip", frameSkip);
2049 
2050   regSetDwordValue("gbFrameSkip", gbFrameSkip);
2051 
2052   regSetDwordValue("autoFrameSkip", autoFrameSkip);
2053 
2054   regSetDwordValue("vsync", vsync);
2055   regSetDwordValue("synchronize", synchronize);
2056   regSetDwordValue("stretch", fullScreenStretch);
2057 
2058   regSetDwordValue("video", videoOption);
2059 
2060   regSetDwordValue("defaultVideoDriver", pVideoDriverGUID == NULL);
2061 
2062   if(pVideoDriverGUID) {
2063     regSetBinaryValue("videoDriverGUID", (char *)&videoDriverGUID,
2064                       sizeof(GUID));
2065   }
2066 
2067 
2068   regSetDwordValue("fsWidth", fsWidth);
2069   regSetDwordValue("fsHeight", fsHeight);
2070   regSetDwordValue("fsColorDepth", fsColorDepth);
2071 
2072   regSetDwordValue("renderMethod", renderMethod);
2073 
2074   regSetDwordValue("windowX", windowPositionX);
2075   regSetDwordValue("windowY", windowPositionY);
2076 
2077   regSetDwordValue("useBios", useBiosFile);
2078 
2079   regSetDwordValue("skipBios", skipBiosFile);
2080 
2081   if(!biosFileName.IsEmpty())
2082     regSetStringValue("biosFile", biosFileName);
2083 
2084   regSetDwordValue("soundEnable", soundGetEnable() & 0x30f);
2085 
2086   regSetDwordValue("soundOff", soundOffFlag);
2087 
2088   regSetDwordValue("soundQuality", soundQuality);
2089 
2090   regSetDwordValue("soundEcho", soundEcho);
2091 
2092   regSetDwordValue("soundLowPass", soundLowPass);
2093 
2094   regSetDwordValue("soundReverse", soundReverse);
2095 
2096   regSetDwordValue("soundVolume", soundVolume);
2097 
2098   regSetDwordValue("ddrawEmulationOnly", ddrawEmulationOnly);
2099   regSetDwordValue("ddrawUseVideoMemory", ddrawUseVideoMemory);
2100   regSetDwordValue("tripleBuffering", tripleBuffering);
2101 
2102   regSetDwordValue("d3dFilter", d3dFilter);
2103   regSetDwordValue("glFilter", glFilter);
2104   regSetDwordValue("glType", glType);
2105 
2106   regSetDwordValue("filter", filterType);
2107 
2108   regSetDwordValue("disableMMX", disableMMX);
2109 
2110   regSetDwordValue("disableStatus", disableStatusMessage);
2111 
2112   regSetDwordValue("showSpeed", showSpeed);
2113 
2114   regSetDwordValue("showSpeedTransparent", showSpeedTransparent);
2115 
2116   regSetDwordValue("gbPrinter", winGbPrinterEnabled);
2117 
2118   regSetDwordValue("pauseWhenInactive", pauseWhenInactive);
2119 
2120   regSetDwordValue("useOldSync", useOldSync);
2121 
2122   regSetDwordValue("captureFormat", captureFormat);
2123 
2124   regSetDwordValue("removeIntros", removeIntros);
2125 
2126   regSetDwordValue("recentFreeze", recentFreeze);
2127 
2128   regSetDwordValue("autoIPS", autoIPS);
2129 
2130   regSetDwordValue("disableSfx", cpuDisableSfx);
2131 
2132   regSetDwordValue("saveType", winSaveType);
2133 
2134   regSetDwordValue("enhancedDetection", cpuEnhancedDetection);
2135 
2136   regSetDwordValue("ifbType", ifbType);
2137 
2138   regSetDwordValue("flashSize", winFlashSize);
2139 
2140   regSetDwordValue("agbPrint", agbPrintIsEnabled());
2141 
2142   regSetDwordValue("rtcEnabled", winRtcEnable);
2143 
2144   regSetDwordValue("autoHideMenu", autoHideMenu);
2145 
2146   regSetDwordValue("skinEnabled", skinEnabled);
2147 
2148   regSetStringValue("skinName", skinName);
2149 
2150   regSetDwordValue("borderOn", winGbBorderOn);
2151   regSetDwordValue("borderAutomatic", gbBorderAutomatic);
2152   regSetDwordValue("emulatorType", gbEmulatorType);
2153   regSetDwordValue("colorOption", gbColorOption);
2154 
2155   regSetDwordValue("priority", threadPriority);
2156 
2157   regSetDwordValue("autoSaveCheatList", autoSaveLoadCheatList);
2158 
2159   regSetDwordValue("gbPaletteOption", gbPaletteOption);
2160 
2161   regSetBinaryValue("gbPalette", (char *)systemGbPalette,
2162                     24*sizeof(u16));
2163 
2164   regSetDwordValue("rewindTimer", rewindTimer/6);
2165 
2166   CString buffer;
2167   for(int i = 0; i < 10; i++) {
2168     buffer.Format("recent%d", i);
2169     regSetStringValue(buffer, recentFiles[i]);
2170   }
2171 
2172   regSetDwordValue("joypadDefault", joypadDefault);
2173   regSetDwordValue("autoLoadMostRecent", autoLoadMostRecent);
2174   regSetDwordValue("cheatsEnabled", cheatsEnabled);
2175   regSetDwordValue("fsMaxScale", fsMaxScale);
2176   regSetDwordValue("throttle", throttle);
2177 }
2178 
winSignal(int,int)2179 void winSignal(int, int)
2180 {
2181 }
2182 
2183 #define CPUReadByteQuick(addr) \
2184   map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]
2185 
winOutput(char * s,u32 addr)2186 void winOutput(char *s, u32 addr)
2187 {
2188   if(s) {
2189     toolsLog(s);
2190   } else {
2191     CString str;
2192     char c;
2193 
2194     c = CPUReadByteQuick(addr);
2195     addr++;
2196     while(c) {
2197       str += c;
2198       c = CPUReadByteQuick(addr);
2199       addr++;
2200     }
2201     toolsLog(str);
2202   }
2203 }
2204