Nominom / BCnEncoder.NET

Cross-platform texture encoding libary for .NET. With support for BC1-3/DXT, BC4-5/RGTC and BC6-7/BPTC compression. Outputs files in ktx or dds formats.
The Unlicense
108 stars 16 forks source link

Possible corruption decoding BC6h uf16 #54

Closed ptasev closed 2 years ago

ptasev commented 2 years ago

I'm converting a decoded BC6h uf16 RgbFloat to Bgr24. Assuming I haven't made a mistake, it appears there may be corruption in the decoder.

Nuget: BcnEncoder.NET ImageSharp 1.1.1 Sample.zip

Here's my code:

var fileName = @"";
var outFileName = fileName + ".png";
var bcDds = DdsFile.Load(fileName);
var width = (int)bcDds.header.dwWidth;
var height = (int)bcDds.header.dwHeight;

var decoder = new BcDecoder();
var source = decoder.DecodeHdr2D(bcDds);

var pixels = new byte[width * height * 3];
var pixelsSpan = MemoryMarshal.Cast<byte, Bgr24>(pixels);
for (var r = 0; r < height; ++r)
{
    var destRow = pixelsSpan.Slice(r * width, width);
    var sorcRow = source.Span.GetRowSpan(r);
    for (var c = 0; c < destRow.Length; ++c)
    {
        ref var destPixel = ref destRow[c];
        ref var sorcPixel = ref sorcRow[c];

        var rgbVal = sorcPixel.ToVector3() * byte.MaxValue;
        var bgr24 = new Bgr24(
            Math.Clamp((byte)rgbVal.X, (byte)0, byte.MaxValue), 
            Math.Clamp((byte)rgbVal.Y, (byte)0, byte.MaxValue), 
            Math.Clamp((byte)rgbVal.Z, (byte)0, byte.MaxValue));
        destPixel = bgr24;
    }
}

unsafe
{
    fixed (void* wrap = pixelsSpan)
    {
        Image.WrapMemory<Bgr24>(wrap, width, height).Save(outFileName);
    }
}
Nominom commented 2 years ago

Hi!

Thanks for the report. I'll take a look today to see if I can spot the issue.

ptasev commented 2 years ago

Hmm, it works just fine if I replace destPixel = bgr24 with destPixel.FromScaledVector4(new Vector4(sorcPixel.ToVector3(), 1));. Since I was casting 256.0+ to byte that resulted in an overflow. Sometimes the RgbFloat value is >1.0 so I have to do the clamping in float first, and then convert to byte last like this:

var vecMax = new Vector3(byte.MaxValue);
var vecHalf = new Vector3(0.5f);
var rgbVal = sorcPixel.ToVector3() * vecMax + vecHalf;
rgbVal = Vector3.Clamp(rgbVal, Vector3.Zero, vecMax);
var bgr24 = new Bgr24((byte)rgbVal.X, (byte)rgbVal.Y, (byte)rgbVal.Z);

The library works just fine, thanks!

Nominom commented 2 years ago

Glad you got it working!