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 #define FILTERS_ENABLED 0
32 #define SDLK_KP2 SDLK_KP_2
33 #define SDLK_KP4 SDLK_KP_4
34 #define SDLK_KP6 SDLK_KP_6
35 #define SDLK_KP8 SDLK_KP_8
36 #define KMOD_META KMOD_GUI
39 #define FILTERS_ENABLED 1
41 //#define FILTERS_ENABLED 0
42 //#define IFB_ENABLED 0
46 #include "../agbprint.h"
56 #include "../gb/gbGlobals.h"
59 #define SYSCONFDIR "/etc"
64 # define GETCWD getcwd
67 # define GETCWD _getcwd
71 # define HAVE_DECL_GETOPT 0
73 # include "../getopt.h"
75 # define HAVE_DECL_GETOPT 1
80 extern "C" bool cpu_mmx
;
82 extern bool soundEcho
;
83 extern bool soundLowPass
;
84 extern bool soundReverse
;
86 #if FILTERS_ENABLED+0 != 0
87 extern int Init_2xSaI(u32
);
88 extern void _2xSaI(u8
*,u32
,u8
*,u8
*,u32
,int,int);
89 extern void _2xSaI32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
90 extern void Super2xSaI(u8
*,u32
,u8
*,u8
*,u32
,int,int);
91 extern void Super2xSaI32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
92 extern void SuperEagle(u8
*,u32
,u8
*,u8
*,u32
,int,int);
93 extern void SuperEagle32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
94 extern void Pixelate(u8
*,u32
,u8
*,u8
*,u32
,int,int);
95 extern void Pixelate32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
96 extern void MotionBlur(u8
*,u32
,u8
*,u8
*,u32
,int,int);
97 extern void MotionBlur32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
98 extern void AdMame2x(u8
*,u32
,u8
*,u8
*,u32
,int,int);
99 extern void AdMame2x32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
100 extern void Simple2x(u8
*,u32
,u8
*,u8
*,u32
,int,int);
101 extern void Simple2x32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
102 extern void Bilinear(u8
*,u32
,u8
*,u8
*,u32
,int,int);
103 extern void Bilinear32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
104 extern void BilinearPlus(u8
*,u32
,u8
*,u8
*,u32
,int,int);
105 extern void BilinearPlus32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
106 extern void Scanlines(u8
*,u32
,u8
*,u8
*,u32
,int,int);
107 extern void Scanlines32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
108 extern void ScanlinesTV(u8
*,u32
,u8
*,u8
*,u32
,int,int);
109 extern void ScanlinesTV32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
110 extern void hq2x(u8
*,u32
,u8
*,u8
*,u32
,int,int);
111 extern void hq2x32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
112 extern void lq2x(u8
*,u32
,u8
*,u8
*,u32
,int,int);
113 extern void lq2x32(u8
*,u32
,u8
*,u8
*,u32
,int,int);
116 #if IFB_ENABLED+0 != 0
117 extern void SmartIB(u8
*,u32
,int,int);
118 extern void SmartIB32(u8
*,u32
,int,int);
119 extern void MotionBlurIB(u8
*,u32
,int,int);
120 extern void MotionBlurIB32(u8
*,u32
,int,int);
123 extern void remoteInit();
124 extern void remoteCleanUp();
125 extern void remoteStubMain();
126 extern void remoteStubSignal(int,int);
127 extern void remoteOutput(char *, u32
);
128 extern void remoteSetProtocol(int);
129 extern void remoteSetPort(int);
130 extern void debuggerOutput(char *, u32
);
132 extern void CPUUpdateRenderBuffers(bool);
133 extern int gbHardware
;
135 struct EmulatedSystem emulator
= {
152 #if SDL_MAJOR_VERSION != 2
153 void Init_Overlay(SDL_Surface
*surface
, int overlaytype
);
154 void Quit_Overlay(void);
155 static void Draw_Overlay(SDL_Surface
*surface
, int size
);
156 SDL_Overlay
*overlay
= NULL
;
157 SDL_Surface
*surface
= NULL
;
158 SDL_Rect overlay_rect
;
162 #define VPFORMAT surface->format
163 #define VPIXELS surface->pixels
164 #define VPITCH surface->pitch
165 #define VSCALE (sizeOption+1)
166 #define VHEIGHT surface->h
168 static SDL_Window
*win
;
169 static SDL_Renderer
*renderer
;
170 static SDL_Texture
*texture
;
171 static SDL_PixelFormat
*format
;
172 #define VPFORMAT format
173 #define VPIXELS pixels
176 #define VHEIGHT srcHeight
181 int systemRedShift
= 0;
182 int systemBlueShift
= 0;
183 int systemGreenShift
= 0;
184 int systemColorDepth
= 0;
186 int systemVerbose
= 0;
187 int systemFrameSkip
= 0;
188 int systemSaveUpdateCounter
= SYSTEM_SAVE_NOT_UPDATED
;
202 int sdlPrintUsage
= 0;
205 int cartridgeType
= 3;
207 int captureFormat
= 0;
209 int pauseWhenInactive
= 0;
212 int RGB_LOW_BITS_MASK
=0x821;
213 u32 systemColorMap32
[0x10000];
214 u16 systemColorMap16
[0x10000];
215 u16 systemGbPalette
[24];
216 void (*filterFunction
)(u8
*,u32
,u8
*,u8
*,u32
,int,int) = NULL
;
217 void (*ifbFunction
)(u8
*,u32
,int,int) = NULL
;
221 char biosFileName
[2048];
222 char captureDir
[2048];
224 char batteryDir
[2048];
226 static char *rewindMemory
= NULL
;
227 static int rewindPos
= 0;
228 static int rewindTopPos
= 0;
229 static int rewindCounter
= 0;
230 static int rewindCount
= 0;
231 static bool rewindSaveNeeded
= false;
232 static int rewindTimer
= 0;
234 #define REWIND_SIZE 400000
235 #define SYSMSG_BUFFER_SIZE 1024
237 #define _stricmp strcasecmp
239 bool sdlButtons
[4][12] = {
240 { false, false, false, false, false, false,
241 false, false, false, false, false, false },
242 { false, false, false, false, false, false,
243 false, false, false, false, false, false },
244 { false, false, false, false, false, false,
245 false, false, false, false, false, false },
246 { false, false, false, false, false, false,
247 false, false, false, false, false, false }
250 bool sdlMotionButtons
[4] = { false, false, false, false };
252 int sdlNumDevices
= 0;
253 SDL_Joystick
**sdlDevices
= NULL
;
255 bool wasPaused
= false;
256 int autoFrameSkip
= 0;
257 int frameskipadjust
= 0;
258 int showRenderedFrames
= 0;
259 int renderedFrames
= 0;
262 u32 throttleLastTime
= 0;
263 u32 autoFrameSkipLastTime
= 0;
266 int showSpeedTransparent
= 1;
267 bool disableStatusMessages
= false;
269 bool pauseNextFrame
= false;
270 bool debugger
= false;
271 bool debuggerStub
= false;
273 bool systemSoundOn
= false;
274 bool removeIntros
= false;
275 int sdlFlashSize
= 0;
277 int sdlRtcEnable
= 0;
279 int sdlMirroringEnable
= 0;
281 int sdlDefaultJoypad
= 0;
283 extern void debuggerSignal(int,int);
285 void (*dbgMain
)() = debuggerMain
;
286 void (*dbgSignal
)(int,int) = debuggerSignal
;
287 void (*dbgOutput
)(char *, u32
) = debuggerOutput
;
289 int mouseCounter
= 0;
291 bool autoFireToggle
= false;
293 bool screenMessage
= false;
294 char screenMessageBuffer
[21];
295 u32 screenMessageTime
= 0;
297 // Patch #1382692 by deathpudding.
298 SDL_sem
*sdlBufferLock
= NULL
;
299 SDL_sem
*sdlBufferFull
= NULL
;
300 SDL_sem
*sdlBufferEmpty
= NULL
;
306 void (*sdlStretcher
)(u8
*, u8
*) = NULL
;
311 KEY_BUTTON_A
, KEY_BUTTON_B
,
312 KEY_BUTTON_START
, KEY_BUTTON_SELECT
,
313 KEY_BUTTON_L
, KEY_BUTTON_R
,
314 KEY_BUTTON_SPEED
, KEY_BUTTON_CAPTURE
317 static u32 joypad
[4][12] = {
318 { SDLK_LEFT
, SDLK_RIGHT
,
321 SDLK_RETURN
,SDLK_BACKSPACE
,
325 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
326 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
327 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
330 static u32 defaultJoypad
[12] = {
331 SDLK_LEFT
, SDLK_RIGHT
,
334 SDLK_RETURN
,SDLK_BACKSPACE
,
340 SDLK_KP4
, SDLK_KP6
, SDLK_KP8
, SDLK_KP2
343 u32 defaultMotion
[4] = {
344 SDLK_KP4
, SDLK_KP6
, SDLK_KP8
, SDLK_KP2
347 struct option sdlOptions
[] = {
348 { "agb-print", no_argument
, &sdlAgbPrint
, 1 },
349 { "auto-frameskip", no_argument
, &autoFrameSkip
, 1 },
350 { "bios", required_argument
, 0, 'b' },
351 { "config", required_argument
, 0, 'c' },
352 { "debug", no_argument
, 0, 'd' },
353 #if FILTERS_ENABLED+0 != 0
354 { "filter", required_argument
, 0, 'f' },
355 { "filter-normal", no_argument
, &filter
, 0 },
356 { "filter-tv-mode", no_argument
, &filter
, 1 },
357 { "filter-2xsai", no_argument
, &filter
, 2 },
358 { "filter-super-2xsai", no_argument
, &filter
, 3 },
359 { "filter-super-eagle", no_argument
, &filter
, 4 },
360 { "filter-pixelate", no_argument
, &filter
, 5 },
361 { "filter-motion-blur", no_argument
, &filter
, 6 },
362 { "filter-advmame", no_argument
, &filter
, 7 },
363 { "filter-simple2x", no_argument
, &filter
, 8 },
364 { "filter-bilinear", no_argument
, &filter
, 9 },
365 { "filter-bilinear+", no_argument
, &filter
, 10 },
366 { "filter-scanlines", no_argument
, &filter
, 11 },
367 { "filter-hq2x", no_argument
, &filter
, 12 },
368 { "filter-lq2x", no_argument
, &filter
, 13 },
370 #if IFB_ENABLED+0 != 0
371 { "ifb-none", no_argument
, &ifbType
, 0 },
372 { "ifb-motion-blur", no_argument
, &ifbType
, 1 },
373 { "ifb-smart", no_argument
, &ifbType
, 2 },
375 { "flash-size", required_argument
, 0, 'S' },
376 { "flash-64k", no_argument
, &sdlFlashSize
, 0 },
377 { "flash-128k", no_argument
, &sdlFlashSize
, 1 },
378 { "frameskip", required_argument
, 0, 's' },
379 { "fullscreen", no_argument
, &fullscreen
, 1 },
380 { "gdb", required_argument
, 0, 'G' },
381 { "help", no_argument
, &sdlPrintUsage
, 1 },
382 { "ips", required_argument
, 0, 'i' },
383 { "no-agb-print", no_argument
, &sdlAgbPrint
, 0 },
384 { "no-auto-frameskip", no_argument
, &autoFrameSkip
, 0 },
385 { "no-debug", no_argument
, 0, 'N' },
386 { "no-ips", no_argument
, &sdlAutoIPS
, 0 },
387 { "no-mmx", no_argument
, &disableMMX
, 1 },
388 { "no-pause-when-inactive", no_argument
, &pauseWhenInactive
, 0 },
389 { "no-rtc", no_argument
, &sdlRtcEnable
, 0 },
390 { "no-show-speed", no_argument
, &showSpeed
, 0 },
391 { "no-throttle", no_argument
, &throttle
, 0 },
392 { "pause-when-inactive", no_argument
, &pauseWhenInactive
, 1 },
393 { "profile", optional_argument
, 0, 'p' },
394 { "rtc", no_argument
, &sdlRtcEnable
, 1 },
395 { "save-type", required_argument
, 0, 't' },
396 { "save-auto", no_argument
, &cpuSaveType
, 0 },
397 { "save-eeprom", no_argument
, &cpuSaveType
, 1 },
398 { "save-sram", no_argument
, &cpuSaveType
, 2 },
399 { "save-flash", no_argument
, &cpuSaveType
, 3 },
400 { "save-sensor", no_argument
, &cpuSaveType
, 4 },
401 { "save-none", no_argument
, &cpuSaveType
, 5 },
402 { "show-speed-normal", no_argument
, &showSpeed
, 1 },
403 { "show-speed-detailed", no_argument
, &showSpeed
, 2 },
404 { "throttle", required_argument
, 0, 'T' },
405 { "verbose", required_argument
, 0, 'v' },
406 { "video-1x", no_argument
, &sizeOption
, 0 },
407 { "video-2x", no_argument
, &sizeOption
, 1 },
408 { "video-3x", no_argument
, &sizeOption
, 2 },
409 { "video-4x", no_argument
, &sizeOption
, 3 },
410 #if SDL_MAJOR_VERSION != 2
411 { "yuv", required_argument
, 0, 'Y' },
413 { NULL
, no_argument
, NULL
, 0 }
416 static int sdlCalculateMaskWidth(u32 mask
)
428 while(!(mask2
& 1)) {
436 static void sdlInitSAI2x(int bitspp
, SDL_PixelFormat
*format
) {
437 #if FILTERS_ENABLED+0 != 0
438 if(bitspp
== 24) return;
440 bitspp
= (sdlCalculateMaskWidth(format
->Gmask
) == 6 ? 565 : 555);
445 static void sdlSelectFilter(void) {
446 #if FILTERS_ENABLED+0 != 0
447 static void (*const filter16_func_map
[])(u8
*,u32
,u8
*,u8
*,u32
,int,int) = {
448 0, ScanlinesTV
, _2xSaI
, Super2xSaI
, SuperEagle
, Pixelate
, MotionBlur
,
449 AdMame2x
, Simple2x
, Bilinear
, BilinearPlus
, Scanlines
, hq2x
, lq2x
,
451 static void (*const filter32_func_map
[])(u8
*,u32
,u8
*,u8
*,u32
,int,int) = {
452 0, ScanlinesTV32
, _2xSaI32
, Super2xSaI32
, SuperEagle32
, Pixelate32
, MotionBlur32
,
453 AdMame2x32
, Simple2x32
, Bilinear32
, BilinearPlus32
, Scanlines32
, hq2x32
, lq2x32
,
455 if(systemColorDepth
!= 32) {
456 filterFunction
= filter16_func_map
[filter
];
458 filterFunction
= filter32_func_map
[filter
];
463 static void sdlSelectIfb(void) {
464 #if IFB_ENABLED+0 != 0
465 static void (*const ifb16_map
[])(u8
*,u32
,int,int) =
466 { 0, MotionBlurIB
, SmartIB
};
467 static void (*const ifb32_map
[])(u8
*,u32
,int,int) =
468 { 0, MotionBlurIB32
, SmartIB32
};
469 if(systemColorDepth
== 16) ifbFunction
= ifb16_map
[ifbType
];
470 if(systemColorDepth
== 32) ifbFunction
= ifb32_map
[ifbType
];
474 static void sdlInit(int soundOffFlag
) {
475 int flags
= SDL_INIT_VIDEO
|SDL_INIT_AUDIO
|
476 SDL_INIT_TIMER
|SDL_INIT_NOPARACHUTE
;
479 flags
^= SDL_INIT_AUDIO
;
481 if(SDL_Init(flags
)) {
482 systemMessage(0, "Failed to init SDL: %s", SDL_GetError());
486 if(SDL_InitSubSystem(SDL_INIT_JOYSTICK
)) {
487 systemMessage(0, "Failed to init joystick support: %s", SDL_GetError());
491 static void sdlToggleFullscreen(void) {
492 #if SDL_MAJOR_VERSION != 2
494 int flags
= surface
->flags
;
495 fullscreen
= !fullscreen
;
496 flags
^= SDL_FULLSCREEN
;
497 SDL_Surface
*old
, *new = SDL_SetVideoMode(surface
->w
, surface
->h
, surface
->format
->BitsPerPixel
, flags
);
500 SDL_FreeSurface(old
);
502 SDL_LockSurface(surface
);
503 SDL_WM_ToggleFullScreen(surface
);
504 fullscreen
= !fullscreen
;
505 SDL_UnlockSurface(surface
);
508 SDL_SetWindowFullscreen(win
, fullscreen
? 0 : SDL_WINDOW_FULLSCREEN
);
509 fullscreen
= !fullscreen
;
513 static void sdlSetTitle(const char* title
) {
514 #if SDL_MAJOR_VERSION != 2
515 SDL_WM_SetCaption(title
, NULL
);
517 SDL_SetWindowTitle(win
, title
);
521 static int sdlCalculateShift(u32 mask
);
522 static void sdlInitShift(SDL_PixelFormat
*format
) {
523 systemRedShift
= sdlCalculateShift(format
->Rmask
);
524 systemGreenShift
= sdlCalculateShift(format
->Gmask
);
525 systemBlueShift
= sdlCalculateShift(format
->Bmask
);
528 static void sdlInitVideo(void) {
529 #if SDL_MAJOR_VERSION != 2
530 surface
= SDL_SetVideoMode(destWidth
, destHeight
, 16,
531 SDL_ANYFORMAT
|SDL_HWSURFACE
|SDL_DOUBLEBUF
|
532 (fullscreen
? SDL_FULLSCREEN
: 0));
534 if(surface
== NULL
) {
535 systemMessage(0, "Failed to set video mode");
540 int flags
= SDL_WINDOW_OPENGL
;
541 if(fullscreen
) flags
|= SDL_WINDOW_FULLSCREEN
;
542 if (!(win
= SDL_CreateWindow("VBA", SDL_WINDOWPOS_UNDEFINED
,
543 SDL_WINDOWPOS_UNDEFINED
, destWidth
, destHeight
, flags
))) {
545 systemMessage(0, "SDL: video setup error: %s\n", SDL_GetError());
549 renderer
= SDL_CreateRenderer(win
, -1,
550 SDL_RENDERER_ACCELERATED
|SDL_RENDERER_PRESENTVSYNC
);
551 if(!renderer
) goto sdl_err
;
552 SDL_RenderSetScale(renderer
, sizeOption
+1, sizeOption
+1);
553 texture
= SDL_CreateTexture(renderer
, SDL_PIXELFORMAT_BGRA32
,
554 SDL_TEXTUREACCESS_STREAMING
, srcWidth
, srcHeight
);
555 format
= SDL_AllocFormat(SDL_PIXELFORMAT_BGRA32
);
559 #define SDL_CALL_STRETCHER \
560 sdlStretcher(src, dest)
562 static void sdlStretch16x1(u8
*src
, u8
*dest
)
564 memcpy(dest
, src
, srcWidth
*2);
567 static void sdlStretch16x2(u8
*src
, u8
*dest
)
570 u16
*d
= (u16
*)dest
;
571 for(int i
= 0; i
< srcWidth
; i
++) {
577 static void sdlStretch16x3(u8
*src
, u8
*dest
)
580 u16
*d
= (u16
*)dest
;
581 for(int i
= 0; i
< srcWidth
; i
++) {
588 static void sdlStretch16x4(u8
*src
, u8
*dest
)
591 u16
*d
= (u16
*)dest
;
592 for(int i
= 0; i
< srcWidth
; i
++) {
600 static void sdlStretch32x1(u8
*src
, u8
*dest
)
602 memcpy(dest
, src
, srcWidth
*4);
605 static void sdlStretch32x2(u8
*src
, u8
*dest
)
608 u32
*d
= (u32
*)dest
;
609 for(int i
= 0; i
< srcWidth
; i
++) {
615 static void sdlStretch32x3(u8
*src
, u8
*dest
)
618 u32
*d
= (u32
*)dest
;
619 for(int i
= 0; i
< srcWidth
; i
++) {
626 static void sdlStretch32x4(u8
*src
, u8
*dest
)
629 u32
*d
= (u32
*)dest
;
630 for(int i
= 0; i
< srcWidth
; i
++) {
638 static void sdlStretch24x1(u8
*src
, u8
*dest
)
640 memcpy(dest
, src
, srcWidth
*3);
643 static void sdlStretch24x2(u8
*src
, u8
*dest
)
647 for(int i
= 0; i
< srcWidth
; i
++) {
659 static void sdlStretch24x3(u8
*src
, u8
*dest
)
663 for(int i
= 0; i
< srcWidth
; i
++) {
679 static void sdlStretch24x4(u8
*src
, u8
*dest
)
683 for(int i
= 0; i
< srcWidth
; i
++) {
703 static void (*const stretcher_tab
[3][4])(u8
*, u8
*) = {
704 {sdlStretch16x1
, sdlStretch16x2
, sdlStretch16x3
, sdlStretch16x4
},
705 {sdlStretch24x1
, sdlStretch24x2
, sdlStretch24x3
, sdlStretch24x4
},
706 {sdlStretch32x1
, sdlStretch32x2
, sdlStretch32x3
, sdlStretch32x4
},
710 u32
sdlFromHex(char *s
)
713 sscanf(s
, "%x", &value
);
719 #define S_IFDIR _S_IFDIR
722 void sdlCheckDirectory(char *dir
)
726 int len
= strlen(dir
);
728 char *p
= dir
+ len
- 1;
734 if(stat(dir
, &buf
) == 0) {
735 if(!(buf
.st_mode
& S_IFDIR
)) {
736 fprintf(stderr
, "Error: %s is not a directory\n", dir
);
740 fprintf(stderr
, "Error: %s does not exist\n", dir
);
745 char *sdlGetFilename(char *name
)
747 static char filebuffer
[2048];
749 int len
= strlen(name
);
751 char *p
= name
+ len
- 1;
766 strcpy(filebuffer
, name
);
768 strcpy(filebuffer
, p
);
772 FILE *sdlFindFile(const char *name
)
779 #define FILE_SEP '\\'
780 #define EXE_NAME "VisualBoyAdvance-SDL.exe"
784 #define EXE_NAME "VisualBoyAdvance"
787 fprintf(stderr
, "Searching for file %s\n", name
);
789 if(GETCWD(buffer
, 2048)) {
790 fprintf(stderr
, "Searching current directory: %s\n", buffer
);
793 FILE *f
= fopen(name
, "r");
798 char *home
= getenv("HOME");
801 fprintf(stderr
, "Searching home directory: %s\n", home
);
802 sprintf(path
, "%s%c%s", home
, FILE_SEP
, name
);
803 f
= fopen(path
, "r");
809 home
= getenv("USERPROFILE");
811 fprintf(stderr
, "Searching user profile directory: %s\n", home
);
812 sprintf(path
, "%s%c%s", home
, FILE_SEP
, name
);
813 f
= fopen(path
, "r");
818 fprintf(stderr
, "Searching system config directory: %s\n", SYSCONFDIR
);
819 sprintf(path
, "%s%c%s", SYSCONFDIR
, FILE_SEP
, name
);
820 f
= fopen(path
, "r");
825 if(!strchr(arg0
, '/') &&
826 !strchr(arg0
, '\\')) {
827 char *path
= getenv("PATH");
830 fprintf(stderr
, "Searching PATH\n");
831 strncpy(buffer
, path
, 4096);
833 char *tok
= strtok(buffer
, PATH_SEP
);
836 sprintf(path
, "%s%c%s", tok
, FILE_SEP
, EXE_NAME
);
837 f
= fopen(path
, "r");
841 sprintf(path2
, "%s%c%s", tok
, FILE_SEP
, name
);
842 f
= fopen(path2
, "r");
844 fprintf(stderr
, "Found at %s\n", path2
);
848 tok
= strtok(NULL
, PATH_SEP
);
852 // executable is relative to some directory
853 fprintf(stderr
, "Searching executable directory\n");
854 strcpy(buffer
, arg0
);
855 char *p
= strrchr(buffer
, FILE_SEP
);
858 sprintf(path
, "%s%c%s", buffer
, FILE_SEP
, name
);
859 f
= fopen(path
, "r");
867 void sdlReadPreferencesF(FILE *f
)
872 char *s
= fgets(buffer
, 2048, f
);
877 char *p
= strchr(s
, '#');
882 char *token
= strtok(s
, " \t\n\r=");
887 if(strlen(token
) == 0)
891 char *value
= strtok(NULL
, "\t\n\r");
894 fprintf(stderr
, "Empty value for key %s\n", key
);
898 if(!strcmp(key
,"Joy0_Left")) {
899 joypad
[0][KEY_LEFT
] = sdlFromHex(value
);
900 } else if(!strcmp(key
, "Joy0_Right")) {
901 joypad
[0][KEY_RIGHT
] = sdlFromHex(value
);
902 } else if(!strcmp(key
, "Joy0_Up")) {
903 joypad
[0][KEY_UP
] = sdlFromHex(value
);
904 } else if(!strcmp(key
, "Joy0_Down")) {
905 joypad
[0][KEY_DOWN
] = sdlFromHex(value
);
906 } else if(!strcmp(key
, "Joy0_A")) {
907 joypad
[0][KEY_BUTTON_A
] = sdlFromHex(value
);
908 } else if(!strcmp(key
, "Joy0_B")) {
909 joypad
[0][KEY_BUTTON_B
] = sdlFromHex(value
);
910 } else if(!strcmp(key
, "Joy0_L")) {
911 joypad
[0][KEY_BUTTON_L
] = sdlFromHex(value
);
912 } else if(!strcmp(key
, "Joy0_R")) {
913 joypad
[0][KEY_BUTTON_R
] = sdlFromHex(value
);
914 } else if(!strcmp(key
, "Joy0_Start")) {
915 joypad
[0][KEY_BUTTON_START
] = sdlFromHex(value
);
916 } else if(!strcmp(key
, "Joy0_Select")) {
917 joypad
[0][KEY_BUTTON_SELECT
] = sdlFromHex(value
);
918 } else if(!strcmp(key
, "Joy0_Speed")) {
919 joypad
[0][KEY_BUTTON_SPEED
] = sdlFromHex(value
);
920 } else if(!strcmp(key
, "Joy0_Capture")) {
921 joypad
[0][KEY_BUTTON_CAPTURE
] = sdlFromHex(value
);
922 } else if(!strcmp(key
,"Joy1_Left")) {
923 joypad
[1][KEY_LEFT
] = sdlFromHex(value
);
924 } else if(!strcmp(key
, "Joy1_Right")) {
925 joypad
[1][KEY_RIGHT
] = sdlFromHex(value
);
926 } else if(!strcmp(key
, "Joy1_Up")) {
927 joypad
[1][KEY_UP
] = sdlFromHex(value
);
928 } else if(!strcmp(key
, "Joy1_Down")) {
929 joypad
[1][KEY_DOWN
] = sdlFromHex(value
);
930 } else if(!strcmp(key
, "Joy1_A")) {
931 joypad
[1][KEY_BUTTON_A
] = sdlFromHex(value
);
932 } else if(!strcmp(key
, "Joy1_B")) {
933 joypad
[1][KEY_BUTTON_B
] = sdlFromHex(value
);
934 } else if(!strcmp(key
, "Joy1_L")) {
935 joypad
[1][KEY_BUTTON_L
] = sdlFromHex(value
);
936 } else if(!strcmp(key
, "Joy1_R")) {
937 joypad
[1][KEY_BUTTON_R
] = sdlFromHex(value
);
938 } else if(!strcmp(key
, "Joy1_Start")) {
939 joypad
[1][KEY_BUTTON_START
] = sdlFromHex(value
);
940 } else if(!strcmp(key
, "Joy1_Select")) {
941 joypad
[1][KEY_BUTTON_SELECT
] = sdlFromHex(value
);
942 } else if(!strcmp(key
, "Joy1_Speed")) {
943 joypad
[1][KEY_BUTTON_SPEED
] = sdlFromHex(value
);
944 } else if(!strcmp(key
, "Joy1_Capture")) {
945 joypad
[1][KEY_BUTTON_CAPTURE
] = sdlFromHex(value
);
946 } else if(!strcmp(key
,"Joy2_Left")) {
947 joypad
[2][KEY_LEFT
] = sdlFromHex(value
);
948 } else if(!strcmp(key
, "Joy2_Right")) {
949 joypad
[2][KEY_RIGHT
] = sdlFromHex(value
);
950 } else if(!strcmp(key
, "Joy2_Up")) {
951 joypad
[2][KEY_UP
] = sdlFromHex(value
);
952 } else if(!strcmp(key
, "Joy2_Down")) {
953 joypad
[2][KEY_DOWN
] = sdlFromHex(value
);
954 } else if(!strcmp(key
, "Joy2_A")) {
955 joypad
[2][KEY_BUTTON_A
] = sdlFromHex(value
);
956 } else if(!strcmp(key
, "Joy2_B")) {
957 joypad
[2][KEY_BUTTON_B
] = sdlFromHex(value
);
958 } else if(!strcmp(key
, "Joy2_L")) {
959 joypad
[2][KEY_BUTTON_L
] = sdlFromHex(value
);
960 } else if(!strcmp(key
, "Joy2_R")) {
961 joypad
[2][KEY_BUTTON_R
] = sdlFromHex(value
);
962 } else if(!strcmp(key
, "Joy2_Start")) {
963 joypad
[2][KEY_BUTTON_START
] = sdlFromHex(value
);
964 } else if(!strcmp(key
, "Joy2_Select")) {
965 joypad
[2][KEY_BUTTON_SELECT
] = sdlFromHex(value
);
966 } else if(!strcmp(key
, "Joy2_Speed")) {
967 joypad
[2][KEY_BUTTON_SPEED
] = sdlFromHex(value
);
968 } else if(!strcmp(key
, "Joy2_Capture")) {
969 joypad
[2][KEY_BUTTON_CAPTURE
] = sdlFromHex(value
);
970 } else if(!strcmp(key
,"Joy4_Left")) {
971 joypad
[4][KEY_LEFT
] = sdlFromHex(value
);
972 } else if(!strcmp(key
, "Joy4_Right")) {
973 joypad
[4][KEY_RIGHT
] = sdlFromHex(value
);
974 } else if(!strcmp(key
, "Joy4_Up")) {
975 joypad
[4][KEY_UP
] = sdlFromHex(value
);
976 } else if(!strcmp(key
, "Joy4_Down")) {
977 joypad
[4][KEY_DOWN
] = sdlFromHex(value
);
978 } else if(!strcmp(key
, "Joy4_A")) {
979 joypad
[4][KEY_BUTTON_A
] = sdlFromHex(value
);
980 } else if(!strcmp(key
, "Joy4_B")) {
981 joypad
[4][KEY_BUTTON_B
] = sdlFromHex(value
);
982 } else if(!strcmp(key
, "Joy4_L")) {
983 joypad
[4][KEY_BUTTON_L
] = sdlFromHex(value
);
984 } else if(!strcmp(key
, "Joy4_R")) {
985 joypad
[4][KEY_BUTTON_R
] = sdlFromHex(value
);
986 } else if(!strcmp(key
, "Joy4_Start")) {
987 joypad
[4][KEY_BUTTON_START
] = sdlFromHex(value
);
988 } else if(!strcmp(key
, "Joy4_Select")) {
989 joypad
[4][KEY_BUTTON_SELECT
] = sdlFromHex(value
);
990 } else if(!strcmp(key
, "Joy4_Speed")) {
991 joypad
[4][KEY_BUTTON_SPEED
] = sdlFromHex(value
);
992 } else if(!strcmp(key
, "Joy4_Capture")) {
993 joypad
[4][KEY_BUTTON_CAPTURE
] = sdlFromHex(value
);
994 } else if(!strcmp(key
, "Motion_Left")) {
995 motion
[KEY_LEFT
] = sdlFromHex(value
);
996 } else if(!strcmp(key
, "Motion_Right")) {
997 motion
[KEY_RIGHT
] = sdlFromHex(value
);
998 } else if(!strcmp(key
, "Motion_Up")) {
999 motion
[KEY_UP
] = sdlFromHex(value
);
1000 } else if(!strcmp(key
, "Motion_Down")) {
1001 motion
[KEY_DOWN
] = sdlFromHex(value
);
1002 } else if(!strcmp(key
, "frameSkip")) {
1003 frameSkip
= sdlFromHex(value
);
1004 if(frameSkip
< 0 || frameSkip
> 9)
1006 } else if(!strcmp(key
, "gbFrameSkip")) {
1007 gbFrameSkip
= sdlFromHex(value
);
1008 if(gbFrameSkip
< 0 || gbFrameSkip
> 9)
1010 } else if(!strcmp(key
, "video")) {
1011 sizeOption
= sdlFromHex(value
);
1012 if(sizeOption
< 0 || sizeOption
> 3)
1014 } else if(!strcmp(key
, "fullScreen")) {
1015 fullscreen
= sdlFromHex(value
) ? 1 : 0;
1016 } else if(!strcmp(key
, "useBios")) {
1017 useBios
= sdlFromHex(value
) ? true : false;
1018 } else if(!strcmp(key
, "skipBios")) {
1019 skipBios
= sdlFromHex(value
) ? true : false;
1020 } else if(!strcmp(key
, "biosFile")) {
1021 strcpy(biosFileName
, value
);
1022 } else if(!strcmp(key
, "filter")) {
1023 filter
= sdlFromHex(value
);
1024 if(filter
< 0 || filter
> 13)
1026 } else if(!strcmp(key
, "disableStatus")) {
1027 disableStatusMessages
= sdlFromHex(value
) ? true : false;
1028 } else if(!strcmp(key
, "borderOn")) {
1029 gbBorderOn
= sdlFromHex(value
) ? true : false;
1030 } else if(!strcmp(key
, "borderAutomatic")) {
1031 gbBorderAutomatic
= sdlFromHex(value
) ? true : false;
1032 } else if(!strcmp(key
, "emulatorType")) {
1033 gbEmulatorType
= sdlFromHex(value
);
1034 if(gbEmulatorType
< 0 || gbEmulatorType
> 5)
1036 } else if(!strcmp(key
, "colorOption")) {
1037 gbColorOption
= sdlFromHex(value
) ? true : false;
1038 } else if(!strcmp(key
, "captureDir")) {
1039 sdlCheckDirectory(value
);
1040 strcpy(captureDir
, value
);
1041 } else if(!strcmp(key
, "saveDir")) {
1042 sdlCheckDirectory(value
);
1043 strcpy(saveDir
, value
);
1044 } else if(!strcmp(key
, "batteryDir")) {
1045 sdlCheckDirectory(value
);
1046 strcpy(batteryDir
, value
);
1047 } else if(!strcmp(key
, "captureFormat")) {
1048 captureFormat
= sdlFromHex(value
);
1049 } else if(!strcmp(key
, "soundQuality")) {
1050 soundQuality
= sdlFromHex(value
);
1051 switch(soundQuality
) {
1057 fprintf(stderr
, "Unknown sound quality %d. Defaulting to 22Khz\n",
1062 } else if(!strcmp(key
, "soundOff")) {
1063 soundOffFlag
= sdlFromHex(value
) ? true : false;
1064 } else if(!strcmp(key
, "soundEnable")) {
1065 int res
= sdlFromHex(value
) & 0x30f;
1068 } else if(!strcmp(key
, "soundEcho")) {
1069 soundEcho
= sdlFromHex(value
) ? true : false;
1070 } else if(!strcmp(key
, "soundLowPass")) {
1071 soundLowPass
= sdlFromHex(value
) ? true : false;
1072 } else if(!strcmp(key
, "soundReverse")) {
1073 soundReverse
= sdlFromHex(value
) ? true : false;
1074 } else if(!strcmp(key
, "soundVolume")) {
1075 soundVolume
= sdlFromHex(value
);
1076 if(soundVolume
< 0 || soundVolume
> 3)
1078 } else if(!strcmp(key
, "removeIntros")) {
1079 removeIntros
= sdlFromHex(value
) ? true : false;
1080 } else if(!strcmp(key
, "saveType")) {
1081 cpuSaveType
= sdlFromHex(value
);
1082 if(cpuSaveType
< 0 || cpuSaveType
> 5)
1084 } else if(!strcmp(key
, "flashSize")) {
1085 sdlFlashSize
= sdlFromHex(value
);
1086 if(sdlFlashSize
!= 0 && sdlFlashSize
!= 1)
1088 } else if(!strcmp(key
, "ifbType")) {
1089 ifbType
= sdlFromHex(value
);
1090 if(ifbType
< 0 || ifbType
> 2)
1092 } else if(!strcmp(key
, "showSpeed")) {
1093 showSpeed
= sdlFromHex(value
);
1094 if(showSpeed
< 0 || showSpeed
> 2)
1096 } else if(!strcmp(key
, "showSpeedTransparent")) {
1097 showSpeedTransparent
= sdlFromHex(value
);
1098 } else if(!strcmp(key
, "autoFrameSkip")) {
1099 autoFrameSkip
= sdlFromHex(value
);
1100 } else if(!strcmp(key
, "throttle")) {
1101 throttle
= sdlFromHex(value
);
1102 if(throttle
!= 0 && (throttle
< 5 || throttle
> 1000))
1104 } else if(!strcmp(key
, "disableMMX")) {
1106 cpu_mmx
= sdlFromHex(value
) ? false : true;
1108 } else if(!strcmp(key
, "pauseWhenInactive")) {
1109 pauseWhenInactive
= sdlFromHex(value
) ? true : false;
1110 } else if(!strcmp(key
, "agbPrint")) {
1111 sdlAgbPrint
= sdlFromHex(value
);
1112 } else if(!strcmp(key
, "rtcEnabled")) {
1113 sdlRtcEnable
= sdlFromHex(value
);
1114 } else if(!strcmp(key
, "rewindTimer")) {
1115 rewindTimer
= sdlFromHex(value
);
1116 if(rewindTimer
< 0 || rewindTimer
> 600)
1118 rewindTimer
*= 6; // convert value to 10 frames multiple
1120 fprintf(stderr
, "Unknown configuration key %s\n", key
);
1125 void sdlReadPreferences()
1127 FILE *f
= sdlFindFile("VisualBoyAdvance.cfg");
1130 fprintf(stderr
, "Configuration file NOT FOUND (using defaults)\n");
1133 fprintf(stderr
, "Reading configuration file.\n");
1135 sdlReadPreferencesF(f
);
1140 static void sdlApplyPerImagePreferences()
1142 FILE *f
= sdlFindFile("vba-over.ini");
1144 fprintf(stderr
, "vba-over.ini NOT FOUND (using emulator settings)\n");
1147 fprintf(stderr
, "Reading vba-over.ini\n");
1151 buffer
[1] = rom
[0xac];
1152 buffer
[2] = rom
[0xad];
1153 buffer
[3] = rom
[0xae];
1154 buffer
[4] = rom
[0xaf];
1158 char readBuffer
[2048];
1163 char *s
= fgets(readBuffer
, 2048, f
);
1168 char *p
= strchr(s
, ';');
1173 char *token
= strtok(s
, " \t\n\r=");
1177 if(strlen(token
) == 0)
1180 if(!strcmp(token
, buffer
)) {
1188 char *s
= fgets(readBuffer
, 2048, f
);
1193 char *p
= strchr(s
, ';');
1197 char *token
= strtok(s
, " \t\n\r=");
1200 if(strlen(token
) == 0)
1203 if(token
[0] == '[') // starting another image settings
1205 char *value
= strtok(NULL
, "\t\n\r=");
1209 if(!strcmp(token
, "rtcEnabled"))
1210 rtcEnable(atoi(value
) == 0 ? false : true);
1211 else if(!strcmp(token
, "flashSize")) {
1212 int size
= atoi(value
);
1213 if(size
== 0x10000 || size
== 0x20000)
1215 } else if(!strcmp(token
, "saveType")) {
1216 int save
= atoi(value
);
1217 if(save
>= 0 && save
<= 5)
1219 } else if(!strcmp(token
, "mirroringEnabled")) {
1220 mirroringEnable
= (atoi(value
) == 0 ? false : true);
1227 static int sdlCalculateShift(u32 mask
)
1239 void sdlWriteState(int num
)
1241 char stateName
[2048];
1244 sprintf(stateName
, "%s/%s%d.sgm", saveDir
, sdlGetFilename(filename
),
1247 sprintf(stateName
,"%s%d.sgm", filename
, num
+1);
1249 if(emulator
.emuWriteState
)
1250 emulator
.emuWriteState(stateName
);
1252 sprintf(stateName
, "Wrote state %d", num
+1);
1253 systemScreenMessage(stateName
);
1258 void sdlReadState(int num
)
1260 char stateName
[2048];
1263 sprintf(stateName
, "%s/%s%d.sgm", saveDir
, sdlGetFilename(filename
),
1266 sprintf(stateName
,"%s%d.sgm", filename
, num
+1);
1268 if(emulator
.emuReadState
)
1269 emulator
.emuReadState(stateName
);
1271 sprintf(stateName
, "Loaded state %d", num
+1);
1272 systemScreenMessage(stateName
);
1277 void sdlWriteBattery()
1282 sprintf(buffer
, "%s/%s.sav", batteryDir
, sdlGetFilename(filename
));
1284 sprintf(buffer
, "%s.sav", filename
);
1286 emulator
.emuWriteBattery(buffer
);
1288 systemScreenMessage("Wrote battery");
1291 void sdlReadBattery()
1296 sprintf(buffer
, "%s/%s.sav", batteryDir
, sdlGetFilename(filename
));
1298 sprintf(buffer
, "%s.sav", filename
);
1302 res
= emulator
.emuReadBattery(buffer
);
1305 systemScreenMessage("Loaded battery");
1308 #define MOD_KEYS (KMOD_CTRL|KMOD_SHIFT|KMOD_ALT|KMOD_META)
1309 #define MOD_NOCTRL (KMOD_SHIFT|KMOD_ALT|KMOD_META)
1310 #define MOD_NOALT (KMOD_CTRL|KMOD_SHIFT|KMOD_META)
1311 #define MOD_NOSHIFT (KMOD_CTRL|KMOD_ALT|KMOD_META)
1313 void sdlUpdateKey(int key
, bool down
)
1316 for(int j
= 0; j
< 4; j
++) {
1317 for(i
= 0 ; i
< 12; i
++) {
1318 if((joypad
[j
][i
] & 0xf000) == 0) {
1319 if(key
== joypad
[j
][i
])
1320 sdlButtons
[j
][i
] = down
;
1324 for(i
= 0 ; i
< 4; i
++) {
1325 if((motion
[i
] & 0xf000) == 0) {
1326 if(key
== motion
[i
])
1327 sdlMotionButtons
[i
] = down
;
1332 void sdlUpdateJoyButton(int which
,
1337 for(int j
= 0; j
< 4; j
++) {
1338 for(i
= 0; i
< 12; i
++) {
1339 int dev
= (joypad
[j
][i
] >> 12);
1340 int b
= joypad
[j
][i
] & 0xfff;
1344 if((dev
== which
) && (b
>= 128) && (b
== (button
+128))) {
1345 sdlButtons
[j
][i
] = pressed
;
1350 for(i
= 0; i
< 4; i
++) {
1351 int dev
= (motion
[i
] >> 12);
1352 int b
= motion
[i
] & 0xfff;
1356 if((dev
== which
) && (b
>= 128) && (b
== (button
+128))) {
1357 sdlMotionButtons
[i
] = pressed
;
1363 void sdlUpdateJoyHat(int which
,
1368 for(int j
= 0; j
< 4; j
++) {
1369 for(i
= 0; i
< 12; i
++) {
1370 int dev
= (joypad
[j
][i
] >> 12);
1371 int a
= joypad
[j
][i
] & 0xfff;
1375 if((dev
== which
) && (a
>=32) && (a
< 48) && (((a
&15)>>2) == hat
)) {
1380 v
= value
& SDL_HAT_UP
;
1383 v
= value
& SDL_HAT_DOWN
;
1386 v
= value
& SDL_HAT_RIGHT
;
1389 v
= value
& SDL_HAT_LEFT
;
1392 sdlButtons
[j
][i
] = (v
? true : false);
1397 for(i
= 0; i
< 4; i
++) {
1398 int dev
= (motion
[i
] >> 12);
1399 int a
= motion
[i
] & 0xfff;
1403 if((dev
== which
) && (a
>=32) && (a
< 48) && (((a
&15)>>2) == hat
)) {
1408 v
= value
& SDL_HAT_UP
;
1411 v
= value
& SDL_HAT_DOWN
;
1414 v
= value
& SDL_HAT_RIGHT
;
1417 v
= value
& SDL_HAT_LEFT
;
1420 sdlMotionButtons
[i
] = (v
? true : false);
1426 void sdlUpdateJoyAxis(int which
,
1431 for(int j
= 0; j
< 4; j
++) {
1432 for(i
= 0; i
< 12; i
++) {
1433 int dev
= (joypad
[j
][i
] >> 12);
1434 int a
= joypad
[j
][i
] & 0xfff;
1438 if((dev
== which
) && (a
< 32) && ((a
>>1) == axis
)) {
1439 sdlButtons
[j
][i
] = (a
& 1) ? (value
> 16384) : (value
< -16384);
1444 for(i
= 0; i
< 4; i
++) {
1445 int dev
= (motion
[i
] >> 12);
1446 int a
= motion
[i
] & 0xfff;
1450 if((dev
== which
) && (a
< 32) && ((a
>>1) == axis
)) {
1451 sdlMotionButtons
[i
] = (a
& 1) ? (value
> 16384) : (value
< -16384);
1457 bool sdlCheckJoyKey(int key
)
1459 int dev
= (key
>> 12) - 1;
1460 int what
= key
& 0xfff;
1464 int button
= what
- 128;
1466 if(button
>= SDL_JoystickNumButtons(sdlDevices
[dev
]))
1468 } else if (what
< 0x20) {
1471 if(what
>= SDL_JoystickNumAxes(sdlDevices
[dev
]))
1473 } else if (what
< 0x30) {
1477 if(what
>= SDL_JoystickNumHats(sdlDevices
[dev
]))
1487 sdlNumDevices
= SDL_NumJoysticks();
1490 sdlDevices
= (SDL_Joystick
**)calloc(1,sdlNumDevices
*
1491 sizeof(SDL_Joystick
**));
1494 bool usesJoy
= false;
1496 for(int j
= 0; j
< 4; j
++) {
1497 for(i
= 0; i
< 12; i
++) {
1498 int dev
= joypad
[j
][i
] >> 12;
1504 if(dev
< sdlNumDevices
) {
1505 if(sdlDevices
[dev
] == NULL
) {
1506 sdlDevices
[dev
] = SDL_JoystickOpen(dev
);
1509 ok
= sdlCheckJoyKey(joypad
[j
][i
]);
1515 joypad
[j
][i
] = defaultJoypad
[i
];
1522 for(i
= 0; i
< 4; i
++) {
1523 int dev
= motion
[i
] >> 12;
1529 if(dev
< sdlNumDevices
) {
1530 if(sdlDevices
[dev
] == NULL
) {
1531 sdlDevices
[dev
] = SDL_JoystickOpen(dev
);
1534 ok
= sdlCheckJoyKey(motion
[i
]);
1540 motion
[i
] = defaultMotion
[i
];
1547 SDL_JoystickEventState(SDL_ENABLE
);
1550 void sdlPollEvents()
1553 while(SDL_PollEvent(&event
)) {
1554 switch(event
.type
) {
1558 #if SDL_MAJOR_VERSION == 2
1559 case SDL_WINDOWEVENT
:
1560 if(pauseWhenInactive
&&
1561 ((event
.window
.event
== SDL_WINDOWEVENT_FOCUS_GAINED
) ||
1562 (event
.window
.event
== SDL_WINDOWEVENT_FOCUS_LOST
))) {
1563 active
= event
.window
.event
== SDL_WINDOWEVENT_FOCUS_GAINED
;
1565 case SDL_ACTIVEEVENT
:
1566 if(pauseWhenInactive
&& (event
.active
.state
& SDL_APPINPUTFOCUS
)) {
1567 active
= event
.active
.gain
;
1576 if(pauseWhenInactive
) {
1581 memset(delta
,255,sizeof(delta
));
1585 case SDL_MOUSEMOTION
:
1586 case SDL_MOUSEBUTTONUP
:
1587 case SDL_MOUSEBUTTONDOWN
:
1589 SDL_ShowCursor(SDL_ENABLE
);
1593 case SDL_JOYHATMOTION
:
1594 sdlUpdateJoyHat(event
.jhat
.which
,
1598 case SDL_JOYBUTTONDOWN
:
1599 case SDL_JOYBUTTONUP
:
1600 sdlUpdateJoyButton(event
.jbutton
.which
,
1601 event
.jbutton
.button
,
1602 event
.jbutton
.state
== SDL_PRESSED
);
1604 case SDL_JOYAXISMOTION
:
1605 sdlUpdateJoyAxis(event
.jaxis
.which
,
1610 sdlUpdateKey(event
.key
.keysym
.sym
, true);
1613 switch(event
.key
.keysym
.sym
) {
1615 if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1616 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1618 emulator
.emuReset();
1620 systemScreenMessage("Reset");
1625 if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1626 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1627 if(emulating
&& emulator
.emuReadMemState
&& rewindMemory
1629 rewindPos
= (rewindPos
- 1) & 7;
1630 emulator
.emuReadMemState(&rewindMemory
[REWIND_SIZE
*rewindPos
],
1634 systemScreenMessage("Rewind");
1639 if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1640 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1642 SDL_PauseAudio(paused
);
1651 if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1652 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1653 sdlToggleFullscreen();
1657 if(dbgMain
!= debuggerMain
) {
1678 if(!(event
.key
.keysym
.mod
& MOD_NOSHIFT
) &&
1679 (event
.key
.keysym
.mod
& KMOD_SHIFT
)) {
1680 sdlWriteState(event
.key
.keysym
.sym
-SDLK_F1
);
1681 } else if(!(event
.key
.keysym
.mod
& MOD_KEYS
)) {
1682 sdlReadState(event
.key
.keysym
.sym
-SDLK_F1
);
1689 if(!(event
.key
.keysym
.mod
& MOD_NOALT
) &&
1690 (event
.key
.keysym
.mod
& KMOD_ALT
)) {
1691 char *disableMessages
[4] =
1692 { "autofire A disabled",
1693 "autofire B disabled",
1694 "autofire R disabled",
1695 "autofire L disabled"};
1696 char *enableMessages
[4] =
1701 int mask
= 1 << (event
.key
.keysym
.sym
- SDLK_1
);
1702 if(event
.key
.keysym
.sym
> SDLK_2
)
1704 if(autoFire
& mask
) {
1706 systemScreenMessage(disableMessages
[event
.key
.keysym
.sym
- SDLK_1
]);
1709 systemScreenMessage(enableMessages
[event
.key
.keysym
.sym
- SDLK_1
]);
1711 } if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1712 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1713 int mask
= 0x0100 << (event
.key
.keysym
.sym
- SDLK_1
);
1714 layerSettings
^= mask
;
1715 layerEnable
= DISPCNT
& layerSettings
;
1716 CPUUpdateRenderBuffers(false);
1723 if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1724 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1725 int mask
= 0x0100 << (event
.key
.keysym
.sym
- SDLK_1
);
1726 layerSettings
^= mask
;
1727 layerEnable
= DISPCNT
& layerSettings
;
1731 if(!(event
.key
.keysym
.mod
& MOD_NOCTRL
) &&
1732 (event
.key
.keysym
.mod
& KMOD_CTRL
)) {
1735 pauseNextFrame
= true;
1741 sdlUpdateKey(event
.key
.keysym
.sym
, false);
1747 void usage(char *cmd
)
1749 printf("%s [option ...] file\n", cmd
);
1753 -1, --video-1x 1x\n\
1754 -2, --video-2x 2x\n\
1755 -3, --video-3x 3x\n\
1756 -4, --video-4x 4x\n\
1757 -F, --fullscreen Full screen\n\
1758 -G, --gdb=PROTOCOL GNU Remote Stub mode:\n\
1759 tcp - use TCP at port 55555\n\
1760 tcp:PORT - use TCP at port PORT\n\
1761 pipe - use pipe transport\n\
1762 -N, --no-debug Don't parse debug information\n\
1763 -S, --flash-size=SIZE Set the Flash size\n\
1764 --flash-64k 0 - 64K Flash\n\
1765 --flash-128k 1 - 128K Flash\n\
1766 -T, --throttle=THROTTLE Set the desired throttle (5...1000)\n\
1767 -b, --bios=BIOS Use given bios file\n\
1768 -c, --config=FILE Read the given configuration file\n\
1769 -d, --debug Enter debugger\n\
1770 -h, --help Print this help\n\
1771 -i, --ips=PATCH Apply given IPS patch\n\
1772 -p, --profile=[HERTZ] Enable profiling\n\
1773 -s, --frameskip=FRAMESKIP Set frame skip (0...9)\n\
1775 #if FILTERS_ENABLED+0 != 0
1777 -f, --filter=FILTER Select filter:\n\
1778 --filter-normal 0 - normal mode\n\
1779 --filter-tv-mode 1 - TV Mode\n\
1780 --filter-2xsai 2 - 2xSaI\n\
1781 --filter-super-2xsai 3 - Super 2xSaI\n\
1782 --filter-super-eagle 4 - Super Eagle\n\
1783 --filter-pixelate 5 - Pixelate\n\
1784 --filter-motion-blur 6 - Motion Blur\n\
1785 --filter-advmame 7 - AdvanceMAME Scale2x\n\
1786 --filter-simple2x 8 - Simple2x\n\
1787 --filter-bilinear 9 - Bilinear\n\
1788 --filter-bilinear+ 10 - Bilinear Plus\n\
1789 --filter-scanlines 11 - Scanlines\n\
1790 --filter-hq2x 12 - hq2x\n\
1791 --filter-lq2x 13 - lq2x\n\
1794 #if SDL_MAJOR_VERSION != 2
1796 -Y, --yuv=TYPE Use YUV overlay for drawing:\n\
1806 -t, --save-type=TYPE Set the available save type\n\
1807 --save-auto 0 - Automatic (EEPROM, SRAM, FLASH)\n\
1808 --save-eeprom 1 - EEPROM\n\
1809 --save-sram 2 - SRAM\n\
1810 --save-flash 3 - FLASH\n\
1811 --save-sensor 4 - EEPROM+Sensor\n\
1812 --save-none 5 - NONE\n\
1813 -v, --verbose=VERBOSE Set verbose logging (trace.log)\n\
1815 2 - Unaligned memory access\n\
1816 4 - Illegal memory write\n\
1817 8 - Illegal memory read\n\
1822 256 - Undefined instruction\n\
1823 512 - AGBPrint messages\n\
1825 Long options only:\n\
1826 --agb-print Enable AGBPrint support\n\
1827 --auto-frameskip Enable auto frameskipping\n\
1828 --no-agb-print Disable AGBPrint support\n\
1829 --no-auto-frameskip Disable auto frameskipping\n\
1830 --no-ips Do not apply IPS patch\n\
1831 --no-mmx Disable MMX support\n\
1832 --no-pause-when-inactive Don't pause when inactive\n\
1833 --no-rtc Disable RTC support\n\
1834 --no-show-speed Don't show emulation speed\n\
1835 --no-throttle Disable throttle\n\
1836 --pause-when-inactive Pause when inactive\n\
1837 --rtc Enable RTC support\n\
1838 --show-speed-normal Show emulation speed\n\
1839 --show-speed-detailed Show detailed speed data\n\
1841 #if IFB_ENABLED+0 != 0
1843 --ifb-none No interframe blending\n\
1844 --ifb-motion-blur Interframe motion blur\n\
1845 --ifb-smart Smart interframe blending\n\
1851 int main(int argc
, char **argv
)
1853 fprintf(stderr
, "VisualBoyAdvance version %s [SDL]\n", VERSION
);
1869 sdlReadPreferences();
1873 while((op
= getopt_long(argc
,
1875 "FNT:Y:G:D:b:c:df:hi:p::s:t:v:1234",
1880 // long option already processed by getopt_long
1884 if(optarg
== NULL
) {
1885 fprintf(stderr
, "Missing BIOS file name\n");
1888 strcpy(biosFileName
, optarg
);
1892 if(optarg
== NULL
) {
1893 fprintf(stderr
, "Missing config file name\n");
1896 FILE *f
= fopen(optarg
, "r");
1898 fprintf(stderr
, "File not found %s\n", optarg
);
1901 sdlReadPreferences(f
);
1912 if(optarg
== NULL
) {
1913 fprintf(stderr
, "Missing IPS name\n");
1915 strcpy(ipsname
, optarg
);
1918 #if SDL_MAJOR_VERSION != 2
1922 yuvType
= atoi(optarg
);
1925 yuvType
= SDL_YV12_OVERLAY
;
1928 yuvType
= SDL_UYVY_OVERLAY
;
1931 yuvType
= SDL_YVYU_OVERLAY
;
1934 yuvType
= SDL_YUY2_OVERLAY
;
1937 yuvType
= SDL_IYUV_OVERLAY
;
1940 yuvType
= SDL_YV12_OVERLAY
;
1943 yuvType
= SDL_YV12_OVERLAY
;
1947 dbgMain
= remoteStubMain
;
1948 dbgSignal
= remoteStubSignal
;
1949 dbgOutput
= remoteOutput
;
1951 debuggerStub
= true;
1954 if(strncmp(s
,"tcp:", 4) == 0) {
1957 remoteSetProtocol(0);
1958 remoteSetPort(port
);
1959 } else if(strcmp(s
,"tcp") == 0) {
1960 remoteSetProtocol(0);
1961 } else if(strcmp(s
, "pipe") == 0) {
1962 remoteSetProtocol(1);
1964 fprintf(stderr
, "Unknown protocol %s\n", s
);
1968 remoteSetProtocol(0);
1976 systemDebug
= atoi(optarg
);
1987 filter
= atoi(optarg
);
1995 cpuEnableProfiling(atoi(optarg
));
1997 cpuEnableProfiling(100);
2001 sdlFlashSize
= atoi(optarg
);
2002 if(sdlFlashSize
< 0 || sdlFlashSize
> 1)
2007 int a
= atoi(optarg
);
2008 if(a
>= 0 && a
<= 9) {
2019 int a
= atoi(optarg
);
2027 int t
= atoi(optarg
);
2028 if(t
< 5 || t
> 1000)
2035 systemVerbose
= atoi(optarg
);
2068 rewindMemory
= (char *)malloc(8*REWIND_SIZE
);
2070 if(sdlFlashSize
== 0)
2071 flashSetSize(0x10000);
2073 flashSetSize(0x20000);
2075 rtcEnable(sdlRtcEnable
? true : false);
2076 agbPrintEnable(sdlAgbPrint
? true : false);
2079 if(optind
>= argc
) {
2080 systemMessage(0,"Missing image name");
2090 for(int i
= 0; i
< 24;) {
2091 systemGbPalette
[i
++] = (0x1f) | (0x1f << 5) | (0x1f << 10);
2092 systemGbPalette
[i
++] = (0x15) | (0x15 << 5) | (0x15 << 10);
2093 systemGbPalette
[i
++] = (0x0c) | (0x0c << 5) | (0x0c << 10);
2094 systemGbPalette
[i
++] = 0;
2097 systemSaveUpdateCounter
= SYSTEM_SAVE_NOT_UPDATED
;
2100 char *szFile
= argv
[optind
];
2101 u32 len
= strlen(szFile
);
2102 if (len
> SYSMSG_BUFFER_SIZE
)
2104 fprintf(stderr
,"%s :%s: File name too long\n",argv
[0],szFile
);
2108 utilGetBaseName(szFile
, filename
);
2109 char *p
= strrchr(filename
, '.');
2115 sprintf(ipsname
, "%s.ips", filename
);
2117 bool failed
= false;
2119 IMAGE_TYPE type
= utilFindType(szFile
);
2121 if(type
== IMAGE_UNKNOWN
) {
2122 systemMessage(0, "Unknown file type %s", szFile
);
2125 cartridgeType
= (int)type
;
2127 if(type
== IMAGE_GB
) {
2128 failed
= !gbLoadRom(szFile
);
2130 gbGetHardwareType();
2132 // used for the handling of the gb Boot Rom
2135 char tempName
[0x800];
2136 strcpy(tempName
, arg0
);
2137 char *p
= strrchr(tempName
, '\\');
2138 if(p
) { *p
= 0x00; }
2139 strcat(tempName
, "\\DMG_ROM.bin");
2140 fprintf(stderr
, "%s\n", tempName
);
2141 gbCPUInit(tempName
, useBios
);
2143 else useBios
= false;
2146 cartridgeType
= IMAGE_GB
;
2147 emulator
= GBSystem
;
2149 int size
= gbRomSize
;
2150 utilApplyIPS(ipsname
, &gbRom
, &size
);
2151 if(size
!= gbRomSize
) {
2152 extern bool gbUpdateSizes();
2158 } else if(type
== IMAGE_GBA
) {
2159 int size
= CPULoadRom(szFile
);
2160 failed
= (size
== 0);
2162 sdlApplyPerImagePreferences();
2164 doMirroring(mirroringEnable
);
2167 emulator
= GBASystem
;
2169 /* disabled due to problems
2170 if(removeIntros && rom != NULL) {
2171 WRITE32LE(&rom[0], 0xea00002e);
2175 CPUInit(biosFileName
, useBios
);
2178 int size
= 0x2000000;
2179 utilApplyIPS(ipsname
, &rom
, &size
);
2180 if(size
!= 0x2000000) {
2188 systemMessage(0, "Failed to load file %s", szFile
);
2193 strcpy(filename
, "gnu_stub");
2194 rom
= (u8
*)malloc(0x2000000);
2195 workRAM
= (u8
*)calloc(1, 0x40000);
2196 bios
= (u8
*)calloc(1,0x4000);
2197 internalRAM
= (u8
*)calloc(1,0x8000);
2198 paletteRAM
= (u8
*)calloc(1,0x400);
2199 vram
= (u8
*)calloc(1, 0x20000);
2200 oam
= (u8
*)calloc(1, 0x400);
2201 pix
= (u8
*)calloc(1, 4 * 241 * 162);
2202 ioMem
= (u8
*)calloc(1, 0x400);
2204 emulator
= GBASystem
;
2206 CPUInit(biosFileName
, useBios
);
2215 sdlInit(soundOffFlag
);
2219 if(cartridgeType
== 0) {
2222 systemFrameSkip
= frameSkip
;
2223 } else if (cartridgeType
== 1) {
2227 gbBorderLineSkip
= 256;
2228 gbBorderColumnSkip
= 48;
2229 gbBorderRowSkip
= 40;
2233 gbBorderLineSkip
= 160;
2234 gbBorderColumnSkip
= 0;
2235 gbBorderRowSkip
= 0;
2237 systemFrameSkip
= gbFrameSkip
;
2243 destWidth
= (sizeOption
+1)*srcWidth
;
2244 destHeight
= (sizeOption
+1)*srcHeight
;
2248 sdlInitShift(VPFORMAT
);
2250 systemColorDepth
= VPFORMAT
->BitsPerPixel
;
2252 #if SDL_MAJOR_VERSION != 2
2254 Init_Overlay(surface
, yuvType
);
2255 systemColorDepth
= 32;
2257 systemGreenShift
= 11;
2258 systemBlueShift
= 19;
2262 static const unsigned char supported_depths
[] = {15,16,24,32,0};
2264 for(i
=j
=0; supported_depths
[i
]; ++i
)
2265 if(systemColorDepth
== supported_depths
[i
]) j
= 1;
2268 fprintf(stderr
,"Unsupported color depth '%d'.\nOnly 16, 24 and 32 bit color depths are supported\n", systemColorDepth
);
2272 static const int lowbittab
[] = {0x421, 0x821, 0x010101, 0x010101};
2273 RGB_LOW_BITS_MASK
= lowbittab
[(systemColorDepth
/8)-1];
2275 if(systemColorDepth
== 15)
2276 systemColorDepth
= 16;
2278 sdlStretcher
= stretcher_tab
[(systemColorDepth
/8)-2][VSCALE
-1];
2280 fprintf(stderr
,"Color depth: %d\n", systemColorDepth
);
2282 srcPitch
= srcWidth
* (systemColorDepth
/8) + (systemColorDepth
== 24 ? 0 : 4);
2283 if(systemColorDepth
== 24) filterFunction
= NULL
;
2284 sdlInitSAI2x(systemColorDepth
, VPFORMAT
);
2286 utilUpdateSystemColorMaps();
2292 delta
= (u8
*)malloc(322*242*4);
2293 memset(delta
, 255, 322*242*4);
2302 autoFrameSkipLastTime
= throttleLastTime
= systemGetClock();
2304 sdlSetTitle("VisualBoyAdvance");
2307 if(!paused
&& active
) {
2308 if(debugger
&& emulator
.emuHasDebugger
)
2311 emulator
.emuMain(emulator
.emuCount
);
2312 if(rewindSaveNeeded
&& rewindMemory
&& emulator
.emuWriteMemState
) {
2316 if(emulator
.emuWriteMemState
&&
2317 emulator
.emuWriteMemState(&rewindMemory
[rewindPos
*REWIND_SIZE
],
2319 rewindPos
= (rewindPos
+ 1) & 7;
2320 if(rewindCount
== 8)
2321 rewindTopPos
= (rewindTopPos
+ 1) & 7;
2325 rewindSaveNeeded
= false;
2333 if(mouseCounter
== 0)
2334 SDL_ShowCursor(SDL_DISABLE
);
2338 fprintf(stderr
,"Shutting down\n");
2339 if(fullscreen
) sdlToggleFullscreen();
2343 if(gbRom
!= NULL
|| rom
!= NULL
) {
2345 emulator
.emuCleanUp();
2357 void systemMessage(int num
, const char *msg
, ...)
2359 char buffer
[SYSMSG_BUFFER_SIZE
*2];
2362 va_start(valist
, msg
);
2363 vsprintf(buffer
, msg
, valist
);
2365 fprintf(stderr
, "%s\n", buffer
);
2369 void systemDrawScreen()
2373 if(do_yuv()) return;
2375 #if SDL_MAJOR_VERSION == 2
2376 int pitch
; void *pixels
;
2377 SDL_LockTexture(texture
, NULL
, &pixels
, &pitch
);
2379 SDL_LockSurface(surface
);
2383 if(cartridgeType
== 1 && gbBorderOn
) {
2384 gbSgbRenderBorder();
2386 if(((systemGetClock() - screenMessageTime
) < 3000) &&
2387 !disableStatusMessages
) {
2388 drawText(pix
, srcPitch
, 10, srcHeight
- 20,
2389 screenMessageBuffer
);
2391 screenMessage
= false;
2396 if(systemColorDepth
== 16)
2397 ifbFunction(pix
+destWidth
+4, destWidth
+4, srcWidth
, srcHeight
);
2399 ifbFunction(pix
+destWidth
*2+4, destWidth
*2+4, srcWidth
, srcHeight
);
2402 if(filterFunction
) {
2403 if(systemColorDepth
== 16)
2404 filterFunction(pix
+destWidth
+4,destWidth
+4, delta
,
2405 (u8
*)VPIXELS
, VPITCH
,
2409 filterFunction(pix
+destWidth
*2+4,
2417 int destPitch
= VPITCH
;
2419 u8
*dest
= (u8
*)VPIXELS
;
2421 u32
*stretcher
= (u32
*)sdlStretcher
;
2422 if(systemColorDepth
== 16)
2424 int option
= sizeOption
;
2425 #if SDL_MAJOR_VERSION != 2
2426 /* FIXME: the function begin exits early if yuv is set. why is this here ? */
2432 for(i
= 0; i
< srcHeight
; i
++) {
2439 for(i
= 0; i
< srcHeight
; i
++) {
2448 for(i
= 0; i
< srcHeight
; i
++) {
2459 for(i
= 0; i
< srcHeight
; i
++) {
2474 if(showSpeed
&& fullscreen
) {
2477 sprintf(buffer
, "%d%%", systemSpeed
);
2479 sprintf(buffer
, "%3d%%(%d, %d fps)", systemSpeed
,
2481 showRenderedFrames
);
2482 if(showSpeedTransparent
)
2483 drawTextTransp((u8
*)VPIXELS
,
2489 drawText((u8
*)VPIXELS
,
2496 #if SDL_MAJOR_VERSION == 2
2497 SDL_UnlockTexture(texture
);
2498 SDL_RenderCopy(renderer
, texture
, NULL
, NULL
);
2499 SDL_RenderPresent(renderer
);
2501 SDL_UnlockSurface(surface
);
2502 // SDL_UpdateRect(surface, 0, 0, destWidth, destHeight);
2507 bool systemReadJoypads()
2512 u32
systemReadJoypad(int which
)
2514 if(which
< 0 || which
> 3)
2515 which
= sdlDefaultJoypad
;
2519 if(sdlButtons
[which
][KEY_BUTTON_A
])
2521 if(sdlButtons
[which
][KEY_BUTTON_B
])
2523 if(sdlButtons
[which
][KEY_BUTTON_SELECT
])
2525 if(sdlButtons
[which
][KEY_BUTTON_START
])
2527 if(sdlButtons
[which
][KEY_RIGHT
])
2529 if(sdlButtons
[which
][KEY_LEFT
])
2531 if(sdlButtons
[which
][KEY_UP
])
2533 if(sdlButtons
[which
][KEY_DOWN
])
2535 if(sdlButtons
[which
][KEY_BUTTON_R
])
2537 if(sdlButtons
[which
][KEY_BUTTON_L
])
2540 // disallow L+R or U+D of being pressed at the same time
2541 if((res
& 48) == 48)
2543 if((res
& 192) == 192)
2546 if(sdlButtons
[which
][KEY_BUTTON_SPEED
])
2548 if(sdlButtons
[which
][KEY_BUTTON_CAPTURE
])
2555 autoFireToggle
= !autoFireToggle
;
2561 void systemSetTitle(const char *title
) {
2565 void systemShowSpeed(int speed
)
2567 systemSpeed
= speed
;
2569 showRenderedFrames
= renderedFrames
;
2572 if(!fullscreen
&& showSpeed
) {
2575 sprintf(buffer
, "VisualBoyAdvance-%3d%%", systemSpeed
);
2577 sprintf(buffer
, "VisualBoyAdvance-%3d%%(%d, %d fps)", systemSpeed
,
2579 showRenderedFrames
);
2581 systemSetTitle(buffer
);
2589 void system10Frames(int rate
)
2591 u32 time
= systemGetClock();
2592 if(!wasPaused
&& autoFrameSkip
&& !throttle
) {
2593 u32 diff
= time
- autoFrameSkipLastTime
;
2597 speed
= (1000000/rate
)/diff
;
2602 if(frameskipadjust
>= 3) {
2604 if(systemFrameSkip
> 0)
2609 frameskipadjust
-= (90 - speed
)/5;
2610 else if(systemFrameSkip
< 9)
2613 if(frameskipadjust
<= -2) {
2614 frameskipadjust
+= 2;
2615 if(systemFrameSkip
< 9)
2620 if(!wasPaused
&& throttle
) {
2622 u32 diff
= time
- throttleLastTime
;
2624 int target
= (1000000/(rate
*throttle
));
2625 int d
= (target
- diff
);
2631 throttleLastTime
= systemGetClock();
2634 if(++rewindCounter
>= rewindTimer
) {
2635 rewindSaveNeeded
= true;
2640 if(systemSaveUpdateCounter
) {
2641 if(--systemSaveUpdateCounter
<= SYSTEM_SAVE_NOT_UPDATED
) {
2643 systemSaveUpdateCounter
= SYSTEM_SAVE_NOT_UPDATED
;
2648 autoFrameSkipLastTime
= time
;
2651 void systemScreenCapture(int a
)
2657 sprintf(buffer
, "%s/%s%02d.bmp", captureDir
, sdlGetFilename(filename
), a
);
2659 sprintf(buffer
, "%s%02d.bmp", filename
, a
);
2661 emulator
.emuWriteBMP(buffer
);
2664 sprintf(buffer
, "%s/%s%02d.png", captureDir
, sdlGetFilename(filename
), a
);
2666 sprintf(buffer
, "%s%02d.png", filename
, a
);
2667 emulator
.emuWritePNG(buffer
);
2670 systemScreenMessage("Screen capture");
2673 void soundCallback(void * unused
,u8
*stream
,int len
)
2678 // Patch #1382692 by deathpudding.
2679 /* since this is running in a different thread, speedup and
2680 * throttle can change at any time; save the value so locks
2682 bool lock
= (!speedup
&& !throttle
) ? true : false;
2685 SDL_SemWait (sdlBufferFull
);
2687 SDL_SemWait (sdlBufferLock
);
2688 memcpy (stream
, sdlBuffer
, len
);
2690 SDL_SemPost (sdlBufferLock
);
2693 SDL_SemPost (sdlBufferEmpty
);
2696 void systemWriteDataToSoundBuffer()
2698 // Patch #1382692 by deathpudding.
2699 if (SDL_GetAudioStatus () != SDL_AUDIO_PLAYING
)
2702 if ((sdlSoundLen
+ soundBufferLen
) >= 2048*2) {
2703 bool lock
= (!speedup
&& !throttle
) ? true : false;
2706 SDL_SemWait (sdlBufferEmpty
);
2708 SDL_SemWait (sdlBufferLock
);
2709 int copied
= 2048*2 - sdlSoundLen
;
2710 memcpy (sdlBuffer
+ sdlSoundLen
, soundFinalWave
, copied
);
2711 sdlSoundLen
= 2048*2;
2712 SDL_SemPost (sdlBufferLock
);
2715 SDL_SemPost (sdlBufferFull
);
2717 /* wait for buffer to be dumped by soundCallback() */
2718 SDL_SemWait (sdlBufferEmpty
);
2719 SDL_SemPost (sdlBufferEmpty
);
2721 SDL_SemWait (sdlBufferLock
);
2722 memcpy (sdlBuffer
, ((u8
*)soundFinalWave
) + copied
,
2723 soundBufferLen
- copied
);
2724 sdlSoundLen
= soundBufferLen
- copied
;
2725 SDL_SemPost (sdlBufferLock
);
2728 SDL_SemWait (sdlBufferLock
);
2729 memcpy (sdlBuffer
, ((u8
*) soundFinalWave
) + copied
, soundBufferLen
);
2730 SDL_SemPost (sdlBufferLock
);
2734 SDL_SemWait (sdlBufferLock
);
2735 memcpy (sdlBuffer
+ sdlSoundLen
, soundFinalWave
, soundBufferLen
);
2736 sdlSoundLen
+= soundBufferLen
;
2737 SDL_SemPost (sdlBufferLock
);
2741 bool systemSoundInit()
2743 SDL_AudioSpec audio
;
2745 switch(soundQuality
) {
2748 soundBufferLen
= 1470*2;
2752 soundBufferLen
= 736*2;
2756 soundBufferLen
= 368*2;
2759 audio
.format
=AUDIO_S16SYS
;
2761 audio
.samples
= 1024;
2762 audio
.callback
= soundCallback
;
2763 audio
.userdata
= NULL
;
2764 if(SDL_OpenAudio(&audio
, NULL
)) {
2765 fprintf(stderr
,"Failed to open audio: %s\n", SDL_GetError());
2768 soundBufferTotalLen
= soundBufferLen
*10;
2769 // Patch #1382692 by deathpudding.
2770 sdlBufferLock
= SDL_CreateSemaphore (1);
2771 sdlBufferFull
= SDL_CreateSemaphore (0);
2772 sdlBufferEmpty
= SDL_CreateSemaphore (1);
2774 systemSoundOn
= true;
2778 void systemSoundShutdown()
2780 SDL_SemPost (sdlBufferFull
); // fix freeze by deathpudding
2782 // Patch #1382692 by deathpudding.
2785 SDL_DestroySemaphore (sdlBufferLock
);
2786 SDL_DestroySemaphore (sdlBufferFull
);
2787 SDL_DestroySemaphore (sdlBufferEmpty
);
2788 sdlBufferLock
= NULL
;
2789 sdlBufferFull
= NULL
;
2790 sdlBufferEmpty
= NULL
;
2793 void systemSoundPause()
2798 void systemSoundResume()
2803 void systemSoundReset()
2807 u32
systemGetClock()
2809 return SDL_GetTicks();
2812 void systemUpdateMotionSensor()
2814 if(sdlMotionButtons
[KEY_LEFT
]) {
2820 } else if(sdlMotionButtons
[KEY_RIGHT
]) {
2826 } else if(sensorX
> 2047) {
2836 if(sdlMotionButtons
[KEY_UP
]) {
2842 } else if(sdlMotionButtons
[KEY_DOWN
]) {
2848 } else if(sensorY
> 2047) {
2859 int systemGetSensorX()
2864 int systemGetSensorY()
2869 void systemGbPrint(u8
*data
,int pages
,int feed
,int palette
, int contrast
)
2873 void systemScreenMessage(const char *msg
)
2875 screenMessage
= true;
2876 screenMessageTime
= systemGetClock();
2877 if(strlen(msg
) > 20) {
2878 strncpy(screenMessageBuffer
, msg
, 20);
2879 screenMessageBuffer
[20] = 0;
2881 strcpy(screenMessageBuffer
, msg
);
2884 bool systemCanChangeSoundQuality()
2889 bool systemPauseOnFrame()
2891 if(pauseNextFrame
) {
2893 pauseNextFrame
= false;
2899 #if SDL_MAJOR_VERSION != 2 /* start SDL1.2 YUV code */
2901 // Code donated by Niels Wagenaar (BoycottAdvance)
2904 #define GBA_WIDTH 240
2905 #define GBA_HEIGHT 160
2907 void Init_Overlay(SDL_Surface
*gbascreen
, int overlaytype
)
2910 overlay
= SDL_CreateYUVOverlay( GBA_WIDTH
,
2912 overlaytype
, gbascreen
);
2913 fprintf(stderr
, "Created %dx%dx%d %s %s overlay\n",
2914 overlay
->w
,overlay
->h
,overlay
->planes
,
2915 overlay
->hw_overlay
?"hardware":"software",
2916 overlay
->format
==SDL_YV12_OVERLAY
?"YV12":
2917 overlay
->format
==SDL_IYUV_OVERLAY
?"IYUV":
2918 overlay
->format
==SDL_YUY2_OVERLAY
?"YUY2":
2919 overlay
->format
==SDL_UYVY_OVERLAY
?"UYVY":
2920 overlay
->format
==SDL_YVYU_OVERLAY
?"YVYU":
2924 void Quit_Overlay(void)
2927 SDL_FreeYUVOverlay(overlay
);
2930 /* NOTE: These RGB conversion functions are not intended for speed,
2933 static inline void RGBtoYUV(Uint8
*rgb
, int *yuv
)
2935 yuv
[0] = (int)((0.257 * rgb
[0]) + (0.504 * rgb
[1]) + (0.098 * rgb
[2]) + 16);
2936 yuv
[1] = (int)(128 - (0.148 * rgb
[0]) - (0.291 * rgb
[1]) + (0.439 * rgb
[2]));
2937 yuv
[2] = (int)(128 + (0.439 * rgb
[0]) - (0.368 * rgb
[1]) - (0.071 * rgb
[2]));
2940 static inline void ConvertRGBtoYV12(SDL_Overlay
*o
)
2946 SDL_LockYUVOverlay(o
);
2948 /* Black initialization */
2950 memset(o->pixels[0],0,o->pitches[0]*o->h);
2951 memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2));
2952 memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2));
2956 for(y
=0; y
<160 && y
<o
->h
; y
++) {
2957 p
=(Uint8
*)pix
+srcPitch
*y
;
2958 op
[0]=o
->pixels
[0]+o
->pitches
[0]*y
;
2959 op
[1]=o
->pixels
[1]+o
->pitches
[1]*(y
/2);
2960 op
[2]=o
->pixels
[2]+o
->pitches
[2]*(y
/2);
2961 for(x
=0; x
<240 && x
<o
->w
; x
++) {
2964 if(x
%2==0 && y
%2==0) {
2968 p
+=4;//s->format->BytesPerPixel;
2972 SDL_UnlockYUVOverlay(o
);
2975 static inline void ConvertRGBtoIYUV(SDL_Overlay
*o
)
2981 SDL_LockYUVOverlay(o
);
2983 /* Black initialization */
2985 memset(o->pixels[0],0,o->pitches[0]*o->h);
2986 memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2));
2987 memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2));
2991 for(y
=0; y
<160 && y
<o
->h
; y
++) {
2992 p
=(Uint8
*)pix
+srcPitch
*y
;
2993 op
[0]=o
->pixels
[0]+o
->pitches
[0]*y
;
2994 op
[1]=o
->pixels
[1]+o
->pitches
[1]*(y
/2);
2995 op
[2]=o
->pixels
[2]+o
->pitches
[2]*(y
/2);
2996 for(x
=0; x
<240 && x
<o
->w
; x
++) {
2999 if(x
%2==0 && y
%2==0) {
3003 p
+=4; //s->format->BytesPerPixel;
3007 SDL_UnlockYUVOverlay(o
);
3010 static inline void ConvertRGBtoUYVY(SDL_Overlay
*o
)
3016 SDL_LockYUVOverlay(o
);
3018 for(y
=0; y
<160 && y
<o
->h
; y
++) {
3019 p
=(Uint8
*)pix
+srcPitch
*y
;
3020 op
=o
->pixels
[0]+o
->pitches
[0]*y
;
3021 for(x
=0; x
<240 && x
<o
->w
; x
++) {
3030 p
+=4; //s->format->BytesPerPixel;
3034 SDL_UnlockYUVOverlay(o
);
3037 static inline void ConvertRGBtoYVYU(SDL_Overlay
*o
)
3043 SDL_LockYUVOverlay(o
);
3045 for(y
=0; y
<160 && y
<o
->h
; y
++) {
3046 p
=(Uint8
*)pix
+srcPitch
*y
;
3047 op
=o
->pixels
[0]+o
->pitches
[0]*y
;
3048 for(x
=0; x
<240 && x
<o
->w
; x
++) {
3059 p
+=4; //s->format->BytesPerPixel;
3063 SDL_UnlockYUVOverlay(o
);
3066 static inline void ConvertRGBtoYUY2(SDL_Overlay
*o
)
3072 SDL_LockYUVOverlay(o
);
3074 for(y
=0; y
<160 && y
<o
->h
; y
++) {
3075 p
=(Uint8
*)pix
+srcPitch
*y
;
3076 op
=o
->pixels
[0]+o
->pitches
[0]*y
;
3077 for(x
=0; x
<240 && x
<o
->w
; x
++) {
3088 p
+=4; //s->format->BytesPerPixel;
3092 SDL_UnlockYUVOverlay(o
);
3095 static inline void Convert32bit(SDL_Surface
*display
)
3097 switch(overlay
->format
) {
3098 case SDL_YV12_OVERLAY
:
3099 ConvertRGBtoYV12(overlay
);
3101 case SDL_UYVY_OVERLAY
:
3102 ConvertRGBtoUYVY(overlay
);
3104 case SDL_YVYU_OVERLAY
:
3105 ConvertRGBtoYVYU(overlay
);
3107 case SDL_YUY2_OVERLAY
:
3108 ConvertRGBtoYUY2(overlay
);
3110 case SDL_IYUV_OVERLAY
:
3111 ConvertRGBtoIYUV(overlay
);
3114 fprintf(stderr
, "cannot convert RGB picture to obtained YUV format!\n");
3122 static inline void Draw_Overlay(SDL_Surface
*display
, int size
)
3124 SDL_LockYUVOverlay(overlay
);
3126 Convert32bit(display
);
3130 overlay_rect
.w
= GBA_WIDTH
* size
;
3131 overlay_rect
.h
= GBA_HEIGHT
* size
;
3133 SDL_DisplayYUVOverlay(overlay
, &overlay_rect
);
3134 SDL_UnlockYUVOverlay(overlay
);
3137 static int do_yuv() {
3138 if(yuv
) Draw_Overlay(surface
, sizeOption
+1);
3141 #endif /* end SDL1.2 YUV code */
3144 void systemGbBorderOn()
3147 "turning SGB border on at runtime not supported.\n"
3148 "set it as command line option instead!\n");