diff options
Diffstat (limited to 'Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs')
-rw-r--r-- | Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs b/Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs new file mode 100644 index 00000000..5aa610e7 --- /dev/null +++ b/Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs @@ -0,0 +1,269 @@ +using System.Collections; +using System.Collections.Generic; + +namespace Ryujinx.Graphics.Texture.Astc +{ + public struct IntegerEncoded + { + public enum EIntegerEncoding + { + JustBits, + Quint, + Trit + } + + EIntegerEncoding _encoding; + public int NumberBits { get; private set; } + public int BitValue { get; private set; } + public int TritValue { get; private set; } + public int QuintValue { get; private set; } + + public IntegerEncoded(EIntegerEncoding encoding, int numBits) + { + _encoding = encoding; + NumberBits = numBits; + BitValue = 0; + TritValue = 0; + QuintValue = 0; + } + + public bool MatchesEncoding(IntegerEncoded other) + { + return _encoding == other._encoding && NumberBits == other.NumberBits; + } + + public EIntegerEncoding GetEncoding() + { + return _encoding; + } + + public int GetBitLength(int numberVals) + { + int totalBits = NumberBits * numberVals; + if (_encoding == EIntegerEncoding.Trit) + { + totalBits += (numberVals * 8 + 4) / 5; + } + else if (_encoding == EIntegerEncoding.Quint) + { + totalBits += (numberVals * 7 + 2) / 3; + } + return totalBits; + } + + public static IntegerEncoded CreateEncoding(int maxVal) + { + while (maxVal > 0) + { + int check = maxVal + 1; + + // Is maxVal a power of two? + if ((check & (check - 1)) == 0) + { + return new IntegerEncoded(EIntegerEncoding.JustBits, BitArrayStream.PopCnt(maxVal)); + } + + // Is maxVal of the type 3*2^n - 1? + if ((check % 3 == 0) && ((check / 3) & ((check / 3) - 1)) == 0) + { + return new IntegerEncoded(EIntegerEncoding.Trit, BitArrayStream.PopCnt(check / 3 - 1)); + } + + // Is maxVal of the type 5*2^n - 1? + if ((check % 5 == 0) && ((check / 5) & ((check / 5) - 1)) == 0) + { + return new IntegerEncoded(EIntegerEncoding.Quint, BitArrayStream.PopCnt(check / 5 - 1)); + } + + // Apparently it can't be represented with a bounded integer sequence... + // just iterate. + maxVal--; + } + + return new IntegerEncoded(EIntegerEncoding.JustBits, 0); + } + + public static void DecodeTritBlock( + BitArrayStream bitStream, + List<IntegerEncoded> listIntegerEncoded, + int numberBitsPerValue) + { + // Implement the algorithm in section C.2.12 + int[] m = new int[5]; + int[] t = new int[5]; + int T; + + // Read the trit encoded block according to + // table C.2.14 + m[0] = bitStream.ReadBits(numberBitsPerValue); + T = bitStream.ReadBits(2); + m[1] = bitStream.ReadBits(numberBitsPerValue); + T |= bitStream.ReadBits(2) << 2; + m[2] = bitStream.ReadBits(numberBitsPerValue); + T |= bitStream.ReadBits(1) << 4; + m[3] = bitStream.ReadBits(numberBitsPerValue); + T |= bitStream.ReadBits(2) << 5; + m[4] = bitStream.ReadBits(numberBitsPerValue); + T |= bitStream.ReadBits(1) << 7; + + int c = 0; + + BitArrayStream tb = new BitArrayStream(new BitArray(new int[] { T })); + if (tb.ReadBits(2, 4) == 7) + { + c = (tb.ReadBits(5, 7) << 2) | tb.ReadBits(0, 1); + t[4] = t[3] = 2; + } + else + { + c = tb.ReadBits(0, 4); + if (tb.ReadBits(5, 6) == 3) + { + t[4] = 2; + t[3] = tb.ReadBit(7); + } + else + { + t[4] = tb.ReadBit(7); + t[3] = tb.ReadBits(5, 6); + } + } + + BitArrayStream cb = new BitArrayStream(new BitArray(new int[] { c })); + if (cb.ReadBits(0, 1) == 3) + { + t[2] = 2; + t[1] = cb.ReadBit(4); + t[0] = (cb.ReadBit(3) << 1) | (cb.ReadBit(2) & ~cb.ReadBit(3)); + } + else if (cb.ReadBits(2, 3) == 3) + { + t[2] = 2; + t[1] = 2; + t[0] = cb.ReadBits(0, 1); + } + else + { + t[2] = cb.ReadBit(4); + t[1] = cb.ReadBits(2, 3); + t[0] = (cb.ReadBit(1) << 1) | (cb.ReadBit(0) & ~cb.ReadBit(1)); + } + + for (int i = 0; i < 5; i++) + { + IntegerEncoded intEncoded = new IntegerEncoded(EIntegerEncoding.Trit, numberBitsPerValue) + { + BitValue = m[i], + TritValue = t[i] + }; + listIntegerEncoded.Add(intEncoded); + } + } + + public static void DecodeQuintBlock( + BitArrayStream bitStream, + List<IntegerEncoded> listIntegerEncoded, + int numberBitsPerValue) + { + // Implement the algorithm in section C.2.12 + int[] m = new int[3]; + int[] qa = new int[3]; + int q; + + // Read the trit encoded block according to + // table C.2.15 + m[0] = bitStream.ReadBits(numberBitsPerValue); + q = bitStream.ReadBits(3); + m[1] = bitStream.ReadBits(numberBitsPerValue); + q |= bitStream.ReadBits(2) << 3; + m[2] = bitStream.ReadBits(numberBitsPerValue); + q |= bitStream.ReadBits(2) << 5; + + BitArrayStream qb = new BitArrayStream(new BitArray(new int[] { q })); + if (qb.ReadBits(1, 2) == 3 && qb.ReadBits(5, 6) == 0) + { + qa[0] = qa[1] = 4; + qa[2] = (qb.ReadBit(0) << 2) | ((qb.ReadBit(4) & ~qb.ReadBit(0)) << 1) | (qb.ReadBit(3) & ~qb.ReadBit(0)); + } + else + { + int c = 0; + if (qb.ReadBits(1, 2) == 3) + { + qa[2] = 4; + c = (qb.ReadBits(3, 4) << 3) | ((~qb.ReadBits(5, 6) & 3) << 1) | qb.ReadBit(0); + } + else + { + qa[2] = qb.ReadBits(5, 6); + c = qb.ReadBits(0, 4); + } + + BitArrayStream cb = new BitArrayStream(new BitArray(new int[] { c })); + if (cb.ReadBits(0, 2) == 5) + { + qa[1] = 4; + qa[0] = cb.ReadBits(3, 4); + } + else + { + qa[1] = cb.ReadBits(3, 4); + qa[0] = cb.ReadBits(0, 2); + } + } + + for (int i = 0; i < 3; i++) + { + IntegerEncoded intEncoded = new IntegerEncoded(EIntegerEncoding.Quint, numberBitsPerValue) + { + BitValue = m[i], + QuintValue = qa[i] + }; + listIntegerEncoded.Add(intEncoded); + } + } + + public static void DecodeIntegerSequence( + List<IntegerEncoded> decodeIntegerSequence, + BitArrayStream bitStream, + int maxRange, + int numberValues) + { + // Determine encoding parameters + IntegerEncoded intEncoded = CreateEncoding(maxRange); + + // Start decoding + int numberValuesDecoded = 0; + while (numberValuesDecoded < numberValues) + { + switch (intEncoded.GetEncoding()) + { + case EIntegerEncoding.Quint: + { + DecodeQuintBlock(bitStream, decodeIntegerSequence, intEncoded.NumberBits); + numberValuesDecoded += 3; + + break; + } + + case EIntegerEncoding.Trit: + { + DecodeTritBlock(bitStream, decodeIntegerSequence, intEncoded.NumberBits); + numberValuesDecoded += 5; + + break; + } + + case EIntegerEncoding.JustBits: + { + intEncoded.BitValue = bitStream.ReadBits(intEncoded.NumberBits); + decodeIntegerSequence.Add(intEncoded); + numberValuesDecoded++; + + break; + } + } + } + } + } +} |