Compare commits
No commits in common. "master" and "beta_2024-07-30" have entirely different histories.
master
...
beta_2024-
|
@ -2,6 +2,7 @@ name: C/C++ CI
|
|||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
|
99
README.md
99
README.md
|
@ -8,14 +8,10 @@ open_agb_firm is also a complete and better alternative to GBA VC injects (AGB_F
|
|||
* User configuration, such as gamma settings
|
||||
* Button remapping
|
||||
* Border support for 1:1 scaling mode
|
||||
* Gamma correction to fix the washed out look of games
|
||||
* Color correction to mimic the look of the GBA/DS phat LCD
|
||||
* And more to come!
|
||||
|
||||
Unlike AGB_FIRM open_agb_firm is not affected by the famous bug where the video output wraps around leaving garbled lines at the bottom of the screen. SD cluster size doesn't matter.
|
||||
|
||||
## Disclaimer
|
||||
open_agb_firm is currently in beta. While open_agb_firm is relatively stable and safe to use, some quirks that have not been fixed. See [Known Issues](#known-issues) for more information.
|
||||
open_agb_firm is currently in alpha. While open_agb_firm is relatively stable and safe to use, some quirks that have not been fixed. See [Known Issues](#known-issues) for more information.
|
||||
|
||||
Additionally, we are not responsible for any damage that may occur to your system as a direct or indirect result of you using open_agb_firm.
|
||||
|
||||
|
@ -49,7 +45,7 @@ Settings are stored in `/3ds/open_agb_firm/config.ini`.
|
|||
### General
|
||||
General settings.
|
||||
|
||||
`u8 backlight` - Backlight brightness in luminance (cd/m²).
|
||||
`u8 backlight` - Backlight brightness in luminance (cd/m²)
|
||||
* Default: `64`
|
||||
* Possible values:
|
||||
* Old 3DS: `20`-`117`
|
||||
|
@ -57,56 +53,44 @@ General settings.
|
|||
* Values ≤`64` are recommended.
|
||||
* Hardware calibration from your CTRNAND is required to get the correct brightness for both LCDs.
|
||||
|
||||
`u8 backlightSteps` - How much to adjust backlight brightness by.
|
||||
`u8 backlightSteps` - How much to adjust backlight brightness by
|
||||
* Default: `5`
|
||||
|
||||
`bool directBoot` - Skip GBA BIOS intro at game startup.
|
||||
`bool directBoot` - Skip GBA BIOS intro at game startup
|
||||
* Default: `false`
|
||||
|
||||
`bool useGbaDb` - Use `gba_db.bin` to get save types.
|
||||
* Default: `true`
|
||||
|
||||
`bool useSavesFolder` - Use `/3ds/open_agb_firm/saves` for save files instead of the ROM directory.
|
||||
`bool useGbaDb` - Use `gba_db.bin` to get save types
|
||||
* Default: `true`
|
||||
|
||||
### Video
|
||||
Video-related settings.
|
||||
|
||||
`string scaler` - Video scaler.
|
||||
* Default: `matrix`
|
||||
* Options: `none`, `bilinear`, `matrix`
|
||||
`u8 scaler` - Video scaler. 0 = none, 1 = bilinear, 2 = hardware.
|
||||
* Default: `2`
|
||||
|
||||
`string colorProfile` - Color correction profile.
|
||||
* Default: `none`
|
||||
* Options:
|
||||
* `none` Disable all color correction options.
|
||||
* `gba` Game Boy Advance.
|
||||
* `gb_micro` Game Boy micro.
|
||||
* `gba_sp101` Game Boy Advance SP (AGS-101).
|
||||
* `nds` Nintendo DS (DS phat).
|
||||
* `ds_lite` Nintendo DS lite.
|
||||
* `nso` Nintendo Switch Online.
|
||||
* `vba` Visual Boy Advance/No$GBA full.
|
||||
* `identity` No color space conversion.
|
||||
* If you just want less saturated colors or to change other basic settings like contrast or brightness then set this to `identity`.
|
||||
* Due to most 2/3DS LCDs not being calibrated correctly from factory the look may not match exactly what you see on real hardware.
|
||||
* Due to a lot of extra RAM access and extra CPU processing per frame, battery runtime is affected with color profiles other than `none`.
|
||||
`float gbaGamma` - GBA input gamma
|
||||
* Default: `2.2`
|
||||
|
||||
`float contrast` - Screen gain. No effect when `colorProfile=none`.
|
||||
`float lcdGamma` - Output LCD gamma
|
||||
* Default : `1.54`
|
||||
|
||||
`float contrast` - Screen gain
|
||||
* Default: `1.0`
|
||||
|
||||
`float brightness` - Screen lift. No effect when `colorProfile=none`.
|
||||
`float brightness` - Screen lift
|
||||
* Default: `0.0`
|
||||
|
||||
`float saturation` - Screen saturation. No effect when `colorProfile=none`.
|
||||
* Default: `1.0`
|
||||
`string colorProfile` - Color correction profile. `none`, `gba`, `nds` or `nds_white`.
|
||||
* Default: `none`
|
||||
* For the gba profile it's recommended to adjust lcdGamma to match a GBA. For New 3DS XL with IPS LCD roughly 1.8 is good.
|
||||
* Due to most 2/3DS LCDs not being calibrated correctly from factory the look may not match exactly what you see on a real GBA.
|
||||
* Due to a lot of extra RAM access and up to 6.3 ms (worst case for scaler=2) of extra CPU processing time per frame, battery run time is affected with color profiles other than none.
|
||||
|
||||
### Audio
|
||||
Audio settings.
|
||||
|
||||
`string audioOut` - Audio output.
|
||||
* Default: `auto`
|
||||
* Options: `auto`, `speakers`, `headphones`
|
||||
`u8 audioOut` - Audio output. 0 = auto, 1 = speakers, 2 = headphones.
|
||||
* Default: `0`
|
||||
|
||||
`s8 volume` - Audio volume. Values above 48 mean control via volume slider. Range -128 (muted) to -20 (100%). Avoid the range -19 to 48.
|
||||
* Default: `127`
|
||||
|
@ -148,7 +132,7 @@ Note that button mappings can cause input lag of up to 1 frame depending on when
|
|||
`L` - Button map for the L button.
|
||||
* Default: `none`
|
||||
|
||||
Example which maps the D-Pad and Circle-Pad to the GBA D-Pad:
|
||||
Example:
|
||||
```
|
||||
[input]
|
||||
RIGHT=RIGHT,CP_RIGHT
|
||||
|
@ -160,38 +144,29 @@ DOWN=DOWN,CP_DOWN
|
|||
### Game
|
||||
Game-specific settings. Only intended to be used in the per-game settings (romName.ini in `/3ds/open_agb_firm/saves`).
|
||||
|
||||
`u8 saveSlot` - Savegame slot (0-9).
|
||||
`u8 saveSlot` - Savegame slot (0-9)
|
||||
* Default: `0`
|
||||
|
||||
`string saveType` - Override to use a specific save type.
|
||||
* Default: `auto`
|
||||
* Options starting with `rom_256m` are intended for 32 MiB games. Options ending with `rtc` enable the hardware real-time clock:
|
||||
* `eeprom_8k`
|
||||
* `rom_256m_eeprom_8k`
|
||||
* `eeprom_64k`
|
||||
* `rom_256m_eeprom_64k`
|
||||
* `flash_512k_atmel_rtc`
|
||||
* `flash_512k_atmel`
|
||||
* `flash_512k_sst_rtc`
|
||||
* `flash_512k_sst`
|
||||
* `flash_512k_panasonic_rtc`
|
||||
* `flash_512k_panasonic`
|
||||
* `flash_1m_macronix_rtc`
|
||||
* `flash_1m_macronix`
|
||||
* `flash_1m_sanyo_rtc`
|
||||
* `flash_1m_sanyo`
|
||||
* `sram_256k`
|
||||
* `none`
|
||||
* `auto`
|
||||
`u8 saveType` - Override to use a specific save type, see values for `defaultSave` (0-15, 255)
|
||||
* Default: `255` (disabled)
|
||||
|
||||
### Advanced
|
||||
Options for advanced users. No pun intended.
|
||||
|
||||
`bool saveOverride` - Open save type override menu after selecting a game.
|
||||
`bool saveOverride` - Open save type override menu after selecting a game
|
||||
* Default: `false`
|
||||
|
||||
`string defaultSave` - Save type default when save type is not in `gba_db.bin` and cannot be autodetected. Same options as for `saveType` above except `auto` is not supported.
|
||||
* Default: `sram_256k`
|
||||
`u16 defaultSave` - Change save type default when save type is not in `gba_db.bin` and cannot be autodetected
|
||||
* Default: `14` (SRAM 256k)
|
||||
* Possible values:
|
||||
* `0`, `1`: EEPROM 8k
|
||||
* `2`, `3`: EEPROM 64k
|
||||
* `4`, `6`, `8`: Flash 512k RTC
|
||||
* `5`, `7`, `9`: Flash 512k
|
||||
* `10`, `12`: Flash 1m RTC
|
||||
* `11`, `13`: Flash 1m
|
||||
* `14`: SRAM 256k
|
||||
* `15`: None
|
||||
|
||||
## Patches
|
||||
open_agb_firm supports automatically applying IPS and UPS patches. To use a patch, rename the patch file to match the ROM file name (without the extension).
|
||||
|
|
|
@ -39,14 +39,14 @@ typedef struct
|
|||
u8 backlightSteps;
|
||||
bool directBoot;
|
||||
bool useGbaDb;
|
||||
bool useSavesFolder;
|
||||
|
||||
// [video]
|
||||
u8 scaler; // 0 = 1:1/none, 1 = bilinear (GPU) x1.5, 2 = matrix (hardware) x1.5.
|
||||
u8 colorProfile; // 0 = none, 1 = GBA, 2 = GB micro, 3 = GBA SP (AGS-101), 4 = DS phat, 5 = DS lite, 6 = Nintendo Switch Online, 7 = Visual Boy Advance/No$GBA, 8 = identity.
|
||||
float contrast; // Range 0.0-1.0.
|
||||
float brightness; // Range 0.0-1.0.
|
||||
float saturation; // Range 0.0-1.0.
|
||||
u8 scaler; // 0 = 1:1, 1 = bilinear (GPU) x1.5, 2 = matrix (hardware) x1.5.
|
||||
float gbaGamma;
|
||||
float lcdGamma;
|
||||
float contrast;
|
||||
float brightness;
|
||||
u8 colorProfile; // 0 = none, 1 = GBA, 2 = DS phat, 3 = DS phat white.
|
||||
|
||||
// [audio]
|
||||
u8 audioOut; // 0 = auto, 1 = speakers, 2 = headphones.
|
||||
|
@ -62,10 +62,11 @@ typedef struct
|
|||
|
||||
// [advanced]
|
||||
bool saveOverride;
|
||||
u16 defaultSave; // TODO: Should be u8. Investigate if u8 has any downsides.
|
||||
u16 defaultSave;
|
||||
} OafConfig;
|
||||
//static_assert(sizeof(OafConfig) == 76, "nope");
|
||||
|
||||
extern OafConfig g_oafConfig; // Global config in config.c.
|
||||
extern OafConfig g_oafConfig;
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f6717f66858634b677ed695ee346a89db7684b43
|
||||
Subproject commit 6259b6b8ffe4bf82481dc93aeadbcc96738c2b9f
|
|
@ -30,23 +30,20 @@
|
|||
"backlight=64\n" \
|
||||
"backlightSteps=5\n" \
|
||||
"directBoot=false\n" \
|
||||
"useGbaDb=true\n" \
|
||||
"useSavesFolder=true\n\n" \
|
||||
\
|
||||
"useGbaDb=true\n\n" \
|
||||
"[video]\n" \
|
||||
"scaler=matrix\n" \
|
||||
"colorProfile=none\n" \
|
||||
"scaler=2\n" \
|
||||
"gbaGamma=2.2\n" \
|
||||
"lcdGamma=1.54\n" \
|
||||
"contrast=1.0\n" \
|
||||
"brightness=0.0\n" \
|
||||
"saturation=1.0\n\n" \
|
||||
\
|
||||
"colorProfile=none\n\n" \
|
||||
"[audio]\n" \
|
||||
"audioOut=auto\n" \
|
||||
"audioOut=0\n" \
|
||||
"volume=127\n\n" \
|
||||
\
|
||||
"[advanced]\n" \
|
||||
"saveOverride=false\n" \
|
||||
"defaultSave=sram_256k"
|
||||
"defaultSave=14"
|
||||
|
||||
|
||||
|
||||
|
@ -58,14 +55,14 @@ OafConfig g_oafConfig =
|
|||
5, // backlightSteps
|
||||
false, // directBoot
|
||||
true, // useGbaDb
|
||||
true, // useSavesFolder
|
||||
|
||||
// [video]
|
||||
2, // scaler
|
||||
0, // colorProfile
|
||||
2.2f, // gbaGamma
|
||||
1.54f, // lcdGamma
|
||||
1.f, // contrast
|
||||
0.f, // brightness
|
||||
1.f, // saturation
|
||||
0, // colorProfile
|
||||
|
||||
// [audio]
|
||||
0, // Automatic audio output.
|
||||
|
@ -87,7 +84,7 @@ OafConfig g_oafConfig =
|
|||
|
||||
// [game]
|
||||
0, // saveSlot
|
||||
255, // saveType
|
||||
0xFF, // saveType
|
||||
|
||||
// [advanced]
|
||||
false, // saveOverride
|
||||
|
@ -132,7 +129,7 @@ static u32 parseButtons(const char *str)
|
|||
return map & ~(1u<<12);
|
||||
}
|
||||
|
||||
static int cfgIniCallback(void *user, const char *section, const char *name, const char *value)
|
||||
static int cfgIniCallback(void* user, const char* section, const char* name, const char* value)
|
||||
{
|
||||
OafConfig *const config = (OafConfig*)user;
|
||||
|
||||
|
@ -146,61 +143,37 @@ static int cfgIniCallback(void *user, const char *section, const char *name, con
|
|||
config->directBoot = (strcmp(value, "false") == 0 ? false : true);
|
||||
else if(strcmp(name, "useGbaDb") == 0)
|
||||
config->useGbaDb = (strcmp(value, "true") == 0 ? true : false);
|
||||
else if(strcmp(name, "useSavesFolder") == 0)
|
||||
config->useSavesFolder = (strcmp(value, "true") == 0 ? true : false);
|
||||
}
|
||||
else if(strcmp(section, "video") == 0)
|
||||
{
|
||||
if(strcmp(name, "scaler") == 0)
|
||||
{
|
||||
if(strcmp(value, "none") == 0)
|
||||
config->scaler = 0;
|
||||
else if(strcmp(value, "bilinear") == 0)
|
||||
config->scaler = 1;
|
||||
else if(strcmp(value, "matrix") == 0)
|
||||
config->scaler = 2;
|
||||
}
|
||||
config->scaler = (u8)strtoul(value, NULL, 10);
|
||||
else if(strcmp(name, "gbaGamma") == 0)
|
||||
config->gbaGamma = str2float(value);
|
||||
else if(strcmp(name, "lcdGamma") == 0)
|
||||
config->lcdGamma = str2float(value);
|
||||
else if(strcmp(name, "contrast") == 0)
|
||||
config->contrast = str2float(value);
|
||||
else if(strcmp(name, "brightness") == 0)
|
||||
config->brightness = str2float(value);
|
||||
else if(strcmp(name, "colorProfile") == 0)
|
||||
{
|
||||
if(strcmp(value, "none") == 0)
|
||||
config->colorProfile = 0;
|
||||
else if(strcmp(value, "gba") == 0)
|
||||
config->colorProfile = 1;
|
||||
else if(strcmp(value, "gb_micro") == 0)
|
||||
config->colorProfile = 2;
|
||||
else if(strcmp(value, "gba_sp101") == 0)
|
||||
config->colorProfile = 3;
|
||||
else if(strcmp(value, "nds") == 0)
|
||||
config->colorProfile = 4;
|
||||
else if(strcmp(value, "ds_lite") == 0)
|
||||
config->colorProfile = 5;
|
||||
else if(strcmp(value, "nso") == 0)
|
||||
config->colorProfile = 6;
|
||||
else if(strcmp(value, "vba") == 0)
|
||||
config->colorProfile = 7;
|
||||
else if(strcmp(value, "identity") == 0)
|
||||
config->colorProfile = 8;
|
||||
config->colorProfile = 2;
|
||||
else if(strcmp(value, "nds_white") == 0)
|
||||
config->colorProfile = 3;
|
||||
//else if(strcmp(value, "custom") == 0) // TODO: Implement user provided profile.
|
||||
// config->colorProfile = 9;
|
||||
// config->colorProfile = 4;
|
||||
}
|
||||
else if(strcmp(name, "contrast") == 0)
|
||||
config->contrast = str2float(value);
|
||||
else if(strcmp(name, "brightness") == 0)
|
||||
config->brightness = str2float(value);
|
||||
else if(strcmp(name, "saturation") == 0)
|
||||
config->saturation = str2float(value);
|
||||
}
|
||||
else if(strcmp(section, "audio") == 0)
|
||||
{
|
||||
if(strcmp(name, "audioOut") == 0)
|
||||
{
|
||||
if(strcmp(value, "auto") == 0)
|
||||
config->audioOut = 0;
|
||||
else if(strcmp(value, "speakers") == 0)
|
||||
config->audioOut = 1;
|
||||
else if(strcmp(value, "headphones") == 0)
|
||||
config->audioOut = 2;
|
||||
}
|
||||
config->audioOut = (u8)strtoul(value, NULL, 10);
|
||||
else if(strcmp(name, "volume") == 0)
|
||||
config->volume = (s8)strtol(value, NULL, 10);
|
||||
}
|
||||
|
@ -220,82 +193,14 @@ static int cfgIniCallback(void *user, const char *section, const char *name, con
|
|||
if(strcmp(name, "saveSlot") == 0)
|
||||
config->saveSlot = (u8)strtoul(value, NULL, 10);
|
||||
if(strcmp(name, "saveType") == 0)
|
||||
{
|
||||
if(strcmp(value, "eeprom_8k") == 0)
|
||||
config->saveType = 0;
|
||||
if(strcmp(value, "rom_256m_eeprom_8k") == 0)
|
||||
config->saveType = 1;
|
||||
if(strcmp(value, "eeprom_64k") == 0)
|
||||
config->saveType = 2;
|
||||
if(strcmp(value, "rom_256m_eeprom_64k") == 0)
|
||||
config->saveType = 3;
|
||||
if(strcmp(value, "flash_512k_atmel_rtc") == 0)
|
||||
config->saveType = 4;
|
||||
if(strcmp(value, "flash_512k_atmel") == 0)
|
||||
config->saveType = 5;
|
||||
if(strcmp(value, "flash_512k_sst_rtc") == 0)
|
||||
config->saveType = 6;
|
||||
if(strcmp(value, "flash_512k_sst") == 0)
|
||||
config->saveType = 7;
|
||||
if(strcmp(value, "flash_512k_panasonic_rtc") == 0)
|
||||
config->saveType = 8;
|
||||
if(strcmp(value, "flash_512k_panasonic") == 0)
|
||||
config->saveType = 9;
|
||||
if(strcmp(value, "flash_1m_macronix_rtc") == 0)
|
||||
config->saveType = 10;
|
||||
if(strcmp(value, "flash_1m_macronix") == 0)
|
||||
config->saveType = 11;
|
||||
if(strcmp(value, "flash_1m_sanyo_rtc") == 0)
|
||||
config->saveType = 12;
|
||||
if(strcmp(value, "flash_1m_sanyo") == 0)
|
||||
config->saveType = 13;
|
||||
if(strcmp(value, "sram_256k") == 0)
|
||||
config->saveType = 14;
|
||||
if(strcmp(value, "none") == 0)
|
||||
config->saveType = 15;
|
||||
if(strcmp(value, "auto") == 0)
|
||||
config->saveType = 255;
|
||||
}
|
||||
config->saveType = (u8)strtoul(value, NULL, 10);
|
||||
}
|
||||
else if(strcmp(section, "advanced") == 0)
|
||||
{
|
||||
if(strcmp(name, "saveOverride") == 0)
|
||||
config->saveOverride = (strcmp(value, "false") == 0 ? false : true);
|
||||
if(strcmp(name, "defaultSave") == 0)
|
||||
{
|
||||
if(strcmp(value, "eeprom_8k") == 0)
|
||||
config->defaultSave = 0;
|
||||
if(strcmp(value, "rom_256m_eeprom_8k") == 0)
|
||||
config->defaultSave = 1;
|
||||
if(strcmp(value, "eeprom_64k") == 0)
|
||||
config->defaultSave = 2;
|
||||
if(strcmp(value, "rom_256m_eeprom_64k") == 0)
|
||||
config->defaultSave = 3;
|
||||
if(strcmp(value, "flash_512k_atmel_rtc") == 0)
|
||||
config->defaultSave = 4;
|
||||
if(strcmp(value, "flash_512k_atmel") == 0)
|
||||
config->defaultSave = 5;
|
||||
if(strcmp(value, "flash_512k_sst_rtc") == 0)
|
||||
config->defaultSave = 6;
|
||||
if(strcmp(value, "flash_512k_sst") == 0)
|
||||
config->defaultSave = 7;
|
||||
if(strcmp(value, "flash_512k_panasonic_rtc") == 0)
|
||||
config->defaultSave = 8;
|
||||
if(strcmp(value, "flash_512k_panasonic") == 0)
|
||||
config->defaultSave = 9;
|
||||
if(strcmp(value, "flash_1m_macronix_rtc") == 0)
|
||||
config->defaultSave = 10;
|
||||
if(strcmp(value, "flash_1m_macronix") == 0)
|
||||
config->defaultSave = 11;
|
||||
if(strcmp(value, "flash_1m_sanyo_rtc") == 0)
|
||||
config->defaultSave = 12;
|
||||
if(strcmp(value, "flash_1m_sanyo") == 0)
|
||||
config->defaultSave = 13;
|
||||
if(strcmp(value, "sram_256k") == 0)
|
||||
config->defaultSave = 14;
|
||||
if(strcmp(value, "none") == 0)
|
||||
config->defaultSave = 15;
|
||||
}
|
||||
config->defaultSave = (u16)strtoul(value, NULL, 10);
|
||||
}
|
||||
else return 0; // Error.
|
||||
|
||||
|
|
|
@ -92,8 +92,7 @@ static Result scanDir(const char *const path, DirList *const dList, const char *
|
|||
const u32 nameLen = strlen(fis[i].fname);
|
||||
if(entType == ENT_TYPE_FILE)
|
||||
{
|
||||
if(nameLen <= filterLen || strcmp(filter, fis[i].fname + nameLen - filterLen) != 0
|
||||
|| fis[i].fname[0] == '.')
|
||||
if(nameLen <= filterLen || strcmp(filter, fis[i].fname + nameLen - filterLen) != 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -126,73 +126,31 @@ typedef struct
|
|||
float displayGamma;
|
||||
} ColorProfile;
|
||||
|
||||
// libretro shader values. Credits: hunterk and Pokefan531.
|
||||
// Last updated 2014-12-03.
|
||||
static const ColorProfile g_colorProfiles[8] =
|
||||
static const ColorProfile g_colorProfiles[3] =
|
||||
{
|
||||
{ // libretro GBA color (sRGB).
|
||||
2.2f + (0.3f * 1.6f), // Darken screen. Default 0. Modified to 0.3.
|
||||
0.91f,
|
||||
0.905f, 0.195f, -0.1f,
|
||||
0.1f, 0.65f, 0.25f,
|
||||
0.1575f, 0.1425f, 0.7f,
|
||||
1.f / 2.2f
|
||||
{ // libretro GBA color (sRGB). Credits: hunterk and Pokefan531.
|
||||
2.f + 0.5f,
|
||||
0.93f,
|
||||
0.8f, 0.275f, -0.075f,
|
||||
0.135f, 0.64f, 0.225f,
|
||||
0.195f, 0.155f, 0.65f,
|
||||
1.f / 2.f
|
||||
},
|
||||
{ // libretro GB micro color (sRGB).
|
||||
2.2f,
|
||||
0.9f,
|
||||
0.8025f, 0.31f, -0.1125f,
|
||||
0.1f, 0.6875f, 0.2125f,
|
||||
0.1225f, 0.1125f, 0.765f,
|
||||
1.f / 2.2f
|
||||
},
|
||||
{ // libretro GBA SP (AGS-101) color (sRGB).
|
||||
2.2f,
|
||||
0.935f,
|
||||
0.96f, 0.11f, -0.07f,
|
||||
0.0325f, 0.89f, 0.0775f,
|
||||
0.001f, -0.03f, 1.029f,
|
||||
1.f / 2.2f
|
||||
},
|
||||
{ // libretro NDS color (sRGB).
|
||||
2.2f,
|
||||
0.905f,
|
||||
0.835f, 0.27f, -0.105f,
|
||||
0.1f, 0.6375f, 0.2625f,
|
||||
0.105f, 0.175f, 0.72f,
|
||||
1.f / 2.2f
|
||||
},
|
||||
{ // libretro NDS lite color (sRGB).
|
||||
2.2f,
|
||||
0.935f,
|
||||
0.93f, 0.14f, -0.07f,
|
||||
0.025f, 0.9f, 0.075f,
|
||||
0.008f, -0.03f, 1.022f,
|
||||
1.f / 2.2f
|
||||
},
|
||||
{ // libretro Nintendo Switch Online color (sRGB).
|
||||
2.2f + 0.8f, // Darken screen. Default 0.8.
|
||||
{ // libretro DS phat (sRGB). Credits: hunterk and Pokefan531.
|
||||
2.f,
|
||||
1.f,
|
||||
0.865f, 0.1225f, 0.0125f,
|
||||
0.0575f, 0.925f, 0.0125f,
|
||||
0.0575f, 0.1225f, 0.82f,
|
||||
1.f / 2.2f
|
||||
0.705f, 0.235f, -0.075f,
|
||||
0.09f, 0.585f, 0.24f,
|
||||
0.1075f, 0.1725f, 0.72f,
|
||||
1.f / 2.f
|
||||
},
|
||||
{ // libretro Visual Boy Advance/No$GBA full color.
|
||||
1.45f + 1.f, // Darken screen. Default 1.
|
||||
1.f,
|
||||
0.73f, 0.27f, 0.f,
|
||||
0.0825f, 0.6775f, 0.24f,
|
||||
0.0825f, 0.24f, 0.6775f,
|
||||
1.f / 1.45f
|
||||
},
|
||||
{ // Identity.
|
||||
1.f,
|
||||
1.f,
|
||||
1.f, 0.f, 0.f,
|
||||
0.f, 1.f, 0.f,
|
||||
0.f, 0.f, 1.f,
|
||||
1.f / 1.f
|
||||
{ // libretro DS phat white (sRGB). Credits: hunterk and Pokefan531.
|
||||
2.f,
|
||||
0.915f,
|
||||
0.815f, 0.275f, -0.09f,
|
||||
0.1f, 0.64f, 0.26f,
|
||||
0.1075f, 0.1725f, 0.72f,
|
||||
1.f / 2.f
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -201,21 +159,9 @@ ALWAYS_INLINE float clamp_float(const float x, const float min, const float max)
|
|||
return (x < min ? min : (x > max ? max : x));
|
||||
}
|
||||
|
||||
void makeColorLut(const ColorProfile *const p)
|
||||
static void makeColorLut(const ColorProfile *const p)
|
||||
{
|
||||
const float targetGamma = p->targetGamma;
|
||||
const float contrast = g_oafConfig.contrast;
|
||||
const float brightness = g_oafConfig.brightness / contrast;
|
||||
const float targetContrast = powf(contrast, targetGamma);
|
||||
|
||||
// Calculate saturation weights.
|
||||
// Note: We are using the Rec. 709 luminance vector here.
|
||||
const float sat = g_oafConfig.saturation;
|
||||
const float rwgt = (1.f - sat) * 0.2126f;
|
||||
const float gwgt = (1.f - sat) * 0.7152f;
|
||||
const float bwgt = (1.f - sat) * 0.0722f;
|
||||
|
||||
u32 *const colorLut = (u32*)COLOR_LUT_ADDR;
|
||||
u32 *colorLut = (u32*)COLOR_LUT_ADDR;
|
||||
for(u32 i = 0; i < 32768; i++)
|
||||
{
|
||||
// Convert to 8-bit and normalize.
|
||||
|
@ -224,9 +170,10 @@ void makeColorLut(const ColorProfile *const p)
|
|||
float r = (float)rgbFive2Eight(i>>10) / 255;
|
||||
|
||||
// Convert to linear gamma.
|
||||
b = powf(b + brightness, targetGamma);
|
||||
g = powf(g + brightness, targetGamma);
|
||||
r = powf(r + brightness, targetGamma);
|
||||
const float targetGamma = p->targetGamma;
|
||||
b = powf(b, targetGamma);
|
||||
g = powf(g, targetGamma);
|
||||
r = powf(r, targetGamma);
|
||||
|
||||
// Apply luminance.
|
||||
const float lum = p->lum;
|
||||
|
@ -246,47 +193,39 @@ void makeColorLut(const ColorProfile *const p)
|
|||
* [rb][gb][ b] [b]
|
||||
*/
|
||||
// Assuming no alpha channel in original calculation.
|
||||
float tmpB = p->rb * r + p->gb * g + p->b * b;
|
||||
float tmpG = p->rg * r + p->g * g + p->bg * b;
|
||||
float tmpR = p->r * r + p->gr * g + p->br * b;
|
||||
float newB = p->rb * r + p->gb * g + p->b * b;
|
||||
float newG = p->rg * r + p->g * g + p->bg * b;
|
||||
float newR = p->r * r + p->gr * g + p->br * b;
|
||||
|
||||
// Apply saturation.
|
||||
// Note: Some duplicated muls here. gcc optimizes them out.
|
||||
b = rwgt * tmpR + gwgt * tmpG + (bwgt + sat) * tmpB;
|
||||
g = rwgt * tmpR + (gwgt + sat) * tmpG + bwgt * tmpB;
|
||||
r = (rwgt + sat) * tmpR + gwgt * tmpG + bwgt * tmpB;
|
||||
|
||||
b = (b < 0.f ? 0.f : b);
|
||||
g = (g < 0.f ? 0.f : g);
|
||||
r = (r < 0.f ? 0.f : r);
|
||||
newB = (newB < 0.f ? 0.f : newB);
|
||||
newG = (newG < 0.f ? 0.f : newG);
|
||||
newR = (newR < 0.f ? 0.f : newR);
|
||||
|
||||
// Convert to display gamma.
|
||||
const float displayGamma = p->displayGamma;
|
||||
b = powf(targetContrast * b, displayGamma);
|
||||
g = powf(targetContrast * g, displayGamma);
|
||||
r = powf(targetContrast * r, displayGamma);
|
||||
newB = powf(newB, displayGamma);
|
||||
newG = powf(newG, displayGamma);
|
||||
newR = powf(newR, displayGamma);
|
||||
|
||||
// Denormalize, clamp, convert to ABGR8 and write lut.
|
||||
u32 entry = 255; // Alpha.
|
||||
entry |= clamp_s32(lroundf(b * 255), 0, 255)<<8;
|
||||
entry |= clamp_s32(lroundf(g * 255), 0, 255)<<16;
|
||||
entry |= clamp_s32(lroundf(r * 255), 0, 255)<<24;
|
||||
colorLut[i] = entry;
|
||||
u32 tmp = 0xFF; // Alpha.
|
||||
tmp |= clamp_s32(lroundf(newB * 255), 0, 255)<<8;
|
||||
tmp |= clamp_s32(lroundf(newG * 255), 0, 255)<<16;
|
||||
tmp |= clamp_s32(lroundf(newR * 255), 0, 255)<<24;
|
||||
*colorLut++ = tmp;
|
||||
}
|
||||
|
||||
flushDCacheRange(colorLut, 4 * 32768);
|
||||
flushDCacheRange((void*)COLOR_LUT_ADDR, 1024u * 128);
|
||||
}
|
||||
|
||||
static Result dumpFrameTex(void)
|
||||
{
|
||||
// Capture a single frame in native resolution.
|
||||
// Note: This adds 1 frame of delay after pressing the screenshot buttons.
|
||||
if(LGYCAP_captureFrameUnscaled(LGYCAP_DEV_TOP) != KRES_OK)
|
||||
return RES_INVALID_ARG;
|
||||
// Stop LgyCap before dumping the frame to prevent glitches.
|
||||
LGYCAP_stop(LGYCAP_DEV_TOP);
|
||||
|
||||
// A1BGR5 format (alpha ignored).
|
||||
constexpr u32 alignment = 0x80; // Make PPF happy.
|
||||
alignas(4) static const BmpV1WithMasks bmpHeaders =
|
||||
alignas(4) static BmpV1WithMasks bmpHeaders =
|
||||
{
|
||||
{
|
||||
.magic = 0x4D42,
|
||||
|
@ -313,12 +252,25 @@ static Result dumpFrameTex(void)
|
|||
.bMask = 0x003E
|
||||
};
|
||||
|
||||
u32 outDim = PPF_DIM(240, 160);
|
||||
u32 fileSize = alignment + 240 * 160 * 2;
|
||||
if(g_oafConfig.scaler > 1)
|
||||
{
|
||||
outDim = PPF_DIM(360, 240);
|
||||
fileSize = alignment + 360 * 240 * 2;
|
||||
|
||||
bmpHeaders.header.fileSize = fileSize;
|
||||
bmpHeaders.dib.width = 360;
|
||||
bmpHeaders.dib.height = -240;
|
||||
bmpHeaders.dib.imageSize = 360 * 240 * 2;
|
||||
}
|
||||
|
||||
// Transfer frame data out of the 512x512 texture.
|
||||
// We will use the currently hidden frame buffer as temporary buffer.
|
||||
// Note: This is a race with the currently displaying frame buffer
|
||||
// because we just swapped buffers in the gfx handler function.
|
||||
u32 *const tmpBuf = GFX_getBuffer(GFX_LCD_TOP, GFX_SIDE_LEFT);
|
||||
GX_displayTransfer((u32*)GPU_TEXTURE_ADDR, PPF_DIM(512, 160), tmpBuf + (alignment / 4), PPF_DIM(240, 160),
|
||||
GX_displayTransfer((u32*)GPU_TEXTURE_ADDR, PPF_DIM(512, 240), tmpBuf + (alignment / 4), outDim,
|
||||
PPF_O_FMT(GX_A1BGR5) | PPF_I_FMT(GX_A1BGR5) | PPF_CROP_EN);
|
||||
memcpy(tmpBuf, &bmpHeaders, sizeof(bmpHeaders));
|
||||
GFX_waitForPPF();
|
||||
|
@ -330,13 +282,8 @@ static Result dumpFrameTex(void)
|
|||
// Construct file path from date & time. Then write the file.
|
||||
char fn[36];
|
||||
ee_sprintf(fn, OAF_SCREENSHOT_DIR "/%04X_%02X_%02X_%02X_%02X_%02X.bmp",
|
||||
td.year + 0x2000, td.mon, td.day, td.hour, td.min, td.sec);
|
||||
const Result res = fsQuickWrite(fn, tmpBuf, bmpHeaders.header.fileSize);
|
||||
|
||||
// Clear overwritten texture area in case we overwrote padding (different resolution).
|
||||
// This is important because padding pixels must be fully transparent to get sharp edges when the GPU renders.
|
||||
GX_memoryFill((u32*)GPU_TEXTURE_ADDR, PSC_FILL_32_BITS, 512 * 160 * 2, 0, NULL, 0, 0, 0);
|
||||
GFX_waitForPSC0();
|
||||
td.y + 0x2000, td.mon, td.d, td.h, td.min, td.s);
|
||||
const Result res = fsQuickWrite(fn, tmpBuf, fileSize);
|
||||
|
||||
// Restart LgyCap.
|
||||
LGYCAP_start(LGYCAP_DEV_TOP);
|
||||
|
|
|
@ -211,23 +211,15 @@ static Result showFileBrowser(char romAndSavePath[512])
|
|||
|
||||
static void rom2GameCfgPath(char romPath[512])
|
||||
{
|
||||
if (g_oafConfig.useSavesFolder)
|
||||
{
|
||||
// Extract the file name and change the extension.
|
||||
// For cfg2SavePath() we need to reserve 2 extra bytes/chars.
|
||||
char tmpIniFileName[256];
|
||||
safeStrcpy(tmpIniFileName, strrchr(romPath, '/') + 1, 256 - 2);
|
||||
strcpy(tmpIniFileName + strlen(tmpIniFileName) - 4, ".ini");
|
||||
// Extract the file name and change the extension.
|
||||
// For cfg2SavePath() we need to reserve 2 extra bytes/chars.
|
||||
char tmpIniFileName[256];
|
||||
safeStrcpy(tmpIniFileName, strrchr(romPath, '/') + 1, 256 - 2);
|
||||
strcpy(tmpIniFileName + strlen(tmpIniFileName) - 4, ".ini");
|
||||
|
||||
// Construct the new path.
|
||||
strcpy(romPath, OAF_SAVE_DIR "/");
|
||||
strcat(romPath, tmpIniFileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Change the extension to .ini.
|
||||
strcpy(romPath + strlen(romPath) - 4, ".ini");
|
||||
}
|
||||
// Construct the new path.
|
||||
strcpy(romPath, OAF_SAVE_DIR "/");
|
||||
strcat(romPath, tmpIniFileName);
|
||||
}
|
||||
|
||||
static void gameCfg2SavePath(char cfgPath[512], const u8 saveSlot)
|
||||
|
|
Loading…
Reference in New Issue