diff --git a/src/platform/core/CMakeLists.txt b/src/platform/core/CMakeLists.txt index 31e2999c..c11f34d5 100644 --- a/src/platform/core/CMakeLists.txt +++ b/src/platform/core/CMakeLists.txt @@ -78,6 +78,7 @@ set(HEADERS src/device/shader/color_agb.glsl.hpp src/device/shader/common.glsl.hpp src/device/shader/lcd_ghosting.glsl.hpp + src/device/shader/lcd1x.glsl.hpp src/device/shader/output.glsl.hpp src/device/shader/sharp_bilinear.glsl.hpp src/device/shader/xbrz.glsl.hpp diff --git a/src/platform/core/include/platform/config.hpp b/src/platform/core/include/platform/config.hpp index 0b676ebd..89c6278a 100644 --- a/src/platform/core/include/platform/config.hpp +++ b/src/platform/core/include/platform/config.hpp @@ -29,7 +29,8 @@ struct PlatformConfig : Config { Nearest, Linear, Sharp, - xBRZ + xBRZ, + Lcd1x } filter = Filter::Linear; enum class Color { diff --git a/src/platform/core/src/config.cpp b/src/platform/core/src/config.cpp index d6fab9c1..be382c94 100644 --- a/src/platform/core/src/config.cpp +++ b/src/platform/core/src/config.cpp @@ -81,7 +81,8 @@ void PlatformConfig::Load(std::string const& path) { { "nearest", Video::Filter::Nearest }, { "linear", Video::Filter::Linear }, { "sharp", Video::Filter::Sharp }, - { "xbrz", Video::Filter::xBRZ } + { "xbrz", Video::Filter::xBRZ }, + { "lcd1x", Video::Filter::Lcd1x } }; const std::map color_corrections{ @@ -181,7 +182,8 @@ void PlatformConfig::Save(std::string const& path) { case Video::Filter::Nearest: filter = "nearest"; break; case Video::Filter::Linear: filter = "linear"; break; case Video::Filter::Sharp: filter = "sharp"; break; - case Video::Filter::xBRZ: filter = "xbrz"; break; + case Video::Filter::xBRZ: filter = "xbrz"; break; + case Video::Filter::Lcd1x: filter = "lcd1x"; break; } switch(this->video.color) { diff --git a/src/platform/core/src/device/ogl_video_device.cpp b/src/platform/core/src/device/ogl_video_device.cpp index a4a68711..d6f94784 100644 --- a/src/platform/core/src/device/ogl_video_device.cpp +++ b/src/platform/core/src/device/ogl_video_device.cpp @@ -16,6 +16,7 @@ #include "device/shader/color_higan.glsl.hpp" #include "device/shader/color_agb.glsl.hpp" #include "device/shader/lcd_ghosting.glsl.hpp" +#include "device/shader/lcd1x.glsl.hpp" #include "device/shader/output.glsl.hpp" #include "device/shader/sharp_bilinear.glsl.hpp" #include "device/shader/xbrz.glsl.hpp" @@ -186,7 +187,15 @@ void OGLVideoDevice::CreateShaderPrograms() { // Sharp bilinear. case Video::Filter::Sharp: { auto [success, program] = CompileProgram(sharp_bilinear_vert, sharp_bilinear_frag); - if (success) { + if(success) { + shader_passes.push_back({program}); + } + break; + } + // Lcd1x filter + case Video::Filter::Lcd1x: { + auto [success, program] = CompileProgram(lcd1x_vert, lcd1x_frag); + if(success) { shader_passes.push_back({program}); } break; diff --git a/src/platform/core/src/device/shader/lcd1x.glsl.hpp b/src/platform/core/src/device/shader/lcd1x.glsl.hpp new file mode 100644 index 00000000..4d719647 --- /dev/null +++ b/src/platform/core/src/device/shader/lcd1x.glsl.hpp @@ -0,0 +1,60 @@ +/* + * lcd1x - Simple LCD 'scanline' shader, based on lcd3x + * + * Original code by Gigaherz, released into the public domain + * + * Ported to NanoBoyAdvance by Destiny + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * lcd1x differs from lcd3x in the following manner: + * + * > Omits LCD-style colour separation + * + * > Has 'correctly' aligned scanlines + */ + +#pragma once + +constexpr auto lcd1x_vert = R"( + #version 330 core + + layout(location = 0) in vec2 position; + layout(location = 1) in vec2 uv; + + out vec2 v_uv; + + void main() { + v_uv = vec2(uv.x, 1.0 - uv.y) * 1.0001; + gl_Position = vec4(position, 0.0, 1.0); + } +)"; + +constexpr auto lcd1x_frag = R"( + #version 330 core + + #define BRIGHTEN_SCANLINES 16.0 + #define BRIGHTEN_LCD 24.0 + #define PI 3.141592653589793 + #define INPUT_SIZE vec2(240,160) + + + layout(location = 0) out vec4 frag_color; + + in vec2 v_uv; + + uniform sampler2D u_input_map; + + void main() { + vec2 angle = 2.0 * PI * ((v_uv.xy * INPUT_SIZE.xy) - 0.25); + float yfactor = (BRIGHTEN_SCANLINES + sin(angle.y)) / (BRIGHTEN_SCANLINES + 1.0); + float xfactor = (BRIGHTEN_LCD + sin(angle.x)) / (BRIGHTEN_LCD + 1.0); + vec3 colour = texture(u_input_map, v_uv).rgb; + colour.rgb = yfactor * xfactor * colour.rgb; + + frag_color = vec4(colour.rgb, 1.0); + } +)"; diff --git a/src/platform/qt/src/widget/main_window.cpp b/src/platform/qt/src/widget/main_window.cpp index 0688e3dc..5f2d8855 100644 --- a/src/platform/qt/src/widget/main_window.cpp +++ b/src/platform/qt/src/widget/main_window.cpp @@ -177,7 +177,8 @@ void MainWindow::CreateVideoMenu(QMenu* parent) { { "Nearest", nba::PlatformConfig::Video::Filter::Nearest }, { "Linear", nba::PlatformConfig::Video::Filter::Linear }, { "Sharp", nba::PlatformConfig::Video::Filter::Sharp }, - { "xBRZ", nba::PlatformConfig::Video::Filter::xBRZ } + { "xBRZ", nba::PlatformConfig::Video::Filter::xBRZ }, + { "Lcd1x", nba::PlatformConfig::Video::Filter::Lcd1x } }, &config->video.filter, false, reload_config); CreateSelectionOption(menu->addMenu(tr("Color correction")), {