diff --git a/Machines/Atari2600/Atari2600.cpp b/Machines/Atari2600/Atari2600.cpp index 3cd0d00be..13d370462 100644 --- a/Machines/Atari2600/Atari2600.cpp +++ b/Machines/Atari2600/Atari2600.cpp @@ -25,6 +25,14 @@ Machine::Machine() : _tiaInputValue{0xff, 0xff} { _crt = new Outputs::CRT(228, Outputs::CRT::DisplayType::NTSC60, 1, 2); + _crt->set_composite_sampling_function( + "float sample(vec2 coordinate, float phase)\n" + "{\n" + "vec2 c = texture(texID, coordinate).rg;" + "float y = 0.1 + c.x * 0.91071428571429;\n" + "float aOffset = 6.283185308 * (c.y - 3.0 / 16.0) * 1.14285714285714;\n" + "return y + step(0.03125, c.y) * 0.1 * cos(phase - aOffset);\n" + "}"); memset(_collisions, 0xff, sizeof(_collisions)); set_reset_line(true); } @@ -147,19 +155,6 @@ void Machine::get_output_pixel(uint8_t *pixel, int offset) pixel[1] = outputColour&0xf0; } -const char *Machine::get_signal_decoder() -{ - return - "float sample(vec2 coordinate, float phase)\n" - "{\n" - "vec2 c = texture(texID, coordinate).rg;" - "float y = 0.1 + c.x * 0.91071428571429;\n" - "float aOffset = 6.283185308 * (c.y - 3.0 / 16.0) * 1.14285714285714;\n" - "return y + step(0.03125, c.y) * 0.1 * cos(phase - aOffset);\n" - "}"; -} - - // in imputing the knowledge that all we're dealing with is the rollover from 159 to 0, // this is faster than the straightforward +1)%160 per profiling #define increment_object_counter(c) _objectCounter[c] = (_objectCounter[c]+1)&~((158-_objectCounter[c]) >> 8) diff --git a/Machines/Atari2600/Atari2600.hpp b/Machines/Atari2600/Atari2600.hpp index 7b65b9db2..8c77f8605 100644 --- a/Machines/Atari2600/Atari2600.hpp +++ b/Machines/Atari2600/Atari2600.hpp @@ -10,7 +10,7 @@ #define Atari2600_cpp #include "../../Processors/6502/CPU6502.hpp" -#include "../../Outputs/CRT.hpp" +#include "../../Outputs/CRT/CRT.hpp" #include #include "Atari2600Inputs.h" @@ -19,7 +19,6 @@ namespace Atari2600 { class Machine: public CPU6502::Processor { public: - Machine(); ~Machine(); @@ -32,8 +31,6 @@ class Machine: public CPU6502::Processor { Outputs::CRT *get_crt() { return _crt; } - const char *get_signal_decoder(); - private: uint8_t *_rom, *_romPages[4], _ram[128]; size_t _rom_size; diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index 44bacb00d..825fe437f 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -29,6 +29,13 @@ Machine::Machine() : _currentOutputLine(0), _crt(Outputs::CRT(crt_cycles_per_line, Outputs::CRT::DisplayType::PAL50, 1, 1)) { + _crt.set_rgb_sampling_function( + "vec4 sample(vec2 coordinate)\n" + "{\n" + "float texValue = texture(texID, coordinate).r;\n" + "return vec4( step(4.0/256.0, mod(texValue, 8.0/256.0)), step(2.0/256.0, mod(texValue, 4.0/256.0)), step(1.0/256.0, mod(texValue, 2.0/256.0)), 1.0);\n" + "}"); + memset(_keyStates, 0, sizeof(_keyStates)); memset(_palette, 0xf, sizeof(_palette)); _interruptStatus = 0x02; @@ -455,7 +462,7 @@ inline void Machine::update_display() } - int pixels_to_output = std::min(_frameCycles - _displayOutputPosition, 104 - line_position); + int pixels_to_output = std::min(104 - line_position, cycles_left); _displayOutputPosition += pixels_to_output; // printf("<- %d ->", pixels_to_output); if(_screenMode >= 4) @@ -528,7 +535,7 @@ inline void Machine::update_display() if(line_position >= 104) { - int pixels_to_output = std::min(_frameCycles - _displayOutputPosition, 128 - line_position); + int pixels_to_output = std::min(128 - line_position, cycles_left); _crt.output_blank((unsigned int)pixels_to_output * crt_cycles_multiplier); _displayOutputPosition += pixels_to_output; @@ -556,16 +563,6 @@ inline void Machine::update_display() } } -const char *Machine::get_signal_decoder() -{ - return - "vec4 sample(vec2 coordinate)\n" - "{\n" - "float texValue = texture(texID, coordinate).r;\n" - "return vec4( step(4.0/256.0, mod(texValue, 8.0/256.0)), step(2.0/256.0, mod(texValue, 4.0/256.0)), step(1.0/256.0, mod(texValue, 2.0/256.0)), 1.0);\n" - "}"; -} - void Machine::set_key_state(Key key, bool isPressed) { if(key == KeyBreak) diff --git a/Machines/Electron/Electron.hpp b/Machines/Electron/Electron.hpp index d730be65a..af80ed2de 100644 --- a/Machines/Electron/Electron.hpp +++ b/Machines/Electron/Electron.hpp @@ -10,7 +10,7 @@ #define Electron_hpp #include "../../Processors/6502/CPU6502.hpp" -#include "../../Outputs/CRT.hpp" +#include "../../Outputs/CRT/CRT.hpp" #include "../../Outputs/Speaker.hpp" #include "../../Storage/Tape/Tape.hpp" #include @@ -148,7 +148,6 @@ class Machine: public CPU6502::Processor, Tape::Delegate { Outputs::CRT *get_crt() { return &_crt; } Outputs::Speaker *get_speaker() { return &_speaker; } - const char *get_signal_decoder(); virtual void tape_did_change_interrupt_status(Tape *tape); diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 24c2b772f..c60adc189 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0CCC421C62D0B3001CAC5F /* CRT.cpp */; }; + 4B0CCC471C62D1A8001CAC5F /* CRTOpenGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0CCC461C62D1A8001CAC5F /* CRTOpenGL.cpp */; }; 4B0EBFB81C487F2F00A11F35 /* AudioQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B0EBFB71C487F2F00A11F35 /* AudioQueue.m */; }; 4B14145B1B58879D00E04248 /* CPU6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* CPU6502.cpp */; }; 4B14145D1B5887A600E04248 /* CPU6502.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1414571B58879D00E04248 /* CPU6502.cpp */; }; @@ -17,7 +19,6 @@ 4B2E2D951C399D1200138695 /* ElectronDocument.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B2E2D931C399D1200138695 /* ElectronDocument.xib */; }; 4B2E2D9A1C3A06EC00138695 /* Atari2600.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D971C3A06EC00138695 /* Atari2600.cpp */; }; 4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D9B1C3A070400138695 /* Electron.cpp */; }; - 4B366DFC1B5C165A0026627B /* CRT.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B366DFA1B5C165A0026627B /* CRT.cpp */; }; 4B55CE4B1C3B3B0C0093A61B /* CSAtari2600.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE4A1C3B3B0C0093A61B /* CSAtari2600.mm */; }; 4B55CE4E1C3B3BDA0093A61B /* CSMachine.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE4D1C3B3BDA0093A61B /* CSMachine.mm */; }; 4B55CE541C3B7ABF0093A61B /* CSElectron.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B55CE531C3B7ABF0093A61B /* CSElectron.mm */; }; @@ -28,6 +29,7 @@ 4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB3B1C4D908A00B5F0AA /* Tape.cpp */; }; 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B69FB421C4D941400B5F0AA /* TapeUEF.cpp */; }; 4B69FB461C4D950F00B5F0AA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B69FB451C4D950F00B5F0AA /* libz.tbd */; }; + 4B7BFEFE1C6446EF00089C1C /* CRTFrameBuilder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7BFEFD1C6446EF00089C1C /* CRTFrameBuilder.cpp */; }; 4B92EACA1B7C112B00246143 /* TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* TimingTests.swift */; }; 4BB298EE1B587D8400A49093 /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E01B587D8300A49093 /* 6502_functional_test.bin */; }; 4BB298EF1B587D8400A49093 /* AllSuiteA.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4BB297E11B587D8300A49093 /* AllSuiteA.bin */; }; @@ -325,6 +327,10 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 4B0CCC421C62D0B3001CAC5F /* CRT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CRT.cpp; sourceTree = ""; }; + 4B0CCC431C62D0B3001CAC5F /* CRT.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CRT.hpp; sourceTree = ""; }; + 4B0CCC441C62D0B3001CAC5F /* CRTFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CRTFrame.h; sourceTree = ""; }; + 4B0CCC461C62D1A8001CAC5F /* CRTOpenGL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CRTOpenGL.cpp; sourceTree = ""; }; 4B0EBFB61C487F2F00A11F35 /* AudioQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioQueue.h; sourceTree = ""; }; 4B0EBFB71C487F2F00A11F35 /* AudioQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AudioQueue.m; sourceTree = ""; }; 4B1414501B58848C00E04248 /* ClockSignal-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ClockSignal-Bridging-Header.h"; sourceTree = ""; }; @@ -337,15 +343,12 @@ 4B2409531C45AB05004DA684 /* Speaker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Speaker.cpp; path = ../../Outputs/Speaker.cpp; sourceTree = ""; }; 4B2409541C45AB05004DA684 /* Speaker.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Speaker.hpp; path = ../../Outputs/Speaker.hpp; sourceTree = ""; }; 4B24095A1C45DF85004DA684 /* Stepper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Stepper.hpp; sourceTree = ""; }; - 4B2632551B631A510082A461 /* CRTFrame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CRTFrame.h; path = ../../Outputs/CRTFrame.h; sourceTree = ""; }; 4B2E2D941C399D1200138695 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ElectronDocument.xib; sourceTree = ""; }; 4B2E2D971C3A06EC00138695 /* Atari2600.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Atari2600.cpp; sourceTree = ""; }; 4B2E2D981C3A06EC00138695 /* Atari2600.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Atari2600.hpp; sourceTree = ""; }; 4B2E2D991C3A06EC00138695 /* Atari2600Inputs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Atari2600Inputs.h; sourceTree = ""; }; 4B2E2D9B1C3A070400138695 /* Electron.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Electron.cpp; path = Electron/Electron.cpp; sourceTree = ""; }; 4B2E2D9C1C3A070400138695 /* Electron.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Electron.hpp; path = Electron/Electron.hpp; sourceTree = ""; }; - 4B366DFA1B5C165A0026627B /* CRT.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CRT.cpp; path = ../../Outputs/CRT.cpp; sourceTree = ""; }; - 4B366DFB1B5C165A0026627B /* CRT.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = CRT.hpp; path = ../../Outputs/CRT.hpp; sourceTree = ""; }; 4B55CE491C3B3B0C0093A61B /* CSAtari2600.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSAtari2600.h; sourceTree = ""; }; 4B55CE4A1C3B3B0C0093A61B /* CSAtari2600.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSAtari2600.mm; sourceTree = ""; }; 4B55CE4C1C3B3BDA0093A61B /* CSMachine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSMachine.h; sourceTree = ""; }; @@ -363,6 +366,7 @@ 4B69FB421C4D941400B5F0AA /* TapeUEF.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TapeUEF.cpp; sourceTree = ""; }; 4B69FB431C4D941400B5F0AA /* TapeUEF.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = TapeUEF.hpp; sourceTree = ""; }; 4B69FB451C4D950F00B5F0AA /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; + 4B7BFEFD1C6446EF00089C1C /* CRTFrameBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CRTFrameBuilder.cpp; sourceTree = ""; }; 4B92EAC91B7C112B00246143 /* TimingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimingTests.swift; sourceTree = ""; }; 4BAE587D1C447B7A005B9AF0 /* KeyCodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyCodes.h; sourceTree = ""; }; 4BB297DF1B587D8200A49093 /* Clock SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Clock SignalTests-Bridging-Header.h"; sourceTree = ""; }; @@ -678,6 +682,19 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 4B0CCC411C62D0B3001CAC5F /* CRT */ = { + isa = PBXGroup; + children = ( + 4B0CCC421C62D0B3001CAC5F /* CRT.cpp */, + 4B0CCC431C62D0B3001CAC5F /* CRT.hpp */, + 4B0CCC441C62D0B3001CAC5F /* CRTFrame.h */, + 4B0CCC461C62D1A8001CAC5F /* CRTOpenGL.cpp */, + 4B7BFEFD1C6446EF00089C1C /* CRTFrameBuilder.cpp */, + ); + name = CRT; + path = ../../Outputs/CRT; + sourceTree = ""; + }; 4B1414561B58879D00E04248 /* 6502 */ = { isa = PBXGroup; children = ( @@ -730,9 +747,7 @@ 4B366DFD1B5C165F0026627B /* Outputs */ = { isa = PBXGroup; children = ( - 4B366DFA1B5C165A0026627B /* CRT.cpp */, - 4B366DFB1B5C165A0026627B /* CRT.hpp */, - 4B2632551B631A510082A461 /* CRTFrame.h */, + 4B0CCC411C62D0B3001CAC5F /* CRT */, 4B2409531C45AB05004DA684 /* Speaker.cpp */, 4B2409541C45AB05004DA684 /* Speaker.hpp */, ); @@ -1588,10 +1603,13 @@ buildActionMask = 2147483647; files = ( 4B55CE541C3B7ABF0093A61B /* CSElectron.mm in Sources */, + 4B0CCC451C62D0B3001CAC5F /* CRT.cpp in Sources */, 4B55CE591C3B7D360093A61B /* ElectronDocument.swift in Sources */, 4B55CE4B1C3B3B0C0093A61B /* CSAtari2600.mm in Sources */, 4B55CE581C3B7D360093A61B /* Atari2600Document.swift in Sources */, + 4B0CCC471C62D1A8001CAC5F /* CRTOpenGL.cpp in Sources */, 4B0EBFB81C487F2F00A11F35 /* AudioQueue.m in Sources */, + 4B7BFEFE1C6446EF00089C1C /* CRTFrameBuilder.cpp in Sources */, 4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */, 4B69FB441C4D941400B5F0AA /* TapeUEF.cpp in Sources */, 4B2409551C45AB05004DA684 /* Speaker.cpp in Sources */, @@ -1599,7 +1617,6 @@ 4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */, 4B69FB3D1C4D908A00B5F0AA /* Tape.cpp in Sources */, 4B55CE5D1C3B7D6F0093A61B /* CSCathodeRayView.m in Sources */, - 4B366DFC1B5C165A0026627B /* CRT.cpp in Sources */, 4B2E2D9A1C3A06EC00138695 /* Atari2600.cpp in Sources */, 4B14145B1B58879D00E04248 /* CPU6502.cpp in Sources */, 4BB73EA21B587A5100552FC2 /* AppDelegate.swift in Sources */, diff --git a/OSBindings/Mac/Clock Signal/Documents/Atari2600Document.swift b/OSBindings/Mac/Clock Signal/Documents/Atari2600Document.swift index ba88e0797..ec6b1e3ce 100644 --- a/OSBindings/Mac/Clock Signal/Documents/Atari2600Document.swift +++ b/OSBindings/Mac/Clock Signal/Documents/Atari2600Document.swift @@ -19,7 +19,7 @@ class Atari2600Document: MachineDocument { override func windowControllerDidLoadNib(aController: NSWindowController) { super.windowControllerDidLoadNib(aController) atari2600.view = openGLView - openGLView.frameBounds = CGRectMake(0.1, 0.1, 0.8, 0.8) +// openGLView.frameBounds = CGRectMake(0.1, 0.1, 0.8, 0.8) } override class func autosavesInPlace() -> Bool { diff --git a/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift b/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift index ba3243a39..43cb38475 100644 --- a/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/ElectronDocument.swift @@ -61,6 +61,10 @@ class ElectronDocument: MachineDocument { electron.runForNumberOfCycles(numberOfCycles) } + override func openGLViewDrawView(view: CSCathodeRayView) { + electron.drawViewForPixelSize(view.backingSize) + } + // MARK: CSOpenGLViewResponderDelegate override func keyDown(event: NSEvent) { electron.setKey(event.keyCode, isPressed: true) diff --git a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift index 428cc05a0..126eb2a9d 100644 --- a/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift +++ b/OSBindings/Mac/Clock Signal/Documents/MachineDocument.swift @@ -46,6 +46,7 @@ class MachineDocument: NSDocument, CSCathodeRayViewDelegate, CSCathodeRayViewRes lastCycleCount = cycleCount } + func openGLViewDrawView(view: CSCathodeRayView) {} func runForNumberOfCycles(numberOfCycles: Int32) {} // MARK: CSOpenGLViewResponderDelegate diff --git a/OSBindings/Mac/Clock Signal/Views/CSCathodeRayView.h b/OSBindings/Mac/Clock Signal/Views/CSCathodeRayView.h index 5eff05a12..abecc655b 100644 --- a/OSBindings/Mac/Clock Signal/Views/CSCathodeRayView.h +++ b/OSBindings/Mac/Clock Signal/Views/CSCathodeRayView.h @@ -7,13 +7,13 @@ // #import -#import "CRTFrame.h" #import @class CSCathodeRayView; @protocol CSCathodeRayViewDelegate - (void)openGLView:(nonnull CSCathodeRayView *)view didUpdateToTime:(CVTimeStamp)time; +- (void)openGLViewDrawView:(nonnull CSCathodeRayView *)view; @end @protocol CSCathodeRayViewResponderDelegate @@ -22,10 +22,6 @@ - (void)flagsChanged:(nonnull NSEvent *)newModifiers; @end -typedef NS_ENUM(NSInteger, CSCathodeRayViewSignalType) { - CSCathodeRayViewSignalTypeNTSC, - CSCathodeRayViewSignalTypeRGB -}; @interface CSCathodeRayView : NSOpenGLView @@ -34,11 +30,6 @@ typedef NS_ENUM(NSInteger, CSCathodeRayViewSignalType) { - (void)invalidate; -- (BOOL)pushFrame:(nonnull CRTFrame *)crtFrame; -- (void)setSignalDecoder:(nonnull NSString *)decoder type:(CSCathodeRayViewSignalType)type; - -// these are relative to a [0, 1] range in both width and height; -// default is .origin = (0, 0), .size = (1, 1) -@property (nonatomic, assign) CGRect frameBounds; +@property (nonatomic, readonly) CGSize backingSize; @end diff --git a/OSBindings/Mac/Clock Signal/Views/CSCathodeRayView.m b/OSBindings/Mac/Clock Signal/Views/CSCathodeRayView.m index 7f08a7107..45a9a3f64 100644 --- a/OSBindings/Mac/Clock Signal/Views/CSCathodeRayView.m +++ b/OSBindings/Mac/Clock Signal/Views/CSCathodeRayView.m @@ -10,38 +10,16 @@ @import CoreVideo; @import GLKit; #import -#import -#import +//#import +//#import @implementation CSCathodeRayView { - CVDisplayLinkRef displayLink; - - GLuint _vertexShader, _fragmentShader; - GLuint _shaderProgram; - GLuint _arrayBuffer, _vertexArray; - GLint _positionAttribute; - GLint _textureCoordinatesAttribute; - GLint _lateralAttribute; - - GLint _textureSizeUniform, _windowSizeUniform; - GLint _boundsOriginUniform, _boundsSizeUniform; - GLint _alphaUniform; - - GLuint _textureName, _shadowMaskTextureName; - CRTSize _textureSize; - - CRTFrame *_crtFrame; - - NSString *_signalDecoder; - CSCathodeRayViewSignalType _signalType; - int32_t _signalDecoderGeneration; - int32_t _compiledSignalDecoderGeneration; - + CVDisplayLinkRef _displayLink; CGRect _aspectRatioCorrectedBounds; } -- (GLuint)textureForImageNamed:(NSString *)name +/*- (GLuint)textureForImageNamed:(NSString *)name { NSImage *const image = [NSImage imageNamed:name]; NSBitmapImageRep *bitmapRepresentation = [[NSBitmapImageRep alloc] initWithData: [image TIFFRepresentation]]; @@ -57,7 +35,7 @@ glGenerateMipmap(GL_TEXTURE_2D); return textureName; -} +}*/ - (void)prepareOpenGL { @@ -66,29 +44,29 @@ [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; // Create a display link capable of being used with all active displays - CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); + CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink); // Set the renderer output callback function - CVDisplayLinkSetOutputCallback(displayLink, DisplayLinkCallback, (__bridge void * __nullable)(self)); + CVDisplayLinkSetOutputCallback(_displayLink, DisplayLinkCallback, (__bridge void * __nullable)(self)); // Set the display link for the current renderer CGLContextObj cglContext = [[self openGLContext] CGLContextObj]; CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj]; - CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat); + CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(_displayLink, cglContext, cglPixelFormat); // install the shadow mask texture as the second texture - glActiveTexture(GL_TEXTURE1); +/* glActiveTexture(GL_TEXTURE1); _shadowMaskTextureName = [self textureForImageNamed:@"ShadowMask"]; // otherwise, we'll be working on the first texture - glActiveTexture(GL_TEXTURE0); + glActiveTexture(GL_TEXTURE0);*/ // get the shader ready, set the clear colour [self.openGLContext makeCurrentContext]; glClearColor(0.0, 0.0, 0.0, 1.0); // Activate the display link - CVDisplayLinkStart(displayLink); + CVDisplayLinkStart(_displayLink); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE); @@ -103,27 +81,26 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt - (void)invalidate { - CVDisplayLinkStop(displayLink); + CVDisplayLinkStop(_displayLink); } - (void)dealloc { // Release the display link - CVDisplayLinkRelease(displayLink); + CVDisplayLinkRelease(_displayLink); // Release OpenGL buffers - [self.openGLContext makeCurrentContext]; - glDeleteBuffers(1, &_arrayBuffer); - glDeleteVertexArrays(1, &_vertexArray); - glDeleteTextures(1, &_textureName); - glDeleteTextures(1, &_shadowMaskTextureName); - glDeleteProgram(_shaderProgram); +// [self.openGLContext makeCurrentContext]; +// glDeleteBuffers(1, &_arrayBuffer); +// glDeleteVertexArrays(1, &_vertexArray); +// glDeleteTextures(1, &_textureName); +// glDeleteTextures(1, &_shadowMaskTextureName); +// glDeleteProgram(_shaderProgram); } -- (NSPoint)backingViewSize +- (CGSize)backingSize { - NSPoint backingSize = {.x = self.bounds.size.width, .y = self.bounds.size.height}; - return [self convertPointToBacking:backingSize]; + return [self convertSizeToBacking:self.bounds.size]; } - (void)reshape @@ -133,49 +110,49 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt [self.openGLContext makeCurrentContext]; CGLLockContext([[self openGLContext] CGLContextObj]); - NSPoint viewSize = [self backingViewSize]; - glViewport(0, 0, (GLsizei)viewSize.x, (GLsizei)viewSize.y); + CGSize viewSize = [self backingSize]; + glViewport(0, 0, (GLsizei)viewSize.width, (GLsizei)viewSize.height); - [self pushSizeUniforms]; +// [self pushSizeUniforms]; CGLUnlockContext([[self openGLContext] CGLContextObj]); } -- (void)setFrameBounds:(CGRect)frameBounds -{ - _frameBounds = frameBounds; - - [self.openGLContext makeCurrentContext]; - CGLLockContext([[self openGLContext] CGLContextObj]); - - [self pushSizeUniforms]; - - CGLUnlockContext([[self openGLContext] CGLContextObj]); -} - -- (void)pushSizeUniforms -{ - if(_shaderProgram) - { - NSPoint viewSize = [self backingViewSize]; - if(_windowSizeUniform >= 0) - { - glUniform2f(_windowSizeUniform, (GLfloat)viewSize.x, (GLfloat)viewSize.y); - } - - CGFloat outputAspectRatioMultiplier = (viewSize.x / viewSize.y) / (4.0 / 3.0); - -// NSLog(@"%0.2f v %0.2f", outputAspectRatio, desiredOutputAspectRatio); - _aspectRatioCorrectedBounds = _frameBounds; - - CGFloat bonusWidth = (outputAspectRatioMultiplier - 1.0f) * _frameBounds.size.width; - _aspectRatioCorrectedBounds.origin.x -= bonusWidth * 0.5f * _aspectRatioCorrectedBounds.size.width; - _aspectRatioCorrectedBounds.size.width *= outputAspectRatioMultiplier; - - if(_boundsOriginUniform >= 0) glUniform2f(_boundsOriginUniform, (GLfloat)_aspectRatioCorrectedBounds.origin.x, (GLfloat)_aspectRatioCorrectedBounds.origin.y); - if(_boundsSizeUniform >= 0) glUniform2f(_boundsSizeUniform, (GLfloat)_aspectRatioCorrectedBounds.size.width, (GLfloat)_aspectRatioCorrectedBounds.size.height); - } -} +//- (void)setFrameBounds:(CGRect)frameBounds +//{ +// _frameBounds = frameBounds; +// +// [self.openGLContext makeCurrentContext]; +// CGLLockContext([[self openGLContext] CGLContextObj]); +// +// [self pushSizeUniforms]; +// +// CGLUnlockContext([[self openGLContext] CGLContextObj]); +//} +// +//- (void)pushSizeUniforms +//{ +// if(_shaderProgram) +// { +// NSPoint viewSize = [self backingViewSize]; +// if(_windowSizeUniform >= 0) +// { +// glUniform2f(_windowSizeUniform, (GLfloat)viewSize.x, (GLfloat)viewSize.y); +// } +// +// CGFloat outputAspectRatioMultiplier = (viewSize.x / viewSize.y) / (4.0 / 3.0); +// +//// NSLog(@"%0.2f v %0.2f", outputAspectRatio, desiredOutputAspectRatio); +// _aspectRatioCorrectedBounds = _frameBounds; +// +// CGFloat bonusWidth = (outputAspectRatioMultiplier - 1.0f) * _frameBounds.size.width; +// _aspectRatioCorrectedBounds.origin.x -= bonusWidth * 0.5f * _aspectRatioCorrectedBounds.size.width; +// _aspectRatioCorrectedBounds.size.width *= outputAspectRatioMultiplier; +// +// if(_boundsOriginUniform >= 0) glUniform2f(_boundsOriginUniform, (GLfloat)_aspectRatioCorrectedBounds.origin.x, (GLfloat)_aspectRatioCorrectedBounds.origin.y); +// if(_boundsSizeUniform >= 0) glUniform2f(_boundsSizeUniform, (GLfloat)_aspectRatioCorrectedBounds.size.width, (GLfloat)_aspectRatioCorrectedBounds.size.height); +// } +//} - (void)awakeFromNib { @@ -205,10 +182,10 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt self.wantsBestResolutionOpenGLSurface = YES; // establish default instance variable values - self.frameBounds = CGRectMake(0.0, 0.0, 1.0, 1.0); +// self.frameBounds = CGRectMake(0.0, 0.0, 1.0, 1.0); } -- (GLint)formatForDepth:(unsigned int)depth +/*- (GLint)formatForDepth:(unsigned int)depth { switch(depth) { @@ -489,7 +466,7 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); -} +}*/ - (void)drawRect:(NSRect)dirtyRect { @@ -501,18 +478,20 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt [self.openGLContext makeCurrentContext]; CGLLockContext([[self openGLContext] CGLContextObj]); - while((!_shaderProgram || (_signalDecoderGeneration != _compiledSignalDecoderGeneration)) && _signalDecoder) { - _compiledSignalDecoderGeneration = _signalDecoderGeneration; - [self prepareShader]; - } - glClear(GL_COLOR_BUFFER_BIT); - - if (_crtFrame) - { - if(_textureSizeUniform >= 0) glUniform2f(_textureSizeUniform, _crtFrame->size.width, _crtFrame->size.height); - glDrawArrays(GL_TRIANGLES, 0, (GLsizei)_crtFrame->number_of_vertices); - } + [self.delegate openGLViewDrawView:self]; +// while((!_shaderProgram || (_signalDecoderGeneration != _compiledSignalDecoderGeneration)) && _signalDecoder) { +// _compiledSignalDecoderGeneration = _signalDecoderGeneration; +// [self prepareShader]; +// } +// +// glClear(GL_COLOR_BUFFER_BIT); +// +// if (_crtFrame) +// { +// if(_textureSizeUniform >= 0) glUniform2f(_textureSizeUniform, _crtFrame->size.width, _crtFrame->size.height); +// glDrawArrays(GL_TRIANGLES, 0, (GLsizei)_crtFrame->number_of_vertices); +// } CGLFlushDrawable([[self openGLContext] CGLContextObj]); CGLUnlockContext([[self openGLContext] CGLContextObj]); diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSAtari2600.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSAtari2600.mm index 49c47e6c3..80e9d564f 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSAtari2600.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSAtari2600.mm @@ -19,7 +19,7 @@ BOOL _didDecideRegion; } -- (void)crt:(Outputs::CRT *)crt didEndFrame:(CRTFrame *)frame didDetectVSync:(BOOL)didDetectVSync { +/*- (void)crt:(Outputs::CRT *)crt didEndFrame:(CRTFrame *)frame didDetectVSync:(BOOL)didDetectVSync { if(!_didDecideRegion) { _frameCount++; @@ -41,7 +41,7 @@ } [super crt:crt didEndFrame:frame didDetectVSync:didDetectVSync]; -} +}*/ - (void)doRunForNumberOfCycles:(int)numberOfCycles { _atari2600.run_for_cycles(numberOfCycles); @@ -65,13 +65,4 @@ }]; } -- (void)setView:(CSCathodeRayView *)view { - [super setView:view]; - [view setSignalDecoder:[NSString stringWithUTF8String:_atari2600.get_signal_decoder()] type:CSCathodeRayViewSignalTypeNTSC]; -} - -- (void)setCRTDelegate:(Outputs::CRT::Delegate *)delegate{ - _atari2600.get_crt()->set_delegate(delegate); -} - @end diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h b/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h index ca21d949d..a58cf49cc 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.h @@ -18,4 +18,6 @@ - (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed; +- (void)drawViewForPixelSize:(CGSize)pixelSize; + @end diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.mm index 54ce70b87..09a50c8f4 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSElectron.mm @@ -14,21 +14,9 @@ @implementation CSElectron { Electron::Machine _electron; - -// NSTimeInterval _periodicStart; -// int _numberOfCycles; } - (void)doRunForNumberOfCycles:(int)numberOfCycles { -/* _numberOfCycles += numberOfCycles; - NSTimeInterval timeNow = [NSDate timeIntervalSinceReferenceDate]; - NSTimeInterval difference = timeNow - _periodicStart; - if(difference > 1.0) - { - NSLog(@"cycles: %0.0f", (double)_numberOfCycles / difference); - _periodicStart = timeNow; - _numberOfCycles = 0; - }*/ _electron.run_for_cycles(numberOfCycles); } @@ -44,8 +32,8 @@ _electron.set_rom((Electron::ROMSlot)slot, rom.length, (const uint8_t *)rom.bytes); } -- (void)setCRTDelegate:(Outputs::CRT::Delegate *)delegate { - _electron.get_crt()->set_delegate(delegate); +- (void)drawViewForPixelSize:(CGSize)pixelSize { + _electron.get_crt()->draw_frame((int)pixelSize.width, (int)pixelSize.height); } - (BOOL)openUEFAtURL:(NSURL *)URL { @@ -67,7 +55,6 @@ - (void)setView:(CSCathodeRayView *)view { [super setView:view]; - [view setSignalDecoder:[NSString stringWithUTF8String:_electron.get_signal_decoder()] type:CSCathodeRayViewSignalTypeRGB]; } - (void)setKey:(uint16_t)key isPressed:(BOOL)isPressed { diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine+Subclassing.h b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine+Subclassing.h index 255af2ae1..0f991da4b 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine+Subclassing.h +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine+Subclassing.h @@ -13,12 +13,10 @@ @interface CSMachine (Subclassing) - (BOOL)setSpeakerDelegate:(Outputs::Speaker::Delegate *)delegate sampleRate:(int)sampleRate; -- (void)setCRTDelegate:(Outputs::CRT::Delegate *)delegate; - (void)doRunForNumberOfCycles:(int)numberOfCycles; - (void)perform:(dispatch_block_t)action; -- (void)crt:(Outputs::CRT *)crt didEndFrame:(CRTFrame *)frame didDetectVSync:(BOOL)didDetectVSync; - (void)speaker:(Outputs::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length; @end diff --git a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm index 0711abeec..a237f1eb7 100644 --- a/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm +++ b/OSBindings/Mac/Clock Signal/Wrappers/CSMachine.mm @@ -9,13 +9,6 @@ #import "CSMachine.h" #import "CSMachine+Subclassing.h" -struct CRTDelegate: public Outputs::CRT::Delegate { - __weak CSMachine *machine; - void crt_did_end_frame(Outputs::CRT *crt, CRTFrame *frame, bool did_detect_vsync) { - [machine crt:crt didEndFrame:frame didDetectVSync:did_detect_vsync]; - } -}; - struct SpeakerDelegate: public Outputs::Speaker::Delegate { __weak CSMachine *machine; void speaker_did_complete_samples(Outputs::Speaker *speaker, const int16_t *buffer, int buffer_size) { @@ -29,7 +22,6 @@ typedef NS_ENUM(NSInteger, CSAtari2600RunningState) { }; @implementation CSMachine { - CRTDelegate _crtDelegate; SpeakerDelegate _speakerDelegate; dispatch_queue_t _serialDispatchQueue; @@ -40,10 +32,6 @@ typedef NS_ENUM(NSInteger, CSAtari2600RunningState) { dispatch_async(_serialDispatchQueue, action); } -- (void)crt:(Outputs::CRT *)crt didEndFrame:(CRTFrame *)frame didDetectVSync:(BOOL)didDetectVSync { - if([self.view pushFrame:frame]) crt->return_frame(); -} - - (void)speaker:(Outputs::Speaker *)speaker didCompleteSamples:(const int16_t *)samples length:(int)length { [self.audioQueue enqueueAudioBuffer:samples numberOfSamples:(unsigned int)length]; } @@ -66,16 +54,13 @@ typedef NS_ENUM(NSInteger, CSAtari2600RunningState) { _serialDispatchQueue = dispatch_queue_create("Machine queue", DISPATCH_QUEUE_SERIAL); _runningLock = [[NSConditionLock alloc] initWithCondition:CSMachineRunningStateStopped]; - _crtDelegate.machine = self; _speakerDelegate.machine = self; - [self setCRTDelegate:&_crtDelegate]; [self setSpeakerDelegate:&_speakerDelegate sampleRate:44100]; } return self; } -- (void)setCRTDelegate:(Outputs::CRT::Delegate *)delegate {} - (BOOL)setSpeakerDelegate:(Outputs::Speaker::Delegate *)delegate sampleRate:(int)sampleRate { return NO; } diff --git a/Outputs/CRT.cpp b/Outputs/CRT/CRT.cpp similarity index 88% rename from Outputs/CRT.cpp rename to Outputs/CRT/CRT.cpp index e87d8b8c2..153059d4f 100644 --- a/Outputs/CRT.cpp +++ b/Outputs/CRT/CRT.cpp @@ -99,13 +99,14 @@ void CRT::allocate_buffers(unsigned int number, va_list sizes) CRT::CRT() : _next_scan(0), - _frames_with_delegate(0), _frame_read_pointer(0), _horizontal_counter(0), _sync_capacitor_charge_level(0), _is_receiving_sync(false), _is_in_hsync(false), _is_in_vsync(false), + _current_frame(nullptr), + _current_frame_mutex(new std::mutex), _rasterPosition({.x = 0, .y = 0}) {} @@ -332,21 +333,24 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi // end of vertical sync: tell the delegate that we finished vertical sync, // releasing all runs back into the common pool case SyncEvent::EndVSync: - if(_delegate && _current_frame_builder) + if(_current_frame_builder) { _current_frame_builder->complete(); - _frames_with_delegate++; - _delegate->crt_did_end_frame(this, &_current_frame_builder->frame, _did_detect_vsync); + _current_frame_mutex->lock(); + _current_frame = &_current_frame_builder->frame; + _current_frame_mutex->unlock(); + // TODO: how to communicate did_detect_vsync? Bring the delegate back? +// _delegate->crt_did_end_frame(this, &_current_frame_builder->frame, _did_detect_vsync); } - if(_frames_with_delegate < kCRTNumberOfFrames) +// if(_frames_with_delegate < kCRTNumberOfFrames) { _frame_read_pointer = (_frame_read_pointer + 1)%kCRTNumberOfFrames; _current_frame_builder = _frame_builders[_frame_read_pointer]; _current_frame_builder->reset(); } - else - _current_frame_builder = nullptr; +// else +// _current_frame_builder = nullptr; _is_in_vsync = false; _did_detect_vsync = false; @@ -358,18 +362,6 @@ void CRT::advance_cycles(unsigned int number_of_cycles, unsigned int source_divi } } -void CRT::return_frame() -{ - _frames_with_delegate--; -} - -#pragma mark - delegate - -void CRT::set_delegate(Delegate *delegate) -{ - _delegate = delegate; -} - #pragma mark - stream feeding methods void CRT::output_scan() @@ -443,82 +435,7 @@ uint8_t *CRT::get_write_target_for_buffer(int buffer) return _current_frame_builder->get_write_target_for_buffer(buffer); } -#pragma mark - CRTFrame -CRTFrameBuilder::CRTFrameBuilder(uint16_t width, uint16_t height, unsigned int number_of_buffers, va_list buffer_sizes) -{ - frame.size.width = width; - frame.size.height = height; - frame.number_of_buffers = number_of_buffers; - frame.buffers = new CRTBuffer[number_of_buffers]; - frame.size_per_vertex = kCRTSizeOfVertex; - frame.geometry_mode = CRTGeometryModeTriangles; - - for(int buffer = 0; buffer < number_of_buffers; buffer++) - { - frame.buffers[buffer].depth = va_arg(buffer_sizes, unsigned int); - frame.buffers[buffer].data = new uint8_t[width * height * frame.buffers[buffer].depth]; - } - - reset(); -} - -CRTFrameBuilder::~CRTFrameBuilder() -{ - for(int buffer = 0; buffer < frame.number_of_buffers; buffer++) - delete[] frame.buffers[buffer].data; - delete frame.buffers; -} - -void CRTFrameBuilder::reset() -{ - frame.number_of_vertices = 0; - _next_write_x_position = _next_write_y_position = 0; - frame.dirty_size.width = 0; - frame.dirty_size.height = 1; -} - -void CRTFrameBuilder::complete() -{ - frame.vertices = &_all_runs[0]; -} - -uint8_t *CRTFrameBuilder::get_next_run() -{ - const size_t vertices_per_run = 6; - - // get a run from the allocated list, allocating more if we're about to overrun - if((frame.number_of_vertices + vertices_per_run) * frame.size_per_vertex >= _all_runs.size()) - { - _all_runs.resize(_all_runs.size() + frame.size_per_vertex * vertices_per_run * 100); - } - - uint8_t *next_run = &_all_runs[frame.number_of_vertices * frame.size_per_vertex]; - frame.number_of_vertices += vertices_per_run; - - return next_run; -} - -void CRTFrameBuilder::allocate_write_area(int required_length) -{ - if (_next_write_x_position + required_length > frame.size.width) - { - _next_write_x_position = 0; - _next_write_y_position = (_next_write_y_position+1)&(frame.size.height-1); - frame.dirty_size.height++; - } - - _write_x_position = _next_write_x_position; - _write_y_position = _next_write_y_position; - _write_target_pointer = (_write_y_position * frame.size.width) + _write_x_position; - _next_write_x_position += required_length; - frame.dirty_size.width = std::max(frame.dirty_size.width, _next_write_x_position); -} - -uint8_t *CRTFrameBuilder::get_write_target_for_buffer(int buffer) -{ - return &frame.buffers[buffer].data[_write_target_pointer * frame.buffers[buffer].depth]; -} char *CRT::get_vertex_shader() { diff --git a/Outputs/CRT.hpp b/Outputs/CRT/CRT.hpp similarity index 98% rename from Outputs/CRT.hpp rename to Outputs/CRT/CRT.hpp index 8a811a888..be40816f9 100644 --- a/Outputs/CRT.hpp +++ b/Outputs/CRT/CRT.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include "CRTFrame.h" @@ -136,12 +137,10 @@ class CRT { */ uint8_t *get_write_target_for_buffer(int buffer); - // MARK: Binding - /*! 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(); + void draw_frame(int output_width, int output_height); /*! Tells the CRT that the next call to draw_frame will occur on a different OpenGL context than the previous. @@ -308,12 +307,13 @@ class CRT { static const int kCRTNumberOfFrames = 4; - // the run delegate and the triple buffer + // the triple buffer and OpenGL state CRTFrameBuilder *_frame_builders[kCRTNumberOfFrames]; CRTFrameBuilder *_current_frame_builder; - int _frames_with_delegate; + CRTFrame *_current_frame; + std::shared_ptr _current_frame_mutex; int _frame_read_pointer; - Delegate *_delegate; + void *openGLState; }; } diff --git a/Outputs/CRTFrame.h b/Outputs/CRT/CRTFrame.h similarity index 100% rename from Outputs/CRTFrame.h rename to Outputs/CRT/CRTFrame.h diff --git a/Outputs/CRT/CRTFrameBuilder.cpp b/Outputs/CRT/CRTFrameBuilder.cpp new file mode 100644 index 000000000..5a7752077 --- /dev/null +++ b/Outputs/CRT/CRTFrameBuilder.cpp @@ -0,0 +1,86 @@ +// +// CRTFrameBuilder.cpp +// Clock Signal +// +// Created by Thomas Harte on 04/02/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "CRT.hpp" + +using namespace Outputs; + +CRT::CRTFrameBuilder::CRTFrameBuilder(uint16_t width, uint16_t height, unsigned int number_of_buffers, va_list buffer_sizes) +{ + frame.size.width = width; + frame.size.height = height; + frame.number_of_buffers = number_of_buffers; + frame.buffers = new CRTBuffer[number_of_buffers]; + frame.size_per_vertex = kCRTSizeOfVertex; + frame.geometry_mode = CRTGeometryModeTriangles; + + for(int buffer = 0; buffer < number_of_buffers; buffer++) + { + frame.buffers[buffer].depth = va_arg(buffer_sizes, unsigned int); + frame.buffers[buffer].data = new uint8_t[width * height * frame.buffers[buffer].depth]; + } + + reset(); +} + +CRT::CRTFrameBuilder::~CRTFrameBuilder() +{ + for(int buffer = 0; buffer < frame.number_of_buffers; buffer++) + delete[] frame.buffers[buffer].data; + delete frame.buffers; +} + +void CRT::CRTFrameBuilder::reset() +{ + frame.number_of_vertices = 0; + _next_write_x_position = _next_write_y_position = 0; + frame.dirty_size.width = 0; + frame.dirty_size.height = 1; +} + +void CRT::CRTFrameBuilder::complete() +{ + frame.vertices = &_all_runs[0]; +} + +uint8_t *CRT::CRTFrameBuilder::get_next_run() +{ + const size_t vertices_per_run = 6; + + // get a run from the allocated list, allocating more if we're about to overrun + if((frame.number_of_vertices + vertices_per_run) * frame.size_per_vertex >= _all_runs.size()) + { + _all_runs.resize(_all_runs.size() + frame.size_per_vertex * vertices_per_run * 100); + } + + uint8_t *next_run = &_all_runs[frame.number_of_vertices * frame.size_per_vertex]; + frame.number_of_vertices += vertices_per_run; + + return next_run; +} + +void CRT::CRTFrameBuilder::allocate_write_area(int required_length) +{ + if (_next_write_x_position + required_length > frame.size.width) + { + _next_write_x_position = 0; + _next_write_y_position = (_next_write_y_position+1)&(frame.size.height-1); + frame.dirty_size.height++; + } + + _write_x_position = _next_write_x_position; + _write_y_position = _next_write_y_position; + _write_target_pointer = (_write_y_position * frame.size.width) + _write_x_position; + _next_write_x_position += required_length; + frame.dirty_size.width = std::max(frame.dirty_size.width, _next_write_x_position); +} + +uint8_t *CRT::CRTFrameBuilder::get_write_target_for_buffer(int buffer) +{ + return &frame.buffers[buffer].data[_write_target_pointer * frame.buffers[buffer].depth]; +} diff --git a/Outputs/CRT/CRTOpenGL.cpp b/Outputs/CRT/CRTOpenGL.cpp new file mode 100644 index 000000000..12174fd22 --- /dev/null +++ b/Outputs/CRT/CRTOpenGL.cpp @@ -0,0 +1,50 @@ +// +// CRTOpenGL.cpp +// Clock Signal +// +// Created by Thomas Harte on 03/02/2016. +// Copyright © 2016 Thomas Harte. All rights reserved. +// + +#include "CRT.hpp" + +// TODO: figure out correct include paths for other platforms. +#include + +using namespace Outputs; + +namespace { + struct OpenGLState { + GLuint _vertexShader, _fragmentShader; + GLuint _shaderProgram; + GLuint _arrayBuffer, _vertexArray; + + GLint _positionAttribute; + GLint _textureCoordinatesAttribute; + GLint _lateralAttribute; + + GLint _textureSizeUniform, _windowSizeUniform; + GLint _boundsOriginUniform, _boundsSizeUniform; + GLint _alphaUniform; + + GLuint _textureName, _shadowMaskTextureName; + }; +} + +void CRT::draw_frame(int output_width, int output_height) +{ + printf("%d %d\n", output_width, output_height); +} + +void CRT::set_openGL_context_will_change(bool should_delete_resources) +{ +} + +void CRT::set_composite_sampling_function(const char *shader) +{ +} + +void CRT::set_rgb_sampling_function(const char *shader) +{ + printf("%s\n", shader); +}