Skip to content

Commit ed8ffde

Browse files
committed
Generic methods for ASTC decoding
1 parent e70c6d9 commit ed8ffde

File tree

3 files changed

+32
-28
lines changed

3 files changed

+32
-28
lines changed

AssetRipper.TextureDecoder.ConsoleApp/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ private static void DecodeAstc(ReadOnlySpan<byte> input, int width, int height,
105105
Console.WriteLine("Arg at index 6 : blockYSize");
106106
int blockXSize = int.Parse(blockXSizeString);
107107
int blockYSize = int.Parse(blockYSizeString);
108-
AstcDecoder.DecodeASTC(input, width, height, blockXSize, blockYSize, output);
108+
AstcDecoder.DecodeASTC<ColorBGRA32, byte>(input, width, height, blockXSize, blockYSize, output);
109109
}
110110

111111
private static void DecodeAtc(ReadOnlySpan<byte> input, int width, int height, string modeString, Span<byte> output)

AssetRipper.TextureDecoder.Tests/AstcTests.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using AssetRipper.TextureDecoder.Astc;
2+
using AssetRipper.TextureDecoder.Rgb.Formats;
23

34
namespace AssetRipper.TextureDecoder.Tests;
45

@@ -67,7 +68,7 @@ public sealed class AstcTests
6768
private static void AssertCorrectDecompression<T>(int blockWidth, int blockHeight, double maxMeanDeviation, double maxStandardDeviation) where T : ITexture
6869
{
6970
ReadOnlySpan<byte> data = T.Data;
70-
int bytesRead = AstcDecoder.DecodeASTC(data, T.Width, T.Height, blockWidth, blockHeight, out byte[] decompressedData);
71+
int bytesRead = AstcDecoder.DecodeASTC<ColorBGRA32, byte>(data, T.Width, T.Height, blockWidth, blockHeight, out byte[] decompressedData);
7172
if (!T.Mips)
7273
{
7374
Assert.That(bytesRead, Is.EqualTo(data.Length));
@@ -78,6 +79,6 @@ private static void AssertCorrectDecompression<T>(int blockWidth, int blockHeigh
7879
[TestCase(new byte[16] { 83, 1, 147, 104, 198, 173, 55, 116, 182, 66, 105, 11, 102, 43, 148, 125 }, 8, 8, TestName = "GetBits Should not throw in DecodeIntseq")]
7980
public void DecodesBlockWithoutThrowing(byte[] block, int blockWidth, int blockHeight)
8081
{
81-
Assert.DoesNotThrow(() => AstcDecoder.DecodeASTC(block, blockWidth, blockHeight, blockWidth, blockHeight, out _));
82+
Assert.DoesNotThrow(() => AstcDecoder.DecodeASTC<ColorBGRA32, byte>(block, blockWidth, blockHeight, blockWidth, blockHeight, out _));
8283
}
8384
}

AssetRipper.TextureDecoder/Astc/AstcDecoder.cs

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using AssetRipper.TextureDecoder.Rgb;
2+
using AssetRipper.TextureDecoder.Rgb.Formats;
13
using System.Buffers.Binary;
24

35
namespace AssetRipper.TextureDecoder.Astc
@@ -12,51 +14,58 @@ private static void ValidateBlockDimension(int value, [CallerArgumentExpression(
1214
}
1315
}
1416

15-
public static int DecodeASTC(ReadOnlySpan<byte> input, int width, int height, int blockWidth, int blockHeight, out byte[] output)
17+
public static int DecodeASTC<TOutputColor, TOutputChannelValue>(ReadOnlySpan<byte> input, int width, int height, int blockWidth, int blockHeight, out byte[] output)
18+
where TOutputChannelValue : unmanaged
19+
where TOutputColor : unmanaged, IColor<TOutputChannelValue>
1620
{
1721
output = new byte[width * height * 4];
18-
return DecodeASTC(input, width, height, blockWidth, blockHeight, output);
22+
return DecodeASTC<TOutputColor, TOutputChannelValue>(input, width, height, blockWidth, blockHeight, output);
1923
}
2024

21-
public static int DecodeASTC(ReadOnlySpan<byte> input, int width, int height, int blockWidth, int blockHeight, Span<byte> output)
25+
public static int DecodeASTC<TOutputColor, TOutputChannelValue>(ReadOnlySpan<byte> input, int width, int height, int blockWidth, int blockHeight, Span<byte> output)
26+
where TOutputChannelValue : unmanaged
27+
where TOutputColor : unmanaged, IColor<TOutputChannelValue>
2228
{
29+
ThrowHelper.ThrowIfNotLittleEndian();
30+
return DecodeASTC<TOutputColor, TOutputChannelValue>(input, width, height, blockWidth, blockHeight, MemoryMarshal.Cast<byte, TOutputColor>(output));
31+
}
32+
33+
public static int DecodeASTC<TOutputColor, TOutputChannelValue>(ReadOnlySpan<byte> input, int width, int height, int blockWidth, int blockHeight, Span<TOutputColor> output)
34+
where TOutputChannelValue : unmanaged
35+
where TOutputColor : unmanaged, IColor<TOutputChannelValue>
36+
{
37+
ThrowHelper.ThrowIfNotEnoughSpace(output.Length, width * height);
2338
ValidateBlockDimension(blockWidth);
2439
ValidateBlockDimension(blockHeight);
2540
int bcw = (width + blockWidth - 1) / blockWidth;
2641
int bch = (height + blockHeight - 1) / blockHeight;
2742
int clen_last = (width + blockWidth - 1) % blockWidth + 1;
28-
Span<uint> buf = stackalloc uint[blockWidth * blockHeight];
43+
Span<ColorRGBA<byte>> buffer = stackalloc ColorRGBA<byte>[blockWidth * blockHeight];
2944
int inputOffset = 0;
3045
for (int t = 0; t < bch; t++)
3146
{
3247
for (int s = 0; s < bcw; s++, inputOffset += 16)
3348
{
34-
DecodeBlock(input[inputOffset..], blockWidth, blockHeight, buf);
49+
DecodeBlock(input[inputOffset..], blockWidth, blockHeight, buffer);
3550
int clen = s < bcw - 1 ? blockWidth : clen_last;
3651
for (int i = 0, y = t * blockHeight; i < blockHeight && y < height; i++, y++)
3752
{
3853
int outputOffsetUInt32 = t * blockHeight * width + s * blockWidth + i * width;
3954
for (int j = 0; j < clen; j++)
4055
{
41-
WriteUInt32(output, outputOffsetUInt32 + j, buf[j + i * blockWidth]);
56+
output[outputOffsetUInt32 + j] = buffer[j + i * blockWidth].Convert<ColorRGBA<byte>, byte, TOutputColor, TOutputChannelValue>();
4257
}
4358
}
4459
}
4560
}
4661
return inputOffset;
47-
48-
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
49-
static void WriteUInt32(Span<byte> buffer, int offsetUInt32, uint value)
50-
{
51-
BinaryPrimitives.WriteUInt32LittleEndian(buffer.Slice(offsetUInt32 * sizeof(uint)), value);
52-
}
5362
}
5463

55-
private static void DecodeBlock(ReadOnlySpan<byte> input, int blockWidth, int blockHeight, Span<uint> output)
64+
private static void DecodeBlock(ReadOnlySpan<byte> input, int blockWidth, int blockHeight, Span<ColorRGBA<byte>> output)
5665
{
5766
if (input[0] == 0xfc && (input[1] & 1) == 1)
5867
{
59-
uint c = Color(input[9], input[11], input[13], input[15]);
68+
ColorRGBA<byte> c = new(input[9], input[11], input[13], input[15]);
6069
for (int i = 0; i < blockWidth * blockHeight; i++)
6170
{
6271
output[i] = c;
@@ -674,7 +683,7 @@ private static void SelectPartition(ReadOnlySpan<byte> input, ref BlockData bloc
674683
}
675684
}
676685

677-
private static void ApplicateColor(BlockData block, Span<uint> output)
686+
private static void ApplicateColor(BlockData block, Span<ColorRGBA<byte>> output)
678687
{
679688
if (block.dual_plane != 0)
680689
{
@@ -689,7 +698,7 @@ private static void ApplicateColor(BlockData block, Span<uint> output)
689698
byte g = SelectColor(block.endpoints[p][1], block.endpoints[p][5], block.weights[i * 2 + ps[1]]);
690699
byte b = SelectColor(block.endpoints[p][2], block.endpoints[p][6], block.weights[i * 2 + ps[2]]);
691700
byte a = SelectColor(block.endpoints[p][3], block.endpoints[p][7], block.weights[i * 2 + ps[3]]);
692-
output[i] = Color(r, g, b, a);
701+
output[i] = new(r, g, b, a);
693702
}
694703
}
695704
else
@@ -700,7 +709,7 @@ private static void ApplicateColor(BlockData block, Span<uint> output)
700709
byte g = SelectColor(block.endpoints[0][1], block.endpoints[0][5], block.weights[i * 2 + ps[1]]);
701710
byte b = SelectColor(block.endpoints[0][2], block.endpoints[0][6], block.weights[i * 2 + ps[2]]);
702711
byte a = SelectColor(block.endpoints[0][3], block.endpoints[0][7], block.weights[i * 2 + ps[3]]);
703-
output[i] = Color(r, g, b, a);
712+
output[i] = new(r, g, b, a);
704713
}
705714
}
706715
}
@@ -713,7 +722,7 @@ private static void ApplicateColor(BlockData block, Span<uint> output)
713722
byte g = SelectColor(block.endpoints[p][1], block.endpoints[p][5], block.weights[i * 2]);
714723
byte b = SelectColor(block.endpoints[p][2], block.endpoints[p][6], block.weights[i * 2]);
715724
byte a = SelectColor(block.endpoints[p][3], block.endpoints[p][7], block.weights[i * 2]);
716-
output[i] = Color(r, g, b, a);
725+
output[i] = new(r, g, b, a);
717726
}
718727
}
719728
else
@@ -724,7 +733,7 @@ private static void ApplicateColor(BlockData block, Span<uint> output)
724733
byte g = SelectColor(block.endpoints[0][1], block.endpoints[0][5], block.weights[i * 2]);
725734
byte b = SelectColor(block.endpoints[0][2], block.endpoints[0][6], block.weights[i * 2]);
726735
byte a = SelectColor(block.endpoints[0][3], block.endpoints[0][7], block.weights[i * 2]);
727-
output[i] = Color(r, g, b, a);
736+
output[i] = new(r, g, b, a);
728737
}
729738
}
730739
}
@@ -849,12 +858,6 @@ private static void DecodeIntseq(ReadOnlySpan<byte> input, int offset, int a, in
849858
}
850859
}
851860

852-
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
853-
private static uint Color(uint r, uint g, uint b, uint a)
854-
{
855-
return r << 16 | g << 8 | b | a << 24;
856-
}
857-
858861
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
859862
private static byte BitReverseU8(byte c, int bits)
860863
{

0 commit comments

Comments
 (0)