mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-29 12:50:28 +00:00
Attempts to add colour double [low/high] resolution output.
This commit is contained in:
parent
d2938ad7c8
commit
9d61665014
@ -190,12 +190,16 @@ void VideoBase::output_row(int row, int start, int end) {
|
||||
if(start == end) return;
|
||||
}
|
||||
|
||||
// The pixel buffer will actually be allocated a column early, to allow double high/low res to start
|
||||
// half a column before everything else.
|
||||
constexpr int pixel_buffer_allocation = start_of_pixels - 1;
|
||||
|
||||
// Possibly output border, pixels, border, if this is a pixel line.
|
||||
if(row < 192 + ((new_video_&0x80) >> 4)) { // i.e. 192 lines for classic Apple II video, 200 for IIgs video.
|
||||
|
||||
// Output left border as far as currently known.
|
||||
if(start >= start_of_left_border && start < start_of_pixels) {
|
||||
const int end_of_period = std::min(start_of_pixels, end);
|
||||
if(start >= start_of_left_border && start < pixel_buffer_allocation) {
|
||||
const int end_of_period = std::min(pixel_buffer_allocation, end);
|
||||
|
||||
if(border_colour_) {
|
||||
uint16_t *const pixel = reinterpret_cast<uint16_t *>(crt_.begin_data(2, 2));
|
||||
@ -212,11 +216,11 @@ void VideoBase::output_row(int row, int start, int end) {
|
||||
assert(end > start);
|
||||
|
||||
// Fetch and output such pixels as it is time for.
|
||||
if(start >= start_of_pixels && start < start_of_right_border) {
|
||||
if(start >= pixel_buffer_allocation && start < start_of_right_border) {
|
||||
const int end_of_period = std::min(start_of_right_border, end);
|
||||
const auto mode = graphics_mode(row);
|
||||
|
||||
if(start == start_of_pixels) {
|
||||
if(start == pixel_buffer_allocation) {
|
||||
// YUCKY HACK. I do not know when the IIgs fetches its super high-res palette
|
||||
// and control byte. Since I do not know, any guess is equally likely negatively
|
||||
// to affect software. Therefore this hack is as good as any other guess:
|
||||
@ -254,31 +258,70 @@ void VideoBase::output_row(int row, int start, int end) {
|
||||
|
||||
// Allocate a new buffer; 640 is as bad as it gets.
|
||||
// TODO: make proper size estimate?
|
||||
next_pixel_ = pixels_ = reinterpret_cast<uint16_t *>(crt_.begin_data(640, 2));
|
||||
next_pixel_ = pixels_ = reinterpret_cast<uint16_t *>(crt_.begin_data(644, 2));
|
||||
pixels_start_column_ = start;
|
||||
pixels_format_ = format_for_mode(mode);
|
||||
}
|
||||
|
||||
if(next_pixel_) {
|
||||
const int window_start = start - start_of_pixels;
|
||||
int window_start = start - start_of_pixels;
|
||||
const int window_end = end_of_period - start_of_pixels;
|
||||
|
||||
// Fill in border colour if this is the first column.
|
||||
if(window_start == -1) {
|
||||
if(next_pixel_) {
|
||||
int extra_border_length;
|
||||
switch(mode) {
|
||||
case GraphicsMode::DoubleText:
|
||||
case GraphicsMode::Text:
|
||||
case GraphicsMode::DoubleHighRes:
|
||||
case GraphicsMode::DoubleLowRes:
|
||||
case GraphicsMode::DoubleHighResMono:
|
||||
extra_border_length = 7;
|
||||
break;
|
||||
case GraphicsMode::HighRes:
|
||||
case GraphicsMode::LowRes:
|
||||
case GraphicsMode::FatLowRes:
|
||||
extra_border_length = 14;
|
||||
break;
|
||||
case GraphicsMode::SuperHighRes:
|
||||
extra_border_length = (line_control_ & 0x80) ? 4 : 2;
|
||||
break;
|
||||
}
|
||||
for(int c = 0; c < extra_border_length; c++) {
|
||||
next_pixel_[c] = border_colour_;
|
||||
}
|
||||
next_pixel_ += extra_border_length;
|
||||
}
|
||||
++window_start;
|
||||
if(window_start == window_end) return;
|
||||
}
|
||||
|
||||
switch(mode) {
|
||||
case GraphicsMode::SuperHighRes:
|
||||
next_pixel_ = output_super_high_res(next_pixel_, window_start, window_end, row);
|
||||
break;
|
||||
|
||||
case GraphicsMode::Text:
|
||||
next_pixel_ = output_text(next_pixel_, window_start, window_end, row);
|
||||
break;
|
||||
case GraphicsMode::DoubleText:
|
||||
next_pixel_ = output_double_text(next_pixel_, window_start, window_end, row);
|
||||
break;
|
||||
|
||||
case GraphicsMode::LowRes:
|
||||
next_pixel_ = output_low_resolution(next_pixel_, window_start, window_end, row);
|
||||
break;
|
||||
case GraphicsMode::DoubleLowRes:
|
||||
next_pixel_ = output_double_low_resolution(next_pixel_, window_start, window_end, row);
|
||||
break;
|
||||
|
||||
case GraphicsMode::HighRes:
|
||||
next_pixel_ = output_high_resolution(next_pixel_, window_start, window_end, row);
|
||||
break;
|
||||
case GraphicsMode::DoubleHighRes:
|
||||
next_pixel_ = output_double_high_resolution(next_pixel_, window_start, window_end, row);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false); // i.e. other modes yet to do.
|
||||
@ -480,6 +523,34 @@ uint16_t *VideoBase::output_low_resolution(uint16_t *target, int start, int end,
|
||||
return target;
|
||||
}
|
||||
|
||||
uint16_t *VideoBase::output_double_low_resolution(uint16_t *target, int start, int end, int row) {
|
||||
const int row_shift = row&4;
|
||||
const uint16_t row_address = get_row_address(row);
|
||||
for(int c = start; c < end; c++) {
|
||||
const uint8_t source[2] = {
|
||||
uint8_t((ram_[row_address + c] >> row_shift) & 0xf),
|
||||
uint8_t((ram_[0x10000 + row_address + c] >> row_shift) & 0xf)
|
||||
};
|
||||
|
||||
// Convulve input as a function of odd/even row; this is very much like low
|
||||
// resolution mode except that the first 7 bits to be output will come from
|
||||
// source[1] and the next 7 from source[0]. Also shifting is offset by
|
||||
// half a window compared to regular low resolution, so the conditional
|
||||
// works the other way around.
|
||||
uint32_t long_source;
|
||||
if(c&1) {
|
||||
long_source = uint32_t((source[1] | ((source[1] << 4) & 0x70) | ((source[0] << 4) & 0x80) | (source[0] << 8) | (source[0] << 12)) & 0x3fff);
|
||||
} else {
|
||||
long_source = uint32_t((source[1] >> 2) | (source[1] << 2) | ((source[1] << 6) & 0x40) | ((source[0] << 6) & 0x380) | (source[0] << 10));
|
||||
}
|
||||
|
||||
ntsc_shift_ = (long_source << 18) | (ntsc_shift_ >> 14);
|
||||
target = output_shift(target, c*2);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
uint16_t *VideoBase::output_high_resolution(uint16_t *target, int start, int end, int row) {
|
||||
const uint16_t row_address = get_row_address(row);
|
||||
for(int c = start; c < end; c++) {
|
||||
@ -499,7 +570,7 @@ uint16_t *VideoBase::output_high_resolution(uint16_t *target, int start, int end
|
||||
// Just append new bits, doubled up (and possibly delayed).
|
||||
// TODO: I can kill the conditional here. Probably?
|
||||
if(source & high_resolution_mask_ & 0x80) {
|
||||
ntsc_shift_ = (doubled_source << 19) | ((ntsc_shift_ >> 13) & 0x40000) | (ntsc_shift_ >> 14);
|
||||
ntsc_shift_ = ((doubled_source & 0x1fff) << 19) | ((ntsc_shift_ >> 13) & 0x40000) | (ntsc_shift_ >> 14);
|
||||
} else {
|
||||
ntsc_shift_ = (doubled_source << 18) | (ntsc_shift_ >> 14);
|
||||
}
|
||||
@ -510,6 +581,21 @@ uint16_t *VideoBase::output_high_resolution(uint16_t *target, int start, int end
|
||||
return target;
|
||||
}
|
||||
|
||||
uint16_t *VideoBase::output_double_high_resolution(uint16_t *target, int start, int end, int row) {
|
||||
const uint16_t row_address = get_row_address(row);
|
||||
for(int c = start; c < end; c++) {
|
||||
const uint8_t source[2] = {
|
||||
ram_[0x10000 + row_address + c],
|
||||
ram_[row_address + c],
|
||||
};
|
||||
|
||||
ntsc_shift_ = unsigned(source[1] << 25) | unsigned(source[0] << 18) | (ntsc_shift_ >> 14);
|
||||
target = output_shift(target, c*2);
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
uint16_t *VideoBase::output_shift(uint16_t *target, int column) {
|
||||
// Make sure that at least two columns are enqueued before output begins;
|
||||
// the top bits can't be understood without reference to bits that come afterwards.
|
||||
|
@ -137,8 +137,10 @@ class VideoBase: public Apple::II::VideoSwitches<Cycles> {
|
||||
uint16_t *output_char(uint16_t *target, uint8_t source, int row) const;
|
||||
|
||||
uint16_t *output_low_resolution(uint16_t *target, int start, int end, int row);
|
||||
uint16_t *output_double_low_resolution(uint16_t *target, int start, int end, int row);
|
||||
|
||||
uint16_t *output_high_resolution(uint16_t *target, int start, int end, int row);
|
||||
uint16_t *output_double_high_resolution(uint16_t *target, int start, int end, int row);
|
||||
|
||||
// Super high-res per-line state.
|
||||
uint8_t line_control_;
|
||||
|
Loading…
Reference in New Issue
Block a user