aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs
diff options
context:
space:
mode:
authorAlex Barney <thealexbarney@gmail.com>2019-12-26 23:09:49 -0700
committerThog <thog@protonmail.com>2020-01-09 02:13:00 +0100
commitd1ab9fb42c2fd9f018d4410ca619cd66294eafc9 (patch)
treedcac71560b921f29d73ee6e21f235528184d9f84 /Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs
parent947e14d3be0f7c5e4b6f77df204ec675b8e9e719 (diff)
ASTC optimizations (#845)
* ASTC optimizations * Move code to Ryujinx.Common * Support 3D textures * Address feedback * Remove ASTC logging * Use stackalloc instead of a Buffer20 struct * Code style and cleanup * Respond to feedback * Rearrange public/private property ordering
Diffstat (limited to 'Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs')
-rw-r--r--Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs334
1 files changed, 205 insertions, 129 deletions
diff --git a/Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs b/Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs
index 5aa610e7..065de46b 100644
--- a/Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs
+++ b/Ryujinx.Graphics.Texture/Astc/IntegerEncoded.cs
@@ -1,11 +1,14 @@
-using System.Collections;
-using System.Collections.Generic;
+using System;
+using System.Numerics;
namespace Ryujinx.Graphics.Texture.Astc
{
- public struct IntegerEncoded
+ internal struct IntegerEncoded
{
- public enum EIntegerEncoding
+ internal const int StructSize = 8;
+ private static readonly IntegerEncoded[] Encodings;
+
+ public enum EIntegerEncoding : byte
{
JustBits,
Quint,
@@ -13,17 +16,27 @@ namespace Ryujinx.Graphics.Texture.Astc
}
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 byte NumberBits { get; private set; }
+ public byte TritValue { get; private set; }
+ public byte QuintValue { get; private set; }
+ public int BitValue { get; private set; }
+
+ static IntegerEncoded()
+ {
+ Encodings = new IntegerEncoded[0x100];
+
+ for (int i = 0; i < Encodings.Length; i++)
+ {
+ Encodings[i] = CreateEncodingCalc(i);
+ }
+ }
public IntegerEncoded(EIntegerEncoding encoding, int numBits)
{
- _encoding = encoding;
- NumberBits = numBits;
- BitValue = 0;
- TritValue = 0;
+ _encoding = encoding;
+ NumberBits = (byte)numBits;
+ BitValue = 0;
+ TritValue = 0;
QuintValue = 0;
}
@@ -53,6 +66,11 @@ namespace Ryujinx.Graphics.Texture.Astc
public static IntegerEncoded CreateEncoding(int maxVal)
{
+ return Encodings[maxVal];
+ }
+
+ private static IntegerEncoded CreateEncodingCalc(int maxVal)
+ {
while (maxVal > 0)
{
int check = maxVal + 1;
@@ -60,19 +78,19 @@ namespace Ryujinx.Graphics.Texture.Astc
// Is maxVal a power of two?
if ((check & (check - 1)) == 0)
{
- return new IntegerEncoded(EIntegerEncoding.JustBits, BitArrayStream.PopCnt(maxVal));
+ return new IntegerEncoded(EIntegerEncoding.JustBits, BitOperations.PopCount((uint)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));
+ return new IntegerEncoded(EIntegerEncoding.Trit, BitOperations.PopCount((uint)(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));
+ return new IntegerEncoded(EIntegerEncoding.Quint, BitOperations.PopCount((uint)(check / 5 - 1)));
}
// Apparently it can't be represented with a bounded integer sequence...
@@ -84,150 +102,78 @@ namespace Ryujinx.Graphics.Texture.Astc
}
public static void DecodeTritBlock(
- BitArrayStream bitStream,
- List<IntegerEncoded> listIntegerEncoded,
- int numberBitsPerValue)
+ ref BitStream128 bitStream,
+ ref IntegerSequence listIntegerEncoded,
+ int numberBitsPerValue)
{
// Implement the algorithm in section C.2.12
- int[] m = new int[5];
- int[] t = new int[5];
- int T;
+ Span<int> m = stackalloc int[5];
- // Read the trit encoded block according to
- // table C.2.14
m[0] = bitStream.ReadBits(numberBitsPerValue);
- T = bitStream.ReadBits(2);
+ int encoded = bitStream.ReadBits(2);
m[1] = bitStream.ReadBits(numberBitsPerValue);
- T |= bitStream.ReadBits(2) << 2;
+ encoded |= bitStream.ReadBits(2) << 2;
m[2] = bitStream.ReadBits(numberBitsPerValue);
- T |= bitStream.ReadBits(1) << 4;
+ encoded |= bitStream.ReadBits(1) << 4;
m[3] = bitStream.ReadBits(numberBitsPerValue);
- T |= bitStream.ReadBits(2) << 5;
+ encoded |= bitStream.ReadBits(2) << 5;
m[4] = bitStream.ReadBits(numberBitsPerValue);
- T |= bitStream.ReadBits(1) << 7;
-
- int c = 0;
+ encoded |= bitStream.ReadBits(1) << 7;
- 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);
- }
- }
+ ReadOnlySpan<byte> encodings = GetTritEncoding(encoded);
- 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));
- }
+ IntegerEncoded intEncoded = new IntegerEncoded(EIntegerEncoding.Trit, numberBitsPerValue);
for (int i = 0; i < 5; i++)
{
- IntegerEncoded intEncoded = new IntegerEncoded(EIntegerEncoding.Trit, numberBitsPerValue)
- {
- BitValue = m[i],
- TritValue = t[i]
- };
- listIntegerEncoded.Add(intEncoded);
+ intEncoded.BitValue = m[i];
+ intEncoded.TritValue = encodings[i];
+
+ listIntegerEncoded.Add(ref intEncoded);
}
}
public static void DecodeQuintBlock(
- BitArrayStream bitStream,
- List<IntegerEncoded> listIntegerEncoded,
- int numberBitsPerValue)
+ ref BitStream128 bitStream,
+ ref IntegerSequence listIntegerEncoded,
+ int numberBitsPerValue)
{
- // Implement the algorithm in section C.2.12
- int[] m = new int[3];
- int[] qa = new int[3];
- int q;
+ ReadOnlySpan<byte> interleavedBits = new byte[] { 3, 2, 2 };
- // 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;
+ // Implement the algorithm in section C.2.12
+ Span<int> m = stackalloc int[3];
+ ulong encoded = 0;
+ int encodedBitsRead = 0;
- 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
+ for (int i = 0; i < m.Length; i++)
{
- 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);
- }
+ m[i] = bitStream.ReadBits(numberBitsPerValue);
- 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);
- }
+ uint encodedBits = (uint)bitStream.ReadBits(interleavedBits[i]);
+
+ encoded |= encodedBits << encodedBitsRead;
+ encodedBitsRead += interleavedBits[i];
}
+ ReadOnlySpan<byte> encodings = GetQuintEncoding((int)encoded);
+
for (int i = 0; i < 3; i++)
{
IntegerEncoded intEncoded = new IntegerEncoded(EIntegerEncoding.Quint, numberBitsPerValue)
{
- BitValue = m[i],
- QuintValue = qa[i]
+ BitValue = m[i],
+ QuintValue = encodings[i]
};
- listIntegerEncoded.Add(intEncoded);
+
+ listIntegerEncoded.Add(ref intEncoded);
}
}
public static void DecodeIntegerSequence(
- List<IntegerEncoded> decodeIntegerSequence,
- BitArrayStream bitStream,
- int maxRange,
- int numberValues)
+ ref IntegerSequence decodeIntegerSequence,
+ ref BitStream128 bitStream,
+ int maxRange,
+ int numberValues)
{
// Determine encoding parameters
IntegerEncoded intEncoded = CreateEncoding(maxRange);
@@ -240,7 +186,7 @@ namespace Ryujinx.Graphics.Texture.Astc
{
case EIntegerEncoding.Quint:
{
- DecodeQuintBlock(bitStream, decodeIntegerSequence, intEncoded.NumberBits);
+ DecodeQuintBlock(ref bitStream, ref decodeIntegerSequence, intEncoded.NumberBits);
numberValuesDecoded += 3;
break;
@@ -248,7 +194,7 @@ namespace Ryujinx.Graphics.Texture.Astc
case EIntegerEncoding.Trit:
{
- DecodeTritBlock(bitStream, decodeIntegerSequence, intEncoded.NumberBits);
+ DecodeTritBlock(ref bitStream, ref decodeIntegerSequence, intEncoded.NumberBits);
numberValuesDecoded += 5;
break;
@@ -257,7 +203,7 @@ namespace Ryujinx.Graphics.Texture.Astc
case EIntegerEncoding.JustBits:
{
intEncoded.BitValue = bitStream.ReadBits(intEncoded.NumberBits);
- decodeIntegerSequence.Add(intEncoded);
+ decodeIntegerSequence.Add(ref intEncoded);
numberValuesDecoded++;
break;
@@ -265,5 +211,135 @@ namespace Ryujinx.Graphics.Texture.Astc
}
}
}
+
+ private static ReadOnlySpan<byte> GetTritEncoding(int index)
+ {
+ return TritEncodings.Slice(index * 5, 5);
+ }
+
+ private static ReadOnlySpan<byte> GetQuintEncoding(int index)
+ {
+ return QuintEncodings.Slice(index * 3, 3);
+ }
+
+ private static ReadOnlySpan<byte> TritEncodings => new byte[]
+ {
+ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0,
+ 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0,
+ 2, 1, 0, 0, 0, 1, 0, 2, 0, 0, 0, 2, 0, 0, 0,
+ 1, 2, 0, 0, 0, 2, 2, 0, 0, 0, 2, 0, 2, 0, 0,
+ 0, 2, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0, 0,
+ 2, 0, 2, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0,
+ 2, 0, 1, 0, 0, 0, 1, 2, 0, 0, 0, 1, 1, 0, 0,
+ 1, 1, 1, 0, 0, 2, 1, 1, 0, 0, 1, 1, 2, 0, 0,
+ 0, 2, 1, 0, 0, 1, 2, 1, 0, 0, 2, 2, 1, 0, 0,
+ 2, 1, 2, 0, 0, 0, 0, 0, 2, 2, 1, 0, 0, 2, 2,
+ 2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 0, 0, 0, 1, 0,
+ 1, 0, 0, 1, 0, 2, 0, 0, 1, 0, 0, 0, 2, 1, 0,
+ 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 2, 1, 0, 1, 0,
+ 1, 0, 2, 1, 0, 0, 2, 0, 1, 0, 1, 2, 0, 1, 0,
+ 2, 2, 0, 1, 0, 2, 0, 2, 1, 0, 0, 2, 2, 1, 0,
+ 1, 2, 2, 1, 0, 2, 2, 2, 1, 0, 2, 0, 2, 1, 0,
+ 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 2, 0, 1, 1, 0,
+ 0, 1, 2, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0,
+ 2, 1, 1, 1, 0, 1, 1, 2, 1, 0, 0, 2, 1, 1, 0,
+ 1, 2, 1, 1, 0, 2, 2, 1, 1, 0, 2, 1, 2, 1, 0,
+ 0, 1, 0, 2, 2, 1, 1, 0, 2, 2, 2, 1, 0, 2, 2,
+ 1, 0, 2, 2, 2, 0, 0, 0, 2, 0, 1, 0, 0, 2, 0,
+ 2, 0, 0, 2, 0, 0, 0, 2, 2, 0, 0, 1, 0, 2, 0,
+ 1, 1, 0, 2, 0, 2, 1, 0, 2, 0, 1, 0, 2, 2, 0,
+ 0, 2, 0, 2, 0, 1, 2, 0, 2, 0, 2, 2, 0, 2, 0,
+ 2, 0, 2, 2, 0, 0, 2, 2, 2, 0, 1, 2, 2, 2, 0,
+ 2, 2, 2, 2, 0, 2, 0, 2, 2, 0, 0, 0, 1, 2, 0,
+ 1, 0, 1, 2, 0, 2, 0, 1, 2, 0, 0, 1, 2, 2, 0,
+ 0, 1, 1, 2, 0, 1, 1, 1, 2, 0, 2, 1, 1, 2, 0,
+ 1, 1, 2, 2, 0, 0, 2, 1, 2, 0, 1, 2, 1, 2, 0,
+ 2, 2, 1, 2, 0, 2, 1, 2, 2, 0, 0, 2, 0, 2, 2,
+ 1, 2, 0, 2, 2, 2, 2, 0, 2, 2, 2, 0, 2, 2, 2,
+ 0, 0, 0, 0, 2, 1, 0, 0, 0, 2, 2, 0, 0, 0, 2,
+ 0, 0, 2, 0, 2, 0, 1, 0, 0, 2, 1, 1, 0, 0, 2,
+ 2, 1, 0, 0, 2, 1, 0, 2, 0, 2, 0, 2, 0, 0, 2,
+ 1, 2, 0, 0, 2, 2, 2, 0, 0, 2, 2, 0, 2, 0, 2,
+ 0, 2, 2, 0, 2, 1, 2, 2, 0, 2, 2, 2, 2, 0, 2,
+ 2, 0, 2, 0, 2, 0, 0, 1, 0, 2, 1, 0, 1, 0, 2,
+ 2, 0, 1, 0, 2, 0, 1, 2, 0, 2, 0, 1, 1, 0, 2,
+ 1, 1, 1, 0, 2, 2, 1, 1, 0, 2, 1, 1, 2, 0, 2,
+ 0, 2, 1, 0, 2, 1, 2, 1, 0, 2, 2, 2, 1, 0, 2,
+ 2, 1, 2, 0, 2, 0, 2, 2, 2, 2, 1, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 0, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1, 2, 0, 0, 0, 1, 0, 0, 2, 0, 1,
+ 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 2, 1, 0, 0, 1,
+ 1, 0, 2, 0, 1, 0, 2, 0, 0, 1, 1, 2, 0, 0, 1,
+ 2, 2, 0, 0, 1, 2, 0, 2, 0, 1, 0, 2, 2, 0, 1,
+ 1, 2, 2, 0, 1, 2, 2, 2, 0, 1, 2, 0, 2, 0, 1,
+ 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 2, 0, 1, 0, 1,
+ 0, 1, 2, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1,
+ 2, 1, 1, 0, 1, 1, 1, 2, 0, 1, 0, 2, 1, 0, 1,
+ 1, 2, 1, 0, 1, 2, 2, 1, 0, 1, 2, 1, 2, 0, 1,
+ 0, 0, 1, 2, 2, 1, 0, 1, 2, 2, 2, 0, 1, 2, 2,
+ 0, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1,
+ 2, 0, 0, 1, 1, 0, 0, 2, 1, 1, 0, 1, 0, 1, 1,
+ 1, 1, 0, 1, 1, 2, 1, 0, 1, 1, 1, 0, 2, 1, 1,
+ 0, 2, 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 1,
+ 2, 0, 2, 1, 1, 0, 2, 2, 1, 1, 1, 2, 2, 1, 1,
+ 2, 2, 2, 1, 1, 2, 0, 2, 1, 1, 0, 0, 1, 1, 1,
+ 1, 0, 1, 1, 1, 2, 0, 1, 1, 1, 0, 1, 2, 1, 1,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1,
+ 1, 1, 2, 1, 1, 0, 2, 1, 1, 1, 1, 2, 1, 1, 1,
+ 2, 2, 1, 1, 1, 2, 1, 2, 1, 1, 0, 1, 1, 2, 2,
+ 1, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 2,
+ 0, 0, 0, 2, 1, 1, 0, 0, 2, 1, 2, 0, 0, 2, 1,
+ 0, 0, 2, 2, 1, 0, 1, 0, 2, 1, 1, 1, 0, 2, 1,
+ 2, 1, 0, 2, 1, 1, 0, 2, 2, 1, 0, 2, 0, 2, 1,
+ 1, 2, 0, 2, 1, 2, 2, 0, 2, 1, 2, 0, 2, 2, 1,
+ 0, 2, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 1,
+ 2, 0, 2, 2, 1, 0, 0, 1, 2, 1, 1, 0, 1, 2, 1,
+ 2, 0, 1, 2, 1, 0, 1, 2, 2, 1, 0, 1, 1, 2, 1,
+ 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1,
+ 0, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 2, 1, 2, 1,
+ 2, 1, 2, 2, 1, 0, 2, 1, 2, 2, 1, 2, 1, 2, 2,
+ 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 0, 0, 0, 1, 2,
+ 1, 0, 0, 1, 2, 2, 0, 0, 1, 2, 0, 0, 2, 1, 2,
+ 0, 1, 0, 1, 2, 1, 1, 0, 1, 2, 2, 1, 0, 1, 2,
+ 1, 0, 2, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 2,
+ 2, 2, 0, 1, 2, 2, 0, 2, 1, 2, 0, 2, 2, 1, 2,
+ 1, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 0, 2, 1, 2,
+ 0, 0, 1, 1, 2, 1, 0, 1, 1, 2, 2, 0, 1, 1, 2,
+ 0, 1, 2, 1, 2, 0, 1, 1, 1, 2, 1, 1, 1, 1, 2,
+ 2, 1, 1, 1, 2, 1, 1, 2, 1, 2, 0, 2, 1, 1, 2,
+ 1, 2, 1, 1, 2, 2, 2, 1, 1, 2, 2, 1, 2, 1, 2,
+ 0, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 1, 2, 2, 2
+ };
+
+ private static ReadOnlySpan<byte> QuintEncodings => new byte[]
+ {
+ 0, 0, 0, 1, 0, 0, 2, 0, 0, 3, 0, 0, 4, 0, 0,
+ 0, 4, 0, 4, 4, 0, 4, 4, 4, 0, 1, 0, 1, 1, 0,
+ 2, 1, 0, 3, 1, 0, 4, 1, 0, 1, 4, 0, 4, 4, 1,
+ 4, 4, 4, 0, 2, 0, 1, 2, 0, 2, 2, 0, 3, 2, 0,
+ 4, 2, 0, 2, 4, 0, 4, 4, 2, 4, 4, 4, 0, 3, 0,
+ 1, 3, 0, 2, 3, 0, 3, 3, 0, 4, 3, 0, 3, 4, 0,
+ 4, 4, 3, 4, 4, 4, 0, 0, 1, 1, 0, 1, 2, 0, 1,
+ 3, 0, 1, 4, 0, 1, 0, 4, 1, 4, 0, 4, 0, 4, 4,
+ 0, 1, 1, 1, 1, 1, 2, 1, 1, 3, 1, 1, 4, 1, 1,
+ 1, 4, 1, 4, 1, 4, 1, 4, 4, 0, 2, 1, 1, 2, 1,
+ 2, 2, 1, 3, 2, 1, 4, 2, 1, 2, 4, 1, 4, 2, 4,
+ 2, 4, 4, 0, 3, 1, 1, 3, 1, 2, 3, 1, 3, 3, 1,
+ 4, 3, 1, 3, 4, 1, 4, 3, 4, 3, 4, 4, 0, 0, 2,
+ 1, 0, 2, 2, 0, 2, 3, 0, 2, 4, 0, 2, 0, 4, 2,
+ 2, 0, 4, 3, 0, 4, 0, 1, 2, 1, 1, 2, 2, 1, 2,
+ 3, 1, 2, 4, 1, 2, 1, 4, 2, 2, 1, 4, 3, 1, 4,
+ 0, 2, 2, 1, 2, 2, 2, 2, 2, 3, 2, 2, 4, 2, 2,
+ 2, 4, 2, 2, 2, 4, 3, 2, 4, 0, 3, 2, 1, 3, 2,
+ 2, 3, 2, 3, 3, 2, 4, 3, 2, 3, 4, 2, 2, 3, 4,
+ 3, 3, 4, 0, 0, 3, 1, 0, 3, 2, 0, 3, 3, 0, 3,
+ 4, 0, 3, 0, 4, 3, 0, 0, 4, 1, 0, 4, 0, 1, 3,
+ 1, 1, 3, 2, 1, 3, 3, 1, 3, 4, 1, 3, 1, 4, 3,
+ 0, 1, 4, 1, 1, 4, 0, 2, 3, 1, 2, 3, 2, 2, 3,
+ 3, 2, 3, 4, 2, 3, 2, 4, 3, 0, 2, 4, 1, 2, 4,
+ 0, 3, 3, 1, 3, 3, 2, 3, 3, 3, 3, 3, 4, 3, 3,
+ 3, 4, 3, 0, 3, 4, 1, 3, 4
+ };
}
}