view src/sdl/SDL.cpp @ 30:48369c6aeaa0 compile-milestone

brought prof package in
author Robert McIntyre <rlm@mit.edu>
date Sun, 04 Mar 2012 22:32:01 -0600
parents f9f4f1b99eed
children 44974c3e093b
line wrap: on
line source
1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
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.
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 #include <config.h>
26 #include "AutoBuild.h"
28 #include "Port.h"
29 #include "SDL.h"
30 #include "debugger.h"
31 #include "gba/GBA.h"
32 #include "gba/GBAGlobals.h"
33 #include "gba/agbprint.h"
34 #include "gba/Flash.h"
35 #include "gba/RTC.h"
36 #include "gba/GBASound.h"
37 #include "gb/GB.h"
38 #include "gb/gbGlobals.h"
39 #include "common/Text.h"
40 #include "common/unzip.h"
41 #include "common/Util.h"
42 #include "common/movie.h"
43 #include "common/System.h"
44 #include "common/inputGlobal.h"
45 #include "../common/vbalua.h"
46 #include "SoundSDL.h"
49 #define GBC_CAPABLE ((gbRom[0x143] & 0x80) != 0)
50 #define SGB_CAPABLE (gbRom[0x146] == 0x03)
52 #ifndef WIN32
53 # include <unistd.h>
54 # define GETCWD getcwd
55 #else // WIN32
56 # include <direct.h>
57 # define GETCWD _getcwd
58 #endif // WIN32
60 #ifndef __GNUC__
61 # define HAVE_DECL_GETOPT 0
62 # define __STDC__ 1
63 # include "getopt.h"
64 #else // ! __GNUC__
65 # define HAVE_DECL_GETOPT 1
66 # include "getopt.h"
67 #endif // ! __GNUC__
69 #ifdef MMX
70 extern "C" bool cpu_mmx;
71 #endif
72 extern bool8 soundEcho;
73 extern bool8 soundLowPass;
74 extern bool8 soundReverse;
75 extern int Init_2xSaI(u32);
76 extern void _2xSaI(u8*,u32,u8*,u8*,u32,int,int);
77 extern void _2xSaI32(u8*,u32,u8*,u8*,u32,int,int);
78 extern void Super2xSaI(u8*,u32,u8*,u8*,u32,int,int);
79 extern void Super2xSaI32(u8*,u32,u8*,u8*,u32,int,int);
80 extern void SuperEagle(u8*,u32,u8*,u8*,u32,int,int);
81 extern void SuperEagle32(u8*,u32,u8*,u8*,u32,int,int);
82 extern void Pixelate2x16(u8*,u32,u8*,u8*,u32,int,int);
83 extern void Pixelate2x32(u8*,u32,u8*,u8*,u32,int,int);
84 extern void MotionBlur(u8*,u32,u8*,u8*,u32,int,int);
85 extern void MotionBlur32(u8*,u32,u8*,u8*,u32,int,int);
86 extern void AdMame2x(u8*,u32,u8*,u8*,u32,int,int);
87 extern void AdMame2x32(u8*,u32,u8*,u8*,u32,int,int);
88 extern void Simple2x16(u8*,u32,u8*,u8*,u32,int,int);
89 extern void Simple2x32(u8*,u32,u8*,u8*,u32,int,int);
90 extern void Bilinear(u8*,u32,u8*,u8*,u32,int,int);
91 extern void Bilinear32(u8*,u32,u8*,u8*,u32,int,int);
92 extern void BilinearPlus(u8*,u32,u8*,u8*,u32,int,int);
93 extern void BilinearPlus32(u8*,u32,u8*,u8*,u32,int,int);
94 extern void Scanlines(u8*,u32,u8*,u8*,u32,int,int);
95 extern void Scanlines32(u8*,u32,u8*,u8*,u32,int,int);
96 extern void ScanlinesTV(u8*,u32,u8*,u8*,u32,int,int);
97 extern void ScanlinesTV32(u8*,u32,u8*,u8*,u32,int,int);
98 extern void hq2x(u8*,u32,u8*,u8*,u32,int,int);
99 extern void hq2x32(u8*,u32,u8*,u8*,u32,int,int);
100 extern void lq2x(u8*,u32,u8*,u8*,u32,int,int);
101 extern void lq2x32(u8*,u32,u8*,u8*,u32,int,int);
103 extern void SmartIB(u8*,u32,int,int);
104 extern void SmartIB32(u8*,u32,int,int);
105 extern void MotionBlurIB(u8*,u32,int,int);
106 extern void MotionBlurIB32(u8*,u32,int,int);
108 void Init_Overlay(SDL_Surface *surface, int overlaytype);
109 void Quit_Overlay(void);
110 void Draw_Overlay(SDL_Surface *surface, int size);
112 extern void remoteInit();
113 extern void remoteCleanUp();
114 extern void remoteStubMain();
115 extern void remoteStubSignal(int,int);
116 extern void remoteOutput(char *, u32);
117 extern void remoteSetProtocol(int);
118 extern void remoteSetPort(int);
119 extern void debuggerOutput(char *, u32);
121 extern void CPUUpdateRenderBuffers(bool);
123 struct EmulatedSystem theEmulator = {
124 NULL,
125 NULL,
126 NULL,
127 NULL,
128 NULL,
129 NULL,
130 NULL,
131 NULL,
132 NULL,
133 NULL,
134 NULL,
135 NULL,
136 false,
137 0
138 };
140 SDL_Surface *surface = NULL;
141 SDL_Overlay *overlay = NULL;
142 SDL_Rect overlay_rect;
144 int systemSpeed = 0;
145 int systemRedShift = 0;
146 int systemBlueShift = 0;
147 int systemGreenShift = 0;
148 int systemColorDepth = 0;
149 int systemDebug = 0;
150 int systemVerbose = 0;
151 int systemFrameSkip = 0;
152 int systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
154 int srcPitch = 0;
155 int srcWidth = 0;
156 int srcHeight = 0;
157 int destWidth = 0;
158 int destHeight = 0;
160 int sensorX = 2047;
161 int sensorY = 2047;
162 bool sensorOn = false;
164 int filter = 0;
165 u8 *delta = NULL;
167 int sdlPrintUsage = 0;
168 int disableMMX = 0;
170 int systemCartridgeType = 3;
171 int sizeOption = 0;
172 int captureFormat = 0;
173 int useMovie = 0;
175 int pauseWhenInactive = 0;
176 int active = 1;
177 int emulating = 0;
178 int RGB_LOW_BITS_MASK=0x821;
179 u32 systemColorMap32[0x10000];
180 u16 systemColorMap16[0x10000];
181 u16 systemGbPalette[24];
182 void (*filterFunction)(u8*,u32,u8*,u8*,u32,int,int) = NULL;
183 void (*ifbFunction)(u8*,u32,int,int) = NULL;
184 int ifbType = 0;
185 char filename[2048];
186 char ipsname[2048];
187 char biosFileName[2048];
188 char movieFileName[2048];
189 char captureDir[2048];
190 char saveDir[2048];
191 char batteryDir[2048];
193 static char *rewindMemory = NULL;
194 static int rewindPos = 0;
195 static int rewindTopPos = 0;
196 static int rewindCounter = 0;
197 static int rewindCount = 0;
198 static bool rewindSaveNeeded = false;
199 static int rewindTimer = 0;
201 #define REWIND_SIZE 400000
203 #define _stricmp strcasecmp
205 /*bool sdlButtons[4][12] = {
206 { false, false, false, false, false, false,
207 false, false, false, false, false, false },
208 { false, false, false, false, false, false,
209 false, false, false, false, false, false },
210 { false, false, false, false, false, false,
211 false, false, false, false, false, false },
212 { false, false, false, false, false, false,
213 false, false, false, false, false, false }
214 };*/
215 /*
216 I'm changing the way the SDL GUI handles the button
217 input to match the one in win32, this is needed in
218 order to be compatible with the format required by
219 common/movie.cpp
220 --Felipe
221 */
223 u16 currentButtons[4] = {0, 0, 0, 0};
225 bool sdlMotionButtons[4] = { false, false, false, false };
226 const int32 INITIAL_SENSOR_VALUE = 2047;
228 int sdlNumDevices = 0;
229 SDL_Joystick **sdlDevices = NULL;
231 bool wasPaused = false;
232 int autoFrameSkip = 0;
233 int frameskipadjust = 0;
234 int showRenderedFrames = 0;
235 int renderedFrames = 0;
237 int throttle = 0;
238 u32 throttleLastTime = 0;
239 u32 autoFrameSkipLastTime = 0;
241 int showSpeed = 1;
242 int showSpeedTransparent = 1;
243 bool disableStatusMessages = false;
244 bool paused = false;
245 bool pauseNextFrame = false;
246 bool debugger = false;
247 bool debuggerStub = false;
248 int fullscreen = 0;
249 bool systemSoundOn = false;
250 bool yuv = false;
251 int yuvType = 0;
252 bool removeIntros = false;
253 int sdlFlashSize = 0;
254 int sdlAutoIPS = 1;
255 int sdlRtcEnable = 0;
256 int sdlAgbPrint = 0;
258 int sdlDefaultJoypad = 0;
260 extern void debuggerSignal(int,int);
262 void (*dbgMain)() = debuggerMain;
263 void (*dbgSignal)(int,int) = debuggerSignal;
264 void (*dbgOutput)(char *, u32) = debuggerOutput;
266 int mouseCounter = 0;
267 int autoFire = 0;
268 bool autoFireToggle = false;
270 bool screenMessage[8] = {false,false,false,false,false,false,false,false};
271 char screenMessageBuffer[8][21];
272 u32 screenMessageTime[8] = {0,0,0,0,0,0,0,0};
273 u32 screenMessageDuration[8] = {0,0,0,0,0,0,0,0};
275 SDL_cond *cond = NULL;
276 SDL_mutex *mutex = NULL;
277 u8* sdlBuffer;
278 int sdlSoundLen = 0;
279 SoundSDL* soundDriver = NULL;
281 char *arg0;
283 #ifndef C_CORE
284 u8 sdlStretcher[16384];
285 int sdlStretcherPos;
286 #else
287 void (*sdlStretcher)(u8 *, u8*) = NULL;
288 #endif
290 u16 joypad[4][12] = {
291 { SDLK_LEFT, SDLK_RIGHT,
292 SDLK_UP, SDLK_DOWN,
293 SDLK_z, SDLK_x,
294 SDLK_RETURN,SDLK_BACKSPACE,
295 SDLK_a, SDLK_s,
296 SDLK_SPACE, SDLK_F12
297 },
298 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
299 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
300 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
301 };
303 u16 defaultJoypad[12] = {
304 SDLK_LEFT, SDLK_RIGHT,
305 SDLK_UP, SDLK_DOWN,
306 SDLK_z, SDLK_x,
307 SDLK_RETURN,SDLK_BACKSPACE,
308 SDLK_a, SDLK_s,
309 SDLK_SPACE, SDLK_F12
310 };
312 u16 motion[4] = {
313 SDLK_KP4, SDLK_KP6, SDLK_KP8, SDLK_KP2
314 };
316 u16 defaultMotion[4] = {
317 SDLK_KP4, SDLK_KP6, SDLK_KP8, SDLK_KP2
318 };
320 struct option sdlOptions[] = {
321 { "agb-print", no_argument, &sdlAgbPrint, 1 },
322 { "auto-frameskip", no_argument, &autoFrameSkip, 1 },
323 { "bios", required_argument, 0, 'b' },
324 { "config", required_argument, 0, 'c' },
325 { "debug", no_argument, 0, 'd' },
326 { "filter", required_argument, 0, 'f' },
327 { "filter-normal", no_argument, &filter, 0 },
328 { "filter-tv-mode", no_argument, &filter, 1 },
329 { "filter-2xsai", no_argument, &filter, 2 },
330 { "filter-super-2xsai", no_argument, &filter, 3 },
331 { "filter-super-eagle", no_argument, &filter, 4 },
332 { "filter-pixelate", no_argument, &filter, 5 },
333 { "filter-motion-blur", no_argument, &filter, 6 },
334 { "filter-advmame", no_argument, &filter, 7 },
335 { "filter-simple2x", no_argument, &filter, 8 },
336 { "filter-bilinear", no_argument, &filter, 9 },
337 { "filter-bilinear+", no_argument, &filter, 10 },
338 { "filter-scanlines", no_argument, &filter, 11 },
339 { "filter-hq2x", no_argument, &filter, 12 },
340 { "filter-lq2x", no_argument, &filter, 13 },
341 { "flash-size", required_argument, 0, 'S' },
342 { "flash-64k", no_argument, &sdlFlashSize, 0 },
343 { "flash-128k", no_argument, &sdlFlashSize, 1 },
344 { "frameskip", required_argument, 0, 's' },
345 { "fullscreen", no_argument, &fullscreen, 1 },
346 { "gdb", required_argument, 0, 'G' },
347 { "help", no_argument, &sdlPrintUsage, 1 },
348 { "ifb-none", no_argument, &ifbType, 0 },
349 { "ifb-motion-blur", no_argument, &ifbType, 1 },
350 { "ifb-smart", no_argument, &ifbType, 2 },
351 { "ips", required_argument, 0, 'i' },
352 { "no-agb-print", no_argument, &sdlAgbPrint, 0 },
353 { "no-auto-frameskip", no_argument, &autoFrameSkip, 0 },
354 { "no-debug", no_argument, 0, 'N' },
355 { "no-ips", no_argument, &sdlAutoIPS, 0 },
356 { "no-mmx", no_argument, &disableMMX, 1 },
357 { "no-pause-when-inactive", no_argument, &pauseWhenInactive, 0 },
358 { "no-rtc", no_argument, &sdlRtcEnable, 0 },
359 { "no-show-speed", no_argument, &showSpeed, 0 },
360 { "no-throttle", no_argument, &throttle, 0 },
361 { "pause-when-inactive", no_argument, &pauseWhenInactive, 1 },
362 { "profile", optional_argument, 0, 'P' },
363 { "rtc", no_argument, &sdlRtcEnable, 1 },
364 { "save-type", required_argument, 0, 't' },
365 { "save-auto", no_argument, &cpuSaveType, 0 },
366 { "save-eeprom", no_argument, &cpuSaveType, 1 },
367 { "save-sram", no_argument, &cpuSaveType, 2 },
368 { "save-flash", no_argument, &cpuSaveType, 3 },
369 { "save-sensor", no_argument, &cpuSaveType, 4 },
370 { "save-none", no_argument, &cpuSaveType, 5 },
371 { "show-speed-normal", no_argument, &showSpeed, 1 },
372 { "show-speed-detailed", no_argument, &showSpeed, 2 },
373 { "throttle", required_argument, 0, 'T' },
374 { "verbose", required_argument, 0, 'v' },
375 { "video-1x", no_argument, &sizeOption, 0 },
376 { "video-2x", no_argument, &sizeOption, 1 },
377 { "video-3x", no_argument, &sizeOption, 2 },
378 { "video-4x", no_argument, &sizeOption, 3 },
379 { "yuv", required_argument, 0, 'Y' },
380 { "recordmovie", required_argument, 0, 'r' },
381 { "playmovie", required_argument, 0, 'p' },
382 { "watchmovie", required_argument, 0, 'w' },
383 { NULL, no_argument, NULL, 0 }
384 };
386 #ifndef C_CORE
387 #define SDL_LONG(val) \
388 *((u32 *)&sdlStretcher[sdlStretcherPos]) = val;\
389 sdlStretcherPos+=4;
391 #define SDL_AND_EAX(val) \
392 sdlStretcher[sdlStretcherPos++] = 0x25;\
393 SDL_LONG(val);
395 #define SDL_AND_EBX(val) \
396 sdlStretcher[sdlStretcherPos++] = 0x81;\
397 sdlStretcher[sdlStretcherPos++] = 0xe3;\
398 SDL_LONG(val);
400 #define SDL_OR_EAX_EBX \
401 sdlStretcher[sdlStretcherPos++] = 0x09;\
402 sdlStretcher[sdlStretcherPos++] = 0xd8;
404 #define SDL_LOADL_EBX \
405 sdlStretcher[sdlStretcherPos++] = 0x8b;\
406 sdlStretcher[sdlStretcherPos++] = 0x1f;
408 #define SDL_LOADW \
409 sdlStretcher[sdlStretcherPos++] = 0x66;\
410 sdlStretcher[sdlStretcherPos++] = 0x8b;\
411 sdlStretcher[sdlStretcherPos++] = 0x06;\
412 sdlStretcher[sdlStretcherPos++] = 0x83;\
413 sdlStretcher[sdlStretcherPos++] = 0xc6;\
414 sdlStretcher[sdlStretcherPos++] = 0x02;
416 #define SDL_LOADL \
417 sdlStretcher[sdlStretcherPos++] = 0x8b;\
418 sdlStretcher[sdlStretcherPos++] = 0x06;\
419 sdlStretcher[sdlStretcherPos++] = 0x83;\
420 sdlStretcher[sdlStretcherPos++] = 0xc6;\
421 sdlStretcher[sdlStretcherPos++] = 0x04;
423 #define SDL_LOADL2 \
424 sdlStretcher[sdlStretcherPos++] = 0x8b;\
425 sdlStretcher[sdlStretcherPos++] = 0x06;\
426 sdlStretcher[sdlStretcherPos++] = 0x83;\
427 sdlStretcher[sdlStretcherPos++] = 0xc6;\
428 sdlStretcher[sdlStretcherPos++] = 0x03;
430 #define SDL_STOREW \
431 sdlStretcher[sdlStretcherPos++] = 0x66;\
432 sdlStretcher[sdlStretcherPos++] = 0x89;\
433 sdlStretcher[sdlStretcherPos++] = 0x07;\
434 sdlStretcher[sdlStretcherPos++] = 0x83;\
435 sdlStretcher[sdlStretcherPos++] = 0xc7;\
436 sdlStretcher[sdlStretcherPos++] = 0x02;
438 #define SDL_STOREL \
439 sdlStretcher[sdlStretcherPos++] = 0x89;\
440 sdlStretcher[sdlStretcherPos++] = 0x07;\
441 sdlStretcher[sdlStretcherPos++] = 0x83;\
442 sdlStretcher[sdlStretcherPos++] = 0xc7;\
443 sdlStretcher[sdlStretcherPos++] = 0x04;
445 #define SDL_STOREL2 \
446 sdlStretcher[sdlStretcherPos++] = 0x89;\
447 sdlStretcher[sdlStretcherPos++] = 0x07;\
448 sdlStretcher[sdlStretcherPos++] = 0x83;\
449 sdlStretcher[sdlStretcherPos++] = 0xc7;\
450 sdlStretcher[sdlStretcherPos++] = 0x03;
452 #define SDL_RET \
453 sdlStretcher[sdlStretcherPos++] = 0xc3;
455 #define SDL_PUSH_EAX \
456 sdlStretcher[sdlStretcherPos++] = 0x50;
458 #define SDL_PUSH_ECX \
459 sdlStretcher[sdlStretcherPos++] = 0x51;
461 #define SDL_PUSH_EBX \
462 sdlStretcher[sdlStretcherPos++] = 0x53;
464 #define SDL_PUSH_ESI \
465 sdlStretcher[sdlStretcherPos++] = 0x56;
467 #define SDL_PUSH_EDI \
468 sdlStretcher[sdlStretcherPos++] = 0x57;
470 #define SDL_POP_EAX \
471 sdlStretcher[sdlStretcherPos++] = 0x58;
473 #define SDL_POP_ECX \
474 sdlStretcher[sdlStretcherPos++] = 0x59;
476 #define SDL_POP_EBX \
477 sdlStretcher[sdlStretcherPos++] = 0x5b;
479 #define SDL_POP_ESI \
480 sdlStretcher[sdlStretcherPos++] = 0x5e;
482 #define SDL_POP_EDI \
483 sdlStretcher[sdlStretcherPos++] = 0x5f;
485 #define SDL_MOV_ECX(val) \
486 sdlStretcher[sdlStretcherPos++] = 0xb9;\
487 SDL_LONG(val);
489 #define SDL_REP_MOVSB \
490 sdlStretcher[sdlStretcherPos++] = 0xf3;\
491 sdlStretcher[sdlStretcherPos++] = 0xa4;
493 #define SDL_REP_MOVSW \
494 sdlStretcher[sdlStretcherPos++] = 0xf3;\
495 sdlStretcher[sdlStretcherPos++] = 0x66;\
496 sdlStretcher[sdlStretcherPos++] = 0xa5;
498 #define SDL_REP_MOVSL \
499 sdlStretcher[sdlStretcherPos++] = 0xf3;\
500 sdlStretcher[sdlStretcherPos++] = 0xa5;
502 void sdlMakeStretcher(int width)
503 {
504 sdlStretcherPos = 0;
505 switch(systemColorDepth) {
506 case 16:
507 if(sizeOption) {
508 SDL_PUSH_EAX;
509 SDL_PUSH_ESI;
510 SDL_PUSH_EDI;
511 for(int i = 0; i < width; i++) {
512 SDL_LOADW;
513 SDL_STOREW;
514 SDL_STOREW;
515 if(sizeOption > 1) {
516 SDL_STOREW;
517 }
518 if(sizeOption > 2) {
519 SDL_STOREW;
520 }
521 }
522 SDL_POP_EDI;
523 SDL_POP_ESI;
524 SDL_POP_EAX;
525 SDL_RET;
526 } else {
527 SDL_PUSH_ESI;
528 SDL_PUSH_EDI;
529 SDL_PUSH_ECX;
530 SDL_MOV_ECX(width);
531 SDL_REP_MOVSW;
532 SDL_POP_ECX;
533 SDL_POP_EDI;
534 SDL_POP_ESI;
535 SDL_RET;
536 }
537 break;
538 case 24:
539 if(sizeOption) {
540 SDL_PUSH_EAX;
541 SDL_PUSH_ESI;
542 SDL_PUSH_EDI;
543 int w = width - 1;
544 for(int i = 0; i < w; i++) {
545 SDL_LOADL2;
546 SDL_STOREL2;
547 SDL_STOREL2;
548 if(sizeOption > 1) {
549 SDL_STOREL2;
550 }
551 if(sizeOption > 2) {
552 SDL_STOREL2;
553 }
554 }
555 // need to write the last one
556 SDL_LOADL2;
557 SDL_STOREL2;
558 if(sizeOption > 1) {
559 SDL_STOREL2;
560 }
561 if(sizeOption > 2) {
562 SDL_STOREL2;
563 }
564 SDL_AND_EAX(0x00ffffff);
565 SDL_PUSH_EBX;
566 SDL_LOADL_EBX;
567 SDL_AND_EBX(0xff000000);
568 SDL_OR_EAX_EBX;
569 SDL_POP_EBX;
570 SDL_STOREL2;
571 SDL_POP_EDI;
572 SDL_POP_ESI;
573 SDL_POP_EAX;
574 SDL_RET;
575 } else {
576 SDL_PUSH_ESI;
577 SDL_PUSH_EDI;
578 SDL_PUSH_ECX;
579 SDL_MOV_ECX(3*width);
580 SDL_REP_MOVSB;
581 SDL_POP_ECX;
582 SDL_POP_EDI;
583 SDL_POP_ESI;
584 SDL_RET;
585 }
586 break;
587 case 32:
588 if(sizeOption) {
589 SDL_PUSH_EAX;
590 SDL_PUSH_ESI;
591 SDL_PUSH_EDI;
592 for(int i = 0; i < width; i++) {
593 SDL_LOADL;
594 SDL_STOREL;
595 SDL_STOREL;
596 if(sizeOption > 1) {
597 SDL_STOREL;
598 }
599 if(sizeOption > 2) {
600 SDL_STOREL;
601 }
602 }
603 SDL_POP_EDI;
604 SDL_POP_ESI;
605 SDL_POP_EAX;
606 SDL_RET;
607 } else {
608 SDL_PUSH_ESI;
609 SDL_PUSH_EDI;
610 SDL_PUSH_ECX;
611 SDL_MOV_ECX(width);
612 SDL_REP_MOVSL;
613 SDL_POP_ECX;
614 SDL_POP_EDI;
615 SDL_POP_ESI;
616 SDL_RET;
617 }
618 break;
619 }
620 }
622 #ifdef _MSC_VER
623 #define SDL_CALL_STRETCHER \
624 {\
625 __asm mov eax, stretcher\
626 __asm mov edi, dest\
627 __asm mov esi, src\
628 __asm call eax\
629 }
630 #else
631 #define SDL_CALL_STRETCHER \
632 asm volatile("call *%%eax"::"a" (stretcher),"S" (src),"D" (dest))
633 #endif
634 #else
635 #define SDL_CALL_STRETCHER \
636 sdlStretcher(src, dest)
638 void sdlStretch16x1(u8 *src, u8 *dest)
639 {
640 u16 *s = (u16 *)src;
641 u16 *d = (u16 *)dest;
642 for(int i = 0; i < srcWidth; i++)
643 *d++ = *s++;
644 }
646 void sdlStretch16x2(u8 *src, u8 *dest)
647 {
648 u16 *s = (u16 *)src;
649 u16 *d = (u16 *)dest;
650 for(int i = 0; i < srcWidth; i++) {
651 *d++ = *s;
652 *d++ = *s++;
653 }
654 }
656 void sdlStretch16x3(u8 *src, u8 *dest)
657 {
658 u16 *s = (u16 *)src;
659 u16 *d = (u16 *)dest;
660 for(int i = 0; i < srcWidth; i++) {
661 *d++ = *s;
662 *d++ = *s;
663 *d++ = *s++;
664 }
665 }
667 void sdlStretch16x4(u8 *src, u8 *dest)
668 {
669 u16 *s = (u16 *)src;
670 u16 *d = (u16 *)dest;
671 for(int i = 0; i < srcWidth; i++) {
672 *d++ = *s;
673 *d++ = *s;
674 *d++ = *s;
675 *d++ = *s++;
676 }
677 }
679 void (*sdlStretcher16[4])(u8 *, u8 *) = {
680 sdlStretch16x1,
681 sdlStretch16x2,
682 sdlStretch16x3,
683 sdlStretch16x4
684 };
686 void sdlStretch32x1(u8 *src, u8 *dest)
687 {
688 u32 *s = (u32 *)src;
689 u32 *d = (u32 *)dest;
690 for(int i = 0; i < srcWidth; i++)
691 *d++ = *s++;
692 }
694 void sdlStretch32x2(u8 *src, u8 *dest)
695 {
696 u32 *s = (u32 *)src;
697 u32 *d = (u32 *)dest;
698 for(int i = 0; i < srcWidth; i++) {
699 *d++ = *s;
700 *d++ = *s++;
701 }
702 }
704 void sdlStretch32x3(u8 *src, u8 *dest)
705 {
706 u32 *s = (u32 *)src;
707 u32 *d = (u32 *)dest;
708 for(int i = 0; i < srcWidth; i++) {
709 *d++ = *s;
710 *d++ = *s;
711 *d++ = *s++;
712 }
713 }
715 void sdlStretch32x4(u8 *src, u8 *dest)
716 {
717 u32 *s = (u32 *)src;
718 u32 *d = (u32 *)dest;
719 for(int i = 0; i < srcWidth; i++) {
720 *d++ = *s;
721 *d++ = *s;
722 *d++ = *s;
723 *d++ = *s++;
724 }
725 }
727 void (*sdlStretcher32[4])(u8 *, u8 *) = {
728 sdlStretch32x1,
729 sdlStretch32x2,
730 sdlStretch32x3,
731 sdlStretch32x4
732 };
734 void sdlStretch24x1(u8 *src, u8 *dest)
735 {
736 u8 *s = src;
737 u8 *d = dest;
738 for(int i = 0; i < srcWidth; i++) {
739 *d++ = *s++;
740 *d++ = *s++;
741 *d++ = *s++;
742 }
743 }
745 void sdlStretch24x2(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 }
759 }
761 void sdlStretch24x3(u8 *src, u8 *dest)
762 {
763 u8 *s = (u8 *)src;
764 u8 *d = (u8 *)dest;
765 for(int i = 0; i < srcWidth; i++) {
766 *d++ = *s;
767 *d++ = *(s+1);
768 *d++ = *(s+2);
769 s += 3;
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 }
779 }
781 void sdlStretch24x4(u8 *src, u8 *dest)
782 {
783 u8 *s = (u8 *)src;
784 u8 *d = (u8 *)dest;
785 for(int i = 0; i < srcWidth; i++) {
786 *d++ = *s;
787 *d++ = *(s+1);
788 *d++ = *(s+2);
789 s += 3;
790 *d++ = *s;
791 *d++ = *(s+1);
792 *d++ = *(s+2);
793 s += 3;
794 *d++ = *s;
795 *d++ = *(s+1);
796 *d++ = *(s+2);
797 s += 3;
798 *d++ = *s;
799 *d++ = *(s+1);
800 *d++ = *(s+2);
801 s += 3;
802 }
803 }
805 void (*sdlStretcher24[4])(u8 *, u8 *) = {
806 sdlStretch24x1,
807 sdlStretch24x2,
808 sdlStretch24x3,
809 sdlStretch24x4
810 };
812 #endif
814 u32 sdlFromHex(char *s)
815 {
816 u32 value;
817 sscanf(s, "%x", &value);
818 return value;
819 }
821 #ifdef __MSC__
822 #define stat _stat
823 #define S_IFDIR _S_IFDIR
824 #endif
826 void sdlCheckDirectory(char *dir)
827 {
828 struct stat buf;
830 int len = strlen(dir);
832 char *p = dir + len - 1;
834 if(*p == '/' ||
835 *p == '\\')
836 *p = 0;
838 if(stat(dir, &buf) == 0) {
839 if(!(buf.st_mode & S_IFDIR)) {
840 fprintf(stderr, "Error: %s is not a directory\n", dir);
841 dir[0] = 0;
842 }
843 } else {
844 fprintf(stderr, "Error: %s does not exist\n", dir);
845 dir[0] = 0;
846 }
847 }
849 char *sdlGetFilename(char *name)
850 {
851 static char filebuffer[2048];
853 int len = strlen(name);
855 char *p = name + len - 1;
857 while(true) {
858 if(*p == '/' ||
859 *p == '\\') {
860 p++;
861 break;
862 }
863 len--;
864 p--;
865 if(len == 0)
866 break;
867 }
869 if(len == 0)
870 strcpy(filebuffer, name);
871 else
872 strcpy(filebuffer, p);
873 return filebuffer;
874 }
876 FILE *sdlFindFile(const char *name)
877 {
878 char buffer[4096];
879 char path[2048];
881 #ifdef WIN32
882 #define PATH_SEP ";"
883 #define FILE_SEP '\\'
884 #define EXE_NAME "VisualBoyAdvance-SDL.exe"
885 #else // ! WIN32
886 #define PATH_SEP ":"
887 #define FILE_SEP '/'
888 #define EXE_NAME "VisualBoyAdvance"
889 #endif // ! WIN32
891 fprintf(stderr, "Searching for file %s\n", name);
893 if(GETCWD(buffer, 2048)) {
894 fprintf(stderr, "Searching current directory: %s\n", buffer);
895 }
897 FILE *f = fopen(name, "r");
898 if(f != NULL) {
899 return f;
900 }
902 char *home = getenv("HOME");
904 if(home != NULL) {
905 fprintf(stderr, "Searching home directory: %s\n", home);
906 sprintf(path, "%s%c%s", home, FILE_SEP, name);
907 f = fopen(path, "r");
908 if(f != NULL)
909 return f;
910 }
912 #ifdef WIN32
913 home = getenv("USERPROFILE");
914 if(home != NULL) {
915 fprintf(stderr, "Searching user profile directory: %s\n", home);
916 sprintf(path, "%s%c%s", home, FILE_SEP, name);
917 f = fopen(path, "r");
918 if(f != NULL)
919 return f;
920 }
921 #else // ! WIN32
922 fprintf(stderr, "Searching system config directory: %s\n", SYSCONFDIR);
923 sprintf(path, "%s%c%s", SYSCONFDIR, FILE_SEP, name);
924 f = fopen(path, "r");
925 if(f != NULL)
926 return f;
927 #endif // ! WIN32
929 if(!strchr(arg0, '/') &&
930 !strchr(arg0, '\\')) {
931 char *path = getenv("PATH");
933 if(path != NULL) {
934 fprintf(stderr, "Searching PATH\n");
935 strncpy(buffer, path, 4096);
936 buffer[4095] = 0;
937 char *tok = strtok(buffer, PATH_SEP);
939 while(tok) {
940 sprintf(path, "%s%c%s", tok, FILE_SEP, EXE_NAME);
941 f = fopen(path, "r");
942 if(f != NULL) {
943 char path2[2048];
944 fclose(f);
945 sprintf(path2, "%s%c%s", tok, FILE_SEP, name);
946 f = fopen(path2, "r");
947 if(f != NULL) {
948 fprintf(stderr, "Found at %s\n", path2);
949 return f;
950 }
951 }
952 tok = strtok(NULL, PATH_SEP);
953 }
954 }
955 } else {
956 // executable is relative to some directory
957 fprintf(stderr, "Searching executable directory\n");
958 strcpy(buffer, arg0);
959 char *p = strrchr(buffer, FILE_SEP);
960 if(p) {
961 *p = 0;
962 sprintf(path, "%s%c%s", buffer, FILE_SEP, name);
963 f = fopen(path, "r");
964 if(f != NULL)
965 return f;
966 }
967 }
968 return NULL;
969 }
971 void sdlReadPreferences(FILE *f)
972 {
973 char buffer[2048];
975 while(1) {
976 char *s = fgets(buffer, 2048, f);
978 if(s == NULL)
979 break;
981 char *p = strchr(s, '#');
983 if(p)
984 *p = 0;
986 char *token = strtok(s, " \t\n\r=");
988 if(!token)
989 continue;
991 if(strlen(token) == 0)
992 continue;
994 char *key = token;
995 char *value = strtok(NULL, "\t\n\r");
997 if(value == NULL) {
998 fprintf(stderr, "Empty value for key %s\n", key);
999 continue;
1002 if(!strcmp(key,"Joy0_Left")) {
1003 joypad[0][KEY_LEFT] = sdlFromHex(value);
1004 } else if(!strcmp(key, "Joy0_Right")) {
1005 joypad[0][KEY_RIGHT] = sdlFromHex(value);
1006 } else if(!strcmp(key, "Joy0_Up")) {
1007 joypad[0][KEY_UP] = sdlFromHex(value);
1008 } else if(!strcmp(key, "Joy0_Down")) {
1009 joypad[0][KEY_DOWN] = sdlFromHex(value);
1010 } else if(!strcmp(key, "Joy0_A")) {
1011 joypad[0][KEY_BUTTON_A] = sdlFromHex(value);
1012 } else if(!strcmp(key, "Joy0_B")) {
1013 joypad[0][KEY_BUTTON_B] = sdlFromHex(value);
1014 } else if(!strcmp(key, "Joy0_L")) {
1015 joypad[0][KEY_BUTTON_L] = sdlFromHex(value);
1016 } else if(!strcmp(key, "Joy0_R")) {
1017 joypad[0][KEY_BUTTON_R] = sdlFromHex(value);
1018 } else if(!strcmp(key, "Joy0_Start")) {
1019 joypad[0][KEY_BUTTON_START] = sdlFromHex(value);
1020 } else if(!strcmp(key, "Joy0_Select")) {
1021 joypad[0][KEY_BUTTON_SELECT] = sdlFromHex(value);
1022 } else if(!strcmp(key, "Joy0_Speed")) {
1023 joypad[0][KEY_BUTTON_SPEED] = sdlFromHex(value);
1024 } else if(!strcmp(key, "Joy0_Capture")) {
1025 joypad[0][KEY_BUTTON_CAPTURE] = sdlFromHex(value);
1026 } else if(!strcmp(key,"Joy1_Left")) {
1027 joypad[1][KEY_LEFT] = sdlFromHex(value);
1028 } else if(!strcmp(key, "Joy1_Right")) {
1029 joypad[1][KEY_RIGHT] = sdlFromHex(value);
1030 } else if(!strcmp(key, "Joy1_Up")) {
1031 joypad[1][KEY_UP] = sdlFromHex(value);
1032 } else if(!strcmp(key, "Joy1_Down")) {
1033 joypad[1][KEY_DOWN] = sdlFromHex(value);
1034 } else if(!strcmp(key, "Joy1_A")) {
1035 joypad[1][KEY_BUTTON_A] = sdlFromHex(value);
1036 } else if(!strcmp(key, "Joy1_B")) {
1037 joypad[1][KEY_BUTTON_B] = sdlFromHex(value);
1038 } else if(!strcmp(key, "Joy1_L")) {
1039 joypad[1][KEY_BUTTON_L] = sdlFromHex(value);
1040 } else if(!strcmp(key, "Joy1_R")) {
1041 joypad[1][KEY_BUTTON_R] = sdlFromHex(value);
1042 } else if(!strcmp(key, "Joy1_Start")) {
1043 joypad[1][KEY_BUTTON_START] = sdlFromHex(value);
1044 } else if(!strcmp(key, "Joy1_Select")) {
1045 joypad[1][KEY_BUTTON_SELECT] = sdlFromHex(value);
1046 } else if(!strcmp(key, "Joy1_Speed")) {
1047 joypad[1][KEY_BUTTON_SPEED] = sdlFromHex(value);
1048 } else if(!strcmp(key, "Joy1_Capture")) {
1049 joypad[1][KEY_BUTTON_CAPTURE] = sdlFromHex(value);
1050 } else if(!strcmp(key,"Joy2_Left")) {
1051 joypad[2][KEY_LEFT] = sdlFromHex(value);
1052 } else if(!strcmp(key, "Joy2_Right")) {
1053 joypad[2][KEY_RIGHT] = sdlFromHex(value);
1054 } else if(!strcmp(key, "Joy2_Up")) {
1055 joypad[2][KEY_UP] = sdlFromHex(value);
1056 } else if(!strcmp(key, "Joy2_Down")) {
1057 joypad[2][KEY_DOWN] = sdlFromHex(value);
1058 } else if(!strcmp(key, "Joy2_A")) {
1059 joypad[2][KEY_BUTTON_A] = sdlFromHex(value);
1060 } else if(!strcmp(key, "Joy2_B")) {
1061 joypad[2][KEY_BUTTON_B] = sdlFromHex(value);
1062 } else if(!strcmp(key, "Joy2_L")) {
1063 joypad[2][KEY_BUTTON_L] = sdlFromHex(value);
1064 } else if(!strcmp(key, "Joy2_R")) {
1065 joypad[2][KEY_BUTTON_R] = sdlFromHex(value);
1066 } else if(!strcmp(key, "Joy2_Start")) {
1067 joypad[2][KEY_BUTTON_START] = sdlFromHex(value);
1068 } else if(!strcmp(key, "Joy2_Select")) {
1069 joypad[2][KEY_BUTTON_SELECT] = sdlFromHex(value);
1070 } else if(!strcmp(key, "Joy2_Speed")) {
1071 joypad[2][KEY_BUTTON_SPEED] = sdlFromHex(value);
1072 } else if(!strcmp(key, "Joy2_Capture")) {
1073 joypad[2][KEY_BUTTON_CAPTURE] = sdlFromHex(value);
1074 } else if(!strcmp(key,"Joy4_Left")) {
1075 joypad[4][KEY_LEFT] = sdlFromHex(value);
1076 } else if(!strcmp(key, "Joy4_Right")) {
1077 joypad[4][KEY_RIGHT] = sdlFromHex(value);
1078 } else if(!strcmp(key, "Joy4_Up")) {
1079 joypad[4][KEY_UP] = sdlFromHex(value);
1080 } else if(!strcmp(key, "Joy4_Down")) {
1081 joypad[4][KEY_DOWN] = sdlFromHex(value);
1082 } else if(!strcmp(key, "Joy4_A")) {
1083 joypad[4][KEY_BUTTON_A] = sdlFromHex(value);
1084 } else if(!strcmp(key, "Joy4_B")) {
1085 joypad[4][KEY_BUTTON_B] = sdlFromHex(value);
1086 } else if(!strcmp(key, "Joy4_L")) {
1087 joypad[4][KEY_BUTTON_L] = sdlFromHex(value);
1088 } else if(!strcmp(key, "Joy4_R")) {
1089 joypad[4][KEY_BUTTON_R] = sdlFromHex(value);
1090 } else if(!strcmp(key, "Joy4_Start")) {
1091 joypad[4][KEY_BUTTON_START] = sdlFromHex(value);
1092 } else if(!strcmp(key, "Joy4_Select")) {
1093 joypad[4][KEY_BUTTON_SELECT] = sdlFromHex(value);
1094 } else if(!strcmp(key, "Joy4_Speed")) {
1095 joypad[4][KEY_BUTTON_SPEED] = sdlFromHex(value);
1096 } else if(!strcmp(key, "Joy4_Capture")) {
1097 joypad[4][KEY_BUTTON_CAPTURE] = sdlFromHex(value);
1098 } else if(!strcmp(key, "Motion_Left")) {
1099 motion[KEY_LEFT] = sdlFromHex(value);
1100 } else if(!strcmp(key, "Motion_Right")) {
1101 motion[KEY_RIGHT] = sdlFromHex(value);
1102 } else if(!strcmp(key, "Motion_Up")) {
1103 motion[KEY_UP] = sdlFromHex(value);
1104 } else if(!strcmp(key, "Motion_Down")) {
1105 motion[KEY_DOWN] = sdlFromHex(value);
1106 } else if(!strcmp(key, "frameSkip")) {
1107 frameSkip = sdlFromHex(value);
1108 if(frameSkip < 0 || frameSkip > 9)
1109 frameSkip = 2;
1110 } else if(!strcmp(key, "gbFrameSkip")) {
1111 gbFrameSkip = sdlFromHex(value);
1112 if(gbFrameSkip < 0 || gbFrameSkip > 9)
1113 gbFrameSkip = 0;
1114 } else if(!strcmp(key, "video")) {
1115 sizeOption = sdlFromHex(value);
1116 if(sizeOption < 0 || sizeOption > 3)
1117 sizeOption = 1;
1118 } else if(!strcmp(key, "fullScreen")) {
1119 fullscreen = sdlFromHex(value) ? 1 : 0;
1120 } else if(!strcmp(key, "useBios")) {
1121 useBios = sdlFromHex(value) ? true : false;
1122 } else if(!strcmp(key, "skipBios")) {
1123 skipBios = sdlFromHex(value) ? true : false;
1124 } else if(!strcmp(key, "biosFile")) {
1125 strcpy(biosFileName, value);
1126 } else if(!strcmp(key, "filter")) {
1127 filter = sdlFromHex(value);
1128 if(filter < 0 || filter > 13)
1129 filter = 0;
1130 } else if(!strcmp(key, "disableStatus")) {
1131 disableStatusMessages = sdlFromHex(value) ? true : false;
1132 } else if(!strcmp(key, "borderOn")) {
1133 gbBorderOn = sdlFromHex(value) ? true : false;
1134 } else if(!strcmp(key, "borderAutomatic")) {
1135 gbBorderAutomatic = sdlFromHex(value) ? true : false;
1136 } else if(!strcmp(key, "emulatorType")) {
1137 gbEmulatorType = sdlFromHex(value);
1138 if(gbEmulatorType < 0 || gbEmulatorType > 5)
1139 gbEmulatorType = 1;
1140 } else if(!strcmp(key, "colorOption")) {
1141 gbColorOption = sdlFromHex(value) ? true : false;
1142 } else if(!strcmp(key, "captureDir")) {
1143 sdlCheckDirectory(value);
1144 strcpy(captureDir, value);
1145 } else if(!strcmp(key, "saveDir")) {
1146 sdlCheckDirectory(value);
1147 strcpy(saveDir, value);
1148 } else if(!strcmp(key, "batteryDir")) {
1149 sdlCheckDirectory(value);
1150 strcpy(batteryDir, value);
1151 } else if(!strcmp(key, "captureFormat")) {
1152 captureFormat = sdlFromHex(value);
1153 } else if(!strcmp(key, "soundQuality")) {
1154 soundQuality = sdlFromHex(value);
1155 switch(soundQuality) {
1156 case 1: break;
1157 default:
1158 fprintf(stderr, "The rerecording version will run only sound at highest quality. Defaulting to 44.1 KHz\n");
1159 soundQuality = 1;
1160 break;
1162 } else if(!strcmp(key, "soundOff")) {
1163 soundOffFlag = sdlFromHex(value) ? true : false;
1164 } else if(!strcmp(key, "soundEnable")) {
1165 int res = sdlFromHex(value) & 0x30f;
1166 soundEnableChannels(res);
1167 soundDisableChannels(~res);
1168 } else if(!strcmp(key, "soundEcho")) {
1169 soundEcho = sdlFromHex(value) ? true : false;
1170 } else if(!strcmp(key, "soundLowPass")) {
1171 soundLowPass = sdlFromHex(value) ? true : false;
1172 } else if(!strcmp(key, "soundReverse")) {
1173 soundReverse = sdlFromHex(value) ? true : false;
1174 } else if(!strcmp(key, "soundVolume")) {
1175 soundVolume = sdlFromHex(value);
1176 if(soundVolume < 0 || soundVolume > 3)
1177 soundVolume = 0;
1178 } else if(!strcmp(key, "removeIntros")) {
1179 removeIntros = sdlFromHex(value) ? true : false;
1180 } else if(!strcmp(key, "saveType")) {
1181 cpuSaveType = sdlFromHex(value);
1182 if(cpuSaveType < 0 || cpuSaveType > 5)
1183 cpuSaveType = 0;
1184 } else if(!strcmp(key, "flashSize")) {
1185 sdlFlashSize = sdlFromHex(value);
1186 if(sdlFlashSize != 0 && sdlFlashSize != 1)
1187 sdlFlashSize = 0;
1188 } else if(!strcmp(key, "ifbType")) {
1189 ifbType = sdlFromHex(value);
1190 if(ifbType < 0 || ifbType > 2)
1191 ifbType = 0;
1192 } else if(!strcmp(key, "showSpeed")) {
1193 showSpeed = sdlFromHex(value);
1194 if(showSpeed < 0 || showSpeed > 2)
1195 showSpeed = 1;
1196 } else if(!strcmp(key, "showSpeedTransparent")) {
1197 showSpeedTransparent = sdlFromHex(value);
1198 } else if(!strcmp(key, "autoFrameSkip")) {
1199 autoFrameSkip = sdlFromHex(value);
1200 } else if(!strcmp(key, "throttle")) {
1201 throttle = sdlFromHex(value);
1202 if(throttle != 0 && (throttle < 5 || throttle > 1000))
1203 throttle = 0;
1204 } else if(!strcmp(key, "disableMMX")) {
1205 #ifdef MMX
1206 cpu_mmx = sdlFromHex(value) ? false : true;
1207 #endif
1208 } else if(!strcmp(key, "pauseWhenInactive")) {
1209 pauseWhenInactive = sdlFromHex(value) ? true : false;
1210 } else if(!strcmp(key, "agbPrint")) {
1211 sdlAgbPrint = sdlFromHex(value);
1212 } else if(!strcmp(key, "rtcEnabled")) {
1213 sdlRtcEnable = sdlFromHex(value);
1214 } else if(!strcmp(key, "rewindTimer")) {
1215 rewindTimer = sdlFromHex(value);
1216 if(rewindTimer < 0 || rewindTimer > 600)
1217 rewindTimer = 0;
1218 rewindTimer *= 6; // convert value to 10 frames multiple
1219 } else if(!strcmp(key, "enhancedDetection")) {
1220 cpuEnhancedDetection = sdlFromHex(value) ? true : false;
1221 } else {
1222 fprintf(stderr, "Unknown configuration key %s\n", key);
1227 void sdlReadPreferences()
1229 FILE *f = sdlFindFile("VisualBoyAdvance.cfg");
1231 if(f == NULL) {
1232 fprintf(stderr, "Configuration file NOT FOUND (using defaults)\n");
1233 return;
1234 } else
1235 fprintf(stderr, "Reading configuration file.\n");
1237 sdlReadPreferences(f);
1239 fclose(f);
1242 static void sdlApplyPerImagePreferences()
1244 FILE *f = sdlFindFile("vba-over.ini");
1245 if(!f) {
1246 fprintf(stderr, "vba-over.ini NOT FOUND (using emulator settings)\n");
1247 return;
1248 } else
1249 fprintf(stderr, "Reading vba-over.ini\n");
1251 char buffer[7];
1252 buffer[0] = '[';
1253 buffer[1] = rom[0xac];
1254 buffer[2] = rom[0xad];
1255 buffer[3] = rom[0xae];
1256 buffer[4] = rom[0xaf];
1257 buffer[5] = ']';
1258 buffer[6] = 0;
1260 char readBuffer[2048];
1262 bool found = false;
1264 while(1) {
1265 char *s = fgets(readBuffer, 2048, f);
1267 if(s == NULL)
1268 break;
1270 char *p = strchr(s, ';');
1272 if(p)
1273 *p = 0;
1275 char *token = strtok(s, " \t\n\r=");
1277 if(!token)
1278 continue;
1279 if(strlen(token) == 0)
1280 continue;
1282 if(!strcmp(token, buffer)) {
1283 found = true;
1284 break;
1288 if(found) {
1289 while(1) {
1290 char *s = fgets(readBuffer, 2048, f);
1292 if(s == NULL)
1293 break;
1295 char *p = strchr(s, ';');
1296 if(p)
1297 *p = 0;
1299 char *token = strtok(s, " \t\n\r=");
1300 if(!token)
1301 continue;
1302 if(strlen(token) == 0)
1303 continue;
1305 if(token[0] == '[') // starting another image settings
1306 break;
1307 char *value = strtok(NULL, "\t\n\r=");
1308 if(value == NULL)
1309 continue;
1311 if(!strcmp(token, "rtcEnabled"))
1312 rtcEnable(atoi(value) == 0 ? false : true);
1313 else if(!strcmp(token, "flashSize")) {
1314 int size = atoi(value);
1315 if(size == 0x10000 || size == 0x20000)
1316 flashSetSize(size);
1317 } else if(!strcmp(token, "saveType")) {
1318 int save = atoi(value);
1319 if(save >= 0 && save <= 5)
1320 cpuSaveType = save;
1324 fclose(f);
1327 static int sdlCalculateShift(u32 mask)
1329 int m = 0;
1331 while(mask) {
1332 m++;
1333 mask >>= 1;
1336 return m-5;
1339 static int sdlCalculateMaskWidth(u32 mask)
1341 int m = 0;
1342 int mask2 = mask;
1344 while(mask2) {
1345 m++;
1346 mask2 >>= 1;
1349 int m2 = 0;
1350 mask2 = mask;
1351 while(!(mask2 & 1)) {
1352 m2++;
1353 mask2 >>= 1;
1356 return m - m2;
1359 void sdlWriteState(int num)
1361 char stateName[2048];
1363 if(saveDir[0])
1364 sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename),
1365 num+1);
1366 else
1367 sprintf(stateName,"%s%d.sgm", filename, num+1);
1368 if(theEmulator.emuWriteState)
1369 theEmulator.emuWriteState(stateName);
1370 sprintf(stateName, "Wrote state %d", num+1);
1371 systemScreenMessage(stateName);
1374 void sdlReadState(int num)
1376 char stateName[2048];
1378 if(saveDir[0])
1379 sprintf(stateName, "%s/%s%d.sgm", saveDir, sdlGetFilename(filename),
1380 num+1);
1381 else
1382 sprintf(stateName,"%s%d.sgm", filename, num+1);
1384 if(theEmulator.emuReadState)
1385 theEmulator.emuReadState(stateName);
1387 sprintf(stateName, "Loaded state %d", num+1);
1388 systemScreenMessage(stateName);
1391 void sdlWriteBattery()
1393 char buffer[1048];
1395 if(batteryDir[0])
1396 sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
1397 else
1398 sprintf(buffer, "%s.sav", filename);
1400 theEmulator.emuWriteBattery(buffer);
1402 systemScreenMessage("Wrote battery");
1405 void sdlReadBattery()
1407 char buffer[1048];
1409 if(batteryDir[0])
1410 sprintf(buffer, "%s/%s.sav", batteryDir, sdlGetFilename(filename));
1411 else
1412 sprintf(buffer, "%s.sav", filename);
1414 bool res = false;
1416 res = theEmulator.emuReadBattery(buffer);
1418 if(res)
1419 systemScreenMessage("Loaded battery");
1422 #define MOD_KEYS (KMOD_CTRL|KMOD_SHIFT|KMOD_ALT|KMOD_META)
1423 #define MOD_NOCTRL (KMOD_SHIFT|KMOD_ALT|KMOD_META)
1424 #define MOD_NOALT (KMOD_CTRL|KMOD_SHIFT|KMOD_META)
1425 #define MOD_NOSHIFT (KMOD_CTRL|KMOD_ALT|KMOD_META)
1427 void sdlUpdateKey(int key, bool down)
1429 int i;
1430 for(int j = 0; j < 4; j++) {
1431 for(i = 0 ; i < 12; i++) {
1432 if((joypad[j][i] & 0xf000) == 0) {
1433 if(key == joypad[j][i])
1434 if (down) currentButtons[j] |= 1<<i;
1435 else currentButtons[j] ^= 1<<i;
1439 for(i = 0 ; i < 4; i++) {
1440 if((motion[i] & 0xf000) == 0) {
1441 if(key == motion[i])
1442 sdlMotionButtons[i] = down;
1447 void sdlUpdateJoyButton(int which,
1448 int button,
1449 bool pressed)
1451 int i;
1452 for(int j = 0; j < 4; j++) {
1453 for(i = 0; i < 12; i++) {
1454 int dev = (joypad[j][i] >> 12);
1455 int b = joypad[j][i] & 0xfff;
1456 if(dev) {
1457 dev--;
1459 if((dev == which) && (b >= 128) && (b == (button+128))) {
1460 if (pressed) currentButtons[j] |= 1<<i;
1461 else currentButtons[j] ^= 1<<i;
1466 for(i = 0; i < 4; i++) {
1467 int dev = (motion[i] >> 12);
1468 int b = motion[i] & 0xfff;
1469 if(dev) {
1470 dev--;
1472 if((dev == which) && (b >= 128) && (b == (button+128))) {
1473 sdlMotionButtons[i] = pressed;
1479 void sdlUpdateJoyHat(int which,
1480 int hat,
1481 int value)
1483 int i;
1484 for(int j = 0; j < 4; j++) {
1485 for(i = 0; i < 12; i++) {
1486 int dev = (joypad[j][i] >> 12);
1487 int a = joypad[j][i] & 0xfff;
1488 if(dev) {
1489 dev--;
1491 if((dev == which) && (a>=32) && (a < 48) && (((a&15)>>2) == hat)) {
1492 int dir = a & 3;
1493 int v = 0;
1494 switch(dir) {
1495 case 0:
1496 v = value & SDL_HAT_UP;
1497 break;
1498 case 1:
1499 v = value & SDL_HAT_DOWN;
1500 break;
1501 case 2:
1502 v = value & SDL_HAT_RIGHT;
1503 break;
1504 case 3:
1505 v = value & SDL_HAT_LEFT;
1506 break;
1508 if (v) currentButtons[j] |= 1<<i;
1509 else currentButtons[j] ^= 1<<i;
1514 for(i = 0; i < 4; i++) {
1515 int dev = (motion[i] >> 12);
1516 int a = motion[i] & 0xfff;
1517 if(dev) {
1518 dev--;
1520 if((dev == which) && (a>=32) && (a < 48) && (((a&15)>>2) == hat)) {
1521 int dir = a & 3;
1522 int v = 0;
1523 switch(dir) {
1524 case 0:
1525 v = value & SDL_HAT_UP;
1526 break;
1527 case 1:
1528 v = value & SDL_HAT_DOWN;
1529 break;
1530 case 2:
1531 v = value & SDL_HAT_RIGHT;
1532 break;
1533 case 3:
1534 v = value & SDL_HAT_LEFT;
1535 break;
1537 sdlMotionButtons[i] = (v ? true : false);
1543 void sdlUpdateJoyAxis(int which,
1544 int axis,
1545 int value)
1547 int i;
1548 for(int j = 0; j < 4; j++) {
1549 for(i = 0; i < 12; i++) {
1550 int dev = (joypad[j][i] >> 12);
1551 int a = joypad[j][i] & 0xfff;
1552 if(dev) {
1553 dev--;
1555 if((dev == which) && (a < 32) && ((a>>1) == axis)) {
1556 //I have no idea what this does, is this reimplementation correct? --Felipe
1557 if (value>16384) {
1558 if (a&1) currentButtons[j] |= 1<<i;
1559 else currentButtons[j] ^= 1<<i;
1561 else if (value<16384){
1562 if (a&1) currentButtons[j] ^= 1<<i;
1563 else currentButtons[j] |= 1<<i;
1569 for(i = 0; i < 4; i++) {
1570 int dev = (motion[i] >> 12);
1571 int a = motion[i] & 0xfff;
1572 if(dev) {
1573 dev--;
1575 if((dev == which) && (a < 32) && ((a>>1) == axis)) {
1576 sdlMotionButtons[i] = (a & 1) ? (value > 16384) : (value < -16384);
1582 bool sdlCheckJoyKey(int key)
1584 int dev = (key >> 12) - 1;
1585 int what = key & 0xfff;
1587 if(what >= 128) {
1588 // joystick button
1589 int button = what - 128;
1591 if(button >= SDL_JoystickNumButtons(sdlDevices[dev]))
1592 return false;
1593 } else if (what < 0x20) {
1594 // joystick axis
1595 what >>= 1;
1596 if(what >= SDL_JoystickNumAxes(sdlDevices[dev]))
1597 return false;
1598 } else if (what < 0x30) {
1599 // joystick hat
1600 what = (what & 15);
1601 what >>= 2;
1602 if(what >= SDL_JoystickNumHats(sdlDevices[dev]))
1603 return false;
1606 // no problem found
1607 return true;
1610 void sdlCheckKeys()
1612 sdlNumDevices = SDL_NumJoysticks();
1614 if(sdlNumDevices)
1615 sdlDevices = (SDL_Joystick **)calloc(1,sdlNumDevices *
1616 sizeof(SDL_Joystick **));
1617 int i;
1619 bool usesJoy = false;
1621 for(int j = 0; j < 4; j++) {
1622 for(i = 0; i < 12; i++) {
1623 int dev = joypad[j][i] >> 12;
1624 if(dev) {
1625 dev--;
1626 bool ok = false;
1628 if(sdlDevices) {
1629 if(dev < sdlNumDevices) {
1630 if(sdlDevices[dev] == NULL) {
1631 sdlDevices[dev] = SDL_JoystickOpen(dev);
1634 ok = sdlCheckJoyKey(joypad[j][i]);
1635 } else
1636 ok = false;
1639 if(!ok)
1640 joypad[j][i] = defaultJoypad[i];
1641 else
1642 usesJoy = true;
1647 for(i = 0; i < 4; i++) {
1648 int dev = motion[i] >> 12;
1649 if(dev) {
1650 dev--;
1651 bool ok = false;
1653 if(sdlDevices) {
1654 if(dev < sdlNumDevices) {
1655 if(sdlDevices[dev] == NULL) {
1656 sdlDevices[dev] = SDL_JoystickOpen(dev);
1659 ok = sdlCheckJoyKey(motion[i]);
1660 } else
1661 ok = false;
1664 if(!ok)
1665 motion[i] = defaultMotion[i];
1666 else
1667 usesJoy = true;
1671 if(usesJoy)
1672 SDL_JoystickEventState(SDL_ENABLE);
1675 void sdlPollEvents()
1677 SDL_Event event;
1678 while(SDL_PollEvent(&event)) {
1679 switch(event.type) {
1680 case SDL_QUIT:
1681 emulating = 0;
1682 break;
1683 case SDL_ACTIVEEVENT:
1684 if(pauseWhenInactive && (event.active.state & SDL_APPINPUTFOCUS)) {
1685 active = event.active.gain;
1686 if(active) {
1687 if(!paused) {
1688 if(emulating)
1689 soundResume();
1691 } else {
1692 wasPaused = true;
1693 if(pauseWhenInactive) {
1694 if(emulating)
1695 soundPause();
1698 memset(delta,255,sizeof(delta));
1701 break;
1702 case SDL_MOUSEMOTION:
1703 case SDL_MOUSEBUTTONUP:
1704 case SDL_MOUSEBUTTONDOWN:
1705 if(fullscreen) {
1706 SDL_ShowCursor(SDL_ENABLE);
1707 mouseCounter = 120;
1709 break;
1710 case SDL_JOYHATMOTION:
1711 sdlUpdateJoyHat(event.jhat.which,
1712 event.jhat.hat,
1713 event.jhat.value);
1714 break;
1715 case SDL_JOYBUTTONDOWN:
1716 case SDL_JOYBUTTONUP:
1717 sdlUpdateJoyButton(event.jbutton.which,
1718 event.jbutton.button,
1719 event.jbutton.state == SDL_PRESSED);
1720 break;
1721 case SDL_JOYAXISMOTION:
1722 sdlUpdateJoyAxis(event.jaxis.which,
1723 event.jaxis.axis,
1724 event.jaxis.value);
1725 break;
1726 case SDL_KEYDOWN:
1727 sdlUpdateKey(event.key.keysym.sym, true);
1728 break;
1729 case SDL_KEYUP:
1730 switch(event.key.keysym.sym) {
1731 case SDLK_r:
1732 if(!(event.key.keysym.mod & MOD_NOCTRL) &&
1733 (event.key.keysym.mod & KMOD_CTRL)) {
1734 if(emulating) {
1735 theEmulator.emuReset(true);
1737 systemScreenMessage("Reset");
1740 break;
1741 case SDLK_b:
1742 if(!(event.key.keysym.mod & MOD_NOCTRL) &&
1743 (event.key.keysym.mod & KMOD_CTRL)) {
1744 if(emulating && theEmulator.emuReadMemState && rewindMemory
1745 && rewindCount) {
1746 rewindPos = --rewindPos & 7;
1747 theEmulator.emuReadMemState(&rewindMemory[REWIND_SIZE*rewindPos],
1748 REWIND_SIZE);
1749 rewindCount--;
1750 rewindCounter = 0;
1751 systemScreenMessage("Rewind");
1754 break;
1755 case SDLK_p:
1756 if(!(event.key.keysym.mod & MOD_NOCTRL) &&
1757 (event.key.keysym.mod & KMOD_CTRL)) {
1758 paused = !paused;
1759 SDL_PauseAudio(paused);
1760 if(paused)
1761 wasPaused = true;
1763 break;
1764 case SDLK_ESCAPE:
1765 emulating = 0;
1766 break;
1767 case SDLK_f:
1768 if(!(event.key.keysym.mod & MOD_NOCTRL) &&
1769 (event.key.keysym.mod & KMOD_CTRL)) {
1770 int flags = 0;
1771 fullscreen = !fullscreen;
1772 if(fullscreen)
1773 flags |= SDL_FULLSCREEN;
1774 SDL_SetVideoMode(destWidth, destHeight, systemColorDepth, flags);
1775 // if(SDL_WM_ToggleFullScreen(surface))
1776 // fullscreen = !fullscreen;
1778 break;
1779 case SDLK_F11:
1780 if(dbgMain != debuggerMain) {
1781 if(armState) {
1782 armNextPC -= 4;
1783 reg[15].I -= 4;
1784 } else {
1785 armNextPC -= 2;
1786 reg[15].I -= 2;
1789 debugger = true;
1790 break;
1791 case SDLK_F1:
1792 case SDLK_F2:
1793 case SDLK_F3:
1794 case SDLK_F4:
1795 case SDLK_F5:
1796 case SDLK_F6:
1797 case SDLK_F7:
1798 case SDLK_F8:
1799 case SDLK_F9:
1800 case SDLK_F10:
1801 if(!(event.key.keysym.mod & MOD_NOSHIFT) &&
1802 (event.key.keysym.mod & KMOD_SHIFT)) {
1803 sdlWriteState(event.key.keysym.sym-SDLK_F1);
1804 } else if(!(event.key.keysym.mod & MOD_KEYS)) {
1805 sdlReadState(event.key.keysym.sym-SDLK_F1);
1807 break;
1808 case SDLK_1:
1809 case SDLK_2:
1810 case SDLK_3:
1811 case SDLK_4:
1812 if(!(event.key.keysym.mod & MOD_NOALT) &&
1813 (event.key.keysym.mod & KMOD_ALT)) {
1814 char *disableMessages[4] =
1815 { "autofire A disabled",
1816 "autofire B disabled",
1817 "autofire R disabled",
1818 "autofire L disabled"};
1819 char *enableMessages[4] =
1820 { "autofire A",
1821 "autofire B",
1822 "autofire R",
1823 "autofire L"};
1824 int mask = 1 << (event.key.keysym.sym - SDLK_1);
1825 if(event.key.keysym.sym > SDLK_2)
1826 mask <<= 6;
1827 if(autoFire & mask) {
1828 autoFire &= ~mask;
1829 systemScreenMessage(disableMessages[event.key.keysym.sym - SDLK_1]);
1830 } else {
1831 autoFire |= mask;
1832 systemScreenMessage(enableMessages[event.key.keysym.sym - SDLK_1]);
1834 } if(!(event.key.keysym.mod & MOD_NOCTRL) &&
1835 (event.key.keysym.mod & KMOD_CTRL)) {
1836 int mask = 0x0100 << (event.key.keysym.sym - SDLK_1);
1837 layerSettings ^= mask;
1838 layerEnable = DISPCNT & layerSettings;
1839 CPUUpdateRenderBuffers(false);
1841 break;
1842 case SDLK_5:
1843 case SDLK_6:
1844 case SDLK_7:
1845 case SDLK_8:
1846 if(!(event.key.keysym.mod & MOD_NOCTRL) &&
1847 (event.key.keysym.mod & KMOD_CTRL)) {
1848 int mask = 0x0100 << (event.key.keysym.sym - SDLK_1);
1849 layerSettings ^= mask;
1850 layerEnable = DISPCNT & layerSettings;
1852 break;
1853 case SDLK_n:
1854 if(!(event.key.keysym.mod & MOD_NOCTRL) &&
1855 (event.key.keysym.mod & KMOD_CTRL)) {
1856 if(paused)
1857 paused = false;
1858 pauseNextFrame = true;
1860 break;
1861 default:
1862 break;
1864 sdlUpdateKey(event.key.keysym.sym, false);
1865 break;
1870 void usage(char *cmd)
1872 printf("%s [option ...] file\n", cmd);
1873 printf("\
1874 \n\
1875 Options:\n\
1876 -1, --video-1x 1x\n\
1877 -2, --video-2x 2x\n\
1878 -3, --video-3x 3x\n\
1879 -4, --video-4x 4x\n\
1880 -F, --fullscreen Full screen\n\
1881 -G, --gdb=PROTOCOL GNU Remote Stub mode:\n\
1882 tcp - use TCP at port 55555\n\
1883 tcp:PORT - use TCP at port PORT\n\
1884 pipe - use pipe transport\n\
1885 -N, --no-debug Don't parse debug information\n\
1886 -S, --flash-size=SIZE Set the Flash size\n\
1887 --flash-64k 0 - 64K Flash\n\
1888 --flash-128k 1 - 128K Flash\n\
1889 -T, --throttle=THROTTLE Set the desired throttle (5...1000)\n\
1890 -Y, --yuv=TYPE Use YUV overlay for drawing:\n\
1891 0 - YV12\n\
1892 1 - UYVY\n\
1893 2 - YVYU\n\
1894 3 - YUY2\n\
1895 4 - IYUV\n\
1896 -b, --bios=BIOS Use given bios file\n\
1897 -c, --config=FILE Read the given configuration file\n\
1898 -d, --debug Enter debugger\n\
1899 -f, --filter=FILTER Select filter:\n\
1900 --filter-normal 0 - normal mode\n\
1901 --filter-tv-mode 1 - TV Mode\n\
1902 --filter-2xsai 2 - 2xSaI\n\
1903 --filter-super-2xsai 3 - Super 2xSaI\n\
1904 --filter-super-eagle 4 - Super Eagle\n\
1905 --filter-pixelate 5 - Pixelate\n\
1906 --filter-motion-blur 6 - Motion Blur\n\
1907 --filter-advmame 7 - AdvanceMAME Scale2x\n\
1908 --filter-simple2x 8 - Simple2x\n\
1909 --filter-bilinear 9 - Bilinear\n\
1910 --filter-bilinear+ 10 - Bilinear Plus\n\
1911 --filter-scanlines 11 - Scanlines\n\
1912 --filter-hq2x 12 - hq2x\n\
1913 --filter-lq2x 13 - lq2x\n\
1914 -h, --help Print this help\n\
1915 -i, --ips=PATCH Apply given IPS patch\n\
1916 -P, --profile=[HERTZ] Enable profiling\n\
1917 -s, --frameskip=FRAMESKIP Set frame skip (0...9)\n\
1918 ");
1919 printf("\
1920 -t, --save-type=TYPE Set the available save type\n\
1921 --save-auto 0 - Automatic (EEPROM, SRAM, FLASH)\n\
1922 --save-eeprom 1 - EEPROM\n\
1923 --save-sram 2 - SRAM\n\
1924 --save-flash 3 - FLASH\n\
1925 --save-sensor 4 - EEPROM+Sensor\n\
1926 --save-none 5 - NONE\n\
1927 -v, --verbose=VERBOSE Set verbose logging (trace.log)\n\
1928 1 - SWI\n\
1929 2 - Unaligned memory access\n\
1930 4 - Illegal memory write\n\
1931 8 - Illegal memory read\n\
1932 16 - DMA 0\n\
1933 32 - DMA 1\n\
1934 64 - DMA 2\n\
1935 128 - DMA 3\n\
1936 256 - Undefined instruction\n\
1937 512 - AGBPrint messages\n\
1938 \n\
1939 Long options only:\n\
1940 --agb-print Enable AGBPrint support\n\
1941 --auto-frameskip Enable auto frameskipping\n\
1942 --ifb-none No interframe blending\n\
1943 --ifb-motion-blur Interframe motion blur\n\
1944 --ifb-smart Smart interframe blending\n\
1945 --no-agb-print Disable AGBPrint support\n\
1946 --no-auto-frameskip Disable auto frameskipping\n\
1947 --no-ips Do not apply IPS patch\n\
1948 --no-mmx Disable MMX support\n\
1949 --no-pause-when-inactive Don't pause when inactive\n\
1950 --no-rtc Disable RTC support\n\
1951 --no-show-speed Don't show emulation speed\n\
1952 --no-throttle Disable thrrotle\n\
1953 --pause-when-inactive Pause when inactive\n\
1954 --rtc Enable RTC support\n\
1955 --show-speed-normal Show emulation speed\n\
1956 --show-speed-detailed Show detailed speed data\n\
1957 ");
1958 printf("\
1959 -r, --recordmovie=filename Start recording input movie\n\
1960 -p, --playmovie=filename Play input movie non-read-only\n\
1961 -w, --watchmovie=filename Play input movie in read-only mode\n\
1962 ");
1965 static char *szFile;
1967 void file_run()
1969 utilGetBaseName(szFile, filename);
1970 char *p = strrchr(filename, '.');
1972 if(p)
1973 *p = 0;
1975 if(ipsname[0] == 0)
1976 sprintf(ipsname, "%s.ips", filename);
1978 bool failed = false;
1980 IMAGE_TYPE type = utilFindType(szFile);
1982 if(type == IMAGE_UNKNOWN) {
1983 systemMessage(0, "Unknown file type %s", szFile);
1984 exit(-1);
1986 systemCartridgeType = (int)type;
1988 if(type == IMAGE_GB) {
1989 failed = !gbLoadRom(szFile);
1990 if(!failed) {
1991 systemCartridgeType = 1;
1992 theEmulator = GBSystem;
1993 if(sdlAutoIPS) {
1994 int size = gbRomSize;
1995 utilApplyIPS(ipsname, &gbRom, &size);
1996 if(size != gbRomSize) {
1997 extern bool gbUpdateSizes();
1998 gbUpdateSizes();
1999 gbReset();
2003 } else if(type == IMAGE_GBA) {
2004 int size = CPULoadRom(szFile);
2005 failed = (size == 0);
2006 if(!failed) {
2007 // if(cpuEnhancedDetection && cpuSaveType == 0) {
2008 // utilGBAFindSave(rom, size);
2009 // }
2011 sdlApplyPerImagePreferences();
2013 systemCartridgeType = 0;
2014 theEmulator = GBASystem;
2016 /* disabled due to problems
2017 if(removeIntros && rom != NULL) {
2018 WRITE32LE(&rom[0], 0xea00002e);
2020 */
2022 //CPUInit(biosFileName, useBios);
2023 CPUInit();
2024 CPUReset();
2025 if(sdlAutoIPS) {
2026 int size = 0x2000000;
2027 utilApplyIPS(ipsname, &rom, &size);
2028 if(size != 0x2000000) {
2029 CPUReset();
2035 if(failed) {
2036 systemMessage(0, "Failed to load file %s", szFile);
2037 exit(-1);
2040 emulating = 1;
2041 renderedFrames = 0;
2044 int main(int argc, char **argv)
2046 fprintf(stderr, "VisualBoyAdvance version %s [SDL]\n", PACKAGE_VERSION);
2048 arg0 = argv[0];
2050 captureDir[0] = 0;
2051 saveDir[0] = 0;
2052 batteryDir[0] = 0;
2053 ipsname[0] = 0;
2055 int op = -1;
2057 frameSkip = 2;
2058 gbBorderOn = 0;
2060 parseDebug = true;
2062 sdlReadPreferences();
2064 sdlPrintUsage = 0;
2066 while((op = getopt_long(argc,
2067 argv,
2068 "FNT:Y:G:D:b:c:df:hi:p::s:t:v:1234",
2069 sdlOptions,
2070 NULL)) != -1) {
2071 switch(op) {
2072 case 0:
2073 // long option already processed by getopt_long
2074 break;
2075 case 'b':
2076 useBios = true;
2077 if(optarg == NULL) {
2078 fprintf(stderr, "Missing BIOS file name\n");
2079 exit(-1);
2081 strcpy(biosFileName, optarg);
2082 break;
2083 case 'c':
2085 if(optarg == NULL) {
2086 fprintf(stderr, "Missing config file name\n");
2087 exit(-1);
2089 FILE *f = fopen(optarg, "r");
2090 if(f == NULL) {
2091 fprintf(stderr, "File not found %s\n", optarg);
2092 exit(-1);
2094 sdlReadPreferences(f);
2095 fclose(f);
2097 break;
2098 case 'd':
2099 debugger = true;
2100 break;
2101 case 'h':
2102 sdlPrintUsage = 1;
2103 break;
2104 case 'i':
2105 if(optarg == NULL) {
2106 fprintf(stderr, "Missing IPS name\n");
2107 exit(-1);
2108 strcpy(ipsname, optarg);
2110 break;
2111 case 'Y':
2112 yuv = true;
2113 if(optarg) {
2114 yuvType = atoi(optarg);
2115 switch(yuvType) {
2116 case 0:
2117 yuvType = SDL_YV12_OVERLAY;
2118 break;
2119 case 1:
2120 yuvType = SDL_UYVY_OVERLAY;
2121 break;
2122 case 2:
2123 yuvType = SDL_YVYU_OVERLAY;
2124 break;
2125 case 3:
2126 yuvType = SDL_YUY2_OVERLAY;
2127 break;
2128 case 4:
2129 yuvType = SDL_IYUV_OVERLAY;
2130 break;
2131 default:
2132 yuvType = SDL_YV12_OVERLAY;
2134 } else
2135 yuvType = SDL_YV12_OVERLAY;
2136 break;
2137 case 'G':
2138 dbgMain = remoteStubMain;
2139 dbgSignal = remoteStubSignal;
2140 dbgOutput = remoteOutput;
2141 debugger = true;
2142 debuggerStub = true;
2143 if(optarg) {
2144 char *s = optarg;
2145 if(strncmp(s,"tcp:", 4) == 0) {
2146 s+=4;
2147 int port = atoi(s);
2148 remoteSetProtocol(0);
2149 remoteSetPort(port);
2150 } else if(strcmp(s,"tcp") == 0) {
2151 remoteSetProtocol(0);
2152 } else if(strcmp(s, "pipe") == 0) {
2153 remoteSetProtocol(1);
2154 } else {
2155 fprintf(stderr, "Unknown protocol %s\n", s);
2156 exit(-1);
2158 } else {
2159 remoteSetProtocol(0);
2161 break;
2162 case 'N':
2163 parseDebug = false;
2164 break;
2165 case 'D':
2166 if(optarg) {
2167 systemDebug = atoi(optarg);
2168 } else {
2169 systemDebug = 1;
2171 break;
2172 case 'F':
2173 fullscreen = 1;
2174 mouseCounter = 120;
2175 break;
2176 case 'f':
2177 if(optarg) {
2178 filter = atoi(optarg);
2179 } else {
2180 filter = 0;
2182 break;
2184 case 'r':
2185 if(optarg == NULL) {
2186 fprintf(stderr, "ERROR: --recordMovie ('r') needs movie filename as option\n");
2187 exit(-1);
2189 strcpy(movieFileName, optarg);
2190 useMovie = 1;
2191 break;
2192 case 'p': // play without read-only (editable)
2193 fprintf (stderr, "-p got called!\n");
2194 if(optarg == NULL) {
2195 fprintf(stderr, "ERROR: --playMovie ('p') needs movie filename as option\n");
2196 exit(-1);
2198 strcpy(movieFileName, optarg);
2199 useMovie = 2;
2200 break;
2201 case 'w': // play with read-only
2202 fprintf (stderr, "-w got called!\n");
2203 if(optarg == NULL) {
2204 fprintf(stderr, "ERROR: --watchMovie ('w') needs movie filename as option\n");
2205 exit(-1);
2207 strcpy(movieFileName, optarg);
2208 useMovie = 3;
2209 break;
2211 case 'P':
2212 #ifdef PROFILING
2213 if(optarg) {
2214 cpuEnableProfiling(atoi(optarg));
2215 } else
2216 cpuEnableProfiling(100);
2217 #endif
2218 break;
2219 case 'S':
2220 sdlFlashSize = atoi(optarg);
2221 if(sdlFlashSize < 0 || sdlFlashSize > 1)
2222 sdlFlashSize = 0;
2223 break;
2224 case 's':
2225 if(optarg) {
2226 int a = atoi(optarg);
2227 if(a >= 0 && a <= 9) {
2228 gbFrameSkip = a;
2229 frameSkip = a;
2231 } else {
2232 frameSkip = 2;
2233 gbFrameSkip = 0;
2235 break;
2236 case 't':
2237 if(optarg) {
2238 int a = atoi(optarg);
2239 if(a < 0 || a > 5)
2240 a = 0;
2241 cpuSaveType = a;
2243 break;
2244 case 'T':
2245 if(optarg) {
2246 int t = atoi(optarg);
2247 throttle = t;
2249 break;
2250 case 'v':
2251 if(optarg) {
2252 systemVerbose = atoi(optarg);
2253 } else
2254 systemVerbose = 0;
2255 break;
2256 case '1':
2257 sizeOption = 0;
2258 break;
2259 case '2':
2260 sizeOption = 1;
2261 break;
2262 case '3':
2263 sizeOption = 2;
2264 break;
2265 case '4':
2266 sizeOption = 3;
2267 break;
2268 case '?':
2269 sdlPrintUsage = 1;
2270 break;
2274 if(sdlPrintUsage) {
2275 usage(argv[0]);
2276 exit(-1);
2279 #ifdef MMX
2280 if(disableMMX)
2281 cpu_mmx = 0;
2282 #endif
2284 if(rewindTimer)
2285 rewindMemory = (char *)malloc(8*REWIND_SIZE);
2287 if(sdlFlashSize == 0)
2288 flashSetSize(0x10000);
2289 else
2290 flashSetSize(0x20000);
2292 rtcEnable(sdlRtcEnable ? true : false);
2293 agbPrintEnable(sdlAgbPrint ? true : false);
2295 if(!debuggerStub) {
2296 if(optind >= argc) {
2297 systemMessage(0,"Missing image name");
2298 usage(argv[0]);
2299 exit(-1);
2303 if(filter) {
2304 sizeOption = 1;
2307 for(int i = 0; i < 24;) {
2308 systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10);
2309 systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10);
2310 systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10);
2311 systemGbPalette[i++] = 0;
2314 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
2316 if(optind < argc)
2318 szFile = argv[optind];
2319 file_run();
2321 else
2323 systemCartridgeType = 0;
2324 strcpy(filename, "gnu_stub");
2325 rom = (u8 *)malloc(0x2000000);
2326 workRAM = (u8 *)calloc(1, 0x40000);
2327 bios = (u8 *)calloc(1,0x4000);
2328 internalRAM = (u8 *)calloc(1,0x8000);
2329 paletteRAM = (u8 *)calloc(1,0x400);
2330 vram = (u8 *)calloc(1, 0x20000);
2331 oam = (u8 *)calloc(1, 0x400);
2332 pix = (u8 *)calloc(1, 4 * 240 * 160);
2333 ioMem = (u8 *)calloc(1, 0x400);
2335 theEmulator = GBASystem;
2337 //CPUInit(biosFileName, useBios);
2338 CPUInit();
2339 CPUReset();
2342 if(debuggerStub)
2343 remoteInit();
2345 int flags = SDL_INIT_VIDEO|SDL_INIT_AUDIO|
2346 SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE;
2348 if(soundOffFlag)
2349 flags ^= SDL_INIT_AUDIO;
2351 if(SDL_Init(flags)) {
2352 systemMessage(0, "Failed to init SDL: %s", SDL_GetError());
2353 exit(-1);
2356 if(SDL_InitSubSystem(SDL_INIT_JOYSTICK)) {
2357 systemMessage(0, "Failed to init joystick support: %s", SDL_GetError());
2360 sdlCheckKeys();
2362 if(systemCartridgeType == 0) {
2363 srcWidth = 240;
2364 srcHeight = 160;
2365 systemFrameSkip = frameSkip;
2366 } else if (systemCartridgeType == 1) {
2367 if(gbBorderOn) {
2368 srcWidth = 256;
2369 srcHeight = 224;
2370 gbBorderLineSkip = 256;
2371 gbBorderColumnSkip = 48;
2372 gbBorderRowSkip = 40;
2373 } else {
2374 srcWidth = 160;
2375 srcHeight = 144;
2376 gbBorderLineSkip = 160;
2377 gbBorderColumnSkip = 0;
2378 gbBorderRowSkip = 0;
2380 systemFrameSkip = gbFrameSkip;
2381 } else {
2382 srcWidth = 320;
2383 srcHeight = 240;
2386 destWidth = (sizeOption+1)*srcWidth;
2387 destHeight = (sizeOption+1)*srcHeight;
2389 surface = SDL_SetVideoMode(destWidth, destHeight, 16,
2390 SDL_ANYFORMAT|SDL_HWSURFACE|SDL_DOUBLEBUF|
2391 (fullscreen ? SDL_FULLSCREEN : 0));
2393 if(surface == NULL) {
2394 systemMessage(0, "Failed to set video mode");
2395 SDL_Quit();
2396 exit(-1);
2399 systemRedShift = sdlCalculateShift(surface->format->Rmask);
2400 systemGreenShift = sdlCalculateShift(surface->format->Gmask);
2401 systemBlueShift = sdlCalculateShift(surface->format->Bmask);
2403 systemColorDepth = surface->format->BitsPerPixel;
2404 if(systemColorDepth == 15)
2405 systemColorDepth = 16;
2407 if(yuv) {
2408 Init_Overlay(surface, yuvType);
2409 systemColorDepth = 32;
2410 systemRedShift = 3;
2411 systemGreenShift = 11;
2412 systemBlueShift = 19;
2415 if(systemColorDepth != 16 && systemColorDepth != 24 &&
2416 systemColorDepth != 32) {
2417 fprintf(stderr,"Unsupported color depth '%d'.\nOnly 16, 24 and 32 bit color depths are supported\n", systemColorDepth);
2418 exit(-1);
2421 #ifndef C_CORE
2422 sdlMakeStretcher(srcWidth);
2423 #else
2424 switch(systemColorDepth) {
2425 case 16:
2426 sdlStretcher = sdlStretcher16[sizeOption];
2427 break;
2428 case 24:
2429 sdlStretcher = sdlStretcher24[sizeOption];
2430 break;
2431 case 32:
2432 sdlStretcher = sdlStretcher32[sizeOption];
2433 break;
2434 default:
2435 fprintf(stderr, "Unsupported resolution: %d\n", systemColorDepth);
2436 exit(-1);
2438 #endif
2440 fprintf(stderr,"Color depth: %d\n", systemColorDepth);
2442 if(systemColorDepth == 16) {
2443 if(sdlCalculateMaskWidth(surface->format->Gmask) == 6) {
2444 Init_2xSaI(565);
2445 RGB_LOW_BITS_MASK = 0x821;
2446 } else {
2447 Init_2xSaI(555);
2448 RGB_LOW_BITS_MASK = 0x421;
2450 if(systemCartridgeType == 2) {
2451 for(int i = 0; i < 0x10000; i++) {
2452 systemColorMap16[i] = (((i >> 1) & 0x1f) << systemBlueShift) |
2453 (((i & 0x7c0) >> 6) << systemGreenShift) |
2454 (((i & 0xf800) >> 11) << systemRedShift);
2456 } else {
2457 for(int i = 0; i < 0x10000; i++) {
2458 systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
2459 (((i & 0x3e0) >> 5) << systemGreenShift) |
2460 (((i & 0x7c00) >> 10) << systemBlueShift);
2463 srcPitch = srcWidth * 2+4;
2464 } else {
2465 if(systemColorDepth != 32)
2466 filterFunction = NULL;
2467 RGB_LOW_BITS_MASK = 0x010101;
2468 if(systemColorDepth == 32) {
2469 Init_2xSaI(32);
2471 for(int i = 0; i < 0x10000; i++) {
2472 systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
2473 (((i & 0x3e0) >> 5) << systemGreenShift) |
2474 (((i & 0x7c00) >> 10) << systemBlueShift);
2476 if(systemColorDepth == 32)
2477 srcPitch = srcWidth*4 + 4;
2478 else
2479 srcPitch = srcWidth*3;
2482 if(systemColorDepth != 32) {
2483 switch(filter) {
2484 case 0:
2485 filterFunction = NULL;
2486 break;
2487 case 1:
2488 filterFunction = ScanlinesTV;
2489 break;
2490 case 2:
2491 filterFunction = _2xSaI;
2492 break;
2493 case 3:
2494 filterFunction = Super2xSaI;
2495 break;
2496 case 4:
2497 filterFunction = SuperEagle;
2498 break;
2499 case 5:
2500 filterFunction = Pixelate2x16;
2501 break;
2502 case 6:
2503 filterFunction = MotionBlur;
2504 break;
2505 case 7:
2506 filterFunction = AdMame2x;
2507 break;
2508 case 8:
2509 filterFunction = Simple2x16;
2510 break;
2511 case 9:
2512 filterFunction = Bilinear;
2513 break;
2514 case 10:
2515 filterFunction = BilinearPlus;
2516 break;
2517 case 11:
2518 filterFunction = Scanlines;
2519 break;
2520 case 12:
2521 filterFunction = hq2x;
2522 break;
2523 case 13:
2524 filterFunction = lq2x;
2525 break;
2526 default:
2527 filterFunction = NULL;
2528 break;
2530 } else {
2531 switch(filter) {
2532 case 0:
2533 filterFunction = NULL;
2534 break;
2535 case 1:
2536 filterFunction = ScanlinesTV32;
2537 break;
2538 case 2:
2539 filterFunction = _2xSaI32;
2540 break;
2541 case 3:
2542 filterFunction = Super2xSaI32;
2543 break;
2544 case 4:
2545 filterFunction = SuperEagle32;
2546 break;
2547 case 5:
2548 filterFunction = Pixelate2x32;
2549 break;
2550 case 6:
2551 filterFunction = MotionBlur32;
2552 break;
2553 case 7:
2554 filterFunction = AdMame2x32;
2555 break;
2556 case 8:
2557 filterFunction = Simple2x32;
2558 break;
2559 case 9:
2560 filterFunction = Bilinear32;
2561 break;
2562 case 10:
2563 filterFunction = BilinearPlus32;
2564 break;
2565 case 11:
2566 filterFunction = Scanlines32;
2567 break;
2568 case 12:
2569 filterFunction = hq2x32;
2570 break;
2571 case 13:
2572 filterFunction = lq2x32;
2573 break;
2574 default:
2575 filterFunction = NULL;
2576 break;
2580 if(systemColorDepth == 16) {
2581 switch(ifbType) {
2582 case 0:
2583 default:
2584 ifbFunction = NULL;
2585 break;
2586 case 1:
2587 ifbFunction = MotionBlurIB;
2588 break;
2589 case 2:
2590 ifbFunction = SmartIB;
2591 break;
2593 } else if(systemColorDepth == 32) {
2594 switch(ifbType) {
2595 case 0:
2596 default:
2597 ifbFunction = NULL;
2598 break;
2599 case 1:
2600 ifbFunction = MotionBlurIB32;
2601 break;
2602 case 2:
2603 ifbFunction = SmartIB32;
2604 break;
2606 } else
2607 ifbFunction = NULL;
2609 if(delta == NULL) {
2610 delta = (u8*)malloc(322*242*4);
2611 memset(delta, 255, 322*242*4);
2614 if(!soundOffFlag)
2615 soundInit();
2617 autoFrameSkipLastTime = throttleLastTime = systemGetClock();
2619 switch(useMovie)
2621 case 1: // --recordMovie
2622 VBAMovieCreate(movieFileName,
2623 /*authorInfo*/"",
2624 /*startFlags*/0,
2625 /*controllerFlags*/MOVIE_CONTROLLER(0),
2626 /*typeFlags*/(systemCartridgeType==IMAGE_GBA)?(MOVIE_TYPE_GBA):(GBC_CAPABLE?MOVIE_TYPE_GBC:MOVIE_TYPE_SGB));
2627 break;
2628 case 2: // --playMovie
2629 VBAMovieOpen(movieFileName, false);
2630 break;
2631 case 3: // --watchMovie
2632 VBAMovieOpen(movieFileName, true);
2633 break;
2634 default:
2635 sdlReadBattery();
2636 break;
2638 SDL_WM_SetCaption("VisualBoyAdvance", NULL);
2640 char *moviefile = getenv("AUTODEMO");
2641 // fprintf (stderr, "Checking for AUTODEMO...\n");
2642 if (moviefile)
2644 // fprintf (stderr, "I got a filename OMG!\nCalling VBAMovieOpen...\n");
2645 VBAMovieOpen(moviefile, true);
2648 while(emulating) {
2649 if(!paused && active) {
2650 if(debugger && theEmulator.emuHasDebugger)
2651 dbgMain();
2652 else {
2653 theEmulator.emuMain(theEmulator.emuCount);
2654 if(rewindSaveNeeded && rewindMemory && theEmulator.emuWriteMemState) {
2655 rewindCount++;
2656 if(rewindCount > 8)
2657 rewindCount = 8;
2658 if(theEmulator.emuWriteMemState &&
2659 theEmulator.emuWriteMemState(&rewindMemory[rewindPos*REWIND_SIZE],
2660 REWIND_SIZE)) {
2661 rewindPos = ++rewindPos & 7;
2662 if(rewindCount == 8)
2663 rewindTopPos = ++rewindTopPos & 7;
2667 rewindSaveNeeded = false;
2669 } else {
2670 SDL_Delay(500);
2672 sdlPollEvents();
2673 if(mouseCounter) {
2674 mouseCounter--;
2675 if(mouseCounter == 0)
2676 SDL_ShowCursor(SDL_DISABLE);
2680 emulating = 0;
2681 fprintf(stderr,"Shutting down\n");
2682 remoteCleanUp();
2683 soundShutdown();
2685 if(gbRom != NULL || rom != NULL) {
2686 sdlWriteBattery();
2687 theEmulator.emuCleanUp();
2690 if(delta) {
2691 free(delta);
2692 delta = NULL;
2695 SDL_Quit();
2696 return 0;
2699 void systemMessage(int num, const char *msg, ...)
2701 char buffer[2048];
2702 va_list valist;
2704 va_start(valist, msg);
2705 vsprintf(buffer, msg, valist);
2707 fprintf(stderr, "%s\n", buffer);
2708 va_end(valist);
2711 //On WIN32, this function messages requesting
2712 //the window to be redrawn. Can this be ignored here?
2713 void systemRefreshScreen(){}
2715 void systemRenderFrame()
2717 renderedFrames++;
2718 VBAUpdateFrameCountDisplay();
2719 VBAUpdateButtonPressDisplay();
2721 if(yuv) {
2722 Draw_Overlay(surface, sizeOption+1);
2723 return;
2726 SDL_LockSurface(surface);
2728 for(int slot = 0 ; slot < 8 ; slot++)
2730 if(screenMessage[slot]) {
2731 if(systemCartridgeType == 1 && gbBorderOn) {
2732 gbSgbRenderBorder();
2734 if(((systemGetClock() - screenMessageTime[slot]) < screenMessageDuration[slot]) &&
2735 !disableStatusMessages) {
2736 drawText(pix, srcPitch, 10, srcHeight - 20*(slot+1),
2737 screenMessageBuffer[slot]);
2738 } else {
2739 screenMessage[slot] = false;
2744 if(ifbFunction) {
2745 if(systemColorDepth == 16)
2746 ifbFunction(pix+destWidth+4, destWidth+4, srcWidth, srcHeight);
2747 else
2748 ifbFunction(pix+destWidth*2+4, destWidth*2+4, srcWidth, srcHeight);
2751 if(filterFunction) {
2752 if(systemColorDepth == 16)
2753 filterFunction(pix+destWidth+4,destWidth+4, delta,
2754 (u8*)surface->pixels,surface->pitch,
2755 srcWidth,
2756 srcHeight);
2757 else
2758 filterFunction(pix+destWidth*2+4,
2759 destWidth*2+4,
2760 delta,
2761 (u8*)surface->pixels,
2762 surface->pitch,
2763 srcWidth,
2764 srcHeight);
2765 } else {
2766 int destPitch = surface->pitch;
2767 u8 *src = pix;
2768 u8 *dest = (u8*)surface->pixels;
2769 int i;
2770 u32 *stretcher = (u32 *)sdlStretcher;
2771 if(systemColorDepth == 16)
2772 src += srcPitch;
2773 int option = sizeOption;
2774 if(yuv)
2775 option = 0;
2776 switch(sizeOption) {
2777 case 0:
2778 for(i = 0; i < srcHeight; i++) {
2779 SDL_CALL_STRETCHER;
2780 src += srcPitch;
2781 dest += destPitch;
2783 break;
2784 case 1:
2785 for(i = 0; i < srcHeight; i++) {
2786 SDL_CALL_STRETCHER;
2787 dest += destPitch;
2788 SDL_CALL_STRETCHER;
2789 src += srcPitch;
2790 dest += destPitch;
2792 break;
2793 case 2:
2794 for(i = 0; i < srcHeight; i++) {
2795 SDL_CALL_STRETCHER;
2796 dest += destPitch;
2797 SDL_CALL_STRETCHER;
2798 dest += destPitch;
2799 SDL_CALL_STRETCHER;
2800 src += srcPitch;
2801 dest += destPitch;
2803 break;
2804 case 3:
2805 for(i = 0; i < srcHeight; i++) {
2806 SDL_CALL_STRETCHER;
2807 dest += destPitch;
2808 SDL_CALL_STRETCHER;
2809 dest += destPitch;
2810 SDL_CALL_STRETCHER;
2811 dest += destPitch;
2812 SDL_CALL_STRETCHER;
2813 src += srcPitch;
2814 dest += destPitch;
2816 break;
2820 if(showSpeed && fullscreen) {
2821 char buffer[50];
2822 if(showSpeed == 1)
2823 sprintf(buffer, "%d%%", systemSpeed);
2824 else
2825 sprintf(buffer, "%3d%%(%d, %d fps)", systemSpeed,
2826 systemFrameSkip,
2827 showRenderedFrames);
2828 if(showSpeedTransparent)
2829 drawTextTransp((u8*)surface->pixels,
2830 surface->pitch,
2831 10,
2832 surface->h-20,
2833 buffer);
2834 else
2835 drawText((u8*)surface->pixels,
2836 surface->pitch,
2837 10,
2838 surface->h-20,
2839 buffer);
2842 SDL_UnlockSurface(surface);
2843 // SDL_UpdateRect(surface, 0, 0, destWidth, destHeight);
2844 SDL_Flip(surface);
2847 bool systemReadJoypads()
2849 return true;
2852 // Kludge to make Lua call the right function.
2853 u32 systemGetOriginalJoypad(int which, bool sensor){
2854 return systemGetJoypad(which,sensor);
2857 u32 systemGetJoypad(int which, bool sensor)
2859 sensorOn = sensor;
2860 if(which < 0 || which > 3)
2861 which = sdlDefaultJoypad;
2863 //VBAMovieUpdate(which);
2864 //VBAMovieUpdateState();
2865 u32 res = 0;
2867 //----------------------------//
2868 if (VBAMoviePlaying()){
2869 // VBAMovieRead() overwrites currentButtons[i]
2870 VBAMovieRead(which, sensor);
2871 res = currentButtons[which];
2872 return res;
2874 //---------------------------//
2875 //Temporary implementation, not sure if it's correct --Felipe
2877 /*
2878 if(sdlButtons[which][KEY_BUTTON_A])
2879 res |= BUTTON_MASK_A;
2880 if(sdlButtons[which][KEY_BUTTON_B])
2881 res |= BUTTON_MASK_B;
2882 if(sdlButtons[which][KEY_BUTTON_SELECT])
2883 res |= BUTTON_MASK_SELECT;
2884 if(sdlButtons[which][KEY_BUTTON_START])
2885 res |= BUTTON_MASK_START;
2886 if(sdlButtons[which][KEY_RIGHT])
2887 res |= BUTTON_MASK_RIGHT;
2888 if(sdlButtons[which][KEY_LEFT])
2889 res |= BUTTON_MASK_LEFT;
2890 if(sdlButtons[which][KEY_UP])
2891 res |= BUTTON_MASK_UP;
2892 if(sdlButtons[which][KEY_DOWN])
2893 res |= BUTTON_MASK_DOWN;
2894 if(sdlButtons[which][KEY_BUTTON_R])
2895 res |= BUTTON_MASK_R;
2896 if(sdlButtons[which][KEY_BUTTON_L])
2897 res |= BUTTON_MASK_L;
2898 */
2899 /*
2900 // disallow L+R or U+D of being pressed at the same time
2901 if((res & 48) == 48)
2902 res &= ~16;
2903 if((res & 192) == 192)
2904 res &= ~128;
2905 */
2906 /*
2907 if(sdlbuttons[which][KEY_BUTTON_SPEED])
2908 res |= 1024;
2909 if(sdlButtons[which][KEY_BUTTON_CAPTURE])
2910 res |= 2048;
2911 */
2912 res = currentButtons[which];
2914 if(autoFire) {
2915 res &= (~autoFire);
2916 if(autoFireToggle)
2917 res |= autoFire;
2918 autoFireToggle = !autoFireToggle;
2921 //if (res) fprintf(stdout,"%x\n",res);
2923 return res;
2926 void systemSetJoypad(int which, u32 buttons)
2928 if(which < 0 || which > 3)
2929 which = sdlDefaultJoypad;
2930 /*
2931 sdlButtons[which][KEY_BUTTON_A] = (buttons & 1) != 0;
2932 sdlButtons[which][KEY_BUTTON_B] = (buttons & 2) != 0;
2933 sdlButtons[which][KEY_BUTTON_SELECT] = (buttons & 4) != 0;
2934 sdlButtons[which][KEY_BUTTON_START] = (buttons & 8) != 0;
2935 sdlButtons[which][KEY_RIGHT] = (buttons & 16) != 0;
2936 sdlButtons[which][KEY_LEFT] = (buttons & 32) != 0;
2937 sdlButtons[which][KEY_UP] = (buttons & 64) != 0;
2938 sdlButtons[which][KEY_DOWN] = (buttons & 128) != 0;
2939 sdlButtons[which][KEY_BUTTON_R] = (buttons & 256) != 0;
2940 sdlButtons[which][KEY_BUTTON_L] = (buttons & 512) != 0;
2941 */
2942 currentButtons[which]= buttons & 0x3ff;
2945 void systemClearJoypads()
2947 for (int i = 0; i < 4; ++i)
2948 currentButtons[i] = 0;
2950 //lastKeys = 0;
2953 void systemSetTitle(const char *title)
2955 SDL_WM_SetCaption(title, NULL);
2958 void systemShowSpeed(int speed)
2960 systemSpeed = speed;
2962 showRenderedFrames = renderedFrames;
2963 renderedFrames = 0;
2965 if(!fullscreen && showSpeed) {
2966 char buffer[80];
2967 if(showSpeed == 1)
2968 sprintf(buffer, "VisualBoyAdvance-%3d%%", systemSpeed);
2969 else
2970 sprintf(buffer, "VisualBoyAdvance-%3d%%(%d, %d fps)", systemSpeed,
2971 systemFrameSkip,
2972 showRenderedFrames);
2974 systemSetTitle(buffer);
2978 // FIXME: the timing
2979 void systemFrame(/*int rate*/) //Looking at System.cpp, it looks like rate should be 600
2981 u32 time = systemGetClock();
2982 if(!wasPaused && autoFrameSkip && !throttle) {
2983 u32 diff = time - autoFrameSkipLastTime;
2984 int speed = 100;
2986 if(diff)
2987 speed = (1000000/600)/diff;
2989 if(speed >= 98) {
2990 frameskipadjust++;
2992 if(frameskipadjust >= 3) {
2993 frameskipadjust=0;
2994 if(systemFrameSkip > 0)
2995 systemFrameSkip--;
2997 } else {
2998 if(speed < 80)
2999 frameskipadjust -= (90 - speed)/5;
3000 else if(systemFrameSkip < 9)
3001 frameskipadjust--;
3003 if(frameskipadjust <= -2) {
3004 frameskipadjust += 2;
3005 if(systemFrameSkip < 9)
3006 systemFrameSkip++;
3010 if(!wasPaused && throttle) {
3011 /*if(!speedup) {
3012 u32 diff = time - throttleLastTime;
3014 int target = (1000000.0/(600*throttle));
3015 int d = (target - diff);
3017 if(d > 0) {
3018 SDL_Delay(d);
3021 throttleLastTime = systemGetClock();
3022 */
3024 if(rewindMemory) {
3025 if(++rewindCounter >= rewindTimer) {
3026 rewindSaveNeeded = true;
3027 rewindCounter = 0;
3031 if(systemSaveUpdateCounter) {
3032 if(--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED) {
3033 sdlWriteBattery();
3034 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
3038 wasPaused = false;
3039 autoFrameSkipLastTime = time;
3042 int systemFramesToSkip(){
3043 return systemFrameSkip;
3046 int systemScreenCapture(int a)
3048 char buffer[2048];
3050 if(captureFormat) {
3051 if(captureDir[0])
3052 sprintf(buffer, "%s/%s%02d.bmp", captureDir, sdlGetFilename(filename), a);
3053 else
3054 sprintf(buffer, "%s%02d.bmp", filename, a);
3056 theEmulator.emuWriteBMP(buffer);
3057 } else {
3058 if(captureDir[0])
3059 sprintf(buffer, "%s/%s%02d.png", captureDir, sdlGetFilename(filename), a);
3060 else
3061 sprintf(buffer, "%s%02d.png", filename, a);
3062 theEmulator.emuWritePNG(buffer);
3065 systemScreenMessage("Screen capture");
3066 return a;
3069 void soundCallback(void *,u8 *stream,int len){}
3071 void systemSoundWriteToBuffer(){
3072 soundDriver->write(soundFinalWave, soundBufferLen);
3075 void systemSoundClearBuffer()
3077 SDL_mutexP(mutex);
3078 memset(sdlBuffer,0,soundBufferTotalLen);
3079 sdlSoundLen=0;
3080 printf("Hi\n");
3081 SDL_mutexV(mutex);
3084 bool systemSoundInit(){
3085 systemSoundShutdown();
3086 soundDriver = new SoundSDL();
3087 if ( !soundDriver )
3088 return false;
3090 if (!soundDriver->init()) //<-- sound sample rate
3091 return false;
3093 if (!(soundDriver->setThrottle(throttle))){
3094 fprintf(stderr,"Failed to set desired throttle, defaulting to 100 %%.\n");
3095 if (!soundDriver->setThrottle(100)) return false;
3097 soundPaused = true;
3098 systemSoundOn = true;
3099 return true;
3102 void systemSoundShutdown(){
3103 if (soundDriver)
3105 delete soundDriver;
3106 soundDriver = 0;
3110 void systemSoundPause()
3112 SDL_PauseAudio(1);
3115 void systemSoundResume()
3117 SDL_PauseAudio(0);
3120 void systemSoundReset()
3124 u32 systemGetClock()
3126 return SDL_GetTicks();
3129 void systemUpdateMotionSensor()
3131 if(sdlMotionButtons[KEY_LEFT]) {
3132 sensorX += 3;
3133 if(sensorX > 2197)
3134 sensorX = 2197;
3135 if(sensorX < 2047)
3136 sensorX = 2057;
3137 } else if(sdlMotionButtons[KEY_RIGHT]) {
3138 sensorX -= 3;
3139 if(sensorX < 1897)
3140 sensorX = 1897;
3141 if(sensorX > 2047)
3142 sensorX = 2037;
3143 } else if(sensorX > 2047) {
3144 sensorX -= 2;
3145 if(sensorX < 2047)
3146 sensorX = 2047;
3147 } else {
3148 sensorX += 2;
3149 if(sensorX > 2047)
3150 sensorX = 2047;
3153 if(sdlMotionButtons[KEY_UP]) {
3154 sensorY += 3;
3155 if(sensorY > 2197)
3156 sensorY = 2197;
3157 if(sensorY < 2047)
3158 sensorY = 2057;
3159 } else if(sdlMotionButtons[KEY_DOWN]) {
3160 sensorY -= 3;
3161 if(sensorY < 1897)
3162 sensorY = 1897;
3163 if(sensorY > 2047)
3164 sensorY = 2037;
3165 } else if(sensorY > 2047) {
3166 sensorY -= 2;
3167 if(sensorY < 2047)
3168 sensorY = 2047;
3169 } else {
3170 sensorY += 2;
3171 if(sensorY > 2047)
3172 sensorY = 2047;
3176 void systemResetSensor()
3178 sensorX = sensorY = INITIAL_SENSOR_VALUE;
3181 int systemGetSensorX()
3183 return sensorX;
3186 int systemGetSensorY()
3188 return sensorY;
3191 void systemGbPrint(u8 *data,int pages,int feed,int palette, int contrast)
3195 void systemScreenMessage(const char *msg, int slot, int duration, const char *colorList)
3197 screenMessage[slot] = true;
3198 screenMessageTime[slot] = systemGetClock();
3199 screenMessageDuration[slot] = duration;
3200 if(strlen(msg) > 20) {
3201 strncpy(screenMessageBuffer[slot], msg, 20);
3202 screenMessageBuffer[slot][20] = 0;
3203 } else
3204 strcpy(screenMessageBuffer[slot], msg);
3207 bool systemSoundCanChangeQuality()
3209 return false;
3212 bool systemSoundSetQuality(int quality)
3214 if (systemCartridgeType == 0)
3215 soundSetQuality(quality);
3216 else
3217 gbSoundSetQuality(quality);
3219 return true;
3222 bool systemPauseOnFrame()
3224 if(pauseNextFrame) {
3225 paused = true;
3226 pauseNextFrame = false;
3227 return true;
3229 return false;
3232 // Code donated by Niels Wagenaar (BoycottAdvance)
3234 // GBA screensize.
3235 #define GBA_WIDTH 240
3236 #define GBA_HEIGHT 160
3238 void Init_Overlay(SDL_Surface *gbascreen, int overlaytype)
3241 overlay = SDL_CreateYUVOverlay( GBA_WIDTH,
3242 GBA_HEIGHT,
3243 overlaytype, gbascreen);
3244 fprintf(stderr, "Created %dx%dx%d %s %s overlay\n",
3245 overlay->w,overlay->h,overlay->planes,
3246 overlay->hw_overlay?"hardware":"software",
3247 overlay->format==SDL_YV12_OVERLAY?"YV12":
3248 overlay->format==SDL_IYUV_OVERLAY?"IYUV":
3249 overlay->format==SDL_YUY2_OVERLAY?"YUY2":
3250 overlay->format==SDL_UYVY_OVERLAY?"UYVY":
3251 overlay->format==SDL_YVYU_OVERLAY?"YVYU":
3252 "Unknown");
3255 void Quit_Overlay(void)
3258 SDL_FreeYUVOverlay(overlay);
3261 /* NOTE: These RGB conversion functions are not intended for speed,
3262 only as examples.
3263 */
3264 inline void RGBtoYUV(Uint8 *rgb, int *yuv)
3266 yuv[0] = (int)((0.257 * rgb[0]) + (0.504 * rgb[1]) + (0.098 * rgb[2]) + 16);
3267 yuv[1] = (int)(128 - (0.148 * rgb[0]) - (0.291 * rgb[1]) + (0.439 * rgb[2]));
3268 yuv[2] = (int)(128 + (0.439 * rgb[0]) - (0.368 * rgb[1]) - (0.071 * rgb[2]));
3271 inline void ConvertRGBtoYV12(SDL_Overlay *o)
3273 int x,y;
3274 int yuv[3];
3275 Uint8 *p,*op[3];
3277 SDL_LockYUVOverlay(o);
3279 /* Black initialization */
3280 /*
3281 memset(o->pixels[0],0,o->pitches[0]*o->h);
3282 memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2));
3283 memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2));
3284 */
3286 /* Convert */
3287 for(y=0; y<160 && y<o->h; y++) {
3288 p=(Uint8 *)pix+srcPitch*y;
3289 op[0]=o->pixels[0]+o->pitches[0]*y;
3290 op[1]=o->pixels[1]+o->pitches[1]*(y/2);
3291 op[2]=o->pixels[2]+o->pitches[2]*(y/2);
3292 for(x=0; x<240 && x<o->w; x++) {
3293 RGBtoYUV(p,yuv);
3294 *(op[0]++)=yuv[0];
3295 if(x%2==0 && y%2==0) {
3296 *(op[1]++)=yuv[2];
3297 *(op[2]++)=yuv[1];
3299 p+=4;//s->format->BytesPerPixel;
3303 SDL_UnlockYUVOverlay(o);
3306 inline void ConvertRGBtoIYUV(SDL_Overlay *o)
3308 int x,y;
3309 int yuv[3];
3310 Uint8 *p,*op[3];
3312 SDL_LockYUVOverlay(o);
3314 /* Black initialization */
3315 /*
3316 memset(o->pixels[0],0,o->pitches[0]*o->h);
3317 memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2));
3318 memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2));
3319 */
3321 /* Convert */
3322 for(y=0; y<160 && y<o->h; y++) {
3323 p=(Uint8 *)pix+srcPitch*y;
3324 op[0]=o->pixels[0]+o->pitches[0]*y;
3325 op[1]=o->pixels[1]+o->pitches[1]*(y/2);
3326 op[2]=o->pixels[2]+o->pitches[2]*(y/2);
3327 for(x=0; x<240 && x<o->w; x++) {
3328 RGBtoYUV(p,yuv);
3329 *(op[0]++)=yuv[0];
3330 if(x%2==0 && y%2==0) {
3331 *(op[1]++)=yuv[1];
3332 *(op[2]++)=yuv[2];
3334 p+=4; //s->format->BytesPerPixel;
3338 SDL_UnlockYUVOverlay(o);
3341 inline void ConvertRGBtoUYVY(SDL_Overlay *o)
3343 int x,y;
3344 int yuv[3];
3345 Uint8 *p,*op;
3347 SDL_LockYUVOverlay(o);
3349 for(y=0; y<160 && y<o->h; y++) {
3350 p=(Uint8 *)pix+srcPitch*y;
3351 op=o->pixels[0]+o->pitches[0]*y;
3352 for(x=0; x<240 && x<o->w; x++) {
3353 RGBtoYUV(p,yuv);
3354 if(x%2==0) {
3355 *(op++)=yuv[1];
3356 *(op++)=yuv[0];
3357 *(op++)=yuv[2];
3358 } else
3359 *(op++)=yuv[0];
3361 p+=4; //s->format->BytesPerPixel;
3365 SDL_UnlockYUVOverlay(o);
3368 inline void ConvertRGBtoYVYU(SDL_Overlay *o)
3370 int x,y;
3371 int yuv[3];
3372 Uint8 *p,*op;
3374 SDL_LockYUVOverlay(o);
3376 for(y=0; y<160 && y<o->h; y++) {
3377 p=(Uint8 *)pix+srcPitch*y;
3378 op=o->pixels[0]+o->pitches[0]*y;
3379 for(x=0; x<240 && x<o->w; x++) {
3380 RGBtoYUV(p,yuv);
3381 if(x%2==0) {
3382 *(op++)=yuv[0];
3383 *(op++)=yuv[2];
3384 op[1]=yuv[1];
3385 } else {
3386 *op=yuv[0];
3387 op+=2;
3390 p+=4; //s->format->BytesPerPixel;
3394 SDL_UnlockYUVOverlay(o);
3397 inline void ConvertRGBtoYUY2(SDL_Overlay *o)
3399 int x,y;
3400 int yuv[3];
3401 Uint8 *p,*op;
3403 SDL_LockYUVOverlay(o);
3405 for(y=0; y<160 && y<o->h; y++) {
3406 p=(Uint8 *)pix+srcPitch*y;
3407 op=o->pixels[0]+o->pitches[0]*y;
3408 for(x=0; x<240 && x<o->w; x++) {
3409 RGBtoYUV(p,yuv);
3410 if(x%2==0) {
3411 *(op++)=yuv[0];
3412 *(op++)=yuv[1];
3413 op[1]=yuv[2];
3414 } else {
3415 *op=yuv[0];
3416 op+=2;
3419 p+=4; //s->format->BytesPerPixel;
3423 SDL_UnlockYUVOverlay(o);
3426 inline void Convert32bit(SDL_Surface *display)
3428 switch(overlay->format) {
3429 case SDL_YV12_OVERLAY:
3430 ConvertRGBtoYV12(overlay);
3431 break;
3432 case SDL_UYVY_OVERLAY:
3433 ConvertRGBtoUYVY(overlay);
3434 break;
3435 case SDL_YVYU_OVERLAY:
3436 ConvertRGBtoYVYU(overlay);
3437 break;
3438 case SDL_YUY2_OVERLAY:
3439 ConvertRGBtoYUY2(overlay);
3440 break;
3441 case SDL_IYUV_OVERLAY:
3442 ConvertRGBtoIYUV(overlay);
3443 break;
3444 default:
3445 fprintf(stderr, "cannot convert RGB picture to obtained YUV format!\n");
3446 exit(1);
3447 break;
3453 inline void Draw_Overlay(SDL_Surface *display, int size)
3455 SDL_LockYUVOverlay(overlay);
3457 Convert32bit(display);
3459 overlay_rect.x = 0;
3460 overlay_rect.y = 0;
3461 overlay_rect.w = GBA_WIDTH * size;
3462 overlay_rect.h = GBA_HEIGHT * size;
3464 SDL_DisplayYUVOverlay(overlay, &overlay_rect);
3465 SDL_UnlockYUVOverlay(overlay);
3468 bool systemIsEmulating()
3470 return emulating != 0;
3473 void systemGbBorderOn()
3475 srcWidth = 256;
3476 srcHeight = 224;
3477 gbBorderLineSkip = 256;
3478 gbBorderColumnSkip = 48;
3479 gbBorderRowSkip = 40;
3481 destWidth = (sizeOption+1)*srcWidth;
3482 destHeight = (sizeOption+1)*srcHeight;
3484 surface = SDL_SetVideoMode(destWidth, destHeight, 16,
3485 SDL_ANYFORMAT|SDL_HWSURFACE|SDL_DOUBLEBUF|
3486 (fullscreen ? SDL_FULLSCREEN : 0));
3487 #ifndef C_CORE
3488 sdlMakeStretcher(srcWidth);
3489 #else
3490 switch(systemColorDepth) {
3491 case 16:
3492 sdlStretcher = sdlStretcher16[sizeOption];
3493 break;
3494 case 24:
3495 sdlStretcher = sdlStretcher24[sizeOption];
3496 break;
3497 case 32:
3498 sdlStretcher = sdlStretcher32[sizeOption];
3499 break;
3500 default:
3501 fprintf(stderr, "Unsupported resolution: %d\n", systemColorDepth);
3502 exit(-1);
3504 #endif
3506 if(systemColorDepth == 16) {
3507 if(sdlCalculateMaskWidth(surface->format->Gmask) == 6) {
3508 Init_2xSaI(565);
3509 RGB_LOW_BITS_MASK = 0x821;
3510 } else {
3511 Init_2xSaI(555);
3512 RGB_LOW_BITS_MASK = 0x421;
3514 if(systemCartridgeType == 2) {
3515 for(int i = 0; i < 0x10000; i++) {
3516 systemColorMap16[i] = (((i >> 1) & 0x1f) << systemBlueShift) |
3517 (((i & 0x7c0) >> 6) << systemGreenShift) |
3518 (((i & 0xf800) >> 11) << systemRedShift);
3520 } else {
3521 for(int i = 0; i < 0x10000; i++) {
3522 systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
3523 (((i & 0x3e0) >> 5) << systemGreenShift) |
3524 (((i & 0x7c00) >> 10) << systemBlueShift);
3527 srcPitch = srcWidth * 2+4;
3528 } else {
3529 if(systemColorDepth != 32)
3530 filterFunction = NULL;
3531 RGB_LOW_BITS_MASK = 0x010101;
3532 if(systemColorDepth == 32) {
3533 Init_2xSaI(32);
3535 for(int i = 0; i < 0x10000; i++) {
3536 systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
3537 (((i & 0x3e0) >> 5) << systemGreenShift) |
3538 (((i & 0x7c00) >> 10) << systemBlueShift);
3540 if(systemColorDepth == 32)
3541 srcPitch = srcWidth*4 + 4;
3542 else
3543 srcPitch = srcWidth*3;
3547 bool systemIsRunningGBA()
3549 return (rom != NULL);
3552 int systemGetDefaultJoypad()
3554 return sdlDefaultJoypad;
3557 bool systemIsPaused()
3559 return paused;
3562 void systemSetPause(bool pause)
3564 paused = pause;
3565 if (pause)
3566 systemSoundPause();
3567 else
3568 systemSoundResume();
3571 u16 checksumBIOS()
3573 bool hasBIOS = false;
3574 u8 * tempBIOS;
3575 if(useBios)
3577 tempBIOS = (u8 *)malloc(0x4000);
3578 int size = 0x4000;
3579 if(utilLoad(biosFileName,
3580 utilIsGBABios,
3581 tempBIOS,
3582 size)) {
3583 if(size == 0x4000)
3584 hasBIOS = true;
3588 u16 biosCheck = 0;
3589 if(hasBIOS) {
3590 for(int i = 0; i < 0x4000; i += 4)
3591 biosCheck += *((u32 *)&tempBIOS[i]);
3592 free(tempBIOS);
3595 return biosCheck;
3598 EmulatedSystemCounters systemCounters = {
3599 0, //framecount
3600 0, //lagcount
3601 0, //extracount
3602 true, //lagged
3603 true //laggedLast
3604 };
3606 void VBAOnEnteringFrameBoundary()
3608 CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION);
3610 if (VBALuaRunning())
3612 VBALuaFrameBoundary();
3615 VBAMovieUpdateState();
3618 void VBAOnExitingFrameBoundary()