From fd579a019b4e76cc068249abe14079abcc41d116 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 28 Nov 2018 20:40:22 -0800 Subject: [PATCH] Introduces a new scan source data type, motivated by the reasoning used by the Oric. Specifically: it'll allow PCM sampling of the potentially arbitrary composite generation logic of various machines. --- Machines/Oric/Oric.cpp | 2 +- Machines/Oric/Video.cpp | 38 +++++++++++++++------- Outputs/OpenGL/ScanTargetGLSLFragments.cpp | 7 ++++ Outputs/ScanTarget.hpp | 8 +++++ 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/Machines/Oric/Oric.cpp b/Machines/Oric/Oric.cpp index 9cf344462..a11b4f6da 100644 --- a/Machines/Oric/Oric.cpp +++ b/Machines/Oric/Oric.cpp @@ -530,7 +530,7 @@ template class Co } void set_display_type(Outputs::Display::DisplayType display_type) override { - video_output_.set_display_type(display_type); +// video_output_.set_display_type(display_type); } Configurable::SelectionSet get_accurate_selections() override { diff --git a/Machines/Oric/Video.cpp b/Machines/Oric/Video.cpp index 69a61d363..f64fb35e1 100644 --- a/Machines/Oric/Video.cpp +++ b/Machines/Oric/Video.cpp @@ -40,12 +40,12 @@ namespace { VideoOutput::VideoOutput(uint8_t *memory) : ram_(memory), - crt_(64*6, 1, Outputs::Display::Type::PAL50, Outputs::Display::InputDataType::Red1Green1Blue1), + crt_(64*6, 1, Outputs::Display::Type::PAL50, Outputs::Display::InputDataType::PhaseLinkedLuminance8), v_sync_start_position_(PAL50VSyncStartPosition), v_sync_end_position_(PAL50VSyncEndPosition), counter_period_(PAL50Period) { -// crt_->set_composite_function_type(Outputs::CRT::CRT::CompositeSourceType::DiscreteFourSamplesPerCycle, 0.0f); + crt_.set_composite_function_type(Outputs::CRT::CRT::CompositeSourceType::DiscreteFourSamplesPerCycle, 1.0f / 8.0f); - set_display_type(Outputs::Display::DisplayType::RGB); + set_display_type(Outputs::Display::DisplayType::CompositeColour); crt_.set_visible_area(crt_.get_rect_for_area(54, 224, 16 * 6, 40 * 6, 4.0f / 3.0f)); } @@ -60,18 +60,32 @@ void VideoOutput::set_scan_target(Outputs::Display::ScanTarget *scan_target) { void VideoOutput::set_colour_rom(const std::vector &rom) { for(std::size_t c = 0; c < 8; c++) { - std::size_t index = (c << 2); - uint16_t rom_value = static_cast((static_cast(rom[index]) << 8) | static_cast(rom[index+1])); - rom_value = (rom_value & 0xff00) | ((rom_value >> 4)&0x000f) | ((rom_value << 4)&0x00f0); - colour_forms_[c] = rom_value; + colour_forms_[c] = 0; + + uint8_t *const colour = reinterpret_cast(&colour_forms_[c]); + const std::size_t index = (c << 2); + + // Values in the ROM are encoded for indexing by two square waves + // in quadrature, which means that they're indexed in the order + // 0, 1, 3, 2. + colour[1] = uint8_t(rom[index] & 0xf0); + colour[0] = uint8_t((rom[index] & 0x0f) << 4); + colour[3] = uint8_t((rom[index+1] & 0x0f) << 4); + colour[2] = uint8_t(rom[index+1] & 0xf0); + + // Extracting just the visible part of the stored range of values + // means etracting the range 0x40 to 0xe0. + for(int sub = 0; sub < 4; ++sub) { + colour[sub] = ((colour[sub] - 0x40) * 255) / 0xa0; + } } - // check for big endianness and byte swap if required - uint16_t test_value = 0x0001; + // Check for big endianness and byte swap if required. + uint32_t test_value = 0x0001; if(*reinterpret_cast(&test_value) != 0x01) { - for(std::size_t c = 0; c < 8; c++) { - colour_forms_[c] = static_cast((colour_forms_[c] >> 8) | (colour_forms_[c] << 8)); - } +// for(std::size_t c = 0; c < 8; c++) { +// colour_forms_[c] = static_cast((colour_forms_[c] >> 8) | (colour_forms_[c] << 8)); +// } } } diff --git a/Outputs/OpenGL/ScanTargetGLSLFragments.cpp b/Outputs/OpenGL/ScanTargetGLSLFragments.cpp index eeb72951a..b69961e47 100644 --- a/Outputs/OpenGL/ScanTargetGLSLFragments.cpp +++ b/Outputs/OpenGL/ScanTargetGLSLFragments.cpp @@ -266,6 +266,13 @@ std::unique_ptr ScanTarget::input_shader(InputDataType input_data_type, fragment_shader += "fragColour = vec3(texture(textureName, textureCoordinate).r / 255.0);"; break; + case InputDataType::PhaseLinkedLuminance8: + computed_display_type = DisplayType::CompositeMonochrome; + fragment_shader += + "uint iPhase = uint(compositeAngle * 2.0 / 3.141592654) & 3u;" + "fragColour = vec3(texture(textureName, textureCoordinate)[iPhase] / 255.0);"; + break; + case InputDataType::Luminance8Phase8: computed_display_type = DisplayType::SVideo; fragment_shader += diff --git a/Outputs/ScanTarget.hpp b/Outputs/ScanTarget.hpp index 215bd1819..ed591c978 100644 --- a/Outputs/ScanTarget.hpp +++ b/Outputs/ScanTarget.hpp @@ -60,6 +60,12 @@ enum class InputDataType { Luminance1, // 1 byte/pixel; any bit set => white; no bits set => black. Luminance8, // 1 byte/pixel; linear scale. + PhaseLinkedLuminance8, // 4 bytes/pixel; each byte is an individual 8-bit luminance + // value and which value is output is a function of + // colour subcarrier phase — byte 0 defines the first quarter + // of each colour cycle, byte 1 the next quarter, etc. This + // format is intended to permit replay of sampled original data. + // The luminance plus phase types describe a luminance and the phase offset // of a colour subcarrier. So they can be used to generate a luminance signal, // or an s-video pipeline. @@ -91,6 +97,7 @@ inline size_t size_for_data_type(InputDataType data_type) { return 2; case InputDataType::Red8Green8Blue8: + case InputDataType::PhaseLinkedLuminance8: return 4; } } @@ -99,6 +106,7 @@ inline DisplayType natural_display_type_for_data_type(InputDataType data_type) { switch(data_type) { case InputDataType::Luminance1: case InputDataType::Luminance8: + case InputDataType::PhaseLinkedLuminance8: return DisplayType::CompositeColour; case InputDataType::Red1Green1Blue1: