view src/sdl/SDL.cpp @ 55:719d910c90f8

can now send button presses to the simulated gameboy
author Robert McIntyre <rlm@mit.edu>
date Wed, 07 Mar 2012 13:24:32 -0600
parents 9d0ec2614443
children 43d4fb2a6fc2
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 step();
2099 currentButtons[0] = keymask;
2104 int main(int argc, char **argv)
2106 fprintf(stderr, "VisualBoyAdvance version %s [SDL]\n", PACKAGE_VERSION);
2108 arg0 = argv[0];
2110 captureDir[0] = 0;
2111 saveDir[0] = 0;
2112 batteryDir[0] = 0;
2113 ipsname[0] = 0;
2115 int op = -1;
2117 frameSkip = 2;
2118 gbBorderOn = 0;
2120 parseDebug = true;
2122 sdlReadPreferences();
2124 sdlPrintUsage = 0;
2126 while((op = getopt_long(argc,
2127 argv,
2128 "FNT:Y:G:D:b:c:df:hi:p::s:t:v:1234",
2129 sdlOptions,
2130 NULL)) != -1) {
2131 switch(op) {
2132 case 0:
2133 // long option already processed by getopt_long
2134 break;
2135 case 'b':
2136 useBios = true;
2137 if(optarg == NULL) {
2138 fprintf(stderr, "Missing BIOS file name\n");
2139 exit(-1);
2141 strcpy(biosFileName, optarg);
2142 break;
2143 case 'c':
2145 if(optarg == NULL) {
2146 fprintf(stderr, "Missing config file name\n");
2147 exit(-1);
2149 FILE *f = fopen(optarg, "r");
2150 if(f == NULL) {
2151 fprintf(stderr, "File not found %s\n", optarg);
2152 exit(-1);
2154 sdlReadPreferences(f);
2155 fclose(f);
2157 break;
2158 case 'd':
2159 debugger = true;
2160 break;
2161 case 'h':
2162 sdlPrintUsage = 1;
2163 break;
2164 case 'i':
2165 if(optarg == NULL) {
2166 fprintf(stderr, "Missing IPS name\n");
2167 exit(-1);
2168 strcpy(ipsname, optarg);
2170 break;
2171 case 'Y':
2172 yuv = true;
2173 if(optarg) {
2174 yuvType = atoi(optarg);
2175 switch(yuvType) {
2176 case 0:
2177 yuvType = SDL_YV12_OVERLAY;
2178 break;
2179 case 1:
2180 yuvType = SDL_UYVY_OVERLAY;
2181 break;
2182 case 2:
2183 yuvType = SDL_YVYU_OVERLAY;
2184 break;
2185 case 3:
2186 yuvType = SDL_YUY2_OVERLAY;
2187 break;
2188 case 4:
2189 yuvType = SDL_IYUV_OVERLAY;
2190 break;
2191 default:
2192 yuvType = SDL_YV12_OVERLAY;
2194 } else
2195 yuvType = SDL_YV12_OVERLAY;
2196 break;
2197 case 'G':
2198 dbgMain = remoteStubMain;
2199 dbgSignal = remoteStubSignal;
2200 dbgOutput = remoteOutput;
2201 debugger = true;
2202 debuggerStub = true;
2203 if(optarg) {
2204 char *s = optarg;
2205 if(strncmp(s,"tcp:", 4) == 0) {
2206 s+=4;
2207 int port = atoi(s);
2208 remoteSetProtocol(0);
2209 remoteSetPort(port);
2210 } else if(strcmp(s,"tcp") == 0) {
2211 remoteSetProtocol(0);
2212 } else if(strcmp(s, "pipe") == 0) {
2213 remoteSetProtocol(1);
2214 } else {
2215 fprintf(stderr, "Unknown protocol %s\n", s);
2216 exit(-1);
2218 } else {
2219 remoteSetProtocol(0);
2221 break;
2222 case 'N':
2223 parseDebug = false;
2224 break;
2225 case 'D':
2226 if(optarg) {
2227 systemDebug = atoi(optarg);
2228 } else {
2229 systemDebug = 1;
2231 break;
2232 case 'F':
2233 fullscreen = 1;
2234 mouseCounter = 120;
2235 break;
2236 case 'f':
2237 if(optarg) {
2238 filter = atoi(optarg);
2239 } else {
2240 filter = 0;
2242 break;
2244 case 'r':
2245 if(optarg == NULL) {
2246 fprintf(stderr, "ERROR: --recordmovie ('r') needs movie filename as option\n");
2247 exit(-1);
2249 strcpy(movieFileName, optarg);
2250 useMovie = 1;
2251 break;
2252 case 'p': // play without read-only (editable)
2253 fprintf (stderr, "-p got called!\n");
2254 if(optarg == NULL) {
2255 fprintf(stderr, "ERROR: --playmovie ('p') needs movie filename as option\n");
2256 exit(-1);
2258 strcpy(movieFileName, optarg);
2259 useMovie = 2;
2260 break;
2261 case 'w': // play with read-only
2262 fprintf (stderr, "-w got called!\n");
2263 if(optarg == NULL) {
2264 fprintf(stderr, "ERROR: --watchmovie ('w') needs movie filename as option\n");
2265 exit(-1);
2267 strcpy(movieFileName, optarg);
2268 useMovie = 3;
2269 break;
2271 case 'P':
2272 #ifdef PROFILING
2273 if(optarg) {
2274 cpuEnableProfiling(atoi(optarg));
2275 } else
2276 cpuEnableProfiling(100);
2277 #endif
2278 break;
2279 case 'S':
2280 sdlFlashSize = atoi(optarg);
2281 if(sdlFlashSize < 0 || sdlFlashSize > 1)
2282 sdlFlashSize = 0;
2283 break;
2284 case 's':
2285 if(optarg) {
2286 int a = atoi(optarg);
2287 if(a >= 0 && a <= 9) {
2288 gbFrameSkip = a;
2289 frameSkip = a;
2291 } else {
2292 frameSkip = 2;
2293 gbFrameSkip = 0;
2295 break;
2296 case 't':
2297 if(optarg) {
2298 int a = atoi(optarg);
2299 if(a < 0 || a > 5)
2300 a = 0;
2301 cpuSaveType = a;
2303 break;
2304 case 'T':
2305 if(optarg) {
2306 int t = atoi(optarg);
2307 throttle = t;
2309 break;
2310 case 'v':
2311 if(optarg) {
2312 systemVerbose = atoi(optarg);
2313 } else
2314 systemVerbose = 0;
2315 break;
2316 case '1':
2317 sizeOption = 0;
2318 break;
2319 case '2':
2320 sizeOption = 1;
2321 break;
2322 case '3':
2323 sizeOption = 2;
2324 break;
2325 case '4':
2326 sizeOption = 3;
2327 break;
2328 case '?':
2329 sdlPrintUsage = 1;
2330 break;
2334 //printf("RLM: derpy loves you!\n");
2335 //printf("RLM: useMovie: %d (1 is record)\n", useMovie);
2336 if(sdlPrintUsage) {
2337 usage(argv[0]);
2338 exit(-1);
2341 #ifdef MMX
2342 if(disableMMX)
2343 cpu_mmx = 0;
2344 #endif
2346 if(rewindTimer)
2347 rewindMemory = (char *)malloc(8*REWIND_SIZE);
2349 if(sdlFlashSize == 0)
2350 flashSetSize(0x10000);
2351 else
2352 flashSetSize(0x20000);
2354 rtcEnable(sdlRtcEnable ? true : false);
2355 agbPrintEnable(sdlAgbPrint ? true : false);
2357 if(!debuggerStub) {
2358 if(optind >= argc) {
2359 systemMessage(0,"Missing image name");
2360 usage(argv[0]);
2361 exit(-1);
2365 if(filter) {
2366 sizeOption = 1;
2369 for(int i = 0; i < 24;) {
2370 systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10);
2371 systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10);
2372 systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10);
2373 systemGbPalette[i++] = 0;
2376 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
2378 if(optind < argc)
2380 szFile = argv[optind];
2381 file_run();
2382 //printf("RLM: file_run() done\n");
2384 else
2386 systemCartridgeType = 0;
2387 strcpy(filename, "gnu_stub");
2388 rom = (u8 *)malloc(0x2000000);
2389 workRAM = (u8 *)calloc(1, 0x40000);
2390 bios = (u8 *)calloc(1,0x4000);
2391 internalRAM = (u8 *)calloc(1,0x8000);
2392 paletteRAM = (u8 *)calloc(1,0x400);
2393 vram = (u8 *)calloc(1, 0x20000);
2394 oam = (u8 *)calloc(1, 0x400);
2395 pix = (u8 *)calloc(1, 4 * 240 * 160);
2396 ioMem = (u8 *)calloc(1, 0x400);
2398 theEmulator = GBASystem;
2400 //CPUInit(biosFileName, useBios);
2401 CPUInit();
2402 CPUReset();
2405 if(debuggerStub)
2406 remoteInit();
2408 int flags = SDL_INIT_VIDEO|SDL_INIT_AUDIO|
2409 SDL_INIT_TIMER|SDL_INIT_NOPARACHUTE;
2411 if(soundOffFlag)
2412 flags ^= SDL_INIT_AUDIO;
2414 if(SDL_Init(flags)) {
2415 systemMessage(0, "Failed to init SDL: %s", SDL_GetError());
2416 exit(-1);
2419 if(SDL_InitSubSystem(SDL_INIT_JOYSTICK)) {
2420 systemMessage(0, "Failed to init joystick support: %s", SDL_GetError());
2423 sdlCheckKeys();
2425 if(systemCartridgeType == 0) {
2426 srcWidth = 240;
2427 srcHeight = 160;
2428 systemFrameSkip = frameSkip;
2429 } else if (systemCartridgeType == 1) {
2430 if(gbBorderOn) {
2431 srcWidth = 256;
2432 srcHeight = 224;
2433 gbBorderLineSkip = 256;
2434 gbBorderColumnSkip = 48;
2435 gbBorderRowSkip = 40;
2436 } else {
2437 srcWidth = 160;
2438 srcHeight = 144;
2439 gbBorderLineSkip = 160;
2440 gbBorderColumnSkip = 0;
2441 gbBorderRowSkip = 0;
2443 systemFrameSkip = gbFrameSkip;
2444 } else {
2445 srcWidth = 320;
2446 srcHeight = 240;
2449 destWidth = (sizeOption+1)*srcWidth;
2450 destHeight = (sizeOption+1)*srcHeight;
2452 surface = SDL_SetVideoMode(destWidth, destHeight, 16,
2453 SDL_ANYFORMAT|SDL_HWSURFACE|SDL_DOUBLEBUF|
2454 (fullscreen ? SDL_FULLSCREEN : 0));
2456 if(surface == NULL) {
2457 systemMessage(0, "Failed to set video mode");
2458 SDL_Quit();
2459 exit(-1);
2462 systemRedShift = sdlCalculateShift(surface->format->Rmask);
2463 systemGreenShift = sdlCalculateShift(surface->format->Gmask);
2464 systemBlueShift = sdlCalculateShift(surface->format->Bmask);
2466 systemColorDepth = surface->format->BitsPerPixel;
2467 if(systemColorDepth == 15)
2468 systemColorDepth = 16;
2470 if(yuv) {
2471 Init_Overlay(surface, yuvType);
2472 systemColorDepth = 32;
2473 systemRedShift = 3;
2474 systemGreenShift = 11;
2475 systemBlueShift = 19;
2478 if(systemColorDepth != 16 && systemColorDepth != 24 &&
2479 systemColorDepth != 32) {
2480 fprintf(stderr,"Unsupported color depth '%d'.\nOnly 16, 24 and 32 bit color depths are supported\n", systemColorDepth);
2481 exit(-1);
2484 #ifndef C_CORE
2485 sdlMakeStretcher(srcWidth);
2486 #else
2487 switch(systemColorDepth) {
2488 case 16:
2489 sdlStretcher = sdlStretcher16[sizeOption];
2490 break;
2491 case 24:
2492 sdlStretcher = sdlStretcher24[sizeOption];
2493 break;
2494 case 32:
2495 sdlStretcher = sdlStretcher32[sizeOption];
2496 break;
2497 default:
2498 fprintf(stderr, "Unsupported resolution: %d\n", systemColorDepth);
2499 exit(-1);
2501 #endif
2503 fprintf(stderr,"Color depth: %d\n", systemColorDepth);
2505 if(systemColorDepth == 16) {
2506 if(sdlCalculateMaskWidth(surface->format->Gmask) == 6) {
2507 Init_2xSaI(565);
2508 RGB_LOW_BITS_MASK = 0x821;
2509 } else {
2510 Init_2xSaI(555);
2511 RGB_LOW_BITS_MASK = 0x421;
2513 if(systemCartridgeType == 2) {
2514 for(int i = 0; i < 0x10000; i++) {
2515 systemColorMap16[i] = (((i >> 1) & 0x1f) << systemBlueShift) |
2516 (((i & 0x7c0) >> 6) << systemGreenShift) |
2517 (((i & 0xf800) >> 11) << systemRedShift);
2519 } else {
2520 for(int i = 0; i < 0x10000; i++) {
2521 systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
2522 (((i & 0x3e0) >> 5) << systemGreenShift) |
2523 (((i & 0x7c00) >> 10) << systemBlueShift);
2526 srcPitch = srcWidth * 2+4;
2527 } else {
2528 if(systemColorDepth != 32)
2529 filterFunction = NULL;
2530 RGB_LOW_BITS_MASK = 0x010101;
2531 if(systemColorDepth == 32) {
2532 Init_2xSaI(32);
2534 for(int i = 0; i < 0x10000; i++) {
2535 systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
2536 (((i & 0x3e0) >> 5) << systemGreenShift) |
2537 (((i & 0x7c00) >> 10) << systemBlueShift);
2539 if(systemColorDepth == 32)
2540 srcPitch = srcWidth*4 + 4;
2541 else
2542 srcPitch = srcWidth*3;
2545 if(systemColorDepth != 32) {
2546 switch(filter) {
2547 case 0:
2548 filterFunction = NULL;
2549 break;
2550 case 1:
2551 filterFunction = ScanlinesTV;
2552 break;
2553 case 2:
2554 filterFunction = _2xSaI;
2555 break;
2556 case 3:
2557 filterFunction = Super2xSaI;
2558 break;
2559 case 4:
2560 filterFunction = SuperEagle;
2561 break;
2562 case 5:
2563 filterFunction = Pixelate2x16;
2564 break;
2565 case 6:
2566 filterFunction = MotionBlur;
2567 break;
2568 case 7:
2569 filterFunction = AdMame2x;
2570 break;
2571 case 8:
2572 filterFunction = Simple2x16;
2573 break;
2574 case 9:
2575 filterFunction = Bilinear;
2576 break;
2577 case 10:
2578 filterFunction = BilinearPlus;
2579 break;
2580 case 11:
2581 filterFunction = Scanlines;
2582 break;
2583 case 12:
2584 filterFunction = hq2x;
2585 break;
2586 case 13:
2587 filterFunction = lq2x;
2588 break;
2589 default:
2590 filterFunction = NULL;
2591 break;
2593 } else {
2594 switch(filter) {
2595 case 0:
2596 filterFunction = NULL;
2597 break;
2598 case 1:
2599 filterFunction = ScanlinesTV32;
2600 break;
2601 case 2:
2602 filterFunction = _2xSaI32;
2603 break;
2604 case 3:
2605 filterFunction = Super2xSaI32;
2606 break;
2607 case 4:
2608 filterFunction = SuperEagle32;
2609 break;
2610 case 5:
2611 filterFunction = Pixelate2x32;
2612 break;
2613 case 6:
2614 filterFunction = MotionBlur32;
2615 break;
2616 case 7:
2617 filterFunction = AdMame2x32;
2618 break;
2619 case 8:
2620 filterFunction = Simple2x32;
2621 break;
2622 case 9:
2623 filterFunction = Bilinear32;
2624 break;
2625 case 10:
2626 filterFunction = BilinearPlus32;
2627 break;
2628 case 11:
2629 filterFunction = Scanlines32;
2630 break;
2631 case 12:
2632 filterFunction = hq2x32;
2633 break;
2634 case 13:
2635 filterFunction = lq2x32;
2636 break;
2637 default:
2638 filterFunction = NULL;
2639 break;
2643 if(systemColorDepth == 16) {
2644 switch(ifbType) {
2645 case 0:
2646 default:
2647 ifbFunction = NULL;
2648 break;
2649 case 1:
2650 ifbFunction = MotionBlurIB;
2651 break;
2652 case 2:
2653 ifbFunction = SmartIB;
2654 break;
2656 } else if(systemColorDepth == 32) {
2657 switch(ifbType) {
2658 case 0:
2659 default:
2660 ifbFunction = NULL;
2661 break;
2662 case 1:
2663 ifbFunction = MotionBlurIB32;
2664 break;
2665 case 2:
2666 ifbFunction = SmartIB32;
2667 break;
2669 } else
2670 ifbFunction = NULL;
2672 if(delta == NULL) {
2673 delta = (u8*)malloc(322*242*4);
2674 memset(delta, 255, 322*242*4);
2677 if(!soundOffFlag)
2678 soundInit();
2680 autoFrameSkipLastTime = throttleLastTime = systemGetClock();
2681 //printf("RLM: and now for the movie part!\n");
2683 switch(useMovie)
2685 case 1: // --recordMovie
2686 VBAMovieCreate(movieFileName,
2687 /*authorInfo*/"",
2688 /*startFlags*/0,
2689 /*controllerFlags*/MOVIE_CONTROLLER(0),
2690 /*typeFlags*/(systemCartridgeType==IMAGE_GBA)?(MOVIE_TYPE_GBA):(GBC_CAPABLE?MOVIE_TYPE_GBC:MOVIE_TYPE_SGB));
2691 break;
2692 case 2: // --playMovie
2693 VBAMovieOpen(movieFileName, false);
2694 break;
2695 case 3: // --watchMovie
2696 VBAMovieOpen(movieFileName, true);
2697 break;
2698 default:
2699 sdlReadBattery();
2700 break;
2702 //printf("RLM: still alive after movie switch\n");
2703 SDL_WM_SetCaption("VisualBoyAdvance", NULL);
2705 char *moviefile = getenv("AUTODEMO");
2706 fprintf (stderr, "Checking for AUTODEMO...\n");
2707 if (moviefile)
2709 fprintf (stderr, "I got a filename OMG!\nCalling VBAMovieOpen...\n");
2710 VBAMovieOpen(moviefile, true);
2712 step();
2713 return 0;
2716 // RLM
2717 int runVBA(int argc, char **argv){
2718 return main(argc, argv);
2727 void systemMessage(int num, const char *msg, ...)
2729 char buffer[2048];
2730 va_list valist;
2732 va_start(valist, msg);
2733 vsprintf(buffer, msg, valist);
2735 fprintf(stderr, "%s\n", buffer);
2736 va_end(valist);
2739 //On WIN32, this function messages requesting
2740 //the window to be redrawn. Can this be ignored here?
2741 void systemRefreshScreen(){}
2743 void systemRenderFrame()
2745 renderedFrames++;
2746 VBAUpdateFrameCountDisplay();
2747 VBAUpdateButtonPressDisplay();
2749 if(yuv) {
2750 Draw_Overlay(surface, sizeOption+1);
2751 return;
2754 SDL_LockSurface(surface);
2756 for(int slot = 0 ; slot < 8 ; slot++)
2758 if(screenMessage[slot]) {
2759 if(systemCartridgeType == 1 && gbBorderOn) {
2760 gbSgbRenderBorder();
2762 if(((systemGetClock() - screenMessageTime[slot]) < screenMessageDuration[slot]) &&
2763 !disableStatusMessages) {
2764 drawText(pix, srcPitch, 10, srcHeight - 20*(slot+1),
2765 screenMessageBuffer[slot]);
2766 } else {
2767 screenMessage[slot] = false;
2772 if(ifbFunction) {
2773 if(systemColorDepth == 16)
2774 ifbFunction(pix+destWidth+4, destWidth+4, srcWidth, srcHeight);
2775 else
2776 ifbFunction(pix+destWidth*2+4, destWidth*2+4, srcWidth, srcHeight);
2779 if(filterFunction) {
2780 if(systemColorDepth == 16)
2781 filterFunction(pix+destWidth+4,destWidth+4, delta,
2782 (u8*)surface->pixels,surface->pitch,
2783 srcWidth,
2784 srcHeight);
2785 else
2786 filterFunction(pix+destWidth*2+4,
2787 destWidth*2+4,
2788 delta,
2789 (u8*)surface->pixels,
2790 surface->pitch,
2791 srcWidth,
2792 srcHeight);
2793 } else {
2794 int destPitch = surface->pitch;
2795 u8 *src = pix;
2796 u8 *dest = (u8*)surface->pixels;
2797 int i;
2798 u32 *stretcher = (u32 *)sdlStretcher;
2799 if(systemColorDepth == 16)
2800 src += srcPitch;
2801 int option = sizeOption;
2802 if(yuv)
2803 option = 0;
2804 switch(sizeOption) {
2805 case 0:
2806 for(i = 0; i < srcHeight; i++) {
2807 SDL_CALL_STRETCHER;
2808 src += srcPitch;
2809 dest += destPitch;
2811 break;
2812 case 1:
2813 for(i = 0; i < srcHeight; i++) {
2814 SDL_CALL_STRETCHER;
2815 dest += destPitch;
2816 SDL_CALL_STRETCHER;
2817 src += srcPitch;
2818 dest += destPitch;
2820 break;
2821 case 2:
2822 for(i = 0; i < srcHeight; i++) {
2823 SDL_CALL_STRETCHER;
2824 dest += destPitch;
2825 SDL_CALL_STRETCHER;
2826 dest += destPitch;
2827 SDL_CALL_STRETCHER;
2828 src += srcPitch;
2829 dest += destPitch;
2831 break;
2832 case 3:
2833 for(i = 0; i < srcHeight; i++) {
2834 SDL_CALL_STRETCHER;
2835 dest += destPitch;
2836 SDL_CALL_STRETCHER;
2837 dest += destPitch;
2838 SDL_CALL_STRETCHER;
2839 dest += destPitch;
2840 SDL_CALL_STRETCHER;
2841 src += srcPitch;
2842 dest += destPitch;
2844 break;
2848 if(showSpeed && fullscreen) {
2849 char buffer[50];
2850 if(showSpeed == 1)
2851 sprintf(buffer, "%d%%", systemSpeed);
2852 else
2853 sprintf(buffer, "%3d%%(%d, %d fps)", systemSpeed,
2854 systemFrameSkip,
2855 showRenderedFrames);
2856 if(showSpeedTransparent)
2857 drawTextTransp((u8*)surface->pixels,
2858 surface->pitch,
2859 10,
2860 surface->h-20,
2861 buffer);
2862 else
2863 drawText((u8*)surface->pixels,
2864 surface->pitch,
2865 10,
2866 surface->h-20,
2867 buffer);
2870 SDL_UnlockSurface(surface);
2871 // SDL_UpdateRect(surface, 0, 0, destWidth, destHeight);
2872 SDL_Flip(surface);
2875 bool systemReadJoypads()
2877 return true;
2880 // Kludge to make Lua call the right function.
2881 u32 systemGetOriginalJoypad(int which, bool sensor){
2882 return systemGetJoypad(which,sensor);
2885 u32 systemGetJoypad(int which, bool sensor)
2887 sensorOn = sensor;
2888 if(which < 0 || which > 3)
2889 which = sdlDefaultJoypad;
2891 //VBAMovieUpdate(which);
2892 //VBAMovieUpdateState();
2893 u32 res = 0;
2895 //----------------------------//
2896 if (VBAMoviePlaying()){
2897 // VBAMovieRead() overwrites currentButtons[i]
2898 VBAMovieRead(which, sensor);
2899 res = currentButtons[which];
2900 return res;
2902 //---------------------------//
2903 //Temporary implementation, not sure if it's correct --Felipe
2905 /*
2906 if(sdlButtons[which][KEY_BUTTON_A])
2907 res |= BUTTON_MASK_A;
2908 if(sdlButtons[which][KEY_BUTTON_B])
2909 res |= BUTTON_MASK_B;
2910 if(sdlButtons[which][KEY_BUTTON_SELECT])
2911 res |= BUTTON_MASK_SELECT;
2912 if(sdlButtons[which][KEY_BUTTON_START])
2913 res |= BUTTON_MASK_START;
2914 if(sdlButtons[which][KEY_RIGHT])
2915 res |= BUTTON_MASK_RIGHT;
2916 if(sdlButtons[which][KEY_LEFT])
2917 res |= BUTTON_MASK_LEFT;
2918 if(sdlButtons[which][KEY_UP])
2919 res |= BUTTON_MASK_UP;
2920 if(sdlButtons[which][KEY_DOWN])
2921 res |= BUTTON_MASK_DOWN;
2922 if(sdlButtons[which][KEY_BUTTON_R])
2923 res |= BUTTON_MASK_R;
2924 if(sdlButtons[which][KEY_BUTTON_L])
2925 res |= BUTTON_MASK_L;
2926 */
2927 /*
2928 // disallow L+R or U+D of being pressed at the same time
2929 if((res & 48) == 48)
2930 res &= ~16;
2931 if((res & 192) == 192)
2932 res &= ~128;
2933 */
2934 /*
2935 if(sdlbuttons[which][KEY_BUTTON_SPEED])
2936 res |= 1024;
2937 if(sdlButtons[which][KEY_BUTTON_CAPTURE])
2938 res |= 2048;
2939 */
2940 res = currentButtons[which];
2942 if(autoFire) {
2943 res &= (~autoFire);
2944 if(autoFireToggle)
2945 res |= autoFire;
2946 autoFireToggle = !autoFireToggle;
2949 //if (res) fprintf(stdout,"%x\n",res);
2951 return res;
2954 void systemSetJoypad(int which, u32 buttons)
2956 if(which < 0 || which > 3)
2957 which = sdlDefaultJoypad;
2958 /*
2959 sdlButtons[which][KEY_BUTTON_A] = (buttons & 1) != 0;
2960 sdlButtons[which][KEY_BUTTON_B] = (buttons & 2) != 0;
2961 sdlButtons[which][KEY_BUTTON_SELECT] = (buttons & 4) != 0;
2962 sdlButtons[which][KEY_BUTTON_START] = (buttons & 8) != 0;
2963 sdlButtons[which][KEY_RIGHT] = (buttons & 16) != 0;
2964 sdlButtons[which][KEY_LEFT] = (buttons & 32) != 0;
2965 sdlButtons[which][KEY_UP] = (buttons & 64) != 0;
2966 sdlButtons[which][KEY_DOWN] = (buttons & 128) != 0;
2967 sdlButtons[which][KEY_BUTTON_R] = (buttons & 256) != 0;
2968 sdlButtons[which][KEY_BUTTON_L] = (buttons & 512) != 0;
2969 */
2970 currentButtons[which]= buttons & 0x3ff;
2973 void systemClearJoypads()
2975 for (int i = 0; i < 4; ++i)
2976 currentButtons[i] = 0;
2978 //lastKeys = 0;
2981 void systemSetTitle(const char *title)
2983 SDL_WM_SetCaption(title, NULL);
2986 void systemShowSpeed(int speed)
2988 systemSpeed = speed;
2990 showRenderedFrames = renderedFrames;
2991 renderedFrames = 0;
2993 if(!fullscreen && showSpeed) {
2994 char buffer[80];
2995 if(showSpeed == 1)
2996 sprintf(buffer, "VisualBoyAdvance-%3d%%", systemSpeed);
2997 else
2998 sprintf(buffer, "VisualBoyAdvance-%3d%%(%d, %d fps)", systemSpeed,
2999 systemFrameSkip,
3000 showRenderedFrames);
3002 systemSetTitle(buffer);
3006 // FIXME: the timing
3007 void systemFrame(/*int rate*/) //Looking at System.cpp, it looks like rate should be 600
3009 u32 time = systemGetClock();
3010 if(!wasPaused && autoFrameSkip && !throttle) {
3011 u32 diff = time - autoFrameSkipLastTime;
3012 int speed = 100;
3014 if(diff)
3015 speed = (1000000/600)/diff;
3017 if(speed >= 98) {
3018 frameskipadjust++;
3020 if(frameskipadjust >= 3) {
3021 frameskipadjust=0;
3022 if(systemFrameSkip > 0)
3023 systemFrameSkip--;
3025 } else {
3026 if(speed < 80)
3027 frameskipadjust -= (90 - speed)/5;
3028 else if(systemFrameSkip < 9)
3029 frameskipadjust--;
3031 if(frameskipadjust <= -2) {
3032 frameskipadjust += 2;
3033 if(systemFrameSkip < 9)
3034 systemFrameSkip++;
3038 if(!wasPaused && throttle) {
3039 /*if(!speedup) {
3040 u32 diff = time - throttleLastTime;
3042 int target = (1000000.0/(600*throttle));
3043 int d = (target - diff);
3045 if(d > 0) {
3046 SDL_Delay(d);
3049 throttleLastTime = systemGetClock();
3050 */
3052 if(rewindMemory) {
3053 if(++rewindCounter >= rewindTimer) {
3054 rewindSaveNeeded = true;
3055 rewindCounter = 0;
3059 if(systemSaveUpdateCounter) {
3060 if(--systemSaveUpdateCounter <= SYSTEM_SAVE_NOT_UPDATED) {
3061 sdlWriteBattery();
3062 systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
3066 wasPaused = false;
3067 autoFrameSkipLastTime = time;
3070 int systemFramesToSkip(){
3071 return systemFrameSkip;
3074 int systemScreenCapture(int a)
3076 char buffer[2048];
3078 if(captureFormat) {
3079 if(captureDir[0])
3080 sprintf(buffer, "%s/%s%02d.bmp", captureDir, sdlGetFilename(filename), a);
3081 else
3082 sprintf(buffer, "%s%02d.bmp", filename, a);
3084 theEmulator.emuWriteBMP(buffer);
3085 } else {
3086 if(captureDir[0])
3087 sprintf(buffer, "%s/%s%02d.png", captureDir, sdlGetFilename(filename), a);
3088 else
3089 sprintf(buffer, "%s%02d.png", filename, a);
3090 theEmulator.emuWritePNG(buffer);
3093 systemScreenMessage("Screen capture");
3094 return a;
3097 void soundCallback(void *,u8 *stream,int len){}
3099 void systemSoundWriteToBuffer(){
3100 soundDriver->write(soundFinalWave, soundBufferLen);
3103 void systemSoundClearBuffer()
3105 SDL_mutexP(mutex);
3106 memset(sdlBuffer,0,soundBufferTotalLen);
3107 sdlSoundLen=0;
3108 printf("Hi\n");
3109 SDL_mutexV(mutex);
3112 bool systemSoundInit(){
3113 systemSoundShutdown();
3114 soundDriver = new SoundSDL();
3115 if ( !soundDriver )
3116 return false;
3118 if (!soundDriver->init()) //<-- sound sample rate
3119 return false;
3121 if (!(soundDriver->setThrottle(throttle))){
3122 fprintf(stderr,"Failed to set desired throttle, defaulting to 100 %%.\n");
3123 if (!soundDriver->setThrottle(100)) return false;
3125 soundPaused = true;
3126 systemSoundOn = true;
3127 return true;
3130 void systemSoundShutdown(){
3131 if (soundDriver)
3133 delete soundDriver;
3134 soundDriver = 0;
3138 void systemSoundPause()
3140 SDL_PauseAudio(1);
3143 void systemSoundResume()
3145 SDL_PauseAudio(0);
3148 void systemSoundReset()
3152 u32 systemGetClock()
3154 return SDL_GetTicks();
3157 void systemUpdateMotionSensor()
3159 if(sdlMotionButtons[KEY_LEFT]) {
3160 sensorX += 3;
3161 if(sensorX > 2197)
3162 sensorX = 2197;
3163 if(sensorX < 2047)
3164 sensorX = 2057;
3165 } else if(sdlMotionButtons[KEY_RIGHT]) {
3166 sensorX -= 3;
3167 if(sensorX < 1897)
3168 sensorX = 1897;
3169 if(sensorX > 2047)
3170 sensorX = 2037;
3171 } else if(sensorX > 2047) {
3172 sensorX -= 2;
3173 if(sensorX < 2047)
3174 sensorX = 2047;
3175 } else {
3176 sensorX += 2;
3177 if(sensorX > 2047)
3178 sensorX = 2047;
3181 if(sdlMotionButtons[KEY_UP]) {
3182 sensorY += 3;
3183 if(sensorY > 2197)
3184 sensorY = 2197;
3185 if(sensorY < 2047)
3186 sensorY = 2057;
3187 } else if(sdlMotionButtons[KEY_DOWN]) {
3188 sensorY -= 3;
3189 if(sensorY < 1897)
3190 sensorY = 1897;
3191 if(sensorY > 2047)
3192 sensorY = 2037;
3193 } else if(sensorY > 2047) {
3194 sensorY -= 2;
3195 if(sensorY < 2047)
3196 sensorY = 2047;
3197 } else {
3198 sensorY += 2;
3199 if(sensorY > 2047)
3200 sensorY = 2047;
3204 void systemResetSensor()
3206 sensorX = sensorY = INITIAL_SENSOR_VALUE;
3209 int systemGetSensorX()
3211 return sensorX;
3214 int systemGetSensorY()
3216 return sensorY;
3219 void systemGbPrint(u8 *data,int pages,int feed,int palette, int contrast)
3223 void systemScreenMessage(const char *msg, int slot, int duration, const char *colorList)
3225 screenMessage[slot] = true;
3226 screenMessageTime[slot] = systemGetClock();
3227 screenMessageDuration[slot] = duration;
3228 if(strlen(msg) > 20) {
3229 strncpy(screenMessageBuffer[slot], msg, 20);
3230 screenMessageBuffer[slot][20] = 0;
3231 } else
3232 strcpy(screenMessageBuffer[slot], msg);
3235 bool systemSoundCanChangeQuality()
3237 return false;
3240 bool systemSoundSetQuality(int quality)
3242 if (systemCartridgeType == 0)
3243 soundSetQuality(quality);
3244 else
3245 gbSoundSetQuality(quality);
3247 return true;
3250 bool systemPauseOnFrame()
3252 if(pauseNextFrame) {
3253 paused = true;
3254 pauseNextFrame = false;
3255 return true;
3257 return false;
3260 // Code donated by Niels Wagenaar (BoycottAdvance)
3262 // GBA screensize.
3263 #define GBA_WIDTH 240
3264 #define GBA_HEIGHT 160
3266 void Init_Overlay(SDL_Surface *gbascreen, int overlaytype)
3269 overlay = SDL_CreateYUVOverlay( GBA_WIDTH,
3270 GBA_HEIGHT,
3271 overlaytype, gbascreen);
3272 fprintf(stderr, "Created %dx%dx%d %s %s overlay\n",
3273 overlay->w,overlay->h,overlay->planes,
3274 overlay->hw_overlay?"hardware":"software",
3275 overlay->format==SDL_YV12_OVERLAY?"YV12":
3276 overlay->format==SDL_IYUV_OVERLAY?"IYUV":
3277 overlay->format==SDL_YUY2_OVERLAY?"YUY2":
3278 overlay->format==SDL_UYVY_OVERLAY?"UYVY":
3279 overlay->format==SDL_YVYU_OVERLAY?"YVYU":
3280 "Unknown");
3283 void Quit_Overlay(void)
3286 SDL_FreeYUVOverlay(overlay);
3289 /* NOTE: These RGB conversion functions are not intended for speed,
3290 only as examples.
3291 */
3292 inline void RGBtoYUV(Uint8 *rgb, int *yuv)
3294 yuv[0] = (int)((0.257 * rgb[0]) + (0.504 * rgb[1]) + (0.098 * rgb[2]) + 16);
3295 yuv[1] = (int)(128 - (0.148 * rgb[0]) - (0.291 * rgb[1]) + (0.439 * rgb[2]));
3296 yuv[2] = (int)(128 + (0.439 * rgb[0]) - (0.368 * rgb[1]) - (0.071 * rgb[2]));
3299 inline void ConvertRGBtoYV12(SDL_Overlay *o)
3301 int x,y;
3302 int yuv[3];
3303 Uint8 *p,*op[3];
3305 SDL_LockYUVOverlay(o);
3307 /* Black initialization */
3308 /*
3309 memset(o->pixels[0],0,o->pitches[0]*o->h);
3310 memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2));
3311 memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2));
3312 */
3314 /* Convert */
3315 for(y=0; y<160 && y<o->h; y++) {
3316 p=(Uint8 *)pix+srcPitch*y;
3317 op[0]=o->pixels[0]+o->pitches[0]*y;
3318 op[1]=o->pixels[1]+o->pitches[1]*(y/2);
3319 op[2]=o->pixels[2]+o->pitches[2]*(y/2);
3320 for(x=0; x<240 && x<o->w; x++) {
3321 RGBtoYUV(p,yuv);
3322 *(op[0]++)=yuv[0];
3323 if(x%2==0 && y%2==0) {
3324 *(op[1]++)=yuv[2];
3325 *(op[2]++)=yuv[1];
3327 p+=4;//s->format->BytesPerPixel;
3331 SDL_UnlockYUVOverlay(o);
3334 inline void ConvertRGBtoIYUV(SDL_Overlay *o)
3336 int x,y;
3337 int yuv[3];
3338 Uint8 *p,*op[3];
3340 SDL_LockYUVOverlay(o);
3342 /* Black initialization */
3343 /*
3344 memset(o->pixels[0],0,o->pitches[0]*o->h);
3345 memset(o->pixels[1],128,o->pitches[1]*((o->h+1)/2));
3346 memset(o->pixels[2],128,o->pitches[2]*((o->h+1)/2));
3347 */
3349 /* Convert */
3350 for(y=0; y<160 && y<o->h; y++) {
3351 p=(Uint8 *)pix+srcPitch*y;
3352 op[0]=o->pixels[0]+o->pitches[0]*y;
3353 op[1]=o->pixels[1]+o->pitches[1]*(y/2);
3354 op[2]=o->pixels[2]+o->pitches[2]*(y/2);
3355 for(x=0; x<240 && x<o->w; x++) {
3356 RGBtoYUV(p,yuv);
3357 *(op[0]++)=yuv[0];
3358 if(x%2==0 && y%2==0) {
3359 *(op[1]++)=yuv[1];
3360 *(op[2]++)=yuv[2];
3362 p+=4; //s->format->BytesPerPixel;
3366 SDL_UnlockYUVOverlay(o);
3369 inline void ConvertRGBtoUYVY(SDL_Overlay *o)
3371 int x,y;
3372 int yuv[3];
3373 Uint8 *p,*op;
3375 SDL_LockYUVOverlay(o);
3377 for(y=0; y<160 && y<o->h; y++) {
3378 p=(Uint8 *)pix+srcPitch*y;
3379 op=o->pixels[0]+o->pitches[0]*y;
3380 for(x=0; x<240 && x<o->w; x++) {
3381 RGBtoYUV(p,yuv);
3382 if(x%2==0) {
3383 *(op++)=yuv[1];
3384 *(op++)=yuv[0];
3385 *(op++)=yuv[2];
3386 } else
3387 *(op++)=yuv[0];
3389 p+=4; //s->format->BytesPerPixel;
3393 SDL_UnlockYUVOverlay(o);
3396 inline void ConvertRGBtoYVYU(SDL_Overlay *o)
3398 int x,y;
3399 int yuv[3];
3400 Uint8 *p,*op;
3402 SDL_LockYUVOverlay(o);
3404 for(y=0; y<160 && y<o->h; y++) {
3405 p=(Uint8 *)pix+srcPitch*y;
3406 op=o->pixels[0]+o->pitches[0]*y;
3407 for(x=0; x<240 && x<o->w; x++) {
3408 RGBtoYUV(p,yuv);
3409 if(x%2==0) {
3410 *(op++)=yuv[0];
3411 *(op++)=yuv[2];
3412 op[1]=yuv[1];
3413 } else {
3414 *op=yuv[0];
3415 op+=2;
3418 p+=4; //s->format->BytesPerPixel;
3422 SDL_UnlockYUVOverlay(o);
3425 inline void ConvertRGBtoYUY2(SDL_Overlay *o)
3427 int x,y;
3428 int yuv[3];
3429 Uint8 *p,*op;
3431 SDL_LockYUVOverlay(o);
3433 for(y=0; y<160 && y<o->h; y++) {
3434 p=(Uint8 *)pix+srcPitch*y;
3435 op=o->pixels[0]+o->pitches[0]*y;
3436 for(x=0; x<240 && x<o->w; x++) {
3437 RGBtoYUV(p,yuv);
3438 if(x%2==0) {
3439 *(op++)=yuv[0];
3440 *(op++)=yuv[1];
3441 op[1]=yuv[2];
3442 } else {
3443 *op=yuv[0];
3444 op+=2;
3447 p+=4; //s->format->BytesPerPixel;
3451 SDL_UnlockYUVOverlay(o);
3454 inline void Convert32bit(SDL_Surface *display)
3456 switch(overlay->format) {
3457 case SDL_YV12_OVERLAY:
3458 ConvertRGBtoYV12(overlay);
3459 break;
3460 case SDL_UYVY_OVERLAY:
3461 ConvertRGBtoUYVY(overlay);
3462 break;
3463 case SDL_YVYU_OVERLAY:
3464 ConvertRGBtoYVYU(overlay);
3465 break;
3466 case SDL_YUY2_OVERLAY:
3467 ConvertRGBtoYUY2(overlay);
3468 break;
3469 case SDL_IYUV_OVERLAY:
3470 ConvertRGBtoIYUV(overlay);
3471 break;
3472 default:
3473 fprintf(stderr, "cannot convert RGB picture to obtained YUV format!\n");
3474 exit(1);
3475 break;
3481 inline void Draw_Overlay(SDL_Surface *display, int size)
3483 SDL_LockYUVOverlay(overlay);
3485 Convert32bit(display);
3487 overlay_rect.x = 0;
3488 overlay_rect.y = 0;
3489 overlay_rect.w = GBA_WIDTH * size;
3490 overlay_rect.h = GBA_HEIGHT * size;
3492 SDL_DisplayYUVOverlay(overlay, &overlay_rect);
3493 SDL_UnlockYUVOverlay(overlay);
3496 bool systemIsEmulating()
3498 return emulating != 0;
3501 void systemGbBorderOn()
3503 srcWidth = 256;
3504 srcHeight = 224;
3505 gbBorderLineSkip = 256;
3506 gbBorderColumnSkip = 48;
3507 gbBorderRowSkip = 40;
3509 destWidth = (sizeOption+1)*srcWidth;
3510 destHeight = (sizeOption+1)*srcHeight;
3512 surface = SDL_SetVideoMode(destWidth, destHeight, 16,
3513 SDL_ANYFORMAT|SDL_HWSURFACE|SDL_DOUBLEBUF|
3514 (fullscreen ? SDL_FULLSCREEN : 0));
3515 #ifndef C_CORE
3516 sdlMakeStretcher(srcWidth);
3517 #else
3518 switch(systemColorDepth) {
3519 case 16:
3520 sdlStretcher = sdlStretcher16[sizeOption];
3521 break;
3522 case 24:
3523 sdlStretcher = sdlStretcher24[sizeOption];
3524 break;
3525 case 32:
3526 sdlStretcher = sdlStretcher32[sizeOption];
3527 break;
3528 default:
3529 fprintf(stderr, "Unsupported resolution: %d\n", systemColorDepth);
3530 exit(-1);
3532 #endif
3534 if(systemColorDepth == 16) {
3535 if(sdlCalculateMaskWidth(surface->format->Gmask) == 6) {
3536 Init_2xSaI(565);
3537 RGB_LOW_BITS_MASK = 0x821;
3538 } else {
3539 Init_2xSaI(555);
3540 RGB_LOW_BITS_MASK = 0x421;
3542 if(systemCartridgeType == 2) {
3543 for(int i = 0; i < 0x10000; i++) {
3544 systemColorMap16[i] = (((i >> 1) & 0x1f) << systemBlueShift) |
3545 (((i & 0x7c0) >> 6) << systemGreenShift) |
3546 (((i & 0xf800) >> 11) << systemRedShift);
3548 } else {
3549 for(int i = 0; i < 0x10000; i++) {
3550 systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
3551 (((i & 0x3e0) >> 5) << systemGreenShift) |
3552 (((i & 0x7c00) >> 10) << systemBlueShift);
3555 srcPitch = srcWidth * 2+4;
3556 } else {
3557 if(systemColorDepth != 32)
3558 filterFunction = NULL;
3559 RGB_LOW_BITS_MASK = 0x010101;
3560 if(systemColorDepth == 32) {
3561 Init_2xSaI(32);
3563 for(int i = 0; i < 0x10000; i++) {
3564 systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
3565 (((i & 0x3e0) >> 5) << systemGreenShift) |
3566 (((i & 0x7c00) >> 10) << systemBlueShift);
3568 if(systemColorDepth == 32)
3569 srcPitch = srcWidth*4 + 4;
3570 else
3571 srcPitch = srcWidth*3;
3575 bool systemIsRunningGBA()
3577 return (rom != NULL);
3580 int systemGetDefaultJoypad()
3582 return sdlDefaultJoypad;
3585 bool systemIsPaused()
3587 return paused;
3590 void systemSetPause(bool pause)
3592 paused = pause;
3593 if (pause)
3594 systemSoundPause();
3595 else
3596 systemSoundResume();
3599 u16 checksumBIOS()
3601 bool hasBIOS = false;
3602 u8 * tempBIOS;
3603 if(useBios)
3605 tempBIOS = (u8 *)malloc(0x4000);
3606 int size = 0x4000;
3607 if(utilLoad(biosFileName,
3608 utilIsGBABios,
3609 tempBIOS,
3610 size)) {
3611 if(size == 0x4000)
3612 hasBIOS = true;
3616 u16 biosCheck = 0;
3617 if(hasBIOS) {
3618 for(int i = 0; i < 0x4000; i += 4)
3619 biosCheck += *((u32 *)&tempBIOS[i]);
3620 free(tempBIOS);
3623 return biosCheck;
3626 EmulatedSystemCounters systemCounters = {
3627 0, //framecount
3628 0, //lagcount
3629 0, //extracount
3630 true, //lagged
3631 true //laggedLast
3632 };
3634 void VBAOnEnteringFrameBoundary()
3636 //printf("RLM: Entering Frame Boundary\n");
3637 CallRegisteredLuaFunctions(LUACALL_AFTEREMULATION);
3639 if (VBALuaRunning())
3641 VBALuaFrameBoundary();
3644 //printf("RLM: Movie state update pending\n");
3645 VBAMovieUpdateState();
3646 //printf("RLM: Movie state updated\n");
3649 void VBAOnExitingFrameBoundary()