mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-08 14:25:05 +00:00
Merge pull request #122 from TomHarte/16bit6560
Increases VIC-I intermediate format to 16 bit and corrects output colours
This commit is contained in:
@@ -43,7 +43,7 @@ class Speaker: public ::Outputs::Filter<Speaker> {
|
|||||||
template <class T> class MOS6560 {
|
template <class T> class MOS6560 {
|
||||||
public:
|
public:
|
||||||
MOS6560() :
|
MOS6560() :
|
||||||
crt_(new Outputs::CRT::CRT(65*4, 4, Outputs::CRT::NTSC60, 1)),
|
crt_(new Outputs::CRT::CRT(65*4, 4, Outputs::CRT::NTSC60, 2)),
|
||||||
speaker_(new Speaker),
|
speaker_(new Speaker),
|
||||||
horizontal_counter_(0),
|
horizontal_counter_(0),
|
||||||
vertical_counter_(0),
|
vertical_counter_(0),
|
||||||
@@ -53,13 +53,11 @@ template <class T> class MOS6560 {
|
|||||||
crt_->set_composite_sampling_function(
|
crt_->set_composite_sampling_function(
|
||||||
"float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)"
|
"float composite_sample(usampler2D texID, vec2 coordinate, vec2 iCoordinate, float phase, float amplitude)"
|
||||||
"{"
|
"{"
|
||||||
"uint c = texture(texID, coordinate).r;"
|
"vec2 yc = texture(texID, coordinate).rg / vec2(255.0);"
|
||||||
"float y = float(c >> 4) / 4.0;"
|
"float phaseOffset = 6.283185308 * 2.0 * yc.y;"
|
||||||
"uint yC = c & 15u;"
|
|
||||||
"float phaseOffset = 6.283185308 * float(yC) / 16.0;"
|
|
||||||
|
|
||||||
"float chroma = cos(phase + phaseOffset);"
|
"float chroma = cos(phase + phaseOffset);"
|
||||||
"return mix(y, step(yC, 14) * chroma, amplitude);"
|
"return mix(yc.x, step(yc.y, 0.75) * chroma, amplitude);"
|
||||||
"}");
|
"}");
|
||||||
|
|
||||||
// default to NTSC
|
// default to NTSC
|
||||||
@@ -82,17 +80,29 @@ template <class T> class MOS6560 {
|
|||||||
*/
|
*/
|
||||||
void set_output_mode(OutputMode output_mode) {
|
void set_output_mode(OutputMode output_mode) {
|
||||||
output_mode_ = output_mode;
|
output_mode_ = output_mode;
|
||||||
const uint8_t luminances[16] = { // range is 0–4
|
|
||||||
0, 4, 1, 3, 2, 2, 1, 3,
|
// Lumunances are encoded trivially: on a 0–255 scale.
|
||||||
2, 1, 2, 1, 2, 3, 2, 3
|
const uint8_t luminances[16] = {
|
||||||
|
0, 255, 109, 189,
|
||||||
|
199, 144, 159, 161,
|
||||||
|
126, 227, 227, 207,
|
||||||
|
235, 173, 188, 196
|
||||||
};
|
};
|
||||||
const uint8_t pal_chrominances[16] = { // range is 0–15; 15 is a special case meaning "no chrominance"
|
|
||||||
15, 15, 5, 13, 2, 10, 0, 8,
|
// Chrominances are encoded such that 0–128 is a complete revolution of phase;
|
||||||
6, 7, 5, 13, 2, 10, 0, 8,
|
// anything above 191 disables the colour subcarrier. Phase is relative to the
|
||||||
|
// colour burst, so 0 is green.
|
||||||
|
const uint8_t pal_chrominances[16] = {
|
||||||
|
255, 255, 40, 112,
|
||||||
|
8, 88, 120, 56,
|
||||||
|
40, 48, 40, 112,
|
||||||
|
8, 88, 120, 56,
|
||||||
};
|
};
|
||||||
const uint8_t ntsc_chrominances[16] = {
|
const uint8_t ntsc_chrominances[16] = {
|
||||||
15, 15, 2, 10, 4, 12, 6, 14,
|
255, 255, 40, 104,
|
||||||
0, 8, 2, 10, 4, 12, 6, 14,
|
64, 120, 80, 16,
|
||||||
|
32, 32, 40, 104,
|
||||||
|
64, 120, 80, 16,
|
||||||
};
|
};
|
||||||
const uint8_t *chrominances;
|
const uint8_t *chrominances;
|
||||||
Outputs::CRT::DisplayType display_type;
|
Outputs::CRT::DisplayType display_type;
|
||||||
@@ -118,7 +128,7 @@ template <class T> class MOS6560 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
crt_->set_new_display_type((unsigned int)(timing_.cycles_per_line*4), display_type);
|
crt_->set_new_display_type((unsigned int)(timing_.cycles_per_line*4), display_type);
|
||||||
// crt_->set_visible_area(Outputs::CRT::Rect(0.1f, 0.1f, 0.8f, 0.8f));
|
crt_->set_visible_area(Outputs::CRT::Rect(0.05f, 0.05f, 0.9f, 0.9f));
|
||||||
|
|
||||||
// switch(output_mode) {
|
// switch(output_mode) {
|
||||||
// case OutputMode::PAL:
|
// case OutputMode::PAL:
|
||||||
@@ -130,7 +140,9 @@ template <class T> class MOS6560 {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
for(int c = 0; c < 16; c++) {
|
for(int c = 0; c < 16; c++) {
|
||||||
colours_[c] = (uint8_t)((luminances[c] << 4) | chrominances[c]);
|
uint8_t *colour = (uint8_t *)&colours_[c];
|
||||||
|
colour[0] = luminances[c];
|
||||||
|
colour[1] = chrominances[c];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,7 +268,7 @@ template <class T> class MOS6560 {
|
|||||||
|
|
||||||
pixel_pointer = nullptr;
|
pixel_pointer = nullptr;
|
||||||
if(output_state_ == State::Pixels) {
|
if(output_state_ == State::Pixels) {
|
||||||
pixel_pointer = crt_->allocate_write_area(260);
|
pixel_pointer = (uint16_t *)crt_->allocate_write_area(260);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cycles_in_state_++;
|
cycles_in_state_++;
|
||||||
@@ -266,9 +278,9 @@ template <class T> class MOS6560 {
|
|||||||
character_value_ = pixel_data;
|
character_value_ = pixel_data;
|
||||||
|
|
||||||
if(pixel_pointer) {
|
if(pixel_pointer) {
|
||||||
uint8_t cell_colour = colours_[character_colour_ & 0x7];
|
uint16_t cell_colour = colours_[character_colour_ & 0x7];
|
||||||
if(!(character_colour_&0x8)) {
|
if(!(character_colour_&0x8)) {
|
||||||
uint8_t colours[2];
|
uint16_t colours[2];
|
||||||
if(registers_.invertedCells) {
|
if(registers_.invertedCells) {
|
||||||
colours[0] = cell_colour;
|
colours[0] = cell_colour;
|
||||||
colours[1] = registers_.backgroundColour;
|
colours[1] = registers_.backgroundColour;
|
||||||
@@ -285,7 +297,7 @@ template <class T> class MOS6560 {
|
|||||||
pixel_pointer[6] = colours[(character_value_ >> 1)&1];
|
pixel_pointer[6] = colours[(character_value_ >> 1)&1];
|
||||||
pixel_pointer[7] = colours[(character_value_ >> 0)&1];
|
pixel_pointer[7] = colours[(character_value_ >> 0)&1];
|
||||||
} else {
|
} else {
|
||||||
uint8_t colours[4] = {registers_.backgroundColour, registers_.borderColour, cell_colour, registers_.auxiliary_colour};
|
uint16_t colours[4] = {registers_.backgroundColour, registers_.borderColour, cell_colour, registers_.auxiliary_colour};
|
||||||
pixel_pointer[0] =
|
pixel_pointer[0] =
|
||||||
pixel_pointer[1] = colours[(character_value_ >> 6)&3];
|
pixel_pointer[1] = colours[(character_value_ >> 6)&3];
|
||||||
pixel_pointer[2] =
|
pixel_pointer[2] =
|
||||||
@@ -295,6 +307,7 @@ template <class T> class MOS6560 {
|
|||||||
pixel_pointer[6] =
|
pixel_pointer[6] =
|
||||||
pixel_pointer[7] = colours[(character_value_ >> 0)&3];
|
pixel_pointer[7] = colours[(character_value_ >> 0)&3];
|
||||||
}
|
}
|
||||||
|
|
||||||
pixel_pointer += 8;
|
pixel_pointer += 8;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -358,7 +371,7 @@ template <class T> class MOS6560 {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0xf: {
|
case 0xf: {
|
||||||
uint8_t new_border_colour = colours_[value & 0x07];
|
uint16_t new_border_colour = colours_[value & 0x07];
|
||||||
if(this_state_ == State::Border && new_border_colour != registers_.borderColour) {
|
if(this_state_ == State::Border && new_border_colour != registers_.borderColour) {
|
||||||
output_border(cycles_in_state_ * 4);
|
output_border(cycles_in_state_ * 4);
|
||||||
cycles_in_state_ = 0;
|
cycles_in_state_ = 0;
|
||||||
@@ -405,7 +418,7 @@ template <class T> class MOS6560 {
|
|||||||
uint8_t first_column_location, first_row_location;
|
uint8_t first_column_location, first_row_location;
|
||||||
uint8_t number_of_columns, number_of_rows;
|
uint8_t number_of_columns, number_of_rows;
|
||||||
uint16_t character_cell_start_address, video_matrix_start_address;
|
uint16_t character_cell_start_address, video_matrix_start_address;
|
||||||
uint8_t backgroundColour, borderColour, auxiliary_colour;
|
uint16_t backgroundColour, borderColour, auxiliary_colour;
|
||||||
bool invertedCells;
|
bool invertedCells;
|
||||||
|
|
||||||
uint8_t direct_values[16];
|
uint8_t direct_values[16];
|
||||||
@@ -436,11 +449,11 @@ template <class T> class MOS6560 {
|
|||||||
bool is_odd_frame_, is_odd_line_;
|
bool is_odd_frame_, is_odd_line_;
|
||||||
|
|
||||||
// lookup table from 6560 colour index to appropriate PAL/NTSC value
|
// lookup table from 6560 colour index to appropriate PAL/NTSC value
|
||||||
uint8_t colours_[16];
|
uint16_t colours_[16];
|
||||||
|
|
||||||
uint8_t *pixel_pointer;
|
uint16_t *pixel_pointer;
|
||||||
void output_border(unsigned int number_of_cycles) {
|
void output_border(unsigned int number_of_cycles) {
|
||||||
uint8_t *colour_pointer = crt_->allocate_write_area(1);
|
uint16_t *colour_pointer = (uint16_t *)crt_->allocate_write_area(1);
|
||||||
if(colour_pointer) *colour_pointer = registers_.borderColour;
|
if(colour_pointer) *colour_pointer = registers_.borderColour;
|
||||||
crt_->output_level(number_of_cycles);
|
crt_->output_level(number_of_cycles);
|
||||||
}
|
}
|
||||||
|
@@ -336,7 +336,7 @@ void OpenGLOutputBuilder::set_output_device(OutputDevice output_device) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLOutputBuilder::set_timing(unsigned int input_frequency, unsigned int cycles_per_line, unsigned int height_of_display, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider) {
|
void OpenGLOutputBuilder::set_timing(unsigned int input_frequency, unsigned int cycles_per_line, unsigned int height_of_display, unsigned int horizontal_scan_period, unsigned int vertical_scan_period, unsigned int vertical_period_divider) {
|
||||||
output_mutex_.lock();
|
std::lock_guard<std::mutex> lock_guard(output_mutex_);
|
||||||
input_frequency_ = input_frequency;
|
input_frequency_ = input_frequency;
|
||||||
cycles_per_line_ = cycles_per_line;
|
cycles_per_line_ = cycles_per_line;
|
||||||
height_of_display_ = height_of_display;
|
height_of_display_ = height_of_display;
|
||||||
@@ -345,7 +345,6 @@ void OpenGLOutputBuilder::set_timing(unsigned int input_frequency, unsigned int
|
|||||||
vertical_period_divider_ = vertical_period_divider;
|
vertical_period_divider_ = vertical_period_divider;
|
||||||
|
|
||||||
set_timing_uniforms();
|
set_timing_uniforms();
|
||||||
output_mutex_.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - Internal Configuration
|
#pragma mark - Internal Configuration
|
||||||
|
@@ -99,7 +99,7 @@ std::unique_ptr<IntermediateShader> IntermediateShader::make_shader(const std::s
|
|||||||
"phaseAndAmplitudeVarying.y = 0.33;" // TODO: reinstate connection with (phaseTimeAndAmplitude.y/256.0)
|
"phaseAndAmplitudeVarying.y = 0.33;" // TODO: reinstate connection with (phaseTimeAndAmplitude.y/256.0)
|
||||||
|
|
||||||
// determine output position by scaling the output position according to the texture size
|
// determine output position by scaling the output position according to the texture size
|
||||||
"vec2 eyePosition = 2.0*(extendedOutputPosition / outputTextureSize) - vec2(1.0) + vec2(1.0)/outputTextureSize;"
|
"vec2 eyePosition = 2.0*(extendedOutputPosition / outputTextureSize) - vec2(1.0);"
|
||||||
"gl_Position = vec4(eyePosition, 0.0, 1.0);"
|
"gl_Position = vec4(eyePosition, 0.0, 1.0);"
|
||||||
"}", sampler_type, input_variable);
|
"}", sampler_type, input_variable);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user