Skip to content

Commit e70c6d9

Browse files
committed
Generic methods for Atc decoding
1 parent 93ad0ee commit e70c6d9

File tree

3 files changed

+61
-34
lines changed

3 files changed

+61
-34
lines changed

AssetRipper.TextureDecoder.ConsoleApp/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,10 @@ private static void DecodeAtc(ReadOnlySpan<byte> input, int width, int height, s
117117
switch (mode)
118118
{
119119
case 0:
120-
AtcDecoder.DecompressAtcRgb4(input, width, height, output);
120+
AtcDecoder.DecompressAtcRgb4<ColorBGRA32, byte>(input, width, height, output);
121121
break;
122122
case 1:
123-
AtcDecoder.DecompressAtcRgba8(input, width, height, output);
123+
AtcDecoder.DecompressAtcRgba8<ColorBGRA32, byte>(input, width, height, output);
124124
break;
125125

126126
default:

AssetRipper.TextureDecoder.Tests/AtcTests.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
namespace AssetRipper.TextureDecoder.Tests
1+
using AssetRipper.TextureDecoder.Rgb.Formats;
2+
3+
namespace AssetRipper.TextureDecoder.Tests
24
{
35
public sealed class AtcTests
46
{
57
[Test]
68
public void DecompressAtcRgb4Test()
79
{
810
byte[] data = File.ReadAllBytes(TestFileFolders.AtcTestFiles + "test.atc_rgb4");
9-
int bytesRead = Atc.AtcDecoder.DecompressAtcRgb4(data, 256, 256, out byte[] decodedData);
11+
int bytesRead = Atc.AtcDecoder.DecompressAtcRgb4<ColorBGRA32, byte>(data, 256, 256, out byte[] decodedData);
1012
Assert.Multiple(() =>
1113
{
1214
Assert.That(bytesRead, Is.EqualTo(data.Length));
@@ -18,7 +20,7 @@ public void DecompressAtcRgb4Test()
1820
public void DecompressAtcRgba8Test()
1921
{
2022
byte[] data = File.ReadAllBytes(TestFileFolders.AtcTestFiles + "test.atc_rgba8");
21-
int bytesRead = Atc.AtcDecoder.DecompressAtcRgba8(data, 256, 256, out byte[] decodedData);
23+
int bytesRead = Atc.AtcDecoder.DecompressAtcRgba8<ColorBGRA32, byte>(data, 256, 256, out byte[] decodedData);
2224
Assert.Multiple(() =>
2325
{
2426
Assert.That(bytesRead, Is.EqualTo(data.Length));

AssetRipper.TextureDecoder/Atc/AtcDecoder.cs

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,103 @@
1+
using AssetRipper.TextureDecoder.Rgb;
12
using System.Buffers.Binary;
23

34
namespace AssetRipper.TextureDecoder.Atc
45
{
56
public static class AtcDecoder
67
{
7-
public static int DecompressAtcRgb4(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
8+
public static int DecompressAtcRgb4<TOutputColor, TOutputChannelValue>(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
9+
where TOutputChannelValue : unmanaged
10+
where TOutputColor : unmanaged, IColor<TOutputChannelValue>
811
{
9-
output = new byte[width * height * 4];
10-
return DecompressAtcRgb4(input, width, height, output);
12+
output = new byte[width * height * Unsafe.SizeOf<TOutputColor>()];
13+
return DecompressAtcRgb4<TOutputColor, TOutputChannelValue>(input, width, height, output);
1114
}
1215

13-
public static int DecompressAtcRgb4(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
16+
public static int DecompressAtcRgb4<TOutputColor, TOutputChannelValue>(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
17+
where TOutputChannelValue : unmanaged
18+
where TOutputColor : unmanaged, IColor<TOutputChannelValue>
1419
{
20+
ThrowHelper.ThrowIfNotLittleEndian();
21+
return DecompressAtcRgb4<TOutputColor, TOutputChannelValue>(input, width, height, MemoryMarshal.Cast<byte, TOutputColor>(output));
22+
}
23+
24+
public static int DecompressAtcRgb4<TOutputColor, TOutputChannelValue>(ReadOnlySpan<byte> input, int width, int height, Span<TOutputColor> output)
25+
where TOutputChannelValue : unmanaged
26+
where TOutputColor : unmanaged, IColor<TOutputChannelValue>
27+
{
28+
ThrowHelper.ThrowIfNotEnoughSpace(output.Length, width * height);
1529
int bcw = (width + 3) / 4;
1630
int bch = (height + 3) / 4;
1731
int clen_last = (width + 3) % 4 + 1;
18-
Span<uint> buf = stackalloc uint[16];
32+
Span<TOutputColor> buf = stackalloc TOutputColor[16];
1933
int inputOffset = 0;
2034
for (int t = 0; t < bch; t++)
2135
{
2236
for (int s = 0; s < bcw; s++, inputOffset += 8)
2337
{
24-
DecodeAtcRgb4Block(input.Slice(inputOffset, 8), buf);
38+
DecodeAtcRgb4Block<TOutputColor, TOutputChannelValue>(input.Slice(inputOffset, 8), buf);
2539
int clen = s < bcw - 1 ? 4 : clen_last;
2640
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
2741
{
28-
int outputOffset = t * 16 * width + s * 16 + i * width * sizeof(uint);
42+
int outputOffset = t * 4 * width + s * 4 + i * width;
2943
for (int j = 0; j < clen; j++)
3044
{
31-
BinaryPrimitives.WriteUInt32LittleEndian(output.Slice(outputOffset + j * sizeof(uint)), buf[j + 4 * i]);
45+
output[outputOffset + j] = buf[j + 4 * i];
3246
}
3347
}
3448
}
3549
}
3650
return inputOffset;
3751
}
3852

39-
public static int DecompressAtcRgba8(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
53+
public static int DecompressAtcRgba8<TOutputColor, TOutputChannelValue>(ReadOnlySpan<byte> input, int width, int height, out byte[] output)
54+
where TOutputChannelValue : unmanaged
55+
where TOutputColor : unmanaged, IColor<TOutputChannelValue>
56+
{
57+
output = new byte[width * height * Unsafe.SizeOf<TOutputColor>()];
58+
return DecompressAtcRgba8<TOutputColor, TOutputChannelValue>(input, width, height, output);
59+
}
60+
61+
public static int DecompressAtcRgba8<TOutputColor, TOutputChannelValue>(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
62+
where TOutputChannelValue : unmanaged
63+
where TOutputColor : unmanaged, IColor<TOutputChannelValue>
4064
{
41-
output = new byte[width * height * 4];
42-
return DecompressAtcRgba8(input, width, height, output);
65+
ThrowHelper.ThrowIfNotLittleEndian();
66+
return DecompressAtcRgba8<TOutputColor, TOutputChannelValue>(input, width, height, MemoryMarshal.Cast<byte, TOutputColor>(output));
4367
}
4468

45-
public static int DecompressAtcRgba8(ReadOnlySpan<byte> input, int width, int height, Span<byte> output)
69+
public static int DecompressAtcRgba8<TOutputColor, TOutputChannelValue>(ReadOnlySpan<byte> input, int width, int height, Span<TOutputColor> output)
70+
where TOutputChannelValue : unmanaged
71+
where TOutputColor : unmanaged, IColor<TOutputChannelValue>
4672
{
73+
ThrowHelper.ThrowIfNotEnoughSpace(output.Length, width * height);
4774
int bcw = (width + 3) / 4;
4875
int bch = (height + 3) / 4;
4976
int clen_last = (width + 3) % 4 + 1;
50-
Span<uint> buf = stackalloc uint[16];
77+
Span<TOutputColor> buf = stackalloc TOutputColor[16];
5178
int inputOffset = 0;
5279
for (int t = 0; t < bch; t++)
5380
{
5481
for (int s = 0; s < bcw; s++, inputOffset += 16)
5582
{
56-
DecodeAtcRgba8Block(input.Slice(inputOffset, 16), buf);
83+
DecodeAtcRgba8Block<TOutputColor, TOutputChannelValue>(input.Slice(inputOffset, 16), buf);
5784
int clen = s < bcw - 1 ? 4 : clen_last;
5885
for (int i = 0, y = t * 4; i < 4 && y < height; i++, y++)
5986
{
60-
int outputOffset = t * 16 * width + s * 16 + i * width * sizeof(uint);
87+
int outputOffset = t * 4 * width + s * 4 + i * width;
6188
for (int j = 0; j < clen; j++)
6289
{
63-
BinaryPrimitives.WriteUInt32LittleEndian(output.Slice(outputOffset + j * sizeof(uint)), buf[j + 4 * i]);
90+
output[outputOffset + j] = buf[j + 4 * i];
6491
}
6592
}
6693
}
6794
}
6895
return inputOffset;
6996
}
7097

71-
private static void DecodeAtcRgb4Block(ReadOnlySpan<byte> input, Span<uint> output)
98+
private static void DecodeAtcRgb4Block<TOutputColor, TOutputChannelValue>(ReadOnlySpan<byte> input, Span<TOutputColor> output)
99+
where TOutputChannelValue : unmanaged
100+
where TOutputColor : unmanaged, IColor<TOutputChannelValue>
72101
{
73102
Span<int> colors = stackalloc int[16];
74103
int c0 = input.ReadAtOffset<ushort>(0);
@@ -83,12 +112,14 @@ private static void DecodeAtcRgb4Block(ReadOnlySpan<byte> input, Span<uint> outp
83112
int cb = colors[cidx * 4 + 0];
84113
int cg = colors[cidx * 4 + 1];
85114
int cr = colors[cidx * 4 + 2];
86-
output[i] = Color(cr, cg, cb, 255);
115+
output[i].SetConvertedChannels<TOutputColor, TOutputChannelValue, byte>((byte)cr, (byte)cg, (byte)cb, byte.MaxValue);
87116
cindex >>= 2;
88117
}
89118
}
90119

91-
private static void DecodeAtcRgba8Block(ReadOnlySpan<byte> input, Span<uint> output)
120+
private static void DecodeAtcRgba8Block<TOutputColor, TOutputChannelValue>(ReadOnlySpan<byte> input, Span<TOutputColor> output)
121+
where TOutputChannelValue : unmanaged
122+
where TOutputColor : unmanaged, IColor<TOutputChannelValue>
92123
{
93124
Span<int> alphas = stackalloc int[16];
94125
ulong avalue = BinaryPrimitives.ReadUInt64LittleEndian(input);
@@ -112,7 +143,7 @@ private static void DecodeAtcRgba8Block(ReadOnlySpan<byte> input, Span<uint> out
112143
int cr = colors[cidx * 4 + 2];
113144
int aidx = unchecked((int)aindex & 7);
114145
int ca = alphas[aidx];
115-
output[i] = Color(cr, cg, cb, ca);
146+
output[i].SetConvertedChannels<TOutputColor, TOutputChannelValue, byte>((byte)cr, (byte)cg, (byte)cb, (byte)ca);
116147
cindex >>= 2;
117148
aindex >>= 3;
118149
}
@@ -160,9 +191,9 @@ private static void DecodeColors(Span<int> colors, int c0, int c1)
160191
colors[13] = Extend((c1 >> 5) & 0x3F, 6, 8);
161192
colors[14] = Extend((c1 >> 11) & 0x1F, 5, 8);
162193

163-
colors[4] = Math.Max(0, colors[8] - colors[12] / 4);
164-
colors[5] = Math.Max(0, colors[9] - colors[13] / 4);
165-
colors[6] = Math.Max(0, colors[10] - colors[14] / 4);
194+
colors[4] = int.Max(0, colors[8] - colors[12] / 4);
195+
colors[5] = int.Max(0, colors[9] - colors[13] / 4);
196+
colors[6] = int.Max(0, colors[10] - colors[14] / 4);
166197
}
167198
}
168199

@@ -197,11 +228,5 @@ private static int Extend(int value, int from, int to)
197228
// bit-pattern replicating scaling (can at most double the bits)
198229
return (value << (to - from)) | (value >> (from * 2 - to));
199230
}
200-
201-
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
202-
private static uint Color(int r, int g, int b, int a)
203-
{
204-
return unchecked((uint)(r << 16 | g << 8 | b | a << 24));
205-
}
206231
}
207232
}

0 commit comments

Comments
 (0)