diff --git a/OSBindings/Mac/Clock Signal/Atari2600.h b/OSBindings/Mac/Clock Signal/Atari2600.h index 8e317f15b..ae445338a 100644 --- a/OSBindings/Mac/Clock Signal/Atari2600.h +++ b/OSBindings/Mac/Clock Signal/Atari2600.h @@ -7,19 +7,13 @@ // #import - -@class CSAtari2600; -@protocol CSAtari2600Delegate -- (void)atari2600NeedsRedraw:(CSAtari2600 *)atari2600; -@end +#import "OpenGLView.h" @interface CSAtari2600 : NSObject -@property (nonatomic, weak) id delegate; +@property (nonatomic, strong) CSCathodeRayView *view; - (void)runForNumberOfCycles:(int)cycles; - (void)setROM:(NSData *)rom; -- (void)draw; - @end diff --git a/OSBindings/Mac/Clock Signal/Atari2600.mm b/OSBindings/Mac/Clock Signal/Atari2600.mm index b768eac5a..3a6ec50b5 100644 --- a/OSBindings/Mac/Clock Signal/Atari2600.mm +++ b/OSBindings/Mac/Clock Signal/Atari2600.mm @@ -8,31 +8,6 @@ #import "Atari2600.h" #import "Atari2600.hpp" -#import - -const char *vertexShader = - "#version 150\n" - "\n" - "in vec2 position;\n" - "\n" - "out vec4 colour;\n" - "\n" - "void main (void)\n" - "{\n" - "colour = vec4(1.0, 1.0, 1.0, 1.0);\n" - "gl_Position = vec4(position.x * 2.0 - 1.0, 1.0 - position.y * 2.0, 0.0, 1.0);\n" - "}\n"; - -const char *fragmentShader = - "#version 150\n" - "\n" - "in vec4 colour;\n" - "out vec4 fragColour;\n" - "\n" - "void main(void)\n" - "{\n" - "fragColour = colour;\n" - "}\n"; @interface CSAtari2600 (Callbacks) - (void)crtDidEndFrame:(CRTFrame *)frame; @@ -48,79 +23,21 @@ struct Atari2600CRTDelegate: public Outputs::CRT::CRTDelegate { Atari2600CRTDelegate _crtDelegate; dispatch_queue_t _serialDispatchQueue; - CRTFrame *_queuedFrame; - - GLuint _vertexShader, _fragmentShader; - GLuint _shaderProgram; - - GLuint _arrayBuffer, _vertexArray; } - (void)crtDidEndFrame:(CRTFrame *)frame { dispatch_async(dispatch_get_main_queue(), ^{ - if(_queuedFrame) { + BOOL hasReturn = !!self.view.crtFrame; + self.view.crtFrame = frame; + + if(hasReturn) dispatch_async(_serialDispatchQueue, ^{ _atari2600.get_crt()->return_frame(); }); - } - _queuedFrame = frame; - - [self.delegate atari2600NeedsRedraw:self]; }); } -- (GLuint)compileShader:(const char *)source type:(GLenum)type -{ - GLuint shader = glCreateShader(type); - glShaderSource(shader, 1, &source, NULL); - glCompileShader(shader); - return shader; -} - -- (void)draw { - - if(!_shaderProgram) - { - _shaderProgram = glCreateProgram(); - _vertexShader = [self compileShader:vertexShader type:GL_VERTEX_SHADER]; - _fragmentShader = [self compileShader:fragmentShader type:GL_FRAGMENT_SHADER]; - - glAttachShader(_shaderProgram, _vertexShader); - glAttachShader(_shaderProgram, _fragmentShader); - glLinkProgram(_shaderProgram); - - glGenVertexArrays(1, &_vertexArray); - glBindVertexArray(_vertexArray); - glGenBuffers(1, &_arrayBuffer); - glBindBuffer(GL_ARRAY_BUFFER, _arrayBuffer); - - GLushort vertices[] = { - 0, 0, - 32767, 32767, - }; - - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW); - } - - if(_queuedFrame) - { - glClearColor(1.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); - - glUseProgram(_shaderProgram); - - GLint position = glGetAttribLocation(_shaderProgram, "position"); - - glBufferData(GL_ARRAY_BUFFER, _queuedFrame->number_of_runs * sizeof(GLushort) * 8, _queuedFrame->runs, GL_DYNAMIC_DRAW); - - glEnableVertexAttribArray(position); - glVertexAttribPointer(position, 2, GL_UNSIGNED_SHORT, GL_TRUE, 4 * sizeof(GLushort), (void *)0); - - glDrawArrays(GL_LINES, 0, _queuedFrame->number_of_runs*2); - } -} - - (void)runForNumberOfCycles:(int)cycles { dispatch_async(_serialDispatchQueue, ^{ _atari2600.run_for_cycles(cycles); diff --git a/OSBindings/Mac/Clock Signal/Atari2600Document.swift b/OSBindings/Mac/Clock Signal/Atari2600Document.swift index 79f5fea35..a23362ac4 100644 --- a/OSBindings/Mac/Clock Signal/Atari2600Document.swift +++ b/OSBindings/Mac/Clock Signal/Atari2600Document.swift @@ -8,18 +8,19 @@ import Cocoa -class Atari2600Document: NSDocument, CSOpenGLViewDelegate, CSAtari2600Delegate { +class Atari2600Document: NSDocument, CSCathodeRayViewDelegate { override init() { super.init() // Add your subclass-specific initialization here. } - @IBOutlet weak var openGLView: CSOpenGLView? + @IBOutlet weak var openGLView: CSCathodeRayView? override func windowControllerDidLoadNib(aController: NSWindowController) { super.windowControllerDidLoadNib(aController) openGLView!.delegate = self + atari2600!.view = openGLView! // bind the content aspect ratio to remain 4:3 from now on aController.window!.contentAspectRatio = NSSize(width: 4.0, height: 3.0) @@ -45,13 +46,12 @@ class Atari2600Document: NSDocument, CSOpenGLViewDelegate, CSAtari2600Delegate { override func readFromData(data: NSData, ofType typeName: String) throws { atari2600 = CSAtari2600() atari2600!.setROM(data) - atari2600!.delegate = self } // MARK: CSOpenGLViewDelegate private var lastCycleCount: Int64? - func openGLView(view: CSOpenGLView!, didUpdateToTime time: CVTimeStamp) { + func openGLView(view: CSCathodeRayView, didUpdateToTime time: CVTimeStamp) { // TODO: treat time as a delta from old time, work out how many cycles that is plus error @@ -70,10 +70,6 @@ class Atari2600Document: NSDocument, CSOpenGLViewDelegate, CSAtari2600Delegate { lastCycleCount = cycleCount } - func openGLViewDrawView(view: CSOpenGLView!) { - atari2600!.draw() - } - // MARK: CSAtari2600Delegate func atari2600NeedsRedraw(atari2600: CSAtari2600!) { diff --git a/OSBindings/Mac/Clock Signal/Base.lproj/Atari2600Document.xib b/OSBindings/Mac/Clock Signal/Base.lproj/Atari2600Document.xib index 226f770d5..7b0cbf2ac 100644 --- a/OSBindings/Mac/Clock Signal/Base.lproj/Atari2600Document.xib +++ b/OSBindings/Mac/Clock Signal/Base.lproj/Atari2600Document.xib @@ -23,7 +23,7 @@ - + diff --git a/OSBindings/Mac/Clock Signal/OpenGLView.h b/OSBindings/Mac/Clock Signal/OpenGLView.h index f1add96a3..0b98f7685 100644 --- a/OSBindings/Mac/Clock Signal/OpenGLView.h +++ b/OSBindings/Mac/Clock Signal/OpenGLView.h @@ -7,17 +7,18 @@ // #import -@import AppKit; +#import "CRTFrame.h" +#import -@class CSOpenGLView; +@class CSCathodeRayView; -@protocol CSOpenGLViewDelegate -- (void)openGLView:(CSOpenGLView *)view didUpdateToTime:(CVTimeStamp)time; -- (void)openGLViewDrawView:(CSOpenGLView *)view; +@protocol CSCathodeRayViewDelegate +- (void)openGLView:(CSCathodeRayView * __nonnull)view didUpdateToTime:(CVTimeStamp)time; @end -@interface CSOpenGLView : NSOpenGLView +@interface CSCathodeRayView : NSOpenGLView -@property (nonatomic, weak) id delegate; +@property (nonatomic, weak) id delegate; +@property (nonatomic, assign, nullable) CRTFrame *crtFrame; @end diff --git a/OSBindings/Mac/Clock Signal/OpenGLView.m b/OSBindings/Mac/Clock Signal/OpenGLView.m index 73aadd41a..75b29bffe 100644 --- a/OSBindings/Mac/Clock Signal/OpenGLView.m +++ b/OSBindings/Mac/Clock Signal/OpenGLView.m @@ -8,10 +8,16 @@ #import "OpenGLView.h" @import CoreVideo; -#import +#import +#import -@implementation CSOpenGLView { +@implementation CSCathodeRayView { CVDisplayLinkRef displayLink; + + GLuint _vertexShader, _fragmentShader; + GLuint _shaderProgram; + GLuint _arrayBuffer, _vertexArray; + GLint _positionAttribute; } - (void)prepareOpenGL @@ -30,14 +36,18 @@ CGLContextObj cglContext = [[self openGLContext] CGLContextObj]; CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj]; CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat); - + + // get the shader ready, set the clear colour + glClearColor(1.0, 0.0, 0.0, 1.0); + [self prepareShader]; + // Activate the display link CVDisplayLinkStart(displayLink); } static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) { - CSOpenGLView *view = (__bridge CSOpenGLView *)displayLinkContext; + CSCathodeRayView *view = (__bridge CSCathodeRayView *)displayLinkContext; [view.delegate openGLView:view didUpdateToTime:*now]; return kCVReturnSuccess; } @@ -58,15 +68,6 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt glViewport(0, 0, viewSize.x, viewSize.y); } -- (void)drawRect:(NSRect)dirtyRect -{ - [self.openGLContext makeCurrentContext]; - - [self.delegate openGLViewDrawView:self]; - - glSwapAPPLE(); -} - - (void) awakeFromNib { NSOpenGLPixelFormatAttribute attributes[] = @@ -93,4 +94,80 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt self.wantsBestResolutionOpenGLSurface = YES; } +- (void)setCrtFrame:(CRTFrame *)crtFrame +{ + _crtFrame = crtFrame; + [self setNeedsDisplay:YES]; +} + +#pragma mark - Frame output + +const char *vertexShader = + "#version 150\n" + "\n" + "in vec2 position;\n" + "\n" + "out vec4 colour;\n" + "\n" + "void main (void)\n" + "{\n" + "colour = vec4(1.0, 1.0, 1.0, 1.0);\n" + "gl_Position = vec4(position.x * 2.0 - 1.0, 1.0 - position.y * 2.0, 0.0, 1.0);\n" + "}\n"; + +const char *fragmentShader = + "#version 150\n" + "\n" + "in vec4 colour;\n" + "out vec4 fragColour;\n" + "\n" + "void main(void)\n" + "{\n" + "fragColour = colour;\n" + "}\n"; + +- (GLuint)compileShader:(const char *)source type:(GLenum)type +{ + GLuint shader = glCreateShader(type); + glShaderSource(shader, 1, &source, NULL); + glCompileShader(shader); + return shader; +} + +- (void)prepareShader +{ + _shaderProgram = glCreateProgram(); + _vertexShader = [self compileShader:vertexShader type:GL_VERTEX_SHADER]; + _fragmentShader = [self compileShader:fragmentShader type:GL_FRAGMENT_SHADER]; + + glAttachShader(_shaderProgram, _vertexShader); + glAttachShader(_shaderProgram, _fragmentShader); + glLinkProgram(_shaderProgram); + + glGenVertexArrays(1, &_vertexArray); + glBindVertexArray(_vertexArray); + glGenBuffers(1, &_arrayBuffer); + glBindBuffer(GL_ARRAY_BUFFER, _arrayBuffer); + + glUseProgram(_shaderProgram); + _positionAttribute = glGetAttribLocation(_shaderProgram, "position"); + glEnableVertexAttribArray(_positionAttribute); + glVertexAttribPointer(_positionAttribute, 2, GL_UNSIGNED_SHORT, GL_TRUE, 4 * sizeof(GLushort), (void *)0); +} + +- (void)drawRect:(NSRect)dirtyRect +{ + [self.openGLContext makeCurrentContext]; + + glClear(GL_COLOR_BUFFER_BIT); + + if (_crtFrame) + { + glBufferData(GL_ARRAY_BUFFER, _crtFrame->number_of_runs * sizeof(GLushort) * 8, _crtFrame->runs, GL_DYNAMIC_DRAW); + glDrawArrays(GL_LINES, 0, _crtFrame->number_of_runs*2); + } + + glSwapAPPLE(); +} + @end diff --git a/Outputs/CRTFrame.h b/Outputs/CRTFrame.h index 0e4fa8176..72186e924 100644 --- a/Outputs/CRTFrame.h +++ b/Outputs/CRTFrame.h @@ -13,16 +13,16 @@ extern "C" { #endif -struct CRTBuffer { +typedef struct { uint8_t *data; int depth; -}; +} CRTBuffer; typedef struct { int width, height; } CRTSize; -struct CRTFrame { +typedef struct { CRTSize size, dirty_size; int number_of_buffers; @@ -30,7 +30,7 @@ struct CRTFrame { int number_of_runs; uint16_t *runs; -}; +} CRTFrame; #ifdef __cplusplus }