From e691cc8723776f3160f4fedc77417fe8297f9db2 Mon Sep 17 00:00:00 2001
From: Thomas Harte <thomas.harte@gmail.com>
Date: Thu, 7 Dec 2023 14:21:09 -0500
Subject: [PATCH] Retain dark yellow for composite output.

---
 Machines/PCCompatible/CGA.hpp          | 80 +++++++++++++++-----------
 Machines/PCCompatible/PCCompatible.cpp |  7 +--
 Outputs/ScanTarget.hpp                 |  4 ++
 3 files changed, 52 insertions(+), 39 deletions(-)

diff --git a/Machines/PCCompatible/CGA.hpp b/Machines/PCCompatible/CGA.hpp
index 4e7b45d5e..56a356615 100644
--- a/Machines/PCCompatible/CGA.hpp
+++ b/Machines/PCCompatible/CGA.hpp
@@ -15,41 +15,6 @@
 
 namespace PCCompatible {
 
-static constexpr uint8_t DarkCyan		= 0b00'10'10;
-static constexpr uint8_t DarkMagenta	= 0b10'00'10;
-static constexpr uint8_t DarkGrey		= 0b10'10'10;
-
-static constexpr uint8_t DarkGreen		= 0b00'10'00;
-static constexpr uint8_t DarkRed		= 0b10'00'00;
-static constexpr uint8_t DarkYellow		= 0b10'10'00;
-
-static constexpr uint8_t Brown			= 0b10'01'00;
-
-/// @returns @c Brown if @c source is @c DarkYellow; @c source otherwise.
-constexpr uint8_t yellow_to_brown(uint8_t source) {
-	return (source == DarkYellow) ? Brown : source;
-}
-
-/// @returns The brightened (i.e. high intensity) version of @c source.
-constexpr uint8_t bright(uint8_t source) {
-	return source | (source >> 1);
-}
-
-/// Maps the RGB TTL triplet @c source to an appropriate output colour.
-constexpr uint8_t rgb(uint8_t source) {
-	return uint8_t(
-		((source & 0x01) << 1) |
-		((source & 0x02) << 2) |
-		((source & 0x04) << 3)
-	);
-}
-
-/// Maps the RGBI value in @c source to an appropriate output colour, including potential yellow-to-brown conversion.
-constexpr uint8_t rgbi(uint8_t source) {
-	const uint8_t result = rgb(source);
-	return (source & 0x10) ? bright(result) : yellow_to_brown(result);
-}
-
 class CGA {
 	public:
 		CGA() : crtc_(Motorola::CRTC::Personality::HD6845S, outputter_) {}
@@ -113,6 +78,7 @@ class CGA {
 
 		void set_display_type(Outputs::Display::DisplayType display_type) {
 			outputter_.crt.set_display_type(display_type);
+			outputter_.set_is_composite(Outputs::Display::is_composite(display_type));
 		}
 		Outputs::Display::DisplayType get_display_type() const {
 			return outputter_.crt.get_display_type();
@@ -165,6 +131,11 @@ class CGA {
 				update_palette();
 			}
 
+			void set_is_composite(bool is_composite) {
+				is_composite_ = is_composite;
+				update_palette();
+			}
+
 			void set_colours(uint8_t value) {
 				colours_ = value;
 				update_palette();
@@ -384,6 +355,7 @@ class CGA {
 			int pixels_per_tick = 8;
 			uint8_t colours_ = 0;
 			uint8_t control_ = 0;
+			bool is_composite_ = false;
 			enum class Mode {
 				Pixels640, Pixels320, Text,
 			} mode_ = Mode::Text;
@@ -425,10 +397,48 @@ class CGA {
 				border_colour = (mode_ != Mode::Pixels640) ? palette320[0] : 0;
 			}
 
+			//
+			// Named colours and mapping logic.
+			//
+			static constexpr uint8_t DarkCyan		= 0b00'10'10;
+			static constexpr uint8_t DarkMagenta	= 0b10'00'10;
+			static constexpr uint8_t DarkGrey		= 0b10'10'10;
+
+			static constexpr uint8_t DarkGreen		= 0b00'10'00;
+			static constexpr uint8_t DarkRed		= 0b10'00'00;
+			static constexpr uint8_t DarkYellow		= 0b10'10'00;
+
+			static constexpr uint8_t Brown			= 0b10'01'00;
+
+			/// @returns @c Brown if @c source is @c DarkYellow and composite output is not enabled; @c source otherwise.
+			constexpr uint8_t yellow_to_brown(uint8_t source) {
+				return (source == DarkYellow && !is_composite_) ? Brown : source;
+			}
+
+			/// @returns The brightened (i.e. high intensity) version of @c source.
+			constexpr uint8_t bright(uint8_t source) {
+				return source | (source >> 1);
+			}
+
+			/// Maps the RGB TTL triplet @c source to an appropriate output colour.
+			constexpr uint8_t rgb(uint8_t source) {
+				return uint8_t(
+					((source & 0x01) << 1) |
+					((source & 0x02) << 2) |
+					((source & 0x04) << 3)
+				);
+			}
+
+			/// Maps the RGBI value in @c source to an appropriate output colour, including potential yellow-to-brown conversion.
+			constexpr uint8_t rgbi(uint8_t source) {
+				const uint8_t result = rgb(source);
+				return (source & 0x10) ? bright(result) : yellow_to_brown(result);
+			}
 		} outputter_;
 		Motorola::CRTC::CRTC6845<CRTCOutputter, Motorola::CRTC::CursorType::MDA> crtc_;
 
 		int full_clock_ = 0;
+
 };
 
 }
diff --git a/Machines/PCCompatible/PCCompatible.cpp b/Machines/PCCompatible/PCCompatible.cpp
index 55529d43b..f36f0b3e7 100644
--- a/Machines/PCCompatible/PCCompatible.cpp
+++ b/Machines/PCCompatible/PCCompatible.cpp
@@ -1109,10 +1109,9 @@ class ConcreteMachine:
 
 		void set_display_type(Outputs::Display::DisplayType display_type) override {
 			video_.set_display_type(display_type);
-			ppi_handler_.hint_is_composite(
-				(display_type == Outputs::Display::DisplayType::CompositeColour) ||
-				(display_type == Outputs::Display::DisplayType::CompositeMonochrome)
-			);
+
+			// Give the PPI a shout-out in case it isn't too late to switch to CGA40.
+			ppi_handler_.hint_is_composite(Outputs::Display::is_composite(display_type));
 		}
 
 		Outputs::Display::DisplayType get_display_type() const override {
diff --git a/Outputs/ScanTarget.hpp b/Outputs/ScanTarget.hpp
index 6b01fe3cc..487559d4f 100644
--- a/Outputs/ScanTarget.hpp
+++ b/Outputs/ScanTarget.hpp
@@ -51,6 +51,10 @@ enum class DisplayType {
 	CompositeMonochrome
 };
 
+constexpr bool is_composite(DisplayType type) {
+	return type == DisplayType::CompositeColour || type == DisplayType::CompositeMonochrome;
+}
+
 /*!
 	Enumerates the potential formats of input data.