home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Freeware / Utilitare / VisualBoyAdvance-1.7.2 / src / sdl / SDL.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-05-21  |  83.2 KB  |  3,443 lines

  1. // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
  2. // Copyright (C) 1999-2003 Forgotten
  3. // Copyright (C) 2004 Forgotten and the VBA development team
  4.  
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 2, or(at your option)
  8. // any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software Foundation,
  17. // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18.  
  19. #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>
  25.  
  26. #include "AutoBuild.h"
  27.  
  28. #include "SDL.h"
  29. #include "GBA.h"
  30. #include "agbprint.h"
  31. #include "Flash.h"
  32. #include "Port.h"
  33. #include "debugger.h"
  34. #include "RTC.h"
  35. #include "Sound.h"
  36. #include "Text.h"
  37. #include "unzip.h"
  38. #include "Util.h"
  39. #include "gb/GB.h"
  40. #include "gb/gbGlobals.h"
  41.  
  42. #ifndef WIN32
  43. # include <unistd.h>
  44. # define GETCWD getcwd
  45. #else // WIN32
  46. # include <direct.h>
  47. # define GETCWD _getcwd
  48. #endif // WIN32
  49.  
  50. #ifndef __GNUC__
  51. # define HAVE_DECL_GETOPT 0
  52. # define __STDC__ 1
  53. # include "getopt.h"
  54. #else // ! __GNUC__
  55. # define HAVE_DECL_GETOPT 1
  56. # include "getopt.h"
  57. #endif // ! __GNUC__
  58.  
  59. #ifdef MMX
  60. extern "C" bool cpu_mmx;
  61. #endif
  62. extern bool soundEcho;
  63. extern bool soundLowPass;
  64. extern bool soundReverse;
  65. extern int Init_2xSaI(u32);
  66. extern void _2xSaI(u8*,u32,u8*,u8*,u32,int,int);
  67. extern void _2xSaI32(u8*,u32,u8*,u8*,u32,int,int);  
  68. extern void Super2xSaI(u8*,u32,u8*,u8*,u32,int,int);
  69. extern void Super2xSaI32(u8*,u32,u8*,u8*,u32,int,int);
  70. extern void SuperEagle(u8*,u32,u8*,u8*,u32,int,int);
  71. extern void SuperEagle32(u8*,u32,u8*,u8*,u32,int,int);  
  72. extern void Pixelate(u8*,u32,u8*,u8*,u32,int,int);
  73. extern void Pixelate32(u8*,u32,u8*,u8*,u32,int,int);
  74. extern void MotionBlur(u8*,u32,u8*,u8*,u32,int,int);
  75. extern void MotionBlur32(u8*,u32,u8*,u8*,u32,int,int);
  76. extern void AdMame2x(u8*,u32,u8*,u8*,u32,int,int);
  77. extern void AdMame2x32(u8*,u32,u8*,u8*,u32,int,int);
  78. extern void Simple2x(u8*,u32,u8*,u8*,u32,int,int);
  79. extern void Simple2x32(u8*,u32,u8*,u8*,u32,int,int);
  80. extern void Bilinear(u8*,u32,u8*,u8*,u32,int,int);
  81. extern void Bilinear32(u8*,u32,u8*,u8*,u32,int,int);
  82. extern void BilinearPlus(u8*,u32,u8*,u8*,u32,int,int);
  83. extern void BilinearPlus32(u8*,u32,u8*,u8*,u32,int,int);
  84. extern void Scanlines(u8*,u32,u8*,u8*,u32,int,int);
  85. extern void Scanlines32(u8*,u32,u8*,u8*,u32,int,int);
  86. extern void ScanlinesTV(u8*,u32,u8*,u8*,u32,int,int);
  87. extern void ScanlinesTV32(u8*,u32,u8*,u8*,u32,int,int);
  88. extern void hq2x(u8*,u32,u8*,u8*,u32,int,int);
  89. extern void hq2x32(u8*,u32,u8*,u8*,u32,int,int);
  90. extern void lq2x(u8*,u32,u8*,u8*,u32,int,int);
  91. extern void lq2x32(u8*,u32,u8*,u8*,u32,int,int);
  92.  
  93. extern void SmartIB(u8*,u32,int,int);
  94. extern void SmartIB32(u8*,u32,int,int);
  95. extern void MotionBlurIB(u8*,u32,int,int);
  96. extern void MotionBlurIB32(u8*,u32,int,int);
  97.  
  98. void Init_Overlay(SDL_Surface *surface, int overlaytype);
  99. void Quit_Overlay(void);
  100. void Draw_Overlay(SDL_Surface *surface, int size);
  101.  
  102. extern void remoteInit();
  103. extern void remoteCleanUp();
  104. extern void remoteStubMain();
  105. extern void remoteStubSignal(int,int);
  106. extern void remoteOutput(char *, u32);
  107. extern void remoteSetProtocol(int);
  108. extern void remoteSetPort(int);
  109. extern void debuggerOutput(char *, u32);
  110.  
  111. extern void CPUUpdateRenderBuffers(bool);
  112.  
  113. struct EmulatedSystem emulator = {
  114.   NULL,
  115.   NULL,
  116.   NULL,
  117.   NULL,
  118.   NULL,
  119.   NULL,
  120.   NULL,
  121.   NULL,
  122.   NULL,
  123.   NULL,
  124.   NULL,
  125.   NULL,
  126.   false,
  127.   0
  128. };
  129.  
  130. SDL_Surface *surface = NULL;
  131. SDL_Overlay *overlay = NULL;
  132. SDL_Rect overlay_rect;
  133.  
  134. int systemSpeed = 0;
  135. int systemRedShift = 0;
  136. int systemBlueShift = 0;
  137. int systemGreenShift = 0;
  138. int systemColorDepth = 0;
  139. int systemDebug = 0;
  140. int systemVerbose = 0;
  141. int systemFrameSkip = 0;
  142. int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
  143.  
  144. int srcPitch = 0;
  145. int srcWidth = 0;
  146. int srcHeight = 0;
  147. int destWidth = 0;
  148. int destHeight = 0;
  149.  
  150. int sensorX = 2047;
  151. int sensorY = 2047;
  152.  
  153. int filter = 0;
  154. u8 *delta = NULL;
  155.  
  156. int sdlPrintUsage = 0;
  157. int disableMMX = 0;
  158.  
  159. int cartridgeType = 3;
  160. int sizeOption = 0;
  161. int captureFormat = 0;
  162.  
  163. int pauseWhenInactive = 0;
  164. int active = 1;
  165. int emulating = 0;
  166. int RGB_LOW_BITS_MASK=0x821;
  167. u32 systemColorMap32[0x10000];
  168. u16 systemColorMap16[0x10000];
  169. u16 systemGbPalette[24];
  170. void (*filterFunction)(u8*,u32,u8*,u8*,u32,int,int) = NULL;
  171. void (*ifbFunction)(u8*,u32,int,int) = NULL;
  172. int ifbType = 0;
  173. char filename[2048];
  174. char ipsname[2048];
  175. char biosFileName[2048];
  176. char captureDir[2048];
  177. char saveDir[2048];
  178. char batteryDir[2048];
  179.  
  180. static char *rewindMemory = NULL;
  181. static int rewindPos = 0;
  182. static int rewindTopPos = 0;
  183. static int rewindCounter = 0;
  184. static int rewindCount = 0;
  185. static bool rewindSaveNeeded = false;
  186. static int rewindTimer = 0;
  187.  
  188. #define REWIND_SIZE 400000
  189.  
  190. #define _stricmp strcasecmp
  191.  
  192. bool sdlButtons[4][12] = {
  193.   { false, false, false, false, false, false, 
  194.     false, false, false, false, false, false },
  195.   { false, false, false, false, false, false,
  196.     false, false, false, false, false, false },
  197.   { false, false, false, false, false, false,
  198.     false, false, false, false, false, false },
  199.   { false, false, false, false, false, false,
  200.     false, false, false, false, false, false }
  201. };
  202.  
  203. bool sdlMotionButtons[4] = { false, false, false, false };
  204.  
  205. int sdlNumDevices = 0;
  206. SDL_Joystick **sdlDevices = NULL;
  207.  
  208. bool wasPaused = false;
  209. int autoFrameSkip = 0;
  210. int frameskipadjust = 0;
  211. int showRenderedFrames = 0;
  212. int renderedFrames = 0;
  213.  
  214. int throttle = 0;
  215. u32 throttleLastTime = 0;
  216. u32 autoFrameSkipLastTime = 0;
  217.  
  218. int showSpeed = 1;
  219. int showSpeedTransparent = 1;
  220. bool disableStatusMessages = false;
  221. bool paused = false;
  222. bool pauseNextFrame = false;
  223. bool debugger = false;
  224. bool debuggerStub = false;
  225. int fullscreen = 0;
  226. bool systemSoundOn = false;
  227. bool yuv = false;
  228. int yuvType = 0;
  229. bool removeIntros = false;
  230. int sdlFlashSize = 0;
  231. int sdlAutoIPS = 1;
  232. int sdlRtcEnable = 0;
  233. int sdlAgbPrint = 0;
  234.  
  235. int sdlDefaultJoypad = 0;
  236.  
  237. extern void debuggerSignal(int,int);
  238.  
  239. void (*dbgMain)() = debuggerMain;
  240. void (*dbgSignal)(int,int) = debuggerSignal;
  241. void (*dbgOutput)(char *, u32) = debuggerOutput;
  242.  
  243. int  mouseCounter = 0;
  244. int autoFire = 0;
  245. bool autoFireToggle = false;
  246.  
  247. bool screenMessage = false;
  248. char screenMessageBuffer[21];
  249. u32  screenMessageTime = 0;
  250.  
  251. SDL_cond *cond = NULL;
  252. SDL_mutex *mutex = NULL;
  253. u8 sdlBuffer[4096];
  254. int sdlSoundLen = 0;
  255.  
  256. char *arg0;
  257.  
  258. #ifndef C_CORE
  259. u8 sdlStretcher[16384];
  260. int sdlStretcherPos;
  261. #else
  262. void (*sdlStretcher)(u8 *, u8*) = NULL;
  263. #endif
  264.  
  265. enum {
  266.   KEY_LEFT, KEY_RIGHT,
  267.   KEY_UP, KEY_DOWN,
  268.   KEY_BUTTON_A, KEY_BUTTON_B,
  269.   KEY_BUTTON_START, KEY_BUTTON_SELECT,
  270.   KEY_BUTTON_L, KEY_BUTTON_R,
  271.   KEY_BUTTON_SPEED, KEY_BUTTON_CAPTURE
  272. };
  273.  
  274. u16 joypad[4][12] = {
  275.   { SDLK_LEFT,  SDLK_RIGHT,
  276.     SDLK_UP,    SDLK_DOWN,
  277.     SDLK_z,     SDLK_x,
  278.     SDLK_RETURN,SDLK_BACKSPACE,
  279.     SDLK_a,     SDLK_s,
  280.     SDLK_SPACE, SDLK_F12
  281.   },
  282.   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  283.   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
  284.   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
  285. };
  286.  
  287. u16 defaultJoypad[12] = {
  288.   SDLK_LEFT,  SDLK_RIGHT,
  289.   SDLK_UP,    SDLK_DOWN,
  290.   SDLK_z,     SDLK_x,
  291.   SDLK_RETURN,SDLK_BACKSPACE,
  292.   SDLK_a,     SDLK_s,
  293.   SDLK_SPACE, SDLK_F12
  294. };
  295.  
  296. u16 motion[4] = {
  297.   SDLK_KP4, SDLK_KP6, SDLK_KP8, SDLK_KP2
  298. };
  299.  
  300. u16 defaultMotion[4] = {
  301.   SDLK_KP4, SDLK_KP6, SDLK_KP8, SDLK_KP2
  302. };
  303.  
  304. struct option sdlOptions[] = {
  305.   { "agb-print", no_argument, &sdlAgbPrint, 1 },
  306.   { "auto-frameskip", no_argument, &autoFrameSkip, 1 },  
  307.   { "bios", required_argument, 0, 'b' },
  308.   { "config", required_argument, 0, 'c' },
  309.   { "debug", no_argument, 0, 'd' },
  310.   { "filter", required_argument, 0, 'f' },
  311.   { "filter-normal", no_argument, &filter, 0 },
  312.   { "filter-tv-mode", no_argument, &filter, 1 },
  313.   { "filter-2xsai", no_argument, &filter, 2 },
  314.   { "filter-super-2xsai", no_argument, &filter, 3 },
  315.   { "filter-super-eagle", no_argument, &filter, 4 },
  316.   { "filter-pixelate", no_argument, &filter, 5 },
  317.   { "filter-motion-blur", no_argument, &filter, 6 },
  318.   { "filter-advmame", no_argument, &filter, 7 },
  319.   { "filter-simple2x", no_argument, &filter, 8 },
  320.   { "filter-bilinear", no_argument, &filter, 9 },
  321.   { "filter-bilinear+", no_argument, &filter, 10 },
  322.   { "filter-scanlines", no_argument, &filter, 11 },
  323.   { "filter-hq2x", no_argument, &filter, 12 },
  324.   { "filter-lq2x", no_argument, &filter, 13 },
  325.   { "flash-size", required_argument, 0, 'S' },
  326.   { "flash-64k", no_argument, &sdlFlashSize, 0 },
  327.   { "flash-128k", no_argument, &sdlFlashSize, 1 },
  328.   { "frameskip", required_argument, 0, 's' },
  329.   { "fullscreen", no_argument, &fullscreen, 1 },
  330.   { "gdb", required_argument, 0, 'G' },
  331.   { "help", no_argument, &sdlPrintUsage, 1 },
  332.   { "ifb-none", no_argument, &ifbType, 0 },
  333.   { "ifb-motion-blur", no_argument, &ifbType, 1 },
  334.   { "ifb-smart", no_argument, &ifbType, 2 },
  335.   { "ips", required_argument, 0, 'i' },
  336.   { "no-agb-print", no_argument, &sdlAgbPrint, 0 },
  337.   { "no-auto-frameskip", no_argument, &autoFrameSkip, 0 },
  338.   { "no-debug", no_argument, 0, 'N' },
  339.   { "no-ips", no_argument, &sdlAutoIPS, 0 },
  340.   { "no-mmx", no_argument, &disableMMX, 1 },
  341.   { "no-pause-when-inactive", no_argument, &pauseWhenInactive, 0 },
  342.   { "no-rtc", no_argument, &sdlRtcEnable, 0 },
  343.   { "no-show-speed", no_argument, &showSpeed, 0 },
  344.   { "no-throttle", no_argument, &throttle, 0 },
  345.   { "pause-when-inactive", no_argument, &pauseWhenInactive, 1 },
  346.   { "profile", optional_argument, 0, 'p' },
  347.   { "rtc", no_argument, &sdlRtcEnable, 1 },
  348.   { "save-type", required_argument, 0, 't' },
  349.   { "save-auto", no_argument, &cpuSaveType, 0 },
  350.   { "save-eeprom", no_argument, &cpuSaveType, 1 },
  351.   { "save-sram", no_argument, &cpuSaveType, 2 },
  352.   { "save-flash", no_argument, &cpuSaveType, 3 },
  353.   { "save-sensor", no_argument, &cpuSaveType, 4 },
  354.   { "save-none", no_argument, &cpuSaveType, 5 },
  355.   { "show-speed-normal", no_argument, &showSpeed, 1 },
  356.   { "show-speed-detailed", no_argument, &showSpeed, 2 },
  357.   { "throttle", required_argument, 0, 'T' },
  358.   { "verbose", required_argument, 0, 'v' },  
  359.   { "video-1x", no_argument, &sizeOption, 0 },
  360.   { "video-2x", no_argument, &sizeOption, 1 },
  361.   { "video-3x", no_argument, &sizeOption, 2 },
  362.   { "video-4x", no_argument, &sizeOption, 3 },
  363.   { "yuv", required_argument, 0, 'Y' },
  364.   { NULL, no_argument, NULL, 0 }
  365. };
  366.  
  367. extern bool CPUIsGBAImage(char *);
  368. extern bool gbIsGameboyRom(char *);
  369.  
  370. #ifndef C_CORE
  371. #define SDL_LONG(val) \
  372.   *((u32 *)&sdlStretcher[sdlStretcherPos]) = val;\
  373.   sdlStretcherPos+=4;
  374.  
  375. #define SDL_AND_EAX(val) \
  376.   sdlStretcher[sdlStretcherPos++] = 0x25;\
  377.   SDL_LONG(val);
  378.  
  379. #define SDL_AND_EBX(val) \
  380.   sdlStretcher[sdlStretcherPos++] = 0x81;\
  381.   sdlStretcher[sdlStretcherPos++] = 0xe3;\
  382.   SDL_LONG(val);
  383.  
  384. #define SDL_OR_EAX_EBX \
  385.   sdlStretcher[sdlStretcherPos++] = 0x09;\
  386.   sdlStretcher[sdlStretcherPos++] = 0xd8;
  387.  
  388. #define SDL_LOADL_EBX \
  389.   sdlStretcher[sdlStretcherPos++] = 0x8b;\
  390.   sdlStretcher[sdlStretcherPos++] = 0x1f;
  391.  
  392. #define SDL_LOADW \
  393.   sdlStretcher[sdlStretcherPos++] = 0x66;\
  394.   sdlStretcher[sdlStretcherPos++] = 0x8b;\
  395.   sdlStretcher[sdlStretcherPos++] = 0x06;\
  396.   sdlStretcher[sdlStretcherPos++] = 0x83;\
  397.   sdlStretcher[sdlStretcherPos++] = 0xc6;\
  398.   sdlStretcher[sdlStretcherPos++] = 0x02;  
  399.  
  400. #define SDL_LOADL \
  401.   sdlStretcher[sdlStretcherPos++] = 0x8b;\
  402.   sdlStretcher[sdlStretcherPos++] = 0x06;\
  403.   sdlStretcher[sdlStretcherPos++] = 0x83;\
  404.   sdlStretcher[sdlStretcherPos++] = 0xc6;\
  405.   sdlStretcher[sdlStretcherPos++] = 0x04;  
  406.  
  407. #define SDL_LOADL2 \
  408.   sdlStretcher[sdlStretcherPos++] = 0x8b;\
  409.   sdlStretcher[sdlStretcherPos++] = 0x06;\
  410.   sdlStretcher[sdlStretcherPos++] = 0x83;\
  411.   sdlStretcher[sdlStretcherPos++] = 0xc6;\
  412.   sdlStretcher[sdlStretcherPos++] = 0x03;  
  413.  
  414. #define SDL_STOREW \
  415.   sdlStretcher[sdlStretcherPos++] = 0x66;\
  416.   sdlStretcher[sdlStretcherPos++] = 0x89;\
  417.   sdlStretcher[sdlStretcherPos++] = 0x07;\
  418.   sdlStretcher[sdlStretcherPos++] = 0x83;\
  419.   sdlStretcher[sdlStretcherPos++] = 0xc7;\
  420.   sdlStretcher[sdlStretcherPos++] = 0x02;  
  421.  
  422. #define SDL_STOREL \
  423.   sdlStretcher[sdlStretcherPos++] = 0x89;\
  424.   sdlStretcher[sdlStretcherPos++] = 0x07;\
  425.   sdlStretcher[sdlStretcherPos++] = 0x83;\
  426.   sdlStretcher[sdlStretcherPos++] = 0xc7;\
  427.   sdlStretcher[sdlStretcherPos++] = 0x04;  
  428.  
  429. #define SDL_STOREL2 \
  430.   sdlStretcher[sdlStretcherPos++] = 0x89;\
  431.   sdlStretcher[sdlStretcherPos++] = 0x07;\
  432.   sdlStretcher[sdlStretcherPos++] = 0x83;\
  433.   sdlStretcher[sdlStretcherPos++] = 0xc7;\
  434.   sdlStretcher[sdlStretcherPos++] = 0x03;  
  435.  
  436. #define SDL_RET \
  437.   sdlStretcher[sdlStretcherPos++] = 0xc3;
  438.  
  439. #define SDL_PUSH_EAX \
  440.   sdlStretcher[sdlStretcherPos++] = 0x50;
  441.  
  442. #define SDL_PUSH_ECX \
  443.   sdlStretcher[sdlStretcherPos++] = 0x51;
  444.  
  445. #define SDL_PUSH_EBX \
  446.   sdlStretcher[sdlStretcherPos++] = 0x53;
  447.  
  448. #define SDL_PUSH_ESI \
  449.   sdlStretcher[sdlStretcherPos++] = 0x56;
  450.  
  451. #define SDL_PUSH_EDI \
  452.   sdlStretcher[sdlStretcherPos++] = 0x57;
  453.  
  454. #define SDL_POP_EAX \
  455.   sdlStretcher[sdlStretcherPos++] = 0x58;
  456.  
  457. #define SDL_POP_ECX \
  458.   sdlStretcher[sdlStretcherPos++] = 0x59;
  459.  
  460. #define SDL_POP_EBX \
  461.   sdlStretcher[sdlStretcherPos++] = 0x5b;
  462.  
  463. #define SDL_POP_ESI \
  464.   sdlStretcher[sdlStretcherPos++] = 0x5e;
  465.  
  466. #define SDL_POP_EDI \
  467.   sdlStretcher[sdlStretcherPos++] = 0x5f;
  468.  
  469. #define SDL_MOV_ECX(val) \
  470.   sdlStretcher[sdlStretcherPos++] = 0xb9;\
  471.   SDL_LONG(val);
  472.  
  473. #define SDL_REP_MOVSB \
  474.   sdlStretcher[sdlStretcherPos++] = 0xf3;\
  475.   sdlStretcher[sdlStretcherPos++] = 0xa4;
  476.  
  477. #define SDL_REP_MOVSW \
  478.   sdlStretcher[sdlStretcherPos++] = 0xf3;\
  479.   sdlStretcher[sdlStretcherPos++] = 0x66;\
  480.   sdlStretcher[sdlStretcherPos++] = 0xa5;
  481.  
  482. #define SDL_REP_MOVSL \
  483.   sdlStretcher[sdlStretcherPos++] = 0xf3;\
  484.   sdlStretcher[sdlStretcherPos++] = 0xa5;
  485.  
  486. void sdlMakeStretcher(int width)
  487. {
  488.   sdlStretcherPos = 0;
  489.   switch(systemColorDepth) {
  490.   case 16:
  491.     if(sizeOption) {
  492.       SDL_PUSH_EAX;
  493.       SDL_PUSH_ESI;
  494.       SDL_PUSH_EDI;
  495.       for(int i = 0; i < width; i++) {
  496.         SDL_LOADW;
  497.         SDL_STOREW;
  498.         SDL_STOREW;
  499.         if(sizeOption > 1) {
  500.           SDL_STOREW;
  501.         }
  502.         if(sizeOption > 2) {
  503.           SDL_STOREW;
  504.         }
  505.       }
  506.       SDL_POP_EDI;
  507.       SDL_POP_ESI;
  508.       SDL_POP_EAX;
  509.       SDL_RET;
  510.     } else {
  511.       SDL_PUSH_ESI;
  512.       SDL_PUSH_EDI;
  513.       SDL_PUSH_ECX;
  514.       SDL_MOV_ECX(width);
  515.       SDL_REP_MOVSW;
  516.       SDL_POP_ECX;
  517.       SDL_POP_EDI;
  518.       SDL_POP_ESI;
  519.       SDL_RET;
  520.     }
  521.     break;
  522.   case 24:
  523.     if(sizeOption) {
  524.       SDL_PUSH_EAX;
  525.       SDL_PUSH_ESI;
  526.       SDL_PUSH_EDI;
  527.       int w = width - 1;
  528.       for(int i = 0; i < w; i++) {
  529.         SDL_LOADL2;
  530.         SDL_STOREL2;
  531.         SDL_STOREL2;
  532.         if(sizeOption > 1) {
  533.           SDL_STOREL2;
  534.         }
  535.         if(sizeOption > 2) {
  536.           SDL_STOREL2;
  537.         }
  538.       }
  539.       // need to write the last one
  540.       SDL_LOADL2;
  541.       SDL_STOREL2;
  542.       if(sizeOption > 1) {
  543.         SDL_STOREL2;
  544.       }
  545.       if(sizeOption > 2) {
  546.         SDL_STOREL2;
  547.       }
  548.       SDL_AND_EAX(0x00ffffff);
  549.       SDL_PUSH_EBX;
  550.       SDL_LOADL_EBX;
  551.       SDL_AND_EBX(0xff000000);
  552.       SDL_OR_EAX_EBX;
  553.       SDL_POP_EBX;
  554.       SDL_STOREL2;
  555.       SDL_POP_EDI;
  556.       SDL_POP_ESI;
  557.       SDL_POP_EAX;
  558.       SDL_RET;
  559.     } else {
  560.       SDL_PUSH_ESI;
  561.       SDL_PUSH_EDI;
  562.       SDL_PUSH_ECX;
  563.       SDL_MOV_ECX(3*width);
  564.       SDL_REP_MOVSB;
  565.       SDL_POP_ECX;
  566.       SDL_POP_EDI;
  567.       SDL_POP_ESI;
  568.       SDL_RET;
  569.     }
  570.     break;
  571.   case 32:
  572.     if(sizeOption) {
  573.       SDL_PUSH_EAX;
  574.       SDL_PUSH_ESI;
  575.       SDL_PUSH_EDI;
  576.       for(int i = 0; i < width; i++) {
  577.         SDL_LOADL;
  578.         SDL_STOREL;
  579.         SDL_STOREL;
  580.         if(sizeOption > 1) {
  581.           SDL_STOREL;
  582.         }
  583.         if(sizeOption > 2) {
  584.           SDL_STOREL;
  585.         }
  586.       }
  587.       SDL_POP_EDI;
  588.       SDL_POP_ESI;
  589.       SDL_POP_EAX;
  590.       SDL_RET;
  591.     } else {
  592.       SDL_PUSH_ESI;
  593.       SDL_PUSH_EDI;
  594.       SDL_PUSH_ECX;
  595.       SDL_MOV_ECX(width);
  596.       SDL_REP_MOVSL;
  597.       SDL_POP_ECX;
  598.       SDL_POP_EDI;
  599.       SDL_POP_ESI;
  600.       SDL_RET;
  601.     }
  602.     break;
  603.   }
  604. }
  605.  
  606. #ifdef _MSC_VER
  607. #define SDL_CALL_STRETCHER \
  608.   {\
  609.     __asm mov eax, stretcher\
  610.     __asm mov edi, dest\
  611.     __asm mov esi, src\
  612.     __asm call eax\
  613.   }
  614. #else
  615. #define SDL_CALL_STRETCHER \
  616.         asm volatile("call *%%eax"::"a" (stretcher),"S" (src),"D" (dest))
  617. #endif
  618. #else
  619. #define SDL_CALL_STRETCHER \
  620.        sdlStretcher(src, dest)
  621.  
  622. void sdlStretch16x1(u8 *src, u8 *dest)
  623. {
  624.   u16 *s = (u16 *)src;
  625.   u16 *d = (u16 *)dest;
  626.   for(int i = 0; i < srcWidth; i++)
  627.     *d++ = *s++;
  628. }
  629.  
  630. void sdlStretch16x2(u8 *src, u8 *dest)
  631. {
  632.   u16 *s = (u16 *)src;
  633.   u16 *d = (u16 *)dest;
  634.   for(int i = 0; i < srcWidth; i++) {
  635.     *d++ = *s;
  636.     *d++ = *s++;
  637.   }
  638. }
  639.  
  640. void sdlStretch16x3(u8 *src, u8 *dest)
  641. {
  642.   u16 *s = (u16 *)src;
  643.   u16 *d = (u16 *)dest;
  644.   for(int i = 0; i < srcWidth; i++) {
  645.     *d++ = *s;
  646.     *d++ = *s;
  647.     *d++ = *s++;
  648.   }
  649. }
  650.  
  651. void sdlStretch16x4(u8 *src, u8 *dest)
  652. {
  653.   u16 *s = (u16 *)src;
  654.   u16 *d = (u16 *)dest;
  655.   for(int i = 0; i < srcWidth; i++) {
  656.     *d++ = *s;
  657.     *d++ = *s;
  658.     *d++ = *s;
  659.     *d++ = *s++;
  660.   }
  661. }
  662.  
  663. void (*sdlStretcher16[4])(u8 *, u8 *) = {
  664.   sdlStretch16x1,
  665.   sdlStretch16x2,
  666.   sdlStretch16x3,
  667.   sdlStretch16x4
  668. };
  669.  
  670. void sdlStretch32x1(u8 *src, u8 *dest)
  671. {
  672.   u32 *s = (u32 *)src;
  673.   u32 *d = (u32 *)dest;
  674.   for(int i = 0; i < srcWidth; i++)
  675.     *d++ = *s++;
  676. }
  677.  
  678. void sdlStretch32x2(u8 *src, u8 *dest)
  679. {
  680.   u32 *s = (u32 *)src;
  681.   u32 *d = (u32 *)dest;
  682.   for(int i = 0; i < srcWidth; i++) {
  683.     *d++ = *s;
  684.     *d++ = *s++;
  685.   }
  686. }
  687.  
  688. void sdlStretch32x3(u8 *src, u8 *dest)
  689. {
  690.   u32 *s = (u32 *)src;
  691.   u32 *d = (u32 *)dest;
  692.   for(int i = 0; i < srcWidth; i++) {
  693.     *d++ = *s;
  694.     *d++ = *s;
  695.     *d++ = *s++;
  696.   }
  697. }
  698.  
  699. void sdlStretch32x4(u8 *src, u8 *dest)
  700. {
  701.   u32 *s = (u32 *)src;
  702.   u32 *d = (u32 *)dest;
  703.   for(int i = 0; i < srcWidth; i++) {
  704.     *d++ = *s;
  705.     *d++ = *s;
  706.     *d++ = *s;
  707.     *d++ = *s++;
  708.   }
  709. }
  710.  
  711. void (*sdlStretcher32[4])(u8 *, u8 *) = {
  712.   sdlStretch32x1,
  713.   sdlStretch32x2,
  714.   sdlStretch32x3,
  715.   sdlStretch32x4
  716. };
  717.  
  718. void sdlStretch24x1(u8 *src, u8 *dest)
  719. {
  720.   u8 *s = src;
  721.   u8 *d = dest;
  722.   for(int i = 0; i < srcWidth; i++) {
  723.     *d++ = *s++;
  724.     *d++ = *s++;
  725.     *d++ = *s++;
  726.   }
  727. }
  728.  
  729. void sdlStretch24x2(u8 *src, u8 *dest)
  730. {
  731.   u8 *s = (u8 *)src;
  732.   u8 *d = (u8 *)dest;
  733.   for(int i = 0; i < srcWidth; i++) {
  734.     *d++ = *s;
  735.     *d++ = *(s+1);
  736.     *d++ = *(s+2);
  737.     s += 3;
  738.     *d++ = *s;
  739.     *d++ = *(s+1);
  740.     *d++ = *(s+2);
  741.     s += 3;
  742.   }
  743. }
  744.  
  745. void sdlStretch24x3(u8 *src, u8 *dest)
  746. {
  747.   u8 *s = (u8 *)src;
  748.   u8 *d = (u8 *)dest;
  749.   for(int i = 0; i < srcWidth; i++) {
  750.     *d++ = *s;
  751.     *d++ = *(s+1);
  752.     *d++ = *(s+2);
  753.     s += 3;
  754.     *d++ = *s;
  755.     *d++ = *(s+1);
  756.     *d++ = *(s+2);
  757.     s += 3;
  758.     *d++ = *s;
  759.     *d++ = *(s+1);
  760.     *d++ = *(s+2);
  761.     s += 3;
  762.   }
  763. }
  764.  
  765. void sdlStretch24x4(u8 *src, u8 *dest)
  766. {
  767.   u8 *s = (u8 *)src;
  768.   u8 *d = (u8 *)dest;
  769.   for(int i = 0; i < srcWidth; i++) {
  770.     *d++ = *s;
  771.     *d++ = *(s+1);
  772.     *d++ = *(s+2);
  773.     s += 3;
  774.     *d++ = *s;
  775.     *d++ = *(s+1);
  776.     *d++ = *(s+2);
  777.     s += 3;
  778.     *d++ = *s;
  779.     *d++ = *(s+1);
  780.     *d++ = *(s+2);
  781.     s += 3;
  782.     *d++ = *s;
  783.     *d++ = *(s+1);
  784.     *d++ = *(s+2);
  785.     s += 3;
  786.   }
  787. }
  788.  
  789. void (*sdlStretcher24[4])(u8 *, u8 *) = {
  790.   sdlStretch24x1,
  791.   sdlStretch24x2,
  792.   sdlStretch24x3,
  793.   sdlStretch24x4
  794. };
  795.  
  796. #endif
  797.  
  798. u32 sdlFromHex(char *s)
  799. {
  800.   u32 value;
  801.   sscanf(s, "%x", &value);
  802.   return value;
  803. }
  804.  
  805. #ifdef __MSC__
  806. #define stat _stat
  807. #define S_IFDIR _S_IFDIR
  808. #endif
  809.  
  810. void sdlCheckDirectory(char *dir)
  811. {
  812.   struct stat buf;
  813.  
  814.   int len = strlen(dir);
  815.  
  816.   char *p = dir + len - 1;
  817.  
  818.   if(*p == '/' ||
  819.      *p == '\\')
  820.     *p = 0;
  821.   
  822.   if(stat(dir, &buf) == 0) {
  823.     if(!(buf.st_mode & S_IFDIR)) {
  824.       fprintf(stderr, "Error: %s is not a directory\n", dir);
  825.       dir[0] = 0;
  826.     }
  827.   } else {
  828.     fprintf(stderr, "Error: %s does not exist\n", dir);
  829.     dir[0] = 0;
  830.   }
  831. }
  832.  
  833. char *sdlGetFilename(char *name)
  834. {
  835.   static char filebuffer[2048];
  836.  
  837.   int len = strlen(name);
  838.   
  839.   char *p = name + len - 1;
  840.   
  841.   while(true) {
  842.     if(*p == '/' ||
  843.        *p == '\\') {
  844.       p++;
  845.       break;
  846.     }
  847.     len--;
  848.     p--;
  849.     if(len == 0)
  850.       break;
  851.   }
  852.   
  853.   if(len == 0)
  854.     strcpy(filebuffer, name);
  855.   else
  856.     strcpy(filebuffer, p);
  857.   return filebuffer;
  858. }
  859.  
  860. FILE *sdlFindFile(const char *name)
  861. {
  862.   char buffer[4096];
  863.   char path[2048];
  864.  
  865. #ifdef WIN32
  866. #define PATH_SEP ";"
  867. #define FILE_SEP '\\'
  868. #define EXE_NAME "VisualBoyAdvance-SDL.exe"
  869. #else // ! WIN32
  870. #define PATH_SEP ":"
  871. #define FILE_SEP '/'
  872. #define EXE_NAME "VisualBoyAdvance"
  873. #endif // ! WIN32
  874.  
  875.   fprintf(stderr, "Searching for file %s\n", name);
  876.   
  877.   if(GETCWD(buffer, 2048)) {
  878.     fprintf(stderr, "Searching current directory: %s\n", buffer);
  879.   }
  880.   
  881.   FILE *f = fopen(name, "r");
  882.   if(f != NULL) {
  883.     return f;
  884.   }
  885.  
  886.   char *home = getenv("HOME");
  887.  
  888.   if(home != NULL) {
  889.     fprintf(stderr, "Searching home directory: %s\n", home);
  890.     sprintf(path, "%s%c%s", home, FILE_SEP, name);
  891.     f = fopen(path, "r");
  892.     if(f != NULL)
  893.       return f;
  894.   }
  895.  
  896. #ifdef WIN32
  897.   home = getenv("USERPROFILE");
  898.   if(home != NULL) {
  899.     fprintf(stderr, "Searching user profile directory: %s\n", home);
  900.     sprintf(path, "%s%c%s", home, FILE_SEP, name);
  901.     f = fopen(path, "r");
  902.     if(f != NULL)
  903.       return f;
  904.   }
  905. #else // ! WIN32
  906.     fprintf(stderr, "Searching system config directory: %s\n", SYSCONFDIR);
  907.     sprintf(path, "%s%c%s", SYSCONFDIR, FILE_SEP, name);
  908.     f = fopen(path, "r");
  909.     if(f != NULL)
  910.       return f;
  911. #endif // ! WIN32
  912.  
  913.   if(!strchr(arg0, '/') &&
  914.      !strchr(arg0, '\\')) {
  915.     char *path = getenv("PATH");
  916.  
  917.     if(path != NULL) {
  918.       fprintf(stderr, "Searching PATH\n");
  919.       strncpy(buffer, path, 4096);
  920.       buffer[4095] = 0;
  921.       char *tok = strtok(buffer, PATH_SEP);
  922.       
  923.       while(tok) {
  924.         sprintf(path, "%s%c%s", tok, FILE_SEP, EXE_NAME);
  925.         f = fopen(path, "r");
  926.         if(f != NULL) {
  927.           char path2[2048];
  928.           fclose(f);
  929.           sprintf(path2, "%s%c%s", tok, FILE_SEP, name);
  930.           f = fopen(path2, "r");
  931.           if(f != NULL) {
  932.             fprintf(stderr, "Found at %s\n", path2);
  933.             return f;
  934.           }
  935.         }
  936.         tok = strtok(NULL, PATH_SEP);
  937.       }
  938.     }
  939.   } else {
  940.     // executable is relative to some directory
  941.     fprintf(stderr, "Searching executable directory\n");
  942.     strcpy(buffer, arg0);
  943.     char *p = strrchr(buffer, FILE_SEP);
  944.     if(p) {
  945.       *p = 0;
  946.       sprintf(path, "%s%c%s", buffer, FILE_SEP, name);
  947.       f = fopen(path, "r");
  948.       if(f != NULL)
  949.         return f;
  950.     }
  951.   }
  952.   return NULL;
  953. }
  954.  
  955. void sdlReadPreferences(FILE *f)
  956. {
  957.   char buffer[2048];
  958.   
  959.   while(1) {
  960.     char *s = fgets(buffer, 2048, f);
  961.  
  962.     if(s == NULL)
  963.       break;
  964.  
  965.     char *p  = strchr(s, '#');
  966.     
  967.     if(p)
  968.       *p = 0;
  969.     
  970.     char *token = strtok(s, " \t\n\r=");
  971.  
  972.     if(!token)
  973.       continue;
  974.  
  975.     if(strlen(token) == 0)
  976.       continue;
  977.  
  978.     char *key = token;
  979.     char *value = strtok(NULL, "\t\n\r");
  980.  
  981.     if(value == NULL) {
  982.       fprintf(stderr, "Empty value for key %s\n", key);
  983.       continue;
  984.     }
  985.  
  986.     if(!strcmp(key,"Joy0_Left")) {
  987.       joypad[0][KEY_LEFT] = sdlFromHex(value);
  988.     } else if(!strcmp(key, "Joy0_Right")) {
  989.       joypad[0][KEY_RIGHT] = sdlFromHex(value);
  990.     } else if(!strcmp(key, "Joy0_Up")) {
  991.       joypad[0][KEY_UP] = sdlFromHex(value);
  992.     } else if(!strcmp(key, "Joy0_Down")) {
  993.       joypad[0][KEY_DOWN] = sdlFromHex(value);
  994.     } else if(!strcmp(key, "Joy0_A")) {
  995.       joypad[0][KEY_BUTTON_A] = sdlFromHex(value);
  996.     } else if(!strcmp(key, "Joy0_B")) {
  997.       joypad[0][KEY_BUTTON_B] = sdlFromHex(value);
  998.     } else if(!strcmp(key, "Joy0_L")) {
  999.       joypad[0][KEY_BUTTON_L] = sdlFromHex(value);
  1000.     } else if(!strcmp(key, "Joy0_R")) {
  1001.       joypad[0][KEY_BUTTON_R] = sdlFromHex(value);
  1002.     } else if(!strcmp(key, "Joy0_Start")) {
  1003.       joypad[0][KEY_BUTTON_START] = sdlFromHex(value);
  1004.     } else if(!strcmp(key, "Joy0_Select")) {
  1005.       joypad[0][KEY_BUTTON_SELECT] = sdlFromHex(value);
  1006.     } else if(!strcmp(key, "Joy0_Speed")) {
  1007.       joypad[0][KEY_BUTTON_SPEED] = sdlFromHex(value);
  1008.     } else if(!strcmp(key, "Joy0_Capture")) {
  1009.       joypad[0][KEY_BUTTON_CAPTURE] = sdlFromHex(value);
  1010.     } else if(!strcmp(key,"Joy1_Left")) {
  1011.       joypad[1][KEY_LEFT] = sdlFromHex(value);
  1012.     } else if(!strcmp(key, "Joy1_Right")) {
  1013.       joypad[1][KEY_RIGHT] = sdlFromHex(value);
  1014.     } else if(!strcmp(key, "Joy1_Up")) {
  1015.       joypad[1][KEY_UP] = sdlFromHex(value);
  1016.     } else if(!strcmp(key, "Joy1_Down")) {
  1017.       joypad[1][KEY_DOWN] = sdlFromHex(value);
  1018.     } else if(!strcmp(key, "Joy1_A")) {
  1019.       joypad[1][KEY_BUTTON_A] = sdlFromHex(value);
  1020.     } else if(!strcmp(key, "Joy1_B")) {
  1021.       joypad[1][KEY_BUTTON_B] = sdlFromHex(value);
  1022.     } else if(!strcmp(key, "Joy1_L")) {
  1023.       joypad[1][KEY_BUTTON_L] = sdlFromHex(value);
  1024.     } else if(!strcmp(key, "Joy1_R")) {
  1025.       joypad[1][KEY_BUTTON_R] = sdlFromHex(value);
  1026.     } else if(!strcmp(key, "Joy1_Start")) {
  1027.       joypad[1][KEY_BUTTON_START] = sdlFromHex(value);
  1028.     } else if(!strcmp(key, "Joy1_Select")) {
  1029.       joypad[1][KEY_BUTTON_SELECT] = sdlFromHex(value);
  1030.     } else if(!strcmp(key, "Joy1_Speed")) {
  1031.       joypad[1][KEY_BUTTON_SPEED] = sdlFromHex(value);
  1032.     } else if(!strcmp(key, "Joy1_Capture")) {
  1033.       joypad[1][KEY_BUTTON_CAPTURE] = sdlFromHex(value);
  1034.     } else if(!strcmp(key,"Joy2_Left")) {
  1035.       joypad[2][KEY_LEFT] = sdlFromHex(value);
  1036.     } else if(!strcmp(key, "Joy2_Right")) {
  1037.       joypad[2][KEY_RIGHT] = sdlFromHex(value);
  1038.     } else if(!strcmp(key, "Joy2_Up")) {
  1039.       joypad[2][KEY_UP] = sdlFromHex(value);
  1040.     } else if(!strcmp(key, "Joy2_Down")) {
  1041.       joypad[2][KEY_DOWN] = sdlFromHex(value);
  1042.     } else if(!strcmp(key, "Joy2_A")) {
  1043.       joypad[2][KEY_BUTTON_A] = sdlFromHex(value);
  1044.     } else if(!strcmp(key, "Joy2_B")) {
  1045.       joypad[2][KEY_BUTTON_B] = sdlFromHex(value);
  1046.     } else if(!strcmp(key, "Joy2_L")) {
  1047.       joypad[2][KEY_BUTTON_L] = sdlFromHex(value);
  1048.     } else if(!strcmp(key, "Joy2_R")) {
  1049.       joypad[2][KEY_BUTTON_R] = sdlFromHex(value);
  1050.     } else if(!strcmp(key, "Joy2_Start")) {
  1051.       joypad[2][KEY_BUTTON_START] = sdlFromHex(value);
  1052.     } else if(!strcmp(key, "Joy2_Select")) {
  1053.       joypad[2][KEY_BUTTON_SELECT] = sdlFromHex(value);
  1054.     } else if(!strcmp(key, "Joy2_Speed")) {
  1055.       joypad[2][KEY_BUTTON_SPEED] = sdlFromHex(value);
  1056.     } else if(!strcmp(key, "Joy2_Capture")) {
  1057.       joypad[2][KEY_BUTTON_CAPTURE] = sdlFromHex(value);
  1058.     } else if(!strcmp(key,"Joy4_Left")) {
  1059.       joypad[4][KEY_LEFT] = sdlFromHex(value);
  1060.     } else if(!strcmp(key, "Joy4_Right")) {
  1061.       joypad[4][KEY_RIGHT] = sdlFromHex(value);
  1062.     } else if(!strcmp(key, "Joy4_Up")) {
  1063.       joypad[4][KEY_UP] = sdlFromHex(value);
  1064.     } else if(!strcmp(key, "Joy4_Down")) {
  1065.       joypad[4][KEY_DOWN] = sdlFromHex(value);
  1066.     } else if(!strcmp(key, "Joy4_A")) {
  1067.       joypad[4][KEY_BUTTON_A] = sdlFromHex(value);
  1068.     } else if(!strcmp(key, "Joy4_B")) {
  1069.       joypad[4][KEY_BUTTON_B] = sdlFromHex(value);
  1070.     } else if(!strcmp(key, "Joy4_L")) {
  1071.       joypad[4][KEY_BUTTON_L] = sdlFromHex(value);
  1072.     } else if(!strcmp(key, "Joy4_R")) {
  1073.       joypad[4][KEY_BUTTON_R] = sdlFromHex(value);
  1074.     } else if(!strcmp(key, "Joy4_Start")) {
  1075.       joypad[4][KEY_BUTTON_START] = sdlFromHex(value);
  1076.     } else if(!strcmp(key, "Joy4_Select")) {
  1077.       joypad[4][KEY_BUTTON_SELECT] = sdlFromHex(value);
  1078.     } else if(!strcmp(key, "Joy4_Speed")) {
  1079.       joypad[4][KEY_BUTTON_SPEED] = sdlFromHex(value);
  1080.     } else if(!strcmp(key, "Joy4_Capture")) {
  1081.       joypad[4][KEY_BUTTON_CAPTURE] = sdlFromHex(value);
  1082.     } else if(!strcmp(key, "Motion_Left")) {
  1083.       motion[KEY_LEFT] = sdlFromHex(value);
  1084.     } else if(!strcmp(key, "Motion_Right")) {
  1085.       motion[KEY_RIGHT] = sdlFromHex(value);
  1086.     } else if(!strcmp(key, "Motion_Up")) {
  1087.       motion[KEY_UP] = sdlFromHex(value);
  1088.     } else if(!strcmp(key, "Motion_Down")) {
  1089.       motion[KEY_DOWN] = sdlFromHex(value);
  1090.     } else if(!strcmp(key, "frameSkip")) {
  1091.       frameSkip = sdlFromHex(value);
  1092.       if(frameSkip < 0 || frameSkip > 9)
  1093.         frameSkip = 2;
  1094.     } else if(!strcmp(key, "gbFrameSkip")) {
  1095.       gbFrameSkip = sdlFromHex(value);
  1096.       if(gbFrameSkip < 0 || gbFrameSkip > 9)
  1097.         gbFrameSkip = 0;      
  1098.     } else if(!strcmp(key, "video")) {
  1099.       sizeOption = sdlFromHex(value);
  1100.       if(sizeOption < 0 || sizeOption > 3)
  1101.         sizeOption = 1;
  1102.     } else if(!strcmp(key, "fullScreen")) {
  1103.       fullscreen = sdlFromHex(value) ? 1 : 0;
  1104.     } else if(!strcmp(key, "useBios")) {
  1105.       useBios = sdlFromHex(value) ? true : false;
  1106.     } else if(!strcmp(key, "skipBios")) {
  1107.       skipBios = sdlFromHex(value) ? true : false;
  1108.     } else if(!strcmp(key, "biosFile")) {
  1109.       strcpy(biosFileName, value);
  1110.     } else if(!strcmp(key, "filter")) {
  1111.       filter = sdlFromHex(value);
  1112.       if(filter < 0 || filter > 13)
  1113.         filter = 0;
  1114.     } else if(!strcmp(key, "disableStatus")) {
  1115.       disableStatusMessages = sdlFromHex(value) ? true : false;
  1116.     } else if(!strcmp(key, "borderOn")) {
  1117.       gbBorderOn = sdlFromHex(value) ? true : false;
  1118.     } else if(!strcmp(key, "borderAutomatic")) {
  1119.       gbBorderAutomatic = sdlFromHex(value) ? true : false;
  1120.     } else if(!strcmp(key, "emulatorType")) {
  1121.       gbEmulatorType = sdlFromHex(value);
  1122.       if(gbEmulatorType < 0 || gbEmulatorType > 5)
  1123.         gbEmulatorType = 1;
  1124.     } else if(!strcmp(key, "colorOption")) {
  1125.       gbColorOption = sdlFromHex(value) ? true : false;
  1126.     } else if(!strcmp(key, "captureDir")) {
  1127.       sdlCheckDirectory(value);
  1128.       strcpy(captureDir, value);
  1129.     } else if(!strcmp(key, "saveDir")) {
  1130.       sdlCheckDirectory(value);
  1131.       strcpy(saveDir, value);
  1132.     } else if(!strcmp(key, "batteryDir")) {
  1133.       sdlCheckDirectory(value);
  1134.       strcpy(batteryDir, value);
  1135.     } else if(!strcmp(key, "captureFormat")) {
  1136.       captureFormat = sdlFromHex(value);
  1137.     } else if(!strcmp(key, "soundQuality")) {
  1138.       soundQuality = sdlFromHex(value);
  1139.       switch(soundQuality) {
  1140.       case 1:
  1141.       case 2:
  1142.       case 4:
  1143.         break;
  1144.       default:
  1145.         fprintf(stderr, "Unknown sound quality %d. Defaulting to 22Khz\n", 
  1146.                 soundQuality);
  1147.         soundQuality = 2;
  1148.         break;
  1149.       }
  1150.     } else if(!strcmp(key, "soundOff")) {
  1151.       soundOffFlag = sdlFromHex(value) ? true : false;
  1152.     } else if(!strcmp(key, "soundEnable")) {
  1153.       int res = sdlFromHex(value) & 0x30f;
  1154.       soundEnable(res);
  1155.       soundDisable(~res);
  1156.     } else if(!strcmp(key, "soundEcho")) {
  1157.       soundEcho = sdlFromHex(value) ? true : false;
  1158.     } else if(!strcmp(key, "soundLowPass")) {
  1159.       soundLowPass = sdlFromHex(value) ? true : false;
  1160.     } else if(!strcmp(key, "soundReverse")) {
  1161.       soundReverse = sdlFromHex(value) ? true : false;
  1162.     } else if(!strcmp(key, "soundVolume")) {
  1163.       soundVolume = sdlFromHex(value);
  1164.       if(soundVolume < 0 || soundVolume > 3)
  1165.         soundVolume = 0;
  1166.     } else if(!strcmp(key, "removeIntros")) {
  1167.       removeIntros = sdlFromHex(value) ? true : false;
  1168.     } else if(!strcmp(key, "saveType")) {
  1169.       cpuSaveType = sdlFromHex(value);
  1170.       if(cpuSaveType < 0 || cpuSaveType > 5)
  1171.         cpuSaveType = 0;
  1172.     } else if(!strcmp(key, "flashSize")) {
  1173.       sdlFlashSize = sdlFromHex(value);
  1174.       if(sdlFlashSize != 0 && sdlFlashSize != 1)
  1175.         sdlFlashSize = 0;
  1176.     } else if(!strcmp(key, "ifbType")) {
  1177.       ifbType = sdlFromHex(value);
  1178.       if(ifbType < 0 || ifbType > 2)
  1179.         ifbType = 0;
  1180.     } else if(!strcmp(key, "showSpeed")) {
  1181.       showSpeed = sdlFromHex(value);
  1182.       if(showSpeed < 0 || showSpeed > 2)
  1183.         showSpeed = 1;
  1184.     } else if(!strcmp(key, "showSpeedTransparent")) {
  1185.       showSpeedTransparent = sdlFromHex(value);
  1186.     } else if(!strcmp(key, "autoFrameSkip")) {
  1187.       autoFrameSkip = sdlFromHex(value);
  1188.     } else if(!strcmp(key, "throttle")) {
  1189.       throttle = sdlFromHex(value);
  1190.       if(throttle != 0 && (throttle < 5 || throttle > 1000))
  1191.         throttle = 0;
  1192.     } else if(!strcmp(key, "disableMMX")) {
  1193. #ifdef MMX
  1194.       cpu_mmx = sdlFromHex(value) ? false : true;
  1195. #endif
  1196.     } else if(!strcmp(key, "pauseWhenInactive")) {
  1197.       pauseWhenInactive = sdlFromHex(value) ? true : false;
  1198.     } else if(!strcmp(key, "agbPrint")) {
  1199.       sdlAgbPrint = sdlFromHex(value);
  1200.     } else if(!strcmp(key, "rtcEnabled")) {
  1201.       sdlRtcEnable = sdlFromHex(value);
  1202.     } else if(!strcmp(key, "rewindTimer")) {
  1203.       rewindTimer = sdlFromHex(value);
  1204.       if(rewindTimer < 0 || rewindTimer > 600)
  1205.         rewindTimer = 0;
  1206.       rewindTimer *= 6;  // convert value to 10 frames multiple
  1207.     } else if(!strcmp(key, "enhancedDetection")) {
  1208.       cpuEnhancedDetection = sdlFromHex(value) ? true : false;
  1209.     } else {
  1210.       fprintf(stderr, "Unknown configuration key %s\n", key);
  1211.     }
  1212.   }
  1213. }
  1214.  
  1215. void sdlReadPreferences()
  1216. {
  1217.   FILE *f = sdlFindFile("VisualBoyAdvance.cfg");
  1218.  
  1219.   if(f == NULL) {
  1220.     fprintf(stderr, "Configuration file NOT FOUND (using defaults)\n");
  1221.     return;
  1222.   } else
  1223.     fprintf(stderr, "Reading configuration file.\n");
  1224.  
  1225.   sdlReadPreferences(f);
  1226.  
  1227.   fclose(f);
  1228. }
  1229.  
  1230. static void sdlApplyPerImagePreferences()
  1231. {
  1232.   FILE *f = sdlFindFile("vba-over.ini");
  1233.   if(!f) {
  1234.     fprintf(stderr, "vba-over.ini NOT FOUND (using emulator settings)\n");
  1235.     return;
  1236.   } else
  1237.     fprintf(stderr, "Reading vba-over.ini\n");
  1238.  
  1239.   char buffer[7];
  1240.   buffer[0] = '[';
  1241.   buffer[1] = rom[0xac];
  1242.   buffer[2] = rom[0xad];
  1243.   buffer[3] = rom[0xae];
  1244.   buffer[4] = rom[0xaf];
  1245.   buffer[5] = ']';
  1246.   buffer[6] = 0;
  1247.  
  1248.   char readBuffer[2048];
  1249.  
  1250.   bool found = false;
  1251.   
  1252.   while(1) {
  1253.     char *s = fgets(readBuffer, 2048, f);
  1254.  
  1255.     if(s == NULL)
  1256.       break;
  1257.  
  1258.     char *p  = strchr(s, ';');
  1259.     
  1260.     if(p)
  1261.       *p = 0;
  1262.     
  1263.     char *token = strtok(s, " \t\n\r=");
  1264.  
  1265.     if(!token)
  1266.       continue;
  1267.     if(strlen(token) == 0)
  1268.       continue;
  1269.  
  1270.     if(!strcmp(token, buffer)) {
  1271.       found = true;
  1272.       break;
  1273.     }
  1274.   }
  1275.  
  1276.   if(found) {
  1277.     while(1) {
  1278.       char *s = fgets(readBuffer, 2048, f);
  1279.  
  1280.       if(s == NULL)
  1281.         break;
  1282.  
  1283.       char *p = strchr(s, ';');
  1284.       if(p)
  1285.         *p = 0;
  1286.  
  1287.       char *token = strtok(s, " \t\n\r=");
  1288.       if(!token)
  1289.         continue;
  1290.       if(strlen(token) == 0)
  1291.         continue;
  1292.  
  1293.       if(token[0] == '[') // starting another image settings
  1294.         break;
  1295.       char *value = strtok(NULL, "\t\n\r=");
  1296.       if(value == NULL)
  1297.         continue;
  1298.       
  1299.       if(!strcmp(token, "rtcEnabled"))
  1300.         rtcEnable(atoi(value) == 0 ? false : true);
  1301.       else if(!strcmp(token, "flashSize")) {
  1302.         int size = atoi(value);
  1303.         if(size == 0x10000 || size == 0x20000)
  1304.           flashSetSize(size);
  1305.       } else if(!strcmp(token, "saveType")) {
  1306.         int save = atoi(value);
  1307.         if(save >= 0 && save <= 5)
  1308.           cpuSaveType = save;
  1309.       }
  1310.     }
  1311.   }
  1312.   fclose(f);
  1313. }
  1314.  
  1315. static int sdlCalculateShift(u32 mask)
  1316. {
  1317.   int m = 0;
  1318.   
  1319.   while(mask) {
  1320.     m++;
  1321.     mask >>= 1;
  1322.   }
  1323.  
  1324.   return m-5;
  1325. }
  1326.  
  1327. static int sdlCalculateMaskWidth(u32 mask)
  1328. {
  1329.   int m = 0;
  1330.   int mask2 = mask;
  1331.  
  1332.   while(mask2) {
  1333.     m++;
  1334.     mask2 >>= 1;
  1335.   }
  1336.  
  1337.   int m2 = 0;
  1338.   mask2 = mask;
  1339.   while(!(mask2 & 1)) {
  1340.     m2++;
  1341.     mask2 >>= 1;
  1342.   }
  1343.  
  1344.   return m - m2;
  1345. }
  1346.  
  1347. void sdlWriteState(int num)
  1348. {
  1349.   char stateName[2048];
  1350.  
  1351.   if(saveDir[0])
  1352.     sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename),
  1353.             num+1);
  1354.   else
  1355.     sprintf(stateName,"%s%d.sgm", filename, num+1);
  1356.   if(emulator.emuWriteState)
  1357.     emulator.emuWriteState(stateName);
  1358.   sprintf(stateName, "Wrote state %d", num+1);
  1359.   systemScreenMessage(stateName);
  1360. }
  1361.  
  1362. void sdlReadState(int num)
  1363. {
  1364.   char stateName[2048];
  1365.  
  1366.   if(saveDir[0])
  1367.     sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename),
  1368.             num+1);
  1369.   else
  1370.     sprintf(stateName,"%s%d.sgm", filename, num+1);
  1371.  
  1372.   if(emulator.emuReadState)
  1373.     emulator.emuReadState(stateName);
  1374.  
  1375.   sprintf(stateName, "Loaded state %d", num+1);
  1376.   systemScreenMessage(stateName);
  1377. }
  1378.  
  1379. void sdlWriteBattery()
  1380. {
  1381.   char buffer[1048];
  1382.  
  1383.   if(batteryDir[0])
  1384.     sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
  1385.   else  
  1386.     sprintf(buffer, "%s.sav", filename);
  1387.  
  1388.   emulator.emuWriteBattery(buffer);
  1389.  
  1390.   systemScreenMessage("Wrote battery");
  1391. }
  1392.  
  1393. void sdlReadBattery()
  1394. {
  1395.   char buffer[1048];
  1396.   
  1397.   if(batteryDir[0])
  1398.     sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
  1399.   else 
  1400.     sprintf(buffer, "%s.sav", filename);
  1401.   
  1402.   bool res = false;
  1403.  
  1404.   res = emulator.emuReadBattery(buffer);
  1405.  
  1406.   if(res)
  1407.     systemScreenMessage("Loaded battery");
  1408. }
  1409.  
  1410. #define MOD_KEYS    (KMOD_CTRL|KMOD_SHIFT|KMOD_ALT|KMOD_META)
  1411. #define MOD_NOCTRL  (KMOD_SHIFT|KMOD_ALT|KMOD_META)
  1412. #define MOD_NOALT   (KMOD_CTRL|KMOD_SHIFT|KMOD_META)
  1413. #define MOD_NOSHIFT (KMOD_CTRL|KMOD_ALT|KMOD_META)
  1414.  
  1415. void sdlUpdateKey(int key, bool down)
  1416. {
  1417.   int i;
  1418.   for(int j = 0; j < 4; j++) {
  1419.     for(i = 0 ; i < 12; i++) {
  1420.       if((joypad[j][i] & 0xf000) == 0) {
  1421.         if(key == joypad[j][i])
  1422.           sdlButtons[j][i] = down;
  1423.       }
  1424.     }
  1425.   }
  1426.   for(i = 0 ; i < 4; i++) {
  1427.     if((motion[i] & 0xf000) == 0) {
  1428.       if(key == motion[i])
  1429.         sdlMotionButtons[i] = down;
  1430.     }
  1431.   }
  1432. }
  1433.  
  1434. void sdlUpdateJoyButton(int which,
  1435.                         int button,
  1436.                         bool pressed)
  1437. {
  1438.   int i;
  1439.   for(int j = 0; j < 4; j++) {
  1440.     for(i = 0; i < 12; i++) {
  1441.       int dev = (joypad[j][i] >> 12);
  1442.       int b = joypad[j][i] & 0xfff;
  1443.       if(dev) {
  1444.         dev--;
  1445.         
  1446.         if((dev == which) && (b >= 128) && (b == (button+128))) {
  1447.           sdlButtons[j][i] = pressed;
  1448.         }
  1449.       }
  1450.     }
  1451.   }
  1452.   for(i = 0; i < 4; i++) {
  1453.     int dev = (motion[i] >> 12);
  1454.     int b = motion[i] & 0xfff;
  1455.     if(dev) {
  1456.       dev--;
  1457.  
  1458.       if((dev == which) && (b >= 128) && (b == (button+128))) {
  1459.         sdlMotionButtons[i] = pressed;
  1460.       }
  1461.     }
  1462.   }  
  1463. }
  1464.  
  1465. void sdlUpdateJoyHat(int which,
  1466.                      int hat,
  1467.                      int value)
  1468. {
  1469.   int i;
  1470.   for(int j = 0; j < 4; j++) {
  1471.     for(i = 0; i < 12; i++) {
  1472.       int dev = (joypad[j][i] >> 12);
  1473.       int a = joypad[j][i] & 0xfff;
  1474.       if(dev) {
  1475.         dev--;
  1476.         
  1477.         if((dev == which) && (a>=32) && (a < 48) && (((a&15)>>2) == hat)) {
  1478.           int dir = a & 3;
  1479.           int v = 0;
  1480.           switch(dir) {
  1481.           case 0:
  1482.             v = value & SDL_HAT_UP;
  1483.             break;
  1484.           case 1:
  1485.             v = value & SDL_HAT_DOWN;
  1486.             break;
  1487.           case 2:
  1488.             v = value & SDL_HAT_RIGHT;
  1489.             break;
  1490.           case 3:
  1491.             v = value & SDL_HAT_LEFT;
  1492.             break;
  1493.           }
  1494.           sdlButtons[j][i] = (v ? true : false);
  1495.         }
  1496.       }
  1497.     }
  1498.   }
  1499.   for(i = 0; i < 4; i++) {
  1500.     int dev = (motion[i] >> 12);
  1501.     int a = motion[i] & 0xfff;
  1502.     if(dev) {
  1503.       dev--;
  1504.  
  1505.       if((dev == which) && (a>=32) && (a < 48) && (((a&15)>>2) == hat)) {
  1506.         int dir = a & 3;
  1507.         int v = 0;
  1508.         switch(dir) {
  1509.         case 0:
  1510.           v = value & SDL_HAT_UP;
  1511.           break;
  1512.         case 1:
  1513.           v = value & SDL_HAT_DOWN;
  1514.           break;
  1515.         case 2:
  1516.           v = value & SDL_HAT_RIGHT;
  1517.           break;
  1518.         case 3:
  1519.           v = value & SDL_HAT_LEFT;
  1520.           break;
  1521.         }
  1522.         sdlMotionButtons[i] = (v ? true : false);
  1523.       }
  1524.     }
  1525.   }      
  1526. }
  1527.  
  1528. void sdlUpdateJoyAxis(int which,
  1529.                       int axis,
  1530.                       int value)
  1531. {
  1532.   int i;
  1533.   for(int j = 0; j < 4; j++) {
  1534.     for(i = 0; i < 12; i++) {
  1535.       int dev = (joypad[j][i] >> 12);
  1536.       int a = joypad[j][i] & 0xfff;
  1537.       if(dev) {
  1538.         dev--;
  1539.         
  1540.         if((dev == which) && (a < 32) && ((a>>1) == axis)) {
  1541.           sdlButtons[j][i] = (a & 1) ? (value > 16384) : (value < -16384);
  1542.         }
  1543.       }
  1544.     }
  1545.   }
  1546.   for(i = 0; i < 4; i++) {
  1547.     int dev = (motion[i] >> 12);
  1548.     int a = motion[i] & 0xfff;
  1549.     if(dev) {
  1550.       dev--;
  1551.  
  1552.       if((dev == which) && (a < 32) && ((a>>1) == axis)) {
  1553.         sdlMotionButtons[i] = (a & 1) ? (value > 16384) : (value < -16384);
  1554.       }
  1555.     }
  1556.   }  
  1557. }
  1558.  
  1559. bool sdlCheckJoyKey(int key)
  1560. {
  1561.   int dev = (key >> 12) - 1;
  1562.   int what = key & 0xfff;
  1563.  
  1564.   if(what >= 128) {
  1565.     // joystick button
  1566.     int button = what - 128;
  1567.  
  1568.     if(button >= SDL_JoystickNumButtons(sdlDevices[dev]))
  1569.       return false;
  1570.   } else if (what < 0x20) {
  1571.     // joystick axis    
  1572.     what >>= 1;
  1573.     if(what >= SDL_JoystickNumAxes(sdlDevices[dev]))
  1574.       return false;
  1575.   } else if (what < 0x30) {
  1576.     // joystick hat
  1577.     what = (what & 15);
  1578.     what >>= 2;
  1579.     if(what >= SDL_JoystickNumHats(sdlDevices[dev]))
  1580.       return false;
  1581.   }
  1582.  
  1583.   // no problem found
  1584.   return true;
  1585. }
  1586.  
  1587. void sdlCheckKeys()
  1588. {
  1589.   sdlNumDevices = SDL_NumJoysticks();
  1590.  
  1591.   if(sdlNumDevices)
  1592.     sdlDevices = (SDL_Joystick **)calloc(1,sdlNumDevices *
  1593.                                          sizeof(SDL_Joystick **));
  1594.   int i;
  1595.  
  1596.   bool usesJoy = false;
  1597.  
  1598.   for(int j = 0; j < 4; j++) {
  1599.     for(i = 0; i < 12; i++) {
  1600.       int dev = joypad[j][i] >> 12;
  1601.       if(dev) {
  1602.         dev--;
  1603.         bool ok = false;
  1604.         
  1605.         if(sdlDevices) {
  1606.           if(dev < sdlNumDevices) {
  1607.             if(sdlDevices[dev] == NULL) {
  1608.               sdlDevices[dev] = SDL_JoystickOpen(dev);
  1609.             }
  1610.             
  1611.             ok = sdlCheckJoyKey(joypad[j][i]);
  1612.           } else
  1613.             ok = false;
  1614.         }
  1615.         
  1616.         if(!ok)
  1617.           joypad[j][i] = defaultJoypad[i];
  1618.         else
  1619.           usesJoy = true;
  1620.       }
  1621.     }
  1622.   }
  1623.  
  1624.   for(i = 0; i < 4; i++) {
  1625.     int dev = motion[i] >> 12;
  1626.     if(dev) {
  1627.       dev--;
  1628.       bool ok = false;
  1629.       
  1630.       if(sdlDevices) {
  1631.         if(dev < sdlNumDevices) {
  1632.           if(sdlDevices[dev] == NULL) {
  1633.             sdlDevices[dev] = SDL_JoystickOpen(dev);
  1634.           }
  1635.           
  1636.           ok = sdlCheckJoyKey(motion[i]);
  1637.         } else
  1638.           ok = false;
  1639.       }
  1640.       
  1641.       if(!ok)
  1642.         motion[i] = defaultMotion[i];
  1643.       else
  1644.         usesJoy = true;
  1645.     }
  1646.   }
  1647.  
  1648.   if(usesJoy)
  1649.     SDL_JoystickEventState(SDL_ENABLE);
  1650. }
  1651.  
  1652. void sdlPollEvents()
  1653. {
  1654.   SDL_Event event;
  1655.   while(SDL_PollEvent(&event)) {
  1656.     switch(event.type) {
  1657.     case SDL_QUIT:
  1658.       emulating = 0;
  1659.       break;
  1660.     case SDL_ACTIVEEVENT:
  1661.       if(pauseWhenInactive && (event.active.state & SDL_APPINPUTFOCUS)) {
  1662.         active = event.active.gain;
  1663.         if(active) {
  1664.           if(!paused) {
  1665.             if(emulating)
  1666.               soundResume();
  1667.           }
  1668.         } else {
  1669.           wasPaused = true;
  1670.           if(pauseWhenInactive) {
  1671.             if(emulating)
  1672.               soundPause();
  1673.           }
  1674.           
  1675.           memset(delta,255,sizeof(delta));
  1676.         }
  1677.       }
  1678.       break;
  1679.     case SDL_MOUSEMOTION:
  1680.     case SDL_MOUSEBUTTONUP:
  1681.     case SDL_MOUSEBUTTONDOWN:
  1682.       if(fullscreen) {
  1683.         SDL_ShowCursor(SDL_ENABLE);
  1684.         mouseCounter = 120;
  1685.       }
  1686.       break;
  1687.     case SDL_JOYHATMOTION:
  1688.       sdlUpdateJoyHat(event.jhat.which,
  1689.                       event.jhat.hat,
  1690.                       event.jhat.value);
  1691.       break;
  1692.     case SDL_JOYBUTTONDOWN:
  1693.     case SDL_JOYBUTTONUP:
  1694.       sdlUpdateJoyButton(event.jbutton.which,
  1695.                          event.jbutton.button,
  1696.                          event.jbutton.state == SDL_PRESSED);
  1697.       break;
  1698.     case SDL_JOYAXISMOTION:
  1699.       sdlUpdateJoyAxis(event.jaxis.which,
  1700.                        event.jaxis.axis,
  1701.                        event.jaxis.value);
  1702.       break;
  1703.     case SDL_KEYDOWN:
  1704.       sdlUpdateKey(event.key.keysym.sym, true);
  1705.       break;
  1706.     case SDL_KEYUP:
  1707.       switch(event.key.keysym.sym) {
  1708.       case SDLK_r:
  1709.         if(!(event.key.keysym.mod & MOD_NOCTRL) &&
  1710.            (event.key.keysym.mod & KMOD_CTRL)) {
  1711.           if(emulating) {
  1712.             emulator.emuReset();
  1713.  
  1714.             systemScreenMessage("Reset");
  1715.           }
  1716.         }
  1717.         break;
  1718.       case SDLK_b:
  1719.         if(!(event.key.keysym.mod & MOD_NOCTRL) &&
  1720.            (event.key.keysym.mod & KMOD_CTRL)) {
  1721.           if(emulating && emulator.emuReadMemState && rewindMemory 
  1722.              && rewindCount) {
  1723.             rewindPos = --rewindPos & 7;
  1724.             emulator.emuReadMemState(&rewindMemory[REWIND_SIZE*rewindPos], 
  1725.                                      REWIND_SIZE);
  1726.             rewindCount--;
  1727.             rewindCounter = 0;
  1728.             systemScreenMessage("Rewind");
  1729.           }
  1730.         }
  1731.         break;
  1732.       case SDLK_p:
  1733.         if(!(event.key.keysym.mod & MOD_NOCTRL) &&
  1734.            (event.key.keysym.mod & KMOD_CTRL)) {
  1735.           paused = !paused;
  1736.           SDL_PauseAudio(paused);
  1737.           if(paused)
  1738.             wasPaused = true;
  1739.         }
  1740.         break;
  1741.       case SDLK_ESCAPE:
  1742.         emulating = 0;
  1743.         break;
  1744.       case SDLK_f:
  1745.         if(!(event.key.keysym.mod & MOD_NOCTRL) &&
  1746.            (event.key.keysym.mod & KMOD_CTRL)) {
  1747.           int flags = 0;
  1748.           fullscreen = !fullscreen;
  1749.           if(fullscreen)
  1750.             flags |= SDL_FULLSCREEN;
  1751.           SDL_SetVideoMode(destWidth, destHeight, systemColorDepth, flags);
  1752.           //          if(SDL_WM_ToggleFullScreen(surface))
  1753.           //            fullscreen = !fullscreen;
  1754.         }
  1755.         break;
  1756.       case SDLK_F11:
  1757.         if(dbgMain != debuggerMain) {
  1758.           if(armState) {
  1759.             armNextPC -= 4;
  1760.             reg[15].I -= 4;
  1761.           } else {
  1762.             armNextPC -= 2;
  1763.             reg[15].I -= 2;
  1764.           }
  1765.         }
  1766.         debugger = true;
  1767.         break;
  1768.       case SDLK_F1:
  1769.       case SDLK_F2:
  1770.       case SDLK_F3:
  1771.       case SDLK_F4:
  1772.       case SDLK_F5:
  1773.       case SDLK_F6:
  1774.       case SDLK_F7:
  1775.       case SDLK_F8:
  1776.       case SDLK_F9:
  1777.       case SDLK_F10:
  1778.         if(!(event.key.keysym.mod & MOD_NOSHIFT) &&
  1779.            (event.key.keysym.mod & KMOD_SHIFT)) {
  1780.           sdlWriteState(event.key.keysym.sym-SDLK_F1);
  1781.         } else if(!(event.key.keysym.mod & MOD_KEYS)) {
  1782.           sdlReadState(event.key.keysym.sym-SDLK_F1);
  1783.         }
  1784.         break;
  1785.       case SDLK_1:
  1786.       case SDLK_2:
  1787.       case SDLK_3:
  1788.       case SDLK_4:
  1789.         if(!(event.key.keysym.mod & MOD_NOALT) &&
  1790.            (event.key.keysym.mod & KMOD_ALT)) {
  1791.           char *disableMessages[4] = 
  1792.             { "autofire A disabled",
  1793.               "autofire B disabled",
  1794.               "autofire R disabled",
  1795.               "autofire L disabled"};
  1796.           char *enableMessages[4] = 
  1797.             { "autofire A",
  1798.               "autofire B",
  1799.               "autofire R",
  1800.               "autofire L"};
  1801.           int mask = 1 << (event.key.keysym.sym - SDLK_1);
  1802.     if(event.key.keysym.sym > SDLK_2)
  1803.       mask <<= 6;
  1804.           if(autoFire & mask) {
  1805.             autoFire &= ~mask;
  1806.             systemScreenMessage(disableMessages[event.key.keysym.sym - SDLK_1]);
  1807.           } else {
  1808.             autoFire |= mask;
  1809.             systemScreenMessage(enableMessages[event.key.keysym.sym - SDLK_1]);
  1810.           }
  1811.         } if(!(event.key.keysym.mod & MOD_NOCTRL) &&
  1812.              (event.key.keysym.mod & KMOD_CTRL)) {
  1813.           int mask = 0x0100 << (event.key.keysym.sym - SDLK_1);
  1814.           layerSettings ^= mask;
  1815.           layerEnable = DISPCNT & layerSettings;
  1816.           CPUUpdateRenderBuffers(false);
  1817.         }
  1818.         break;
  1819.       case SDLK_5:
  1820.       case SDLK_6:
  1821.       case SDLK_7:
  1822.       case SDLK_8:
  1823.         if(!(event.key.keysym.mod & MOD_NOCTRL) &&
  1824.            (event.key.keysym.mod & KMOD_CTRL)) {
  1825.           int mask = 0x0100 << (event.key.keysym.sym - SDLK_1);
  1826.           layerSettings ^= mask;
  1827.           layerEnable = DISPCNT & layerSettings;
  1828.         }
  1829.         break;
  1830.       case SDLK_n:
  1831.         if(!(event.key.keysym.mod & MOD_NOCTRL) &&
  1832.            (event.key.keysym.mod & KMOD_CTRL)) {
  1833.           if(paused)
  1834.             paused = false;
  1835.           pauseNextFrame = true;
  1836.         }
  1837.         break;
  1838.       default:
  1839.         break;
  1840.       }
  1841.       sdlUpdateKey(event.key.keysym.sym, false);
  1842.       break;
  1843.     }
  1844.   }
  1845. }
  1846.  
  1847. void usage(char *cmd)
  1848. {
  1849.   printf("%s [option ...] file\n", cmd);
  1850.   printf("\
  1851. \n\
  1852. Options:\n\
  1853.   -1, --video-1x               1x\n\
  1854.   -2, --video-2x               2x\n\
  1855.   -3, --video-3x               3x\n\
  1856.   -4, --video-4x               4x\n\
  1857.   -F, --fullscreen             Full screen\n\
  1858.   -G, --gdb=PROTOCOL           GNU Remote Stub mode:\n\
  1859.                                 tcp      - use TCP at port 55555\n\
  1860.                                 tcp:PORT - use TCP at port PORT\n\
  1861.                                 pipe     - use pipe transport\n\
  1862.   -N, --no-debug               Don't parse debug information\n\
  1863.   -S, --flash-size=SIZE        Set the Flash size\n\
  1864.       --flash-64k               0 -  64K Flash\n\
  1865.       --flash-128k              1 - 128K Flash\n\
  1866.   -T, --throttle=THROTTLE      Set the desired throttle (5...1000)\n\
  1867.   -Y, --yuv=TYPE               Use YUV overlay for drawing:\n\
  1868.                                 0 - YV12\n\
  1869.                                 1 - UYVY\n\
  1870.                                 2 - YVYU\n\
  1871.                                 3 - YUY2\n\
  1872.                                 4 - IYUV\n\
  1873.   -b, --bios=BIOS              Use given bios file\n\
  1874.   -c, --config=FILE            Read the given configuration file\n\
  1875.   -d, --debug                  Enter debugger\n\
  1876.   -f, --filter=FILTER          Select filter:\n\
  1877.       --filter-normal            0 - normal mode\n\
  1878.       --filter-tv-mode           1 - TV Mode\n\
  1879.       --filter-2xsai             2 - 2xSaI\n\
  1880.       --filter-super-2xsai       3 - Super 2xSaI\n\
  1881.       --filter-super-eagle       4 - Super Eagle\n\
  1882.       --filter-pixelate          5 - Pixelate\n\
  1883.       --filter-motion-blur       6 - Motion Blur\n\
  1884.       --filter-advmame           7 - AdvanceMAME Scale2x\n\
  1885.       --filter-simple2x          8 - Simple2x\n\
  1886.       --filter-bilinear          9 - Bilinear\n\
  1887.       --filter-bilinear+        10 - Bilinear Plus\n\
  1888.       --filter-scanlines        11 - Scanlines\n\
  1889.       --filter-hq2x             12 - hq2x\n\
  1890.       --filter-lq2x             13 - lq2x\n\
  1891.   -h, --help                   Print this help\n\
  1892.   -i, --ips=PATCH              Apply given IPS patch\n\
  1893.   -p, --profile=[HERTZ]        Enable profiling\n\
  1894.   -s, --frameskip=FRAMESKIP    Set frame skip (0...9)\n\
  1895. ");
  1896.   printf("\
  1897.   -t, --save-type=TYPE         Set the available save type\n\
  1898.       --save-auto               0 - Automatic (EEPROM, SRAM, FLASH)\n\
  1899.       --save-eeprom             1 - EEPROM\n\
  1900.       --save-sram               2 - SRAM\n\
  1901.       --save-flash              3 - FLASH\n\
  1902.       --save-sensor             4 - EEPROM+Sensor\n\
  1903.       --save-none               5 - NONE\n\
  1904.   -v, --verbose=VERBOSE        Set verbose logging (trace.log)\n\
  1905.                                   1 - SWI\n\
  1906.                                   2 - Unaligned memory access\n\
  1907.                                   4 - Illegal memory write\n\
  1908.                                   8 - Illegal memory read\n\
  1909.                                  16 - DMA 0\n\
  1910.                                  32 - DMA 1\n\
  1911.                                  64 - DMA 2\n\
  1912.                                 128 - DMA 3\n\
  1913.                                 256 - Undefined instruction\n\
  1914.                                 512 - AGBPrint messages\n\
  1915. \n\
  1916. Long options only:\n\
  1917.       --agb-print              Enable AGBPrint support\n\
  1918.       --auto-frameskip         Enable auto frameskipping\n\
  1919.       --ifb-none               No interframe blending\n\
  1920.       --ifb-motion-blur        Interframe motion blur\n\
  1921.       --ifb-smart              Smart interframe blending\n\
  1922.       --no-agb-print           Disable AGBPrint support\n\
  1923.       --no-auto-frameskip      Disable auto frameskipping\n\
  1924.       --no-ips                 Do not apply IPS patch\n\
  1925.       --no-mmx                 Disable MMX support\n\
  1926.       --no-pause-when-inactive Don't pause when inactive\n\
  1927.       --no-rtc                 Disable RTC support\n\
  1928.       --no-show-speed          Don't show emulation speed\n\
  1929.       --no-throttle            Disable thrrotle\n\
  1930.       --pause-when-inactive    Pause when inactive\n\
  1931.       --rtc                    Enable RTC support\n\
  1932.       --show-speed-normal      Show emulation speed\n\
  1933.       --show-speed-detailed    Show detailed speed data\n\
  1934. ");
  1935. }
  1936.  
  1937. int main(int argc, char **argv)
  1938. {
  1939.   fprintf(stderr, "VisualBoyAdvance version %s [SDL]\n", VERSION);
  1940.  
  1941.   arg0 = argv[0];
  1942.   
  1943.   captureDir[0] = 0;
  1944.   saveDir[0] = 0;
  1945.   batteryDir[0] = 0;
  1946.   ipsname[0] = 0;
  1947.   
  1948.   int op = -1;
  1949.  
  1950.   frameSkip = 2;
  1951.   gbBorderOn = 0;
  1952.  
  1953.   parseDebug = true;
  1954.  
  1955.   sdlReadPreferences();
  1956.  
  1957.   sdlPrintUsage = 0;
  1958.   
  1959.   while((op = getopt_long(argc,
  1960.                           argv,
  1961.                           "FNT:Y:G:D:b:c:df:hi:p::s:t:v:1234",
  1962.                           sdlOptions,
  1963.                           NULL)) != -1) {
  1964.     switch(op) {
  1965.     case 0:
  1966.       // long option already processed by getopt_long
  1967.       break;
  1968.     case 'b':
  1969.       useBios = true;
  1970.       if(optarg == NULL) {
  1971.         fprintf(stderr, "Missing BIOS file name\n");
  1972.         exit(-1);
  1973.       }
  1974.       strcpy(biosFileName, optarg);
  1975.       break;
  1976.     case 'c':
  1977.       {
  1978.         if(optarg == NULL) {
  1979.           fprintf(stderr, "Missing config file name\n");
  1980.           exit(-1);
  1981.         }
  1982.         FILE *f = fopen(optarg, "r");
  1983.         if(f == NULL) {
  1984.           fprintf(stderr, "File not found %s\n", optarg);
  1985.           exit(-1);
  1986.         }
  1987.         sdlReadPreferences(f);
  1988.         fclose(f);
  1989.       }
  1990.       break;
  1991.     case 'd':
  1992.       debugger = true;
  1993.       break;
  1994.     case 'h':
  1995.       sdlPrintUsage = 1;
  1996.       break;
  1997.     case 'i':
  1998.       if(optarg == NULL) {
  1999.         fprintf(stderr, "Missing IPS name\n");
  2000.         exit(-1);
  2001.         strcpy(ipsname, optarg);
  2002.       }
  2003.       break;
  2004.     case 'Y':
  2005.       yuv = true;
  2006.       if(optarg) {
  2007.         yuvType = atoi(optarg);
  2008.         switch(yuvType) {
  2009.         case 0:
  2010.           yuvType = SDL_YV12_OVERLAY;
  2011.           break;
  2012.         case 1:
  2013.           yuvType = SDL_UYVY_OVERLAY;
  2014.           break;
  2015.         case 2:
  2016.           yuvType = SDL_YVYU_OVERLAY;
  2017.           break;
  2018.         case 3:
  2019.           yuvType = SDL_YUY2_OVERLAY;
  2020.           break;
  2021.         case 4:
  2022.           yuvType = SDL_IYUV_OVERLAY;
  2023.           break;
  2024.         default:
  2025.           yuvType = SDL_YV12_OVERLAY;
  2026.         }
  2027.       } else
  2028.         yuvType = SDL_YV12_OVERLAY;
  2029.       break;
  2030.     case 'G':
  2031.       dbgMain = remoteStubMain;
  2032.       dbgSignal = remoteStubSignal;
  2033.       dbgOutput = remoteOutput;
  2034.       debugger = true;
  2035.       debuggerStub = true;
  2036.       if(optarg) {
  2037.         char *s = optarg;
  2038.         if(strncmp(s,"tcp:", 4) == 0) {
  2039.           s+=4;
  2040.           int port = atoi(s);
  2041.           remoteSetProtocol(0);
  2042.           remoteSetPort(port);
  2043.         } else if(strcmp(s,"tcp") == 0) {
  2044.           remoteSetProtocol(0);
  2045.         } else if(strcmp(s, "pipe") == 0) {
  2046.           remoteSetProtocol(1);
  2047.         } else {
  2048.           fprintf(stderr, "Unknown protocol %s\n", s);
  2049.           exit(-1);
  2050.         }
  2051.       } else {
  2052.         remoteSetProtocol(0);
  2053.       }
  2054.       break;
  2055.     case 'N':
  2056.       parseDebug = false;
  2057.       break;
  2058.     case 'D':
  2059.       if(optarg) {
  2060.         systemDebug = atoi(optarg);
  2061.       } else {
  2062.         systemDebug = 1;
  2063.       }
  2064.       break;
  2065.     case 'F':
  2066.       fullscreen = 1;
  2067.       mouseCounter = 120;
  2068.       break;
  2069.     case 'f':
  2070.       if(optarg) {
  2071.         filter = atoi(optarg);
  2072.       } else {
  2073.         filter = 0;
  2074.       }
  2075.       break;
  2076.     case 'p':
  2077. #ifdef PROFILING
  2078.       if(optarg) {
  2079.         cpuEnableProfiling(atoi(optarg));
  2080.       } else
  2081.         cpuEnableProfiling(100);
  2082. #endif
  2083.       break;
  2084.     case 'S':
  2085.       sdlFlashSize = atoi(optarg);
  2086.       if(sdlFlashSize < 0 || sdlFlashSize > 1)
  2087.         sdlFlashSize = 0;
  2088.       break;
  2089.     case 's':
  2090.       if(optarg) {
  2091.         int a = atoi(optarg);
  2092.         if(a >= 0 && a <= 9) {
  2093.           gbFrameSkip = a;
  2094.           frameSkip = a;
  2095.         }
  2096.       } else {
  2097.         frameSkip = 2;
  2098.         gbFrameSkip = 0;
  2099.       }
  2100.       break;
  2101.     case 't':
  2102.       if(optarg) {
  2103.         int a = atoi(optarg);
  2104.         if(a < 0 || a > 5)
  2105.           a = 0;
  2106.         cpuSaveType = a;
  2107.       }
  2108.       break;
  2109.     case 'T':
  2110.       if(optarg) {
  2111.         int t = atoi(optarg);
  2112.         if(t < 5 || t > 1000)
  2113.           t = 0;
  2114.         throttle = t;
  2115.       }
  2116.       break;
  2117.     case 'v':
  2118.       if(optarg) {
  2119.         systemVerbose = atoi(optarg);
  2120.       } else 
  2121.         systemVerbose = 0;
  2122.       break;
  2123.     case '1':
  2124.       sizeOption = 0;
  2125.       break;
  2126.     case '2':
  2127.       sizeOption = 1;
  2128.       break;
  2129.     case '3':
  2130.       sizeOption = 2;
  2131.       break;
  2132.     case '4':
  2133.       sizeOption = 3;
  2134.       break;
  2135.     case '?':
  2136.       sdlPrintUsage = 1;
  2137.       break;
  2138.     }
  2139.   }
  2140.  
  2141.   if(sdlPrintUsage) {
  2142.     usage(argv[0]);
  2143.     exit(-1);
  2144.   }
  2145.  
  2146. #ifdef MMX
  2147.   if(disableMMX)
  2148.     cpu_mmx = 0;
  2149. #endif
  2150.  
  2151.   if(rewindTimer)
  2152.     rewindMemory = (char *)malloc(8*REWIND_SIZE);
  2153.  
  2154.   if(sdlFlashSize == 0)
  2155.     flashSetSize(0x10000);
  2156.   else
  2157.     flashSetSize(0x20000);
  2158.  
  2159.   rtcEnable(sdlRtcEnable ? true : false);
  2160.   agbPrintEnable(sdlAgbPrint ? true : false);
  2161.   
  2162.   if(!debuggerStub) {
  2163.     if(optind >= argc) {
  2164.       systemMessage(0,"Missing image name");
  2165.       usage(argv[0]);
  2166.       exit(-1);
  2167.     }
  2168.   }
  2169.  
  2170.   if(filter) {
  2171.     sizeOption = 1;
  2172.   }
  2173.  
  2174.   for(int i = 0; i < 24;) {
  2175.     systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10);
  2176.     systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10);
  2177.     systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10);
  2178.     systemGbPalette[i++] = 0;
  2179.   }
  2180.  
  2181.   systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
  2182.  
  2183.   if(optind < argc) {
  2184.     char *szFile = argv[optind];
  2185.  
  2186.     utilGetBaseName(szFile, filename);
  2187.     char *p = strrchr(filename, '.');
  2188.  
  2189.     if(p)
  2190.       *p = 0;
  2191.  
  2192.     if(ipsname[0] == 0)
  2193.       sprintf(ipsname, "%s.ips", filename);
  2194.     
  2195.     bool failed = false;
  2196.  
  2197.     IMAGE_TYPE type = utilFindType(szFile);
  2198.  
  2199.     if(type == IMAGE_UNKNOWN) {
  2200.       systemMessage(0, "Unknown file type %s", szFile);
  2201.       exit(-1);
  2202.     }
  2203.     cartridgeType = (int)type;
  2204.     
  2205.     if(type == IMAGE_GB) {
  2206.       failed = !gbLoadRom(szFile);
  2207.       if(!failed) {
  2208.         cartridgeType = 1;
  2209.         emulator = GBSystem;
  2210.         if(sdlAutoIPS) {
  2211.           int size = gbRomSize;
  2212.           utilApplyIPS(ipsname, &gbRom, &size);
  2213.           if(size != gbRomSize) {
  2214.             extern bool gbUpdateSizes();
  2215.             gbUpdateSizes();
  2216.             gbReset();
  2217.           }
  2218.         }
  2219.       }
  2220.     } else if(type == IMAGE_GBA) {
  2221.       int size = CPULoadRom(szFile);
  2222.       failed = (size == 0);
  2223.       if(!failed) {
  2224.         //        if(cpuEnhancedDetection && cpuSaveType == 0) {
  2225.         //          utilGBAFindSave(rom, size);
  2226.         //        }
  2227.  
  2228.         sdlApplyPerImagePreferences();
  2229.         
  2230.         cartridgeType = 0;
  2231.         emulator = GBASystem;
  2232.  
  2233.         /* disabled due to problems
  2234.         if(removeIntros && rom != NULL) {
  2235.           WRITE32LE(&rom[0], 0xea00002e);
  2236.         }
  2237.         */
  2238.         
  2239.         CPUInit(biosFileName, useBios);
  2240.         CPUReset();
  2241.         if(sdlAutoIPS) {
  2242.           int size = 0x2000000;
  2243.           utilApplyIPS(ipsname, &rom, &size);
  2244.           if(size != 0x2000000) {
  2245.             CPUReset();
  2246.           }
  2247.         }
  2248.       }
  2249.     }
  2250.     
  2251.     if(failed) {
  2252.       systemMessage(0, "Failed to load file %s", szFile);
  2253.       exit(-1);
  2254.     }
  2255.   } else {
  2256.     cartridgeType = 0;
  2257.     strcpy(filename, "gnu_stub");
  2258.     rom = (u8 *)malloc(0x2000000);
  2259.     workRAM = (u8 *)calloc(1, 0x40000);
  2260.     bios = (u8 *)calloc(1,0x4000);
  2261.     internalRAM = (u8 *)calloc(1,0x8000);
  2262.     paletteRAM = (u8 *)calloc(1,0x400);
  2263.     vram = (u8 *)calloc(1, 0x20000);
  2264.     oam = (u8 *)calloc(1, 0x400);
  2265.     pix = (u8 *)calloc(1, 4 * 240 * 160);
  2266.     ioMem = (u8 *)calloc(1, 0x400);
  2267.  
  2268.     emulator = GBASystem;
  2269.     
  2270.     CPUInit(biosFileName, useBios);
  2271.     CPUReset();    
  2272.   }
  2273.   
  2274.   sdlReadBattery();
  2275.   
  2276.   if(debuggerStub) 
  2277.     remoteInit();
  2278.   
  2279.   int flags = SDL_INIT_VIDEO|SDL_INIT_AUDIO|
  2280.     SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE;
  2281.  
  2282.   if(soundOffFlag)
  2283.     flags ^= SDL_INIT_AUDIO;
  2284.   
  2285.   if(SDL_Init(flags)) {
  2286.     systemMessage(0, "Failed to init SDL: %s", SDL_GetError());
  2287.     exit(-1);
  2288.   }
  2289.  
  2290.   if(SDL_InitSubSystem(SDL_INIT_JOYSTICK)) {
  2291.     systemMessage(0, "Failed to init joystick support: %s", SDL_GetError());
  2292.   }
  2293.   
  2294.   sdlCheckKeys();
  2295.   
  2296.   if(cartridgeType == 0) {
  2297.     srcWidth = 240;
  2298.     srcHeight = 160;
  2299.     systemFrameSkip = frameSkip;
  2300.   } else if (cartridgeType == 1) {
  2301.     if(gbBorderOn) {
  2302.       srcWidth = 256;
  2303.       srcHeight = 224;
  2304.       gbBorderLineSkip = 256;
  2305.       gbBorderColumnSkip = 48;
  2306.       gbBorderRowSkip = 40;
  2307.     } else {      
  2308.       srcWidth = 160;
  2309.       srcHeight = 144;
  2310.       gbBorderLineSkip = 160;
  2311.       gbBorderColumnSkip = 0;
  2312.       gbBorderRowSkip = 0;
  2313.     }
  2314.     systemFrameSkip = gbFrameSkip;
  2315.   } else {
  2316.     srcWidth = 320;
  2317.     srcHeight = 240;
  2318.   }
  2319.   
  2320.   destWidth = (sizeOption+1)*srcWidth;
  2321.   destHeight = (sizeOption+1)*srcHeight;
  2322.   
  2323.   surface = SDL_SetVideoMode(destWidth, destHeight, 16,
  2324.                              SDL_ANYFORMAT|SDL_HWSURFACE|SDL_DOUBLEBUF|
  2325.                              (fullscreen ? SDL_FULLSCREEN : 0));
  2326.   
  2327.   if(surface == NULL) {
  2328.     systemMessage(0, "Failed to set video mode");
  2329.     SDL_Quit();
  2330.     exit(-1);
  2331.   }
  2332.   
  2333.   systemRedShift = sdlCalculateShift(surface->format->Rmask);
  2334.   systemGreenShift = sdlCalculateShift(surface->format->Gmask);
  2335.   systemBlueShift = sdlCalculateShift(surface->format->Bmask);
  2336.   
  2337.   systemColorDepth = surface->format->BitsPerPixel;
  2338.   if(systemColorDepth == 15)
  2339.     systemColorDepth = 16;
  2340.  
  2341.   if(yuv) {
  2342.     Init_Overlay(surface, yuvType);
  2343.     systemColorDepth = 32;
  2344.     systemRedShift = 3;
  2345.     systemGreenShift = 11;
  2346.     systemBlueShift =  19;
  2347.   }
  2348.   
  2349.   if(systemColorDepth != 16 && systemColorDepth != 24 &&
  2350.      systemColorDepth != 32) {
  2351.     fprintf(stderr,"Unsupported color depth '%d'.\nOnly 16, 24 and 32 bit color depths are supported\n", systemColorDepth);
  2352.     exit(-1);
  2353.   }
  2354.  
  2355. #ifndef C_CORE
  2356.   sdlMakeStretcher(srcWidth);
  2357. #else
  2358.   switch(systemColorDepth) {
  2359.   case 16:
  2360.     sdlStretcher = sdlStretcher16[sizeOption];
  2361.     break;
  2362.   case 24:
  2363.     sdlStretcher = sdlStretcher24[sizeOption];
  2364.     break;
  2365.   case 32:
  2366.     sdlStretcher = sdlStretcher32[sizeOption];
  2367.     break;
  2368.   default:
  2369.     fprintf(stderr, "Unsupported resolution: %d\n", systemColorDepth);
  2370.     exit(-1);
  2371.   }
  2372. #endif
  2373.  
  2374.   fprintf(stderr,"Color depth: %d\n", systemColorDepth);
  2375.   
  2376.   if(systemColorDepth == 16) {
  2377.     if(sdlCalculateMaskWidth(surface->format->Gmask) == 6) {
  2378.       Init_2xSaI(565);
  2379.       RGB_LOW_BITS_MASK = 0x821;
  2380.     } else {
  2381.       Init_2xSaI(555);
  2382.       RGB_LOW_BITS_MASK = 0x421;      
  2383.     }
  2384.     if(cartridgeType == 2) {
  2385.       for(int i = 0; i < 0x10000; i++) {
  2386.         systemColorMap16[i] = (((i >> 1) & 0x1f) << systemBlueShift) |
  2387.           (((i & 0x7c0) >> 6) << systemGreenShift) |
  2388.           (((i & 0xf800) >> 11) << systemRedShift);  
  2389.       }      
  2390.     } else {
  2391.       for(int i = 0; i < 0x10000; i++) {
  2392.         systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
  2393.           (((i & 0x3e0) >> 5) << systemGreenShift) |
  2394.           (((i & 0x7c00) >> 10) << systemBlueShift);  
  2395.       }
  2396.     }
  2397.     srcPitch = srcWidth * 2+4;
  2398.   } else {
  2399.     if(systemColorDepth != 32)
  2400.       filterFunction = NULL;
  2401.     RGB_LOW_BITS_MASK = 0x010101;
  2402.     if(systemColorDepth == 32) {
  2403.       Init_2xSaI(32);
  2404.     }
  2405.     for(int i = 0; i < 0x10000; i++) {
  2406.       systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
  2407.         (((i & 0x3e0) >> 5) << systemGreenShift) |
  2408.         (((i & 0x7c00) >> 10) << systemBlueShift);  
  2409.     }
  2410.     if(systemColorDepth == 32)
  2411.       srcPitch = srcWidth*4 + 4;
  2412.     else
  2413.       srcPitch = srcWidth*3;
  2414.   }
  2415.  
  2416.   if(systemColorDepth != 32) {
  2417.     switch(filter) {
  2418.     case 0:
  2419.       filterFunction = NULL;
  2420.       break;
  2421.     case 1:
  2422.       filterFunction = ScanlinesTV;
  2423.       break;
  2424.     case 2:
  2425.       filterFunction = _2xSaI;
  2426.       break;
  2427.     case 3:
  2428.       filterFunction = Super2xSaI;
  2429.       break;
  2430.     case 4:
  2431.       filterFunction = SuperEagle;
  2432.       break;
  2433.     case 5:
  2434.       filterFunction = Pixelate;
  2435.       break;
  2436.     case 6:
  2437.       filterFunction = MotionBlur;
  2438.       break;
  2439.     case 7:
  2440.       filterFunction = AdMame2x;
  2441.       break;
  2442.     case 8:
  2443.       filterFunction = Simple2x;
  2444.       break;
  2445.     case 9:
  2446.       filterFunction = Bilinear;
  2447.       break;
  2448.     case 10:
  2449.       filterFunction = BilinearPlus;
  2450.       break;
  2451.     case 11:
  2452.       filterFunction = Scanlines;
  2453.       break;
  2454.     case 12:
  2455.       filterFunction = hq2x;
  2456.       break;
  2457.     case 13:
  2458.       filterFunction = lq2x;
  2459.       break;
  2460.     default:
  2461.       filterFunction = NULL;
  2462.       break;
  2463.     }
  2464.   } else {
  2465.     switch(filter) {
  2466.     case 0:
  2467.       filterFunction = NULL;
  2468.       break;
  2469.     case 1:
  2470.       filterFunction = ScanlinesTV32;
  2471.       break;
  2472.     case 2:
  2473.       filterFunction = _2xSaI32;
  2474.       break;
  2475.     case 3:
  2476.       filterFunction = Super2xSaI32;
  2477.       break;
  2478.     case 4:
  2479.       filterFunction = SuperEagle32;
  2480.       break;
  2481.     case 5:
  2482.       filterFunction = Pixelate32;
  2483.       break;
  2484.     case 6:
  2485.       filterFunction = MotionBlur32;
  2486.       break;
  2487.     case 7:
  2488.       filterFunction = AdMame2x32;
  2489.       break;
  2490.     case 8:
  2491.       filterFunction = Simple2x32;
  2492.       break;
  2493.     case 9:
  2494.       filterFunction = Bilinear32;
  2495.       break;
  2496.     case 10:
  2497.       filterFunction = BilinearPlus32;
  2498.       break;
  2499.     case 11:
  2500.       filterFunction = Scanlines32;
  2501.       break;
  2502.     case 12:
  2503.       filterFunction = hq2x32;
  2504.       break;
  2505.     case 13:
  2506.       filterFunction = lq2x32;
  2507.       break;
  2508.     default:
  2509.       filterFunction = NULL;
  2510.       break;
  2511.     }
  2512.   }
  2513.   
  2514.   if(systemColorDepth == 16) {
  2515.     switch(ifbType) {
  2516.     case 0:
  2517.     default:
  2518.       ifbFunction = NULL;
  2519.       break;
  2520.     case 1:
  2521.       ifbFunction = MotionBlurIB;
  2522.       break;
  2523.     case 2:
  2524.       ifbFunction = SmartIB;
  2525.       break;
  2526.     }
  2527.   } else if(systemColorDepth == 32) {
  2528.     switch(ifbType) {
  2529.     case 0:
  2530.     default:
  2531.       ifbFunction = NULL;
  2532.       break;
  2533.     case 1:
  2534.       ifbFunction = MotionBlurIB32;
  2535.       break;
  2536.     case 2:
  2537.       ifbFunction = SmartIB32;
  2538.       break;
  2539.     }
  2540.   } else
  2541.     ifbFunction = NULL;
  2542.  
  2543.   if(delta == NULL) {
  2544.     delta = (u8*)malloc(322*242*4);
  2545.     memset(delta, 255, 322*242*4);
  2546.   }
  2547.   
  2548.   emulating = 1;
  2549.   renderedFrames = 0;
  2550.  
  2551.   if(!soundOffFlag)
  2552.     soundInit();
  2553.  
  2554.   autoFrameSkipLastTime = throttleLastTime = systemGetClock();
  2555.   
  2556.   SDL_WM_SetCaption("VisualBoyAdvance", NULL);
  2557.  
  2558.   while(emulating) {
  2559.     if(!paused && active) {
  2560.       if(debugger && emulator.emuHasDebugger)
  2561.         dbgMain();
  2562.       else {
  2563.         emulator.emuMain(emulator.emuCount);
  2564.         if(rewindSaveNeeded && rewindMemory && emulator.emuWriteMemState) {
  2565.           rewindCount++;
  2566.           if(rewindCount > 8)
  2567.             rewindCount = 8;
  2568.           if(emulator.emuWriteMemState &&
  2569.              emulator.emuWriteMemState(&rewindMemory[rewindPos*REWIND_SIZE], 
  2570.                                        REWIND_SIZE)) {
  2571.             rewindPos = ++rewindPos & 7;
  2572.             if(rewindCount == 8)
  2573.               rewindTopPos = ++rewindTopPos & 7;
  2574.           }
  2575.         }
  2576.  
  2577.         rewindSaveNeeded = false;
  2578.       }
  2579.     } else {
  2580.       SDL_Delay(500);
  2581.     }
  2582.     sdlPollEvents();
  2583.     if(mouseCounter) {
  2584.       mouseCounter--;
  2585.       if(mouseCounter == 0)
  2586.         SDL_ShowCursor(SDL_DISABLE);
  2587.     }
  2588.   }
  2589.   
  2590.   emulating = 0;
  2591.   fprintf(stderr,"Shutting down\n");
  2592.   remoteCleanUp();
  2593.   soundShutdown();
  2594.  
  2595.   if(gbRom != NULL || rom != NULL) {
  2596.     sdlWriteBattery();
  2597.     emulator.emuCleanUp();
  2598.   }
  2599.  
  2600.   if(delta) {
  2601.     free(delta);
  2602.     delta = NULL;
  2603.   }
  2604.   
  2605.   SDL_Quit();
  2606.   return 0;
  2607. }
  2608.  
  2609. void systemMessage(int num, const char *msg, ...)
  2610. {
  2611.   char buffer[2048];
  2612.   va_list valist;
  2613.   
  2614.   va_start(valist, msg);
  2615.   vsprintf(buffer, msg, valist);
  2616.   
  2617.   fprintf(stderr, "%s\n", buffer);
  2618.   va_end(valist);
  2619. }
  2620.  
  2621. void systemDrawScreen()
  2622. {
  2623.   renderedFrames++;
  2624.   
  2625.   if(yuv) {
  2626.     Draw_Overlay(surface, sizeOption+1);
  2627.     return;
  2628.   }
  2629.   
  2630.   SDL_LockSurface(surface);
  2631.  
  2632.   if(screenMessage) {
  2633.     if(cartridgeType == 1 && gbBorderOn) {
  2634.       gbSgbRenderBorder();
  2635.     }
  2636.     if(((systemGetClock() - screenMessageTime) < 3000) &&
  2637.        !disableStatusMessages) {
  2638.       drawText(pix, srcPitch, 10, srcHeight - 20,
  2639.                screenMessageBuffer); 
  2640.     } else {
  2641.       screenMessage = false;
  2642.     }
  2643.   }
  2644.  
  2645.   if(ifbFunction) {
  2646.     if(systemColorDepth == 16)
  2647.       ifbFunction(pix+destWidth+4, destWidth+4, srcWidth, srcHeight);
  2648.     else
  2649.       ifbFunction(pix+destWidth*2+4, destWidth*2+4, srcWidth, srcHeight);
  2650.   }
  2651.   
  2652.   if(filterFunction) {
  2653.     if(systemColorDepth == 16)
  2654.       filterFunction(pix+destWidth+4,destWidth+4, delta,
  2655.                      (u8*)surface->pixels,surface->pitch,
  2656.                      srcWidth,
  2657.                      srcHeight);
  2658.     else
  2659.       filterFunction(pix+destWidth*2+4,
  2660.                      destWidth*2+4,
  2661.                      delta,
  2662.                      (u8*)surface->pixels,
  2663.                      surface->pitch,
  2664.                      srcWidth,
  2665.                      srcHeight);
  2666.   } else {
  2667.     int destPitch = surface->pitch;
  2668.     u8 *src = pix;
  2669.     u8 *dest = (u8*)surface->pixels;
  2670.     int i;
  2671.     u32 *stretcher = (u32 *)sdlStretcher;
  2672.     if(systemColorDepth == 16)
  2673.       src += srcPitch;
  2674.     int option = sizeOption;
  2675.     if(yuv)
  2676.       option = 0;
  2677.     switch(sizeOption) {
  2678.     case 0:
  2679.       for(i = 0; i < srcHeight; i++) {
  2680.         SDL_CALL_STRETCHER;
  2681.         src += srcPitch;
  2682.         dest += destPitch;
  2683.       }
  2684.       break;
  2685.     case 1:
  2686.       for(i = 0; i < srcHeight; i++) {
  2687.         SDL_CALL_STRETCHER;     
  2688.         dest += destPitch;
  2689.         SDL_CALL_STRETCHER;
  2690.         src += srcPitch;
  2691.         dest += destPitch;
  2692.       }
  2693.       break;
  2694.     case 2:
  2695.       for(i = 0; i < srcHeight; i++) {
  2696.         SDL_CALL_STRETCHER;
  2697.         dest += destPitch;
  2698.         SDL_CALL_STRETCHER;
  2699.         dest += destPitch;
  2700.         SDL_CALL_STRETCHER;
  2701.         src += srcPitch;
  2702.         dest += destPitch;
  2703.       }
  2704.       break;
  2705.     case 3:
  2706.       for(i = 0; i < srcHeight; i++) {
  2707.         SDL_CALL_STRETCHER;
  2708.         dest += destPitch;
  2709.         SDL_CALL_STRETCHER;
  2710.         dest += destPitch;
  2711.         SDL_CALL_STRETCHER;
  2712.         dest += destPitch;
  2713.         SDL_CALL_STRETCHER;
  2714.         src += srcPitch;
  2715.         dest += destPitch;
  2716.       }
  2717.       break;
  2718.     }
  2719.   }
  2720.  
  2721.   if(showSpeed && fullscreen) {
  2722.     char buffer[50];
  2723.     if(showSpeed == 1)
  2724.       sprintf(buffer, "%d%%", systemSpeed);
  2725.     else
  2726.       sprintf(buffer, "%3d%%(%d, %d fps)", systemSpeed,
  2727.               systemFrameSkip,
  2728.               showRenderedFrames);
  2729.     if(showSpeedTransparent)
  2730.       drawTextTransp((u8*)surface->pixels,
  2731.                      surface->pitch,
  2732.                      10,
  2733.                      surface->h-20,
  2734.                      buffer);
  2735.     else
  2736.       drawText((u8*)surface->pixels,
  2737.                surface->pitch,
  2738.                10,
  2739.                surface->h-20,
  2740.                buffer);        
  2741.   }  
  2742.  
  2743.   SDL_UnlockSurface(surface);
  2744.   //  SDL_UpdateRect(surface, 0, 0, destWidth, destHeight);
  2745.   SDL_Flip(surface);
  2746. }
  2747.  
  2748. bool systemReadJoypads()
  2749. {
  2750.   return true;
  2751. }
  2752.  
  2753. u32 systemReadJoypad(int which)
  2754. {
  2755.   if(which < 0 || which > 3)
  2756.     which = sdlDefaultJoypad;
  2757.   
  2758.   u32 res = 0;
  2759.   
  2760.   if(sdlButtons[which][KEY_BUTTON_A])
  2761.     res |= 1;
  2762.   if(sdlButtons[which][KEY_BUTTON_B])
  2763.     res |= 2;
  2764.   if(sdlButtons[which][KEY_BUTTON_SELECT])
  2765.     res |= 4;
  2766.   if(sdlButtons[which][KEY_BUTTON_START])
  2767.     res |= 8;
  2768.   if(sdlButtons[which][KEY_RIGHT])
  2769.     res |= 16;
  2770.   if(sdlButtons[which][KEY_LEFT])
  2771.     res |= 32;
  2772.   if(sdlButtons[which][KEY_UP])
  2773.     res |= 64;
  2774.   if(sdlButtons[which][KEY_DOWN])
  2775.     res |= 128;
  2776.   if(sdlButtons[which][KEY_BUTTON_R])
  2777.     res |= 256;
  2778.   if(sdlButtons[which][KEY_BUTTON_L])
  2779.     res |= 512;
  2780.  
  2781.   // disallow L+R or U+D of being pressed at the same time
  2782.   if((res & 48) == 48)
  2783.     res &= ~16;
  2784.   if((res & 192) == 192)
  2785.     res &= ~128;
  2786.  
  2787.   if(sdlButtons[which][KEY_BUTTON_SPEED])
  2788.     res |= 1024;
  2789.   if(sdlButtons[which][KEY_BUTTON_CAPTURE])
  2790.     res |= 2048;
  2791.  
  2792.   if(autoFire) {
  2793.     res &= (~autoFire);
  2794.     if(autoFireToggle)
  2795.       res |= autoFire;
  2796.     autoFireToggle = !autoFireToggle;
  2797.   }
  2798.   
  2799.   return res;
  2800. }
  2801.  
  2802. void systemSetTitle(const char *title)
  2803. {
  2804.   SDL_WM_SetCaption(title, NULL);
  2805. }
  2806.  
  2807. void systemShowSpeed(int speed)
  2808. {
  2809.   systemSpeed = speed;
  2810.  
  2811.   showRenderedFrames = renderedFrames;
  2812.   renderedFrames = 0;  
  2813.  
  2814.   if(!fullscreen && showSpeed) {
  2815.     char buffer[80];
  2816.     if(showSpeed == 1)
  2817.       sprintf(buffer, "VisualBoyAdvance-%3d%%", systemSpeed);
  2818.     else
  2819.       sprintf(buffer, "VisualBoyAdvance-%3d%%(%d, %d fps)", systemSpeed,
  2820.               systemFrameSkip,
  2821.               showRenderedFrames);
  2822.  
  2823.     systemSetTitle(buffer);
  2824.   }
  2825. }
  2826.  
  2827. void systemFrame()
  2828. {
  2829. }
  2830.  
  2831. void system10Frames(int rate)
  2832. {
  2833.   u32 time = systemGetClock();  
  2834.   if(!wasPaused && autoFrameSkip && !throttle) {
  2835.     u32 diff = time - autoFrameSkipLastTime;
  2836.     int speed = 100;
  2837.  
  2838.     if(diff)
  2839.       speed = (1000000/rate)/diff;
  2840.     
  2841.     if(speed >= 98) {
  2842.       frameskipadjust++;
  2843.  
  2844.       if(frameskipadjust >= 3) {
  2845.         frameskipadjust=0;
  2846.         if(systemFrameSkip > 0)
  2847.           systemFrameSkip--;
  2848.       }
  2849.     } else {
  2850.       if(speed  < 80)
  2851.         frameskipadjust -= (90 - speed)/5;
  2852.       else if(systemFrameSkip < 9)
  2853.         frameskipadjust--;
  2854.  
  2855.       if(frameskipadjust <= -2) {
  2856.         frameskipadjust += 2;
  2857.         if(systemFrameSkip < 9)
  2858.           systemFrameSkip++;
  2859.       }
  2860.     }    
  2861.   }
  2862.   if(!wasPaused && throttle) {
  2863.     if(!speedup) {
  2864.       u32 diff = time - throttleLastTime;
  2865.       
  2866.       int target = (1000000/(rate*throttle));
  2867.       int d = (target - diff);
  2868.       
  2869.       if(d > 0) {
  2870.         SDL_Delay(d);
  2871.       }
  2872.     }
  2873.     throttleLastTime = systemGetClock();
  2874.   }
  2875.   if(rewindMemory) {
  2876.     if(++rewindCounter >= rewindTimer) {
  2877.       rewindSaveNeeded = true;
  2878.       rewindCounter = 0;
  2879.     }
  2880.   }
  2881.  
  2882.   if(systemSaveUpdateCounter) {
  2883.     if(--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED) {
  2884.       sdlWriteBattery();
  2885.       systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
  2886.     }
  2887.   }
  2888.  
  2889.   wasPaused = false;
  2890.   autoFrameSkipLastTime = time;
  2891. }
  2892.  
  2893. void systemScreenCapture(int a)
  2894. {
  2895.   char buffer[2048];
  2896.  
  2897.   if(captureFormat) {
  2898.     if(captureDir[0])
  2899.       sprintf(buffer, "%s/%s%02d.bmp", captureDir, sdlGetFilename(filename), a);
  2900.     else
  2901.       sprintf(buffer, "%s%02d.bmp", filename, a);
  2902.  
  2903.     emulator.emuWriteBMP(buffer);
  2904.   } else {
  2905.     if(captureDir[0])
  2906.       sprintf(buffer, "%s/%s%02d.png", captureDir, sdlGetFilename(filename), a);
  2907.     else
  2908.       sprintf(buffer, "%s%02d.png", filename, a);
  2909.     emulator.emuWritePNG(buffer);
  2910.   }
  2911.  
  2912.   systemScreenMessage("Screen capture");
  2913. }
  2914.  
  2915. void soundCallback(void *,u8 *stream,int len)
  2916. {
  2917.   if(!emulating)
  2918.     return;
  2919.   SDL_mutexP(mutex);
  2920.   //  printf("Locked mutex\n");
  2921.   if(!speedup && !throttle) {
  2922.     while(sdlSoundLen < 2048*2) {
  2923.       if(emulating)
  2924.         SDL_CondWait(cond, mutex);
  2925.       else 
  2926.         break;
  2927.     }
  2928.   }
  2929.   if(emulating) {
  2930.     //  printf("Copying data\n");
  2931.     memcpy(stream, sdlBuffer, len);
  2932.   }
  2933.   sdlSoundLen = 0;
  2934.   if(mutex)
  2935.     SDL_mutexV(mutex);
  2936. }
  2937.  
  2938. void systemWriteDataToSoundBuffer()
  2939. {
  2940.   if(SDL_GetAudioStatus() != SDL_AUDIO_PLAYING)
  2941.     SDL_PauseAudio(0);
  2942.   bool cont = true;
  2943.   while(cont && !speedup && !throttle) {
  2944.     SDL_mutexP(mutex);
  2945.     //    printf("Waiting for len < 2048 (speed up %d)\n", speedup);
  2946.     if(sdlSoundLen < 2048*2)
  2947.       cont = false;
  2948.     SDL_mutexV(mutex);
  2949.   }
  2950.  
  2951.   int len = soundBufferLen;
  2952.   int copied = 0;
  2953.   if((sdlSoundLen+len) >= 2048*2) {
  2954.     //    printf("Case 1\n");
  2955.     memcpy(&sdlBuffer[sdlSoundLen],soundFinalWave, 2048*2-sdlSoundLen);
  2956.     copied = 2048*2 - sdlSoundLen;
  2957.     sdlSoundLen = 2048*2;
  2958.     SDL_CondSignal(cond);
  2959.     cont = true;
  2960.     if(!speedup && !throttle) {
  2961.       while(cont) {
  2962.         SDL_mutexP(mutex);
  2963.         if(sdlSoundLen < 2048*2)
  2964.           cont = false;
  2965.         SDL_mutexV(mutex);
  2966.       }
  2967.       memcpy(&sdlBuffer[0],&(((u8 *)soundFinalWave)[copied]),
  2968.              soundBufferLen-copied);
  2969.       sdlSoundLen = soundBufferLen-copied;
  2970.     } else {
  2971.       memcpy(&sdlBuffer[0], &(((u8 *)soundFinalWave)[copied]), 
  2972. soundBufferLen);
  2973.     }
  2974.   } else {
  2975.     //    printf("case 2\n");
  2976.     memcpy(&sdlBuffer[sdlSoundLen], soundFinalWave, soundBufferLen);
  2977.     sdlSoundLen += soundBufferLen;
  2978.   }
  2979. }
  2980.  
  2981. bool systemSoundInit()
  2982. {
  2983.   SDL_AudioSpec audio;
  2984.  
  2985.   switch(soundQuality) {
  2986.   case 1:
  2987.     audio.freq = 44100;
  2988.     soundBufferLen = 1470*2;
  2989.     break;
  2990.   case 2:
  2991.     audio.freq = 22050;
  2992.     soundBufferLen = 736*2;
  2993.     break;
  2994.   case 4:
  2995.     audio.freq = 11025;
  2996.     soundBufferLen = 368*2;
  2997.     break;
  2998.   }
  2999.   audio.format=AUDIO_S16SYS;
  3000.   audio.channels = 2;
  3001.   audio.samples = 1024;
  3002.   audio.callback = soundCallback;
  3003.   audio.userdata = NULL;
  3004.   if(SDL_OpenAudio(&audio, NULL)) {
  3005.     fprintf(stderr,"Failed to open audio: %s\n", SDL_GetError());
  3006.     return false;
  3007.   }
  3008.   soundBufferTotalLen = soundBufferLen*10;
  3009.   cond = SDL_CreateCond();
  3010.   mutex = SDL_CreateMutex();
  3011.   sdlSoundLen = 0;
  3012.   systemSoundOn = true;
  3013.   return true;
  3014. }
  3015.  
  3016. void systemSoundShutdown()
  3017. {
  3018.   SDL_mutexP(mutex);
  3019.   SDL_CondSignal(cond);
  3020.   SDL_mutexV(mutex);
  3021.   SDL_DestroyCond(cond);
  3022.   cond = NULL;
  3023.   SDL_DestroyMutex(mutex);
  3024.   mutex = NULL;
  3025.   SDL_CloseAudio();
  3026. }
  3027.  
  3028. void systemSoundPause()
  3029. {
  3030.   SDL_PauseAudio(1);
  3031. }
  3032.  
  3033. void systemSoundResume()
  3034. {
  3035.   SDL_PauseAudio(0);
  3036. }
  3037.  
  3038. void systemSoundReset()
  3039. {
  3040. }
  3041.  
  3042. u32 systemGetClock()
  3043. {
  3044.   return SDL_GetTicks();
  3045. }
  3046.  
  3047. void systemUpdateMotionSensor()
  3048. {
  3049.   if(sdlMotionButtons[KEY_LEFT]) {
  3050.     sensorX += 3;
  3051.     if(sensorX > 2197)
  3052.       sensorX = 2197;
  3053.     if(sensorX < 2047)
  3054.       sensorX = 2057;
  3055.   } else if(sdlMotionButtons[KEY_RIGHT]) {
  3056.     sensorX -= 3;
  3057.     if(sensorX < 1897)
  3058.       sensorX = 1897;
  3059.     if(sensorX > 2047)
  3060.       sensorX = 2037;
  3061.   } else if(sensorX > 2047) {
  3062.     sensorX -= 2;
  3063.     if(sensorX < 2047)
  3064.       sensorX = 2047;
  3065.   } else {
  3066.     sensorX += 2;
  3067.     if(sensorX > 2047)
  3068.       sensorX = 2047;
  3069.   }
  3070.  
  3071.   if(sdlMotionButtons[KEY_UP]) {
  3072.     sensorY += 3;
  3073.     if(sensorY > 2197)
  3074.       sensorY = 2197;
  3075.     if(sensorY < 2047)
  3076.       sensorY = 2057;
  3077.   } else if(sdlMotionButtons[KEY_DOWN]) {
  3078.     sensorY -= 3;
  3079.     if(sensorY < 1897)
  3080.       sensorY = 1897;
  3081.     if(sensorY > 2047)
  3082.       sensorY = 2037;
  3083.   } else if(sensorY > 2047) {
  3084.     sensorY -= 2;
  3085.     if(sensorY < 2047)
  3086.       sensorY = 2047;
  3087.   } else {
  3088.     sensorY += 2;
  3089.     if(sensorY > 2047)
  3090.       sensorY = 2047;
  3091.   }    
  3092. }
  3093.  
  3094. int systemGetSensorX()
  3095. {
  3096.   return sensorX;
  3097. }
  3098.  
  3099. int systemGetSensorY()
  3100. {
  3101.   return sensorY;
  3102. }
  3103.  
  3104. void systemGbPrint(u8 *data,int pages,int feed,int palette, int contrast)
  3105. {
  3106. }
  3107.  
  3108. void systemScreenMessage(const char *msg)
  3109. {
  3110.   screenMessage = true;
  3111.   screenMessageTime = systemGetClock();
  3112.   if(strlen(msg) > 20) {
  3113.     strncpy(screenMessageBuffer, msg, 20);
  3114.     screenMessageBuffer[20] = 0;
  3115.   } else
  3116.     strcpy(screenMessageBuffer, msg);  
  3117. }
  3118.  
  3119. bool systemCanChangeSoundQuality()
  3120. {
  3121.   return false;
  3122. }
  3123.  
  3124. bool systemPauseOnFrame()
  3125. {
  3126.   if(pauseNextFrame) {
  3127.     paused = true;
  3128.     pauseNextFrame = false;
  3129.     return true;
  3130.   }
  3131.   return false;
  3132. }
  3133.  
  3134. // Code donated by Niels Wagenaar (BoycottAdvance)
  3135.  
  3136. // GBA screensize.
  3137. #define GBA_WIDTH   240
  3138. #define GBA_HEIGHT  160
  3139.  
  3140. void Init_Overlay(SDL_Surface *gbascreen, int overlaytype)
  3141. {
  3142.   
  3143.   overlay = SDL_CreateYUVOverlay( GBA_WIDTH,
  3144.                                   GBA_HEIGHT,
  3145.                                   overlaytype, gbascreen);
  3146.   fprintf(stderr, "Created %dx%dx%d %s %s overlay\n",
  3147.           overlay->w,overlay->h,overlay->planes,
  3148.           overlay->hw_overlay?"hardware":"software",
  3149.           overlay->format==SDL_YV12_OVERLAY?"YV12":
  3150.           overlay->format==SDL_IYUV_OVERLAY?"IYUV":
  3151.           overlay->format==SDL_YUY2_OVERLAY?"YUY2":
  3152.           overlay->format==SDL_UYVY_OVERLAY?"UYVY":
  3153.           overlay->format==SDL_YVYU_OVERLAY?"YVYU":
  3154.           "Unknown");
  3155. }
  3156.  
  3157. void Quit_Overlay(void)
  3158. {
  3159.   
  3160.   SDL_FreeYUVOverlay(overlay);
  3161. }
  3162.  
  3163. /* NOTE: These RGB conversion functions are not intended for speed,
  3164.    only as examples.
  3165. */
  3166. inline void RGBtoYUV(Uint8 *rgb, int *yuv)
  3167. {
  3168.   yuv[0] = (int)((0.257 * rgb[0]) + (0.504 * rgb[1]) + (0.098 * rgb[2]) + 16);
  3169.   yuv[1] = (int)(128 - (0.148 * rgb[0]) - (0.291 * rgb[1]) + (0.439 * rgb[2]));
  3170.   yuv[2] = (int)(128 + (0.439 * rgb[0]) - (0.368 * rgb[1]) - (0.071 * rgb[2]));
  3171. }
  3172.  
  3173. inline void ConvertRGBtoYV12(SDL_Overlay *o)
  3174. {
  3175.   int x,y;
  3176.   int yuv[3];
  3177.   Uint8 *p,*op[3];
  3178.   
  3179.   SDL_LockYUVOverlay(o);
  3180.   
  3181.   /* Black initialization */
  3182.   /*
  3183.     memset(o->pixels[0],0,o->pitches[0]*o->h);
  3184.     memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2));
  3185.     memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2));
  3186.   */
  3187.   
  3188.   /* Convert */
  3189.   for(y=0; y<160 && y<o->h; y++) {
  3190.     p=(Uint8 *)pix+srcPitch*y;
  3191.     op[0]=o->pixels[0]+o->pitches[0]*y;
  3192.     op[1]=o->pixels[1]+o->pitches[1]*(y/2);
  3193.     op[2]=o->pixels[2]+o->pitches[2]*(y/2);
  3194.     for(x=0; x<240 && x<o->w; x++) {
  3195.       RGBtoYUV(p,yuv);
  3196.       *(op[0]++)=yuv[0];
  3197.       if(x%2==0 && y%2==0) {
  3198.         *(op[1]++)=yuv[2];
  3199.         *(op[2]++)=yuv[1];
  3200.       }
  3201.       p+=4;//s->format->BytesPerPixel;
  3202.     }
  3203.   }
  3204.   
  3205.   SDL_UnlockYUVOverlay(o);
  3206. }
  3207.  
  3208. inline void ConvertRGBtoIYUV(SDL_Overlay *o)
  3209. {
  3210.   int x,y;
  3211.   int yuv[3];
  3212.   Uint8 *p,*op[3];
  3213.   
  3214.   SDL_LockYUVOverlay(o);
  3215.   
  3216.   /* Black initialization */
  3217.   /*
  3218.     memset(o->pixels[0],0,o->pitches[0]*o->h);
  3219.     memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2));
  3220.     memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2));
  3221.   */
  3222.   
  3223.   /* Convert */
  3224.   for(y=0; y<160 && y<o->h; y++) {
  3225.     p=(Uint8 *)pix+srcPitch*y;
  3226.     op[0]=o->pixels[0]+o->pitches[0]*y;
  3227.     op[1]=o->pixels[1]+o->pitches[1]*(y/2);
  3228.     op[2]=o->pixels[2]+o->pitches[2]*(y/2);
  3229.     for(x=0; x<240 && x<o->w; x++) {
  3230.       RGBtoYUV(p,yuv);
  3231.       *(op[0]++)=yuv[0];
  3232.       if(x%2==0 && y%2==0) {
  3233.         *(op[1]++)=yuv[1];
  3234.         *(op[2]++)=yuv[2];
  3235.       }
  3236.       p+=4; //s->format->BytesPerPixel;
  3237.     }
  3238.   }
  3239.   
  3240.   SDL_UnlockYUVOverlay(o);
  3241. }
  3242.  
  3243. inline void ConvertRGBtoUYVY(SDL_Overlay *o)
  3244. {
  3245.   int x,y;
  3246.   int yuv[3];
  3247.   Uint8 *p,*op;
  3248.   
  3249.   SDL_LockYUVOverlay(o);
  3250.   
  3251.   for(y=0; y<160 && y<o->h; y++) {
  3252.     p=(Uint8 *)pix+srcPitch*y;
  3253.     op=o->pixels[0]+o->pitches[0]*y;
  3254.     for(x=0; x<240 && x<o->w; x++) {
  3255.       RGBtoYUV(p,yuv);
  3256.       if(x%2==0) {
  3257.         *(op++)=yuv[1];
  3258.         *(op++)=yuv[0];
  3259.         *(op++)=yuv[2];
  3260.       } else
  3261.         *(op++)=yuv[0];
  3262.       
  3263.       p+=4; //s->format->BytesPerPixel;
  3264.     }
  3265.   }
  3266.   
  3267.   SDL_UnlockYUVOverlay(o);
  3268. }
  3269.  
  3270. inline void ConvertRGBtoYVYU(SDL_Overlay *o)
  3271. {
  3272.   int x,y;
  3273.   int yuv[3];
  3274.   Uint8 *p,*op;
  3275.   
  3276.   SDL_LockYUVOverlay(o);
  3277.   
  3278.   for(y=0; y<160 && y<o->h; y++) {
  3279.     p=(Uint8 *)pix+srcPitch*y;
  3280.     op=o->pixels[0]+o->pitches[0]*y;
  3281.     for(x=0; x<240 && x<o->w; x++) {
  3282.       RGBtoYUV(p,yuv);
  3283.       if(x%2==0) {
  3284.         *(op++)=yuv[0];
  3285.         *(op++)=yuv[2];
  3286.         op[1]=yuv[1];
  3287.       } else {
  3288.         *op=yuv[0];
  3289.         op+=2;
  3290.       }
  3291.       
  3292.       p+=4; //s->format->BytesPerPixel;
  3293.     }
  3294.   }
  3295.   
  3296.   SDL_UnlockYUVOverlay(o);
  3297. }
  3298.  
  3299. inline void ConvertRGBtoYUY2(SDL_Overlay *o)
  3300. {
  3301.   int x,y;
  3302.   int yuv[3];
  3303.   Uint8 *p,*op;
  3304.   
  3305.   SDL_LockYUVOverlay(o);
  3306.   
  3307.   for(y=0; y<160 && y<o->h; y++) {
  3308.     p=(Uint8 *)pix+srcPitch*y;
  3309.     op=o->pixels[0]+o->pitches[0]*y;
  3310.     for(x=0; x<240 && x<o->w; x++) {
  3311.       RGBtoYUV(p,yuv);
  3312.       if(x%2==0) {
  3313.         *(op++)=yuv[0];
  3314.         *(op++)=yuv[1];
  3315.         op[1]=yuv[2];
  3316.       } else {
  3317.         *op=yuv[0];
  3318.         op+=2;
  3319.       }
  3320.       
  3321.       p+=4; //s->format->BytesPerPixel;
  3322.     }
  3323.   }
  3324.   
  3325.   SDL_UnlockYUVOverlay(o);
  3326. }
  3327.  
  3328. inline void Convert32bit(SDL_Surface *display)
  3329. {
  3330.   switch(overlay->format) {
  3331.   case SDL_YV12_OVERLAY:
  3332.     ConvertRGBtoYV12(overlay);
  3333.     break;
  3334.   case SDL_UYVY_OVERLAY:
  3335.     ConvertRGBtoUYVY(overlay);
  3336.     break;
  3337.   case SDL_YVYU_OVERLAY:
  3338.     ConvertRGBtoYVYU(overlay);
  3339.     break;
  3340.   case SDL_YUY2_OVERLAY:
  3341.     ConvertRGBtoYUY2(overlay);
  3342.     break;
  3343.   case SDL_IYUV_OVERLAY:
  3344.     ConvertRGBtoIYUV(overlay);
  3345.     break;
  3346.   default:
  3347.     fprintf(stderr, "cannot convert RGB picture to obtained YUV format!\n");
  3348.     exit(1);
  3349.     break;
  3350.   }
  3351.   
  3352. }
  3353.  
  3354.  
  3355. inline void Draw_Overlay(SDL_Surface *display, int size)
  3356. {
  3357.   SDL_LockYUVOverlay(overlay);
  3358.   
  3359.   Convert32bit(display);
  3360.   
  3361.   overlay_rect.x = 0;
  3362.   overlay_rect.y = 0;
  3363.   overlay_rect.w = GBA_WIDTH  * size;
  3364.   overlay_rect.h = GBA_HEIGHT * size;
  3365.  
  3366.   SDL_DisplayYUVOverlay(overlay, &overlay_rect);
  3367.   SDL_UnlockYUVOverlay(overlay);
  3368. }
  3369.  
  3370. void systemGbBorderOn()
  3371. {
  3372.   srcWidth = 256;
  3373.   srcHeight = 224;
  3374.   gbBorderLineSkip = 256;
  3375.   gbBorderColumnSkip = 48;
  3376.   gbBorderRowSkip = 40;
  3377.  
  3378.   destWidth = (sizeOption+1)*srcWidth;
  3379.   destHeight = (sizeOption+1)*srcHeight;
  3380.   
  3381.   surface = SDL_SetVideoMode(destWidth, destHeight, 16,
  3382.                              SDL_ANYFORMAT|SDL_HWSURFACE|SDL_DOUBLEBUF|
  3383.                              (fullscreen ? SDL_FULLSCREEN : 0));  
  3384. #ifndef C_CORE
  3385.   sdlMakeStretcher(srcWidth);
  3386. #else
  3387.   switch(systemColorDepth) {
  3388.   case 16:
  3389.     sdlStretcher = sdlStretcher16[sizeOption];
  3390.     break;
  3391.   case 24:
  3392.     sdlStretcher = sdlStretcher24[sizeOption];
  3393.     break;
  3394.   case 32:
  3395.     sdlStretcher = sdlStretcher32[sizeOption];
  3396.     break;
  3397.   default:
  3398.     fprintf(stderr, "Unsupported resolution: %d\n", systemColorDepth);
  3399.     exit(-1);
  3400.   }
  3401. #endif
  3402.  
  3403.   if(systemColorDepth == 16) {
  3404.     if(sdlCalculateMaskWidth(surface->format->Gmask) == 6) {
  3405.       Init_2xSaI(565);
  3406.       RGB_LOW_BITS_MASK = 0x821;
  3407.     } else {
  3408.       Init_2xSaI(555);
  3409.       RGB_LOW_BITS_MASK = 0x421;      
  3410.     }
  3411.     if(cartridgeType == 2) {
  3412.       for(int i = 0; i < 0x10000; i++) {
  3413.         systemColorMap16[i] = (((i >> 1) & 0x1f) << systemBlueShift) |
  3414.           (((i & 0x7c0) >> 6) << systemGreenShift) |
  3415.           (((i & 0xf800) >> 11) << systemRedShift);  
  3416.       }      
  3417.     } else {
  3418.       for(int i = 0; i < 0x10000; i++) {
  3419.         systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
  3420.           (((i & 0x3e0) >> 5) << systemGreenShift) |
  3421.           (((i & 0x7c00) >> 10) << systemBlueShift);  
  3422.       }
  3423.     }
  3424.     srcPitch = srcWidth * 2+4;
  3425.   } else {
  3426.     if(systemColorDepth != 32)
  3427.       filterFunction = NULL;
  3428.     RGB_LOW_BITS_MASK = 0x010101;
  3429.     if(systemColorDepth == 32) {
  3430.       Init_2xSaI(32);
  3431.     }
  3432.     for(int i = 0; i < 0x10000; i++) {
  3433.       systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
  3434.         (((i & 0x3e0) >> 5) << systemGreenShift) |
  3435.         (((i & 0x7c00) >> 10) << systemBlueShift);  
  3436.     }
  3437.     if(systemColorDepth == 32)
  3438.       srcPitch = srcWidth*4 + 4;
  3439.     else
  3440.       srcPitch = srcWidth*3;
  3441.   }
  3442. }
  3443.