Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optionally regenerate BC5 blue channel when decoding #67

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions BCnEnc.Net/Decoder/BcBlockDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,16 +127,18 @@ internal class Bc5Decoder : BaseBcBlockDecoder<Bc5Block, RawBlock4X4Rgba32>
{
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);
}
}

Expand Down
4 changes: 2 additions & 2 deletions BCnEnc.Net/Decoder/BcDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1598,7 +1598,7 @@ private IBcBlockDecoder<RawBlock4X4Rgba32> 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();
Expand Down Expand Up @@ -1773,7 +1773,7 @@ public int GetBlockSize(CompressionFormat format)

case CompressionFormat.Unknown:
return 0;

default:
throw new ArgumentOutOfRangeException(nameof(format), format, null);
}
Expand Down
5 changes: 5 additions & 0 deletions BCnEnc.Net/Decoder/Options/DecoderOutputOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,10 @@ public class DecoderOutputOptions
/// The color channel to populate with the values of the second BC5 block.
/// </summary>
public ColorComponent Bc5Component2 { get; set; } = ColorComponent.G;

/// <summary>
/// BC5 option to recalculate the blue channel
/// </summary>
public bool Bc5RecalculateBlueChannel { get; set; } = false;
}
}
19 changes: 18 additions & 1 deletion BCnEnc.Net/Shared/EncodedBlocks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,18 +251,35 @@ 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;

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;
Expand Down