view src/sdl/SDL.cpp @ 70:ff6f1acae59e

removed zero frame confusion
author Robert McIntyre <rlm@mit.edu>
date Thu, 08 Mar 2012 02:25:20 -0600
parents 43d4fb2a6fc2
children 1ff2c546f5ad
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"
47 #include "Drive.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 //printf("RLM: file_run\n");
1970 utilGetBaseName(szFile, filename);
1971 char *p = strrchr(filename, '.');
1973 if(p)
1974 *p = 0;
1976 if(ipsname[0] == 0)
1977 sprintf(ipsname, "%s.ips", filename);
1979 bool failed = false;
1981 IMAGE_TYPE type = utilFindType(szFile);
1983 if(type == IMAGE_UNKNOWN) {
1984 systemMessage(0, "Unknown file type %s", szFile);
1985 exit(-1);
1987 systemCartridgeType = (int)type;
1989 if(type == IMAGE_GB) {
1990 failed = !gbLoadRom(szFile);
1991 if(!failed) {
1992 systemCartridgeType = 1;
1993 //printf("RLM: choosing GBSystem\n");
1994 theEmulator = GBSystem;
1995 if(sdlAutoIPS) {
1996 int size = gbRomSize;
1997 utilApplyIPS(ipsname, &gbRom, &size);
1998 if(size != gbRomSize) {
1999 extern bool gbUpdateSizes();
2000 gbUpdateSizes();
2001 gbReset();
2005 } else if(type == IMAGE_GBA) {
2006 int size = CPULoadRom(szFile);
2007 failed = (size == 0);
2008 if(!failed) {
2009 // if(cpuEnhancedDetection && cpuSaveType == 0) {
2010 // utilGBAFindSave(rom, size);
2011 // }
2013 sdlApplyPerImagePreferences();
2015 systemCartridgeType = 0;
2016 theEmulator = GBASystem;
2018 /* disabled due to problems
2019 if(removeIntros && rom != NULL) {
2020 WRITE32LE(&rom[0], 0xea00002e);
2022 */
2024 //CPUInit(biosFileName, useBios);
2025 CPUInit();
2026 CPUReset();
2027 if(sdlAutoIPS) {
2028 int size = 0x2000000;
2029 utilApplyIPS(ipsname, &rom, &size);
2030 if(size != 0x2000000) {
2031 CPUReset();
2037 if(failed) {
2038 systemMessage(0, "Failed to load file %s", szFile);
2039 exit(-1);
2042 emulating = 1;
2043 renderedFrames = 0;
2047 void shutdown () {
2048 fprintf(stderr,"Shutting down\n");
2049 remoteCleanUp();
2050 soundShutdown();
2052 if(gbRom != NULL || rom != NULL) {
2053 sdlWriteBattery();
2054 theEmulator.emuCleanUp();
2057 if(delta) {
2058 free(delta);
2059 delta = NULL;
2062 SDL_Quit();
2066 void step () {
2067 if(!paused && active) {
2068 if(debugger && theEmulator.emuHasDebugger)
2069 dbgMain();
2070 else {
2071 //printf("RLM: emulator main\n");
2072 theEmulator.emuMain(theEmulator.emuCount);
2073 //printf("RLM: emulator main called\n");
2074 if(rewindSaveNeeded && rewindMemory && theEmulator.emuWriteMemState) {
2075 rewindCount++;
2076 if(rewindCount > 8)
2077 rewindCount = 8;
2078 if(theEmulator.emuWriteMemState &&
2079 theEmulator.emuWriteMemState(&rewindMemory[rewindPos*REWIND_SIZE],
2080 REWIND_SIZE)) {
2081 rewindPos = ++rewindPos & 7;
2082 if(rewindCount == 8)
2083 rewindTopPos = ++rewindTopPos & 7;
2087 rewindSaveNeeded = false;
2089 } else {
2090 SDL_Delay(500);
2092 sdlPollEvents();
2093 SDL_ShowCursor(SDL_DISABLE);
2096 void step(int keymask){
2097 currentButtons[0] = keymask;
2098 if (keymask == 0x0800){
2099 theEmulator.emuReset(true);
2101 else {
2102 step();
2104 currentButtons[0] = keymask;
2109 int main(int argc, char **argv)
2111 fprintf(stderr, "VisualBoyAdvance version %s [SDL]\n", PACKAGE_VERSION);
2113 arg0 = argv[0];
2115 captureDir[0] = 0;
2116 saveDir[0] = 0;
2117 batteryDir[0] = 0;
2118 ipsname[0] = 0;
2120 int op = -1;
2122 frameSkip = 2;
2123 gbBorderOn = 0;
2125 parseDebug = true;
2127 sdlReadPreferences();
2129 sdlPrintUsage = 0;
2131 while((op = getopt_long(argc,
2132 argv,
2133 "FNT:Y:G:D:b:c:df:hi:p::s:t:v:1234",
2134 sdlOptions,
2135 NULL)) != -1) {
2136 switch(op) {
2137 case 0:
2138 // long option already processed by getopt_long
2139 break;
2140 case 'b':
2141 useBios = true;
2142 if(optarg == NULL) {
2143 fprintf(stderr, "Missing BIOS file name\n");
2144 exit(-1);
2146 strcpy(biosFileName, optarg);
2147 break;
2148 case 'c':
2150 if(optarg == NULL) {
2151 fprintf(stderr, "Missing config file name\n");
2152 exit(-1);
2154 FILE *f = fopen(optarg, "r");
2155 if(f == NULL) {
2156 fprintf(stderr, "File not found %s\n", optarg);
2157 exit(-1);
2159 sdlReadPreferences(f);
2160 fclose(f);
2162 break;
2163 case 'd':
2164 debugger = true;
2165 break;
2166 case 'h':
2167 sdlPrintUsage = 1;
2168 break;
2169 case 'i':
2170 if(optarg == NULL) {
2171 fprintf(stderr, "Missing IPS name\n");
2172 exit(-1);
2173 strcpy(ipsname, optarg);
2175 break;
2176 case 'Y':
2177 yuv = true;
2178 if(optarg) {
2179 yuvType = atoi(optarg);
2180 switch(yuvType) {
2181 case 0:
2182 yuvType = SDL_YV12_OVERLAY;
2183 break;
2184 case 1:
2185 yuvType = SDL_UYVY_OVERLAY;
2186 break;
2187 case 2:
2188 yuvType = SDL_YVYU_OVERLAY;
2189 break;
2190 case 3:
2191 yuvType = SDL_YUY2_OVERLAY;
2192 break;
2193 case 4:
2194 yuvType = SDL_IYUV_OVERLAY;
2195 break;
2196 default:
2197 yuvType = SDL_YV12_OVERLAY;
2199 } else
2200 yuvType = SDL_YV12_OVERLAY;
2201 break;
2202 case 'G':
2203 dbgMain = remoteStubMain;
2204 dbgSignal = remoteStubSignal;
2205 dbgOutput = remoteOutput;
2206 debugger = true;
2207 debuggerStub = true;
2208 if(optarg) {
2209 char *s = optarg;
2210 if(strncmp(s,"tcp:", 4) == 0) {
2211 s+=4;
2212 int port = atoi(s);
2213 remoteSetProtocol(0);
2214 remoteSetPort(port);
2215 } else if(strcmp(s,"tcp") == 0) {
2216 remoteSetProtocol(0);
2217 } else if(strcmp(s, "pipe") == 0) {
2218 remoteSetProtocol(1);
2219 } else {
2220 fprintf(stderr, "Unknown protocol %s\n", s);
2221 exit(-1);
2223 } else {
2224 remoteSetProtocol(0);
2226 break;
2227 case 'N':
2228 parseDebug = false;
2229 break;
2230 case 'D':
2231 if(optarg) {
2232 systemDebug = atoi(optarg);
2233 } else {
2234 systemDebug = 1;
2236 break;
2237 case 'F':
2238 fullscreen = 1;
2239 mouseCounter = 120;
2240 break;
2241 case 'f':
2242 if(optarg) {
2243 filter = atoi(optarg);
2244 } else {
2245 filter = 0;
2247 break;
2249 case 'r':
2250 if(optarg == NULL) {
2251 fprintf(stderr, "ERROR: --recordmovie ('r') needs movie filename as option\n");
2252 exit(-1);
2254 strcpy(movieFileName, optarg);
2255 useMovie = 1;
2256 break;
2257 case 'p': // play without read-only (editable)
2258 fprintf (stderr, "-p got called!\n");
2259 if(optarg == NULL) {
2260 fprintf(stderr, "ERROR: --playmovie ('p') needs movie filename as option\n");
2261 exit(-1);
2263 strcpy(movieFileName, optarg);
2264 useMovie = 2;
2265 break;
2266 case 'w': // play with read-only
2267 fprintf (stderr, "-w got called!\n");
2268 if(optarg == NULL) {
2269 fprintf(stderr, "ERROR: --watchmovie ('w') needs movie filename as option\n");
2270 exit(-1);
2272 strcpy(movieFileName, optarg);
2273 useMovie = 3;
2274 break;
2276 case 'P':
2277 #ifdef PROFILING
2278 if(optarg) {
2279 cpuEnableProfiling(atoi(optarg));
2280 } else
2281 cpuEnableProfiling(100);
2282 #endif
2283 break;
2284 case 'S':
2285 sdlFlashSize = atoi(optarg);
2286 if(sdlFlashSize < 0 || sdlFlashSize > 1)
2287 sdlFlashSize = 0;
2288 break;
2289 case 's':
2290 if(optarg) {
2291 int a = atoi(optarg);
2292 if(a >= 0 && a <= 9) {
2293 gbFrameSkip = a;
2294 frameSkip = a;
2296 } else {
2297 frameSkip = 2;
2298 gbFrameSkip = 0;
2300 break;
2301 case 't':
2302 if(optarg) {
2303 int a = atoi(optarg);
2304 if(a < 0 || a > 5)
2305 a = 0;
2306 cpuSaveType = a;
2308 break;
2309 case 'T':
2310 if(optarg) {
2311 int t = atoi(optarg);
2312 throttle = t;
2314 break;
2315 case 'v':
2316 if(optarg) {
2317 systemVerbose = atoi(optarg);
2318 } else
2319 systemVerbose = 0;
2320 break;
2321 case '1':
2322 sizeOption = 0;
2323 break;
2324 case '2':
2325 sizeOption = 1;
2326 break;
2327 case '3':
2328 sizeOption = 2;
2329 break;
2330 case '4':
2331 sizeOption = 3;
2332 break;
2333 case '?':
2334 sdlPrintUsage = 1;
2335 break;
2339 //printf("RLM: derpy loves you!\n");
2340 //printf("RLM: useMovie: %d (1 is record)\n", useMovie);
2341 if(sdlPrintUsage) {
2342 usage(argv[0]);
2343 exit(-1);
2346 #ifdef MMX
2347 if(disableMMX)
2348 cpu_mmx = 0;
2349 #endif
2351 if(rewindTimer)
2352 rewindMemory = (char *)malloc(8*REWIND_SIZE);
2354 if(sdlFlashSize == 0)
2355 flashSetSize(0x10000);
2356 else
2357 flashSetSize(0x20000);
2359 rtcEnable(sdlRtcEnable ? true : false);
2360 agbPrintEnable(sdlAgbPrint ? true : false);
2362 if(!debuggerStub) {
2363 if(optind >= argc) {
2364 systemMessage(0,"Missing image name");
2365 usage(argv[0]);
2366 exit(-1);
2370 if(filter) {
2371 sizeOption = 1;
2374 for(int i = 0; i < 24;) {
2375 systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10);
2376 systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10);
2377 systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10);
2378 systemGbPalette[i++] = 0;
2381 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
2383 if(optind < argc)
2385 szFile = argv[optind];
2386 file_run();
2387 //printf("RLM: file_run() done\n");
2389 else
2391 systemCartridgeType = 0;
2392 strcpy(filename, "gnu_stub");
2393 rom = (u8 *)malloc(0x2000000);
2394 workRAM = (u8 *)calloc(1, 0x40000);
2395 bios = (u8 *)calloc(1,0x4000);
2396 internalRAM = (u8 *)calloc(1,0x8000);
2397 paletteRAM = (u8 *)calloc(1,0x400);
2398 vram = (u8 *)calloc(1, 0x20000);
2399 oam = (u8 *)calloc(1, 0x400);
2400 pix = (u8 *)calloc(1, 4 * 240 * 160);
2401 ioMem = (u8 *)calloc(1, 0x400);
2403 theEmulator = GBASystem;
2405 //CPUInit(biosFileName, useBios);
2406 CPUInit();
2407 CPUReset();
2410 if(debuggerStub)
2411 remoteInit();
2413 int flags = SDL_INIT_VIDEO|SDL_INIT_AUDIO|
2414 SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE;
2416 if(soundOffFlag)
2417 flags ^= SDL_INIT_AUDIO;
2419 if(SDL_Init(flags)) {
2420 systemMessage(0, "Failed to init SDL: %s", SDL_GetError());
2421 exit(-1);
2424 if(SDL_InitSubSystem(SDL_INIT_JOYSTICK)) {
2425 systemMessage(0, "Failed to init joystick support: %s", SDL_GetError());
2428 sdlCheckKeys();
2430 if(systemCartridgeType == 0) {
2431 srcWidth = 240;
2432 srcHeight = 160;
2433 systemFrameSkip = frameSkip;
2434 } else if (systemCartridgeType == 1) {
2435 if(gbBorderOn) {
2436 srcWidth = 256;
2437 srcHeight = 224;
2438 gbBorderLineSkip = 256;
2439 gbBorderColumnSkip = 48;
2440 gbBorderRowSkip = 40;
2441 } else {
2442 srcWidth = 160;
2443 srcHeight = 144;
2444 gbBorderLineSkip = 160;
2445 gbBorderColumnSkip = 0;
2446 gbBorderRowSkip = 0;
2448 systemFrameSkip = gbFrameSkip;
2449 } else {
2450 srcWidth = 320;
2451 srcHeight = 240;
2454 destWidth = (sizeOption+1)*srcWidth;
2455 destHeight = (sizeOption+1)*srcHeight;
2457 surface = SDL_SetVideoMode(destWidth, destHeight, 16,
2458 SDL_ANYFORMAT|SDL_HWSURFACE|SDL_DOUBLEBUF|
2459 (fullscreen ? SDL_FULLSCREEN : 0));
2461 if(surface == NULL) {
2462 systemMessage(0, "Failed to set video mode");
2463 SDL_Quit();
2464 exit(-1);
2467 systemRedShift = sdlCalculateShift(surface->format->Rmask);
2468 systemGreenShift = sdlCalculateShift(surface->format->Gmask);
2469 systemBlueShift = sdlCalculateShift(surface->format->Bmask);
2471 systemColorDepth = surface->format->BitsPerPixel;
2472 if(systemColorDepth == 15)
2473 systemColorDepth = 16;
2475 if(yuv) {
2476 Init_Overlay(surface, yuvType);
2477 systemColorDepth = 32;
2478 systemRedShift = 3;
2479 systemGreenShift = 11;
2480 systemBlueShift = 19;
2483 if(systemColorDepth != 16 && systemColorDepth != 24 &&
2484 systemColorDepth != 32) {
2485 fprintf(stderr,"Unsupported color depth '%d'.\nOnly 16, 24 and 32 bit color depths are supported\n", systemColorDepth);
2486 exit(-1);
2489 #ifndef C_CORE
2490 sdlMakeStretcher(srcWidth);
2491 #else
2492 switch(systemColorDepth) {
2493 case 16:
2494 sdlStretcher = sdlStretcher16[sizeOption];
2495 break;
2496 case 24:
2497 sdlStretcher = sdlStretcher24[sizeOption];
2498 break;
2499 case 32:
2500 sdlStretcher = sdlStretcher32[sizeOption];
2501 break;
2502 default:
2503 fprintf(stderr, "Unsupported resolution: %d\n", systemColorDepth);
2504 exit(-1);
2506 #endif
2508 fprintf(stderr,"Color depth: %d\n", systemColorDepth);
2510 if(systemColorDepth == 16) {
2511 if(sdlCalculateMaskWidth(surface->format->Gmask) == 6) {
2512 Init_2xSaI(565);
2513 RGB_LOW_BITS_MASK = 0x821;
2514 } else {
2515 Init_2xSaI(555);
2516 RGB_LOW_BITS_MASK = 0x421;
2518 if(systemCartridgeType == 2) {
2519 for(int i = 0; i < 0x10000; i++) {
2520 systemColorMap16[i] = (((i >> 1) & 0x1f) << systemBlueShift) |
2521 (((i & 0x7c0) >> 6) << systemGreenShift) |
2522 (((i & 0xf800) >> 11) << systemRedShift);
2524 } else {
2525 for(int i = 0; i < 0x10000; i++) {
2526 systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
2527 (((i & 0x3e0) >> 5) << systemGreenShift) |
2528 (((i & 0x7c00) >> 10) << systemBlueShift);
2531 srcPitch = srcWidth * 2+4;
2532 } else {
2533 if(systemColorDepth != 32)
2534 filterFunction = NULL;
2535 RGB_LOW_BITS_MASK = 0x010101;
2536 if(systemColorDepth == 32) {
2537 Init_2xSaI(32);
2539 for(int i = 0; i < 0x10000; i++) {
2540 systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
2541 (((i & 0x3e0) >> 5) << systemGreenShift) |
2542 (((i & 0x7c00) >> 10) << systemBlueShift);
2544 if(systemColorDepth == 32)
2545 srcPitch = srcWidth*4 + 4;
2546 else
2547 srcPitch = srcWidth*3;
2550 if(systemColorDepth != 32) {
2551 switch(filter) {
2552 case 0:
2553 filterFunction = NULL;
2554 break;
2555 case 1:
2556 filterFunction = ScanlinesTV;
2557 break;
2558 case 2:
2559 filterFunction = _2xSaI;
2560 break;
2561 case 3:
2562 filterFunction = Super2xSaI;
2563 break;
2564 case 4:
2565 filterFunction = SuperEagle;
2566 break;
2567 case 5:
2568 filterFunction = Pixelate2x16;
2569 break;
2570 case 6:
2571 filterFunction = MotionBlur;
2572 break;
2573 case 7:
2574 filterFunction = AdMame2x;
2575 break;
2576 case 8:
2577 filterFunction = Simple2x16;
2578 break;
2579 case 9:
2580 filterFunction = Bilinear;
2581 break;
2582 case 10:
2583 filterFunction = BilinearPlus;
2584 break;
2585 case 11:
2586 filterFunction = Scanlines;
2587 break;
2588 case 12:
2589 filterFunction = hq2x;
2590 break;
2591 case 13:
2592 filterFunction = lq2x;
2593 break;
2594 default:
2595 filterFunction = NULL;
2596 break;
2598 } else {
2599 switch(filter) {
2600 case 0:
2601 filterFunction = NULL;
2602 break;
2603 case 1:
2604 filterFunction = ScanlinesTV32;
2605 break;
2606 case 2:
2607 filterFunction = _2xSaI32;
2608 break;
2609 case 3:
2610 filterFunction = Super2xSaI32;
2611 break;
2612 case 4:
2613 filterFunction = SuperEagle32;
2614 break;
2615 case 5:
2616 filterFunction = Pixelate2x32;
2617 break;
2618 case 6:
2619 filterFunction = MotionBlur32;
2620 break;
2621 case 7:
2622 filterFunction = AdMame2x32;
2623 break;
2624 case 8:
2625 filterFunction = Simple2x32;
2626 break;
2627 case 9:
2628 filterFunction = Bilinear32;
2629 break;
2630 case 10:
2631 filterFunction = BilinearPlus32;
2632 break;
2633 case 11:
2634 filterFunction = Scanlines32;
2635 break;
2636 case 12:
2637 filterFunction = hq2x32;
2638 break;
2639 case 13:
2640 filterFunction = lq2x32;
2641 break;
2642 default:
2643 filterFunction = NULL;
2644 break;
2648 if(systemColorDepth == 16) {
2649 switch(ifbType) {
2650 case 0:
2651 default:
2652 ifbFunction = NULL;
2653 break;
2654 case 1:
2655 ifbFunction = MotionBlurIB;
2656 break;
2657 case 2:
2658 ifbFunction = SmartIB;
2659 break;
2661 } else if(systemColorDepth == 32) {
2662 switch(ifbType) {
2663 case 0:
2664 default:
2665 ifbFunction = NULL;
2666 break;
2667 case 1:
2668 ifbFunction = MotionBlurIB32;
2669 break;
2670 case 2:
2671 ifbFunction = SmartIB32;
2672 break;
2674 } else
2675 ifbFunction = NULL;
2677 if(delta == NULL) {
2678 delta = (u8*)malloc(322*242*4);
2679 memset(delta, 255, 322*242*4);
2682 if(!soundOffFlag)
2683 soundInit();
2685 autoFrameSkipLastTime = throttleLastTime = systemGetClock();
2686 //printf("RLM: and now for the movie part!\n");
2688 switch(useMovie)
2690 case 1: // --recordMovie
2691 VBAMovieCreate(movieFileName,
2692 /*authorInfo*/"",
2693 /*startFlags*/0,
2694 /*controllerFlags*/MOVIE_CONTROLLER(0),
2695 /*typeFlags*/(systemCartridgeType==IMAGE_GBA)?(MOVIE_TYPE_GBA):(GBC_CAPABLE?MOVIE_TYPE_GBC:MOVIE_TYPE_SGB));
2696 break;
2697 case 2: // --playMovie
2698 VBAMovieOpen(movieFileName, false);
2699 break;
2700 case 3: // --watchMovie
2701 VBAMovieOpen(movieFileName, true);
2702 break;
2703 default:
2704 sdlReadBattery();
2705 break;
2707 //printf("RLM: still alive after movie switch\n");
2708 SDL_WM_SetCaption("VisualBoyAdvance", NULL);
2710 char *moviefile = getenv("AUTODEMO");
2711 fprintf (stderr, "Checking for AUTODEMO...\n");
2712 if (moviefile)
2714 fprintf (stderr, "I got a filename OMG!\nCalling VBAMovieOpen...\n");
2715 VBAMovieOpen(moviefile, true);
2717 //step();
2718 return 0;
2721 // RLM
2722 int runVBA(int argc, char **argv){
2723 return main(argc, argv);
2732 void systemMessage(int num, const char *msg, ...)
2734 char buffer[2048];
2735 va_list valist;
2737 va_start(valist, msg);
2738 vsprintf(buffer, msg, valist);
2740 fprintf(stderr, "%s\n", buffer);
2741 va_end(valist);
2744 //On WIN32, this function messages requesting
2745 //the window to be redrawn. Can this be ignored here?
2746 void systemRefreshScreen(){}
2748 void systemRenderFrame()
2750 renderedFrames++;
2751 VBAUpdateFrameCountDisplay();
2752 VBAUpdateButtonPressDisplay();
2754 if(yuv) {
2755 Draw_Overlay(surface, sizeOption+1);
2756 return;
2759 SDL_LockSurface(surface);
2761 for(int slot = 0 ; slot < 8 ; slot++)
2763 if(screenMessage[slot]) {
2764 if(systemCartridgeType == 1 && gbBorderOn) {
2765 gbSgbRenderBorder();
2767 if(((systemGetClock() - screenMessageTime[slot]) < screenMessageDuration[slot]) &&
2768 !disableStatusMessages) {
2769 drawText(pix, srcPitch, 10, srcHeight - 20*(slot+1),
2770 screenMessageBuffer[slot]);
2771 } else {
2772 screenMessage[slot] = false;
2777 if(ifbFunction) {
2778 if(systemColorDepth == 16)
2779 ifbFunction(pix+destWidth+4, destWidth+4, srcWidth, srcHeight);
2780 else
2781 ifbFunction(pix+destWidth*2+4, destWidth*2+4, srcWidth, srcHeight);
2784 if(filterFunction) {
2785 if(systemColorDepth == 16)
2786 filterFunction(pix+destWidth+4,destWidth+4, delta,
2787 (u8*)surface->pixels,surface->pitch,
2788 srcWidth,
2789 srcHeight);
2790 else
2791 filterFunction(pix+destWidth*2+4,
2792 destWidth*2+4,
2793 delta,
2794 (u8*)surface->pixels,
2795 surface->pitch,
2796 srcWidth,
2797 srcHeight);
2798 } else {
2799 int destPitch = surface->pitch;
2800 u8 *src = pix;
2801 u8 *dest = (u8*)surface->pixels;
2802 int i;
2803 u32 *stretcher = (u32 *)sdlStretcher;
2804 if(systemColorDepth == 16)
2805 src += srcPitch;
2806 int option = sizeOption;
2807 if(yuv)
2808 option = 0;
2809 switch(sizeOption) {
2810 case 0:
2811 for(i = 0; i < srcHeight; i++) {
2812 SDL_CALL_STRETCHER;
2813 src += srcPitch;
2814 dest += destPitch;
2816 break;
2817 case 1:
2818 for(i = 0; i < srcHeight; i++) {
2819 SDL_CALL_STRETCHER;
2820 dest += destPitch;
2821 SDL_CALL_STRETCHER;
2822 src += srcPitch;
2823 dest += destPitch;
2825 break;
2826 case 2:
2827 for(i = 0; i < srcHeight; i++) {
2828 SDL_CALL_STRETCHER;
2829 dest += destPitch;
2830 SDL_CALL_STRETCHER;
2831 dest += destPitch;
2832 SDL_CALL_STRETCHER;
2833 src += srcPitch;
2834 dest += destPitch;
2836 break;
2837 case 3:
2838 for(i = 0; i < srcHeight; i++) {
2839 SDL_CALL_STRETCHER;
2840 dest += destPitch;
2841 SDL_CALL_STRETCHER;
2842 dest += destPitch;
2843 SDL_CALL_STRETCHER;
2844 dest += destPitch;
2845 SDL_CALL_STRETCHER;
2846 src += srcPitch;
2847 dest += destPitch;
2849 break;
2853 if(showSpeed && fullscreen) {
2854 char buffer[50];
2855 if(showSpeed == 1)
2856 sprintf(buffer, "%d%%", systemSpeed);
2857 else
2858 sprintf(buffer, "%3d%%(%d, %d fps)", systemSpeed,
2859 systemFrameSkip,
2860 showRenderedFrames);
2861 if(showSpeedTransparent)
2862 drawTextTransp((u8*)surface->pixels,
2863 surface->pitch,
2864 10,
2865 surface->h-20,
2866 buffer);
2867 else
2868 drawText((u8*)surface->pixels,
2869 surface->pitch,
2870 10,
2871 surface->h-20,
2872 buffer);
2875 SDL_UnlockSurface(surface);
2876 // SDL_UpdateRect(surface, 0, 0, destWidth, destHeight);
2877 SDL_Flip(surface);
2880 bool systemReadJoypads()
2882 return true;
2885 // Kludge to make Lua call the right function.
2886 u32 systemGetOriginalJoypad(int which, bool sensor){
2887 return systemGetJoypad(which,sensor);
2890 u32 systemGetJoypad(int which, bool sensor)
2892 sensorOn = sensor;
2893 if(which < 0 || which > 3)
2894 which = sdlDefaultJoypad;
2896 //VBAMovieUpdate(which);
2897 //VBAMovieUpdateState();
2898 u32 res = 0;
2900 //----------------------------//
2901 if (VBAMoviePlaying()){
2902 // VBAMovieRead() overwrites currentButtons[i]
2903 VBAMovieRead(which, sensor);
2904 res = currentButtons[which];
2905 return res;
2907 //---------------------------//
2908 //Temporary implementation, not sure if it's correct --Felipe
2910 /*
2911 if(sdlButtons[which][KEY_BUTTON_A])
2912 res |= BUTTON_MASK_A;
2913 if(sdlButtons[which][KEY_BUTTON_B])
2914 res |= BUTTON_MASK_B;
2915 if(sdlButtons[which][KEY_BUTTON_SELECT])
2916 res |= BUTTON_MASK_SELECT;
2917 if(sdlButtons[which][KEY_BUTTON_START])
2918 res |= BUTTON_MASK_START;
2919 if(sdlButtons[which][KEY_RIGHT])
2920 res |= BUTTON_MASK_RIGHT;
2921 if(sdlButtons[which][KEY_LEFT])
2922 res |= BUTTON_MASK_LEFT;
2923 if(sdlButtons[which][KEY_UP])
2924 res |= BUTTON_MASK_UP;
2925 if(sdlButtons[which][KEY_DOWN])
2926 res |= BUTTON_MASK_DOWN;
2927 if(sdlButtons[which][KEY_BUTTON_R])
2928 res |= BUTTON_MASK_R;
2929 if(sdlButtons[which][KEY_BUTTON_L])
2930 res |= BUTTON_MASK_L;
2931 */
2932 /*
2933 // disallow L+R or U+D of being pressed at the same time
2934 if((res & 48) == 48)
2935 res &= ~16;
2936 if((res & 192) == 192)
2937 res &= ~128;
2938 */
2939 /*
2940 if(sdlbuttons[which][KEY_BUTTON_SPEED])
2941 res |= 1024;
2942 if(sdlButtons[which][KEY_BUTTON_CAPTURE])
2943 res |= 2048;
2944 */
2945 res = currentButtons[which];
2947 if(autoFire) {
2948 res &= (~autoFire);
2949 if(autoFireToggle)
2950 res |= autoFire;
2951 autoFireToggle = !autoFireToggle;
2954 //if (res) fprintf(stdout,"%x\n",res);
2956 return res;
2959 void systemSetJoypad(int which, u32 buttons)
2961 if(which < 0 || which > 3)
2962 which = sdlDefaultJoypad;
2963 /*
2964 sdlButtons[which][KEY_BUTTON_A] = (buttons & 1) != 0;
2965 sdlButtons[which][KEY_BUTTON_B] = (buttons & 2) != 0;
2966 sdlButtons[which][KEY_BUTTON_SELECT] = (buttons & 4) != 0;
2967 sdlButtons[which][KEY_BUTTON_START] = (buttons & 8) != 0;
2968 sdlButtons[which][KEY_RIGHT] = (buttons & 16) != 0;
2969 sdlButtons[which][KEY_LEFT] = (buttons & 32) != 0;
2970 sdlButtons[which][KEY_UP] = (buttons & 64) != 0;
2971 sdlButtons[which][KEY_DOWN] = (buttons & 128) != 0;
2972 sdlButtons[which][KEY_BUTTON_R] = (buttons & 256) != 0;
2973 sdlButtons[which][KEY_BUTTON_L] = (buttons & 512) != 0;
2974 */
2975 currentButtons[which]= buttons & 0x3ff;
2978 void systemClearJoypads()
2980 for (int i = 0; i < 4; ++i)
2981 currentButtons[i] = 0;
2983 //lastKeys = 0;
2986 void systemSetTitle(const char *title)
2988 SDL_WM_SetCaption(title, NULL);
2991 void systemShowSpeed(int speed)
2993 systemSpeed = speed;
2995 showRenderedFrames = renderedFrames;
2996 renderedFrames = 0;
2998 if(!fullscreen && showSpeed) {
2999 char buffer[80];
3000 if(showSpeed == 1)
3001 sprintf(buffer, "VisualBoyAdvance-%3d%%", systemSpeed);
3002 else
3003 sprintf(buffer, "VisualBoyAdvance-%3d%%(%d, %d fps)", systemSpeed,
3004 systemFrameSkip,
3005 showRenderedFrames);
3007 systemSetTitle(buffer);
3011 // FIXME: the timing
3012 void systemFrame(/*int rate*/) //Looking at System.cpp, it looks like rate should be 600
3014 u32 time = systemGetClock();
3015 if(!wasPaused && autoFrameSkip && !throttle) {
3016 u32 diff = time - autoFrameSkipLastTime;
3017 int speed = 100;
3019 if(diff)
3020 speed = (1000000/600)/diff;
3022 if(speed >= 98) {
3023 frameskipadjust++;
3025 if(frameskipadjust >= 3) {
3026 frameskipadjust=0;
3027 if(systemFrameSkip > 0)
3028 systemFrameSkip--;
3030 } else {
3031 if(speed < 80)
3032 frameskipadjust -= (90 - speed)/5;
3033 else if(systemFrameSkip < 9)
3034 frameskipadjust--;
3036 if(frameskipadjust <= -2) {
3037 frameskipadjust += 2;
3038 if(systemFrameSkip < 9)
3039 systemFrameSkip++;
3043 if(!wasPaused && throttle) {
3044 /*if(!speedup) {
3045 u32 diff = time - throttleLastTime;
3047 int target = (1000000.0/(600*throttle));
3048 int d = (target - diff);
3050 if(d > 0) {
3051 SDL_Delay(d);
3054 throttleLastTime = systemGetClock();
3055 */
3057 if(rewindMemory) {
3058 if(++rewindCounter >= rewindTimer) {
3059 rewindSaveNeeded = true;
3060 rewindCounter = 0;
3064 if(systemSaveUpdateCounter) {
3065 if(--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED) {
3066 sdlWriteBattery();
3067 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
3071 wasPaused = false;
3072 autoFrameSkipLastTime = time;
3075 int systemFramesToSkip(){
3076 return systemFrameSkip;
3079 int systemScreenCapture(int a)
3081 char buffer[2048];
3083 if(captureFormat) {
3084 if(captureDir[0])
3085 sprintf(buffer, "%s/%s%02d.bmp", captureDir, sdlGetFilename(filename), a);
3086 else
3087 sprintf(buffer, "%s%02d.bmp", filename, a);
3089 theEmulator.emuWriteBMP(buffer);
3090 } else {
3091 if(captureDir[0])
3092 sprintf(buffer, "%s/%s%02d.png", captureDir, sdlGetFilename(filename), a);
3093 else
3094 sprintf(buffer, "%s%02d.png", filename, a);
3095 theEmulator.emuWritePNG(buffer);
3098 systemScreenMessage("Screen capture");
3099 return a;
3102 void soundCallback(void *,u8 *stream,int len){}
3104 void systemSoundWriteToBuffer(){
3105 soundDriver->write(soundFinalWave, soundBufferLen);
3108 void systemSoundClearBuffer()
3110 SDL_mutexP(mutex);
3111 memset(sdlBuffer,0,soundBufferTotalLen);
3112 sdlSoundLen=0;
3113 printf("Hi\n");
3114 SDL_mutexV(mutex);
3117 bool systemSoundInit(){
3118 systemSoundShutdown();
3119 soundDriver = new SoundSDL();
3120 if ( !soundDriver )
3121 return false;
3123 if (!soundDriver->init()) //<-- sound sample rate
3124 return false;
3126 if (!(soundDriver->setThrottle(throttle))){
3127 fprintf(stderr,"Failed to set desired throttle, defaulting to 100 %%.\n");
3128 if (!soundDriver->setThrottle(100)) return false;
3130 soundPaused = true;
3131 systemSoundOn = true;
3132 return true;
3135 void systemSoundShutdown(){
3136 if (soundDriver)
3138 delete soundDriver;
3139 soundDriver = 0;
3143 void systemSoundPause()
3145 SDL_PauseAudio(1);
3148 void systemSoundResume()
3150 SDL_PauseAudio(0);
3153 void systemSoundReset()
3157 u32 systemGetClock()
3159 return SDL_GetTicks();
3162 void systemUpdateMotionSensor()
3164 if(sdlMotionButtons[KEY_LEFT]) {
3165 sensorX += 3;
3166 if(sensorX > 2197)
3167 sensorX = 2197;
3168 if(sensorX < 2047)
3169 sensorX = 2057;
3170 } else if(sdlMotionButtons[KEY_RIGHT]) {
3171 sensorX -= 3;
3172 if(sensorX < 1897)
3173 sensorX = 1897;
3174 if(sensorX > 2047)
3175 sensorX = 2037;
3176 } else if(sensorX > 2047) {
3177 sensorX -= 2;
3178 if(sensorX < 2047)
3179 sensorX = 2047;
3180 } else {
3181 sensorX += 2;
3182 if(sensorX > 2047)
3183 sensorX = 2047;
3186 if(sdlMotionButtons[KEY_UP]) {
3187 sensorY += 3;
3188 if(sensorY > 2197)
3189 sensorY = 2197;
3190 if(sensorY < 2047)
3191 sensorY = 2057;
3192 } else if(sdlMotionButtons[KEY_DOWN]) {
3193 sensorY -= 3;
3194 if(sensorY < 1897)
3195 sensorY = 1897;
3196 if(sensorY > 2047)
3197 sensorY = 2037;
3198 } else if(sensorY > 2047) {
3199 sensorY -= 2;
3200 if(sensorY < 2047)
3201 sensorY = 2047;
3202 } else {
3203 sensorY += 2;
3204 if(sensorY > 2047)
3205 sensorY = 2047;
3209 void systemResetSensor()
3211 sensorX = sensorY = INITIAL_SENSOR_VALUE;
3214 int systemGetSensorX()
3216 return sensorX;
3219 int systemGetSensorY()
3221 return sensorY;
3224 void systemGbPrint(u8 *data,int pages,int feed,int palette, int contrast)
3228 void systemScreenMessage(const char *msg, int slot, int duration, const char *colorList)
3230 screenMessage[slot] = true;
3231 screenMessageTime[slot] = systemGetClock();
3232 screenMessageDuration[slot] = duration;
3233 if(strlen(msg) > 20) {
3234 strncpy(screenMessageBuffer[slot], msg, 20);
3235 screenMessageBuffer[slot][20] = 0;
3236 } else
3237 strcpy(screenMessageBuffer[slot], msg);
3240 bool systemSoundCanChangeQuality()
3242 return false;
3245 bool systemSoundSetQuality(int quality)
3247 if (systemCartridgeType == 0)
3248 soundSetQuality(quality);
3249 else
3250 gbSoundSetQuality(quality);
3252 return true;
3255 bool systemPauseOnFrame()
3257 if(pauseNextFrame) {
3258 paused = true;
3259 pauseNextFrame = false;
3260 return true;
3262 return false;
3265 // Code donated by Niels Wagenaar (BoycottAdvance)
3267 // GBA screensize.
3268 #define GBA_WIDTH 240
3269 #define GBA_HEIGHT 160
3271 void Init_Overlay(SDL_Surface *gbascreen, int overlaytype)
3274 overlay = SDL_CreateYUVOverlay( GBA_WIDTH,
3275 GBA_HEIGHT,
3276 overlaytype, gbascreen);
3277 fprintf(stderr, "Created %dx%dx%d %s %s overlay\n",
3278 overlay->w,overlay->h,overlay->planes,
3279 overlay->hw_overlay?"hardware":"software",
3280 overlay->format==SDL_YV12_OVERLAY?"YV12":
3281 overlay->format==SDL_IYUV_OVERLAY?"IYUV":
3282 overlay->format==SDL_YUY2_OVERLAY?"YUY2":
3283 overlay->format==SDL_UYVY_OVERLAY?"UYVY":
3284 overlay->format==SDL_YVYU_OVERLAY?"YVYU":
3285 "Unknown");
3288 void Quit_Overlay(void)
3291 SDL_FreeYUVOverlay(overlay);
3294 /* NOTE: These RGB conversion functions are not intended for speed,
3295 only as examples.
3296 */
3297 inline void RGBtoYUV(Uint8 *rgb, int *yuv)
3299 yuv[0] = (int)((0.257 * rgb[0]) + (0.504 * rgb[1]) + (0.098 * rgb[2]) + 16);
3300 yuv[1] = (int)(128 - (0.148 * rgb[0]) - (0.291 * rgb[1]) + (0.439 * rgb[2]));
3301 yuv[2] = (int)(128 + (0.439 * rgb[0]) - (0.368 * rgb[1]) - (0.071 * rgb[2]));
3304 inline void ConvertRGBtoYV12(SDL_Overlay *o)
3306 int x,y;
3307 int yuv[3];
3308 Uint8 *p,*op[3];
3310 SDL_LockYUVOverlay(o);
3312 /* Black initialization */
3313 /*
3314 memset(o->pixels[0],0,o->pitches[0]*o->h);
3315 memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2));
3316 memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2));
3317 */
3319 /* Convert */
3320 for(y=0; y<160 && y<o->h; y++) {
3321 p=(Uint8 *)pix+srcPitch*y;
3322 op[0]=o->pixels[0]+o->pitches[0]*y;
3323 op[1]=o->pixels[1]+o->pitches[1]*(y/2);
3324 op[2]=o->pixels[2]+o->pitches[2]*(y/2);
3325 for(x=0; x<240 && x<o->w; x++) {
3326 RGBtoYUV(p,yuv);
3327 *(op[0]++)=yuv[0];
3328 if(x%2==0 && y%2==0) {
3329 *(op[1]++)=yuv[2];
3330 *(op[2]++)=yuv[1];
3332 p+=4;//s->format->BytesPerPixel;
3336 SDL_UnlockYUVOverlay(o);
3339 inline void ConvertRGBtoIYUV(SDL_Overlay *o)
3341 int x,y;
3342 int yuv[3];
3343 Uint8 *p,*op[3];
3345 SDL_LockYUVOverlay(o);
3347 /* Black initialization */
3348 /*
3349 memset(o->pixels[0],0,o->pitches[0]*o->h);
3350 memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2));
3351 memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2));
3352 */
3354 /* Convert */
3355 for(y=0; y<160 && y<o->h; y++) {
3356 p=(Uint8 *)pix+srcPitch*y;
3357 op[0]=o->pixels[0]+o->pitches[0]*y;
3358 op[1]=o->pixels[1]+o->pitches[1]*(y/2);
3359 op[2]=o->pixels[2]+o->pitches[2]*(y/2);
3360 for(x=0; x<240 && x<o->w; x++) {
3361 RGBtoYUV(p,yuv);
3362 *(op[0]++)=yuv[0];
3363 if(x%2==0 && y%2==0) {
3364 *(op[1]++)=yuv[1];
3365 *(op[2]++)=yuv[2];
3367 p+=4; //s->format->BytesPerPixel;
3371 SDL_UnlockYUVOverlay(o);
3374 inline void ConvertRGBtoUYVY(SDL_Overlay *o)
3376 int x,y;
3377 int yuv[3];
3378 Uint8 *p,*op;
3380 SDL_LockYUVOverlay(o);
3382 for(y=0; y<160 && y<o->h; y++) {
3383 p=(Uint8 *)pix+srcPitch*y;
3384 op=o->pixels[0]+o->pitches[0]*y;
3385 for(x=0; x<240 && x<o->w; x++) {
3386 RGBtoYUV(p,yuv);
3387 if(x%2==0) {
3388 *(op++)=yuv[1];
3389 *(op++)=yuv[0];
3390 *(op++)=yuv[2];
3391 } else
3392 *(op++)=yuv[0];
3394 p+=4; //s->format->BytesPerPixel;
3398 SDL_UnlockYUVOverlay(o);
3401 inline void ConvertRGBtoYVYU(SDL_Overlay *o)
3403 int x,y;
3404 int yuv[3];
3405 Uint8 *p,*op;
3407 SDL_LockYUVOverlay(o);
3409 for(y=0; y<160 && y<o->h; y++) {
3410 p=(Uint8 *)pix+srcPitch*y;
3411 op=o->pixels[0]+o->pitches[0]*y;
3412 for(x=0; x<240 && x<o->w; x++) {
3413 RGBtoYUV(p,yuv);
3414 if(x%2==0) {
3415 *(op++)=yuv[0];
3416 *(op++)=yuv[2];
3417 op[1]=yuv[1];
3418 } else {
3419 *op=yuv[0];
3420 op+=2;
3423 p+=4; //s->format->BytesPerPixel;
3427 SDL_UnlockYUVOverlay(o);
3430 inline void ConvertRGBtoYUY2(SDL_Overlay *o)
3432 int x,y;
3433 int yuv[3];
3434 Uint8 *p,*op;
3436 SDL_LockYUVOverlay(o);
3438 for(y=0; y<160 && y<o->h; y++) {
3439 p=(Uint8 *)pix+srcPitch*y;
3440 op=o->pixels[0]+o->pitches[0]*y;
3441 for(x=0; x<240 && x<o->w; x++) {
3442 RGBtoYUV(p,yuv);
3443 if(x%2==0) {
3444 *(op++)=yuv[0];
3445 *(op++)=yuv[1];
3446 op[1]=yuv[2];
3447 } else {
3448 *op=yuv[0];
3449 op+=2;
3452 p+=4; //s->format->BytesPerPixel;
3456 SDL_UnlockYUVOverlay(o);
3459 inline void Convert32bit(SDL_Surface *display)
3461 switch(overlay->format) {
3462 case SDL_YV12_OVERLAY:
3463 ConvertRGBtoYV12(overlay);
3464 break;
3465 case SDL_UYVY_OVERLAY:
3466 ConvertRGBtoUYVY(overlay);
3467 break;
3468 case SDL_YVYU_OVERLAY:
3469 ConvertRGBtoYVYU(overlay);
3470 break;
3471 case SDL_YUY2_OVERLAY:
3472 ConvertRGBtoYUY2(overlay);
3473 break;
3474 case SDL_IYUV_OVERLAY:
3475 ConvertRGBtoIYUV(overlay);
3476 break;
3477 default:
3478 fprintf(stderr, "cannot convert RGB picture to obtained YUV format!\n");
3479 exit(1);
3480 break;
3486 inline void Draw_Overlay(SDL_Surface *display, int size)
3488 SDL_LockYUVOverlay(overlay);
3490 Convert32bit(display);
3492 overlay_rect.x = 0;
3493 overlay_rect.y = 0;
3494 overlay_rect.w = GBA_WIDTH * size;
3495 overlay_rect.h = GBA_HEIGHT * size;
3497 SDL_DisplayYUVOverlay(overlay, &overlay_rect);
3498 SDL_UnlockYUVOverlay(overlay);
3501 bool systemIsEmulating()
3503 return emulating != 0;
3506 void systemGbBorderOn()
3508 srcWidth = 256;
3509 srcHeight = 224;
3510 gbBorderLineSkip = 256;
3511 gbBorderColumnSkip = 48;
3512 gbBorderRowSkip = 40;
3514 destWidth = (sizeOption+1)*srcWidth;
3515 destHeight = (sizeOption+1)*srcHeight;
3517 surface = SDL_SetVideoMode(destWidth, destHeight, 16,
3518 SDL_ANYFORMAT|SDL_HWSURFACE|SDL_DOUBLEBUF|
3519 (fullscreen ? SDL_FULLSCREEN : 0));
3520 #ifndef C_CORE
3521 sdlMakeStretcher(srcWidth);
3522 #else
3523 switch(systemColorDepth) {
3524 case 16:
3525 sdlStretcher = sdlStretcher16[sizeOption];
3526 break;
3527 case 24:
3528 sdlStretcher = sdlStretcher24[sizeOption];
3529 break;
3530 case 32:
3531 sdlStretcher = sdlStretcher32[sizeOption];
3532 break;
3533 default:
3534 fprintf(stderr, "Unsupported resolution: %d\n", systemColorDepth);
3535 exit(-1);
3537 #endif
3539 if(systemColorDepth == 16) {
3540 if(sdlCalculateMaskWidth(surface->format->Gmask) == 6) {
3541 Init_2xSaI(565);
3542 RGB_LOW_BITS_MASK = 0x821;
3543 } else {
3544 Init_2xSaI(555);
3545 RGB_LOW_BITS_MASK = 0x421;
3547 if(systemCartridgeType == 2) {
3548 for(int i = 0; i < 0x10000; i++) {
3549 systemColorMap16[i] = (((i >> 1) & 0x1f) << systemBlueShift) |
3550 (((i & 0x7c0) >> 6) << systemGreenShift) |
3551 (((i & 0xf800) >> 11) << systemRedShift);
3553 } else {
3554 for(int i = 0; i < 0x10000; i++) {
3555 systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
3556 (((i & 0x3e0) >> 5) << systemGreenShift) |
3557 (((i & 0x7c00) >> 10) << systemBlueShift);
3560 srcPitch = srcWidth * 2+4;
3561 } else {
3562 if(systemColorDepth != 32)
3563 filterFunction = NULL;
3564 RGB_LOW_BITS_MASK = 0x010101;
3565 if(systemColorDepth == 32) {
3566 Init_2xSaI(32);
3568 for(int i = 0; i < 0x10000; i++) {
3569 systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
3570 (((i & 0x3e0) >> 5) << systemGreenShift) |
3571 (((i & 0x7c00) >> 10) << systemBlueShift);
3573 if(systemColorDepth == 32)
3574 srcPitch = srcWidth*4 + 4;
3575 else
3576 srcPitch = srcWidth*3;
3580 bool systemIsRunningGBA()
3582 return (rom != NULL);
3585 int systemGetDefaultJoypad()
3587 return sdlDefaultJoypad;
3590 bool systemIsPaused()
3592 return paused;
3595 void systemSetPause(bool pause)
3597 paused = pause;
3598 if (pause)
3599 systemSoundPause();
3600 else
3601 systemSoundResume();
3604 u16 checksumBIOS()
3606 bool hasBIOS = false;
3607 u8 * tempBIOS;
3608 if(useBios)
3610 tempBIOS = (u8 *)malloc(0x4000);
3611 int size = 0x4000;
3612 if(utilLoad(biosFileName,
3613 utilIsGBABios,
3614 tempBIOS,
3615 size)) {
3616 if(size == 0x4000)
3617 hasBIOS = true;
3621 u16 biosCheck = 0;
3622 if(hasBIOS) {
3623 for(int i = 0; i < 0x4000; i += 4)
3624 biosCheck += *((u32 *)&tempBIOS[i]);
3625 free(tempBIOS);
3628 return biosCheck;
3631 EmulatedSystemCounters systemCounters = {
3632 0, //framecount
3633 0, //lagcount
3634 0, //extracount
3635 true, //lagged
3636 true //laggedLast
3637 };
3639 void VBAOnEnteringFrameBoundary()
3641 //printf("RLM: Entering Frame Boundary\n");
3642 CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION);
3644 if (VBALuaRunning())
3646 VBALuaFrameBoundary();
3649 //printf("RLM: Movie state update pending\n");
3650 VBAMovieUpdateState();
3651 //printf("RLM: Movie state updated\n");
3654 void VBAOnExitingFrameBoundary()