merging changes from Zopenko, libertyernie, Glitch, cebolleto, and
others
4
Makefile
@ -1,8 +1,8 @@
|
||||
.PHONY = all wii gc wii-clean gc-clean wii-run gc-run
|
||||
|
||||
all: wii gc
|
||||
all: wii
|
||||
|
||||
clean: wii-clean gc-clean
|
||||
clean: wii-clean
|
||||
|
||||
run: wii-run
|
||||
|
||||
|
@ -21,7 +21,7 @@ BUILD := build_gc
|
||||
SOURCES := source source/images source/sounds source/fonts source/lang \
|
||||
source/gui source/utils source/utils/sz \
|
||||
source/vba source/vba/apu source/vba/common \
|
||||
source/vba/gb source/vba/gba
|
||||
source/vba/gb source/vba/gba source/goomba source/goomba/minilzo-2.06
|
||||
INCLUDES := source source/vba
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
@ -29,7 +29,8 @@ INCLUDES := source source/vba
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
CFLAGS = -g -O3 -Wall $(MACHDEP) $(INCLUDE) \
|
||||
-DNO_SOUND -DUSE_VM -DWORDS_BIGENDIAN \
|
||||
-DNO_SOUND -DUSE_VM -DWORDS_BIGENDIAN -DNO_LINK -DNO_FEX \
|
||||
-DTILED_RENDERING \
|
||||
-DC_CORE -D__ppc__ -D__POWERPC__ -DFINAL_VERSION \
|
||||
-DSDL -DNO_PNG -DHAVE_ZUTIL_H \
|
||||
-D_SZ_ONE_DIRECTORY -D_LZMA_IN_CB -D_LZMA_OUT_READ \
|
||||
|
@ -21,7 +21,7 @@ BUILD := build_wii
|
||||
SOURCES := source source/images source/sounds source/fonts source/lang \
|
||||
source/gui source/utils source/utils/sz source/utils/unzip \
|
||||
source/vba source/vba/apu source/vba/common \
|
||||
source/vba/gb source/vba/gba
|
||||
source/vba/gb source/vba/gba source/goomba source/goomba/minilzo-2.06
|
||||
INCLUDES := source source/vba
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
@ -29,19 +29,20 @@ INCLUDES := source source/vba
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
CFLAGS = -g -O3 -Wall $(MACHDEP) $(INCLUDE) \
|
||||
-DWORDS_BIGENDIAN \
|
||||
-DWORDS_BIGENDIAN -DNO_LINK -DNO_FEX \
|
||||
-DTILED_RENDERING \
|
||||
-DC_CORE -D__ppc__ -D__POWERPC__ -DFINAL_VERSION \
|
||||
-DSDL -DNO_PNG -DHAVE_ZUTIL_H \
|
||||
-D_SZ_ONE_DIRECTORY -D_LZMA_IN_CB -D_LZMA_OUT_READ \
|
||||
-fomit-frame-pointer \
|
||||
-Wno-unused-parameter -Wno-strict-aliasing -Wno-parentheses
|
||||
CXXFLAGS = $(CFLAGS)
|
||||
LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map
|
||||
LDFLAGS = -g $(MACHDEP) -Wl,-Map,$(notdir $@).map,-wrap,wiiuse_register
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# any extra libraries we wish to link with
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBS := -ldi -liso9660 -lpng -lmxml -lfat -lwiiuse -lz -lbte -lasnd -logc \
|
||||
LIBS := -ldi -liso9660 -lpng -lmxml -lfat -lwiiuse -lwupc -lz -lbte -lasnd -logc \
|
||||
-lvorbisidec -lfreetype -ltinysmb
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
191
readme.txt
@ -1,8 +1,8 @@
|
||||
¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤
|
||||
|
||||
- Visual Boy Advance GX -
|
||||
http://code.google.com/p/vba-wii
|
||||
(Under GPL License)
|
||||
- Visual Boy Advance GX -
|
||||
https://github.com/dborth/vba-wii
|
||||
(Under GPL License)
|
||||
|
||||
¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤
|
||||
|
||||
@ -18,15 +18,86 @@ With it you can play GBA/Game Boy Color/Game Boy games on your Wii/GameCube.
|
||||
* IPS/UPS patch support
|
||||
* Custom controller configurations
|
||||
* SD, USB, DVD, SMB, Zip, and 7z support
|
||||
* Compatibility based on VBA-M r927
|
||||
* Compatibility based on VBA-M r1231
|
||||
* MEM2 ROM Storage for fast access
|
||||
* Auto frame skip for those core heavy games
|
||||
* Auto frame skip (optional) for those core heavy games
|
||||
* Turbo speed, video zooming, widescreen, and unfiltered video options
|
||||
* Native loading/saving of ROMS and SRAM from Goomba (a GB emulator for GBA)
|
||||
* Improved video rendering from RetroArch
|
||||
* Screenshots can be displayed on the main menu
|
||||
* Fixed pixel ratio mode (1x, 2x, and 3x)
|
||||
* Borders (from Super Game Boy games or custom from .png)
|
||||
* Wii U Pro Controller support
|
||||
* 240p support
|
||||
|
||||
×—–—–—–—– –—–—–—–—–—–—–—–—–—–— —–—–—–—–—–—–—–—-—–-–•¬
|
||||
|0O×øo· UPDATE HISTORY ·oø×O0|
|
||||
`¨•¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨ ¨¨¨¨¨¨¨¨¨¨¨¨¨'
|
||||
|
||||
[2.3.3] - Zopenko
|
||||
|
||||
* fixes the gc pad down on file browser
|
||||
* added koston default green gb color screen
|
||||
* added the screenshot/preview button
|
||||
* added the wiiupro icon on the controller settings
|
||||
* increased and centered the screenshot image
|
||||
* added the screenshot white image background
|
||||
|
||||
[2.3.2 - March 4, 2015] - libertyernie
|
||||
|
||||
* Wii U: if widescreen is enabled in the Wii U setting, VBA GX will use a 16:9
|
||||
aspect ratio, except while playing a game with fixed pixel mode turned on
|
||||
* There are now three options for border in the emulation settings menu (see
|
||||
"Super Game Boy borders" section for details)
|
||||
* PNG borders now supported for GBA games
|
||||
* Video mode "PAL (50Hz)" renamed to "PAL (576i)"
|
||||
* Video mode "PAL (60Hz)" renamed to "European RGB (480i)"
|
||||
* 240p support added (NTSC and European RGB modes)
|
||||
* All video modes now use a width of 704 for the best pixel aspect ratio
|
||||
|
||||
[2.3.1b - November 8, 2014] - Glitch
|
||||
|
||||
* Added FIX94's libwupc for WiiU Pro Controllers
|
||||
* Added tueidj's vWii Widescreen Fix
|
||||
|
||||
[2.3.1 - October 14, 2014] - libertyernie
|
||||
|
||||
* Super Game Boy border support
|
||||
* Borders can be loaded from (and are automatically saved to) PNG files
|
||||
* Any border loaded from the game itself will override the custom PNG border
|
||||
* Custom palette support from 2.2.8 restored
|
||||
* Option added to select Game Boy hardware (GB/SGB/GBC/auto)
|
||||
* Fixed pixel ratio mode added
|
||||
* Overrides zoom and aspect ratio settings
|
||||
* To squish the picture so it appears correctly on a 16:9 TV, you can open
|
||||
the settings.xml file and add 10 to the gbFixed/gbaFixed value. However,
|
||||
setting your TV to 4:3 mode will yield a better picture.
|
||||
* Real-time clock fixes for GB/GBC games, including Pokémon G/S/C
|
||||
* RTC data in save file stored as little-endian
|
||||
* Option added for UTC offset in the main menu (only required if you use the
|
||||
same SRAM on other, time-zone-aware platforms)
|
||||
* New option for selecting "sharp" or "soft" filtering settings
|
||||
* "Sharp" was the default for 480p, "soft" was the default for 480i
|
||||
|
||||
[2.3.0 - September 10, 2014] - libertyernie
|
||||
|
||||
* VBA-M core updated to r1231
|
||||
* Tiled rendering used for GBA games (new VBA-M feature, originally from
|
||||
RetroArch) - provides a major speed boost!
|
||||
* Changes from cebolleto's version
|
||||
* Screenshots can be displayed for each game on the menu
|
||||
* Nicer 7-Zip support
|
||||
* When you leave a folder, the folder you just left will be selected
|
||||
* New options available:
|
||||
* Disable the " Auto" string being appended to save files
|
||||
* Disable frameskip entirely on GBA
|
||||
* Keyboard fixed (from libwiigui r56)
|
||||
* GUI prompt is now purple instead of green (button colors more intuitive)
|
||||
* Goomba and Goomba Color ROM support:
|
||||
* Any Game Boy ROM stored within a Goomba ROM can be loaded "natively" in
|
||||
the Game Boy (Color) emulator (or the Goomba ROM can be loaded as GBA)
|
||||
* Game Boy SRAM stored within Goomba SRAM is loaded and saved correctly
|
||||
|
||||
[2.2.8 - July 29, 2012]
|
||||
|
||||
* Fixed lag with GameCube controllers
|
||||
@ -508,9 +579,8 @@ Z = Gameboy A Button
|
||||
C = Gameboy B Button
|
||||
|
||||
Classic Controller:
|
||||
Use the buttons as labelled.
|
||||
A = Gameboy A Button
|
||||
B = Gameboy B Button
|
||||
B = Gameboy A Button
|
||||
Y = Gameboy B Button
|
||||
R = Gameboy R Button
|
||||
L = Gameboy L Button
|
||||
|
||||
@ -535,6 +605,43 @@ to the main menu and B again to return to the game.
|
||||
A+B, Spacebar, or right analog stick: fast forward
|
||||
Right analog stick: zoom (if enabled)
|
||||
|
||||
-=[ Super Game Boy borders ]=-
|
||||
|
||||
VBA-GX has supported Super Game Boy borders since 2.3.1. You can enable this
|
||||
feature in the Emulation settings on the main menu.
|
||||
|
||||
Borders can be loaded from two locations:
|
||||
* PNG files in the borders folder (by default, /vbagx/borders)
|
||||
* The game itself
|
||||
|
||||
Borders will only be loaded from the game itself when the emulator is running
|
||||
in Super Game Boy mode, and the border setting in Emulation settings is set to
|
||||
"From game (SGB only)". (You can also use the Emulation settings menu to
|
||||
force SGB mode even for Game Boy Color games.) If the borders folder exists,
|
||||
but no border for the game is present, the loaded Super Game Boy border will
|
||||
be written to a .png file, which can be loaded later in "From .png file" mode.
|
||||
|
||||
In addition, if the borders folder exists but there is no border for the game,
|
||||
the first border loaded from the game will be written to a PNG file so it can
|
||||
be loaded in the future (even in Game Boy Color mode.) This means after you
|
||||
run a game once in SGB mode, you can then use the same border in GBC mode.
|
||||
|
||||
If the border setting is set to "From .png file", borders will be loaded
|
||||
from the borders folder. Borders can be up to 640x480 and will work for both
|
||||
Game Boy (Color) and Game Boy Advance games.
|
||||
|
||||
For both loading and saving, the PNG filename is [TITLE].png, where [TITLE]
|
||||
is the ROM title defined at 0x134 (for GB games) or 0xA0 (for GBA games). For
|
||||
example, POKEMON_SFXAAXE.png will be loaded for Pokémon Silver. If no PNG file
|
||||
by that name exists, VBA-GX will try loading default.png (for GB games) or
|
||||
defaultgba.png (for GBA games) instead.
|
||||
|
||||
Since the borders are rendered along with the video output of the game, the
|
||||
pixels in the border will be the same size as game pixels. This means that
|
||||
a Game Boy game will appear in the middle 160x144 pixels of the border, and a
|
||||
Game Boy Advance game will appear in the middle 240x160 pixels, regardless of
|
||||
the resolution of the border PNG image.
|
||||
|
||||
-=[ Match Wii Controls ]=-
|
||||
|
||||
Special Wii controls exist for the following games:
|
||||
@ -577,8 +684,8 @@ Medal Of Honour Underground, Medal Of Honour Infiltrator
|
||||
|
||||
One Piece can be played with One Piece Unlimited Adventure controls.
|
||||
|
||||
Boktai 1, Boktai 2, Boktai 3, Kirby's Tilt n Tumble, and WarioWare Twisted
|
||||
can be played with controls I designed for them.
|
||||
Boktai 1, Boktai 2, Boktai 3, and Kirby's Tilt n Tumble can be played with
|
||||
controls designed for them.
|
||||
|
||||
-=[ Zelda, Match Wii Controls ]=-
|
||||
|
||||
@ -740,8 +847,11 @@ A = spin attack
|
||||
X/Y = shoot, run, hold on to things, yoshi's tongue, etc.
|
||||
ZL or sometimes L = crouch or lay egg. Press in the air to butt stomp.
|
||||
+ = pause
|
||||
L/R sometimes look around
|
||||
L/R = look around (if the game supports it)
|
||||
ZR = fast forward (8-bit Game Boy only)
|
||||
|
||||
In Super Mario World and Super Mario Land 2, you can use the A or R
|
||||
buttons for a spin jump.
|
||||
|
||||
-=[ Yoshi's Universal Gravitation (Topsy Turvy), Match Wii Controls ]=-
|
||||
|
||||
@ -834,20 +944,9 @@ Z or 1 = change element, or change subscreen (L)
|
||||
|
||||
-=[ WarioWare Twisted, Match Wii Controls ]=-
|
||||
|
||||
Turn "Match Wii Controls" ON to use these controls.
|
||||
|
||||
WarioWare Twisted uses similar controls to the Gameboy game.
|
||||
|
||||
The Wii WarioWare Twisted controls are:
|
||||
=======================================
|
||||
|
||||
Rotate the Wii Remote to rotate.
|
||||
|
||||
Hold Z to lock the current menu item.
|
||||
|
||||
A = Select
|
||||
B = Cancel
|
||||
+ = Start
|
||||
NOTE: For unknown reasons (but probably related to the update of the VBA-M
|
||||
emulator code), WarioWare Twisted will no longer work on VBA-GX. For now, you
|
||||
will need to go back to VBA-GX 2.2.8 to play it.
|
||||
|
||||
-=[ Kirby's Tilt n Tumble, Match Wii Controls ]=-
|
||||
|
||||
@ -987,11 +1086,51 @@ Z = grab
|
||||
right analog stick = fast forward
|
||||
1 = select (maybe does nothing)
|
||||
|
||||
-=[ Kid Dracula, Match Wii Controls ]=-
|
||||
|
||||
Turn "Match Wii Controls" ON to use these controls.
|
||||
|
||||
(There's no Kid Dracula game for the Wii, but this is a good opportunity to
|
||||
show off some fancy memory-swapping tricks. -libertyernie)
|
||||
|
||||
The Kid Dracula Wii controls (remote + nunchuk) are:
|
||||
====================================================
|
||||
|
||||
A = jump
|
||||
B = use selected weapon
|
||||
Z = use NOR weapon (fireball)
|
||||
C = use BAT weapon (turn into bat for 5 sec)
|
||||
+ = pause
|
||||
- = switch item
|
||||
1/2 = fast forward
|
||||
|
||||
The Kid Dracula Classic Controller controls are:
|
||||
================================================
|
||||
|
||||
A/B = jump
|
||||
Y = use selected weapon
|
||||
X = use NOR weapon (fireball)
|
||||
R/ZR = use BAT weapon (turn into bat for 5 sec)
|
||||
+ = pause
|
||||
- = switch item
|
||||
1/2 = fast forward
|
||||
|
||||
In Kid Dracula, pressing the "fire" button will always shoot a small fireball,
|
||||
but holding the button for a second or so to charge up the shoot lets you use
|
||||
whichever item is selected.
|
||||
|
||||
Pressing B (nunchuk) or Y (classic) will switch back to whatever item was
|
||||
selected before you pressed Z/C (nunchuk) or X/R/ZR (classic), unless you have
|
||||
switched items since then.
|
||||
|
||||
¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤
|
||||
|
||||
-=[ Credits ]=-
|
||||
|
||||
Coding & menu design Tantric
|
||||
Codebase update & Goomba libertyernie
|
||||
Menu screenshots cebolleto
|
||||
GBA tiled rendering bgK (for RetroArch)
|
||||
Additional coding Carl Kenner, dancinninjac
|
||||
Menu artwork the3seashells
|
||||
Menu sound Peter de Man
|
||||
@ -1009,6 +1148,6 @@ right analog stick = fast forward
|
||||
¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤
|
||||
|
||||
VBAGX Web Site
|
||||
http://code.google.com/p/vba-wii
|
||||
https://github.com/dborth/vba-wii
|
||||
|
||||
¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤
|
||||
|
@ -35,6 +35,7 @@ BROWSERINFO browser;
|
||||
BROWSERENTRY * browserList = NULL; // list of files/folders in browser
|
||||
|
||||
char szpath[MAXPATHLEN];
|
||||
char szname[MAXPATHLEN];
|
||||
bool inSz = false;
|
||||
|
||||
char ROMFilename[512];
|
||||
@ -211,6 +212,8 @@ int UpdateDirName()
|
||||
|
||||
/* remove last subdirectory name */
|
||||
size = strlen(browser.dir) - size - 1;
|
||||
strncpy(GCSettings.LastFileLoaded, &browser.dir[size], strlen(browser.dir) - size - 1); //set as loaded file the previous dir
|
||||
GCSettings.LastFileLoaded[strlen(browser.dir) - size - 1] = 0;
|
||||
browser.dir[size] = 0;
|
||||
}
|
||||
|
||||
@ -255,6 +258,24 @@ bool MakeFilePath(char filepath[], int type, char * filename, int filenum)
|
||||
sprintf(temppath, "%s%s",browser.dir,browserList[browser.selIndex].filename);
|
||||
}
|
||||
}
|
||||
else if (type == FILE_BORDER_PNG)
|
||||
{
|
||||
const char* loadedpath = filename;
|
||||
if (loadedpath == NULL) loadedpath = "default";
|
||||
// Ensure that loadedname contains only the filename, not the path
|
||||
const char* loadedname = strrchr(loadedpath, '/');
|
||||
if (loadedname == NULL) loadedname = loadedpath;
|
||||
|
||||
// Check path length
|
||||
if ((strlen(pathPrefix[GCSettings.LoadMethod]) + strlen(GCSettings.BorderFolder) + strlen(loadedname)) >= MAXPATHLEN) {
|
||||
ErrorPrompt("Maximum filepath length reached!");
|
||||
filepath[0] = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
StripExt(file, loadedname);
|
||||
sprintf(temppath, "%s%s/%s.png", pathPrefix[GCSettings.LoadMethod], GCSettings.BorderFolder, file);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(GCSettings.SaveMethod == DEVICE_AUTO)
|
||||
@ -277,7 +298,14 @@ bool MakeFilePath(char filepath[], int type, char * filename, int filenum)
|
||||
if(filenum == -1)
|
||||
sprintf(file, "%s.%s", filename, ext);
|
||||
else if(filenum == 0)
|
||||
sprintf(file, "%s Auto.%s", filename, ext);
|
||||
if (GCSettings.AppendAuto <= 0)
|
||||
{
|
||||
sprintf(file, "%s.%s", filename, ext);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(file, "%s Auto.%s", filename, ext);
|
||||
}
|
||||
else
|
||||
sprintf(file, "%s %i.%s", filename, filenum, ext);
|
||||
}
|
||||
@ -344,7 +372,7 @@ bool IsSz()
|
||||
*
|
||||
* Strips an extension from a filename
|
||||
***************************************************************************/
|
||||
void StripExt(char* returnstring, char * inputstring)
|
||||
void StripExt(char* returnstring, const char * inputstring)
|
||||
{
|
||||
char* loc_dot;
|
||||
|
||||
@ -436,12 +464,11 @@ void ShortenFilename(char * returnstring, char * inputstring)
|
||||
***************************************************************************/
|
||||
int BrowserLoadSz()
|
||||
{
|
||||
char filepath[MAXPATHLEN];
|
||||
memset(filepath, 0, MAXPATHLEN);
|
||||
memset(szpath, 0, MAXPATHLEN);
|
||||
strncpy(szpath, browser.dir, strlen(browser.dir) - 1);
|
||||
|
||||
// we'll store the 7z filepath for extraction later
|
||||
if(!MakeFilePath(szpath, FILE_ROM))
|
||||
return 0;
|
||||
strncpy(szname, strrchr(szpath, '/') + 1, strrchr(szpath, '.') - strrchr(szpath, '/'));
|
||||
*strrchr(szname, '.') = '\0';
|
||||
|
||||
int szfiles = SzParse(szpath);
|
||||
if(szfiles)
|
||||
@ -469,7 +496,7 @@ int BrowserLoadFile()
|
||||
|
||||
// store the filename (w/o ext) - used for sram/freeze naming
|
||||
StripExt(ROMFilename, browserList[browser.selIndex].filename);
|
||||
strcpy(loadedFile, browserList[browser.selIndex].filename);
|
||||
snprintf(GCSettings.LastFileLoaded, MAXPATHLEN, "%s", browserList[browser.selIndex].filename);
|
||||
|
||||
loadingFile = true;
|
||||
ROMLoaded = LoadVBAROM();
|
||||
@ -516,12 +543,22 @@ int BrowserChangeFolder()
|
||||
if(!UpdateDirName())
|
||||
return -1;
|
||||
|
||||
HaltParseThread(); // halt parsing
|
||||
HaltParseThread();
|
||||
CleanupPath(browser.dir);
|
||||
ResetBrowser(); // reset browser
|
||||
ResetBrowser();
|
||||
|
||||
if(browser.dir[0] != 0)
|
||||
ParseDirectory();
|
||||
{
|
||||
if(strstr(browser.dir, ".7z"))
|
||||
{
|
||||
BrowserLoadSz();
|
||||
}
|
||||
else
|
||||
{
|
||||
ParseDirectory(true, true);
|
||||
}
|
||||
FindAndSelectLastLoadedFile();
|
||||
}
|
||||
|
||||
if(browser.numEntries == 0)
|
||||
{
|
||||
|
@ -47,6 +47,7 @@ extern bool ROMLoaded;
|
||||
extern bool loadingFile;
|
||||
extern char szpath[MAXPATHLEN];
|
||||
extern bool inSz;
|
||||
extern char szname[MAXPATHLEN];
|
||||
|
||||
enum
|
||||
{
|
||||
@ -64,7 +65,7 @@ int OpenGameList();
|
||||
int autoLoadMethod();
|
||||
int autoSaveMethod(bool silent);
|
||||
int FileSortCallback(const void *f1, const void *f2);
|
||||
void StripExt(char* returnstring, char * inputstring);
|
||||
void StripExt(char* returnstring, const char* inputstring);
|
||||
bool IsSz();
|
||||
void ResetBrowser();
|
||||
bool AddBrowserEntry();
|
||||
|
@ -104,6 +104,8 @@ extern const u8 icon_settings_gamecube_png[];
|
||||
extern const u32 icon_settings_gamecube_png_size;
|
||||
extern const u8 icon_settings_nunchuk_png[];
|
||||
extern const u32 icon_settings_nunchuk_png_size;
|
||||
extern const u8 icon_settings_wiiupro_png[];
|
||||
extern const u32 icon_settings_wiiupro_png_size;
|
||||
|
||||
extern const u8 icon_settings_file_png[];
|
||||
extern const u32 icon_settings_file_png_size;
|
||||
@ -115,6 +117,8 @@ extern const u8 icon_settings_network_png[];
|
||||
extern const u32 icon_settings_network_png_size;
|
||||
extern const u8 icon_settings_video_png[];
|
||||
extern const u32 icon_settings_video_png_size;
|
||||
extern const u8 icon_settings_screenshot_png[];
|
||||
extern const u32 icon_settings_screenshot_png_size;
|
||||
|
||||
extern const u8 button_png[];
|
||||
extern const u32 button_png_size;
|
||||
@ -242,6 +246,9 @@ extern const u32 bg_game_selection_png_size;
|
||||
extern const u8 bg_game_selection_entry_png[];
|
||||
extern const u32 bg_game_selection_entry_png_size;
|
||||
|
||||
extern const u8 bg_preview_png[];
|
||||
extern const u32 bg_preview_png_size;
|
||||
|
||||
extern const u8 scrollbar_png[];
|
||||
extern const u32 scrollbar_png_size;
|
||||
|
||||
|
@ -53,7 +53,7 @@ bool isMounted[7] = { false, false, false, false, false, false, false };
|
||||
|
||||
// folder parsing thread
|
||||
static lwp_t parsethread = LWP_THREAD_NULL;
|
||||
static DIR * dir = NULL;
|
||||
static DIR *dir = NULL;
|
||||
static bool parseHalt = true;
|
||||
static bool parseFilter = true;
|
||||
static bool ParseDirEntries();
|
||||
@ -490,6 +490,40 @@ bool GetFileSize(int i)
|
||||
return true;
|
||||
}
|
||||
|
||||
void FindAndSelectLastLoadedFile ()
|
||||
{
|
||||
int indexFound = -1;
|
||||
|
||||
for(int j=1; j < browser.numEntries; j++)
|
||||
{
|
||||
if(strcmp(browserList[j].filename, GCSettings.LastFileLoaded) == 0)
|
||||
{
|
||||
indexFound = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// move to this file
|
||||
if(indexFound > 0)
|
||||
{
|
||||
if(indexFound >= FILE_PAGESIZE)
|
||||
{
|
||||
int newIndex = (floor(indexFound/(float)FILE_PAGESIZE)) * FILE_PAGESIZE;
|
||||
|
||||
if(newIndex + FILE_PAGESIZE > browser.numEntries)
|
||||
newIndex = browser.numEntries - FILE_PAGESIZE;
|
||||
|
||||
if(newIndex < 0)
|
||||
newIndex = 0;
|
||||
|
||||
browser.pageIndex = newIndex;
|
||||
}
|
||||
browser.selIndex = indexFound;
|
||||
}
|
||||
|
||||
selectLoadedFile = 2; // selecting done
|
||||
}
|
||||
|
||||
static bool ParseDirEntries()
|
||||
{
|
||||
if(!dir)
|
||||
@ -578,39 +612,6 @@ static bool ParseDirEntries()
|
||||
closedir(dir); // close directory
|
||||
dir = NULL;
|
||||
|
||||
// try to find and select the last loaded file
|
||||
if(selectLoadedFile == 1 && !parseHalt && loadedFile[0] != 0 && browser.dir[0] != 0)
|
||||
{
|
||||
int indexFound = -1;
|
||||
|
||||
for(int j=1; j < browser.numEntries; j++)
|
||||
{
|
||||
if(strcmp(browserList[j].filename, loadedFile) == 0)
|
||||
{
|
||||
indexFound = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// move to this file
|
||||
if(indexFound > 0)
|
||||
{
|
||||
if(indexFound >= FILE_PAGESIZE)
|
||||
{
|
||||
int newIndex = (floor(indexFound/(float)FILE_PAGESIZE)) * FILE_PAGESIZE;
|
||||
|
||||
if(newIndex + FILE_PAGESIZE > browser.numEntries)
|
||||
newIndex = browser.numEntries - FILE_PAGESIZE;
|
||||
|
||||
if(newIndex < 0)
|
||||
newIndex = 0;
|
||||
|
||||
browser.pageIndex = newIndex;
|
||||
}
|
||||
browser.selIndex = indexFound;
|
||||
}
|
||||
selectLoadedFile = 2; // selecting done
|
||||
}
|
||||
return false; // no more entries
|
||||
}
|
||||
return true; // more entries
|
||||
@ -824,6 +825,12 @@ LoadFile (char * rbuffer, char *filepath, size_t length, bool silent)
|
||||
|
||||
while(!feof(file))
|
||||
{
|
||||
// If the size requested is *less* than the filesize, only read that much - we don't want to overrun the buffer
|
||||
int toread = 4096;
|
||||
if (length > 0 && offset+toread > length) {
|
||||
toread = length - offset;
|
||||
}
|
||||
|
||||
ShowProgress ("Loading...", offset, size);
|
||||
readsize = fread (rbuffer + offset, 1, 4096, file); // read in next chunk
|
||||
|
||||
@ -831,6 +838,9 @@ LoadFile (char * rbuffer, char *filepath, size_t length, bool silent)
|
||||
break; // reading finished (or failed)
|
||||
|
||||
offset += readsize;
|
||||
if (length > 0 && offset >= length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
size = offset;
|
||||
CancelAction();
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include <fat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define SAVEBUFFERSIZE (1024 * 1024 * 2)
|
||||
#define SAVEBUFFERSIZE (1024 * 512)
|
||||
|
||||
void InitDeviceThread();
|
||||
void ResumeDeviceThread();
|
||||
@ -32,6 +32,7 @@ bool ChangeInterface(int device, bool silent);
|
||||
bool ChangeInterface(char * filepath, bool silent);
|
||||
void CreateAppPath(char * origpath);
|
||||
bool GetFileSize(int i);
|
||||
void FindAndSelectLastLoadedFile();
|
||||
int ParseDirectory(bool waitParse = false, bool filter = true);
|
||||
void AllocSaveBuffer();
|
||||
void FreeSaveBuffer();
|
||||
|
@ -1540,3 +1540,119 @@ u32 CastlevaniaCircleMoonInput(unsigned short pad) {
|
||||
return J;
|
||||
}
|
||||
|
||||
u8 KD_NOR[64] = {
|
||||
0x7f, 0x00, 0x98, 0x67, 0x00, 0x99, 0x00, 0x89, 0x00, 0xa1, 0x00, 0xb1, 0x10, 0xa9, 0x18, 0x67,
|
||||
0xff, 0x00, 0x81, 0x7e, 0x00, 0x81, 0x00, 0xb9, 0x10, 0xa9, 0x00, 0xb9, 0x00, 0x81, 0x81, 0x7e,
|
||||
0xfe, 0x00, 0x03, 0xfc, 0x01, 0x82, 0x00, 0xb9, 0x00, 0xb9, 0x01, 0x82, 0x00, 0xb9, 0x10, 0xef,
|
||||
0x00, 0x00, 0x00, 0x20, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
u8 KD_BAT[64] = {
|
||||
0x7f, 0x00, 0x83, 0x7c, 0x01, 0x82, 0x00, 0xb9, 0x01, 0x82, 0x00, 0xb9, 0x00, 0x81, 0x01, 0x7e,
|
||||
0xff, 0x00, 0x81, 0x7e, 0x00, 0x81, 0x00, 0xb9, 0x00, 0xb9, 0x00, 0x81, 0x00, 0xb9, 0x10, 0xef,
|
||||
0xfe, 0x00, 0x00, 0xff, 0x00, 0x81, 0x00, 0xe7, 0xc3, 0x24, 0xc3, 0x24, 0xc3, 0x24, 0xc2, 0x3c,
|
||||
0x00, 0x00, 0x00, 0x20, 0x00, 0x70, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
u8 KD_ACTUAL[64];
|
||||
|
||||
u8 KD_NOR_GRAPHICS[128] = {
|
||||
0x00, 0x00, 0x00, 0x0f, 0x04, 0x07, 0x18, 0x1f, 0x0d, 0x0e, 0x40, 0x7f, 0x18, 0x1f, 0x70, 0x7f,
|
||||
0xc0, 0xff, 0x70, 0x7f, 0x01, 0x3e, 0x0c, 0x0f, 0x3e, 0x3f, 0x10, 0x1f, 0x06, 0x07, 0x00, 0x00,
|
||||
0x00, 0x00, 0x18, 0xe0, 0xe4, 0x18, 0x3a, 0xc4, 0xfc, 0x02, 0x3d, 0xc2, 0xfe, 0x01, 0x3e, 0xc1,
|
||||
0x7e, 0x81, 0x3e, 0xc1, 0xfd, 0x02, 0x7c, 0x82, 0x1a, 0xe4, 0xe4, 0x18, 0x10, 0xe0, 0x00, 0x00,
|
||||
0x04, 0x03, 0x13, 0x0c, 0x2f, 0x10, 0x5f, 0x20, 0x5f, 0x20, 0x3f, 0x40, 0x2a, 0x55, 0x2a, 0x55,
|
||||
0x08, 0x77, 0x00, 0x7f, 0x28, 0x7f, 0x1a, 0x5f, 0x13, 0x17, 0x01, 0x05, 0x05, 0x05, 0x00, 0x00,
|
||||
0x20, 0xc0, 0xc8, 0x30, 0xf4, 0x08, 0xf8, 0x04, 0xfa, 0x04, 0xf4, 0x0a, 0xb4, 0x4a, 0x24, 0xda,
|
||||
0x20, 0xde, 0x0a, 0xfe, 0x1a, 0xfe, 0x18, 0xfc, 0x4c, 0xec, 0x48, 0xe8, 0xc0, 0xc0, 0x80, 0x80};
|
||||
u8 KD_ACTUAL_GRAPHICS[128];
|
||||
|
||||
bool KD_WeaponPressed = false;
|
||||
s8 KD_LastWeapon; // -1 for selected weapon, 0 for NOR, 4 for BAT
|
||||
u8 KD_ActualItem; // Item selected by the player (byte in memory)
|
||||
|
||||
void KD_WeaponToMemory() {
|
||||
// If the fourth 8x8 tile of the weapon indicator doesn't contain the "+" icon I made, the weapon has been changed in the game and has to be updated in memory.
|
||||
bool hasPlusIcon = true;
|
||||
for (int i=48; i<64; i++) {
|
||||
if (gbReadMemory(0x9110+i) != KD_BAT[i]) {
|
||||
hasPlusIcon = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasPlusIcon) return;
|
||||
|
||||
KD_ActualItem = gbReadMemory(0xC8CB);
|
||||
for (int i=0; i<64; i++) {
|
||||
KD_ACTUAL[i] = gbReadMemory(0x9110+i);
|
||||
}
|
||||
for (int i=0; i<128; i++) {
|
||||
KD_ACTUAL_GRAPHICS[i] = gbReadMemory(0x8f40+i);
|
||||
}
|
||||
}
|
||||
|
||||
u32 KidDraculaInput(unsigned short pad) {
|
||||
// Only Nunchuk and Classic controls available
|
||||
// Wiimote and Gamecube controls depend on user configuration
|
||||
u32 J = StandardMovement(pad) | DecodeGamecube(pad) | DecodeWiimote(pad) | DecodeClassic(pad);
|
||||
bool JumpButton=0, ShootButton=0, PauseButton=0, SelectButton=0, SpeedButton=0, NorButton=0, BatButton=0;
|
||||
#ifdef HW_RVL
|
||||
WPADData * wp = WPAD_Data(pad);
|
||||
if (wp->exp.type == WPAD_EXP_NUNCHUK) {
|
||||
JumpButton = wp->btns_h & WPAD_BUTTON_A;
|
||||
ShootButton = wp->btns_h & WPAD_BUTTON_B;
|
||||
PauseButton = wp->btns_h & WPAD_BUTTON_PLUS;
|
||||
SelectButton = wp->btns_h & WPAD_BUTTON_MINUS;
|
||||
SpeedButton = wp->btns_h & WPAD_BUTTON_1 || wp->btns_h & WPAD_BUTTON_2;
|
||||
NorButton = wp->btns_h & WPAD_NUNCHUK_BUTTON_Z;
|
||||
BatButton = wp->btns_h & WPAD_NUNCHUK_BUTTON_C;
|
||||
} else if (wp->exp.type == WPAD_EXP_CLASSIC) {
|
||||
JumpButton = wp->btns_h & (WPAD_CLASSIC_BUTTON_B | WPAD_CLASSIC_BUTTON_A);
|
||||
ShootButton = wp->btns_h & WPAD_CLASSIC_BUTTON_Y;
|
||||
PauseButton = wp->btns_h & WPAD_CLASSIC_BUTTON_PLUS;
|
||||
SelectButton = wp->btns_h & WPAD_CLASSIC_BUTTON_MINUS;
|
||||
SpeedButton = wp->btns_h & (WPAD_CLASSIC_BUTTON_ZL | WPAD_CLASSIC_BUTTON_FULL_L);
|
||||
NorButton = wp->btns_h & WPAD_CLASSIC_BUTTON_X;
|
||||
BatButton = wp->btns_h & (WPAD_CLASSIC_BUTTON_ZR | WPAD_CLASSIC_BUTTON_FULL_R);
|
||||
}
|
||||
#endif
|
||||
if (JumpButton) J |= VBA_BUTTON_A;
|
||||
if (ShootButton && !(KD_WeaponPressed && KD_LastWeapon != -1)) {
|
||||
J |= VBA_BUTTON_B;
|
||||
KD_LastWeapon = -1;
|
||||
// Insert original weapon and graphics
|
||||
KD_WeaponToMemory();
|
||||
gbWriteMemory(0xC8CB, KD_ActualItem);
|
||||
for (int i=0; i<64; i++) {
|
||||
gbWriteMemory(0x9110+i, KD_ACTUAL[i]);
|
||||
}
|
||||
for (int i=0; i<128; i++) {
|
||||
gbWriteMemory(0x8f40+i, KD_ACTUAL_GRAPHICS[i]);
|
||||
}
|
||||
}
|
||||
if (NorButton && !(KD_WeaponPressed && KD_LastWeapon != 0)) {
|
||||
J |= VBA_BUTTON_B;
|
||||
KD_LastWeapon = 0;
|
||||
// Insert NOR weapon and graphics
|
||||
KD_WeaponToMemory();
|
||||
gbWriteMemory(0xC8CB, 0);
|
||||
for (int i=0; i<64; i++) {
|
||||
gbWriteMemory(0x9110+i, KD_NOR[i]);
|
||||
}
|
||||
for (int i=0; i<128; i++) {
|
||||
gbWriteMemory(0x8f40+i, KD_NOR_GRAPHICS[i]);
|
||||
}
|
||||
}
|
||||
if (BatButton && !(KD_WeaponPressed && KD_LastWeapon != 4)) {
|
||||
J |= VBA_BUTTON_B;
|
||||
KD_LastWeapon = 4;
|
||||
// Insert BAT weapon and graphics
|
||||
KD_WeaponToMemory();
|
||||
gbWriteMemory(0xC8CB, 4);
|
||||
for (int i=0; i<64; i++) {
|
||||
gbWriteMemory(0x9110+i, KD_BAT[i]);
|
||||
}
|
||||
}
|
||||
if (PauseButton) J |= VBA_BUTTON_START;
|
||||
if (SelectButton) J |= VBA_BUTTON_SELECT;
|
||||
if (SpeedButton) J |= VBA_SPEED;
|
||||
KD_WeaponPressed = (ShootButton || NorButton || BatButton);
|
||||
return J;
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@
|
||||
#define CVCLASSIC gid('F','A','D')
|
||||
#define CVDOUBLE gid('B','X','K')
|
||||
|
||||
|
||||
#define KIDDRACULA 0xFF0014
|
||||
|
||||
#define MARBLEMADNESS 0xFF000A
|
||||
|
||||
@ -205,6 +205,7 @@ u32 CastlevaniaAdventureInput(unsigned short pad);
|
||||
u32 CastlevaniaBelmontInput(unsigned short pad);
|
||||
u32 CastlevaniaLegendsInput(unsigned short pad);
|
||||
u32 CastlevaniaCircleMoonInput(unsigned short pad);
|
||||
u32 KidDraculaInput(unsigned short pad);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "vbagx.h"
|
||||
#include "fileop.h"
|
||||
@ -367,14 +368,15 @@ int SzParse(char * filepath)
|
||||
|
||||
int device;
|
||||
|
||||
if(!FindDevice(browser.dir, &device) || !GetFileSize(browser.selIndex))
|
||||
struct stat filestat;
|
||||
if(stat(filepath, &filestat) < 0)
|
||||
return 0;
|
||||
unsigned int filelen = filestat.st_size;
|
||||
|
||||
if(!FindDevice(filepath, &device) || !filelen)
|
||||
return 0;
|
||||
|
||||
int nbfiles = 0;
|
||||
|
||||
// save the length/offset of this file
|
||||
unsigned int filelen = browserList[browser.selIndex].length;
|
||||
|
||||
// setup archive stream
|
||||
SzArchiveStream.offset = 0;
|
||||
SzArchiveStream.len = filelen;
|
||||
@ -423,7 +425,7 @@ int SzParse(char * filepath)
|
||||
|
||||
// add '..' folder in case the user wants exit the 7z
|
||||
AddBrowserEntry();
|
||||
|
||||
sprintf(browserList[0].filename, "..");
|
||||
sprintf(browserList[0].displayname, "Up One Level");
|
||||
browserList[0].isdir = 1;
|
||||
browserList[0].length = filelen;
|
||||
@ -452,6 +454,12 @@ int SzParse(char * filepath)
|
||||
// parse information about this file to the file list structure
|
||||
snprintf(browserList[SzJ].filename, MAXJOLIET, "%s", SzF->Name);
|
||||
StripExt(browserList[SzJ].displayname, browserList[SzJ].filename);
|
||||
char* strPos = strstr(browserList[SzJ].displayname, szname);
|
||||
if(strPos)
|
||||
{
|
||||
snprintf(browserList[SzJ].displayname, MAXJOLIET, "%s", strPos + strlen(szname));
|
||||
}
|
||||
|
||||
browserList[SzJ].length = SzF->Size; // filesize
|
||||
browserList[SzJ].isdir = 0; // only files will be displayed (-> no flags)
|
||||
browserList[SzJ].filenum = SzI; // the extraction function identifies the file with this number
|
||||
|
6
source/goomba/README.txt
Normal file
@ -0,0 +1,6 @@
|
||||
goombasav.c is designed to edit the compressed SRAM data of the Goomba and Goomba Color emulators. It can extract and replace the compressed Game Boy / Game Boy Color SRAM data. It can't edit savestate data or add new SRAM (yet).
|
||||
|
||||
goombarom.c can find uncompressed Game Boy ROMs within larger files (e.g. a Goomba Color .gba ROM, or a .tar archive.) It was written for my fork of TGB Dual.
|
||||
|
||||
https://github.com/libertyernie/goombasav
|
||||
https://github.com/libertyernie/tgbdual
|
84
source/goomba/goombarom.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
/* goombarom.c - functions to find uncompressed Game Boy ROM images
|
||||
stored within a larger file (e.g. Goomba Color ROMs, TAR archives)
|
||||
|
||||
Copyright (C) 2014 libertyernie
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
When compiling in Visual Studio, set all goombarom files to compile
|
||||
as C++ code (Properties -> C/C++ -> Advanced -> Compile As.)
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "goombarom.h"
|
||||
|
||||
const char NINTENDO_LOGO_GB[48] = { 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E };
|
||||
char gb_title_buffer[16];
|
||||
|
||||
/* Finds the (expected) size of a Game Boy ROM, given a pointer to the start
|
||||
of the ROM image. */
|
||||
unsigned int gb_rom_size(const void* rom_start) {
|
||||
const char* ptr = (const char*)rom_start;
|
||||
return 0x8000 << ptr[0x148];
|
||||
}
|
||||
|
||||
/* Finds the first Game Boy ROM in the given data block by looking for the
|
||||
Nintendo logo that shows when you turn the Game Boy on. If no valid data is
|
||||
found, this method will return NULL. */
|
||||
const void* gb_first_rom(const void* data, size_t length) {
|
||||
const char* ptr = (const char*)data;
|
||||
const char* end = ptr + length;
|
||||
int logo_pos = 0;
|
||||
while (ptr < end) {
|
||||
if (*ptr == NINTENDO_LOGO_GB[logo_pos]) {
|
||||
// match
|
||||
logo_pos++;
|
||||
if (logo_pos == 48) { // matched all of GB logo - on last byte (0x133)
|
||||
return ptr - 0x133;
|
||||
}
|
||||
} else {
|
||||
// no match, try again
|
||||
if (logo_pos > 0) {
|
||||
ptr -= logo_pos;
|
||||
logo_pos = 0;
|
||||
}
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Returns a pointer to the next Game Boy ROM in the data. If no valid Game
|
||||
Boy ROM is found between *data and *data+length, starting at *rom, this method
|
||||
will return NULL.*/
|
||||
const void* gb_next_rom(const void* data, size_t length, const void* rom) {
|
||||
size_t diff = (const char*)rom - (const char*)data;
|
||||
if (diff > length) {
|
||||
//fprintf(stderr, "*data and *rom are farther apart than length param\n");
|
||||
return NULL;
|
||||
}
|
||||
size_t effective_length = length - diff;
|
||||
if (effective_length <= 0x200) {
|
||||
return NULL;
|
||||
}
|
||||
return gb_first_rom((const char*)rom + 0x134, effective_length - 0x134);
|
||||
}
|
||||
|
||||
const char* gb_get_title(const void* rom, char* buffer) {
|
||||
char* title = buffer != NULL ? buffer : gb_title_buffer;
|
||||
title[15] = '\0';
|
||||
memcpy(title, (char*)rom + 0x134, 15);
|
||||
return title;
|
||||
}
|
43
source/goomba/goombarom.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* goombarom.h - functions to find uncompressed Game Boy ROM images
|
||||
stored within a larger file (e.g. Goomba Color ROMs, TAR archives)
|
||||
|
||||
Copyright (C) 2014 libertyernie
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
When compiling in Visual Studio, set all goombarom files to compile
|
||||
as C++ code (Properties -> C/C++ -> Advanced -> Compile As.)
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* Finds the (expected) size of a Game Boy ROM, given a pointer to the start
|
||||
of the ROM image. */
|
||||
unsigned int gb_rom_size(const void* rom_start);
|
||||
|
||||
/* Finds the first Game Boy ROM in the given data block by looking for the
|
||||
Nintendo logo that shows when you turn the Game Boy on. If no valid data is
|
||||
found, this method will return NULL. */
|
||||
const void* gb_first_rom(const void* data, size_t length);
|
||||
|
||||
/* Returns a pointer to the next Game Boy ROM in the data. If the location
|
||||
where the next ROM would be does not contain a valid Nintendo logo at 0x104,
|
||||
this method will return NULL. */
|
||||
const void* gb_next_rom(const void* data, size_t length, const void* first_rom);
|
||||
|
||||
/* Returns a copy of the title from the ROM header. If buffer is NULL, the
|
||||
string will be allocated in an internal 16-byte buffer which will be
|
||||
overwritten later. If buffer is not NULL, the title will be copied to buffer,
|
||||
and buffer will be returned. */
|
||||
const char* gb_get_title(const void* rom, char* buffer);
|
445
source/goomba/goombasav.cpp
Normal file
@ -0,0 +1,445 @@
|
||||
/* goombasav.c - functions to handle Goomba / Goomba Color SRAM
|
||||
|
||||
last updated September 8, 2014
|
||||
Copyright (C) 2014 libertyernie
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
https://github.com/libertyernie/goombasav
|
||||
|
||||
When compiling in Visual Studio, set all goombasav files to compile
|
||||
as C++ code (Properties -> C/C++ -> Advanced -> Compile As.)
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "goombasav.h"
|
||||
#include "minilzo-2.06/minilzo.h"
|
||||
|
||||
#define goomba_error(...) { sprintf(last_error, __VA_ARGS__); }
|
||||
|
||||
#define F16 little_endian_conv_16
|
||||
#define F32 little_endian_conv_32
|
||||
|
||||
static const char* const sleeptxt[] = { "5min", "10min", "30min", "OFF" };
|
||||
static const char* const brightxt[] = { "I", "II", "III", "IIII", "IIIII" };
|
||||
|
||||
static char last_error[256] = "No error has occured yet.";
|
||||
static char goomba_strbuf[256];
|
||||
|
||||
const char* goomba_last_error() {
|
||||
return (const char*)last_error;
|
||||
}
|
||||
|
||||
size_t goomba_set_last_error(const char* msg) {
|
||||
size_t len = strnlen(msg, sizeof(last_error)-1);
|
||||
memcpy(last_error, msg, len);
|
||||
last_error[sizeof(last_error)-1] = '\0';
|
||||
return len;
|
||||
}
|
||||
|
||||
// For making a checksum of the compressed data.
|
||||
// output_bytes is limited to 8 at maximum
|
||||
uint64_t checksum_slow(const void* ptr, size_t length, int output_bytes) {
|
||||
const unsigned char* p = (const unsigned char*)ptr;
|
||||
uint64_t sum=0;
|
||||
char* sumptr = (char*)∑
|
||||
size_t j;
|
||||
for (j=0;j<length;j++) {
|
||||
int index = j%output_bytes;
|
||||
sumptr[index] += *p;
|
||||
p++;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
uint16_t little_endian_conv_16(uint16_t value) {
|
||||
if (*(uint16_t *)"\0\xff" < 0x100) {
|
||||
uint16_t buffer;
|
||||
((char*)&buffer)[0] = ((char*)&value)[1];
|
||||
((char*)&buffer)[1] = ((char*)&value)[0];
|
||||
return buffer;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t little_endian_conv_32(uint32_t value) {
|
||||
if (*(uint16_t *)"\0\xff" < 0x100) {
|
||||
uint32_t buffer;
|
||||
((char*)&buffer)[0] = ((char*)&value)[3];
|
||||
((char*)&buffer)[1] = ((char*)&value)[2];
|
||||
((char*)&buffer)[2] = ((char*)&value)[1];
|
||||
((char*)&buffer)[3] = ((char*)&value)[0];
|
||||
return buffer;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
configdata_misc_strings configdata_get_misc(char misc) {
|
||||
configdata_misc_strings s;
|
||||
s.sleep = sleeptxt[misc & 0x3];
|
||||
s.autoload_state = ((misc & 0x10) >> 4) ? "ON" : "OFF";
|
||||
s.gamma = brightxt[(misc & 0xE0) >> 5];
|
||||
return s;
|
||||
}
|
||||
|
||||
const char* stateheader_typestr(uint16_t type) {
|
||||
switch (type) {
|
||||
case GOOMBA_STATESAVE:
|
||||
return "Savestate";
|
||||
case GOOMBA_SRAMSAVE:
|
||||
return "SRAM";
|
||||
case GOOMBA_CONFIGSAVE:
|
||||
return "Configuration";
|
||||
case GOOMBA_PALETTE: // Used by Goomba Paletted
|
||||
return "Palette";
|
||||
default:
|
||||
return "Unknown"; // Stateheaders with these types are rejected by stateheader_plausible
|
||||
}
|
||||
}
|
||||
|
||||
const char* stateheader_str(const stateheader* sh) {
|
||||
int j = 0;
|
||||
j += sprintf(goomba_strbuf + j, "size: %u\n", F16(sh->size));
|
||||
j += sprintf(goomba_strbuf + j, "type: %s (%u)\n", stateheader_typestr(F16(sh->type)), F16(sh->type));
|
||||
if (F16(sh->type) == GOOMBA_CONFIGSAVE) {
|
||||
configdata* cd = (configdata*)sh;
|
||||
j += sprintf(goomba_strbuf + j, "bordercolor: %u\n", cd->bordercolor);
|
||||
j += sprintf(goomba_strbuf + j, "palettebank: %u\n", cd->palettebank);
|
||||
configdata_misc_strings strs = configdata_get_misc(cd->misc);
|
||||
j += sprintf(goomba_strbuf + j, "sleep: %s\n", strs.sleep);
|
||||
j += sprintf(goomba_strbuf + j, "autoload state: %s\n", strs.autoload_state);
|
||||
j += sprintf(goomba_strbuf + j, "gamma: %s\n", strs.gamma);
|
||||
j += sprintf(goomba_strbuf + j, "rom checksum: %8X (0xE000-0xFFFF %s)\n", F32(cd->sram_checksum),
|
||||
cd->sram_checksum != 0 ? "occupied" : "free");
|
||||
} else {
|
||||
j += sprintf(goomba_strbuf + j, "%scompressed_size: %u\n",
|
||||
(F32(sh->uncompressed_size) < F16(sh->size) ? "" : "un"),
|
||||
F32(sh->uncompressed_size));
|
||||
j += sprintf(goomba_strbuf + j, "framecount: %u\n", F32(sh->framecount));
|
||||
j += sprintf(goomba_strbuf + j, "rom checksum: %8X\n", F32(sh->checksum));
|
||||
}
|
||||
j += sprintf(goomba_strbuf + j, "title: %s", sh->title);
|
||||
return goomba_strbuf;
|
||||
}
|
||||
|
||||
const char* stateheader_summary_str(const stateheader* sh) {
|
||||
sprintf(goomba_strbuf, "%s: %s (%u b / %u uncomp)", stateheader_typestr(
|
||||
F16(sh->type)), sh->title, F16(sh->size), F32(sh->uncompressed_size));
|
||||
return goomba_strbuf;
|
||||
}
|
||||
|
||||
int stateheader_plausible(const stateheader* sh) {
|
||||
uint16_t type = F16(sh->type);
|
||||
if (type < 0 || type == 3 || type == 4 || type > 5) return 0;
|
||||
return F16(sh->size) >= sizeof(stateheader) && // check size (at least 48)
|
||||
(F16(sh->type) == GOOMBA_CONFIGSAVE || sh->uncompressed_size != 0); // check uncompressed_size, but not for configsave
|
||||
// when checking for whether something equals 0, endian conversion is not necessary
|
||||
}
|
||||
|
||||
stateheader* stateheader_advance(const stateheader* sh) {
|
||||
if (!stateheader_plausible(sh)) return NULL;
|
||||
|
||||
uint16_t s = F16(sh->size);
|
||||
char* c = (char*)sh;
|
||||
c += s;
|
||||
return (stateheader*)c;
|
||||
}
|
||||
|
||||
stateheader** stateheader_scan(const void* gba_data) {
|
||||
// Do not edit gba_data!
|
||||
// We are casting to non-const pointers so the client gets non-const pointers back.
|
||||
const goomba_size_t psize = sizeof(stateheader*);
|
||||
stateheader** headers = (stateheader**)malloc(psize * 64);
|
||||
memset(headers, 0, psize * 64);
|
||||
|
||||
uint32_t* check = (uint32_t*)gba_data;
|
||||
if (F32(*check) == GOOMBA_STATEID) check++;
|
||||
|
||||
stateheader* sh = (stateheader*)check;
|
||||
int i = 0;
|
||||
while (stateheader_plausible(sh) && i < 63) {
|
||||
headers[i] = sh;
|
||||
i++;
|
||||
sh = stateheader_advance(sh);
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
stateheader* stateheader_for(const void* gba_data, const char* gbc_title) {
|
||||
char title[0x10];
|
||||
memcpy(title, gbc_title, 0x0F);
|
||||
title[0x0F] = '\0';
|
||||
stateheader* use_this = NULL;
|
||||
stateheader** headers = stateheader_scan(gba_data);
|
||||
int i;
|
||||
for (i = 0; headers[i] != NULL; i++) {
|
||||
if (strcmp(headers[i]->title, title) == 0 && F16(headers[i]->type) == GOOMBA_SRAMSAVE) {
|
||||
use_this = headers[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(headers);
|
||||
if (use_this == NULL) sprintf(last_error, "Could not find SRAM data for %s", title);
|
||||
return use_this;
|
||||
}
|
||||
|
||||
// Uses checksum_slow, and looks at the compressed data (not the header).
|
||||
// output_bytes is limited to 8 at maximum
|
||||
uint64_t goomba_compressed_data_checksum(const stateheader* sh, int output_bytes) {
|
||||
return checksum_slow(sh+1, F16(sh->size) - sizeof(stateheader), output_bytes);
|
||||
}
|
||||
|
||||
int goomba_is_sram(const void* data) {
|
||||
return F32(*(uint32_t*)data) == GOOMBA_STATEID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 32-bit checksum (unsigned) in the configdata header, or -1 if
|
||||
* stateheader_scan returns NULL due to an error. When using this function,
|
||||
* first check if the value is less than 0, then (if not) cast to uint32_t.
|
||||
*/
|
||||
int64_t goomba_get_configdata_checksum_field(const void* gba_data) {
|
||||
// todo fix
|
||||
stateheader** headers = stateheader_scan(gba_data);
|
||||
if (headers == NULL) return -1;
|
||||
|
||||
int i;
|
||||
for (i = 0; headers[i] != NULL; i++) {
|
||||
if (F16(headers[i]->type) == GOOMBA_CONFIGSAVE) {
|
||||
// found configdata
|
||||
const configdata* cd = (configdata*)headers[i];
|
||||
free(headers);
|
||||
return F32(cd->sram_checksum); // 0 = clean, postitive = unclean
|
||||
}
|
||||
}
|
||||
|
||||
free(headers);
|
||||
return -1; // not sure when this would happen
|
||||
}
|
||||
|
||||
char* goomba_cleanup(const void* gba_data_param) {
|
||||
char gba_data[GOOMBA_COLOR_SRAM_SIZE]; // on stack - do not need to free
|
||||
memcpy(gba_data, gba_data_param, GOOMBA_COLOR_SRAM_SIZE);
|
||||
|
||||
stateheader** headers = stateheader_scan(gba_data);
|
||||
if (headers == NULL) return NULL;
|
||||
|
||||
int i, j;
|
||||
for (i = 0; headers[i] != NULL; i++) {
|
||||
if (F16(headers[i]->type) == GOOMBA_CONFIGSAVE) {
|
||||
// found configdata
|
||||
configdata* cd = (configdata*)headers[i];
|
||||
const uint32_t checksum = F32(cd->sram_checksum);
|
||||
for (j = 0; headers[j] != NULL; j++) {
|
||||
stateheader* sh = headers[j];
|
||||
if (F16(sh->type) == GOOMBA_SRAMSAVE && F32(sh->checksum) == checksum) {
|
||||
// found stateheader
|
||||
free(headers); // so make sure we return something before the loop goes around again!!
|
||||
|
||||
cd->sram_checksum = 0; // because we do this here, goomba_new_sav should not complain about an unclean file
|
||||
|
||||
char gbc_data[GOOMBA_COLOR_SRAM_SIZE - GOOMBA_COLOR_AVAILABLE_SIZE];
|
||||
memcpy(gbc_data,
|
||||
gba_data + GOOMBA_COLOR_AVAILABLE_SIZE,
|
||||
sizeof(gbc_data)); // Extract GBC data at 0xe000 to an array
|
||||
|
||||
char* new_gba_data = goomba_new_sav(gba_data, sh, gbc_data, sizeof(gbc_data));
|
||||
if (new_gba_data != NULL) memset(new_gba_data + GOOMBA_COLOR_AVAILABLE_SIZE, 0, sizeof(gbc_data));
|
||||
return new_gba_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(headers);
|
||||
return (char*)gba_data_param;
|
||||
}
|
||||
|
||||
void* goomba_extract(const void* gba_data, const stateheader* header_ptr, goomba_size_t* size_output) {
|
||||
const stateheader* sh = (const stateheader*)header_ptr;
|
||||
|
||||
if (F16(sh->type) != GOOMBA_SRAMSAVE) {
|
||||
goomba_error("Error: this program can only extract SRAM data.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const int64_t ck = goomba_get_configdata_checksum_field(gba_data);
|
||||
if (ck < 0) {
|
||||
return NULL;
|
||||
} else if (ck == F32(sh->checksum)) {
|
||||
goomba_error("File is unclean - run goomba_cleanup before trying to extract SRAM, or you might get old data\n");
|
||||
return NULL;
|
||||
} else if (ck != 0) {
|
||||
fprintf(stderr, "File is unclean, but it shouldn't affect retrieval of the data you asked for\n");
|
||||
}
|
||||
|
||||
lzo_uint compressed_size = F16(sh->size) - sizeof(stateheader);
|
||||
lzo_uint output_size = 32768;
|
||||
const unsigned char* compressed_data = (unsigned char*)header_ptr + sizeof(stateheader);
|
||||
unsigned char* uncompressed_data = (unsigned char*)malloc(output_size);
|
||||
int r = lzo1x_decompress_safe(compressed_data, compressed_size,
|
||||
uncompressed_data, &output_size,
|
||||
(void*)NULL);
|
||||
//fprintf(stderr, "Actual uncompressed size: %lu\n", output_size);
|
||||
if (r == LZO_E_INPUT_NOT_CONSUMED) {
|
||||
//goomba_error("Warning: input not fully used. Double-check the result to make sure it works.\n");
|
||||
} else if (r < 0) {
|
||||
goomba_error("Cannot decompress data (lzoconf.h error code %d).\n", r);
|
||||
free(uncompressed_data);
|
||||
return NULL;
|
||||
}
|
||||
*size_output = output_size;
|
||||
return uncompressed_data;
|
||||
}
|
||||
|
||||
goomba_size_t copy_until_invalid_header(void* dest, const stateheader* src_param) {
|
||||
const void* src = src_param;
|
||||
goomba_size_t bytes_copied = 0;
|
||||
while (1) {
|
||||
const stateheader* sh = (const stateheader*)src;
|
||||
if (!stateheader_plausible(sh)) break;
|
||||
|
||||
memcpy(dest, src, F16(sh->size));
|
||||
|
||||
src = (char*)src + F16(sh->size);
|
||||
dest = (char*)dest + F16(sh->size);
|
||||
bytes_copied += F16(sh->size);
|
||||
}
|
||||
memcpy(dest, src, sizeof(stateheader)); // copy "footer"
|
||||
return bytes_copied + sizeof(stateheader);
|
||||
}
|
||||
|
||||
char* goomba_new_sav(const void* gba_data, const void* gba_header, const void* gbc_sram, goomba_size_t gbc_length) {
|
||||
unsigned char* gba_header_ptr = (unsigned char*)gba_header;
|
||||
stateheader* sh = (stateheader*)gba_header_ptr;
|
||||
|
||||
int64_t ck = goomba_get_configdata_checksum_field(gba_data);
|
||||
if (ck < 0) {
|
||||
return NULL;
|
||||
} else if (ck == F32(sh->checksum)) {
|
||||
// have to clean file
|
||||
goomba_error("File is unclean - run goomba_cleanup before trying to replace SRAM, or your new data might get overwritten");
|
||||
return NULL;
|
||||
} else if (ck != 0) {
|
||||
fprintf(stderr, "File is unclean, but it shouldn't affect replacement of the data you asked for\n");
|
||||
}
|
||||
|
||||
if (F16(sh->type) != GOOMBA_SRAMSAVE) {
|
||||
goomba_error("Error - This program cannot replace non-SRAM data.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// sh->uncompressed_size is valid for Goomba Color.
|
||||
// For Goomba, it's actually compressed size (and will be less than sh->size).
|
||||
goomba_size_t uncompressed_size;
|
||||
if (F16(sh->size) > F32(sh->uncompressed_size)) {
|
||||
// Uncompress to a temporary location, just so we can see how big it is
|
||||
goomba_size_t output;
|
||||
void* dump = goomba_extract(gba_data, sh, &output);
|
||||
if (dump == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
free(dump);
|
||||
uncompressed_size = output;
|
||||
} else {
|
||||
// Goomba Color header - use size from there
|
||||
uncompressed_size = F32(sh->uncompressed_size);
|
||||
}
|
||||
|
||||
if (gbc_length < uncompressed_size) {
|
||||
goomba_error("Error: the length of the GBC data (%u) is too short - expected %u bytes.\n",
|
||||
gbc_length, uncompressed_size);
|
||||
return NULL;
|
||||
} else if (gbc_length - 4 == uncompressed_size) {
|
||||
goomba_error("Note: RTC data (TGB_Dual format) will not be copied\n");
|
||||
} else if (gbc_length - 44 == uncompressed_size) {
|
||||
goomba_error("Note: RTC data (old VBA format) will not be copied\n");
|
||||
} else if (gbc_length - 48 == uncompressed_size) {
|
||||
goomba_error("Note: RTC data (new VBA format) will not be copied\n");
|
||||
} else if (gbc_length > uncompressed_size) {
|
||||
goomba_error("Warning: unknown data at end of GBC save file - only first %u bytes will be used\n", uncompressed_size);
|
||||
}
|
||||
|
||||
if (F16(sh->type) != GOOMBA_SRAMSAVE) {
|
||||
goomba_error("The data at gba_header is not SRAM data.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* const goomba_new_sav = (char*)malloc(GOOMBA_COLOR_SRAM_SIZE);
|
||||
memset(goomba_new_sav, 0, GOOMBA_COLOR_SRAM_SIZE);
|
||||
char* working = goomba_new_sav; // will be incremented throughout
|
||||
|
||||
goomba_size_t before_header = (char*)gba_header - (char*)gba_data;
|
||||
// copy anything before stateheader
|
||||
memcpy(goomba_new_sav, gba_data, before_header);
|
||||
working += before_header;
|
||||
// copy stateheader
|
||||
memcpy(working, sh, sizeof(stateheader));
|
||||
stateheader* new_sh = (stateheader*)working;
|
||||
working += sizeof(stateheader);
|
||||
|
||||
// backup data that comes after this header
|
||||
unsigned char* backup = (unsigned char*)malloc(GOOMBA_COLOR_SRAM_SIZE);
|
||||
goomba_size_t backup_len = copy_until_invalid_header(backup, (stateheader*)(gba_header_ptr + F16(sh->size)));
|
||||
|
||||
// compress gbc sram
|
||||
lzo_uint compressed_size;
|
||||
unsigned char* dest = (unsigned char*)working;
|
||||
void* wrkmem = malloc(LZO1X_1_MEM_COMPRESS);
|
||||
lzo1x_1_compress((const unsigned char*)gbc_sram, uncompressed_size,
|
||||
dest, &compressed_size,
|
||||
wrkmem);
|
||||
free(wrkmem);
|
||||
working += compressed_size;
|
||||
//fprintf(stderr, "Compressed %u bytes (compressed size: %lu)\n", uncompressed_size, compressed_size);
|
||||
|
||||
if (F16(sh->size) > F32(sh->uncompressed_size)) {
|
||||
// Goomba header (not Goomba Color)
|
||||
new_sh->uncompressed_size = F32(compressed_size);
|
||||
}
|
||||
|
||||
new_sh->size = F16((uint16_t)(compressed_size + sizeof(stateheader)));
|
||||
// pad to 4 bytes!
|
||||
// if I don't do this, goomba color might not load the palette settings, or seemingly 'forget' them later
|
||||
// btw, the settings are stored in the configdata struct defined in goombasav.h
|
||||
uint16_t s = F16(new_sh->size);
|
||||
while (s % 4 != 0) {
|
||||
*working = 0;
|
||||
working++;
|
||||
s++;
|
||||
}
|
||||
new_sh->size = F16(s);
|
||||
|
||||
goomba_size_t used = working - goomba_new_sav;
|
||||
if (used + backup_len > GOOMBA_COLOR_AVAILABLE_SIZE) {
|
||||
goomba_error("Not enough room in file for the new save data (0xe000-0xffff must be kept free, I think)\n");
|
||||
free(backup);
|
||||
free(goomba_new_sav);
|
||||
return NULL;
|
||||
}
|
||||
// restore the backup - just assume we have enough space
|
||||
memcpy(working, backup, backup_len);
|
||||
free(backup);
|
||||
|
||||
// restore data from 0xe000 to 0xffff
|
||||
memcpy(goomba_new_sav + GOOMBA_COLOR_AVAILABLE_SIZE,
|
||||
(char*)gba_data + GOOMBA_COLOR_AVAILABLE_SIZE,
|
||||
GOOMBA_COLOR_SRAM_SIZE - GOOMBA_COLOR_AVAILABLE_SIZE);
|
||||
|
||||
return goomba_new_sav;
|
||||
}
|
184
source/goomba/goombasav.h
Normal file
@ -0,0 +1,184 @@
|
||||
/* goombasav.h - functions to handle Goomba / Goomba Color SRAM
|
||||
|
||||
last updated July 3, 2014
|
||||
Copyright (C) 2014 libertyernie
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
https://github.com/libertyernie/goombasav
|
||||
|
||||
When compiling in Visual Studio, set all goombasav files to compile
|
||||
as C++ code (Properties -> C/C++ -> Advanced -> Compile As.)
|
||||
*/
|
||||
|
||||
#ifndef __GOOMBASAV_H
|
||||
#define __GOOMBASAV_H
|
||||
|
||||
#include <stdint.h>
|
||||
#define GOOMBA_COLOR_SRAM_SIZE 65536
|
||||
#define GOOMBA_COLOR_AVAILABLE_SIZE 57344
|
||||
#define GOOMBA_STATEID 0x57a731d8
|
||||
#define GOOMBA_STATESAVE 0
|
||||
#define GOOMBA_SRAMSAVE 1
|
||||
#define GOOMBA_CONFIGSAVE 2
|
||||
#define GOOMBA_PALETTE 5
|
||||
|
||||
typedef uint32_t goomba_size_t; // want a consistent size for printf. This is an alias for uint32_t, but this makes it clear that we're counting the size of something.
|
||||
|
||||
/* 16-bit and 32-bit values in the stateheader are stored as little endian
|
||||
(native to the GBA's ARM chip as well as x86 processors.) Use this function
|
||||
after getting or before setting a value if your code might run on a big-endian
|
||||
processor (e.g. PowerPC.) */
|
||||
uint16_t little_endian_conv_16(uint16_t value);
|
||||
|
||||
/* 16-bit and 32-bit values in the stateheader are stored as little endian
|
||||
(native to the GBA's ARM chip as well as x86 processors.) Use this function
|
||||
after getting or before setting a value if your code might run on a big-endian
|
||||
processor (e.g. PowerPC.) */
|
||||
uint32_t little_endian_conv_32(uint32_t value);
|
||||
|
||||
typedef struct { //(modified stateheader)
|
||||
uint16_t size;
|
||||
uint16_t type; //=CONFIGSAVE
|
||||
char bordercolor;
|
||||
char palettebank;
|
||||
char misc;
|
||||
char reserved3;
|
||||
uint32_t sram_checksum; //checksum of rom using SRAM e000-ffff
|
||||
uint32_t zero; //=0
|
||||
char reserved4[32]; //="CFG"
|
||||
} configdata;
|
||||
|
||||
typedef struct {
|
||||
uint16_t size; //header+data
|
||||
uint16_t type; //=STATESAVE or SRAMSAVE
|
||||
uint32_t uncompressed_size;
|
||||
uint32_t framecount;
|
||||
uint32_t checksum;
|
||||
char title[32];
|
||||
} stateheader;
|
||||
|
||||
typedef struct {
|
||||
const char* sleep;
|
||||
const char* autoload_state;
|
||||
const char* gamma;
|
||||
} configdata_misc_strings;
|
||||
|
||||
/**
|
||||
* Returns the last error encountered by goombasav (for functions that return
|
||||
* NULL on error.) This string is stored statically by goombasav and its
|
||||
* contents may change over time.
|
||||
*/
|
||||
const char* goomba_last_error();
|
||||
|
||||
/**
|
||||
* Set the string buffer used by goomba_last_error to a custom value. If the
|
||||
* input string is too long, the resulting goomba_last_error string will be
|
||||
* truncated.
|
||||
* Returns the number of bytes copied to the buffer (at present, the maximum
|
||||
* is 255.)
|
||||
*/
|
||||
size_t goomba_set_last_error(const char* msg);
|
||||
|
||||
/**
|
||||
* Gets a struct containing pointers to three static strings (which do not
|
||||
* need to be deallocated.)
|
||||
*/
|
||||
configdata_misc_strings configdata_get_misc(char misc);
|
||||
|
||||
/**
|
||||
* Returns a multi-line description string that includes all parameters of the
|
||||
* given stateheader or configdata structure.
|
||||
* This string is stored in a static character buffer, and subsequent calls to
|
||||
* stateheader_str or stateheader_summary_str will overwrite this buffer.
|
||||
*/
|
||||
const char* stateheader_str(const stateheader* sh);
|
||||
|
||||
/**
|
||||
* Returns a one-line summary string displaying the size and title of the
|
||||
* stateheader or configdata structure.
|
||||
* This string is stored in a static character buffer, and subsequent calls to
|
||||
* stateheader_str or stateheader_summary_str will overwrite this buffer.
|
||||
*/
|
||||
const char* stateheader_summary_str(const stateheader* sh);
|
||||
|
||||
int stateheader_plausible(const stateheader* sh);
|
||||
|
||||
/**
|
||||
* When given a pointer to a stateheader, returns a pointer to where the next
|
||||
* stateheader will be located (if any). Use stateheader_plausible to
|
||||
* determine if there really is a header at this location.
|
||||
*
|
||||
* If stateheader_plausible determines that the input is not a valid
|
||||
* stateheader, NULL will be returned.
|
||||
*/
|
||||
stateheader* stateheader_advance(const stateheader* sh);
|
||||
|
||||
/**
|
||||
* Scans for valid stateheaders and allocates an array to store them. The array
|
||||
* will have a capacity of 64, and any difference between that
|
||||
* and the number of headers found will be filled with NULL entries. The last
|
||||
* entry (array[63]) is guaranteed to be NULL.
|
||||
* NOTE: the gba_data parameter can point to a valid header, or to a sequence
|
||||
* equal to GOOMBA_STATEID immediately before a valid header.
|
||||
*/
|
||||
stateheader** stateheader_scan(const void* gba_data);
|
||||
|
||||
/**
|
||||
* Returns the stateheader in gba_data with the title field = gbc_title,
|
||||
* or NULL if there is none. Only the first 15 bytes of gbc_title will be
|
||||
* used in the comparison.
|
||||
*/
|
||||
stateheader* stateheader_for(const void* gba_data, const char* gbc_title_ptr);
|
||||
|
||||
/**
|
||||
* Returns true if the given data starts with GOOMBA_STATEID (little endian.)
|
||||
*/
|
||||
int goomba_is_sram(const void* data);
|
||||
|
||||
/**
|
||||
* Makes a hash of the compressed data that comes after the given header,
|
||||
* using output_bytes bytes. A three-byte hash can be displayed as a color to
|
||||
* give visual feedback of a change in the data. The maximum of output_bytes is
|
||||
* sizeof(int).
|
||||
*/
|
||||
uint64_t goomba_compressed_data_checksum(const stateheader* sh, int output_bytes);
|
||||
|
||||
/**
|
||||
* If there is save data in 0xe000-0xffff (as signaled by the configdata),
|
||||
* this function compresses it to where it's supposed to go. In the event that
|
||||
* the data passed in is already clean, the same pointer will be returned.
|
||||
* NULL will be returned if an error occurs.
|
||||
*
|
||||
* The given pointer must be at least GOOMBA_COLOR_SRAM_SIZE bytes in length.
|
||||
* If it is longer, any information after GOOMBA_COLOR_SRAM_SIZE bytes will be
|
||||
* ignored.
|
||||
*/
|
||||
char* goomba_cleanup(const void* gba_data_param);
|
||||
|
||||
/**
|
||||
* Allocates memory to store the uncompressed GB/GBC save file extracted from
|
||||
* the Goomba Color save file stored in header_ptr, or returns NULL if the
|
||||
* decompression failed.
|
||||
*/
|
||||
void* goomba_extract(const void* gba_data, const stateheader* header_ptr, goomba_size_t* size_output);
|
||||
|
||||
/**
|
||||
* Copies data from the source (which must point to a valid stateheader or
|
||||
* configdata) to dest, up to and including the first 48 bytes that do not
|
||||
* constitute a valid header.
|
||||
*/
|
||||
char* goomba_new_sav(const void* gba_data, const void* gba_header, const void* gbc_sram, goomba_size_t gbc_length);
|
||||
|
||||
#endif
|
339
source/goomba/minilzo-2.06/COPYING
Normal file
@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
124
source/goomba/minilzo-2.06/README.LZO
Normal file
@ -0,0 +1,124 @@
|
||||
|
||||
============================================================================
|
||||
miniLZO -- mini subset of the LZO real-time data compression library
|
||||
============================================================================
|
||||
|
||||
Author : Markus Franz Xaver Johannes Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
Version : 2.06
|
||||
Date : 12 Aug 2011
|
||||
|
||||
I've created miniLZO for projects where it is inconvenient to
|
||||
include (or require) the full LZO source code just because you
|
||||
want to add a little bit of data compression to your application.
|
||||
|
||||
miniLZO implements the LZO1X-1 compressor and both the standard and
|
||||
safe LZO1X decompressor. Apart from fast compression it also useful
|
||||
for situations where you want to use pre-compressed data files (which
|
||||
must have been compressed with LZO1X-999).
|
||||
|
||||
miniLZO consists of one C source file and three header files:
|
||||
minilzo.c
|
||||
minilzo.h, lzoconf.h, lzodefs.h
|
||||
|
||||
To use miniLZO just copy these files into your source directory, add
|
||||
minilzo.c to your Makefile and #include minilzo.h from your program.
|
||||
Note: you also must distribute this file ('README.LZO') with your project.
|
||||
|
||||
minilzo.o compiles to about 6 KiB (using gcc or Visual C on an i386), and
|
||||
the sources are about 30 KiB when packed with zip - so there's no more
|
||||
excuse that your application doesn't support data compression :-)
|
||||
|
||||
For more information, documentation, example programs and other support
|
||||
files (like Makefiles and build scripts) please download the full LZO
|
||||
package from
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
|
||||
Have fun,
|
||||
Markus
|
||||
|
||||
|
||||
P.S. minilzo.c is generated automatically from the LZO sources and
|
||||
therefore functionality is completely identical
|
||||
|
||||
|
||||
Appendix A: building miniLZO
|
||||
----------------------------
|
||||
miniLZO is written such a way that it should compile and run
|
||||
out-of-the-box on most machines.
|
||||
|
||||
If you are running on a very unusual architecture and lzo_init() fails then
|
||||
you should first recompile with '-DLZO_DEBUG' to see what causes the failure.
|
||||
The most probable case is something like 'sizeof(void *) != sizeof(size_t)'.
|
||||
After identifying the problem you can compile by adding some defines
|
||||
like '-DSIZEOF_VOID_P=8' to your Makefile.
|
||||
|
||||
The best solution is (of course) using Autoconf - if your project uses
|
||||
Autoconf anyway just add '-DMINILZO_HAVE_CONFIG_H' to your compiler
|
||||
flags when compiling minilzo.c. See the LZO distribution for an example
|
||||
how to set up configure.ac.
|
||||
|
||||
|
||||
Appendix B: list of public functions available in miniLZO
|
||||
---------------------------------------------------------
|
||||
Library initialization
|
||||
lzo_init()
|
||||
|
||||
Compression
|
||||
lzo1x_1_compress()
|
||||
|
||||
Decompression
|
||||
lzo1x_decompress()
|
||||
lzo1x_decompress_safe()
|
||||
|
||||
Checksum functions
|
||||
lzo_adler32()
|
||||
|
||||
Version functions
|
||||
lzo_version()
|
||||
lzo_version_string()
|
||||
lzo_version_date()
|
||||
|
||||
Portable (but slow) string functions
|
||||
lzo_memcmp()
|
||||
lzo_memcpy()
|
||||
lzo_memmove()
|
||||
lzo_memset()
|
||||
|
||||
|
||||
Appendix C: suggested macros for 'configure.ac' when using Autoconf
|
||||
-------------------------------------------------------------------
|
||||
Checks for typedefs and structures
|
||||
AC_CHECK_TYPE(ptrdiff_t,long)
|
||||
AC_TYPE_SIZE_T
|
||||
AC_CHECK_SIZEOF(short)
|
||||
AC_CHECK_SIZEOF(int)
|
||||
AC_CHECK_SIZEOF(long)
|
||||
AC_CHECK_SIZEOF(long long)
|
||||
AC_CHECK_SIZEOF(__int64)
|
||||
AC_CHECK_SIZEOF(void *)
|
||||
AC_CHECK_SIZEOF(size_t)
|
||||
AC_CHECK_SIZEOF(ptrdiff_t)
|
||||
|
||||
Checks for compiler characteristics
|
||||
AC_C_CONST
|
||||
|
||||
Checks for library functions
|
||||
AC_CHECK_FUNCS(memcmp memcpy memmove memset)
|
||||
|
||||
|
||||
Appendix D: Copyright
|
||||
---------------------
|
||||
LZO and miniLZO are Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001,
|
||||
2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
|
||||
Markus Franz Xaver Oberhumer <markus@oberhumer.com>.
|
||||
|
||||
LZO and miniLZO are distributed under the terms of the GNU General
|
||||
Public License (GPL). See the file COPYING.
|
||||
|
||||
Special licenses for commercial and other applications which
|
||||
are not willing to accept the GNU General Public License
|
||||
are available by contacting the author.
|
||||
|
||||
|
446
source/goomba/minilzo-2.06/lzoconf.h
Normal file
@ -0,0 +1,446 @@
|
||||
/* lzoconf.h -- configuration of the LZO data compression library
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __LZOCONF_H_INCLUDED
|
||||
#define __LZOCONF_H_INCLUDED 1
|
||||
|
||||
#define LZO_VERSION 0x2060
|
||||
#define LZO_VERSION_STRING "2.06"
|
||||
#define LZO_VERSION_DATE "Aug 12 2011"
|
||||
|
||||
/* internal Autoconf configuration file - only used when building LZO */
|
||||
#if defined(LZO_HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// LZO requires a conforming <limits.h>
|
||||
************************************************************************/
|
||||
|
||||
#if !defined(CHAR_BIT) || (CHAR_BIT != 8)
|
||||
# error "invalid CHAR_BIT"
|
||||
#endif
|
||||
#if !defined(UCHAR_MAX) || !defined(UINT_MAX) || !defined(ULONG_MAX)
|
||||
# error "check your compiler installation"
|
||||
#endif
|
||||
#if (USHRT_MAX < 1) || (UINT_MAX < 1) || (ULONG_MAX < 1)
|
||||
# error "your limits.h macros are broken"
|
||||
#endif
|
||||
|
||||
/* get OS and architecture defines */
|
||||
#ifndef __LZODEFS_H_INCLUDED
|
||||
#include "lzodefs.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// some core defines
|
||||
************************************************************************/
|
||||
|
||||
#if !defined(LZO_UINT32_C)
|
||||
# if (UINT_MAX < LZO_0xffffffffL)
|
||||
# define LZO_UINT32_C(c) c ## UL
|
||||
# else
|
||||
# define LZO_UINT32_C(c) ((c) + 0U)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* memory checkers */
|
||||
#if !defined(__LZO_CHECKER)
|
||||
# if defined(__BOUNDS_CHECKING_ON)
|
||||
# define __LZO_CHECKER 1
|
||||
# elif defined(__CHECKER__)
|
||||
# define __LZO_CHECKER 1
|
||||
# elif defined(__INSURE__)
|
||||
# define __LZO_CHECKER 1
|
||||
# elif defined(__PURIFY__)
|
||||
# define __LZO_CHECKER 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// integral and pointer types
|
||||
************************************************************************/
|
||||
|
||||
/* lzo_uint should match size_t */
|
||||
#if !defined(LZO_UINT_MAX)
|
||||
# if defined(LZO_ABI_LLP64) /* WIN64 */
|
||||
# if defined(LZO_OS_WIN64)
|
||||
typedef unsigned __int64 lzo_uint;
|
||||
typedef __int64 lzo_int;
|
||||
# else
|
||||
typedef unsigned long long lzo_uint;
|
||||
typedef long long lzo_int;
|
||||
# endif
|
||||
# define LZO_UINT_MAX 0xffffffffffffffffull
|
||||
# define LZO_INT_MAX 9223372036854775807LL
|
||||
# define LZO_INT_MIN (-1LL - LZO_INT_MAX)
|
||||
# elif defined(LZO_ABI_IP32L64) /* MIPS R5900 */
|
||||
typedef unsigned int lzo_uint;
|
||||
typedef int lzo_int;
|
||||
# define LZO_UINT_MAX UINT_MAX
|
||||
# define LZO_INT_MAX INT_MAX
|
||||
# define LZO_INT_MIN INT_MIN
|
||||
# elif (ULONG_MAX >= LZO_0xffffffffL)
|
||||
typedef unsigned long lzo_uint;
|
||||
typedef long lzo_int;
|
||||
# define LZO_UINT_MAX ULONG_MAX
|
||||
# define LZO_INT_MAX LONG_MAX
|
||||
# define LZO_INT_MIN LONG_MIN
|
||||
# else
|
||||
# error "lzo_uint"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Integral types with 32 bits or more. */
|
||||
#if !defined(LZO_UINT32_MAX)
|
||||
# if (UINT_MAX >= LZO_0xffffffffL)
|
||||
typedef unsigned int lzo_uint32;
|
||||
typedef int lzo_int32;
|
||||
# define LZO_UINT32_MAX UINT_MAX
|
||||
# define LZO_INT32_MAX INT_MAX
|
||||
# define LZO_INT32_MIN INT_MIN
|
||||
# elif (ULONG_MAX >= LZO_0xffffffffL)
|
||||
typedef unsigned long lzo_uint32;
|
||||
typedef long lzo_int32;
|
||||
# define LZO_UINT32_MAX ULONG_MAX
|
||||
# define LZO_INT32_MAX LONG_MAX
|
||||
# define LZO_INT32_MIN LONG_MIN
|
||||
# else
|
||||
# error "lzo_uint32"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Integral types with exactly 64 bits. */
|
||||
#if !defined(LZO_UINT64_MAX)
|
||||
# if (LZO_UINT_MAX >= LZO_0xffffffffL)
|
||||
# if ((((LZO_UINT_MAX) >> 31) >> 31) == 3)
|
||||
# define lzo_uint64 lzo_uint
|
||||
# define lzo_int64 lzo_int
|
||||
# define LZO_UINT64_MAX LZO_UINT_MAX
|
||||
# define LZO_INT64_MAX LZO_INT_MAX
|
||||
# define LZO_INT64_MIN LZO_INT_MIN
|
||||
# endif
|
||||
# elif (ULONG_MAX >= LZO_0xffffffffL)
|
||||
# if ((((ULONG_MAX) >> 31) >> 31) == 3)
|
||||
typedef unsigned long lzo_uint64;
|
||||
typedef long lzo_int64;
|
||||
# define LZO_UINT64_MAX ULONG_MAX
|
||||
# define LZO_INT64_MAX LONG_MAX
|
||||
# define LZO_INT64_MIN LONG_MIN
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* The larger type of lzo_uint and lzo_uint32. */
|
||||
#if (LZO_UINT_MAX >= LZO_UINT32_MAX)
|
||||
# define lzo_xint lzo_uint
|
||||
#else
|
||||
# define lzo_xint lzo_uint32
|
||||
#endif
|
||||
|
||||
/* Memory model that allows to access memory at offsets of lzo_uint. */
|
||||
#if !defined(__LZO_MMODEL)
|
||||
# if (LZO_UINT_MAX <= UINT_MAX)
|
||||
# define __LZO_MMODEL /*empty*/
|
||||
# elif defined(LZO_HAVE_MM_HUGE_PTR)
|
||||
# define __LZO_MMODEL_HUGE 1
|
||||
# define __LZO_MMODEL __huge
|
||||
# else
|
||||
# define __LZO_MMODEL /*empty*/
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* no typedef here because of const-pointer issues */
|
||||
#define lzo_bytep unsigned char __LZO_MMODEL *
|
||||
#define lzo_charp char __LZO_MMODEL *
|
||||
#define lzo_voidp void __LZO_MMODEL *
|
||||
#define lzo_shortp short __LZO_MMODEL *
|
||||
#define lzo_ushortp unsigned short __LZO_MMODEL *
|
||||
#define lzo_uint32p lzo_uint32 __LZO_MMODEL *
|
||||
#define lzo_int32p lzo_int32 __LZO_MMODEL *
|
||||
#if defined(LZO_UINT64_MAX)
|
||||
#define lzo_uint64p lzo_uint64 __LZO_MMODEL *
|
||||
#define lzo_int64p lzo_int64 __LZO_MMODEL *
|
||||
#endif
|
||||
#define lzo_uintp lzo_uint __LZO_MMODEL *
|
||||
#define lzo_intp lzo_int __LZO_MMODEL *
|
||||
#define lzo_xintp lzo_xint __LZO_MMODEL *
|
||||
#define lzo_voidpp lzo_voidp __LZO_MMODEL *
|
||||
#define lzo_bytepp lzo_bytep __LZO_MMODEL *
|
||||
/* deprecated - use 'lzo_bytep' instead of 'lzo_byte *' */
|
||||
#define lzo_byte unsigned char __LZO_MMODEL
|
||||
|
||||
typedef int lzo_bool;
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// function types
|
||||
************************************************************************/
|
||||
|
||||
/* name mangling */
|
||||
#if !defined(__LZO_EXTERN_C)
|
||||
# ifdef __cplusplus
|
||||
# define __LZO_EXTERN_C extern "C"
|
||||
# else
|
||||
# define __LZO_EXTERN_C extern
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* calling convention */
|
||||
#if !defined(__LZO_CDECL)
|
||||
# define __LZO_CDECL __lzo_cdecl
|
||||
#endif
|
||||
|
||||
/* DLL export information */
|
||||
#if !defined(__LZO_EXPORT1)
|
||||
# define __LZO_EXPORT1 /*empty*/
|
||||
#endif
|
||||
#if !defined(__LZO_EXPORT2)
|
||||
# define __LZO_EXPORT2 /*empty*/
|
||||
#endif
|
||||
|
||||
/* __cdecl calling convention for public C and assembly functions */
|
||||
#if !defined(LZO_PUBLIC)
|
||||
# define LZO_PUBLIC(_rettype) __LZO_EXPORT1 _rettype __LZO_EXPORT2 __LZO_CDECL
|
||||
#endif
|
||||
#if !defined(LZO_EXTERN)
|
||||
# define LZO_EXTERN(_rettype) __LZO_EXTERN_C LZO_PUBLIC(_rettype)
|
||||
#endif
|
||||
#if !defined(LZO_PRIVATE)
|
||||
# define LZO_PRIVATE(_rettype) static _rettype __LZO_CDECL
|
||||
#endif
|
||||
|
||||
/* function types */
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_compress_t) ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_decompress_t) ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_optimize_t) ( lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_compress_dict_t)(const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem,
|
||||
const lzo_bytep dict, lzo_uint dict_len );
|
||||
|
||||
typedef int
|
||||
(__LZO_CDECL *lzo_decompress_dict_t)(const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem,
|
||||
const lzo_bytep dict, lzo_uint dict_len );
|
||||
|
||||
|
||||
/* Callback interface. Currently only the progress indicator ("nprogress")
|
||||
* is used, but this may change in a future release. */
|
||||
|
||||
struct lzo_callback_t;
|
||||
typedef struct lzo_callback_t lzo_callback_t;
|
||||
#define lzo_callback_p lzo_callback_t __LZO_MMODEL *
|
||||
|
||||
/* malloc & free function types */
|
||||
typedef lzo_voidp (__LZO_CDECL *lzo_alloc_func_t)
|
||||
(lzo_callback_p self, lzo_uint items, lzo_uint size);
|
||||
typedef void (__LZO_CDECL *lzo_free_func_t)
|
||||
(lzo_callback_p self, lzo_voidp ptr);
|
||||
|
||||
/* a progress indicator callback function */
|
||||
typedef void (__LZO_CDECL *lzo_progress_func_t)
|
||||
(lzo_callback_p, lzo_uint, lzo_uint, int);
|
||||
|
||||
struct lzo_callback_t
|
||||
{
|
||||
/* custom allocators (set to 0 to disable) */
|
||||
lzo_alloc_func_t nalloc; /* [not used right now] */
|
||||
lzo_free_func_t nfree; /* [not used right now] */
|
||||
|
||||
/* a progress indicator callback function (set to 0 to disable) */
|
||||
lzo_progress_func_t nprogress;
|
||||
|
||||
/* NOTE: the first parameter "self" of the nalloc/nfree/nprogress
|
||||
* callbacks points back to this struct, so you are free to store
|
||||
* some extra info in the following variables. */
|
||||
lzo_voidp user1;
|
||||
lzo_xint user2;
|
||||
lzo_xint user3;
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// error codes and prototypes
|
||||
************************************************************************/
|
||||
|
||||
/* Error codes for the compression/decompression functions. Negative
|
||||
* values are errors, positive values will be used for special but
|
||||
* normal events.
|
||||
*/
|
||||
#define LZO_E_OK 0
|
||||
#define LZO_E_ERROR (-1)
|
||||
#define LZO_E_OUT_OF_MEMORY (-2) /* [lzo_alloc_func_t failure] */
|
||||
#define LZO_E_NOT_COMPRESSIBLE (-3) /* [not used right now] */
|
||||
#define LZO_E_INPUT_OVERRUN (-4)
|
||||
#define LZO_E_OUTPUT_OVERRUN (-5)
|
||||
#define LZO_E_LOOKBEHIND_OVERRUN (-6)
|
||||
#define LZO_E_EOF_NOT_FOUND (-7)
|
||||
#define LZO_E_INPUT_NOT_CONSUMED (-8)
|
||||
#define LZO_E_NOT_YET_IMPLEMENTED (-9) /* [not used right now] */
|
||||
#define LZO_E_INVALID_ARGUMENT (-10)
|
||||
|
||||
|
||||
#ifndef lzo_sizeof_dict_t
|
||||
# define lzo_sizeof_dict_t ((unsigned)sizeof(lzo_bytep))
|
||||
#endif
|
||||
|
||||
/* lzo_init() should be the first function you call.
|
||||
* Check the return code !
|
||||
*
|
||||
* lzo_init() is a macro to allow checking that the library and the
|
||||
* compiler's view of various types are consistent.
|
||||
*/
|
||||
#define lzo_init() __lzo_init_v2(LZO_VERSION,(int)sizeof(short),(int)sizeof(int),\
|
||||
(int)sizeof(long),(int)sizeof(lzo_uint32),(int)sizeof(lzo_uint),\
|
||||
(int)lzo_sizeof_dict_t,(int)sizeof(char *),(int)sizeof(lzo_voidp),\
|
||||
(int)sizeof(lzo_callback_t))
|
||||
LZO_EXTERN(int) __lzo_init_v2(unsigned,int,int,int,int,int,int,int,int,int);
|
||||
|
||||
/* version functions (useful for shared libraries) */
|
||||
LZO_EXTERN(unsigned) lzo_version(void);
|
||||
LZO_EXTERN(const char *) lzo_version_string(void);
|
||||
LZO_EXTERN(const char *) lzo_version_date(void);
|
||||
LZO_EXTERN(const lzo_charp) _lzo_version_string(void);
|
||||
LZO_EXTERN(const lzo_charp) _lzo_version_date(void);
|
||||
|
||||
/* string functions */
|
||||
LZO_EXTERN(int)
|
||||
lzo_memcmp(const lzo_voidp a, const lzo_voidp b, lzo_uint len);
|
||||
LZO_EXTERN(lzo_voidp)
|
||||
lzo_memcpy(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
|
||||
LZO_EXTERN(lzo_voidp)
|
||||
lzo_memmove(lzo_voidp dst, const lzo_voidp src, lzo_uint len);
|
||||
LZO_EXTERN(lzo_voidp)
|
||||
lzo_memset(lzo_voidp buf, int c, lzo_uint len);
|
||||
|
||||
/* checksum functions */
|
||||
LZO_EXTERN(lzo_uint32)
|
||||
lzo_adler32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
|
||||
LZO_EXTERN(lzo_uint32)
|
||||
lzo_crc32(lzo_uint32 c, const lzo_bytep buf, lzo_uint len);
|
||||
LZO_EXTERN(const lzo_uint32p)
|
||||
lzo_get_crc32_table(void);
|
||||
|
||||
/* misc. */
|
||||
LZO_EXTERN(int) _lzo_config_check(void);
|
||||
typedef union { lzo_bytep p; lzo_uint u; } __lzo_pu_u;
|
||||
typedef union { lzo_bytep p; lzo_uint32 u32; } __lzo_pu32_u;
|
||||
typedef union { void *vp; lzo_bytep bp; lzo_uint u; lzo_uint32 u32; unsigned long l; } lzo_align_t;
|
||||
|
||||
/* align a char pointer on a boundary that is a multiple of 'size' */
|
||||
LZO_EXTERN(unsigned) __lzo_align_gap(const lzo_voidp p, lzo_uint size);
|
||||
#define LZO_PTR_ALIGN_UP(p,size) \
|
||||
((p) + (lzo_uint) __lzo_align_gap((const lzo_voidp)(p),(lzo_uint)(size)))
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
// deprecated macros - only for backward compatibility with LZO v1.xx
|
||||
************************************************************************/
|
||||
|
||||
#if defined(LZO_CFG_COMPAT)
|
||||
|
||||
#define __LZOCONF_H 1
|
||||
|
||||
#if defined(LZO_ARCH_I086)
|
||||
# define __LZO_i386 1
|
||||
#elif defined(LZO_ARCH_I386)
|
||||
# define __LZO_i386 1
|
||||
#endif
|
||||
|
||||
#if defined(LZO_OS_DOS16)
|
||||
# define __LZO_DOS 1
|
||||
# define __LZO_DOS16 1
|
||||
#elif defined(LZO_OS_DOS32)
|
||||
# define __LZO_DOS 1
|
||||
#elif defined(LZO_OS_WIN16)
|
||||
# define __LZO_WIN 1
|
||||
# define __LZO_WIN16 1
|
||||
#elif defined(LZO_OS_WIN32)
|
||||
# define __LZO_WIN 1
|
||||
#endif
|
||||
|
||||
#define __LZO_CMODEL /*empty*/
|
||||
#define __LZO_DMODEL /*empty*/
|
||||
#define __LZO_ENTRY __LZO_CDECL
|
||||
#define LZO_EXTERN_CDECL LZO_EXTERN
|
||||
#define LZO_ALIGN LZO_PTR_ALIGN_UP
|
||||
|
||||
#define lzo_compress_asm_t lzo_compress_t
|
||||
#define lzo_decompress_asm_t lzo_decompress_t
|
||||
|
||||
#endif /* LZO_CFG_COMPAT */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* already included */
|
||||
|
||||
|
||||
/* vim:set ts=4 et: */
|
1852
source/goomba/minilzo-2.06/lzodefs.h
Normal file
4579
source/goomba/minilzo-2.06/minilzo.cpp
Normal file
109
source/goomba/minilzo-2.06/minilzo.h
Normal file
@ -0,0 +1,109 @@
|
||||
/* minilzo.h -- mini subset of the LZO real-time data compression library
|
||||
|
||||
This file is part of the LZO real-time data compression library.
|
||||
|
||||
Copyright (C) 2011 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2010 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2009 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
|
||||
Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
|
||||
All Rights Reserved.
|
||||
|
||||
The LZO library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
The LZO library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with the LZO library; see the file COPYING.
|
||||
If not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
Markus F.X.J. Oberhumer
|
||||
<markus@oberhumer.com>
|
||||
http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* the full LZO package can be found at
|
||||
* http://www.oberhumer.com/opensource/lzo/
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __MINILZO_H
|
||||
#define __MINILZO_H 1
|
||||
|
||||
#define MINILZO_VERSION 0x2060
|
||||
|
||||
#ifdef __LZOCONF_H
|
||||
# error "you cannot use both LZO and miniLZO"
|
||||
#endif
|
||||
|
||||
#undef LZO_HAVE_CONFIG_H
|
||||
#include "lzoconf.h"
|
||||
|
||||
#if !defined(LZO_VERSION) || (LZO_VERSION != MINILZO_VERSION)
|
||||
# error "version mismatch in header files"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
//
|
||||
************************************************************************/
|
||||
|
||||
/* Memory required for the wrkmem parameter.
|
||||
* When the required size is 0, you can also pass a NULL pointer.
|
||||
*/
|
||||
|
||||
#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS
|
||||
#define LZO1X_1_MEM_COMPRESS ((lzo_uint32) (16384L * lzo_sizeof_dict_t))
|
||||
#define LZO1X_MEM_DECOMPRESS (0)
|
||||
|
||||
|
||||
/* compression */
|
||||
LZO_EXTERN(int)
|
||||
lzo1x_1_compress ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem );
|
||||
|
||||
/* decompression */
|
||||
LZO_EXTERN(int)
|
||||
lzo1x_decompress ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem /* NOT USED */ );
|
||||
|
||||
/* safe decompression with overrun testing */
|
||||
LZO_EXTERN(int)
|
||||
lzo1x_decompress_safe ( const lzo_bytep src, lzo_uint src_len,
|
||||
lzo_bytep dst, lzo_uintp dst_len,
|
||||
lzo_voidp wrkmem /* NOT USED */ );
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* already included */
|
||||
|
@ -123,6 +123,16 @@ typedef struct _paddata {
|
||||
u8 triggerR;
|
||||
} PADData;
|
||||
|
||||
typedef struct _wupcfulldata {
|
||||
u32 btns_d;
|
||||
u32 btns_u;
|
||||
u32 btns_h;
|
||||
s16 stickX;
|
||||
s16 stickY;
|
||||
s16 substickX;
|
||||
s16 substickY;
|
||||
} WUPCFullData;
|
||||
|
||||
#define EFFECT_SLIDE_TOP 1
|
||||
#define EFFECT_SLIDE_BOTTOM 2
|
||||
#define EFFECT_SLIDE_RIGHT 4
|
||||
@ -226,6 +236,7 @@ class GuiTrigger
|
||||
|
||||
WPADData wpaddata; //!< Wii controller trigger data
|
||||
PADData pad; //!< GameCube controller trigger data
|
||||
WUPCFullData wupcdata; //!< WiiU Pro controller trigger data
|
||||
WPADData * wpad; //!< Wii controller trigger
|
||||
s32 chan; //!< Trigger controller channel (0-3, -1 for all)
|
||||
u8 type; //!< trigger type (TRIGGER_SIMPLE, TRIGGER_HELD, TRIGGER_BUTTON_ONLY, TRIGGER_BUTTON_ONLY_IN_FOCUS)
|
||||
@ -240,7 +251,7 @@ class GuiElement
|
||||
//!Constructor
|
||||
GuiElement();
|
||||
//!Destructor
|
||||
~GuiElement();
|
||||
virtual ~GuiElement();
|
||||
//!Set the element's parent
|
||||
//!\param e Pointer to parent element
|
||||
void SetParent(GuiElement * e);
|
||||
|
@ -254,7 +254,7 @@ void GuiButton::Update(GuiTrigger * t)
|
||||
// button triggers
|
||||
if(this->IsClickable())
|
||||
{
|
||||
s32 wm_btns, wm_btns_trig, cc_btns, cc_btns_trig;
|
||||
s32 wm_btns, wm_btns_trig, cc_btns, cc_btns_trig, wupc_btns, wupc_btns_trig;
|
||||
for(int i=0; i<3; i++)
|
||||
{
|
||||
if(trigger[i] && (trigger[i]->chan == -1 || trigger[i]->chan == t->chan))
|
||||
@ -267,11 +267,16 @@ void GuiButton::Update(GuiTrigger * t)
|
||||
cc_btns = t->wpad->btns_d >> 16;
|
||||
cc_btns_trig = trigger[i]->wpad->btns_d >> 16;
|
||||
|
||||
// lower 16 bits only (WiiU Pro controller)
|
||||
wupc_btns = t->wupcdata.btns_d >> 16;
|
||||
wupc_btns_trig = trigger[i]->wupcdata.btns_d >> 16;
|
||||
|
||||
if(
|
||||
(t->wpad->btns_d > 0 &&
|
||||
(wm_btns == wm_btns_trig ||
|
||||
(cc_btns == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) ||
|
||||
(t->pad.btns_d == trigger[i]->pad.btns_d && t->pad.btns_d > 0))
|
||||
(t->pad.btns_d == trigger[i]->pad.btns_d && t->pad.btns_d > 0) ||
|
||||
(wupc_btns == wupc_btns_trig && wupc_btns_trig > 0))
|
||||
{
|
||||
if(t->chan == stateChan || stateChan == -1)
|
||||
{
|
||||
@ -303,7 +308,7 @@ void GuiButton::Update(GuiTrigger * t)
|
||||
if(this->IsHoldable())
|
||||
{
|
||||
bool held = false;
|
||||
s32 wm_btns, wm_btns_h, wm_btns_trig, cc_btns, cc_btns_h, cc_btns_trig;
|
||||
s32 wm_btns, wm_btns_h, wm_btns_trig, cc_btns, cc_btns_h, cc_btns_trig, wupc_btns, wupc_btns_h, wupc_btns_trig;
|
||||
|
||||
for(int i=0; i<3; i++)
|
||||
{
|
||||
@ -319,11 +324,17 @@ void GuiButton::Update(GuiTrigger * t)
|
||||
cc_btns_h = t->wpad->btns_h >> 16;
|
||||
cc_btns_trig = trigger[i]->wpad->btns_h >> 16;
|
||||
|
||||
// lower 16 bits only (WiiU Pro controller)
|
||||
wupc_btns = t->wpad->btns_d >> 16;
|
||||
wupc_btns_h = t->wpad->btns_h >> 16;
|
||||
wupc_btns_trig = trigger[i]->wpad->btns_h >> 16;
|
||||
|
||||
if(
|
||||
(t->wpad->btns_d > 0 &&
|
||||
(wm_btns == wm_btns_trig ||
|
||||
(cc_btns == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) ||
|
||||
(t->pad.btns_d == trigger[i]->pad.btns_h && t->pad.btns_d > 0))
|
||||
(t->pad.btns_d == trigger[i]->pad.btns_h && t->pad.btns_d > 0) ||
|
||||
(wupc_btns == wupc_btns_trig && wupc_btns > 0))
|
||||
{
|
||||
if(trigger[i]->type == TRIGGER_HELD && state == STATE_SELECTED &&
|
||||
(t->chan == stateChan || stateChan == -1))
|
||||
@ -334,7 +345,8 @@ void GuiButton::Update(GuiTrigger * t)
|
||||
(t->wpad->btns_h > 0 &&
|
||||
(wm_btns_h == wm_btns_trig ||
|
||||
(cc_btns_h == cc_btns_trig && t->wpad->exp.type == EXP_CLASSIC))) ||
|
||||
(t->pad.btns_h == trigger[i]->pad.btns_h && t->pad.btns_h > 0))
|
||||
(t->pad.btns_h == trigger[i]->pad.btns_h && t->pad.btns_h > 0) ||
|
||||
(wupc_btns_h == wupc_btns_trig && wupc_btns_h > 0))
|
||||
{
|
||||
if(trigger[i]->type == TRIGGER_HELD)
|
||||
held = true;
|
||||
|
@ -108,12 +108,12 @@ GuiFileBrowser::GuiFileBrowser(int w, int h)
|
||||
fileListText[i] = new GuiText(NULL, 20, (GXColor){0, 0, 0, 0xff});
|
||||
fileListText[i]->SetAlignment(ALIGN_LEFT, ALIGN_MIDDLE);
|
||||
fileListText[i]->SetPosition(5,0);
|
||||
fileListText[i]->SetMaxWidth(380);
|
||||
fileListText[i]->SetMaxWidth(295);
|
||||
|
||||
fileListBg[i] = new GuiImage(bgFileSelectionEntry);
|
||||
fileListIcon[i] = NULL;
|
||||
|
||||
fileList[i] = new GuiButton(380, 26);
|
||||
fileList[i] = new GuiButton(295, 26);
|
||||
fileList[i]->SetParent(this);
|
||||
fileList[i]->SetLabel(fileListText[i]);
|
||||
fileList[i]->SetImageOver(fileListBg[i]);
|
||||
|
@ -22,7 +22,8 @@ static char * GetDisplayText(char * t)
|
||||
if(len < MAX_KEYBOARD_DISPLAY)
|
||||
return t;
|
||||
|
||||
snprintf(tmptxt, MAX_KEYBOARD_DISPLAY, "%s", &t[len-MAX_KEYBOARD_DISPLAY]);
|
||||
strncpy(tmptxt, &t[len-MAX_KEYBOARD_DISPLAY], MAX_KEYBOARD_DISPLAY);
|
||||
tmptxt[MAX_KEYBOARD_DISPLAY-1] = 0;
|
||||
return &tmptxt[0];
|
||||
}
|
||||
|
||||
@ -40,7 +41,8 @@ GuiKeyboard::GuiKeyboard(char * t, u32 max)
|
||||
focus = 0; // allow focus
|
||||
alignmentHor = ALIGN_CENTRE;
|
||||
alignmentVert = ALIGN_MIDDLE;
|
||||
snprintf(kbtextstr, 255, "%s", t);
|
||||
strncpy(kbtextstr, t, max);
|
||||
kbtextstr[max] = 0;
|
||||
kbtextmaxlen = max;
|
||||
|
||||
Key thekeys[4][11] = {
|
||||
@ -106,7 +108,7 @@ GuiKeyboard::GuiKeyboard(char * t, u32 max)
|
||||
keyTextboxImg->SetPosition(0, 0);
|
||||
this->Append(keyTextboxImg);
|
||||
|
||||
kbText = new GuiText(GetDisplayText(kbtextstr), 22, (GXColor){0, 0, 0, 0xff});
|
||||
kbText = new GuiText(GetDisplayText(kbtextstr), 20, (GXColor){0, 0, 0, 0xff});
|
||||
kbText->SetAlignment(ALIGN_CENTRE, ALIGN_TOP);
|
||||
kbText->SetPosition(0, 13);
|
||||
this->Append(kbText);
|
||||
@ -128,7 +130,7 @@ GuiKeyboard::GuiKeyboard(char * t, u32 max)
|
||||
|
||||
keyBackImg = new GuiImage(keyMedium);
|
||||
keyBackOverImg = new GuiImage(keyMediumOver);
|
||||
keyBackText = new GuiText("Back", 22, (GXColor){0, 0, 0, 0xff});
|
||||
keyBackText = new GuiText("Back", 20, (GXColor){0, 0, 0, 0xff});
|
||||
keyBack = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight());
|
||||
keyBack->SetImage(keyBackImg);
|
||||
keyBack->SetImageOver(keyBackOverImg);
|
||||
@ -143,7 +145,7 @@ GuiKeyboard::GuiKeyboard(char * t, u32 max)
|
||||
|
||||
keyCapsImg = new GuiImage(keyMedium);
|
||||
keyCapsOverImg = new GuiImage(keyMediumOver);
|
||||
keyCapsText = new GuiText("Caps", 22, (GXColor){0, 0, 0, 0xff});
|
||||
keyCapsText = new GuiText("Caps", 20, (GXColor){0, 0, 0, 0xff});
|
||||
keyCaps = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight());
|
||||
keyCaps->SetImage(keyCapsImg);
|
||||
keyCaps->SetImageOver(keyCapsOverImg);
|
||||
@ -158,7 +160,7 @@ GuiKeyboard::GuiKeyboard(char * t, u32 max)
|
||||
|
||||
keyShiftImg = new GuiImage(keyMedium);
|
||||
keyShiftOverImg = new GuiImage(keyMediumOver);
|
||||
keyShiftText = new GuiText("Shift", 22, (GXColor){0, 0, 0, 0xff});
|
||||
keyShiftText = new GuiText("Shift", 20, (GXColor){0, 0, 0, 0xff});
|
||||
keyShift = new GuiButton(keyMedium->GetWidth(), keyMedium->GetHeight());
|
||||
keyShift->SetImage(keyShiftImg);
|
||||
keyShift->SetImageOver(keyShiftOverImg);
|
||||
@ -196,9 +198,9 @@ GuiKeyboard::GuiKeyboard(char * t, u32 max)
|
||||
txt[0] = keys[i][j].ch;
|
||||
keyImg[i][j] = new GuiImage(key);
|
||||
keyImgOver[i][j] = new GuiImage(keyOver);
|
||||
keyTxt[i][j] = new GuiText(txt, 22, (GXColor){0, 0, 0, 0xff});
|
||||
keyTxt[i][j] = new GuiText(txt, 20, (GXColor){0, 0, 0, 0xff});
|
||||
keyTxt[i][j]->SetAlignment(ALIGN_CENTRE, ALIGN_BOTTOM);
|
||||
keyTxt[i][j]->SetPosition(0, -8);
|
||||
keyTxt[i][j]->SetPosition(0, -10);
|
||||
keyBtn[i][j] = new GuiButton(key->GetWidth(), key->GetHeight());
|
||||
keyBtn[i][j]->SetImage(keyImg[i][j]);
|
||||
keyBtn[i][j]->SetImageOver(keyImgOver[i][j]);
|
||||
|
@ -22,6 +22,7 @@ static u32 delay[4];
|
||||
GuiTrigger::GuiTrigger()
|
||||
{
|
||||
chan = -1;
|
||||
memset(&wupcdata, 0, sizeof(WUPCFullData));
|
||||
memset(&wpaddata, 0, sizeof(WPADData));
|
||||
memset(&pad, 0, sizeof(PADData));
|
||||
wpad = &wpaddata;
|
||||
@ -43,6 +44,7 @@ void GuiTrigger::SetSimpleTrigger(s32 ch, u32 wiibtns, u16 gcbtns)
|
||||
{
|
||||
type = TRIGGER_SIMPLE;
|
||||
chan = ch;
|
||||
wupcdata.btns_d = wiibtns;
|
||||
wpaddata.btns_d = wiibtns;
|
||||
pad.btns_d = gcbtns;
|
||||
}
|
||||
@ -56,6 +58,7 @@ void GuiTrigger::SetHeldTrigger(s32 ch, u32 wiibtns, u16 gcbtns)
|
||||
{
|
||||
type = TRIGGER_HELD;
|
||||
chan = ch;
|
||||
wupcdata.btns_h = wiibtns;
|
||||
wpaddata.btns_h = wiibtns;
|
||||
pad.btns_h = gcbtns;
|
||||
}
|
||||
@ -68,6 +71,7 @@ void GuiTrigger::SetButtonOnlyTrigger(s32 ch, u32 wiibtns, u16 gcbtns)
|
||||
{
|
||||
type = TRIGGER_BUTTON_ONLY;
|
||||
chan = ch;
|
||||
wupcdata.btns_d = wiibtns;
|
||||
wpaddata.btns_d = wiibtns;
|
||||
pad.btns_d = gcbtns;
|
||||
}
|
||||
@ -81,6 +85,7 @@ void GuiTrigger::SetButtonOnlyInFocusTrigger(s32 ch, u32 wiibtns, u16 gcbtns)
|
||||
{
|
||||
type = TRIGGER_BUTTON_ONLY_IN_FOCUS;
|
||||
chan = ch;
|
||||
wupcdata.btns_d = wiibtns;
|
||||
wpaddata.btns_d = wiibtns;
|
||||
pad.btns_d = gcbtns;
|
||||
}
|
||||
@ -158,12 +163,15 @@ bool GuiTrigger::Left()
|
||||
u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_UP : WPAD_BUTTON_LEFT;
|
||||
|
||||
if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT)
|
||||
|| (wupcdata.btns_d | wupcdata.btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT)
|
||||
|| (pad.btns_d | pad.btns_h) & PAD_BUTTON_LEFT
|
||||
|| pad.stickX < -PADCAL
|
||||
|| WPAD_StickX(0) < -PADCAL)
|
||||
|| WPAD_StickX(0) < -PADCAL
|
||||
|| wupcdata.stickX < -WUPCCAL)
|
||||
{
|
||||
if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT)
|
||||
|| pad.btns_d & PAD_BUTTON_LEFT)
|
||||
if((wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT))
|
||||
|| (wupcdata.btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_LEFT))
|
||||
|| pad.btns_d & PAD_BUTTON_LEFT)
|
||||
{
|
||||
prev[chan] = gettime();
|
||||
delay[chan] = SCROLL_DELAY_INITIAL; // reset scroll delay
|
||||
@ -191,11 +199,14 @@ bool GuiTrigger::Right()
|
||||
u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_DOWN : WPAD_BUTTON_RIGHT;
|
||||
|
||||
if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT)
|
||||
|| ((wupcdata.btns_d | wupcdata.btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT))
|
||||
|| (pad.btns_d | pad.btns_h) & PAD_BUTTON_RIGHT
|
||||
|| pad.stickX > PADCAL
|
||||
|| WPAD_StickX(0) > PADCAL)
|
||||
|| WPAD_StickX(0) > PADCAL
|
||||
|| wupcdata.stickX > WUPCCAL)
|
||||
{
|
||||
if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT)
|
||||
if((wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT))
|
||||
|| (wupcdata.btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_RIGHT))
|
||||
|| pad.btns_d & PAD_BUTTON_RIGHT)
|
||||
{
|
||||
prev[chan] = gettime();
|
||||
@ -223,12 +234,15 @@ bool GuiTrigger::Up()
|
||||
{
|
||||
u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_RIGHT : WPAD_BUTTON_UP;
|
||||
|
||||
if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_UP)
|
||||
if(((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_UP))
|
||||
|| ((wupcdata.btns_d | wupcdata.btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_UP))
|
||||
|| (pad.btns_d | pad.btns_h) & PAD_BUTTON_UP
|
||||
|| pad.stickY > PADCAL
|
||||
|| WPAD_StickY(0) > PADCAL)
|
||||
|| WPAD_StickY(0) > PADCAL
|
||||
|| wupcdata.stickY > WUPCCAL)
|
||||
{
|
||||
if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_UP)
|
||||
if((wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_UP))
|
||||
|| (wupcdata.btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_UP))
|
||||
|| pad.btns_d & PAD_BUTTON_UP)
|
||||
{
|
||||
prev[chan] = gettime();
|
||||
@ -256,12 +270,15 @@ bool GuiTrigger::Down()
|
||||
{
|
||||
u32 wiibtn = GCSettings.WiimoteOrientation ? WPAD_BUTTON_LEFT : WPAD_BUTTON_DOWN;
|
||||
|
||||
if((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN)
|
||||
if(((wpad->btns_d | wpad->btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN))
|
||||
|| ((wupcdata.btns_d | wupcdata.btns_h) & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN))
|
||||
|| (pad.btns_d | pad.btns_h) & PAD_BUTTON_DOWN
|
||||
|| pad.stickY < -PADCAL
|
||||
|| WPAD_StickY(0) < -PADCAL)
|
||||
|| WPAD_StickY(0) < -PADCAL
|
||||
|| wupcdata.stickY < -WUPCCAL)
|
||||
{
|
||||
if(wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN)
|
||||
if((wpad->btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN))
|
||||
|| wupcdata.btns_d & (wiibtn | WPAD_CLASSIC_BUTTON_DOWN)
|
||||
|| pad.btns_d & PAD_BUTTON_DOWN)
|
||||
{
|
||||
prev[chan] = gettime();
|
||||
|
@ -228,8 +228,8 @@ void GuiWindow::ToggleFocus(GuiTrigger * t)
|
||||
}
|
||||
}
|
||||
// change focus
|
||||
else if(t->wpad->btns_d & (WPAD_BUTTON_1 | WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B)
|
||||
|| t->pad.btns_d & PAD_BUTTON_B)
|
||||
else if((t->wpad->btns_d & (WPAD_BUTTON_1 | WPAD_BUTTON_B | WPAD_CLASSIC_BUTTON_B))
|
||||
|| (t->pad.btns_d & PAD_BUTTON_B) || (t->wupcdata.btns_d & WPAD_CLASSIC_BUTTON_B))
|
||||
{
|
||||
for (i = found; i < elemSize; ++i)
|
||||
{
|
||||
|
BIN
source/images/bg_preview.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 69 KiB |
BIN
source/images/icon_settings_screenshot.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
source/images/icon_settings_wiiupro.png
Normal file
After Width: | Height: | Size: 10 KiB |
102
source/input.cpp
@ -16,6 +16,7 @@
|
||||
#include <ogcsys.h>
|
||||
#include <unistd.h>
|
||||
#include <wiiuse/wpad.h>
|
||||
#include <wupc/wupc.h>
|
||||
#include <ogc/lwp_watchdog.h>
|
||||
|
||||
#include "vbagx.h"
|
||||
@ -138,6 +139,7 @@ void
|
||||
UpdatePads()
|
||||
{
|
||||
#ifdef HW_RVL
|
||||
WUPC_UpdateButtonStats();
|
||||
WPAD_ScanPads();
|
||||
#endif
|
||||
|
||||
@ -154,6 +156,15 @@ UpdatePads()
|
||||
userInput[i].pad.substickY = PAD_SubStickY(i);
|
||||
userInput[i].pad.triggerL = PAD_TriggerL(i);
|
||||
userInput[i].pad.triggerR = PAD_TriggerR(i);
|
||||
#ifdef HW_RVL
|
||||
userInput[i].wupcdata.btns_d = WUPC_ButtonsDown(i);
|
||||
userInput[i].wupcdata.btns_u = WUPC_ButtonsUp(i);
|
||||
userInput[i].wupcdata.btns_h = WUPC_ButtonsHeld(i);
|
||||
userInput[i].wupcdata.stickX = WUPC_lStickX(i);
|
||||
userInput[i].wupcdata.stickY = WUPC_lStickY(i);
|
||||
userInput[i].wupcdata.substickX = WUPC_rStickX(i);
|
||||
userInput[i].wupcdata.substickY = WUPC_rStickY(i);
|
||||
#endif
|
||||
--i;
|
||||
} while(i >= 0);
|
||||
}
|
||||
@ -311,6 +322,9 @@ u32 StandardMovement(unsigned short chan)
|
||||
#ifdef HW_RVL
|
||||
s8 wm_ax = userInput[0].WPAD_StickX(0);
|
||||
s8 wm_ay = userInput[0].WPAD_StickY(0);
|
||||
|
||||
s16 wupc_ax = userInput[chan].wupcdata.stickX;
|
||||
s16 wupc_ay = userInput[chan].wupcdata.stickY;
|
||||
#endif
|
||||
|
||||
/***
|
||||
@ -338,7 +352,19 @@ u32 StandardMovement(unsigned short chan)
|
||||
if (wm_ax * wm_ax + wm_ay * wm_ay > PADCAL * PADCAL)
|
||||
{
|
||||
angle = atan2(wm_ay, wm_ax);
|
||||
|
||||
if(cos(angle) > THRES)
|
||||
J |= VBA_RIGHT;
|
||||
else if(cos(angle) < -THRES)
|
||||
J |= VBA_LEFT;
|
||||
if(sin(angle) > THRES)
|
||||
J |= VBA_UP;
|
||||
else if(sin(angle) < -THRES)
|
||||
J |= VBA_DOWN;
|
||||
}
|
||||
/* WiiU Pro Controller */
|
||||
if (wupc_ax * wupc_ax + wupc_ay * wupc_ay > WUPCCAL * WUPCCAL)
|
||||
{
|
||||
angle = atan2(wupc_ay, wupc_ax);
|
||||
if(cos(angle) > THRES)
|
||||
J |= VBA_RIGHT;
|
||||
else if(cos(angle) < -THRES)
|
||||
@ -380,7 +406,19 @@ u32 StandardDPad(unsigned short pad)
|
||||
if (wp & WPAD_CLASSIC_BUTTON_RIGHT)
|
||||
J |= VBA_RIGHT;
|
||||
}
|
||||
/* WiiU Pro Controller */
|
||||
u32 wupcp = userInput[pad].wupcdata.btns_h;
|
||||
if (wupcp & WPAD_CLASSIC_BUTTON_UP)
|
||||
J |= VBA_UP;
|
||||
if (wupcp & WPAD_CLASSIC_BUTTON_DOWN)
|
||||
J |= VBA_DOWN;
|
||||
if (wupcp & WPAD_CLASSIC_BUTTON_LEFT)
|
||||
J |= VBA_LEFT;
|
||||
if (wupcp & WPAD_CLASSIC_BUTTON_RIGHT)
|
||||
J |= VBA_RIGHT;
|
||||
|
||||
#endif
|
||||
|
||||
if (jp & PAD_BUTTON_UP)
|
||||
J |= VBA_UP;
|
||||
if (jp & PAD_BUTTON_DOWN)
|
||||
@ -436,7 +474,8 @@ u32 StandardClassic(unsigned short pad)
|
||||
{
|
||||
u32 J = 0;
|
||||
#ifdef HW_RVL
|
||||
u32 wp = userInput[pad].wpad->btns_h;
|
||||
u32 wp = userInput[pad].wpad->btns_h
|
||||
| userInput[pad].wupcdata.btns_h; /* just add pro controller */
|
||||
|
||||
if (wp & WPAD_CLASSIC_BUTTON_RIGHT)
|
||||
J |= VBA_RIGHT;
|
||||
@ -536,6 +575,14 @@ u32 DecodeClassic(unsigned short pad)
|
||||
WPADData * wp = WPAD_Data(pad);
|
||||
u32 wpad_btns_h = wp->btns_h;
|
||||
|
||||
/* WiiU Pro Controller */
|
||||
u32 wupc_btns_h = userInput[pad].wupcdata.btns_h;
|
||||
for (u32 i = 0; i < MAXJP; ++i)
|
||||
{
|
||||
if(wupc_btns_h & btnmap[CTRLR_CLASSIC][i])
|
||||
J |= vbapadmap[i];
|
||||
}
|
||||
|
||||
if(wp->exp.type == WPAD_EXP_CLASSIC){
|
||||
for (u32 i = 0; i < MAXJP; ++i){
|
||||
if (wpad_btns_h & btnmap[CTRLR_CLASSIC][i] )
|
||||
@ -811,13 +858,16 @@ static u32 DecodeJoy(unsigned short pad)
|
||||
case CVHARMONY:
|
||||
case CVARIA:
|
||||
return CastlevaniaCircleMoonInput(pad);
|
||||
|
||||
case KIDDRACULA:
|
||||
return KidDraculaInput(pad);
|
||||
}
|
||||
|
||||
// the function result, J, is a combination of flags for all the VBA buttons that are down
|
||||
u32 J = StandardMovement(pad);
|
||||
|
||||
// Turbo feature
|
||||
if(userInput[0].pad.substickX > 70 || userInput[0].WPAD_Stick(1,0) > 70)
|
||||
if(userInput[0].pad.substickX > 70 || userInput[0].WPAD_Stick(1,0) > 70 || userInput[0].wupcdata.substickX > 560)
|
||||
J |= VBA_SPEED;
|
||||
|
||||
// Report pressed buttons (gamepads)
|
||||
@ -849,6 +899,7 @@ static u32 DecodeJoy(unsigned short pad)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else if(wpad_exp_type == WPAD_EXP_NUNCHUK)
|
||||
{ // nunchuk + wiimote
|
||||
|
||||
@ -858,8 +909,8 @@ static u32 DecodeJoy(unsigned short pad)
|
||||
|| ( (wpad_btns_h & btnmap[CTRLR_NUNCHUK][i]) ))
|
||||
J |= vbapadmap[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
// Check out this trickery!
|
||||
// If all else fails OR if HW_RVL is undefined, the result is the same
|
||||
@ -871,32 +922,38 @@ static u32 DecodeJoy(unsigned short pad)
|
||||
J |= vbapadmap[i];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HW_RVL
|
||||
/* WiiU Pro Controller */
|
||||
u32 wupc_btns_h = userInput[pad].wupcdata.btns_h;
|
||||
for (u32 i =0; i < MAXJP; ++i)
|
||||
{
|
||||
if(wupc_btns_h & btnmap[CTRLR_CLASSIC][i])
|
||||
J |= vbapadmap[i];
|
||||
}
|
||||
#endif
|
||||
|
||||
return J;
|
||||
}
|
||||
|
||||
bool MenuRequested()
|
||||
{
|
||||
if( (userInput[0].pad.substickX < -70) ||
|
||||
(userInput[0].wpad->btns_h & WPAD_BUTTON_HOME) ||
|
||||
(userInput[0].wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME)
|
||||
||
|
||||
(userInput[1].pad.substickX < -70) ||
|
||||
(userInput[1].wpad->btns_h & WPAD_BUTTON_HOME) ||
|
||||
(userInput[1].wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME)
|
||||
||
|
||||
(userInput[2].pad.substickX < -70) ||
|
||||
(userInput[2].wpad->btns_h & WPAD_BUTTON_HOME) ||
|
||||
(userInput[2].wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME)
|
||||
||
|
||||
(userInput[3].pad.substickX < -70) ||
|
||||
(userInput[3].wpad->btns_h & WPAD_BUTTON_HOME) ||
|
||||
(userInput[3].wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME)
|
||||
for(int i=0; i<4; i++)
|
||||
{
|
||||
if (
|
||||
(userInput[i].pad.substickX < -70)
|
||||
#ifdef HW_RVL
|
||||
|| (userInput[i].wpad->btns_h & WPAD_BUTTON_HOME) ||
|
||||
(userInput[i].wpad->btns_h & WPAD_CLASSIC_BUTTON_HOME) ||
|
||||
(userInput[i].wupcdata.btns_h & WPAD_CLASSIC_BUTTON_HOME)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetJoy(int pad)
|
||||
{
|
||||
@ -915,5 +972,6 @@ u32 GetJoy(int pad)
|
||||
if ((J & 192) == 192)
|
||||
J &= ~128;
|
||||
updateRumbleFrame();
|
||||
|
||||
return J;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#define PI 3.14159265f
|
||||
#define PADCAL 50
|
||||
#define WUPCCAL 400
|
||||
#define MAXJP 10 // # of mappable controller buttons
|
||||
|
||||
#define VBA_BUTTON_A 1
|
||||
|
@ -396,13 +396,8 @@ u32 MarioLand2Input(unsigned short pad) {
|
||||
if (wp->btns_h & WPAD_CLASSIC_BUTTON_X || wp->btns_h & WPAD_CLASSIC_BUTTON_Y || run)
|
||||
J |= VBA_BUTTON_B;
|
||||
// Spin attack
|
||||
if (wp->btns_h & WPAD_CLASSIC_BUTTON_A)
|
||||
if (wp->btns_h & WPAD_CLASSIC_BUTTON_A || wp->btns_h & WPAD_CLASSIC_BUTTON_FULL_R)
|
||||
J |= VBA_DOWN | VBA_BUTTON_A;
|
||||
// Camera
|
||||
if (wp->btns_h & WPAD_CLASSIC_BUTTON_FULL_L)
|
||||
J |= VBA_DOWN | VBA_BUTTON_B;
|
||||
if (wp->btns_h & WPAD_CLASSIC_BUTTON_FULL_R)
|
||||
J |= VBA_UP | VBA_BUTTON_B;
|
||||
// Crouch
|
||||
if (wp->btns_h & WPAD_CLASSIC_BUTTON_ZL && (!(wp->btns_h & WPAD_CLASSIC_BUTTON_A))) {
|
||||
J |= VBA_DOWN;
|
||||
|
@ -241,6 +241,18 @@ msgstr "Presione un bot
|
||||
msgid "Press any button on the Wiimote or Nunchuk now. Press Home to clear the existing mapping."
|
||||
msgstr "Presione un botón en el Wiimote o Nunchuck. Presione HOME para eliminar la configuración actual."
|
||||
|
||||
msgid "Press any button on the Wii U Pro Controller now. Press Home to clear the existing mapping."
|
||||
msgstr "Presione un botón en el Mando Wii U Pro. Presione HOME para eliminar la configuración actual."
|
||||
|
||||
msgid "ScreenShot"
|
||||
msgstr "Pantalla"
|
||||
|
||||
msgid "Preview Screenshot"
|
||||
msgstr "Imagen de Pantalla"
|
||||
|
||||
msgid "Save a new Preview Screenshot? Current Screenshot image will be overwritten."
|
||||
msgstr "¿Grabar una nueva imagen de pantalla? La imagen actual será sobre-escrita."
|
||||
|
||||
msgid "Progressive (480p)"
|
||||
msgstr "Progresivo (480p)"
|
||||
|
||||
|
629
source/menu.cpp
@ -21,6 +21,7 @@ void MainMenu (int menuitem);
|
||||
void ErrorPrompt(const char * msg);
|
||||
int ErrorPromptRetry(const char * msg);
|
||||
void InfoPrompt(const char * msg);
|
||||
int YesNoPrompt(const char *msg, bool yesDefault);
|
||||
void ShowAction (const char *msg);
|
||||
void CancelAction();
|
||||
void ShowProgress (const char *msg, int done, int total);
|
||||
@ -43,7 +44,8 @@ enum
|
||||
MENU_GAMESETTINGS_MAPPINGS_MAP,
|
||||
MENU_GAMESETTINGS_VIDEO,
|
||||
MENU_GAMESETTINGS_CHEATS,
|
||||
MENU_GAMESETTINGS_PALETTE
|
||||
MENU_GAMESETTINGS_PALETTE,
|
||||
MENU_SETTINGS_EMULATION
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -3,7 +3,7 @@
|
||||
* PNGU
|
||||
*
|
||||
* Original author: frontier (http://frontier-dev.net)
|
||||
* Modified by Tantric, 2009-2010
|
||||
* This is Tantric's modified/condensed version + RGB565 decoder from original
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
@ -16,18 +16,6 @@
|
||||
#define PNGU_SOURCE_BUFFER 1
|
||||
#define PNGU_SOURCE_DEVICE 2
|
||||
|
||||
// Return codes
|
||||
#define PNGU_OK 0
|
||||
#define PNGU_ODD_WIDTH 1
|
||||
#define PNGU_ODD_STRIDE 2
|
||||
#define PNGU_INVALID_WIDTH_OR_HEIGHT 3
|
||||
#define PNGU_FILE_IS_NOT_PNG 4
|
||||
#define PNGU_UNSUPPORTED_COLOR_TYPE 5
|
||||
#define PNGU_NO_FILE_SELECTED 6
|
||||
#define PNGU_CANT_OPEN_FILE 7
|
||||
#define PNGU_CANT_READ_FILE 8
|
||||
#define PNGU_LIB_ERROR 9
|
||||
|
||||
// Color types
|
||||
#define PNGU_COLOR_TYPE_GRAY 1
|
||||
#define PNGU_COLOR_TYPE_GRAY_ALPHA 2
|
||||
@ -311,7 +299,7 @@ static int pngu_decode (IMGCTX ctx, u32 width, u32 height, u32 stripAlpha)
|
||||
return PNGU_INVALID_WIDTH_OR_HEIGHT;
|
||||
|
||||
// Check if color type is supported by PNGU
|
||||
if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_PALETTE) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_UNKNOWN) )
|
||||
if (ctx->prop.imgColorType == PNGU_COLOR_TYPE_UNKNOWN)
|
||||
return PNGU_UNSUPPORTED_COLOR_TYPE;
|
||||
|
||||
// Scale 16 bit samples to 8 bit
|
||||
@ -330,6 +318,10 @@ static int pngu_decode (IMGCTX ctx, u32 width, u32 height, u32 stripAlpha)
|
||||
if ( (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY) || (ctx->prop.imgColorType == PNGU_COLOR_TYPE_GRAY_ALPHA) )
|
||||
png_set_gray_to_rgb (ctx->png_ptr);
|
||||
|
||||
// Transform palette images to RGB
|
||||
if (ctx->prop.imgColorType == PNGU_COLOR_TYPE_PALETTE)
|
||||
png_set_palette_to_rgb(ctx->png_ptr);
|
||||
|
||||
// Flush transformations
|
||||
png_read_update_info (ctx->png_ptr, ctx->info_ptr);
|
||||
|
||||
@ -479,6 +471,70 @@ static u8 * PNGU_DecodeTo4x4RGBA8 (IMGCTX ctx, u32 width, u32 height, int * dstW
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
int PNGU_DecodeTo4x4RGB565 (IMGCTX ctx, u32 width, u32 height, void *buffer)
|
||||
{
|
||||
int result;
|
||||
u32 x, y, qwidth, qheight;
|
||||
|
||||
// width and height need to be divisible by four
|
||||
if ((width % 4) || (height % 4))
|
||||
return PNGU_INVALID_WIDTH_OR_HEIGHT;
|
||||
|
||||
result = pngu_decode (ctx, width, height, 1);
|
||||
if (result != PNGU_OK)
|
||||
return result;
|
||||
|
||||
// Copy image to the output buffer
|
||||
qwidth = width / 4;
|
||||
qheight = height / 4;
|
||||
|
||||
for (y = 0; y < qheight; y++)
|
||||
for (x = 0; x < qwidth; x++)
|
||||
{
|
||||
int blockbase = (y * qwidth + x) * 4;
|
||||
|
||||
u64 field64 = *((u64 *)(ctx->row_pointers[y*4]+x*12));
|
||||
u64 field32 = (u64) *((u32 *)(ctx->row_pointers[y*4]+x*12+8));
|
||||
((u64 *) buffer)[blockbase] =
|
||||
(((field64 & 0xF800000000000000ULL) | ((field64 & 0xFC000000000000ULL) << 3) | ((field64 & 0xF80000000000ULL) << 5)) |
|
||||
(((field64 & 0xF800000000ULL) << 8) | ((field64 & 0xFC000000ULL) << 11) | ((field64 & 0xF80000ULL) << 13)) |
|
||||
(((field64 & 0xF800ULL) << 16) | ((field64 & 0xFCULL) << 19) | ((field32 & 0xF8000000ULL) >> 11)) |
|
||||
(((field32 & 0xF80000ULL) >> 8) | ((field32 & 0xFC00ULL) >> 5) | ((field32 & 0xF8ULL) >> 3)));
|
||||
|
||||
field64 = *((u64 *)(ctx->row_pointers[y*4+1]+x*12));
|
||||
field32 = (u64) *((u32 *)(ctx->row_pointers[y*4+1]+x*12+8));
|
||||
((u64 *) buffer)[blockbase+1] =
|
||||
(((field64 & 0xF800000000000000ULL) | ((field64 & 0xFC000000000000ULL) << 3) | ((field64 & 0xF80000000000ULL) << 5)) |
|
||||
(((field64 & 0xF800000000ULL) << 8) | ((field64 & 0xFC000000ULL) << 11) | ((field64 & 0xF80000ULL) << 13)) |
|
||||
(((field64 & 0xF800ULL) << 16) | ((field64 & 0xFCULL) << 19) | ((field32 & 0xF8000000ULL) >> 11)) |
|
||||
(((field32 & 0xF80000ULL) >> 8) | ((field32 & 0xFC00ULL) >> 5) | ((field32 & 0xF8ULL) >> 3)));
|
||||
|
||||
field64 = *((u64 *)(ctx->row_pointers[y*4+2]+x*12));
|
||||
field32 = (u64) *((u32 *)(ctx->row_pointers[y*4+2]+x*12+8));
|
||||
((u64 *) buffer)[blockbase+2] =
|
||||
(((field64 & 0xF800000000000000ULL) | ((field64 & 0xFC000000000000ULL) << 3) | ((field64 & 0xF80000000000ULL) << 5)) |
|
||||
(((field64 & 0xF800000000ULL) << 8) | ((field64 & 0xFC000000ULL) << 11) | ((field64 & 0xF80000ULL) << 13)) |
|
||||
(((field64 & 0xF800ULL) << 16) | ((field64 & 0xFCULL) << 19) | ((field32 & 0xF8000000ULL) >> 11)) |
|
||||
(((field32 & 0xF80000ULL) >> 8) | ((field32 & 0xFC00ULL) >> 5) | ((field32 & 0xF8ULL) >> 3)));
|
||||
|
||||
field64 = *((u64 *)(ctx->row_pointers[y*4+3]+x*12));
|
||||
field32 = (u64) *((u32 *)(ctx->row_pointers[y*4+3]+x*12+8));
|
||||
((u64 *) buffer)[blockbase+3] =
|
||||
(((field64 & 0xF800000000000000ULL) | ((field64 & 0xFC000000000000ULL) << 3) | ((field64 & 0xF80000000000ULL) << 5)) |
|
||||
(((field64 & 0xF800000000ULL) << 8) | ((field64 & 0xFC000000ULL) << 11) | ((field64 & 0xF80000ULL) << 13)) |
|
||||
(((field64 & 0xF800ULL) << 16) | ((field64 & 0xFCULL) << 19) | ((field32 & 0xF8000000ULL) >> 11)) |
|
||||
(((field32 & 0xF80000ULL) >> 8) | ((field32 & 0xFC00ULL) >> 5) | ((field32 & 0xF8ULL) >> 3)));
|
||||
}
|
||||
|
||||
// Free resources
|
||||
free (ctx->img_data);
|
||||
free (ctx->row_pointers);
|
||||
|
||||
// Success
|
||||
return PNGU_OK;
|
||||
}
|
||||
|
||||
IMGCTX PNGU_SelectImageFromBuffer (const void *buffer)
|
||||
{
|
||||
IMGCTX ctx = NULL;
|
||||
@ -749,3 +805,38 @@ int PNGU_EncodeFromEFB (IMGCTX ctx, u32 width, u32 height)
|
||||
free(tmpbuffer);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Added by libertyernie
|
||||
int PNGU_EncodeFromLinearRGB565 (IMGCTX ctx, u32 width, u32 height, const void* buffer, int rowlength)
|
||||
{
|
||||
int res;
|
||||
u32 x, y, tmpy1, tmpxy;
|
||||
|
||||
u16 * src = (u16 *)buffer;
|
||||
unsigned char * tmpbuffer = malloc(width*height*3);
|
||||
|
||||
if(!tmpbuffer)
|
||||
return PNGU_LIB_ERROR;
|
||||
|
||||
for(y=0; y < height; y++)
|
||||
{
|
||||
tmpy1 = y * width * 3;
|
||||
|
||||
for(x=0; x < width; x++)
|
||||
{
|
||||
tmpxy = x * 3 + tmpy1;
|
||||
u16 color = *src++;
|
||||
tmpbuffer[tmpxy ] = (color >> 11) << 3; // R
|
||||
tmpbuffer[tmpxy+1] = ((color >> 6) & 31) << 3; // G - discard least significant byte
|
||||
tmpbuffer[tmpxy+2] = (color & 31) << 3; // B
|
||||
}
|
||||
|
||||
if (rowlength > width) {
|
||||
src += (rowlength - width);
|
||||
}
|
||||
}
|
||||
|
||||
res = PNGU_EncodeFromRGB (ctx, width, height, tmpbuffer, 0);
|
||||
free(tmpbuffer);
|
||||
return res;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
* PNGU
|
||||
*
|
||||
* Original author: frontier (http://frontier-dev.net)
|
||||
* Modified by Tantric, 2009-2010
|
||||
* This is Tantric's modified/condensed version + RGB565 decoder from original
|
||||
*
|
||||
********************************************************************************************/
|
||||
|
||||
@ -16,6 +16,18 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Return codes
|
||||
#define PNGU_OK 0
|
||||
#define PNGU_ODD_WIDTH 1
|
||||
#define PNGU_ODD_STRIDE 2
|
||||
#define PNGU_INVALID_WIDTH_OR_HEIGHT 3
|
||||
#define PNGU_FILE_IS_NOT_PNG 4
|
||||
#define PNGU_UNSUPPORTED_COLOR_TYPE 5
|
||||
#define PNGU_NO_FILE_SELECTED 6
|
||||
#define PNGU_CANT_OPEN_FILE 7
|
||||
#define PNGU_CANT_READ_FILE 8
|
||||
#define PNGU_LIB_ERROR 9
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 r;
|
||||
@ -68,6 +80,9 @@ int PNGU_EncodeFromRGB (IMGCTX ctx, u32 width, u32 height, void *buffer, u32 str
|
||||
int PNGU_EncodeFromGXTexture (IMGCTX ctx, u32 width, u32 height, void *buffer, u32 stride);
|
||||
int PNGU_EncodeFromEFB (IMGCTX ctx, u32 width, u32 height);
|
||||
|
||||
int PNGU_DecodeTo4x4RGB565 (IMGCTX ctx, u32 width, u32 height, void *buffer);
|
||||
int PNGU_EncodeFromLinearRGB565 (IMGCTX ctx, u32 width, u32 height, const void* buffer, int rowlength);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1,58 +1,57 @@
|
||||
#ifndef SYSTEM_H
|
||||
#define SYSTEM_H
|
||||
|
||||
#include "common/Types.h"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
class SoundDriver;
|
||||
|
||||
struct EmulatedSystem {
|
||||
// main emulation function
|
||||
void (*emuMain)(int);
|
||||
// reset emulator
|
||||
void (*emuReset)();
|
||||
// clean up memory
|
||||
void (*emuCleanUp)();
|
||||
// load battery file
|
||||
bool (*emuReadBattery)(const char *);
|
||||
// write battery file
|
||||
bool (*emuWriteBattery)(const char *);
|
||||
// load state
|
||||
bool (*emuReadState)(const char *);
|
||||
// save state
|
||||
bool (*emuWriteState)(const char *);
|
||||
// load memory state (rewind)
|
||||
bool (*emuReadMemState)(char *, int);
|
||||
// write memory state (rewind)
|
||||
bool (*emuWriteMemState)(char *, int);
|
||||
// write PNG file
|
||||
bool (*emuWritePNG)(const char *);
|
||||
// write BMP file
|
||||
bool (*emuWriteBMP)(const char *);
|
||||
// emulator update CPSR (ARM only)
|
||||
void (*emuUpdateCPSR)();
|
||||
// emulator has debugger
|
||||
bool emuHasDebugger;
|
||||
// clock ticks to emulate
|
||||
int emuCount;
|
||||
// main emulation function
|
||||
void (*emuMain)(int);
|
||||
// reset emulator
|
||||
void (*emuReset)();
|
||||
// clean up memory
|
||||
void (*emuCleanUp)();
|
||||
// load battery file
|
||||
bool (*emuReadBattery)(const char *);
|
||||
// write battery file
|
||||
bool (*emuWriteBattery)(const char *);
|
||||
#ifdef __LIBRETRO__
|
||||
// load state
|
||||
bool (*emuReadState)(const u8*, unsigned);
|
||||
// load state
|
||||
unsigned (*emuWriteState)(u8*, unsigned);
|
||||
#else
|
||||
// load state
|
||||
bool (*emuReadState)(const char *);
|
||||
// save state
|
||||
bool (*emuWriteState)(const char *);
|
||||
#endif
|
||||
// load memory state (rewind)
|
||||
bool (*emuReadMemState)(char *, int);
|
||||
// write memory state (rewind)
|
||||
bool (*emuWriteMemState)(char *, int);
|
||||
// write PNG file
|
||||
bool (*emuWritePNG)(const char *);
|
||||
// write BMP file
|
||||
bool (*emuWriteBMP)(const char *);
|
||||
// emulator update CPSR (ARM only)
|
||||
void (*emuUpdateCPSR)();
|
||||
// emulator has debugger
|
||||
bool emuHasDebugger;
|
||||
// clock ticks to emulate
|
||||
int emuCount;
|
||||
};
|
||||
|
||||
extern void log(const char *,...);
|
||||
|
||||
extern bool systemPauseOnFrame();
|
||||
extern void systemGbPrint(u8 *,int,int,int,int);
|
||||
extern void systemGbPrint(u8 *,int,int,int,int,int);
|
||||
extern void systemScreenCapture(int);
|
||||
extern void systemDrawScreen();
|
||||
// updates the joystick data
|
||||
extern bool systemReadJoypads();
|
||||
// return information about the given joystick, -1 for default joystick
|
||||
extern u32 systemReadJoypad(int);
|
||||
// this function should turn on or off rumble on the gamepad
|
||||
extern void systemCartridgeRumble(bool);
|
||||
extern void systemPossibleCartridgeRumble(bool);
|
||||
// This should be called once per frame
|
||||
extern void updateRumbleFrame();
|
||||
extern u32 systemGetClock();
|
||||
extern void systemMessage(int, const char *, ...);
|
||||
extern void systemSetTitle(const char *);
|
||||
@ -61,26 +60,26 @@ extern void systemOnWriteDataToSoundBuffer(const u16 * finalWave, int length);
|
||||
extern void systemOnSoundShutdown();
|
||||
extern void systemScreenMessage(const char *);
|
||||
extern void systemUpdateMotionSensor();
|
||||
extern int systemGetSensorX();
|
||||
extern int systemGetSensorY();
|
||||
extern int systemGetSensorX();
|
||||
extern int systemGetSensorY();
|
||||
extern bool systemCanChangeSoundQuality();
|
||||
extern void systemShowSpeed(int);
|
||||
extern void system10Frames(int);
|
||||
extern void systemFrame();
|
||||
extern void systemGbBorderOn();
|
||||
|
||||
extern void Sm60FPS_Init();
|
||||
extern bool Sm60FPS_CanSkipFrame();
|
||||
extern void Sm60FPS_Sleep();
|
||||
extern void DbgMsg(const char *msg, ...);
|
||||
#ifdef SDL
|
||||
#define winlog log
|
||||
#else
|
||||
extern void winlog(const char *,...);
|
||||
|
||||
#endif
|
||||
extern void (*dbgOutput)(const char *s, u32 addr);
|
||||
extern void (*dbgSignal)(int sig,int number);
|
||||
|
||||
extern u16 systemColorMap16[0x10000];
|
||||
//extern u32 systemColorMap32[0x10000];
|
||||
extern u32 *systemColorMap32;
|
||||
extern u32 systemColorMap32[0x10000];
|
||||
extern u16 systemGbPalette[24];
|
||||
extern int systemRedShift;
|
||||
extern int systemGreenShift;
|
||||
@ -91,8 +90,6 @@ extern int systemVerbose;
|
||||
extern int systemFrameSkip;
|
||||
extern int systemSaveUpdateCounter;
|
||||
extern int systemSpeed;
|
||||
|
||||
#define SYSTEM_SAVE_UPDATED 30
|
||||
#define SYSTEM_SAVE_NOT_UPDATED 0
|
||||
|
||||
#endif // SYSTEM_H
|
||||
|
@ -1,26 +1,14 @@
|
||||
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
||||
// Copyright (C) 1999-2003 Forgotten
|
||||
// Copyright (C) 2004-2006 Forgotten and the VBA development team
|
||||
// Copyright (C) 2007-2008 VBA-M development team and Shay Green
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2, or(at your option)
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software Foundation,
|
||||
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#ifndef NO_PNG
|
||||
extern "C" {
|
||||
#include <png.h>
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "System.h"
|
||||
#include "NLS.h"
|
||||
#include "Util.h"
|
||||
@ -29,12 +17,18 @@
|
||||
#include "gba/Globals.h"
|
||||
#include "gba/RTC.h"
|
||||
#include "common/Port.h"
|
||||
#include "../utils/unzip/unzip.h"
|
||||
|
||||
#ifndef NO_FEX
|
||||
#include "fex/fex.h"
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include "common/memgzio.h"
|
||||
}
|
||||
|
||||
#include "gba/gbafilter.h"
|
||||
#include "gb/gbGlobals.h"
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#define _stricmp strcasecmp
|
||||
#endif // ! _MSC_VER
|
||||
@ -45,13 +39,283 @@ extern int systemGreenShift;
|
||||
extern int systemBlueShift;
|
||||
|
||||
extern u16 systemColorMap16[0x10000];
|
||||
//extern u32 systemColorMap32[0x10000];
|
||||
extern u32 *systemColorMap32;
|
||||
extern u32 systemColorMap32[0x10000];
|
||||
|
||||
static int (*utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL;
|
||||
static int (*utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL;
|
||||
static int (*utilGzCloseFunc)(gzFile) = NULL;
|
||||
static z_off_t (*utilGzSeekFunc)(gzFile, z_off_t, int) = NULL;
|
||||
static int (ZEXPORT *utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL;
|
||||
static int (ZEXPORT *utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL;
|
||||
static int (ZEXPORT *utilGzCloseFunc)(gzFile) = NULL;
|
||||
static z_off_t (ZEXPORT *utilGzSeekFunc)(gzFile, z_off_t, int) = NULL;
|
||||
|
||||
bool utilWritePNGFile(const char *fileName, int w, int h, u8 *pix)
|
||||
{
|
||||
#ifndef NO_PNG
|
||||
u8 writeBuffer[512 * 3];
|
||||
|
||||
FILE *fp = fopen(fileName,"wb");
|
||||
|
||||
if(!fp) {
|
||||
systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
if(!png_ptr) {
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
|
||||
if(!info_ptr) {
|
||||
png_destroy_write_struct(&png_ptr,NULL);
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(setjmp(png_jmpbuf(png_ptr))) {
|
||||
png_destroy_write_struct(&png_ptr,NULL);
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_init_io(png_ptr,fp);
|
||||
|
||||
png_set_IHDR(png_ptr,
|
||||
info_ptr,
|
||||
w,
|
||||
h,
|
||||
8,
|
||||
PNG_COLOR_TYPE_RGB,
|
||||
PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT);
|
||||
|
||||
png_write_info(png_ptr,info_ptr);
|
||||
|
||||
u8 *b = writeBuffer;
|
||||
|
||||
int sizeX = w;
|
||||
int sizeY = h;
|
||||
|
||||
switch(systemColorDepth) {
|
||||
case 16:
|
||||
{
|
||||
u16 *p = (u16 *)(pix+(w+2)*2); // skip first black line
|
||||
for(int y = 0; y < sizeY; y++) {
|
||||
for(int x = 0; x < sizeX; x++) {
|
||||
u16 v = *p++;
|
||||
|
||||
*b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
|
||||
*b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
|
||||
*b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B
|
||||
}
|
||||
p++; // skip black pixel for filters
|
||||
p++; // skip black pixel for filters
|
||||
png_write_row(png_ptr,writeBuffer);
|
||||
|
||||
b = writeBuffer;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
{
|
||||
u8 *pixU8 = (u8 *)pix;
|
||||
for(int y = 0; y < sizeY; y++) {
|
||||
for(int x = 0; x < sizeX; x++) {
|
||||
if(systemRedShift < systemBlueShift) {
|
||||
*b++ = *pixU8++; // R
|
||||
*b++ = *pixU8++; // G
|
||||
*b++ = *pixU8++; // B
|
||||
} else {
|
||||
int blue = *pixU8++;
|
||||
int green = *pixU8++;
|
||||
int red = *pixU8++;
|
||||
|
||||
*b++ = red;
|
||||
*b++ = green;
|
||||
*b++ = blue;
|
||||
}
|
||||
}
|
||||
png_write_row(png_ptr,writeBuffer);
|
||||
|
||||
b = writeBuffer;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
{
|
||||
u32 *pixU32 = (u32 *)(pix+4*(w+1));
|
||||
for(int y = 0; y < sizeY; y++) {
|
||||
for(int x = 0; x < sizeX; x++) {
|
||||
u32 v = *pixU32++;
|
||||
|
||||
*b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
|
||||
*b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
|
||||
*b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B
|
||||
}
|
||||
pixU32++;
|
||||
|
||||
png_write_row(png_ptr,writeBuffer);
|
||||
|
||||
b = writeBuffer;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
png_write_end(png_ptr, info_ptr);
|
||||
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void utilPutDword(u8 *p, u32 value)
|
||||
{
|
||||
*p++ = value & 255;
|
||||
*p++ = (value >> 8) & 255;
|
||||
*p++ = (value >> 16) & 255;
|
||||
*p = (value >> 24) & 255;
|
||||
}
|
||||
|
||||
void utilPutWord(u8 *p, u16 value)
|
||||
{
|
||||
*p++ = value & 255;
|
||||
*p = (value >> 8) & 255;
|
||||
}
|
||||
|
||||
bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix)
|
||||
{
|
||||
u8 writeBuffer[512 * 3];
|
||||
|
||||
FILE *fp = fopen(fileName,"wb");
|
||||
|
||||
if(!fp) {
|
||||
systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct {
|
||||
u8 ident[2];
|
||||
u8 filesize[4];
|
||||
u8 reserved[4];
|
||||
u8 dataoffset[4];
|
||||
u8 headersize[4];
|
||||
u8 width[4];
|
||||
u8 height[4];
|
||||
u8 planes[2];
|
||||
u8 bitsperpixel[2];
|
||||
u8 compression[4];
|
||||
u8 datasize[4];
|
||||
u8 hres[4];
|
||||
u8 vres[4];
|
||||
u8 colors[4];
|
||||
u8 importantcolors[4];
|
||||
// u8 pad[2];
|
||||
} bmpheader;
|
||||
memset(&bmpheader, 0, sizeof(bmpheader));
|
||||
|
||||
bmpheader.ident[0] = 'B';
|
||||
bmpheader.ident[1] = 'M';
|
||||
|
||||
u32 fsz = sizeof(bmpheader) + w*h*3;
|
||||
utilPutDword(bmpheader.filesize, fsz);
|
||||
utilPutDword(bmpheader.dataoffset, 0x36);
|
||||
utilPutDword(bmpheader.headersize, 0x28);
|
||||
utilPutDword(bmpheader.width, w);
|
||||
utilPutDword(bmpheader.height, h);
|
||||
utilPutDword(bmpheader.planes, 1);
|
||||
utilPutDword(bmpheader.bitsperpixel, 24);
|
||||
utilPutDword(bmpheader.datasize, 3*w*h);
|
||||
|
||||
fwrite(&bmpheader, 1, sizeof(bmpheader), fp);
|
||||
|
||||
u8 *b = writeBuffer;
|
||||
|
||||
int sizeX = w;
|
||||
int sizeY = h;
|
||||
|
||||
switch(systemColorDepth) {
|
||||
case 16:
|
||||
{
|
||||
u16 *p = (u16 *)(pix+(w+2)*(h)*2); // skip first black line
|
||||
for(int y = 0; y < sizeY; y++) {
|
||||
for(int x = 0; x < sizeX; x++) {
|
||||
u16 v = *p++;
|
||||
|
||||
*b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B
|
||||
*b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
|
||||
*b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
|
||||
}
|
||||
p++; // skip black pixel for filters
|
||||
p++; // skip black pixel for filters
|
||||
p -= 2*(w+2);
|
||||
fwrite(writeBuffer, 1, 3*w, fp);
|
||||
|
||||
b = writeBuffer;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
{
|
||||
u8 *pixU8 = (u8 *)pix+3*w*(h-1);
|
||||
for(int y = 0; y < sizeY; y++) {
|
||||
for(int x = 0; x < sizeX; x++) {
|
||||
if(systemRedShift > systemBlueShift) {
|
||||
*b++ = *pixU8++; // B
|
||||
*b++ = *pixU8++; // G
|
||||
*b++ = *pixU8++; // R
|
||||
} else {
|
||||
int red = *pixU8++;
|
||||
int green = *pixU8++;
|
||||
int blue = *pixU8++;
|
||||
|
||||
*b++ = blue;
|
||||
*b++ = green;
|
||||
*b++ = red;
|
||||
}
|
||||
}
|
||||
pixU8 -= 2*3*w;
|
||||
fwrite(writeBuffer, 1, 3*w, fp);
|
||||
|
||||
b = writeBuffer;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
{
|
||||
u32 *pixU32 = (u32 *)(pix+4*(w+1)*(h));
|
||||
for(int y = 0; y < sizeY; y++) {
|
||||
for(int x = 0; x < sizeX; x++) {
|
||||
u32 v = *pixU32++;
|
||||
|
||||
*b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B
|
||||
*b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G
|
||||
*b++ = ((v >> systemRedShift) & 0x001f) << 3; // R
|
||||
}
|
||||
pixU32++;
|
||||
pixU32 -= 2*(w+1);
|
||||
|
||||
fwrite(writeBuffer, 1, 3*w, fp);
|
||||
|
||||
b = writeBuffer;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern bool cpuIsMultiBoot;
|
||||
|
||||
@ -95,34 +359,221 @@ bool utilIsGBImage(const char * file)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool utilIsZipFile(const char *file)
|
||||
bool utilIsGzipFile(const char *file)
|
||||
{
|
||||
if(strlen(file) > 4)
|
||||
{
|
||||
char * p = strrchr(file,'.');
|
||||
if(strlen(file) > 3) {
|
||||
const char * p = strrchr(file,'.');
|
||||
|
||||
if(p != NULL)
|
||||
{
|
||||
if(_stricmp(p, ".zip") == 0)
|
||||
return true;
|
||||
}
|
||||
if(p != NULL) {
|
||||
if(_stricmp(p, ".gz") == 0)
|
||||
return true;
|
||||
if(_stricmp(p, ".z") == 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void utilPutDword(u8 *p, u32 value)
|
||||
// strip .gz or .z off end
|
||||
void utilStripDoubleExtension(const char *file, char *buffer)
|
||||
{
|
||||
*p++ = value & 255;
|
||||
*p++ = (value >> 8) & 255;
|
||||
*p++ = (value >> 16) & 255;
|
||||
*p = (value >> 24) & 255;
|
||||
if(buffer != file) // allows conversion in place
|
||||
strcpy(buffer, file);
|
||||
|
||||
if(utilIsGzipFile(file)) {
|
||||
char *p = strrchr(buffer, '.');
|
||||
|
||||
if(p)
|
||||
*p = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void utilPutWord(u8 *p, u16 value)
|
||||
#ifndef NO_FEX
|
||||
// Opens and scans archive using accept(). Returns fex_t if found.
|
||||
// If error or not found, displays message and returns NULL.
|
||||
static fex_t* scan_arc(const char *file, bool (*accept)(const char *),
|
||||
char (&buffer) [2048] )
|
||||
{
|
||||
*p++ = value & 255;
|
||||
*p = (value >> 8) & 255;
|
||||
fex_t* fe;
|
||||
fex_err_t err = fex_open( &fe, file );
|
||||
if(!fe)
|
||||
{
|
||||
systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s: %s"), file, err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Scan filenames
|
||||
bool found=false;
|
||||
while(!fex_done(fe)) {
|
||||
strncpy(buffer,fex_name(fe),sizeof buffer);
|
||||
buffer [sizeof buffer-1] = '\0';
|
||||
|
||||
utilStripDoubleExtension(buffer, buffer);
|
||||
|
||||
if(accept(buffer)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
fex_err_t err = fex_next(fe);
|
||||
if(err) {
|
||||
systemMessage(MSG_BAD_ZIP_FILE, N_("Cannot read archive %s: %s"), file, err);
|
||||
fex_close(fe);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found) {
|
||||
systemMessage(MSG_NO_IMAGE_ON_ZIP,
|
||||
N_("No image found in file %s"), file);
|
||||
fex_close(fe);
|
||||
return NULL;
|
||||
}
|
||||
return fe;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool utilIsImage(const char *file)
|
||||
{
|
||||
return utilIsGBAImage(file) || utilIsGBImage(file);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
IMAGE_TYPE utilFindType(const char *file, char (&buffer)[2048]);
|
||||
|
||||
IMAGE_TYPE utilFindType(const char *file)
|
||||
{
|
||||
char buffer [2048];
|
||||
return utilFindType(file, buffer);
|
||||
}
|
||||
|
||||
IMAGE_TYPE utilFindType(const char *file, char (&buffer)[2048])
|
||||
{
|
||||
#ifndef NO_FEX
|
||||
#ifdef WIN32
|
||||
DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, file, -1, NULL, 0);
|
||||
wchar_t *pwText;
|
||||
pwText = new wchar_t[dwNum];
|
||||
if(!pwText)
|
||||
{
|
||||
return IMAGE_UNKNOWN;
|
||||
}
|
||||
MultiByteToWideChar (CP_ACP, 0, file, -1, pwText, dwNum );
|
||||
char* file_conv = fex_wide_to_path( pwText);
|
||||
// if ( !utilIsImage( file_conv ) ) // TODO: utilIsArchive() instead?
|
||||
// {
|
||||
fex_t* fe = scan_arc(file_conv,utilIsImage,buffer);
|
||||
if(!fe)
|
||||
return IMAGE_UNKNOWN;
|
||||
fex_close(fe);
|
||||
file = buffer;
|
||||
// }
|
||||
free(file_conv);
|
||||
#else
|
||||
// if ( !utilIsImage( file ) ) // TODO: utilIsArchive() instead?
|
||||
// {
|
||||
fex_t* fe = scan_arc(file,utilIsImage,buffer);
|
||||
if(!fe)
|
||||
return IMAGE_UNKNOWN;
|
||||
fex_close(fe);
|
||||
file = buffer;
|
||||
// }
|
||||
#endif
|
||||
#endif
|
||||
return utilIsGBAImage(file) ? IMAGE_GBA : IMAGE_GB;
|
||||
}
|
||||
|
||||
static int utilGetSize(int size)
|
||||
{
|
||||
int res = 1;
|
||||
while(res < size)
|
||||
res <<= 1;
|
||||
return res;
|
||||
}
|
||||
|
||||
u8 *utilLoad(const char *file,
|
||||
bool (*accept)(const char *),
|
||||
u8 *data,
|
||||
int &size)
|
||||
{
|
||||
// find image file
|
||||
char buffer [2048];
|
||||
#ifdef NO_FEX
|
||||
FILE* f = fopen(file, "rb");
|
||||
fseek(f, 0, SEEK_END);
|
||||
int fileSize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
#else
|
||||
#ifdef WIN32
|
||||
DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, file, -1, NULL, 0);
|
||||
wchar_t *pwText;
|
||||
pwText = new wchar_t[dwNum];
|
||||
if(!pwText)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
MultiByteToWideChar (CP_ACP, 0, file, -1, pwText, dwNum );
|
||||
char* file_conv = fex_wide_to_path( pwText);
|
||||
delete []pwText;
|
||||
fex_t *fe = scan_arc(file_conv,accept,buffer);
|
||||
if(!fe)
|
||||
return NULL;
|
||||
free(file_conv);
|
||||
#else
|
||||
fex_t *fe = scan_arc(file,accept,buffer);
|
||||
if(!fe)
|
||||
return NULL;
|
||||
#endif
|
||||
// Allocate space for image
|
||||
fex_err_t err = fex_stat(fe);
|
||||
int fileSize = fex_size(fe);
|
||||
if(size == 0)
|
||||
size = fileSize;
|
||||
#endif
|
||||
|
||||
u8 *image = data;
|
||||
|
||||
if(image == NULL) {
|
||||
// allocate buffer memory if none was passed to the function
|
||||
image = (u8 *)malloc(utilGetSize(size));
|
||||
if(image == NULL) {
|
||||
#ifdef NO_FEX
|
||||
fclose(f);
|
||||
#else
|
||||
fex_close(fe);
|
||||
#endif
|
||||
systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"),
|
||||
"data");
|
||||
return NULL;
|
||||
}
|
||||
size = fileSize;
|
||||
}
|
||||
|
||||
// Read image
|
||||
int read = fileSize <= size ? fileSize : size; // do not read beyond file
|
||||
#ifdef NO_FEX
|
||||
int br = fread(image, 1, read, f);
|
||||
const char* err = (br < read) ? "too few bytes from fread" : NULL;
|
||||
fclose(f);
|
||||
#else
|
||||
err = fex_read(fe, image, read);
|
||||
fex_close(fe);
|
||||
#endif
|
||||
if(err) {
|
||||
systemMessage(MSG_ERROR_READING_IMAGE,
|
||||
N_("Error reading image from %s: %s"), buffer, err);
|
||||
if(data == NULL)
|
||||
free(image);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = fileSize;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void utilWriteInt(gzFile gzFile, int i)
|
||||
@ -163,7 +614,7 @@ void utilWriteData(gzFile gzFile, variable_desc *data)
|
||||
|
||||
gzFile utilGzOpen(const char *file, const char *mode)
|
||||
{
|
||||
utilGzWriteFunc = (int (ZEXPORT *)(void *,void * const, unsigned int))gzwrite;
|
||||
utilGzWriteFunc = (int (ZEXPORT *)(gzFile, void * const, unsigned int))gzwrite;
|
||||
utilGzReadFunc = gzread;
|
||||
utilGzCloseFunc = gzclose;
|
||||
utilGzSeekFunc = gzseek;
|
||||
@ -176,6 +627,7 @@ gzFile utilMemGzOpen(char *memory, int available, const char *mode)
|
||||
utilGzWriteFunc = memgzwrite;
|
||||
utilGzReadFunc = memgzread;
|
||||
utilGzCloseFunc = memgzclose;
|
||||
utilGzSeekFunc = memgzseek;
|
||||
|
||||
return memgzopen(memory, available, mode);
|
||||
}
|
||||
@ -204,3 +656,90 @@ long utilGzMemTell(gzFile file)
|
||||
{
|
||||
return memtell(file);
|
||||
}
|
||||
|
||||
void utilGBAFindSave(const u8 *data, const int size)
|
||||
{
|
||||
u32 *p = (u32 *)data;
|
||||
u32 *end = (u32 *)(data + size);
|
||||
int saveType = 0;
|
||||
int flashSize = 0x10000;
|
||||
bool rtcFound = false;
|
||||
|
||||
while(p < end) {
|
||||
u32 d = READ32LE(p);
|
||||
|
||||
if(d == 0x52504545) {
|
||||
if(memcmp(p, "EEPROM_", 7) == 0) {
|
||||
if(saveType == 0)
|
||||
saveType = 3;
|
||||
}
|
||||
} else if (d == 0x4D415253) {
|
||||
if(memcmp(p, "SRAM_", 5) == 0) {
|
||||
if(saveType == 0)
|
||||
saveType = 1;
|
||||
}
|
||||
} else if (d == 0x53414C46) {
|
||||
if(memcmp(p, "FLASH1M_", 8) == 0) {
|
||||
if(saveType == 0) {
|
||||
saveType = 2;
|
||||
flashSize = 0x20000;
|
||||
}
|
||||
} else if(memcmp(p, "FLASH", 5) == 0) {
|
||||
if(saveType == 0) {
|
||||
saveType = 2;
|
||||
flashSize = 0x10000;
|
||||
}
|
||||
}
|
||||
} else if (d == 0x52494953) {
|
||||
if(memcmp(p, "SIIRTC_V", 8) == 0)
|
||||
rtcFound = true;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
// if no matches found, then set it to NONE
|
||||
if(saveType == 0) {
|
||||
saveType = 5;
|
||||
}
|
||||
rtcEnable(rtcFound);
|
||||
cpuSaveType = saveType;
|
||||
flashSetSize(flashSize);
|
||||
}
|
||||
|
||||
void utilUpdateSystemColorMaps(bool lcd)
|
||||
{
|
||||
switch(systemColorDepth) {
|
||||
case 16:
|
||||
{
|
||||
for(int i = 0; i < 0x10000; i++) {
|
||||
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
|
||||
(((i & 0x3e0) >> 5) << systemGreenShift) |
|
||||
(((i & 0x7c00) >> 10) << systemBlueShift);
|
||||
}
|
||||
if (lcd) gbafilter_pal(systemColorMap16, 0x10000);
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
{
|
||||
for(int i = 0; i < 0x10000; i++) {
|
||||
systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
|
||||
(((i & 0x3e0) >> 5) << systemGreenShift) |
|
||||
(((i & 0x7c00) >> 10) << systemBlueShift);
|
||||
}
|
||||
if (lcd) gbafilter_pal32(systemColorMap32, 0x10000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for existence of file.
|
||||
bool utilFileExists( const char *filename )
|
||||
{
|
||||
FILE *f = fopen( filename, "r" );
|
||||
if( f == NULL ) {
|
||||
return false;
|
||||
} else {
|
||||
fclose( f );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,5 @@
|
||||
// -*- C++ -*-
|
||||
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
||||
// Copyright (C) 1999-2003 Forgotten
|
||||
// Copyright (C) 2004 Forgotten and the VBA development team
|
||||
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2, or(at your option)
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software Foundation,
|
||||
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef VBA_UTIL_H
|
||||
#define VBA_UTIL_H
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include "System.h"
|
||||
|
||||
@ -29,28 +10,47 @@ enum IMAGE_TYPE {
|
||||
};
|
||||
|
||||
// save game
|
||||
|
||||
typedef struct {
|
||||
void *address;
|
||||
int size;
|
||||
void *address;
|
||||
int size;
|
||||
} variable_desc;
|
||||
bool utilWritePNGFile(const char *, int, int, u8 *);
|
||||
bool utilWriteBMPFile(const char *, int, int, u8 *);
|
||||
void utilApplyIPS(const char *ips, uint8_t **rom, int *size);
|
||||
bool utilIsGBAImage(const char *);
|
||||
bool utilIsGBImage(const char *);
|
||||
bool utilIsGzipFile(const char *);
|
||||
void utilStripDoubleExtension(const char *, char *);
|
||||
IMAGE_TYPE utilFindType(const char *);
|
||||
uint8_t *utilLoad(const char *, bool (*)(const char*), uint8_t *, int &);
|
||||
|
||||
extern bool utilIsGBAImage(const char *);
|
||||
extern bool utilIsGBImage(const char *);
|
||||
extern bool utilIsZipFile(const char *);
|
||||
void utilPutDword(uint8_t *, uint32_t);
|
||||
void utilPutWord(uint8_t *, uint16_t);
|
||||
void utilWriteData(gzFile, variable_desc *);
|
||||
void utilReadData(gzFile, variable_desc *);
|
||||
void utilReadDataSkip(gzFile, variable_desc *);
|
||||
int utilReadInt(gzFile);
|
||||
void utilWriteInt(gzFile, int);
|
||||
gzFile utilGzOpen(const char *file, const char *mode);
|
||||
gzFile utilMemGzOpen(char *memory, int available, const char *mode);
|
||||
int utilGzWrite(gzFile file, const voidp buffer, unsigned int len);
|
||||
int utilGzRead(gzFile file, voidp buffer, unsigned int len);
|
||||
int utilGzClose(gzFile file);
|
||||
z_off_t utilGzSeek(gzFile file, z_off_t offset, int whence);
|
||||
long utilGzMemTell(gzFile file);
|
||||
void utilGBAFindSave(const u8 *, const int);
|
||||
void utilUpdateSystemColorMaps(bool lcd = false);
|
||||
bool utilFileExists( const char *filename );
|
||||
|
||||
extern void utilPutDword(u8 *, u32);
|
||||
extern void utilPutWord(u8 *, u16);
|
||||
extern void utilWriteData(gzFile, variable_desc *);
|
||||
extern void utilReadData(gzFile, variable_desc *);
|
||||
extern void utilReadDataSkip(gzFile, variable_desc *);
|
||||
extern int utilReadInt(gzFile);
|
||||
extern void utilWriteInt(gzFile, int);
|
||||
extern gzFile utilGzOpen(const char *file, const char *mode);
|
||||
extern gzFile utilMemGzOpen(char *memory, int available, const char *mode);
|
||||
extern int utilGzWrite(gzFile file, const voidp buffer, unsigned int len);
|
||||
extern int utilGzRead(gzFile file, voidp buffer, unsigned int len);
|
||||
extern int utilGzClose(gzFile file);
|
||||
extern z_off_t utilGzSeek(gzFile file, z_off_t offset, int whence);
|
||||
extern long utilGzMemTell(gzFile file);
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
void utilWriteIntMem(uint8_t *& data, int);
|
||||
void utilWriteMem(uint8_t *& data, const void *in_data, unsigned size);
|
||||
void utilWriteDataMem(uint8_t *& data, variable_desc *);
|
||||
|
||||
int utilReadIntMem(const uint8_t *& data);
|
||||
void utilReadMem(void *buf, const uint8_t *& data, unsigned size);
|
||||
void utilReadDataMem(const uint8_t *& data, variable_desc *);
|
||||
#endif
|
||||
|
||||
#endif // UTIL_H
|
||||
|
@ -29,7 +29,7 @@ int const silent_buf_size = 1; // size used for Silent_Blip_Buffer
|
||||
|
||||
Blip_Buffer::Blip_Buffer()
|
||||
{
|
||||
factor_ = LONG_MAX;
|
||||
factor_ = (blip_ulong)LONG_MAX;
|
||||
buffer_ = 0;
|
||||
buffer_size_ = 0;
|
||||
sample_rate_ = 0;
|
||||
@ -126,7 +126,7 @@ Blip_Buffer::blargg_err_t Blip_Buffer::set_sample_rate( long new_rate, int msec
|
||||
|
||||
blip_resampled_time_t Blip_Buffer::clock_rate_factor( long rate ) const
|
||||
{
|
||||
double ratio = (double)(sample_rate_) / double(rate);
|
||||
double ratio = (double) sample_rate_ / rate;
|
||||
blip_long factor = (blip_long) floor( ratio * (1L << BLIP_BUFFER_ACCURACY) + 0.5 );
|
||||
assert( factor > 0 || !sample_rate_ ); // fails if clock/output ratio is too large
|
||||
return (blip_resampled_time_t) factor;
|
||||
@ -226,17 +226,15 @@ static void gen_sinc( float* out, int count, double oversample, double treble, d
|
||||
treble = 5.0;
|
||||
|
||||
double const maxh = 4096.0;
|
||||
double const rolloff = pow( 10.0, treble / (maxh * 20.0 * (1.0 - cutoff)) );
|
||||
double const rolloff = pow( 10.0, 1.0 / (maxh * 20.0) * treble / (1.0 - cutoff) );
|
||||
double const pow_a_n = pow( rolloff, maxh - maxh * cutoff );
|
||||
double const to_angle = PI / (2.0 * maxh * oversample);
|
||||
double const to_angle = PI / 2 / maxh / oversample;
|
||||
for ( int i = 0; i < count; i++ )
|
||||
{
|
||||
double angle = double(((i - count)<<1) + 1) * to_angle;
|
||||
double maxhAngle = maxh * angle;
|
||||
double c = rolloff * cos( maxhAngle - angle ) - cos( maxhAngle );
|
||||
double cos_nc_angle = cos( maxhAngle * cutoff );
|
||||
double cos_nc1_angle = cos( maxhAngle * cutoff - angle );
|
||||
|
||||
double angle = ((i - count) * 2 + 1) * to_angle;
|
||||
double c = rolloff * cos( (maxh - 1.0) * angle ) - cos( maxh * angle );
|
||||
double cos_nc_angle = cos( maxh * cutoff * angle );
|
||||
double cos_nc1_angle = cos( (maxh * cutoff - 1.0) * angle );
|
||||
double cos_angle = cos( angle );
|
||||
|
||||
c = c * pow_a_n - rolloff * cos_nc1_angle + cos_nc_angle;
|
||||
@ -252,7 +250,7 @@ void blip_eq_t::generate( float* out, int count ) const
|
||||
{
|
||||
// lower cutoff freq for narrow kernels with their wider transition band
|
||||
// (8 points->1.49, 16 points->1.15)
|
||||
double oversample = blip_res * 2.25 / double(count) + 0.85;
|
||||
double oversample = blip_res * 2.25 / count + 0.85;
|
||||
double half_rate = sample_rate * 0.5;
|
||||
if ( cutoff_freq )
|
||||
oversample = half_rate / cutoff_freq;
|
||||
@ -270,9 +268,7 @@ void Blip_Synth_::adjust_impulse()
|
||||
{
|
||||
// sum pairs for each phase and add error correction to end of first half
|
||||
int const size = impulses_size();
|
||||
|
||||
int blipRes2 = blip_res >> 1;
|
||||
for ( int p = blip_res; p-- >= blipRes2; )
|
||||
for ( int p = blip_res; p-- >= blip_res / 2; )
|
||||
{
|
||||
int p2 = blip_res - 2 - p;
|
||||
long error = kernel_unit;
|
||||
@ -294,11 +290,9 @@ void Blip_Synth_::adjust_impulse()
|
||||
|
||||
void Blip_Synth_::treble_eq( blip_eq_t const& eq )
|
||||
{
|
||||
int blipRes2 = blip_res >> 1;
|
||||
float fimpulse [blip_res / 2 * (blip_widest_impulse_ - 1) + blip_res * 2];
|
||||
|
||||
float fimpulse [blipRes2 * (blip_widest_impulse_ - 1) + blip_res * 2];
|
||||
|
||||
int const half_size = blipRes2 * (width - 1);
|
||||
int const half_size = blip_res / 2 * (width - 1);
|
||||
eq.generate( &fimpulse [blip_res], half_size );
|
||||
|
||||
int i;
|
||||
@ -308,25 +302,25 @@ void Blip_Synth_::treble_eq( blip_eq_t const& eq )
|
||||
fimpulse [blip_res + half_size + i] = fimpulse [blip_res + half_size - 1 - i];
|
||||
|
||||
// starts at 0
|
||||
for ( i = 0; i < blip_res; ++i )
|
||||
for ( i = 0; i < blip_res; i++ )
|
||||
fimpulse [i] = 0.0f;
|
||||
|
||||
// find rescale factor
|
||||
double total = 0.0;
|
||||
for ( i = 0; i < half_size; ++i )
|
||||
for ( i = 0; i < half_size; i++ )
|
||||
total += fimpulse [blip_res + i];
|
||||
|
||||
//double const base_unit = 44800.0 - 128 * 18; // allows treble up to +0 dB
|
||||
//double const base_unit = 37888.0; // allows treble to +5 dB
|
||||
double const base_unit = 32768.0; // necessary for blip_unscaled to work
|
||||
double rescale = base_unit / (2 * total);
|
||||
double rescale = base_unit / 2 / total;
|
||||
kernel_unit = (long) base_unit;
|
||||
|
||||
// integrate, first difference, rescale, convert to int
|
||||
double sum = 0.0;
|
||||
double next = 0.0;
|
||||
int const size = this->impulses_size();
|
||||
for ( i = 0; i < size; ++i )
|
||||
for ( i = 0; i < size; i++ )
|
||||
{
|
||||
impulses [i] = (short) (int) floor( (next - sum) * rescale + 0.5 );
|
||||
sum += fimpulse [i];
|
||||
@ -361,7 +355,7 @@ void Blip_Synth_::volume_unit( double new_unit )
|
||||
// if unit is really small, might need to attenuate kernel
|
||||
while ( factor < 2.0 )
|
||||
{
|
||||
++shift;
|
||||
shift++;
|
||||
factor *= 2.0;
|
||||
}
|
||||
|
||||
@ -417,7 +411,7 @@ long Blip_Buffer::read_samples( blip_sample_t* out_, long max_samples, int stere
|
||||
blip_long s = BLIP_READER_READ( reader );
|
||||
BLIP_READER_NEXT_IDX_( reader, bass, offset );
|
||||
BLIP_CLAMP( s, s );
|
||||
out [offset << 1] = (blip_sample_t) s;
|
||||
out [offset * 2] = (blip_sample_t) s;
|
||||
}
|
||||
while ( ++offset );
|
||||
}
|
||||
|
@ -505,7 +505,7 @@ void Effects_Buffer::mix_effects( blip_sample_t* out_, int pair_count )
|
||||
int bufs_remain = bufs_size;
|
||||
do
|
||||
{
|
||||
if ( buf->non_silent() && ( buf->echo == (bool)echo_phase ) )
|
||||
if ( buf->non_silent() && ( buf->echo == !!echo_phase ) )
|
||||
{
|
||||
stereo_fixed_t* BLIP_RESTRICT out = (stereo_fixed_t*) &echo [echo_pos];
|
||||
int const bass = BLIP_READER_BASS( *buf );
|
||||
|
@ -50,6 +50,7 @@ public:
|
||||
|
||||
class Gb_Env : public Gb_Osc {
|
||||
public:
|
||||
Gb_Env() : env_enabled(false), env_delay(0) {}
|
||||
int env_delay;
|
||||
int volume;
|
||||
bool env_enabled;
|
||||
|
@ -1,471 +1,445 @@
|
||||
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
||||
// Copyright (C) 1999-2003 Forgotten
|
||||
// Copyright (C) 2004-2006 Forgotten and the VBA development team
|
||||
// Copyright (C) 2007-2008 VBA-M development team and Shay Green
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2, or(at your option)
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software Foundation,
|
||||
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "../System.h"
|
||||
#include "memfile.h"
|
||||
#include "Patch.h"
|
||||
|
||||
/*
|
||||
#ifdef __GNUC__
|
||||
typedef off64_t __off64_t;
|
||||
#endif
|
||||
*/
|
||||
#ifndef _MSC_VER
|
||||
#define _stricmp strcasecmp
|
||||
#endif // ! _MSC_VER
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define fseeko64 _fseeki64
|
||||
#define ftello64 _ftelli64
|
||||
typedef __int64 __off64_t;
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined (MACOSX)
|
||||
#define fseeko64 fseeko
|
||||
#define ftello64 ftello
|
||||
typedef off_t __off64_t;
|
||||
#endif /* __APPLE__ || MACOSX */
|
||||
|
||||
static int readInt2(MFILE *f) {
|
||||
int res = 0;
|
||||
int c = memfgetc(f);
|
||||
if (c == MEOF)
|
||||
return -1;
|
||||
res = c;
|
||||
c = memfgetc(f);
|
||||
if (c == MEOF)
|
||||
return -1;
|
||||
return c + (res << 8);
|
||||
static int readInt2(MFILE *f)
|
||||
{
|
||||
int res = 0;
|
||||
int c = memfgetc(f);
|
||||
if(c == MEOF)
|
||||
return -1;
|
||||
res = c;
|
||||
c = memfgetc(f);
|
||||
if(c == MEOF)
|
||||
return -1;
|
||||
return c + (res<<8);
|
||||
}
|
||||
|
||||
static int readInt3(MFILE *f) {
|
||||
int res = 0;
|
||||
int c = memfgetc(f);
|
||||
if (c == MEOF)
|
||||
return -1;
|
||||
res = c;
|
||||
c = memfgetc(f);
|
||||
if (c == MEOF)
|
||||
return -1;
|
||||
res = c + (res << 8);
|
||||
c = memfgetc(f);
|
||||
if (c == MEOF)
|
||||
return -1;
|
||||
return c + (res << 8);
|
||||
static int readInt3(MFILE *f)
|
||||
{
|
||||
int res = 0;
|
||||
int c = memfgetc(f);
|
||||
if(c == MEOF)
|
||||
return -1;
|
||||
res = c;
|
||||
c = memfgetc(f);
|
||||
if(c == MEOF)
|
||||
return -1;
|
||||
res = c + (res<<8);
|
||||
c = memfgetc(f);
|
||||
if(c == MEOF)
|
||||
return -1;
|
||||
return c + (res<<8);
|
||||
}
|
||||
|
||||
static s64 readInt4(MFILE *f) {
|
||||
s64 tmp, res = 0;
|
||||
int c;
|
||||
static s64 readInt4(MFILE *f)
|
||||
{
|
||||
s64 tmp, res = 0;
|
||||
int c;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
c = memfgetc(f);
|
||||
if (c == MEOF)
|
||||
return -1;
|
||||
tmp = c;
|
||||
res = res + (tmp << (i * 8));
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
c = memfgetc(f);
|
||||
if (c == MEOF)
|
||||
return -1;
|
||||
tmp = c;
|
||||
res = res + (tmp << (i*8));
|
||||
}
|
||||
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
|
||||
static s64 readInt8(MFILE *f) {
|
||||
s64 tmp, res = 0;
|
||||
int c;
|
||||
static s64 readInt8(MFILE *f)
|
||||
{
|
||||
s64 tmp, res = 0;
|
||||
int c;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
c = memfgetc(f);
|
||||
if (c == MEOF)
|
||||
return -1;
|
||||
tmp = c;
|
||||
res = res + (tmp << (i * 8));
|
||||
}
|
||||
for (int i = 0; i < 8; i++) {
|
||||
c = memfgetc(f);
|
||||
if (c == MEOF)
|
||||
return -1;
|
||||
tmp = c;
|
||||
res = res + (tmp << (i*8));
|
||||
}
|
||||
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
|
||||
static s64 readVarPtr(MFILE *f) {
|
||||
s64 offset = 0, shift = 1;
|
||||
for (;;) {
|
||||
int c = memfgetc(f);
|
||||
if (c == MEOF)
|
||||
return 0;
|
||||
offset += (c & 0x7F) * shift;
|
||||
if (c & 0x80)
|
||||
break;
|
||||
shift <<= 7;
|
||||
offset += shift;
|
||||
}
|
||||
return offset;
|
||||
static s64 readVarPtr(MFILE *f)
|
||||
{
|
||||
s64 offset = 0, shift = 1;
|
||||
for (;;) {
|
||||
int c = memfgetc(f);
|
||||
if (c == MEOF) return 0;
|
||||
offset += (c & 0x7F) * shift;
|
||||
if (c & 0x80) break;
|
||||
shift <<= 7;
|
||||
offset += shift;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#endif
|
||||
|
||||
static uLong computePatchCRC(MFILE *f, unsigned int size) {
|
||||
Bytef buf[4096];
|
||||
long readed;
|
||||
static uLong computePatchCRC(MFILE *f, unsigned int size)
|
||||
{
|
||||
Bytef buf[4096];
|
||||
long readed;
|
||||
|
||||
uLong crc = crc32(0L, Z_NULL, 0);
|
||||
do {
|
||||
readed = memfread(buf, 1, MIN(size, sizeof(buf)), f);
|
||||
crc = crc32(crc, buf, readed);
|
||||
size -= readed;
|
||||
} while (readed > 0);
|
||||
|
||||
return crc;
|
||||
uLong crc = crc32(0L, Z_NULL, 0);
|
||||
do {
|
||||
readed = memfread(buf, 1, MIN(size, sizeof(buf)), f);
|
||||
crc = crc32(crc, buf, readed);
|
||||
size -= readed;
|
||||
} while (readed > 0);
|
||||
return crc;
|
||||
}
|
||||
|
||||
bool patchApplyIPS(MFILE * f, u8 **r, int *s) {
|
||||
// from the IPS spec at http://zerosoft.zophar.net/ips.htm
|
||||
bool patchApplyIPS(MFILE *f, u8 **r, int *s)
|
||||
{
|
||||
// from the IPS spec at http://zerosoft.zophar.net/ips.htm
|
||||
|
||||
bool result = false;
|
||||
bool result = false;
|
||||
|
||||
u8 *rom = *r;
|
||||
int size = *s;
|
||||
if (memfgetc(f) == 'P' && memfgetc(f) == 'A' && memfgetc(f) == 'T'
|
||||
&& memfgetc(f) == 'C' && memfgetc(f) == 'H') {
|
||||
int b;
|
||||
int offset;
|
||||
int len;
|
||||
u8 *rom = *r;
|
||||
int size = *s;
|
||||
if(memfgetc(f) == 'P' &&
|
||||
memfgetc(f) == 'A' &&
|
||||
memfgetc(f) == 'T' &&
|
||||
memfgetc(f) == 'C' &&
|
||||
memfgetc(f) == 'H') {
|
||||
int b;
|
||||
int offset;
|
||||
int len;
|
||||
|
||||
result = true;
|
||||
result = true;
|
||||
|
||||
for (;;) {
|
||||
// read offset
|
||||
offset = readInt3(f);
|
||||
// if offset == MEOF, end of patch
|
||||
if (offset == 0x454f46 || offset == -1)
|
||||
break;
|
||||
// read length
|
||||
len = readInt2(f);
|
||||
if (!len) {
|
||||
// len == 0, RLE block
|
||||
len = readInt2(f);
|
||||
// byte to fill
|
||||
int c = memfgetc(f);
|
||||
if (c == -1)
|
||||
break;
|
||||
b = (u8) c;
|
||||
} else
|
||||
b = -1;
|
||||
// check if we need to reallocate our ROM
|
||||
if ((offset + len) >= size) {
|
||||
for(;;) {
|
||||
// read offset
|
||||
offset = readInt3(f);
|
||||
// if offset == MEOF, end of patch
|
||||
if(offset == 0x454f46 || offset == -1)
|
||||
break;
|
||||
// read length
|
||||
len = readInt2(f);
|
||||
if(!len) {
|
||||
// len == 0, RLE block
|
||||
len = readInt2(f);
|
||||
// byte to fill
|
||||
int c = memfgetc(f);
|
||||
if(c == -1)
|
||||
break;
|
||||
b = (u8)c;
|
||||
} else
|
||||
b= -1;
|
||||
// check if we need to reallocate our ROM
|
||||
if((offset + len) >= size) {
|
||||
#ifdef GEKKO
|
||||
size = offset + len;
|
||||
size = offset + len;
|
||||
#else
|
||||
size *= 2;
|
||||
rom = (u8 *) realloc(rom, size);
|
||||
size *= 2;
|
||||
rom = (u8 *)realloc(rom, size);
|
||||
#endif
|
||||
*r = rom;
|
||||
*s = size;
|
||||
}
|
||||
if (b == -1) {
|
||||
// normal block, just read the data
|
||||
if (memfread(&rom[offset], 1, len, f) != (size_t) len)
|
||||
break;
|
||||
} else {
|
||||
// fill the region with the given byte
|
||||
while (len--) {
|
||||
rom[offset++] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
*r = rom;
|
||||
*s = size;
|
||||
}
|
||||
if(b == -1) {
|
||||
// normal block, just read the data
|
||||
if(memfread(&rom[offset], 1, len, f) != (size_t)len)
|
||||
break;
|
||||
} else {
|
||||
// fill the region with the given byte
|
||||
while(len--) {
|
||||
rom[offset++] = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool patchApplyUPS(MFILE * f, u8 **rom, int *size) {
|
||||
bool patchApplyUPS(MFILE *f, u8 **rom, int *size)
|
||||
{
|
||||
s64 srcCRC, dstCRC, patchCRC;
|
||||
|
||||
s64 srcCRC, dstCRC, patchCRC;
|
||||
memfseek(f, 0, MSEEK_END);
|
||||
long int patchSize = memftell(f);
|
||||
if (patchSize < 20) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memfseek(f, 0, MSEEK_END);
|
||||
long int patchSize = memftell(f);
|
||||
if (patchSize < 20) {
|
||||
return false;
|
||||
}
|
||||
memfseek(f, 0, MSEEK_SET);
|
||||
if(memfgetc(f) != 'U' || memfgetc(f) != 'P' || memfgetc(f) != 'S' || memfgetc(f) != '1') {
|
||||
return false;
|
||||
}
|
||||
|
||||
memfseek(f, 0, MSEEK_SET);
|
||||
memfseek(f, -12, MSEEK_END);
|
||||
srcCRC = readInt4(f);
|
||||
dstCRC = readInt4(f);
|
||||
patchCRC = readInt4(f);
|
||||
if (srcCRC == -1 || dstCRC == -1 || patchCRC == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memfgetc(f) != 'U' || memfgetc(f) != 'P' || memfgetc(f) != 'S'
|
||||
|| memfgetc(f) != '1') {
|
||||
return false;
|
||||
}
|
||||
memfseek(f, 0, MSEEK_SET);
|
||||
u32 crc = computePatchCRC(f, patchSize-4);
|
||||
|
||||
memfseek(f, -12, MSEEK_END);
|
||||
srcCRC = readInt4(f);
|
||||
dstCRC = readInt4(f);
|
||||
patchCRC = readInt4(f);
|
||||
if (srcCRC == -1 || dstCRC == -1 || patchCRC == -1) {
|
||||
return false;
|
||||
}
|
||||
if (crc != patchCRC) {
|
||||
return false;
|
||||
}
|
||||
|
||||
memfseek(f, 0, MSEEK_SET);
|
||||
u32 crc = computePatchCRC(f, patchSize - 4);
|
||||
crc = crc32(0L, Z_NULL, 0);
|
||||
crc = crc32(crc, *rom, *size);
|
||||
|
||||
if (crc != patchCRC) {
|
||||
return false;
|
||||
}
|
||||
memfseek(f, 4, MSEEK_SET);
|
||||
s64 dataSize;
|
||||
s64 srcSize = readVarPtr(f);
|
||||
s64 dstSize = readVarPtr(f);
|
||||
|
||||
crc = crc32(0L, Z_NULL, 0);
|
||||
crc = crc32(crc, *rom, *size);
|
||||
if (crc == srcCRC) {
|
||||
if (srcSize != *size) {
|
||||
return false;
|
||||
}
|
||||
dataSize = dstSize;
|
||||
} else if (crc == dstCRC) {
|
||||
if (dstSize != *size) {
|
||||
return false;
|
||||
}
|
||||
dataSize = srcSize;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (dataSize > *size) {
|
||||
*rom = (u8*)realloc(*rom, dataSize);
|
||||
memset(*rom + *size, 0, dataSize - *size);
|
||||
*size = dataSize;
|
||||
}
|
||||
|
||||
memfseek(f, 4, MSEEK_SET);
|
||||
s64 dataSize;
|
||||
s64 srcSize = readVarPtr(f);
|
||||
s64 dstSize = readVarPtr(f);
|
||||
s64 relative = 0;
|
||||
u8 *mem;
|
||||
while(memftell(f) < patchSize - 12) {
|
||||
relative += readVarPtr(f);
|
||||
if (relative > dataSize) continue;
|
||||
mem = *rom + relative;
|
||||
for(s64 i = relative; i < dataSize; i++) {
|
||||
int x = memfgetc(f);
|
||||
relative++;
|
||||
if (!x) break;
|
||||
if (i < dataSize) {
|
||||
*mem++ ^= x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (crc == srcCRC) {
|
||||
dataSize = srcSize;
|
||||
} else if (crc == dstCRC) {
|
||||
dataSize = dstSize;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (dataSize != *size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
s64 relative = 0;
|
||||
u8 *mem;
|
||||
while (memftell(f) < patchSize - 12) {
|
||||
relative += readVarPtr(f);
|
||||
if (relative > dataSize)
|
||||
continue;
|
||||
mem = *rom + relative;
|
||||
for (s64 i = relative; i < dataSize; i++) {
|
||||
int x = memfgetc(f);
|
||||
relative++;
|
||||
if (!x)
|
||||
break;
|
||||
if (i < dataSize) {
|
||||
*mem++ ^= x;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int ppfVersion(MFILE *f) {
|
||||
memfseek(f, 0, MSEEK_SET);
|
||||
if (memfgetc(f) != 'P' || memfgetc(f) != 'P' || memfgetc(f) != 'F')
|
||||
return 0;
|
||||
switch (memfgetc(f)) {
|
||||
case '1':
|
||||
return 1;
|
||||
case '2':
|
||||
return 2;
|
||||
case '3':
|
||||
return 3;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
static int ppfVersion(MFILE *f)
|
||||
{
|
||||
memfseek(f, 0, MSEEK_SET);
|
||||
if (memfgetc(f) != 'P' || memfgetc(f) != 'P' || memfgetc(f) != 'F') //-V501
|
||||
return 0;
|
||||
switch(memfgetc(f)){
|
||||
case '1': return 1;
|
||||
case '2': return 2;
|
||||
case '3': return 3;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int ppfFileIdLen(MFILE *f, int version) {
|
||||
if (version == 2) {
|
||||
memfseek(f, -8, MSEEK_END);
|
||||
} else {
|
||||
memfseek(f, -6, MSEEK_END);
|
||||
}
|
||||
static int ppfFileIdLen(MFILE *f, int version)
|
||||
{
|
||||
if (version == 2) {
|
||||
memfseek(f, -8, MSEEK_END);
|
||||
} else {
|
||||
memfseek(f, -6, MSEEK_END);
|
||||
}
|
||||
|
||||
if (memfgetc(f) != '.' || memfgetc(f) != 'D' || memfgetc(f) != 'I'
|
||||
|| memfgetc(f) != 'Z')
|
||||
return 0;
|
||||
if (memfgetc(f) != '.' || memfgetc(f) != 'D' || memfgetc(f) != 'I' || memfgetc(f) != 'Z')
|
||||
return 0;
|
||||
|
||||
return (version == 2) ? readInt4(f) : readInt2(f);
|
||||
return (version == 2) ? readInt4(f) : readInt2(f);
|
||||
}
|
||||
|
||||
static bool patchApplyPPF1(MFILE *f, u8 **rom, int *size) {
|
||||
memfseek(f, 0, MSEEK_END);
|
||||
int count = memftell(f);
|
||||
if (count < 56)
|
||||
return false;
|
||||
count -= 56;
|
||||
static bool patchApplyPPF1(MFILE *f, u8 **rom, int *size)
|
||||
{
|
||||
memfseek(f, 0, MSEEK_END);
|
||||
int count = memftell(f);
|
||||
if (count < 56)
|
||||
return false;
|
||||
count -= 56;
|
||||
|
||||
memfseek(f, 56, MSEEK_SET);
|
||||
memfseek(f, 56, MSEEK_SET);
|
||||
|
||||
u8 *mem = *rom;
|
||||
u8 *mem = *rom;
|
||||
|
||||
while (count > 0) {
|
||||
int offset = readInt4(f);
|
||||
if (offset == -1)
|
||||
break;
|
||||
int len = memfgetc(f);
|
||||
if (len == MEOF)
|
||||
break;
|
||||
if (offset + len > *size)
|
||||
break;
|
||||
if (memfread(&mem[offset], 1, len, f) != (size_t) len)
|
||||
break;
|
||||
count -= 4 + 1 + len;
|
||||
}
|
||||
while (count > 0) {
|
||||
int offset = readInt4(f);
|
||||
if (offset == -1)
|
||||
break;
|
||||
int len = memfgetc(f);
|
||||
if (len == MEOF)
|
||||
break;
|
||||
if (offset+len > *size)
|
||||
break;
|
||||
if (memfread(&mem[offset], 1, len, f) != (size_t)len)
|
||||
break;
|
||||
count -= 4 + 1 + len;
|
||||
}
|
||||
|
||||
return (count == 0);
|
||||
return (count == 0);
|
||||
}
|
||||
|
||||
static bool patchApplyPPF2(MFILE *f, u8 **rom, int *size) {
|
||||
memfseek(f, 0, MSEEK_END);
|
||||
int count = memftell(f);
|
||||
if (count < 56 + 4 + 1024)
|
||||
return false;
|
||||
count -= 56 + 4 + 1024;
|
||||
static bool patchApplyPPF2(MFILE *f, u8 **rom, int *size)
|
||||
{
|
||||
memfseek(f, 0, MSEEK_END);
|
||||
int count = memftell(f);
|
||||
if (count < 56+4+1024)
|
||||
return false;
|
||||
count -= 56+4+1024;
|
||||
|
||||
memfseek(f, 56, MSEEK_SET);
|
||||
memfseek(f, 56, MSEEK_SET);
|
||||
|
||||
int datalen = readInt4(f);
|
||||
if (datalen != *size)
|
||||
return false;
|
||||
int datalen = readInt4(f);
|
||||
if (datalen != *size)
|
||||
return false;
|
||||
|
||||
u8 *mem = *rom;
|
||||
u8 *mem = *rom;
|
||||
|
||||
u8 block[1024];
|
||||
memfread(&block, 1, 1024, f);
|
||||
if (memcmp(&mem[0x9320], &block, 1024) != 0)
|
||||
return false;
|
||||
u8 block[1024];
|
||||
memfread(&block, 1, 1024, f);
|
||||
if (memcmp(&mem[0x9320], &block, 1024) != 0)
|
||||
return false;
|
||||
|
||||
int idlen = ppfFileIdLen(f, 2);
|
||||
if (idlen > 0)
|
||||
count -= 16 + 16 + idlen;
|
||||
int idlen = ppfFileIdLen(f, 2);
|
||||
if (idlen > 0)
|
||||
count -= 16 + 16 + idlen;
|
||||
|
||||
memfseek(f, 56 + 4 + 1024, MSEEK_SET);
|
||||
memfseek(f, 56+4+1024, MSEEK_SET);
|
||||
|
||||
while (count > 0) {
|
||||
int offset = readInt4(f);
|
||||
if (offset == -1)
|
||||
break;
|
||||
int len = memfgetc(f);
|
||||
if (len == MEOF)
|
||||
break;
|
||||
if (offset + len > *size)
|
||||
break;
|
||||
if (memfread(&mem[offset], 1, len, f) != (size_t) len)
|
||||
break;
|
||||
count -= 4 + 1 + len;
|
||||
}
|
||||
while (count > 0) {
|
||||
int offset = readInt4(f);
|
||||
if (offset == -1)
|
||||
break;
|
||||
int len = memfgetc(f);
|
||||
if (len == MEOF)
|
||||
break;
|
||||
if (offset+len > *size)
|
||||
break;
|
||||
if (memfread(&mem[offset], 1, len, f) != (size_t)len)
|
||||
break;
|
||||
count -= 4 + 1 + len;
|
||||
}
|
||||
|
||||
return (count == 0);
|
||||
return (count == 0);
|
||||
}
|
||||
|
||||
static bool patchApplyPPF3(MFILE *f, u8 **rom, int *size) {
|
||||
memfseek(f, 0, MSEEK_END);
|
||||
int count = memftell(f);
|
||||
if (count < 56 + 4 + 1024)
|
||||
return false;
|
||||
count -= 56 + 4;
|
||||
static bool patchApplyPPF3(MFILE *f, u8 **rom, int *size)
|
||||
{
|
||||
memfseek(f, 0, MSEEK_END);
|
||||
int count = memftell(f);
|
||||
if (count < 56+4+1024)
|
||||
return false;
|
||||
count -= 56+4;
|
||||
|
||||
memfseek(f, 56, MSEEK_SET);
|
||||
memfseek(f, 56, MSEEK_SET);
|
||||
|
||||
int imagetype = memfgetc(f);
|
||||
int blockcheck = memfgetc(f);
|
||||
int undo = memfgetc(f);
|
||||
memfgetc(f);
|
||||
int imagetype = memfgetc(f);
|
||||
int blockcheck = memfgetc(f);
|
||||
int undo = memfgetc(f);
|
||||
memfgetc(f);
|
||||
|
||||
u8 *mem = *rom;
|
||||
u8 *mem = *rom;
|
||||
|
||||
if (blockcheck) {
|
||||
u8 block[1024];
|
||||
memfread(&block, 1, 1024, f);
|
||||
if (memcmp(&mem[(imagetype == 0) ? 0x9320 : 0x80A0], &block, 1024) != 0)
|
||||
return false;
|
||||
count -= 1024;
|
||||
}
|
||||
if (blockcheck) {
|
||||
u8 block[1024];
|
||||
memfread(&block, 1, 1024, f);
|
||||
if (memcmp(&mem[(imagetype == 0) ? 0x9320 : 0x80A0], &block, 1024) != 0)
|
||||
return false;
|
||||
count -= 1024;
|
||||
}
|
||||
|
||||
int idlen = ppfFileIdLen(f, 2);
|
||||
if (idlen > 0)
|
||||
count -= 16 + 16 + idlen;
|
||||
int idlen = ppfFileIdLen(f, 2);
|
||||
if (idlen > 0)
|
||||
count -= 16 + 16 + idlen;
|
||||
|
||||
memfseek(f, 56 + 4 + (blockcheck ? 1024 : 0), MSEEK_SET);
|
||||
memfseek(f, 56+4+(blockcheck ? 1024 : 0), MSEEK_SET);
|
||||
|
||||
while (count > 0) {
|
||||
s64 offset = readInt8(f);
|
||||
if (offset == -1)
|
||||
break;
|
||||
int len = memfgetc(f);
|
||||
if (len == MEOF)
|
||||
break;
|
||||
if (offset + len > *size)
|
||||
break;
|
||||
if (memfread(&mem[offset], 1, len, f) != (size_t) len)
|
||||
break;
|
||||
if (undo)
|
||||
memfseek(f, len, MSEEK_CUR);
|
||||
count -= 8 + 1 + len;
|
||||
if (undo)
|
||||
count -= len;
|
||||
}
|
||||
while (count > 0) {
|
||||
s64 offset = readInt8(f);
|
||||
if (offset == -1)
|
||||
break;
|
||||
int len = memfgetc(f);
|
||||
if (len == MEOF)
|
||||
break;
|
||||
if (offset+len > *size)
|
||||
break;
|
||||
if (memfread(&mem[offset], 1, len, f) != (size_t)len)
|
||||
break;
|
||||
if (undo) memfseek(f, len, MSEEK_CUR);
|
||||
count -= 8 + 1 + len;
|
||||
if (undo) count -= len;
|
||||
}
|
||||
|
||||
return (count == 0);
|
||||
return (count == 0);
|
||||
}
|
||||
|
||||
bool patchApplyPPF(MFILE *f, u8 **rom, int *size)
|
||||
{
|
||||
bool res = false;
|
||||
bool res = false;
|
||||
|
||||
int version = ppfVersion(f);
|
||||
switch (version)
|
||||
{
|
||||
case 1: res = patchApplyPPF1(f, rom, size); break;
|
||||
case 2: res = patchApplyPPF2(f, rom, size); break;
|
||||
case 3: res = patchApplyPPF3(f, rom, size); break;
|
||||
}
|
||||
int version = ppfVersion(f);
|
||||
switch (version) {
|
||||
case 1: res = patchApplyPPF1(f, rom, size); break;
|
||||
case 2: res = patchApplyPPF2(f, rom, size); break;
|
||||
case 3: res = patchApplyPPF3(f, rom, size); break;
|
||||
}
|
||||
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool applyPatch(const char *patchname, u8 **rom, int *size)
|
||||
{
|
||||
bool result = false;
|
||||
bool result = false;
|
||||
|
||||
if (strlen(patchname) < 5)
|
||||
return false;
|
||||
const char * p = strrchr(patchname, '.');
|
||||
if (p == NULL)
|
||||
return false;
|
||||
if (strlen(patchname) < 5)
|
||||
return false;
|
||||
const char * p = strrchr(patchname, '.');
|
||||
if (p == NULL)
|
||||
return false;
|
||||
|
||||
FILE *f = fopen(patchname, "rb");
|
||||
if (!f)
|
||||
return false;
|
||||
FILE *f = fopen(patchname, "rb");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
// read in file
|
||||
fseek(f, 0, SEEK_END); // go to end of file
|
||||
int filesize = ftell(f); // get filesize
|
||||
fseek(f, 0, SEEK_SET); // go to start of file
|
||||
char * pbuffer = (char *) malloc(filesize);
|
||||
fread (pbuffer, 1, filesize, f);
|
||||
fclose(f);
|
||||
// read in file
|
||||
fseek(f, 0, SEEK_END); // go to end of file
|
||||
int filesize = ftell(f); // get filesize
|
||||
fseek(f, 0, SEEK_SET); // go to start of file
|
||||
char * pbuffer = (char *) malloc(filesize);
|
||||
fread (pbuffer, 1, filesize, f);
|
||||
fclose(f);
|
||||
|
||||
MFILE * mf = memfopen(pbuffer, filesize); // create memory file
|
||||
MFILE * mf = memfopen(pbuffer, filesize); // create memory file
|
||||
|
||||
if (_stricmp(p, ".ips") == 0)
|
||||
result = patchApplyIPS(mf, rom, size);
|
||||
else if (_stricmp(p, ".ups") == 0)
|
||||
result = patchApplyUPS(mf, rom, size);
|
||||
else if (_stricmp(p, ".ppf") == 0)
|
||||
result = patchApplyPPF(mf, rom, size);
|
||||
if (_stricmp(p, ".ips") == 0)
|
||||
result = patchApplyIPS(mf, rom, size);
|
||||
else if (_stricmp(p, ".ups") == 0)
|
||||
result = patchApplyUPS(mf, rom, size);
|
||||
else if (_stricmp(p, ".ppf") == 0)
|
||||
result = patchApplyPPF(mf, rom, size);
|
||||
|
||||
memfclose(mf); // close memory file
|
||||
free(pbuffer); // free buffer
|
||||
memfclose(mf); // close memory file
|
||||
free(pbuffer); // free buffer
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
@ -1,31 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
||||
// Copyright (C) 1999-2003 Forgotten
|
||||
// Copyright (C) 2004 Forgotten and the VBA development team
|
||||
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2, or(at your option)
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software Foundation,
|
||||
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#ifndef VBA_PATCH_H
|
||||
#define VBA_PATCH_H
|
||||
#ifndef PATCH_H
|
||||
#define PATCH_H
|
||||
|
||||
#include "memfile.h"
|
||||
#include "System.h"
|
||||
#include "Types.h"
|
||||
|
||||
bool applyPatch(const char *patchname, u8 **rom, int *size);
|
||||
bool patchApplyIPS(MFILE * f, u8 **r, int *s);
|
||||
bool patchApplyUPS(MFILE * f, u8 **rom, int *size);
|
||||
bool patchApplyPPF(MFILE *f, u8 **rom, int *size);
|
||||
|
||||
#endif
|
||||
#endif // PATCH_H
|
||||
|
@ -1,24 +1,17 @@
|
||||
// -*- C++ -*-
|
||||
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
||||
// Copyright (C) 1999-2003 Forgotten
|
||||
// Copyright (C) 2004 Forgotten and the VBA development team
|
||||
#ifndef PORT_H
|
||||
#define PORT_H
|
||||
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2, or(at your option)
|
||||
// any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software Foundation,
|
||||
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#ifdef __CELLOS_LV2__
|
||||
/* PlayStation3 */
|
||||
#include <ppu_intrinsics.h>
|
||||
#endif
|
||||
|
||||
#ifndef VBA_PORT_H
|
||||
#define VBA_PORT_H
|
||||
#ifdef _XBOX360
|
||||
/* XBox 360 */
|
||||
#include <ppcintrinsics.h>
|
||||
#endif
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
// swaps a 16-bit value
|
||||
static inline u16 swap16(u16 v)
|
||||
@ -72,4 +65,4 @@ static inline u32 swap32(u32 v)
|
||||
*((u32 *)x) = (v)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif // PORT_H
|
||||
|
@ -13,7 +13,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software Foundation,
|
||||
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifndef __VBA_SOUND_DRIVER_H__
|
||||
#define __VBA_SOUND_DRIVER_H__
|
||||
|
@ -13,7 +13,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software Foundation,
|
||||
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifndef __VBA_TYPES_H__
|
||||
#define __VBA_TYPES_H__
|
||||
|
@ -9,7 +9,7 @@
|
||||
* Adapted from original gzio.c from zlib library by Forgotten
|
||||
*/
|
||||
|
||||
/* @(#) $Id: memgzio.c,v 1.5 2006/06/06 21:04:20 spacy51 Exp $ */
|
||||
/* @(#) $Id: memgzio.c 1213 2013-09-21 13:57:40Z kode54 $ */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
@ -697,3 +697,23 @@ long ZEXPORT memtell(file)
|
||||
|
||||
return memTell(s->file);
|
||||
}
|
||||
|
||||
z_off_t ZEXPORT memgzseek(gzFile file, z_off_t off, int whence)
|
||||
{
|
||||
char buf[80];
|
||||
|
||||
if(whence != SEEK_CUR) {
|
||||
fputs("FIXME: memgzio does not support seeking\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// this is inefficient, but the best I can do without actually reading
|
||||
// the above code
|
||||
while(off > 0) {
|
||||
int r = memgzread(file, buf, off > 80 ? 80 : off);
|
||||
if(r <= 0)
|
||||
return -1;
|
||||
off -= r;
|
||||
}
|
||||
return memtell(file);
|
||||
}
|
||||
|
@ -19,5 +19,6 @@ int ZEXPORT memgzread(gzFile file, voidp buf, unsigned len);
|
||||
int ZEXPORT memgzwrite(gzFile file, const voidp buf, unsigned len);
|
||||
int ZEXPORT memgzclose(gzFile file);
|
||||
long ZEXPORT memtell(gzFile file);
|
||||
z_off_t ZEXPORT memgzseek(gzFile file, z_off_t off, int whence);
|
||||
|
||||
#endif // MEMGZIO_H
|
||||
|
@ -17,7 +17,12 @@ typedef union {
|
||||
u16 W;
|
||||
} gbRegister;
|
||||
|
||||
extern gbRegister AF, BC, DE, HL, SP, PC;
|
||||
extern u16 IFF;
|
||||
int gbDis(char *, u16);
|
||||
|
||||
bool gbLoadRom(const char *);
|
||||
bool gbUpdateSizes();
|
||||
void gbEmulate(int);
|
||||
void gbWriteMemory(register u16, register u8);
|
||||
void gbDrawLine();
|
||||
@ -38,8 +43,11 @@ bool gbWritePNGFile(const char *);
|
||||
bool gbWriteBMPFile(const char *);
|
||||
bool gbReadGSASnapshot(const char *);
|
||||
|
||||
extern int gbHardware;
|
||||
|
||||
extern struct EmulatedSystem GBSystem;
|
||||
|
||||
// For VBA-GX
|
||||
bool MemgbReadBatteryFile(char * membuffer, int read);
|
||||
int MemgbWriteBatteryFile(char * membuffer);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include <string.h>
|
||||
#include <cstdlib>
|
||||
#include "../common/Types.h"
|
||||
|
||||
u8 *gbMemoryMap[16];
|
||||
@ -30,7 +30,7 @@ u16 gbColorFilter[32768];
|
||||
int gbColorOption = 0;
|
||||
int gbPaletteOption = 0;
|
||||
int gbEmulatorType = 0;
|
||||
int gbBorderOn = 1;
|
||||
int gbBorderOn = 0;
|
||||
int gbBorderAutomatic = 0;
|
||||
int gbBorderLineSkip = 160;
|
||||
int gbBorderRowSkip = 0;
|
||||
@ -38,3 +38,4 @@ int gbBorderColumnSkip = 0;
|
||||
int gbDmaTicks = 0;
|
||||
|
||||
u8 (*gbSerialFunction)(u8) = NULL;
|
||||
void (*sgbBorderListener)(bool) = NULL;
|
||||
|
@ -5,10 +5,12 @@
|
||||
#include "gb.h"
|
||||
u8 gbDaysinMonth [12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
const u8 gbDisabledRam [8] = {0x80, 0xff, 0xf0, 0x00, 0x30, 0xbf, 0xbf, 0xbf};
|
||||
extern int gbHardware;
|
||||
extern int gbGBCColorType;
|
||||
extern gbRegister PC;
|
||||
|
||||
// for UTC offset
|
||||
#include "../../vbagx.h"
|
||||
|
||||
mapperMBC1 gbDataMBC1 = {
|
||||
0, // RAM enable
|
||||
1, // ROM bank
|
||||
@ -327,7 +329,7 @@ mapperMBC3 gbDataMBC3 = {
|
||||
|
||||
void memoryUpdateMBC3Clock()
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
time_t now = time(NULL) - (GCSettings.OffsetMinutesUTC*60);
|
||||
time_t diff = now - gbDataMBC3.mapperLastTime;
|
||||
if(diff > 0) {
|
||||
// update the clock according to the last update time
|
||||
@ -437,6 +439,7 @@ void mapperMBC3RAM(u16 address, u8 value)
|
||||
}
|
||||
} else {
|
||||
time(&gbDataMBC3.mapperLastTime);
|
||||
gbDataMBC3.mapperLastTime -= (GCSettings.OffsetMinutesUTC*60);
|
||||
switch(gbDataMBC3.mapperClockRegister) {
|
||||
case 0x08:
|
||||
gbDataMBC3.mapperSeconds = value;
|
||||
@ -540,7 +543,6 @@ mapperMBC5 gbDataMBC5 = {
|
||||
0 // is rumble cartridge?
|
||||
};
|
||||
|
||||
extern int ConfigRequested;
|
||||
// MBC5 ROM write registers
|
||||
void mapperMBC5ROM(u16 address, u8 value)
|
||||
{
|
||||
@ -581,18 +583,10 @@ void mapperMBC5ROM(u16 address, u8 value)
|
||||
gbMemoryMap[0x07] = &gbRom[tmpAddress + 0x3000];
|
||||
}
|
||||
break;
|
||||
case 0x4000: // RAM bank select, plus rumble
|
||||
// Some games support rumble, such as Disney Tarzan, but aren't on a
|
||||
// rumble cartridge. As long as the RAM is less than or equal to 256Kbit
|
||||
// we know that the last address line is not used for real RAM addresses,
|
||||
// so it must be a rumble signal instead.
|
||||
if(gbDataMBC5.isRumbleCartridge) {
|
||||
systemCartridgeRumble(value & 0x08);
|
||||
case 0x4000: // RAM bank select
|
||||
if(gbDataMBC5.isRumbleCartridge)
|
||||
value &= 0x07;
|
||||
} else if (gbRamSizeMask <= 0x7FFF) {
|
||||
systemPossibleCartridgeRumble(value & 0x08);
|
||||
value &= 0x07;
|
||||
} else
|
||||
else
|
||||
value &= 0x0f;
|
||||
if(value == gbDataMBC5.mapperRAMBank)
|
||||
break;
|
||||
@ -1231,7 +1225,7 @@ void memoryUpdateTAMA5Clock()
|
||||
else
|
||||
gbDaysinMonth[1] = 28;
|
||||
|
||||
time_t now = time(NULL);
|
||||
time_t now = time(NULL) - (GCSettings.OffsetMinutesUTC*60);
|
||||
time_t diff = now - gbDataTAMA5.mapperLastTime;
|
||||
if(diff > 0) {
|
||||
// update the clock according to the last update time
|
||||
@ -1428,6 +1422,7 @@ void mapperTAMA5RAM(u16 address, u8 value)
|
||||
gbTAMA5ram[0x94] = MonthsH*16+MonthsL; // incorrect ? (not used by the game) ?
|
||||
|
||||
time(&gbDataTAMA5.mapperLastTime);
|
||||
gbDataMBC3.mapperLastTime -= (GCSettings.OffsetMinutesUTC*60);
|
||||
|
||||
gbMemoryMap[0xa][0] = 1;
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ void gbPrinterReset()
|
||||
void gbPrinterShowData()
|
||||
{
|
||||
systemGbPrint(gbPrinterData,
|
||||
gbPrinterDataCount,
|
||||
gbPrinterPacket[6],
|
||||
gbPrinterPacket[7],
|
||||
gbPrinterPacket[8],
|
||||
@ -87,6 +88,7 @@ void gbPrinterShowData()
|
||||
|
||||
void gbPrinterReceiveData()
|
||||
{
|
||||
int i = gbPrinterDataCount;
|
||||
if(gbPrinterPacket[3]) { // compressed
|
||||
u8 *data = &gbPrinterPacket[6];
|
||||
u8 *dest = &gbPrinterData[gbPrinterDataCount];
|
||||
@ -97,16 +99,17 @@ void gbPrinterReceiveData()
|
||||
control &= 0x7f;
|
||||
control += 2;
|
||||
memset(dest, *data++, control);
|
||||
len += control;
|
||||
len += 2;
|
||||
dest += control;
|
||||
} else { // raw data
|
||||
control++;
|
||||
memcpy(dest, data, control);
|
||||
dest += control;
|
||||
data += control;
|
||||
len += control;
|
||||
len += control + 1;
|
||||
}
|
||||
}
|
||||
gbPrinterDataCount = (int)(dest - gbPrinterData);
|
||||
} else {
|
||||
memcpy(&gbPrinterData[gbPrinterDataCount],
|
||||
&gbPrinterPacket[6],
|
||||
|
@ -40,7 +40,7 @@ u8 gbSgbScreenBuffer[4160];
|
||||
|
||||
inline void gbSgbDraw24Bit(u8 *p, u16 v)
|
||||
{
|
||||
*((u32*) p) = systemColorMap32[v];
|
||||
memcpy(p, &systemColorMap32[v], 3);
|
||||
}
|
||||
|
||||
inline void gbSgbDraw32Bit(u32 *p, u16 v)
|
||||
@ -188,9 +188,9 @@ void gbSgbRenderScreenToBuffer()
|
||||
|
||||
void gbSgbDrawBorderTile(int x, int y, int tile, int attr)
|
||||
{
|
||||
u16 *dest = (u16*)pix + ((y+1) * (256+2)) + x;
|
||||
u16 *dest = (u16*)pix + (y * (256+2)) + x;
|
||||
u8 *dest8 = (u8*)pix + ((y*256)+x)*3;
|
||||
u32 *dest32 = (u32*)pix + ((y+1)*257) + x;
|
||||
u32 *dest32 = (u32*)pix + (y*257) + x;
|
||||
|
||||
u8 *tileAddress = &gbSgbBorderChar[tile * 32];
|
||||
u8 *tileAddress2 = &gbSgbBorderChar[tile * 32 + 16];
|
||||
|
@ -4,11 +4,11 @@
|
||||
#include "../Util.h"
|
||||
#include "gbGlobals.h"
|
||||
#include "gbSound.h"
|
||||
#include "gb.h"
|
||||
|
||||
#include "../apu/Gb_Apu.h"
|
||||
#include "../apu/Effects_Buffer.h"
|
||||
|
||||
extern int gbHardware;
|
||||
extern long soundSampleRate; // current sound quality
|
||||
|
||||
gb_effects_config_t gb_effects_config = { false, 0.20f, 0.15f, false };
|
||||
@ -121,6 +121,13 @@ static void reset_apu()
|
||||
|
||||
static void remake_stereo_buffer()
|
||||
{
|
||||
// APU
|
||||
if ( !gb_apu )
|
||||
{
|
||||
gb_apu = new Gb_Apu; // TODO: handle errors
|
||||
reset_apu();
|
||||
}
|
||||
|
||||
// Stereo_Buffer
|
||||
delete stereo_buffer;
|
||||
stereo_buffer = 0;
|
||||
@ -129,19 +136,14 @@ static void remake_stereo_buffer()
|
||||
if ( stereo_buffer->set_sample_rate( soundSampleRate ) ) { } // TODO: handle out of memory
|
||||
stereo_buffer->clock_rate( gb_apu->clock_rate );
|
||||
|
||||
// APU
|
||||
// Multi_Buffer
|
||||
static int const chan_types [chan_count] = {
|
||||
Multi_Buffer::wave_type+1, Multi_Buffer::wave_type+2,
|
||||
Multi_Buffer::wave_type+3, Multi_Buffer::mixed_type+1
|
||||
};
|
||||
if ( stereo_buffer->set_channel_count( chan_count, chan_types ) ) { } // TODO: handle errors
|
||||
|
||||
if ( !gb_apu )
|
||||
{
|
||||
gb_apu = new Gb_Apu; // TODO: handle errors
|
||||
reset_apu();
|
||||
}
|
||||
|
||||
// Volume Level
|
||||
apply_effects();
|
||||
apply_volume();
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include <string.h>
|
||||
#ifndef __LIBRETRO__
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
@ -910,24 +910,24 @@ int cheatsCheckKeys(u32 keys, u32 extended)
|
||||
}
|
||||
break;
|
||||
case GSA_8_BIT_POINTER :
|
||||
if ((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000) ||
|
||||
(CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000))
|
||||
if (((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000)) ||
|
||||
((CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000)))
|
||||
{
|
||||
CPUWriteByte(CPUReadMemory(cheatsList[i].address)+((cheatsList[i].value & 0xFFFFFF00) >> 8),
|
||||
cheatsList[i].value & 0xFF);
|
||||
}
|
||||
break;
|
||||
case GSA_16_BIT_POINTER :
|
||||
if ((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000) ||
|
||||
(CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000))
|
||||
if (((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000)) ||
|
||||
((CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000)))
|
||||
{
|
||||
CPUWriteHalfWord(CPUReadMemory(cheatsList[i].address)+((cheatsList[i].value & 0xFFFF0000) >> 15),
|
||||
cheatsList[i].value & 0xFFFF);
|
||||
}
|
||||
break;
|
||||
case GSA_32_BIT_POINTER :
|
||||
if ((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000) ||
|
||||
(CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000))
|
||||
if (((CPUReadMemory(cheatsList[i].address)>=0x02000000) && (CPUReadMemory(cheatsList[i].address)<0x02040000)) ||
|
||||
((CPUReadMemory(cheatsList[i].address)>=0x03000000) && (CPUReadMemory(cheatsList[i].address)<0x03008000)))
|
||||
{
|
||||
CPUWriteMemory(CPUReadMemory(cheatsList[i].address),
|
||||
cheatsList[i].value);
|
||||
@ -935,15 +935,15 @@ int cheatsCheckKeys(u32 keys, u32 extended)
|
||||
break;
|
||||
case GSA_8_BIT_ADD :
|
||||
CPUWriteByte(cheatsList[i].address,
|
||||
(cheatsList[i].value & 0xFF) + CPUReadMemory(cheatsList[i].address) & 0xFF);
|
||||
((cheatsList[i].value & 0xFF) + CPUReadMemory(cheatsList[i].address)) & 0xFF);
|
||||
break;
|
||||
case GSA_16_BIT_ADD :
|
||||
CPUWriteHalfWord(cheatsList[i].address,
|
||||
(cheatsList[i].value & 0xFFFF) + CPUReadMemory(cheatsList[i].address) & 0xFFFF);
|
||||
((cheatsList[i].value & 0xFFFF) + CPUReadMemory(cheatsList[i].address)) & 0xFFFF);
|
||||
break;
|
||||
case GSA_32_BIT_ADD :
|
||||
CPUWriteMemory(cheatsList[i].address ,
|
||||
cheatsList[i].value + CPUReadMemory(cheatsList[i].address) & 0xFFFFFFFF);
|
||||
(cheatsList[i].value + CPUReadMemory(cheatsList[i].address)) & 0xFFFFFFFF);
|
||||
break;
|
||||
case GSA_8_BIT_IF_LOWER_U:
|
||||
if (!(CPUReadByte(cheatsList[i].address) < (cheatsList[i].value & 0xFF))) {
|
||||
@ -2678,8 +2678,6 @@ void cheatsReadGameSkip( gzFile file, int version )
|
||||
utilGzSeek( file, sizeof( cheatsList ), SEEK_CUR );
|
||||
}
|
||||
|
||||
bool firstCodeBreaker = true;
|
||||
|
||||
for( int i = 0; i < nCheats; i++ ) {
|
||||
if( version < 9 ) {
|
||||
utilGzSeek( file, ( 7 * sizeof(int) ) + ( 52 * sizeof(char) ), SEEK_CUR );
|
||||
@ -2898,3 +2896,4 @@ void cheatsWriteByte(u32, u8)
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
@ -9,7 +9,15 @@ int eepromMode = EEPROM_IDLE;
|
||||
int eepromByte = 0;
|
||||
int eepromBits = 0;
|
||||
int eepromAddress = 0;
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
// Workaround for broken-by-design GBA save semantics
|
||||
extern u8 libretro_save_buf[0x20000 + 0x2000];
|
||||
u8 *eepromData = libretro_save_buf + 0x20000;
|
||||
#else
|
||||
u8 eepromData[0x2000];
|
||||
#endif
|
||||
|
||||
u8 eepromBuffer[16];
|
||||
bool eepromInUse = false;
|
||||
int eepromSize = 512;
|
||||
@ -27,7 +35,11 @@ variable_desc eepromSaveData[] = {
|
||||
|
||||
void eepromInit()
|
||||
{
|
||||
memset(eepromData, 255, sizeof(eepromData));
|
||||
#ifdef __LIBRETRO__
|
||||
memset(eepromData, 255, 0x2000);
|
||||
#else
|
||||
memset(eepromData, 255, sizeof(eepromData));
|
||||
#endif
|
||||
}
|
||||
|
||||
void eepromReset()
|
||||
@ -40,6 +52,26 @@ void eepromReset()
|
||||
eepromSize = 512;
|
||||
}
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
void eepromSaveGame(uint8_t *& data)
|
||||
{
|
||||
utilWriteDataMem(data, eepromSaveData);
|
||||
utilWriteIntMem(data, eepromSize);
|
||||
utilWriteMem(data, eepromData, 0x2000);
|
||||
}
|
||||
|
||||
void eepromReadGame(const uint8_t *& data, int version)
|
||||
{
|
||||
utilReadDataMem(data, eepromSaveData);
|
||||
if (version >= SAVE_GAME_VERSION_3) {
|
||||
eepromSize = utilReadIntMem(data);
|
||||
utilReadMem(eepromData, data, 0x2000);
|
||||
} else {
|
||||
// prior to 0.7.1, only 4K EEPROM was supported
|
||||
eepromSize = 512;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void eepromSaveGame(gzFile gzFile)
|
||||
{
|
||||
utilWriteData(gzFile, eepromSaveData);
|
||||
@ -68,6 +100,7 @@ void eepromReadGameSkip(gzFile gzFile, int version)
|
||||
utilGzSeek(gzFile, 0x2000, SEEK_CUR);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int eepromRead(u32 /* address */)
|
||||
{
|
||||
|
@ -1,14 +1,23 @@
|
||||
#ifndef EEPROM_H
|
||||
#define EEPROM_H
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
extern void eepromSaveGame(u8* &data);
|
||||
extern void eepromReadGame(const u8 *&data, int version);
|
||||
#else
|
||||
extern void eepromSaveGame(gzFile _gzFile);
|
||||
extern void eepromReadGame(gzFile _gzFile, int version);
|
||||
#endif
|
||||
extern void eepromReadGameSkip(gzFile _gzFile, int version);
|
||||
extern int eepromRead(u32 address);
|
||||
extern void eepromWrite(u32 address, u8 value);
|
||||
extern void eepromInit();
|
||||
extern void eepromReset();
|
||||
#ifdef __LIBRETRO__
|
||||
extern u8 *eepromData;
|
||||
#else
|
||||
extern u8 eepromData[0x2000];
|
||||
#endif
|
||||
extern bool eepromInUse;
|
||||
extern int eepromSize;
|
||||
|
||||
|
@ -17,7 +17,13 @@
|
||||
#define FLASH_PROGRAM 8
|
||||
#define FLASH_SETBANK 9
|
||||
|
||||
u8 flashSaveMemory[0x20000];
|
||||
#ifdef __LIBRETRO__
|
||||
extern uint8_t libretro_save_buf[0x20000 + 0x2000];
|
||||
uint8_t *flashSaveMemory = libretro_save_buf;
|
||||
#else
|
||||
uint8_t flashSaveMemory[FLASH_128K_SZ];
|
||||
#endif
|
||||
|
||||
int flashState = FLASH_READ_ARRAY;
|
||||
int flashReadState = FLASH_READ_ARRAY;
|
||||
int flashSize = 0x10000;
|
||||
@ -51,7 +57,11 @@ static variable_desc flashSaveData3[] = {
|
||||
|
||||
void flashInit()
|
||||
{
|
||||
memset(flashSaveMemory, 0xff, sizeof(flashSaveMemory));
|
||||
#ifdef __LIBRETRO__
|
||||
memset(flashSaveMemory, 0xff, 0x20000);
|
||||
#else
|
||||
memset(flashSaveMemory, 0xff, sizeof(flashSaveMemory));
|
||||
#endif
|
||||
}
|
||||
|
||||
void flashReset()
|
||||
@ -61,6 +71,17 @@ void flashReset()
|
||||
flashBank = 0;
|
||||
}
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
void flashSaveGame(uint8_t *& data)
|
||||
{
|
||||
utilWriteDataMem(data, flashSaveData3);
|
||||
}
|
||||
|
||||
void flashReadGame(const uint8_t *& data, int)
|
||||
{
|
||||
utilReadDataMem(data, flashSaveData3);
|
||||
}
|
||||
#else
|
||||
void flashSaveGame(gzFile gzFile)
|
||||
{
|
||||
utilWriteData(gzFile, flashSaveData3);
|
||||
@ -90,6 +111,8 @@ void flashReadGameSkip(gzFile gzFile, int version)
|
||||
utilReadDataSkip(gzFile, flashSaveData3);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void flashSetSize(int size)
|
||||
{
|
||||
|
@ -1,13 +1,24 @@
|
||||
#ifndef FLASH_H
|
||||
#define FLASH_H
|
||||
|
||||
#define FLASH_128K_SZ 0x20000
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
extern void flashSaveGame(u8 *& data);
|
||||
extern void flashReadGame(const u8 *& data, int);
|
||||
#else
|
||||
extern void flashSaveGame(gzFile _gzFile);
|
||||
extern void flashReadGame(gzFile _gzFile, int version);
|
||||
#endif
|
||||
extern void flashReadGameSkip(gzFile _gzFile, int version);
|
||||
extern u8 flashRead(u32 address);
|
||||
extern void flashWrite(u32 address, u8 byte);
|
||||
extern void flashDelayedWrite(u32 address, u8 byte);
|
||||
extern u8 flashSaveMemory[0x20000];
|
||||
#ifdef __LIBRETRO__
|
||||
extern uint8_t *flashSaveMemory;
|
||||
#else
|
||||
extern u8 flashSaveMemory[FLASH_128K_SZ];
|
||||
#endif
|
||||
extern void flashSaveDecide(u32 address, u8 byte);
|
||||
extern void flashReset();
|
||||
extern void flashSetSize(int size);
|
||||
|
@ -297,7 +297,7 @@ static void count(u32 opcode, int cond_res)
|
||||
#define EMIT0(op) #op"; "
|
||||
#define EMIT1(op,arg) #op" "arg"; "
|
||||
#define EMIT2(op,src,dest) #op" "src", "dest"; "
|
||||
#define CONST(val) "$"#val
|
||||
#define KONST(val) "$"#val
|
||||
#define ASMVAR(cvar) ASMVAR2 (__USER_LABEL_PREFIX__, cvar)
|
||||
#define ASMVAR2(prefix,cvar) STRING (prefix) cvar
|
||||
#define STRING(x) #x
|
||||
@ -330,7 +330,7 @@ static void count(u32 opcode, int cond_res)
|
||||
#define EMIT0(op) __asm op
|
||||
#define EMIT1(op,arg) __asm op arg
|
||||
#define EMIT2(op,src,dest) __asm op dest, src
|
||||
#define CONST(val) val
|
||||
#define KONST(val) val
|
||||
#define VAR(var) var
|
||||
#define VARL(var) dword ptr var
|
||||
#define REGREF1(index) reg[index]
|
||||
@ -349,15 +349,19 @@ static void count(u32 opcode, int cond_res)
|
||||
|
||||
// Helper macros for loading value / shift count
|
||||
#define VALUE_LOAD_IMM \
|
||||
EMIT2(and, CONST(0x0F), eax) \
|
||||
EMIT2(and, KONST(0x0F), eax) \
|
||||
EMIT2(mov, REGREF2(eax,4), eax) \
|
||||
EMIT2(shr, CONST(7), ecx) \
|
||||
EMIT2(and, CONST(0x1F), ecx)
|
||||
EMIT2(shr, KONST(7), ecx) \
|
||||
EMIT2(and, KONST(0x1F), ecx)
|
||||
#define VALUE_LOAD_REG \
|
||||
EMIT2(and, CONST(0x0F), eax) \
|
||||
EMIT2(mov, REGREF2(eax,4), eax) \
|
||||
EMIT2(and, KONST(0x0F), eax) \
|
||||
EMIT2(cmp, KONST(0x0F), eax) \
|
||||
EMIT2(mov, REGREF2(eax,4), eax) \
|
||||
EMIT1(jne, LABELREF(3,f)) \
|
||||
EMIT2(add, KONST(4), eax) \
|
||||
LABEL(3) \
|
||||
EMIT2(movzx, ch, ecx) \
|
||||
EMIT2(and, CONST(0x0F), ecx) \
|
||||
EMIT2(and, KONST(0x0F), ecx) \
|
||||
EMIT2(mov, REGREF2(ecx,4), ecx)
|
||||
|
||||
// Helper macros for setting flags
|
||||
@ -381,13 +385,13 @@ static void count(u32 opcode, int cond_res)
|
||||
ALU_HEADER \
|
||||
LOAD_C_FLAG \
|
||||
EMIT2(mov, ecx, edx) \
|
||||
EMIT2(shr, CONST(14), edx) \
|
||||
EMIT2(shr, KONST(14), edx) \
|
||||
EMIT2(mov, ecx, eax) \
|
||||
EMIT2(mov, ecx, esi) \
|
||||
EMIT2(shr, CONST(10), esi) \
|
||||
EMIT2(and, CONST(0x3C), edx) \
|
||||
EMIT2(shr, KONST(10), esi) \
|
||||
EMIT2(and, KONST(0x3C), edx) \
|
||||
EMIT2(mov, REGREF1(edx), edx) \
|
||||
EMIT2(and, CONST(0x3C), esi)
|
||||
EMIT2(and, KONST(0x3C), esi)
|
||||
|
||||
#define LOAD_C_FLAG_YES EMIT2(mov, VAR(C_FLAG), bl)
|
||||
#define LOAD_C_FLAG_NO /*nothing*/
|
||||
@ -415,14 +419,14 @@ static void count(u32 opcode, int cond_res)
|
||||
VALUE_LOAD_REG \
|
||||
EMIT2(test, cl, cl) \
|
||||
EMIT1(jz, LABELREF(0,f)) \
|
||||
EMIT2(cmp, CONST(0x20), cl) \
|
||||
EMIT2(cmp, KONST(0x20), cl) \
|
||||
EMIT1(je, LABELREF(1,f)) \
|
||||
EMIT1(ja, LABELREF(2,f)) \
|
||||
EMIT2(shl, cl, eax) \
|
||||
EMIT1(setc, bl) \
|
||||
EMIT1(jmp, LABELREF(0,f)) \
|
||||
LABEL(1) \
|
||||
EMIT2(test, CONST(1), al) \
|
||||
EMIT2(test, KONST(1), al) \
|
||||
EMIT1(setnz, bl) \
|
||||
EMIT2(xor, eax, eax) \
|
||||
EMIT1(jmp, LABELREF(0,f)) \
|
||||
@ -432,7 +436,7 @@ static void count(u32 opcode, int cond_res)
|
||||
LABEL(0)
|
||||
#define VALUE_LSL_REG_NC \
|
||||
VALUE_LOAD_REG \
|
||||
EMIT2(cmp, CONST(0x20), cl) \
|
||||
EMIT2(cmp, KONST(0x20), cl) \
|
||||
EMIT1(jae, LABELREF(1,f)) \
|
||||
EMIT2(shl, cl, eax) \
|
||||
EMIT1(jmp, LABELREF(0,f)) \
|
||||
@ -466,7 +470,7 @@ static void count(u32 opcode, int cond_res)
|
||||
VALUE_LOAD_REG \
|
||||
EMIT2(test, cl, cl) \
|
||||
EMIT1(jz, LABELREF(0,f)) \
|
||||
EMIT2(cmp, CONST(0x20), cl) \
|
||||
EMIT2(cmp, KONST(0x20), cl) \
|
||||
EMIT1(je, LABELREF(1,f)) \
|
||||
EMIT1(ja, LABELREF(2,f)) \
|
||||
EMIT2(shr, cl, eax) \
|
||||
@ -483,7 +487,7 @@ static void count(u32 opcode, int cond_res)
|
||||
LABEL(0)
|
||||
#define VALUE_LSR_REG_NC \
|
||||
VALUE_LOAD_REG \
|
||||
EMIT2(cmp, CONST(0x20), cl) \
|
||||
EMIT2(cmp, KONST(0x20), cl) \
|
||||
EMIT1(jae, LABELREF(1,f)) \
|
||||
EMIT2(shr, cl, eax) \
|
||||
EMIT1(jmp, LABELREF(0,f)) \
|
||||
@ -499,7 +503,7 @@ static void count(u32 opcode, int cond_res)
|
||||
EMIT1(setc, bl) \
|
||||
EMIT1(jmp, LABELREF(0,f)) \
|
||||
LABEL(1) \
|
||||
EMIT2(sar, CONST(31), eax) \
|
||||
EMIT2(sar, KONST(31), eax) \
|
||||
EMIT1(sets, bl) \
|
||||
LABEL(0)
|
||||
#define VALUE_ASR_IMM_NC \
|
||||
@ -508,7 +512,7 @@ static void count(u32 opcode, int cond_res)
|
||||
EMIT2(sar, cl, eax) \
|
||||
EMIT1(jmp, LABELREF(0,f)) \
|
||||
LABEL(1) \
|
||||
EMIT2(sar, CONST(31), eax) \
|
||||
EMIT2(sar, KONST(31), eax) \
|
||||
LABEL(0)
|
||||
|
||||
// OP Rd,Rb,Rm ASR Rs
|
||||
@ -516,23 +520,23 @@ static void count(u32 opcode, int cond_res)
|
||||
VALUE_LOAD_REG \
|
||||
EMIT2(test, cl, cl) \
|
||||
EMIT1(jz, LABELREF(0,f)) \
|
||||
EMIT2(cmp, CONST(0x20), cl) \
|
||||
EMIT2(cmp, KONST(0x20), cl) \
|
||||
EMIT1(jae, LABELREF(1,f)) \
|
||||
EMIT2(sar, cl, eax) \
|
||||
EMIT1(setc, bl) \
|
||||
EMIT1(jmp, LABELREF(0,f)) \
|
||||
LABEL(1) \
|
||||
EMIT2(sar, CONST(31), eax) \
|
||||
EMIT2(sar, KONST(31), eax) \
|
||||
EMIT1(sets, bl) \
|
||||
LABEL(0)
|
||||
#define VALUE_ASR_REG_NC \
|
||||
VALUE_LOAD_REG \
|
||||
EMIT2(cmp, CONST(0x20), cl) \
|
||||
EMIT2(cmp, KONST(0x20), cl) \
|
||||
EMIT1(jae, LABELREF(1,f)) \
|
||||
EMIT2(sar, cl, eax) \
|
||||
EMIT1(jmp, LABELREF(0,f)) \
|
||||
LABEL(1) \
|
||||
EMIT2(sar, CONST(31), eax) \
|
||||
EMIT2(sar, KONST(31), eax) \
|
||||
LABEL(0)
|
||||
|
||||
// OP Rd,Rb,Rm ROR #
|
||||
@ -542,8 +546,8 @@ static void count(u32 opcode, int cond_res)
|
||||
EMIT2(ror, cl, eax) \
|
||||
EMIT1(jmp, LABELREF(0,f)) \
|
||||
LABEL(1) \
|
||||
EMIT2(bt, CONST(0), ebx) \
|
||||
EMIT2(rcr, CONST(1), eax) \
|
||||
EMIT2(bt, KONST(0), ebx) \
|
||||
EMIT2(rcr, KONST(1), eax) \
|
||||
LABEL(0) \
|
||||
EMIT1(setc, bl)
|
||||
#define VALUE_ROR_IMM_NC \
|
||||
@ -552,14 +556,14 @@ static void count(u32 opcode, int cond_res)
|
||||
EMIT2(ror, cl, eax) \
|
||||
EMIT1(jmp, LABELREF(0,f)) \
|
||||
LABEL(1) \
|
||||
EMIT2(bt, CONST(0), VARL(C_FLAG)) \
|
||||
EMIT2(rcr, CONST(1), eax) \
|
||||
EMIT2(bt, KONST(0), VARL(C_FLAG)) \
|
||||
EMIT2(rcr, KONST(1), eax) \
|
||||
LABEL(0)
|
||||
|
||||
// OP Rd,Rb,Rm ROR Rs
|
||||
#define VALUE_ROR_REG_C \
|
||||
VALUE_LOAD_REG \
|
||||
EMIT2(bt, CONST(0), ebx) \
|
||||
EMIT2(bt, KONST(0), ebx) \
|
||||
EMIT2(ror, cl, eax) \
|
||||
EMIT1(setc, bl)
|
||||
#define VALUE_ROR_REG_NC \
|
||||
@ -571,7 +575,7 @@ static void count(u32 opcode, int cond_res)
|
||||
EMIT2(movzx, ch, ecx) \
|
||||
EMIT2(add, ecx, ecx) \
|
||||
EMIT2(movzx, al, eax) \
|
||||
EMIT2(bt, CONST(0), ebx) \
|
||||
EMIT2(bt, KONST(0), ebx) \
|
||||
EMIT2(ror, cl, eax) \
|
||||
EMIT1(setc, bl)
|
||||
#define VALUE_IMM_NC \
|
||||
@ -584,7 +588,7 @@ static void count(u32 opcode, int cond_res)
|
||||
|
||||
// Set condition codes iff the destination register is not R15 (PC)
|
||||
#define CHECK_PC(OP, SETCOND) \
|
||||
EMIT2(cmp, CONST(0x3C), esi) \
|
||||
EMIT2(cmp, KONST(0x3C), esi) \
|
||||
EMIT1(je, LABELREF(8,f)) \
|
||||
OP SETCOND \
|
||||
EMIT1(jmp, LABELREF(9,f)) \
|
||||
@ -613,18 +617,18 @@ static void count(u32 opcode, int cond_res)
|
||||
EMIT2(mov, edx, REGREF1(esi))
|
||||
#define OP_ADDS CHECK_PC(OP_ADD, SETCOND_ADD)
|
||||
#define OP_ADC \
|
||||
EMIT2(bt, CONST(0), VARL(C_FLAG)) \
|
||||
EMIT2(bt, KONST(0), VARL(C_FLAG)) \
|
||||
EMIT2(adc, eax, edx) \
|
||||
EMIT2(mov, edx, REGREF1(esi))
|
||||
#define OP_ADCS CHECK_PC(OP_ADC, SETCOND_ADD)
|
||||
#define OP_SBC \
|
||||
EMIT2(bt, CONST(0), VARL(C_FLAG)) \
|
||||
EMIT2(bt, KONST(0), VARL(C_FLAG)) \
|
||||
EMIT0(cmc) \
|
||||
EMIT2(sbb, eax, edx) \
|
||||
EMIT2(mov, edx, REGREF1(esi))
|
||||
#define OP_SBCS CHECK_PC(OP_SBC, SETCOND_SUB)
|
||||
#define OP_RSC \
|
||||
EMIT2(bt, CONST(0), VARL(C_FLAG)) \
|
||||
EMIT2(bt, KONST(0), VARL(C_FLAG)) \
|
||||
EMIT0(cmc) \
|
||||
EMIT2(sbb, edx, eax) \
|
||||
EMIT2(mov, eax, REGREF1(esi))
|
||||
@ -656,7 +660,7 @@ static void count(u32 opcode, int cond_res)
|
||||
#define OP_MVN \
|
||||
EMIT1(not, eax) \
|
||||
EMIT2(mov, eax, REGREF1(esi))
|
||||
#define OP_MVNS CHECK_PC(OP_MVN, SETCOND_LOGICAL)
|
||||
#define OP_MVNS CHECK_PC(OP_MVN EMIT2(test,eax,eax), SETCOND_LOGICAL)
|
||||
|
||||
// ALU cleanup macro
|
||||
#define ALU_FINISH ALU_TRAILER
|
||||
@ -677,7 +681,7 @@ static void count(u32 opcode, int cond_res)
|
||||
: "0" (offset), "c" (shift));
|
||||
|
||||
#define RRX_OFFSET \
|
||||
asm(EMIT2(btl,CONST(0),VAR(C_FLAG)) \
|
||||
asm(EMIT2(btl,KONST(0),VAR(C_FLAG)) \
|
||||
"rcr $1, %0" \
|
||||
: "=r" (offset) \
|
||||
: "0" (offset));
|
||||
@ -752,27 +756,31 @@ static void count(u32 opcode, int cond_res)
|
||||
// OP Rd,Rb,Rm LSL Rs
|
||||
#ifndef VALUE_LSL_REG_C
|
||||
#define VALUE_LSL_REG_C \
|
||||
unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
|
||||
if (LIKELY(shift)) { \
|
||||
if (shift == 32) { \
|
||||
value = 0; \
|
||||
C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false);\
|
||||
} else if (LIKELY(shift < 32)) { \
|
||||
u32 v = reg[opcode & 0x0F].I; \
|
||||
C_OUT = (v >> (32 - shift)) & 1 ? true : false;\
|
||||
value = v << shift; \
|
||||
} else { \
|
||||
value = 0; \
|
||||
C_OUT = false; \
|
||||
} \
|
||||
} else { \
|
||||
value = reg[opcode & 0x0F].I; \
|
||||
u32 shift = reg[(opcode >> 8)&15].B.B0; \
|
||||
u32 rm = reg[opcode & 0x0F].I; \
|
||||
if((opcode & 0x0F) == 15) { \
|
||||
rm += 4; \
|
||||
} \
|
||||
if (LIKELY(shift)) { \
|
||||
if (shift == 32) { \
|
||||
value = 0; \
|
||||
C_OUT = (rm & 1 ? true : false); \
|
||||
} else if (LIKELY(shift < 32)) { \
|
||||
u32 v = rm; \
|
||||
C_OUT = (v >> (32 - shift)) & 1 ? true : false; \
|
||||
value = v << shift; \
|
||||
} else { \
|
||||
value = 0; \
|
||||
C_OUT = false; \
|
||||
} \
|
||||
} else { \
|
||||
value = rm; \
|
||||
}
|
||||
#endif
|
||||
// OP Rd,Rb,Rm LSR #
|
||||
#ifndef VALUE_LSR_IMM_C
|
||||
#define VALUE_LSR_IMM_C \
|
||||
unsigned int shift = (opcode >> 7) & 0x1F; \
|
||||
u32 shift = (opcode >> 7) & 0x1F; \
|
||||
if (LIKELY(shift)) { \
|
||||
u32 v = reg[opcode & 0x0F].I; \
|
||||
C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
|
||||
@ -786,12 +794,16 @@ static void count(u32 opcode, int cond_res)
|
||||
#ifndef VALUE_LSR_REG_C
|
||||
#define VALUE_LSR_REG_C \
|
||||
unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
|
||||
u32 rm = reg[opcode & 0x0F].I; \
|
||||
if((opcode & 0x0F) == 15) { \
|
||||
rm += 4; \
|
||||
} \
|
||||
if (LIKELY(shift)) { \
|
||||
if (shift == 32) { \
|
||||
value = 0; \
|
||||
C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false);\
|
||||
C_OUT = (rm & 0x80000000 ? true : false);\
|
||||
} else if (LIKELY(shift < 32)) { \
|
||||
u32 v = reg[opcode & 0x0F].I; \
|
||||
u32 v = rm; \
|
||||
C_OUT = (v >> (shift - 1)) & 1 ? true : false;\
|
||||
value = v >> shift; \
|
||||
} else { \
|
||||
@ -799,7 +811,7 @@ static void count(u32 opcode, int cond_res)
|
||||
C_OUT = false; \
|
||||
} \
|
||||
} else { \
|
||||
value = reg[opcode & 0x0F].I; \
|
||||
value = rm; \
|
||||
}
|
||||
#endif
|
||||
// OP Rd,Rb,Rm ASR #
|
||||
@ -825,13 +837,17 @@ static void count(u32 opcode, int cond_res)
|
||||
#ifndef VALUE_ASR_REG_C
|
||||
#define VALUE_ASR_REG_C \
|
||||
unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
|
||||
u32 rm = reg[opcode & 0x0F].I; \
|
||||
if((opcode & 0x0F) == 15) { \
|
||||
rm += 4; \
|
||||
} \
|
||||
if (LIKELY(shift < 32)) { \
|
||||
if (LIKELY(shift)) { \
|
||||
s32 v = reg[opcode & 0x0F].I; \
|
||||
s32 v = rm; \
|
||||
C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\
|
||||
value = v >> (int)shift; \
|
||||
} else { \
|
||||
value = reg[opcode & 0x0F].I; \
|
||||
value = rm; \
|
||||
} \
|
||||
} else { \
|
||||
if (reg[opcode & 0x0F].I & 0x80000000) { \
|
||||
@ -863,13 +879,17 @@ static void count(u32 opcode, int cond_res)
|
||||
#ifndef VALUE_ROR_REG_C
|
||||
#define VALUE_ROR_REG_C \
|
||||
unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
|
||||
u32 rm = reg[opcode & 0x0F].I; \
|
||||
if((opcode & 0x0F) == 15) { \
|
||||
rm += 4; \
|
||||
} \
|
||||
if (LIKELY(shift & 0x1F)) { \
|
||||
u32 v = reg[opcode & 0x0F].I; \
|
||||
u32 v = rm; \
|
||||
C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
|
||||
value = ((v << (32 - shift)) | \
|
||||
(v >> shift)); \
|
||||
} else { \
|
||||
value = reg[opcode & 0x0F].I; \
|
||||
value = rm; \
|
||||
if (shift) \
|
||||
C_OUT = (value & 0x80000000 ? true : false);\
|
||||
}
|
||||
@ -950,9 +970,9 @@ static void count(u32 opcode, int cond_res)
|
||||
#endif
|
||||
#ifndef OP_RSB
|
||||
#define OP_RSB \
|
||||
u32 lhs = reg[(opcode>>16)&15].I; \
|
||||
u32 rhs = value; \
|
||||
u32 res = rhs - lhs; \
|
||||
u32 lhs = value; \
|
||||
u32 rhs = reg[(opcode>>16)&15].I; \
|
||||
u32 res = lhs - rhs; \
|
||||
reg[dest].I = res;
|
||||
#endif
|
||||
#ifndef OP_RSBS
|
||||
@ -990,9 +1010,9 @@ static void count(u32 opcode, int cond_res)
|
||||
#endif
|
||||
#ifndef OP_RSC
|
||||
#define OP_RSC \
|
||||
u32 lhs = reg[(opcode>>16)&15].I; \
|
||||
u32 rhs = value; \
|
||||
u32 res = rhs - lhs - !((u32)C_FLAG); \
|
||||
u32 lhs = value; \
|
||||
u32 rhs = reg[(opcode>>16)&15].I; \
|
||||
u32 res = lhs - rhs - !((u32)C_FLAG); \
|
||||
reg[dest].I = res;
|
||||
#endif
|
||||
#ifndef OP_RSCS
|
||||
@ -1516,7 +1536,7 @@ static INSN_REGPARM void arm121(u32 opcode)
|
||||
#define OP_LDR reg[dest].I = CPUReadMemory(address)
|
||||
#define OP_LDRH reg[dest].I = CPUReadHalfWord(address)
|
||||
#define OP_LDRB reg[dest].I = CPUReadByte(address)
|
||||
#define OP_LDRSH reg[dest].I = (s16)CPUReadHalfWordSigned(address)
|
||||
#define OP_LDRSH reg[dest].I = (u32)CPUReadHalfWordSigned(address)
|
||||
#define OP_LDRSB reg[dest].I = (s8)CPUReadByte(address)
|
||||
|
||||
#define WRITEBACK_NONE /*nothing*/
|
||||
@ -2591,8 +2611,7 @@ static INSN_REGPARM void armA00(u32 opcode)
|
||||
reg[15].I += 4;
|
||||
ARM_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq32(armNextPC) + 1;
|
||||
clockTicks += 2 + codeTicksAccess32(armNextPC)
|
||||
+ codeTicksAccessSeq32(armNextPC);
|
||||
clockTicks = (clockTicks * 2) + codeTicksAccess32(armNextPC) + 1;
|
||||
busPrefetchCount = 0;
|
||||
}
|
||||
|
||||
@ -2608,8 +2627,7 @@ static INSN_REGPARM void armB00(u32 opcode)
|
||||
reg[15].I += 4;
|
||||
ARM_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq32(armNextPC) + 1;
|
||||
clockTicks += 2 + codeTicksAccess32(armNextPC)
|
||||
+ codeTicksAccessSeq32(armNextPC);
|
||||
clockTicks = (clockTicks * 2) + codeTicksAccess32(armNextPC) + 1;
|
||||
busPrefetchCount = 0;
|
||||
}
|
||||
|
||||
@ -2627,9 +2645,8 @@ static INSN_REGPARM void armE01(u32 opcode)
|
||||
// SWI <comment>
|
||||
static INSN_REGPARM void armF00(u32 opcode)
|
||||
{
|
||||
clockTicks = codeTicksAccessSeq32(armNextPC) + 1;
|
||||
clockTicks += 2 + codeTicksAccess32(armNextPC)
|
||||
+ codeTicksAccessSeq32(armNextPC);
|
||||
clockTicks = codeTicksAccessSeq32(armNextPC) + 1;
|
||||
clockTicks = (clockTicks * 2) + codeTicksAccess32(armNextPC) + 1;
|
||||
busPrefetchCount = 0;
|
||||
CPUSoftwareInterrupt(opcode & 0x00FFFFFF);
|
||||
}
|
||||
@ -2681,9 +2698,9 @@ static insnfunc_t armInsnTable[4096] = {
|
||||
arm0D0,arm0D1,arm0D2,arm0D3,arm0D4,arm0D5,arm0D6,arm0D7, // 0D0
|
||||
arm0D0,arm0D9,arm0D2,arm0DB,arm0D4,arm0DD,arm0D6,arm0DF, // 0D8
|
||||
arm0E0,arm0E1,arm0E2,arm0E3,arm0E4,arm0E5,arm0E6,arm0E7, // 0E0
|
||||
arm0E0,arm0E9,arm0E2,arm_UI,arm0E4,arm_UI,arm0E6,arm_UI, // 0E8
|
||||
arm0E0,arm0E9,arm0E2,arm0CB,arm0E4,arm_UI,arm0E6,arm_UI, // 0E8
|
||||
arm0F0,arm0F1,arm0F2,arm0F3,arm0F4,arm0F5,arm0F6,arm0F7, // 0F0
|
||||
arm0F0,arm0F9,arm0F2,arm_UI,arm0F4,arm0DD,arm0F6,arm0DF, // 0F8
|
||||
arm0F0,arm0F9,arm0F2,arm0DB,arm0F4,arm0DD,arm0F6,arm0DF, // 0F8
|
||||
|
||||
arm100,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 100
|
||||
arm_UI,arm109,arm_UI,arm10B,arm_UI,arm_UI,arm_UI,arm_UI, // 108
|
||||
|
@ -300,7 +300,7 @@ static INSN_REGPARM void thumbBreakpoint(u32 opcode)
|
||||
#else
|
||||
#define EMIT1(op,arg) #op" "arg"; "
|
||||
#define EMIT2(op,src,dest) #op" "src", "dest"; "
|
||||
#define CONST(val) "$"#val
|
||||
#define KONST(val) "$"#val
|
||||
#define ASMVAR(cvar) ASMVAR2 (__USER_LABEL_PREFIX__, cvar)
|
||||
#define ASMVAR2(prefix,cvar) STRING (prefix) cvar
|
||||
#define STRING(x) #x
|
||||
@ -327,7 +327,7 @@ static INSN_REGPARM void thumbBreakpoint(u32 opcode)
|
||||
: \
|
||||
: "r" (value), "r" (reg[dest].I):"1");
|
||||
#define ADC_RD_RS \
|
||||
asm (EMIT2(bt,CONST(0),VAR(C_FLAG)) \
|
||||
asm (EMIT2(bt,KONST(0),VAR(C_FLAG)) \
|
||||
"adc %1, %%ebx;"\
|
||||
EMIT1(setsb, VAR(N_FLAG)) \
|
||||
EMIT1(setzb, VAR(Z_FLAG)) \
|
||||
@ -345,7 +345,7 @@ static INSN_REGPARM void thumbBreakpoint(u32 opcode)
|
||||
: "=m" (reg[(d)].I));
|
||||
#define MOV_RN_O8(d) \
|
||||
asm ("andl $0xFF, %%eax;"\
|
||||
EMIT2(movb,CONST(0),VAR(N_FLAG)) \
|
||||
EMIT2(movb,KONST(0),VAR(N_FLAG)) \
|
||||
"movl %%eax, %0;"\
|
||||
EMIT1(setzb, VAR(Z_FLAG)) \
|
||||
: "=m" (reg[(d)].I));
|
||||
@ -359,7 +359,7 @@ static INSN_REGPARM void thumbBreakpoint(u32 opcode)
|
||||
: \
|
||||
: "m" (reg[(d)].I));
|
||||
#define SBC_RD_RS \
|
||||
asm volatile (EMIT2(bt,CONST(0),VAR(C_FLAG)) \
|
||||
asm volatile (EMIT2(bt,KONST(0),VAR(C_FLAG)) \
|
||||
"cmc;"\
|
||||
"sbb %1, %%ebx;"\
|
||||
EMIT1(setsb, VAR(N_FLAG)) \
|
||||
@ -464,9 +464,9 @@ static INSN_REGPARM void thumbBreakpoint(u32 opcode)
|
||||
EMIT1(setcb, VAR(C_FLAG)) \
|
||||
EMIT1(setob, VAR(V_FLAG))
|
||||
#define ADD_RD_RS_O3_0(N) \
|
||||
EMIT2(movb,CONST(0),VAR(C_FLAG)) \
|
||||
EMIT2(movb,KONST(0),VAR(C_FLAG)) \
|
||||
"add $0,%%ecx;" \
|
||||
EMIT2(movb,CONST(0),VAR(V_FLAG))
|
||||
EMIT2(movb,KONST(0),VAR(V_FLAG))
|
||||
#define SUB_RD_RS_RN(N) \
|
||||
EMIT2(sub,VAR(reg)"+"#N"*4",ecx) \
|
||||
EMIT1(setncb, VAR(C_FLAG)) \
|
||||
@ -476,9 +476,9 @@ static INSN_REGPARM void thumbBreakpoint(u32 opcode)
|
||||
EMIT1(setncb, VAR(C_FLAG)) \
|
||||
EMIT1(setob, VAR(V_FLAG))
|
||||
#define SUB_RD_RS_O3_0(N) \
|
||||
EMIT2(movb,CONST(1),VAR(C_FLAG)) \
|
||||
EMIT2(movb,KONST(1),VAR(C_FLAG)) \
|
||||
"sub $0,%%ecx;" \
|
||||
EMIT2(movb,CONST(0),VAR(V_FLAG))
|
||||
EMIT2(movb,KONST(0),VAR(V_FLAG))
|
||||
#endif
|
||||
#else // !__GNUC__
|
||||
#define ADD_RD_RS_RN(N) \
|
||||
@ -1416,10 +1416,18 @@ static INSN_REGPARM void thumb45_3(u32 opcode)
|
||||
CMP_RD_RS;
|
||||
}
|
||||
|
||||
// MOV Rd, Rs
|
||||
static INSN_REGPARM void thumb46_0(u32 opcode)
|
||||
{
|
||||
reg[opcode&7].I = reg[((opcode>>3)&7)].I;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
}
|
||||
|
||||
// MOV Rd, Hs
|
||||
static INSN_REGPARM void thumb46_1(u32 opcode)
|
||||
{
|
||||
reg[opcode&7].I = reg[((opcode>>3)&7)+8].I;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
}
|
||||
|
||||
// MOV Hd, Rs
|
||||
@ -1466,16 +1474,14 @@ static INSN_REGPARM void thumb47(u32 opcode)
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC)
|
||||
+ codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 3;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC)*2 + codeTicksAccess16(armNextPC) + 3;
|
||||
} else {
|
||||
armState = true;
|
||||
reg[15].I &= 0xFFFFFFFC;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 4;
|
||||
ARM_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq32(armNextPC)
|
||||
+ codeTicksAccessSeq32(armNextPC) + codeTicksAccess32(armNextPC) + 3;
|
||||
clockTicks = codeTicksAccessSeq32(armNextPC)*2 + codeTicksAccess32(armNextPC) + 3;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1569,7 +1575,7 @@ static INSN_REGPARM void thumb5E(u32 opcode)
|
||||
if (busPrefetchCount == 0)
|
||||
busPrefetch = busPrefetchEnable;
|
||||
u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
|
||||
reg[opcode&7].I = (s16)CPUReadHalfWordSigned(address);
|
||||
reg[opcode&7].I = (u32)CPUReadHalfWordSigned(address);
|
||||
clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC);
|
||||
}
|
||||
|
||||
@ -1662,6 +1668,7 @@ static INSN_REGPARM void thumbA0(u32 opcode)
|
||||
{
|
||||
u8 regist = (opcode >> 8) & 7;
|
||||
reg[regist].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2);
|
||||
clockTicks = 1 + codeTicksAccess16(armNextPC);
|
||||
}
|
||||
|
||||
// ADD R0~R7, SP, Imm
|
||||
@ -1669,6 +1676,7 @@ static INSN_REGPARM void thumbA8(u32 opcode)
|
||||
{
|
||||
u8 regist = (opcode >> 8) & 7;
|
||||
reg[regist].I = reg[13].I + ((opcode&255)<<2);
|
||||
clockTicks = 1 + codeTicksAccess16(armNextPC);
|
||||
}
|
||||
|
||||
// ADD SP, Imm
|
||||
@ -1678,6 +1686,7 @@ static INSN_REGPARM void thumbB0(u32 opcode)
|
||||
if(opcode & 0x80)
|
||||
offset = -offset;
|
||||
reg[13].I += offset;
|
||||
clockTicks = 1 + codeTicksAccess16(armNextPC);
|
||||
}
|
||||
|
||||
// Push and pop ///////////////////////////////////////////////////////////
|
||||
@ -1875,13 +1884,13 @@ static INSN_REGPARM void thumbC8(u32 opcode)
|
||||
static INSN_REGPARM void thumbD0(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
if(Z_FLAG) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -1890,13 +1899,13 @@ static INSN_REGPARM void thumbD0(u32 opcode)
|
||||
static INSN_REGPARM void thumbD1(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
if(!Z_FLAG) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -1905,13 +1914,13 @@ static INSN_REGPARM void thumbD1(u32 opcode)
|
||||
static INSN_REGPARM void thumbD2(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
if(C_FLAG) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -1920,13 +1929,13 @@ static INSN_REGPARM void thumbD2(u32 opcode)
|
||||
static INSN_REGPARM void thumbD3(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
if(!C_FLAG) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -1935,13 +1944,13 @@ static INSN_REGPARM void thumbD3(u32 opcode)
|
||||
static INSN_REGPARM void thumbD4(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
if(N_FLAG) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -1950,13 +1959,13 @@ static INSN_REGPARM void thumbD4(u32 opcode)
|
||||
static INSN_REGPARM void thumbD5(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
if(!N_FLAG) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -1965,13 +1974,13 @@ static INSN_REGPARM void thumbD5(u32 opcode)
|
||||
static INSN_REGPARM void thumbD6(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
if(V_FLAG) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -1980,13 +1989,13 @@ static INSN_REGPARM void thumbD6(u32 opcode)
|
||||
static INSN_REGPARM void thumbD7(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
if(!V_FLAG) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -1995,13 +2004,13 @@ static INSN_REGPARM void thumbD7(u32 opcode)
|
||||
static INSN_REGPARM void thumbD8(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
if(C_FLAG && !Z_FLAG) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -2010,13 +2019,13 @@ static INSN_REGPARM void thumbD8(u32 opcode)
|
||||
static INSN_REGPARM void thumbD9(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
if(!C_FLAG || Z_FLAG) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -2025,13 +2034,13 @@ static INSN_REGPARM void thumbD9(u32 opcode)
|
||||
static INSN_REGPARM void thumbDA(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
if(N_FLAG == V_FLAG) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -2040,13 +2049,13 @@ static INSN_REGPARM void thumbDA(u32 opcode)
|
||||
static INSN_REGPARM void thumbDB(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
if(N_FLAG != V_FLAG) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -2055,13 +2064,13 @@ static INSN_REGPARM void thumbDB(u32 opcode)
|
||||
static INSN_REGPARM void thumbDC(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + 1;
|
||||
if(!Z_FLAG && (N_FLAG == V_FLAG)) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -2070,13 +2079,13 @@ static INSN_REGPARM void thumbDC(u32 opcode)
|
||||
static INSN_REGPARM void thumbDD(u32 opcode)
|
||||
{
|
||||
UPDATE_OLDREG;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC);
|
||||
if(Z_FLAG || (N_FLAG != V_FLAG)) {
|
||||
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC)+3;
|
||||
clockTicks += codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 2;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
}
|
||||
@ -2087,8 +2096,8 @@ static INSN_REGPARM void thumbDD(u32 opcode)
|
||||
static INSN_REGPARM void thumbDF(u32 opcode)
|
||||
{
|
||||
u32 address = 0;
|
||||
clockTicks = codeTicksAccessSeq16(address) + codeTicksAccessSeq16(address) +
|
||||
codeTicksAccess16(address)+3;
|
||||
//clockTicks = codeTicksAccessSeq16(address)*2 + codeTicksAccess16(address)+3;
|
||||
clockTicks = 3;
|
||||
busPrefetchCount=0;
|
||||
CPUSoftwareInterrupt(opcode & 0xFF);
|
||||
}
|
||||
@ -2103,8 +2112,7 @@ static INSN_REGPARM void thumbE0(u32 opcode)
|
||||
armNextPC = reg[15].I;
|
||||
reg[15].I += 2;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) + codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC) + 3;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC)*2 + codeTicksAccess16(armNextPC)+3;
|
||||
busPrefetchCount=0;
|
||||
}
|
||||
|
||||
@ -2134,8 +2142,7 @@ static INSN_REGPARM void thumbF8(u32 opcode)
|
||||
reg[15].I += 2;
|
||||
reg[14].I = temp|1;
|
||||
THUMB_PREFETCH;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC) +
|
||||
codeTicksAccess16(armNextPC) + codeTicksAccessSeq16(armNextPC) + 3;
|
||||
clockTicks = codeTicksAccessSeq16(armNextPC)*2 + codeTicksAccess16(armNextPC) + 3;
|
||||
busPrefetchCount = 0;
|
||||
}
|
||||
|
||||
@ -2184,7 +2191,7 @@ static insnfunc_t thumbInsnTable[1024] = {
|
||||
thumb40_0,thumb40_1,thumb40_2,thumb40_3,thumb41_0,thumb41_1,thumb41_2,thumb41_3, // 40
|
||||
thumb42_0,thumb42_1,thumb42_2,thumb42_3,thumb43_0,thumb43_1,thumb43_2,thumb43_3,
|
||||
thumbUI,thumb44_1,thumb44_2,thumb44_3,thumbUI,thumb45_1,thumb45_2,thumb45_3,
|
||||
thumbUI,thumb46_1,thumb46_2,thumb46_3,thumb47,thumb47,thumbUI,thumbUI,
|
||||
thumb46_0,thumb46_1,thumb46_2,thumb46_3,thumb47,thumb47,thumbUI,thumbUI,
|
||||
thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48, // 48
|
||||
thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,
|
||||
thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,thumb48,
|
||||
|
@ -78,6 +78,7 @@ extern char oldbuffer[10];
|
||||
#endif
|
||||
|
||||
extern bool CPUReadGSASnapshot(const char *);
|
||||
extern bool CPUReadGSASPSnapshot(const char *);
|
||||
extern bool CPUWriteGSASnapshot(const char *, const char *, const char *, const char *);
|
||||
extern bool CPUWriteBatteryFile(const char *);
|
||||
extern bool CPUReadBatteryFile(const char *);
|
||||
@ -89,9 +90,14 @@ extern void CPUCleanUp();
|
||||
extern void CPUUpdateRender();
|
||||
extern void CPUUpdateRenderBuffers(bool);
|
||||
extern bool CPUReadMemState(char *, int);
|
||||
extern bool CPUReadState(const char *);
|
||||
extern bool CPUWriteMemState(char *, int);
|
||||
#ifdef __LIBRETRO__
|
||||
extern bool CPUReadState(const u8*, unsigned);
|
||||
extern unsigned int CPUWriteState(u8 *data, unsigned int size);
|
||||
#else
|
||||
extern bool CPUReadState(const char *);
|
||||
extern bool CPUWriteState(const char *);
|
||||
#endif
|
||||
extern int CPULoadRom(const char *);
|
||||
extern void doMirroring(bool);
|
||||
extern void CPUUpdateRegister(u32, u16);
|
||||
|
@ -8,7 +8,11 @@
|
||||
|
||||
//#define SPRITE_DEBUG
|
||||
|
||||
#ifdef TILED_RENDERING
|
||||
extern void gfxDrawTextScreen(u16, u16, u16, u32 *);
|
||||
#else
|
||||
static void gfxDrawTextScreen(u16, u16, u16, u32 *);
|
||||
#endif
|
||||
static void gfxDrawRotScreen(u16,
|
||||
u16, u16,
|
||||
u16, u16,
|
||||
@ -98,6 +102,7 @@ static inline void gfxClearArray(u32 *array)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef TILED_RENDERING
|
||||
static inline void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs,
|
||||
u32 *line)
|
||||
{
|
||||
@ -238,6 +243,7 @@ static inline void gfxDrawTextScreen(u16 control, u16 hofs, u16 vofs,
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void gfxDrawRotScreen(u16 control,
|
||||
u16 x_l, u16 x_h,
|
||||
|
187
source/vba/gba/GBALink.h
Normal file
@ -0,0 +1,187 @@
|
||||
#ifndef GBA_GBALINK_H
|
||||
#define GBA_GBALINK_H
|
||||
|
||||
#pragma once
|
||||
|
||||
// register definitions; these are always present
|
||||
|
||||
#define UNSUPPORTED -1
|
||||
#define MULTIPLAYER 0
|
||||
#define NORMAL8 1
|
||||
#define NORMAL32 2
|
||||
#define UART 3
|
||||
#define JOYBUS 4
|
||||
#define GP 5
|
||||
|
||||
#define RFU_INIT 0
|
||||
#define RFU_COMM 1
|
||||
#define RFU_SEND 2
|
||||
#define RFU_RECV 3
|
||||
|
||||
#define COMM_SIODATA32_L 0x120
|
||||
#define COMM_SIODATA32_H 0x122
|
||||
#define COMM_SIOCNT 0x128
|
||||
#define COMM_SIODATA8 0x12a
|
||||
#define COMM_SIOMLT_SEND 0x12a
|
||||
#define COMM_SIOMULTI0 0x120
|
||||
#define COMM_SIOMULTI1 0x122
|
||||
#define COMM_SIOMULTI2 0x124
|
||||
#define COMM_SIOMULTI3 0x126
|
||||
#define COMM_RCNT 0x134
|
||||
#define COMM_JOYCNT 0x140
|
||||
#define COMM_JOY_RECV_L 0x150
|
||||
#define COMM_JOY_RECV_H 0x152
|
||||
#define COMM_JOY_TRANS_L 0x154
|
||||
#define COMM_JOY_TRANS_H 0x156
|
||||
#define COMM_JOYSTAT 0x158
|
||||
|
||||
#define JOYSTAT_RECV 2
|
||||
#define JOYSTAT_SEND 8
|
||||
|
||||
#define JOYCNT_RESET 1
|
||||
#define JOYCNT_RECV_COMPLETE 2
|
||||
#define JOYCNT_SEND_COMPLETE 4
|
||||
#define JOYCNT_INT_ENABLE 0x40
|
||||
|
||||
enum
|
||||
{
|
||||
JOY_CMD_RESET = 0xff,
|
||||
JOY_CMD_STATUS = 0x00,
|
||||
JOY_CMD_READ = 0x14,
|
||||
JOY_CMD_WRITE = 0x15
|
||||
};
|
||||
|
||||
extern const char *MakeInstanceFilename(const char *Input);
|
||||
|
||||
#ifndef NO_LINK
|
||||
// Link implementation
|
||||
#include <SFML/System.hpp>
|
||||
#include <SFML/Network.hpp>
|
||||
|
||||
class ServerInfoDisplay
|
||||
{
|
||||
public:
|
||||
virtual void ShowServerIP(const sf::IPAddress& addr) = 0;
|
||||
virtual void ShowConnect(const int player) = 0;
|
||||
virtual void Ping() = 0;
|
||||
virtual void Connected() = 0;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
u16 linkdata[5];
|
||||
u16 linkcmd;
|
||||
u16 numtransfers;
|
||||
int lastlinktime;
|
||||
u8 numgbas;
|
||||
u8 trgbas;
|
||||
u8 linkflags;
|
||||
int rfu_q[4];
|
||||
u8 rfu_request[4];
|
||||
int rfu_linktime[4];
|
||||
u32 rfu_bdata[4][7];
|
||||
u32 rfu_data[4][32];
|
||||
} LINKDATA;
|
||||
|
||||
class lserver{
|
||||
int numbytes;
|
||||
sf::Selector<sf::SocketTCP> fdset;
|
||||
//timeval udptimeout;
|
||||
char inbuffer[256], outbuffer[256];
|
||||
s32 *intinbuffer;
|
||||
u16 *u16inbuffer;
|
||||
s32 *intoutbuffer;
|
||||
u16 *u16outbuffer;
|
||||
int counter;
|
||||
int done;
|
||||
public:
|
||||
int howmanytimes;
|
||||
sf::SocketTCP tcpsocket[4];
|
||||
sf::IPAddress udpaddr[4];
|
||||
lserver(void);
|
||||
bool Init(ServerInfoDisplay *);
|
||||
void Send(void);
|
||||
void Recv(void);
|
||||
};
|
||||
|
||||
class ClientInfoDisplay {
|
||||
public:
|
||||
virtual void ConnectStart(const sf::IPAddress& addr) = 0;
|
||||
virtual void Ping() = 0;
|
||||
virtual void ShowConnect(const int player, const int togo) = 0;
|
||||
virtual void Connected() = 0;
|
||||
};
|
||||
|
||||
class lclient{
|
||||
sf::Selector<sf::SocketTCP> fdset;
|
||||
char inbuffer[256], outbuffer[256];
|
||||
s32 *intinbuffer;
|
||||
u16 *u16inbuffer;
|
||||
s32 *intoutbuffer;
|
||||
u16 *u16outbuffer;
|
||||
int numbytes;
|
||||
public:
|
||||
sf::IPAddress serveraddr;
|
||||
unsigned short serverport;
|
||||
sf::SocketTCP noblock;
|
||||
int numtransfers;
|
||||
lclient(void);
|
||||
bool Init(sf::IPAddress, ClientInfoDisplay *);
|
||||
void Send(void);
|
||||
void Recv(void);
|
||||
void CheckConn(void);
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
sf::SocketTCP tcpsocket;
|
||||
//sf::SocketUDP udpsocket;
|
||||
int numslaves;
|
||||
sf::Thread *thread;
|
||||
int type;
|
||||
bool server;
|
||||
bool terminate;
|
||||
bool connected;
|
||||
bool speed;
|
||||
bool active;
|
||||
} LANLINKDATA;
|
||||
|
||||
extern bool gba_joybus_enabled;
|
||||
extern bool gba_link_enabled;
|
||||
|
||||
extern sf::IPAddress joybusHostAddr;
|
||||
extern void JoyBusConnect();
|
||||
extern void JoyBusShutdown();
|
||||
extern void JoyBusUpdate(int ticks);
|
||||
|
||||
extern bool InitLink();
|
||||
extern void CloseLink();
|
||||
extern void StartLink(u16);
|
||||
extern void StartGPLink(u16);
|
||||
extern void LinkUpdate(int);
|
||||
extern void CleanLocalLink();
|
||||
extern LANLINKDATA lanlink;
|
||||
extern int vbaid;
|
||||
extern bool rfu_enabled;
|
||||
extern int linktimeout;
|
||||
extern lclient lc;
|
||||
extern lserver ls;
|
||||
extern int linkid;
|
||||
|
||||
#else
|
||||
|
||||
// stubs to keep #ifdef's out of mainline
|
||||
const bool gba_joybus_enabled = false;
|
||||
const bool gba_link_enabled = false;
|
||||
|
||||
inline void JoyBusConnect() { }
|
||||
inline void JoyBusShutdown() { }
|
||||
inline void JoyBusUpdate(int) { }
|
||||
|
||||
inline bool InitLink() { return true; }
|
||||
inline void CloseLink() { }
|
||||
inline void StartLink(u16) { }
|
||||
inline void StartGPLink(u16) { }
|
||||
inline void LinkUpdate(int) { }
|
||||
inline void CleanLocalLink() { }
|
||||
#endif
|
||||
|
||||
#endif /* GBA_GBALINK_H */
|
@ -5,8 +5,11 @@ extern int armExecute();
|
||||
extern int thumbExecute();
|
||||
|
||||
#ifdef __GNUC__
|
||||
#ifndef __APPLE__
|
||||
# define INSN_REGPARM __attribute__((regparm(1)))
|
||||
#else
|
||||
# define INSN_REGPARM /*nothing*/
|
||||
//# define INSN_REGPARM __attribute__((regparm(1)))
|
||||
#endif
|
||||
# define LIKELY(x) __builtin_expect(!!(x),1)
|
||||
# define UNLIKELY(x) __builtin_expect(!!(x),0)
|
||||
#else
|
||||
|
@ -6,7 +6,8 @@
|
||||
#include "RTC.h"
|
||||
#include "Sound.h"
|
||||
#include "agbprint.h"
|
||||
#include "vmmem.h" // Nintendo GC Virtual Memory
|
||||
#include "GBAcpu.h"
|
||||
#include "GBALink.h"
|
||||
|
||||
extern const u32 objTilesAddress[3];
|
||||
|
||||
@ -33,103 +34,33 @@ extern bool timer3On;
|
||||
extern int timer3Ticks;
|
||||
extern int timer3ClockReload;
|
||||
extern int cpuTotalTicks;
|
||||
extern u32 RomIdCode;
|
||||
|
||||
#define gid(a,b,c) (a|(b<<8)|(c<<16))
|
||||
#define CORVETTE gid('A','V','C')
|
||||
|
||||
/*****************************************************************************
|
||||
* Nintendo GC Virtual Memory function override
|
||||
* Tantric September 2008
|
||||
****************************************************************************/
|
||||
|
||||
#define CPUReadByteQuickDef(addr) \
|
||||
#define CPUReadByteQuick(addr) \
|
||||
map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]
|
||||
|
||||
#define CPUReadHalfWordQuickDef(addr) \
|
||||
#define CPUReadHalfWordQuick(addr) \
|
||||
READ16LE(((u16*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
|
||||
|
||||
#define CPUReadMemoryQuickDef(addr) \
|
||||
#define CPUReadMemoryQuick(addr) \
|
||||
READ32LE(((u32*)&map[(addr)>>24].address[(addr) & map[(addr)>>24].mask]))
|
||||
|
||||
u8 inline CPUReadByteQuick( u32 addr )
|
||||
{
|
||||
switch(addr >> 24 )
|
||||
{
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
case 0x0A:
|
||||
case 0x0C:
|
||||
#ifdef USE_VM
|
||||
return VMRead8( addr & 0x1FFFFFF );
|
||||
#endif
|
||||
default:
|
||||
return CPUReadByteQuickDef(addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u16 inline CPUReadHalfWordQuick( u32 addr )
|
||||
{
|
||||
switch(addr >> 24)
|
||||
{
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
case 0x0A:
|
||||
case 0x0C:
|
||||
#ifdef USE_VM
|
||||
return VMRead16( addr & 0x1FFFFFF );
|
||||
#endif
|
||||
default:
|
||||
return CPUReadHalfWordQuickDef(addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 inline CPUReadMemoryQuick( u32 addr )
|
||||
{
|
||||
switch(addr >> 24)
|
||||
{
|
||||
case 0x08:
|
||||
case 0x09:
|
||||
case 0x0A:
|
||||
case 0x0C:
|
||||
#ifdef USE_VM
|
||||
return VMRead32( addr & 0x1FFFFFF );
|
||||
#endif
|
||||
default:
|
||||
return CPUReadMemoryQuickDef(addr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* End of VM override
|
||||
****************************************************************************/
|
||||
|
||||
static inline u32 CPUReadMemory(u32 address)
|
||||
{
|
||||
#ifdef GBA_LOGGING
|
||||
if(address & 3) {
|
||||
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
|
||||
log("Unaligned word read: %08x at %08x\n", address, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 value;
|
||||
u32 oldAddress = address;
|
||||
|
||||
if(address & 3) {
|
||||
address &= ~0x03;
|
||||
}
|
||||
|
||||
switch(address >> 24) {
|
||||
case 0x00:
|
||||
case 0:
|
||||
if(reg[15].I >> 24) {
|
||||
if(address < 0x4000) {
|
||||
#ifdef GBA_LOGGING
|
||||
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
|
||||
log("Illegal word read: %08x at %08x\n", address, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2);
|
||||
log("Illegal word read from bios: %08x at %08x\n", address, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -139,117 +70,92 @@ static inline u32 CPUReadMemory(u32 address)
|
||||
} else
|
||||
value = READ32LE(((u32 *)&bios[address & 0x3FFC]));
|
||||
break;
|
||||
case 0x02:
|
||||
case 2:
|
||||
value = READ32LE(((u32 *)&workRAM[address & 0x3FFFC]));
|
||||
break;
|
||||
case 0x03:
|
||||
case 3:
|
||||
value = READ32LE(((u32 *)&internalRAM[address & 0x7ffC]));
|
||||
break;
|
||||
case 0x04:
|
||||
if((address < 0x4000400) && ioReadable[address & 0x3fc]) {
|
||||
if(ioReadable[(address & 0x3fc) + 2])
|
||||
case 4:
|
||||
if((address < 0x4000400) && ioReadable[address & 0x3fc]) {
|
||||
if(ioReadable[(address & 0x3fc) + 2]) {
|
||||
value = READ32LE(((u32 *)&ioMem[address & 0x3fC]));
|
||||
else
|
||||
if ((address & 0x3fc) == COMM_JOY_RECV_L)
|
||||
UPDATE_REG(COMM_JOYSTAT, READ16LE(&ioMem[COMM_JOYSTAT]) & ~JOYSTAT_RECV);
|
||||
} else {
|
||||
value = READ16LE(((u16 *)&ioMem[address & 0x3fc]));
|
||||
} else goto unreadable;
|
||||
break;
|
||||
case 0x05:
|
||||
}
|
||||
}
|
||||
else
|
||||
goto unreadable;
|
||||
break;
|
||||
case 5:
|
||||
value = READ32LE(((u32 *)&paletteRAM[address & 0x3fC]));
|
||||
break;
|
||||
case 0x06:
|
||||
case 6:
|
||||
address = (address & 0x1fffc);
|
||||
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
|
||||
{
|
||||
value = 0;
|
||||
break;
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
if ((address & 0x18000) == 0x18000)
|
||||
address &= 0x17fff;
|
||||
value = READ32LE(((u32 *)&vram[address]));
|
||||
break;
|
||||
case 0x07:
|
||||
case 7:
|
||||
value = READ32LE(((u32 *)&oam[address & 0x3FC]));
|
||||
break;
|
||||
case 0x08:
|
||||
// Must be cartridge ROM, reading other sensors doesn't allow 32-bit access.
|
||||
case 0x09:
|
||||
case 0x0A:
|
||||
case 0x0B:
|
||||
case 0x0C:
|
||||
#ifdef USE_VM // Nintendo GC Virtual Memory
|
||||
value = VMRead32( address & 0x1FFFFFC );
|
||||
#else
|
||||
value = READ32LE(((u32 *)&rom[address&0x1FFFFFC]));
|
||||
#endif
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
value = READ32LE(((u32 *)&rom[address&0x1FFFFFC]));
|
||||
break;
|
||||
case 0x0D:
|
||||
if(cpuEEPROMEnabled)
|
||||
// no need to swap this
|
||||
return eepromRead(address);
|
||||
goto unreadable;
|
||||
case 0x0E:
|
||||
// Yoshi's Universal Gravitation (Topsy Turvy)
|
||||
// Koro Koro
|
||||
if(cpuEEPROMSensorEnabled) {
|
||||
switch(address & 0x00008f00) {
|
||||
case 0x8200:
|
||||
return systemGetSensorX() & 255;
|
||||
case 0x8300:
|
||||
return (systemGetSensorX() >> 8)|0x80;
|
||||
case 0x8400:
|
||||
return systemGetSensorY() & 255;
|
||||
case 0x8500:
|
||||
return systemGetSensorY() >> 8;
|
||||
}
|
||||
}
|
||||
if(cpuFlashEnabled | cpuSramEnabled)
|
||||
// no need to swap this
|
||||
return flashRead(address);
|
||||
case 13:
|
||||
value = eepromRead(address);
|
||||
break;
|
||||
case 14:
|
||||
case 15:
|
||||
value = flashRead(address) * 0x01010101;
|
||||
break;
|
||||
// default
|
||||
default:
|
||||
unreadable:
|
||||
unreadable:
|
||||
#ifdef GBA_LOGGING
|
||||
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
|
||||
log("Illegal word read: %08x at %08x\n", address, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2);
|
||||
armNextPC - 4 : armNextPC - 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(cpuDmaHack) {
|
||||
value = cpuDmaLast;
|
||||
} else {
|
||||
if(cpuDmaHack) {
|
||||
value = cpuDmaLast;
|
||||
} else {
|
||||
if(armState) {
|
||||
#ifdef USE_VM // Nintendo GC Virtual Memory
|
||||
value = CPUReadMemoryQuick(reg[15].I);
|
||||
#else
|
||||
value = CPUReadMemoryQuickDef(reg[15].I);
|
||||
#endif
|
||||
return CPUReadMemoryQuick(reg[15].I);
|
||||
} else {
|
||||
#ifdef USE_VM // Nintendo GC Virtual Memory
|
||||
value = CPUReadHalfWordQuick(reg[15].I) |
|
||||
CPUReadHalfWordQuick(reg[15].I) << 16;
|
||||
#else
|
||||
value = CPUReadHalfWordQuickDef(reg[15].I) |
|
||||
CPUReadHalfWordQuickDef(reg[15].I) << 16;
|
||||
#endif
|
||||
return CPUReadHalfWordQuick(reg[15].I) |
|
||||
CPUReadHalfWordQuick(reg[15].I) << 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(address & 3) {
|
||||
if(oldAddress & 3) {
|
||||
#ifdef C_CORE
|
||||
int shift = (address & 3) << 3;
|
||||
int shift = (oldAddress & 3) << 3;
|
||||
value = (value >> shift) | (value << (32 - shift));
|
||||
#else
|
||||
#ifdef __GNUC__
|
||||
asm("and $3, %%ecx;"
|
||||
"shl $3 ,%%ecx;"
|
||||
"ror %%cl, %0"
|
||||
: "=r" (value)
|
||||
: "r" (value), "c" (address));
|
||||
"shl $3 ,%%ecx;"
|
||||
"ror %%cl, %0"
|
||||
: "=r" (value)
|
||||
: "r" (value), "c" (oldAddress));
|
||||
#else
|
||||
__asm {
|
||||
mov ecx, address;
|
||||
mov ecx, oldAddress;
|
||||
and ecx, 3;
|
||||
shl ecx, 3;
|
||||
ror [dword ptr value], cl;
|
||||
@ -257,6 +163,15 @@ static inline u32 CPUReadMemory(u32 address)
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef GBA_LOGGING
|
||||
if(oldAddress & 3) {
|
||||
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
|
||||
log("Unaligned word read from: %08x at %08x (%08x)\n", oldAddress, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2, value);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -264,25 +179,21 @@ extern u32 myROM[];
|
||||
|
||||
static inline u32 CPUReadHalfWord(u32 address)
|
||||
{
|
||||
#ifdef GBA_LOGGING
|
||||
if(address & 1) {
|
||||
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
|
||||
log("Unaligned halfword read: %08x at %08x\n", address, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
u32 value;
|
||||
u32 oldAddress = address;
|
||||
|
||||
if(address & 1) {
|
||||
address &= ~0x01;
|
||||
}
|
||||
|
||||
switch(address >> 24) {
|
||||
case 0x00:
|
||||
case 0:
|
||||
if (reg[15].I >> 24) {
|
||||
if(address < 0x4000) {
|
||||
#ifdef GBA_LOGGING
|
||||
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
|
||||
log("Illegal halfword read: %08x at %08x\n", address, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2);
|
||||
log("Illegal halfword read from bios: %08x at %08x\n", oldAddress, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2);
|
||||
}
|
||||
#endif
|
||||
value = READ16LE(((u16 *)&biosProtected[address&2]));
|
||||
@ -290,13 +201,13 @@ static inline u32 CPUReadHalfWord(u32 address)
|
||||
} else
|
||||
value = READ16LE(((u16 *)&bios[address & 0x3FFE]));
|
||||
break;
|
||||
case 0x02:
|
||||
case 2:
|
||||
value = READ16LE(((u16 *)&workRAM[address & 0x3FFFE]));
|
||||
break;
|
||||
case 0x03:
|
||||
case 3:
|
||||
value = READ16LE(((u16 *)&internalRAM[address & 0x7ffe]));
|
||||
break;
|
||||
case 0x04:
|
||||
case 4:
|
||||
if((address < 0x4000400) && ioReadable[address & 0x3fe])
|
||||
{
|
||||
value = READ16LE(((u16 *)&ioMem[address & 0x3fe]));
|
||||
@ -305,216 +216,182 @@ static inline u32 CPUReadHalfWord(u32 address)
|
||||
if (((address & 0x3fe) == 0x100) && timer0On)
|
||||
value = 0xFFFF - ((timer0Ticks-cpuTotalTicks) >> timer0ClockReload);
|
||||
else
|
||||
if (((address & 0x3fe) == 0x104) && timer1On && !(TM1CNT & 4))
|
||||
value = 0xFFFF - ((timer1Ticks-cpuTotalTicks) >> timer1ClockReload);
|
||||
else
|
||||
if (((address & 0x3fe) == 0x108) && timer2On && !(TM2CNT & 4))
|
||||
value = 0xFFFF - ((timer2Ticks-cpuTotalTicks) >> timer2ClockReload);
|
||||
else
|
||||
if (((address & 0x3fe) == 0x10C) && timer3On && !(TM3CNT & 4))
|
||||
value = 0xFFFF - ((timer3Ticks-cpuTotalTicks) >> timer3ClockReload);
|
||||
if (((address & 0x3fe) == 0x104) && timer1On && !(TM1CNT & 4))
|
||||
value = 0xFFFF - ((timer1Ticks-cpuTotalTicks) >> timer1ClockReload);
|
||||
else
|
||||
if (((address & 0x3fe) == 0x108) && timer2On && !(TM2CNT & 4))
|
||||
value = 0xFFFF - ((timer2Ticks-cpuTotalTicks) >> timer2ClockReload);
|
||||
else
|
||||
if (((address & 0x3fe) == 0x10C) && timer3On && !(TM3CNT & 4))
|
||||
value = 0xFFFF - ((timer3Ticks-cpuTotalTicks) >> timer3ClockReload);
|
||||
}
|
||||
}
|
||||
else if((address < 0x4000400) && ioReadable[address & 0x3fc])
|
||||
{
|
||||
value = 0;
|
||||
}
|
||||
else goto unreadable;
|
||||
break;
|
||||
case 0x05:
|
||||
case 5:
|
||||
value = READ16LE(((u16 *)&paletteRAM[address & 0x3fe]));
|
||||
break;
|
||||
case 0x06:
|
||||
case 6:
|
||||
address = (address & 0x1fffe);
|
||||
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
|
||||
{
|
||||
value = 0;
|
||||
break;
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
if ((address & 0x18000) == 0x18000)
|
||||
address &= 0x17fff;
|
||||
value = READ16LE(((u16 *)&vram[address]));
|
||||
break;
|
||||
case 0x07:
|
||||
case 7:
|
||||
value = READ16LE(((u16 *)&oam[address & 0x3fe]));
|
||||
break;
|
||||
case 0x08:
|
||||
// Use existing case statement and faster test for potential speed improvement
|
||||
// This is possibly the GPIO port that controls the real time clock,
|
||||
// WarioWare Twisted! tilt sensors, rumble, and solar sensors.
|
||||
if(address >= 0x80000c4 && address <= 0x80000c8) {
|
||||
// this function still works if there is no real time clock
|
||||
// and does a normal memory read in that case.
|
||||
value = rtcRead(address & 0xFFFFFFE);
|
||||
break;
|
||||
}
|
||||
case 0x09:
|
||||
case 0x0A:
|
||||
case 0x0B:
|
||||
case 0x0C:
|
||||
#ifdef USE_VM // Nintendo GC Virtual Memory
|
||||
value = VMRead16( address & 0x1FFFFFE );
|
||||
#else
|
||||
value = READ16LE(((u16 *)&rom[address & 0x1FFFFFE]));
|
||||
#endif
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8)
|
||||
value = rtcRead(address);
|
||||
else
|
||||
value = READ16LE(((u16 *)&rom[address & 0x1FFFFFE]));
|
||||
break;
|
||||
case 0x0D:
|
||||
if(cpuEEPROMEnabled)
|
||||
// no need to swap this
|
||||
return eepromRead(address);
|
||||
goto unreadable;
|
||||
case 0x0E:
|
||||
// Yoshi's Universal Gravitation (Topsy Turvy)
|
||||
// Koro Koro
|
||||
if(cpuEEPROMSensorEnabled) {
|
||||
switch(address & 0x00008f00) {
|
||||
case 0x8200:
|
||||
return systemGetSensorX() & 255;
|
||||
case 0x8300:
|
||||
return (systemGetSensorX() >> 8)|0x80;
|
||||
case 0x8400:
|
||||
return systemGetSensorY() & 255;
|
||||
case 0x8500:
|
||||
return systemGetSensorY() >> 8;
|
||||
}
|
||||
}
|
||||
if(cpuFlashEnabled | cpuSramEnabled)
|
||||
// no need to swap this
|
||||
return flashRead(address);
|
||||
case 13:
|
||||
value = eepromRead(address);
|
||||
break;
|
||||
case 14:
|
||||
case 15:
|
||||
value = flashRead(address) * 0x0101;
|
||||
break;
|
||||
// default
|
||||
default:
|
||||
unreadable:
|
||||
unreadable:
|
||||
if(cpuDmaHack) {
|
||||
value = cpuDmaLast & 0xFFFF;
|
||||
} else {
|
||||
if(armState) {
|
||||
value = CPUReadHalfWordQuick(reg[15].I + (address & 2));
|
||||
} else {
|
||||
value = CPUReadHalfWordQuick(reg[15].I);
|
||||
}
|
||||
}
|
||||
#ifdef GBA_LOGGING
|
||||
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
|
||||
log("Illegal halfword read: %08x at %08x\n", address, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2);
|
||||
}
|
||||
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
|
||||
log("Illegal halfword read: %08x at %08x (%08x)\n", oldAddress, reg[15].I, value);
|
||||
}
|
||||
#endif
|
||||
if(cpuDmaHack) {
|
||||
value = cpuDmaLast & 0xFFFF;
|
||||
} else {
|
||||
if(armState) {
|
||||
#ifdef USE_VM // Nintendo GC Virtual Memory
|
||||
value = CPUReadHalfWordQuick(reg[15].I + (address & 2));
|
||||
#else
|
||||
value = CPUReadHalfWordQuickDef(reg[15].I + (address & 2));
|
||||
#endif
|
||||
} else {
|
||||
#ifdef USE_VM // Nintendo GC Virtual Memory
|
||||
value = CPUReadHalfWordQuick(reg[15].I);
|
||||
#else
|
||||
value = CPUReadHalfWordQuickDef(reg[15].I);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
return value;
|
||||
}
|
||||
|
||||
if(address & 1) {
|
||||
value = (value >> 8) | (value << 24);
|
||||
if(oldAddress & 1) {
|
||||
value = (value >> 8) | (value << 24);
|
||||
#ifdef GBA_LOGGING
|
||||
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
|
||||
log("Unaligned halfword read from: %08x at %08x (%08x)\n", oldAddress, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2, value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline u16 CPUReadHalfWordSigned(u32 address)
|
||||
static inline s16 CPUReadHalfWordSigned(u32 address)
|
||||
{
|
||||
u16 value = CPUReadHalfWord(address);
|
||||
s32 value = (s32)CPUReadHalfWord(address);
|
||||
if((address & 1))
|
||||
value = (s8)value;
|
||||
return value;
|
||||
{
|
||||
#ifdef GBA_LOGGING
|
||||
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
|
||||
log("Unaligned signed halfword read from: %08x at %08x (%08x)\n", address, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2, value);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return (s16)value;
|
||||
}
|
||||
|
||||
static inline u8 CPUReadByte(u32 address)
|
||||
{
|
||||
switch(address >> 24) {
|
||||
case 0x00:
|
||||
case 0:
|
||||
if (reg[15].I >> 24) {
|
||||
if(address < 0x4000) {
|
||||
#ifdef GBA_LOGGING
|
||||
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
|
||||
log("Illegal byte read: %08x at %08x\n", address, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2);
|
||||
log("Illegal byte read from bios: %08x at %08x\n", address, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2);
|
||||
}
|
||||
#endif
|
||||
return biosProtected[address & 3];
|
||||
} else goto unreadable;
|
||||
}
|
||||
return bios[address & 0x3FFF];
|
||||
case 0x02:
|
||||
case 2:
|
||||
return workRAM[address & 0x3FFFF];
|
||||
case 0x03:
|
||||
case 3:
|
||||
return internalRAM[address & 0x7fff];
|
||||
case 0x04:
|
||||
case 4:
|
||||
if((address < 0x4000400) && ioReadable[address & 0x3ff])
|
||||
return ioMem[address & 0x3ff];
|
||||
else goto unreadable;
|
||||
case 0x05:
|
||||
case 5:
|
||||
return paletteRAM[address & 0x3ff];
|
||||
case 0x06:
|
||||
case 6:
|
||||
address = (address & 0x1ffff);
|
||||
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
|
||||
return 0;
|
||||
return 0;
|
||||
if ((address & 0x18000) == 0x18000)
|
||||
address &= 0x17fff;
|
||||
return vram[address];
|
||||
case 0x07:
|
||||
case 7:
|
||||
return oam[address & 0x3ff];
|
||||
case 0x08:
|
||||
// the real time clock doesn't support byte reads, so don't bother checking for it.
|
||||
case 0x09:
|
||||
case 0x0A:
|
||||
case 0x0B:
|
||||
case 0x0C:
|
||||
#ifdef USE_VM // Nintendo GC Virtual Memory
|
||||
return VMRead8( address & 0x1FFFFFF );
|
||||
#else
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
return rom[address & 0x1FFFFFF];
|
||||
#endif
|
||||
case 0x0D:
|
||||
if(cpuEEPROMEnabled)
|
||||
return eepromRead(address);
|
||||
goto unreadable;
|
||||
case 0x0E:
|
||||
// Yoshi's Universal Gravitation (Topsy Turvy)
|
||||
// Koro Koro
|
||||
if(cpuEEPROMSensorEnabled) {
|
||||
switch(address & 0x00008f00) {
|
||||
case 0x8200:
|
||||
return systemGetSensorX() & 255;
|
||||
case 0x8300:
|
||||
return (systemGetSensorX() >> 8)|0x80;
|
||||
case 0x8400:
|
||||
return systemGetSensorY() & 255;
|
||||
case 0x8500:
|
||||
return systemGetSensorY() >> 8;
|
||||
}
|
||||
}
|
||||
if(cpuSramEnabled | cpuFlashEnabled)
|
||||
return flashRead(address);
|
||||
case 13:
|
||||
return eepromRead(address);
|
||||
case 14:
|
||||
case 15:
|
||||
{
|
||||
if (cpuEEPROMSensorEnabled) {
|
||||
switch (address & 0x00008f00) {
|
||||
case 0x8200:
|
||||
return systemGetSensorX() & 255;
|
||||
case 0x8300:
|
||||
return (systemGetSensorX() >> 8) | 0x80;
|
||||
case 0x8400:
|
||||
return systemGetSensorY() & 255;
|
||||
case 0x8500:
|
||||
return systemGetSensorY() >> 8;
|
||||
}
|
||||
}
|
||||
return flashRead(address);
|
||||
}
|
||||
// default
|
||||
default:
|
||||
unreadable:
|
||||
unreadable:
|
||||
#ifdef GBA_LOGGING
|
||||
if(systemVerbose & VERBOSE_ILLEGAL_READ) {
|
||||
log("Illegal byte read: %08x at %08x\n", address, armMode ?
|
||||
armNextPC - 4 : armNextPC - 2);
|
||||
armNextPC - 4 : armNextPC - 2);
|
||||
}
|
||||
#endif
|
||||
if(cpuDmaHack) {
|
||||
return cpuDmaLast & 0xFF;
|
||||
} else {
|
||||
if(armState) {
|
||||
#ifdef USE_VM // Nintendo GC Virtual Memory
|
||||
return CPUReadByteQuick(reg[15].I+(address & 3));
|
||||
#else
|
||||
return CPUReadByteQuickDef(reg[15].I+(address & 3));
|
||||
#endif
|
||||
} else {
|
||||
#ifdef USE_VM // Nintendo GC Virtual Memory
|
||||
return CPUReadByteQuick(reg[15].I+(address & 1));
|
||||
#else
|
||||
return CPUReadByteQuickDef(reg[15].I+(address & 1));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
break;
|
||||
if(cpuDmaHack) {
|
||||
return cpuDmaLast & 0xFF;
|
||||
} else {
|
||||
if(armState) {
|
||||
return CPUReadByteQuick(reg[15].I + (address & 3));
|
||||
} else {
|
||||
return CPUReadByteQuick(reg[15].I + (address & 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -525,19 +402,21 @@ static inline void CPUWriteMemory(u32 address, u32 value)
|
||||
if(address & 3) {
|
||||
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
|
||||
log("Unaligned word write: %08x to %08x from %08x\n",
|
||||
value,
|
||||
address,
|
||||
armMode ? armNextPC - 4 : armNextPC - 2);
|
||||
value,
|
||||
address,
|
||||
armMode ? armNextPC - 4 : armNextPC - 2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
address &= 0xFFFFFFFC;
|
||||
|
||||
switch(address >> 24) {
|
||||
case 0x02:
|
||||
#ifdef BKPT_SUPPORT
|
||||
if(*((u32 *)&freezeWorkRAM[address & 0x3FFFC]))
|
||||
cheatsWriteMemory(address & 0x203FFFC,
|
||||
value);
|
||||
value);
|
||||
else
|
||||
#endif
|
||||
WRITE32LE(((u32 *)&workRAM[address & 0x3FFFC]), value);
|
||||
@ -546,7 +425,7 @@ static inline void CPUWriteMemory(u32 address, u32 value)
|
||||
#ifdef BKPT_SUPPORT
|
||||
if(*((u32 *)&freezeInternalRAM[address & 0x7ffc]))
|
||||
cheatsWriteMemory(address & 0x3007FFC,
|
||||
value);
|
||||
value);
|
||||
else
|
||||
#endif
|
||||
WRITE32LE(((u32 *)&internalRAM[address & 0x7ffC]), value);
|
||||
@ -561,16 +440,15 @@ static inline void CPUWriteMemory(u32 address, u32 value)
|
||||
#ifdef BKPT_SUPPORT
|
||||
if(*((u32 *)&freezePRAM[address & 0x3fc]))
|
||||
cheatsWriteMemory(address & 0x70003FC,
|
||||
value);
|
||||
value);
|
||||
else
|
||||
#endif
|
||||
if(address < 0x5000400 || (RomIdCode & 0xFFFFFF) != CORVETTE)
|
||||
WRITE32LE(((u32 *)&paletteRAM[address & 0x3FC]), value);
|
||||
WRITE32LE(((u32 *)&paletteRAM[address & 0x3FC]), value);
|
||||
break;
|
||||
case 0x06:
|
||||
address = (address & 0x1fffc);
|
||||
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
|
||||
return;
|
||||
return;
|
||||
if ((address & 0x18000) == 0x18000)
|
||||
address &= 0x17fff;
|
||||
|
||||
@ -580,16 +458,16 @@ static inline void CPUWriteMemory(u32 address, u32 value)
|
||||
else
|
||||
#endif
|
||||
|
||||
WRITE32LE(((u32 *)&vram[address]), value);
|
||||
WRITE32LE(((u32 *)&vram[address]), value);
|
||||
break;
|
||||
case 0x07:
|
||||
#ifdef BKPT_SUPPORT
|
||||
if(*((u32 *)&freezeOAM[address & 0x3fc]))
|
||||
cheatsWriteMemory(address & 0x70003FC,
|
||||
value);
|
||||
value);
|
||||
else
|
||||
#endif
|
||||
WRITE32LE(((u32 *)&oam[address & 0x3fc]), value);
|
||||
WRITE32LE(((u32 *)&oam[address & 0x3fc]), value);
|
||||
break;
|
||||
case 0x0D:
|
||||
if(cpuEEPROMEnabled) {
|
||||
@ -598,19 +476,20 @@ static inline void CPUWriteMemory(u32 address, u32 value)
|
||||
}
|
||||
goto unwritable;
|
||||
case 0x0E:
|
||||
if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled) {
|
||||
case 0x0F:
|
||||
if((!eepromInUse) | cpuSramEnabled | cpuFlashEnabled) {
|
||||
(*cpuSaveGameFunc)(address, (u8)value);
|
||||
break;
|
||||
}
|
||||
// default
|
||||
default:
|
||||
unwritable:
|
||||
unwritable:
|
||||
#ifdef GBA_LOGGING
|
||||
if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
|
||||
log("Illegal word write: %08x to %08x from %08x\n",
|
||||
value,
|
||||
address,
|
||||
armMode ? armNextPC - 4 : armNextPC - 2);
|
||||
value,
|
||||
address,
|
||||
armMode ? armNextPC - 4 : armNextPC - 2);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@ -623,19 +502,21 @@ static inline void CPUWriteHalfWord(u32 address, u16 value)
|
||||
if(address & 1) {
|
||||
if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
|
||||
log("Unaligned halfword write: %04x to %08x from %08x\n",
|
||||
value,
|
||||
address,
|
||||
armMode ? armNextPC - 4 : armNextPC - 2);
|
||||
value,
|
||||
address,
|
||||
armMode ? armNextPC - 4 : armNextPC - 2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
address &= 0xFFFFFFFE;
|
||||
|
||||
switch(address >> 24) {
|
||||
case 2:
|
||||
#ifdef BKPT_SUPPORT
|
||||
if(*((u16 *)&freezeWorkRAM[address & 0x3FFFE]))
|
||||
cheatsWriteHalfWord(address & 0x203FFFE,
|
||||
value);
|
||||
value);
|
||||
else
|
||||
#endif
|
||||
WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]),value);
|
||||
@ -644,7 +525,7 @@ static inline void CPUWriteHalfWord(u32 address, u16 value)
|
||||
#ifdef BKPT_SUPPORT
|
||||
if(*((u16 *)&freezeInternalRAM[address & 0x7ffe]))
|
||||
cheatsWriteHalfWord(address & 0x3007ffe,
|
||||
value);
|
||||
value);
|
||||
else
|
||||
#endif
|
||||
WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value);
|
||||
@ -658,34 +539,33 @@ static inline void CPUWriteHalfWord(u32 address, u16 value)
|
||||
#ifdef BKPT_SUPPORT
|
||||
if(*((u16 *)&freezePRAM[address & 0x03fe]))
|
||||
cheatsWriteHalfWord(address & 0x70003fe,
|
||||
value);
|
||||
value);
|
||||
else
|
||||
#endif
|
||||
if(address < 0x5000400 || (RomIdCode & 0xFFFFFF) != CORVETTE)
|
||||
WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value);
|
||||
WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value);
|
||||
break;
|
||||
case 6:
|
||||
address = (address & 0x1fffe);
|
||||
if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
|
||||
return;
|
||||
return;
|
||||
if ((address & 0x18000) == 0x18000)
|
||||
address &= 0x17fff;
|
||||
#ifdef BKPT_SUPPORT
|
||||
if(*((u16 *)&freezeVRAM[address]))
|
||||
cheatsWriteHalfWord(address + 0x06000000,
|
||||
value);
|
||||
value);
|
||||
else
|
||||
#endif
|
||||
WRITE16LE(((u16 *)&vram[address]), value);
|
||||
WRITE16LE(((u16 *)&vram[address]), value);
|
||||
break;
|
||||
case 7:
|
||||
#ifdef BKPT_SUPPORT
|
||||
if(*((u16 *)&freezeOAM[address & 0x03fe]))
|
||||
cheatsWriteHalfWord(address & 0x70003fe,
|
||||
value);
|
||||
value);
|
||||
else
|
||||
#endif
|
||||
WRITE16LE(((u16 *)&oam[address & 0x3fe]), value);
|
||||
WRITE16LE(((u16 *)&oam[address & 0x3fe]), value);
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
@ -701,19 +581,20 @@ static inline void CPUWriteHalfWord(u32 address, u16 value)
|
||||
}
|
||||
goto unwritable;
|
||||
case 14:
|
||||
if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled) {
|
||||
case 15:
|
||||
if((!eepromInUse) | cpuSramEnabled | cpuFlashEnabled) {
|
||||
(*cpuSaveGameFunc)(address, (u8)value);
|
||||
break;
|
||||
}
|
||||
goto unwritable;
|
||||
default:
|
||||
unwritable:
|
||||
unwritable:
|
||||
#ifdef GBA_LOGGING
|
||||
if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
|
||||
log("Illegal halfword write: %04x to %08x from %08x\n",
|
||||
value,
|
||||
address,
|
||||
armMode ? armNextPC - 4 : armNextPC - 2);
|
||||
value,
|
||||
address,
|
||||
armMode ? armNextPC - 4 : armNextPC - 2);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
@ -837,7 +718,8 @@ static inline void CPUWriteByte(u32 address, u8 b)
|
||||
}
|
||||
goto unwritable;
|
||||
case 14:
|
||||
if (!(saveType == 5) && (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)) {
|
||||
case 15:
|
||||
if ((saveType != 5) && ((!eepromInUse) | cpuSramEnabled | cpuFlashEnabled)) {
|
||||
|
||||
//if(!cpuEEPROMEnabled && (cpuSramEnabled | cpuFlashEnabled)) {
|
||||
|
||||
|
@ -1,11 +1,3 @@
|
||||
/*
|
||||
Mode 0 is the tiled graphics mode, with all the layers available.
|
||||
There is no rotation or scaling in this mode.
|
||||
It can be either 16 colours (with 16 different palettes) or 256 colors.
|
||||
There are 1024 tiles available.
|
||||
|
||||
These routines only render a single line at a time, because of the way the GBA does events.
|
||||
*/
|
||||
#include "GBA.h"
|
||||
#include "Globals.h"
|
||||
#include "GBAGfx.h"
|
||||
@ -15,18 +7,9 @@ void mode0RenderLine()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x80) {
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -55,55 +38,11 @@ void mode0RenderLine()
|
||||
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
|
||||
}
|
||||
|
||||
for(u32 x = 0; x < 240u; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = backdrop;
|
||||
u8 top = 0x20;
|
||||
//--DCN
|
||||
//
|
||||
// !NON-PORTABLE!!NON-PORTABLE!
|
||||
//
|
||||
// This takes advantage of the fact that the Wii has far more registers
|
||||
// (32 vs 8) than IA-32 based processors processors (Intel, AMD).
|
||||
// This actually runs SLOWER on those. This code will only show
|
||||
// improvements on a PowerPC machine! (19.5% improvement: isolated tests)
|
||||
//*
|
||||
u8 li1 = (u8)(line1[x]>>24);
|
||||
u8 li2 = (u8)(line2[x]>>24);
|
||||
u8 li3 = (u8)(line3[x]>>24);
|
||||
u8 li4 = (u8)(lineOBJ[x]>>24);
|
||||
|
||||
u8 r = (li2 < li1) ? (li2) : (li1);
|
||||
|
||||
if(li3 < r) {
|
||||
r = (li4 < li3) ? (li4) : (li3);
|
||||
}else if(li4 < r){
|
||||
r = (li4);
|
||||
}
|
||||
|
||||
if(line0[x] < backdrop) {
|
||||
color = line0[x];
|
||||
top = 0x01;
|
||||
}
|
||||
|
||||
if(r < (u8)(color >> 24)) {
|
||||
if(r == li1){
|
||||
color = line1[x];
|
||||
top = 0x02;
|
||||
}else if(r == li2){
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}else if(r == li3){
|
||||
color = line3[x];
|
||||
top = 0x08;
|
||||
}else if(r == li4){
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
//Original
|
||||
/*
|
||||
if(line0[x] < color) {
|
||||
if(line0[x] < color) {
|
||||
color = line0[x];
|
||||
top = 0x01;
|
||||
}
|
||||
@ -117,49 +56,41 @@ void mode0RenderLine()
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
if((u8)(line3[x]>>24) < (u8)(color >> 24)) {
|
||||
|
||||
if((u8)(line3[x]>>24) < (u8)(color >> 24)) {
|
||||
color = line3[x];
|
||||
top = 0x08;
|
||||
}
|
||||
|
||||
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
//*/
|
||||
|
||||
if((top & 0x10) && (color & 0x00010000)) {
|
||||
// semi-transparent OBJ
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
u8 li0 = (u8)(line0[x]>>24);
|
||||
u8 li1 = (u8)(line1[x]>>24);
|
||||
u8 li2 = (u8)(line2[x]>>24);
|
||||
u8 li3 = (u8)(line3[x]>>24);
|
||||
if((u8)(line0[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}
|
||||
|
||||
u8 r = (li1 < li0) ? (li1) : (li0);
|
||||
if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line1[x];
|
||||
top2 = 0x02;
|
||||
}
|
||||
|
||||
if(li2 < r) {
|
||||
r = (li3 < li2) ? (li3) : (li2);
|
||||
}else if(li3 < r){
|
||||
r = (li3);
|
||||
}
|
||||
if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
|
||||
if(r < (u8)(color >> 24)) {
|
||||
if(r == li0){
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}else if(r == li1){
|
||||
back = line1[x];
|
||||
top2 = 0x02;
|
||||
}else if(r == li2){
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}else if(r == li3){
|
||||
back = line3[x];
|
||||
top2 = 0x08;
|
||||
}
|
||||
}
|
||||
if((u8)(line3[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line3[x];
|
||||
top2 = 0x08;
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
color = gfxAlphaBlend(color, back,
|
||||
@ -188,20 +119,9 @@ void mode0RenderLineNoWindow()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x80) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -234,41 +154,32 @@ void mode0RenderLineNoWindow()
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = backdrop;
|
||||
u8 top = 0x20;
|
||||
u8 top = 0x20;
|
||||
|
||||
u8 li1 = (u8)(line1[x]>>24);
|
||||
u8 li2 = (u8)(line2[x]>>24);
|
||||
u8 li3 = (u8)(line3[x]>>24);
|
||||
u8 li4 = (u8)(lineOBJ[x]>>24);
|
||||
if(line0[x] < color) {
|
||||
color = line0[x];
|
||||
top = 0x01;
|
||||
}
|
||||
|
||||
u8 r = (li2 < li1) ? (li2) : (li1);
|
||||
if(line1[x] < (color & 0xFF000000)) {
|
||||
color = line1[x];
|
||||
top = 0x02;
|
||||
}
|
||||
|
||||
if(li3 < r) {
|
||||
r = (li4 < li3) ? (li4) : (li3);
|
||||
}else if(li4 < r){
|
||||
r = (li4);
|
||||
}
|
||||
if(line2[x] < (color & 0xFF000000)) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
|
||||
if(line0[x] < backdrop) {
|
||||
color = line0[x];
|
||||
top = 0x01;
|
||||
}
|
||||
if(line3[x] < (color & 0xFF000000)) {
|
||||
color = line3[x];
|
||||
top = 0x08;
|
||||
}
|
||||
|
||||
if(r < (u8)(color >> 24)) {
|
||||
if(r == li1){
|
||||
color = line1[x];
|
||||
top = 0x02;
|
||||
}else if(r == li2){
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}else if(r == li3){
|
||||
color = line3[x];
|
||||
top = 0x08;
|
||||
}else if(r == li4){
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
}
|
||||
if(lineOBJ[x] < (color & 0xFF000000)) {
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
|
||||
if(!(color & 0x00010000)) {
|
||||
switch(effect) {
|
||||
@ -278,30 +189,40 @@ void mode0RenderLineNoWindow()
|
||||
{
|
||||
if(top & BLDMOD) {
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if((top != 0x01) && line0[x] < back) {
|
||||
u8 top2 = 0x20;
|
||||
if(line0[x] < back) {
|
||||
if(top != 0x01) {
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}
|
||||
}
|
||||
if((top != 0x02) && line1[x] < (back & 0xFF000000)) {
|
||||
|
||||
if(line1[x] < (back & 0xFF000000)) {
|
||||
if(top != 0x02) {
|
||||
back = line1[x];
|
||||
top2 = 0x02;
|
||||
}
|
||||
}
|
||||
|
||||
if((top != 0x04) && line2[x] < (back & 0xFF000000)) {
|
||||
if(line2[x] < (back & 0xFF000000)) {
|
||||
if(top != 0x04) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if((top != 0x08) && line3[x] < (back & 0xFF000000)) {
|
||||
if(line3[x] < (back & 0xFF000000)) {
|
||||
if(top != 0x08) {
|
||||
back = line3[x];
|
||||
top2 = 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
if((top != 0x10) && lineOBJ[x] < (back & 0xFF000000)) {
|
||||
if(lineOBJ[x] < (back & 0xFF000000)) {
|
||||
if(top != 0x10) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
@ -326,43 +247,25 @@ void mode0RenderLineNoWindow()
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
//--DCN
|
||||
// This is pretty much the exact same result:
|
||||
// line1[x] < (back & 0xFF000000)
|
||||
//
|
||||
// (u8)(line0[x]>>24) < (u8)(back >> 24)
|
||||
//
|
||||
// The only difference is that the first is stored in a u32,
|
||||
// and the second is stored in a u8
|
||||
//*
|
||||
u8 li0 = (u8)(line0[x]>>24);
|
||||
u8 li1 = (u8)(line1[x]>>24);
|
||||
u8 li2 = (u8)(line2[x]>>24);
|
||||
u8 li3 = (u8)(line3[x]>>24);
|
||||
if(line0[x] < back) {
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}
|
||||
|
||||
u8 r = (li1 < li0) ? (li1) : (li0);
|
||||
if(line1[x] < (back & 0xFF000000)) {
|
||||
back = line1[x];
|
||||
top2 = 0x02;
|
||||
}
|
||||
|
||||
if(li2 < r) {
|
||||
r = (li3 < li2) ? (li3) : (li2);
|
||||
}else if(li3 < r){
|
||||
r = (li3);
|
||||
}
|
||||
if(line2[x] < (back & 0xFF000000)) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
|
||||
if(r < (u8)(color >> 24)) {
|
||||
if(r == li0){
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}else if(r == li1){
|
||||
back = line1[x];
|
||||
top2 = 0x02;
|
||||
}else if(r == li2){
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}else if(r == li3){
|
||||
back = line3[x];
|
||||
top2 = 0x08;
|
||||
}
|
||||
}
|
||||
if(line3[x] < (back & 0xFF000000)) {
|
||||
back = line3[x];
|
||||
top2 = 0x08;
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
color = gfxAlphaBlend(color, back,
|
||||
@ -391,20 +294,9 @@ void mode0RenderLineAll()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x80) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -480,7 +372,7 @@ void mode0RenderLineAll()
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 1) && (line0[x] < color)) {
|
||||
if((mask & 1) && (line0[x] < color)) {
|
||||
color = line0[x];
|
||||
top = 0x01;
|
||||
}
|
||||
@ -556,30 +448,39 @@ void mode0RenderLineAll()
|
||||
if(top & BLDMOD) {
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if((mask & 1) && (top != 0x01) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
|
||||
if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x01) {
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 2) && (top != 0x02) && (u8)(line1[x]>>24) < (u8)(back >> 24)) {
|
||||
if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x02) {
|
||||
back = line1[x];
|
||||
top2 = 0x02;
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 4) && (top != 0x04) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
|
||||
if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x04) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 8) && (top != 0x08) && (u8)(line3[x]>>24) < (u8)(back >> 24)) {
|
||||
if((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x08) {
|
||||
back = line3[x];
|
||||
top2 = 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x10) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
|
@ -1,12 +1,3 @@
|
||||
/*
|
||||
Mode 1 is a tiled graphics mode, but with background layer 2 supporting scaling and rotation.
|
||||
There is no layer 3 in this mode.
|
||||
Layers 0 and 1 can be either 16 colours (with 16 different palettes) or 256 colours.
|
||||
There are 1024 tiles available.
|
||||
Layer 2 is 256 colours and allows only 256 tiles.
|
||||
|
||||
These routines only render a single line at a time, because of the way the GBA does events.
|
||||
*/
|
||||
#include "GBA.h"
|
||||
#include "Globals.h"
|
||||
#include "GBAGfx.h"
|
||||
@ -16,20 +7,9 @@ void mode1RenderLine()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x80) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -60,64 +40,49 @@ void mode1RenderLine()
|
||||
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
|
||||
}
|
||||
|
||||
for(u32 x = 0; x < 240u; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = backdrop;
|
||||
u8 top = 0x20;
|
||||
|
||||
u8 li1 = (u8)(line1[x]>>24);
|
||||
u8 li2 = (u8)(line2[x]>>24);
|
||||
u8 li4 = (u8)(lineOBJ[x]>>24);
|
||||
if(line0[x] < color) {
|
||||
color = line0[x];
|
||||
top = 0x01;
|
||||
}
|
||||
|
||||
u8 r = (li2 < li1) ? (li2) : (li1);
|
||||
if((u8)(line1[x]>>24) < (u8)(color >> 24)) {
|
||||
color = line1[x];
|
||||
top = 0x02;
|
||||
}
|
||||
|
||||
if(li4 < r){
|
||||
r = (li4);
|
||||
}
|
||||
if((u8)(line2[x]>>24) < (u8)(color >> 24)) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
|
||||
if(line0[x] < backdrop) {
|
||||
color = line0[x];
|
||||
top = 0x01;
|
||||
}
|
||||
|
||||
if(r < (u8)(color >> 24)) {
|
||||
if(r == li1){
|
||||
color = line1[x];
|
||||
top = 0x02;
|
||||
}else if(r == li2){
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}else if(r == li4){
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
}
|
||||
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
|
||||
if((top & 0x10) && (color & 0x00010000)) {
|
||||
// semi-transparent OBJ
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
u8 li0 = (u8)(line0[x]>>24);
|
||||
u8 li1 = (u8)(line1[x]>>24);
|
||||
u8 li2 = (u8)(line2[x]>>24);
|
||||
u8 r = (li1 < li0) ? (li1) : (li0);
|
||||
if((u8)(line0[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}
|
||||
|
||||
if(li2 < r) {
|
||||
r = (li2);
|
||||
}
|
||||
if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line1[x];
|
||||
top2 = 0x02;
|
||||
}
|
||||
|
||||
if(r < (u8)(back >> 24)) {
|
||||
if(r == li0){
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}else if(r == li1){
|
||||
back = line1[x];
|
||||
top2 = 0x02;
|
||||
}else if(r == li2){
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
color = gfxAlphaBlend(color, back,
|
||||
@ -148,20 +113,9 @@ void mode1RenderLineNoWindow()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x80) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -193,37 +147,29 @@ void mode1RenderLineNoWindow()
|
||||
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
|
||||
}
|
||||
|
||||
for(int x = 0; x < 240; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = backdrop;
|
||||
u8 top = 0x20;
|
||||
|
||||
u8 li1 = (u8)(line1[x]>>24);
|
||||
u8 li2 = (u8)(line2[x]>>24);
|
||||
u8 li4 = (u8)(lineOBJ[x]>>24);
|
||||
if(line0[x] < color) {
|
||||
color = line0[x];
|
||||
top = 0x01;
|
||||
}
|
||||
|
||||
u8 r = (li2 < li1) ? (li2) : (li1);
|
||||
if((u8)(line1[x]>>24) < (u8)(color >> 24)) {
|
||||
color = line1[x];
|
||||
top = 0x02;
|
||||
}
|
||||
|
||||
if(li4 < r){
|
||||
r = (li4);
|
||||
}
|
||||
if((u8)(line2[x]>>24) < (u8)(color >> 24)) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
|
||||
if(line0[x] < backdrop) {
|
||||
color = line0[x];
|
||||
top = 0x01;
|
||||
}
|
||||
|
||||
if(r < (u8)(color >> 24)) {
|
||||
if(r == li1){
|
||||
color = line1[x];
|
||||
top = 0x02;
|
||||
}else if(r == li2){
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}else if(r == li4){
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
}
|
||||
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
|
||||
if(!(color & 0x00010000)) {
|
||||
switch((BLDMOD >> 6) & 3) {
|
||||
@ -234,26 +180,33 @@ void mode1RenderLineNoWindow()
|
||||
if(top & BLDMOD) {
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
if((u8)(line0[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x01) {
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
if((top != 0x01) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}
|
||||
if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x02) {
|
||||
back = line1[x];
|
||||
top2 = 0x02;
|
||||
}
|
||||
}
|
||||
|
||||
if((top != 0x02) && (u8)(line1[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line1[x];
|
||||
top2 = 0x02;
|
||||
}
|
||||
if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x04) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if((top != 0x04) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
|
||||
if((top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x10) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
color = gfxAlphaBlend(color, back,
|
||||
@ -272,32 +225,24 @@ void mode1RenderLineNoWindow()
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// semi-transparent OBJ
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
// semi-transparent OBJ
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
u8 li0 = (u8)(line0[x]>>24);
|
||||
u8 li1 = (u8)(line1[x]>>24);
|
||||
u8 li2 = (u8)(line2[x]>>24);
|
||||
if((u8)(line0[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}
|
||||
|
||||
u8 r = (li1 < li0) ? (li1) : (li0);
|
||||
if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line1[x];
|
||||
top2 = 0x02;
|
||||
}
|
||||
|
||||
if(li2 < r) {
|
||||
r = (li2);
|
||||
}
|
||||
|
||||
if(r < (u8)(back >> 24)) {
|
||||
if(r == li0){
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}else if(r == li1){
|
||||
back = line1[x];
|
||||
top2 = 0x02;
|
||||
}else if(r == li2){
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
color = gfxAlphaBlend(color, back,
|
||||
@ -328,20 +273,9 @@ void mode1RenderLineAll()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x80) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -399,7 +333,7 @@ void mode1RenderLineAll()
|
||||
u8 inWin1Mask = WININ >> 8;
|
||||
u8 outMask = WINOUT & 0xFF;
|
||||
|
||||
for(int x = 0; x < 240; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = backdrop;
|
||||
u8 top = 0x20;
|
||||
u8 mask = outMask;
|
||||
@ -419,23 +353,22 @@ void mode1RenderLineAll()
|
||||
}
|
||||
}
|
||||
|
||||
// At the very least, move the inexpensive 'mask' operation up front
|
||||
if((mask & 1) && line0[x] < backdrop) {
|
||||
if(line0[x] < color && (mask & 1)) {
|
||||
color = line0[x];
|
||||
top = 0x01;
|
||||
}
|
||||
|
||||
if((mask & 2) && (u8)(line1[x]>>24) < (u8)(color >> 24)) {
|
||||
if((u8)(line1[x]>>24) < (u8)(color >> 24) && (mask & 2)) {
|
||||
color = line1[x];
|
||||
top = 0x02;
|
||||
}
|
||||
|
||||
if((mask & 4) && (u8)(line2[x]>>24) < (u8)(color >> 24)) {
|
||||
if((u8)(line2[x]>>24) < (u8)(color >> 24) && (mask & 4)) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
|
||||
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
|
||||
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24) && (mask & 16)) {
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
@ -445,7 +378,7 @@ void mode1RenderLineAll()
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if((mask & 1) && (u8)(line0[x]>>24) < (u8)(backdrop >> 24)) {
|
||||
if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}
|
||||
@ -487,24 +420,32 @@ void mode1RenderLineAll()
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if((mask & 1) && (top != 0x01) && (u8)(line0[x]>>24) < (u8)(backdrop >> 24)) {
|
||||
if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x01) {
|
||||
back = line0[x];
|
||||
top2 = 0x01;
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 2) && (top != 0x02) && (u8)(line1[x]>>24) < (u8)(back >> 24)) {
|
||||
if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x02) {
|
||||
back = line1[x];
|
||||
top2 = 0x02;
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 4) && (top != 0x04) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
|
||||
if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x04) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x10) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
|
@ -1,11 +1,3 @@
|
||||
/*
|
||||
Mode 2 is a 256 colour tiled graphics mode which supports scaling and rotation.
|
||||
There is no background layer 0 or 1 in this mode. Only background layers 2 and 3.
|
||||
There are 256 tiles available.
|
||||
It does not support flipping.
|
||||
|
||||
These routines only render a single line at a time, because of the way the GBA does events.
|
||||
*/
|
||||
#include "GBA.h"
|
||||
#include "Globals.h"
|
||||
#include "GBAGfx.h"
|
||||
@ -15,20 +7,9 @@ void mode2RenderLine()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x80) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -62,51 +43,40 @@ void mode2RenderLine()
|
||||
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
|
||||
}
|
||||
|
||||
for(int x = 0; x < 240; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = backdrop;
|
||||
u8 top = 0x20;
|
||||
|
||||
u8 li2 = (u8)(line2[x]>>24);
|
||||
u8 li3 = (u8)(line3[x]>>24);
|
||||
u8 li4 = (u8)(lineOBJ[x]>>24);
|
||||
|
||||
u8 r = (li3 < li2) ? (li3) : (li2);
|
||||
if((u8)(line2[x]>>24) < (u8)(color >> 24)) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
|
||||
if(li4 < r){
|
||||
r = (li4);
|
||||
}
|
||||
if((u8)(line3[x]>>24) < (u8)(color >> 24)) {
|
||||
color = line3[x];
|
||||
top = 0x08;
|
||||
}
|
||||
|
||||
if(r < (u8)(color >> 24)) {
|
||||
if(r == li2){
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}else if(r == li3){
|
||||
color = line3[x];
|
||||
top = 0x08;
|
||||
}else if(r == li4){
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
}
|
||||
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
|
||||
if((top & 0x10) && (color & 0x00010000)) {
|
||||
// semi-transparent OBJ
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
u8 li2 = (u8)(line2[x]>>24);
|
||||
u8 li3 = (u8)(line3[x]>>24);
|
||||
u8 r = (li3 < li2) ? (li3) : (li2);
|
||||
if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
|
||||
if(r < (u8)(back >> 24)) {
|
||||
if(r == li2){
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}else if(r == li3){
|
||||
back = line3[x];
|
||||
top2 = 0x08;
|
||||
}
|
||||
}
|
||||
if((u8)(line3[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line3[x];
|
||||
top2 = 0x08;
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
color = gfxAlphaBlend(color, back,
|
||||
@ -138,20 +108,9 @@ void mode2RenderLineNoWindow()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x80) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -185,32 +144,25 @@ void mode2RenderLineNoWindow()
|
||||
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
|
||||
}
|
||||
|
||||
for(int x = 0; x < 240; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = backdrop;
|
||||
u8 top = 0x20;
|
||||
|
||||
u8 li2 = (u8)(line2[x]>>24);
|
||||
u8 li3 = (u8)(line3[x]>>24);
|
||||
u8 li4 = (u8)(lineOBJ[x]>>24);
|
||||
|
||||
u8 r = (li3 < li2) ? (li3) : (li2);
|
||||
if((u8)(line2[x]>>24) < (u8)(color >> 24)) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
|
||||
if(li4 < r){
|
||||
r = (li4);
|
||||
}
|
||||
if((u8)(line3[x]>>24) < (u8)(color >> 24)) {
|
||||
color = line3[x];
|
||||
top = 0x08;
|
||||
}
|
||||
|
||||
if(r < (u8)(color >> 24)) {
|
||||
if(r == li2){
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}else if(r == li3){
|
||||
color = line3[x];
|
||||
top = 0x08;
|
||||
}else if(r == li4){
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
}
|
||||
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
|
||||
if(!(color & 0x00010000)) {
|
||||
switch((BLDMOD >> 6) & 3) {
|
||||
@ -222,20 +174,26 @@ void mode2RenderLineNoWindow()
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if((top != 0x04) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x04) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if((top != 0x08) && (u8)(line3[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line3[x];
|
||||
top2 = 0x08;
|
||||
}
|
||||
if((u8)(line3[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x08) {
|
||||
back = line3[x];
|
||||
top2 = 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
if((top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x10) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
color = gfxAlphaBlend(color, back,
|
||||
@ -258,19 +216,15 @@ void mode2RenderLineNoWindow()
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
u8 li2 = (u8)(line2[x]>>24);
|
||||
u8 li3 = (u8)(line3[x]>>24);
|
||||
u8 r = (li3 < li2) ? (li3) : (li2);
|
||||
if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
|
||||
if(r < (u8)(back >> 24)) {
|
||||
if(r == li2){
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}else if(r == li3){
|
||||
back = line3[x];
|
||||
top2 = 0x08;
|
||||
}
|
||||
}
|
||||
if((u8)(line3[x]>>24) < (u8)(back >> 24)) {
|
||||
back = line3[x];
|
||||
top2 = 0x08;
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
color = gfxAlphaBlend(color, back,
|
||||
@ -302,20 +256,9 @@ void mode2RenderLineAll()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x80) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -396,17 +339,17 @@ void mode2RenderLineAll()
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 4) && line2[x] < color) {
|
||||
if(line2[x] < color && (mask & 4)) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
|
||||
if((mask & 8) && (u8)(line3[x]>>24) < (u8)(color >> 24)) {
|
||||
if((u8)(line3[x]>>24) < (u8)(color >> 24) && (mask & 8)) {
|
||||
color = line3[x];
|
||||
top = 0x08;
|
||||
}
|
||||
|
||||
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
|
||||
if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24) && (mask & 16)) {
|
||||
color = lineOBJ[x];
|
||||
top = 0x10;
|
||||
}
|
||||
@ -453,19 +396,25 @@ void mode2RenderLineAll()
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if((mask & 4) && (top != 0x04) && line2[x] < back) {
|
||||
if((mask & 4) && line2[x] < back) {
|
||||
if(top != 0x04) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 8) && (top != 0x08) && (u8)(line3[x]>>24) < (u8)(back >> 24)) {
|
||||
if((mask & 8) && (u8)(line3[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x08) {
|
||||
back = line3[x];
|
||||
top2 = 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x10) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
|
@ -1,10 +1,3 @@
|
||||
/*
|
||||
Mode 3 is a 15-bit (32768) colour bitmap graphics mode.
|
||||
It has a single layer, background layer 2, the same size as the screen.
|
||||
It doesn't support paging, scrolling, flipping, rotation or tiles.
|
||||
|
||||
These routines only render a single line at a time, because of the way the GBA does events.
|
||||
*/
|
||||
#include "GBA.h"
|
||||
#include "Globals.h"
|
||||
#include "GBAGfx.h"
|
||||
@ -14,20 +7,9 @@ void mode3RenderLine()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x80) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -54,7 +36,7 @@ void mode3RenderLine()
|
||||
background = ((customBackdropColor & 0x7FFF) | 0x30000000);
|
||||
}
|
||||
|
||||
for(int x = 0; x < 240; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = background;
|
||||
u8 top = 0x20;
|
||||
|
||||
@ -73,7 +55,7 @@ void mode3RenderLine()
|
||||
u32 back = background;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if(line2[x] < background) {
|
||||
if(line2[x] < back) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
@ -107,20 +89,9 @@ void mode3RenderLineNoWindow()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x80) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -147,11 +118,11 @@ void mode3RenderLineNoWindow()
|
||||
background = ((customBackdropColor & 0x7FFF) | 0x30000000);
|
||||
}
|
||||
|
||||
for(int x = 0; x < 240; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = background;
|
||||
u8 top = 0x20;
|
||||
|
||||
if(line2[x] < background) {
|
||||
if(line2[x] < color) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
@ -171,14 +142,18 @@ void mode3RenderLineNoWindow()
|
||||
u32 back = background;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if(top != 0x04 && (line2[x] < background) ) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
if(line2[x] < back) {
|
||||
if(top != 0x04) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if(top != 0x10 && ((u8)(lineOBJ[x]>>24) < (u8)(back >> 24))) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x10) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
@ -203,7 +178,7 @@ void mode3RenderLineNoWindow()
|
||||
u32 back = background;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if(line2[x] < background) {
|
||||
if(line2[x] < back) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
@ -237,20 +212,9 @@ void mode3RenderLineAll()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x80) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -304,7 +268,7 @@ void mode3RenderLineAll()
|
||||
background = ((customBackdropColor & 0x7FFF) | 0x30000000);
|
||||
}
|
||||
|
||||
for(int x = 0; x < 240; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = background;
|
||||
u8 top = 0x20;
|
||||
u8 mask = outMask;
|
||||
@ -324,7 +288,7 @@ void mode3RenderLineAll()
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 4) && line2[x] < background) {
|
||||
if((mask & 4) && (line2[x] < color)) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
@ -339,7 +303,7 @@ void mode3RenderLineAll()
|
||||
u32 back = background;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if((mask & 4) && line2[x] < background) {
|
||||
if((mask & 4) && line2[x] < back) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
@ -370,20 +334,25 @@ void mode3RenderLineAll()
|
||||
u32 back = background;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if((mask & 4) && (top != 0x04) && line2[x] < back) {
|
||||
if((mask & 4) && line2[x] < back) {
|
||||
if(top != 0x04) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x10) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
color = gfxAlphaBlend(color, back,
|
||||
coeff[COLEV & 0x1F],
|
||||
coeff[(COLEV >> 8) & 0x1F]);
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1,10 +1,3 @@
|
||||
/*
|
||||
Mode 4 is a 256 colour bitmap graphics mode with 2 swappable pages.
|
||||
It has a single layer, background layer 2, the same size as the screen.
|
||||
It doesn't support scrolling, flipping, rotation or tiles.
|
||||
|
||||
These routines only render a single line at a time, because of the way the GBA does events.
|
||||
*/
|
||||
#include "GBA.h"
|
||||
#include "GBAGfx.h"
|
||||
#include "Globals.h"
|
||||
@ -14,20 +7,9 @@ void mode4RenderLine()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x0080) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -53,11 +35,11 @@ void mode4RenderLine()
|
||||
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
|
||||
}
|
||||
|
||||
for(int x = 0; x < 240; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = backdrop;
|
||||
u8 top = 0x20;
|
||||
|
||||
if(line2[x] < backdrop) {
|
||||
if(line2[x] < color) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
@ -72,7 +54,7 @@ void mode4RenderLine()
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if(line2[x] < backdrop) {
|
||||
if(line2[x] < back) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
@ -106,20 +88,9 @@ void mode4RenderLineNoWindow()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x0080) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -145,11 +116,11 @@ void mode4RenderLineNoWindow()
|
||||
backdrop = ((customBackdropColor & 0x7FFF) | 0x30000000);
|
||||
}
|
||||
|
||||
for(int x = 0; x < 240; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = backdrop;
|
||||
u8 top = 0x20;
|
||||
|
||||
if(line2[x] < backdrop) {
|
||||
if(line2[x] < color) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
@ -169,14 +140,18 @@ void mode4RenderLineNoWindow()
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if((top != 0x04) && line2[x] < backdrop) {
|
||||
if(line2[x] < back) {
|
||||
if(top != 0x04) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if((top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x10) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
@ -235,20 +210,9 @@ void mode4RenderLineAll()
|
||||
u16 *palette = (u16 *)paletteRAM;
|
||||
|
||||
if(DISPCNT & 0x0080) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -301,7 +265,7 @@ void mode4RenderLineAll()
|
||||
u8 inWin1Mask = WININ >> 8;
|
||||
u8 outMask = WINOUT & 0xFF;
|
||||
|
||||
for(int x = 0; x < 240; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = backdrop;
|
||||
u8 top = 0x20;
|
||||
u8 mask = outMask;
|
||||
@ -321,7 +285,7 @@ void mode4RenderLineAll()
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 4) && (line2[x] < backdrop)) {
|
||||
if((mask & 4) && (line2[x] < color)) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
@ -367,20 +331,25 @@ void mode4RenderLineAll()
|
||||
u32 back = backdrop;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if((mask & 4) && (top != 0x04) && (line2[x] < backdrop)) {
|
||||
if((mask & 4) && line2[x] < back) {
|
||||
if(top != 0x04) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x10) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
color = gfxAlphaBlend(color, back,
|
||||
coeff[COLEV & 0x1F],
|
||||
coeff[(COLEV >> 8) & 0x1F]);
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1,11 +1,3 @@
|
||||
/*
|
||||
Mode 5 is a low resolution (160x128) 15-bit colour bitmap graphics mode
|
||||
with 2 swappable pages!
|
||||
It has a single layer, background layer 2, lower resolution than the screen.
|
||||
It doesn't support scrolling, flipping, rotation or tiles.
|
||||
|
||||
These routines only render a single line at a time, because of the way the GBA does events.
|
||||
*/
|
||||
#include "GBA.h"
|
||||
#include "Globals.h"
|
||||
#include "GBAGfx.h"
|
||||
@ -13,20 +5,9 @@ These routines only render a single line at a time, because of the way the GBA d
|
||||
void mode5RenderLine()
|
||||
{
|
||||
if(DISPCNT & 0x0080) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -55,11 +36,11 @@ void mode5RenderLine()
|
||||
background = ((customBackdropColor & 0x7FFF) | 0x30000000);
|
||||
}
|
||||
|
||||
for(int x = 0; x < 240; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = background;
|
||||
u8 top = 0x20;
|
||||
|
||||
if(line2[x] < background) {
|
||||
if(line2[x] < color) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
@ -106,20 +87,9 @@ void mode5RenderLine()
|
||||
void mode5RenderLineNoWindow()
|
||||
{
|
||||
if(DISPCNT & 0x0080) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -148,11 +118,11 @@ void mode5RenderLineNoWindow()
|
||||
background = ((customBackdropColor & 0x7FFF) | 0x30000000);
|
||||
}
|
||||
|
||||
for(int x = 0; x < 240; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = background;
|
||||
u8 top = 0x20;
|
||||
|
||||
if(line2[x] < background) {
|
||||
if(line2[x] < color) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
@ -172,14 +142,18 @@ void mode5RenderLineNoWindow()
|
||||
u32 back = background;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if((top != 0x04) && line2[x] < background) {
|
||||
if(line2[x] < back) {
|
||||
if(top != 0x04) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if((top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x10) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
@ -236,19 +210,9 @@ void mode5RenderLineNoWindow()
|
||||
void mode5RenderLineAll()
|
||||
{
|
||||
if(DISPCNT & 0x0080) {
|
||||
|
||||
int x = 232; //240 - 8
|
||||
do{
|
||||
lineMix[x ] =
|
||||
lineMix[x+1] =
|
||||
lineMix[x+2] =
|
||||
lineMix[x+3] =
|
||||
lineMix[x+4] =
|
||||
lineMix[x+5] =
|
||||
lineMix[x+6] =
|
||||
lineMix[x+7] = 0x7fff;
|
||||
x-=8;
|
||||
}while(x>=0);
|
||||
for(int x = 0; x < 240; x++) {
|
||||
lineMix[x] = 0x7fff;
|
||||
}
|
||||
gfxLastVCOUNT = VCOUNT;
|
||||
return;
|
||||
}
|
||||
@ -304,7 +268,7 @@ void mode5RenderLineAll()
|
||||
background = ((customBackdropColor & 0x7FFF) | 0x30000000);
|
||||
}
|
||||
|
||||
for(int x = 0; x < 240; ++x) {
|
||||
for(int x = 0; x < 240; x++) {
|
||||
u32 color = background;
|
||||
u8 top = 0x20;
|
||||
u8 mask = outMask;
|
||||
@ -324,7 +288,7 @@ void mode5RenderLineAll()
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 4) && (line2[x] < background)) {
|
||||
if((mask & 4) && (line2[x] < color)) {
|
||||
color = line2[x];
|
||||
top = 0x04;
|
||||
}
|
||||
@ -370,14 +334,18 @@ void mode5RenderLineAll()
|
||||
u32 back = background;
|
||||
u8 top2 = 0x20;
|
||||
|
||||
if((mask & 4) && (top != 0x04) && (line2[x] < background)) {
|
||||
if((mask & 4) && line2[x] < back) {
|
||||
if(top != 0x04) {
|
||||
back = line2[x];
|
||||
top2 = 0x04;
|
||||
}
|
||||
}
|
||||
|
||||
if((mask & 16) && (top != 0x10) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
|
||||
if(top != 0x10) {
|
||||
back = lineOBJ[x];
|
||||
top2 = 0x10;
|
||||
}
|
||||
}
|
||||
|
||||
if(top2 & (BLDMOD>>8))
|
||||
|
@ -8,13 +8,21 @@
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Defined in VGA-GX input.cpp
|
||||
void systemCartridgeRumble(bool);
|
||||
|
||||
enum RTCSTATE
|
||||
{
|
||||
IDLE = 0,
|
||||
COMMAND,
|
||||
DATA,
|
||||
READDATA
|
||||
};
|
||||
|
||||
u8 systemGetSensorDarkness();
|
||||
int systemGetSensorZ();
|
||||
|
||||
enum RTCSTATE { IDLE, COMMAND, DATA, READDATA };
|
||||
|
||||
typedef struct {
|
||||
u8 byte0;
|
||||
u8 byte1;
|
||||
@ -271,6 +279,17 @@ void rtcReset()
|
||||
rtcClockData.reserved[11] = 0;
|
||||
}
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
void rtcSaveGame(u8 *&data)
|
||||
{
|
||||
utilWriteMem(data, &rtcClockData, sizeof(rtcClockData));
|
||||
}
|
||||
|
||||
void rtcReadGame(const u8 *&data)
|
||||
{
|
||||
utilReadMem(&rtcClockData, data, sizeof(rtcClockData));
|
||||
}
|
||||
#else
|
||||
void rtcSaveGame(gzFile gzFile)
|
||||
{
|
||||
utilGzWrite(gzFile, &rtcClockData, sizeof(rtcClockData));
|
||||
@ -280,3 +299,4 @@ void rtcReadGame(gzFile gzFile)
|
||||
{
|
||||
utilGzRead(gzFile, &rtcClockData, sizeof(rtcClockData));
|
||||
}
|
||||
#endif
|
||||
|
@ -8,7 +8,12 @@ void rtcEnableWarioRumble(bool);
|
||||
bool rtcIsEnabled();
|
||||
void rtcReset();
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
void rtcReadGame(const u8 *&data);
|
||||
void rtcSaveGame(u8 *&data);
|
||||
#else
|
||||
void rtcReadGame(gzFile gzFile);
|
||||
void rtcSaveGame(gzFile gzFile);
|
||||
#endif
|
||||
|
||||
#endif // RTC_H
|
||||
|
@ -50,8 +50,8 @@ int soundTicks = SOUND_CLOCK_TICKS_;
|
||||
|
||||
static float soundVolume = 1.0f;
|
||||
static int soundEnableFlag = 0x3ff; // emulator channels enabled
|
||||
static float soundFiltering_ = -1.0f;
|
||||
static float soundVolume_ = -1.0f;
|
||||
static float soundFiltering_ = -1;
|
||||
static float soundVolume_ = -1;
|
||||
|
||||
void interp_rate() { /* empty for now */ }
|
||||
|
||||
@ -82,8 +82,8 @@ public:
|
||||
int readIndex;
|
||||
int count;
|
||||
int writeIndex;
|
||||
int dac;
|
||||
u8 fifo [32];
|
||||
int dac;
|
||||
private:
|
||||
|
||||
int timer;
|
||||
@ -115,7 +115,7 @@ void Gba_Pcm::apply_control( int idx )
|
||||
|
||||
int ch = 0;
|
||||
if ( (soundEnableFlag >> idx & 0x100) && (ioMem [NR52] & 0x80) )
|
||||
ch = ioMem [SGCNT0_H+1] >> (idx <<2) & 3;
|
||||
ch = ioMem [SGCNT0_H+1] >> (idx * 4) & 3;
|
||||
|
||||
Blip_Buffer* out = 0;
|
||||
switch ( ch )
|
||||
@ -162,10 +162,11 @@ void Gba_Pcm::update( int dac )
|
||||
int filter = 0;
|
||||
if ( soundInterpolation )
|
||||
{
|
||||
unsigned period = unsigned(time - last_time);
|
||||
unsigned idx = period >> 9;
|
||||
// base filtering on how long since last sample was output
|
||||
int period = time - last_time;
|
||||
|
||||
if ( idx > 3 )
|
||||
int idx = (unsigned) period / 512;
|
||||
if ( idx >= 3 )
|
||||
idx = 3;
|
||||
|
||||
static int const filters [4] = { 0, 0, 1, 2 };
|
||||
@ -182,32 +183,28 @@ void Gba_Pcm_Fifo::timer_overflowed( int which_timer )
|
||||
{
|
||||
if ( which_timer == timer && enabled )
|
||||
{
|
||||
if ( count <= 16 )
|
||||
/* Mother 3 fix, refined to not break Metroid Fusion */
|
||||
if ( count == 16 || count == 0 )
|
||||
{
|
||||
// Need to fill FIFO
|
||||
int saved_count = count;
|
||||
CPUCheckDMA( 3, which ? 4 : 2 );
|
||||
if ( count <= 16 )
|
||||
if ( saved_count == 0 && count == 16 )
|
||||
CPUCheckDMA( 3, which ? 4 : 2 );
|
||||
if ( count == 0 )
|
||||
{
|
||||
// Not filled by DMA, so fill with 16 bytes of silence
|
||||
int reg = which ? FIFOB_L : FIFOA_L;
|
||||
|
||||
// No loops, yay!
|
||||
soundEvent(reg , (u16)0);
|
||||
soundEvent(reg+2, (u16)0);
|
||||
//
|
||||
soundEvent(reg , (u16)0);
|
||||
soundEvent(reg+2, (u16)0);
|
||||
//
|
||||
soundEvent(reg , (u16)0);
|
||||
soundEvent(reg+2, (u16)0);
|
||||
//
|
||||
soundEvent(reg , (u16)0);
|
||||
soundEvent(reg+2, (u16)0);
|
||||
for ( int n = 8; n--; )
|
||||
{
|
||||
soundEvent(reg , (u16)0);
|
||||
soundEvent(reg+2, (u16)0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read next sample from FIFO
|
||||
--count;
|
||||
count--;
|
||||
dac = fifo [readIndex];
|
||||
readIndex = (readIndex + 1) & 31;
|
||||
pcm.update( dac );
|
||||
@ -287,17 +284,14 @@ static void apply_volume( bool apu_only = false )
|
||||
|
||||
if ( gb_apu )
|
||||
{
|
||||
static float const apu_vols [4] = { 0.25f, 0.5f, 1.0f, 0.25f };
|
||||
static float const apu_vols [4] = { 0.25, 0.5, 1, 0.25 };
|
||||
gb_apu->volume( soundVolume_ * apu_vols [ioMem [SGCNT0_H] & 3] );
|
||||
}
|
||||
|
||||
if ( !apu_only )
|
||||
{
|
||||
double tmpVol = 0.002578125 * soundVolume_; // 0.66 / 256 * soundVolume_
|
||||
|
||||
pcm_synth[0].volume( tmpVol );
|
||||
pcm_synth[1].volume( tmpVol );
|
||||
pcm_synth[2].volume( tmpVol );
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
pcm_synth [i].volume( 0.66 / 256 * soundVolume_ );
|
||||
}
|
||||
}
|
||||
|
||||
@ -358,14 +352,19 @@ static void end_frame( blip_time_t time )
|
||||
|
||||
void flush_samples(Multi_Buffer * buffer)
|
||||
{
|
||||
#ifdef __LIBRETRO__
|
||||
int numSamples = buffer->read_samples( (blip_sample_t*) soundFinalWave, buffer->samples_avail() );
|
||||
soundDriver->write(soundFinalWave, numSamples);
|
||||
systemOnWriteDataToSoundBuffer(soundFinalWave, numSamples);
|
||||
#else
|
||||
// We want to write the data frame by frame to support legacy audio drivers
|
||||
// that don't use the length parameter of the write method.
|
||||
// TODO: Update the Win32 audio drivers (DS, OAL, XA2), and flush all the
|
||||
// samples at once to help reducing the audio delay on all platforms.
|
||||
int soundBufferLen = ( soundSampleRate / 60 ) << 2;
|
||||
int soundBufferLen = ( soundSampleRate / 60 ) * 4;
|
||||
|
||||
// soundBufferLen should have a whole number of sample pairs
|
||||
assert( soundBufferLen % ((sizeof *soundFinalWave)<<1) == 0 );
|
||||
assert( soundBufferLen % (2 * sizeof *soundFinalWave) == 0 );
|
||||
|
||||
// number of samples in output buffer
|
||||
int const out_buf_size = soundBufferLen / sizeof *soundFinalWave;
|
||||
@ -380,16 +379,15 @@ void flush_samples(Multi_Buffer * buffer)
|
||||
soundDriver->write(soundFinalWave, soundBufferLen);
|
||||
systemOnWriteDataToSoundBuffer(soundFinalWave, soundBufferLen);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void apply_filtering()
|
||||
{
|
||||
soundFiltering_ = soundFiltering;
|
||||
|
||||
// Yes, I changed soundFiltering_ to soundFiltering, the reason is
|
||||
// to eliminate a write-read dependency
|
||||
int const base_freq = 32768 - (int) (soundFiltering * 16384.0f);
|
||||
int const nyquist = stereo_buffer->sample_rate() >> 1;
|
||||
int const base_freq = (int) (32768 - soundFiltering_ * 16384);
|
||||
int const nyquist = stereo_buffer->sample_rate() / 2;
|
||||
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
@ -458,6 +456,13 @@ static void remake_stereo_buffer()
|
||||
pcm [0].pcm.init();
|
||||
pcm [1].pcm.init();
|
||||
|
||||
// APU
|
||||
if ( !gb_apu )
|
||||
{
|
||||
gb_apu = new Gb_Apu; // TODO: handle out of memory
|
||||
reset_apu();
|
||||
}
|
||||
|
||||
// Stereo_Buffer
|
||||
delete stereo_buffer;
|
||||
stereo_buffer = 0;
|
||||
@ -471,13 +476,7 @@ static void remake_stereo_buffer()
|
||||
pcm [1].which = 1;
|
||||
apply_filtering();
|
||||
|
||||
// APU
|
||||
if ( !gb_apu )
|
||||
{
|
||||
gb_apu = new Gb_Apu; // TODO: handle out of memory
|
||||
reset_apu();
|
||||
}
|
||||
|
||||
// Volume Level
|
||||
apply_muting();
|
||||
apply_volume();
|
||||
}
|
||||
@ -596,8 +595,8 @@ static struct {
|
||||
gb_apu_state_t apu;
|
||||
|
||||
// old state
|
||||
int soundDSBValue;
|
||||
u8 soundDSAValue;
|
||||
int soundDSBValue;
|
||||
} state;
|
||||
|
||||
// Old GBA sound state format
|
||||
@ -755,16 +754,25 @@ static void skip_read( gzFile in, int count )
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
void soundSaveGame( u8 *&out )
|
||||
#else
|
||||
void soundSaveGame( gzFile out )
|
||||
#endif
|
||||
{
|
||||
gb_apu->save_state( &state.apu );
|
||||
|
||||
// Be sure areas for expansion get written as zero
|
||||
memset( dummy_state, 0, sizeof dummy_state );
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
utilWriteDataMem( out, gba_state );
|
||||
#else
|
||||
utilWriteData( out, gba_state );
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef __LIBRETRO__
|
||||
static void soundReadGameOld( gzFile in, int version )
|
||||
{
|
||||
// Read main data
|
||||
@ -799,19 +807,28 @@ static void soundReadGameOld( gzFile in, int version )
|
||||
|
||||
(void) utilReadInt( in ); // ignore quality
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __LIBRETRO__
|
||||
void soundReadGame(const u8*& in, int version )
|
||||
#else
|
||||
void soundReadGame( gzFile in, int version )
|
||||
#endif
|
||||
{
|
||||
// Prepare APU and default state
|
||||
reset_apu();
|
||||
gb_apu->save_state( &state.apu );
|
||||
|
||||
if ( version > SAVE_GAME_VERSION_9 )
|
||||
#ifdef __LIBRETRO__
|
||||
utilReadDataMem( in, gba_state );
|
||||
#else
|
||||
utilReadData( in, gba_state );
|
||||
else
|
||||
soundReadGameOld( in, version );
|
||||
#endif
|
||||
|
||||
gb_apu->load_state( state.apu );
|
||||
write_SGCNT0_H( READ16LE( &ioMem [SGCNT0_H] ) & 0x770F );
|
||||
|
@ -74,8 +74,13 @@ extern int SOUND_CLOCK_TICKS; // Number of 16.8 MHz clocks between calls to so
|
||||
extern int soundTicks; // Number of 16.8 MHz clocks until soundTick() will be called
|
||||
|
||||
// Saves/loads emulator state
|
||||
#ifdef __LIBRETRO__
|
||||
void soundSaveGame( u8 *& );
|
||||
void soundReadGame(const u8*& in, int version );
|
||||
#else
|
||||
void soundSaveGame( gzFile );
|
||||
void soundReadGame( gzFile, int version );
|
||||
#endif
|
||||
|
||||
class Multi_Buffer;
|
||||
|
||||
|
@ -1058,7 +1058,7 @@ void elfParseCFA(u8 *top)
|
||||
|
||||
if(id == 0xffffffff) {
|
||||
// skip version
|
||||
*data++;
|
||||
(*data)++;
|
||||
|
||||
ELFcie *cie = (ELFcie *)calloc(1, sizeof(ELFcie));
|
||||
|
||||
|
227
source/vba/gba/gbafilter.cpp
Normal file
@ -0,0 +1,227 @@
|
||||
#include "gbafilter.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
extern int systemColorDepth;
|
||||
extern int systemRedShift;
|
||||
extern int systemGreenShift;
|
||||
extern int systemBlueShift;
|
||||
|
||||
extern u16 systemColorMap16[0x10000];
|
||||
extern u32 systemColorMap32[0x10000];
|
||||
|
||||
static const unsigned char curve[32] = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x10, 0x12,
|
||||
0x14, 0x16, 0x18, 0x1c, 0x20, 0x28, 0x30, 0x38,
|
||||
0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x80,
|
||||
0x88, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0};
|
||||
|
||||
// output R G B
|
||||
static const unsigned char influence[3 * 3] = { 16, 4, 4, // red
|
||||
8, 16, 8, // green
|
||||
0, 8, 16};// blue
|
||||
|
||||
inline void swap(short & a, short & b)
|
||||
{
|
||||
short temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
void gbafilter_pal(u16 * buf, int count)
|
||||
{
|
||||
short temp[3 * 3], s;
|
||||
unsigned pix;
|
||||
u8 red, green, blue;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
pix = *buf;
|
||||
|
||||
s = curve[(pix >> systemGreenShift) & 0x1f];
|
||||
temp[3] = s * influence[3];
|
||||
temp[4] = s * influence[4];
|
||||
temp[5] = s * influence[5];
|
||||
|
||||
s = curve[(pix >> systemRedShift) & 0x1f];
|
||||
temp[0] = s * influence[0];
|
||||
temp[1] = s * influence[1];
|
||||
temp[2] = s * influence[2];
|
||||
|
||||
s = curve[(pix >> systemBlueShift) & 0x1f];
|
||||
temp[6] = s * influence[6];
|
||||
temp[7] = s * influence[7];
|
||||
temp[8] = s * influence[8];
|
||||
|
||||
if (temp[0] < temp[3]) swap(temp[0], temp[3]);
|
||||
if (temp[0] < temp[6]) swap(temp[0], temp[6]);
|
||||
if (temp[3] < temp[6]) swap(temp[3], temp[6]);
|
||||
temp[3] <<= 1;
|
||||
temp[0] <<= 2;
|
||||
temp[0] += temp[3] + temp[6];
|
||||
|
||||
red = ((int(temp[0]) * 160) >> 17) + 4;
|
||||
if (red > 31) red = 31;
|
||||
|
||||
if (temp[2] < temp[5]) swap(temp[2], temp[5]);
|
||||
if (temp[2] < temp[8]) swap(temp[2], temp[8]);
|
||||
if (temp[5] < temp[8]) swap(temp[5], temp[8]);
|
||||
temp[5] <<= 1;
|
||||
temp[2] <<= 2;
|
||||
temp[2] += temp[5] + temp[8];
|
||||
|
||||
blue = ((int(temp[2]) * 160) >> 17) + 4;
|
||||
if (blue > 31) blue = 31;
|
||||
|
||||
if (temp[1] < temp[4]) swap(temp[1], temp[4]);
|
||||
if (temp[1] < temp[7]) swap(temp[1], temp[7]);
|
||||
if (temp[4] < temp[7]) swap(temp[4], temp[7]);
|
||||
temp[4] <<= 1;
|
||||
temp[1] <<= 2;
|
||||
temp[1] += temp[4] + temp[7];
|
||||
|
||||
green = ((int(temp[1]) * 160) >> 17) + 4;
|
||||
if (green > 31) green = 31;
|
||||
|
||||
pix = red << systemRedShift;
|
||||
pix += green << systemGreenShift;
|
||||
pix += blue << systemBlueShift;
|
||||
|
||||
*buf++ = pix;
|
||||
}
|
||||
}
|
||||
|
||||
void gbafilter_pal32(u32 * buf, int count)
|
||||
{
|
||||
short temp[3 * 3], s;
|
||||
unsigned pix;
|
||||
u8 red, green, blue;
|
||||
|
||||
while (count--)
|
||||
{
|
||||
pix = *buf;
|
||||
|
||||
s = curve[(pix >> systemGreenShift) & 0x1f];
|
||||
temp[3] = s * influence[3];
|
||||
temp[4] = s * influence[4];
|
||||
temp[5] = s * influence[5];
|
||||
|
||||
s = curve[(pix >> systemRedShift) & 0x1f];
|
||||
temp[0] = s * influence[0];
|
||||
temp[1] = s * influence[1];
|
||||
temp[2] = s * influence[2];
|
||||
|
||||
s = curve[(pix >> systemBlueShift) & 0x1f];
|
||||
temp[6] = s * influence[6];
|
||||
temp[7] = s * influence[7];
|
||||
temp[8] = s * influence[8];
|
||||
|
||||
if (temp[0] < temp[3]) swap(temp[0], temp[3]);
|
||||
if (temp[0] < temp[6]) swap(temp[0], temp[6]);
|
||||
if (temp[3] < temp[6]) swap(temp[3], temp[6]);
|
||||
temp[3] <<= 1;
|
||||
temp[0] <<= 2;
|
||||
temp[0] += temp[3] + temp[6];
|
||||
|
||||
//red = ((int(temp[0]) * 160) >> 17) + 4;
|
||||
red = ((int(temp[0]) * 160) >> 14) + 32;
|
||||
|
||||
if (temp[2] < temp[5]) swap(temp[2], temp[5]);
|
||||
if (temp[2] < temp[8]) swap(temp[2], temp[8]);
|
||||
if (temp[5] < temp[8]) swap(temp[5], temp[8]);
|
||||
temp[5] <<= 1;
|
||||
temp[2] <<= 2;
|
||||
temp[2] += temp[5] + temp[8];
|
||||
|
||||
//blue = ((int(temp[2]) * 160) >> 17) + 4;
|
||||
blue = ((int(temp[2]) * 160) >> 14) + 32;
|
||||
|
||||
if (temp[1] < temp[4]) swap(temp[1], temp[4]);
|
||||
if (temp[1] < temp[7]) swap(temp[1], temp[7]);
|
||||
if (temp[4] < temp[7]) swap(temp[4], temp[7]);
|
||||
temp[4] <<= 1;
|
||||
temp[1] <<= 2;
|
||||
temp[1] += temp[4] + temp[7];
|
||||
|
||||
//green = ((int(temp[1]) * 160) >> 17) + 4;
|
||||
green = ((int(temp[1]) * 160) >> 14) + 32;
|
||||
|
||||
//pix = red << redshift;
|
||||
//pix += green << greenshift;
|
||||
//pix += blue << blueshift;
|
||||
|
||||
pix = red << (systemRedShift - 3);
|
||||
pix += green << (systemGreenShift - 3);
|
||||
pix += blue << (systemBlueShift - 3);
|
||||
|
||||
*buf++ = pix;
|
||||
}
|
||||
}
|
||||
|
||||
// for palette mode to work with the three spoony filters in 32bpp depth
|
||||
|
||||
void gbafilter_pad(u8 * buf, int count)
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
u8 r;
|
||||
u8 g;
|
||||
u8 b;
|
||||
u8 a;
|
||||
} part;
|
||||
unsigned whole;
|
||||
}
|
||||
mask;
|
||||
|
||||
mask.whole = 0x1f << systemRedShift;
|
||||
mask.whole += 0x1f << systemGreenShift;
|
||||
mask.whole += 0x1f << systemBlueShift;
|
||||
|
||||
switch (systemColorDepth)
|
||||
{
|
||||
case 24:
|
||||
while (count--)
|
||||
{
|
||||
*buf++ &= mask.part.r;
|
||||
*buf++ &= mask.part.g;
|
||||
*buf++ &= mask.part.b;
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
while (count--)
|
||||
{
|
||||
*((u32*)buf) &= mask.whole;
|
||||
buf += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void UpdateSystemColorMaps(int lcd)
|
||||
{
|
||||
switch(systemColorDepth) {
|
||||
case 16:
|
||||
{
|
||||
for(int i = 0; i < 0x10000; i++) {
|
||||
systemColorMap16[i] = ((i & 0x1f) << systemRedShift) |
|
||||
(((i & 0x3e0) >> 5) << systemGreenShift) |
|
||||
(((i & 0x7c00) >> 10) << systemBlueShift);
|
||||
}
|
||||
if (lcd == 1) gbafilter_pal(systemColorMap16, 0x10000);
|
||||
}
|
||||
break;
|
||||
case 24:
|
||||
case 32:
|
||||
{
|
||||
for(int i = 0; i < 0x10000; i++) {
|
||||
systemColorMap32[i] = ((i & 0x1f) << systemRedShift) |
|
||||
(((i & 0x3e0) >> 5) << systemGreenShift) |
|
||||
(((i & 0x7c00) >> 10) << systemBlueShift);
|
||||
}
|
||||
if (lcd == 1) gbafilter_pal32(systemColorMap32, 0x10000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
5
source/vba/gba/gbafilter.h
Normal file
@ -0,0 +1,5 @@
|
||||
#include "../System.h"
|
||||
|
||||
void gbafilter_pal(u16 * buf, int count);
|
||||
void gbafilter_pal32(u32 * buf, int count);
|
||||
void gbafilter_pad(u8 * buf, int count);
|
@ -15,6 +15,7 @@
|
||||
#include <ogcsys.h>
|
||||
#include <unistd.h>
|
||||
#include <wiiuse/wpad.h>
|
||||
#include <wupc/wupc.h>
|
||||
#include <sys/iosupport.h>
|
||||
|
||||
#ifdef HW_RVL
|
||||
@ -51,7 +52,8 @@ int ShutdownRequested = 0;
|
||||
int ResetRequested = 0;
|
||||
int ExitRequested = 0;
|
||||
char appPath[1024] = { 0 };
|
||||
char loadedFile[1024] = { 0 };
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Shutdown / Reboot / Exit
|
||||
@ -341,6 +343,7 @@ int main(int argc, char *argv[])
|
||||
SYS_SetPowerCallback(ShutdownCB);
|
||||
SYS_SetResetCallback(ResetCB);
|
||||
|
||||
WUPC_Init();
|
||||
WPAD_Init();
|
||||
WPAD_SetPowerButtonCallback((WPADShutdownCallback)ShutdownCB);
|
||||
DI_Init();
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "utils/FreeTypeGX.h"
|
||||
|
||||
#define APPNAME "Visual Boy Advance GX"
|
||||
#define APPVERSION "2.2.8"
|
||||
#define APPVERSION "2.3.3"
|
||||
#define APPFOLDER "vbagx"
|
||||
#define PREF_FILE_NAME "settings.xml"
|
||||
#define PAL_FILE_NAME "palettes.xml"
|
||||
@ -40,7 +40,8 @@ enum {
|
||||
enum {
|
||||
FILE_SRAM,
|
||||
FILE_SNAPSHOT,
|
||||
FILE_ROM
|
||||
FILE_ROM,
|
||||
FILE_BORDER_PNG
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -66,16 +67,20 @@ struct SGCSettings{
|
||||
float gbaZoomVert; // GBA vertical zoom amount
|
||||
float gbZoomHor; // GB horizontal zoom amount
|
||||
float gbZoomVert; // GB vertical zoom amount
|
||||
int gbFixed;
|
||||
int gbaFixed;
|
||||
int AutoLoad;
|
||||
int AutoSave;
|
||||
int LoadMethod; // For ROMS: Auto, SD, DVD, USB, Network (SMB)
|
||||
int SaveMethod; // For SRAM, Freeze, Prefs: Auto, SD, USB, SMB
|
||||
int AppendAuto; // 0 - no, 1 - yes
|
||||
int videomode; // 0 - automatic, 1 - NTSC (480i), 2 - Progressive (480p), 3 - PAL (50Hz), 4 - PAL (60Hz)
|
||||
int scaling; // 0 - default, 1 - partial stretch, 2 - stretch to fit, 3 - widescreen correction
|
||||
int render; // 0 - original, 1 - filtered, 2 - unfiltered
|
||||
int xshift; // video output shift
|
||||
int yshift;
|
||||
int colorize; // colorize Mono Gameboy games
|
||||
int gbaFrameskip; // turn on auto-frameskip for GBA games
|
||||
int WiiControls; // Match Wii Game
|
||||
int WiimoteOrientation;
|
||||
int ExitAction;
|
||||
@ -83,15 +88,20 @@ struct SGCSettings{
|
||||
int SFXVolume;
|
||||
int Rumble;
|
||||
int language;
|
||||
int OffsetMinutesUTC; // Used for clock on MBC3 and TAMA5
|
||||
int GBHardware; // Mapped to gbEmulatorType in VBA
|
||||
int SGBBorder;
|
||||
char LoadFolder[MAXPATHLEN]; // Path to game files
|
||||
char LastFileLoaded[MAXPATHLEN]; //Last file loaded filename
|
||||
char SaveFolder[MAXPATHLEN]; // Path to save files
|
||||
char CheatFolder[MAXPATHLEN]; // Path to cheat files
|
||||
char ScreenshotsFolder[MAXPATHLEN]; //Path to screenshots files
|
||||
char BorderFolder[MAXPATHLEN]; // Path to Super Game Boy border files
|
||||
char smbip[80];
|
||||
char smbuser[20];
|
||||
char smbpwd[20];
|
||||
char smbshare[20];
|
||||
};
|
||||
|
||||
void ExitApp();
|
||||
void ShutdownWii();
|
||||
bool SupportedIOS(u32 ios);
|
||||
@ -102,7 +112,7 @@ extern int ConfigRequested;
|
||||
extern int ShutdownRequested;
|
||||
extern int ExitRequested;
|
||||
extern char appPath[];
|
||||
extern char loadedFile[];
|
||||
|
||||
extern FreeTypeGX *fontSystem[];
|
||||
|
||||
#endif
|
||||
|
@ -16,6 +16,9 @@
|
||||
#include <malloc.h>
|
||||
#include <ogc/lwp_watchdog.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "vbagx.h"
|
||||
#include "fileop.h"
|
||||
#include "filebrowser.h"
|
||||
@ -46,6 +49,9 @@
|
||||
#include "vba/gb/gbCheats.h"
|
||||
#include "vba/gb/gbSound.h"
|
||||
|
||||
#include "goomba/goombarom.h"
|
||||
#include "goomba/goombasav.h"
|
||||
|
||||
static u32 start;
|
||||
int cartridgeType = 0;
|
||||
u32 RomIdCode;
|
||||
@ -72,7 +78,7 @@ int systemGreenShift = 0;
|
||||
int systemColorDepth = 0;
|
||||
u16 systemGbPalette[24];
|
||||
u16 systemColorMap16[0x10000];
|
||||
u32 *systemColorMap32 = NULL;
|
||||
u32 systemColorMap32[0x10000];
|
||||
|
||||
void gbSetPalette(u32 RRGGBB[]);
|
||||
bool StartColorizing();
|
||||
@ -141,29 +147,36 @@ void system10Frames(int rate)
|
||||
|
||||
if (cartridgeType == 2) // GBA games require frameskipping
|
||||
{
|
||||
// consider increasing skip
|
||||
if(speed < 60)
|
||||
systemFrameSkip += 4;
|
||||
else if(speed < 70)
|
||||
systemFrameSkip += 3;
|
||||
else if(speed < 80)
|
||||
systemFrameSkip += 2;
|
||||
else if(speed < 98)
|
||||
++systemFrameSkip;
|
||||
|
||||
// consider decreasing skip
|
||||
else if(speed > 185)
|
||||
systemFrameSkip -= 3;
|
||||
else if(speed > 145)
|
||||
systemFrameSkip -= 2;
|
||||
else if(speed > 125)
|
||||
systemFrameSkip -= 1;
|
||||
|
||||
// correct invalid frame skip values
|
||||
if(systemFrameSkip > 20)
|
||||
systemFrameSkip = 20;
|
||||
else if(systemFrameSkip < 0)
|
||||
if (!GCSettings.gbaFrameskip)
|
||||
{
|
||||
systemFrameSkip = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// consider increasing skip
|
||||
if(speed < 60)
|
||||
systemFrameSkip += 4;
|
||||
else if(speed < 70)
|
||||
systemFrameSkip += 3;
|
||||
else if(speed < 80)
|
||||
systemFrameSkip += 2;
|
||||
else if(speed < 98)
|
||||
++systemFrameSkip;
|
||||
|
||||
// consider decreasing skip
|
||||
else if(speed > 185)
|
||||
systemFrameSkip -= 3;
|
||||
else if(speed > 145)
|
||||
systemFrameSkip -= 2;
|
||||
else if(speed > 125)
|
||||
systemFrameSkip -= 1;
|
||||
|
||||
// correct invalid frame skip values
|
||||
if(systemFrameSkip > 20)
|
||||
systemFrameSkip = 20;
|
||||
else if(systemFrameSkip < 0)
|
||||
systemFrameSkip = 0;
|
||||
}
|
||||
}
|
||||
lastTime = gettime();
|
||||
}
|
||||
@ -268,6 +281,34 @@ bool LoadBatteryOrState(char * filepath, int action, bool silent)
|
||||
// load the file into savebuffer
|
||||
offset = LoadFile(filepath, silent);
|
||||
|
||||
if (cartridgeType == 1 && goomba_is_sram(savebuffer)) {
|
||||
void* cleaned = goomba_cleanup(savebuffer);
|
||||
if (savebuffer == NULL) {
|
||||
ErrorPrompt(goomba_last_error());
|
||||
offset = 0;
|
||||
} else {
|
||||
if (cleaned != savebuffer) {
|
||||
memcpy(savebuffer, cleaned, GOOMBA_COLOR_SRAM_SIZE);
|
||||
free(cleaned);
|
||||
}
|
||||
stateheader* sh = stateheader_for(savebuffer, RomTitle);
|
||||
if (sh == NULL) {
|
||||
ErrorPrompt(goomba_last_error());
|
||||
offset = 0;
|
||||
} else {
|
||||
goomba_size_t outsize;
|
||||
void* gbc_sram = goomba_extract(savebuffer, sh, &outsize);
|
||||
if (gbc_sram == NULL) {
|
||||
ErrorPrompt(goomba_last_error());
|
||||
offset = 0;
|
||||
} else {
|
||||
memcpy(savebuffer, gbc_sram, outsize);
|
||||
offset = outsize;
|
||||
free(gbc_sram);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// load savebuffer into VBA memory
|
||||
if (offset > 0)
|
||||
{
|
||||
@ -319,6 +360,9 @@ bool LoadBatteryOrStateAuto(int action, bool silent)
|
||||
if (LoadBatteryOrState(filepath, action, SILENT))
|
||||
return true;
|
||||
|
||||
if (!GCSettings.AppendAuto)
|
||||
return false;
|
||||
|
||||
// look for file with no number or Auto appended
|
||||
if(!MakeFilePath(filepath2, action, ROMFilename, -1))
|
||||
return false;
|
||||
@ -372,6 +416,41 @@ bool SaveBatteryOrState(char * filepath, int action, bool silent)
|
||||
datasize = MemgbWriteBatteryFile((char *)savebuffer);
|
||||
else
|
||||
datasize = MemCPUWriteBatteryFile((char *)savebuffer);
|
||||
|
||||
if (cartridgeType == 1) {
|
||||
const char* generic_goomba_error = "Cannot save SRAM in Goomba format (did not load correctly.)";
|
||||
// check for goomba sram format
|
||||
char* old_sram = (char*)malloc(GOOMBA_COLOR_SRAM_SIZE);
|
||||
size_t br = LoadFile(old_sram, filepath, GOOMBA_COLOR_SRAM_SIZE, true);
|
||||
if (br >= GOOMBA_COLOR_SRAM_SIZE && goomba_is_sram(old_sram)) {
|
||||
void* cleaned = goomba_cleanup(old_sram);
|
||||
if (cleaned == NULL) {
|
||||
ErrorPrompt(generic_goomba_error);
|
||||
datasize = 0;
|
||||
} else {
|
||||
if (cleaned != old_sram) {
|
||||
free(old_sram);
|
||||
old_sram = (char*)cleaned;
|
||||
}
|
||||
stateheader* sh = stateheader_for(old_sram, RomTitle);
|
||||
if (sh == NULL) {
|
||||
// Game probably doesn't use SRAM
|
||||
datasize = 0;
|
||||
} else {
|
||||
void* new_sram = goomba_new_sav(old_sram, sh, savebuffer, datasize);
|
||||
if (new_sram == NULL) {
|
||||
ErrorPrompt(goomba_last_error());
|
||||
datasize = 0;
|
||||
} else {
|
||||
memcpy(savebuffer, new_sram, GOOMBA_COLOR_SRAM_SIZE);
|
||||
datasize = GOOMBA_COLOR_SRAM_SIZE;
|
||||
free(new_sram);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(old_sram);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -411,6 +490,30 @@ bool SaveBatteryOrStateAuto(int action, bool silent)
|
||||
|
||||
return SaveBatteryOrState(filepath, action, silent);
|
||||
}
|
||||
/****************************************************************************
|
||||
* Save Screenshot / Preview image
|
||||
***************************************************************************/
|
||||
|
||||
int SavePreviewImg(char * filepath, bool silent)
|
||||
{
|
||||
int device;
|
||||
|
||||
if(!FindDevice(filepath, &device))
|
||||
return 0;
|
||||
|
||||
if(gameScreenPngSize > 0)
|
||||
{
|
||||
char screenpath[1024];
|
||||
strcpy(screenpath, filepath);
|
||||
screenpath[strlen(screenpath)] = 0;
|
||||
sprintf(screenpath, "%s.png", screenpath);
|
||||
SaveFile((char *)gameScreenPng, screenpath, gameScreenPngSize, silent);
|
||||
}
|
||||
|
||||
if(!silent)
|
||||
InfoPrompt ("Save successful");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Sound
|
||||
@ -614,11 +717,14 @@ void systemUpdateMotionSensor()
|
||||
****************************************************************************/
|
||||
static int srcWidth = 0;
|
||||
static int srcHeight = 0;
|
||||
static int srcPitch = 0;
|
||||
|
||||
void systemDrawScreen()
|
||||
{
|
||||
GX_Render( srcWidth, srcHeight, pix, srcPitch );
|
||||
GX_Render(
|
||||
srcWidth,
|
||||
srcHeight,
|
||||
pix
|
||||
);
|
||||
}
|
||||
|
||||
static bool ValidGameId(u32 id)
|
||||
@ -710,6 +816,8 @@ static void gbApplyPerImagePreferences()
|
||||
RomIdCode = SWEP5;
|
||||
else if (strcmp(RomTitle, "SRJ DMG") == 0)
|
||||
RomIdCode = SWEP6;
|
||||
else if (strcmp(RomTitle, "KID DRACULA") == 0)
|
||||
RomIdCode = KIDDRACULA;
|
||||
}
|
||||
// look for matching palettes if a monochrome gameboy game
|
||||
// (or if a Super Gameboy game, but the palette will be ignored later in that case)
|
||||
@ -825,11 +933,143 @@ void LoadPatch()
|
||||
FreeSaveBuffer ();
|
||||
}
|
||||
|
||||
void SaveSGBBorderIfNoneExists(const void* buffer) {
|
||||
char* borderPath = NULL;
|
||||
FILE* f = NULL;
|
||||
void* rgba8 = NULL;
|
||||
IMGCTX pngContext = NULL;
|
||||
|
||||
int err;
|
||||
|
||||
struct stat s;
|
||||
borderPath = AllocAndGetPNGBorderPath(NULL);
|
||||
|
||||
char* slash = strrchr(borderPath, '/');
|
||||
*slash = '\0'; // cut string off at directory name
|
||||
|
||||
err = stat(borderPath, &s);
|
||||
if (err == -1) goto cleanup;
|
||||
if (!S_ISDIR(s.st_mode)) goto cleanup;
|
||||
|
||||
*slash = '/'; // restore slash, bring filename back
|
||||
|
||||
err = stat(borderPath, &s);
|
||||
if (err != -1 || errno != ENOENT) goto cleanup;
|
||||
|
||||
f = fopen(borderPath, "wb");
|
||||
if (!f) goto cleanup;
|
||||
|
||||
rgba8 = malloc(256*224*3);
|
||||
if (!rgba8) goto cleanup;
|
||||
pngContext = PNGU_SelectImageFromBuffer(rgba8);
|
||||
if (pngContext == NULL) goto cleanup;
|
||||
|
||||
PNGU_EncodeFromLinearRGB565(pngContext, 256, 224, buffer, 258);
|
||||
fwrite(rgba8, 1, 256*224*3, f);
|
||||
|
||||
cleanup:
|
||||
if (borderPath) free(borderPath);
|
||||
if (f) fclose(f);
|
||||
if (rgba8) free(rgba8);
|
||||
if (pngContext) PNGU_ReleaseImageContext(pngContext);
|
||||
}
|
||||
|
||||
char* AllocAndGetPNGBorderPath(const char* title) {
|
||||
const char* method = pathPrefix[GCSettings.LoadMethod];
|
||||
const char* folder = GCSettings.BorderFolder;
|
||||
|
||||
char tmp[13];
|
||||
|
||||
// If no title was passed in, get the rom title
|
||||
if (title == NULL) {
|
||||
if (cartridgeType == 1) {
|
||||
title = gb_get_title(gbRom, NULL);
|
||||
} else if (cartridgeType == 2) {
|
||||
memcpy(tmp, rom + 0xA0, 12);
|
||||
tmp[12] = '\0';
|
||||
title = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
size_t length = strlen(method) + strlen(folder) + strlen(title) + 6;
|
||||
char* path = (char*)malloc(length);
|
||||
if (path) sprintf(path, "%s%s/%s.png", method, folder, title);
|
||||
return path;
|
||||
}
|
||||
|
||||
void LoadPNGBorder(const char* fallback)
|
||||
{
|
||||
void* png_tmp_buf = malloc(1024*1024);
|
||||
char* borderPath = AllocAndGetPNGBorderPath(NULL);
|
||||
PNGUPROP imgProp;
|
||||
IMGCTX ctx = NULL;
|
||||
char error[1024]; error[1023] = 0;
|
||||
int r;
|
||||
|
||||
bool borderLoaded = LoadFile((char*)png_tmp_buf, borderPath, 1024*1024, SILENT);
|
||||
if (!borderLoaded) {
|
||||
// Try default border.png
|
||||
free(borderPath);
|
||||
borderPath = AllocAndGetPNGBorderPath(fallback);
|
||||
borderLoaded = LoadFile((char*)png_tmp_buf, borderPath, 1024*1024, SILENT);
|
||||
}
|
||||
if (!borderLoaded) goto cleanup;
|
||||
|
||||
ctx = PNGU_SelectImageFromBuffer(png_tmp_buf);
|
||||
|
||||
if (ctx == NULL) {
|
||||
snprintf(error, 1023, "Error reading %s", borderPath);
|
||||
ErrorPrompt(error);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
r = PNGU_GetImageProperties(ctx, &imgProp);
|
||||
if (r != PNGU_OK) {
|
||||
snprintf(error, 1023, "PNGU properties error (%d): %s", r, borderPath);
|
||||
ErrorPrompt(error);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (imgProp.imgWidth > 640 || imgProp.imgHeight > 480) {
|
||||
snprintf(error, 1023, "Wrong size (should be 640x480 or smaller): %s", borderPath);
|
||||
ErrorPrompt(error);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
InitialBorder = (u16*)malloc(640*480*2);
|
||||
r = PNGU_DecodeTo4x4RGB565 (ctx, imgProp.imgWidth, imgProp.imgHeight, InitialBorder);
|
||||
if (r != PNGU_OK) {
|
||||
snprintf(error, 1023, "PNGU decoding error (%d): %s", r, borderPath);
|
||||
ErrorPrompt(error);
|
||||
free(InitialBorder);
|
||||
InitialBorder = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
InitialBorderWidth = imgProp.imgWidth;
|
||||
InitialBorderHeight = imgProp.imgHeight;
|
||||
|
||||
cleanup:
|
||||
if (png_tmp_buf) free(png_tmp_buf);
|
||||
if (borderPath) free(borderPath);
|
||||
if (ctx) PNGU_ReleaseImageContext(ctx);
|
||||
}
|
||||
|
||||
extern bool gbUpdateSizes();
|
||||
|
||||
bool LoadGBROM()
|
||||
{
|
||||
gbRom = (u8 *)malloc(1024*1024*4); // allocate 4 MB to GB ROM
|
||||
gbEmulatorType = GCSettings.GBHardware;
|
||||
|
||||
if (browserList[browser.selIndex].length > 1024*1024*8) {
|
||||
InfoPrompt("ROM size is too large (> 8 MB)");
|
||||
return false;
|
||||
}
|
||||
gbRom = (u8 *)malloc(1024*1024*8); // 32 MB is too much for sure
|
||||
if (!gbRom) {
|
||||
InfoPrompt("Unable to allocate 8 MB of memory");
|
||||
return false;
|
||||
}
|
||||
bios = (u8 *)calloc(1,0x100);
|
||||
|
||||
systemSaveUpdateCounter = SYSTEM_SAVE_NOT_UPDATED;
|
||||
@ -848,16 +1088,51 @@ bool LoadGBROM()
|
||||
gbRomSize = LoadSzFile(szpath, (unsigned char *)gbRom);
|
||||
}
|
||||
|
||||
const void* firstRom = gb_first_rom(gbRom, gbRomSize);
|
||||
const void* secondRom = gb_next_rom(gbRom, gbRomSize, firstRom);
|
||||
if (firstRom != NULL && firstRom != gbRom) {
|
||||
char msgbuf[32];
|
||||
const void* rom;
|
||||
for (rom = firstRom; rom != NULL; rom = gb_next_rom(gbRom, gbRomSize, rom)) {
|
||||
sprintf(msgbuf, "Load %s?", gb_get_title(rom, NULL));
|
||||
if (secondRom == NULL || YesNoPrompt(msgbuf, true)) {
|
||||
gbRomSize = gb_rom_size(rom);
|
||||
memmove(gbRom, rom, gbRomSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (rom == NULL) {
|
||||
InfoPrompt("No more ROMs found in the file.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (GCSettings.SGBBorder == 2) LoadPNGBorder("default");
|
||||
|
||||
if(gbRomSize <= 0)
|
||||
return false;
|
||||
|
||||
return gbUpdateSizes();
|
||||
}
|
||||
|
||||
bool utilIsZipFile(const char* file)
|
||||
{
|
||||
if(strlen(file) > 4)
|
||||
{
|
||||
char * p = strrchr(file,'.');
|
||||
if(p != NULL)
|
||||
{
|
||||
if(strcasecmp(p, ".zip") == 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LoadVBAROM()
|
||||
{
|
||||
cartridgeType = 0;
|
||||
bool loaded = false;
|
||||
int loaded = 0;
|
||||
|
||||
// image type (checks file extension)
|
||||
if(utilIsGBAImage(browserList[browser.selIndex].filename))
|
||||
@ -907,49 +1182,57 @@ bool LoadVBAROM()
|
||||
|
||||
srcWidth = 0;
|
||||
srcHeight = 0;
|
||||
srcPitch = 0;
|
||||
|
||||
VMClose(); // cleanup GBA memory
|
||||
gbCleanUp(); // cleanup GB memory
|
||||
|
||||
switch(cartridgeType)
|
||||
if (InitialBorder != NULL) {
|
||||
free(InitialBorder);
|
||||
InitialBorder = NULL;
|
||||
}
|
||||
SGBBorderLoadedFromGame = false; // don't try to copy sgb border from game to png unless we're in sgb mode
|
||||
|
||||
if(cartridgeType == 2)
|
||||
{
|
||||
case 2:
|
||||
emulator = GBASystem;
|
||||
srcWidth = 240;
|
||||
srcHeight = 160;
|
||||
loaded = VMCPULoadROM();
|
||||
srcPitch = 484;
|
||||
soundSetSampleRate(22050); //44100 / 2
|
||||
cpuSaveType = 0;
|
||||
break;
|
||||
emulator = GBASystem;
|
||||
srcWidth = 240;
|
||||
srcHeight = 160;
|
||||
loaded = VMCPULoadROM();
|
||||
soundSetSampleRate(22050); //44100 / 2
|
||||
cpuSaveType = 0;
|
||||
if (loaded == 2) {
|
||||
loaded = 0;
|
||||
cartridgeType = 1;
|
||||
} else if (loaded == 1 && GCSettings.SGBBorder == 2) {
|
||||
LoadPNGBorder("defaultgba");
|
||||
}
|
||||
}
|
||||
|
||||
case 1:
|
||||
emulator = GBSystem;
|
||||
if (cartridgeType == 1)
|
||||
{
|
||||
emulator = GBSystem;
|
||||
gbBorderOn = (GCSettings.SGBBorder == 1);
|
||||
|
||||
gbBorderOn = 0; // GB borders always off
|
||||
if(gbBorderOn)
|
||||
{
|
||||
srcWidth = 256;
|
||||
srcHeight = 224;
|
||||
gbBorderLineSkip = 256;
|
||||
gbBorderColumnSkip = 48;
|
||||
gbBorderRowSkip = 40;
|
||||
SGBBorderLoadedFromGame = false; // try to load the border during rendering
|
||||
}
|
||||
else
|
||||
{
|
||||
srcWidth = 160;
|
||||
srcHeight = 144;
|
||||
gbBorderLineSkip = 160;
|
||||
gbBorderColumnSkip = 0;
|
||||
gbBorderRowSkip = 0;
|
||||
}
|
||||
|
||||
if(gbBorderOn)
|
||||
{
|
||||
srcWidth = 256;
|
||||
srcHeight = 224;
|
||||
gbBorderLineSkip = 256;
|
||||
gbBorderColumnSkip = 48;
|
||||
gbBorderRowSkip = 40;
|
||||
}
|
||||
else
|
||||
{
|
||||
srcWidth = 160;
|
||||
srcHeight = 144;
|
||||
gbBorderLineSkip = 160;
|
||||
gbBorderColumnSkip = 0;
|
||||
gbBorderRowSkip = 0;
|
||||
}
|
||||
|
||||
loaded = LoadGBROM();
|
||||
srcPitch = 324;
|
||||
soundSetSampleRate(44100);
|
||||
break;
|
||||
loaded = LoadGBROM();
|
||||
soundSetSampleRate(44100);
|
||||
}
|
||||
|
||||
if(!loaded)
|
||||
@ -960,7 +1243,11 @@ bool LoadVBAROM()
|
||||
else
|
||||
{
|
||||
// Setup GX
|
||||
GX_Render_Init(srcWidth, srcHeight);
|
||||
if (InitialBorder) {
|
||||
GX_Render_Init(InitialBorderWidth, InitialBorderHeight);
|
||||
} else {
|
||||
GX_Render_Init(srcWidth, srcHeight);
|
||||
}
|
||||
|
||||
if (cartridgeType == 1)
|
||||
{
|
||||
@ -1023,9 +1310,9 @@ void InitialisePalette()
|
||||
// Build GBPalette
|
||||
for( i = 0; i < 24; )
|
||||
{
|
||||
systemGbPalette[i++] = (0x1f) | (0x1f << 5) | (0x1f << 10);
|
||||
systemGbPalette[i++] = (0x15) | (0x15 << 5) | (0x15 << 10);
|
||||
systemGbPalette[i++] = (0x0c) | (0x0c << 5) | (0x0c << 10);
|
||||
systemGbPalette[i++] = (0x1c) | (0x1e << 5) | (0x1c << 10);
|
||||
systemGbPalette[i++] = (0x10) | (0x17 << 5) | (0x0b << 10);
|
||||
systemGbPalette[i++] = (0x27) | (0x0c << 5) | (0x0a << 10);
|
||||
systemGbPalette[i++] = 0;
|
||||
}
|
||||
// Set palette etc - Fixed to RGB565
|
||||
|
@ -28,5 +28,6 @@ bool LoadBatteryOrState(char * filepath, int action, bool silent);
|
||||
bool LoadBatteryOrStateAuto(int action, bool silent);
|
||||
bool SaveBatteryOrState(char * filepath, int action, bool silent);
|
||||
bool SaveBatteryOrStateAuto(int action, bool silent);
|
||||
bool SavePreviewImg (char * filepath, bool silent);
|
||||
|
||||
#endif
|
||||
|
183
source/video.cpp
@ -11,6 +11,7 @@
|
||||
|
||||
#include <gccore.h>
|
||||
#include <ogcsys.h>
|
||||
#include <ogc/machine/processor.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -19,6 +20,7 @@
|
||||
#include "vbagx.h"
|
||||
#include "menu.h"
|
||||
#include "input.h"
|
||||
#include "vbasupport.h"
|
||||
|
||||
s32 CursorX, CursorY;
|
||||
bool CursorVisible;
|
||||
@ -41,6 +43,11 @@ int gameScreenPngSize = 0;
|
||||
int screenheight = 480;
|
||||
int screenwidth = 640;
|
||||
|
||||
u16 *InitialBorder = NULL;
|
||||
int InitialBorderWidth = 0;
|
||||
int InitialBorderHeight = 0;
|
||||
bool SGBBorderLoadedFromGame = false;
|
||||
|
||||
/*** 3D GX ***/
|
||||
#define DEFAULT_FIFO_SIZE ( 256 * 1024 )
|
||||
static u8 gp_fifo[DEFAULT_FIFO_SIZE] ATTRIBUTE_ALIGN(32);
|
||||
@ -160,7 +167,7 @@ static inline void draw_init(void)
|
||||
|
||||
GX_InitTexObj(&texobj, texturemem, vwidth, vheight, GX_TF_RGB565,
|
||||
GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||
if (!(GCSettings.render&1))
|
||||
if (GCSettings.render == 2)
|
||||
GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,2.5,9.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1); // original/unfiltered video mode: force texture filtering OFF
|
||||
}
|
||||
|
||||
@ -246,7 +253,7 @@ static inline void draw_cursor(Mtx v)
|
||||
|
||||
GX_InitTexObj(&texobj, texturemem, vwidth, vheight, GX_TF_RGB565,
|
||||
GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||
if (!(GCSettings.render&1))
|
||||
if (GCSettings.render == 2)
|
||||
GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,2.5,9.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1); // original/unfiltered video mode: force texture filtering OFF
|
||||
}
|
||||
#endif
|
||||
@ -290,6 +297,12 @@ static GXRModeObj * FindVideoMode()
|
||||
case 4: // PAL (60Hz)
|
||||
mode = &TVEurgb60Hz480IntDf;
|
||||
break;
|
||||
case 5: // NTSC (240p)
|
||||
mode = &TVNtsc240Ds;
|
||||
break;
|
||||
case 6: // PAL (60Hz 240p)
|
||||
mode = &TVEurgb60Hz240Ds;
|
||||
break;
|
||||
default:
|
||||
mode = VIDEO_GetPreferredMode(NULL);
|
||||
|
||||
@ -316,7 +329,7 @@ static GXRModeObj * FindVideoMode()
|
||||
if (mode == &TVPal576IntDfScale)
|
||||
pal = true;
|
||||
|
||||
if (CONF_GetAspectRatio() == CONF_ASPECT_16_9)
|
||||
/*if (CONF_GetAspectRatio() == CONF_ASPECT_16_9 && mode->xfbHeight != 240)
|
||||
{
|
||||
if (pal)
|
||||
{
|
||||
@ -334,9 +347,9 @@ static GXRModeObj * FindVideoMode()
|
||||
mode->efbHeight = 456;
|
||||
mode->viWidth = 686;
|
||||
}
|
||||
else
|
||||
else*/
|
||||
{
|
||||
mode->viWidth = 672;
|
||||
mode->viWidth = 704;
|
||||
}
|
||||
|
||||
if (pal)
|
||||
@ -453,10 +466,7 @@ static inline void UpdateScaling()
|
||||
TvAspectRatio = 4.0f/3.0f;
|
||||
#endif
|
||||
|
||||
if (vwidth == 240) // GBA
|
||||
GameboyAspectRatio = 240.0f/160.0f; // assumes square pixels on GB Advance
|
||||
else // GB or GBC
|
||||
GameboyAspectRatio = 160.0f/144.0f; // assumes square pixels on GB Colour
|
||||
GameboyAspectRatio = ((vwidth * 1.0) / vheight);
|
||||
|
||||
if (TvAspectRatio>GameboyAspectRatio)
|
||||
{
|
||||
@ -476,17 +486,37 @@ static inline void UpdateScaling()
|
||||
}
|
||||
|
||||
// change zoom
|
||||
if (vwidth == 240) // GBA
|
||||
float zoomHor, zoomVert;
|
||||
int fixed;
|
||||
if (cartridgeType == 2) // GBA
|
||||
{
|
||||
xscale *= GCSettings.gbaZoomHor;
|
||||
yscale *= GCSettings.gbaZoomVert;
|
||||
zoomHor = GCSettings.gbaZoomHor;
|
||||
zoomVert = GCSettings.gbaZoomVert;
|
||||
fixed = GCSettings.gbaFixed;
|
||||
}
|
||||
else
|
||||
{
|
||||
xscale *= GCSettings.gbZoomHor;
|
||||
yscale *= GCSettings.gbZoomVert;
|
||||
zoomHor = GCSettings.gbZoomHor;
|
||||
zoomVert = GCSettings.gbZoomVert;
|
||||
fixed = GCSettings.gbFixed;
|
||||
}
|
||||
|
||||
if (fixed) {
|
||||
xscale = 320;
|
||||
yscale = 240;
|
||||
} else {
|
||||
xscale *= zoomHor;
|
||||
yscale *= zoomVert;
|
||||
}
|
||||
|
||||
#ifdef HW_RVL
|
||||
if (fixed && CONF_GetAspectRatio() == CONF_ASPECT_16_9 && (*(u32*)(0xCD8005A0) >> 16) == 0xCAFE) // Wii U
|
||||
{
|
||||
/* vWii widescreen patch by tueidj */
|
||||
write32(0xd8006a0, fixed ? 0x30000002 : 0x30000004), mask32(0xd8006a8, 0, 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set new aspect
|
||||
square[0] = square[9] = -xscale + GCSettings.xshift;
|
||||
square[3] = square[6] = xscale + GCSettings.xshift;
|
||||
@ -498,7 +528,23 @@ static inline void UpdateScaling()
|
||||
|
||||
memset(&view, 0, sizeof(Mtx));
|
||||
guLookAt(view, &cam.pos, &cam.up, &cam.view);
|
||||
GX_SetViewport(0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1);
|
||||
if (fixed) {
|
||||
int ratio = fixed % 10;
|
||||
bool widescreen = fixed / 10;
|
||||
|
||||
float vw = vwidth * ratio;
|
||||
if (widescreen) vw /= 4.0 / 3.0;
|
||||
float vh = vheight * ratio;
|
||||
|
||||
// 240p adjustment
|
||||
if (GCSettings.videomode == 5 || GCSettings.videomode == 6) vw *= 2;
|
||||
|
||||
float vx = (vmode->fbWidth - vw) / 2;
|
||||
float vy = (vmode->efbHeight - vh) / 2;
|
||||
GX_SetViewport(vx, vy, vw, vh, 0, 1);
|
||||
} else {
|
||||
GX_SetViewport(0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1);
|
||||
}
|
||||
|
||||
updateScaling = 0;
|
||||
}
|
||||
@ -523,7 +569,13 @@ ResetVideo_Emu ()
|
||||
|
||||
GX_SetDispCopySrc (0, 0, rmode->fbWidth, rmode->efbHeight);
|
||||
GX_SetDispCopyDst (rmode->fbWidth, rmode->xfbHeight);
|
||||
GX_SetCopyFilter (rmode->aa, rmode->sample_pattern, (GCSettings.render == 1) ? GX_TRUE : GX_FALSE, rmode->vfilter); // deflickering filter only for filtered mode
|
||||
u8 sharp[7] = {0,0,21,22,21,0,0};
|
||||
u8 soft[7] = {8,8,10,12,10,8,8};
|
||||
u8* vfilter =
|
||||
GCSettings.render == 3 ? sharp
|
||||
: GCSettings.render == 4 ? soft
|
||||
: rmode->vfilter;
|
||||
GX_SetCopyFilter (rmode->aa, rmode->sample_pattern, (GCSettings.render != 2) ? GX_TRUE : GX_FALSE, vfilter); // deflickering filter only for filtered mode
|
||||
|
||||
GX_SetFieldMode (rmode->field_rendering, ((rmode->viHeight == 2 * rmode->xfbHeight) ? GX_ENABLE : GX_DISABLE));
|
||||
|
||||
@ -542,7 +594,7 @@ ResetVideo_Emu ()
|
||||
// reinitialize texture
|
||||
GX_InvalidateTexAll ();
|
||||
GX_InitTexObj (&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE); // initialize the texture obj we are going to use
|
||||
if (!(GCSettings.render&1))
|
||||
if (GCSettings.render == 2)
|
||||
GX_InitTexObjLOD(&texobj,GX_NEAR,GX_NEAR_MIP_NEAR,2.5,9.0,0.0,GX_FALSE,GX_FALSE,GX_ANISO_1); // original/unfiltered video mode: force texture filtering OFF
|
||||
|
||||
GX_Flush();
|
||||
@ -569,26 +621,55 @@ void GX_Render_Init(int width, int height)
|
||||
vheight = height;
|
||||
}
|
||||
|
||||
bool borderAreaEmpty(const u16* buffer) {
|
||||
u16 reference = buffer[0];
|
||||
for (int y=0; y<40; y++) {
|
||||
for (int x=0; x<256; x++) {
|
||||
if (buffer[258*y + x] != reference) return false;
|
||||
}
|
||||
}
|
||||
for (int y=40; y<184; y++) {
|
||||
for (int x=0; x<48; x++) {
|
||||
if (buffer[258*y + x] != reference) return false;
|
||||
}
|
||||
for (int x=208; x<224; x++) {
|
||||
if (buffer[258*y + x] != reference) return false;
|
||||
}
|
||||
}
|
||||
for (int y=184; y<224; y++) {
|
||||
for (int x=0; x<256; x++) {
|
||||
if (buffer[258*y + x] != reference) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* GX_Render
|
||||
*
|
||||
* Pass in a buffer, width and height to update as a tiled RGB565 texture
|
||||
* (2 bytes per pixel)
|
||||
****************************************************************************/
|
||||
void GX_Render(int width, int height, u8 * buffer, int pitch)
|
||||
void GX_Render(int gbWidth, int gbHeight, u8 * buffer)
|
||||
{
|
||||
int borderWidth = InitialBorder ? InitialBorderWidth : gbWidth;
|
||||
int borderHeight = InitialBorder ? InitialBorderHeight : gbHeight;
|
||||
|
||||
int h, w;
|
||||
long long int *dst = (long long int *) texturemem;
|
||||
int gbPitch = gbWidth * 2 + 4;
|
||||
long long int *dst = (long long int *) texturemem; // Pointer in 8-byte units / 4-pixel units
|
||||
long long int *src1 = (long long int *) buffer;
|
||||
long long int *src2 = (long long int *) (buffer + pitch);
|
||||
long long int *src3 = (long long int *) (buffer + (pitch << 1));
|
||||
long long int *src4 = (long long int *) (buffer + (pitch * 3));
|
||||
int rowpitch = (pitch >> 3) * 3;
|
||||
int rowadjust = ( pitch % 8 ) << 2;
|
||||
long long int *src2 = (long long int *) (buffer + gbPitch);
|
||||
long long int *src3 = (long long int *) (buffer + (gbPitch << 1));
|
||||
long long int *src4 = (long long int *) (buffer + (gbPitch * 3));
|
||||
int srcrowpitch = (gbPitch >> 3) * 3;
|
||||
int srcrowadjust = ( gbPitch % 8 ) << 2;
|
||||
int dstrowpitch = borderWidth - gbWidth;
|
||||
|
||||
vwidth = width;
|
||||
vheight = height;
|
||||
vwidth = borderWidth;
|
||||
vheight = borderHeight;
|
||||
|
||||
int vwid2 = (vwidth >> 2);
|
||||
int vwid2 = (gbWidth >> 2);
|
||||
char *ra = NULL;
|
||||
|
||||
// Ensure previous vb has complete
|
||||
@ -606,7 +687,26 @@ void GX_Render(int width, int height, u8 * buffer, int pitch)
|
||||
GX_SetTevOp(GX_TEVSTAGE0, GX_DECAL);
|
||||
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
|
||||
|
||||
for (h = 0; h < vheight; h += 4)
|
||||
if (gbWidth == 256 && gbHeight == 224 && !SGBBorderLoadedFromGame) {
|
||||
if (borderAreaEmpty((u16*)buffer)) {
|
||||
// TODO: don't paint empty SGB border
|
||||
} else {
|
||||
// don't try to load the default border anymore
|
||||
SGBBorderLoadedFromGame = true;
|
||||
SaveSGBBorderIfNoneExists(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// The InitialBorder, if any, should already be properly tiled
|
||||
if (InitialBorder) {
|
||||
memcpy(dst, InitialBorder, borderWidth * borderHeight * 2);
|
||||
|
||||
int rows_to_skip = (borderHeight - gbHeight) / 2;
|
||||
if (rows_to_skip > 0) dst += rows_to_skip * borderWidth / 4;
|
||||
dst += (borderWidth - gbWidth) / 2;
|
||||
}
|
||||
|
||||
for (h = 0; h < gbHeight; h += 4)
|
||||
{
|
||||
for (w = 0; w < vwid2; ++w)
|
||||
{
|
||||
@ -616,21 +716,22 @@ void GX_Render(int width, int height, u8 * buffer, int pitch)
|
||||
*dst++ = *src4++;
|
||||
}
|
||||
|
||||
src1 += rowpitch;
|
||||
src2 += rowpitch;
|
||||
src3 += rowpitch;
|
||||
src4 += rowpitch;
|
||||
src1 += srcrowpitch;
|
||||
src2 += srcrowpitch;
|
||||
src3 += srcrowpitch;
|
||||
src4 += srcrowpitch;
|
||||
dst += dstrowpitch;
|
||||
|
||||
if ( rowadjust )
|
||||
if ( srcrowadjust )
|
||||
{
|
||||
ra = (char *)src1;
|
||||
src1 = (long long int *)(ra + rowadjust);
|
||||
src1 = (long long int *)(ra + srcrowadjust);
|
||||
ra = (char *)src2;
|
||||
src2 = (long long int *)(ra + rowadjust);
|
||||
src2 = (long long int *)(ra + srcrowadjust);
|
||||
ra = (char *)src3;
|
||||
src3 = (long long int *)(ra + rowadjust);
|
||||
src3 = (long long int *)(ra + srcrowadjust);
|
||||
ra = (char *)src4;
|
||||
src4 = (long long int *)(ra + rowadjust);
|
||||
src4 = (long long int *)(ra + srcrowadjust);
|
||||
}
|
||||
}
|
||||
|
||||
@ -690,6 +791,14 @@ void TakeScreenshot()
|
||||
void
|
||||
ResetVideo_Menu ()
|
||||
{
|
||||
#ifdef HW_RVL
|
||||
if (CONF_GetAspectRatio() == CONF_ASPECT_16_9 && (*(u32*)(0xCD8005A0) >> 16) == 0xCAFE) // Wii U
|
||||
{
|
||||
/* vWii widescreen patch by tueidj */
|
||||
write32(0xd8006a0, 0x30000004), mask32(0xd8006a8, 0, 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
Mtx44 p;
|
||||
f32 yscale;
|
||||
u32 xfbHeight;
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
void InitializeVideo ();
|
||||
void GX_Render_Init(int width, int height);
|
||||
void GX_Render(int width, int height, u8 * buffer, int pitch);
|
||||
void GX_Render(int gbWidth, int gbHeight, u8 * buffer);
|
||||
void StopGX();
|
||||
void ResetVideo_Emu();
|
||||
void ResetVideo_Menu();
|
||||
@ -38,4 +38,11 @@ extern u8 * gameScreenPng;
|
||||
extern int gameScreenPngSize;
|
||||
extern u32 FrameTimer;
|
||||
|
||||
char *AllocAndGetPNGBorderPath(const char* title);
|
||||
void SaveSGBBorderIfNoneExists(const void* buffer);
|
||||
extern u16 *InitialBorder;
|
||||
extern int InitialBorderWidth;
|
||||
extern int InitialBorderHeight;
|
||||
extern bool SGBBorderLoadedFromGame;
|
||||
|
||||
#endif
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "vba/gba/Globals.h"
|
||||
#include "vba/Util.h"
|
||||
#include "vba/common/Port.h"
|
||||
#include "goomba/goombarom.h"
|
||||
|
||||
#define MEM_BAD 0xff
|
||||
#define MEM_VM 0x01
|
||||
@ -152,10 +153,9 @@ static void VMAllocGBA( void )
|
||||
* MEM2 version of GBA CPULoadROM
|
||||
****************************************************************************/
|
||||
|
||||
bool VMCPULoadROM()
|
||||
int VMCPULoadROM()
|
||||
{
|
||||
VMClose();
|
||||
VMAllocGBA();
|
||||
GBAROMSize = 0;
|
||||
|
||||
if(!inSz)
|
||||
@ -163,7 +163,7 @@ bool VMCPULoadROM()
|
||||
char filepath[1024];
|
||||
|
||||
if(!MakeFilePath(filepath, FILE_ROM))
|
||||
return false;
|
||||
return 0;
|
||||
|
||||
GBAROMSize = LoadFile ((char *)rom, filepath, browserList[browser.selIndex].length, NOTSILENT);
|
||||
}
|
||||
@ -172,17 +172,26 @@ bool VMCPULoadROM()
|
||||
GBAROMSize = LoadSzFile(szpath, (unsigned char *)rom);
|
||||
}
|
||||
|
||||
if(gb_first_rom(rom, GBAROMSize)) {
|
||||
int r = YesNoPrompt("This file contains uncompressed Game Boy (Color) ROMs. Do you want to run these?", true);
|
||||
if (r) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
VMAllocGBA();
|
||||
|
||||
if(GBAROMSize)
|
||||
{
|
||||
flashInit();
|
||||
eepromInit();
|
||||
CPUUpdateRenderBuffers( true );
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
VMClose();
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -11,7 +11,7 @@
|
||||
#ifndef __VBAVMHDR__
|
||||
#define __VBAVMHDR__
|
||||
|
||||
bool VMCPULoadROM();
|
||||
int VMCPULoadROM();
|
||||
void VMClose();
|
||||
|
||||
#ifdef USE_VM
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<app version="2.2.8">
|
||||
<file url="http://vba-wii.googlecode.com/files/Visual%20Boy%20Advance%20GX%202.2.8.zip"></file>
|
||||
<file url="http://github.com/dborth/vba-wii/releases/download/2.2.8/Visual.Boy.Advance.GX.2.2.8.zip"></file>
|
||||
</app>
|
||||
|