bsnes/qt/link/filter.cpp

240 lines
5.5 KiB
C++
Executable File

//==============
//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;
}