1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2005-2006 Forgotten and the VBA development team
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)
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.
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.
23 #include <sys/types.h>
26 #include "../AutoBuild.h"
30 #include "../agbprint.h"
40 #include "../gb/gbGlobals.h"
44 # define GETCWD getcwd
47 # define GETCWD _getcwd
51 # define HAVE_DECL_GETOPT 0
53 # include "../getopt.h"
55 # define HAVE_DECL_GETOPT 1
60 extern "C" bool cpu_mmx
;
62 extern bool soundEcho
;
63 extern bool soundLowPass
;
64 extern bool soundReverse
;
65 extern int Init_2xSaI(u32
);
66 extern void _2xSaI(u8
*,u32
,u8
*,u8
*,u32
,int,int);
67 extern void _2xSaI32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
68 extern void Super2xSaI(u8
*,u32
,u8
*,u8
*,u32
,int,int);
69 extern void Super2xSaI32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
70 extern void SuperEagle(u8
*,u32
,u8
*,u8
*,u32
,int,int);
71 extern void SuperEagle32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
72 extern void Pixelate(u8
*,u32
,u8
*,u8
*,u32
,int,int);
73 extern void Pixelate32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
74 extern void MotionBlur(u8
*,u32
,u8
*,u8
*,u32
,int,int);
75 extern void MotionBlur32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
76 extern void AdMame2x(u8
*,u32
,u8
*,u8
*,u32
,int,int);
77 extern void AdMame2x32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
78 extern void Simple2x(u8
*,u32
,u8
*,u8
*,u32
,int,int);
79 extern void Simple2x32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
80 extern void Bilinear(u8
*,u32
,u8
*,u8
*,u32
,int,int);
81 extern void Bilinear32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
82 extern void BilinearPlus(u8
*,u32
,u8
*,u8
*,u32
,int,int);
83 extern void BilinearPlus32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
84 extern void Scanlines(u8
*,u32
,u8
*,u8
*,u32
,int,int);
85 extern void Scanlines32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
86 extern void ScanlinesTV(u8
*,u32
,u8
*,u8
*,u32
,int,int);
87 extern void ScanlinesTV32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
88 extern void hq2x(u8
*,u32
,u8
*,u8
*,u32
,int,int);
89 extern void hq2x32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
90 extern void lq2x(u8
*,u32
,u8
*,u8
*,u32
,int,int);
91 extern void lq2x32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
93 extern void SmartIB(u8
*,u32
,int,int);
94 extern void SmartIB32(u8
*,u32
,int,int);
95 extern void MotionBlurIB(u8
*,u32
,int,int);
96 extern void MotionBlurIB32(u8
*,u32
,int,int);
98 void Init_Overlay(SDL_Surface
*surface
, int overlaytype
);
99 void Quit_Overlay(void);
100 void Draw_Overlay(SDL_Surface
*surface
, int size
);
102 extern void remoteInit();
103 extern void remoteCleanUp();
104 extern void remoteStubMain();
105 extern void remoteStubSignal(int,int);
106 extern void remoteOutput(char *, u32
);
107 extern void remoteSetProtocol(int);
108 extern void remoteSetPort(int);
109 extern void debuggerOutput(char *, u32
);
111 extern void CPUUpdateRenderBuffers(bool);
112 extern int gbHardware
;
114 struct EmulatedSystem emulator
= {
131 SDL_Surface
*surface
= NULL
;
132 SDL_Overlay
*overlay
= NULL
;
133 SDL_Rect overlay_rect
;
136 int systemRedShift
= 0;
137 int systemBlueShift
= 0;
138 int systemGreenShift
= 0;
139 int systemColorDepth
= 0;
141 int systemVerbose
= 0;
142 int systemFrameSkip
= 0;
143 int systemSaveUpdateCounter
= SYSTEM_SAVE_NOT_UPDATED
;
157 int sdlPrintUsage
= 0;
160 int cartridgeType
= 3;
162 int captureFormat
= 0;
164 int pauseWhenInactive
= 0;
167 int RGB_LOW_BITS_MASK
=0x821;
168 u32 systemColorMap32
[0x10000];
169 u16 systemColorMap16
[0x10000];
170 u16 systemGbPalette
[24];
171 void (*filterFunction
)(u8
*,u32
,u8
*,u8
*,u32
,int,int) = NULL
;
172 void (*ifbFunction
)(u8
*,u32
,int,int) = NULL
;
176 char biosFileName
[2048];
177 char captureDir
[2048];
179 char batteryDir
[2048];
181 static char *rewindMemory
= NULL
;
182 static int rewindPos
= 0;
183 static int rewindTopPos
= 0;
184 static int rewindCounter
= 0;
185 static int rewindCount
= 0;
186 static bool rewindSaveNeeded
= false;
187 static int rewindTimer
= 0;
189 #define REWIND_SIZE 400000
190 #define SYSMSG_BUFFER_SIZE 1024
192 #define _stricmp strcasecmp
194 bool sdlButtons
[4][12] = {
195 { false, false, false, false, false, false,
196 false, false, false, false, false, false },
197 { false, false, false, false, false, false,
198 false, false, false, false, false, false },
199 { false, false, false, false, false, false,
200 false, false, false, false, false, false },
201 { false, false, false, false, false, false,
202 false, false, false, false, false, false }
205 bool sdlMotionButtons
[4] = { false, false, false, false };
207 int sdlNumDevices
= 0;
208 SDL_Joystick
**sdlDevices
= NULL
;
210 bool wasPaused
= false;
211 int autoFrameSkip
= 0;
212 int frameskipadjust
= 0;
213 int showRenderedFrames
= 0;
214 int renderedFrames
= 0;
217 u32 throttleLastTime
= 0;
218 u32 autoFrameSkipLastTime
= 0;
221 int showSpeedTransparent
= 1;
222 bool disableStatusMessages
= false;
224 bool pauseNextFrame
= false;
225 bool debugger
= false;
226 bool debuggerStub
= false;
228 bool systemSoundOn
= false;
231 bool removeIntros
= false;
232 int sdlFlashSize
= 0;
234 int sdlRtcEnable
= 0;
236 int sdlMirroringEnable
= 0;
238 int sdlDefaultJoypad
= 0;
240 extern void debuggerSignal(int,int);
242 void (*dbgMain
)() = debuggerMain
;
243 void (*dbgSignal
)(int,int) = debuggerSignal
;
244 void (*dbgOutput
)(char *, u32
) = debuggerOutput
;
246 int mouseCounter
= 0;
248 bool autoFireToggle
= false;
250 bool screenMessage
= false;
251 char screenMessageBuffer
[21];
252 u32 screenMessageTime
= 0;
254 // Patch #1382692 by deathpudding.
255 SDL_sem
*sdlBufferLock
= NULL
;
256 SDL_sem
*sdlBufferFull
= NULL
;
257 SDL_sem
*sdlBufferEmpty
= NULL
;
264 u8 sdlStretcher
[16384];
267 void (*sdlStretcher
)(u8
*, u8
*) = NULL
;
273 KEY_BUTTON_A
, KEY_BUTTON_B
,
274 KEY_BUTTON_START
, KEY_BUTTON_SELECT
,
275 KEY_BUTTON_L
, KEY_BUTTON_R
,
276 KEY_BUTTON_SPEED
, KEY_BUTTON_CAPTURE
279 u16 joypad
[4][12] = {
280 { SDLK_LEFT
, SDLK_RIGHT
,
283 SDLK_RETURN
,SDLK_BACKSPACE
,
287 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
288 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
289 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
292 u16 defaultJoypad
[12] = {
293 SDLK_LEFT
, SDLK_RIGHT
,
296 SDLK_RETURN
,SDLK_BACKSPACE
,
302 SDLK_KP4
, SDLK_KP6
, SDLK_KP8
, SDLK_KP2
305 u16 defaultMotion
[4] = {
306 SDLK_KP4
, SDLK_KP6
, SDLK_KP8
, SDLK_KP2
309 struct option sdlOptions
[] = {
310 { "agb-print", no_argument
, &sdlAgbPrint
, 1 },
311 { "auto-frameskip", no_argument
, &autoFrameSkip
, 1 },
312 { "bios", required_argument
, 0, 'b' },
313 { "config", required_argument
, 0, 'c' },
314 { "debug", no_argument
, 0, 'd' },
315 { "filter", required_argument
, 0, 'f' },
316 { "filter-normal", no_argument
, &filter
, 0 },
317 { "filter-tv-mode", no_argument
, &filter
, 1 },
318 { "filter-2xsai", no_argument
, &filter
, 2 },
319 { "filter-super-2xsai", no_argument
, &filter
, 3 },
320 { "filter-super-eagle", no_argument
, &filter
, 4 },
321 { "filter-pixelate", no_argument
, &filter
, 5 },
322 { "filter-motion-blur", no_argument
, &filter
, 6 },
323 { "filter-advmame", no_argument
, &filter
, 7 },
324 { "filter-simple2x", no_argument
, &filter
, 8 },
325 { "filter-bilinear", no_argument
, &filter
, 9 },
326 { "filter-bilinear+", no_argument
, &filter
, 10 },
327 { "filter-scanlines", no_argument
, &filter
, 11 },
328 { "filter-hq2x", no_argument
, &filter
, 12 },
329 { "filter-lq2x", no_argument
, &filter
, 13 },
330 { "flash-size", required_argument
, 0, 'S' },
331 { "flash-64k", no_argument
, &sdlFlashSize
, 0 },
332 { "flash-128k", no_argument
, &sdlFlashSize
, 1 },
333 { "frameskip", required_argument
, 0, 's' },
334 { "fullscreen", no_argument
, &fullscreen
, 1 },
335 { "gdb", required_argument
, 0, 'G' },
336 { "help", no_argument
, &sdlPrintUsage
, 1 },
337 { "ifb-none", no_argument
, &ifbType
, 0 },
338 { "ifb-motion-blur", no_argument
, &ifbType
, 1 },
339 { "ifb-smart", no_argument
, &ifbType
, 2 },
340 { "ips", required_argument
, 0, 'i' },
341 { "no-agb-print", no_argument
, &sdlAgbPrint
, 0 },
342 { "no-auto-frameskip", no_argument
, &autoFrameSkip
, 0 },
343 { "no-debug", no_argument
, 0, 'N' },
344 { "no-ips", no_argument
, &sdlAutoIPS
, 0 },
345 { "no-mmx", no_argument
, &disableMMX
, 1 },
346 { "no-pause-when-inactive", no_argument
, &pauseWhenInactive
, 0 },
347 { "no-rtc", no_argument
, &sdlRtcEnable
, 0 },
348 { "no-show-speed", no_argument
, &showSpeed
, 0 },
349 { "no-throttle", no_argument
, &throttle
, 0 },
350 { "pause-when-inactive", no_argument
, &pauseWhenInactive
, 1 },
351 { "profile", optional_argument
, 0, 'p' },
352 { "rtc", no_argument
, &sdlRtcEnable
, 1 },
353 { "save-type", required_argument
, 0, 't' },
354 { "save-auto", no_argument
, &cpuSaveType
, 0 },
355 { "save-eeprom", no_argument
, &cpuSaveType
, 1 },
356 { "save-sram", no_argument
, &cpuSaveType
, 2 },
357 { "save-flash", no_argument
, &cpuSaveType
, 3 },
358 { "save-sensor", no_argument
, &cpuSaveType
, 4 },
359 { "save-none", no_argument
, &cpuSaveType
, 5 },
360 { "show-speed-normal", no_argument
, &showSpeed
, 1 },
361 { "show-speed-detailed", no_argument
, &showSpeed
, 2 },
362 { "throttle", required_argument
, 0, 'T' },
363 { "verbose", required_argument
, 0, 'v' },
364 { "video-1x", no_argument
, &sizeOption
, 0 },
365 { "video-2x", no_argument
, &sizeOption
, 1 },
366 { "video-3x", no_argument
, &sizeOption
, 2 },
367 { "video-4x", no_argument
, &sizeOption
, 3 },
368 { "yuv", required_argument
, 0, 'Y' },
369 { NULL
, no_argument
, NULL
, 0 }
372 extern bool CPUIsGBAImage(char *);
373 extern bool gbIsGameboyRom(char *);
376 #define SDL_LONG(val) \
377 *((u32 *)&sdlStretcher[sdlStretcherPos]) = val;\
380 #define SDL_AND_EAX(val) \
381 sdlStretcher[sdlStretcherPos++] = 0x25;\
384 #define SDL_AND_EBX(val) \
385 sdlStretcher[sdlStretcherPos++] = 0x81;\
386 sdlStretcher[sdlStretcherPos++] = 0xe3;\
389 #define SDL_OR_EAX_EBX \
390 sdlStretcher[sdlStretcherPos++] = 0x09;\
391 sdlStretcher[sdlStretcherPos++] = 0xd8;
393 #define SDL_LOADL_EBX \
394 sdlStretcher[sdlStretcherPos++] = 0x8b;\
395 sdlStretcher[sdlStretcherPos++] = 0x1f;
398 sdlStretcher[sdlStretcherPos++] = 0x66;\
399 sdlStretcher[sdlStretcherPos++] = 0x8b;\
400 sdlStretcher[sdlStretcherPos++] = 0x06;\
401 sdlStretcher[sdlStretcherPos++] = 0x83;\
402 sdlStretcher[sdlStretcherPos++] = 0xc6;\
403 sdlStretcher[sdlStretcherPos++] = 0x02;
406 sdlStretcher[sdlStretcherPos++] = 0x8b;\
407 sdlStretcher[sdlStretcherPos++] = 0x06;\
408 sdlStretcher[sdlStretcherPos++] = 0x83;\
409 sdlStretcher[sdlStretcherPos++] = 0xc6;\
410 sdlStretcher[sdlStretcherPos++] = 0x04;
413 sdlStretcher[sdlStretcherPos++] = 0x8b;\
414 sdlStretcher[sdlStretcherPos++] = 0x06;\
415 sdlStretcher[sdlStretcherPos++] = 0x83;\
416 sdlStretcher[sdlStretcherPos++] = 0xc6;\
417 sdlStretcher[sdlStretcherPos++] = 0x03;
420 sdlStretcher[sdlStretcherPos++] = 0x66;\
421 sdlStretcher[sdlStretcherPos++] = 0x89;\
422 sdlStretcher[sdlStretcherPos++] = 0x07;\
423 sdlStretcher[sdlStretcherPos++] = 0x83;\
424 sdlStretcher[sdlStretcherPos++] = 0xc7;\
425 sdlStretcher[sdlStretcherPos++] = 0x02;
428 sdlStretcher[sdlStretcherPos++] = 0x89;\
429 sdlStretcher[sdlStretcherPos++] = 0x07;\
430 sdlStretcher[sdlStretcherPos++] = 0x83;\
431 sdlStretcher[sdlStretcherPos++] = 0xc7;\
432 sdlStretcher[sdlStretcherPos++] = 0x04;
434 #define SDL_STOREL2 \
435 sdlStretcher[sdlStretcherPos++] = 0x89;\
436 sdlStretcher[sdlStretcherPos++] = 0x07;\
437 sdlStretcher[sdlStretcherPos++] = 0x83;\
438 sdlStretcher[sdlStretcherPos++] = 0xc7;\
439 sdlStretcher[sdlStretcherPos++] = 0x03;
442 sdlStretcher[sdlStretcherPos++] = 0xc3;
444 #define SDL_PUSH_EAX \
445 sdlStretcher[sdlStretcherPos++] = 0x50;
447 #define SDL_PUSH_ECX \
448 sdlStretcher[sdlStretcherPos++] = 0x51;
450 #define SDL_PUSH_EBX \
451 sdlStretcher[sdlStretcherPos++] = 0x53;
453 #define SDL_PUSH_ESI \
454 sdlStretcher[sdlStretcherPos++] = 0x56;
456 #define SDL_PUSH_EDI \
457 sdlStretcher[sdlStretcherPos++] = 0x57;
459 #define SDL_POP_EAX \
460 sdlStretcher[sdlStretcherPos++] = 0x58;
462 #define SDL_POP_ECX \
463 sdlStretcher[sdlStretcherPos++] = 0x59;
465 #define SDL_POP_EBX \
466 sdlStretcher[sdlStretcherPos++] = 0x5b;
468 #define SDL_POP_ESI \
469 sdlStretcher[sdlStretcherPos++] = 0x5e;
471 #define SDL_POP_EDI \
472 sdlStretcher[sdlStretcherPos++] = 0x5f;
474 #define SDL_MOV_ECX(val) \
475 sdlStretcher[sdlStretcherPos++] = 0xb9;\
478 #define SDL_REP_MOVSB \
479 sdlStretcher[sdlStretcherPos++] = 0xf3;\
480 sdlStretcher[sdlStretcherPos++] = 0xa4;
482 #define SDL_REP_MOVSW \
483 sdlStretcher[sdlStretcherPos++] = 0xf3;\
484 sdlStretcher[sdlStretcherPos++] = 0x66;\
485 sdlStretcher[sdlStretcherPos++] = 0xa5;
487 #define SDL_REP_MOVSL \
488 sdlStretcher[sdlStretcherPos++] = 0xf3;\
489 sdlStretcher[sdlStretcherPos++] = 0xa5;
491 void sdlMakeStretcher(int width
)
494 switch(systemColorDepth
) {
500 for(int i
= 0; i
< width
; i
++) {
533 for(int i
= 0; i
< w
; i
++) {
544 // need to write the last one
553 SDL_AND_EAX(0x00ffffff);
556 SDL_AND_EBX(0xff000000);
568 SDL_MOV_ECX(3*width
);
581 for(int i
= 0; i
< width
; i
++) {
612 #define SDL_CALL_STRETCHER \
614 __asm mov eax, stretcher\
620 #define SDL_CALL_STRETCHER \
621 asm volatile("call *%%eax"::"a" (stretcher),"S" (src),"D" (dest))
624 #define SDL_CALL_STRETCHER \
625 sdlStretcher(src, dest)
627 void sdlStretch16x1(u8
*src
, u8
*dest
)
630 u16
*d
= (u16
*)dest
;
631 for(int i
= 0; i
< srcWidth
; i
++)
635 void sdlStretch16x2(u8
*src
, u8
*dest
)
638 u16
*d
= (u16
*)dest
;
639 for(int i
= 0; i
< srcWidth
; i
++) {
645 void sdlStretch16x3(u8
*src
, u8
*dest
)
648 u16
*d
= (u16
*)dest
;
649 for(int i
= 0; i
< srcWidth
; i
++) {
656 void sdlStretch16x4(u8
*src
, u8
*dest
)
659 u16
*d
= (u16
*)dest
;
660 for(int i
= 0; i
< srcWidth
; i
++) {
668 void (*sdlStretcher16
[4])(u8
*, u8
*) = {
675 void sdlStretch32x1(u8
*src
, u8
*dest
)
678 u32
*d
= (u32
*)dest
;
679 for(int i
= 0; i
< srcWidth
; i
++)
683 void sdlStretch32x2(u8
*src
, u8
*dest
)
686 u32
*d
= (u32
*)dest
;
687 for(int i
= 0; i
< srcWidth
; i
++) {
693 void sdlStretch32x3(u8
*src
, u8
*dest
)
696 u32
*d
= (u32
*)dest
;
697 for(int i
= 0; i
< srcWidth
; i
++) {
704 void sdlStretch32x4(u8
*src
, u8
*dest
)
707 u32
*d
= (u32
*)dest
;
708 for(int i
= 0; i
< srcWidth
; i
++) {
716 void (*sdlStretcher32
[4])(u8
*, u8
*) = {
723 void sdlStretch24x1(u8
*src
, u8
*dest
)
727 for(int i
= 0; i
< srcWidth
; i
++) {
734 void sdlStretch24x2(u8
*src
, u8
*dest
)
738 for(int i
= 0; i
< srcWidth
; i
++) {
750 void sdlStretch24x3(u8
*src
, u8
*dest
)
754 for(int i
= 0; i
< srcWidth
; i
++) {
770 void sdlStretch24x4(u8
*src
, u8
*dest
)
774 for(int i
= 0; i
< srcWidth
; i
++) {
794 void (*sdlStretcher24
[4])(u8
*, u8
*) = {
803 u32
sdlFromHex(char *s
)
806 sscanf(s
, "%x", &value
);
812 #define S_IFDIR _S_IFDIR
815 void sdlCheckDirectory(char *dir
)
819 int len
= strlen(dir
);
821 char *p
= dir
+ len
- 1;
827 if(stat(dir
, &buf
) == 0) {
828 if(!(buf
.st_mode
& S_IFDIR
)) {
829 fprintf(stderr
, "Error: %s is not a directory\n", dir
);
833 fprintf(stderr
, "Error: %s does not exist\n", dir
);
838 char *sdlGetFilename(char *name
)
840 static char filebuffer
[2048];
842 int len
= strlen(name
);
844 char *p
= name
+ len
- 1;
859 strcpy(filebuffer
, name
);
861 strcpy(filebuffer
, p
);
865 FILE *sdlFindFile(const char *name
)
872 #define FILE_SEP '\\'
873 #define EXE_NAME "VisualBoyAdvance-SDL.exe"
877 #define EXE_NAME "VisualBoyAdvance"
880 fprintf(stderr
, "Searching for file %s\n", name
);
882 if(GETCWD(buffer
, 2048)) {
883 fprintf(stderr
, "Searching current directory: %s\n", buffer
);
886 FILE *f
= fopen(name
, "r");
891 char *home
= getenv("HOME");
894 fprintf(stderr
, "Searching home directory: %s\n", home
);
895 sprintf(path
, "%s%c%s", home
, FILE_SEP
, name
);
896 f
= fopen(path
, "r");
902 home
= getenv("USERPROFILE");
904 fprintf(stderr
, "Searching user profile directory: %s\n", home
);
905 sprintf(path
, "%s%c%s", home
, FILE_SEP
, name
);
906 f
= fopen(path
, "r");
911 fprintf(stderr
, "Searching system config directory: %s\n", SYSCONFDIR
);
912 sprintf(path
, "%s%c%s", SYSCONFDIR
, FILE_SEP
, name
);
913 f
= fopen(path
, "r");
918 if(!strchr(arg0
, '/') &&
919 !strchr(arg0
, '\\')) {
920 char *path
= getenv("PATH");
923 fprintf(stderr
, "Searching PATH\n");
924 strncpy(buffer
, path
, 4096);
926 char *tok
= strtok(buffer
, PATH_SEP
);
929 sprintf(path
, "%s%c%s", tok
, FILE_SEP
, EXE_NAME
);
930 f
= fopen(path
, "r");
934 sprintf(path2
, "%s%c%s", tok
, FILE_SEP
, name
);
935 f
= fopen(path2
, "r");
937 fprintf(stderr
, "Found at %s\n", path2
);
941 tok
= strtok(NULL
, PATH_SEP
);
945 // executable is relative to some directory
946 fprintf(stderr
, "Searching executable directory\n");
947 strcpy(buffer
, arg0
);
948 char *p
= strrchr(buffer
, FILE_SEP
);
951 sprintf(path
, "%s%c%s", buffer
, FILE_SEP
, name
);
952 f
= fopen(path
, "r");
960 void sdlReadPreferences(FILE *f
)
965 char *s
= fgets(buffer
, 2048, f
);
970 char *p
= strchr(s
, '#');
975 char *token
= strtok(s
, " \t\n\r=");
980 if(strlen(token
) == 0)
984 char *value
= strtok(NULL
, "\t\n\r");
987 fprintf(stderr
, "Empty value for key %s\n", key
);
991 if(!strcmp(key
,"Joy0_Left")) {
992 joypad
[0][KEY_LEFT
] = sdlFromHex(value
);
993 } else if(!strcmp(key
, "Joy0_Right")) {
994 joypad
[0][KEY_RIGHT
] = sdlFromHex(value
);
995 } else if(!strcmp(key
, "Joy0_Up")) {
996 joypad
[0][KEY_UP
] = sdlFromHex(value
);
997 } else if(!strcmp(key
, "Joy0_Down")) {
998 joypad
[0][KEY_DOWN
] = sdlFromHex(value
);
999 } else if(!strcmp(key
, "Joy0_A")) {
1000 joypad
[0][KEY_BUTTON_A
] = sdlFromHex(value
);
1001 } else if(!strcmp(key
, "Joy0_B")) {
1002 joypad
[0][KEY_BUTTON_B
] = sdlFromHex(value
);
1003 } else if(!strcmp(key
, "Joy0_L")) {
1004 joypad
[0][KEY_BUTTON_L
] = sdlFromHex(value
);
1005 } else if(!strcmp(key
, "Joy0_R")) {
1006 joypad
[0][KEY_BUTTON_R
] = sdlFromHex(value
);
1007 } else if(!strcmp(key
, "Joy0_Start")) {
1008 joypad
[0][KEY_BUTTON_START
] = sdlFromHex(value
);
1009 } else if(!strcmp(key
, "Joy0_Select")) {
1010 joypad
[0][KEY_BUTTON_SELECT
] = sdlFromHex(value
);
1011 } else if(!strcmp(key
, "Joy0_Speed")) {
1012 joypad
[0][KEY_BUTTON_SPEED
] = sdlFromHex(value
);
1013 } else if(!strcmp(key
, "Joy0_Capture")) {
1014 joypad
[0][KEY_BUTTON_CAPTURE
] = sdlFromHex(value
);
1015 } else if(!strcmp(key
,"Joy1_Left")) {
1016 joypad
[1][KEY_LEFT
] = sdlFromHex(value
);
1017 } else if(!strcmp(key
, "Joy1_Right")) {
1018 joypad
[1][KEY_RIGHT
] = sdlFromHex(value
);
1019 } else if(!strcmp(key
, "Joy1_Up")) {
1020 joypad
[1][KEY_UP
] = sdlFromHex(value
);
1021 } else if(!strcmp(key
, "Joy1_Down")) {
1022 joypad
[1][KEY_DOWN
] = sdlFromHex(value
);
1023 } else if(!strcmp(key
, "Joy1_A")) {
1024 joypad
[1][KEY_BUTTON_A
] = sdlFromHex(value
);
1025 } else if(!strcmp(key
, "Joy1_B")) {
1026 joypad
[1][KEY_BUTTON_B
] = sdlFromHex(value
);
1027 } else if(!strcmp(key
, "Joy1_L")) {
1028 joypad
[1][KEY_BUTTON_L
] = sdlFromHex(value
);
1029 } else if(!strcmp(key
, "Joy1_R")) {
1030 joypad
[1][KEY_BUTTON_R
] = sdlFromHex(value
);
1031 } else if(!strcmp(key
, "Joy1_Start")) {
1032 joypad
[1][KEY_BUTTON_START
] = sdlFromHex(value
);
1033 } else if(!strcmp(key
, "Joy1_Select")) {
1034 joypad
[1][KEY_BUTTON_SELECT
] = sdlFromHex(value
);
1035 } else if(!strcmp(key
, "Joy1_Speed")) {
1036 joypad
[1][KEY_BUTTON_SPEED
] = sdlFromHex(value
);
1037 } else if(!strcmp(key
, "Joy1_Capture")) {
1038 joypad
[1][KEY_BUTTON_CAPTURE
] = sdlFromHex(value
);
1039 } else if(!strcmp(key
,"Joy2_Left")) {
1040 joypad
[2][KEY_LEFT
] = sdlFromHex(value
);
1041 } else if(!strcmp(key
, "Joy2_Right")) {
1042 joypad
[2][KEY_RIGHT
] = sdlFromHex(value
);
1043 } else if(!strcmp(key
, "Joy2_Up")) {
1044 joypad
[2][KEY_UP
] = sdlFromHex(value
);
1045 } else if(!strcmp(key
, "Joy2_Down")) {
1046 joypad
[2][KEY_DOWN
] = sdlFromHex(value
);
1047 } else if(!strcmp(key
, "Joy2_A")) {
1048 joypad
[2][KEY_BUTTON_A
] = sdlFromHex(value
);
1049 } else if(!strcmp(key
, "Joy2_B")) {
1050 joypad
[2][KEY_BUTTON_B
] = sdlFromHex(value
);
1051 } else if(!strcmp(key
, "Joy2_L")) {
1052 joypad
[2][KEY_BUTTON_L
] = sdlFromHex(value
);
1053 } else if(!strcmp(key
, "Joy2_R")) {
1054 joypad
[2][KEY_BUTTON_R
] = sdlFromHex(value
);
1055 } else if(!strcmp(key
, "Joy2_Start")) {
1056 joypad
[2][KEY_BUTTON_START
] = sdlFromHex(value
);
1057 } else if(!strcmp(key
, "Joy2_Select")) {
1058 joypad
[2][KEY_BUTTON_SELECT
] = sdlFromHex(value
);
1059 } else if(!strcmp(key
, "Joy2_Speed")) {
1060 joypad
[2][KEY_BUTTON_SPEED
] = sdlFromHex(value
);
1061 } else if(!strcmp(key
, "Joy2_Capture")) {
1062 joypad
[2][KEY_BUTTON_CAPTURE
] = sdlFromHex(value
);
1063 } else if(!strcmp(key
,"Joy4_Left")) {
1064 joypad
[4][KEY_LEFT
] = sdlFromHex(value
);
1065 } else if(!strcmp(key
, "Joy4_Right")) {
1066 joypad
[4][KEY_RIGHT
] = sdlFromHex(value
);
1067 } else if(!strcmp(key
, "Joy4_Up")) {
1068 joypad
[4][KEY_UP
] = sdlFromHex(value
);
1069 } else if(!strcmp(key
, "Joy4_Down")) {
1070 joypad
[4][KEY_DOWN
] = sdlFromHex(value
);
1071 } else if(!strcmp(key
, "Joy4_A")) {
1072 joypad
[4][KEY_BUTTON_A
] = sdlFromHex(value
);
1073 } else if(!strcmp(key
, "Joy4_B")) {
1074 joypad
[4][KEY_BUTTON_B
] = sdlFromHex(value
);
1075 } else if(!strcmp(key
, "Joy4_L")) {
1076 joypad
[4][KEY_BUTTON_L
] = sdlFromHex(value
);
1077 } else if(!strcmp(key
, "Joy4_R")) {
1078 joypad
[4][KEY_BUTTON_R
] = sdlFromHex(value
);
1079 } else if(!strcmp(key
, "Joy4_Start")) {
1080 joypad
[4][KEY_BUTTON_START
] = sdlFromHex(value
);
1081 } else if(!strcmp(key
, "Joy4_Select")) {
1082 joypad
[4][KEY_BUTTON_SELECT
] = sdlFromHex(value
);
1083 } else if(!strcmp(key
, "Joy4_Speed")) {
1084 joypad
[4][KEY_BUTTON_SPEED
] = sdlFromHex(value
);
1085 } else if(!strcmp(key
, "Joy4_Capture")) {
1086 joypad
[4][KEY_BUTTON_CAPTURE
] = sdlFromHex(value
);
1087 } else if(!strcmp(key
, "Motion_Left")) {
1088 motion
[KEY_LEFT
] = sdlFromHex(value
);
1089 } else if(!strcmp(key
, "Motion_Right")) {
1090 motion
[KEY_RIGHT
] = sdlFromHex(value
);
1091 } else if(!strcmp(key
, "Motion_Up")) {
1092 motion
[KEY_UP
] = sdlFromHex(value
);
1093 } else if(!strcmp(key
, "Motion_Down")) {
1094 motion
[KEY_DOWN
] = sdlFromHex(value
);
1095 } else if(!strcmp(key
, "frameSkip")) {
1096 frameSkip
= sdlFromHex(value
);
1097 if(frameSkip
< 0 || frameSkip
> 9)
1099 } else if(!strcmp(key
, "gbFrameSkip")) {
1100 gbFrameSkip
= sdlFromHex(value
);
1101 if(gbFrameSkip
< 0 || gbFrameSkip
> 9)
1103 } else if(!strcmp(key
, "video")) {
1104 sizeOption
= sdlFromHex(value
);
1105 if(sizeOption
< 0 || sizeOption
> 3)
1107 } else if(!strcmp(key
, "fullScreen")) {
1108 fullscreen
= sdlFromHex(value
) ? 1 : 0;
1109 } else if(!strcmp(key
, "useBios")) {
1110 useBios
= sdlFromHex(value
) ? true : false;
1111 } else if(!strcmp(key
, "skipBios")) {
1112 skipBios
= sdlFromHex(value
) ? true : false;
1113 } else if(!strcmp(key
, "biosFile")) {
1114 strcpy(biosFileName
, value
);
1115 } else if(!strcmp(key
, "filter")) {
1116 filter
= sdlFromHex(value
);
1117 if(filter
< 0 || filter
> 13)
1119 } else if(!strcmp(key
, "disableStatus")) {
1120 disableStatusMessages
= sdlFromHex(value
) ? true : false;
1121 } else if(!strcmp(key
, "borderOn")) {
1122 gbBorderOn
= sdlFromHex(value
) ? true : false;
1123 } else if(!strcmp(key
, "borderAutomatic")) {
1124 gbBorderAutomatic
= sdlFromHex(value
) ? true : false;
1125 } else if(!strcmp(key
, "emulatorType")) {
1126 gbEmulatorType
= sdlFromHex(value
);
1127 if(gbEmulatorType
< 0 || gbEmulatorType
> 5)
1129 } else if(!strcmp(key
, "colorOption")) {
1130 gbColorOption
= sdlFromHex(value
) ? true : false;
1131 } else if(!strcmp(key
, "captureDir")) {
1132 sdlCheckDirectory(value
);
1133 strcpy(captureDir
, value
);
1134 } else if(!strcmp(key
, "saveDir")) {
1135 sdlCheckDirectory(value
);
1136 strcpy(saveDir
, value
);
1137 } else if(!strcmp(key
, "batteryDir")) {
1138 sdlCheckDirectory(value
);
1139 strcpy(batteryDir
, value
);
1140 } else if(!strcmp(key
, "captureFormat")) {
1141 captureFormat
= sdlFromHex(value
);
1142 } else if(!strcmp(key
, "soundQuality")) {
1143 soundQuality
= sdlFromHex(value
);
1144 switch(soundQuality
) {
1150 fprintf(stderr
, "Unknown sound quality %d. Defaulting to 22Khz\n",
1155 } else if(!strcmp(key
, "soundOff")) {
1156 soundOffFlag
= sdlFromHex(value
) ? true : false;
1157 } else if(!strcmp(key
, "soundEnable")) {
1158 int res
= sdlFromHex(value
) & 0x30f;
1161 } else if(!strcmp(key
, "soundEcho")) {
1162 soundEcho
= sdlFromHex(value
) ? true : false;
1163 } else if(!strcmp(key
, "soundLowPass")) {
1164 soundLowPass
= sdlFromHex(value
) ? true : false;
1165 } else if(!strcmp(key
, "soundReverse")) {
1166 soundReverse
= sdlFromHex(value
) ? true : false;
1167 } else if(!strcmp(key
, "soundVolume")) {
1168 soundVolume
= sdlFromHex(value
);
1169 if(soundVolume
< 0 || soundVolume
> 3)
1171 } else if(!strcmp(key
, "removeIntros")) {
1172 removeIntros
= sdlFromHex(value
) ? true : false;
1173 } else if(!strcmp(key
, "saveType")) {
1174 cpuSaveType
= sdlFromHex(value
);
1175 if(cpuSaveType
< 0 || cpuSaveType
> 5)
1177 } else if(!strcmp(key
, "flashSize")) {
1178 sdlFlashSize
= sdlFromHex(value
);
1179 if(sdlFlashSize
!= 0 && sdlFlashSize
!= 1)
1181 } else if(!strcmp(key
, "ifbType")) {
1182 ifbType
= sdlFromHex(value
);
1183 if(ifbType
< 0 || ifbType
> 2)
1185 } else if(!strcmp(key
, "showSpeed")) {
1186 showSpeed
= sdlFromHex(value
);
1187 if(showSpeed
< 0 || showSpeed
> 2)
1189 } else if(!strcmp(key
, "showSpeedTransparent")) {
1190 showSpeedTransparent
= sdlFromHex(value
);
1191 } else if(!strcmp(key
, "autoFrameSkip")) {
1192 autoFrameSkip
= sdlFromHex(value
);
1193 } else if(!strcmp(key
, "throttle")) {
1194 throttle
= sdlFromHex(value
);
1195 if(throttle
!= 0 && (throttle
< 5 || throttle
> 1000))
1197 } else if(!strcmp(key
, "disableMMX")) {
1199 cpu_mmx
= sdlFromHex(value
) ? false : true;
1201 } else if(!strcmp(key
, "pauseWhenInactive")) {
1202 pauseWhenInactive
= sdlFromHex(value
) ? true : false;
1203 } else if(!strcmp(key
, "agbPrint")) {
1204 sdlAgbPrint
= sdlFromHex(value
);
1205 } else if(!strcmp(key
, "rtcEnabled")) {
1206 sdlRtcEnable
= sdlFromHex(value
);
1207 } else if(!strcmp(key
, "rewindTimer")) {
1208 rewindTimer
= sdlFromHex(value
);
1209 if(rewindTimer
< 0 || rewindTimer
> 600)
1211 rewindTimer
*= 6; // convert value to 10 frames multiple
1213 fprintf(stderr
, "Unknown configuration key %s\n", key
);
1218 void sdlReadPreferences()
1220 FILE *f
= sdlFindFile("VisualBoyAdvance.cfg");
1223 fprintf(stderr
, "Configuration file NOT FOUND (using defaults)\n");
1226 fprintf(stderr
, "Reading configuration file.\n");
1228 sdlReadPreferences(f
);
1233 static void sdlApplyPerImagePreferences()
1235 FILE *f
= sdlFindFile("vba-over.ini");
1237 fprintf(stderr
, "vba-over.ini NOT FOUND (using emulator settings)\n");
1240 fprintf(stderr
, "Reading vba-over.ini\n");
1244 buffer
[1] = rom
[0xac];
1245 buffer
[2] = rom
[0xad];
1246 buffer
[3] = rom
[0xae];
1247 buffer
[4] = rom
[0xaf];
1251 char readBuffer
[2048];
1256 char *s
= fgets(readBuffer
, 2048, f
);
1261 char *p
= strchr(s
, ';');
1266 char *token
= strtok(s
, " \t\n\r=");
1270 if(strlen(token
) == 0)
1273 if(!strcmp(token
, buffer
)) {
1281 char *s
= fgets(readBuffer
, 2048, f
);
1286 char *p
= strchr(s
, ';');
1290 char *token
= strtok(s
, " \t\n\r=");
1293 if(strlen(token
) == 0)
1296 if(token
[0] == '[') // starting another image settings
1298 char *value
= strtok(NULL
, "\t\n\r=");
1302 if(!strcmp(token
, "rtcEnabled"))
1303 rtcEnable(atoi(value
) == 0 ? false : true);
1304 else if(!strcmp(token
, "flashSize")) {
1305 int size
= atoi(value
);
1306 if(size
== 0x10000 || size
== 0x20000)
1308 } else if(!strcmp(token
, "saveType")) {
1309 int save
= atoi(value
);
1310 if(save
>= 0 && save
<= 5)
1312 } else if(!strcmp(token
, "mirroringEnabled")) {
1313 mirroringEnable
= (atoi(value
) == 0 ? false : true);
1320 static int sdlCalculateShift(u32 mask
)
1332 static int sdlCalculateMaskWidth(u32 mask
)
1344 while(!(mask2
& 1)) {
1352 void sdlWriteState(int num
)
1354 char stateName
[2048];
1357 sprintf(stateName
, "%s/%s%d.sgm", saveDir
, sdlGetFilename(filename
),
1360 sprintf(stateName
,"%s%d.sgm", filename
, num
+1);
1362 if(emulator
.emuWriteState
)
1363 emulator
.emuWriteState(stateName
);
1365 sprintf(stateName
, "Wrote state %d", num
+1);
1366 systemScreenMessage(stateName
);
1371 void sdlReadState(int num
)
1373 char stateName
[2048];
1376 sprintf(stateName
, "%s/%s%d.sgm", saveDir
, sdlGetFilename(filename
),
1379 sprintf(stateName
,"%s%d.sgm", filename
, num
+1);
1381 if(emulator
.emuReadState
)
1382 emulator
.emuReadState(stateName
);
1384 sprintf(stateName
, "Loaded state %d", num
+1);
1385 systemScreenMessage(stateName
);
1390 void sdlWriteBattery()
1395 sprintf(buffer
, "%s/%s.sav", batteryDir
, sdlGetFilename(filename
));
1397 sprintf(buffer
, "%s.sav", filename
);
1399 emulator
.emuWriteBattery(buffer
);
1401 systemScreenMessage("Wrote battery");
1404 void sdlReadBattery()
1409 sprintf(buffer
, "%s/%s.sav", batteryDir
, sdlGetFilename(filename
));
1411 sprintf(buffer
, "%s.sav", filename
);
1415 res
= emulator
.emuReadBattery(buffer
);
1418 systemScreenMessage("Loaded battery");
1421 #define MOD_KEYS (KMOD_CTRL|KMOD_SHIFT|KMOD_ALT|KMOD_META)
1422 #define MOD_NOCTRL (KMOD_SHIFT|KMOD_ALT|KMOD_META)
1423 #define MOD_NOALT (KMOD_CTRL|KMOD_SHIFT|KMOD_META)
1424 #define MOD_NOSHIFT (KMOD_CTRL|KMOD_ALT|KMOD_META)
1426 void sdlUpdateKey(int key
, bool down
)
1429 for(int j
= 0; j
< 4; j
++) {
1430 for(i
= 0 ; i
< 12; i
++) {
1431 if((joypad
[j
][i
] & 0xf000) == 0) {
1432 if(key
== joypad
[j
][i
])
1433 sdlButtons
[j
][i
] = down
;
1437 for(i
= 0 ; i
< 4; i
++) {
1438 if((motion
[i
] & 0xf000) == 0) {
1439 if(key
== motion
[i
])
1440 sdlMotionButtons
[i
] = down
;
1445 void sdlUpdateJoyButton(int which
,
1450 for(int j
= 0; j
< 4; j
++) {
1451 for(i
= 0; i
< 12; i
++) {
1452 int dev
= (joypad
[j
][i
] >> 12);
1453 int b
= joypad
[j
][i
] & 0xfff;
1457 if((dev
== which
) && (b
>= 128) && (b
== (button
+128))) {
1458 sdlButtons
[j
][i
] = pressed
;
1463 for(i
= 0; i
< 4; i
++) {
1464 int dev
= (motion
[i
] >> 12);
1465 int b
= motion
[i
] & 0xfff;
1469 if((dev
== which
) && (b
>= 128) && (b
== (button
+128))) {
1470 sdlMotionButtons
[i
] = pressed
;
1476 void sdlUpdateJoyHat(int which
,
1481 for(int j
= 0; j
< 4; j
++) {
1482 for(i
= 0; i
< 12; i
++) {
1483 int dev
= (joypad
[j
][i
] >> 12);
1484 int a
= joypad
[j
][i
] & 0xfff;
1488 if((dev
== which
) && (a
>=32) && (a
< 48) && (((a
&15)>>2) == hat
)) {
1493 v
= value
& SDL_HAT_UP
;
1496 v
= value
& SDL_HAT_DOWN
;
1499 v
= value
& SDL_HAT_RIGHT
;
1502 v
= value
& SDL_HAT_LEFT
;
1505 sdlButtons
[j
][i
] = (v
? true : false);
1510 for(i
= 0; i
< 4; i
++) {
1511 int dev
= (motion
[i
] >> 12);
1512 int a
= motion
[i
] & 0xfff;
1516 if((dev
== which
) && (a
>=32) && (a
< 48) && (((a
&15)>>2) == hat
)) {
1521 v
= value
& SDL_HAT_UP
;
1524 v
= value
& SDL_HAT_DOWN
;
1527 v
= value
& SDL_HAT_RIGHT
;
1530 v
= value
& SDL_HAT_LEFT
;
1533 sdlMotionButtons
[i
] = (v
? true : false);
1539 void sdlUpdateJoyAxis(int which
,
1544 for(int j
= 0; j
< 4; j
++) {
1545 for(i
= 0; i
< 12; i
++) {
1546 int dev
= (joypad
[j
][i
] >> 12);
1547 int a
= joypad
[j
][i
] & 0xfff;
1551 if((dev
== which
) && (a
< 32) && ((a
>>1) == axis
)) {
1552 sdlButtons
[j
][i
] = (a
& 1) ? (value
> 16384) : (value
< -16384);
1557 for(i
= 0; i
< 4; i
++) {
1558 int dev
= (motion
[i
] >> 12);
1559 int a
= motion
[i
] & 0xfff;
1563 if((dev
== which
) && (a
< 32) && ((a
>>1) == axis
)) {
1564 sdlMotionButtons
[i
] = (a
& 1) ? (value
> 16384) : (value
< -16384);
1570 bool sdlCheckJoyKey(int key
)
1572 int dev
= (key
>> 12) - 1;
1573 int what
= key
& 0xfff;
1577 int button
= what
- 128;
1579 if(button
>= SDL_JoystickNumButtons(sdlDevices
[dev
]))
1581 } else if (what
< 0x20) {
1584 if(what
>= SDL_JoystickNumAxes(sdlDevices
[dev
]))
1586 } else if (what
< 0x30) {
1590 if(what
>= SDL_JoystickNumHats(sdlDevices
[dev
]))
1600 sdlNumDevices
= SDL_NumJoysticks();
1603 sdlDevices
= (SDL_Joystick
**)calloc(1,sdlNumDevices
*
1604 sizeof(SDL_Joystick
**));
1607 bool usesJoy
= false;
1609 for(int j
= 0; j
< 4; j
++) {
1610 for(i
= 0; i
< 12; i
++) {
1611 int dev
= joypad
[j
][i
] >> 12;
1617 if(dev
< sdlNumDevices
) {
1618 if(sdlDevices
[dev
] == NULL
) {
1619 sdlDevices
[dev
] = SDL_JoystickOpen(dev
);
1622 ok
= sdlCheckJoyKey(joypad
[j
][i
]);
1628 joypad
[j
][i
] = defaultJoypad
[i
];
1635 for(i
= 0; i
< 4; i
++) {
1636 int dev
= motion
[i
] >> 12;
1642 if(dev
< sdlNumDevices
) {
1643 if(sdlDevices
[dev
] == NULL
) {
1644 sdlDevices
[dev
] = SDL_JoystickOpen(dev
);
1647 ok
= sdlCheckJoyKey(motion
[i
]);
1653 motion
[i
] = defaultMotion
[i
];
1660 SDL_JoystickEventState(SDL_ENABLE
);
1663 void sdlPollEvents()
1666 while(SDL_PollEvent(&event
)) {
1667 switch(event
.type
) {
1671 case SDL_ACTIVEEVENT
:
1672 if(pauseWhenInactive
&& (event
.active
.state
& SDL_APPINPUTFOCUS
)) {
1673 active
= event
.active
.gain
;
1681 if(pauseWhenInactive
) {
1686 memset(delta
,255,sizeof(delta
));
1690 case SDL_MOUSEMOTION
:
1691 case SDL_MOUSEBUTTONUP
:
1692 case SDL_MOUSEBUTTONDOWN
:
1694 SDL_ShowCursor(SDL_ENABLE
);
1698 case SDL_JOYHATMOTION
:
1699 sdlUpdateJoyHat(event
.jhat
.which
,
1703 case SDL_JOYBUTTONDOWN
:
1704 case SDL_JOYBUTTONUP
:
1705 sdlUpdateJoyButton(event
.jbutton
.which
,
1706 event
.jbutton
.button
,
1707 event
.jbutton
.state
== SDL_PRESSED
);
1709 case SDL_JOYAXISMOTION
:
1710 sdlUpdateJoyAxis(event
.jaxis
.which
,
1715 sdlUpdateKey(event
.key
.keysym
.sym
, true);
1718 switch(event
.key
.keysym
.sym
) {
1720 if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1721 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1723 emulator
.emuReset();
1725 systemScreenMessage("Reset");
1730 if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1731 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1732 if(emulating
&& emulator
.emuReadMemState
&& rewindMemory
1734 rewindPos
= (rewindPos
- 1) & 7;
1735 emulator
.emuReadMemState(&rewindMemory
[REWIND_SIZE
*rewindPos
],
1739 systemScreenMessage("Rewind");
1744 if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1745 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1747 SDL_PauseAudio(paused
);
1756 if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1757 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1759 fullscreen
= !fullscreen
;
1761 flags
|= SDL_FULLSCREEN
;
1762 SDL_SetVideoMode(destWidth
, destHeight
, systemColorDepth
, flags
);
1763 // if(SDL_WM_ToggleFullScreen(surface))
1764 // fullscreen = !fullscreen;
1768 if(dbgMain
!= debuggerMain
) {
1789 if(!(event
.key
.keysym
.mod
& MOD_NOSHIFT
) &&
1790 (event
.key
.keysym
.mod
& KMOD_SHIFT
)) {
1791 sdlWriteState(event
.key
.keysym
.sym
-SDLK_F1
);
1792 } else if(!(event
.key
.keysym
.mod
& MOD_KEYS
)) {
1793 sdlReadState(event
.key
.keysym
.sym
-SDLK_F1
);
1800 if(!(event
.key
.keysym
.mod
& MOD_NOALT
) &&
1801 (event
.key
.keysym
.mod
& KMOD_ALT
)) {
1802 char *disableMessages
[4] =
1803 { "autofire A disabled",
1804 "autofire B disabled",
1805 "autofire R disabled",
1806 "autofire L disabled"};
1807 char *enableMessages
[4] =
1812 int mask
= 1 << (event
.key
.keysym
.sym
- SDLK_1
);
1813 if(event
.key
.keysym
.sym
> SDLK_2
)
1815 if(autoFire
& mask
) {
1817 systemScreenMessage(disableMessages
[event
.key
.keysym
.sym
- SDLK_1
]);
1820 systemScreenMessage(enableMessages
[event
.key
.keysym
.sym
- SDLK_1
]);
1822 } if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1823 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1824 int mask
= 0x0100 << (event
.key
.keysym
.sym
- SDLK_1
);
1825 layerSettings
^= mask
;
1826 layerEnable
= DISPCNT
& layerSettings
;
1827 CPUUpdateRenderBuffers(false);
1834 if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1835 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1836 int mask
= 0x0100 << (event
.key
.keysym
.sym
- SDLK_1
);
1837 layerSettings
^= mask
;
1838 layerEnable
= DISPCNT
& layerSettings
;
1842 if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1843 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1846 pauseNextFrame
= true;
1852 sdlUpdateKey(event
.key
.keysym
.sym
, false);
1858 void usage(char *cmd
)
1860 printf("%s [option ...] file\n", cmd
);
1864 -1, --video-1x 1x\n\
1865 -2, --video-2x 2x\n\
1866 -3, --video-3x 3x\n\
1867 -4, --video-4x 4x\n\
1868 -F, --fullscreen Full screen\n\
1869 -G, --gdb=PROTOCOL GNU Remote Stub mode:\n\
1870 tcp - use TCP at port 55555\n\
1871 tcp:PORT - use TCP at port PORT\n\
1872 pipe - use pipe transport\n\
1873 -N, --no-debug Don't parse debug information\n\
1874 -S, --flash-size=SIZE Set the Flash size\n\
1875 --flash-64k 0 - 64K Flash\n\
1876 --flash-128k 1 - 128K Flash\n\
1877 -T, --throttle=THROTTLE Set the desired throttle (5...1000)\n\
1878 -Y, --yuv=TYPE Use YUV overlay for drawing:\n\
1884 -b, --bios=BIOS Use given bios file\n\
1885 -c, --config=FILE Read the given configuration file\n\
1886 -d, --debug Enter debugger\n\
1887 -f, --filter=FILTER Select filter:\n\
1888 --filter-normal 0 - normal mode\n\
1889 --filter-tv-mode 1 - TV Mode\n\
1890 --filter-2xsai 2 - 2xSaI\n\
1891 --filter-super-2xsai 3 - Super 2xSaI\n\
1892 --filter-super-eagle 4 - Super Eagle\n\
1893 --filter-pixelate 5 - Pixelate\n\
1894 --filter-motion-blur 6 - Motion Blur\n\
1895 --filter-advmame 7 - AdvanceMAME Scale2x\n\
1896 --filter-simple2x 8 - Simple2x\n\
1897 --filter-bilinear 9 - Bilinear\n\
1898 --filter-bilinear+ 10 - Bilinear Plus\n\
1899 --filter-scanlines 11 - Scanlines\n\
1900 --filter-hq2x 12 - hq2x\n\
1901 --filter-lq2x 13 - lq2x\n\
1902 -h, --help Print this help\n\
1903 -i, --ips=PATCH Apply given IPS patch\n\
1904 -p, --profile=[HERTZ] Enable profiling\n\
1905 -s, --frameskip=FRAMESKIP Set frame skip (0...9)\n\
1908 -t, --save-type=TYPE Set the available save type\n\
1909 --save-auto 0 - Automatic (EEPROM, SRAM, FLASH)\n\
1910 --save-eeprom 1 - EEPROM\n\
1911 --save-sram 2 - SRAM\n\
1912 --save-flash 3 - FLASH\n\
1913 --save-sensor 4 - EEPROM+Sensor\n\
1914 --save-none 5 - NONE\n\
1915 -v, --verbose=VERBOSE Set verbose logging (trace.log)\n\
1917 2 - Unaligned memory access\n\
1918 4 - Illegal memory write\n\
1919 8 - Illegal memory read\n\
1924 256 - Undefined instruction\n\
1925 512 - AGBPrint messages\n\
1927 Long options only:\n\
1928 --agb-print Enable AGBPrint support\n\
1929 --auto-frameskip Enable auto frameskipping\n\
1930 --ifb-none No interframe blending\n\
1931 --ifb-motion-blur Interframe motion blur\n\
1932 --ifb-smart Smart interframe blending\n\
1933 --no-agb-print Disable AGBPrint support\n\
1934 --no-auto-frameskip Disable auto frameskipping\n\
1935 --no-ips Do not apply IPS patch\n\
1936 --no-mmx Disable MMX support\n\
1937 --no-pause-when-inactive Don't pause when inactive\n\
1938 --no-rtc Disable RTC support\n\
1939 --no-show-speed Don't show emulation speed\n\
1940 --no-throttle Disable thrrotle\n\
1941 --pause-when-inactive Pause when inactive\n\
1942 --rtc Enable RTC support\n\
1943 --show-speed-normal Show emulation speed\n\
1944 --show-speed-detailed Show detailed speed data\n\
1948 int main(int argc
, char **argv
)
1950 fprintf(stderr
, "VisualBoyAdvance version %s [SDL]\n", VERSION
);
1966 sdlReadPreferences();
1970 while((op
= getopt_long(argc
,
1972 "FNT:Y:G:D:b:c:df:hi:p::s:t:v:1234",
1977 // long option already processed by getopt_long
1981 if(optarg
== NULL
) {
1982 fprintf(stderr
, "Missing BIOS file name\n");
1985 strcpy(biosFileName
, optarg
);
1989 if(optarg
== NULL
) {
1990 fprintf(stderr
, "Missing config file name\n");
1993 FILE *f
= fopen(optarg
, "r");
1995 fprintf(stderr
, "File not found %s\n", optarg
);
1998 sdlReadPreferences(f
);
2009 if(optarg
== NULL
) {
2010 fprintf(stderr
, "Missing IPS name\n");
2012 strcpy(ipsname
, optarg
);
2018 yuvType
= atoi(optarg
);
2021 yuvType
= SDL_YV12_OVERLAY
;
2024 yuvType
= SDL_UYVY_OVERLAY
;
2027 yuvType
= SDL_YVYU_OVERLAY
;
2030 yuvType
= SDL_YUY2_OVERLAY
;
2033 yuvType
= SDL_IYUV_OVERLAY
;
2036 yuvType
= SDL_YV12_OVERLAY
;
2039 yuvType
= SDL_YV12_OVERLAY
;
2042 dbgMain
= remoteStubMain
;
2043 dbgSignal
= remoteStubSignal
;
2044 dbgOutput
= remoteOutput
;
2046 debuggerStub
= true;
2049 if(strncmp(s
,"tcp:", 4) == 0) {
2052 remoteSetProtocol(0);
2053 remoteSetPort(port
);
2054 } else if(strcmp(s
,"tcp") == 0) {
2055 remoteSetProtocol(0);
2056 } else if(strcmp(s
, "pipe") == 0) {
2057 remoteSetProtocol(1);
2059 fprintf(stderr
, "Unknown protocol %s\n", s
);
2063 remoteSetProtocol(0);
2071 systemDebug
= atoi(optarg
);
2082 filter
= atoi(optarg
);
2090 cpuEnableProfiling(atoi(optarg
));
2092 cpuEnableProfiling(100);
2096 sdlFlashSize
= atoi(optarg
);
2097 if(sdlFlashSize
< 0 || sdlFlashSize
> 1)
2102 int a
= atoi(optarg
);
2103 if(a
>= 0 && a
<= 9) {
2114 int a
= atoi(optarg
);
2122 int t
= atoi(optarg
);
2123 if(t
< 5 || t
> 1000)
2130 systemVerbose
= atoi(optarg
);
2163 rewindMemory
= (char *)malloc(8*REWIND_SIZE
);
2165 if(sdlFlashSize
== 0)
2166 flashSetSize(0x10000);
2168 flashSetSize(0x20000);
2170 rtcEnable(sdlRtcEnable
? true : false);
2171 agbPrintEnable(sdlAgbPrint
? true : false);
2174 if(optind
>= argc
) {
2175 systemMessage(0,"Missing image name");
2185 for(int i
= 0; i
< 24;) {
2186 systemGbPalette
[i
++] = (0x1f) | (0x1f << 5) | (0x1f << 10);
2187 systemGbPalette
[i
++] = (0x15) | (0x15 << 5) | (0x15 << 10);
2188 systemGbPalette
[i
++] = (0x0c) | (0x0c << 5) | (0x0c << 10);
2189 systemGbPalette
[i
++] = 0;
2192 systemSaveUpdateCounter
= SYSTEM_SAVE_NOT_UPDATED
;
2195 char *szFile
= argv
[optind
];
2196 u32 len
= strlen(szFile
);
2197 if (len
> SYSMSG_BUFFER_SIZE
)
2199 fprintf(stderr
,"%s :%s: File name too long\n",argv
[0],szFile
);
2203 utilGetBaseName(szFile
, filename
);
2204 char *p
= strrchr(filename
, '.');
2210 sprintf(ipsname
, "%s.ips", filename
);
2212 bool failed
= false;
2214 IMAGE_TYPE type
= utilFindType(szFile
);
2216 if(type
== IMAGE_UNKNOWN
) {
2217 systemMessage(0, "Unknown file type %s", szFile
);
2220 cartridgeType
= (int)type
;
2222 if(type
== IMAGE_GB
) {
2223 failed
= !gbLoadRom(szFile
);
2225 gbGetHardwareType();
2227 // used for the handling of the gb Boot Rom
2230 char tempName
[0x800];
2231 strcpy(tempName
, arg0
);
2232 char *p
= strrchr(tempName
, '\\');
2233 if(p
) { *p
= 0x00; }
2234 strcat(tempName
, "\\DMG_ROM.bin");
2235 fprintf(stderr
, "%s\n", tempName
);
2236 gbCPUInit(tempName
, useBios
);
2238 else useBios
= false;
2241 cartridgeType
= IMAGE_GB
;
2242 emulator
= GBSystem
;
2244 int size
= gbRomSize
;
2245 utilApplyIPS(ipsname
, &gbRom
, &size
);
2246 if(size
!= gbRomSize
) {
2247 extern bool gbUpdateSizes();
2253 } else if(type
== IMAGE_GBA
) {
2254 int size
= CPULoadRom(szFile
);
2255 failed
= (size
== 0);
2257 sdlApplyPerImagePreferences();
2259 doMirroring(mirroringEnable
);
2262 emulator
= GBASystem
;
2264 /* disabled due to problems
2265 if(removeIntros && rom != NULL) {
2266 WRITE32LE(&rom[0], 0xea00002e);
2270 CPUInit(biosFileName
, useBios
);
2273 int size
= 0x2000000;
2274 utilApplyIPS(ipsname
, &rom
, &size
);
2275 if(size
!= 0x2000000) {
2283 systemMessage(0, "Failed to load file %s", szFile
);
2288 strcpy(filename
, "gnu_stub");
2289 rom
= (u8
*)malloc(0x2000000);
2290 workRAM
= (u8
*)calloc(1, 0x40000);
2291 bios
= (u8
*)calloc(1,0x4000);
2292 internalRAM
= (u8
*)calloc(1,0x8000);
2293 paletteRAM
= (u8
*)calloc(1,0x400);
2294 vram
= (u8
*)calloc(1, 0x20000);
2295 oam
= (u8
*)calloc(1, 0x400);
2296 pix
= (u8
*)calloc(1, 4 * 241 * 162);
2297 ioMem
= (u8
*)calloc(1, 0x400);
2299 emulator
= GBASystem
;
2301 CPUInit(biosFileName
, useBios
);
2310 int flags
= SDL_INIT_VIDEO
|SDL_INIT_AUDIO
|
2311 SDL_INIT_TIMER
|SDL_INIT_NOPARACHUTE
;
2314 flags
^= SDL_INIT_AUDIO
;
2316 if(SDL_Init(flags
)) {
2317 systemMessage(0, "Failed to init SDL: %s", SDL_GetError());
2321 if(SDL_InitSubSystem(SDL_INIT_JOYSTICK
)) {
2322 systemMessage(0, "Failed to init joystick support: %s", SDL_GetError());
2327 if(cartridgeType
== 0) {
2330 systemFrameSkip
= frameSkip
;
2331 } else if (cartridgeType
== 1) {
2335 gbBorderLineSkip
= 256;
2336 gbBorderColumnSkip
= 48;
2337 gbBorderRowSkip
= 40;
2341 gbBorderLineSkip
= 160;
2342 gbBorderColumnSkip
= 0;
2343 gbBorderRowSkip
= 0;
2345 systemFrameSkip
= gbFrameSkip
;
2351 destWidth
= (sizeOption
+1)*srcWidth
;
2352 destHeight
= (sizeOption
+1)*srcHeight
;
2354 surface
= SDL_SetVideoMode(destWidth
, destHeight
, 16,
2355 SDL_ANYFORMAT
|SDL_HWSURFACE
|SDL_DOUBLEBUF
|
2356 (fullscreen
? SDL_FULLSCREEN
: 0));
2358 if(surface
== NULL
) {
2359 systemMessage(0, "Failed to set video mode");
2364 systemRedShift
= sdlCalculateShift(surface
->format
->Rmask
);
2365 systemGreenShift
= sdlCalculateShift(surface
->format
->Gmask
);
2366 systemBlueShift
= sdlCalculateShift(surface
->format
->Bmask
);
2368 systemColorDepth
= surface
->format
->BitsPerPixel
;
2369 if(systemColorDepth
== 15)
2370 systemColorDepth
= 16;
2373 Init_Overlay(surface
, yuvType
);
2374 systemColorDepth
= 32;
2376 systemGreenShift
= 11;
2377 systemBlueShift
= 19;
2380 if(systemColorDepth
!= 16 && systemColorDepth
!= 24 &&
2381 systemColorDepth
!= 32) {
2382 fprintf(stderr
,"Unsupported color depth '%d'.\nOnly 16, 24 and 32 bit color depths are supported\n", systemColorDepth
);
2387 sdlMakeStretcher(srcWidth
);
2389 switch(systemColorDepth
) {
2391 sdlStretcher
= sdlStretcher16
[sizeOption
];
2394 sdlStretcher
= sdlStretcher24
[sizeOption
];
2397 sdlStretcher
= sdlStretcher32
[sizeOption
];
2400 fprintf(stderr
, "Unsupported resolution: %d\n", systemColorDepth
);
2405 fprintf(stderr
,"Color depth: %d\n", systemColorDepth
);
2407 if(systemColorDepth
== 16) {
2408 if(sdlCalculateMaskWidth(surface
->format
->Gmask
) == 6) {
2413 srcPitch
= srcWidth
* 2+4;
2415 if(systemColorDepth
!= 32)
2416 filterFunction
= NULL
;
2418 if(systemColorDepth
== 32)
2419 srcPitch
= srcWidth
*4 + 4;
2421 srcPitch
= srcWidth
*3;
2424 utilUpdateSystemColorMaps();
2426 if(systemColorDepth
!= 32) {
2429 filterFunction
= NULL
;
2432 filterFunction
= ScanlinesTV
;
2435 filterFunction
= _2xSaI
;
2438 filterFunction
= Super2xSaI
;
2441 filterFunction
= SuperEagle
;
2444 filterFunction
= Pixelate
;
2447 filterFunction
= MotionBlur
;
2450 filterFunction
= AdMame2x
;
2453 filterFunction
= Simple2x
;
2456 filterFunction
= Bilinear
;
2459 filterFunction
= BilinearPlus
;
2462 filterFunction
= Scanlines
;
2465 filterFunction
= hq2x
;
2468 filterFunction
= lq2x
;
2471 filterFunction
= NULL
;
2477 filterFunction
= NULL
;
2480 filterFunction
= ScanlinesTV32
;
2483 filterFunction
= _2xSaI32
;
2486 filterFunction
= Super2xSaI32
;
2489 filterFunction
= SuperEagle32
;
2492 filterFunction
= Pixelate32
;
2495 filterFunction
= MotionBlur32
;
2498 filterFunction
= AdMame2x32
;
2501 filterFunction
= Simple2x32
;
2504 filterFunction
= Bilinear32
;
2507 filterFunction
= BilinearPlus32
;
2510 filterFunction
= Scanlines32
;
2513 filterFunction
= hq2x32
;
2516 filterFunction
= lq2x32
;
2519 filterFunction
= NULL
;
2524 if(systemColorDepth
== 16) {
2531 ifbFunction
= MotionBlurIB
;
2534 ifbFunction
= SmartIB
;
2537 } else if(systemColorDepth
== 32) {
2544 ifbFunction
= MotionBlurIB32
;
2547 ifbFunction
= SmartIB32
;
2554 delta
= (u8
*)malloc(322*242*4);
2555 memset(delta
, 255, 322*242*4);
2564 autoFrameSkipLastTime
= throttleLastTime
= systemGetClock();
2566 SDL_WM_SetCaption("VisualBoyAdvance", NULL
);
2569 if(!paused
&& active
) {
2570 if(debugger
&& emulator
.emuHasDebugger
)
2573 emulator
.emuMain(emulator
.emuCount
);
2574 if(rewindSaveNeeded
&& rewindMemory
&& emulator
.emuWriteMemState
) {
2578 if(emulator
.emuWriteMemState
&&
2579 emulator
.emuWriteMemState(&rewindMemory
[rewindPos
*REWIND_SIZE
],
2581 rewindPos
= (rewindPos
+ 1) & 7;
2582 if(rewindCount
== 8)
2583 rewindTopPos
= (rewindTopPos
+ 1) & 7;
2587 rewindSaveNeeded
= false;
2595 if(mouseCounter
== 0)
2596 SDL_ShowCursor(SDL_DISABLE
);
2601 fprintf(stderr
,"Shutting down\n");
2605 if(gbRom
!= NULL
|| rom
!= NULL
) {
2607 emulator
.emuCleanUp();
2619 void systemMessage(int num
, const char *msg
, ...)
2621 char buffer
[SYSMSG_BUFFER_SIZE
*2];
2624 va_start(valist
, msg
);
2625 vsprintf(buffer
, msg
, valist
);
2627 fprintf(stderr
, "%s\n", buffer
);
2631 void systemDrawScreen()
2636 Draw_Overlay(surface
, sizeOption
+1);
2640 SDL_LockSurface(surface
);
2643 if(cartridgeType
== 1 && gbBorderOn
) {
2644 gbSgbRenderBorder();
2646 if(((systemGetClock() - screenMessageTime
) < 3000) &&
2647 !disableStatusMessages
) {
2648 drawText(pix
, srcPitch
, 10, srcHeight
- 20,
2649 screenMessageBuffer
);
2651 screenMessage
= false;
2656 if(systemColorDepth
== 16)
2657 ifbFunction(pix
+destWidth
+4, destWidth
+4, srcWidth
, srcHeight
);
2659 ifbFunction(pix
+destWidth
*2+4, destWidth
*2+4, srcWidth
, srcHeight
);
2662 if(filterFunction
) {
2663 if(systemColorDepth
== 16)
2664 filterFunction(pix
+destWidth
+4,destWidth
+4, delta
,
2665 (u8
*)surface
->pixels
,surface
->pitch
,
2669 filterFunction(pix
+destWidth
*2+4,
2672 (u8
*)surface
->pixels
,
2677 int destPitch
= surface
->pitch
;
2679 u8
*dest
= (u8
*)surface
->pixels
;
2681 u32
*stretcher
= (u32
*)sdlStretcher
;
2682 if(systemColorDepth
== 16)
2684 int option
= sizeOption
;
2687 switch(sizeOption
) {
2689 for(i
= 0; i
< srcHeight
; i
++) {
2696 for(i
= 0; i
< srcHeight
; i
++) {
2705 for(i
= 0; i
< srcHeight
; i
++) {
2716 for(i
= 0; i
< srcHeight
; i
++) {
2731 if(showSpeed
&& fullscreen
) {
2734 sprintf(buffer
, "%d%%", systemSpeed
);
2736 sprintf(buffer
, "%3d%%(%d, %d fps)", systemSpeed
,
2738 showRenderedFrames
);
2739 if(showSpeedTransparent
)
2740 drawTextTransp((u8
*)surface
->pixels
,
2746 drawText((u8
*)surface
->pixels
,
2753 SDL_UnlockSurface(surface
);
2754 // SDL_UpdateRect(surface, 0, 0, destWidth, destHeight);
2758 bool systemReadJoypads()
2763 u32
systemReadJoypad(int which
)
2765 if(which
< 0 || which
> 3)
2766 which
= sdlDefaultJoypad
;
2770 if(sdlButtons
[which
][KEY_BUTTON_A
])
2772 if(sdlButtons
[which
][KEY_BUTTON_B
])
2774 if(sdlButtons
[which
][KEY_BUTTON_SELECT
])
2776 if(sdlButtons
[which
][KEY_BUTTON_START
])
2778 if(sdlButtons
[which
][KEY_RIGHT
])
2780 if(sdlButtons
[which
][KEY_LEFT
])
2782 if(sdlButtons
[which
][KEY_UP
])
2784 if(sdlButtons
[which
][KEY_DOWN
])
2786 if(sdlButtons
[which
][KEY_BUTTON_R
])
2788 if(sdlButtons
[which
][KEY_BUTTON_L
])
2791 // disallow L+R or U+D of being pressed at the same time
2792 if((res
& 48) == 48)
2794 if((res
& 192) == 192)
2797 if(sdlButtons
[which
][KEY_BUTTON_SPEED
])
2799 if(sdlButtons
[which
][KEY_BUTTON_CAPTURE
])
2806 autoFireToggle
= !autoFireToggle
;
2812 void systemSetTitle(const char *title
)
2814 SDL_WM_SetCaption(title
, NULL
);
2817 void systemShowSpeed(int speed
)
2819 systemSpeed
= speed
;
2821 showRenderedFrames
= renderedFrames
;
2824 if(!fullscreen
&& showSpeed
) {
2827 sprintf(buffer
, "VisualBoyAdvance-%3d%%", systemSpeed
);
2829 sprintf(buffer
, "VisualBoyAdvance-%3d%%(%d, %d fps)", systemSpeed
,
2831 showRenderedFrames
);
2833 systemSetTitle(buffer
);
2841 void system10Frames(int rate
)
2843 u32 time
= systemGetClock();
2844 if(!wasPaused
&& autoFrameSkip
&& !throttle
) {
2845 u32 diff
= time
- autoFrameSkipLastTime
;
2849 speed
= (1000000/rate
)/diff
;
2854 if(frameskipadjust
>= 3) {
2856 if(systemFrameSkip
> 0)
2861 frameskipadjust
-= (90 - speed
)/5;
2862 else if(systemFrameSkip
< 9)
2865 if(frameskipadjust
<= -2) {
2866 frameskipadjust
+= 2;
2867 if(systemFrameSkip
< 9)
2872 if(!wasPaused
&& throttle
) {
2874 u32 diff
= time
- throttleLastTime
;
2876 int target
= (1000000/(rate
*throttle
));
2877 int d
= (target
- diff
);
2883 throttleLastTime
= systemGetClock();
2886 if(++rewindCounter
>= rewindTimer
) {
2887 rewindSaveNeeded
= true;
2892 if(systemSaveUpdateCounter
) {
2893 if(--systemSaveUpdateCounter
<= SYSTEM_SAVE_NOT_UPDATED
) {
2895 systemSaveUpdateCounter
= SYSTEM_SAVE_NOT_UPDATED
;
2900 autoFrameSkipLastTime
= time
;
2903 void systemScreenCapture(int a
)
2909 sprintf(buffer
, "%s/%s%02d.bmp", captureDir
, sdlGetFilename(filename
), a
);
2911 sprintf(buffer
, "%s%02d.bmp", filename
, a
);
2913 emulator
.emuWriteBMP(buffer
);
2916 sprintf(buffer
, "%s/%s%02d.png", captureDir
, sdlGetFilename(filename
), a
);
2918 sprintf(buffer
, "%s%02d.png", filename
, a
);
2919 emulator
.emuWritePNG(buffer
);
2922 systemScreenMessage("Screen capture");
2925 void soundCallback(void *,u8
*stream
,int len
)
2930 // Patch #1382692 by deathpudding.
2931 /* since this is running in a different thread, speedup and
2932 * throttle can change at any time; save the value so locks
2934 bool lock
= (!speedup
&& !throttle
) ? true : false;
2937 SDL_SemWait (sdlBufferFull
);
2939 SDL_SemWait (sdlBufferLock
);
2940 memcpy (stream
, sdlBuffer
, len
);
2942 SDL_SemPost (sdlBufferLock
);
2945 SDL_SemPost (sdlBufferEmpty
);
2948 void systemWriteDataToSoundBuffer()
2950 // Patch #1382692 by deathpudding.
2951 if (SDL_GetAudioStatus () != SDL_AUDIO_PLAYING
)
2954 if ((sdlSoundLen
+ soundBufferLen
) >= 2048*2) {
2955 bool lock
= (!speedup
&& !throttle
) ? true : false;
2958 SDL_SemWait (sdlBufferEmpty
);
2960 SDL_SemWait (sdlBufferLock
);
2961 int copied
= 2048*2 - sdlSoundLen
;
2962 memcpy (sdlBuffer
+ sdlSoundLen
, soundFinalWave
, copied
);
2963 sdlSoundLen
= 2048*2;
2964 SDL_SemPost (sdlBufferLock
);
2967 SDL_SemPost (sdlBufferFull
);
2969 /* wait for buffer to be dumped by soundCallback() */
2970 SDL_SemWait (sdlBufferEmpty
);
2971 SDL_SemPost (sdlBufferEmpty
);
2973 SDL_SemWait (sdlBufferLock
);
2974 memcpy (sdlBuffer
, ((u8
*)soundFinalWave
) + copied
,
2975 soundBufferLen
- copied
);
2976 sdlSoundLen
= soundBufferLen
- copied
;
2977 SDL_SemPost (sdlBufferLock
);
2980 SDL_SemWait (sdlBufferLock
);
2981 memcpy (sdlBuffer
, ((u8
*) soundFinalWave
) + copied
, soundBufferLen
);
2982 SDL_SemPost (sdlBufferLock
);
2986 SDL_SemWait (sdlBufferLock
);
2987 memcpy (sdlBuffer
+ sdlSoundLen
, soundFinalWave
, soundBufferLen
);
2988 sdlSoundLen
+= soundBufferLen
;
2989 SDL_SemPost (sdlBufferLock
);
2993 bool systemSoundInit()
2995 SDL_AudioSpec audio
;
2997 switch(soundQuality
) {
3000 soundBufferLen
= 1470*2;
3004 soundBufferLen
= 736*2;
3008 soundBufferLen
= 368*2;
3011 audio
.format
=AUDIO_S16SYS
;
3013 audio
.samples
= 1024;
3014 audio
.callback
= soundCallback
;
3015 audio
.userdata
= NULL
;
3016 if(SDL_OpenAudio(&audio
, NULL
)) {
3017 fprintf(stderr
,"Failed to open audio: %s\n", SDL_GetError());
3020 soundBufferTotalLen
= soundBufferLen
*10;
3021 // Patch #1382692 by deathpudding.
3022 sdlBufferLock
= SDL_CreateSemaphore (1);
3023 sdlBufferFull
= SDL_CreateSemaphore (0);
3024 sdlBufferEmpty
= SDL_CreateSemaphore (1);
3026 systemSoundOn
= true;
3030 void systemSoundShutdown()
3032 // Patch #1382692 by deathpudding.
3033 SDL_CloseAudio (); //TODO: fix freeze
3034 SDL_DestroySemaphore (sdlBufferLock
);
3035 SDL_DestroySemaphore (sdlBufferFull
);
3036 SDL_DestroySemaphore (sdlBufferEmpty
);
3037 sdlBufferLock
= NULL
;
3038 sdlBufferFull
= NULL
;
3039 sdlBufferEmpty
= NULL
;
3042 void systemSoundPause()
3047 void systemSoundResume()
3052 void systemSoundReset()
3056 u32
systemGetClock()
3058 return SDL_GetTicks();
3061 void systemUpdateMotionSensor()
3063 if(sdlMotionButtons
[KEY_LEFT
]) {
3069 } else if(sdlMotionButtons
[KEY_RIGHT
]) {
3075 } else if(sensorX
> 2047) {
3085 if(sdlMotionButtons
[KEY_UP
]) {
3091 } else if(sdlMotionButtons
[KEY_DOWN
]) {
3097 } else if(sensorY
> 2047) {
3108 int systemGetSensorX()
3113 int systemGetSensorY()
3118 void systemGbPrint(u8
*data
,int pages
,int feed
,int palette
, int contrast
)
3122 void systemScreenMessage(const char *msg
)
3124 screenMessage
= true;
3125 screenMessageTime
= systemGetClock();
3126 if(strlen(msg
) > 20) {
3127 strncpy(screenMessageBuffer
, msg
, 20);
3128 screenMessageBuffer
[20] = 0;
3130 strcpy(screenMessageBuffer
, msg
);
3133 bool systemCanChangeSoundQuality()
3138 bool systemPauseOnFrame()
3140 if(pauseNextFrame
) {
3142 pauseNextFrame
= false;
3148 // Code donated by Niels Wagenaar (BoycottAdvance)
3151 #define GBA_WIDTH 240
3152 #define GBA_HEIGHT 160
3154 void Init_Overlay(SDL_Surface
*gbascreen
, int overlaytype
)
3157 overlay
= SDL_CreateYUVOverlay( GBA_WIDTH
,
3159 overlaytype
, gbascreen
);
3160 fprintf(stderr
, "Created %dx%dx%d %s %s overlay\n",
3161 overlay
->w
,overlay
->h
,overlay
->planes
,
3162 overlay
->hw_overlay
?"hardware":"software",
3163 overlay
->format
==SDL_YV12_OVERLAY
?"YV12":
3164 overlay
->format
==SDL_IYUV_OVERLAY
?"IYUV":
3165 overlay
->format
==SDL_YUY2_OVERLAY
?"YUY2":
3166 overlay
->format
==SDL_UYVY_OVERLAY
?"UYVY":
3167 overlay
->format
==SDL_YVYU_OVERLAY
?"YVYU":
3171 void Quit_Overlay(void)
3174 SDL_FreeYUVOverlay(overlay
);
3177 /* NOTE: These RGB conversion functions are not intended for speed,
3180 inline void RGBtoYUV(Uint8
*rgb
, int *yuv
)
3182 yuv
[0] = (int)((0.257 * rgb
[0]) + (0.504 * rgb
[1]) + (0.098 * rgb
[2]) + 16);
3183 yuv
[1] = (int)(128 - (0.148 * rgb
[0]) - (0.291 * rgb
[1]) + (0.439 * rgb
[2]));
3184 yuv
[2] = (int)(128 + (0.439 * rgb
[0]) - (0.368 * rgb
[1]) - (0.071 * rgb
[2]));
3187 inline void ConvertRGBtoYV12(SDL_Overlay
*o
)
3193 SDL_LockYUVOverlay(o
);
3195 /* Black initialization */
3197 memset(o->pixels[0],0,o->pitches[0]*o->h);
3198 memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2));
3199 memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2));
3203 for(y
=0; y
<160 && y
<o
->h
; y
++) {
3204 p
=(Uint8
*)pix
+srcPitch
*y
;
3205 op
[0]=o
->pixels
[0]+o
->pitches
[0]*y
;
3206 op
[1]=o
->pixels
[1]+o
->pitches
[1]*(y
/2);
3207 op
[2]=o
->pixels
[2]+o
->pitches
[2]*(y
/2);
3208 for(x
=0; x
<240 && x
<o
->w
; x
++) {
3211 if(x
%2==0 && y
%2==0) {
3215 p
+=4;//s->format->BytesPerPixel;
3219 SDL_UnlockYUVOverlay(o
);
3222 inline void ConvertRGBtoIYUV(SDL_Overlay
*o
)
3228 SDL_LockYUVOverlay(o
);
3230 /* Black initialization */
3232 memset(o->pixels[0],0,o->pitches[0]*o->h);
3233 memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2));
3234 memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2));
3238 for(y
=0; y
<160 && y
<o
->h
; y
++) {
3239 p
=(Uint8
*)pix
+srcPitch
*y
;
3240 op
[0]=o
->pixels
[0]+o
->pitches
[0]*y
;
3241 op
[1]=o
->pixels
[1]+o
->pitches
[1]*(y
/2);
3242 op
[2]=o
->pixels
[2]+o
->pitches
[2]*(y
/2);
3243 for(x
=0; x
<240 && x
<o
->w
; x
++) {
3246 if(x
%2==0 && y
%2==0) {
3250 p
+=4; //s->format->BytesPerPixel;
3254 SDL_UnlockYUVOverlay(o
);
3257 inline void ConvertRGBtoUYVY(SDL_Overlay
*o
)
3263 SDL_LockYUVOverlay(o
);
3265 for(y
=0; y
<160 && y
<o
->h
; y
++) {
3266 p
=(Uint8
*)pix
+srcPitch
*y
;
3267 op
=o
->pixels
[0]+o
->pitches
[0]*y
;
3268 for(x
=0; x
<240 && x
<o
->w
; x
++) {
3277 p
+=4; //s->format->BytesPerPixel;
3281 SDL_UnlockYUVOverlay(o
);
3284 inline void ConvertRGBtoYVYU(SDL_Overlay
*o
)
3290 SDL_LockYUVOverlay(o
);
3292 for(y
=0; y
<160 && y
<o
->h
; y
++) {
3293 p
=(Uint8
*)pix
+srcPitch
*y
;
3294 op
=o
->pixels
[0]+o
->pitches
[0]*y
;
3295 for(x
=0; x
<240 && x
<o
->w
; x
++) {
3306 p
+=4; //s->format->BytesPerPixel;
3310 SDL_UnlockYUVOverlay(o
);
3313 inline void ConvertRGBtoYUY2(SDL_Overlay
*o
)
3319 SDL_LockYUVOverlay(o
);
3321 for(y
=0; y
<160 && y
<o
->h
; y
++) {
3322 p
=(Uint8
*)pix
+srcPitch
*y
;
3323 op
=o
->pixels
[0]+o
->pitches
[0]*y
;
3324 for(x
=0; x
<240 && x
<o
->w
; x
++) {
3335 p
+=4; //s->format->BytesPerPixel;
3339 SDL_UnlockYUVOverlay(o
);
3342 inline void Convert32bit(SDL_Surface
*display
)
3344 switch(overlay
->format
) {
3345 case SDL_YV12_OVERLAY
:
3346 ConvertRGBtoYV12(overlay
);
3348 case SDL_UYVY_OVERLAY
:
3349 ConvertRGBtoUYVY(overlay
);
3351 case SDL_YVYU_OVERLAY
:
3352 ConvertRGBtoYVYU(overlay
);
3354 case SDL_YUY2_OVERLAY
:
3355 ConvertRGBtoYUY2(overlay
);
3357 case SDL_IYUV_OVERLAY
:
3358 ConvertRGBtoIYUV(overlay
);
3361 fprintf(stderr
, "cannot convert RGB picture to obtained YUV format!\n");
3369 inline void Draw_Overlay(SDL_Surface
*display
, int size
)
3371 SDL_LockYUVOverlay(overlay
);
3373 Convert32bit(display
);
3377 overlay_rect
.w
= GBA_WIDTH
* size
;
3378 overlay_rect
.h
= GBA_HEIGHT
* size
;
3380 SDL_DisplayYUVOverlay(overlay
, &overlay_rect
);
3381 SDL_UnlockYUVOverlay(overlay
);
3384 void systemGbBorderOn()
3388 gbBorderLineSkip
= 256;
3389 gbBorderColumnSkip
= 48;
3390 gbBorderRowSkip
= 40;
3392 destWidth
= (sizeOption
+1)*srcWidth
;
3393 destHeight
= (sizeOption
+1)*srcHeight
;
3395 surface
= SDL_SetVideoMode(destWidth
, destHeight
, 16,
3396 SDL_ANYFORMAT
|SDL_HWSURFACE
|SDL_DOUBLEBUF
|
3397 (fullscreen
? SDL_FULLSCREEN
: 0));
3399 sdlMakeStretcher(srcWidth
);
3401 switch(systemColorDepth
) {
3403 sdlStretcher
= sdlStretcher16
[sizeOption
];
3406 sdlStretcher
= sdlStretcher24
[sizeOption
];
3409 sdlStretcher
= sdlStretcher32
[sizeOption
];
3412 fprintf(stderr
, "Unsupported resolution: %d\n", systemColorDepth
);
3417 if(systemColorDepth
== 16) {
3418 if(sdlCalculateMaskWidth(surface
->format
->Gmask
) == 6) {
3420 RGB_LOW_BITS_MASK
= 0x821;
3423 RGB_LOW_BITS_MASK
= 0x421;
3425 if(cartridgeType
== 2) {
3426 for(int i
= 0; i
< 0x10000; i
++) {
3427 systemColorMap16
[i
] = (((i
>> 1) & 0x1f) << systemBlueShift
) |
3428 (((i
& 0x7c0) >> 6) << systemGreenShift
) |
3429 (((i
& 0xf800) >> 11) << systemRedShift
);
3432 for(int i
= 0; i
< 0x10000; i
++) {
3433 systemColorMap16
[i
] = ((i
& 0x1f) << systemRedShift
) |
3434 (((i
& 0x3e0) >> 5) << systemGreenShift
) |
3435 (((i
& 0x7c00) >> 10) << systemBlueShift
);
3438 srcPitch
= srcWidth
* 2+4;
3440 if(systemColorDepth
!= 32)
3441 filterFunction
= NULL
;
3442 RGB_LOW_BITS_MASK
= 0x010101;
3443 if(systemColorDepth
== 32) {
3446 for(int i
= 0; i
< 0x10000; i
++) {
3447 systemColorMap32
[i
] = ((i
& 0x1f) << systemRedShift
) |
3448 (((i
& 0x3e0) >> 5) << systemGreenShift
) |
3449 (((i
& 0x7c00) >> 10) << systemBlueShift
);
3451 if(systemColorDepth
== 32)
3452 srcPitch
= srcWidth
*4 + 4;
3454 srcPitch
= srcWidth
*3;