bsnes-hd/bsnes/target-bsnes/program/video.cpp
2020-01-12 22:12:37 +01:00

153 lines
4.2 KiB
C++

auto Program::updateVideoDriver(Window parent) -> void {
auto changed = (bool)video;
video.create(settings.video.driver);
video.setContext(presentation.viewport.handle());
if(changed) {
settings.video.format = video.format();
}
updateVideoExclusive();
updateVideoBlocking();
updateVideoFlush();
updateVideoMonitor();
updateVideoFormat();
updateVideoShader();
if(video.ready()) {
video.clear();
updateVideoShader();
}
video.onUpdate([&](uint width, uint height) {
if(!emulator->loaded()) video.clear();
});
if(!video.ready()) {
MessageDialog({
"Error: failed to initialize [", settings.video.driver, "] video driver."
}).setAlignment(parent).error();
settings.video.driver = "None";
return updateVideoDriver(parent);
}
presentation.updateShaders();
}
auto Program::updateVideoExclusive() -> void {
video.setExclusive(settings.video.exclusive);
}
auto Program::updateVideoBlocking() -> void {
video.setBlocking(settings.video.blocking);
}
auto Program::updateVideoFlush() -> void {
video.setFlush(settings.video.flush);
}
auto Program::updateVideoMonitor() -> void {
if(!video.hasMonitor(settings.video.monitor)) {
settings.video.monitor = video.monitor();
}
video.setMonitor(settings.video.monitor);
}
auto Program::updateVideoFormat() -> void {
if(!video.hasFormat(settings.video.format)) {
settings.video.format = video.format();
}
video.setFormat(settings.video.format);
}
auto Program::updateVideoShader() -> void {
video.setShader(settings.video.shader);
}
auto Program::updateVideoPalette() -> void {
double luminance = settings.video.luminance / 100.0;
double saturation = settings.video.saturation / 100.0;
double gamma = settings.video.gamma / 100.0;
uint depth = 24;
if(video.format() == "RGB30") depth = 30;
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;
}
}
emulator->configure("Video/ColorEmulation", false);
}
auto Program::updateVideoEffects() -> void {
emulator->configure("Video/BlurEmulation", settings.video.blur);
}
auto Program::toggleVideoFullScreen() -> void {
if(!video.hasFullScreen()) return;
if(presentation.fullScreen()) return;
video.clear();
if(!video.fullScreen()) {
video.setFullScreen(true);
if(!input.acquired() && (video.exclusive() || video.hasMonitors().size() == 1)) input.acquire();
} else {
if(input.acquired()) input.release();
video.setFullScreen(false);
presentation.viewport.setFocused();
}
}
auto Program::toggleVideoPseudoFullScreen() -> void {
if(video.fullScreen()) return;
if(!presentation.fullScreen()) {
presentation.setFullScreen(true);
presentation.menuBar.setVisible(false);
if(!input.acquired() && video.hasMonitors().size() == 1) input.acquire();
} else {
if(input.acquired()) input.release();
presentation.menuBar.setVisible(true);
presentation.setFullScreen(false);
}
}