From c66409421e325eb789d8e18b8431c506c9b3f94f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 10 Feb 2016 23:11:25 -0500 Subject: [PATCH] Switched to generating an interlaced output, that apparently being correct. Enabled a poor man's version of phosphor persistence to smooth things out a little. It's not completely unconvincing. --- Machines/Electron/Electron.cpp | 31 ++++++++++++++++++++++--------- Machines/Electron/Electron.hpp | 1 + Outputs/CRT/CRT.hpp | 2 +- Outputs/CRT/CRTOpenGL.cpp | 12 ++++++++++-- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 86ddbfd2e..86150efd2 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -19,6 +19,7 @@ static const unsigned int crt_cycles_multiplier = 8; static const unsigned int crt_cycles_per_line = crt_cycles_multiplier * cycles_per_line; const int first_graphics_line = 28; +const int first_graphics_cycle = 33; Machine::Machine() : _interruptControl(0), @@ -27,6 +28,7 @@ Machine::Machine() : _audioOutputPosition(0), _audioOutputPositionError(0), _currentOutputLine(0), + _is_odd_field(false), _crt(Outputs::CRT(crt_cycles_per_line, Outputs::CRT::DisplayType::PAL50, 1, 1)) { _crt.set_rgb_sampling_function( @@ -84,8 +86,8 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { const int current_line = _frameCycles >> 7; const int line_position = _frameCycles & 127; - if(current_line >= first_graphics_line && current_line < first_graphics_line+256 && line_position >= 24 && line_position < 104) - cycles = (unsigned int)(104 - line_position); + if(current_line >= first_graphics_line && current_line < first_graphics_line+256 && line_position >= first_graphics_cycle && line_position < first_graphics_cycle + 80) + cycles = (unsigned int)(80 + first_graphics_cycle - line_position); } } else @@ -376,20 +378,31 @@ inline void Machine::update_display() // assert sync for the first three lines of the display, with a break at the end for horizontal alignment if(_displayOutputPosition < end_of_hsync) { - for(int c = 0; c < lines_of_hsync; c++) - { - _crt.output_sync(119 * crt_cycles_multiplier); - _crt.output_blank(9 * crt_cycles_multiplier); - } + // on an odd field, output a half line of level data, then 2.5 lines of sync; on an even field + // output 2.5 lines of sync, then half a line of level. +// if (_is_odd_field) +// { + _crt.output_blank(64 * crt_cycles_multiplier); + _crt.output_sync(320 * crt_cycles_multiplier); +// } +// else +// { +// _crt.output_sync(320 * crt_cycles_multiplier); +// _crt.output_blank(64 * crt_cycles_multiplier); +// } + + _is_odd_field ^= true; _displayOutputPosition = end_of_hsync; } while(_displayOutputPosition >= end_of_hsync && _displayOutputPosition < _frameCycles) { - const int current_line = _displayOutputPosition >> 7; - const int line_position = _displayOutputPosition & 127; const int cycles_left = _frameCycles - _displayOutputPosition; + const int fieldOutputPosition = _displayOutputPosition + (_is_odd_field ? 64 : 0); + const int current_line = fieldOutputPosition >> 7; + const int line_position = fieldOutputPosition & 127; + // all lines then start with 9 cycles of sync if(line_position < 9) { diff --git a/Machines/Electron/Electron.hpp b/Machines/Electron/Electron.hpp index af80ed2de..1da9e81c1 100644 --- a/Machines/Electron/Electron.hpp +++ b/Machines/Electron/Electron.hpp @@ -179,6 +179,7 @@ class Machine: public CPU6502::Processor, Tape::Delegate { int _currentOutputLine; unsigned int _currentOutputDivider; uint8_t *_currentLine, *_writePointer; + bool _is_odd_field; // Tape. Tape _tape; diff --git a/Outputs/CRT/CRT.hpp b/Outputs/CRT/CRT.hpp index d9766acd8..f07dbb186 100644 --- a/Outputs/CRT/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -164,7 +164,7 @@ class CRT { /*! Causes appropriate OpenGL or OpenGL ES calls to be issued in order to draw the current CRT state. The caller is responsible for ensuring that a valid OpenGL context exists for the duration of this call. */ - void draw_frame(int output_width, int output_height, bool only_if_dirty); + void draw_frame(unsigned int output_width, unsigned int output_height, bool only_if_dirty); /*! Tells the CRT that the next call to draw_frame will occur on a different OpenGL context than the previous. diff --git a/Outputs/CRT/CRTOpenGL.cpp b/Outputs/CRT/CRTOpenGL.cpp index 967dbdfba..7da1bb85e 100644 --- a/Outputs/CRT/CRTOpenGL.cpp +++ b/Outputs/CRT/CRTOpenGL.cpp @@ -68,7 +68,7 @@ void CRT::destruct_openGL() if(_rgb_shader) free(_rgb_shader); } -void CRT::draw_frame(int output_width, int output_height, bool only_if_dirty) +void CRT::draw_frame(unsigned int output_width, unsigned int output_height, bool only_if_dirty) { _current_frame_mutex->lock(); @@ -105,6 +105,13 @@ void CRT::draw_frame(int output_width, int output_height, bool only_if_dirty) push_size_uniforms(output_width, output_height); + if(_last_drawn_frame != nullptr) + { + glUniform1f(_openGL_state->alphaUniform, 0.4f); + glDrawArrays(GL_TRIANGLES, 0, (GLsizei)_last_drawn_frame->number_of_vertices); + } + glUniform1f(_openGL_state->alphaUniform, 1.0f); + glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(_current_frame->number_of_vertices * _current_frame->size_per_vertex), _current_frame->vertices, GL_DYNAMIC_DRAW); glBindTexture(GL_TEXTURE_2D, _openGL_state->textureName); @@ -121,6 +128,7 @@ void CRT::draw_frame(int output_width, int output_height, bool only_if_dirty) glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _current_frame->size.width, _current_frame->dirty_size.height, formatForDepth(_current_frame->buffers[0].depth), GL_UNSIGNED_BYTE, _current_frame->buffers[0].data); glDrawArrays(GL_TRIANGLES, 0, (GLsizei)_current_frame->number_of_vertices); + _last_drawn_frame = _current_frame; } _current_frame_mutex->unlock(); @@ -264,7 +272,7 @@ char *CRT::get_fragment_shader() "void main(void)" "{" - "fragColour = vec4(rgb_sample(srcCoordinatesVarying).rgb, 1.0);" + "fragColour = vec4(rgb_sample(srcCoordinatesVarying).rgb, alpha);" "}" , _rgb_shader); }