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