269 lines
8.8 KiB
C#
269 lines
8.8 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|