using System.Collections; using System.Collections.Generic; namespace Ryujinx.Graphics.Texture { 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 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 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 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; } } } } } }