1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-07 23:29:06 +00:00

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.

This commit is contained in:
Thomas Harte 2016-02-10 23:11:25 -05:00
parent b5bcadb8d3
commit c66409421e
4 changed files with 34 additions and 12 deletions

View File

@ -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)
{

View File

@ -179,6 +179,7 @@ class Machine: public CPU6502::Processor<Machine>, Tape::Delegate {
int _currentOutputLine;
unsigned int _currentOutputDivider;
uint8_t *_currentLine, *_writePointer;
bool _is_odd_field;
// Tape.
Tape _tape;

View File

@ -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.

View File

@ -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);
}