From f8ee94150af6e02ba3b5fbc4240a428b1634345e Mon Sep 17 00:00:00 2001 From: Eonzenex Date: Fri, 24 Nov 2023 18:01:32 +1300 Subject: [PATCH] Optionally regenerate BC5 blue channel when decoding --- BCnEnc.Net/Decoder/BcBlockDecoder.cs | 6 ++++-- BCnEnc.Net/Decoder/BcDecoder.cs | 4 ++-- .../Decoder/Options/DecoderOutputOptions.cs | 5 +++++ BCnEnc.Net/Shared/EncodedBlocks.cs | 19 ++++++++++++++++++- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/BCnEnc.Net/Decoder/BcBlockDecoder.cs b/BCnEnc.Net/Decoder/BcBlockDecoder.cs index 7706639..501c2bd 100644 --- a/BCnEnc.Net/Decoder/BcBlockDecoder.cs +++ b/BCnEnc.Net/Decoder/BcBlockDecoder.cs @@ -127,16 +127,18 @@ internal class Bc5Decoder : BaseBcBlockDecoder { private readonly ColorComponent component1; private readonly ColorComponent component2; + private readonly bool recalculateBlueChannel; - public Bc5Decoder(ColorComponent component1, ColorComponent component2) + public Bc5Decoder(ColorComponent component1, ColorComponent component2, bool recalculateBlueChannel) { this.component1 = component1; this.component2 = component2; + this.recalculateBlueChannel = recalculateBlueChannel; } protected override RawBlock4X4Rgba32 DecodeBlock(Bc5Block block) { - return block.Decode(component1, component2); + return block.Decode(component1, component2, recalculateBlueChannel); } } diff --git a/BCnEnc.Net/Decoder/BcDecoder.cs b/BCnEnc.Net/Decoder/BcDecoder.cs index 6c37ad9..bec7da9 100644 --- a/BCnEnc.Net/Decoder/BcDecoder.cs +++ b/BCnEnc.Net/Decoder/BcDecoder.cs @@ -1598,7 +1598,7 @@ private IBcBlockDecoder GetRgba32Decoder(CompressionFormat fo return new Bc4Decoder(OutputOptions.Bc4Component); case CompressionFormat.Bc5: - return new Bc5Decoder(OutputOptions.Bc5Component1, OutputOptions.Bc5Component2); + return new Bc5Decoder(OutputOptions.Bc5Component1, OutputOptions.Bc5Component2, OutputOptions.Bc5RecalculateBlueChannel); case CompressionFormat.Bc7: return new Bc7Decoder(); @@ -1773,7 +1773,7 @@ public int GetBlockSize(CompressionFormat format) case CompressionFormat.Unknown: return 0; - + default: throw new ArgumentOutOfRangeException(nameof(format), format, null); } diff --git a/BCnEnc.Net/Decoder/Options/DecoderOutputOptions.cs b/BCnEnc.Net/Decoder/Options/DecoderOutputOptions.cs index f221800..850b3a2 100644 --- a/BCnEnc.Net/Decoder/Options/DecoderOutputOptions.cs +++ b/BCnEnc.Net/Decoder/Options/DecoderOutputOptions.cs @@ -29,5 +29,10 @@ public class DecoderOutputOptions /// The color channel to populate with the values of the second BC5 block. /// public ColorComponent Bc5Component2 { get; set; } = ColorComponent.G; + + /// + /// BC5 option to recalculate the blue channel + /// + public bool Bc5RecalculateBlueChannel { get; set; } = false; } } diff --git a/BCnEnc.Net/Shared/EncodedBlocks.cs b/BCnEnc.Net/Shared/EncodedBlocks.cs index e67b205..db847f1 100644 --- a/BCnEnc.Net/Shared/EncodedBlocks.cs +++ b/BCnEnc.Net/Shared/EncodedBlocks.cs @@ -251,7 +251,7 @@ public byte Green1 public void SetGreenIndex(int pixelIndex, byte greenIndex) => greenBlock.SetComponentIndex(pixelIndex, greenIndex); - public readonly RawBlock4X4Rgba32 Decode(ColorComponent component1 = ColorComponent.R, ColorComponent component2 = ColorComponent.G) + public readonly RawBlock4X4Rgba32 Decode(ColorComponent component1 = ColorComponent.R, ColorComponent component2 = ColorComponent.G, bool recalculateBlueChannel = false) { var output = new RawBlock4X4Rgba32(); var pixels = output.AsSpan; @@ -259,10 +259,27 @@ public readonly RawBlock4X4Rgba32 Decode(ColorComponent component1 = ColorCompon var reds = redBlock.Decode(); var greens = greenBlock.Decode(); + var blues = new byte[pixels.Length]; + if (recalculateBlueChannel) + { + for (var i = 0; i < pixels.Length; i++) + { + var red = (float) reds[i] / 255; + var green = (float) greens[i] / 255; + + var blue = 1 - red * red - green * green; + blue = blue < 0 ? 0f : (float) Math.Sqrt(blue); + blue = Math.Clamp((blue + 1) / 2f, 0f, 1f); + + blues[i] = (byte) (blue * 255); + } + } + for (var i = 0; i < pixels.Length; i++) { pixels[i] = ComponentHelper.ComponentToColor(component1, reds[i]); pixels[i] = ComponentHelper.ComponentToColor(pixels[i], component2, greens[i]); + pixels[i] = ComponentHelper.ComponentToColor(pixels[i], ColorComponent.B, blues[i]); } return output;