/* Near Infinity - An Infinity Engine Browser and Editor
* Copyright (C) 2001 - 2005 Jon Olav Hauglid
* See LICENSE.txt for license information
*
* The DXT compression algorithm is based on libsquish:
* -----------------------------------------------------------------------------
* Copyright (c) 2006 Simon Brown si@sjbrown.co.uk
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* -----------------------------------------------------------------------------
*/
package org.infinity.resource.graphics;
/**
* Encodes pixel data into the DXT1/DXT3/DXT5 format.
*/
public final class DxtEncoder
{
/**
* Supported DXT compression types
*/
public static enum DxtType { DXT1, DXT3, DXT5 }
/**
* Encodes an image into a series of DXTn code blocks.
* @param pixels The pixel data as array of integers in ARGB format.
* @param width The width of the image (must be a multiple of 4).
* @param height The height of the image (must be a multiple of 4).
* @param dxtType The compression type to use.
* @return A data block containing the DXT-encoded image.
* @throws Exception
*/
static public byte[] encodeImage(int[] pixels, int width, int height, DxtType dxtType) throws Exception
{
// consistency check
if (dxtType == null)
throw new Exception("No DXT type specified");
if (width <= 0 || height <= 0)
throw new Exception("Invalid width or height specified");
if ((width & 3) != 0 || (height & 3) != 0)
throw new Exception("Width and height must be a multiple of 4");
if (pixels == null || pixels.length < width*height)
throw new Exception("Insufficient source data.");
int size = calcImageSize(width, height, dxtType);
byte[] output = new byte[size];
try {
encodeImage(pixels, width, height, output, dxtType);
} catch (Exception e) {
output = null;
throw e;
}
return output;
}
/**
* Encodes an image into a series of DXTn code blocks.
* @param pixels The pixel data as array of integers in ARGB format.
* @param width The width of the image (must be a multiple of 4).
* @param height The height of the image (must be a multiple of 4).
* @param output The storage space for the compressed data.
* @param dxtType The compression type to use.
* @throws Exception
*/
static public void encodeImage(int[] pixels, int width, int height, byte[] output,
DxtType dxtType) throws Exception
{
// consistency check
if (dxtType == null)
throw new Exception("No DXT type specified");
if (width <= 0 || height <= 0)
throw new Exception("Invalid width or height specified");
if ((width & 3) != 0 || (height & 3) != 0)
throw new Exception("Width and height must be a multiple of 4");
if (pixels == null || pixels.length < width*height)
throw new Exception("Insufficient source data.");
if (output == null || output.length < calcImageSize(width, height, dxtType))
throw new Exception(String.format("Insufficient space in output array. Needed: %1$d bytes, available: %2$d bytes",
calcImageSize(width, height, dxtType), (output == null) ? 0 : output.length));
int outputOfs = 0; // points to the end of encoded data
int bw = width / 4;
int bh = height / 4;
int[] inBlock = new int[16];
byte[] outBlock = new byte[calcBlockSize(dxtType)];
for (int y = 0; y < bh; y++) {
for (int x = 0; x < bw; x++) {
// create 4x4 block of pixels for DXTn compression
int ofs = (y*4)*width + (x*4);
for (int i = 0; i < 4; i++, ofs+=width) {
System.arraycopy(pixels, ofs, inBlock, i*4, 4);
}
// compress pixel block
encodeBlock(inBlock, outBlock, dxtType);
System.arraycopy(outBlock, 0, output, outputOfs, outBlock.length);
outputOfs += outBlock.length;
}
}
}
/**
* Encodes a single 4x4 block of pixel data in ARGB format into a DXTn code block.
* @param pixels The block of pixels to encode.
* @param block Data block to store the compressed DXTn data in.
* @param dxtType The DXT type to use.
*/
public static void encodeBlock(int[] pixels, byte[] block, DxtType dxtType) throws Exception
{
if (pixels == null || pixels.length < 16)
throw new Exception("Insufficient source data.");
if (block == null || block.length < calcBlockSize(dxtType))
throw new Exception(String.format("Insufficient output space. Needed: %1$d bytes, available: %2$d bytes",
calcBlockSize(dxtType), (block == null) ? 0 : block.length));
byte[] colorBlock = new byte[8];
byte[] alphaBlock = null;
if (dxtType == DxtType.DXT3 || dxtType == DxtType.DXT5) {
alphaBlock = new byte[8];
}
// create the minimal point set
ColorSet colors = new ColorSet(pixels, dxtType);
// check the compression type and compress color
ColorFit fit = null;
if (colors.getCount() == 1) {
// always do a single color fit
fit = new SingleColorFit(colors, dxtType);
} else if (colors.getCount() == 0) {
// do a range fit
fit = new RangeFit(colors, dxtType);
} else {
// default to a cluster fit
fit = new ClusterFit(colors, dxtType);
}
fit.compress(colorBlock);
// compress alpha separately if necessary
if (dxtType == DxtType.DXT3) {
Alpha.compressAlphaDxt3(pixels, alphaBlock);
} else if (dxtType == DxtType.DXT5) {
Alpha.compressAlphaDxt5(pixels, alphaBlock);
}
int ofs = 0;
if (alphaBlock != null) {
for (int i = 0; i < alphaBlock.length; i++, ofs++) {
block[ofs] = alphaBlock[i];
}
}
for (int i = 0; i < colorBlock.length; i++, ofs++) {
block[ofs] = colorBlock[i];
}
}
/**
* Calculates the size of a single DXT encoded 4x4 block of pixels.
* @param dxtType The desired compression.
* @return The number of bytes to hold the compressed data of a 4x4 block of pixels.
*/
public static int calcBlockSize(DxtType dxtType)
{
if (dxtType != null) {
switch (dxtType) {
case DXT1:
return 8;
case DXT3:
case DXT5:
return 16;
}
}
return 0;
}
/**
* Calculates the compressed size of an image.
* @param width The width in pixels (will be rounded up to a multiple of 4).
* @param height The height in pixels (will be rounded up to a multiple of 4).
* @param dxtType The desired compression type.
* @return The number of bytes required to hold the compressed image data.
*/
public static int calcImageSize(int width, int height, DxtType dxtType)
{
if (width <= 0 || height <= 0 || dxtType == null)
return 0;
width += (4 - (width & 3)) & 3;
height += (4 - (height & 3)) & 3;
return (width*height)/16 * calcBlockSize(dxtType);
}
// --------------------------- INNER CLASSES ---------------------------
private static class ColorSet
{
private final Vec3[] points;
private final float[] weights;
private final int[] remap;
private int count;
private boolean transparent;
// Extracts the color component at the specified pos (0..3 = blue,green,red,alpha)
public static int argb(int color, int pos)
{
return (color >>> ((pos & 3) << 3)) & 0xff;
}
public ColorSet(int[] pixels, DxtType dxtType)
{
points = new Vec3[16];
weights = new float[16];
remap = new int[16];
count = 0;
transparent = false;
boolean isDXT1 = (dxtType == DxtType.DXT1);
// create minimal set
for (int i = 0; i < 16; i++) {
// check for transparent pixels when using DXT1
if (isDXT1 && argb(pixels[i], 3) < 128) {
remap[i] = -1;
transparent = true;
continue;
}
// loop over previous points for a match
for (int j = 0; ; j++) {
// allocate new points
if (j == i) {
// normalize coordinates to [0, 1]
float x = (float)argb(pixels[i], 2) / 255.0f;
float y = (float)argb(pixels[i], 1) / 255.0f;
float z = (float)argb(pixels[i], 0) / 255.0f;
// ensure there is always non-zero weight even for zero alpha
float w = (float)(argb(pixels[i], 3) + 1) / 256.0f;
// add the points
points[count] = new Vec3(x, y, z);
weights[count] = w;
remap[i] = count;
count++;
break;
}
// check for a match
boolean match = (argb(pixels[i], 0) == argb(pixels[j], 0) &&
argb(pixels[i], 1) == argb(pixels[j], 1) &&
argb(pixels[i], 2) == argb(pixels[j], 2) &&
(argb(pixels[j], 3) >= 128 || !isDXT1));
if (match) {
// get the index of the match
int index = remap[j];
// ensure there is always non-zero weight even for zero alpha
float w = (float)(argb(pixels[i], 3) + 1) / 256.0f;
// map to this point and increase the weight
weights[index] += w;
remap[i] = index;
break;
}
}
}
// square root the weights
for (int i = 0; i < count; i++) {
weights[i] = (float)Math.sqrt(weights[i]);
}
}
public int getCount() { return count; }
public Vec3[] getPoints() { return points; }
public float[] getWeights() { return weights; }
public boolean isTransparent() { return transparent; }
public void remapIndices(int[] source, int[] target)
{
for (int i = 0; i < 16; i++) {
int j = remap[i];
target[i] = (j == -1) ? 3 : source[j];
}
}
}
private static abstract class ColorFit
{
protected ColorSet colors;
protected DxtType dxtType;
public ColorFit(ColorSet colors, DxtType dxtType)
{
this.colors = colors;
this.dxtType = dxtType;
}
public void compress(byte[] block)
{
boolean isDXT1 = (dxtType == DxtType.DXT1);
if (isDXT1) {
compress3(block);
if (!colors.isTransparent()) {
compress4(block);
}
} else {
compress4(block);
}
}
protected abstract void compress3(byte[] block);
protected abstract void compress4(byte[] block);
}
private static class SingleColorFit extends ColorFit
{
private final int[] color;
private Vec3 start, end;
private int index;
private int error;
private int bestError;
public SingleColorFit(ColorSet colors, DxtType dxtType)
{
super(colors, dxtType);
color = new int[3];
start = new Vec3();
end = new Vec3();
// grab the single color
Vec3 value = this.colors.getPoints()[0];
color[0] = Misc.floatToInt(255.0f*value.x(), 255);
color[1] = Misc.floatToInt(255.0f*value.y(), 255);
color[2] = Misc.floatToInt(255.0f*value.z(), 255);
// initialize the best error
bestError = Integer.MAX_VALUE;
}
@Override
protected void compress3(byte[] block)
{
// build the table of lookups
SingleColorLookup[][] lookups = new SingleColorLookup[][]{
Lookups.lookup53, Lookups.lookup63, Lookups.lookup53
};
// find the best end-points and index
computeEndPoints(lookups);
// build the block if we win
if (error < bestError) {
// remap indices
int[] indices = new int[16];
colors.remapIndices(new int[]{index}, indices);
// save the block
ColorBlock.writeColorBlock3(start, end, indices, block);
// save the error
bestError = error;
}
}
@Override
protected void compress4(byte[] block)
{
// build the table of lookups
SingleColorLookup[][] lookups = new SingleColorLookup[][]{
Lookups.lookup54, Lookups.lookup64, Lookups.lookup54
};
// find the best end-points and index
computeEndPoints(lookups);
// build the block if we win
if (error < bestError) {
// remap indices
int[] indices = new int[16];
colors.remapIndices(new int[]{index}, indices);
// save the block
ColorBlock.writeColorBlock4(start, end, indices, block);
// save the error
bestError = error;
}
}
protected void computeEndPoints(SingleColorLookup[][] lookups)
{
// check each index combination (endpoint or intermediate)
this.error = Integer.MAX_VALUE;
for (int index = 0; index < 2; index++) {
SourceBlock[] sources = new SourceBlock[3];
int error = 0;
for (int channel = 0; channel < 3; channel++) {
// grab the lookup table and index for this channel
SingleColorLookup[] lookup = lookups[channel];
int target = color[channel];
// store a pointer to the source for this channel
sources[channel] = lookup[target].sources[index];
// accumulate the error
int diff = sources[channel].error;
error += diff * diff;
}
// keep it if the error is lower
if (error < this.error) {
start = new Vec3((float)sources[0].start / 31.0f,
(float)sources[1].start / 63.0f,
(float)sources[2].start / 31.0f);
end = new Vec3((float)sources[0].end / 31.0f,
(float)sources[1].end / 63.0f,
(float)sources[2].end / 31.0f);
this.index = 2 * index;
this.error = error;
}
}
}
}
private static class RangeFit extends ColorFit
{
private Vec3 metric, start, end;
private float bestError;
public RangeFit(ColorSet colors, DxtType dxtType)
{
super(colors, dxtType);
// using perceptual metric for color error
metric = new Vec3(0.2126f, 0.7152f, 0.0722f);
// initialize the best error
bestError = Float.MAX_VALUE;
// cache some values
int count = this.colors.getCount();
Vec3[] values = this.colors.getPoints();
float[] weights = this.colors.getWeights();
// get the covariance matrix
Sym3x3 covariance = Sym3x3.computeWeightedCovariance(count, values, weights);
// compute the principle component
Vec3 principle = Sym3x3.computePrincipleComponent(covariance);
// get the min and max range as the codebook endpoints
Vec3 start = new Vec3();
Vec3 end = new Vec3();
if (count > 0) {
float min, max;
// compute the range
start = end = values[0];
min = max = Vec3.dot(values[0], principle);
for (int i = 1; i < count; i++) {
float val = Vec3.dot(values[i], principle);
if (val < min) {
start = values[i];
min = val;
} else if (val > max) {
end = values[i];
max = val;
}
}
}
// clamp the output to [0, 1]
final Vec3 one = new Vec3(1.0f);
final Vec3 zero = new Vec3(0.0f);
start = Vec3.min(one, Vec3.max(zero, start));
end = Vec3.min(one, Vec3.max(zero, end));
// clamp the grid and save
final Vec3 grid = new Vec3(31.0f, 63.0f, 31.0f);
final Vec3 gridrcp = new Vec3(1.0f/31.0f, 1.0f/63.0f, 1.0f/31.0f);
final Vec3 half = new Vec3(0.5f);
this.start = Vec3.truncate(Vec3.mul(grid, start).add(half)).mul(gridrcp);
this.end = Vec3.truncate(Vec3.mul(grid, end).add(half)).mul(gridrcp);
}
@Override
protected void compress3(byte[] block)
{
// cache some values
int count = colors.getCount();
Vec3[] values = colors.getPoints();
// create a codebook
Vec3[] codes = new Vec3[3];
codes[0] = start;
codes[1] = end;
codes[2] = Vec3.mul(start, 0.5f).add(Vec3.mul(end, 0.5f));
// match each point to the closest code
int[] closest = new int[16];
float error = 0.0f;
for (int i = 0; i < count; i++) {
// find the closest code
float dist = Float.MAX_VALUE;
int idx = 0;
for (int j = 0; j < 3; j++) {
float d = Vec3.lengthSquared(Vec3.mul(metric, Vec3.sub(values[i], codes[j])));
if (d < dist) {
dist = d;
idx = j;
}
}
// save the index
closest[i] = idx;
// accumulate the error
error += dist;
}
// save this scheme if it wins
if (error < bestError) {
// remap the indices
int[] indices = new int[16];
colors.remapIndices(closest, indices);
// save the block
ColorBlock.writeColorBlock3(start, end, indices, block);
// save the error
bestError = error;
}
}
@Override
protected void compress4(byte[] block)
{
// cache some values
int count = colors.getCount();
Vec3[] values = colors.getPoints();
// create a codebook
Vec3[] codes = new Vec3[4];
codes[0] = start;
codes[1] = end;
codes[2] = Vec3.mul(start, 2.0f/3.0f).add(Vec3.mul(end, 1.0f/3.0f));
codes[3] = Vec3.mul(start, 1.0f/3.0f).add(Vec3.mul(end, 2.0f/3.0f));
// match each point to the closest code
int[] closest = new int[16];
float error = 0.0f;
for (int i = 0; i < count; i++) {
// find the closest code
float dist = Float.MAX_VALUE;
int idx = 0;
for (int j = 0; j < 4; j++) {
float d = Vec3.lengthSquared(Vec3.mul(metric, Vec3.sub(values[i], codes[j])));
if (d < dist) {
dist = d;
idx = j;
}
}
// save the index
closest[i] = idx;
// accumulate the error
error += dist;
}
// save this scheme if it wins
if (error < bestError) {
// remap the indices
int[] indices = new int[16];
colors.remapIndices(closest, indices);
// save the block
ColorBlock.writeColorBlock4(start, end, indices, block);
// save the error
bestError = error;
}
}
}
private static class ClusterFit extends ColorFit
{
private static final int IterationCount = 8;
private final int[] order;
private final Vec4[] pointsWeights;
private Vec3 principle;
private Vec4 xsum_wsum;
private Vec4 metric;
private Vec4 bestError;
public ClusterFit(ColorSet colors, DxtType dxtType)
{
super(colors, dxtType);
order = new int[16*IterationCount];
pointsWeights = new Vec4[16];
// initialize the best error
bestError = new Vec4(Float.MAX_VALUE);
// using perceptual metric for color error
metric = new Vec4(0.2126f, 0.7152f, 0.0722f, 0.0f);
// get the covariance matrix
Sym3x3 covariance = Sym3x3.computeWeightedCovariance(this.colors.getCount(),
this.colors.getPoints(),
this.colors.getWeights());
// compute the principle component
principle = Sym3x3.computePrincipleComponent(covariance);
}
@Override
protected void compress3(byte[] block)
{
// declare variables
final int count = colors.getCount();
final Vec4 two = new Vec4(2.0f);
final Vec4 one = new Vec4(1.0f);
final Vec4 halfHalf2 = new Vec4(0.5f, 0.5f, 0.5f, 0.25f);
final Vec4 zero = new Vec4(0.0f);
final Vec4 half = new Vec4(0.5f);
final Vec4 grid = new Vec4(31.0f, 63.0f, 31.0f, 0.0f);
final Vec4 gridrcp = new Vec4(1.0f/31.0f, 1.0f/63.0f, 1.0f/31.0f, 0.0f);
// prepare an ordering using the principle axis
constructOrdering(principle, 0);
// check all possible clusters and iterate on the total order
Vec4 bestStart = new Vec4();
Vec4 bestEnd = new Vec4();
Vec4 bestError = this.bestError;
int[] bestIndices = new int[16];
int bestIteration = 0;
int bestI = 0, bestJ = 0;
// loop over iterations (we avoid the case that all points in first or last cluster)
for (int iterIndex = 0; ; ) {
// first cluster [0, i) is at the start
Vec4 part0 = new Vec4();
for (int i = 0; i < count; i++) {
// second cluster [i, j) is half along
Vec4 part1 = (i == 0) ? (Vec4)pointsWeights[0].clone() : new Vec4();
int jmin = (i == 0) ? 1 : i;
for (int j = jmin; ; ) {
// last cluster [j, count) is at the end
Vec4 part2 = Vec4.sub(xsum_wsum, part1).sub(part0);
// compute least squares terms directly
Vec4 alphaXSum = Vec4.multiplyAdd(part1, halfHalf2, part0);
Vec4 alpha2Sum = alphaXSum.splatW();
Vec4 betaXSum = Vec4.multiplyAdd(part1, halfHalf2, part2);
Vec4 beta2Sum = betaXSum.splatW();
Vec4 alphaBetaSum = Vec4.mul(part1, halfHalf2).splatW();
// compute the least squares optimal points
Vec4 factor = Vec4.reciprocal(Vec4.negMulSub(alphaBetaSum, alphaBetaSum, Vec4.mul(alpha2Sum, beta2Sum)));
Vec4 a = Vec4.negMulSub(betaXSum, alphaBetaSum, Vec4.mul(alphaXSum, beta2Sum)).mul(factor);
Vec4 b = Vec4.negMulSub(alphaXSum, alphaBetaSum, Vec4.mul(betaXSum, alpha2Sum)).mul(factor);
// clamp to the grid
a = Vec4.min(one, Vec4.max(zero, a));
b = Vec4.min(one, Vec4.max(zero, b));
a = Vec4.truncate(Vec4.multiplyAdd(grid, a, half)).mul(gridrcp);
b = Vec4.truncate(Vec4.multiplyAdd(grid, b, half)).mul(gridrcp);
// compute the error (we skip the constant xxsum)
Vec4 e1 = Vec4.multiplyAdd(Vec4.mul(a, a), alpha2Sum, Vec4.mul(b, b).mul(beta2Sum));
Vec4 e2 = Vec4.negMulSub(a, alphaXSum, Vec4.mul(a, b).mul(alphaBetaSum));
Vec4 e3 = Vec4.negMulSub(b, betaXSum, e2);
Vec4 e4 = Vec4.multiplyAdd(two, e3, e1);
// apply the metric to the error terms
Vec4 e5 = Vec4.mul(e4, metric);
Vec4 error = Vec4.add(e5.splatX(), e5.splatY()).add(e5.splatZ());
// keep the solution if it wins
if (Vec4.compareAnyLessThan(error, bestError)) {
bestStart = a;
bestEnd = b;
bestI = i;
bestJ = j;
bestError = error;
bestIteration = iterIndex;
}
// advance
if (j == count)
break;
part1.add(pointsWeights[j]);
j++;
}
// advance
part0.add(pointsWeights[i]);
}
// stop if we didn't improve in this iteration
if (bestIteration != iterIndex)
break;
// advance if possible
iterIndex++;
if (iterIndex == IterationCount)
break;
// stop if a new iteration is an ordering that has already been tried
Vec3 axis = Vec4.sub(bestEnd, bestStart).getVec3();
if (!constructOrdering(axis, iterIndex))
break;
}
// save the block if necessary
if (Vec4.compareAnyLessThan(bestError, this.bestError)) {
// remap the indices
int orderIdx = 16*bestIteration;
int[] unordered = new int[16];
for (int m = 0; m < bestI; m++)
unordered[order[orderIdx+m]] = 0;
for (int m = bestI; m < bestJ; m++)
unordered[order[orderIdx+m]] = 2;
for (int m = bestJ; m < count; m++)
unordered[order[orderIdx+m]] = 1;
colors.remapIndices(unordered, bestIndices);
// save the block
ColorBlock.writeColorBlock3(bestStart.getVec3(), bestEnd.getVec3(), bestIndices, block);
// save the error
this.bestError = bestError;
}
}
@Override
protected void compress4(byte[] block)
{
// declare variables
final int count = colors.getCount();
final Vec4 two = new Vec4(2.0f);
final Vec4 one = new Vec4(1.0f);
final Vec4 oneThirdOneThird2 = new Vec4(1.0f/3.0f, 1.0f/3.0f, 1.0f/3.0f, 1.0f/9.0f);
final Vec4 twoThirdsTwoThirds2 = new Vec4(2.0f/3.0f, 2.0f/3.0f, 2.0f/3.0f, 4.0f/9.0f);
final Vec4 twoNineth = new Vec4(2.0f/9.0f);
final Vec4 zero = new Vec4(0.0f);
final Vec4 half = new Vec4(0.5f);
final Vec4 grid = new Vec4(31.0f, 63.0f, 31.0f, 0.0f);
final Vec4 gridrcp = new Vec4(1.0f/31.0f, 1.0f/63.0f, 1.0f/31.0f, 0.0f);
// prepare an ordering using the principle axis
constructOrdering(principle, 0);
// check all possible clusters and iterate on the total order
Vec4 bestStart = new Vec4();
Vec4 bestEnd = new Vec4();
Vec4 bestError = this.bestError;
int[] bestIndices = new int[16];
int bestIteration = 0;
int bestI = 0, bestJ = 0, bestK = 0;
// loop over iterations (we avoid the case all points in first or last cluster)
for (int iterIndex = 0; ; ) {
// first cluster [0, i) is at the start
Vec4 part0 = new Vec4();
for (int i = 0; i < count; i++) {
// second cluster [i, j) is one third along
Vec4 part1 = new Vec4();
for (int j = i; ; ) {
// third cluster [j, k) is two thirds along
Vec4 part2 = (j == 0) ? (Vec4)pointsWeights[0].clone() : new Vec4();
int kmin = (j == 0) ? 1 : j;
for (int k = kmin; ; ) {
// last cluster [k, count) is at the end
Vec4 part3 = Vec4.sub(xsum_wsum, part2).sub(part1).sub(part0);
// compute least squares terms directly
Vec4 alphaXSum = Vec4.multiplyAdd(part2, oneThirdOneThird2,
Vec4.multiplyAdd(part1, twoThirdsTwoThirds2, part0));
Vec4 alpha2Sum = alphaXSum.splatW();
Vec4 betaXSum = Vec4.multiplyAdd(part1, oneThirdOneThird2,
Vec4.multiplyAdd(part2, twoThirdsTwoThirds2, part3));
Vec4 beta2Sum = betaXSum.splatW();
Vec4 alphaBetaSum = Vec4.mul(twoNineth, Vec4.add(part1, part2).splatW());
// compute the least-squares optimal points
Vec4 factor = Vec4.reciprocal(Vec4.negMulSub(alphaBetaSum, alphaBetaSum,
Vec4.mul(alpha2Sum, beta2Sum)));
Vec4 a = Vec4.negMulSub(betaXSum, alphaBetaSum, Vec4.mul(alphaXSum, beta2Sum)).mul(factor);
Vec4 b = Vec4.negMulSub(alphaXSum, alphaBetaSum, Vec4.mul(betaXSum, alpha2Sum)).mul(factor);
// clamp to the grid
a = Vec4.min(one, Vec4.max(zero, a));
b = Vec4.min(one, Vec4.max(zero, b));
a = Vec4.truncate(Vec4.multiplyAdd(grid, a, half)).mul(gridrcp);
b = Vec4.truncate(Vec4.multiplyAdd(grid, b, half)).mul(gridrcp);
// compute the error (we skip the constant xxsum)
Vec4 e1 = Vec4.multiplyAdd(Vec4.mul(a, a), alpha2Sum, Vec4.mul(b, b).mul(beta2Sum));
Vec4 e2 = Vec4.negMulSub(a, alphaXSum, Vec4.mul(a, b).mul(alphaBetaSum));
Vec4 e3 = Vec4.negMulSub(b, betaXSum, e2);
Vec4 e4 = Vec4.multiplyAdd(two, e3, e1);
// apply the metric to the error term
Vec4 e5 = Vec4.mul(e4, metric);
Vec4 error = Vec4.add(e5.splatX(), e5.splatY()).add(e5.splatZ());
// keep the solution if it wins
if (Vec4.compareAnyLessThan(error, bestError)) {
bestStart = a;
bestEnd = b;
bestError = error;
bestI = i;
bestJ = j;
bestK = k;
bestIteration = iterIndex;
}
// advance
if (k == count)
break;
part2.add(pointsWeights[k]);
k++;
}
// advance
if (j == count)
break;
part1.add(pointsWeights[j]);
j++;
}
// advance
part0.add(pointsWeights[i]);
}
// stop if we didn't improve in this iteration
if (bestIteration != iterIndex)
break;
// advance if possible
iterIndex++;
if (iterIndex == IterationCount)
break;
// stop if a new iteration is an ordering that has already been tried
Vec3 axis = Vec4.sub(bestEnd, bestStart).getVec3();
if (!constructOrdering(axis, iterIndex))
break;
}
// save the block if necessary
if (Vec4.compareAnyLessThan(bestError, this.bestError)) {
// remap the indices
int orderIdx = 16*bestIteration;
int[] unordered = new int[16];
for (int m = 0; m < bestI; m++)
unordered[order[orderIdx+m]] = 0;
for (int m = bestI; m < bestJ; m++)
unordered[order[orderIdx+m]] = 2;
for (int m = bestJ; m < bestK; m++)
unordered[order[orderIdx+m]] = 3;
for (int m = bestK; m < count; m++)
unordered[order[orderIdx+m]] = 1;
colors.remapIndices(unordered, bestIndices);
// save the block
ColorBlock.writeColorBlock4(bestStart.getVec3(), bestEnd.getVec3(), bestIndices, block);
// save the error
this.bestError = bestError;
}
}
private boolean constructOrdering(Vec3 axis, int iteration)
{
// cache some values
final int count = colors.getCount();
final Vec3[] values = colors.getPoints();
// build list of dot products
float[] dps = new float[16];
int orderIdx = 16*iteration;
for (int i = 0; i < count; i++) {
dps[i] = Vec3.dot(values[i], axis);
order[orderIdx+i] = i;
}
// stable sort using them
for (int i = 0; i < count; i++) {
for (int j = i; j > 0 && dps[j] < dps[j-1]; j--) {
float tmp1 = dps[j]; dps[j] = dps[j-1]; dps[j-1] = tmp1;
int tmp2 = order[orderIdx+j]; order[orderIdx+j] = order[orderIdx+j-1]; order[orderIdx+j-1] = tmp2;
}
}
// check this ordering is unique
for (int it = 0; it < iteration; it++) {
int prevIdx = 16*it;
boolean same = true;
for (int i = 0; i < count; i++) {
if (order[orderIdx+i] != order[prevIdx+i]) {
same = false;
break;
}
}
if (same)
return false;
}
// copy the ordering and weight all the points
final Vec3[] unweighted = colors.getPoints();
final float[] weights = colors.getWeights();
xsum_wsum = new Vec4();
for (int i = 0; i < count; i++) {
int j = order[orderIdx+i];
Vec4 p = new Vec4(unweighted[j].x(), unweighted[j].y(), unweighted[j].z(), 1.0f);
Vec4 w = new Vec4(weights[j]);
Vec4 x = Vec4.mul(p, w);
pointsWeights[i] = x;
xsum_wsum.add(x);
}
return true;
}
}
private static final class ColorBlock
{
public static void writeColorBlock3(Vec3 start, Vec3 end, int[] indices, byte[] block)
{
// get the packed values
int a = floatTo565(start);
int b = floatTo565(end);
// remap the indices
int[] remapped = new int[16];
if (a <= b) {
// use the indices directly
for (int i = 0; i < 16; i++) {
remapped[i] = indices[i];
}
} else {
// swap a and b
int tmp = a; a = b; b = tmp;
for (int i = 0; i < 16; i++) {
if (indices[i] == 0) {
remapped[i] = 1;
} else if (indices[i] == 1) {
remapped[i] = 0;
} else {
remapped[i] = indices[i];
}
}
}
// write the block
writeColorBlock(a, b, remapped, block);
}
public static void writeColorBlock4(Vec3 start, Vec3 end, int[] indices, byte[] block)
{
// get the packed values
int a = floatTo565(start);
int b = floatTo565(end);
// remap the indices
int[] remapped = new int[16];
if (a < b) {
// swap a and b
int tmp = a; a = b; b = tmp;
for (int i = 0; i < 16; i++) {
remapped[i] = (indices[i] ^ 1) & 3;
}
} else if (a == b) {
// use index 0
for (int i = 0; i < 16; i++) {
remapped[i] = 0;
}
} else {
// use the indices directly
for (int i = 0; i < 16; i++)
remapped[i] = indices[i];
}
// write the block
writeColorBlock(a, b, remapped, block);
}
private static int floatTo565(Vec3 color)
{
// get the components in the correct range
int r = Misc.floatToInt(31.0f*color.x(), 31);
int g = Misc.floatToInt(63.0f*color.y(), 63);
int b = Misc.floatToInt(31.0f*color.z(), 31);
// pack the color into a single value
return ((r << 11) | (g << 5) | b) & 0xffff;
}
private static void writeColorBlock(int a, int b, int[] indices, byte[] block)
{
// write the endpoints
block[0] = (byte)(a & 0xff);
block[1] = (byte)((a >>> 8) & 0xff);
block[2] = (byte)(b & 0xff);
block[3] = (byte)((b >>> 8) & 0xff);
// write the indices
for (int i = 0; i < 4; i++) {
int idx = 4*i;
block[i+4] = (byte)((indices[idx+0]) | (indices[idx+1] << 2) |
(indices[idx+2] << 4) | (indices[idx+3] << 6));
}
}
}
private static final class Alpha
{
public static void compressAlphaDxt3(int[] pixels, byte[] block)
{
// quantize and pack the alpha values pairwise
for (int i = 0; i < 8; i++) {
// quantize down to 4 bits
float alpha1 = (float)ColorSet.argb(pixels[2*i], 3) * (15.0f / 255.0f);
float alpha2 = (float)ColorSet.argb(pixels[2*i+1], 3) * (15.0f / 255.0f);
int quant1 = Misc.floatToInt(alpha1, 15);
int quant2 = Misc.floatToInt(alpha2, 15);
// pack into the byte
block[i] = (byte)(quant1 | (quant2 << 4));
}
}
public static void compressAlphaDxt5(int[] pixels, byte[] block)
{
// get the range for 5-alpha and 7-alpha interpolation
int min5 = 255;
int max5 = 0;
int min7 = 255;
int max7 = 0;
for (int i = 0; i < 16; i++) {
// incorporate into the min/max
int value = ColorSet.argb(pixels[i], 3);
if (value < min7)
min7 = value;
if (value > max7)
max7 = value;
if (value != 0 && value < min5)
min5 = value;
if (value != 255 && value > max5)
max5 = value;
}
// handle the case that no valid range was found
if (min5 > max5)
min5 = max5;
if (min7 > max7)
min7 = max7;
// fix the range to be the minimum in each case
int[] minmax = new int[2];
minmax[0] = min5; minmax[1] = max5;
fixRange(minmax, 5);
min5 = minmax[0]; max5 = minmax[1];
minmax[0] = min7; minmax[1] = max7;
fixRange(minmax, 7);
min7 = minmax[0]; max7 = minmax[1];
// set up the 5-alpha code book
int[] codes5 = new int[8];
codes5[0] = min5;
codes5[1] = max5;
for (int i = 1; i < 5; i++) {
codes5[i+1] = ((5 - i)*min5 + i*max5) / 5;
}
codes5[6] = 0;
codes5[7] = 255;
// set up the 7-alpha code book
int[] codes7 = new int[8];
codes7[0] = min7;
codes7[1] = max7;
for (int i = 1; i < 7; i++) {
codes7[i+1] = ((7 - i)*min7 + i*max7) / 7;
}
// fit the data to both code books
int[] indices5 = new int[16];
int[] indices7 = new int[16];
int err5 = fitCodes(pixels, codes5, indices5);
int err7 = fitCodes(pixels, codes7, indices7);
// save the block with the least error
if (err5 <= err7) {
writeAlphaBlock5(min5, max5, indices5, block);
} else {
writeAlphaBlock7(min7, max7, indices7, block);
}
}
private static void fixRange(int[] minMax, int steps)
{
if (minMax[1] - minMax[0] < steps)
minMax[1] = Math.min(minMax[0] + steps, 255);
if (minMax[1] - minMax[0] < steps)
minMax[0] = Math.max(0, minMax[1] - steps);
}
private static int fitCodes(int[] pixels, int[] codes, int[] indices)
{
// fit each alpha value to the code book
int err = 0;
for (int i = 0; i < 16; i++) {
// find the least error and corresponding index
int value = ColorSet.argb(pixels[i], 3);
int least = Integer.MAX_VALUE;
int index = 0;
for (int j = 0; j < 8; j++) {
// get the squared error from this code
int dist = value - codes[j];
dist *= dist;
// compare with the best so far
if (dist < least) {
least = dist;
index = j;
}
}
// save this index and accumulate the error
indices[i] = index;
err += least;
}
// return the total error
return err;
}
private static void writeAlphaBlock(int alpha0, int alpha1, int[] indices, byte[] block)
{
// write the first two bytes
block[0] = (byte)(alpha0 & 0xff);
block[1] = (byte)(alpha1 & 0xff);
// pack the indices with 3 bits each
for (int i = 0, srcIdx = 0, dstIdx = 2; i < 2; i++) {
// pack 8 3-bit values
int value = 0;
for (int j = 0; j < 8; j++) {
int index = indices[srcIdx++];
value |= (index << (3*j));
}
// store in 3 bytes
for (int j = 0; j < 3; j++) {
byte b = (byte)((value >>> (8*j)) & 0xff);
block[dstIdx++] = b;
}
}
}
private static void writeAlphaBlock5(int alpha0, int alpha1, int[] indices, byte[] block)
{
// check the relative values of the endpoints
if (alpha0 > alpha1) {
// swap the indices
int[] swapped = new int[16];
for (int i = 0; i < 16; i++) {
int index = indices[i];
if (index == 0) {
swapped[i] = 1;
} else if (index == 1) {
swapped[i] = 0;
} else if (index <= 5) {
swapped[i] = 7 - index;
} else {
swapped[i] = index;
}
}
// write the block
writeAlphaBlock(alpha1, alpha0, swapped, block);
} else {
// write the block
writeAlphaBlock(alpha0, alpha1, indices, block);
}
}
private static void writeAlphaBlock7(int alpha0, int alpha1, int[] indices, byte[] block)
{
if (alpha0 < alpha1) {
// swap the indices
int[] swapped = new int[16];
for (int i = 0; i < 16; i++) {
int index = indices[i];
if (index == 0) {
swapped[i] = 1;
} else if (index == 1) {
swapped[i] = 0;
} else {
swapped[i] = 9 - index;
}
}
// write the block
writeAlphaBlock(alpha1, alpha0, swapped, block);
} else {
// write the block
writeAlphaBlock(alpha0, alpha1, indices, block);
}
}
}
private static final class SourceBlock
{
public final int start, end, error;
public SourceBlock(int start, int end, int error)
{
this.start = start;
this.end = end;
this.error = error;
}
}
private static final class SingleColorLookup
{
public final SourceBlock[] sources;
public SingleColorLookup(SourceBlock sb1, SourceBlock sb2)
{
sources = new SourceBlock[]{sb1, sb2};
}
}
private static final class Lookups
{
public static final int SIZE = 256;
public static final SingleColorLookup[] lookup53 = new SingleColorLookup[SIZE];
public static final SingleColorLookup[] lookup63 = new SingleColorLookup[SIZE];
public static final SingleColorLookup[] lookup54 = new SingleColorLookup[SIZE];
public static final SingleColorLookup[] lookup64 = new SingleColorLookup[SIZE];
static {
lookup53[0] = new SingleColorLookup(new SourceBlock(0, 0, 0), new SourceBlock(0, 0, 0));
lookup53[1] = new SingleColorLookup(new SourceBlock(0, 0, 1), new SourceBlock(0, 0, 1));
lookup53[2] = new SingleColorLookup(new SourceBlock(0, 0, 2), new SourceBlock(0, 0, 2));
lookup53[3] = new SingleColorLookup(new SourceBlock(0, 0, 3), new SourceBlock(0, 1, 1));
lookup53[4] = new SingleColorLookup(new SourceBlock(0, 0, 4), new SourceBlock(0, 1, 0));
lookup53[5] = new SingleColorLookup(new SourceBlock(1, 0, 3), new SourceBlock(0, 1, 1));
lookup53[6] = new SingleColorLookup(new SourceBlock(1, 0, 2), new SourceBlock(0, 1, 2));
lookup53[7] = new SingleColorLookup(new SourceBlock(1, 0, 1), new SourceBlock(0, 2, 1));
lookup53[8] = new SingleColorLookup(new SourceBlock(1, 0, 0), new SourceBlock(0, 2, 0));
lookup53[9] = new SingleColorLookup(new SourceBlock(1, 0, 1), new SourceBlock(0, 2, 1));
lookup53[10] = new SingleColorLookup(new SourceBlock(1, 0, 2), new SourceBlock(0, 2, 2));
lookup53[11] = new SingleColorLookup(new SourceBlock(1, 0, 3), new SourceBlock(0, 3, 1));
lookup53[12] = new SingleColorLookup(new SourceBlock(1, 0, 4), new SourceBlock(0, 3, 0));
lookup53[13] = new SingleColorLookup(new SourceBlock(2, 0, 3), new SourceBlock(0, 3, 1));
lookup53[14] = new SingleColorLookup(new SourceBlock(2, 0, 2), new SourceBlock(0, 3, 2));
lookup53[15] = new SingleColorLookup(new SourceBlock(2, 0, 1), new SourceBlock(0, 4, 1));
lookup53[16] = new SingleColorLookup(new SourceBlock(2, 0, 0), new SourceBlock(0, 4, 0));
lookup53[17] = new SingleColorLookup(new SourceBlock(2, 0, 1), new SourceBlock(0, 4, 1));
lookup53[18] = new SingleColorLookup(new SourceBlock(2, 0, 2), new SourceBlock(0, 4, 2));
lookup53[19] = new SingleColorLookup(new SourceBlock(2, 0, 3), new SourceBlock(0, 5, 1));
lookup53[20] = new SingleColorLookup(new SourceBlock(2, 0, 4), new SourceBlock(0, 5, 0));
lookup53[21] = new SingleColorLookup(new SourceBlock(3, 0, 3), new SourceBlock(0, 5, 1));
lookup53[22] = new SingleColorLookup(new SourceBlock(3, 0, 2), new SourceBlock(0, 5, 2));
lookup53[23] = new SingleColorLookup(new SourceBlock(3, 0, 1), new SourceBlock(0, 6, 1));
lookup53[24] = new SingleColorLookup(new SourceBlock(3, 0, 0), new SourceBlock(0, 6, 0));
lookup53[25] = new SingleColorLookup(new SourceBlock(3, 0, 1), new SourceBlock(0, 6, 1));
lookup53[26] = new SingleColorLookup(new SourceBlock(3, 0, 2), new SourceBlock(0, 6, 2));
lookup53[27] = new SingleColorLookup(new SourceBlock(3, 0, 3), new SourceBlock(0, 7, 1));
lookup53[28] = new SingleColorLookup(new SourceBlock(3, 0, 4), new SourceBlock(0, 7, 0));
lookup53[29] = new SingleColorLookup(new SourceBlock(4, 0, 4), new SourceBlock(0, 7, 1));
lookup53[30] = new SingleColorLookup(new SourceBlock(4, 0, 3), new SourceBlock(0, 7, 2));
lookup53[31] = new SingleColorLookup(new SourceBlock(4, 0, 2), new SourceBlock(1, 7, 1));
lookup53[32] = new SingleColorLookup(new SourceBlock(4, 0, 1), new SourceBlock(1, 7, 0));
lookup53[33] = new SingleColorLookup(new SourceBlock(4, 0, 0), new SourceBlock(0, 8, 0));
lookup53[34] = new SingleColorLookup(new SourceBlock(4, 0, 1), new SourceBlock(0, 8, 1));
lookup53[35] = new SingleColorLookup(new SourceBlock(4, 0, 2), new SourceBlock(2, 7, 1));
lookup53[36] = new SingleColorLookup(new SourceBlock(4, 0, 3), new SourceBlock(2, 7, 0));
lookup53[37] = new SingleColorLookup(new SourceBlock(4, 0, 4), new SourceBlock(0, 9, 0));
lookup53[38] = new SingleColorLookup(new SourceBlock(5, 0, 3), new SourceBlock(0, 9, 1));
lookup53[39] = new SingleColorLookup(new SourceBlock(5, 0, 2), new SourceBlock(3, 7, 1));
lookup53[40] = new SingleColorLookup(new SourceBlock(5, 0, 1), new SourceBlock(3, 7, 0));
lookup53[41] = new SingleColorLookup(new SourceBlock(5, 0, 0), new SourceBlock(0, 10, 0));
lookup53[42] = new SingleColorLookup(new SourceBlock(5, 0, 1), new SourceBlock(0, 10, 1));
lookup53[43] = new SingleColorLookup(new SourceBlock(5, 0, 2), new SourceBlock(0, 10, 2));
lookup53[44] = new SingleColorLookup(new SourceBlock(5, 0, 3), new SourceBlock(0, 11, 1));
lookup53[45] = new SingleColorLookup(new SourceBlock(5, 0, 4), new SourceBlock(0, 11, 0));
lookup53[46] = new SingleColorLookup(new SourceBlock(6, 0, 3), new SourceBlock(0, 11, 1));
lookup53[47] = new SingleColorLookup(new SourceBlock(6, 0, 2), new SourceBlock(0, 11, 2));
lookup53[48] = new SingleColorLookup(new SourceBlock(6, 0, 1), new SourceBlock(0, 12, 1));
lookup53[49] = new SingleColorLookup(new SourceBlock(6, 0, 0), new SourceBlock(0, 12, 0));
lookup53[50] = new SingleColorLookup(new SourceBlock(6, 0, 1), new SourceBlock(0, 12, 1));
lookup53[51] = new SingleColorLookup(new SourceBlock(6, 0, 2), new SourceBlock(0, 12, 2));
lookup53[52] = new SingleColorLookup(new SourceBlock(6, 0, 3), new SourceBlock(0, 13, 1));
lookup53[53] = new SingleColorLookup(new SourceBlock(6, 0, 4), new SourceBlock(0, 13, 0));
lookup53[54] = new SingleColorLookup(new SourceBlock(7, 0, 3), new SourceBlock(0, 13, 1));
lookup53[55] = new SingleColorLookup(new SourceBlock(7, 0, 2), new SourceBlock(0, 13, 2));
lookup53[56] = new SingleColorLookup(new SourceBlock(7, 0, 1), new SourceBlock(0, 14, 1));
lookup53[57] = new SingleColorLookup(new SourceBlock(7, 0, 0), new SourceBlock(0, 14, 0));
lookup53[58] = new SingleColorLookup(new SourceBlock(7, 0, 1), new SourceBlock(0, 14, 1));
lookup53[59] = new SingleColorLookup(new SourceBlock(7, 0, 2), new SourceBlock(0, 14, 2));
lookup53[60] = new SingleColorLookup(new SourceBlock(7, 0, 3), new SourceBlock(0, 15, 1));
lookup53[61] = new SingleColorLookup(new SourceBlock(7, 0, 4), new SourceBlock(0, 15, 0));
lookup53[62] = new SingleColorLookup(new SourceBlock(8, 0, 4), new SourceBlock(0, 15, 1));
lookup53[63] = new SingleColorLookup(new SourceBlock(8, 0, 3), new SourceBlock(0, 15, 2));
lookup53[64] = new SingleColorLookup(new SourceBlock(8, 0, 2), new SourceBlock(1, 15, 1));
lookup53[65] = new SingleColorLookup(new SourceBlock(8, 0, 1), new SourceBlock(1, 15, 0));
lookup53[66] = new SingleColorLookup(new SourceBlock(8, 0, 0), new SourceBlock(0, 16, 0));
lookup53[67] = new SingleColorLookup(new SourceBlock(8, 0, 1), new SourceBlock(0, 16, 1));
lookup53[68] = new SingleColorLookup(new SourceBlock(8, 0, 2), new SourceBlock(2, 15, 1));
lookup53[69] = new SingleColorLookup(new SourceBlock(8, 0, 3), new SourceBlock(2, 15, 0));
lookup53[70] = new SingleColorLookup(new SourceBlock(8, 0, 4), new SourceBlock(0, 17, 0));
lookup53[71] = new SingleColorLookup(new SourceBlock(9, 0, 3), new SourceBlock(0, 17, 1));
lookup53[72] = new SingleColorLookup(new SourceBlock(9, 0, 2), new SourceBlock(3, 15, 1));
lookup53[73] = new SingleColorLookup(new SourceBlock(9, 0, 1), new SourceBlock(3, 15, 0));
lookup53[74] = new SingleColorLookup(new SourceBlock(9, 0, 0), new SourceBlock(0, 18, 0));
lookup53[75] = new SingleColorLookup(new SourceBlock(9, 0, 1), new SourceBlock(0, 18, 1));
lookup53[76] = new SingleColorLookup(new SourceBlock(9, 0, 2), new SourceBlock(0, 18, 2));
lookup53[77] = new SingleColorLookup(new SourceBlock(9, 0, 3), new SourceBlock(0, 19, 1));
lookup53[78] = new SingleColorLookup(new SourceBlock(9, 0, 4), new SourceBlock(0, 19, 0));
lookup53[79] = new SingleColorLookup(new SourceBlock(10, 0, 3), new SourceBlock(0, 19, 1));
lookup53[80] = new SingleColorLookup(new SourceBlock(10, 0, 2), new SourceBlock(0, 19, 2));
lookup53[81] = new SingleColorLookup(new SourceBlock(10, 0, 1), new SourceBlock(0, 20, 1));
lookup53[82] = new SingleColorLookup(new SourceBlock(10, 0, 0), new SourceBlock(0, 20, 0));
lookup53[83] = new SingleColorLookup(new SourceBlock(10, 0, 1), new SourceBlock(0, 20, 1));
lookup53[84] = new SingleColorLookup(new SourceBlock(10, 0, 2), new SourceBlock(0, 20, 2));
lookup53[85] = new SingleColorLookup(new SourceBlock(10, 0, 3), new SourceBlock(0, 21, 1));
lookup53[86] = new SingleColorLookup(new SourceBlock(10, 0, 4), new SourceBlock(0, 21, 0));
lookup53[87] = new SingleColorLookup(new SourceBlock(11, 0, 3), new SourceBlock(0, 21, 1));
lookup53[88] = new SingleColorLookup(new SourceBlock(11, 0, 2), new SourceBlock(0, 21, 2));
lookup53[89] = new SingleColorLookup(new SourceBlock(11, 0, 1), new SourceBlock(0, 22, 1));
lookup53[90] = new SingleColorLookup(new SourceBlock(11, 0, 0), new SourceBlock(0, 22, 0));
lookup53[91] = new SingleColorLookup(new SourceBlock(11, 0, 1), new SourceBlock(0, 22, 1));
lookup53[92] = new SingleColorLookup(new SourceBlock(11, 0, 2), new SourceBlock(0, 22, 2));
lookup53[93] = new SingleColorLookup(new SourceBlock(11, 0, 3), new SourceBlock(0, 23, 1));
lookup53[94] = new SingleColorLookup(new SourceBlock(11, 0, 4), new SourceBlock(0, 23, 0));
lookup53[95] = new SingleColorLookup(new SourceBlock(12, 0, 4), new SourceBlock(0, 23, 1));
lookup53[96] = new SingleColorLookup(new SourceBlock(12, 0, 3), new SourceBlock(0, 23, 2));
lookup53[97] = new SingleColorLookup(new SourceBlock(12, 0, 2), new SourceBlock(1, 23, 1));
lookup53[98] = new SingleColorLookup(new SourceBlock(12, 0, 1), new SourceBlock(1, 23, 0));
lookup53[99] = new SingleColorLookup(new SourceBlock(12, 0, 0), new SourceBlock(0, 24, 0));
lookup53[100] = new SingleColorLookup(new SourceBlock(12, 0, 1), new SourceBlock(0, 24, 1));
lookup53[101] = new SingleColorLookup(new SourceBlock(12, 0, 2), new SourceBlock(2, 23, 1));
lookup53[102] = new SingleColorLookup(new SourceBlock(12, 0, 3), new SourceBlock(2, 23, 0));
lookup53[103] = new SingleColorLookup(new SourceBlock(12, 0, 4), new SourceBlock(0, 25, 0));
lookup53[104] = new SingleColorLookup(new SourceBlock(13, 0, 3), new SourceBlock(0, 25, 1));
lookup53[105] = new SingleColorLookup(new SourceBlock(13, 0, 2), new SourceBlock(3, 23, 1));
lookup53[106] = new SingleColorLookup(new SourceBlock(13, 0, 1), new SourceBlock(3, 23, 0));
lookup53[107] = new SingleColorLookup(new SourceBlock(13, 0, 0), new SourceBlock(0, 26, 0));
lookup53[108] = new SingleColorLookup(new SourceBlock(13, 0, 1), new SourceBlock(0, 26, 1));
lookup53[109] = new SingleColorLookup(new SourceBlock(13, 0, 2), new SourceBlock(0, 26, 2));
lookup53[110] = new SingleColorLookup(new SourceBlock(13, 0, 3), new SourceBlock(0, 27, 1));
lookup53[111] = new SingleColorLookup(new SourceBlock(13, 0, 4), new SourceBlock(0, 27, 0));
lookup53[112] = new SingleColorLookup(new SourceBlock(14, 0, 3), new SourceBlock(0, 27, 1));
lookup53[113] = new SingleColorLookup(new SourceBlock(14, 0, 2), new SourceBlock(0, 27, 2));
lookup53[114] = new SingleColorLookup(new SourceBlock(14, 0, 1), new SourceBlock(0, 28, 1));
lookup53[115] = new SingleColorLookup(new SourceBlock(14, 0, 0), new SourceBlock(0, 28, 0));
lookup53[116] = new SingleColorLookup(new SourceBlock(14, 0, 1), new SourceBlock(0, 28, 1));
lookup53[117] = new SingleColorLookup(new SourceBlock(14, 0, 2), new SourceBlock(0, 28, 2));
lookup53[118] = new SingleColorLookup(new SourceBlock(14, 0, 3), new SourceBlock(0, 29, 1));
lookup53[119] = new SingleColorLookup(new SourceBlock(14, 0, 4), new SourceBlock(0, 29, 0));
lookup53[120] = new SingleColorLookup(new SourceBlock(15, 0, 3), new SourceBlock(0, 29, 1));
lookup53[121] = new SingleColorLookup(new SourceBlock(15, 0, 2), new SourceBlock(0, 29, 2));
lookup53[122] = new SingleColorLookup(new SourceBlock(15, 0, 1), new SourceBlock(0, 30, 1));
lookup53[123] = new SingleColorLookup(new SourceBlock(15, 0, 0), new SourceBlock(0, 30, 0));
lookup53[124] = new SingleColorLookup(new SourceBlock(15, 0, 1), new SourceBlock(0, 30, 1));
lookup53[125] = new SingleColorLookup(new SourceBlock(15, 0, 2), new SourceBlock(0, 30, 2));
lookup53[126] = new SingleColorLookup(new SourceBlock(15, 0, 3), new SourceBlock(0, 31, 1));
lookup53[127] = new SingleColorLookup(new SourceBlock(15, 0, 4), new SourceBlock(0, 31, 0));
lookup53[128] = new SingleColorLookup(new SourceBlock(16, 0, 4), new SourceBlock(0, 31, 1));
lookup53[129] = new SingleColorLookup(new SourceBlock(16, 0, 3), new SourceBlock(0, 31, 2));
lookup53[130] = new SingleColorLookup(new SourceBlock(16, 0, 2), new SourceBlock(1, 31, 1));
lookup53[131] = new SingleColorLookup(new SourceBlock(16, 0, 1), new SourceBlock(1, 31, 0));
lookup53[132] = new SingleColorLookup(new SourceBlock(16, 0, 0), new SourceBlock(4, 28, 0));
lookup53[133] = new SingleColorLookup(new SourceBlock(16, 0, 1), new SourceBlock(4, 28, 1));
lookup53[134] = new SingleColorLookup(new SourceBlock(16, 0, 2), new SourceBlock(2, 31, 1));
lookup53[135] = new SingleColorLookup(new SourceBlock(16, 0, 3), new SourceBlock(2, 31, 0));
lookup53[136] = new SingleColorLookup(new SourceBlock(16, 0, 4), new SourceBlock(4, 29, 0));
lookup53[137] = new SingleColorLookup(new SourceBlock(17, 0, 3), new SourceBlock(4, 29, 1));
lookup53[138] = new SingleColorLookup(new SourceBlock(17, 0, 2), new SourceBlock(3, 31, 1));
lookup53[139] = new SingleColorLookup(new SourceBlock(17, 0, 1), new SourceBlock(3, 31, 0));
lookup53[140] = new SingleColorLookup(new SourceBlock(17, 0, 0), new SourceBlock(4, 30, 0));
lookup53[141] = new SingleColorLookup(new SourceBlock(17, 0, 1), new SourceBlock(4, 30, 1));
lookup53[142] = new SingleColorLookup(new SourceBlock(17, 0, 2), new SourceBlock(4, 30, 2));
lookup53[143] = new SingleColorLookup(new SourceBlock(17, 0, 3), new SourceBlock(4, 31, 1));
lookup53[144] = new SingleColorLookup(new SourceBlock(17, 0, 4), new SourceBlock(4, 31, 0));
lookup53[145] = new SingleColorLookup(new SourceBlock(18, 0, 3), new SourceBlock(4, 31, 1));
lookup53[146] = new SingleColorLookup(new SourceBlock(18, 0, 2), new SourceBlock(4, 31, 2));
lookup53[147] = new SingleColorLookup(new SourceBlock(18, 0, 1), new SourceBlock(5, 31, 1));
lookup53[148] = new SingleColorLookup(new SourceBlock(18, 0, 0), new SourceBlock(5, 31, 0));
lookup53[149] = new SingleColorLookup(new SourceBlock(18, 0, 1), new SourceBlock(5, 31, 1));
lookup53[150] = new SingleColorLookup(new SourceBlock(18, 0, 2), new SourceBlock(5, 31, 2));
lookup53[151] = new SingleColorLookup(new SourceBlock(18, 0, 3), new SourceBlock(6, 31, 1));
lookup53[152] = new SingleColorLookup(new SourceBlock(18, 0, 4), new SourceBlock(6, 31, 0));
lookup53[153] = new SingleColorLookup(new SourceBlock(19, 0, 3), new SourceBlock(6, 31, 1));
lookup53[154] = new SingleColorLookup(new SourceBlock(19, 0, 2), new SourceBlock(6, 31, 2));
lookup53[155] = new SingleColorLookup(new SourceBlock(19, 0, 1), new SourceBlock(7, 31, 1));
lookup53[156] = new SingleColorLookup(new SourceBlock(19, 0, 0), new SourceBlock(7, 31, 0));
lookup53[157] = new SingleColorLookup(new SourceBlock(19, 0, 1), new SourceBlock(7, 31, 1));
lookup53[158] = new SingleColorLookup(new SourceBlock(19, 0, 2), new SourceBlock(7, 31, 2));
lookup53[159] = new SingleColorLookup(new SourceBlock(19, 0, 3), new SourceBlock(8, 31, 1));
lookup53[160] = new SingleColorLookup(new SourceBlock(19, 0, 4), new SourceBlock(8, 31, 0));
lookup53[161] = new SingleColorLookup(new SourceBlock(20, 0, 4), new SourceBlock(8, 31, 1));
lookup53[162] = new SingleColorLookup(new SourceBlock(20, 0, 3), new SourceBlock(8, 31, 2));
lookup53[163] = new SingleColorLookup(new SourceBlock(20, 0, 2), new SourceBlock(9, 31, 1));
lookup53[164] = new SingleColorLookup(new SourceBlock(20, 0, 1), new SourceBlock(9, 31, 0));
lookup53[165] = new SingleColorLookup(new SourceBlock(20, 0, 0), new SourceBlock(12, 28, 0));
lookup53[166] = new SingleColorLookup(new SourceBlock(20, 0, 1), new SourceBlock(12, 28, 1));
lookup53[167] = new SingleColorLookup(new SourceBlock(20, 0, 2), new SourceBlock(10, 31, 1));
lookup53[168] = new SingleColorLookup(new SourceBlock(20, 0, 3), new SourceBlock(10, 31, 0));
lookup53[169] = new SingleColorLookup(new SourceBlock(20, 0, 4), new SourceBlock(12, 29, 0));
lookup53[170] = new SingleColorLookup(new SourceBlock(21, 0, 3), new SourceBlock(12, 29, 1));
lookup53[171] = new SingleColorLookup(new SourceBlock(21, 0, 2), new SourceBlock(11, 31, 1));
lookup53[172] = new SingleColorLookup(new SourceBlock(21, 0, 1), new SourceBlock(11, 31, 0));
lookup53[173] = new SingleColorLookup(new SourceBlock(21, 0, 0), new SourceBlock(12, 30, 0));
lookup53[174] = new SingleColorLookup(new SourceBlock(21, 0, 1), new SourceBlock(12, 30, 1));
lookup53[175] = new SingleColorLookup(new SourceBlock(21, 0, 2), new SourceBlock(12, 30, 2));
lookup53[176] = new SingleColorLookup(new SourceBlock(21, 0, 3), new SourceBlock(12, 31, 1));
lookup53[177] = new SingleColorLookup(new SourceBlock(21, 0, 4), new SourceBlock(12, 31, 0));
lookup53[178] = new SingleColorLookup(new SourceBlock(22, 0, 3), new SourceBlock(12, 31, 1));
lookup53[179] = new SingleColorLookup(new SourceBlock(22, 0, 2), new SourceBlock(12, 31, 2));
lookup53[180] = new SingleColorLookup(new SourceBlock(22, 0, 1), new SourceBlock(13, 31, 1));
lookup53[181] = new SingleColorLookup(new SourceBlock(22, 0, 0), new SourceBlock(13, 31, 0));
lookup53[182] = new SingleColorLookup(new SourceBlock(22, 0, 1), new SourceBlock(13, 31, 1));
lookup53[183] = new SingleColorLookup(new SourceBlock(22, 0, 2), new SourceBlock(13, 31, 2));
lookup53[184] = new SingleColorLookup(new SourceBlock(22, 0, 3), new SourceBlock(14, 31, 1));
lookup53[185] = new SingleColorLookup(new SourceBlock(22, 0, 4), new SourceBlock(14, 31, 0));
lookup53[186] = new SingleColorLookup(new SourceBlock(23, 0, 3), new SourceBlock(14, 31, 1));
lookup53[187] = new SingleColorLookup(new SourceBlock(23, 0, 2), new SourceBlock(14, 31, 2));
lookup53[188] = new SingleColorLookup(new SourceBlock(23, 0, 1), new SourceBlock(15, 31, 1));
lookup53[189] = new SingleColorLookup(new SourceBlock(23, 0, 0), new SourceBlock(15, 31, 0));
lookup53[190] = new SingleColorLookup(new SourceBlock(23, 0, 1), new SourceBlock(15, 31, 1));
lookup53[191] = new SingleColorLookup(new SourceBlock(23, 0, 2), new SourceBlock(15, 31, 2));
lookup53[192] = new SingleColorLookup(new SourceBlock(23, 0, 3), new SourceBlock(16, 31, 1));
lookup53[193] = new SingleColorLookup(new SourceBlock(23, 0, 4), new SourceBlock(16, 31, 0));
lookup53[194] = new SingleColorLookup(new SourceBlock(24, 0, 4), new SourceBlock(16, 31, 1));
lookup53[195] = new SingleColorLookup(new SourceBlock(24, 0, 3), new SourceBlock(16, 31, 2));
lookup53[196] = new SingleColorLookup(new SourceBlock(24, 0, 2), new SourceBlock(17, 31, 1));
lookup53[197] = new SingleColorLookup(new SourceBlock(24, 0, 1), new SourceBlock(17, 31, 0));
lookup53[198] = new SingleColorLookup(new SourceBlock(24, 0, 0), new SourceBlock(20, 28, 0));
lookup53[199] = new SingleColorLookup(new SourceBlock(24, 0, 1), new SourceBlock(20, 28, 1));
lookup53[200] = new SingleColorLookup(new SourceBlock(24, 0, 2), new SourceBlock(18, 31, 1));
lookup53[201] = new SingleColorLookup(new SourceBlock(24, 0, 3), new SourceBlock(18, 31, 0));
lookup53[202] = new SingleColorLookup(new SourceBlock(24, 0, 4), new SourceBlock(20, 29, 0));
lookup53[203] = new SingleColorLookup(new SourceBlock(25, 0, 3), new SourceBlock(20, 29, 1));
lookup53[204] = new SingleColorLookup(new SourceBlock(25, 0, 2), new SourceBlock(19, 31, 1));
lookup53[205] = new SingleColorLookup(new SourceBlock(25, 0, 1), new SourceBlock(19, 31, 0));
lookup53[206] = new SingleColorLookup(new SourceBlock(25, 0, 0), new SourceBlock(20, 30, 0));
lookup53[207] = new SingleColorLookup(new SourceBlock(25, 0, 1), new SourceBlock(20, 30, 1));
lookup53[208] = new SingleColorLookup(new SourceBlock(25, 0, 2), new SourceBlock(20, 30, 2));
lookup53[209] = new SingleColorLookup(new SourceBlock(25, 0, 3), new SourceBlock(20, 31, 1));
lookup53[210] = new SingleColorLookup(new SourceBlock(25, 0, 4), new SourceBlock(20, 31, 0));
lookup53[211] = new SingleColorLookup(new SourceBlock(26, 0, 3), new SourceBlock(20, 31, 1));
lookup53[212] = new SingleColorLookup(new SourceBlock(26, 0, 2), new SourceBlock(20, 31, 2));
lookup53[213] = new SingleColorLookup(new SourceBlock(26, 0, 1), new SourceBlock(21, 31, 1));
lookup53[214] = new SingleColorLookup(new SourceBlock(26, 0, 0), new SourceBlock(21, 31, 0));
lookup53[215] = new SingleColorLookup(new SourceBlock(26, 0, 1), new SourceBlock(21, 31, 1));
lookup53[216] = new SingleColorLookup(new SourceBlock(26, 0, 2), new SourceBlock(21, 31, 2));
lookup53[217] = new SingleColorLookup(new SourceBlock(26, 0, 3), new SourceBlock(22, 31, 1));
lookup53[218] = new SingleColorLookup(new SourceBlock(26, 0, 4), new SourceBlock(22, 31, 0));
lookup53[219] = new SingleColorLookup(new SourceBlock(27, 0, 3), new SourceBlock(22, 31, 1));
lookup53[220] = new SingleColorLookup(new SourceBlock(27, 0, 2), new SourceBlock(22, 31, 2));
lookup53[221] = new SingleColorLookup(new SourceBlock(27, 0, 1), new SourceBlock(23, 31, 1));
lookup53[222] = new SingleColorLookup(new SourceBlock(27, 0, 0), new SourceBlock(23, 31, 0));
lookup53[223] = new SingleColorLookup(new SourceBlock(27, 0, 1), new SourceBlock(23, 31, 1));
lookup53[224] = new SingleColorLookup(new SourceBlock(27, 0, 2), new SourceBlock(23, 31, 2));
lookup53[225] = new SingleColorLookup(new SourceBlock(27, 0, 3), new SourceBlock(24, 31, 1));
lookup53[226] = new SingleColorLookup(new SourceBlock(27, 0, 4), new SourceBlock(24, 31, 0));
lookup53[227] = new SingleColorLookup(new SourceBlock(28, 0, 4), new SourceBlock(24, 31, 1));
lookup53[228] = new SingleColorLookup(new SourceBlock(28, 0, 3), new SourceBlock(24, 31, 2));
lookup53[229] = new SingleColorLookup(new SourceBlock(28, 0, 2), new SourceBlock(25, 31, 1));
lookup53[230] = new SingleColorLookup(new SourceBlock(28, 0, 1), new SourceBlock(25, 31, 0));
lookup53[231] = new SingleColorLookup(new SourceBlock(28, 0, 0), new SourceBlock(28, 28, 0));
lookup53[232] = new SingleColorLookup(new SourceBlock(28, 0, 1), new SourceBlock(28, 28, 1));
lookup53[233] = new SingleColorLookup(new SourceBlock(28, 0, 2), new SourceBlock(26, 31, 1));
lookup53[234] = new SingleColorLookup(new SourceBlock(28, 0, 3), new SourceBlock(26, 31, 0));
lookup53[235] = new SingleColorLookup(new SourceBlock(28, 0, 4), new SourceBlock(28, 29, 0));
lookup53[236] = new SingleColorLookup(new SourceBlock(29, 0, 3), new SourceBlock(28, 29, 1));
lookup53[237] = new SingleColorLookup(new SourceBlock(29, 0, 2), new SourceBlock(27, 31, 1));
lookup53[238] = new SingleColorLookup(new SourceBlock(29, 0, 1), new SourceBlock(27, 31, 0));
lookup53[239] = new SingleColorLookup(new SourceBlock(29, 0, 0), new SourceBlock(28, 30, 0));
lookup53[240] = new SingleColorLookup(new SourceBlock(29, 0, 1), new SourceBlock(28, 30, 1));
lookup53[241] = new SingleColorLookup(new SourceBlock(29, 0, 2), new SourceBlock(28, 30, 2));
lookup53[242] = new SingleColorLookup(new SourceBlock(29, 0, 3), new SourceBlock(28, 31, 1));
lookup53[243] = new SingleColorLookup(new SourceBlock(29, 0, 4), new SourceBlock(28, 31, 0));
lookup53[244] = new SingleColorLookup(new SourceBlock(30, 0, 3), new SourceBlock(28, 31, 1));
lookup53[245] = new SingleColorLookup(new SourceBlock(30, 0, 2), new SourceBlock(28, 31, 2));
lookup53[246] = new SingleColorLookup(new SourceBlock(30, 0, 1), new SourceBlock(29, 31, 1));
lookup53[247] = new SingleColorLookup(new SourceBlock(30, 0, 0), new SourceBlock(29, 31, 0));
lookup53[248] = new SingleColorLookup(new SourceBlock(30, 0, 1), new SourceBlock(29, 31, 1));
lookup53[249] = new SingleColorLookup(new SourceBlock(30, 0, 2), new SourceBlock(29, 31, 2));
lookup53[250] = new SingleColorLookup(new SourceBlock(30, 0, 3), new SourceBlock(30, 31, 1));
lookup53[251] = new SingleColorLookup(new SourceBlock(30, 0, 4), new SourceBlock(30, 31, 0));
lookup53[252] = new SingleColorLookup(new SourceBlock(31, 0, 3), new SourceBlock(30, 31, 1));
lookup53[253] = new SingleColorLookup(new SourceBlock(31, 0, 2), new SourceBlock(30, 31, 2));
lookup53[254] = new SingleColorLookup(new SourceBlock(31, 0, 1), new SourceBlock(31, 31, 1));
lookup53[255] = new SingleColorLookup(new SourceBlock(31, 0, 0), new SourceBlock(31, 31, 0));
lookup63[0] = new SingleColorLookup(new SourceBlock(0, 0, 0), new SourceBlock(0, 0, 0));
lookup63[1] = new SingleColorLookup(new SourceBlock(0, 0, 1), new SourceBlock(0, 1, 1));
lookup63[2] = new SingleColorLookup(new SourceBlock(0, 0, 2), new SourceBlock(0, 1, 0));
lookup63[3] = new SingleColorLookup(new SourceBlock(1, 0, 1), new SourceBlock(0, 2, 1));
lookup63[4] = new SingleColorLookup(new SourceBlock(1, 0, 0), new SourceBlock(0, 2, 0));
lookup63[5] = new SingleColorLookup(new SourceBlock(1, 0, 1), new SourceBlock(0, 3, 1));
lookup63[6] = new SingleColorLookup(new SourceBlock(1, 0, 2), new SourceBlock(0, 3, 0));
lookup63[7] = new SingleColorLookup(new SourceBlock(2, 0, 1), new SourceBlock(0, 4, 1));
lookup63[8] = new SingleColorLookup(new SourceBlock(2, 0, 0), new SourceBlock(0, 4, 0));
lookup63[9] = new SingleColorLookup(new SourceBlock(2, 0, 1), new SourceBlock(0, 5, 1));
lookup63[10] = new SingleColorLookup(new SourceBlock(2, 0, 2), new SourceBlock(0, 5, 0));
lookup63[11] = new SingleColorLookup(new SourceBlock(3, 0, 1), new SourceBlock(0, 6, 1));
lookup63[12] = new SingleColorLookup(new SourceBlock(3, 0, 0), new SourceBlock(0, 6, 0));
lookup63[13] = new SingleColorLookup(new SourceBlock(3, 0, 1), new SourceBlock(0, 7, 1));
lookup63[14] = new SingleColorLookup(new SourceBlock(3, 0, 2), new SourceBlock(0, 7, 0));
lookup63[15] = new SingleColorLookup(new SourceBlock(4, 0, 1), new SourceBlock(0, 8, 1));
lookup63[16] = new SingleColorLookup(new SourceBlock(4, 0, 0), new SourceBlock(0, 8, 0));
lookup63[17] = new SingleColorLookup(new SourceBlock(4, 0, 1), new SourceBlock(0, 9, 1));
lookup63[18] = new SingleColorLookup(new SourceBlock(4, 0, 2), new SourceBlock(0, 9, 0));
lookup63[19] = new SingleColorLookup(new SourceBlock(5, 0, 1), new SourceBlock(0, 10, 1));
lookup63[20] = new SingleColorLookup(new SourceBlock(5, 0, 0), new SourceBlock(0, 10, 0));
lookup63[21] = new SingleColorLookup(new SourceBlock(5, 0, 1), new SourceBlock(0, 11, 1));
lookup63[22] = new SingleColorLookup(new SourceBlock(5, 0, 2), new SourceBlock(0, 11, 0));
lookup63[23] = new SingleColorLookup(new SourceBlock(6, 0, 1), new SourceBlock(0, 12, 1));
lookup63[24] = new SingleColorLookup(new SourceBlock(6, 0, 0), new SourceBlock(0, 12, 0));
lookup63[25] = new SingleColorLookup(new SourceBlock(6, 0, 1), new SourceBlock(0, 13, 1));
lookup63[26] = new SingleColorLookup(new SourceBlock(6, 0, 2), new SourceBlock(0, 13, 0));
lookup63[27] = new SingleColorLookup(new SourceBlock(7, 0, 1), new SourceBlock(0, 14, 1));
lookup63[28] = new SingleColorLookup(new SourceBlock(7, 0, 0), new SourceBlock(0, 14, 0));
lookup63[29] = new SingleColorLookup(new SourceBlock(7, 0, 1), new SourceBlock(0, 15, 1));
lookup63[30] = new SingleColorLookup(new SourceBlock(7, 0, 2), new SourceBlock(0, 15, 0));
lookup63[31] = new SingleColorLookup(new SourceBlock(8, 0, 1), new SourceBlock(0, 16, 1));
lookup63[32] = new SingleColorLookup(new SourceBlock(8, 0, 0), new SourceBlock(0, 16, 0));
lookup63[33] = new SingleColorLookup(new SourceBlock(8, 0, 1), new SourceBlock(0, 17, 1));
lookup63[34] = new SingleColorLookup(new SourceBlock(8, 0, 2), new SourceBlock(0, 17, 0));
lookup63[35] = new SingleColorLookup(new SourceBlock(9, 0, 1), new SourceBlock(0, 18, 1));
lookup63[36] = new SingleColorLookup(new SourceBlock(9, 0, 0), new SourceBlock(0, 18, 0));
lookup63[37] = new SingleColorLookup(new SourceBlock(9, 0, 1), new SourceBlock(0, 19, 1));
lookup63[38] = new SingleColorLookup(new SourceBlock(9, 0, 2), new SourceBlock(0, 19, 0));
lookup63[39] = new SingleColorLookup(new SourceBlock(10, 0, 1), new SourceBlock(0, 20, 1));
lookup63[40] = new SingleColorLookup(new SourceBlock(10, 0, 0), new SourceBlock(0, 20, 0));
lookup63[41] = new SingleColorLookup(new SourceBlock(10, 0, 1), new SourceBlock(0, 21, 1));
lookup63[42] = new SingleColorLookup(new SourceBlock(10, 0, 2), new SourceBlock(0, 21, 0));
lookup63[43] = new SingleColorLookup(new SourceBlock(11, 0, 1), new SourceBlock(0, 22, 1));
lookup63[44] = new SingleColorLookup(new SourceBlock(11, 0, 0), new SourceBlock(0, 22, 0));
lookup63[45] = new SingleColorLookup(new SourceBlock(11, 0, 1), new SourceBlock(0, 23, 1));
lookup63[46] = new SingleColorLookup(new SourceBlock(11, 0, 2), new SourceBlock(0, 23, 0));
lookup63[47] = new SingleColorLookup(new SourceBlock(12, 0, 1), new SourceBlock(0, 24, 1));
lookup63[48] = new SingleColorLookup(new SourceBlock(12, 0, 0), new SourceBlock(0, 24, 0));
lookup63[49] = new SingleColorLookup(new SourceBlock(12, 0, 1), new SourceBlock(0, 25, 1));
lookup63[50] = new SingleColorLookup(new SourceBlock(12, 0, 2), new SourceBlock(0, 25, 0));
lookup63[51] = new SingleColorLookup(new SourceBlock(13, 0, 1), new SourceBlock(0, 26, 1));
lookup63[52] = new SingleColorLookup(new SourceBlock(13, 0, 0), new SourceBlock(0, 26, 0));
lookup63[53] = new SingleColorLookup(new SourceBlock(13, 0, 1), new SourceBlock(0, 27, 1));
lookup63[54] = new SingleColorLookup(new SourceBlock(13, 0, 2), new SourceBlock(0, 27, 0));
lookup63[55] = new SingleColorLookup(new SourceBlock(14, 0, 1), new SourceBlock(0, 28, 1));
lookup63[56] = new SingleColorLookup(new SourceBlock(14, 0, 0), new SourceBlock(0, 28, 0));
lookup63[57] = new SingleColorLookup(new SourceBlock(14, 0, 1), new SourceBlock(0, 29, 1));
lookup63[58] = new SingleColorLookup(new SourceBlock(14, 0, 2), new SourceBlock(0, 29, 0));
lookup63[59] = new SingleColorLookup(new SourceBlock(15, 0, 1), new SourceBlock(0, 30, 1));
lookup63[60] = new SingleColorLookup(new SourceBlock(15, 0, 0), new SourceBlock(0, 30, 0));
lookup63[61] = new SingleColorLookup(new SourceBlock(15, 0, 1), new SourceBlock(0, 31, 1));
lookup63[62] = new SingleColorLookup(new SourceBlock(15, 0, 2), new SourceBlock(0, 31, 0));
lookup63[63] = new SingleColorLookup(new SourceBlock(16, 0, 2), new SourceBlock(1, 31, 1));
lookup63[64] = new SingleColorLookup(new SourceBlock(16, 0, 1), new SourceBlock(1, 31, 0));
lookup63[65] = new SingleColorLookup(new SourceBlock(16, 0, 0), new SourceBlock(0, 32, 0));
lookup63[66] = new SingleColorLookup(new SourceBlock(16, 0, 1), new SourceBlock(2, 31, 0));
lookup63[67] = new SingleColorLookup(new SourceBlock(16, 0, 2), new SourceBlock(0, 33, 0));
lookup63[68] = new SingleColorLookup(new SourceBlock(17, 0, 1), new SourceBlock(3, 31, 0));
lookup63[69] = new SingleColorLookup(new SourceBlock(17, 0, 0), new SourceBlock(0, 34, 0));
lookup63[70] = new SingleColorLookup(new SourceBlock(17, 0, 1), new SourceBlock(4, 31, 0));
lookup63[71] = new SingleColorLookup(new SourceBlock(17, 0, 2), new SourceBlock(0, 35, 0));
lookup63[72] = new SingleColorLookup(new SourceBlock(18, 0, 1), new SourceBlock(5, 31, 0));
lookup63[73] = new SingleColorLookup(new SourceBlock(18, 0, 0), new SourceBlock(0, 36, 0));
lookup63[74] = new SingleColorLookup(new SourceBlock(18, 0, 1), new SourceBlock(6, 31, 0));
lookup63[75] = new SingleColorLookup(new SourceBlock(18, 0, 2), new SourceBlock(0, 37, 0));
lookup63[76] = new SingleColorLookup(new SourceBlock(19, 0, 1), new SourceBlock(7, 31, 0));
lookup63[77] = new SingleColorLookup(new SourceBlock(19, 0, 0), new SourceBlock(0, 38, 0));
lookup63[78] = new SingleColorLookup(new SourceBlock(19, 0, 1), new SourceBlock(8, 31, 0));
lookup63[79] = new SingleColorLookup(new SourceBlock(19, 0, 2), new SourceBlock(0, 39, 0));
lookup63[80] = new SingleColorLookup(new SourceBlock(20, 0, 1), new SourceBlock(9, 31, 0));
lookup63[81] = new SingleColorLookup(new SourceBlock(20, 0, 0), new SourceBlock(0, 40, 0));
lookup63[82] = new SingleColorLookup(new SourceBlock(20, 0, 1), new SourceBlock(10, 31, 0));
lookup63[83] = new SingleColorLookup(new SourceBlock(20, 0, 2), new SourceBlock(0, 41, 0));
lookup63[84] = new SingleColorLookup(new SourceBlock(21, 0, 1), new SourceBlock(11, 31, 0));
lookup63[85] = new SingleColorLookup(new SourceBlock(21, 0, 0), new SourceBlock(0, 42, 0));
lookup63[86] = new SingleColorLookup(new SourceBlock(21, 0, 1), new SourceBlock(12, 31, 0));
lookup63[87] = new SingleColorLookup(new SourceBlock(21, 0, 2), new SourceBlock(0, 43, 0));
lookup63[88] = new SingleColorLookup(new SourceBlock(22, 0, 1), new SourceBlock(13, 31, 0));
lookup63[89] = new SingleColorLookup(new SourceBlock(22, 0, 0), new SourceBlock(0, 44, 0));
lookup63[90] = new SingleColorLookup(new SourceBlock(22, 0, 1), new SourceBlock(14, 31, 0));
lookup63[91] = new SingleColorLookup(new SourceBlock(22, 0, 2), new SourceBlock(0, 45, 0));
lookup63[92] = new SingleColorLookup(new SourceBlock(23, 0, 1), new SourceBlock(15, 31, 0));
lookup63[93] = new SingleColorLookup(new SourceBlock(23, 0, 0), new SourceBlock(0, 46, 0));
lookup63[94] = new SingleColorLookup(new SourceBlock(23, 0, 1), new SourceBlock(0, 47, 1));
lookup63[95] = new SingleColorLookup(new SourceBlock(23, 0, 2), new SourceBlock(0, 47, 0));
lookup63[96] = new SingleColorLookup(new SourceBlock(24, 0, 1), new SourceBlock(0, 48, 1));
lookup63[97] = new SingleColorLookup(new SourceBlock(24, 0, 0), new SourceBlock(0, 48, 0));
lookup63[98] = new SingleColorLookup(new SourceBlock(24, 0, 1), new SourceBlock(0, 49, 1));
lookup63[99] = new SingleColorLookup(new SourceBlock(24, 0, 2), new SourceBlock(0, 49, 0));
lookup63[100] = new SingleColorLookup(new SourceBlock(25, 0, 1), new SourceBlock(0, 50, 1));
lookup63[101] = new SingleColorLookup(new SourceBlock(25, 0, 0), new SourceBlock(0, 50, 0));
lookup63[102] = new SingleColorLookup(new SourceBlock(25, 0, 1), new SourceBlock(0, 51, 1));
lookup63[103] = new SingleColorLookup(new SourceBlock(25, 0, 2), new SourceBlock(0, 51, 0));
lookup63[104] = new SingleColorLookup(new SourceBlock(26, 0, 1), new SourceBlock(0, 52, 1));
lookup63[105] = new SingleColorLookup(new SourceBlock(26, 0, 0), new SourceBlock(0, 52, 0));
lookup63[106] = new SingleColorLookup(new SourceBlock(26, 0, 1), new SourceBlock(0, 53, 1));
lookup63[107] = new SingleColorLookup(new SourceBlock(26, 0, 2), new SourceBlock(0, 53, 0));
lookup63[108] = new SingleColorLookup(new SourceBlock(27, 0, 1), new SourceBlock(0, 54, 1));
lookup63[109] = new SingleColorLookup(new SourceBlock(27, 0, 0), new SourceBlock(0, 54, 0));
lookup63[110] = new SingleColorLookup(new SourceBlock(27, 0, 1), new SourceBlock(0, 55, 1));
lookup63[111] = new SingleColorLookup(new SourceBlock(27, 0, 2), new SourceBlock(0, 55, 0));
lookup63[112] = new SingleColorLookup(new SourceBlock(28, 0, 1), new SourceBlock(0, 56, 1));
lookup63[113] = new SingleColorLookup(new SourceBlock(28, 0, 0), new SourceBlock(0, 56, 0));
lookup63[114] = new SingleColorLookup(new SourceBlock(28, 0, 1), new SourceBlock(0, 57, 1));
lookup63[115] = new SingleColorLookup(new SourceBlock(28, 0, 2), new SourceBlock(0, 57, 0));
lookup63[116] = new SingleColorLookup(new SourceBlock(29, 0, 1), new SourceBlock(0, 58, 1));
lookup63[117] = new SingleColorLookup(new SourceBlock(29, 0, 0), new SourceBlock(0, 58, 0));
lookup63[118] = new SingleColorLookup(new SourceBlock(29, 0, 1), new SourceBlock(0, 59, 1));
lookup63[119] = new SingleColorLookup(new SourceBlock(29, 0, 2), new SourceBlock(0, 59, 0));
lookup63[120] = new SingleColorLookup(new SourceBlock(30, 0, 1), new SourceBlock(0, 60, 1));
lookup63[121] = new SingleColorLookup(new SourceBlock(30, 0, 0), new SourceBlock(0, 60, 0));
lookup63[122] = new SingleColorLookup(new SourceBlock(30, 0, 1), new SourceBlock(0, 61, 1));
lookup63[123] = new SingleColorLookup(new SourceBlock(30, 0, 2), new SourceBlock(0, 61, 0));
lookup63[124] = new SingleColorLookup(new SourceBlock(31, 0, 1), new SourceBlock(0, 62, 1));
lookup63[125] = new SingleColorLookup(new SourceBlock(31, 0, 0), new SourceBlock(0, 62, 0));
lookup63[126] = new SingleColorLookup(new SourceBlock(31, 0, 1), new SourceBlock(0, 63, 1));
lookup63[127] = new SingleColorLookup(new SourceBlock(31, 0, 2), new SourceBlock(0, 63, 0));
lookup63[128] = new SingleColorLookup(new SourceBlock(32, 0, 2), new SourceBlock(1, 63, 1));
lookup63[129] = new SingleColorLookup(new SourceBlock(32, 0, 1), new SourceBlock(1, 63, 0));
lookup63[130] = new SingleColorLookup(new SourceBlock(32, 0, 0), new SourceBlock(16, 48, 0));
lookup63[131] = new SingleColorLookup(new SourceBlock(32, 0, 1), new SourceBlock(2, 63, 0));
lookup63[132] = new SingleColorLookup(new SourceBlock(32, 0, 2), new SourceBlock(16, 49, 0));
lookup63[133] = new SingleColorLookup(new SourceBlock(33, 0, 1), new SourceBlock(3, 63, 0));
lookup63[134] = new SingleColorLookup(new SourceBlock(33, 0, 0), new SourceBlock(16, 50, 0));
lookup63[135] = new SingleColorLookup(new SourceBlock(33, 0, 1), new SourceBlock(4, 63, 0));
lookup63[136] = new SingleColorLookup(new SourceBlock(33, 0, 2), new SourceBlock(16, 51, 0));
lookup63[137] = new SingleColorLookup(new SourceBlock(34, 0, 1), new SourceBlock(5, 63, 0));
lookup63[138] = new SingleColorLookup(new SourceBlock(34, 0, 0), new SourceBlock(16, 52, 0));
lookup63[139] = new SingleColorLookup(new SourceBlock(34, 0, 1), new SourceBlock(6, 63, 0));
lookup63[140] = new SingleColorLookup(new SourceBlock(34, 0, 2), new SourceBlock(16, 53, 0));
lookup63[141] = new SingleColorLookup(new SourceBlock(35, 0, 1), new SourceBlock(7, 63, 0));
lookup63[142] = new SingleColorLookup(new SourceBlock(35, 0, 0), new SourceBlock(16, 54, 0));
lookup63[143] = new SingleColorLookup(new SourceBlock(35, 0, 1), new SourceBlock(8, 63, 0));
lookup63[144] = new SingleColorLookup(new SourceBlock(35, 0, 2), new SourceBlock(16, 55, 0));
lookup63[145] = new SingleColorLookup(new SourceBlock(36, 0, 1), new SourceBlock(9, 63, 0));
lookup63[146] = new SingleColorLookup(new SourceBlock(36, 0, 0), new SourceBlock(16, 56, 0));
lookup63[147] = new SingleColorLookup(new SourceBlock(36, 0, 1), new SourceBlock(10, 63, 0));
lookup63[148] = new SingleColorLookup(new SourceBlock(36, 0, 2), new SourceBlock(16, 57, 0));
lookup63[149] = new SingleColorLookup(new SourceBlock(37, 0, 1), new SourceBlock(11, 63, 0));
lookup63[150] = new SingleColorLookup(new SourceBlock(37, 0, 0), new SourceBlock(16, 58, 0));
lookup63[151] = new SingleColorLookup(new SourceBlock(37, 0, 1), new SourceBlock(12, 63, 0));
lookup63[152] = new SingleColorLookup(new SourceBlock(37, 0, 2), new SourceBlock(16, 59, 0));
lookup63[153] = new SingleColorLookup(new SourceBlock(38, 0, 1), new SourceBlock(13, 63, 0));
lookup63[154] = new SingleColorLookup(new SourceBlock(38, 0, 0), new SourceBlock(16, 60, 0));
lookup63[155] = new SingleColorLookup(new SourceBlock(38, 0, 1), new SourceBlock(14, 63, 0));
lookup63[156] = new SingleColorLookup(new SourceBlock(38, 0, 2), new SourceBlock(16, 61, 0));
lookup63[157] = new SingleColorLookup(new SourceBlock(39, 0, 1), new SourceBlock(15, 63, 0));
lookup63[158] = new SingleColorLookup(new SourceBlock(39, 0, 0), new SourceBlock(16, 62, 0));
lookup63[159] = new SingleColorLookup(new SourceBlock(39, 0, 1), new SourceBlock(16, 63, 1));
lookup63[160] = new SingleColorLookup(new SourceBlock(39, 0, 2), new SourceBlock(16, 63, 0));
lookup63[161] = new SingleColorLookup(new SourceBlock(40, 0, 1), new SourceBlock(17, 63, 1));
lookup63[162] = new SingleColorLookup(new SourceBlock(40, 0, 0), new SourceBlock(17, 63, 0));
lookup63[163] = new SingleColorLookup(new SourceBlock(40, 0, 1), new SourceBlock(18, 63, 1));
lookup63[164] = new SingleColorLookup(new SourceBlock(40, 0, 2), new SourceBlock(18, 63, 0));
lookup63[165] = new SingleColorLookup(new SourceBlock(41, 0, 1), new SourceBlock(19, 63, 1));
lookup63[166] = new SingleColorLookup(new SourceBlock(41, 0, 0), new SourceBlock(19, 63, 0));
lookup63[167] = new SingleColorLookup(new SourceBlock(41, 0, 1), new SourceBlock(20, 63, 1));
lookup63[168] = new SingleColorLookup(new SourceBlock(41, 0, 2), new SourceBlock(20, 63, 0));
lookup63[169] = new SingleColorLookup(new SourceBlock(42, 0, 1), new SourceBlock(21, 63, 1));
lookup63[170] = new SingleColorLookup(new SourceBlock(42, 0, 0), new SourceBlock(21, 63, 0));
lookup63[171] = new SingleColorLookup(new SourceBlock(42, 0, 1), new SourceBlock(22, 63, 1));
lookup63[172] = new SingleColorLookup(new SourceBlock(42, 0, 2), new SourceBlock(22, 63, 0));
lookup63[173] = new SingleColorLookup(new SourceBlock(43, 0, 1), new SourceBlock(23, 63, 1));
lookup63[174] = new SingleColorLookup(new SourceBlock(43, 0, 0), new SourceBlock(23, 63, 0));
lookup63[175] = new SingleColorLookup(new SourceBlock(43, 0, 1), new SourceBlock(24, 63, 1));
lookup63[176] = new SingleColorLookup(new SourceBlock(43, 0, 2), new SourceBlock(24, 63, 0));
lookup63[177] = new SingleColorLookup(new SourceBlock(44, 0, 1), new SourceBlock(25, 63, 1));
lookup63[178] = new SingleColorLookup(new SourceBlock(44, 0, 0), new SourceBlock(25, 63, 0));
lookup63[179] = new SingleColorLookup(new SourceBlock(44, 0, 1), new SourceBlock(26, 63, 1));
lookup63[180] = new SingleColorLookup(new SourceBlock(44, 0, 2), new SourceBlock(26, 63, 0));
lookup63[181] = new SingleColorLookup(new SourceBlock(45, 0, 1), new SourceBlock(27, 63, 1));
lookup63[182] = new SingleColorLookup(new SourceBlock(45, 0, 0), new SourceBlock(27, 63, 0));
lookup63[183] = new SingleColorLookup(new SourceBlock(45, 0, 1), new SourceBlock(28, 63, 1));
lookup63[184] = new SingleColorLookup(new SourceBlock(45, 0, 2), new SourceBlock(28, 63, 0));
lookup63[185] = new SingleColorLookup(new SourceBlock(46, 0, 1), new SourceBlock(29, 63, 1));
lookup63[186] = new SingleColorLookup(new SourceBlock(46, 0, 0), new SourceBlock(29, 63, 0));
lookup63[187] = new SingleColorLookup(new SourceBlock(46, 0, 1), new SourceBlock(30, 63, 1));
lookup63[188] = new SingleColorLookup(new SourceBlock(46, 0, 2), new SourceBlock(30, 63, 0));
lookup63[189] = new SingleColorLookup(new SourceBlock(47, 0, 1), new SourceBlock(31, 63, 1));
lookup63[190] = new SingleColorLookup(new SourceBlock(47, 0, 0), new SourceBlock(31, 63, 0));
lookup63[191] = new SingleColorLookup(new SourceBlock(47, 0, 1), new SourceBlock(32, 63, 1));
lookup63[192] = new SingleColorLookup(new SourceBlock(47, 0, 2), new SourceBlock(32, 63, 0));
lookup63[193] = new SingleColorLookup(new SourceBlock(48, 0, 2), new SourceBlock(33, 63, 1));
lookup63[194] = new SingleColorLookup(new SourceBlock(48, 0, 1), new SourceBlock(33, 63, 0));
lookup63[195] = new SingleColorLookup(new SourceBlock(48, 0, 0), new SourceBlock(48, 48, 0));
lookup63[196] = new SingleColorLookup(new SourceBlock(48, 0, 1), new SourceBlock(34, 63, 0));
lookup63[197] = new SingleColorLookup(new SourceBlock(48, 0, 2), new SourceBlock(48, 49, 0));
lookup63[198] = new SingleColorLookup(new SourceBlock(49, 0, 1), new SourceBlock(35, 63, 0));
lookup63[199] = new SingleColorLookup(new SourceBlock(49, 0, 0), new SourceBlock(48, 50, 0));
lookup63[200] = new SingleColorLookup(new SourceBlock(49, 0, 1), new SourceBlock(36, 63, 0));
lookup63[201] = new SingleColorLookup(new SourceBlock(49, 0, 2), new SourceBlock(48, 51, 0));
lookup63[202] = new SingleColorLookup(new SourceBlock(50, 0, 1), new SourceBlock(37, 63, 0));
lookup63[203] = new SingleColorLookup(new SourceBlock(50, 0, 0), new SourceBlock(48, 52, 0));
lookup63[204] = new SingleColorLookup(new SourceBlock(50, 0, 1), new SourceBlock(38, 63, 0));
lookup63[205] = new SingleColorLookup(new SourceBlock(50, 0, 2), new SourceBlock(48, 53, 0));
lookup63[206] = new SingleColorLookup(new SourceBlock(51, 0, 1), new SourceBlock(39, 63, 0));
lookup63[207] = new SingleColorLookup(new SourceBlock(51, 0, 0), new SourceBlock(48, 54, 0));
lookup63[208] = new SingleColorLookup(new SourceBlock(51, 0, 1), new SourceBlock(40, 63, 0));
lookup63[209] = new SingleColorLookup(new SourceBlock(51, 0, 2), new SourceBlock(48, 55, 0));
lookup63[210] = new SingleColorLookup(new SourceBlock(52, 0, 1), new SourceBlock(41, 63, 0));
lookup63[211] = new SingleColorLookup(new SourceBlock(52, 0, 0), new SourceBlock(48, 56, 0));
lookup63[212] = new SingleColorLookup(new SourceBlock(52, 0, 1), new SourceBlock(42, 63, 0));
lookup63[213] = new SingleColorLookup(new SourceBlock(52, 0, 2), new SourceBlock(48, 57, 0));
lookup63[214] = new SingleColorLookup(new SourceBlock(53, 0, 1), new SourceBlock(43, 63, 0));
lookup63[215] = new SingleColorLookup(new SourceBlock(53, 0, 0), new SourceBlock(48, 58, 0));
lookup63[216] = new SingleColorLookup(new SourceBlock(53, 0, 1), new SourceBlock(44, 63, 0));
lookup63[217] = new SingleColorLookup(new SourceBlock(53, 0, 2), new SourceBlock(48, 59, 0));
lookup63[218] = new SingleColorLookup(new SourceBlock(54, 0, 1), new SourceBlock(45, 63, 0));
lookup63[219] = new SingleColorLookup(new SourceBlock(54, 0, 0), new SourceBlock(48, 60, 0));
lookup63[220] = new SingleColorLookup(new SourceBlock(54, 0, 1), new SourceBlock(46, 63, 0));
lookup63[221] = new SingleColorLookup(new SourceBlock(54, 0, 2), new SourceBlock(48, 61, 0));
lookup63[222] = new SingleColorLookup(new SourceBlock(55, 0, 1), new SourceBlock(47, 63, 0));
lookup63[223] = new SingleColorLookup(new SourceBlock(55, 0, 0), new SourceBlock(48, 62, 0));
lookup63[224] = new SingleColorLookup(new SourceBlock(55, 0, 1), new SourceBlock(48, 63, 1));
lookup63[225] = new SingleColorLookup(new SourceBlock(55, 0, 2), new SourceBlock(48, 63, 0));
lookup63[226] = new SingleColorLookup(new SourceBlock(56, 0, 1), new SourceBlock(49, 63, 1));
lookup63[227] = new SingleColorLookup(new SourceBlock(56, 0, 0), new SourceBlock(49, 63, 0));
lookup63[228] = new SingleColorLookup(new SourceBlock(56, 0, 1), new SourceBlock(50, 63, 1));
lookup63[229] = new SingleColorLookup(new SourceBlock(56, 0, 2), new SourceBlock(50, 63, 0));
lookup63[230] = new SingleColorLookup(new SourceBlock(57, 0, 1), new SourceBlock(51, 63, 1));
lookup63[231] = new SingleColorLookup(new SourceBlock(57, 0, 0), new SourceBlock(51, 63, 0));
lookup63[232] = new SingleColorLookup(new SourceBlock(57, 0, 1), new SourceBlock(52, 63, 1));
lookup63[233] = new SingleColorLookup(new SourceBlock(57, 0, 2), new SourceBlock(52, 63, 0));
lookup63[234] = new SingleColorLookup(new SourceBlock(58, 0, 1), new SourceBlock(53, 63, 1));
lookup63[235] = new SingleColorLookup(new SourceBlock(58, 0, 0), new SourceBlock(53, 63, 0));
lookup63[236] = new SingleColorLookup(new SourceBlock(58, 0, 1), new SourceBlock(54, 63, 1));
lookup63[237] = new SingleColorLookup(new SourceBlock(58, 0, 2), new SourceBlock(54, 63, 0));
lookup63[238] = new SingleColorLookup(new SourceBlock(59, 0, 1), new SourceBlock(55, 63, 1));
lookup63[239] = new SingleColorLookup(new SourceBlock(59, 0, 0), new SourceBlock(55, 63, 0));
lookup63[240] = new SingleColorLookup(new SourceBlock(59, 0, 1), new SourceBlock(56, 63, 1));
lookup63[241] = new SingleColorLookup(new SourceBlock(59, 0, 2), new SourceBlock(56, 63, 0));
lookup63[242] = new SingleColorLookup(new SourceBlock(60, 0, 1), new SourceBlock(57, 63, 1));
lookup63[243] = new SingleColorLookup(new SourceBlock(60, 0, 0), new SourceBlock(57, 63, 0));
lookup63[244] = new SingleColorLookup(new SourceBlock(60, 0, 1), new SourceBlock(58, 63, 1));
lookup63[245] = new SingleColorLookup(new SourceBlock(60, 0, 2), new SourceBlock(58, 63, 0));
lookup63[246] = new SingleColorLookup(new SourceBlock(61, 0, 1), new SourceBlock(59, 63, 1));
lookup63[247] = new SingleColorLookup(new SourceBlock(61, 0, 0), new SourceBlock(59, 63, 0));
lookup63[248] = new SingleColorLookup(new SourceBlock(61, 0, 1), new SourceBlock(60, 63, 1));
lookup63[249] = new SingleColorLookup(new SourceBlock(61, 0, 2), new SourceBlock(60, 63, 0));
lookup63[250] = new SingleColorLookup(new SourceBlock(62, 0, 1), new SourceBlock(61, 63, 1));
lookup63[251] = new SingleColorLookup(new SourceBlock(62, 0, 0), new SourceBlock(61, 63, 0));
lookup63[252] = new SingleColorLookup(new SourceBlock(62, 0, 1), new SourceBlock(62, 63, 1));
lookup63[253] = new SingleColorLookup(new SourceBlock(62, 0, 2), new SourceBlock(62, 63, 0));
lookup63[254] = new SingleColorLookup(new SourceBlock(63, 0, 1), new SourceBlock(63, 63, 1));
lookup63[255] = new SingleColorLookup(new SourceBlock(63, 0, 0), new SourceBlock(63, 63, 0));
lookup54[0] = new SingleColorLookup(new SourceBlock(0, 0, 0), new SourceBlock(0, 0, 0));
lookup54[1] = new SingleColorLookup(new SourceBlock(0, 0, 1), new SourceBlock(0, 1, 1));
lookup54[2] = new SingleColorLookup(new SourceBlock(0, 0, 2), new SourceBlock(0, 1, 0));
lookup54[3] = new SingleColorLookup(new SourceBlock(0, 0, 3), new SourceBlock(0, 1, 1));
lookup54[4] = new SingleColorLookup(new SourceBlock(0, 0, 4), new SourceBlock(0, 2, 1));
lookup54[5] = new SingleColorLookup(new SourceBlock(1, 0, 3), new SourceBlock(0, 2, 0));
lookup54[6] = new SingleColorLookup(new SourceBlock(1, 0, 2), new SourceBlock(0, 2, 1));
lookup54[7] = new SingleColorLookup(new SourceBlock(1, 0, 1), new SourceBlock(0, 3, 1));
lookup54[8] = new SingleColorLookup(new SourceBlock(1, 0, 0), new SourceBlock(0, 3, 0));
lookup54[9] = new SingleColorLookup(new SourceBlock(1, 0, 1), new SourceBlock(1, 2, 1));
lookup54[10] = new SingleColorLookup(new SourceBlock(1, 0, 2), new SourceBlock(1, 2, 0));
lookup54[11] = new SingleColorLookup(new SourceBlock(1, 0, 3), new SourceBlock(0, 4, 0));
lookup54[12] = new SingleColorLookup(new SourceBlock(1, 0, 4), new SourceBlock(0, 5, 1));
lookup54[13] = new SingleColorLookup(new SourceBlock(2, 0, 3), new SourceBlock(0, 5, 0));
lookup54[14] = new SingleColorLookup(new SourceBlock(2, 0, 2), new SourceBlock(0, 5, 1));
lookup54[15] = new SingleColorLookup(new SourceBlock(2, 0, 1), new SourceBlock(0, 6, 1));
lookup54[16] = new SingleColorLookup(new SourceBlock(2, 0, 0), new SourceBlock(0, 6, 0));
lookup54[17] = new SingleColorLookup(new SourceBlock(2, 0, 1), new SourceBlock(2, 3, 1));
lookup54[18] = new SingleColorLookup(new SourceBlock(2, 0, 2), new SourceBlock(2, 3, 0));
lookup54[19] = new SingleColorLookup(new SourceBlock(2, 0, 3), new SourceBlock(0, 7, 0));
lookup54[20] = new SingleColorLookup(new SourceBlock(2, 0, 4), new SourceBlock(1, 6, 1));
lookup54[21] = new SingleColorLookup(new SourceBlock(3, 0, 3), new SourceBlock(1, 6, 0));
lookup54[22] = new SingleColorLookup(new SourceBlock(3, 0, 2), new SourceBlock(0, 8, 0));
lookup54[23] = new SingleColorLookup(new SourceBlock(3, 0, 1), new SourceBlock(0, 9, 1));
lookup54[24] = new SingleColorLookup(new SourceBlock(3, 0, 0), new SourceBlock(0, 9, 0));
lookup54[25] = new SingleColorLookup(new SourceBlock(3, 0, 1), new SourceBlock(0, 9, 1));
lookup54[26] = new SingleColorLookup(new SourceBlock(3, 0, 2), new SourceBlock(0, 10, 1));
lookup54[27] = new SingleColorLookup(new SourceBlock(3, 0, 3), new SourceBlock(0, 10, 0));
lookup54[28] = new SingleColorLookup(new SourceBlock(3, 0, 4), new SourceBlock(2, 7, 1));
lookup54[29] = new SingleColorLookup(new SourceBlock(4, 0, 4), new SourceBlock(2, 7, 0));
lookup54[30] = new SingleColorLookup(new SourceBlock(4, 0, 3), new SourceBlock(0, 11, 0));
lookup54[31] = new SingleColorLookup(new SourceBlock(4, 0, 2), new SourceBlock(1, 10, 1));
lookup54[32] = new SingleColorLookup(new SourceBlock(4, 0, 1), new SourceBlock(1, 10, 0));
lookup54[33] = new SingleColorLookup(new SourceBlock(4, 0, 0), new SourceBlock(0, 12, 0));
lookup54[34] = new SingleColorLookup(new SourceBlock(4, 0, 1), new SourceBlock(0, 13, 1));
lookup54[35] = new SingleColorLookup(new SourceBlock(4, 0, 2), new SourceBlock(0, 13, 0));
lookup54[36] = new SingleColorLookup(new SourceBlock(4, 0, 3), new SourceBlock(0, 13, 1));
lookup54[37] = new SingleColorLookup(new SourceBlock(4, 0, 4), new SourceBlock(0, 14, 1));
lookup54[38] = new SingleColorLookup(new SourceBlock(5, 0, 3), new SourceBlock(0, 14, 0));
lookup54[39] = new SingleColorLookup(new SourceBlock(5, 0, 2), new SourceBlock(2, 11, 1));
lookup54[40] = new SingleColorLookup(new SourceBlock(5, 0, 1), new SourceBlock(2, 11, 0));
lookup54[41] = new SingleColorLookup(new SourceBlock(5, 0, 0), new SourceBlock(0, 15, 0));
lookup54[42] = new SingleColorLookup(new SourceBlock(5, 0, 1), new SourceBlock(1, 14, 1));
lookup54[43] = new SingleColorLookup(new SourceBlock(5, 0, 2), new SourceBlock(1, 14, 0));
lookup54[44] = new SingleColorLookup(new SourceBlock(5, 0, 3), new SourceBlock(0, 16, 0));
lookup54[45] = new SingleColorLookup(new SourceBlock(5, 0, 4), new SourceBlock(0, 17, 1));
lookup54[46] = new SingleColorLookup(new SourceBlock(6, 0, 3), new SourceBlock(0, 17, 0));
lookup54[47] = new SingleColorLookup(new SourceBlock(6, 0, 2), new SourceBlock(0, 17, 1));
lookup54[48] = new SingleColorLookup(new SourceBlock(6, 0, 1), new SourceBlock(0, 18, 1));
lookup54[49] = new SingleColorLookup(new SourceBlock(6, 0, 0), new SourceBlock(0, 18, 0));
lookup54[50] = new SingleColorLookup(new SourceBlock(6, 0, 1), new SourceBlock(2, 15, 1));
lookup54[51] = new SingleColorLookup(new SourceBlock(6, 0, 2), new SourceBlock(2, 15, 0));
lookup54[52] = new SingleColorLookup(new SourceBlock(6, 0, 3), new SourceBlock(0, 19, 0));
lookup54[53] = new SingleColorLookup(new SourceBlock(6, 0, 4), new SourceBlock(1, 18, 1));
lookup54[54] = new SingleColorLookup(new SourceBlock(7, 0, 3), new SourceBlock(1, 18, 0));
lookup54[55] = new SingleColorLookup(new SourceBlock(7, 0, 2), new SourceBlock(0, 20, 0));
lookup54[56] = new SingleColorLookup(new SourceBlock(7, 0, 1), new SourceBlock(0, 21, 1));
lookup54[57] = new SingleColorLookup(new SourceBlock(7, 0, 0), new SourceBlock(0, 21, 0));
lookup54[58] = new SingleColorLookup(new SourceBlock(7, 0, 1), new SourceBlock(0, 21, 1));
lookup54[59] = new SingleColorLookup(new SourceBlock(7, 0, 2), new SourceBlock(0, 22, 1));
lookup54[60] = new SingleColorLookup(new SourceBlock(7, 0, 3), new SourceBlock(0, 22, 0));
lookup54[61] = new SingleColorLookup(new SourceBlock(7, 0, 4), new SourceBlock(2, 19, 1));
lookup54[62] = new SingleColorLookup(new SourceBlock(8, 0, 4), new SourceBlock(2, 19, 0));
lookup54[63] = new SingleColorLookup(new SourceBlock(8, 0, 3), new SourceBlock(0, 23, 0));
lookup54[64] = new SingleColorLookup(new SourceBlock(8, 0, 2), new SourceBlock(1, 22, 1));
lookup54[65] = new SingleColorLookup(new SourceBlock(8, 0, 1), new SourceBlock(1, 22, 0));
lookup54[66] = new SingleColorLookup(new SourceBlock(8, 0, 0), new SourceBlock(0, 24, 0));
lookup54[67] = new SingleColorLookup(new SourceBlock(8, 0, 1), new SourceBlock(0, 25, 1));
lookup54[68] = new SingleColorLookup(new SourceBlock(8, 0, 2), new SourceBlock(0, 25, 0));
lookup54[69] = new SingleColorLookup(new SourceBlock(8, 0, 3), new SourceBlock(0, 25, 1));
lookup54[70] = new SingleColorLookup(new SourceBlock(8, 0, 4), new SourceBlock(0, 26, 1));
lookup54[71] = new SingleColorLookup(new SourceBlock(9, 0, 3), new SourceBlock(0, 26, 0));
lookup54[72] = new SingleColorLookup(new SourceBlock(9, 0, 2), new SourceBlock(2, 23, 1));
lookup54[73] = new SingleColorLookup(new SourceBlock(9, 0, 1), new SourceBlock(2, 23, 0));
lookup54[74] = new SingleColorLookup(new SourceBlock(9, 0, 0), new SourceBlock(0, 27, 0));
lookup54[75] = new SingleColorLookup(new SourceBlock(9, 0, 1), new SourceBlock(1, 26, 1));
lookup54[76] = new SingleColorLookup(new SourceBlock(9, 0, 2), new SourceBlock(1, 26, 0));
lookup54[77] = new SingleColorLookup(new SourceBlock(9, 0, 3), new SourceBlock(0, 28, 0));
lookup54[78] = new SingleColorLookup(new SourceBlock(9, 0, 4), new SourceBlock(0, 29, 1));
lookup54[79] = new SingleColorLookup(new SourceBlock(10, 0, 3), new SourceBlock(0, 29, 0));
lookup54[80] = new SingleColorLookup(new SourceBlock(10, 0, 2), new SourceBlock(0, 29, 1));
lookup54[81] = new SingleColorLookup(new SourceBlock(10, 0, 1), new SourceBlock(0, 30, 1));
lookup54[82] = new SingleColorLookup(new SourceBlock(10, 0, 0), new SourceBlock(0, 30, 0));
lookup54[83] = new SingleColorLookup(new SourceBlock(10, 0, 1), new SourceBlock(2, 27, 1));
lookup54[84] = new SingleColorLookup(new SourceBlock(10, 0, 2), new SourceBlock(2, 27, 0));
lookup54[85] = new SingleColorLookup(new SourceBlock(10, 0, 3), new SourceBlock(0, 31, 0));
lookup54[86] = new SingleColorLookup(new SourceBlock(10, 0, 4), new SourceBlock(1, 30, 1));
lookup54[87] = new SingleColorLookup(new SourceBlock(11, 0, 3), new SourceBlock(1, 30, 0));
lookup54[88] = new SingleColorLookup(new SourceBlock(11, 0, 2), new SourceBlock(4, 24, 0));
lookup54[89] = new SingleColorLookup(new SourceBlock(11, 0, 1), new SourceBlock(1, 31, 1));
lookup54[90] = new SingleColorLookup(new SourceBlock(11, 0, 0), new SourceBlock(1, 31, 0));
lookup54[91] = new SingleColorLookup(new SourceBlock(11, 0, 1), new SourceBlock(1, 31, 1));
lookup54[92] = new SingleColorLookup(new SourceBlock(11, 0, 2), new SourceBlock(2, 30, 1));
lookup54[93] = new SingleColorLookup(new SourceBlock(11, 0, 3), new SourceBlock(2, 30, 0));
lookup54[94] = new SingleColorLookup(new SourceBlock(11, 0, 4), new SourceBlock(2, 31, 1));
lookup54[95] = new SingleColorLookup(new SourceBlock(12, 0, 4), new SourceBlock(2, 31, 0));
lookup54[96] = new SingleColorLookup(new SourceBlock(12, 0, 3), new SourceBlock(4, 27, 0));
lookup54[97] = new SingleColorLookup(new SourceBlock(12, 0, 2), new SourceBlock(3, 30, 1));
lookup54[98] = new SingleColorLookup(new SourceBlock(12, 0, 1), new SourceBlock(3, 30, 0));
lookup54[99] = new SingleColorLookup(new SourceBlock(12, 0, 0), new SourceBlock(4, 28, 0));
lookup54[100] = new SingleColorLookup(new SourceBlock(12, 0, 1), new SourceBlock(3, 31, 1));
lookup54[101] = new SingleColorLookup(new SourceBlock(12, 0, 2), new SourceBlock(3, 31, 0));
lookup54[102] = new SingleColorLookup(new SourceBlock(12, 0, 3), new SourceBlock(3, 31, 1));
lookup54[103] = new SingleColorLookup(new SourceBlock(12, 0, 4), new SourceBlock(4, 30, 1));
lookup54[104] = new SingleColorLookup(new SourceBlock(13, 0, 3), new SourceBlock(4, 30, 0));
lookup54[105] = new SingleColorLookup(new SourceBlock(13, 0, 2), new SourceBlock(6, 27, 1));
lookup54[106] = new SingleColorLookup(new SourceBlock(13, 0, 1), new SourceBlock(6, 27, 0));
lookup54[107] = new SingleColorLookup(new SourceBlock(13, 0, 0), new SourceBlock(4, 31, 0));
lookup54[108] = new SingleColorLookup(new SourceBlock(13, 0, 1), new SourceBlock(5, 30, 1));
lookup54[109] = new SingleColorLookup(new SourceBlock(13, 0, 2), new SourceBlock(5, 30, 0));
lookup54[110] = new SingleColorLookup(new SourceBlock(13, 0, 3), new SourceBlock(8, 24, 0));
lookup54[111] = new SingleColorLookup(new SourceBlock(13, 0, 4), new SourceBlock(5, 31, 1));
lookup54[112] = new SingleColorLookup(new SourceBlock(14, 0, 3), new SourceBlock(5, 31, 0));
lookup54[113] = new SingleColorLookup(new SourceBlock(14, 0, 2), new SourceBlock(5, 31, 1));
lookup54[114] = new SingleColorLookup(new SourceBlock(14, 0, 1), new SourceBlock(6, 30, 1));
lookup54[115] = new SingleColorLookup(new SourceBlock(14, 0, 0), new SourceBlock(6, 30, 0));
lookup54[116] = new SingleColorLookup(new SourceBlock(14, 0, 1), new SourceBlock(6, 31, 1));
lookup54[117] = new SingleColorLookup(new SourceBlock(14, 0, 2), new SourceBlock(6, 31, 0));
lookup54[118] = new SingleColorLookup(new SourceBlock(14, 0, 3), new SourceBlock(8, 27, 0));
lookup54[119] = new SingleColorLookup(new SourceBlock(14, 0, 4), new SourceBlock(7, 30, 1));
lookup54[120] = new SingleColorLookup(new SourceBlock(15, 0, 3), new SourceBlock(7, 30, 0));
lookup54[121] = new SingleColorLookup(new SourceBlock(15, 0, 2), new SourceBlock(8, 28, 0));
lookup54[122] = new SingleColorLookup(new SourceBlock(15, 0, 1), new SourceBlock(7, 31, 1));
lookup54[123] = new SingleColorLookup(new SourceBlock(15, 0, 0), new SourceBlock(7, 31, 0));
lookup54[124] = new SingleColorLookup(new SourceBlock(15, 0, 1), new SourceBlock(7, 31, 1));
lookup54[125] = new SingleColorLookup(new SourceBlock(15, 0, 2), new SourceBlock(8, 30, 1));
lookup54[126] = new SingleColorLookup(new SourceBlock(15, 0, 3), new SourceBlock(8, 30, 0));
lookup54[127] = new SingleColorLookup(new SourceBlock(15, 0, 4), new SourceBlock(10, 27, 1));
lookup54[128] = new SingleColorLookup(new SourceBlock(16, 0, 4), new SourceBlock(10, 27, 0));
lookup54[129] = new SingleColorLookup(new SourceBlock(16, 0, 3), new SourceBlock(8, 31, 0));
lookup54[130] = new SingleColorLookup(new SourceBlock(16, 0, 2), new SourceBlock(9, 30, 1));
lookup54[131] = new SingleColorLookup(new SourceBlock(16, 0, 1), new SourceBlock(9, 30, 0));
lookup54[132] = new SingleColorLookup(new SourceBlock(16, 0, 0), new SourceBlock(12, 24, 0));
lookup54[133] = new SingleColorLookup(new SourceBlock(16, 0, 1), new SourceBlock(9, 31, 1));
lookup54[134] = new SingleColorLookup(new SourceBlock(16, 0, 2), new SourceBlock(9, 31, 0));
lookup54[135] = new SingleColorLookup(new SourceBlock(16, 0, 3), new SourceBlock(9, 31, 1));
lookup54[136] = new SingleColorLookup(new SourceBlock(16, 0, 4), new SourceBlock(10, 30, 1));
lookup54[137] = new SingleColorLookup(new SourceBlock(17, 0, 3), new SourceBlock(10, 30, 0));
lookup54[138] = new SingleColorLookup(new SourceBlock(17, 0, 2), new SourceBlock(10, 31, 1));
lookup54[139] = new SingleColorLookup(new SourceBlock(17, 0, 1), new SourceBlock(10, 31, 0));
lookup54[140] = new SingleColorLookup(new SourceBlock(17, 0, 0), new SourceBlock(12, 27, 0));
lookup54[141] = new SingleColorLookup(new SourceBlock(17, 0, 1), new SourceBlock(11, 30, 1));
lookup54[142] = new SingleColorLookup(new SourceBlock(17, 0, 2), new SourceBlock(11, 30, 0));
lookup54[143] = new SingleColorLookup(new SourceBlock(17, 0, 3), new SourceBlock(12, 28, 0));
lookup54[144] = new SingleColorLookup(new SourceBlock(17, 0, 4), new SourceBlock(11, 31, 1));
lookup54[145] = new SingleColorLookup(new SourceBlock(18, 0, 3), new SourceBlock(11, 31, 0));
lookup54[146] = new SingleColorLookup(new SourceBlock(18, 0, 2), new SourceBlock(11, 31, 1));
lookup54[147] = new SingleColorLookup(new SourceBlock(18, 0, 1), new SourceBlock(12, 30, 1));
lookup54[148] = new SingleColorLookup(new SourceBlock(18, 0, 0), new SourceBlock(12, 30, 0));
lookup54[149] = new SingleColorLookup(new SourceBlock(18, 0, 1), new SourceBlock(14, 27, 1));
lookup54[150] = new SingleColorLookup(new SourceBlock(18, 0, 2), new SourceBlock(14, 27, 0));
lookup54[151] = new SingleColorLookup(new SourceBlock(18, 0, 3), new SourceBlock(12, 31, 0));
lookup54[152] = new SingleColorLookup(new SourceBlock(18, 0, 4), new SourceBlock(13, 30, 1));
lookup54[153] = new SingleColorLookup(new SourceBlock(19, 0, 3), new SourceBlock(13, 30, 0));
lookup54[154] = new SingleColorLookup(new SourceBlock(19, 0, 2), new SourceBlock(16, 24, 0));
lookup54[155] = new SingleColorLookup(new SourceBlock(19, 0, 1), new SourceBlock(13, 31, 1));
lookup54[156] = new SingleColorLookup(new SourceBlock(19, 0, 0), new SourceBlock(13, 31, 0));
lookup54[157] = new SingleColorLookup(new SourceBlock(19, 0, 1), new SourceBlock(13, 31, 1));
lookup54[158] = new SingleColorLookup(new SourceBlock(19, 0, 2), new SourceBlock(14, 30, 1));
lookup54[159] = new SingleColorLookup(new SourceBlock(19, 0, 3), new SourceBlock(14, 30, 0));
lookup54[160] = new SingleColorLookup(new SourceBlock(19, 0, 4), new SourceBlock(14, 31, 1));
lookup54[161] = new SingleColorLookup(new SourceBlock(20, 0, 4), new SourceBlock(14, 31, 0));
lookup54[162] = new SingleColorLookup(new SourceBlock(20, 0, 3), new SourceBlock(16, 27, 0));
lookup54[163] = new SingleColorLookup(new SourceBlock(20, 0, 2), new SourceBlock(15, 30, 1));
lookup54[164] = new SingleColorLookup(new SourceBlock(20, 0, 1), new SourceBlock(15, 30, 0));
lookup54[165] = new SingleColorLookup(new SourceBlock(20, 0, 0), new SourceBlock(16, 28, 0));
lookup54[166] = new SingleColorLookup(new SourceBlock(20, 0, 1), new SourceBlock(15, 31, 1));
lookup54[167] = new SingleColorLookup(new SourceBlock(20, 0, 2), new SourceBlock(15, 31, 0));
lookup54[168] = new SingleColorLookup(new SourceBlock(20, 0, 3), new SourceBlock(15, 31, 1));
lookup54[169] = new SingleColorLookup(new SourceBlock(20, 0, 4), new SourceBlock(16, 30, 1));
lookup54[170] = new SingleColorLookup(new SourceBlock(21, 0, 3), new SourceBlock(16, 30, 0));
lookup54[171] = new SingleColorLookup(new SourceBlock(21, 0, 2), new SourceBlock(18, 27, 1));
lookup54[172] = new SingleColorLookup(new SourceBlock(21, 0, 1), new SourceBlock(18, 27, 0));
lookup54[173] = new SingleColorLookup(new SourceBlock(21, 0, 0), new SourceBlock(16, 31, 0));
lookup54[174] = new SingleColorLookup(new SourceBlock(21, 0, 1), new SourceBlock(17, 30, 1));
lookup54[175] = new SingleColorLookup(new SourceBlock(21, 0, 2), new SourceBlock(17, 30, 0));
lookup54[176] = new SingleColorLookup(new SourceBlock(21, 0, 3), new SourceBlock(20, 24, 0));
lookup54[177] = new SingleColorLookup(new SourceBlock(21, 0, 4), new SourceBlock(17, 31, 1));
lookup54[178] = new SingleColorLookup(new SourceBlock(22, 0, 3), new SourceBlock(17, 31, 0));
lookup54[179] = new SingleColorLookup(new SourceBlock(22, 0, 2), new SourceBlock(17, 31, 1));
lookup54[180] = new SingleColorLookup(new SourceBlock(22, 0, 1), new SourceBlock(18, 30, 1));
lookup54[181] = new SingleColorLookup(new SourceBlock(22, 0, 0), new SourceBlock(18, 30, 0));
lookup54[182] = new SingleColorLookup(new SourceBlock(22, 0, 1), new SourceBlock(18, 31, 1));
lookup54[183] = new SingleColorLookup(new SourceBlock(22, 0, 2), new SourceBlock(18, 31, 0));
lookup54[184] = new SingleColorLookup(new SourceBlock(22, 0, 3), new SourceBlock(20, 27, 0));
lookup54[185] = new SingleColorLookup(new SourceBlock(22, 0, 4), new SourceBlock(19, 30, 1));
lookup54[186] = new SingleColorLookup(new SourceBlock(23, 0, 3), new SourceBlock(19, 30, 0));
lookup54[187] = new SingleColorLookup(new SourceBlock(23, 0, 2), new SourceBlock(20, 28, 0));
lookup54[188] = new SingleColorLookup(new SourceBlock(23, 0, 1), new SourceBlock(19, 31, 1));
lookup54[189] = new SingleColorLookup(new SourceBlock(23, 0, 0), new SourceBlock(19, 31, 0));
lookup54[190] = new SingleColorLookup(new SourceBlock(23, 0, 1), new SourceBlock(19, 31, 1));
lookup54[191] = new SingleColorLookup(new SourceBlock(23, 0, 2), new SourceBlock(20, 30, 1));
lookup54[192] = new SingleColorLookup(new SourceBlock(23, 0, 3), new SourceBlock(20, 30, 0));
lookup54[193] = new SingleColorLookup(new SourceBlock(23, 0, 4), new SourceBlock(22, 27, 1));
lookup54[194] = new SingleColorLookup(new SourceBlock(24, 0, 4), new SourceBlock(22, 27, 0));
lookup54[195] = new SingleColorLookup(new SourceBlock(24, 0, 3), new SourceBlock(20, 31, 0));
lookup54[196] = new SingleColorLookup(new SourceBlock(24, 0, 2), new SourceBlock(21, 30, 1));
lookup54[197] = new SingleColorLookup(new SourceBlock(24, 0, 1), new SourceBlock(21, 30, 0));
lookup54[198] = new SingleColorLookup(new SourceBlock(24, 0, 0), new SourceBlock(24, 24, 0));
lookup54[199] = new SingleColorLookup(new SourceBlock(24, 0, 1), new SourceBlock(21, 31, 1));
lookup54[200] = new SingleColorLookup(new SourceBlock(24, 0, 2), new SourceBlock(21, 31, 0));
lookup54[201] = new SingleColorLookup(new SourceBlock(24, 0, 3), new SourceBlock(21, 31, 1));
lookup54[202] = new SingleColorLookup(new SourceBlock(24, 0, 4), new SourceBlock(22, 30, 1));
lookup54[203] = new SingleColorLookup(new SourceBlock(25, 0, 3), new SourceBlock(22, 30, 0));
lookup54[204] = new SingleColorLookup(new SourceBlock(25, 0, 2), new SourceBlock(22, 31, 1));
lookup54[205] = new SingleColorLookup(new SourceBlock(25, 0, 1), new SourceBlock(22, 31, 0));
lookup54[206] = new SingleColorLookup(new SourceBlock(25, 0, 0), new SourceBlock(24, 27, 0));
lookup54[207] = new SingleColorLookup(new SourceBlock(25, 0, 1), new SourceBlock(23, 30, 1));
lookup54[208] = new SingleColorLookup(new SourceBlock(25, 0, 2), new SourceBlock(23, 30, 0));
lookup54[209] = new SingleColorLookup(new SourceBlock(25, 0, 3), new SourceBlock(24, 28, 0));
lookup54[210] = new SingleColorLookup(new SourceBlock(25, 0, 4), new SourceBlock(23, 31, 1));
lookup54[211] = new SingleColorLookup(new SourceBlock(26, 0, 3), new SourceBlock(23, 31, 0));
lookup54[212] = new SingleColorLookup(new SourceBlock(26, 0, 2), new SourceBlock(23, 31, 1));
lookup54[213] = new SingleColorLookup(new SourceBlock(26, 0, 1), new SourceBlock(24, 30, 1));
lookup54[214] = new SingleColorLookup(new SourceBlock(26, 0, 0), new SourceBlock(24, 30, 0));
lookup54[215] = new SingleColorLookup(new SourceBlock(26, 0, 1), new SourceBlock(26, 27, 1));
lookup54[216] = new SingleColorLookup(new SourceBlock(26, 0, 2), new SourceBlock(26, 27, 0));
lookup54[217] = new SingleColorLookup(new SourceBlock(26, 0, 3), new SourceBlock(24, 31, 0));
lookup54[218] = new SingleColorLookup(new SourceBlock(26, 0, 4), new SourceBlock(25, 30, 1));
lookup54[219] = new SingleColorLookup(new SourceBlock(27, 0, 3), new SourceBlock(25, 30, 0));
lookup54[220] = new SingleColorLookup(new SourceBlock(27, 0, 2), new SourceBlock(28, 24, 0));
lookup54[221] = new SingleColorLookup(new SourceBlock(27, 0, 1), new SourceBlock(25, 31, 1));
lookup54[222] = new SingleColorLookup(new SourceBlock(27, 0, 0), new SourceBlock(25, 31, 0));
lookup54[223] = new SingleColorLookup(new SourceBlock(27, 0, 1), new SourceBlock(25, 31, 1));
lookup54[224] = new SingleColorLookup(new SourceBlock(27, 0, 2), new SourceBlock(26, 30, 1));
lookup54[225] = new SingleColorLookup(new SourceBlock(27, 0, 3), new SourceBlock(26, 30, 0));
lookup54[226] = new SingleColorLookup(new SourceBlock(27, 0, 4), new SourceBlock(26, 31, 1));
lookup54[227] = new SingleColorLookup(new SourceBlock(28, 0, 4), new SourceBlock(26, 31, 0));
lookup54[228] = new SingleColorLookup(new SourceBlock(28, 0, 3), new SourceBlock(28, 27, 0));
lookup54[229] = new SingleColorLookup(new SourceBlock(28, 0, 2), new SourceBlock(27, 30, 1));
lookup54[230] = new SingleColorLookup(new SourceBlock(28, 0, 1), new SourceBlock(27, 30, 0));
lookup54[231] = new SingleColorLookup(new SourceBlock(28, 0, 0), new SourceBlock(28, 28, 0));
lookup54[232] = new SingleColorLookup(new SourceBlock(28, 0, 1), new SourceBlock(27, 31, 1));
lookup54[233] = new SingleColorLookup(new SourceBlock(28, 0, 2), new SourceBlock(27, 31, 0));
lookup54[234] = new SingleColorLookup(new SourceBlock(28, 0, 3), new SourceBlock(27, 31, 1));
lookup54[235] = new SingleColorLookup(new SourceBlock(28, 0, 4), new SourceBlock(28, 30, 1));
lookup54[236] = new SingleColorLookup(new SourceBlock(29, 0, 3), new SourceBlock(28, 30, 0));
lookup54[237] = new SingleColorLookup(new SourceBlock(29, 0, 2), new SourceBlock(30, 27, 1));
lookup54[238] = new SingleColorLookup(new SourceBlock(29, 0, 1), new SourceBlock(30, 27, 0));
lookup54[239] = new SingleColorLookup(new SourceBlock(29, 0, 0), new SourceBlock(28, 31, 0));
lookup54[240] = new SingleColorLookup(new SourceBlock(29, 0, 1), new SourceBlock(29, 30, 1));
lookup54[241] = new SingleColorLookup(new SourceBlock(29, 0, 2), new SourceBlock(29, 30, 0));
lookup54[242] = new SingleColorLookup(new SourceBlock(29, 0, 3), new SourceBlock(29, 30, 1));
lookup54[243] = new SingleColorLookup(new SourceBlock(29, 0, 4), new SourceBlock(29, 31, 1));
lookup54[244] = new SingleColorLookup(new SourceBlock(30, 0, 3), new SourceBlock(29, 31, 0));
lookup54[245] = new SingleColorLookup(new SourceBlock(30, 0, 2), new SourceBlock(29, 31, 1));
lookup54[246] = new SingleColorLookup(new SourceBlock(30, 0, 1), new SourceBlock(30, 30, 1));
lookup54[247] = new SingleColorLookup(new SourceBlock(30, 0, 0), new SourceBlock(30, 30, 0));
lookup54[248] = new SingleColorLookup(new SourceBlock(30, 0, 1), new SourceBlock(30, 31, 1));
lookup54[249] = new SingleColorLookup(new SourceBlock(30, 0, 2), new SourceBlock(30, 31, 0));
lookup54[250] = new SingleColorLookup(new SourceBlock(30, 0, 3), new SourceBlock(30, 31, 1));
lookup54[251] = new SingleColorLookup(new SourceBlock(30, 0, 4), new SourceBlock(31, 30, 1));
lookup54[252] = new SingleColorLookup(new SourceBlock(31, 0, 3), new SourceBlock(31, 30, 0));
lookup54[253] = new SingleColorLookup(new SourceBlock(31, 0, 2), new SourceBlock(31, 30, 1));
lookup54[254] = new SingleColorLookup(new SourceBlock(31, 0, 1), new SourceBlock(31, 31, 1));
lookup54[255] = new SingleColorLookup(new SourceBlock(31, 0, 0), new SourceBlock(31, 31, 0));
lookup64[0] = new SingleColorLookup(new SourceBlock(0, 0, 0), new SourceBlock(0, 0, 0));
lookup64[1] = new SingleColorLookup(new SourceBlock(0, 0, 1), new SourceBlock(0, 1, 0));
lookup64[2] = new SingleColorLookup(new SourceBlock(0, 0, 2), new SourceBlock(0, 2, 0));
lookup64[3] = new SingleColorLookup(new SourceBlock(1, 0, 1), new SourceBlock(0, 3, 1));
lookup64[4] = new SingleColorLookup(new SourceBlock(1, 0, 0), new SourceBlock(0, 3, 0));
lookup64[5] = new SingleColorLookup(new SourceBlock(1, 0, 1), new SourceBlock(0, 4, 0));
lookup64[6] = new SingleColorLookup(new SourceBlock(1, 0, 2), new SourceBlock(0, 5, 0));
lookup64[7] = new SingleColorLookup(new SourceBlock(2, 0, 1), new SourceBlock(0, 6, 1));
lookup64[8] = new SingleColorLookup(new SourceBlock(2, 0, 0), new SourceBlock(0, 6, 0));
lookup64[9] = new SingleColorLookup(new SourceBlock(2, 0, 1), new SourceBlock(0, 7, 0));
lookup64[10] = new SingleColorLookup(new SourceBlock(2, 0, 2), new SourceBlock(0, 8, 0));
lookup64[11] = new SingleColorLookup(new SourceBlock(3, 0, 1), new SourceBlock(0, 9, 1));
lookup64[12] = new SingleColorLookup(new SourceBlock(3, 0, 0), new SourceBlock(0, 9, 0));
lookup64[13] = new SingleColorLookup(new SourceBlock(3, 0, 1), new SourceBlock(0, 10, 0));
lookup64[14] = new SingleColorLookup(new SourceBlock(3, 0, 2), new SourceBlock(0, 11, 0));
lookup64[15] = new SingleColorLookup(new SourceBlock(4, 0, 1), new SourceBlock(0, 12, 1));
lookup64[16] = new SingleColorLookup(new SourceBlock(4, 0, 0), new SourceBlock(0, 12, 0));
lookup64[17] = new SingleColorLookup(new SourceBlock(4, 0, 1), new SourceBlock(0, 13, 0));
lookup64[18] = new SingleColorLookup(new SourceBlock(4, 0, 2), new SourceBlock(0, 14, 0));
lookup64[19] = new SingleColorLookup(new SourceBlock(5, 0, 1), new SourceBlock(0, 15, 1));
lookup64[20] = new SingleColorLookup(new SourceBlock(5, 0, 0), new SourceBlock(0, 15, 0));
lookup64[21] = new SingleColorLookup(new SourceBlock(5, 0, 1), new SourceBlock(0, 16, 0));
lookup64[22] = new SingleColorLookup(new SourceBlock(5, 0, 2), new SourceBlock(1, 15, 0));
lookup64[23] = new SingleColorLookup(new SourceBlock(6, 0, 1), new SourceBlock(0, 17, 0));
lookup64[24] = new SingleColorLookup(new SourceBlock(6, 0, 0), new SourceBlock(0, 18, 0));
lookup64[25] = new SingleColorLookup(new SourceBlock(6, 0, 1), new SourceBlock(0, 19, 0));
lookup64[26] = new SingleColorLookup(new SourceBlock(6, 0, 2), new SourceBlock(3, 14, 0));
lookup64[27] = new SingleColorLookup(new SourceBlock(7, 0, 1), new SourceBlock(0, 20, 0));
lookup64[28] = new SingleColorLookup(new SourceBlock(7, 0, 0), new SourceBlock(0, 21, 0));
lookup64[29] = new SingleColorLookup(new SourceBlock(7, 0, 1), new SourceBlock(0, 22, 0));
lookup64[30] = new SingleColorLookup(new SourceBlock(7, 0, 2), new SourceBlock(4, 15, 0));
lookup64[31] = new SingleColorLookup(new SourceBlock(8, 0, 1), new SourceBlock(0, 23, 0));
lookup64[32] = new SingleColorLookup(new SourceBlock(8, 0, 0), new SourceBlock(0, 24, 0));
lookup64[33] = new SingleColorLookup(new SourceBlock(8, 0, 1), new SourceBlock(0, 25, 0));
lookup64[34] = new SingleColorLookup(new SourceBlock(8, 0, 2), new SourceBlock(6, 14, 0));
lookup64[35] = new SingleColorLookup(new SourceBlock(9, 0, 1), new SourceBlock(0, 26, 0));
lookup64[36] = new SingleColorLookup(new SourceBlock(9, 0, 0), new SourceBlock(0, 27, 0));
lookup64[37] = new SingleColorLookup(new SourceBlock(9, 0, 1), new SourceBlock(0, 28, 0));
lookup64[38] = new SingleColorLookup(new SourceBlock(9, 0, 2), new SourceBlock(7, 15, 0));
lookup64[39] = new SingleColorLookup(new SourceBlock(10, 0, 1), new SourceBlock(0, 29, 0));
lookup64[40] = new SingleColorLookup(new SourceBlock(10, 0, 0), new SourceBlock(0, 30, 0));
lookup64[41] = new SingleColorLookup(new SourceBlock(10, 0, 1), new SourceBlock(0, 31, 0));
lookup64[42] = new SingleColorLookup(new SourceBlock(10, 0, 2), new SourceBlock(9, 14, 0));
lookup64[43] = new SingleColorLookup(new SourceBlock(11, 0, 1), new SourceBlock(0, 32, 0));
lookup64[44] = new SingleColorLookup(new SourceBlock(11, 0, 0), new SourceBlock(0, 33, 0));
lookup64[45] = new SingleColorLookup(new SourceBlock(11, 0, 1), new SourceBlock(2, 30, 0));
lookup64[46] = new SingleColorLookup(new SourceBlock(11, 0, 2), new SourceBlock(0, 34, 0));
lookup64[47] = new SingleColorLookup(new SourceBlock(12, 0, 1), new SourceBlock(0, 35, 0));
lookup64[48] = new SingleColorLookup(new SourceBlock(12, 0, 0), new SourceBlock(0, 36, 0));
lookup64[49] = new SingleColorLookup(new SourceBlock(12, 0, 1), new SourceBlock(3, 31, 0));
lookup64[50] = new SingleColorLookup(new SourceBlock(12, 0, 2), new SourceBlock(0, 37, 0));
lookup64[51] = new SingleColorLookup(new SourceBlock(13, 0, 1), new SourceBlock(0, 38, 0));
lookup64[52] = new SingleColorLookup(new SourceBlock(13, 0, 0), new SourceBlock(0, 39, 0));
lookup64[53] = new SingleColorLookup(new SourceBlock(13, 0, 1), new SourceBlock(5, 30, 0));
lookup64[54] = new SingleColorLookup(new SourceBlock(13, 0, 2), new SourceBlock(0, 40, 0));
lookup64[55] = new SingleColorLookup(new SourceBlock(14, 0, 1), new SourceBlock(0, 41, 0));
lookup64[56] = new SingleColorLookup(new SourceBlock(14, 0, 0), new SourceBlock(0, 42, 0));
lookup64[57] = new SingleColorLookup(new SourceBlock(14, 0, 1), new SourceBlock(6, 31, 0));
lookup64[58] = new SingleColorLookup(new SourceBlock(14, 0, 2), new SourceBlock(0, 43, 0));
lookup64[59] = new SingleColorLookup(new SourceBlock(15, 0, 1), new SourceBlock(0, 44, 0));
lookup64[60] = new SingleColorLookup(new SourceBlock(15, 0, 0), new SourceBlock(0, 45, 0));
lookup64[61] = new SingleColorLookup(new SourceBlock(15, 0, 1), new SourceBlock(8, 30, 0));
lookup64[62] = new SingleColorLookup(new SourceBlock(15, 0, 2), new SourceBlock(0, 46, 0));
lookup64[63] = new SingleColorLookup(new SourceBlock(16, 0, 2), new SourceBlock(0, 47, 0));
lookup64[64] = new SingleColorLookup(new SourceBlock(16, 0, 1), new SourceBlock(1, 46, 0));
lookup64[65] = new SingleColorLookup(new SourceBlock(16, 0, 0), new SourceBlock(0, 48, 0));
lookup64[66] = new SingleColorLookup(new SourceBlock(16, 0, 1), new SourceBlock(0, 49, 0));
lookup64[67] = new SingleColorLookup(new SourceBlock(16, 0, 2), new SourceBlock(0, 50, 0));
lookup64[68] = new SingleColorLookup(new SourceBlock(17, 0, 1), new SourceBlock(2, 47, 0));
lookup64[69] = new SingleColorLookup(new SourceBlock(17, 0, 0), new SourceBlock(0, 51, 0));
lookup64[70] = new SingleColorLookup(new SourceBlock(17, 0, 1), new SourceBlock(0, 52, 0));
lookup64[71] = new SingleColorLookup(new SourceBlock(17, 0, 2), new SourceBlock(0, 53, 0));
lookup64[72] = new SingleColorLookup(new SourceBlock(18, 0, 1), new SourceBlock(4, 46, 0));
lookup64[73] = new SingleColorLookup(new SourceBlock(18, 0, 0), new SourceBlock(0, 54, 0));
lookup64[74] = new SingleColorLookup(new SourceBlock(18, 0, 1), new SourceBlock(0, 55, 0));
lookup64[75] = new SingleColorLookup(new SourceBlock(18, 0, 2), new SourceBlock(0, 56, 0));
lookup64[76] = new SingleColorLookup(new SourceBlock(19, 0, 1), new SourceBlock(5, 47, 0));
lookup64[77] = new SingleColorLookup(new SourceBlock(19, 0, 0), new SourceBlock(0, 57, 0));
lookup64[78] = new SingleColorLookup(new SourceBlock(19, 0, 1), new SourceBlock(0, 58, 0));
lookup64[79] = new SingleColorLookup(new SourceBlock(19, 0, 2), new SourceBlock(0, 59, 0));
lookup64[80] = new SingleColorLookup(new SourceBlock(20, 0, 1), new SourceBlock(7, 46, 0));
lookup64[81] = new SingleColorLookup(new SourceBlock(20, 0, 0), new SourceBlock(0, 60, 0));
lookup64[82] = new SingleColorLookup(new SourceBlock(20, 0, 1), new SourceBlock(0, 61, 0));
lookup64[83] = new SingleColorLookup(new SourceBlock(20, 0, 2), new SourceBlock(0, 62, 0));
lookup64[84] = new SingleColorLookup(new SourceBlock(21, 0, 1), new SourceBlock(8, 47, 0));
lookup64[85] = new SingleColorLookup(new SourceBlock(21, 0, 0), new SourceBlock(0, 63, 0));
lookup64[86] = new SingleColorLookup(new SourceBlock(21, 0, 1), new SourceBlock(1, 62, 0));
lookup64[87] = new SingleColorLookup(new SourceBlock(21, 0, 2), new SourceBlock(1, 63, 0));
lookup64[88] = new SingleColorLookup(new SourceBlock(22, 0, 1), new SourceBlock(10, 46, 0));
lookup64[89] = new SingleColorLookup(new SourceBlock(22, 0, 0), new SourceBlock(2, 62, 0));
lookup64[90] = new SingleColorLookup(new SourceBlock(22, 0, 1), new SourceBlock(2, 63, 0));
lookup64[91] = new SingleColorLookup(new SourceBlock(22, 0, 2), new SourceBlock(3, 62, 0));
lookup64[92] = new SingleColorLookup(new SourceBlock(23, 0, 1), new SourceBlock(11, 47, 0));
lookup64[93] = new SingleColorLookup(new SourceBlock(23, 0, 0), new SourceBlock(3, 63, 0));
lookup64[94] = new SingleColorLookup(new SourceBlock(23, 0, 1), new SourceBlock(4, 62, 0));
lookup64[95] = new SingleColorLookup(new SourceBlock(23, 0, 2), new SourceBlock(4, 63, 0));
lookup64[96] = new SingleColorLookup(new SourceBlock(24, 0, 1), new SourceBlock(13, 46, 0));
lookup64[97] = new SingleColorLookup(new SourceBlock(24, 0, 0), new SourceBlock(5, 62, 0));
lookup64[98] = new SingleColorLookup(new SourceBlock(24, 0, 1), new SourceBlock(5, 63, 0));
lookup64[99] = new SingleColorLookup(new SourceBlock(24, 0, 2), new SourceBlock(6, 62, 0));
lookup64[100] = new SingleColorLookup(new SourceBlock(25, 0, 1), new SourceBlock(14, 47, 0));
lookup64[101] = new SingleColorLookup(new SourceBlock(25, 0, 0), new SourceBlock(6, 63, 0));
lookup64[102] = new SingleColorLookup(new SourceBlock(25, 0, 1), new SourceBlock(7, 62, 0));
lookup64[103] = new SingleColorLookup(new SourceBlock(25, 0, 2), new SourceBlock(7, 63, 0));
lookup64[104] = new SingleColorLookup(new SourceBlock(26, 0, 1), new SourceBlock(16, 45, 0));
lookup64[105] = new SingleColorLookup(new SourceBlock(26, 0, 0), new SourceBlock(8, 62, 0));
lookup64[106] = new SingleColorLookup(new SourceBlock(26, 0, 1), new SourceBlock(8, 63, 0));
lookup64[107] = new SingleColorLookup(new SourceBlock(26, 0, 2), new SourceBlock(9, 62, 0));
lookup64[108] = new SingleColorLookup(new SourceBlock(27, 0, 1), new SourceBlock(16, 48, 0));
lookup64[109] = new SingleColorLookup(new SourceBlock(27, 0, 0), new SourceBlock(9, 63, 0));
lookup64[110] = new SingleColorLookup(new SourceBlock(27, 0, 1), new SourceBlock(10, 62, 0));
lookup64[111] = new SingleColorLookup(new SourceBlock(27, 0, 2), new SourceBlock(10, 63, 0));
lookup64[112] = new SingleColorLookup(new SourceBlock(28, 0, 1), new SourceBlock(16, 51, 0));
lookup64[113] = new SingleColorLookup(new SourceBlock(28, 0, 0), new SourceBlock(11, 62, 0));
lookup64[114] = new SingleColorLookup(new SourceBlock(28, 0, 1), new SourceBlock(11, 63, 0));
lookup64[115] = new SingleColorLookup(new SourceBlock(28, 0, 2), new SourceBlock(12, 62, 0));
lookup64[116] = new SingleColorLookup(new SourceBlock(29, 0, 1), new SourceBlock(16, 54, 0));
lookup64[117] = new SingleColorLookup(new SourceBlock(29, 0, 0), new SourceBlock(12, 63, 0));
lookup64[118] = new SingleColorLookup(new SourceBlock(29, 0, 1), new SourceBlock(13, 62, 0));
lookup64[119] = new SingleColorLookup(new SourceBlock(29, 0, 2), new SourceBlock(13, 63, 0));
lookup64[120] = new SingleColorLookup(new SourceBlock(30, 0, 1), new SourceBlock(16, 57, 0));
lookup64[121] = new SingleColorLookup(new SourceBlock(30, 0, 0), new SourceBlock(14, 62, 0));
lookup64[122] = new SingleColorLookup(new SourceBlock(30, 0, 1), new SourceBlock(14, 63, 0));
lookup64[123] = new SingleColorLookup(new SourceBlock(30, 0, 2), new SourceBlock(15, 62, 0));
lookup64[124] = new SingleColorLookup(new SourceBlock(31, 0, 1), new SourceBlock(16, 60, 0));
lookup64[125] = new SingleColorLookup(new SourceBlock(31, 0, 0), new SourceBlock(15, 63, 0));
lookup64[126] = new SingleColorLookup(new SourceBlock(31, 0, 1), new SourceBlock(24, 46, 0));
lookup64[127] = new SingleColorLookup(new SourceBlock(31, 0, 2), new SourceBlock(16, 62, 0));
lookup64[128] = new SingleColorLookup(new SourceBlock(32, 0, 2), new SourceBlock(16, 63, 0));
lookup64[129] = new SingleColorLookup(new SourceBlock(32, 0, 1), new SourceBlock(17, 62, 0));
lookup64[130] = new SingleColorLookup(new SourceBlock(32, 0, 0), new SourceBlock(25, 47, 0));
lookup64[131] = new SingleColorLookup(new SourceBlock(32, 0, 1), new SourceBlock(17, 63, 0));
lookup64[132] = new SingleColorLookup(new SourceBlock(32, 0, 2), new SourceBlock(18, 62, 0));
lookup64[133] = new SingleColorLookup(new SourceBlock(33, 0, 1), new SourceBlock(18, 63, 0));
lookup64[134] = new SingleColorLookup(new SourceBlock(33, 0, 0), new SourceBlock(27, 46, 0));
lookup64[135] = new SingleColorLookup(new SourceBlock(33, 0, 1), new SourceBlock(19, 62, 0));
lookup64[136] = new SingleColorLookup(new SourceBlock(33, 0, 2), new SourceBlock(19, 63, 0));
lookup64[137] = new SingleColorLookup(new SourceBlock(34, 0, 1), new SourceBlock(20, 62, 0));
lookup64[138] = new SingleColorLookup(new SourceBlock(34, 0, 0), new SourceBlock(28, 47, 0));
lookup64[139] = new SingleColorLookup(new SourceBlock(34, 0, 1), new SourceBlock(20, 63, 0));
lookup64[140] = new SingleColorLookup(new SourceBlock(34, 0, 2), new SourceBlock(21, 62, 0));
lookup64[141] = new SingleColorLookup(new SourceBlock(35, 0, 1), new SourceBlock(21, 63, 0));
lookup64[142] = new SingleColorLookup(new SourceBlock(35, 0, 0), new SourceBlock(30, 46, 0));
lookup64[143] = new SingleColorLookup(new SourceBlock(35, 0, 1), new SourceBlock(22, 62, 0));
lookup64[144] = new SingleColorLookup(new SourceBlock(35, 0, 2), new SourceBlock(22, 63, 0));
lookup64[145] = new SingleColorLookup(new SourceBlock(36, 0, 1), new SourceBlock(23, 62, 0));
lookup64[146] = new SingleColorLookup(new SourceBlock(36, 0, 0), new SourceBlock(31, 47, 0));
lookup64[147] = new SingleColorLookup(new SourceBlock(36, 0, 1), new SourceBlock(23, 63, 0));
lookup64[148] = new SingleColorLookup(new SourceBlock(36, 0, 2), new SourceBlock(24, 62, 0));
lookup64[149] = new SingleColorLookup(new SourceBlock(37, 0, 1), new SourceBlock(24, 63, 0));
lookup64[150] = new SingleColorLookup(new SourceBlock(37, 0, 0), new SourceBlock(32, 47, 0));
lookup64[151] = new SingleColorLookup(new SourceBlock(37, 0, 1), new SourceBlock(25, 62, 0));
lookup64[152] = new SingleColorLookup(new SourceBlock(37, 0, 2), new SourceBlock(25, 63, 0));
lookup64[153] = new SingleColorLookup(new SourceBlock(38, 0, 1), new SourceBlock(26, 62, 0));
lookup64[154] = new SingleColorLookup(new SourceBlock(38, 0, 0), new SourceBlock(32, 50, 0));
lookup64[155] = new SingleColorLookup(new SourceBlock(38, 0, 1), new SourceBlock(26, 63, 0));
lookup64[156] = new SingleColorLookup(new SourceBlock(38, 0, 2), new SourceBlock(27, 62, 0));
lookup64[157] = new SingleColorLookup(new SourceBlock(39, 0, 1), new SourceBlock(27, 63, 0));
lookup64[158] = new SingleColorLookup(new SourceBlock(39, 0, 0), new SourceBlock(32, 53, 0));
lookup64[159] = new SingleColorLookup(new SourceBlock(39, 0, 1), new SourceBlock(28, 62, 0));
lookup64[160] = new SingleColorLookup(new SourceBlock(39, 0, 2), new SourceBlock(28, 63, 0));
lookup64[161] = new SingleColorLookup(new SourceBlock(40, 0, 1), new SourceBlock(29, 62, 0));
lookup64[162] = new SingleColorLookup(new SourceBlock(40, 0, 0), new SourceBlock(32, 56, 0));
lookup64[163] = new SingleColorLookup(new SourceBlock(40, 0, 1), new SourceBlock(29, 63, 0));
lookup64[164] = new SingleColorLookup(new SourceBlock(40, 0, 2), new SourceBlock(30, 62, 0));
lookup64[165] = new SingleColorLookup(new SourceBlock(41, 0, 1), new SourceBlock(30, 63, 0));
lookup64[166] = new SingleColorLookup(new SourceBlock(41, 0, 0), new SourceBlock(32, 59, 0));
lookup64[167] = new SingleColorLookup(new SourceBlock(41, 0, 1), new SourceBlock(31, 62, 0));
lookup64[168] = new SingleColorLookup(new SourceBlock(41, 0, 2), new SourceBlock(31, 63, 0));
lookup64[169] = new SingleColorLookup(new SourceBlock(42, 0, 1), new SourceBlock(32, 61, 0));
lookup64[170] = new SingleColorLookup(new SourceBlock(42, 0, 0), new SourceBlock(32, 62, 0));
lookup64[171] = new SingleColorLookup(new SourceBlock(42, 0, 1), new SourceBlock(32, 63, 0));
lookup64[172] = new SingleColorLookup(new SourceBlock(42, 0, 2), new SourceBlock(41, 46, 0));
lookup64[173] = new SingleColorLookup(new SourceBlock(43, 0, 1), new SourceBlock(33, 62, 0));
lookup64[174] = new SingleColorLookup(new SourceBlock(43, 0, 0), new SourceBlock(33, 63, 0));
lookup64[175] = new SingleColorLookup(new SourceBlock(43, 0, 1), new SourceBlock(34, 62, 0));
lookup64[176] = new SingleColorLookup(new SourceBlock(43, 0, 2), new SourceBlock(42, 47, 0));
lookup64[177] = new SingleColorLookup(new SourceBlock(44, 0, 1), new SourceBlock(34, 63, 0));
lookup64[178] = new SingleColorLookup(new SourceBlock(44, 0, 0), new SourceBlock(35, 62, 0));
lookup64[179] = new SingleColorLookup(new SourceBlock(44, 0, 1), new SourceBlock(35, 63, 0));
lookup64[180] = new SingleColorLookup(new SourceBlock(44, 0, 2), new SourceBlock(44, 46, 0));
lookup64[181] = new SingleColorLookup(new SourceBlock(45, 0, 1), new SourceBlock(36, 62, 0));
lookup64[182] = new SingleColorLookup(new SourceBlock(45, 0, 0), new SourceBlock(36, 63, 0));
lookup64[183] = new SingleColorLookup(new SourceBlock(45, 0, 1), new SourceBlock(37, 62, 0));
lookup64[184] = new SingleColorLookup(new SourceBlock(45, 0, 2), new SourceBlock(45, 47, 0));
lookup64[185] = new SingleColorLookup(new SourceBlock(46, 0, 1), new SourceBlock(37, 63, 0));
lookup64[186] = new SingleColorLookup(new SourceBlock(46, 0, 0), new SourceBlock(38, 62, 0));
lookup64[187] = new SingleColorLookup(new SourceBlock(46, 0, 1), new SourceBlock(38, 63, 0));
lookup64[188] = new SingleColorLookup(new SourceBlock(46, 0, 2), new SourceBlock(47, 46, 0));
lookup64[189] = new SingleColorLookup(new SourceBlock(47, 0, 1), new SourceBlock(39, 62, 0));
lookup64[190] = new SingleColorLookup(new SourceBlock(47, 0, 0), new SourceBlock(39, 63, 0));
lookup64[191] = new SingleColorLookup(new SourceBlock(47, 0, 1), new SourceBlock(40, 62, 0));
lookup64[192] = new SingleColorLookup(new SourceBlock(47, 0, 2), new SourceBlock(48, 46, 0));
lookup64[193] = new SingleColorLookup(new SourceBlock(48, 0, 2), new SourceBlock(40, 63, 0));
lookup64[194] = new SingleColorLookup(new SourceBlock(48, 0, 1), new SourceBlock(41, 62, 0));
lookup64[195] = new SingleColorLookup(new SourceBlock(48, 0, 0), new SourceBlock(41, 63, 0));
lookup64[196] = new SingleColorLookup(new SourceBlock(48, 0, 1), new SourceBlock(48, 49, 0));
lookup64[197] = new SingleColorLookup(new SourceBlock(48, 0, 2), new SourceBlock(42, 62, 0));
lookup64[198] = new SingleColorLookup(new SourceBlock(49, 0, 1), new SourceBlock(42, 63, 0));
lookup64[199] = new SingleColorLookup(new SourceBlock(49, 0, 0), new SourceBlock(43, 62, 0));
lookup64[200] = new SingleColorLookup(new SourceBlock(49, 0, 1), new SourceBlock(48, 52, 0));
lookup64[201] = new SingleColorLookup(new SourceBlock(49, 0, 2), new SourceBlock(43, 63, 0));
lookup64[202] = new SingleColorLookup(new SourceBlock(50, 0, 1), new SourceBlock(44, 62, 0));
lookup64[203] = new SingleColorLookup(new SourceBlock(50, 0, 0), new SourceBlock(44, 63, 0));
lookup64[204] = new SingleColorLookup(new SourceBlock(50, 0, 1), new SourceBlock(48, 55, 0));
lookup64[205] = new SingleColorLookup(new SourceBlock(50, 0, 2), new SourceBlock(45, 62, 0));
lookup64[206] = new SingleColorLookup(new SourceBlock(51, 0, 1), new SourceBlock(45, 63, 0));
lookup64[207] = new SingleColorLookup(new SourceBlock(51, 0, 0), new SourceBlock(46, 62, 0));
lookup64[208] = new SingleColorLookup(new SourceBlock(51, 0, 1), new SourceBlock(48, 58, 0));
lookup64[209] = new SingleColorLookup(new SourceBlock(51, 0, 2), new SourceBlock(46, 63, 0));
lookup64[210] = new SingleColorLookup(new SourceBlock(52, 0, 1), new SourceBlock(47, 62, 0));
lookup64[211] = new SingleColorLookup(new SourceBlock(52, 0, 0), new SourceBlock(47, 63, 0));
lookup64[212] = new SingleColorLookup(new SourceBlock(52, 0, 1), new SourceBlock(48, 61, 0));
lookup64[213] = new SingleColorLookup(new SourceBlock(52, 0, 2), new SourceBlock(48, 62, 0));
lookup64[214] = new SingleColorLookup(new SourceBlock(53, 0, 1), new SourceBlock(56, 47, 0));
lookup64[215] = new SingleColorLookup(new SourceBlock(53, 0, 0), new SourceBlock(48, 63, 0));
lookup64[216] = new SingleColorLookup(new SourceBlock(53, 0, 1), new SourceBlock(49, 62, 0));
lookup64[217] = new SingleColorLookup(new SourceBlock(53, 0, 2), new SourceBlock(49, 63, 0));
lookup64[218] = new SingleColorLookup(new SourceBlock(54, 0, 1), new SourceBlock(58, 46, 0));
lookup64[219] = new SingleColorLookup(new SourceBlock(54, 0, 0), new SourceBlock(50, 62, 0));
lookup64[220] = new SingleColorLookup(new SourceBlock(54, 0, 1), new SourceBlock(50, 63, 0));
lookup64[221] = new SingleColorLookup(new SourceBlock(54, 0, 2), new SourceBlock(51, 62, 0));
lookup64[222] = new SingleColorLookup(new SourceBlock(55, 0, 1), new SourceBlock(59, 47, 0));
lookup64[223] = new SingleColorLookup(new SourceBlock(55, 0, 0), new SourceBlock(51, 63, 0));
lookup64[224] = new SingleColorLookup(new SourceBlock(55, 0, 1), new SourceBlock(52, 62, 0));
lookup64[225] = new SingleColorLookup(new SourceBlock(55, 0, 2), new SourceBlock(52, 63, 0));
lookup64[226] = new SingleColorLookup(new SourceBlock(56, 0, 1), new SourceBlock(61, 46, 0));
lookup64[227] = new SingleColorLookup(new SourceBlock(56, 0, 0), new SourceBlock(53, 62, 0));
lookup64[228] = new SingleColorLookup(new SourceBlock(56, 0, 1), new SourceBlock(53, 63, 0));
lookup64[229] = new SingleColorLookup(new SourceBlock(56, 0, 2), new SourceBlock(54, 62, 0));
lookup64[230] = new SingleColorLookup(new SourceBlock(57, 0, 1), new SourceBlock(62, 47, 0));
lookup64[231] = new SingleColorLookup(new SourceBlock(57, 0, 0), new SourceBlock(54, 63, 0));
lookup64[232] = new SingleColorLookup(new SourceBlock(57, 0, 1), new SourceBlock(55, 62, 0));
lookup64[233] = new SingleColorLookup(new SourceBlock(57, 0, 2), new SourceBlock(55, 63, 0));
lookup64[234] = new SingleColorLookup(new SourceBlock(58, 0, 1), new SourceBlock(56, 62, 1));
lookup64[235] = new SingleColorLookup(new SourceBlock(58, 0, 0), new SourceBlock(56, 62, 0));
lookup64[236] = new SingleColorLookup(new SourceBlock(58, 0, 1), new SourceBlock(56, 63, 0));
lookup64[237] = new SingleColorLookup(new SourceBlock(58, 0, 2), new SourceBlock(57, 62, 0));
lookup64[238] = new SingleColorLookup(new SourceBlock(59, 0, 1), new SourceBlock(57, 63, 1));
lookup64[239] = new SingleColorLookup(new SourceBlock(59, 0, 0), new SourceBlock(57, 63, 0));
lookup64[240] = new SingleColorLookup(new SourceBlock(59, 0, 1), new SourceBlock(58, 62, 0));
lookup64[241] = new SingleColorLookup(new SourceBlock(59, 0, 2), new SourceBlock(58, 63, 0));
lookup64[242] = new SingleColorLookup(new SourceBlock(60, 0, 1), new SourceBlock(59, 62, 1));
lookup64[243] = new SingleColorLookup(new SourceBlock(60, 0, 0), new SourceBlock(59, 62, 0));
lookup64[244] = new SingleColorLookup(new SourceBlock(60, 0, 1), new SourceBlock(59, 63, 0));
lookup64[245] = new SingleColorLookup(new SourceBlock(60, 0, 2), new SourceBlock(60, 62, 0));
lookup64[246] = new SingleColorLookup(new SourceBlock(61, 0, 1), new SourceBlock(60, 63, 1));
lookup64[247] = new SingleColorLookup(new SourceBlock(61, 0, 0), new SourceBlock(60, 63, 0));
lookup64[248] = new SingleColorLookup(new SourceBlock(61, 0, 1), new SourceBlock(61, 62, 0));
lookup64[249] = new SingleColorLookup(new SourceBlock(61, 0, 2), new SourceBlock(61, 63, 0));
lookup64[250] = new SingleColorLookup(new SourceBlock(62, 0, 1), new SourceBlock(62, 62, 1));
lookup64[251] = new SingleColorLookup(new SourceBlock(62, 0, 0), new SourceBlock(62, 62, 0));
lookup64[252] = new SingleColorLookup(new SourceBlock(62, 0, 1), new SourceBlock(62, 63, 0));
lookup64[253] = new SingleColorLookup(new SourceBlock(62, 0, 2), new SourceBlock(63, 62, 0));
lookup64[254] = new SingleColorLookup(new SourceBlock(63, 0, 1), new SourceBlock(63, 63, 1));
lookup64[255] = new SingleColorLookup(new SourceBlock(63, 0, 0), new SourceBlock(63, 63, 0));
}
}
public static class Vec3
{
float vx, vy, vz;
public static Vec3 neg(Vec3 v)
{
return new Vec3(-v.vx, -v.vy, -v.vz);
}
public static Vec3 add(Vec3 v1, Vec3 v2)
{
return new Vec3(v1.vx + v2.vx, v1.vy + v2.vy, v1.vz + v2.vz);
}
public static Vec3 sub(Vec3 v1, Vec3 v2)
{
return new Vec3(v1.vx - v2.vx, v1.vy - v2.vy, v1.vz - v2.vz);
}
public static Vec3 mul(Vec3 v1, Vec3 v2)
{
return new Vec3(v1.vx * v2.vx, v1.vy * v2.vy, v1.vz * v2.vz);
}
public static Vec3 mul(Vec3 v, float s)
{
return new Vec3(v.vx * s, v.vy * s, v.vz * s);
}
public static Vec3 div(Vec3 v1, Vec3 v2)
{
return new Vec3(v1.vx / v2.vx, v1.vy / v2.vy, v1.vz / v2.vz);
}
public static Vec3 div(Vec3 v, float s)
{
float t = 1.0f / s;
return new Vec3(v.vx * t, v.vy * t, v.vz * t);
}
public static float dot(Vec3 v1, Vec3 v2)
{
return v1.vx*v2.vx + v1.vy*v2.vy + v1.vz*v2.vz;
}
public static Vec3 min(Vec3 v1, Vec3 v2)
{
v1.fixNaN(); v2.fixNaN();
return new Vec3(Math.min(v1.vx, v2.vx), Math.min(v1.vy, v2.vy), Math.min(v1.vz, v2.vz));
}
public static Vec3 max(Vec3 v1, Vec3 v2)
{
v1.fixNaN(); v2.fixNaN();
return new Vec3(Math.max(v1.vx, v2.vx), Math.max(v1.vy, v2.vy), Math.max(v1.vz, v2.vz));
}
public static Vec3 truncate(Vec3 v)
{
return new Vec3((v.vx > 0.0f) ? (float)Math.floor(v.vx) : (float)Math.ceil(v.vx),
(v.vy > 0.0f) ? (float)Math.floor(v.vy) : (float)Math.ceil(v.vy),
(v.vz > 0.0f) ? (float)Math.floor(v.vz) : (float)Math.ceil(v.vz));
}
public static float lengthSquared(Vec3 v)
{
return v.vx*v.vx + v.vy*v.vy + v.vz*v.vz;
}
public Vec3()
{
vx = 0.0f; vy = 0.0f; vz = 0.0f;
}
public Vec3(float s)
{
vx = s; vy = s; vz = s;
}
public Vec3(float x, float y, float z)
{
vx = x; vy = y; vz = z;
}
@Override
public boolean equals(Object o)
{
if (o instanceof Vec3) {
return ((Vec3)o).x() == vx && ((Vec3)o).y() == vy && ((Vec3)o).z() == vz;
} else if (o instanceof Vec4) {
return ((Vec4)o).x() == vx && ((Vec4)o).y() == vy && ((Vec4)o).z() == vz && ((Vec4)o).w() == 0.0f;
} else {
return false;
}
}
@Override
public String toString()
{
return "(" + vx + ", " + vy + ", " + vz + ")";
}
@Override
public Object clone()
{
return new Vec3(vx, vy, vz);
}
public float x() { return vx; }
public float y() { return vy; }
public float z() { return vz; }
public Vec3 add(Vec3 v)
{
vx += v.vx;
vy += v.vy;
vz += v.vz;
return this;
}
public Vec3 sub(Vec3 v)
{
vx -= v.vx;
vy -= v.vy;
vz -= v.vz;
return this;
}
public Vec3 mul(Vec3 v)
{
vx *= v.vx;
vy *= v.vy;
vz *= v.vz;
return this;
}
public Vec3 mul(float s)
{
vx *= s;
vy *= s;
vz *= s;
return this;
}
public Vec3 div(Vec3 v)
{
vx /= v.vx;
vy /= v.vy;
vz /= v.vz;
return this;
}
public Vec3 div(float s)
{
float t = 1.0f / s;
vx *= t;
vy *= t;
vz *= t;
return this;
}
public float dot(Vec3 v)
{
return vx*v.vx + vy*v.vy + vz*v.vz;
}
// Converts NaN values into a defined number
private Vec3 fixNaN()
{
if (Float.isNaN(vx)) vx = 0.0f;
if (Float.isNaN(vy)) vy = 0.0f;
if (Float.isNaN(vz)) vz = 0.0f;
return this;
}
}
public static class Vec4
{
float vx, vy, vz, vw;
// public static Vec4 neg(Vec4 v)
// {
// return new Vec4(-v.vx, -v.vy, -v.vz, -v.vw);
// }
public static Vec4 add(Vec4 v1, Vec4 v2)
{
return new Vec4(v1.vx + v2.vx, v1.vy + v2.vy, v1.vz + v2.vz, v1.vw + v2.vw);
}
public static Vec4 sub(Vec4 v1, Vec4 v2)
{
return new Vec4(v1.vx - v2.vx, v1.vy - v2.vy, v1.vz - v2.vz, v1.vw - v2.vw);
}
public static Vec4 mul(Vec4 v1, Vec4 v2)
{
return new Vec4(v1.vx * v2.vx, v1.vy * v2.vy, v1.vz * v2.vz, v1.vw * v2.vw);
}
public static Vec4 multiplyAdd(Vec4 v1, Vec4 v2, Vec4 v3)
{
return new Vec4(v1.vx*v2.vx + v3.vx, v1.vy*v2.vy + v3.vy, v1.vz*v2.vz + v3.vz, v1.vw*v2.vw + v3.vw);
}
public static Vec4 negMulSub(Vec4 v1, Vec4 v2, Vec4 v3)
{
return new Vec4(v3.vx - v1.vx*v2.vx, v3.vy - v1.vy*v2.vy, v3.vz - v1.vz*v2.vz, v3.vw - v1.vw*v2.vw);
}
public static Vec4 reciprocal(Vec4 v)
{
return new Vec4(1.0f / v.vx, 1.0f / v.vy, 1.0f / v.vz, 1.0f / v.vw);
}
public static Vec4 min(Vec4 v1, Vec4 v2)
{
v1.fixNaN(); v2.fixNaN();
return new Vec4(Math.min(v1.vx, v2.vx),
Math.min(v1.vy, v2.vy),
Math.min(v1.vz, v2.vz),
Math.min(v1.vw, v2.vw));
}
public static Vec4 max(Vec4 v1, Vec4 v2)
{
v1.fixNaN(); v2.fixNaN();
return new Vec4(Math.max(v1.vx, v2.vx),
Math.max(v1.vy, v2.vy),
Math.max(v1.vz, v2.vz),
Math.max(v1.vw, v2.vw));
}
public static Vec4 truncate(Vec4 v)
{
return new Vec4((v.vx > 0.0f) ? (float)Math.floor(v.vx) : (float)Math.ceil(v.vx),
(v.vy > 0.0f) ? (float)Math.floor(v.vy) : (float)Math.ceil(v.vy),
(v.vz > 0.0f) ? (float)Math.floor(v.vz) : (float)Math.ceil(v.vz),
(v.vw > 0.0f) ? (float)Math.floor(v.vw) : (float)Math.ceil(v.vw));
}
public static boolean compareAnyLessThan(Vec4 v1, Vec4 v2)
{
return (v1.vx < v2.vx || v1.vy < v2.vy || v1.vz < v2.vz || v1.vw < v2.vw);
}
public Vec4()
{
vx = 0.0f; vy = 0.0f; vz = 0.0f; vw = 0.0f;
}
public Vec4(float s)
{
vx = s; vy = s; vz = s; vw = s;
}
public Vec4(float x, float y, float z, float w)
{
vx = x; vy = y; vz = z; vw = w;
}
@Override
public boolean equals(Object o)
{
if (o instanceof Vec4) {
return ((Vec4)o).x() == vx && ((Vec4)o).y() == vy && ((Vec4)o).z() == vz && ((Vec4)o).w() == vw;
} else if (o instanceof Vec3) {
return ((Vec3)o).x() == vx && ((Vec3)o).y() == vy && ((Vec3)o).z() == vz && vw == 0.0f;
} else {
return false;
}
}
@Override
public String toString()
{
return "(" + vx + ", " + vy + ", " + vz + ", " + vw + ")";
}
@Override
public Object clone()
{
return new Vec4(vx, vy, vz, vw);
}
public Vec3 getVec3() { return new Vec3(vx, vy, vz); }
public Vec4 splatX() { return new Vec4(vx); }
public Vec4 splatY() { return new Vec4(vy); }
public Vec4 splatZ() { return new Vec4(vz); }
public Vec4 splatW() { return new Vec4(vw); }
public float x() { return vx; }
public float y() { return vy; }
public float z() { return vz; }
public float w() { return vw; }
public Vec4 add(Vec4 v)
{
vx += v.vx;
vy += v.vy;
vz += v.vz;
vw += v.vw;
return this;
}
public Vec4 sub(Vec4 v)
{
vx -= v.vx;
vy -= v.vy;
vz -= v.vz;
vw -= v.vw;
return this;
}
public Vec4 mul(Vec4 v)
{
vx *= v.vx;
vy *= v.vy;
vz *= v.vz;
vw *= v.vw;
return this;
}
// Converts NaN values into a defined number
private Vec4 fixNaN()
{
if (Float.isNaN(vx)) vx = 0.0f;
if (Float.isNaN(vy)) vy = 0.0f;
if (Float.isNaN(vz)) vz = 0.0f;
if (Float.isNaN(vw)) vw = 0.0f;
return this;
}
}
public static class Sym3x3
{
private static final float FLT_EPSILON = Float.intBitsToFloat(0x34000000); // = 1.1920929e-7
private final float[] m;
public static Sym3x3 computeWeightedCovariance(int count, Vec3[] points, float[] weights)
{
// computing the centroid
float total = 0.0f;
Vec3 centroid = new Vec3();
for (int i = 0; i < count; i++) {
total += weights[i];
centroid.add(Vec3.mul(points[i], weights[i]));
}
centroid.div(total);
// accumulating the covariance matrix
Sym3x3 covariance = new Sym3x3(0.0f);
for (int i = 0; i < count; i++) {
Vec3 a = Vec3.sub(points[i], centroid);
Vec3 b = Vec3.mul(a, weights[i]);
covariance.m[0] += a.x()*b.x();
covariance.m[1] += a.x()*b.y();
covariance.m[2] += a.x()*b.z();
covariance.m[3] += a.y()*b.y();
covariance.m[4] += a.y()*b.z();
covariance.m[5] += a.z()*b.z();
}
return covariance;
}
public static Vec3 computePrincipleComponent(Sym3x3 matrix)
{
// computing the cubic coefficients
float c0 = matrix.m[0] * matrix.m[3] * matrix.m[5] +
2.0f * matrix.m[1] * matrix.m[2] * matrix.m[4] -
matrix.m[0] * matrix.m[4] * matrix.m[4] -
matrix.m[3] * matrix.m[2] * matrix.m[2] -
matrix.m[5] * matrix.m[1] * matrix.m[1];
float c1 = matrix.m[0] * matrix.m[3] +
matrix.m[0] * matrix.m[5] +
matrix.m[3] * matrix.m[5] -
matrix.m[1] * matrix.m[1] -
matrix.m[2] * matrix.m[2] -
matrix.m[4] * matrix.m[4];
float c2 = matrix.m[0] + matrix.m[3] + matrix.m[5];
// computing the quadratic coefficients
float a = c1 - (1.0f/3.0f)*c2*c2;
float b = (-2.0f/27.0f)*c2*c2*c2 + (1.0f/3.0f)*c1*c2 - c0;
// computing the root count check
float Q = 0.25f*b*b + (1.0f/27.0f)*a*a*a;
// testing the multiplicity
if (FLT_EPSILON < Q) {
// only one root, which implies we have a multiple of the identity
return new Vec3(1.0f);
} else if (Q < -FLT_EPSILON) {
// three distinct roots
double theta = Math.atan2(Math.sqrt(-Q), -0.5*b);
double rho = Math.sqrt(0.25*b*b - Q);
float rt = (float)Math.pow(rho, 1.0/3.0);
float ct = (float)Math.cos(theta/3.0);
float st = (float)Math.sin(theta/3.0);
float l1 = (1.0f / 3.0f)*c2 + 2.0f*rt*ct;
float l2 = (1.0f / 3.0f)*c2 - rt*(ct + (float)Math.sqrt(3.0)*st);
float l3 = (1.0f / 3.0f)*c2 - rt*(ct - (float)Math.sqrt(3.0)*st);
// pick the larger
if (Math.abs(l2) > Math.abs(l1))
l1 = l2;
if (Math.abs(l3) > Math.abs(l1))
l1 = l3;
// getting the eigenvector
return getMultiplicity1Evector(matrix, l1);
} else { // if (-FLT_EPSILON <= Q && Q <= FLT_EPSILON)
// two roots
float rt = (float)((b < 0.0f) ? -Math.pow(-0.5*b, 1.0/3.0) : Math.pow(0.5*b, 1.0/3.0));
float l1 = (1.0f/3.0f)*c2 + rt; // repeated
float l2 = (1.0f/3.0f)*c2 - 2.0f*rt;
// getting the eigenvector
if (Math.abs(l1) > Math.abs(l2)) {
return getMultiplicity2Evector(matrix, l1);
} else {
return getMultiplicity1Evector(matrix, l2);
}
}
}
private static Vec3 getMultiplicity1Evector(Sym3x3 matrix, float evalue)
{
if (matrix == null)
throw new NullPointerException();
// computing M
Sym3x3 m = new Sym3x3();
m.m[0] = matrix.m[0] - evalue;
m.m[1] = matrix.m[1];
m.m[2] = matrix.m[2];
m.m[3] = matrix.m[3] - evalue;
m.m[4] = matrix.m[4];
m.m[5] = matrix.m[5] - evalue;
// computing U
Sym3x3 u = new Sym3x3();
u.m[0] = m.m[3]*m.m[5] - m.m[4]*m.m[4];
u.m[1] = m.m[2]*m.m[4] - m.m[1]*m.m[5];
u.m[2] = m.m[1]*m.m[4] - m.m[2]*m.m[3];
u.m[3] = m.m[0]*m.m[5] - m.m[2]*m.m[2];
u.m[4] = m.m[1]*m.m[2] - m.m[4]*m.m[0];
u.m[5] = m.m[0]*m.m[3] - m.m[1]*m.m[1];
// finding the largest component
float mc = Math.abs(u.m[0]);
int mi = 0;
for (int i = 1; i < 6; i++) {
float c = Math.abs(u.m[i]);
if (c > mc) {
mc = c;
mi = i;
}
}
// picking the column with this component
switch (mi) {
case 0:
return new Vec3(u.m[0], u.m[1], u.m[2]);
case 1:
case 3:
return new Vec3(u.m[1], u.m[3], u.m[4]);
default:
return new Vec3(u.m[2], u.m[4], u.m[5]);
}
}
private static Vec3 getMultiplicity2Evector(Sym3x3 matrix, float evalue)
{
if (matrix == null)
throw new NullPointerException();
// computing M
Sym3x3 m = new Sym3x3();
m.m[0] = matrix.m[0] - evalue;
m.m[1] = matrix.m[1];
m.m[2] = matrix.m[2];
m.m[3] = matrix.m[3] - evalue;
m.m[4] = matrix.m[4];
m.m[5] = matrix.m[5] - evalue;
// finding the largest component
float mc = Math.abs(m.m[0]);
int mi = 0;
for (int i = 1; i < 6; i++) {
float c = Math.abs(m.m[i]);
if (c > mc) {
mc = c;
mi = i;
}
}
// picking the first eigenvector based on this index
switch (mi) {
case 0:
case 1:
return new Vec3(-m.m[1], m.m[0], 0.0f);
case 2:
return new Vec3(m.m[2], 0.0f, -m.m[0]);
case 3:
case 4:
return new Vec3(0.0f, -m.m[4], m.m[3]);
default:
return new Vec3(0.0f, -m.m[5], m.m[4]);
}
}
public Sym3x3()
{
m = new float[6];
for (int i = 0; i < m.length; i++) {
m[i] = 0.0f;
}
}
public Sym3x3(float s)
{
m = new float[6];
for (int i = 0; i < m.length; i++) {
m[i] = s;
}
}
@Override
public String toString()
{
return String.format("(%1$f, %2$f, %3$f, %4$f, %5$f, %6$f)", m[0], m[1], m[2], m[3], m[4], m[5]);
}
@Override
public Object clone()
{
Sym3x3 s = new Sym3x3();
s.m[0] = m[0]; s.m[1] = m[1]; s.m[2] = m[2]; s.m[3] = m[3]; s.m[4] = m[4]; s.m[5] = m[5];
return s;
}
public float get(int idx)
{
return m[idx];
}
public Sym3x3 set(int idx, float s)
{
m[idx] = s;
return this;
}
}
private static final class Misc
{
public static int floatToInt(float a, int limit)
{
// use ANSI round-to-zero behavior to get round-to-nearest
int i = (int)(a + 0.5f);
// clamp to the limit
if (i < 0)
i = 0;
else if (i > limit)
i = limit;
return i;
}
}
}