diff --git a/Machines/Atari2600.cpp b/Machines/Atari2600.cpp index 01ae7387e..5be759b7d 100644 --- a/Machines/Atari2600.cpp +++ b/Machines/Atari2600.cpp @@ -12,11 +12,12 @@ using namespace Atari2600; static const char atari2600DataType[] = "Atari2600"; +static const int horizontalTimerReload = 227; Machine::Machine() { _timestamp = 0; - _horizontalTimer = 227; + _horizontalTimer = horizontalTimerReload; _lastOutputStateDuration = 0; _lastOutputState = OutputState::Sync; _crt = new Outputs::CRT(228, 312, 1, 4); @@ -187,7 +188,7 @@ void Machine::output_pixels(int count) // an attempt to avoid both the % operator and a conditional _horizontalTimer--; const int32_t sign_extension = _horizontalTimer >> 31; - _horizontalTimer = (_horizontalTimer&~sign_extension) | (sign_extension&227); + _horizontalTimer = (_horizontalTimer&~sign_extension) | (sign_extension&horizontalTimerReload); } } @@ -196,7 +197,7 @@ int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t add uint8_t returnValue = 0xff; output_pixels(3); - if(_horizontalTimer == 227) + if(_horizontalTimer == horizontalTimerReload) set_ready_line(false); if(operation != CPU6502::BusOperation::Ready) { @@ -236,7 +237,7 @@ int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t add case 0x02: { set_ready_line(true); } break; - case 0x03: _horizontalTimer = 227; break; + case 0x03: _horizontalTimer = horizontalTimerReload; break; case 0x04: _playerAndMissileSize[0] = *value; break; case 0x05: _playerAndMissileSize[1] = *value; break; diff --git a/OSBindings/Mac/Clock Signal/CSAtari2600.mm b/OSBindings/Mac/Clock Signal/CSAtari2600.mm index adb593afe..9fa31e202 100644 --- a/OSBindings/Mac/Clock Signal/CSAtari2600.mm +++ b/OSBindings/Mac/Clock Signal/CSAtari2600.mm @@ -28,8 +28,7 @@ struct Atari2600CRTDelegate: public Outputs::CRT::CRTDelegate { - (void)crtDidEndFrame:(CRTFrame *)frame { dispatch_async(dispatch_get_main_queue(), ^{ - BOOL hasReturn = !!self.view.crtFrame; - self.view.crtFrame = frame; + BOOL hasReturn = [self.view pushFrame:frame]; if(hasReturn) dispatch_async(_serialDispatchQueue, ^{ diff --git a/OSBindings/Mac/Clock Signal/CSCathodeRayView.h b/OSBindings/Mac/Clock Signal/CSCathodeRayView.h index 6411ce1d7..0a21eed44 100644 --- a/OSBindings/Mac/Clock Signal/CSCathodeRayView.h +++ b/OSBindings/Mac/Clock Signal/CSCathodeRayView.h @@ -19,8 +19,9 @@ @interface CSCathodeRayView : NSOpenGLView @property (nonatomic, weak) id delegate; -@property (nonatomic, assign, nullable) CRTFrame *crtFrame; - (void)invalidate; +- (BOOL)pushFrame:(CRTFrame * __nonnull)crtFrame; + @end diff --git a/OSBindings/Mac/Clock Signal/CSCathodeRayView.m b/OSBindings/Mac/Clock Signal/CSCathodeRayView.m index 5537ee36c..dece049c7 100644 --- a/OSBindings/Mac/Clock Signal/CSCathodeRayView.m +++ b/OSBindings/Mac/Clock Signal/CSCathodeRayView.m @@ -22,6 +22,8 @@ GLuint _textureName; CRTSize _textureSize; + + CRTFrame *_crtFrame; } - (void)prepareOpenGL @@ -50,7 +52,7 @@ CVDisplayLinkStart(displayLink); glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ZERO); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); } static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp *now, const CVTimeStamp *outputTime, CVOptionFlags flagsIn, CVOptionFlags *flagsOut, void *displayLinkContext) @@ -116,7 +118,8 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt self.wantsBestResolutionOpenGLSurface = YES; } -- (void)setCrtFrame:(CRTFrame *)crtFrame + +- (BOOL)pushFrame:(CRTFrame * __nonnull)crtFrame { _crtFrame = crtFrame; [self setNeedsDisplay:YES]; @@ -136,6 +139,8 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt else glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _crtFrame->size.width, _crtFrame->dirty_size.height, GL_RGBA, GL_UNSIGNED_BYTE, _crtFrame->buffers[0].data); } + + return YES; } #pragma mark - Frame output @@ -153,7 +158,7 @@ const char *vertexShader = "\n" "void main (void)\n" "{\n" - "srcCoordinatesVarying = vec2(srcCoordinates.x / 512.0, (srcCoordinates.y + 0.5) / 512.0);\n" + "srcCoordinatesVarying = vec2(srcCoordinates.x / 512.0, srcCoordinates.y / 512.0);\n" "gl_Position = vec4(position.x * 2.0 - 1.0, 1.0 - position.y * 2.0 + position.x / 131.0, 0.0, 1.0);\n" "}\n"; @@ -167,7 +172,7 @@ const char *fragmentShader = "\n" "void main(void)\n" "{\n" - "fragColour = texture(texID, srcCoordinatesVarying);\n" // vec4(1.0, 1.0, 1.0, 0.5) + "fragColour = texture(texID, srcCoordinatesVarying) * sin(mod(srcCoordinatesVarying.y * 512, 1.0) * 2.09435310266667 + 0.52359877566668);\n" // vec4(1.0, 1.0, 1.0, 0.5) "}\n"; #if defined(DEBUG) diff --git a/Outputs/CRT.cpp b/Outputs/CRT.cpp index b2f0f0b6f..4464e2571 100644 --- a/Outputs/CRT.cpp +++ b/Outputs/CRT.cpp @@ -12,8 +12,8 @@ using namespace Outputs; -static const uint32_t kCRTFixedPointRange = 0xf8ffffff; -static const uint32_t kCRTFixedPointOffset = 0x00800000; +static const uint32_t kCRTFixedPointRange = 0xefffffff; +static const uint32_t kCRTFixedPointOffset = 0x08000000; #define kRetraceXMask 0x01 #define kRetraceYMask 0x02 @@ -58,7 +58,7 @@ CRT::CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...) // width should be 1.0 / _height_of_display, rotated to match the direction float angle = atan2f(scanSpeedYfl, scanSpeedXfl); - float halfLineWidth = (float)_height_of_display * 1.9f; + float halfLineWidth = (float)_height_of_display * 1.6f; _widths[0][0] = (sinf(angle) / halfLineWidth) * kCRTFixedPointRange; _widths[0][1] = (cosf(angle) / halfLineWidth) * kCRTFixedPointRange; @@ -66,7 +66,7 @@ CRT::CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...) // number of buffers, size of buffer 1, size of buffer 2... const int bufferWidth = 512; const int bufferHeight = 512; - for(int frame = 0; frame < 3; frame++) + for(int frame = 0; frame < sizeof(_frame_builders) / sizeof(*_frame_builders); frame++) { va_list va; va_start(va, number_of_buffers); @@ -95,7 +95,7 @@ CRT::CRT(int cycles_per_line, int height_of_display, int number_of_buffers, ...) CRT::~CRT() { - for(int frame = 0; frame < 3; frame++) + for(int frame = 0; frame < sizeof(_frame_builders) / sizeof(*_frame_builders); frame++) { delete _frame_builders[frame]; } @@ -119,7 +119,7 @@ CRT::SyncEvent CRT::next_vertical_sync_event(bool vsync_is_charging, int cycles_ if (_sync_capacitor_charge_level < _sync_capacitor_charge_threshold && _sync_capacitor_charge_level + proposedSyncTime >= _sync_capacitor_charge_threshold) { uint32_t proposed_sync_y = _rasterPosition.y + (_sync_capacitor_charge_threshold - _sync_capacitor_charge_level) * _scanSpeed.y; - if(proposed_sync_y > (kCRTFixedPointRange * 7) >> 3) { + if(proposed_sync_y > (kCRTFixedPointRange * 15) >> 4) { proposedSyncTime = _sync_capacitor_charge_threshold - _sync_capacitor_charge_level; proposedEvent = SyncEvent::StartVSync; } @@ -208,7 +208,8 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool next_run[5] = (kCRTFixedPointOffset + _rasterPosition.y - width[1]) >> 16; next_run[2] = next_run[6] = next_run[22] = tex_x; - next_run[3] = next_run[7] = next_run[23] = tex_y; + next_run[3] = next_run[23] = tex_y; + next_run[7] = tex_y + 1; } // advance the raster position as dictated by current sync status @@ -236,7 +237,8 @@ void CRT::advance_cycles(int number_of_cycles, bool hsync_requested, const bool // if this is a data or level run then store the end point next_run[10] = next_run[14] = next_run[18] = tex_x; - next_run[11] = next_run[15] = next_run[19] = tex_y; + next_run[11] = next_run[15] = tex_y + 1; + next_run[19] = tex_y; } // decrement the number of cycles left to run for and increment the diff --git a/Outputs/CRT.hpp b/Outputs/CRT.hpp index 6fdc68b2d..4639d8e4a 100644 --- a/Outputs/CRT.hpp +++ b/Outputs/CRT.hpp @@ -44,7 +44,7 @@ struct CRTFrameBuilder { int _write_target_pointer; }; -static const int kCRTNumberOfFrames = 3; +static const int kCRTNumberOfFrames = 4; class CRT { public: