mirror of https://github.com/bsnes-emu/bsnes.git
Update to v084 release.
byuu says: This release adds preliminary Game Boy Color emulation. Due to lack of technical information, this is undoubtedly the least stable module I provide at this time; but improvements should continue as it is developed. This release also polishes the NES emulation and user interface code. Changelog (since v083): - added preliminary Game Boy Color emulation - NES: added MMC6, VRC1, VRC2, VRC3 emulation - NES: fixed MMC5 banking and added split-screen support [Cydrak] - NES: pass all of blargg's ppu_vbl_nmi tests, pass more sprite tests - NES: palette is now generated algorithmically [Bisqwit] - SNES: fixed SA-1 IRQ regression caused by code refactoring - Game Boy: rewrote audio channel mixing code; sound output is greatly improved as a result - Game Boy: uses DMG boot ROM instead of SGB boot ROM - Game Boy: fixed potential bug when loading save states - phoenix: fixed ListView focus issue [X-Fi6] - phoenix: fixed dialog message parsing [X-Fi6] - ui: video output is truly 24-bit now; SNES luma=0 edge case emulated - ui: audio frequency, latency, resampler are now user configurable - ui: gamma ramp is dynamically adjustable - ui: all filters ported to 24-bit mode (speed hit to HQ2x) - ui: added turbo button mappings for all generic controllers - ui: fixed audio volume on unmute via menu [Ver Greeneyes] - ui: shrink window option does nothing when no cartridge is loaded - ui: re-added compositor disable, driver verification from v082
This commit is contained in:
parent
891f1ab7af
commit
01750e9c83
|
@ -1,17 +1,29 @@
|
|||
struct KonamiVRC2 : Board {
|
||||
|
||||
struct Settings {
|
||||
struct Pinout {
|
||||
unsigned a0;
|
||||
unsigned a1;
|
||||
} pinout;
|
||||
} settings;
|
||||
|
||||
VRC2 vrc2;
|
||||
bool latch;
|
||||
|
||||
uint8 prg_read(unsigned addr) {
|
||||
if(addr == 0x6000) return latch;
|
||||
if(addr & 0x8000) return prgrom.read(vrc2.prg_addr(addr));
|
||||
return cpu.mdr();
|
||||
if(addr < 0x6000) return cpu.mdr();
|
||||
if(addr < 0x8000) return vrc2.ram_read(addr);
|
||||
return prgrom.read(vrc2.prg_addr(addr));
|
||||
}
|
||||
|
||||
void prg_write(unsigned addr, uint8 data) {
|
||||
if(addr == 0x6000) latch = data & 0x01;
|
||||
if(addr & 0x8000) return vrc2.reg_write(addr, data);
|
||||
if(addr < 0x6000) return;
|
||||
if(addr < 0x8000) return vrc2.ram_write(addr, data);
|
||||
|
||||
bool a0 = (addr & settings.pinout.a0);
|
||||
bool a1 = (addr & settings.pinout.a1);
|
||||
addr &= 0xfff0;
|
||||
addr |= (a0 << 0) | (a1 << 1);
|
||||
return vrc2.reg_write(addr, data);
|
||||
}
|
||||
|
||||
uint8 chr_read(unsigned addr) {
|
||||
|
@ -30,16 +42,16 @@ void power() {
|
|||
|
||||
void reset() {
|
||||
vrc2.reset();
|
||||
latch = 0;
|
||||
}
|
||||
|
||||
void serialize(serializer &s) {
|
||||
Board::serialize(s);
|
||||
vrc2.serialize(s);
|
||||
s.integer(latch);
|
||||
}
|
||||
|
||||
KonamiVRC2(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc2(*this) {
|
||||
settings.pinout.a0 = 1 << decimal(board["chip"]["pinout"]["a0"].value);
|
||||
settings.pinout.a1 = 1 << decimal(board["chip"]["pinout"]["a1"].value);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
struct VRC2 : Chip {
|
||||
|
||||
uint4 prg_bank[2];
|
||||
uint5 prg_bank[2];
|
||||
uint8 chr_bank[8];
|
||||
uint2 mirror;
|
||||
bool latch;
|
||||
|
||||
unsigned prg_addr(unsigned addr) const {
|
||||
unsigned bank;
|
||||
switch(addr & 0xe000) {
|
||||
case 0x8000: bank = prg_bank[0]; break;
|
||||
case 0xa000: bank = prg_bank[1]; break;
|
||||
case 0xc000: bank = 0x0e; break;
|
||||
case 0xe000: bank = 0x0f; break;
|
||||
case 0xc000: bank = 0x1e; break;
|
||||
case 0xe000: bank = 0x1f; break;
|
||||
}
|
||||
return (bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
@ -30,10 +31,26 @@ unsigned ciram_addr(unsigned addr) const {
|
|||
throw;
|
||||
}
|
||||
|
||||
uint8 ram_read(unsigned addr) {
|
||||
if(board.prgram.size == 0) {
|
||||
if((addr & 0xf000) == 0x6000) return cpu.mdr() | latch;
|
||||
return cpu.mdr();
|
||||
}
|
||||
return board.prgram.read(addr & 0x1fff);
|
||||
}
|
||||
|
||||
void ram_write(unsigned addr, uint8 data) {
|
||||
if(board.prgram.size == 0) {
|
||||
if((addr & 0xf000) == 0x6000) latch = data & 0x01;
|
||||
return;
|
||||
}
|
||||
return board.prgram.write(addr & 0x1fff, data);
|
||||
}
|
||||
|
||||
void reg_write(unsigned addr, uint8 data) {
|
||||
switch(addr) {
|
||||
case 0x8000: case 0x8001: case 0x8002: case 0x8003:
|
||||
prg_bank[0] = data & 0x0f;
|
||||
prg_bank[0] = data & 0x1f;
|
||||
break;
|
||||
|
||||
case 0x9000: case 0x9001: case 0x9002: case 0x9003:
|
||||
|
@ -41,7 +58,7 @@ void reg_write(unsigned addr, uint8 data) {
|
|||
break;
|
||||
|
||||
case 0xa000: case 0xa001: case 0xa002: case 0xa003:
|
||||
prg_bank[1] = data & 0x0f;
|
||||
prg_bank[1] = data & 0x1f;
|
||||
break;
|
||||
|
||||
case 0xb000: chr_bank[0] = (chr_bank[0] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
|
@ -77,12 +94,14 @@ void reset() {
|
|||
for(auto &n : prg_bank) n = 0;
|
||||
for(auto &n : chr_bank) n = 0;
|
||||
mirror = 0;
|
||||
latch = 0;
|
||||
}
|
||||
|
||||
void serialize(serializer &s) {
|
||||
for(auto &n : prg_bank) s.integer(n);
|
||||
for(auto &n : chr_bank) s.integer(n);
|
||||
s.integer(mirror);
|
||||
s.integer(latch);
|
||||
}
|
||||
|
||||
VRC2(Board &board) : Chip(board) {
|
||||
|
|
|
@ -49,6 +49,32 @@ void main() {
|
|||
}
|
||||
}
|
||||
|
||||
unsigned prg_addr(unsigned addr) const {
|
||||
unsigned bank = 0, banks = board.prgrom.size / 0x2000;
|
||||
switch(addr & 0xe000) {
|
||||
case 0x8000: bank = prg_mode == 0 ? (unsigned)prg_bank[0] : banks - 2; break;
|
||||
case 0xa000: bank = prg_bank[1]; break;
|
||||
case 0xc000: bank = prg_mode == 0 ? banks - 2 : (unsigned)prg_bank[0]; break;
|
||||
case 0xe000: bank = banks - 1; break;
|
||||
}
|
||||
return (bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
||||
unsigned chr_addr(unsigned addr) const {
|
||||
unsigned bank = chr_bank[addr / 0x0400];
|
||||
return (bank * 0x0400) + (addr & 0x03ff);
|
||||
}
|
||||
|
||||
unsigned ciram_addr(unsigned addr) const {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first)
|
||||
case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second)
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
void reg_write(unsigned addr, uint8 data) {
|
||||
switch(addr) {
|
||||
case 0x8000: case 0x8001: case 0x8002: case 0x8003:
|
||||
|
@ -117,32 +143,6 @@ void reg_write(unsigned addr, uint8 data) {
|
|||
}
|
||||
}
|
||||
|
||||
unsigned prg_addr(unsigned addr) const {
|
||||
unsigned bank = 0, banks = board.prgrom.size / 0x2000;
|
||||
switch((addr / 0x2000) & 3) {
|
||||
case 0: bank = prg_mode == 0 ? (unsigned)prg_bank[0] : banks - 2; break;
|
||||
case 1: bank = prg_bank[1]; break;
|
||||
case 2: bank = prg_mode == 0 ? banks - 2 : (unsigned)prg_bank[0]; break;
|
||||
case 3: bank = banks - 1; break;
|
||||
}
|
||||
return (bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
||||
unsigned chr_addr(unsigned addr) const {
|
||||
unsigned bank = chr_bank[addr / 0x0400];
|
||||
return (bank * 0x0400) + (addr & 0x03ff);
|
||||
}
|
||||
|
||||
unsigned ciram_addr(unsigned addr) const {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first)
|
||||
case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second)
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
void power() {
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ static string iNES(const uint8_t *data, unsigned size) {
|
|||
unsigned prgram = 0;
|
||||
unsigned chrram = chrrom == 0 ? 8192 : 0;
|
||||
|
||||
print("iNES mapper: ", mapper, "\n");
|
||||
//print("iNES mapper: ", mapper, "\n");
|
||||
|
||||
output.append("cartridge\n");
|
||||
|
||||
|
@ -81,9 +81,6 @@ static string iNES(const uint8_t *data, unsigned size) {
|
|||
case 21:
|
||||
case 23:
|
||||
case 25:
|
||||
//VRC2
|
||||
//output.append("\tboard type:KONAMI-VRC-2\n");
|
||||
//output.append("\t\tchip type:VRC2\n");
|
||||
//VRC4
|
||||
output.append("\tboard type:KONAMI-VRC-4\n");
|
||||
output.append("\t\tchip type:VRC4\n");
|
||||
|
@ -91,6 +88,13 @@ static string iNES(const uint8_t *data, unsigned size) {
|
|||
prgram = 8192;
|
||||
break;
|
||||
|
||||
case 22:
|
||||
//VRC2
|
||||
output.append("\tboard type:KONAMI-VRC-2\n");
|
||||
output.append("\t\tchip type:VRC2\n");
|
||||
output.append("\t\t\tpinout a0=0 a1=1\n");
|
||||
break;
|
||||
|
||||
case 24:
|
||||
output.append("\tboard type:KONAMI-VRC-6\n");
|
||||
output.append("\t\tchip type:VRC6\n");
|
||||
|
@ -140,7 +144,7 @@ static string iNES(const uint8_t *data, unsigned size) {
|
|||
output.append("\t\tprg rom=", prgrom, " ram=", prgram, "\n");
|
||||
output.append("\t\tchr rom=", chrrom, " ram=", chrram, "\n");
|
||||
|
||||
print(output, "\n");
|
||||
//print(output, "\n");
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ FileBrowser::FileBrowser() {
|
|||
setPath(path);
|
||||
};
|
||||
|
||||
fileList.onChange = { &FileBrowser::synchronize, this };
|
||||
fileList.onActivate = openButton.onTick = { &FileBrowser::fileListActivate, this };
|
||||
|
||||
filterModes.append({ "Default", "", { "*" } });
|
||||
|
@ -53,6 +54,11 @@ FileBrowser::FileBrowser() {
|
|||
for(auto &mode : filterModes) config.attach(mode.path, mode.name);
|
||||
config.load(application->path("paths.cfg"));
|
||||
config.save(application->path("paths.cfg"));
|
||||
synchronize();
|
||||
}
|
||||
|
||||
void FileBrowser::synchronize() {
|
||||
openButton.setEnabled(fileList.selected());
|
||||
}
|
||||
|
||||
FileBrowser::~FileBrowser() {
|
||||
|
@ -103,6 +109,7 @@ void FileBrowser::setPath(const string &path) {
|
|||
for(auto &fileName : fileNameList) fileList.append(fileName);
|
||||
fileList.setSelection(0);
|
||||
fileList.setFocused();
|
||||
synchronize();
|
||||
}
|
||||
|
||||
void FileBrowser::fileListActivate() {
|
||||
|
|
|
@ -27,6 +27,7 @@ private:
|
|||
lstring fileNameList;
|
||||
function<void (string)> callback;
|
||||
|
||||
void synchronize();
|
||||
void setPath(const string &path);
|
||||
void fileListActivate();
|
||||
bool loadFolder(const string &path);
|
||||
|
|
|
@ -297,7 +297,7 @@ MainWindow::MainWindow() {
|
|||
|
||||
settingsMuteAudio.onTick = [&] {
|
||||
config->audio.mute = settingsMuteAudio.checked();
|
||||
dspaudio.setVolume(config->audio.mute == false ? 1.0 : 0.0);
|
||||
dspaudio.setVolume(config->audio.mute == false ? (double)config->audio.volume / 100.0 : 0.0);
|
||||
};
|
||||
|
||||
settingsConfiguration.onTick = [&] { settingsWindow->setVisible(); };
|
||||
|
|
|
@ -27,7 +27,7 @@ void Application::run() {
|
|||
}
|
||||
|
||||
Application::Application(int argc, char **argv) {
|
||||
title = "bsnes v083.10";
|
||||
title = "bsnes v084";
|
||||
|
||||
application = this;
|
||||
quit = false;
|
||||
|
@ -76,7 +76,11 @@ Application::Application(int argc, char **argv) {
|
|||
video.driver(config->video.driver);
|
||||
video.set(Video::Handle, mainWindow->viewport.handle());
|
||||
video.set(Video::Synchronize, config->video.synchronize);
|
||||
video.init();
|
||||
if(video.init() == false) {
|
||||
MessageWindow::critical(*mainWindow, { "Failed to initialize ", config->video.driver, " video driver." });
|
||||
video.driver("None");
|
||||
video.init();
|
||||
}
|
||||
utility->bindVideoFilter();
|
||||
utility->bindVideoShader();
|
||||
|
||||
|
@ -85,17 +89,25 @@ Application::Application(int argc, char **argv) {
|
|||
audio.set(Audio::Synchronize, config->audio.synchronize);
|
||||
audio.set(Audio::Latency, config->audio.latency);
|
||||
audio.set(Audio::Frequency, config->audio.frequency);
|
||||
audio.init();
|
||||
if(audio.init() == false) {
|
||||
MessageWindow::critical(*mainWindow, { "Failed to initialize ", config->audio.driver, " audio driver." });
|
||||
audio.driver("None");
|
||||
audio.init();
|
||||
}
|
||||
|
||||
dspaudio.setPrecision(16);
|
||||
dspaudio.setVolume(config->audio.mute == false ? 1.0 : 0.0);
|
||||
dspaudio.setVolume(config->audio.mute == false ? (double)config->audio.volume / 100.0 : 0.0);
|
||||
dspaudio.setBalance(0.0);
|
||||
dspaudio.setResampler(DSP::ResampleEngine::Sinc);
|
||||
dspaudio.setResamplerFrequency(config->audio.frequency);
|
||||
|
||||
input.driver(config->input.driver);
|
||||
input.set(Input::Handle, mainWindow->viewport.handle());
|
||||
input.init();
|
||||
if(input.init() == false) {
|
||||
MessageWindow::critical(*mainWindow, { "Failed to initialize ", config->input.driver, " input driver." });
|
||||
input.driver("None");
|
||||
input.init();
|
||||
}
|
||||
|
||||
if(config->video.startFullScreen) utility->toggleFullScreen();
|
||||
if(argc == 2) interface->loadCartridge(argv[1]);
|
||||
|
|
|
@ -8,6 +8,7 @@ void Utility::setMode(Interface::Mode mode) {
|
|||
mainWindow->nesMenu.setVisible(false);
|
||||
mainWindow->snesMenu.setVisible(false);
|
||||
mainWindow->gameBoyMenu.setVisible(false);
|
||||
mainWindow->viewport.setVisible(mode != Interface::Mode::None);
|
||||
|
||||
if(mode == Interface::Mode::None) {
|
||||
mainWindow->setTitle(application->title);
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
#include <nall/platform.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
using namespace nall;
|
||||
|
||||
extern "C" {
|
||||
void filter_size(unsigned&, unsigned&);
|
||||
void filter_render(uint16_t*, unsigned, const uint16_t*, unsigned, unsigned, unsigned);
|
||||
};
|
||||
|
||||
enum {
|
||||
diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407,
|
||||
diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0,
|
||||
};
|
||||
|
||||
uint32_t *yuvTable;
|
||||
uint8_t rotate[256];
|
||||
|
||||
const uint8_t hqTable[256] = {
|
||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
|
||||
4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
|
||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
|
||||
4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
|
||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
|
||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
|
||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
|
||||
4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
|
||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
|
||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
|
||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
|
||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
|
||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
|
||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
|
||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
|
||||
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14,
|
||||
};
|
||||
|
||||
static void initialize() {
|
||||
static bool initialized = false;
|
||||
if(initialized == true) return;
|
||||
initialized = true;
|
||||
|
||||
yuvTable = new uint32_t[32768];
|
||||
|
||||
for(unsigned i = 0; i < 32768; i++) {
|
||||
uint8_t R = (i >> 0) & 31;
|
||||
uint8_t G = (i >> 5) & 31;
|
||||
uint8_t B = (i >> 10) & 31;
|
||||
|
||||
//bgr555->bgr888
|
||||
double r = (R << 3) | (R >> 2);
|
||||
double g = (G << 3) | (G >> 2);
|
||||
double b = (B << 3) | (B >> 2);
|
||||
|
||||
//bgr888->yuv
|
||||
double y = (r + g + b) * (0.25f * (63.5f / 48.0f));
|
||||
double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f);
|
||||
double v = ((g * 2.0f - r - b) * 0.125f + 128.0f) * (7.5f / 6.0f);
|
||||
|
||||
yuvTable[i] = ((unsigned)y << 21) + ((unsigned)u << 11) + ((unsigned)v);
|
||||
}
|
||||
|
||||
//counter-clockwise rotation table; one revolution:
|
||||
//123 369 12346789
|
||||
//4.6 -> 2.8 =
|
||||
//789 147 36928147
|
||||
for(unsigned n = 0; n < 256; n++) {
|
||||
rotate[n] = ((n >> 2) & 0x11) | ((n << 2) & 0x88)
|
||||
| ((n & 0x01) << 5) | ((n & 0x08) << 3)
|
||||
| ((n & 0x10) >> 3) | ((n & 0x80) >> 5);
|
||||
}
|
||||
}
|
||||
|
||||
static void terminate() {
|
||||
delete[] yuvTable;
|
||||
}
|
||||
|
||||
static bool same(uint16_t x, uint16_t y) {
|
||||
return !((yuvTable[x] - yuvTable[y] + diff_offset) & diff_mask);
|
||||
}
|
||||
|
||||
static bool diff(uint32_t x, uint16_t y) {
|
||||
return ((x - yuvTable[y]) & diff_mask);
|
||||
}
|
||||
|
||||
static void grow(uint32_t &n) { n |= n << 16; n &= 0x03e07c1f; }
|
||||
static uint16_t pack(uint32_t n) { n &= 0x03e07c1f; return n | (n >> 16); }
|
||||
|
||||
static uint16_t blend1(uint32_t A, uint32_t B) {
|
||||
grow(A); grow(B);
|
||||
return pack((A * 3 + B) >> 2);
|
||||
}
|
||||
|
||||
static uint16_t blend2(uint32_t A, uint32_t B, uint32_t C) {
|
||||
grow(A); grow(B); grow(C);
|
||||
return pack((A * 2 + B + C) >> 2);
|
||||
}
|
||||
|
||||
static uint16_t blend3(uint32_t A, uint32_t B, uint32_t C) {
|
||||
grow(A); grow(B); grow(C);
|
||||
return pack((A * 5 + B * 2 + C) >> 3);
|
||||
}
|
||||
|
||||
static uint16_t blend4(uint32_t A, uint32_t B, uint32_t C) {
|
||||
grow(A); grow(B); grow(C);
|
||||
return pack((A * 6 + B + C) >> 3);
|
||||
}
|
||||
|
||||
static uint16_t blend5(uint32_t A, uint32_t B, uint32_t C) {
|
||||
grow(A); grow(B); grow(C);
|
||||
return pack((A * 2 + (B + C) * 3) >> 3);
|
||||
}
|
||||
|
||||
static uint16_t blend6(uint32_t A, uint32_t B, uint32_t C) {
|
||||
grow(A); grow(B); grow(C);
|
||||
return pack((A * 14 + B + C) >> 4);
|
||||
}
|
||||
|
||||
static uint16_t blend(unsigned rule, uint16_t E, uint16_t A, uint16_t B, uint16_t D, uint16_t F, uint16_t H) {
|
||||
switch(rule) { default:
|
||||
case 0: return E;
|
||||
case 1: return blend1(E, A);
|
||||
case 2: return blend1(E, D);
|
||||
case 3: return blend1(E, B);
|
||||
case 4: return blend2(E, D, B);
|
||||
case 5: return blend2(E, A, B);
|
||||
case 6: return blend2(E, A, D);
|
||||
case 7: return blend3(E, B, D);
|
||||
case 8: return blend3(E, D, B);
|
||||
case 9: return blend4(E, D, B);
|
||||
case 10: return blend5(E, D, B);
|
||||
case 11: return blend6(E, D, B);
|
||||
case 12: return same(B, D) ? blend2(E, D, B) : E;
|
||||
case 13: return same(B, D) ? blend5(E, D, B) : E;
|
||||
case 14: return same(B, D) ? blend6(E, D, B) : E;
|
||||
case 15: return same(B, D) ? blend2(E, D, B) : blend1(E, A);
|
||||
case 16: return same(B, D) ? blend4(E, D, B) : blend1(E, A);
|
||||
case 17: return same(B, D) ? blend5(E, D, B) : blend1(E, A);
|
||||
case 18: return same(B, F) ? blend3(E, B, D) : blend1(E, D);
|
||||
case 19: return same(D, H) ? blend3(E, D, B) : blend1(E, B);
|
||||
}
|
||||
}
|
||||
|
||||
dllexport void filter_size(unsigned &width, unsigned &height) {
|
||||
initialize();
|
||||
width *= 2;
|
||||
height *= 2;
|
||||
}
|
||||
|
||||
dllexport void filter_render(
|
||||
uint16_t *output, unsigned outputPitch,
|
||||
const uint16_t *input, unsigned inputPitch,
|
||||
unsigned width, unsigned height
|
||||
) {
|
||||
initialize();
|
||||
outputPitch >>= 1, inputPitch >>= 1;
|
||||
|
||||
#pragma omp parallel for
|
||||
for(unsigned y = 0; y < height; y++) {
|
||||
const uint16_t *in = input + y * inputPitch;
|
||||
uint16_t *out0 = output + y * outputPitch * 2;
|
||||
uint16_t *out1 = output + y * outputPitch * 2 + outputPitch;
|
||||
|
||||
int prevline = (y == 0 ? 0 : inputPitch);
|
||||
int nextline = (y == height - 1 ? 0 : inputPitch);
|
||||
|
||||
in++;
|
||||
*out0++ = 0; *out0++ = 0;
|
||||
*out1++ = 0; *out1++ = 0;
|
||||
|
||||
for(unsigned x = 1; x < width - 1; x++) {
|
||||
uint16_t A = *(in - prevline - 1);
|
||||
uint16_t B = *(in - prevline + 0);
|
||||
uint16_t C = *(in - prevline + 1);
|
||||
uint16_t D = *(in - 1);
|
||||
uint16_t E = *(in + 0);
|
||||
uint16_t F = *(in + 1);
|
||||
uint16_t G = *(in + nextline - 1);
|
||||
uint16_t H = *(in + nextline + 0);
|
||||
uint16_t I = *(in + nextline + 1);
|
||||
uint32_t e = yuvTable[E] + diff_offset;
|
||||
|
||||
uint8_t pattern;
|
||||
pattern = diff(e, A) << 0;
|
||||
pattern |= diff(e, B) << 1;
|
||||
pattern |= diff(e, C) << 2;
|
||||
pattern |= diff(e, D) << 3;
|
||||
pattern |= diff(e, F) << 4;
|
||||
pattern |= diff(e, G) << 5;
|
||||
pattern |= diff(e, H) << 6;
|
||||
pattern |= diff(e, I) << 7;
|
||||
|
||||
*(out0 + 0) = blend(hqTable[pattern], E, A, B, D, F, H); pattern = rotate[pattern];
|
||||
*(out0 + 1) = blend(hqTable[pattern], E, C, F, B, H, D); pattern = rotate[pattern];
|
||||
*(out1 + 1) = blend(hqTable[pattern], E, I, H, F, D, B); pattern = rotate[pattern];
|
||||
*(out1 + 0) = blend(hqTable[pattern], E, G, D, H, B, F);
|
||||
|
||||
in++;
|
||||
out0 += 2;
|
||||
out1 += 2;
|
||||
}
|
||||
|
||||
in++;
|
||||
*out0++ = 0; *out0++ = 0;
|
||||
*out1++ = 0; *out1++ = 0;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue