mirror of
https://github.com/TomHarte/CLK.git
synced 2024-09-05 13:29:06 +00:00
Merge pull request #401 from TomHarte/VideoQuirks
Corrects composite output of the ZX80/81 and the Oric
This commit is contained in:
commit
60cf6b3cfd
@ -67,6 +67,10 @@ class Machine: public ROMMachine::Machine {
|
|||||||
return clock_rate_;
|
return clock_rate_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Maps from Configurable::Display to Outputs::CRT::VideoSignal and calls
|
||||||
|
@c set_video_signal with the result.
|
||||||
|
*/
|
||||||
void set_video_signal_configurable(Configurable::Display type) {
|
void set_video_signal_configurable(Configurable::Display type) {
|
||||||
Outputs::CRT::VideoSignal signal;
|
Outputs::CRT::VideoSignal signal;
|
||||||
switch(type) {
|
switch(type) {
|
||||||
@ -81,7 +85,14 @@ class Machine: public ROMMachine::Machine {
|
|||||||
signal = Outputs::CRT::VideoSignal::Composite;
|
signal = Outputs::CRT::VideoSignal::Composite;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
get_crt()->set_video_signal(signal);
|
set_video_signal(signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Forwards the video signal to the CRT returned by get_crt().
|
||||||
|
*/
|
||||||
|
virtual void set_video_signal(Outputs::CRT::VideoSignal video_signal) {
|
||||||
|
get_crt()->set_video_signal(video_signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -263,10 +263,6 @@ class ConcreteMachine:
|
|||||||
use_fast_tape_hack_ = activate;
|
use_fast_tape_hack_ = activate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_output_device(Outputs::CRT::VideoSignal output_device) {
|
|
||||||
video_output_->set_output_device(output_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
// to satisfy ConfigurationTarget::Machine
|
// to satisfy ConfigurationTarget::Machine
|
||||||
void configure_as_target(const Analyser::Static::Target *target) override final {
|
void configure_as_target(const Analyser::Static::Target *target) override final {
|
||||||
auto *const oric_target = dynamic_cast<const Analyser::Static::Oric::Target *>(target);
|
auto *const oric_target = dynamic_cast<const Analyser::Static::Oric::Target *>(target);
|
||||||
@ -392,7 +388,7 @@ class ConcreteMachine:
|
|||||||
|
|
||||||
video_output_.reset(new VideoOutput(ram_));
|
video_output_.reset(new VideoOutput(ram_));
|
||||||
if(!colour_rom_.empty()) video_output_->set_colour_rom(colour_rom_);
|
if(!colour_rom_.empty()) video_output_->set_colour_rom(colour_rom_);
|
||||||
set_output_device(Outputs::CRT::VideoSignal::RGB);
|
set_video_signal(Outputs::CRT::VideoSignal::RGB);
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_output() override final {
|
void close_output() override final {
|
||||||
@ -469,6 +465,10 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_video_signal(Outputs::CRT::VideoSignal video_signal) override {
|
||||||
|
video_output_->set_video_signal(video_signal);
|
||||||
|
}
|
||||||
|
|
||||||
Configurable::SelectionSet get_accurate_selections() override {
|
Configurable::SelectionSet get_accurate_selections() override {
|
||||||
Configurable::SelectionSet selection_set;
|
Configurable::SelectionSet selection_set;
|
||||||
Configurable::append_quick_load_tape_selection(selection_set, false);
|
Configurable::append_quick_load_tape_selection(selection_set, false);
|
||||||
|
@ -41,13 +41,13 @@ VideoOutput::VideoOutput(uint8_t *memory) :
|
|||||||
);
|
);
|
||||||
crt_->set_composite_function_type(Outputs::CRT::CRT::CompositeSourceType::DiscreteFourSamplesPerCycle, 0.0f);
|
crt_->set_composite_function_type(Outputs::CRT::CRT::CompositeSourceType::DiscreteFourSamplesPerCycle, 0.0f);
|
||||||
|
|
||||||
set_output_device(Outputs::CRT::VideoSignal::Composite);
|
set_video_signal(Outputs::CRT::VideoSignal::Composite);
|
||||||
crt_->set_visible_area(crt_->get_rect_for_area(53, 224, 16 * 6, 40 * 6, 4.0f / 3.0f));
|
crt_->set_visible_area(crt_->get_rect_for_area(53, 224, 16 * 6, 40 * 6, 4.0f / 3.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoOutput::set_output_device(Outputs::CRT::VideoSignal output_device) {
|
void VideoOutput::set_video_signal(Outputs::CRT::VideoSignal video_signal) {
|
||||||
output_device_ = output_device;
|
video_signal_ = video_signal;
|
||||||
crt_->set_video_signal(output_device);
|
crt_->set_video_signal(video_signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoOutput::set_colour_rom(const std::vector<uint8_t> &rom) {
|
void VideoOutput::set_colour_rom(const std::vector<uint8_t> &rom) {
|
||||||
@ -129,7 +129,7 @@ void VideoOutput::run_for(const Cycles cycles) {
|
|||||||
if(control_byte & 0x60) {
|
if(control_byte & 0x60) {
|
||||||
if(pixel_target_) {
|
if(pixel_target_) {
|
||||||
uint16_t colours[2];
|
uint16_t colours[2];
|
||||||
if(output_device_ == Outputs::CRT::VideoSignal::RGB) {
|
if(video_signal_ == Outputs::CRT::VideoSignal::RGB) {
|
||||||
colours[0] = static_cast<uint8_t>(paper_ ^ inverse_mask);
|
colours[0] = static_cast<uint8_t>(paper_ ^ inverse_mask);
|
||||||
colours[1] = static_cast<uint8_t>(ink_ ^ inverse_mask);
|
colours[1] = static_cast<uint8_t>(ink_ ^ inverse_mask);
|
||||||
} else {
|
} else {
|
||||||
@ -183,7 +183,7 @@ void VideoOutput::run_for(const Cycles cycles) {
|
|||||||
pixel_target_[0] = pixel_target_[1] =
|
pixel_target_[0] = pixel_target_[1] =
|
||||||
pixel_target_[2] = pixel_target_[3] =
|
pixel_target_[2] = pixel_target_[3] =
|
||||||
pixel_target_[4] = pixel_target_[5] =
|
pixel_target_[4] = pixel_target_[5] =
|
||||||
(output_device_ == Outputs::CRT::VideoSignal::RGB) ? paper_ ^ inverse_mask : colour_forms_[paper_ ^ inverse_mask];
|
(video_signal_ == Outputs::CRT::VideoSignal::RGB) ? paper_ ^ inverse_mask : colour_forms_[paper_ ^ inverse_mask];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(pixel_target_) pixel_target_ += 6;
|
if(pixel_target_) pixel_target_ += 6;
|
||||||
|
@ -20,7 +20,7 @@ class VideoOutput {
|
|||||||
Outputs::CRT::CRT *get_crt();
|
Outputs::CRT::CRT *get_crt();
|
||||||
void run_for(const Cycles cycles);
|
void run_for(const Cycles cycles);
|
||||||
void set_colour_rom(const std::vector<uint8_t> &rom);
|
void set_colour_rom(const std::vector<uint8_t> &rom);
|
||||||
void set_output_device(Outputs::CRT::VideoSignal output_device);
|
void set_video_signal(Outputs::CRT::VideoSignal output_device);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t *ram_;
|
uint8_t *ram_;
|
||||||
@ -33,7 +33,7 @@ class VideoOutput {
|
|||||||
// Output target and device
|
// Output target and device
|
||||||
uint16_t *pixel_target_;
|
uint16_t *pixel_target_;
|
||||||
uint16_t colour_forms_[8];
|
uint16_t colour_forms_[8];
|
||||||
Outputs::CRT::VideoSignal output_device_;
|
Outputs::CRT::VideoSignal video_signal_;
|
||||||
|
|
||||||
// Registers
|
// Registers
|
||||||
uint8_t ink_, paper_;
|
uint8_t ink_, paper_;
|
||||||
|
@ -22,6 +22,7 @@ Video::Video() :
|
|||||||
"}");
|
"}");
|
||||||
|
|
||||||
// Show only the centre 80% of the TV frame.
|
// Show only the centre 80% of the TV frame.
|
||||||
|
crt_->set_video_signal(Outputs::CRT::VideoSignal::Composite);
|
||||||
crt_->set_visible_area(Outputs::CRT::Rect(0.1f, 0.1f, 0.8f, 0.8f));
|
crt_->set_visible_area(Outputs::CRT::Rect(0.1f, 0.1f, 0.8f, 0.8f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,15 +18,15 @@
|
|||||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||||
<windowCollectionBehavior key="collectionBehavior" fullScreenPrimary="YES"/>
|
<windowCollectionBehavior key="collectionBehavior" fullScreenPrimary="YES"/>
|
||||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||||
<rect key="contentRect" x="133" y="235" width="400" height="300"/>
|
<rect key="contentRect" x="133" y="235" width="600" height="450"/>
|
||||||
<rect key="screenRect" x="0.0" y="0.0" width="1366" height="768"/>
|
<rect key="screenRect" x="0.0" y="0.0" width="1366" height="768"/>
|
||||||
<value key="minSize" type="size" width="228" height="171"/>
|
<value key="minSize" type="size" width="228" height="171"/>
|
||||||
<view key="contentView" id="gIp-Ho-8D9">
|
<view key="contentView" id="gIp-Ho-8D9">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="400" height="300"/>
|
<rect key="frame" x="0.0" y="0.0" width="600" height="450"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<openGLView hidden="YES" useAuxiliaryDepthBufferStencil="NO" allowOffline="YES" wantsBestResolutionOpenGLSurface="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DEG-fq-cjd" customClass="CSOpenGLView">
|
<openGLView hidden="YES" useAuxiliaryDepthBufferStencil="NO" allowOffline="YES" wantsBestResolutionOpenGLSurface="YES" translatesAutoresizingMaskIntoConstraints="NO" id="DEG-fq-cjd" customClass="CSOpenGLView">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="400" height="300"/>
|
<rect key="frame" x="0.0" y="0.0" width="600" height="450"/>
|
||||||
</openGLView>
|
</openGLView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
|
@ -315,20 +315,22 @@ void OpenGLOutputBuilder::prepare_composite_input_shaders() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLOutputBuilder::prepare_svideo_input_shaders() {
|
void OpenGLOutputBuilder::prepare_svideo_input_shaders() {
|
||||||
svideo_input_shader_program_ = OpenGL::IntermediateShader::make_svideo_source_shader(svideo_shader_, rgb_shader_);
|
if(!svideo_shader_.empty() || !rgb_shader_.empty()) {
|
||||||
svideo_input_shader_program_->set_source_texture_unit(source_data_texture_unit);
|
svideo_input_shader_program_ = OpenGL::IntermediateShader::make_svideo_source_shader(svideo_shader_, rgb_shader_);
|
||||||
svideo_input_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight);
|
svideo_input_shader_program_->set_source_texture_unit(source_data_texture_unit);
|
||||||
|
svideo_input_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight);
|
||||||
|
|
||||||
// TODO: the below is related to texture fencing, which is not yet implemented correctly, so not yet enabled.
|
// TODO: the below is related to texture fencing, which is not yet implemented correctly, so not yet enabled.
|
||||||
if(work_texture_) {
|
if(work_texture_) {
|
||||||
svideo_input_shader_program_->set_is_double_height(true, 0.0f, 0.0f);
|
svideo_input_shader_program_->set_is_double_height(true, 0.0f, 0.0f);
|
||||||
} else {
|
} else {
|
||||||
svideo_input_shader_program_->set_is_double_height(false);
|
svideo_input_shader_program_->set_is_double_height(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLOutputBuilder::prepare_rgb_input_shaders() {
|
void OpenGLOutputBuilder::prepare_rgb_input_shaders() {
|
||||||
if(rgb_shader_.size()) {
|
if(!rgb_shader_.empty()) {
|
||||||
rgb_input_shader_program_ = OpenGL::IntermediateShader::make_rgb_source_shader(rgb_shader_);
|
rgb_input_shader_program_ = OpenGL::IntermediateShader::make_rgb_source_shader(rgb_shader_);
|
||||||
rgb_input_shader_program_->set_source_texture_unit(source_data_texture_unit);
|
rgb_input_shader_program_->set_source_texture_unit(source_data_texture_unit);
|
||||||
rgb_input_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight);
|
rgb_input_shader_program_->set_output_size(IntermediateBufferWidth, IntermediateBufferHeight);
|
||||||
@ -340,11 +342,13 @@ void OpenGLOutputBuilder::prepare_rgb_input_shaders() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLOutputBuilder::prepare_source_vertex_array() {
|
void OpenGLOutputBuilder::prepare_source_vertex_array() {
|
||||||
if(composite_input_shader_program_) {
|
if(composite_input_shader_program_ || svideo_input_shader_program_) {
|
||||||
glBindVertexArray(source_vertex_array_);
|
glBindVertexArray(source_vertex_array_);
|
||||||
array_builder.bind_input();
|
array_builder.bind_input();
|
||||||
|
}
|
||||||
|
|
||||||
using Shader = OpenGL::IntermediateShader;
|
using Shader = OpenGL::IntermediateShader;
|
||||||
|
if(composite_input_shader_program_) {
|
||||||
composite_input_shader_program_->enable_vertex_attribute_with_pointer(
|
composite_input_shader_program_->enable_vertex_attribute_with_pointer(
|
||||||
Shader::get_input_name(Shader::Input::InputStart),
|
Shader::get_input_name(Shader::Input::InputStart),
|
||||||
2, GL_UNSIGNED_SHORT, GL_FALSE, SourceVertexSize,
|
2, GL_UNSIGNED_SHORT, GL_FALSE, SourceVertexSize,
|
||||||
@ -364,7 +368,9 @@ void OpenGLOutputBuilder::prepare_source_vertex_array() {
|
|||||||
Shader::get_input_name(Shader::Input::PhaseTimeAndAmplitude),
|
Shader::get_input_name(Shader::Input::PhaseTimeAndAmplitude),
|
||||||
3, GL_UNSIGNED_BYTE, GL_FALSE, SourceVertexSize,
|
3, GL_UNSIGNED_BYTE, GL_FALSE, SourceVertexSize,
|
||||||
(void *)SourceVertexOffsetOfPhaseTimeAndAmplitude, 1);
|
(void *)SourceVertexOffsetOfPhaseTimeAndAmplitude, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(svideo_input_shader_program_) {
|
||||||
svideo_input_shader_program_->enable_vertex_attribute_with_pointer(
|
svideo_input_shader_program_->enable_vertex_attribute_with_pointer(
|
||||||
Shader::get_input_name(Shader::Input::InputStart),
|
Shader::get_input_name(Shader::Input::InputStart),
|
||||||
2, GL_UNSIGNED_SHORT, GL_FALSE, SourceVertexSize,
|
2, GL_UNSIGNED_SHORT, GL_FALSE, SourceVertexSize,
|
||||||
|
Loading…
Reference in New Issue
Block a user