diff --git a/Machines/Atari2600.cpp b/Machines/Atari2600.cpp index 582d7c579..20efe774c 100644 --- a/Machines/Atari2600.cpp +++ b/Machines/Atari2600.cpp @@ -14,12 +14,13 @@ using namespace Atari2600; Machine::Machine() { - reset(); _timestamp = 0; _horizontalTimer = 0; _lastOutputStateDuration = 0; _lastOutputState = OutputState::Sync; - _crt = new Outputs::CRT(228); + _crt = new Outputs::CRT(228, 1, 4); + + reset(); } void Machine::get_output_pixel(uint8_t *pixel, int offset) @@ -76,22 +77,34 @@ void Machine::output_state(OutputState state, uint8_t *pixel) _lastOutputStateDuration++; if(state != _lastOutputState) { - static uint8_t blankingLevel[3] = {0, 0, 0}; switch(_lastOutputState) { - case OutputState::Blank: _crt->output_level(_lastOutputStateDuration, blankingLevel, "Atari2600"); break; + case OutputState::Blank: { + _crt->allocate_write_area(1); + _outputBuffer = _crt->get_write_target_for_buffer(0); + _outputBuffer[0] = _outputBuffer[1] = _outputBuffer[2] = 0; + _outputBuffer[3] = 0xff; + _crt->output_level(_lastOutputStateDuration, "Atari2600"); + } break; case OutputState::Sync: _crt->output_sync(_lastOutputStateDuration); break; - case OutputState::Pixel: _crt->output_data(_lastOutputStateDuration, _outPixels, "Atari2600"); break; + case OutputState::Pixel: _crt->output_data(_lastOutputStateDuration, "Atari2600"); break; } _lastOutputStateDuration = 0; _lastOutputState = state; + + if(state == OutputState::Pixel) + { + _crt->allocate_write_area(160); + _outputBuffer = _crt->get_write_target_for_buffer(0); + } } if(state == OutputState::Pixel) { - _outPixels[(_lastOutputStateDuration * 3) + 0] = pixel[0]; - _outPixels[(_lastOutputStateDuration * 3) + 1] = pixel[1]; - _outPixels[(_lastOutputStateDuration * 3) + 2] = pixel[2]; + _outputBuffer[(_lastOutputStateDuration * 4) + 0] = pixel[0]; + _outputBuffer[(_lastOutputStateDuration * 4) + 1] = pixel[1]; + _outputBuffer[(_lastOutputStateDuration * 4) + 2] = pixel[2]; + _outputBuffer[(_lastOutputStateDuration * 4) + 3] = 0xff; } } diff --git a/Machines/Atari2600.hpp b/Machines/Atari2600.hpp index fe318e0a8..75eeda41a 100644 --- a/Machines/Atari2600.hpp +++ b/Machines/Atari2600.hpp @@ -53,9 +53,9 @@ class Machine: public CPU6502::Processor { Outputs::CRT *_crt; // latched output state - uint8_t _outPixels[480]; int _lastOutputStateDuration; OutputState _lastOutputState; + uint8_t *_outputBuffer; }; } diff --git a/Outputs/CRT.cpp b/Outputs/CRT.cpp index 23adb2604..e558017c4 100644 --- a/Outputs/CRT.cpp +++ b/Outputs/CRT.cpp @@ -7,13 +7,42 @@ // #include "CRT.hpp" +#include + +static const int bufferWidth = 512; +static const int bufferHeight = 512; using namespace Outputs; -CRT::CRT(int cycles_per_line) +CRT::CRT(int cycles_per_line, int number_of_buffers, ...) { _horizontalOffset = 0.0f; _verticalOffset = 0.0f; + + _numberOfBuffers = number_of_buffers; + _bufferSizes = new int[_numberOfBuffers]; + _buffers = new uint8_t *[_numberOfBuffers]; + + va_list va; + va_start(va, number_of_buffers); + for(int c = 0; c < _numberOfBuffers; c++) + { + _bufferSizes[c] = va_arg(va, int); + _buffers[c] = new uint8_t[bufferHeight * bufferWidth * _bufferSizes[c]]; + } + va_end(va); + + _write_allocation_pointer = 0; +} + +CRT::~CRT() +{ + delete[] _bufferSizes; + for(int c = 0; c < _numberOfBuffers; c++) + { + delete[] _buffers[c]; + } + delete[] _buffers; } void CRT::output_sync(int number_of_cycles) @@ -22,12 +51,32 @@ void CRT::output_sync(int number_of_cycles) _syncCapacitorChargeLevel += number_of_cycles; } -void CRT::output_level(int number_of_cycles, uint8_t *level, std::string type) +void CRT::output_level(int number_of_cycles, std::string type) { _syncCapacitorChargeLevel -= number_of_cycles; } -void CRT::output_data(int number_of_cycles, uint8_t *data, std::string type) +void CRT::output_data(int number_of_cycles, std::string type) { _syncCapacitorChargeLevel -= number_of_cycles; } + +#pragma mark - Buffer supplying + +void CRT::allocate_write_area(int required_length) +{ + int xPos = _write_allocation_pointer & (bufferWidth - 1); + if (xPos + required_length > bufferWidth) + { + _write_allocation_pointer &= ~(bufferWidth - 1); + _write_allocation_pointer = (_write_allocation_pointer + bufferWidth) & ((bufferHeight-1) * bufferWidth); + } + + _write_target_pointer = _write_allocation_pointer; + _write_allocation_pointer += required_length; +} + +uint8_t *CRT::get_write_target_for_buffer(int buffer) +{ + return &_buffers[buffer][_write_target_pointer * _bufferSizes[buffer]]; +} diff --git a/Outputs/CRT.hpp b/Outputs/CRT.hpp index c895e51a7..310bed018 100644 --- a/Outputs/CRT.hpp +++ b/Outputs/CRT.hpp @@ -16,10 +16,12 @@ namespace Outputs { class CRT { public: - CRT(int cycles_per_line); + CRT(int cycles_per_line, int number_of_buffers, ...); + ~CRT(); + void output_sync(int number_of_cycles); - void output_level(int number_of_cycles, uint8_t *level, std::string type); - void output_data(int number_of_cycles, uint8_t *data, std::string type); + void output_level(int number_of_cycles, std::string type); + void output_data(int number_of_cycles, std::string type); struct CRTRun { struct Point { @@ -30,6 +32,7 @@ class CRT { Sync, Level, Data } type; + std::string data_type; uint8_t *data; }; @@ -39,11 +42,20 @@ class CRT { }; void set_crt_delegate(CRTDelegate *); + void allocate_write_area(int required_length); + uint8_t *get_write_target_for_buffer(int buffer); + private: CRTDelegate *_delegate; int _syncCapacitorChargeLevel; float _horizontalOffset, _verticalOffset; + + uint8_t **_buffers; + int *_bufferSizes; + int _numberOfBuffers; + + int _write_allocation_pointer, _write_target_pointer; }; }