mirror of https://github.com/bsnes-emu/bsnes.git
240 lines
5.5 KiB
C++
240 lines
5.5 KiB
C++
|
//==============
|
||
|
//ScanlineFilter
|
||
|
//==============
|
||
|
|
||
|
ScanlineFilter scanlineFilter;
|
||
|
|
||
|
void ScanlineFilter::size(unsigned &width, unsigned &height) {
|
||
|
if(enabled && height <= 240) height *= 2;
|
||
|
}
|
||
|
|
||
|
void ScanlineFilter::render(
|
||
|
const uint16_t *&input, unsigned &pitch,
|
||
|
unsigned width, unsigned &height
|
||
|
) {
|
||
|
if(enabled && height <= 240) {
|
||
|
pitch >>= 1;
|
||
|
|
||
|
const uint16_t *sp = input;
|
||
|
uint16_t *dp = buffer;
|
||
|
for(unsigned y = 0; y < height; y++) {
|
||
|
for(unsigned x = 0; x < width; x++) {
|
||
|
uint16_t color = *sp++;
|
||
|
*(dp + 0) = color;
|
||
|
*(dp + 512) = adjust[color];
|
||
|
dp++;
|
||
|
}
|
||
|
|
||
|
sp += pitch - width;
|
||
|
dp += 1024 - width;
|
||
|
}
|
||
|
|
||
|
input = buffer;
|
||
|
pitch = 1024;
|
||
|
height *= 2;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ScanlineFilter::setIntensity(unsigned intensity) {
|
||
|
if(intensity >= 100) {
|
||
|
enabled = false;
|
||
|
} else {
|
||
|
enabled = true;
|
||
|
|
||
|
for(unsigned i = 0; i < 32768; i++) {
|
||
|
unsigned r = (i >> 0) & 31;
|
||
|
unsigned g = (i >> 5) & 31;
|
||
|
unsigned b = (i >> 10) & 31;
|
||
|
|
||
|
r = (double)r * (double)intensity / 100.0;
|
||
|
g = (double)g * (double)intensity / 100.0;
|
||
|
b = (double)b * (double)intensity / 100.0;
|
||
|
|
||
|
adjust[i] = (r << 0) + (g << 5) + (b << 10);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ScanlineFilter::ScanlineFilter() {
|
||
|
enabled = false;
|
||
|
adjust = new uint16_t[32768];
|
||
|
buffer = new uint16_t[512 * 480];
|
||
|
setIntensity(50);
|
||
|
}
|
||
|
|
||
|
ScanlineFilter::~ScanlineFilter() {
|
||
|
delete[] adjust;
|
||
|
delete[] buffer;
|
||
|
}
|
||
|
|
||
|
//======
|
||
|
//Filter
|
||
|
//======
|
||
|
|
||
|
Filter filter;
|
||
|
|
||
|
const uint8_t Filter::gamma_ramp_table[32] = {
|
||
|
0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c,
|
||
|
0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78,
|
||
|
0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0,
|
||
|
0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff,
|
||
|
};
|
||
|
|
||
|
uint8_t Filter::contrast_adjust(uint8_t input) {
|
||
|
signed result = input - contrast + (2 * contrast * input + 127) / 255;
|
||
|
return max(0, min(255, result));
|
||
|
}
|
||
|
|
||
|
uint8_t Filter::brightness_adjust(uint8_t input) {
|
||
|
signed result = input + brightness;
|
||
|
return max(0, min(255, result));
|
||
|
}
|
||
|
|
||
|
uint8_t Filter::gamma_adjust(uint8_t input) {
|
||
|
signed result = (signed)(pow(((double)input / 255.0), (double)gamma / 100.0) * 255.0 + 0.5);
|
||
|
return max(0, min(255, result));
|
||
|
}
|
||
|
|
||
|
void Filter::colortable_update() {
|
||
|
double kr = 0.2126, kb = 0.0722, kg = (1.0 - kr - kb); //luminance weights
|
||
|
|
||
|
for(unsigned i = 0; i < 32768; i++) {
|
||
|
unsigned color //rgb555->rgb888 conversion
|
||
|
= ((i & 0x7c00) << 9) + ((i & 0x7000) << 4)
|
||
|
+ ((i & 0x03e0) << 6) + ((i & 0x0380) << 1)
|
||
|
+ ((i & 0x001f) << 3) + ((i & 0x001c) >> 2);
|
||
|
|
||
|
signed l;
|
||
|
signed r = (color >> 16) & 0xff;
|
||
|
signed g = (color >> 8) & 0xff;
|
||
|
signed b = (color ) & 0xff;
|
||
|
|
||
|
if(gamma_ramp == true) {
|
||
|
r = gamma_ramp_table[r >> 3];
|
||
|
g = gamma_ramp_table[g >> 3];
|
||
|
b = gamma_ramp_table[b >> 3];
|
||
|
}
|
||
|
|
||
|
if(contrast != 0) {
|
||
|
r = contrast_adjust(r);
|
||
|
g = contrast_adjust(g);
|
||
|
b = contrast_adjust(b);
|
||
|
}
|
||
|
|
||
|
if(brightness != 0) {
|
||
|
r = brightness_adjust(r);
|
||
|
g = brightness_adjust(g);
|
||
|
b = brightness_adjust(b);
|
||
|
}
|
||
|
|
||
|
if(gamma != 100) {
|
||
|
r = gamma_adjust(r);
|
||
|
g = gamma_adjust(g);
|
||
|
b = gamma_adjust(b);
|
||
|
}
|
||
|
|
||
|
if(sepia == true) {
|
||
|
l = (signed)((double)r * kr + (double)g * kg + (double)b * kb);
|
||
|
l = max(0, min(255, l));
|
||
|
|
||
|
r = (signed)((double)l * (1.0 + 0.300));
|
||
|
g = (signed)((double)l * (1.0 - 0.055));
|
||
|
b = (signed)((double)l * (1.0 - 0.225));
|
||
|
|
||
|
r = max(0, min(255, r));
|
||
|
g = max(0, min(255, g));
|
||
|
b = max(0, min(255, b));
|
||
|
}
|
||
|
|
||
|
if(grayscale == true) {
|
||
|
l = (signed)((double)r * kr + (double)g * kg + (double)b * kb);
|
||
|
l = max(0, min(255, l));
|
||
|
r = g = b = l;
|
||
|
}
|
||
|
|
||
|
if(invert == true) {
|
||
|
r ^= 0xff;
|
||
|
g ^= 0xff;
|
||
|
b ^= 0xff;
|
||
|
}
|
||
|
|
||
|
colortable[i] = (r << 16) | (g << 8) | (b);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Filter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
|
||
|
scanlineFilter.size(width, height);
|
||
|
|
||
|
if(opened() && renderer > 0) {
|
||
|
return dl_size(renderer, outwidth, outheight, width, height);
|
||
|
}
|
||
|
|
||
|
outwidth = width;
|
||
|
outheight = height;
|
||
|
}
|
||
|
|
||
|
void Filter::render(
|
||
|
uint32_t *output, unsigned outpitch,
|
||
|
const uint16_t *input, unsigned pitch, unsigned width, unsigned height
|
||
|
) {
|
||
|
scanlineFilter.render(input, pitch, width, height);
|
||
|
|
||
|
if(opened() && renderer > 0) {
|
||
|
return dl_render(renderer, output, outpitch, input, pitch, width, height);
|
||
|
}
|
||
|
|
||
|
pitch >>= 1;
|
||
|
outpitch >>= 2;
|
||
|
|
||
|
for(unsigned y = 0; y < height; y++) {
|
||
|
const uint16_t *in = input + y * pitch;
|
||
|
uint32_t *out = output + y * outpitch;
|
||
|
for(unsigned x = 0; x < width; x++) {
|
||
|
*out++ = colortable[*in++];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
QWidget* Filter::settings() {
|
||
|
if(opened() && renderer > 0) {
|
||
|
return dl_settings(renderer);
|
||
|
} else {
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Filter::Filter() {
|
||
|
renderer = 0;
|
||
|
|
||
|
contrast = 0;
|
||
|
brightness = 0;
|
||
|
gamma = 100;
|
||
|
|
||
|
gamma_ramp = false;
|
||
|
sepia = false;
|
||
|
grayscale = false;
|
||
|
invert = false;
|
||
|
|
||
|
colortable = new uint32_t[32768];
|
||
|
colortable_update();
|
||
|
|
||
|
if(open("snesfilter")) {
|
||
|
dl_supported = sym("snesfilter_supported");
|
||
|
dl_colortable = sym("snesfilter_colortable");
|
||
|
dl_configuration = sym("snesfilter_configuration");
|
||
|
dl_size = sym("snesfilter_size");
|
||
|
dl_render = sym("snesfilter_render");
|
||
|
dl_settings = sym("snesfilter_settings");
|
||
|
|
||
|
dl_colortable(colortable);
|
||
|
dl_configuration(config());
|
||
|
} else {
|
||
|
config().video.windowed.swFilter = 0;
|
||
|
config().video.fullscreen.swFilter = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Filter::~Filter() {
|
||
|
delete[] colortable;
|
||
|
}
|