// #region License
// /*
// Microsoft Public License (Ms-PL)
// MonoGame - Copyright © 2009 The MonoGame Team
//
// All rights reserved.
//
// This license governs use of the accompanying software. If you use the software, you accept this license. If you do not
// accept the license, do not use the software.
//
// 1. Definitions
// The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under
// U.S. copyright law.
//
// A "contribution" is the original software, or any additions or changes to the software.
// A "contributor" is any person that distributes its contribution under this license.
// "Licensed patents" are a contributor's patent claims that read directly on its contribution.
//
// 2. Grant of Rights
// (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
// each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
// (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
// each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
//
// 3. Conditions and Limitations
// (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
// (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software,
// your patent license from such contributor to the software ends automatically.
// (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution
// notices that are present in the software.
// (D) If you distribute any portion of the software in source code form, you may do so only under this license by including
// a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object
// code form, you may only do so under a license that complies with this license.
// (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees
// or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent
// permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular
// purpose and non-infringement.
// */
// #endregion License
//
// https://github.com/mono/MonoGame/blob/develop/MonoGame.Framework/Graphics/DxtUtil.cs
//
namespace SpaceEngineersBlueprintEditor.SpaceEngineersCore.InnerModel;
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
public static class DxtUtil
{
#region Internal Static Methods
internal static byte[] DecompressDxt1(byte[] imageData, int width, int height)
{
using (MemoryStream imageStream = new MemoryStream(imageData))
{
return DecompressDxt1(imageStream, width, height);
}
}
internal static byte[] DecompressDxt1(Stream imageStream, int width, int height)
{
byte[] imageData = new byte[width * height * 4];
using (BinaryReader imageReader = new BinaryReader(imageStream))
{
int blockCountX = (width + 3) / 4;
int blockCountY = (height + 3) / 4;
for (int y = 0; y < blockCountY; y++)
{
for (int x = 0; x < blockCountX; x++)
{
DecompressDxt1Block(imageReader, x, y, blockCountX, width, height, imageData);
}
}
}
return imageData;
}
internal static byte[] DecompressDxt3(byte[] imageData, int width, int height)
{
using (MemoryStream imageStream = new MemoryStream(imageData))
{
return DecompressDxt3(imageStream, width, height);
}
}
internal static byte[] DecompressDxt3(Stream imageStream, int width, int height)
{
byte[] imageData = new byte[width * height * 4];
using (BinaryReader imageReader = new BinaryReader(imageStream))
{
int blockCountX = (width + 3) / 4;
int blockCountY = (height + 3) / 4;
for (int y = 0; y < blockCountY; y++)
{
for (int x = 0; x < blockCountX; x++)
{
DecompressDxt3Block(imageReader, x, y, blockCountX, width, height, imageData);
}
}
}
return imageData;
}
internal static byte[] DecompressDxt5(byte[] imageData, int width, int height, ImageConverter.DXGI_FORMAT dxgiFormat)
{
using (MemoryStream imageStream = new MemoryStream(imageData))
{
return DecompressDxt5(imageStream, width, height, dxgiFormat);
}
}
internal static byte[] DecompressDxt5(Stream imageStream, int width, int height, ImageConverter.DXGI_FORMAT dxgiFormat)
{
byte[] imageData = new byte[width * height * 4];
using (BinaryReader imageReader = new BinaryReader(imageStream))
{
int blockCountX = (width + 3) / 4;
int blockCountY = (height + 3) / 4;
for (int y = 0; y < blockCountY; y++)
{
for (int x = 0; x < blockCountX; x++)
{
switch (dxgiFormat)
{
case ImageConverter.DXGI_FORMAT.DXGI_FORMAT_BC7_TYPELESS:
case ImageConverter.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM:
case ImageConverter.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM_SRGB:
DecompressBc7Block(imageReader, x, y, blockCountX, width, height, imageData, dxgiFormat);
break;
default:
DecompressDxt5Block(imageReader, x, y, blockCountX, width, height, imageData);
break;
}
}
}
}
return imageData;
}
#endregion
#region Private Static Methods
private static void DecompressDxt1Block(BinaryReader imageReader, int x, int y, int blockCountX, int width, int height, byte[] imageData)
{
ushort c0 = imageReader.ReadUInt16();
ushort c1 = imageReader.ReadUInt16();
byte r0, g0, b0;
byte r1, g1, b1;
ConvertRgb565ToRgb888(c0, out r0, out g0, out b0);
ConvertRgb565ToRgb888(c1, out r1, out g1, out b1);
uint lookupTable = imageReader.ReadUInt32();
for (int blockY = 0; blockY < 4; blockY++)
{
for (int blockX = 0; blockX < 4; blockX++)
{
byte r = 0, g = 0, b = 0, a = 255;
uint index = lookupTable >> 2 * (4 * blockY + blockX) & 0x03;
if (c0 > c1)
{
switch (index)
{
case 0:
r = r0;
g = g0;
b = b0;
break;
case 1:
r = r1;
g = g1;
b = b1;
break;
case 2:
r = (byte)((2 * r0 + r1) / 3);
g = (byte)((2 * g0 + g1) / 3);
b = (byte)((2 * b0 + b1) / 3);
break;
case 3:
r = (byte)((r0 + 2 * r1) / 3);
g = (byte)((g0 + 2 * g1) / 3);
b = (byte)((b0 + 2 * b1) / 3);
break;
}
}
else
{
switch (index)
{
case 0:
r = r0;
g = g0;
b = b0;
break;
case 1:
r = r1;
g = g1;
b = b1;
break;
case 2:
r = (byte)((r0 + r1) / 2);
g = (byte)((g0 + g1) / 2);
b = (byte)((b0 + b1) / 2);
break;
case 3:
r = 0;
g = 0;
b = 0;
a = 0;
break;
}
}
int px = (x << 2) + blockX;
int py = (y << 2) + blockY;
if (px < width && py < height)
{
int offset = py * width + px << 2;
imageData[offset] = r;
imageData[offset + 1] = g;
imageData[offset + 2] = b;
imageData[offset + 3] = a;
}
}
}
}
private static void DecompressDxt3Block(BinaryReader imageReader, int x, int y, int blockCountX, int width, int height, byte[] imageData)
{
byte a0 = imageReader.ReadByte();
byte a1 = imageReader.ReadByte();
byte a2 = imageReader.ReadByte();
byte a3 = imageReader.ReadByte();
byte a4 = imageReader.ReadByte();
byte a5 = imageReader.ReadByte();
byte a6 = imageReader.ReadByte();
byte a7 = imageReader.ReadByte();
ushort c0 = imageReader.ReadUInt16();
ushort c1 = imageReader.ReadUInt16();
byte r0, g0, b0;
byte r1, g1, b1;
ConvertRgb565ToRgb888(c0, out r0, out g0, out b0);
ConvertRgb565ToRgb888(c1, out r1, out g1, out b1);
uint lookupTable = imageReader.ReadUInt32();
int alphaIndex = 0;
for (int blockY = 0; blockY < 4; blockY++)
{
for (int blockX = 0; blockX < 4; blockX++)
{
byte r = 0, g = 0, b = 0, a = 0;
uint index = lookupTable >> 2 * (4 * blockY + blockX) & 0x03;
switch (alphaIndex)
{
case 0:
a = (byte)(a0 & 0x0F | (a0 & 0x0F) << 4);
break;
case 1:
a = (byte)(a0 & 0xF0 | (a0 & 0xF0) >> 4);
break;
case 2:
a = (byte)(a1 & 0x0F | (a1 & 0x0F) << 4);
break;
case 3:
a = (byte)(a1 & 0xF0 | (a1 & 0xF0) >> 4);
break;
case 4:
a = (byte)(a2 & 0x0F | (a2 & 0x0F) << 4);
break;
case 5:
a = (byte)(a2 & 0xF0 | (a2 & 0xF0) >> 4);
break;
case 6:
a = (byte)(a3 & 0x0F | (a3 & 0x0F) << 4);
break;
case 7:
a = (byte)(a3 & 0xF0 | (a3 & 0xF0) >> 4);
break;
case 8:
a = (byte)(a4 & 0x0F | (a4 & 0x0F) << 4);
break;
case 9:
a = (byte)(a4 & 0xF0 | (a4 & 0xF0) >> 4);
break;
case 10:
a = (byte)(a5 & 0x0F | (a5 & 0x0F) << 4);
break;
case 11:
a = (byte)(a5 & 0xF0 | (a5 & 0xF0) >> 4);
break;
case 12:
a = (byte)(a6 & 0x0F | (a6 & 0x0F) << 4);
break;
case 13:
a = (byte)(a6 & 0xF0 | (a6 & 0xF0) >> 4);
break;
case 14:
a = (byte)(a7 & 0x0F | (a7 & 0x0F) << 4);
break;
case 15:
a = (byte)(a7 & 0xF0 | (a7 & 0xF0) >> 4);
break;
}
++alphaIndex;
switch (index)
{
case 0:
r = r0;
g = g0;
b = b0;
break;
case 1:
r = r1;
g = g1;
b = b1;
break;
case 2:
r = (byte)((2 * r0 + r1) / 3);
g = (byte)((2 * g0 + g1) / 3);
b = (byte)((2 * b0 + b1) / 3);
break;
case 3:
r = (byte)((r0 + 2 * r1) / 3);
g = (byte)((g0 + 2 * g1) / 3);
b = (byte)((b0 + 2 * b1) / 3);
break;
}
int px = (x << 2) + blockX;
int py = (y << 2) + blockY;
if (px < width && py < height)
{
int offset = py * width + px << 2;
imageData[offset] = r;
imageData[offset + 1] = g;
imageData[offset + 2] = b;
imageData[offset + 3] = a;
}
}
}
}
private static void DecompressDxt5Block(BinaryReader imageReader, int x, int y, int blockCountX, int width, int height, byte[] imageData)
{
byte alpha0 = imageReader.ReadByte();
byte alpha1 = imageReader.ReadByte();
ulong alphaMask = imageReader.ReadByte();
alphaMask += (ulong)imageReader.ReadByte() << 8;
alphaMask += (ulong)imageReader.ReadByte() << 16;
alphaMask += (ulong)imageReader.ReadByte() << 24;
alphaMask += (ulong)imageReader.ReadByte() << 32;
alphaMask += (ulong)imageReader.ReadByte() << 40;
ushort c0 = imageReader.ReadUInt16();
ushort c1 = imageReader.ReadUInt16();
byte r0, g0, b0;
byte r1, g1, b1;
ConvertRgb565ToRgb888(c0, out r0, out g0, out b0);
ConvertRgb565ToRgb888(c1, out r1, out g1, out b1);
uint lookupTable = imageReader.ReadUInt32();
for (int blockY = 0; blockY < 4; blockY++)
{
for (int blockX = 0; blockX < 4; blockX++)
{
byte r = 0, g = 0, b = 0, a = 255;
uint index = lookupTable >> 2 * (4 * blockY + blockX) & 0x03;
uint alphaIndex = (uint)(alphaMask >> 3 * (4 * blockY + blockX) & 0x07);
if (alphaIndex == 0)
{
a = alpha0;
}
else if (alphaIndex == 1)
{
a = alpha1;
}
else if (alpha0 > alpha1)
{
a = (byte)(((8 - alphaIndex) * alpha0 + (alphaIndex - 1) * alpha1) / 7);
}
else if (alphaIndex == 6)
{
a = 0;
}
else if (alphaIndex == 7)
{
a = 0xff;
}
else
{
a = (byte)(((6 - alphaIndex) * alpha0 + (alphaIndex - 1) * alpha1) / 5);
}
switch (index)
{
case 0:
r = r0;
g = g0;
b = b0;
break;
case 1:
r = r1;
g = g1;
b = b1;
break;
case 2:
r = (byte)((2 * r0 + r1) / 3);
g = (byte)((2 * g0 + g1) / 3);
b = (byte)((2 * b0 + b1) / 3);
break;
case 3:
r = (byte)((r0 + 2 * r1) / 3);
g = (byte)((g0 + 2 * g1) / 3);
b = (byte)((b0 + 2 * b1) / 3);
break;
}
int px = (x << 2) + blockX;
int py = (y << 2) + blockY;
if (px < width && py < height)
{
int offset = py * width + px << 2;
imageData[offset] = r;
imageData[offset + 1] = g;
imageData[offset + 2] = b;
imageData[offset + 3] = a;
}
}
}
}
private static void ConvertRgb565ToRgb888(ushort color, out byte r, out byte g, out byte b)
{
int temp = (color >> 11) * 255 + 16;
r = (byte)((temp / 32 + temp) / 32);
temp = ((color & 0x07E0) >> 5) * 255 + 32;
g = (byte)((temp / 64 + temp) / 64);
temp = (color & 0x001F) * 255 + 16;
b = (byte)((temp / 32 + temp) / 32);
}
#region BC7 helpers
// Converted from the DirectXTex code.
// Licensed under the MIT License.
// http://go.microsoft.com/fwlink/?LinkId=248926
// TODO: there are still some issues with the brightness of the returned image.
// It is not caused by the premultiplied Alpha, as it persists with linear Alpha.
// At this stage it looks like the SRGB, but the code I have doesn't produce the exact result, but it is very close.
private static void DecompressBc7Block(BinaryReader imageReader, int x, int y, int blockCountX, int width, int height, byte[] imageData, ImageConverter.DXGI_FORMAT dxgiFormat)
{
assert(imageReader != null);
byte[] buffer = imageReader.ReadBytes(16);
m_uBits = new BitArray(buffer);
assert(buffer.Length > 0);
uint uFirst = 0;
while (uFirst < 128 && !GetBit(ref uFirst)) { }
byte uMode = (byte)(uFirst - 1);
if (uMode < 8)
{
byte uPartitions = ms_aInfo[uMode].uPartitions;
assert(uPartitions < BC7_MAX_REGIONS);
byte uNumEndPts = (byte)(uPartitions + 1 << 1);
byte uIndexPrec = ms_aInfo[uMode].uIndexPrec;
byte uIndexPrec2 = ms_aInfo[uMode].uIndexPrec2;
int uStartBit = uMode + 1;
byte[] P = new byte[6];
byte uShape = GetBits<byte>(ref uStartBit, ms_aInfo[uMode].uPartitionBits);
assert(uShape < BC7_MAX_SHAPES);
byte uRotation = GetBits<byte>(ref uStartBit, ms_aInfo[uMode].uRotationBits);
assert(uRotation < 4);
byte uIndexMode = GetBits<byte>(ref uStartBit, ms_aInfo[uMode].uIndexModeBits);
assert(uIndexMode < 2);
LDRColorA[] c = new LDRColorA[BC7_MAX_REGIONS << 1];
for (int i = 0; i < BC7_MAX_REGIONS << 1; i++)
c[i] = new LDRColorA();
LDRColorA RGBAPrec = ms_aInfo[uMode].RGBAPrec;
LDRColorA RGBAPrecWithP = ms_aInfo[uMode].RGBAPrecWithP;
assert(uNumEndPts <= BC7_MAX_REGIONS << 1);
// Red channel
for (int i = 0; i < uNumEndPts; i++)
{
if (uStartBit + RGBAPrec.r > 128)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
c[i].r = GetBits<byte>(ref uStartBit, RGBAPrec.r);
}
// Green channel
for (int i = 0; i < uNumEndPts; i++)
{
if (uStartBit + RGBAPrec.g > 128)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
c[i].g = GetBits<byte>(ref uStartBit, RGBAPrec.g);
}
// Blue channel
for (int i = 0; i < uNumEndPts; i++)
{
if (uStartBit + RGBAPrec.b > 128)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
c[i].b = GetBits<byte>(ref uStartBit, RGBAPrec.b);
}
// Alpha channel
for (int i = 0; i < uNumEndPts; i++)
{
if (uStartBit + RGBAPrec.a > 128)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
c[i].a = RGBAPrec.a != 0 ? GetBits<byte>(ref uStartBit, RGBAPrec.a) : (byte)255;
}
// P-bits
assert(ms_aInfo[uMode].uPBits <= 6);
for (int i = 0; i < ms_aInfo[uMode].uPBits; i++)
{
if (uStartBit > 127)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
//Debugger.Break(); // I'm not sure about this C++ conversion.
P[i] = GetBit(ref uStartBit) ? (byte)0 : (byte)1;
}
if (ms_aInfo[uMode].uPBits != 0)
{
for (int i = 0; i < uNumEndPts; i++)
{
int pi = i * ms_aInfo[uMode].uPBits / uNumEndPts;
for (uint ch = 0; ch < BC7_NUM_CHANNELS; ch++)
{
if (RGBAPrec[ch] != RGBAPrecWithP[ch])
{
c[i][ch] = (byte)(c[i][ch] << 1 | P[pi]);
}
}
}
}
for (int i = 0; i < uNumEndPts; i++)
{
c[i] = Unquantize(c[i], RGBAPrecWithP);
}
byte[] w1 = new byte[NUM_PIXELS_PER_BLOCK];
byte[] w2 = new byte[NUM_PIXELS_PER_BLOCK];
// read color indices
for (int i = 0; i < NUM_PIXELS_PER_BLOCK; i++)
{
uint uNumBits = (uint)(IsFixUpOffset(ms_aInfo[uMode].uPartitions, uShape, i) ? uIndexPrec - 1 : uIndexPrec);
if (uStartBit + uNumBits > 128)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
w1[i] = GetBits<byte>(ref uStartBit, (int)uNumBits);
}
// read alpha indices
if (uIndexPrec2 > 0)
{
for (int i = 0; i < NUM_PIXELS_PER_BLOCK; i++)
{
uint uNumBits = (uint)(i > 0 ? uIndexPrec2 : uIndexPrec2 - 1);
if (uStartBit + uNumBits > 128)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
w2[i] = GetBits<byte>(ref uStartBit, (int)uNumBits);
}
}
int blockSize = (int)Math.Sqrt(NUM_PIXELS_PER_BLOCK);
for (int i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)
{
uint uRegion = g_aPartitionTable[uPartitions][uShape][i];
LDRColorA outPixel;
if (uIndexPrec2 == 0)
{
LDRColorA.Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w1[i], w1[i], uIndexPrec, uIndexPrec, out outPixel);
}
else
{
if (uIndexMode == 0)
{
LDRColorA.Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w1[i], w2[i], uIndexPrec, uIndexPrec2, out outPixel);
}
else
{
LDRColorA.Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w2[i], w1[i], uIndexPrec2, uIndexPrec, out outPixel);
}
}
switch (uRotation)
{
case 1: { byte t = outPixel.r; outPixel.r = outPixel.a; outPixel.a = t; } break;
case 2: { byte t = outPixel.g; outPixel.g = outPixel.a; outPixel.a = t; } break;
case 3: { byte t = outPixel.b; outPixel.b = outPixel.a; outPixel.a = t; } break;
}
int dataX = x * blockSize + i % blockSize;
int dataY = y * blockSize + i / blockSize;
int dataOffset = (dataY * blockCountX * 4 + dataX) * 4;
if (outPixel.a != 0)
{
// final texture uses premultiplied alpha ????
//outPixel.r = (byte)((float)outPixel.r / outPixel.a * 255f);
//outPixel.g = (byte)((float)outPixel.g / outPixel.a * 255f);
//outPixel.b = (byte)((float)outPixel.b / outPixel.a * 255f);
// linear to pm
//outPixel.r = (byte)((float)outPixel.r * outPixel.a / 255f);
//outPixel.g = (byte)((float)outPixel.g * outPixel.a / 255f);
//outPixel.b = (byte)((float)outPixel.b * outPixel.a / 255f);
}
// TODO: SRGB check probably should be somewhere else.
if (dxgiFormat == ImageConverter.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM_SRGB)
{
float r = outPixel.r * (1f / 255f);
float g = outPixel.g * (1f / 255f);
float b = outPixel.b * (1f / 255f);
outPixel.r = (byte)Math.Round(D3DX_SRGB_to_FLOAT_inexact(r) * 255f, 0);
outPixel.g = (byte)Math.Round(D3DX_SRGB_to_FLOAT_inexact(g) * 255f, 0);
outPixel.b = (byte)Math.Round(D3DX_SRGB_to_FLOAT_inexact(b) * 255f, 0);
//outPixel.r = (byte)Math.Round(255f * D3DX_SRGB_to_FLOAT(outPixel.r), 0);
//outPixel.g = (byte)Math.Round(255f * D3DX_SRGB_to_FLOAT(outPixel.g), 0);
//outPixel.b = (byte)Math.Round(255f * D3DX_SRGB_to_FLOAT(outPixel.b), 0);
}
imageData[dataOffset] = outPixel.r;
imageData[dataOffset + 1] = outPixel.g;
imageData[dataOffset + 2] = outPixel.b;
imageData[dataOffset + 3] = outPixel.a;
//pOut[i] = HDRColorA(outPixel);
}
}
else
{
throw new Exception("BC7: Reserved mode 8 encountered during decoding");
}
}
private static BitArray m_uBits;
const uint BC7_MAX_REGIONS = 3;
const uint BC7_MAX_INDICES = 16;
const int BC7_NUM_CHANNELS = 4;
const int BC7_MAX_SHAPES = 64;
const int BC67_WEIGHT_MAX = 64;
const int BC67_WEIGHT_SHIFT = 6;
const int BC67_WEIGHT_ROUND = 32;
// Because these are used in SAL annotations, they need to remain macros rather than const values
const int NUM_PIXELS_PER_BLOCK = 16;
private static readonly ModeInfo[] ms_aInfo = new ModeInfo[]
{
/// Mode 0: Color only, 3 Subsets, RGBP 4441 (unique P-bit), 3-bit indecies, 16 partitions
new ModeInfo (2, 4, 6, 0, 0, 3, 0, new LDRColorA(4,4,4,0), new LDRColorA(5,5,5,0)),
/// Mode 1: Color only, 2 Subsets, RGBP 6661 (shared P-bit), 3-bit indecies, 64 partitions
new ModeInfo (1, 6, 2, 0, 0, 3, 0, new LDRColorA(6,6,6,0), new LDRColorA(7,7,7,0)),
/// Mode 2: Color only, 3 Subsets, RGB 555, 2-bit indecies, 64 partitions
new ModeInfo(2, 6, 0, 0, 0, 2, 0, new LDRColorA(5,5,5,0), new LDRColorA(5,5,5,0)),
/// Mode 3: Color only, 2 Subsets, RGBP 7771 (unique P-bit), 2-bits indecies, 64 partitions
new ModeInfo(1, 6, 4, 0, 0, 2, 0, new LDRColorA(7,7,7,0), new LDRColorA(8,8,8,0)),
/// Mode 4: Color w/ Separate Alpha, 1 Subset, RGB 555, A6, 16x2/16x3-bit indices, 2-bit rotation, 1-bit index selector
new ModeInfo(0, 0, 0, 2, 1, 2, 3, new LDRColorA(5,5,5,6), new LDRColorA(5,5,5,6)),
/// Mode 5: Color w/ Separate Alpha, 1 Subset, RGB 777, A8, 16x2/16x2-bit indices, 2-bit rotation
new ModeInfo(0, 0, 0, 2, 0, 2, 2, new LDRColorA(7,7,7,8), new LDRColorA(7,7,7,8)),
/// Mode 6: Color+Alpha, 1 Subset, RGBAP 77771 (unique P-bit), 16x4-bit indecies
new ModeInfo(0, 0, 2, 0, 0, 4, 0, new LDRColorA(7,7,7,7), new LDRColorA(8,8,8,8)),
/// Mode 7: Color+Alpha, 2 Subsets, RGBAP 55551 (unique P-bit), 2-bit indices, 64 partitions
new ModeInfo(1, 6, 4, 0, 0, 2, 0, new LDRColorA(5,5,5,5), new LDRColorA(6,6,6,6))
};
// Partition, Shape, Fixup
static readonly uint[][][] g_aFixUp = new uint[][][]
{
new uint[][]{ // No fix-ups for 1st subset for BC6H or BC7
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 }
},
new uint[][]{ // BC6H/BC7 Partition Set Fixups for 2 Subsets
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0, 2, 0 },
new uint[]{ 0, 2, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0, 2, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 2, 0 },
new uint[]{ 0, 8, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 2, 0 },
// BC7 Partition Set Fixups for 2 Subsets (second-half)
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0, 6, 0 },new uint[]{ 0, 8, 0 },
new uint[]{ 0, 2, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0, 2, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 2, 0 },
new uint[]{ 0, 2, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0, 6, 0 },
new uint[]{ 0, 6, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 6, 0 },new uint[]{ 0, 8, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 2, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0,15, 0 }
},
new uint[][]{ // BC7 Partition Set Fixups for 3 Subsets
new uint[]{ 0, 3,15 },new uint[]{ 0, 3, 8 },new uint[]{ 0,15, 8 },new uint[]{ 0,15, 3 },
new uint[]{ 0, 8,15 },new uint[]{ 0, 3,15 },new uint[]{ 0,15, 3 },new uint[]{ 0,15, 8 },
new uint[]{ 0, 8,15 },new uint[]{ 0, 8,15 },new uint[]{ 0, 6,15 },new uint[]{ 0, 6,15 },
new uint[]{ 0, 6,15 },new uint[]{ 0, 5,15 },new uint[]{ 0, 3,15 },new uint[]{ 0, 3, 8 },
new uint[]{ 0, 3,15 },new uint[]{ 0, 3, 8 },new uint[]{ 0, 8,15 },new uint[]{ 0,15, 3 },
new uint[]{ 0, 3,15 },new uint[]{ 0, 3, 8 },new uint[]{ 0, 6,15 },new uint[]{ 0,10, 8 },
new uint[]{ 0, 5, 3 },new uint[]{ 0, 8,15 },new uint[]{ 0, 8, 6 },new uint[]{ 0, 6,10 },
new uint[]{ 0, 8,15 },new uint[]{ 0, 5,15 },new uint[]{ 0,15,10 },new uint[]{ 0,15, 8 },
new uint[]{ 0, 8,15 },new uint[]{ 0,15, 3 },new uint[]{ 0, 3,15 },new uint[]{ 0, 5,10 },
new uint[]{ 0, 6,10 },new uint[]{ 0,10, 8 },new uint[]{ 0, 8, 9 },new uint[]{ 0,15,10 },
new uint[]{ 0,15, 6 },new uint[]{ 0, 3,15 },new uint[]{ 0,15, 8 },new uint[]{ 0, 5,15 },
new uint[]{ 0,15, 3 },new uint[]{ 0,15, 6 },new uint[]{ 0,15, 6 },new uint[]{ 0,15, 8 },
new uint[]{ 0, 3,15 },new uint[]{ 0,15, 3 },new uint[]{ 0, 5,15 },new uint[]{ 0, 5,15 },
new uint[]{ 0, 5,15 },new uint[]{ 0, 8,15 },new uint[]{ 0, 5,15 },new uint[]{ 0,10,15 },
new uint[]{ 0, 5,15 },new uint[]{ 0,10,15 },new uint[]{ 0, 8,15 },new uint[]{ 0,13,15 },
new uint[]{ 0,15, 3 },new uint[]{ 0,12,15 },new uint[]{ 0, 3,15 },new uint[]{ 0, 3, 8 }
}
};
// Partition, Shape, Pixel (index into 4x4 block)
static readonly uint[][][] g_aPartitionTable = new uint[][][]
{
new uint[][]{ // 1 Region case has no subsets (all 0)
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
},
new uint[][]{ // BC6H/BC7 Partition Set for 2 Subsets
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 }, // Shape 0
new uint[]{ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }, // Shape 1
new uint[]{ 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 }, // Shape 2
new uint[]{ 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 3
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 }, // Shape 4
new uint[]{ 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 5
new uint[]{ 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 6
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 7
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 }, // Shape 8
new uint[]{ 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 9
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 10
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 }, // Shape 11
new uint[]{ 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 12
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 13
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 14
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 }, // Shape 15
new uint[]{ 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1 }, // Shape 16
new uint[]{ 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, // Shape 17
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0 }, // Shape 18
new uint[]{ 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, // Shape 19
new uint[]{ 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, // Shape 20
new uint[]{ 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 }, // Shape 21
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 }, // Shape 22
new uint[]{ 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1 }, // Shape 23
new uint[]{ 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, // Shape 24
new uint[]{ 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 }, // Shape 25
new uint[]{ 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 }, // Shape 26
new uint[]{ 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0 }, // Shape 27
new uint[]{ 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 }, // Shape 28
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, // Shape 29
new uint[]{ 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0 }, // Shape 30
new uint[]{ 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 }, // Shape 31
// BC7 Partition Set for 2 Subsets (second-half)
new uint[]{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 }, // Shape 32
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 }, // Shape 33
new uint[]{ 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0 }, // Shape 34
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0 }, // Shape 35
new uint[]{ 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0 }, // Shape 36
new uint[]{ 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0 }, // Shape 37
new uint[]{ 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1 }, // Shape 38
new uint[]{ 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 }, // Shape 39
new uint[]{ 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0 }, // Shape 40
new uint[]{ 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 }, // Shape 41
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 }, // Shape 42
new uint[]{ 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 }, // Shape 43
new uint[]{ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }, // Shape 44
new uint[]{ 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1 }, // Shape 45
new uint[]{ 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 }, // Shape 46
new uint[]{ 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 }, // Shape 47
new uint[]{ 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // Shape 48
new uint[]{ 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, // Shape 49
new uint[]{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0 }, // Shape 50
new uint[]{ 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 }, // Shape 51
new uint[]{ 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 }, // Shape 52
new uint[]{ 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1 }, // Shape 53
new uint[]{ 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0 }, // Shape 54
new uint[]{ 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0 }, // Shape 55
new uint[]{ 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 }, // Shape 56
new uint[]{ 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1 }, // Shape 57
new uint[]{ 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 }, // Shape 58
new uint[]{ 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 }, // Shape 59
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 }, // Shape 60
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, // Shape 61
new uint[]{ 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 }, // Shape 62
new uint[]{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1 } // Shape 63
},
new uint[][]{ // BC7 Partition Set for 3 Subsets
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 1, 2, 2, 2, 2 }, // Shape 0
new uint[]{ 0, 0, 0, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1 }, // Shape 1
new uint[]{ 0, 0, 0, 0, 2, 0, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1 }, // Shape 2
new uint[]{ 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 3
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2 }, // Shape 4
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 2, 2 }, // Shape 5
new uint[]{ 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 6
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1 }, // Shape 7
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2 }, // Shape 8
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 }, // Shape 9
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 10
new uint[]{ 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2 }, // Shape 11
new uint[]{ 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2 }, // Shape 12
new uint[]{ 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2 }, // Shape 13
new uint[]{ 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2 }, // Shape 14
new uint[]{ 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0 }, // Shape 15
new uint[]{ 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2 }, // Shape 16
new uint[]{ 0, 1, 1, 1, 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0 }, // Shape 17
new uint[]{ 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2 }, // Shape 18
new uint[]{ 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1 }, // Shape 19
new uint[]{ 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2 }, // Shape 20
new uint[]{ 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 2, 1 }, // Shape 21
new uint[]{ 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2 }, // Shape 22
new uint[]{ 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 1, 0, 2, 2, 1, 0 }, // Shape 23
new uint[]{ 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0 }, // Shape 24
new uint[]{ 0, 0, 1, 2, 0, 0, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2 }, // Shape 25
new uint[]{ 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1, 0, 1, 1, 0 }, // Shape 26
new uint[]{ 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1 }, // Shape 27
new uint[]{ 0, 0, 2, 2, 1, 1, 0, 2, 1, 1, 0, 2, 0, 0, 2, 2 }, // Shape 28
new uint[]{ 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 0, 2, 2, 2, 2, 2 }, // Shape 29
new uint[]{ 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1 }, // Shape 30
new uint[]{ 0, 0, 0, 0, 2, 0, 0, 0, 2, 2, 1, 1, 2, 2, 2, 1 }, // Shape 31
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 2, 2, 2 }, // Shape 32
new uint[]{ 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 2, 0, 0, 1, 1 }, // Shape 33
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 2, 2, 0, 2, 2, 2 }, // Shape 34
new uint[]{ 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0 }, // Shape 35
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0 }, // Shape 36
new uint[]{ 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0 }, // Shape 37
new uint[]{ 0, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 0, 1, 2, 0 }, // Shape 38
new uint[]{ 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1 }, // Shape 39
new uint[]{ 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1 }, // Shape 40
new uint[]{ 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 41
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1 }, // Shape 42
new uint[]{ 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2, 1, 1, 2, 2 }, // Shape 43
new uint[]{ 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1 }, // Shape 44
new uint[]{ 0, 2, 2, 0, 1, 2, 2, 1, 0, 2, 2, 0, 1, 2, 2, 1 }, // Shape 45
new uint[]{ 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 1 }, // Shape 46
new uint[]{ 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1 }, // Shape 47
new uint[]{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2 }, // Shape 48
new uint[]{ 0, 2, 2, 2, 0, 1, 1, 1, 0, 2, 2, 2, 0, 1, 1, 1 }, // Shape 49
new uint[]{ 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2 }, // Shape 50
new uint[]{ 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2 }, // Shape 51
new uint[]{ 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2 }, // Shape 52
new uint[]{ 0, 0, 0, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2 }, // Shape 53
new uint[]{ 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2 }, // Shape 54
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2 }, // Shape 55
new uint[]{ 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 56
new uint[]{ 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2 }, // Shape 57
new uint[]{ 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2 }, // Shape 58
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2 }, // Shape 59
new uint[]{ 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1 }, // Shape 60
new uint[]{ 0, 2, 2, 2, 1, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2 }, // Shape 61
new uint[]{ 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 62
new uint[]{ 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 2, 2, 2, 0 } // Shape 63
}
};
static readonly int[] g_aWeights2 = { 0, 21, 43, 64 };
static readonly int[] g_aWeights3 = { 0, 9, 18, 27, 37, 46, 55, 64 };
static readonly int[] g_aWeights4 = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };
private static void assert(bool condition)
{
if (!condition)
{
Debugger.Break();
}
}
private static bool GetBit(ref uint uStartBit)
{
bool ret = m_uBits[(int)uStartBit];
uStartBit++;
return ret;
}
private static bool GetBit(ref int uStartBit)
{
bool ret = m_uBits[uStartBit];
uStartBit++;
return ret;
}
private static T GetBits<T>(ref int uStartBit, int uNumBits)
{
if (uNumBits == 0)
return default;
BitArray newBits = new BitArray(uNumBits);
for (int i = 0; i < uNumBits; i++)
{
newBits[i] = m_uBits[uStartBit];
uStartBit++;
}
if (uNumBits > 32)
{
Debugger.Break();
// TODO: this exceeds the size of the uint
}
int[] theIntArray = new int[(newBits.Length + 31) / 32];
new BitArray(newBits).CopyTo(theIntArray, 0);
if (theIntArray[0] > 255)
{
Debugger.Break();
// TODO: might be a converstion issue with int>uint
}
return (T)Convert.ChangeType(theIntArray[0], typeof(T));
}
class LDRColorA
{
public byte r, g, b, a;
public LDRColorA() { }
public LDRColorA(byte rColor, byte gColor, byte bColor, byte aColor)
{
r = rColor;
g = gColor;
b = bColor;
a = aColor;
}
public byte this[uint uElement]
{
get
{
switch (uElement)
{
case 0: return r;
case 1: return g;
case 2: return b;
case 3: return a;
default: assert(false); return r;
}
}
set
{
switch (uElement)
{
case 0: r = value; break;
case 1: g = value; break;
case 2: b = value; break;
case 3: a = value; break;
default: Debugger.Break(); break;
}
}
}
//static void InterpolateRGB(_In_ const LDRColorA& c0, _In_ const LDRColorA& c1, _In_ size_t wc, _In_ _In_range_(2, 4) size_t wcprec, _Out_ LDRColorA& out)
static void InterpolateRGB(LDRColorA c0, LDRColorA c1, int wc, int wcprec, ref LDRColorA outVal)
{
int[] aWeights;
switch (wcprec)
{
case 2: aWeights = g_aWeights2; assert(wc < 4); break;
case 3: aWeights = g_aWeights3; assert(wc < 8); break;
case 4: aWeights = g_aWeights4; assert(wc < 16); break;
default: assert(false); outVal.r = outVal.g = outVal.b = 0; return;
}
if (c1.r > 60)
{
}
outVal.r = (byte)(c0.r * (BC67_WEIGHT_MAX - aWeights[wc]) + c1.r * aWeights[wc] + BC67_WEIGHT_ROUND >> BC67_WEIGHT_SHIFT);
outVal.g = (byte)(c0.g * (BC67_WEIGHT_MAX - aWeights[wc]) + c1.g * aWeights[wc] + BC67_WEIGHT_ROUND >> BC67_WEIGHT_SHIFT);
outVal.b = (byte)(c0.b * (BC67_WEIGHT_MAX - aWeights[wc]) + c1.b * aWeights[wc] + BC67_WEIGHT_ROUND >> BC67_WEIGHT_SHIFT);
}
// static void InterpolateA(_In_ const LDRColorA& c0, _In_ const LDRColorA& c1, _In_ size_t wa, _In_range_(2, 4) _In_ size_t waprec, _Out_ LDRColorA& out)
static void InterpolateA(LDRColorA c0, LDRColorA c1, int wa, int waprec, ref LDRColorA outVal)
{
int[] aWeights;
switch (waprec)
{
case 2: aWeights = g_aWeights2; assert(wa < 4); break;
case 3: aWeights = g_aWeights3; assert(wa < 8); break;
case 4: aWeights = g_aWeights4; assert(wa < 16); break;
default: assert(false); outVal.a = 0; return;
}
outVal.a = (byte)(c0.a * (BC67_WEIGHT_MAX - aWeights[wa]) + c1.a * aWeights[wa] + BC67_WEIGHT_ROUND >> BC67_WEIGHT_SHIFT);
}
// static void Interpolate(_In_ const LDRColorA& c0, _In_ const LDRColorA& c1, _In_ size_t wc, _In_ size_t wa, _In_ _In_range_(2, 4) size_t wcprec, _In_ _In_range_(2, 4) size_t waprec, _Out_ LDRColorA& out)
public static void Interpolate(LDRColorA c0, LDRColorA c1, int wc, int wa, int wcprec, int waprec, out LDRColorA outVal)
{
outVal = new LDRColorA();
InterpolateRGB(c0, c1, wc, wcprec, ref outVal);
InterpolateA(c0, c1, wa, waprec, ref outVal);
}
}
class ModeInfo
{
public byte uPartitions;
public byte uPartitionBits;
public byte uPBits;
public byte uRotationBits;
public byte uIndexModeBits;
public byte uIndexPrec;
public byte uIndexPrec2;
public LDRColorA RGBAPrec;
public LDRColorA RGBAPrecWithP;
public ModeInfo(byte partitions, byte partitionBits, byte pBits, byte rotationBits, byte indexModeBits, byte indexPrec, byte indexPrec2, LDRColorA rgbaPrec, LDRColorA rgbaPrecWithP)
{
uPartitions = partitions;
uPartitionBits = partitionBits;
uPBits = pBits;
uRotationBits = rotationBits;
uIndexModeBits = indexModeBits;
uIndexPrec = indexPrec;
uIndexPrec2 = indexPrec2;
RGBAPrec = rgbaPrec;
RGBAPrecWithP = rgbaPrecWithP;
}
};
static byte Unquantize(byte comp, int uPrec)
{
assert(0 < uPrec && uPrec <= 8);
comp = (byte)(comp << 8 - uPrec);
return (byte)(comp | comp >> uPrec);
}
static LDRColorA Unquantize(LDRColorA c, LDRColorA RGBAPrec)
{
LDRColorA q = new LDRColorA();
q.r = Unquantize(c.r, RGBAPrec.r);
q.g = Unquantize(c.g, RGBAPrec.g);
q.b = Unquantize(c.b, RGBAPrec.b);
q.a = RGBAPrec.a > 0 ? Unquantize(c.a, RGBAPrec.a) : (byte)255;
return q;
}
// inline bool IsFixUpOffset(_In_range_(0, 2) size_t uPartitions, _In_range_(0, 63) size_t uShape, _In_range_(0, 15) size_t uOffset)
static bool IsFixUpOffset(uint uPartitions, uint uShape, int uOffset)
{
assert(uPartitions < 3 && uShape < 64 && uOffset < 16);
for (int p = 0; p <= uPartitions; p++)
{
if (uOffset == g_aFixUp[uPartitions][uShape][p])
{
return true;
}
}
return false;
}
#endregion
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff728749(v=vs.85).aspx
// D3DX_DXGIFormatConvert.inl
private static float D3DX_SRGB_to_FLOAT_inexact(float srgb)
{
float linear;
if (srgb <= 0.04045f)
linear = srgb / 12.92f;
else
linear = (float)Math.Pow((srgb + 0.055f) / 1.055f, 2.4f);
return linear;
}
// https://gamedevdaily.io/the-srgb-learning-curve-773b7f68cf7a
private static float D3DX_FLOAT_to_SRGB(float linear)
{
float srgb;
if (linear < 0.0031308f)
srgb = linear * 12.92f;
else
srgb = 1.055f * (float)Math.Pow(linear, 1.0f / 2.4f) - 0.055f;
return srgb;
}
static readonly uint[] D3DX_SRGBTable =
{
0x00000000,0x399f22b4,0x3a1f22b4,0x3a6eb40e,0x3a9f22b4,0x3ac6eb61,0x3aeeb40e,0x3b0b3e5d,
0x3b1f22b4,0x3b33070b,0x3b46eb61,0x3b5b518d,0x3b70f18d,0x3b83e1c6,0x3b8fe616,0x3b9c87fd,
0x3ba9c9b7,0x3bb7ad6f,0x3bc63549,0x3bd56361,0x3be539c1,0x3bf5ba70,0x3c0373b5,0x3c0c6152,
0x3c15a703,0x3c1f45be,0x3c293e6b,0x3c3391f7,0x3c3e4149,0x3c494d43,0x3c54b6c7,0x3c607eb1,
0x3c6ca5df,0x3c792d22,0x3c830aa8,0x3c89af9f,0x3c9085db,0x3c978dc5,0x3c9ec7c2,0x3ca63433,
0x3cadd37d,0x3cb5a601,0x3cbdac20,0x3cc5e639,0x3cce54ab,0x3cd6f7d5,0x3cdfd010,0x3ce8ddb9,
0x3cf2212c,0x3cfb9ac1,0x3d02a569,0x3d0798dc,0x3d0ca7e6,0x3d11d2af,0x3d171963,0x3d1c7c2e,
0x3d21fb3c,0x3d2796b2,0x3d2d4ebb,0x3d332380,0x3d39152b,0x3d3f23e3,0x3d454fd1,0x3d4b991c,
0x3d51ffef,0x3d58846a,0x3d5f26b7,0x3d65e6fe,0x3d6cc564,0x3d73c20f,0x3d7add29,0x3d810b67,
0x3d84b795,0x3d887330,0x3d8c3e4a,0x3d9018f6,0x3d940345,0x3d97fd4a,0x3d9c0716,0x3da020bb,
0x3da44a4b,0x3da883d7,0x3daccd70,0x3db12728,0x3db59112,0x3dba0b3b,0x3dbe95b5,0x3dc33092,
0x3dc7dbe2,0x3dcc97b6,0x3dd1641f,0x3dd6412c,0x3ddb2eef,0x3de02d77,0x3de53cd5,0x3dea5d19,
0x3def8e52,0x3df4d091,0x3dfa23e8,0x3dff8861,0x3e027f07,0x3e054280,0x3e080ea3,0x3e0ae378,
0x3e0dc105,0x3e10a754,0x3e13966b,0x3e168e52,0x3e198f10,0x3e1c98ad,0x3e1fab30,0x3e22c6a3,
0x3e25eb09,0x3e29186c,0x3e2c4ed0,0x3e2f8e41,0x3e32d6c4,0x3e362861,0x3e39831e,0x3e3ce703,
0x3e405416,0x3e43ca5f,0x3e4749e4,0x3e4ad2ae,0x3e4e64c2,0x3e520027,0x3e55a4e6,0x3e595303,
0x3e5d0a8b,0x3e60cb7c,0x3e6495e0,0x3e6869bf,0x3e6c4720,0x3e702e0c,0x3e741e84,0x3e781890,
0x3e7c1c38,0x3e8014c2,0x3e82203c,0x3e84308d,0x3e8645ba,0x3e885fc5,0x3e8a7eb2,0x3e8ca283,
0x3e8ecb3d,0x3e90f8e1,0x3e932b74,0x3e9562f8,0x3e979f71,0x3e99e0e2,0x3e9c274e,0x3e9e72b7,
0x3ea0c322,0x3ea31892,0x3ea57308,0x3ea7d289,0x3eaa3718,0x3eaca0b7,0x3eaf0f69,0x3eb18333,
0x3eb3fc18,0x3eb67a18,0x3eb8fd37,0x3ebb8579,0x3ebe12e1,0x3ec0a571,0x3ec33d2d,0x3ec5da17,
0x3ec87c33,0x3ecb2383,0x3ecdd00b,0x3ed081cd,0x3ed338cc,0x3ed5f50b,0x3ed8b68d,0x3edb7d54,
0x3ede4965,0x3ee11ac1,0x3ee3f16b,0x3ee6cd67,0x3ee9aeb6,0x3eec955d,0x3eef815d,0x3ef272ba,
0x3ef56976,0x3ef86594,0x3efb6717,0x3efe6e02,0x3f00bd2d,0x3f02460e,0x3f03d1a7,0x3f055ff9,
0x3f06f106,0x3f0884cf,0x3f0a1b56,0x3f0bb49b,0x3f0d50a0,0x3f0eef67,0x3f1090f1,0x3f12353e,
0x3f13dc51,0x3f15862b,0x3f1732cd,0x3f18e239,0x3f1a946f,0x3f1c4971,0x3f1e0141,0x3f1fbbdf,
0x3f21794e,0x3f23398e,0x3f24fca0,0x3f26c286,0x3f288b41,0x3f2a56d3,0x3f2c253d,0x3f2df680,
0x3f2fca9e,0x3f31a197,0x3f337b6c,0x3f355820,0x3f3737b3,0x3f391a26,0x3f3aff7c,0x3f3ce7b5,
0x3f3ed2d2,0x3f40c0d4,0x3f42b1be,0x3f44a590,0x3f469c4b,0x3f4895f1,0x3f4a9282,0x3f4c9201,
0x3f4e946e,0x3f5099cb,0x3f52a218,0x3f54ad57,0x3f56bb8a,0x3f58ccb0,0x3f5ae0cd,0x3f5cf7e0,
0x3f5f11ec,0x3f612eee,0x3f634eef,0x3f6571e9,0x3f6797e3,0x3f69c0d6,0x3f6beccd,0x3f6e1bbf,
0x3f704db8,0x3f7282af,0x3f74baae,0x3f76f5ae,0x3f7933b9,0x3f7b74c6,0x3f7db8e0,0x3f800000
};
static float D3DX_SRGB_to_FLOAT(uint val)
{
return BitConverter.ToSingle(BitConverter.GetBytes(D3DX_SRGBTable[val]), 0);
//return (float)D3DX_SRGBTable[val];
}
#endregion
}
// #region License
// /*
// Microsoft Public License (Ms-PL)
// MonoGame - Copyright © 2009 The MonoGame Team
//
// All rights reserved.
//
// This license governs use of the accompanying software. If you use the software, you accept this license. If you do not
// accept the license, do not use the software.
//
// 1. Definitions
// The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under
// U.S. copyright law.
//
// A "contribution" is the original software, or any additions or changes to the software.
// A "contributor" is any person that distributes its contribution under this license.
// "Licensed patents" are a contributor's patent claims that read directly on its contribution.
//
// 2. Grant of Rights
// (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
// each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
// (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3,
// each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
//
// 3. Conditions and Limitations
// (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
// (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software,
// your patent license from such contributor to the software ends automatically.
// (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution
// notices that are present in the software.
// (D) If you distribute any portion of the software in source code form, you may do so only under this license by including
// a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object
// code form, you may only do so under a license that complies with this license.
// (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees
// or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent
// permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular
// purpose and non-infringement.
// */
// #endregion License
//
// https://github.com/mono/MonoGame/blob/develop/MonoGame.Framework/Graphics/DxtUtil.cs
//
namespace SpaceEngineersBlueprintEditor.SpaceEngineersCore.InnerModel;
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
public static class DxtUtil
{
#region Internal Static Methods
internal static byte[] DecompressDxt1(byte[] imageData, int width, int height)
{
using (MemoryStream imageStream = new MemoryStream(imageData))
{
return DecompressDxt1(imageStream, width, height);
}
}
internal static byte[] DecompressDxt1(Stream imageStream, int width, int height)
{
byte[] imageData = new byte[width * height * 4];
using (BinaryReader imageReader = new BinaryReader(imageStream))
{
int blockCountX = (width + 3) / 4;
int blockCountY = (height + 3) / 4;
for (int y = 0; y < blockCountY; y++)
{
for (int x = 0; x < blockCountX; x++)
{
DecompressDxt1Block(imageReader, x, y, blockCountX, width, height, imageData);
}
}
}
return imageData;
}
internal static byte[] DecompressDxt3(byte[] imageData, int width, int height)
{
using (MemoryStream imageStream = new MemoryStream(imageData))
{
return DecompressDxt3(imageStream, width, height);
}
}
internal static byte[] DecompressDxt3(Stream imageStream, int width, int height)
{
byte[] imageData = new byte[width * height * 4];
using (BinaryReader imageReader = new BinaryReader(imageStream))
{
int blockCountX = (width + 3) / 4;
int blockCountY = (height + 3) / 4;
for (int y = 0; y < blockCountY; y++)
{
for (int x = 0; x < blockCountX; x++)
{
DecompressDxt3Block(imageReader, x, y, blockCountX, width, height, imageData);
}
}
}
return imageData;
}
internal static byte[] DecompressDxt5(byte[] imageData, int width, int height, ImageConverter.DXGI_FORMAT dxgiFormat)
{
using (MemoryStream imageStream = new MemoryStream(imageData))
{
return DecompressDxt5(imageStream, width, height, dxgiFormat);
}
}
internal static byte[] DecompressDxt5(Stream imageStream, int width, int height, ImageConverter.DXGI_FORMAT dxgiFormat)
{
byte[] imageData = new byte[width * height * 4];
using (BinaryReader imageReader = new BinaryReader(imageStream))
{
int blockCountX = (width + 3) / 4;
int blockCountY = (height + 3) / 4;
for (int y = 0; y < blockCountY; y++)
{
for (int x = 0; x < blockCountX; x++)
{
switch (dxgiFormat)
{
case ImageConverter.DXGI_FORMAT.DXGI_FORMAT_BC7_TYPELESS:
case ImageConverter.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM:
case ImageConverter.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM_SRGB:
DecompressBc7Block(imageReader, x, y, blockCountX, width, height, imageData, dxgiFormat);
break;
default:
DecompressDxt5Block(imageReader, x, y, blockCountX, width, height, imageData);
break;
}
}
}
}
return imageData;
}
#endregion
#region Private Static Methods
private static void DecompressDxt1Block(BinaryReader imageReader, int x, int y, int blockCountX, int width, int height, byte[] imageData)
{
ushort c0 = imageReader.ReadUInt16();
ushort c1 = imageReader.ReadUInt16();
byte r0, g0, b0;
byte r1, g1, b1;
ConvertRgb565ToRgb888(c0, out r0, out g0, out b0);
ConvertRgb565ToRgb888(c1, out r1, out g1, out b1);
uint lookupTable = imageReader.ReadUInt32();
for (int blockY = 0; blockY < 4; blockY++)
{
for (int blockX = 0; blockX < 4; blockX++)
{
byte r = 0, g = 0, b = 0, a = 255;
uint index = lookupTable >> 2 * (4 * blockY + blockX) & 0x03;
if (c0 > c1)
{
switch (index)
{
case 0:
r = r0;
g = g0;
b = b0;
break;
case 1:
r = r1;
g = g1;
b = b1;
break;
case 2:
r = (byte)((2 * r0 + r1) / 3);
g = (byte)((2 * g0 + g1) / 3);
b = (byte)((2 * b0 + b1) / 3);
break;
case 3:
r = (byte)((r0 + 2 * r1) / 3);
g = (byte)((g0 + 2 * g1) / 3);
b = (byte)((b0 + 2 * b1) / 3);
break;
}
}
else
{
switch (index)
{
case 0:
r = r0;
g = g0;
b = b0;
break;
case 1:
r = r1;
g = g1;
b = b1;
break;
case 2:
r = (byte)((r0 + r1) / 2);
g = (byte)((g0 + g1) / 2);
b = (byte)((b0 + b1) / 2);
break;
case 3:
r = 0;
g = 0;
b = 0;
a = 0;
break;
}
}
int px = (x << 2) + blockX;
int py = (y << 2) + blockY;
if (px < width && py < height)
{
int offset = py * width + px << 2;
imageData[offset] = r;
imageData[offset + 1] = g;
imageData[offset + 2] = b;
imageData[offset + 3] = a;
}
}
}
}
private static void DecompressDxt3Block(BinaryReader imageReader, int x, int y, int blockCountX, int width, int height, byte[] imageData)
{
byte a0 = imageReader.ReadByte();
byte a1 = imageReader.ReadByte();
byte a2 = imageReader.ReadByte();
byte a3 = imageReader.ReadByte();
byte a4 = imageReader.ReadByte();
byte a5 = imageReader.ReadByte();
byte a6 = imageReader.ReadByte();
byte a7 = imageReader.ReadByte();
ushort c0 = imageReader.ReadUInt16();
ushort c1 = imageReader.ReadUInt16();
byte r0, g0, b0;
byte r1, g1, b1;
ConvertRgb565ToRgb888(c0, out r0, out g0, out b0);
ConvertRgb565ToRgb888(c1, out r1, out g1, out b1);
uint lookupTable = imageReader.ReadUInt32();
int alphaIndex = 0;
for (int blockY = 0; blockY < 4; blockY++)
{
for (int blockX = 0; blockX < 4; blockX++)
{
byte r = 0, g = 0, b = 0, a = 0;
uint index = lookupTable >> 2 * (4 * blockY + blockX) & 0x03;
switch (alphaIndex)
{
case 0:
a = (byte)(a0 & 0x0F | (a0 & 0x0F) << 4);
break;
case 1:
a = (byte)(a0 & 0xF0 | (a0 & 0xF0) >> 4);
break;
case 2:
a = (byte)(a1 & 0x0F | (a1 & 0x0F) << 4);
break;
case 3:
a = (byte)(a1 & 0xF0 | (a1 & 0xF0) >> 4);
break;
case 4:
a = (byte)(a2 & 0x0F | (a2 & 0x0F) << 4);
break;
case 5:
a = (byte)(a2 & 0xF0 | (a2 & 0xF0) >> 4);
break;
case 6:
a = (byte)(a3 & 0x0F | (a3 & 0x0F) << 4);
break;
case 7:
a = (byte)(a3 & 0xF0 | (a3 & 0xF0) >> 4);
break;
case 8:
a = (byte)(a4 & 0x0F | (a4 & 0x0F) << 4);
break;
case 9:
a = (byte)(a4 & 0xF0 | (a4 & 0xF0) >> 4);
break;
case 10:
a = (byte)(a5 & 0x0F | (a5 & 0x0F) << 4);
break;
case 11:
a = (byte)(a5 & 0xF0 | (a5 & 0xF0) >> 4);
break;
case 12:
a = (byte)(a6 & 0x0F | (a6 & 0x0F) << 4);
break;
case 13:
a = (byte)(a6 & 0xF0 | (a6 & 0xF0) >> 4);
break;
case 14:
a = (byte)(a7 & 0x0F | (a7 & 0x0F) << 4);
break;
case 15:
a = (byte)(a7 & 0xF0 | (a7 & 0xF0) >> 4);
break;
}
++alphaIndex;
switch (index)
{
case 0:
r = r0;
g = g0;
b = b0;
break;
case 1:
r = r1;
g = g1;
b = b1;
break;
case 2:
r = (byte)((2 * r0 + r1) / 3);
g = (byte)((2 * g0 + g1) / 3);
b = (byte)((2 * b0 + b1) / 3);
break;
case 3:
r = (byte)((r0 + 2 * r1) / 3);
g = (byte)((g0 + 2 * g1) / 3);
b = (byte)((b0 + 2 * b1) / 3);
break;
}
int px = (x << 2) + blockX;
int py = (y << 2) + blockY;
if (px < width && py < height)
{
int offset = py * width + px << 2;
imageData[offset] = r;
imageData[offset + 1] = g;
imageData[offset + 2] = b;
imageData[offset + 3] = a;
}
}
}
}
private static void DecompressDxt5Block(BinaryReader imageReader, int x, int y, int blockCountX, int width, int height, byte[] imageData)
{
byte alpha0 = imageReader.ReadByte();
byte alpha1 = imageReader.ReadByte();
ulong alphaMask = imageReader.ReadByte();
alphaMask += (ulong)imageReader.ReadByte() << 8;
alphaMask += (ulong)imageReader.ReadByte() << 16;
alphaMask += (ulong)imageReader.ReadByte() << 24;
alphaMask += (ulong)imageReader.ReadByte() << 32;
alphaMask += (ulong)imageReader.ReadByte() << 40;
ushort c0 = imageReader.ReadUInt16();
ushort c1 = imageReader.ReadUInt16();
byte r0, g0, b0;
byte r1, g1, b1;
ConvertRgb565ToRgb888(c0, out r0, out g0, out b0);
ConvertRgb565ToRgb888(c1, out r1, out g1, out b1);
uint lookupTable = imageReader.ReadUInt32();
for (int blockY = 0; blockY < 4; blockY++)
{
for (int blockX = 0; blockX < 4; blockX++)
{
byte r = 0, g = 0, b = 0, a = 255;
uint index = lookupTable >> 2 * (4 * blockY + blockX) & 0x03;
uint alphaIndex = (uint)(alphaMask >> 3 * (4 * blockY + blockX) & 0x07);
if (alphaIndex == 0)
{
a = alpha0;
}
else if (alphaIndex == 1)
{
a = alpha1;
}
else if (alpha0 > alpha1)
{
a = (byte)(((8 - alphaIndex) * alpha0 + (alphaIndex - 1) * alpha1) / 7);
}
else if (alphaIndex == 6)
{
a = 0;
}
else if (alphaIndex == 7)
{
a = 0xff;
}
else
{
a = (byte)(((6 - alphaIndex) * alpha0 + (alphaIndex - 1) * alpha1) / 5);
}
switch (index)
{
case 0:
r = r0;
g = g0;
b = b0;
break;
case 1:
r = r1;
g = g1;
b = b1;
break;
case 2:
r = (byte)((2 * r0 + r1) / 3);
g = (byte)((2 * g0 + g1) / 3);
b = (byte)((2 * b0 + b1) / 3);
break;
case 3:
r = (byte)((r0 + 2 * r1) / 3);
g = (byte)((g0 + 2 * g1) / 3);
b = (byte)((b0 + 2 * b1) / 3);
break;
}
int px = (x << 2) + blockX;
int py = (y << 2) + blockY;
if (px < width && py < height)
{
int offset = py * width + px << 2;
imageData[offset] = r;
imageData[offset + 1] = g;
imageData[offset + 2] = b;
imageData[offset + 3] = a;
}
}
}
}
private static void ConvertRgb565ToRgb888(ushort color, out byte r, out byte g, out byte b)
{
int temp = (color >> 11) * 255 + 16;
r = (byte)((temp / 32 + temp) / 32);
temp = ((color & 0x07E0) >> 5) * 255 + 32;
g = (byte)((temp / 64 + temp) / 64);
temp = (color & 0x001F) * 255 + 16;
b = (byte)((temp / 32 + temp) / 32);
}
#region BC7 helpers
// Converted from the DirectXTex code.
// Licensed under the MIT License.
// http://go.microsoft.com/fwlink/?LinkId=248926
// TODO: there are still some issues with the brightness of the returned image.
// It is not caused by the premultiplied Alpha, as it persists with linear Alpha.
// At this stage it looks like the SRGB, but the code I have doesn't produce the exact result, but it is very close.
private static void DecompressBc7Block(BinaryReader imageReader, int x, int y, int blockCountX, int width, int height, byte[] imageData, ImageConverter.DXGI_FORMAT dxgiFormat)
{
assert(imageReader != null);
byte[] buffer = imageReader.ReadBytes(16);
m_uBits = new BitArray(buffer);
assert(buffer.Length > 0);
uint uFirst = 0;
while (uFirst < 128 && !GetBit(ref uFirst)) { }
byte uMode = (byte)(uFirst - 1);
if (uMode < 8)
{
byte uPartitions = ms_aInfo[uMode].uPartitions;
assert(uPartitions < BC7_MAX_REGIONS);
byte uNumEndPts = (byte)(uPartitions + 1 << 1);
byte uIndexPrec = ms_aInfo[uMode].uIndexPrec;
byte uIndexPrec2 = ms_aInfo[uMode].uIndexPrec2;
int uStartBit = uMode + 1;
byte[] P = new byte[6];
byte uShape = GetBits<byte>(ref uStartBit, ms_aInfo[uMode].uPartitionBits);
assert(uShape < BC7_MAX_SHAPES);
byte uRotation = GetBits<byte>(ref uStartBit, ms_aInfo[uMode].uRotationBits);
assert(uRotation < 4);
byte uIndexMode = GetBits<byte>(ref uStartBit, ms_aInfo[uMode].uIndexModeBits);
assert(uIndexMode < 2);
LDRColorA[] c = new LDRColorA[BC7_MAX_REGIONS << 1];
for (int i = 0; i < BC7_MAX_REGIONS << 1; i++)
c[i] = new LDRColorA();
LDRColorA RGBAPrec = ms_aInfo[uMode].RGBAPrec;
LDRColorA RGBAPrecWithP = ms_aInfo[uMode].RGBAPrecWithP;
assert(uNumEndPts <= BC7_MAX_REGIONS << 1);
// Red channel
for (int i = 0; i < uNumEndPts; i++)
{
if (uStartBit + RGBAPrec.r > 128)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
c[i].r = GetBits<byte>(ref uStartBit, RGBAPrec.r);
}
// Green channel
for (int i = 0; i < uNumEndPts; i++)
{
if (uStartBit + RGBAPrec.g > 128)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
c[i].g = GetBits<byte>(ref uStartBit, RGBAPrec.g);
}
// Blue channel
for (int i = 0; i < uNumEndPts; i++)
{
if (uStartBit + RGBAPrec.b > 128)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
c[i].b = GetBits<byte>(ref uStartBit, RGBAPrec.b);
}
// Alpha channel
for (int i = 0; i < uNumEndPts; i++)
{
if (uStartBit + RGBAPrec.a > 128)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
c[i].a = RGBAPrec.a != 0 ? GetBits<byte>(ref uStartBit, RGBAPrec.a) : (byte)255;
}
// P-bits
assert(ms_aInfo[uMode].uPBits <= 6);
for (int i = 0; i < ms_aInfo[uMode].uPBits; i++)
{
if (uStartBit > 127)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
//Debugger.Break(); // I'm not sure about this C++ conversion.
P[i] = GetBit(ref uStartBit) ? (byte)0 : (byte)1;
}
if (ms_aInfo[uMode].uPBits != 0)
{
for (int i = 0; i < uNumEndPts; i++)
{
int pi = i * ms_aInfo[uMode].uPBits / uNumEndPts;
for (uint ch = 0; ch < BC7_NUM_CHANNELS; ch++)
{
if (RGBAPrec[ch] != RGBAPrecWithP[ch])
{
c[i][ch] = (byte)(c[i][ch] << 1 | P[pi]);
}
}
}
}
for (int i = 0; i < uNumEndPts; i++)
{
c[i] = Unquantize(c[i], RGBAPrecWithP);
}
byte[] w1 = new byte[NUM_PIXELS_PER_BLOCK];
byte[] w2 = new byte[NUM_PIXELS_PER_BLOCK];
// read color indices
for (int i = 0; i < NUM_PIXELS_PER_BLOCK; i++)
{
uint uNumBits = (uint)(IsFixUpOffset(ms_aInfo[uMode].uPartitions, uShape, i) ? uIndexPrec - 1 : uIndexPrec);
if (uStartBit + uNumBits > 128)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
w1[i] = GetBits<byte>(ref uStartBit, (int)uNumBits);
}
// read alpha indices
if (uIndexPrec2 > 0)
{
for (int i = 0; i < NUM_PIXELS_PER_BLOCK; i++)
{
uint uNumBits = (uint)(i > 0 ? uIndexPrec2 : uIndexPrec2 - 1);
if (uStartBit + uNumBits > 128)
{
throw new Exception("BC7: Invalid block encountered during decoding");
}
w2[i] = GetBits<byte>(ref uStartBit, (int)uNumBits);
}
}
int blockSize = (int)Math.Sqrt(NUM_PIXELS_PER_BLOCK);
for (int i = 0; i < NUM_PIXELS_PER_BLOCK; ++i)
{
uint uRegion = g_aPartitionTable[uPartitions][uShape][i];
LDRColorA outPixel;
if (uIndexPrec2 == 0)
{
LDRColorA.Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w1[i], w1[i], uIndexPrec, uIndexPrec, out outPixel);
}
else
{
if (uIndexMode == 0)
{
LDRColorA.Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w1[i], w2[i], uIndexPrec, uIndexPrec2, out outPixel);
}
else
{
LDRColorA.Interpolate(c[uRegion << 1], c[(uRegion << 1) + 1], w2[i], w1[i], uIndexPrec2, uIndexPrec, out outPixel);
}
}
switch (uRotation)
{
case 1: { byte t = outPixel.r; outPixel.r = outPixel.a; outPixel.a = t; } break;
case 2: { byte t = outPixel.g; outPixel.g = outPixel.a; outPixel.a = t; } break;
case 3: { byte t = outPixel.b; outPixel.b = outPixel.a; outPixel.a = t; } break;
}
int dataX = x * blockSize + i % blockSize;
int dataY = y * blockSize + i / blockSize;
int dataOffset = (dataY * blockCountX * 4 + dataX) * 4;
if (outPixel.a != 0)
{
// final texture uses premultiplied alpha ????
//outPixel.r = (byte)((float)outPixel.r / outPixel.a * 255f);
//outPixel.g = (byte)((float)outPixel.g / outPixel.a * 255f);
//outPixel.b = (byte)((float)outPixel.b / outPixel.a * 255f);
// linear to pm
//outPixel.r = (byte)((float)outPixel.r * outPixel.a / 255f);
//outPixel.g = (byte)((float)outPixel.g * outPixel.a / 255f);
//outPixel.b = (byte)((float)outPixel.b * outPixel.a / 255f);
}
// TODO: SRGB check probably should be somewhere else.
if (dxgiFormat == ImageConverter.DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM_SRGB)
{
float r = outPixel.r * (1f / 255f);
float g = outPixel.g * (1f / 255f);
float b = outPixel.b * (1f / 255f);
outPixel.r = (byte)Math.Round(D3DX_SRGB_to_FLOAT_inexact(r) * 255f, 0);
outPixel.g = (byte)Math.Round(D3DX_SRGB_to_FLOAT_inexact(g) * 255f, 0);
outPixel.b = (byte)Math.Round(D3DX_SRGB_to_FLOAT_inexact(b) * 255f, 0);
//outPixel.r = (byte)Math.Round(255f * D3DX_SRGB_to_FLOAT(outPixel.r), 0);
//outPixel.g = (byte)Math.Round(255f * D3DX_SRGB_to_FLOAT(outPixel.g), 0);
//outPixel.b = (byte)Math.Round(255f * D3DX_SRGB_to_FLOAT(outPixel.b), 0);
}
imageData[dataOffset] = outPixel.r;
imageData[dataOffset + 1] = outPixel.g;
imageData[dataOffset + 2] = outPixel.b;
imageData[dataOffset + 3] = outPixel.a;
//pOut[i] = HDRColorA(outPixel);
}
}
else
{
throw new Exception("BC7: Reserved mode 8 encountered during decoding");
}
}
private static BitArray m_uBits;
const uint BC7_MAX_REGIONS = 3;
const uint BC7_MAX_INDICES = 16;
const int BC7_NUM_CHANNELS = 4;
const int BC7_MAX_SHAPES = 64;
const int BC67_WEIGHT_MAX = 64;
const int BC67_WEIGHT_SHIFT = 6;
const int BC67_WEIGHT_ROUND = 32;
// Because these are used in SAL annotations, they need to remain macros rather than const values
const int NUM_PIXELS_PER_BLOCK = 16;
private static readonly ModeInfo[] ms_aInfo = new ModeInfo[]
{
/// Mode 0: Color only, 3 Subsets, RGBP 4441 (unique P-bit), 3-bit indecies, 16 partitions
new ModeInfo (2, 4, 6, 0, 0, 3, 0, new LDRColorA(4,4,4,0), new LDRColorA(5,5,5,0)),
/// Mode 1: Color only, 2 Subsets, RGBP 6661 (shared P-bit), 3-bit indecies, 64 partitions
new ModeInfo (1, 6, 2, 0, 0, 3, 0, new LDRColorA(6,6,6,0), new LDRColorA(7,7,7,0)),
/// Mode 2: Color only, 3 Subsets, RGB 555, 2-bit indecies, 64 partitions
new ModeInfo(2, 6, 0, 0, 0, 2, 0, new LDRColorA(5,5,5,0), new LDRColorA(5,5,5,0)),
/// Mode 3: Color only, 2 Subsets, RGBP 7771 (unique P-bit), 2-bits indecies, 64 partitions
new ModeInfo(1, 6, 4, 0, 0, 2, 0, new LDRColorA(7,7,7,0), new LDRColorA(8,8,8,0)),
/// Mode 4: Color w/ Separate Alpha, 1 Subset, RGB 555, A6, 16x2/16x3-bit indices, 2-bit rotation, 1-bit index selector
new ModeInfo(0, 0, 0, 2, 1, 2, 3, new LDRColorA(5,5,5,6), new LDRColorA(5,5,5,6)),
/// Mode 5: Color w/ Separate Alpha, 1 Subset, RGB 777, A8, 16x2/16x2-bit indices, 2-bit rotation
new ModeInfo(0, 0, 0, 2, 0, 2, 2, new LDRColorA(7,7,7,8), new LDRColorA(7,7,7,8)),
/// Mode 6: Color+Alpha, 1 Subset, RGBAP 77771 (unique P-bit), 16x4-bit indecies
new ModeInfo(0, 0, 2, 0, 0, 4, 0, new LDRColorA(7,7,7,7), new LDRColorA(8,8,8,8)),
/// Mode 7: Color+Alpha, 2 Subsets, RGBAP 55551 (unique P-bit), 2-bit indices, 64 partitions
new ModeInfo(1, 6, 4, 0, 0, 2, 0, new LDRColorA(5,5,5,5), new LDRColorA(6,6,6,6))
};
// Partition, Shape, Fixup
static readonly uint[][][] g_aFixUp = new uint[][][]
{
new uint[][]{ // No fix-ups for 1st subset for BC6H or BC7
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },
new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 },new uint[]{ 0, 0, 0 }
},
new uint[][]{ // BC6H/BC7 Partition Set Fixups for 2 Subsets
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0, 2, 0 },
new uint[]{ 0, 2, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0, 2, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 2, 0 },
new uint[]{ 0, 8, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 2, 0 },
// BC7 Partition Set Fixups for 2 Subsets (second-half)
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0, 6, 0 },new uint[]{ 0, 8, 0 },
new uint[]{ 0, 2, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0, 2, 0 },new uint[]{ 0, 8, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 2, 0 },
new uint[]{ 0, 2, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0, 6, 0 },
new uint[]{ 0, 6, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 6, 0 },new uint[]{ 0, 8, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 2, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },new uint[]{ 0,15, 0 },
new uint[]{ 0,15, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0, 2, 0 },new uint[]{ 0,15, 0 }
},
new uint[][]{ // BC7 Partition Set Fixups for 3 Subsets
new uint[]{ 0, 3,15 },new uint[]{ 0, 3, 8 },new uint[]{ 0,15, 8 },new uint[]{ 0,15, 3 },
new uint[]{ 0, 8,15 },new uint[]{ 0, 3,15 },new uint[]{ 0,15, 3 },new uint[]{ 0,15, 8 },
new uint[]{ 0, 8,15 },new uint[]{ 0, 8,15 },new uint[]{ 0, 6,15 },new uint[]{ 0, 6,15 },
new uint[]{ 0, 6,15 },new uint[]{ 0, 5,15 },new uint[]{ 0, 3,15 },new uint[]{ 0, 3, 8 },
new uint[]{ 0, 3,15 },new uint[]{ 0, 3, 8 },new uint[]{ 0, 8,15 },new uint[]{ 0,15, 3 },
new uint[]{ 0, 3,15 },new uint[]{ 0, 3, 8 },new uint[]{ 0, 6,15 },new uint[]{ 0,10, 8 },
new uint[]{ 0, 5, 3 },new uint[]{ 0, 8,15 },new uint[]{ 0, 8, 6 },new uint[]{ 0, 6,10 },
new uint[]{ 0, 8,15 },new uint[]{ 0, 5,15 },new uint[]{ 0,15,10 },new uint[]{ 0,15, 8 },
new uint[]{ 0, 8,15 },new uint[]{ 0,15, 3 },new uint[]{ 0, 3,15 },new uint[]{ 0, 5,10 },
new uint[]{ 0, 6,10 },new uint[]{ 0,10, 8 },new uint[]{ 0, 8, 9 },new uint[]{ 0,15,10 },
new uint[]{ 0,15, 6 },new uint[]{ 0, 3,15 },new uint[]{ 0,15, 8 },new uint[]{ 0, 5,15 },
new uint[]{ 0,15, 3 },new uint[]{ 0,15, 6 },new uint[]{ 0,15, 6 },new uint[]{ 0,15, 8 },
new uint[]{ 0, 3,15 },new uint[]{ 0,15, 3 },new uint[]{ 0, 5,15 },new uint[]{ 0, 5,15 },
new uint[]{ 0, 5,15 },new uint[]{ 0, 8,15 },new uint[]{ 0, 5,15 },new uint[]{ 0,10,15 },
new uint[]{ 0, 5,15 },new uint[]{ 0,10,15 },new uint[]{ 0, 8,15 },new uint[]{ 0,13,15 },
new uint[]{ 0,15, 3 },new uint[]{ 0,12,15 },new uint[]{ 0, 3,15 },new uint[]{ 0, 3, 8 }
}
};
// Partition, Shape, Pixel (index into 4x4 block)
static readonly uint[][][] g_aPartitionTable = new uint[][][]
{
new uint[][]{ // 1 Region case has no subsets (all 0)
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
},
new uint[][]{ // BC6H/BC7 Partition Set for 2 Subsets
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 }, // Shape 0
new uint[]{ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 }, // Shape 1
new uint[]{ 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 }, // Shape 2
new uint[]{ 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 3
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 }, // Shape 4
new uint[]{ 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 5
new uint[]{ 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 6
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 7
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 }, // Shape 8
new uint[]{ 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 9
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 }, // Shape 10
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 }, // Shape 11
new uint[]{ 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 12
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 13
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 14
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 }, // Shape 15
new uint[]{ 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1 }, // Shape 16
new uint[]{ 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, // Shape 17
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0 }, // Shape 18
new uint[]{ 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, // Shape 19
new uint[]{ 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }, // Shape 20
new uint[]{ 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 }, // Shape 21
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 }, // Shape 22
new uint[]{ 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1 }, // Shape 23
new uint[]{ 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 }, // Shape 24
new uint[]{ 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 }, // Shape 25
new uint[]{ 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 }, // Shape 26
new uint[]{ 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0 }, // Shape 27
new uint[]{ 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 }, // Shape 28
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, // Shape 29
new uint[]{ 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0 }, // Shape 30
new uint[]{ 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 }, // Shape 31
// BC7 Partition Set for 2 Subsets (second-half)
new uint[]{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 }, // Shape 32
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 }, // Shape 33
new uint[]{ 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0 }, // Shape 34
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0 }, // Shape 35
new uint[]{ 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0 }, // Shape 36
new uint[]{ 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0 }, // Shape 37
new uint[]{ 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1 }, // Shape 38
new uint[]{ 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 }, // Shape 39
new uint[]{ 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0 }, // Shape 40
new uint[]{ 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 }, // Shape 41
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 }, // Shape 42
new uint[]{ 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 }, // Shape 43
new uint[]{ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }, // Shape 44
new uint[]{ 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1 }, // Shape 45
new uint[]{ 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 }, // Shape 46
new uint[]{ 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 }, // Shape 47
new uint[]{ 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // Shape 48
new uint[]{ 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 }, // Shape 49
new uint[]{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0 }, // Shape 50
new uint[]{ 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 }, // Shape 51
new uint[]{ 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 }, // Shape 52
new uint[]{ 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1 }, // Shape 53
new uint[]{ 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0 }, // Shape 54
new uint[]{ 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0 }, // Shape 55
new uint[]{ 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 }, // Shape 56
new uint[]{ 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1 }, // Shape 57
new uint[]{ 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 }, // Shape 58
new uint[]{ 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 }, // Shape 59
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 }, // Shape 60
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }, // Shape 61
new uint[]{ 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 }, // Shape 62
new uint[]{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1 } // Shape 63
},
new uint[][]{ // BC7 Partition Set for 3 Subsets
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 1, 2, 2, 2, 2 }, // Shape 0
new uint[]{ 0, 0, 0, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1 }, // Shape 1
new uint[]{ 0, 0, 0, 0, 2, 0, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1 }, // Shape 2
new uint[]{ 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 1, 1, 1 }, // Shape 3
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2 }, // Shape 4
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 2, 2 }, // Shape 5
new uint[]{ 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 }, // Shape 6
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1 }, // Shape 7
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2 }, // Shape 8
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 }, // Shape 9
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 10
new uint[]{ 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2 }, // Shape 11
new uint[]{ 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2 }, // Shape 12
new uint[]{ 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2 }, // Shape 13
new uint[]{ 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2 }, // Shape 14
new uint[]{ 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0 }, // Shape 15
new uint[]{ 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2 }, // Shape 16
new uint[]{ 0, 1, 1, 1, 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0 }, // Shape 17
new uint[]{ 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2 }, // Shape 18
new uint[]{ 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1 }, // Shape 19
new uint[]{ 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2 }, // Shape 20
new uint[]{ 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 2, 1 }, // Shape 21
new uint[]{ 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2 }, // Shape 22
new uint[]{ 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 1, 0, 2, 2, 1, 0 }, // Shape 23
new uint[]{ 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0 }, // Shape 24
new uint[]{ 0, 0, 1, 2, 0, 0, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2 }, // Shape 25
new uint[]{ 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1, 0, 1, 1, 0 }, // Shape 26
new uint[]{ 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1 }, // Shape 27
new uint[]{ 0, 0, 2, 2, 1, 1, 0, 2, 1, 1, 0, 2, 0, 0, 2, 2 }, // Shape 28
new uint[]{ 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 0, 2, 2, 2, 2, 2 }, // Shape 29
new uint[]{ 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1 }, // Shape 30
new uint[]{ 0, 0, 0, 0, 2, 0, 0, 0, 2, 2, 1, 1, 2, 2, 2, 1 }, // Shape 31
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 2, 2, 2 }, // Shape 32
new uint[]{ 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 2, 0, 0, 1, 1 }, // Shape 33
new uint[]{ 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 2, 2, 0, 2, 2, 2 }, // Shape 34
new uint[]{ 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0 }, // Shape 35
new uint[]{ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0 }, // Shape 36
new uint[]{ 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0 }, // Shape 37
new uint[]{ 0, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 0, 1, 2, 0 }, // Shape 38
new uint[]{ 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1 }, // Shape 39
new uint[]{ 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1 }, // Shape 40
new uint[]{ 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 41
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1 }, // Shape 42
new uint[]{ 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2, 1, 1, 2, 2 }, // Shape 43
new uint[]{ 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1 }, // Shape 44
new uint[]{ 0, 2, 2, 0, 1, 2, 2, 1, 0, 2, 2, 0, 1, 2, 2, 1 }, // Shape 45
new uint[]{ 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 1 }, // Shape 46
new uint[]{ 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1 }, // Shape 47
new uint[]{ 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2 }, // Shape 48
new uint[]{ 0, 2, 2, 2, 0, 1, 1, 1, 0, 2, 2, 2, 0, 1, 1, 1 }, // Shape 49
new uint[]{ 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2 }, // Shape 50
new uint[]{ 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2 }, // Shape 51
new uint[]{ 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2 }, // Shape 52
new uint[]{ 0, 0, 0, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2 }, // Shape 53
new uint[]{ 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2 }, // Shape 54
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2 }, // Shape 55
new uint[]{ 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 56
new uint[]{ 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2 }, // Shape 57
new uint[]{ 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2 }, // Shape 58
new uint[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2 }, // Shape 59
new uint[]{ 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1 }, // Shape 60
new uint[]{ 0, 2, 2, 2, 1, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2 }, // Shape 61
new uint[]{ 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }, // Shape 62
new uint[]{ 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 2, 2, 2, 0 } // Shape 63
}
};
static readonly int[] g_aWeights2 = { 0, 21, 43, 64 };
static readonly int[] g_aWeights3 = { 0, 9, 18, 27, 37, 46, 55, 64 };
static readonly int[] g_aWeights4 = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };
private static void assert(bool condition)
{
if (!condition)
{
Debugger.Break();
}
}
private static bool GetBit(ref uint uStartBit)
{
bool ret = m_uBits[(int)uStartBit];
uStartBit++;
return ret;
}
private static bool GetBit(ref int uStartBit)
{
bool ret = m_uBits[uStartBit];
uStartBit++;
return ret;
}
private static T GetBits<T>(ref int uStartBit, int uNumBits)
{
if (uNumBits == 0)
return default;
BitArray newBits = new BitArray(uNumBits);
for (int i = 0; i < uNumBits; i++)
{
newBits[i] = m_uBits[uStartBit];
uStartBit++;
}
if (uNumBits > 32)
{
Debugger.Break();
// TODO: this exceeds the size of the uint
}
int[] theIntArray = new int[(newBits.Length + 31) / 32];
new BitArray(newBits).CopyTo(theIntArray, 0);
if (theIntArray[0] > 255)
{
Debugger.Break();
// TODO: might be a converstion issue with int>uint
}
return (T)Convert.ChangeType(theIntArray[0], typeof(T));
}
class LDRColorA
{
public byte r, g, b, a;
public LDRColorA() { }
public LDRColorA(byte rColor, byte gColor, byte bColor, byte aColor)
{
r = rColor;
g = gColor;
b = bColor;
a = aColor;
}
public byte this[uint uElement]
{
get
{
switch (uElement)
{
case 0: return r;
case 1: return g;
case 2: return b;
case 3: return a;
default: assert(false); return r;
}
}
set
{
switch (uElement)
{
case 0: r = value; break;
case 1: g = value; break;
case 2: b = value; break;
case 3: a = value; break;
default: Debugger.Break(); break;
}
}
}
//static void InterpolateRGB(_In_ const LDRColorA& c0, _In_ const LDRColorA& c1, _In_ size_t wc, _In_ _In_range_(2, 4) size_t wcprec, _Out_ LDRColorA& out)
static void InterpolateRGB(LDRColorA c0, LDRColorA c1, int wc, int wcprec, ref LDRColorA outVal)
{
int[] aWeights;
switch (wcprec)
{
case 2: aWeights = g_aWeights2; assert(wc < 4); break;
case 3: aWeights = g_aWeights3; assert(wc < 8); break;
case 4: aWeights = g_aWeights4; assert(wc < 16); break;
default: assert(false); outVal.r = outVal.g = outVal.b = 0; return;
}
if (c1.r > 60)
{
}
outVal.r = (byte)(c0.r * (BC67_WEIGHT_MAX - aWeights[wc]) + c1.r * aWeights[wc] + BC67_WEIGHT_ROUND >> BC67_WEIGHT_SHIFT);
outVal.g = (byte)(c0.g * (BC67_WEIGHT_MAX - aWeights[wc]) + c1.g * aWeights[wc] + BC67_WEIGHT_ROUND >> BC67_WEIGHT_SHIFT);
outVal.b = (byte)(c0.b * (BC67_WEIGHT_MAX - aWeights[wc]) + c1.b * aWeights[wc] + BC67_WEIGHT_ROUND >> BC67_WEIGHT_SHIFT);
}
// static void InterpolateA(_In_ const LDRColorA& c0, _In_ const LDRColorA& c1, _In_ size_t wa, _In_range_(2, 4) _In_ size_t waprec, _Out_ LDRColorA& out)
static void InterpolateA(LDRColorA c0, LDRColorA c1, int wa, int waprec, ref LDRColorA outVal)
{
int[] aWeights;
switch (waprec)
{
case 2: aWeights = g_aWeights2; assert(wa < 4); break;
case 3: aWeights = g_aWeights3; assert(wa < 8); break;
case 4: aWeights = g_aWeights4; assert(wa < 16); break;
default: assert(false); outVal.a = 0; return;
}
outVal.a = (byte)(c0.a * (BC67_WEIGHT_MAX - aWeights[wa]) + c1.a * aWeights[wa] + BC67_WEIGHT_ROUND >> BC67_WEIGHT_SHIFT);
}
// static void Interpolate(_In_ const LDRColorA& c0, _In_ const LDRColorA& c1, _In_ size_t wc, _In_ size_t wa, _In_ _In_range_(2, 4) size_t wcprec, _In_ _In_range_(2, 4) size_t waprec, _Out_ LDRColorA& out)
public static void Interpolate(LDRColorA c0, LDRColorA c1, int wc, int wa, int wcprec, int waprec, out LDRColorA outVal)
{
outVal = new LDRColorA();
InterpolateRGB(c0, c1, wc, wcprec, ref outVal);
InterpolateA(c0, c1, wa, waprec, ref outVal);
}
}
class ModeInfo
{
public byte uPartitions;
public byte uPartitionBits;
public byte uPBits;
public byte uRotationBits;
public byte uIndexModeBits;
public byte uIndexPrec;
public byte uIndexPrec2;
public LDRColorA RGBAPrec;
public LDRColorA RGBAPrecWithP;
public ModeInfo(byte partitions, byte partitionBits, byte pBits, byte rotationBits, byte indexModeBits, byte indexPrec, byte indexPrec2, LDRColorA rgbaPrec, LDRColorA rgbaPrecWithP)
{
uPartitions = partitions;
uPartitionBits = partitionBits;
uPBits = pBits;
uRotationBits = rotationBits;
uIndexModeBits = indexModeBits;
uIndexPrec = indexPrec;
uIndexPrec2 = indexPrec2;
RGBAPrec = rgbaPrec;
RGBAPrecWithP = rgbaPrecWithP;
}
};
static byte Unquantize(byte comp, int uPrec)
{
assert(0 < uPrec && uPrec <= 8);
comp = (byte)(comp << 8 - uPrec);
return (byte)(comp | comp >> uPrec);
}
static LDRColorA Unquantize(LDRColorA c, LDRColorA RGBAPrec)
{
LDRColorA q = new LDRColorA();
q.r = Unquantize(c.r, RGBAPrec.r);
q.g = Unquantize(c.g, RGBAPrec.g);
q.b = Unquantize(c.b, RGBAPrec.b);
q.a = RGBAPrec.a > 0 ? Unquantize(c.a, RGBAPrec.a) : (byte)255;
return q;
}
// inline bool IsFixUpOffset(_In_range_(0, 2) size_t uPartitions, _In_range_(0, 63) size_t uShape, _In_range_(0, 15) size_t uOffset)
static bool IsFixUpOffset(uint uPartitions, uint uShape, int uOffset)
{
assert(uPartitions < 3 && uShape < 64 && uOffset < 16);
for (int p = 0; p <= uPartitions; p++)
{
if (uOffset == g_aFixUp[uPartitions][uShape][p])
{
return true;
}
}
return false;
}
#endregion
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff728749(v=vs.85).aspx
// D3DX_DXGIFormatConvert.inl
private static float D3DX_SRGB_to_FLOAT_inexact(float srgb)
{
float linear;
if (srgb <= 0.04045f)
linear = srgb / 12.92f;
else
linear = (float)Math.Pow((srgb + 0.055f) / 1.055f, 2.4f);
return linear;
}
// https://gamedevdaily.io/the-srgb-learning-curve-773b7f68cf7a
private static float D3DX_FLOAT_to_SRGB(float linear)
{
float srgb;
if (linear < 0.0031308f)
srgb = linear * 12.92f;
else
srgb = 1.055f * (float)Math.Pow(linear, 1.0f / 2.4f) - 0.055f;
return srgb;
}
static readonly uint[] D3DX_SRGBTable =
{
0x00000000,0x399f22b4,0x3a1f22b4,0x3a6eb40e,0x3a9f22b4,0x3ac6eb61,0x3aeeb40e,0x3b0b3e5d,
0x3b1f22b4,0x3b33070b,0x3b46eb61,0x3b5b518d,0x3b70f18d,0x3b83e1c6,0x3b8fe616,0x3b9c87fd,
0x3ba9c9b7,0x3bb7ad6f,0x3bc63549,0x3bd56361,0x3be539c1,0x3bf5ba70,0x3c0373b5,0x3c0c6152,
0x3c15a703,0x3c1f45be,0x3c293e6b,0x3c3391f7,0x3c3e4149,0x3c494d43,0x3c54b6c7,0x3c607eb1,
0x3c6ca5df,0x3c792d22,0x3c830aa8,0x3c89af9f,0x3c9085db,0x3c978dc5,0x3c9ec7c2,0x3ca63433,
0x3cadd37d,0x3cb5a601,0x3cbdac20,0x3cc5e639,0x3cce54ab,0x3cd6f7d5,0x3cdfd010,0x3ce8ddb9,
0x3cf2212c,0x3cfb9ac1,0x3d02a569,0x3d0798dc,0x3d0ca7e6,0x3d11d2af,0x3d171963,0x3d1c7c2e,
0x3d21fb3c,0x3d2796b2,0x3d2d4ebb,0x3d332380,0x3d39152b,0x3d3f23e3,0x3d454fd1,0x3d4b991c,
0x3d51ffef,0x3d58846a,0x3d5f26b7,0x3d65e6fe,0x3d6cc564,0x3d73c20f,0x3d7add29,0x3d810b67,
0x3d84b795,0x3d887330,0x3d8c3e4a,0x3d9018f6,0x3d940345,0x3d97fd4a,0x3d9c0716,0x3da020bb,
0x3da44a4b,0x3da883d7,0x3daccd70,0x3db12728,0x3db59112,0x3dba0b3b,0x3dbe95b5,0x3dc33092,
0x3dc7dbe2,0x3dcc97b6,0x3dd1641f,0x3dd6412c,0x3ddb2eef,0x3de02d77,0x3de53cd5,0x3dea5d19,
0x3def8e52,0x3df4d091,0x3dfa23e8,0x3dff8861,0x3e027f07,0x3e054280,0x3e080ea3,0x3e0ae378,
0x3e0dc105,0x3e10a754,0x3e13966b,0x3e168e52,0x3e198f10,0x3e1c98ad,0x3e1fab30,0x3e22c6a3,
0x3e25eb09,0x3e29186c,0x3e2c4ed0,0x3e2f8e41,0x3e32d6c4,0x3e362861,0x3e39831e,0x3e3ce703,
0x3e405416,0x3e43ca5f,0x3e4749e4,0x3e4ad2ae,0x3e4e64c2,0x3e520027,0x3e55a4e6,0x3e595303,
0x3e5d0a8b,0x3e60cb7c,0x3e6495e0,0x3e6869bf,0x3e6c4720,0x3e702e0c,0x3e741e84,0x3e781890,
0x3e7c1c38,0x3e8014c2,0x3e82203c,0x3e84308d,0x3e8645ba,0x3e885fc5,0x3e8a7eb2,0x3e8ca283,
0x3e8ecb3d,0x3e90f8e1,0x3e932b74,0x3e9562f8,0x3e979f71,0x3e99e0e2,0x3e9c274e,0x3e9e72b7,
0x3ea0c322,0x3ea31892,0x3ea57308,0x3ea7d289,0x3eaa3718,0x3eaca0b7,0x3eaf0f69,0x3eb18333,
0x3eb3fc18,0x3eb67a18,0x3eb8fd37,0x3ebb8579,0x3ebe12e1,0x3ec0a571,0x3ec33d2d,0x3ec5da17,
0x3ec87c33,0x3ecb2383,0x3ecdd00b,0x3ed081cd,0x3ed338cc,0x3ed5f50b,0x3ed8b68d,0x3edb7d54,
0x3ede4965,0x3ee11ac1,0x3ee3f16b,0x3ee6cd67,0x3ee9aeb6,0x3eec955d,0x3eef815d,0x3ef272ba,
0x3ef56976,0x3ef86594,0x3efb6717,0x3efe6e02,0x3f00bd2d,0x3f02460e,0x3f03d1a7,0x3f055ff9,
0x3f06f106,0x3f0884cf,0x3f0a1b56,0x3f0bb49b,0x3f0d50a0,0x3f0eef67,0x3f1090f1,0x3f12353e,
0x3f13dc51,0x3f15862b,0x3f1732cd,0x3f18e239,0x3f1a946f,0x3f1c4971,0x3f1e0141,0x3f1fbbdf,
0x3f21794e,0x3f23398e,0x3f24fca0,0x3f26c286,0x3f288b41,0x3f2a56d3,0x3f2c253d,0x3f2df680,
0x3f2fca9e,0x3f31a197,0x3f337b6c,0x3f355820,0x3f3737b3,0x3f391a26,0x3f3aff7c,0x3f3ce7b5,
0x3f3ed2d2,0x3f40c0d4,0x3f42b1be,0x3f44a590,0x3f469c4b,0x3f4895f1,0x3f4a9282,0x3f4c9201,
0x3f4e946e,0x3f5099cb,0x3f52a218,0x3f54ad57,0x3f56bb8a,0x3f58ccb0,0x3f5ae0cd,0x3f5cf7e0,
0x3f5f11ec,0x3f612eee,0x3f634eef,0x3f6571e9,0x3f6797e3,0x3f69c0d6,0x3f6beccd,0x3f6e1bbf,
0x3f704db8,0x3f7282af,0x3f74baae,0x3f76f5ae,0x3f7933b9,0x3f7b74c6,0x3f7db8e0,0x3f800000
};
static float D3DX_SRGB_to_FLOAT(uint val)
{
return BitConverter.ToSingle(BitConverter.GetBytes(D3DX_SRGBTable[val]), 0);
//return (float)D3DX_SRGBTable[val];
}
#endregion
}