implement SDL2 backend, use it by default
[rofl0r-VisualBoyAdvance.git] / src / sdl / SDL.c
blobe08ef95ee1caabd6b5ae3533bef9fee7c278374b
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)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
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.
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
26 #include "../AutoBuild.h"
28 #ifdef USE_SDL2
29 #include <SDL2/SDL.h>
30 #define FILTERS_ENABLED 0
31 #define IFB_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
37 #else
38 #include <SDL/SDL.h>
39 #define FILTERS_ENABLED 1
40 #define IFB_ENABLED 1
41 //#define FILTERS_ENABLED 0
42 //#define IFB_ENABLED 0
43 #endif
45 #include "../GBA.h"
46 #include "../agbprint.h"
47 #include "../Flash.h"
48 #include "../Port.h"
49 #include "debugger.h"
50 #include "../RTC.h"
51 #include "../Sound.h"
52 #include "../Text.h"
53 #include "../unzip.h"
54 #include "../Util.h"
55 #include "../gb/GB.h"
56 #include "../gb/gbGlobals.h"
58 #ifndef SYSCONFDIR
59 #define SYSCONFDIR "/etc"
60 #endif
62 #ifndef _WIN32
63 # include <unistd.h>
64 # define GETCWD getcwd
65 #else // _WIN32
66 # include <direct.h>
67 # define GETCWD _getcwd
68 #endif // _WIN32
70 #ifndef __GNUC__
71 # define HAVE_DECL_GETOPT 0
72 # define __STDC__ 1
73 # include "../getopt.h"
74 #else // ! __GNUC__
75 # define HAVE_DECL_GETOPT 1
76 # include "getopt.h"
77 #endif // ! __GNUC__
79 #ifdef MMX
80 extern "C" bool cpu_mmx;
81 #endif
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);
114 #endif
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);
121 #endif
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 = {
136 NULL,
137 NULL,
138 NULL,
139 NULL,
140 NULL,
141 NULL,
142 NULL,
143 NULL,
144 NULL,
145 NULL,
146 NULL,
147 NULL,
148 false,
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;
159 bool yuv = false;
160 int yuvType = 0;
161 static int do_yuv();
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
167 #else
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
174 #define VPITCH pitch
175 #define VSCALE (1)
176 #define VHEIGHT srcHeight
177 #define do_yuv() 0
178 #endif
180 int systemSpeed = 0;
181 int systemRedShift = 0;
182 int systemBlueShift = 0;
183 int systemGreenShift = 0;
184 int systemColorDepth = 0;
185 int systemDebug = 0;
186 int systemVerbose = 0;
187 int systemFrameSkip = 0;
188 int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
190 int srcPitch = 0;
191 int srcWidth = 0;
192 int srcHeight = 0;
193 int destWidth = 0;
194 int destHeight = 0;
196 int sensorX = 2047;
197 int sensorY = 2047;
199 int filter = 0;
200 u8 *delta = NULL;
202 int sdlPrintUsage = 0;
203 int disableMMX = 0;
205 int cartridgeType = 3;
206 int sizeOption = 0;
207 int captureFormat = 0;
209 int pauseWhenInactive = 0;
210 int active = 1;
211 int emulating = 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;
218 int ifbType = 0;
219 char filename[2048];
220 char ipsname[2048];
221 char biosFileName[2048];
222 char captureDir[2048];
223 char saveDir[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;
261 int throttle = 0;
262 u32 throttleLastTime = 0;
263 u32 autoFrameSkipLastTime = 0;
265 int showSpeed = 1;
266 int showSpeedTransparent = 1;
267 bool disableStatusMessages = false;
268 bool paused = false;
269 bool pauseNextFrame = false;
270 bool debugger = false;
271 bool debuggerStub = false;
272 int fullscreen = 0;
273 bool systemSoundOn = false;
274 bool removeIntros = false;
275 int sdlFlashSize = 0;
276 int sdlAutoIPS = 1;
277 int sdlRtcEnable = 0;
278 int sdlAgbPrint = 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;
290 int autoFire = 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;
301 u8 sdlBuffer[4096];
302 int sdlSoundLen = 0;
304 char *arg0;
306 void (*sdlStretcher)(u8 *, u8*) = NULL;
308 enum {
309 KEY_LEFT, KEY_RIGHT,
310 KEY_UP, KEY_DOWN,
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,
319 SDLK_UP, SDLK_DOWN,
320 SDLK_z, SDLK_x,
321 SDLK_RETURN,SDLK_BACKSPACE,
322 SDLK_a, SDLK_s,
323 SDLK_SPACE, SDLK_F12
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,
332 SDLK_UP, SDLK_DOWN,
333 SDLK_z, SDLK_x,
334 SDLK_RETURN,SDLK_BACKSPACE,
335 SDLK_a, SDLK_s,
336 SDLK_SPACE, SDLK_F12
339 u32 motion[4] = {
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 },
369 #endif
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 },
374 #endif
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' },
412 #endif
413 { NULL, no_argument, NULL, 0 }
416 static int sdlCalculateMaskWidth(u32 mask)
418 int m = 0;
419 int mask2 = mask;
421 while(mask2) {
422 m++;
423 mask2 >>= 1;
426 int m2 = 0;
427 mask2 = mask;
428 while(!(mask2 & 1)) {
429 m2++;
430 mask2 >>= 1;
433 return m - m2;
436 static void sdlInitSAI2x(int bitspp, SDL_PixelFormat *format) {
437 #if FILTERS_ENABLED+0 != 0
438 if(bitspp == 24) return;
439 if(bitspp == 16)
440 bitspp = (sdlCalculateMaskWidth(format->Gmask) == 6 ? 565 : 555);
441 Init_2xSaI(bitspp);
442 #endif
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];
457 } else {
458 filterFunction = filter32_func_map[filter];
460 #endif
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];
471 #endif
474 static void sdlInit(int soundOffFlag) {
475 int flags = SDL_INIT_VIDEO|SDL_INIT_AUDIO|
476 SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE;
478 if(soundOffFlag)
479 flags ^= SDL_INIT_AUDIO;
481 if(SDL_Init(flags)) {
482 systemMessage(0, "Failed to init SDL: %s", SDL_GetError());
483 exit(-1);
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
493 #if 1
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);
498 old = surface;
499 surface = new;
500 SDL_FreeSurface(old);
501 #else
502 SDL_LockSurface(surface);
503 SDL_WM_ToggleFullScreen(surface);
504 fullscreen = !fullscreen;
505 SDL_UnlockSurface(surface);
506 #endif
507 #else
508 SDL_SetWindowFullscreen(win, fullscreen ? 0 : SDL_WINDOW_FULLSCREEN);
509 fullscreen = !fullscreen;
510 #endif
513 static void sdlSetTitle(const char* title) {
514 #if SDL_MAJOR_VERSION != 2
515 SDL_WM_SetCaption(title, NULL);
516 #else
517 SDL_SetWindowTitle(win, title);
518 #endif
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");
536 SDL_Quit();
537 exit(-1);
539 #else
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))) {
544 sdl_err:
545 systemMessage(0, "SDL: video setup error: %s\n", SDL_GetError());
546 SDL_Quit();
547 exit(-1);
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);
556 #endif
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)
569 u16 *s = (u16 *)src;
570 u16 *d = (u16 *)dest;
571 for(int i = 0; i < srcWidth; i++) {
572 *d++ = *s;
573 *d++ = *s++;
577 static void sdlStretch16x3(u8 *src, u8 *dest)
579 u16 *s = (u16 *)src;
580 u16 *d = (u16 *)dest;
581 for(int i = 0; i < srcWidth; i++) {
582 *d++ = *s;
583 *d++ = *s;
584 *d++ = *s++;
588 static void sdlStretch16x4(u8 *src, u8 *dest)
590 u16 *s = (u16 *)src;
591 u16 *d = (u16 *)dest;
592 for(int i = 0; i < srcWidth; i++) {
593 *d++ = *s;
594 *d++ = *s;
595 *d++ = *s;
596 *d++ = *s++;
600 static void sdlStretch32x1(u8 *src, u8 *dest)
602 memcpy(dest, src, srcWidth*4);
605 static void sdlStretch32x2(u8 *src, u8 *dest)
607 u32 *s = (u32 *)src;
608 u32 *d = (u32 *)dest;
609 for(int i = 0; i < srcWidth; i++) {
610 *d++ = *s;
611 *d++ = *s++;
615 static void sdlStretch32x3(u8 *src, u8 *dest)
617 u32 *s = (u32 *)src;
618 u32 *d = (u32 *)dest;
619 for(int i = 0; i < srcWidth; i++) {
620 *d++ = *s;
621 *d++ = *s;
622 *d++ = *s++;
626 static void sdlStretch32x4(u8 *src, u8 *dest)
628 u32 *s = (u32 *)src;
629 u32 *d = (u32 *)dest;
630 for(int i = 0; i < srcWidth; i++) {
631 *d++ = *s;
632 *d++ = *s;
633 *d++ = *s;
634 *d++ = *s++;
638 static void sdlStretch24x1(u8 *src, u8 *dest)
640 memcpy(dest, src, srcWidth*3);
643 static void sdlStretch24x2(u8 *src, u8 *dest)
645 u8 *s = (u8 *)src;
646 u8 *d = (u8 *)dest;
647 for(int i = 0; i < srcWidth; i++) {
648 *d++ = *s;
649 *d++ = *(s+1);
650 *d++ = *(s+2);
651 s += 3;
652 *d++ = *s;
653 *d++ = *(s+1);
654 *d++ = *(s+2);
655 s += 3;
659 static void sdlStretch24x3(u8 *src, u8 *dest)
661 u8 *s = (u8 *)src;
662 u8 *d = (u8 *)dest;
663 for(int i = 0; i < srcWidth; i++) {
664 *d++ = *s;
665 *d++ = *(s+1);
666 *d++ = *(s+2);
667 s += 3;
668 *d++ = *s;
669 *d++ = *(s+1);
670 *d++ = *(s+2);
671 s += 3;
672 *d++ = *s;
673 *d++ = *(s+1);
674 *d++ = *(s+2);
675 s += 3;
679 static void sdlStretch24x4(u8 *src, u8 *dest)
681 u8 *s = (u8 *)src;
682 u8 *d = (u8 *)dest;
683 for(int i = 0; i < srcWidth; i++) {
684 *d++ = *s;
685 *d++ = *(s+1);
686 *d++ = *(s+2);
687 s += 3;
688 *d++ = *s;
689 *d++ = *(s+1);
690 *d++ = *(s+2);
691 s += 3;
692 *d++ = *s;
693 *d++ = *(s+1);
694 *d++ = *(s+2);
695 s += 3;
696 *d++ = *s;
697 *d++ = *(s+1);
698 *d++ = *(s+2);
699 s += 3;
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)
712 u32 value;
713 sscanf(s, "%x", &value);
714 return value;
717 #ifdef __MSC__
718 #define stat _stat
719 #define S_IFDIR _S_IFDIR
720 #endif
722 void sdlCheckDirectory(char *dir)
724 struct stat buf;
726 int len = strlen(dir);
728 char *p = dir + len - 1;
730 if(*p == '/' ||
731 *p == '\\')
732 *p = 0;
734 if(stat(dir, &buf) == 0) {
735 if(!(buf.st_mode & S_IFDIR)) {
736 fprintf(stderr, "Error: %s is not a directory\n", dir);
737 dir[0] = 0;
739 } else {
740 fprintf(stderr, "Error: %s does not exist\n", dir);
741 dir[0] = 0;
745 char *sdlGetFilename(char *name)
747 static char filebuffer[2048];
749 int len = strlen(name);
751 char *p = name + len - 1;
753 while(true) {
754 if(*p == '/' ||
755 *p == '\\') {
756 p++;
757 break;
759 len--;
760 p--;
761 if(len == 0)
762 break;
765 if(len == 0)
766 strcpy(filebuffer, name);
767 else
768 strcpy(filebuffer, p);
769 return filebuffer;
772 FILE *sdlFindFile(const char *name)
774 char buffer[4096];
775 char path[2048];
777 #ifdef _WIN32
778 #define PATH_SEP ";"
779 #define FILE_SEP '\\'
780 #define EXE_NAME "VisualBoyAdvance-SDL.exe"
781 #else // ! _WIN32
782 #define PATH_SEP ":"
783 #define FILE_SEP '/'
784 #define EXE_NAME "VisualBoyAdvance"
785 #endif // ! _WIN32
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");
794 if(f != NULL) {
795 return f;
798 char *home = getenv("HOME");
800 if(home != NULL) {
801 fprintf(stderr, "Searching home directory: %s\n", home);
802 sprintf(path, "%s%c%s", home, FILE_SEP, name);
803 f = fopen(path, "r");
804 if(f != NULL)
805 return f;
808 #ifdef _WIN32
809 home = getenv("USERPROFILE");
810 if(home != NULL) {
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");
814 if(f != NULL)
815 return f;
817 #else // ! _WIN32
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");
821 if(f != NULL)
822 return f;
823 #endif // ! _WIN32
825 if(!strchr(arg0, '/') &&
826 !strchr(arg0, '\\')) {
827 char *path = getenv("PATH");
829 if(path != NULL) {
830 fprintf(stderr, "Searching PATH\n");
831 strncpy(buffer, path, 4096);
832 buffer[4095] = 0;
833 char *tok = strtok(buffer, PATH_SEP);
835 while(tok) {
836 sprintf(path, "%s%c%s", tok, FILE_SEP, EXE_NAME);
837 f = fopen(path, "r");
838 if(f != NULL) {
839 char path2[2048];
840 fclose(f);
841 sprintf(path2, "%s%c%s", tok, FILE_SEP, name);
842 f = fopen(path2, "r");
843 if(f != NULL) {
844 fprintf(stderr, "Found at %s\n", path2);
845 return f;
848 tok = strtok(NULL, PATH_SEP);
851 } else {
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);
856 if(p) {
857 *p = 0;
858 sprintf(path, "%s%c%s", buffer, FILE_SEP, name);
859 f = fopen(path, "r");
860 if(f != NULL)
861 return f;
864 return NULL;
867 void sdlReadPreferencesF(FILE *f)
869 char buffer[2048];
871 while(1) {
872 char *s = fgets(buffer, 2048, f);
874 if(s == NULL)
875 break;
877 char *p = strchr(s, '#');
879 if(p)
880 *p = 0;
882 char *token = strtok(s, " \t\n\r=");
884 if(!token)
885 continue;
887 if(strlen(token) == 0)
888 continue;
890 char *key = token;
891 char *value = strtok(NULL, "\t\n\r");
893 if(value == NULL) {
894 fprintf(stderr, "Empty value for key %s\n", key);
895 continue;
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)
1005 frameSkip = 2;
1006 } else if(!strcmp(key, "gbFrameSkip")) {
1007 gbFrameSkip = sdlFromHex(value);
1008 if(gbFrameSkip < 0 || gbFrameSkip > 9)
1009 gbFrameSkip = 0;
1010 } else if(!strcmp(key, "video")) {
1011 sizeOption = sdlFromHex(value);
1012 if(sizeOption < 0 || sizeOption > 3)
1013 sizeOption = 1;
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)
1025 filter = 0;
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)
1035 gbEmulatorType = 1;
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) {
1052 case 1:
1053 case 2:
1054 case 4:
1055 break;
1056 default:
1057 fprintf(stderr, "Unknown sound quality %d. Defaulting to 22Khz\n",
1058 soundQuality);
1059 soundQuality = 2;
1060 break;
1062 } else if(!strcmp(key, "soundOff")) {
1063 soundOffFlag = sdlFromHex(value) ? true : false;
1064 } else if(!strcmp(key, "soundEnable")) {
1065 int res = sdlFromHex(value) & 0x30f;
1066 soundEnable(res);
1067 soundDisable(~res);
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)
1077 soundVolume = 0;
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)
1083 cpuSaveType = 0;
1084 } else if(!strcmp(key, "flashSize")) {
1085 sdlFlashSize = sdlFromHex(value);
1086 if(sdlFlashSize != 0 && sdlFlashSize != 1)
1087 sdlFlashSize = 0;
1088 } else if(!strcmp(key, "ifbType")) {
1089 ifbType = sdlFromHex(value);
1090 if(ifbType < 0 || ifbType > 2)
1091 ifbType = 0;
1092 } else if(!strcmp(key, "showSpeed")) {
1093 showSpeed = sdlFromHex(value);
1094 if(showSpeed < 0 || showSpeed > 2)
1095 showSpeed = 1;
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))
1103 throttle = 0;
1104 } else if(!strcmp(key, "disableMMX")) {
1105 #ifdef MMX
1106 cpu_mmx = sdlFromHex(value) ? false : true;
1107 #endif
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)
1117 rewindTimer = 0;
1118 rewindTimer *= 6; // convert value to 10 frames multiple
1119 } else {
1120 fprintf(stderr, "Unknown configuration key %s\n", key);
1125 void sdlReadPreferences()
1127 FILE *f = sdlFindFile("VisualBoyAdvance.cfg");
1129 if(f == NULL) {
1130 fprintf(stderr, "Configuration file NOT FOUND (using defaults)\n");
1131 return;
1132 } else
1133 fprintf(stderr, "Reading configuration file.\n");
1135 sdlReadPreferencesF(f);
1137 fclose(f);
1140 static void sdlApplyPerImagePreferences()
1142 FILE *f = sdlFindFile("vba-over.ini");
1143 if(!f) {
1144 fprintf(stderr, "vba-over.ini NOT FOUND (using emulator settings)\n");
1145 return;
1146 } else
1147 fprintf(stderr, "Reading vba-over.ini\n");
1149 char buffer[7];
1150 buffer[0] = '[';
1151 buffer[1] = rom[0xac];
1152 buffer[2] = rom[0xad];
1153 buffer[3] = rom[0xae];
1154 buffer[4] = rom[0xaf];
1155 buffer[5] = ']';
1156 buffer[6] = 0;
1158 char readBuffer[2048];
1160 bool found = false;
1162 while(1) {
1163 char *s = fgets(readBuffer, 2048, f);
1165 if(s == NULL)
1166 break;
1168 char *p = strchr(s, ';');
1170 if(p)
1171 *p = 0;
1173 char *token = strtok(s, " \t\n\r=");
1175 if(!token)
1176 continue;
1177 if(strlen(token) == 0)
1178 continue;
1180 if(!strcmp(token, buffer)) {
1181 found = true;
1182 break;
1186 if(found) {
1187 while(1) {
1188 char *s = fgets(readBuffer, 2048, f);
1190 if(s == NULL)
1191 break;
1193 char *p = strchr(s, ';');
1194 if(p)
1195 *p = 0;
1197 char *token = strtok(s, " \t\n\r=");
1198 if(!token)
1199 continue;
1200 if(strlen(token) == 0)
1201 continue;
1203 if(token[0] == '[') // starting another image settings
1204 break;
1205 char *value = strtok(NULL, "\t\n\r=");
1206 if(value == NULL)
1207 continue;
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)
1214 flashSetSize(size);
1215 } else if(!strcmp(token, "saveType")) {
1216 int save = atoi(value);
1217 if(save >= 0 && save <= 5)
1218 cpuSaveType = save;
1219 } else if(!strcmp(token, "mirroringEnabled")) {
1220 mirroringEnable = (atoi(value) == 0 ? false : true);
1224 fclose(f);
1227 static int sdlCalculateShift(u32 mask)
1229 int m = 0;
1231 while(mask) {
1232 m++;
1233 mask >>= 1;
1236 return m-5;
1239 void sdlWriteState(int num)
1241 char stateName[2048];
1243 if(saveDir[0])
1244 sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename),
1245 num+1);
1246 else
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);
1255 systemDrawScreen();
1258 void sdlReadState(int num)
1260 char stateName[2048];
1262 if(saveDir[0])
1263 sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename),
1264 num+1);
1265 else
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);
1274 systemDrawScreen();
1277 void sdlWriteBattery()
1279 char buffer[1048];
1281 if(batteryDir[0])
1282 sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
1283 else
1284 sprintf(buffer, "%s.sav", filename);
1286 emulator.emuWriteBattery(buffer);
1288 systemScreenMessage("Wrote battery");
1291 void sdlReadBattery()
1293 char buffer[1048];
1295 if(batteryDir[0])
1296 sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
1297 else
1298 sprintf(buffer, "%s.sav", filename);
1300 bool res = false;
1302 res = emulator.emuReadBattery(buffer);
1304 if(res)
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)
1315 int i;
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,
1333 int button,
1334 bool pressed)
1336 int i;
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;
1341 if(dev) {
1342 dev--;
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;
1353 if(dev) {
1354 dev--;
1356 if((dev == which) && (b >= 128) && (b == (button+128))) {
1357 sdlMotionButtons[i] = pressed;
1363 void sdlUpdateJoyHat(int which,
1364 int hat,
1365 int value)
1367 int i;
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;
1372 if(dev) {
1373 dev--;
1375 if((dev == which) && (a>=32) && (a < 48) && (((a&15)>>2) == hat)) {
1376 int dir = a & 3;
1377 int v = 0;
1378 switch(dir) {
1379 case 0:
1380 v = value & SDL_HAT_UP;
1381 break;
1382 case 1:
1383 v = value & SDL_HAT_DOWN;
1384 break;
1385 case 2:
1386 v = value & SDL_HAT_RIGHT;
1387 break;
1388 case 3:
1389 v = value & SDL_HAT_LEFT;
1390 break;
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;
1400 if(dev) {
1401 dev--;
1403 if((dev == which) && (a>=32) && (a < 48) && (((a&15)>>2) == hat)) {
1404 int dir = a & 3;
1405 int v = 0;
1406 switch(dir) {
1407 case 0:
1408 v = value & SDL_HAT_UP;
1409 break;
1410 case 1:
1411 v = value & SDL_HAT_DOWN;
1412 break;
1413 case 2:
1414 v = value & SDL_HAT_RIGHT;
1415 break;
1416 case 3:
1417 v = value & SDL_HAT_LEFT;
1418 break;
1420 sdlMotionButtons[i] = (v ? true : false);
1426 void sdlUpdateJoyAxis(int which,
1427 int axis,
1428 int value)
1430 int i;
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;
1435 if(dev) {
1436 dev--;
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;
1447 if(dev) {
1448 dev--;
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;
1462 if(what >= 128) {
1463 // joystick button
1464 int button = what - 128;
1466 if(button >= SDL_JoystickNumButtons(sdlDevices[dev]))
1467 return false;
1468 } else if (what < 0x20) {
1469 // joystick axis
1470 what >>= 1;
1471 if(what >= SDL_JoystickNumAxes(sdlDevices[dev]))
1472 return false;
1473 } else if (what < 0x30) {
1474 // joystick hat
1475 what = (what & 15);
1476 what >>= 2;
1477 if(what >= SDL_JoystickNumHats(sdlDevices[dev]))
1478 return false;
1481 // no problem found
1482 return true;
1485 void sdlCheckKeys()
1487 sdlNumDevices = SDL_NumJoysticks();
1489 if(sdlNumDevices)
1490 sdlDevices = (SDL_Joystick **)calloc(1,sdlNumDevices *
1491 sizeof(SDL_Joystick **));
1492 int i;
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;
1499 if(dev) {
1500 dev--;
1501 bool ok = false;
1503 if(sdlDevices) {
1504 if(dev < sdlNumDevices) {
1505 if(sdlDevices[dev] == NULL) {
1506 sdlDevices[dev] = SDL_JoystickOpen(dev);
1509 ok = sdlCheckJoyKey(joypad[j][i]);
1510 } else
1511 ok = false;
1514 if(!ok)
1515 joypad[j][i] = defaultJoypad[i];
1516 else
1517 usesJoy = true;
1522 for(i = 0; i < 4; i++) {
1523 int dev = motion[i] >> 12;
1524 if(dev) {
1525 dev--;
1526 bool ok = false;
1528 if(sdlDevices) {
1529 if(dev < sdlNumDevices) {
1530 if(sdlDevices[dev] == NULL) {
1531 sdlDevices[dev] = SDL_JoystickOpen(dev);
1534 ok = sdlCheckJoyKey(motion[i]);
1535 } else
1536 ok = false;
1539 if(!ok)
1540 motion[i] = defaultMotion[i];
1541 else
1542 usesJoy = true;
1546 if(usesJoy)
1547 SDL_JoystickEventState(SDL_ENABLE);
1550 void sdlPollEvents()
1552 SDL_Event event;
1553 while(SDL_PollEvent(&event)) {
1554 switch(event.type) {
1555 case SDL_QUIT:
1556 emulating = 0;
1557 break;
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;
1564 #else
1565 case SDL_ACTIVEEVENT:
1566 if(pauseWhenInactive && (event.active.state & SDL_APPINPUTFOCUS)) {
1567 active = event.active.gain;
1568 #endif
1569 if(active) {
1570 if(!paused) {
1571 if(emulating)
1572 soundResume();
1574 } else {
1575 wasPaused = true;
1576 if(pauseWhenInactive) {
1577 if(emulating)
1578 soundPause();
1581 memset(delta,255,sizeof(delta));
1584 break;
1585 case SDL_MOUSEMOTION:
1586 case SDL_MOUSEBUTTONUP:
1587 case SDL_MOUSEBUTTONDOWN:
1588 if(fullscreen) {
1589 SDL_ShowCursor(SDL_ENABLE);
1590 mouseCounter = 120;
1592 break;
1593 case SDL_JOYHATMOTION:
1594 sdlUpdateJoyHat(event.jhat.which,
1595 event.jhat.hat,
1596 event.jhat.value);
1597 break;
1598 case SDL_JOYBUTTONDOWN:
1599 case SDL_JOYBUTTONUP:
1600 sdlUpdateJoyButton(event.jbutton.which,
1601 event.jbutton.button,
1602 event.jbutton.state == SDL_PRESSED);
1603 break;
1604 case SDL_JOYAXISMOTION:
1605 sdlUpdateJoyAxis(event.jaxis.which,
1606 event.jaxis.axis,
1607 event.jaxis.value);
1608 break;
1609 case SDL_KEYDOWN:
1610 sdlUpdateKey(event.key.keysym.sym, true);
1611 break;
1612 case SDL_KEYUP:
1613 switch(event.key.keysym.sym) {
1614 case SDLK_r:
1615 if(!(event.key.keysym.mod & MOD_NOCTRL) &&
1616 (event.key.keysym.mod & KMOD_CTRL)) {
1617 if(emulating) {
1618 emulator.emuReset();
1620 systemScreenMessage("Reset");
1623 break;
1624 case SDLK_b:
1625 if(!(event.key.keysym.mod & MOD_NOCTRL) &&
1626 (event.key.keysym.mod & KMOD_CTRL)) {
1627 if(emulating && emulator.emuReadMemState && rewindMemory
1628 && rewindCount) {
1629 rewindPos = (rewindPos - 1) & 7;
1630 emulator.emuReadMemState(&rewindMemory[REWIND_SIZE*rewindPos],
1631 REWIND_SIZE);
1632 rewindCount--;
1633 rewindCounter = 0;
1634 systemScreenMessage("Rewind");
1637 break;
1638 case SDLK_p:
1639 if(!(event.key.keysym.mod & MOD_NOCTRL) &&
1640 (event.key.keysym.mod & KMOD_CTRL)) {
1641 paused = !paused;
1642 SDL_PauseAudio(paused);
1643 if(paused)
1644 wasPaused = true;
1646 break;
1647 case SDLK_ESCAPE:
1648 emulating = 0;
1649 break;
1650 case SDLK_f:
1651 if(!(event.key.keysym.mod & MOD_NOCTRL) &&
1652 (event.key.keysym.mod & KMOD_CTRL)) {
1653 sdlToggleFullscreen();
1655 break;
1656 case SDLK_F11:
1657 if(dbgMain != debuggerMain) {
1658 if(armState) {
1659 armNextPC -= 4;
1660 reg[15].I -= 4;
1661 } else {
1662 armNextPC -= 2;
1663 reg[15].I -= 2;
1666 debugger = true;
1667 break;
1668 case SDLK_F1:
1669 case SDLK_F2:
1670 case SDLK_F3:
1671 case SDLK_F4:
1672 case SDLK_F5:
1673 case SDLK_F6:
1674 case SDLK_F7:
1675 case SDLK_F8:
1676 case SDLK_F9:
1677 case SDLK_F10:
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);
1684 break;
1685 case SDLK_1:
1686 case SDLK_2:
1687 case SDLK_3:
1688 case SDLK_4:
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] =
1697 { "autofire A",
1698 "autofire B",
1699 "autofire R",
1700 "autofire L"};
1701 int mask = 1 << (event.key.keysym.sym - SDLK_1);
1702 if(event.key.keysym.sym > SDLK_2)
1703 mask <<= 6;
1704 if(autoFire & mask) {
1705 autoFire &= ~mask;
1706 systemScreenMessage(disableMessages[event.key.keysym.sym - SDLK_1]);
1707 } else {
1708 autoFire |= mask;
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);
1718 break;
1719 case SDLK_5:
1720 case SDLK_6:
1721 case SDLK_7:
1722 case SDLK_8:
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;
1729 break;
1730 case SDLK_n:
1731 if(!(event.key.keysym.mod & MOD_NOCTRL) &&
1732 (event.key.keysym.mod & KMOD_CTRL)) {
1733 if(paused)
1734 paused = false;
1735 pauseNextFrame = true;
1737 break;
1738 default:
1739 break;
1741 sdlUpdateKey(event.key.keysym.sym, false);
1742 break;
1747 void usage(char *cmd)
1749 printf("%s [option ...] file\n", cmd);
1750 printf("\
1752 Options:\n\
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\
1793 #endif
1794 #if SDL_MAJOR_VERSION != 2
1796 -Y, --yuv=TYPE Use YUV overlay for drawing:\n\
1797 0 - YV12\n\
1798 1 - UYVY\n\
1799 2 - YVYU\n\
1800 3 - YUY2\n\
1801 4 - IYUV\n\
1803 #endif
1805 printf("\
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\
1814 1 - SWI\n\
1815 2 - Unaligned memory access\n\
1816 4 - Illegal memory write\n\
1817 8 - Illegal memory read\n\
1818 16 - DMA 0\n\
1819 32 - DMA 1\n\
1820 64 - DMA 2\n\
1821 128 - DMA 3\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\
1847 #endif
1851 int main(int argc, char **argv)
1853 fprintf(stderr, "VisualBoyAdvance version %s [SDL]\n", VERSION);
1855 arg0 = argv[0];
1857 captureDir[0] = 0;
1858 saveDir[0] = 0;
1859 batteryDir[0] = 0;
1860 ipsname[0] = 0;
1862 int i, j, op = -1;
1864 frameSkip = 2;
1865 gbBorderOn = 0;
1867 parseDebug = true;
1869 sdlReadPreferences();
1871 sdlPrintUsage = 0;
1873 while((op = getopt_long(argc,
1874 argv,
1875 "FNT:Y:G:D:b:c:df:hi:p::s:t:v:1234",
1876 sdlOptions,
1877 NULL)) != -1) {
1878 switch(op) {
1879 case 0:
1880 // long option already processed by getopt_long
1881 break;
1882 case 'b':
1883 useBios = true;
1884 if(optarg == NULL) {
1885 fprintf(stderr, "Missing BIOS file name\n");
1886 exit(-1);
1888 strcpy(biosFileName, optarg);
1889 break;
1890 case 'c':
1892 if(optarg == NULL) {
1893 fprintf(stderr, "Missing config file name\n");
1894 exit(-1);
1896 FILE *f = fopen(optarg, "r");
1897 if(f == NULL) {
1898 fprintf(stderr, "File not found %s\n", optarg);
1899 exit(-1);
1901 sdlReadPreferences(f);
1902 fclose(f);
1904 break;
1905 case 'd':
1906 debugger = true;
1907 break;
1908 case 'h':
1909 sdlPrintUsage = 1;
1910 break;
1911 case 'i':
1912 if(optarg == NULL) {
1913 fprintf(stderr, "Missing IPS name\n");
1914 exit(-1);
1915 strcpy(ipsname, optarg);
1917 break;
1918 #if SDL_MAJOR_VERSION != 2
1919 case 'Y':
1920 yuv = true;
1921 if(optarg) {
1922 yuvType = atoi(optarg);
1923 switch(yuvType) {
1924 case 0:
1925 yuvType = SDL_YV12_OVERLAY;
1926 break;
1927 case 1:
1928 yuvType = SDL_UYVY_OVERLAY;
1929 break;
1930 case 2:
1931 yuvType = SDL_YVYU_OVERLAY;
1932 break;
1933 case 3:
1934 yuvType = SDL_YUY2_OVERLAY;
1935 break;
1936 case 4:
1937 yuvType = SDL_IYUV_OVERLAY;
1938 break;
1939 default:
1940 yuvType = SDL_YV12_OVERLAY;
1942 } else
1943 yuvType = SDL_YV12_OVERLAY;
1944 break;
1945 #endif
1946 case 'G':
1947 dbgMain = remoteStubMain;
1948 dbgSignal = remoteStubSignal;
1949 dbgOutput = remoteOutput;
1950 debugger = true;
1951 debuggerStub = true;
1952 if(optarg) {
1953 char *s = optarg;
1954 if(strncmp(s,"tcp:", 4) == 0) {
1955 s+=4;
1956 int port = atoi(s);
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);
1963 } else {
1964 fprintf(stderr, "Unknown protocol %s\n", s);
1965 exit(-1);
1967 } else {
1968 remoteSetProtocol(0);
1970 break;
1971 case 'N':
1972 parseDebug = false;
1973 break;
1974 case 'D':
1975 if(optarg) {
1976 systemDebug = atoi(optarg);
1977 } else {
1978 systemDebug = 1;
1980 break;
1981 case 'F':
1982 fullscreen = 1;
1983 mouseCounter = 120;
1984 break;
1985 case 'f':
1986 if(optarg) {
1987 filter = atoi(optarg);
1988 } else {
1989 filter = 0;
1991 break;
1992 case 'p':
1993 #ifdef PROFILING
1994 if(optarg) {
1995 cpuEnableProfiling(atoi(optarg));
1996 } else
1997 cpuEnableProfiling(100);
1998 #endif
1999 break;
2000 case 'S':
2001 sdlFlashSize = atoi(optarg);
2002 if(sdlFlashSize < 0 || sdlFlashSize > 1)
2003 sdlFlashSize = 0;
2004 break;
2005 case 's':
2006 if(optarg) {
2007 int a = atoi(optarg);
2008 if(a >= 0 && a <= 9) {
2009 gbFrameSkip = a;
2010 frameSkip = a;
2012 } else {
2013 frameSkip = 2;
2014 gbFrameSkip = 0;
2016 break;
2017 case 't':
2018 if(optarg) {
2019 int a = atoi(optarg);
2020 if(a < 0 || a > 5)
2021 a = 0;
2022 cpuSaveType = a;
2024 break;
2025 case 'T':
2026 if(optarg) {
2027 int t = atoi(optarg);
2028 if(t < 5 || t > 1000)
2029 t = 0;
2030 throttle = t;
2032 break;
2033 case 'v':
2034 if(optarg) {
2035 systemVerbose = atoi(optarg);
2036 } else
2037 systemVerbose = 0;
2038 break;
2039 case '1':
2040 sizeOption = 0;
2041 break;
2042 case '2':
2043 sizeOption = 1;
2044 break;
2045 case '3':
2046 sizeOption = 2;
2047 break;
2048 case '4':
2049 sizeOption = 3;
2050 break;
2051 case '?':
2052 sdlPrintUsage = 1;
2053 break;
2057 if(sdlPrintUsage) {
2058 usage(argv[0]);
2059 exit(-1);
2062 #ifdef MMX
2063 if(disableMMX)
2064 cpu_mmx = 0;
2065 #endif
2067 if(rewindTimer)
2068 rewindMemory = (char *)malloc(8*REWIND_SIZE);
2070 if(sdlFlashSize == 0)
2071 flashSetSize(0x10000);
2072 else
2073 flashSetSize(0x20000);
2075 rtcEnable(sdlRtcEnable ? true : false);
2076 agbPrintEnable(sdlAgbPrint ? true : false);
2078 if(!debuggerStub) {
2079 if(optind >= argc) {
2080 systemMessage(0,"Missing image name");
2081 usage(argv[0]);
2082 exit(-1);
2086 if(filter) {
2087 sizeOption = 1;
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;
2099 if(optind < argc) {
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);
2105 exit(-1);
2108 utilGetBaseName(szFile, filename);
2109 char *p = strrchr(filename, '.');
2111 if(p)
2112 *p = 0;
2114 if(ipsname[0] == 0)
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);
2123 exit(-1);
2125 cartridgeType = (int)type;
2127 if(type == IMAGE_GB) {
2128 failed = !gbLoadRom(szFile);
2129 if(!failed) {
2130 gbGetHardwareType();
2132 // used for the handling of the gb Boot Rom
2133 if (gbHardware & 5)
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;
2145 gbReset();
2146 cartridgeType = IMAGE_GB;
2147 emulator = GBSystem;
2148 if(sdlAutoIPS) {
2149 int size = gbRomSize;
2150 utilApplyIPS(ipsname, &gbRom, &size);
2151 if(size != gbRomSize) {
2152 extern bool gbUpdateSizes();
2153 gbUpdateSizes();
2154 gbReset();
2158 } else if(type == IMAGE_GBA) {
2159 int size = CPULoadRom(szFile);
2160 failed = (size == 0);
2161 if(!failed) {
2162 sdlApplyPerImagePreferences();
2164 doMirroring(mirroringEnable);
2166 cartridgeType = 0;
2167 emulator = GBASystem;
2169 /* disabled due to problems
2170 if(removeIntros && rom != NULL) {
2171 WRITE32LE(&rom[0], 0xea00002e);
2175 CPUInit(biosFileName, useBios);
2176 CPUReset();
2177 if(sdlAutoIPS) {
2178 int size = 0x2000000;
2179 utilApplyIPS(ipsname, &rom, &size);
2180 if(size != 0x2000000) {
2181 CPUReset();
2187 if(failed) {
2188 systemMessage(0, "Failed to load file %s", szFile);
2189 exit(-1);
2191 } else {
2192 cartridgeType = 0;
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);
2207 CPUReset();
2210 sdlReadBattery();
2212 if(debuggerStub)
2213 remoteInit();
2215 sdlInit(soundOffFlag);
2217 sdlCheckKeys();
2219 if(cartridgeType == 0) {
2220 srcWidth = 240;
2221 srcHeight = 160;
2222 systemFrameSkip = frameSkip;
2223 } else if (cartridgeType == 1) {
2224 if(gbBorderOn) {
2225 srcWidth = 256;
2226 srcHeight = 224;
2227 gbBorderLineSkip = 256;
2228 gbBorderColumnSkip = 48;
2229 gbBorderRowSkip = 40;
2230 } else {
2231 srcWidth = 160;
2232 srcHeight = 144;
2233 gbBorderLineSkip = 160;
2234 gbBorderColumnSkip = 0;
2235 gbBorderRowSkip = 0;
2237 systemFrameSkip = gbFrameSkip;
2238 } else {
2239 srcWidth = 320;
2240 srcHeight = 240;
2243 destWidth = (sizeOption+1)*srcWidth;
2244 destHeight = (sizeOption+1)*srcHeight;
2246 sdlInitVideo();
2248 sdlInitShift(VPFORMAT);
2250 systemColorDepth = VPFORMAT->BitsPerPixel;
2252 #if SDL_MAJOR_VERSION != 2
2253 if(yuv) {
2254 Init_Overlay(surface, yuvType);
2255 systemColorDepth = 32;
2256 systemRedShift = 3;
2257 systemGreenShift = 11;
2258 systemBlueShift = 19;
2260 #endif
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;
2267 if(!j) {
2268 fprintf(stderr,"Unsupported color depth '%d'.\nOnly 16, 24 and 32 bit color depths are supported\n", systemColorDepth);
2269 exit(-1);
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();
2288 sdlSelectFilter();
2289 sdlSelectIfb();
2291 if(delta == NULL) {
2292 delta = (u8*)malloc(322*242*4);
2293 memset(delta, 255, 322*242*4);
2296 emulating = 1;
2297 renderedFrames = 0;
2299 if(!soundOffFlag)
2300 soundInit();
2302 autoFrameSkipLastTime = throttleLastTime = systemGetClock();
2304 sdlSetTitle("VisualBoyAdvance");
2306 while(emulating) {
2307 if(!paused && active) {
2308 if(debugger && emulator.emuHasDebugger)
2309 dbgMain();
2310 else {
2311 emulator.emuMain(emulator.emuCount);
2312 if(rewindSaveNeeded && rewindMemory && emulator.emuWriteMemState) {
2313 rewindCount++;
2314 if(rewindCount > 8)
2315 rewindCount = 8;
2316 if(emulator.emuWriteMemState &&
2317 emulator.emuWriteMemState(&rewindMemory[rewindPos*REWIND_SIZE],
2318 REWIND_SIZE)) {
2319 rewindPos = (rewindPos + 1) & 7;
2320 if(rewindCount == 8)
2321 rewindTopPos = (rewindTopPos + 1) & 7;
2325 rewindSaveNeeded = false;
2327 } else {
2328 SDL_Delay(500);
2330 sdlPollEvents();
2331 if(mouseCounter) {
2332 mouseCounter--;
2333 if(mouseCounter == 0)
2334 SDL_ShowCursor(SDL_DISABLE);
2338 fprintf(stderr,"Shutting down\n");
2339 if(fullscreen) sdlToggleFullscreen();
2340 remoteCleanUp();
2341 soundShutdown();
2343 if(gbRom != NULL || rom != NULL) {
2344 sdlWriteBattery();
2345 emulator.emuCleanUp();
2348 if(delta) {
2349 free(delta);
2350 delta = NULL;
2353 SDL_Quit();
2354 return 0;
2357 void systemMessage(int num, const char *msg, ...)
2359 char buffer[SYSMSG_BUFFER_SIZE*2];
2360 va_list valist;
2362 va_start(valist, msg);
2363 vsprintf(buffer, msg, valist);
2365 fprintf(stderr, "%s\n", buffer);
2366 va_end(valist);
2369 void systemDrawScreen()
2371 renderedFrames++;
2373 if(do_yuv()) return;
2375 #if SDL_MAJOR_VERSION == 2
2376 int pitch; void *pixels;
2377 SDL_LockTexture(texture, NULL, &pixels, &pitch);
2378 #else
2379 SDL_LockSurface(surface);
2380 #endif
2382 if(screenMessage) {
2383 if(cartridgeType == 1 && gbBorderOn) {
2384 gbSgbRenderBorder();
2386 if(((systemGetClock() - screenMessageTime) < 3000) &&
2387 !disableStatusMessages) {
2388 drawText(pix, srcPitch, 10, srcHeight - 20,
2389 screenMessageBuffer);
2390 } else {
2391 screenMessage = false;
2395 if(ifbFunction) {
2396 if(systemColorDepth == 16)
2397 ifbFunction(pix+destWidth+4, destWidth+4, srcWidth, srcHeight);
2398 else
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,
2406 srcWidth,
2407 srcHeight);
2408 else
2409 filterFunction(pix+destWidth*2+4,
2410 destWidth*2+4,
2411 delta,
2412 (u8*)VPIXELS,
2413 VPITCH,
2414 srcWidth,
2415 srcHeight);
2416 } else {
2417 int destPitch = VPITCH;
2418 u8 *src = pix;
2419 u8 *dest = (u8*)VPIXELS;
2420 int i;
2421 u32 *stretcher = (u32 *)sdlStretcher;
2422 if(systemColorDepth == 16)
2423 src += srcPitch;
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 ? */
2427 if(yuv)
2428 option = 0;
2429 #endif
2430 switch(VSCALE-1) {
2431 case 0:
2432 for(i = 0; i < srcHeight; i++) {
2433 SDL_CALL_STRETCHER;
2434 src += srcPitch;
2435 dest += destPitch;
2437 break;
2438 case 1:
2439 for(i = 0; i < srcHeight; i++) {
2440 SDL_CALL_STRETCHER;
2441 dest += destPitch;
2442 SDL_CALL_STRETCHER;
2443 src += srcPitch;
2444 dest += destPitch;
2446 break;
2447 case 2:
2448 for(i = 0; i < srcHeight; i++) {
2449 SDL_CALL_STRETCHER;
2450 dest += destPitch;
2451 SDL_CALL_STRETCHER;
2452 dest += destPitch;
2453 SDL_CALL_STRETCHER;
2454 src += srcPitch;
2455 dest += destPitch;
2457 break;
2458 case 3:
2459 for(i = 0; i < srcHeight; i++) {
2460 SDL_CALL_STRETCHER;
2461 dest += destPitch;
2462 SDL_CALL_STRETCHER;
2463 dest += destPitch;
2464 SDL_CALL_STRETCHER;
2465 dest += destPitch;
2466 SDL_CALL_STRETCHER;
2467 src += srcPitch;
2468 dest += destPitch;
2470 break;
2474 if(showSpeed && fullscreen) {
2475 char buffer[50];
2476 if(showSpeed == 1)
2477 sprintf(buffer, "%d%%", systemSpeed);
2478 else
2479 sprintf(buffer, "%3d%%(%d, %d fps)", systemSpeed,
2480 systemFrameSkip,
2481 showRenderedFrames);
2482 if(showSpeedTransparent)
2483 drawTextTransp((u8*)VPIXELS,
2484 VPITCH,
2486 VHEIGHT-20,
2487 buffer);
2488 else
2489 drawText((u8*)VPIXELS,
2490 VPITCH,
2492 VHEIGHT-20,
2493 buffer);
2496 #if SDL_MAJOR_VERSION == 2
2497 SDL_UnlockTexture(texture);
2498 SDL_RenderCopy(renderer, texture, NULL, NULL);
2499 SDL_RenderPresent(renderer);
2500 #else
2501 SDL_UnlockSurface(surface);
2502 // SDL_UpdateRect(surface, 0, 0, destWidth, destHeight);
2503 SDL_Flip(surface);
2504 #endif
2507 bool systemReadJoypads()
2509 return true;
2512 u32 systemReadJoypad(int which)
2514 if(which < 0 || which > 3)
2515 which = sdlDefaultJoypad;
2517 u32 res = 0;
2519 if(sdlButtons[which][KEY_BUTTON_A])
2520 res |= 1;
2521 if(sdlButtons[which][KEY_BUTTON_B])
2522 res |= 2;
2523 if(sdlButtons[which][KEY_BUTTON_SELECT])
2524 res |= 4;
2525 if(sdlButtons[which][KEY_BUTTON_START])
2526 res |= 8;
2527 if(sdlButtons[which][KEY_RIGHT])
2528 res |= 16;
2529 if(sdlButtons[which][KEY_LEFT])
2530 res |= 32;
2531 if(sdlButtons[which][KEY_UP])
2532 res |= 64;
2533 if(sdlButtons[which][KEY_DOWN])
2534 res |= 128;
2535 if(sdlButtons[which][KEY_BUTTON_R])
2536 res |= 256;
2537 if(sdlButtons[which][KEY_BUTTON_L])
2538 res |= 512;
2540 // disallow L+R or U+D of being pressed at the same time
2541 if((res & 48) == 48)
2542 res &= ~16;
2543 if((res & 192) == 192)
2544 res &= ~128;
2546 if(sdlButtons[which][KEY_BUTTON_SPEED])
2547 res |= 1024;
2548 if(sdlButtons[which][KEY_BUTTON_CAPTURE])
2549 res |= 2048;
2551 if(autoFire) {
2552 res &= (~autoFire);
2553 if(autoFireToggle)
2554 res |= autoFire;
2555 autoFireToggle = !autoFireToggle;
2558 return res;
2561 void systemSetTitle(const char *title) {
2562 sdlSetTitle(title);
2565 void systemShowSpeed(int speed)
2567 systemSpeed = speed;
2569 showRenderedFrames = renderedFrames;
2570 renderedFrames = 0;
2572 if(!fullscreen && showSpeed) {
2573 char buffer[80];
2574 if(showSpeed == 1)
2575 sprintf(buffer, "VisualBoyAdvance-%3d%%", systemSpeed);
2576 else
2577 sprintf(buffer, "VisualBoyAdvance-%3d%%(%d, %d fps)", systemSpeed,
2578 systemFrameSkip,
2579 showRenderedFrames);
2581 systemSetTitle(buffer);
2585 void systemFrame()
2589 void system10Frames(int rate)
2591 u32 time = systemGetClock();
2592 if(!wasPaused && autoFrameSkip && !throttle) {
2593 u32 diff = time - autoFrameSkipLastTime;
2594 int speed = 100;
2596 if(diff)
2597 speed = (1000000/rate)/diff;
2599 if(speed >= 98) {
2600 frameskipadjust++;
2602 if(frameskipadjust >= 3) {
2603 frameskipadjust=0;
2604 if(systemFrameSkip > 0)
2605 systemFrameSkip--;
2607 } else {
2608 if(speed < 80)
2609 frameskipadjust -= (90 - speed)/5;
2610 else if(systemFrameSkip < 9)
2611 frameskipadjust--;
2613 if(frameskipadjust <= -2) {
2614 frameskipadjust += 2;
2615 if(systemFrameSkip < 9)
2616 systemFrameSkip++;
2620 if(!wasPaused && throttle) {
2621 if(!speedup) {
2622 u32 diff = time - throttleLastTime;
2624 int target = (1000000/(rate*throttle));
2625 int d = (target - diff);
2627 if(d > 0) {
2628 SDL_Delay(d);
2631 throttleLastTime = systemGetClock();
2633 if(rewindMemory) {
2634 if(++rewindCounter >= rewindTimer) {
2635 rewindSaveNeeded = true;
2636 rewindCounter = 0;
2640 if(systemSaveUpdateCounter) {
2641 if(--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED) {
2642 sdlWriteBattery();
2643 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
2647 wasPaused = false;
2648 autoFrameSkipLastTime = time;
2651 void systemScreenCapture(int a)
2653 char buffer[2048];
2655 if(captureFormat) {
2656 if(captureDir[0])
2657 sprintf(buffer, "%s/%s%02d.bmp", captureDir, sdlGetFilename(filename), a);
2658 else
2659 sprintf(buffer, "%s%02d.bmp", filename, a);
2661 emulator.emuWriteBMP(buffer);
2662 } else {
2663 if(captureDir[0])
2664 sprintf(buffer, "%s/%s%02d.png", captureDir, sdlGetFilename(filename), a);
2665 else
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)
2675 if (!emulating)
2676 return;
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
2681 * stay in sync */
2682 bool lock = (!speedup && !throttle) ? true : false;
2684 if (lock)
2685 SDL_SemWait (sdlBufferFull);
2687 SDL_SemWait (sdlBufferLock);
2688 memcpy (stream, sdlBuffer, len);
2689 sdlSoundLen = 0;
2690 SDL_SemPost (sdlBufferLock);
2692 if (lock)
2693 SDL_SemPost (sdlBufferEmpty);
2696 void systemWriteDataToSoundBuffer()
2698 // Patch #1382692 by deathpudding.
2699 if (SDL_GetAudioStatus () != SDL_AUDIO_PLAYING)
2700 SDL_PauseAudio (0);
2702 if ((sdlSoundLen + soundBufferLen) >= 2048*2) {
2703 bool lock = (!speedup && !throttle) ? true : false;
2705 if (lock)
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);
2714 if (lock) {
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);
2727 else {
2728 SDL_SemWait (sdlBufferLock);
2729 memcpy (sdlBuffer, ((u8 *) soundFinalWave) + copied, soundBufferLen);
2730 SDL_SemPost (sdlBufferLock);
2733 else {
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) {
2746 case 1:
2747 audio.freq = 44100;
2748 soundBufferLen = 1470*2;
2749 break;
2750 case 2:
2751 audio.freq = 22050;
2752 soundBufferLen = 736*2;
2753 break;
2754 case 4:
2755 audio.freq = 11025;
2756 soundBufferLen = 368*2;
2757 break;
2759 audio.format=AUDIO_S16SYS;
2760 audio.channels = 2;
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());
2766 return false;
2768 soundBufferTotalLen = soundBufferLen*10;
2769 // Patch #1382692 by deathpudding.
2770 sdlBufferLock = SDL_CreateSemaphore (1);
2771 sdlBufferFull = SDL_CreateSemaphore (0);
2772 sdlBufferEmpty = SDL_CreateSemaphore (1);
2773 sdlSoundLen = 0;
2774 systemSoundOn = true;
2775 return true;
2778 void systemSoundShutdown()
2780 SDL_SemPost (sdlBufferFull); // fix freeze by deathpudding
2782 // Patch #1382692 by deathpudding.
2783 SDL_CloseAudio ();
2785 SDL_DestroySemaphore (sdlBufferLock);
2786 SDL_DestroySemaphore (sdlBufferFull);
2787 SDL_DestroySemaphore (sdlBufferEmpty);
2788 sdlBufferLock = NULL;
2789 sdlBufferFull = NULL;
2790 sdlBufferEmpty = NULL;
2793 void systemSoundPause()
2795 SDL_PauseAudio(1);
2798 void systemSoundResume()
2800 SDL_PauseAudio(0);
2803 void systemSoundReset()
2807 u32 systemGetClock()
2809 return SDL_GetTicks();
2812 void systemUpdateMotionSensor()
2814 if(sdlMotionButtons[KEY_LEFT]) {
2815 sensorX += 3;
2816 if(sensorX > 2197)
2817 sensorX = 2197;
2818 if(sensorX < 2047)
2819 sensorX = 2057;
2820 } else if(sdlMotionButtons[KEY_RIGHT]) {
2821 sensorX -= 3;
2822 if(sensorX < 1897)
2823 sensorX = 1897;
2824 if(sensorX > 2047)
2825 sensorX = 2037;
2826 } else if(sensorX > 2047) {
2827 sensorX -= 2;
2828 if(sensorX < 2047)
2829 sensorX = 2047;
2830 } else {
2831 sensorX += 2;
2832 if(sensorX > 2047)
2833 sensorX = 2047;
2836 if(sdlMotionButtons[KEY_UP]) {
2837 sensorY += 3;
2838 if(sensorY > 2197)
2839 sensorY = 2197;
2840 if(sensorY < 2047)
2841 sensorY = 2057;
2842 } else if(sdlMotionButtons[KEY_DOWN]) {
2843 sensorY -= 3;
2844 if(sensorY < 1897)
2845 sensorY = 1897;
2846 if(sensorY > 2047)
2847 sensorY = 2037;
2848 } else if(sensorY > 2047) {
2849 sensorY -= 2;
2850 if(sensorY < 2047)
2851 sensorY = 2047;
2852 } else {
2853 sensorY += 2;
2854 if(sensorY > 2047)
2855 sensorY = 2047;
2859 int systemGetSensorX()
2861 return sensorX;
2864 int systemGetSensorY()
2866 return sensorY;
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;
2880 } else
2881 strcpy(screenMessageBuffer, msg);
2884 bool systemCanChangeSoundQuality()
2886 return false;
2889 bool systemPauseOnFrame()
2891 if(pauseNextFrame) {
2892 paused = true;
2893 pauseNextFrame = false;
2894 return true;
2896 return false;
2899 #if SDL_MAJOR_VERSION != 2 /* start SDL1.2 YUV code */
2901 // Code donated by Niels Wagenaar (BoycottAdvance)
2903 // GBA screensize.
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,
2911 GBA_HEIGHT,
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":
2921 "Unknown");
2924 void Quit_Overlay(void)
2927 SDL_FreeYUVOverlay(overlay);
2930 /* NOTE: These RGB conversion functions are not intended for speed,
2931 only as examples.
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)
2942 int x,y;
2943 int yuv[3];
2944 Uint8 *p,*op[3];
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));
2955 /* Convert */
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++) {
2962 RGBtoYUV(p,yuv);
2963 *(op[0]++)=yuv[0];
2964 if(x%2==0 && y%2==0) {
2965 *(op[1]++)=yuv[2];
2966 *(op[2]++)=yuv[1];
2968 p+=4;//s->format->BytesPerPixel;
2972 SDL_UnlockYUVOverlay(o);
2975 static inline void ConvertRGBtoIYUV(SDL_Overlay *o)
2977 int x,y;
2978 int yuv[3];
2979 Uint8 *p,*op[3];
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));
2990 /* Convert */
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++) {
2997 RGBtoYUV(p,yuv);
2998 *(op[0]++)=yuv[0];
2999 if(x%2==0 && y%2==0) {
3000 *(op[1]++)=yuv[1];
3001 *(op[2]++)=yuv[2];
3003 p+=4; //s->format->BytesPerPixel;
3007 SDL_UnlockYUVOverlay(o);
3010 static inline void ConvertRGBtoUYVY(SDL_Overlay *o)
3012 int x,y;
3013 int yuv[3];
3014 Uint8 *p,*op;
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++) {
3022 RGBtoYUV(p,yuv);
3023 if(x%2==0) {
3024 *(op++)=yuv[1];
3025 *(op++)=yuv[0];
3026 *(op++)=yuv[2];
3027 } else
3028 *(op++)=yuv[0];
3030 p+=4; //s->format->BytesPerPixel;
3034 SDL_UnlockYUVOverlay(o);
3037 static inline void ConvertRGBtoYVYU(SDL_Overlay *o)
3039 int x,y;
3040 int yuv[3];
3041 Uint8 *p,*op;
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++) {
3049 RGBtoYUV(p,yuv);
3050 if(x%2==0) {
3051 *(op++)=yuv[0];
3052 *(op++)=yuv[2];
3053 op[1]=yuv[1];
3054 } else {
3055 *op=yuv[0];
3056 op+=2;
3059 p+=4; //s->format->BytesPerPixel;
3063 SDL_UnlockYUVOverlay(o);
3066 static inline void ConvertRGBtoYUY2(SDL_Overlay *o)
3068 int x,y;
3069 int yuv[3];
3070 Uint8 *p,*op;
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++) {
3078 RGBtoYUV(p,yuv);
3079 if(x%2==0) {
3080 *(op++)=yuv[0];
3081 *(op++)=yuv[1];
3082 op[1]=yuv[2];
3083 } else {
3084 *op=yuv[0];
3085 op+=2;
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);
3100 break;
3101 case SDL_UYVY_OVERLAY:
3102 ConvertRGBtoUYVY(overlay);
3103 break;
3104 case SDL_YVYU_OVERLAY:
3105 ConvertRGBtoYVYU(overlay);
3106 break;
3107 case SDL_YUY2_OVERLAY:
3108 ConvertRGBtoYUY2(overlay);
3109 break;
3110 case SDL_IYUV_OVERLAY:
3111 ConvertRGBtoIYUV(overlay);
3112 break;
3113 default:
3114 fprintf(stderr, "cannot convert RGB picture to obtained YUV format!\n");
3115 exit(1);
3116 break;
3122 static inline void Draw_Overlay(SDL_Surface *display, int size)
3124 SDL_LockYUVOverlay(overlay);
3126 Convert32bit(display);
3128 overlay_rect.x = 0;
3129 overlay_rect.y = 0;
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);
3139 return yuv;
3141 #endif /* end SDL1.2 YUV code */
3144 void systemGbBorderOn()
3146 fprintf(stderr,
3147 "turning SGB border on at runtime not supported.\n"
3148 "set it as command line option instead!\n");
3149 gbBorderOn = 0;