diff --git a/Outputs/CRT/Internals/CRTOpenGL.cpp b/Outputs/CRT/Internals/CRTOpenGL.cpp index 19f24884e..6e630d04f 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.cpp +++ b/Outputs/CRT/Internals/CRTOpenGL.cpp @@ -227,11 +227,18 @@ void OpenGLOutputBuilder::draw_frame(unsigned int output_width, unsigned int out output_shader_program_->set_output_size(output_width, output_height, visible_area_); last_output_width_ = output_width; last_output_height_ = output_height; + + // Configure a right gutter to crop the right-hand 2% of the display. + right_overlay_.reset(new OpenGL::Rectangle(output_shader_program_->get_right_extent() * 0.98, -1.0, 1.0, 2.0)); } output_shader_program_->bind(); // draw glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei)array_submission.output_size / OutputVertexSize); + + // mask off the gutter + glDisable(GL_BLEND); + right_overlay_->draw(0.0, 0.0, 0.0); } #ifdef GL_NV_texture_barrier diff --git a/Outputs/CRT/Internals/CRTOpenGL.hpp b/Outputs/CRT/Internals/CRTOpenGL.hpp index 23462831d..adbc35e71 100644 --- a/Outputs/CRT/Internals/CRTOpenGL.hpp +++ b/Outputs/CRT/Internals/CRTOpenGL.hpp @@ -20,6 +20,7 @@ #include "Shaders/OutputShader.hpp" #include "Shaders/IntermediateShader.hpp" +#include "Rectangle.hpp" #include #include @@ -106,6 +107,18 @@ class OpenGLOutputBuilder { float integer_coordinate_multiplier_ = 1.0f; + // Maintain a couple of rectangles for masking off the extreme edge of the display; + // this is a bit of a cheat: there's some tolerance in when a sync pulse will be + // generated. So it might be slightly later than expected. Which might cause a scan + // that is slightly longer than expected. Which means that from then on, those scans + // might have touched parts of the extreme edge of the display which are not rescanned. + // Which because I've implemented persistence-of-vision as an in-buffer effect will + // cause perpetual persistence. + // + // The fix: just always treat that area as invisible. This is acceptable thanks to + // the concept of overscan. One is allowed not to display extreme ends of the image. + std::unique_ptr right_overlay_; + public: // These two are protected by output_mutex_. TextureBuilder texture_builder; diff --git a/Outputs/CRT/Internals/Shaders/OutputShader.cpp b/Outputs/CRT/Internals/Shaders/OutputShader.cpp index 0ab9c2ff3..8f3687fab 100644 --- a/Outputs/CRT/Internals/Shaders/OutputShader.cpp +++ b/Outputs/CRT/Internals/Shaders/OutputShader.cpp @@ -94,15 +94,21 @@ std::unique_ptr OutputShader::make_shader(const char *fragment_met void OutputShader::set_output_size(unsigned int output_width, unsigned int output_height, Outputs::CRT::Rect visible_area) { GLfloat outputAspectRatioMultiplier = (static_cast(output_width) / static_cast(output_height)) / (4.0f / 3.0f); - GLfloat bonusWidth = (outputAspectRatioMultiplier - 1.0f) * visible_area.size.width; - visible_area.origin.x -= bonusWidth * 0.5f * visible_area.size.width; + + right_extent_ = (1.0f / outputAspectRatioMultiplier) / visible_area.size.width; + + visible_area.origin.x -= bonusWidth * 0.5f; visible_area.size.width *= outputAspectRatioMultiplier; set_uniform("boundsOrigin", (GLfloat)visible_area.origin.x, (GLfloat)visible_area.origin.y); set_uniform("boundsSize", (GLfloat)visible_area.size.width, (GLfloat)visible_area.size.height); } +float OutputShader::get_right_extent() { + return right_extent_; +} + void OutputShader::set_source_texture_unit(GLenum unit) { set_uniform("texID", (GLint)(unit - GL_TEXTURE0)); } diff --git a/Outputs/CRT/Internals/Shaders/OutputShader.hpp b/Outputs/CRT/Internals/Shaders/OutputShader.hpp index cbb7f7aa5..2ca65b572 100644 --- a/Outputs/CRT/Internals/Shaders/OutputShader.hpp +++ b/Outputs/CRT/Internals/Shaders/OutputShader.hpp @@ -87,6 +87,14 @@ public: space, 0.5 means use half, etc. */ void set_input_width_scaler(float input_scaler); + + /*! + @returns The location, in eye coordinates, of the right edge of the output area. + */ + float get_right_extent(); + +private: + float right_extent_ = 0.0f; }; }