diff --git a/Models/ReactionTest.cs b/Models/ReactionTest.cs --- a/Models/ReactionTest.cs +++ b/Models/ReactionTest.cs @@ -177,13 +177,13 @@ namespace DesertPaintCodex.Models Reaction = null; BadReaction = null; State = TestState.Scanning; + bool testing3Way = Requires3Way && BufferIsSelected; bool foundLab = await ReactionScannerService.Instance.CaptureReactionAsync(this); if (foundLab) { ObservedColor = ReactionScannerService.Instance.RecordedColor; if (_observedColor != null) { - // Handle the normal case. Clipped = _observedColor.Red switch { 0 => ClipType.RedLow, @@ -212,6 +212,32 @@ namespace DesertPaintCodex.Models { State = TestState.ClippedResult; BadReaction = CalculateReaction(); + + // SPECIAL CASE: + // Check to see if we've got a white-shift reaction that's partially clipped, where we can + // still extrapolate the reaction, based on the available information. + if (!testing3Way && (BadReaction != null)) + { + PaintColor baseColor = _recipe.BaseColor; + if ((BadReaction.Red < baseColor.Red) && + (BadReaction.Green < baseColor.Green) && + (BadReaction.Blue < baseColor.Blue)) + { + // White-shift down clip. + bool extrapolated = ExtrapolateWhiteFromOneChannel(_observedColor.Red, 0, BadReaction.Red); + if (!extrapolated) extrapolated = ExtrapolateWhiteFromOneChannel(_observedColor.Green, 0, BadReaction.Green); + if (!extrapolated) ExtrapolateWhiteFromOneChannel(_observedColor.Blue, 0, BadReaction.Blue); + } + else if ((BadReaction.Red > baseColor.Red) && + (BadReaction.Green > baseColor.Green) && + (BadReaction.Blue > baseColor.Blue)) + { + // White-shift up clip. + bool extrapolated = ExtrapolateWhiteFromOneChannel(_observedColor.Red, 255, BadReaction.Red); + if (!extrapolated) extrapolated = ExtrapolateWhiteFromOneChannel(_observedColor.Green, 255, BadReaction.Green); + if (!extrapolated) ExtrapolateWhiteFromOneChannel(_observedColor.Blue, 255, BadReaction.Blue); + } + } } PlayerProfile? profile = ProfileManager.CurrentProfile; @@ -225,6 +251,18 @@ namespace DesertPaintCodex.Models } } + private bool ExtrapolateWhiteFromOneChannel(int result, int clipBound, int reaction) + { + if (result == clipBound) return false; + + Clipped = ClipType.None; + Reaction = new Reaction(reaction, reaction, reaction); + BadReaction = null; + State = TestState.GoodResult; + return true; + } + + public void CancelScan() { ReactionScannerService.Instance.CancelScan();