mirror of https://github.com/bsnes-emu/bsnes.git
libretro: Support blargg's NTSC filter
This commit is contained in:
parent
ea05fa0c3e
commit
18afbc3770
|
@ -288,6 +288,31 @@ static void flush_variables()
|
|||
run_ahead_frames = atoi(variable.value);
|
||||
}
|
||||
|
||||
variable = { "bsnes_video_filter", nullptr };
|
||||
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &variable) && variable.value)
|
||||
{
|
||||
if (strcmp(variable.value, "None") == 0) {
|
||||
program->filterRender = &Filter::None::render;
|
||||
program->filterSize = &Filter::None::size;
|
||||
}
|
||||
else if (strcmp(variable.value, "NTSC (RF)") == 0) {
|
||||
program->filterRender = &Filter::NTSC_RF::render;
|
||||
program->filterSize = &Filter::NTSC_RF::size;
|
||||
}
|
||||
else if (strcmp(variable.value, "NTSC (Composite)") == 0) {
|
||||
program->filterRender = &Filter::NTSC_Composite::render;
|
||||
program->filterSize = &Filter::NTSC_Composite::size;
|
||||
}
|
||||
else if (strcmp(variable.value, "NTSC (S-Video)") == 0) {
|
||||
program->filterRender = &Filter::NTSC_SVideo::render;
|
||||
program->filterSize = &Filter::NTSC_SVideo::size;
|
||||
}
|
||||
else if (strcmp(variable.value, "NTSC (RGB)") == 0) {
|
||||
program->filterRender = &Filter::NTSC_RGB::render;
|
||||
program->filterSize = &Filter::NTSC_RGB::size;
|
||||
}
|
||||
}
|
||||
|
||||
// Refresh Geometry
|
||||
struct retro_system_av_info avinfo;
|
||||
retro_get_system_av_info(&avinfo);
|
||||
|
@ -483,6 +508,7 @@ static void set_environment_info(retro_environment_t cb)
|
|||
{ "bsnes_coprocessor_prefer_hle", "Coprocessor Prefer HLE; ON|OFF" },
|
||||
{ "bsnes_sgb_bios", "Preferred Super GameBoy BIOS (restart); SGB1.sfc|SGB2.sfc" },
|
||||
{ "bsnes_run_ahead_frames", "Amount of frames for run-ahead; OFF|1|2|3|4" },
|
||||
{ "bsnes_video_filter", "Video Filter; None|NTSC (RF)|NTSC (Composite)|NTSC (S-Video)|NTSC (RGB)" },
|
||||
{ nullptr },
|
||||
};
|
||||
cb(RETRO_ENVIRONMENT_SET_VARIABLES, const_cast<retro_variable *>(vars));
|
||||
|
@ -653,13 +679,14 @@ RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code)
|
|||
|
||||
RETRO_API bool retro_load_game(const retro_game_info *game)
|
||||
{
|
||||
// bsnes uses 0RGB1555 internally but it is deprecated
|
||||
// let software conversion happen in frontend
|
||||
/*retro_pixel_format fmt = RETRO_PIXEL_FORMAT_0RGB1555;
|
||||
retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
|
||||
if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
|
||||
return false;*/
|
||||
return false;
|
||||
|
||||
emulator->configure("Audio/Frequency", SAMPLERATE);
|
||||
program->filterRender = &Filter::None::render;
|
||||
program->filterSize = &Filter::None::size;
|
||||
program->updateVideoPalette();
|
||||
|
||||
flush_variables();
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ struct Program : Emulator::Platform
|
|||
auto openRomBSMemory(string name, vfs::file::mode mode) -> shared_pointer<vfs::file>;
|
||||
|
||||
auto hackPatchMemory(vector<uint8_t>& data) -> void;
|
||||
auto updateVideoPalette() -> void;
|
||||
|
||||
string base_name;
|
||||
|
||||
|
@ -79,6 +80,13 @@ public:
|
|||
struct BSMemory : Game {
|
||||
vector<uint8_t> program;
|
||||
} bsMemory;
|
||||
|
||||
uint32_t palette[32768];
|
||||
uint32_t paletteDimmed[32768];
|
||||
uint32_t videoOut[2304*2160];
|
||||
|
||||
Filter::Render filterRender;
|
||||
Filter::Size filterSize;
|
||||
};
|
||||
|
||||
static Program *program = nullptr;
|
||||
|
@ -157,6 +165,59 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) ->
|
|||
return result;
|
||||
}
|
||||
|
||||
auto Program::updateVideoPalette() -> void {
|
||||
double luminance = 100.0 / 100.0;
|
||||
double saturation = 100.0 / 100.0;
|
||||
double gamma = 150.0 / 100.0;
|
||||
|
||||
uint depth = 24;
|
||||
|
||||
for(uint color : range(32768)) {
|
||||
uint16 r = (color >> 10) & 31;
|
||||
uint16 g = (color >> 5) & 31;
|
||||
uint16 b = (color >> 0) & 31;
|
||||
|
||||
r = r << 3 | r >> 2; r = r << 8 | r << 0;
|
||||
g = g << 3 | g >> 2; g = g << 8 | g << 0;
|
||||
b = b << 3 | b >> 2; b = b << 8 | b << 0;
|
||||
|
||||
if(saturation != 1.0) {
|
||||
uint16 grayscale = uclamp<16>((r + g + b) / 3);
|
||||
double inverse = max(0.0, 1.0 - saturation);
|
||||
r = uclamp<16>(r * saturation + grayscale * inverse);
|
||||
g = uclamp<16>(g * saturation + grayscale * inverse);
|
||||
b = uclamp<16>(b * saturation + grayscale * inverse);
|
||||
}
|
||||
|
||||
if(gamma != 1.0) {
|
||||
double reciprocal = 1.0 / 32767.0;
|
||||
r = r > 32767 ? r : uint16(32767 * pow(r * reciprocal, gamma));
|
||||
g = g > 32767 ? g : uint16(32767 * pow(g * reciprocal, gamma));
|
||||
b = b > 32767 ? b : uint16(32767 * pow(b * reciprocal, gamma));
|
||||
}
|
||||
|
||||
if(luminance != 1.0) {
|
||||
r = uclamp<16>(r * luminance);
|
||||
g = uclamp<16>(g * luminance);
|
||||
b = uclamp<16>(b * luminance);
|
||||
}
|
||||
|
||||
switch(depth) {
|
||||
case 24: palette[color] = r >> 8 << 16 | g >> 8 << 8 | b >> 8 << 0; break;
|
||||
case 30: palette[color] = r >> 6 << 20 | g >> 6 << 10 | b >> 6 << 0; break;
|
||||
}
|
||||
|
||||
r >>= 1;
|
||||
g >>= 1;
|
||||
b >>= 1;
|
||||
|
||||
switch(depth) {
|
||||
case 24: paletteDimmed[color] = r >> 8 << 16 | g >> 8 << 8 | b >> 8 << 0; break;
|
||||
case 30: paletteDimmed[color] = r >> 6 << 20 | g >> 6 << 10 | b >> 6 << 0; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto Program::load() -> void {
|
||||
emulator->unload();
|
||||
emulator->load();
|
||||
|
@ -227,12 +288,12 @@ auto Program::load(uint id, string name, string type, vector<string> options) ->
|
|||
{
|
||||
if (loadGameBoy(gameBoy.location))
|
||||
{
|
||||
return { id, NULL };
|
||||
return { id, "" };
|
||||
}
|
||||
}
|
||||
else if (id == 3) {
|
||||
if (loadBSMemory(bsMemory.location)) {
|
||||
return { id, NULL };
|
||||
return { id, "" };
|
||||
}
|
||||
}
|
||||
return { id, options(0) };
|
||||
|
@ -245,7 +306,20 @@ auto Program::videoFrame(const uint16* data, uint pitch, uint width, uint height
|
|||
data += 8 * (pitch >> 1) * multiplier;
|
||||
height -= 16 * multiplier;
|
||||
}
|
||||
video_cb(data, width, height, pitch);
|
||||
|
||||
uint filterWidth = width, filterHeight = height;
|
||||
|
||||
filterSize(filterWidth, filterHeight);
|
||||
|
||||
// Scale the NTSC filter properly for HD Mode 7
|
||||
if ((scale > 1) && (filterWidth == 602))
|
||||
{
|
||||
filterWidth = 301 * scale;
|
||||
}
|
||||
|
||||
filterRender(palette, videoOut, filterWidth << 2, (const uint16_t*)data, pitch, width, height);
|
||||
|
||||
video_cb(videoOut, filterWidth, filterHeight, filterWidth << 2);
|
||||
}
|
||||
|
||||
// Double the fun!
|
||||
|
|
Loading…
Reference in New Issue