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