diff --git a/ClockReceiver/JustInTime.hpp b/ClockReceiver/JustInTime.hpp index 7c3445721..b1de4a0d8 100644 --- a/ClockReceiver/JustInTime.hpp +++ b/ClockReceiver/JustInTime.hpp @@ -70,7 +70,7 @@ template forceinline bool check_flush_threshold() { if(time_since_update_.as_integral() >= threshold) { flush(); diff --git a/Machines/Apple/AppleIIgs/AppleIIgs.cpp b/Machines/Apple/AppleIIgs/AppleIIgs.cpp index 9d607ed31..b470597bd 100644 --- a/Machines/Apple/AppleIIgs/AppleIIgs.cpp +++ b/Machines/Apple/AppleIIgs/AppleIIgs.cpp @@ -533,6 +533,7 @@ class ConcreteMachine: video_ += duration; // Ensure no more than a single line is enqueued for just-in-time video purposes. + // TODO: as implemented, check_flush_threshold doesn't actually work. Can it be made to, or is it a bad idea? if(video_.check_flush_threshold<131>()) { update_interrupts(); } diff --git a/Machines/Apple/AppleIIgs/Video.cpp b/Machines/Apple/AppleIIgs/Video.cpp index 9363ebd3c..07db9ef14 100644 --- a/Machines/Apple/AppleIIgs/Video.cpp +++ b/Machines/Apple/AppleIIgs/Video.cpp @@ -111,7 +111,7 @@ void VideoBase::output_row(int row, int start, int end) { // // Guessing four cycles of sync, I've chosen to arrange one output row for this emulator as: // - // 5 cycles of back porch; + // 5 cycles of back porch; [TODO: include a colour burst] // 8 windows left border, the final five of which fetch palette and control if in IIgs mode; // 40 windows of pixel output; // 8 cycles of right border; @@ -166,20 +166,47 @@ void VideoBase::output_row(int row, int start, int end) { if(start == end) return; } - // Output left border as far as currently known. + // Fetch and output such pixels as it is time for. if(start >= start_of_pixels && start < start_of_right_border) { const int end_of_period = std::min(start_of_right_border, end); - // TODO: output real pixels. - uint16_t *const pixel = reinterpret_cast(crt_.begin_data(2, 2)); - if(pixel) *pixel = appleii_palette[7]; - crt_.output_data((end_of_period - start) * CyclesPerTick, 1); + if(start == start_of_pixels) { + // 640 is the absolute most number of pixels that might be generated + next_pixel_ = pixels_ = reinterpret_cast(crt_.begin_data(640, 2)); + } + + // TODO: support modes other than 40-column text. + if(next_pixel_) { + uint16_t row_address = get_row_address(row); + for(int c = start; c < end_of_period; c++) { + const uint8_t source = ram_[row_address + c]; + const int character = source & character_zones_[source >> 6].address_mask; + const uint8_t xor_mask = character_zones_[source >> 6].xor_mask; + const std::size_t character_address = size_t(character << 3) + (row & 7); + const uint8_t character_pattern = character_rom_[character_address] ^ xor_mask; + const uint16_t colours[2] = {background_colour_, text_colour_}; + + next_pixel_[0] = colours[(character_pattern & 0x40) >> 6]; + next_pixel_[1] = colours[(character_pattern & 0x20) >> 5]; + next_pixel_[2] = colours[(character_pattern & 0x10) >> 4]; + next_pixel_[3] = colours[(character_pattern & 0x08) >> 3]; + next_pixel_[4] = colours[(character_pattern & 0x04) >> 2]; + next_pixel_[5] = colours[(character_pattern & 0x02) >> 1]; + next_pixel_[6] = colours[(character_pattern & 0x01) >> 0]; + next_pixel_ += 7; + } + } + + if(end_of_period == start_of_right_border) { + crt_.output_data((start_of_right_border - start_of_pixels) * CyclesPerTick, next_pixel_ ? size_t(next_pixel_ - pixels_) : 1); + next_pixel_ = pixels_ = nullptr; + } start = end_of_period; if(start == end) return; } - // Output left border as far as currently known. + // Output right border as far as currently known. if(start >= start_of_right_border && start < start_of_sync) { const int end_of_period = std::min(start_of_sync, end); diff --git a/Machines/Apple/AppleIIgs/Video.hpp b/Machines/Apple/AppleIIgs/Video.hpp index fb12a081d..10c02fb90 100644 --- a/Machines/Apple/AppleIIgs/Video.hpp +++ b/Machines/Apple/AppleIIgs/Video.hpp @@ -70,6 +70,9 @@ class VideoBase: public Apple::II::VideoSwitches { uint16_t text_colour_ = 0xfff; uint16_t background_colour_ = 0; + // Current pixel output buffer. + uint16_t *pixels_ = nullptr, *next_pixel_ = nullptr; + void output_row(int row, int start, int end); };