mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-24 12:30:17 +00:00
Factored out a few more constants, started trying to ensure there's enough slack and the mechanisms in place for the CathodeRayView to hold onto two frames if it desires, for potential phosphor simulation, switched once again to additive blending — much more like a real CRT — and added a sine function across the width of spans per my understanding of how an electron gun actually fires.
Why do all this when overall timing is still so far off? It helps me more easily see how overall timing is so far off.
This commit is contained in:
parent
c1d1fb65cb
commit
a5d66e9dd6
@ -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;
|
||||
|
@ -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, ^{
|
||||
|
@ -19,8 +19,9 @@
|
||||
@interface CSCathodeRayView : NSOpenGLView
|
||||
|
||||
@property (nonatomic, weak) id <CSCathodeRayViewDelegate> delegate;
|
||||
@property (nonatomic, assign, nullable) CRTFrame *crtFrame;
|
||||
|
||||
- (void)invalidate;
|
||||
|
||||
- (BOOL)pushFrame:(CRTFrame * __nonnull)crtFrame;
|
||||
|
||||
@end
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -44,7 +44,7 @@ struct CRTFrameBuilder {
|
||||
int _write_target_pointer;
|
||||
};
|
||||
|
||||
static const int kCRTNumberOfFrames = 3;
|
||||
static const int kCRTNumberOfFrames = 4;
|
||||
|
||||
class CRT {
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user