Initial commit with a few modifications

This commit is contained in:
Pavel Krajcevski 2012-08-24 15:56:45 -04:00
commit efdca4b5bb
21 changed files with 8700 additions and 0 deletions

View File

@ -0,0 +1,57 @@
INCLUDE_DIRECTORIES(${TexC_SOURCE_DIR}/BPTCEncoder/include)
INCLUDE(CheckCXXSourceCompiles)
SET(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
IF(CMAKE_COMPILER_IS_GNUCC)
SET(CMAKE_REQUIRED_FLAGS -msse4.1)
CHECK_CXX_SOURCE_COMPILES("config/testsse4.1.cpp" HAS_SSE_41)
IF(HAS_SSE_41)
SET(CMAKE_REQUIRED_FLAGS -msse4.2)
CHECK_CXX_SOURCE_COMPILES("config/testsse4.2.cpp" HAS_SSE_POPCNT)
ENDIF(HAS_SSE_41)
ELSEIF(MSVC)
ENDIF()
SET(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
CONFIGURE_FILE(
"config/BC7Config.h.in"
"src/BC7Config.h"
)
IF(CMAKE_COMPILER_IS_GNUCC)
ADD_DEFINITIONS(-fasm-blocks)
ENDIF(CMAKE_COMPILER_IS_GNUCC)
SET( HEADERS
src/BC7CompressionMode.h
src/BC7IntTypes.h
src/BitStream.h
src/RGBAEndpoints.h
)
SET( SOURCES
src/BC7Compressor.cpp
src/RGBAEndpoints.cpp
)
IF( HAS_SSE_41 )
SET( HEADERS
${HEADERS}
src/RGBAEndpointsSIMD.h
src/BC7CompressionModeSIMD.h
)
SET( SOURCES
${SOURCES}
src/BC7CompressorSIMD.cpp
src/RGBAEndpointsSIMD.cpp
)
ENDIF( HAS_SSE_41 )
ADD_LIBRARY( BPTCEncoder
${SOURCES}
${SIMD_SOURCES}
)

View File

@ -0,0 +1,8 @@
// Copyright (c) 2012 Pavel Krajcevski
// All Rights Reserved
// BC7Config.h.in -- This file contains variables that are introduced
// explicitly by the CMake build process.
// Do we have the proper popcnt instruction defined?
#define HAS_SSE_POPCNT @HAS_SSE_POPCNT@

View File

@ -0,0 +1,10 @@
#include <smmintrin.h>
int main() {
const __m128 fv = _mm_set1_ps(1.0f);
const __m128 fv2 = _mm_set1_ps(2.0f);
const __m128 ans = _mm_blend_ps(fv, fv2, 2);
return ((int *)(&ans))[0];
}

View File

@ -0,0 +1,61 @@
//--------------------------------------------------------------------------------------
// Copyright 2011 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies. Intel makes no representations about the
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//
//--------------------------------------------------------------------------------------
namespace BC7C
{
// This is the error metric that is applied to our error measurement algorithm
// in order to bias calculation towards results that are more in-line with
// how the Human Visual System works. Uniform error means that each color
// channel is treated equally. For a while, the widely accepted non-uniform metric
// has been to give red 30%, green 59% and blue 11% weight when computing the error
// between two pixels.
enum ErrorMetric
{
eErrorMetric_Uniform, // Treats r, g, and b channels equally
eErrorMetric_Nonuniform, // { 0.3, 0.59, 0.11 }
kNumErrorMetrics
};
// Sets the error metric to be the one specified.
void SetErrorMetric(ErrorMetric e);
// Retreives a float4 pointer for the r, g, b, a weights for each color channel, in
// that order, based on the current error metric.
const float *GetErrorMetric();
// Returns the enumeration for the current error metric.
ErrorMetric GetErrorMetricEnum();
// Sets the number of steps that we use to perform simulated annealing. In general, a
// larger number produces better results. The default is set to 50. This metric works
// on a logarithmic scale -- twice the value will double the compute time, but only
// decrease the error by two times a factor.
void SetQualityLevel(int q);
int GetQualityLevel();
// Compress the image given as RGBA data to BC7 format. Width and Height are the dimensions of
// the image in pixels.
void CompressImageBC7(const unsigned char *inBuf, unsigned char *outBuf, int width, int height);
// Compress the image given as RGBA data to BC7 format using an algorithm optimized for SIMD
// enabled platforms. Width and Height are the dimensions of the image in pixels.
void CompressImageBC7SIMD(const unsigned char* inBuf, unsigned char* outBuf, int width, int height);
// Decompress the image given as BC7 data to R8G8B8A8 format. Width and Height are the dimensions of the image in pixels.
void DecompressImageBC7SIMD(const unsigned char* inBuf, unsigned char* outBuf, int width, int height);
}

View File

@ -0,0 +1,191 @@
//--------------------------------------------------------------------------------------
// Copyright 2011 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies. Intel makes no representations about the
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//
//--------------------------------------------------------------------------------------
#ifndef __BC7_COMPRESSIONMODE_SIMD_H__
#define __BC7_COMPRESSIONMODE_SIMD_H__
#include "RGBAEndpoints.h"
// Forward Declarations
class BitStream;
const int kMaxEndpoints = 3;
static const int kPBits[4][2] = {
{ 0, 0 },
{ 0, 1 },
{ 1, 0 },
{ 1, 1 }
};
// Abstract class that outlines all of the different settings for BC7 compression modes
// Note that at the moment, we only support modes 0-3, so we don't deal with alpha channels.
class BC7CompressionMode {
public:
static const int kMaxNumSubsets = 3;
static const int kNumModes = 8;
explicit BC7CompressionMode(int mode, bool opaque = true) : m_IsOpaque(opaque), m_Attributes(&(kModeAttributes[mode])), m_RotateMode(0), m_IndexMode(0) { }
~BC7CompressionMode() { }
static int NumUses[8];
static void ResetNumUses() { memset(NumUses, 0, sizeof(NumUses)); }
double Compress(BitStream &stream, const int shapeIdx, const RGBACluster *clusters);
// This switch controls the quality of the simulated annealing optimizer. We will not make
// more than this many steps regardless of how bad the error is. Higher values will produce
// better quality results but will run slower. Default is 20.
static int MaxAnnealingIterations; // This is a setting
static const int kMaxAnnealingIterations = 256; // This is a limit
enum EPBitType {
ePBitType_Shared,
ePBitType_NotShared,
ePBitType_None
};
static struct Attributes {
int modeNumber;
int numPartitionBits;
int numSubsets;
int numBitsPerIndex;
int numBitsPerAlpha;
int colorChannelPrecision;
int alphaChannelPrecision;
bool hasRotation;
bool hasIdxMode;
EPBitType pbitType;
} kModeAttributes[kNumModes];
static const Attributes *GetAttributesForMode(int mode) {
if(mode < 0 || mode >= 8) return NULL;
return &kModeAttributes[mode];
}
private:
const Attributes *const m_Attributes;
int m_RotateMode;
int m_IndexMode;
void SetIndexMode(int mode) { m_IndexMode = mode; }
void SetRotationMode(int mode) { m_RotateMode = mode; }
int GetRotationMode() const { return m_Attributes->hasRotation? m_RotateMode : 0; }
int GetModeNumber() const { return m_Attributes->modeNumber; }
int GetNumberOfPartitionBits() const { return m_Attributes->numPartitionBits; }
int GetNumberOfSubsets() const { return m_Attributes->numSubsets; }
int GetNumberOfBitsPerIndex(int indexMode = -1) const {
if(indexMode < 0) indexMode = m_IndexMode;
if(indexMode == 0)
return m_Attributes->numBitsPerIndex;
else
return m_Attributes->numBitsPerAlpha;
}
int GetNumberOfBitsPerAlpha(int indexMode = -1) const {
if(indexMode < 0) indexMode = m_IndexMode;
if(indexMode == 0)
return m_Attributes->numBitsPerAlpha;
else
return m_Attributes->numBitsPerIndex;
}
// If we handle alpha separately, then we will consider the alpha channel
// to be not used whenever we do any calculations...
int GetAlphaChannelPrecision() const {
if(m_Attributes->hasRotation) return 0;
else return m_Attributes->alphaChannelPrecision;
}
RGBAVector GetErrorMetric() const {
const float *w = BC7C::GetErrorMetric();
switch(GetRotationMode()) {
default:
case 0: return RGBAVector(w[0], w[1], w[2], w[3]);
case 1: return RGBAVector(w[3], w[1], w[2], w[0]);
case 2: return RGBAVector(w[0], w[3], w[2], w[1]);
case 3: return RGBAVector(w[0], w[1], w[3], w[2]);
}
}
EPBitType GetPBitType() const { return m_Attributes->pbitType; }
unsigned int GetQuantizationMask() const {
const int maskSeed = 0x80000000;
return (
(maskSeed >> (24 + m_Attributes->colorChannelPrecision - 1) & 0xFF) |
(maskSeed >> (16 + m_Attributes->colorChannelPrecision - 1) & 0xFF00) |
(maskSeed >> (8 + m_Attributes->colorChannelPrecision - 1) & 0xFF0000) |
(maskSeed >> (GetAlphaChannelPrecision() - 1) & 0xFF000000)
);
}
int GetNumPbitCombos() const {
switch(GetPBitType()) {
case ePBitType_Shared: return 2;
case ePBitType_NotShared: return 4;
default:
case ePBitType_None: return 1;
}
}
const int *GetPBitCombo(int idx) const {
switch(GetPBitType()) {
case ePBitType_Shared: return (idx)? kPBits[3] : kPBits[0];
case ePBitType_NotShared: return kPBits[idx % 4];
default:
case ePBitType_None: return kPBits[0];
}
}
double OptimizeEndpointsForCluster(const RGBACluster &cluster, RGBAVector &p1, RGBAVector &p2, int *bestIndices, int &bestPbitCombo) const;
struct VisitedState {
RGBAVector p1;
RGBAVector p2;
int pBitCombo;
};
void PickBestNeighboringEndpoints(
const RGBACluster &cluster,
const RGBAVector &p1, const RGBAVector &p2,
const int curPbitCombo,
RGBAVector &np1, RGBAVector &np2,
int &nPbitCombo,
const VisitedState *visitedStates,
int nVisited,
float stepSz = 1.0f
) const;
bool AcceptNewEndpointError(double newError, double oldError, float temp) const;
double CompressSingleColor(const RGBAVector &p, RGBAVector &p1, RGBAVector &p2, int &bestPbitCombo) const;
double CompressCluster(const RGBACluster &cluster, RGBAVector &p1, RGBAVector &p2, int *bestIndices, int &bestPbitCombo) const;
double CompressCluster(const RGBACluster &cluster, RGBAVector &p1, RGBAVector &p2, int *bestIndices, int *alphaIndices) const;
void ClampEndpointsToGrid(RGBAVector &p1, RGBAVector &p2, int &bestPBitCombo) const;
const double m_IsOpaque;
};
extern const uint32 kBC7InterpolationValues[4][16][2];
#endif // __BC7_COMPRESSIONMODE_SIMD_H__

View File

@ -0,0 +1,153 @@
//--------------------------------------------------------------------------------------
// Copyright 2011 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies. Intel makes no representations about the
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//
//--------------------------------------------------------------------------------------
#ifndef __BC7_COMPRESSIONMODE_H__
#define __BC7_COMPRESSIONMODE_H__
#include "BC7IntTypes.h"
#include "RGBAEndpointsSIMD.h"
// Forward Declarations
class BitStream;
static const int kPBits[4][2] = {
{ 0, 0 },
{ 0, 1 },
{ 1, 0 },
{ 1, 1 }
};
// Abstract class that outlines all of the different settings for BC7 compression modes
// Note that at the moment, we only support modes 0-3, so we don't deal with alpha channels.
class BC7CompressionModeSIMD {
public:
static const int kMaxNumSubsets = 3;
static const int kNumModes = 8;
enum EPBitType {
ePBitType_Shared,
ePBitType_NotShared,
ePBitType_None
};
BC7CompressionModeSIMD(int mode, double err) : m_EstimatedError(err), m_Attributes(&(kModeAttributes[mode])) { }
~BC7CompressionModeSIMD() { }
static int NumUses[8];
static void ResetNumUses() { memset(NumUses, 0, sizeof(NumUses)); }
double Compress(BitStream &stream, const int shapeIdx, const RGBAClusterSIMD *clusters) const;
// This switch controls the quality of the simulated annealing optimizer. We will not make
// more than this many steps regardless of how bad the error is. Higher values will produce
// better quality results but will run slower. Default is 50.
static int MaxAnnealingIterations; // This is a setting
private:
static struct Attributes {
int modeNumber;
int numPartitionBits;
int numSubsets;
int numBitsPerIndex;
int redChannelPrecision;
int greenChannelPrecision;
int blueChannelPrecision;
int alphaChannelPrecision;
EPBitType pbitType;
} kModeAttributes[kNumModes];
protected:
const Attributes *const m_Attributes;
int GetModeNumber() const { return m_Attributes->modeNumber; }
int GetNumberOfPartitionBits() const { return m_Attributes->numPartitionBits; }
int GetNumberOfSubsets() const { return m_Attributes->numSubsets; }
int GetNumberOfBitsPerIndex() const { return m_Attributes->numBitsPerIndex; }
int GetRedChannelPrecision() const { return m_Attributes->redChannelPrecision; }
int GetGreenChannelPrecision() const { return m_Attributes->greenChannelPrecision; }
int GetBlueChannelPrecision() const { return m_Attributes->blueChannelPrecision; }
int GetAlphaChannelPrecision() const { return m_Attributes->alphaChannelPrecision; }
EPBitType GetPBitType() const { return m_Attributes->pbitType; }
// !SPEED! Add this to the attributes lookup table
void GetQuantizationMask(__m128i &mask) const {
const int maskSeed = 0x80000000;
mask = _mm_set_epi32(
(GetAlphaChannelPrecision() > 0)? (maskSeed >> (24 + GetAlphaChannelPrecision() - 1) & 0xFF) : 0xFF,
(maskSeed >> (24 + GetBlueChannelPrecision() - 1) & 0xFF),
(maskSeed >> (24 + GetGreenChannelPrecision() - 1) & 0xFF),
(maskSeed >> (24 + GetRedChannelPrecision() - 1) & 0xFF)
);
}
int GetNumPbitCombos() const {
switch(GetPBitType()) {
case ePBitType_Shared: return 2;
case ePBitType_NotShared: return 4;
default:
case ePBitType_None: return 1;
}
}
const int *GetPBitCombo(int idx) const {
switch(GetPBitType()) {
case ePBitType_Shared: return (idx)? kPBits[3] : kPBits[0];
case ePBitType_NotShared: return kPBits[idx % 4];
default:
case ePBitType_None: return kPBits[0];
}
}
double OptimizeEndpointsForCluster(const RGBAClusterSIMD &cluster, RGBAVectorSIMD &p1, RGBAVectorSIMD &p2, __m128i *bestIndices, int &bestPbitCombo) const;
struct VisitedState {
RGBAVectorSIMD p1;
RGBAVectorSIMD p2;
int pBitCombo;
};
void PickBestNeighboringEndpoints(
const RGBAClusterSIMD &cluster,
const RGBAVectorSIMD &p1, const RGBAVectorSIMD &p2,
const int curPbitCombo,
RGBAVectorSIMD &np1, RGBAVectorSIMD &np2,
int &nPbitCombo,
const __m128 &stepVec
) const;
bool AcceptNewEndpointError(float newError, float oldError, float temp) const;
double CompressSingleColor(const RGBAVectorSIMD &p, RGBAVectorSIMD &p1, RGBAVectorSIMD &p2, int &bestPbitCombo) const;
double CompressCluster(const RGBAClusterSIMD &cluster, RGBAVectorSIMD &p1, RGBAVectorSIMD &p2, __m128i *bestIndices, int &bestPbitCombo) const;
void ClampEndpointsToGrid(RGBAVectorSIMD &p1, RGBAVectorSIMD &p2, int &bestPBitCombo) const;
int GetSubsetForIndex(int idx, const int shapeIdx) const;
int GetAnchorIndexForSubset(int subset, const int shapeIdx) const;
double GetEstimatedError() const { return m_EstimatedError; }
const double m_EstimatedError;
};
extern const __m128i kBC7InterpolationValuesSIMD[4][16][2];
extern const uint32 kBC7InterpolationValuesScalar[4][16][2];
#endif // __BC7_COMPRESSIONMODE_H__

1925
BPTCEncoder/src/BC7Compressor.cpp Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
// Copyright 2012 (c) Pavel Krajcevski
// BC7IntTypes.h
// This file contains all of the various platform definitions for fixed width integers
// on various platforms.
// !FIXME! Still needs to be tested on Windows platforms.
#ifdef _MSC_VER
typedef __int16 int16;
typedef __uint16 uint16;
typedef __int32 int32;
typedef __uint32 uint32;
typedef __int8 int8;
typedef __uint8 uint8;
#else
#include <stdint.h>
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef uint8_t uint8;
typedef uint16_t uint16;
typedef uint32_t uint32;
#endif

945
BPTCEncoder/src/BCLookupTables.h Executable file
View File

@ -0,0 +1,945 @@
//--------------------------------------------------------------------------------------
// Copyright 2011 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies. Intel makes no representations about the
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//
//--------------------------------------------------------------------------------------
// Each value from 0 to 255 can be exactly interpolated between two other values
// with 7 bit precision. BC7 Mode 5 gives us this precision, so we can use look-up
// tables to speed up this precision by allowing every value to be 1/3 of the way
// between the two colors specified.
/*
UINT nbits = 7;
UINT lastNum = -1;
UINT vals[255];
UINT valIdx = 0;
for(UINT i = 0; i < 256; i++) {
UINT num = (i >> (8 - nbits));
num <<= (8-nbits);
num |= i >> nbits;
if(num != lastNum) {
lastNum = num;
vals[valIdx++] = num;
}
}
for(UINT i = 0; i < 256; i++) {
UINT mindist = 0xFFFFFFFF;
UINT minj = 0, mink = 0;
UINT tableEntry[2] = { 0, 0 };
mindist = 0xFFFFFFFF;
minj = 0, mink = 0;
for(UINT j = 0; j < valIdx; j++) {
for(UINT k = 0; k < valIdx ; k++) {
UINT combo = (43 * vals[j] + 21 * vals[k] + 32) >> 6;
UINT dist = ((i > combo) ? i - combo : combo - i);
if( dist < mindist )
{
mindist = dist;
minj = j;
mink = k;
}
}
}
assert(mindist == 0);
tableEntry[0] = vals[minj];
tableEntry[1] = vals[mink];
wchar_t tableEntryStr[256];
swprintf(tableEntryStr, 256, L"{ 0x%02x, 0x%02x },\n",
tableEntry[0] >> (8 - nbits),
tableEntry[1] >> (8 - nbits)
);
OutputDebugString(tableEntryStr);
}
*/
static unsigned char Optimal7CompressBC7Mode5[256][2] = {
{ 0x00, 0x00 },
{ 0x00, 0x01 },
{ 0x00, 0x03 },
{ 0x00, 0x04 },
{ 0x00, 0x06 },
{ 0x00, 0x07 },
{ 0x00, 0x09 },
{ 0x00, 0x0a },
{ 0x00, 0x0c },
{ 0x00, 0x0d },
{ 0x00, 0x0f },
{ 0x00, 0x10 },
{ 0x00, 0x12 },
{ 0x00, 0x14 },
{ 0x00, 0x15 },
{ 0x00, 0x17 },
{ 0x00, 0x18 },
{ 0x00, 0x1a },
{ 0x00, 0x1b },
{ 0x00, 0x1d },
{ 0x00, 0x1e },
{ 0x00, 0x20 },
{ 0x00, 0x21 },
{ 0x00, 0x23 },
{ 0x00, 0x24 },
{ 0x00, 0x26 },
{ 0x00, 0x27 },
{ 0x00, 0x29 },
{ 0x00, 0x2a },
{ 0x00, 0x2c },
{ 0x00, 0x2d },
{ 0x00, 0x2f },
{ 0x00, 0x30 },
{ 0x00, 0x32 },
{ 0x00, 0x34 },
{ 0x00, 0x35 },
{ 0x00, 0x37 },
{ 0x00, 0x38 },
{ 0x00, 0x3a },
{ 0x00, 0x3b },
{ 0x00, 0x3d },
{ 0x00, 0x3e },
{ 0x00, 0x40 },
{ 0x00, 0x41 },
{ 0x00, 0x42 },
{ 0x00, 0x44 },
{ 0x00, 0x45 },
{ 0x00, 0x47 },
{ 0x00, 0x48 },
{ 0x00, 0x4a },
{ 0x00, 0x4b },
{ 0x00, 0x4d },
{ 0x00, 0x4e },
{ 0x00, 0x50 },
{ 0x00, 0x52 },
{ 0x00, 0x53 },
{ 0x00, 0x55 },
{ 0x00, 0x56 },
{ 0x00, 0x58 },
{ 0x00, 0x59 },
{ 0x00, 0x5b },
{ 0x00, 0x5c },
{ 0x00, 0x5e },
{ 0x00, 0x5f },
{ 0x00, 0x61 },
{ 0x00, 0x62 },
{ 0x00, 0x64 },
{ 0x00, 0x65 },
{ 0x00, 0x67 },
{ 0x00, 0x68 },
{ 0x00, 0x6a },
{ 0x00, 0x6b },
{ 0x00, 0x6d },
{ 0x00, 0x6e },
{ 0x00, 0x70 },
{ 0x00, 0x72 },
{ 0x00, 0x73 },
{ 0x00, 0x75 },
{ 0x00, 0x76 },
{ 0x00, 0x78 },
{ 0x00, 0x79 },
{ 0x00, 0x7b },
{ 0x00, 0x7c },
{ 0x00, 0x7e },
{ 0x00, 0x7f },
{ 0x01, 0x7f },
{ 0x02, 0x7e },
{ 0x03, 0x7e },
{ 0x03, 0x7f },
{ 0x04, 0x7f },
{ 0x05, 0x7e },
{ 0x06, 0x7e },
{ 0x06, 0x7f },
{ 0x07, 0x7f },
{ 0x08, 0x7e },
{ 0x09, 0x7e },
{ 0x09, 0x7f },
{ 0x0a, 0x7f },
{ 0x0b, 0x7e },
{ 0x0c, 0x7e },
{ 0x0c, 0x7f },
{ 0x0d, 0x7f },
{ 0x0e, 0x7e },
{ 0x0f, 0x7d },
{ 0x0f, 0x7f },
{ 0x10, 0x7e },
{ 0x11, 0x7e },
{ 0x11, 0x7f },
{ 0x12, 0x7f },
{ 0x13, 0x7e },
{ 0x14, 0x7e },
{ 0x14, 0x7f },
{ 0x15, 0x7f },
{ 0x16, 0x7e },
{ 0x17, 0x7e },
{ 0x17, 0x7f },
{ 0x18, 0x7f },
{ 0x19, 0x7e },
{ 0x1a, 0x7e },
{ 0x1a, 0x7f },
{ 0x1b, 0x7f },
{ 0x1c, 0x7e },
{ 0x1d, 0x7e },
{ 0x1d, 0x7f },
{ 0x1e, 0x7f },
{ 0x1f, 0x7e },
{ 0x20, 0x7e },
{ 0x20, 0x7f },
{ 0x21, 0x7f },
{ 0x22, 0x7e },
{ 0x23, 0x7e },
{ 0x23, 0x7f },
{ 0x24, 0x7f },
{ 0x25, 0x7e },
{ 0x26, 0x7e },
{ 0x26, 0x7f },
{ 0x27, 0x7f },
{ 0x28, 0x7e },
{ 0x29, 0x7e },
{ 0x29, 0x7f },
{ 0x2a, 0x7f },
{ 0x2b, 0x7e },
{ 0x2c, 0x7e },
{ 0x2c, 0x7f },
{ 0x2d, 0x7f },
{ 0x2e, 0x7e },
{ 0x2f, 0x7d },
{ 0x2f, 0x7f },
{ 0x30, 0x7e },
{ 0x31, 0x7e },
{ 0x31, 0x7f },
{ 0x32, 0x7f },
{ 0x33, 0x7e },
{ 0x34, 0x7e },
{ 0x34, 0x7f },
{ 0x35, 0x7f },
{ 0x36, 0x7e },
{ 0x37, 0x7e },
{ 0x37, 0x7f },
{ 0x38, 0x7f },
{ 0x39, 0x7e },
{ 0x3a, 0x7e },
{ 0x3a, 0x7f },
{ 0x3b, 0x7f },
{ 0x3c, 0x7e },
{ 0x3d, 0x7e },
{ 0x3d, 0x7f },
{ 0x3e, 0x7f },
{ 0x3f, 0x7e },
{ 0x40, 0x7d },
{ 0x40, 0x7e },
{ 0x41, 0x7e },
{ 0x41, 0x7f },
{ 0x42, 0x7f },
{ 0x43, 0x7e },
{ 0x44, 0x7e },
{ 0x44, 0x7f },
{ 0x45, 0x7f },
{ 0x46, 0x7e },
{ 0x47, 0x7e },
{ 0x47, 0x7f },
{ 0x48, 0x7f },
{ 0x49, 0x7e },
{ 0x4a, 0x7e },
{ 0x4a, 0x7f },
{ 0x4b, 0x7f },
{ 0x4c, 0x7e },
{ 0x4d, 0x7d },
{ 0x4d, 0x7f },
{ 0x4e, 0x7e },
{ 0x4f, 0x7e },
{ 0x4f, 0x7f },
{ 0x50, 0x7f },
{ 0x51, 0x7e },
{ 0x52, 0x7e },
{ 0x52, 0x7f },
{ 0x53, 0x7f },
{ 0x54, 0x7e },
{ 0x55, 0x7e },
{ 0x55, 0x7f },
{ 0x56, 0x7f },
{ 0x57, 0x7e },
{ 0x58, 0x7e },
{ 0x58, 0x7f },
{ 0x59, 0x7f },
{ 0x5a, 0x7e },
{ 0x5b, 0x7e },
{ 0x5b, 0x7f },
{ 0x5c, 0x7f },
{ 0x5d, 0x7e },
{ 0x5e, 0x7e },
{ 0x5e, 0x7f },
{ 0x5f, 0x7f },
{ 0x60, 0x7e },
{ 0x61, 0x7e },
{ 0x61, 0x7f },
{ 0x62, 0x7f },
{ 0x63, 0x7e },
{ 0x64, 0x7e },
{ 0x64, 0x7f },
{ 0x65, 0x7f },
{ 0x66, 0x7e },
{ 0x67, 0x7e },
{ 0x67, 0x7f },
{ 0x68, 0x7f },
{ 0x69, 0x7e },
{ 0x6a, 0x7e },
{ 0x6a, 0x7f },
{ 0x6b, 0x7f },
{ 0x6c, 0x7e },
{ 0x6d, 0x7d },
{ 0x6d, 0x7f },
{ 0x6e, 0x7e },
{ 0x6f, 0x7e },
{ 0x6f, 0x7f },
{ 0x70, 0x7f },
{ 0x71, 0x7e },
{ 0x72, 0x7e },
{ 0x72, 0x7f },
{ 0x73, 0x7f },
{ 0x74, 0x7e },
{ 0x75, 0x7e },
{ 0x75, 0x7f },
{ 0x76, 0x7f },
{ 0x77, 0x7e },
{ 0x78, 0x7e },
{ 0x78, 0x7f },
{ 0x79, 0x7f },
{ 0x7a, 0x7e },
{ 0x7b, 0x7e },
{ 0x7b, 0x7f },
{ 0x7c, 0x7f },
{ 0x7d, 0x7e },
{ 0x7e, 0x7e },
{ 0x7e, 0x7f },
{ 0x7f, 0x7f }
};
// For each value, we give the best possible compression range for that value with 5 bits.
// The first value says whether or not it's
// 1 - the midpoint of two other values, or
// 0 - 1/3 of the way in between two other values.
// If the first value is 1 or 2 then the last two values are the range between which the
// value should be interpolated. If the first value is 2, then it should be interpolated
// one third of the way from the second to third value...
//
// The following tables were generated with the following program:
/*
UINT nbits = 5;
UINT lastNum = -1;
UINT vals[255];
UINT valIdx = 0;
for(UINT i = 0; i < 256; i++) {
UINT num = (i >> (8 - nbits));
num <<= (8-nbits);
num |= i >> nbits;
if(num != lastNum) {
lastNum = num;
vals[valIdx++] = num;
}
}
for(UINT i = 0; i < 256; i++) {
UINT mindist = 0xFFFFFFFF;
UINT minj = 0, mink = 0;
UINT tableEntry[2][4] = { {1, 0, 0, 0xFFFFFFFF}, {0, 0, 0, 0xFFFFFFFF} };
for(UINT j = 0; j < valIdx; j++) {
for(UINT k = j; k < valIdx ; k++) {
UINT combo = (vals[j] + vals[k]) / 2;
UINT dist = ((i > combo) ? i - combo : combo - i);
if( dist < mindist )
{
mindist = dist;
minj = j;
mink = k;
}
}
}
tableEntry[0][1] = vals[minj];
tableEntry[0][2] = vals[mink];
tableEntry[0][3] = mindist;
mindist = 0xFFFFFFFF;
minj = 0, mink = 0;
for(UINT j = 0; j < valIdx; j++) {
for(UINT k = j; k < valIdx ; k++) {
UINT combo = (2 * vals[j] + vals[k]) / 3;
UINT dist = ((i > combo) ? i - combo : combo - i);
if( dist < mindist )
{
mindist = dist;
minj = j;
mink = k;
}
}
}
tableEntry[1][1] = vals[minj];
tableEntry[1][2] = vals[mink];
tableEntry[1][3] = mindist;
wchar_t tableEntryStr[256];
if(tableEntry[1][3] > tableEntry[0][3]) {
swprintf(tableEntryStr, 256, L"{ { %d, 0x%02x, 0x%02x }, { %d, 0x%02x, 0x%02x } },\n",
tableEntry[0][0],
tableEntry[0][1] >> (8 - nbits),
tableEntry[0][2] >> (8 - nbits),
tableEntry[1][0],
tableEntry[1][1] >> (8 - nbits),
tableEntry[1][2] >> (8 - nbits)
);
}
else {
swprintf(tableEntryStr, 256, L"{ { %d, 0x%02x, 0x%02x }, { %d, 0x%02x, 0x%02x } },\n",
tableEntry[1][0],
tableEntry[1][1] >> (8 - nbits),
tableEntry[1][2] >> (8 - nbits),
tableEntry[0][0],
tableEntry[0][1] >> (8 - nbits),
tableEntry[0][2] >> (8 - nbits)
);
}
OutputDebugString(tableEntryStr);
}
*/
static unsigned char Optimal5CompressDXT1[256][2][3] = {
{ { 0, 0x00, 0x00 }, { 1, 0x00, 0x00 } },
{ { 0, 0x00, 0x00 }, { 1, 0x00, 0x00 } },
{ { 0, 0x00, 0x01 }, { 1, 0x00, 0x00 } },
{ { 0, 0x00, 0x01 }, { 1, 0x00, 0x01 } },
{ { 1, 0x00, 0x01 }, { 0, 0x00, 0x02 } },
{ { 0, 0x00, 0x02 }, { 1, 0x00, 0x01 } },
{ { 0, 0x00, 0x02 }, { 1, 0x00, 0x01 } },
{ { 0, 0x00, 0x03 }, { 1, 0x00, 0x02 } },
{ { 0, 0x00, 0x03 }, { 1, 0x00, 0x02 } },
{ { 0, 0x00, 0x03 }, { 1, 0x00, 0x02 } },
{ { 0, 0x01, 0x02 }, { 1, 0x00, 0x02 } },
{ { 0, 0x00, 0x04 }, { 1, 0x00, 0x03 } },
{ { 1, 0x00, 0x03 }, { 0, 0x00, 0x04 } },
{ { 0, 0x00, 0x05 }, { 1, 0x00, 0x03 } },
{ { 0, 0x00, 0x05 }, { 1, 0x00, 0x03 } },
{ { 0, 0x00, 0x06 }, { 1, 0x00, 0x04 } },
{ { 0, 0x00, 0x06 }, { 1, 0x00, 0x04 } },
{ { 0, 0x00, 0x06 }, { 1, 0x00, 0x04 } },
{ { 0, 0x02, 0x03 }, { 1, 0x00, 0x04 } },
{ { 0, 0x00, 0x07 }, { 1, 0x00, 0x05 } },
{ { 1, 0x00, 0x05 }, { 0, 0x00, 0x07 } },
{ { 0, 0x01, 0x06 }, { 1, 0x00, 0x05 } },
{ { 0, 0x00, 0x08 }, { 1, 0x00, 0x05 } },
{ { 0, 0x00, 0x08 }, { 1, 0x00, 0x06 } },
{ { 0, 0x00, 0x09 }, { 1, 0x00, 0x06 } },
{ { 0, 0x00, 0x09 }, { 1, 0x00, 0x06 } },
{ { 0, 0x00, 0x0a }, { 1, 0x00, 0x06 } },
{ { 0, 0x00, 0x0a }, { 1, 0x00, 0x07 } },
{ { 1, 0x00, 0x07 }, { 0, 0x00, 0x0a } },
{ { 0, 0x02, 0x07 }, { 1, 0x00, 0x07 } },
{ { 0, 0x00, 0x0b }, { 1, 0x00, 0x07 } },
{ { 0, 0x00, 0x0b }, { 1, 0x01, 0x07 } },
{ { 0, 0x01, 0x0a }, { 1, 0x01, 0x07 } },
{ { 0, 0x00, 0x0c }, { 1, 0x00, 0x08 } },
{ { 0, 0x00, 0x0c }, { 1, 0x00, 0x08 } },
{ { 0, 0x00, 0x0d }, { 1, 0x02, 0x07 } },
{ { 1, 0x02, 0x07 }, { 0, 0x00, 0x0d } },
{ { 1, 0x00, 0x09 }, { 0, 0x00, 0x0e } },
{ { 0, 0x00, 0x0e }, { 1, 0x00, 0x09 } },
{ { 0, 0x00, 0x0e }, { 1, 0x03, 0x07 } },
{ { 0, 0x02, 0x0b }, { 1, 0x03, 0x07 } },
{ { 0, 0x00, 0x0f }, { 1, 0x00, 0x0a } },
{ { 0, 0x00, 0x0f }, { 1, 0x00, 0x0a } },
{ { 0, 0x01, 0x0e }, { 1, 0x00, 0x0a } },
{ { 0, 0x00, 0x10 }, { 1, 0x00, 0x0b } },
{ { 1, 0x00, 0x0b }, { 0, 0x00, 0x10 } },
{ { 0, 0x00, 0x11 }, { 1, 0x00, 0x0b } },
{ { 0, 0x00, 0x11 }, { 1, 0x00, 0x0b } },
{ { 0, 0x00, 0x12 }, { 1, 0x00, 0x0c } },
{ { 0, 0x00, 0x12 }, { 1, 0x00, 0x0c } },
{ { 0, 0x00, 0x12 }, { 1, 0x00, 0x0c } },
{ { 0, 0x02, 0x0f }, { 1, 0x00, 0x0c } },
{ { 0, 0x00, 0x13 }, { 1, 0x00, 0x0d } },
{ { 1, 0x00, 0x0d }, { 0, 0x00, 0x13 } },
{ { 0, 0x01, 0x12 }, { 1, 0x00, 0x0d } },
{ { 0, 0x00, 0x14 }, { 1, 0x00, 0x0d } },
{ { 0, 0x00, 0x14 }, { 1, 0x00, 0x0e } },
{ { 0, 0x00, 0x15 }, { 1, 0x00, 0x0e } },
{ { 0, 0x00, 0x15 }, { 1, 0x00, 0x0e } },
{ { 0, 0x00, 0x16 }, { 1, 0x00, 0x0e } },
{ { 0, 0x00, 0x16 }, { 1, 0x00, 0x0f } },
{ { 1, 0x00, 0x0f }, { 0, 0x00, 0x16 } },
{ { 0, 0x02, 0x13 }, { 1, 0x00, 0x0f } },
{ { 0, 0x00, 0x17 }, { 1, 0x00, 0x0f } },
{ { 0, 0x00, 0x17 }, { 1, 0x01, 0x0f } },
{ { 0, 0x01, 0x16 }, { 1, 0x01, 0x0f } },
{ { 0, 0x00, 0x18 }, { 1, 0x00, 0x10 } },
{ { 0, 0x00, 0x18 }, { 1, 0x00, 0x10 } },
{ { 0, 0x00, 0x19 }, { 1, 0x02, 0x0f } },
{ { 1, 0x02, 0x0f }, { 0, 0x00, 0x19 } },
{ { 1, 0x00, 0x11 }, { 0, 0x00, 0x1a } },
{ { 0, 0x00, 0x1a }, { 1, 0x00, 0x11 } },
{ { 0, 0x00, 0x1a }, { 1, 0x03, 0x0f } },
{ { 0, 0x02, 0x17 }, { 1, 0x03, 0x0f } },
{ { 0, 0x00, 0x1b }, { 1, 0x00, 0x12 } },
{ { 0, 0x00, 0x1b }, { 1, 0x00, 0x12 } },
{ { 0, 0x01, 0x1a }, { 1, 0x00, 0x12 } },
{ { 0, 0x00, 0x1c }, { 1, 0x00, 0x13 } },
{ { 1, 0x00, 0x13 }, { 0, 0x00, 0x1c } },
{ { 0, 0x00, 0x1d }, { 1, 0x00, 0x13 } },
{ { 0, 0x00, 0x1d }, { 1, 0x00, 0x13 } },
{ { 0, 0x00, 0x1e }, { 1, 0x00, 0x14 } },
{ { 0, 0x00, 0x1e }, { 1, 0x00, 0x14 } },
{ { 0, 0x00, 0x1e }, { 1, 0x00, 0x14 } },
{ { 0, 0x02, 0x1b }, { 1, 0x00, 0x14 } },
{ { 0, 0x00, 0x1f }, { 1, 0x00, 0x15 } },
{ { 1, 0x00, 0x15 }, { 0, 0x00, 0x1f } },
{ { 0, 0x01, 0x1e }, { 1, 0x00, 0x15 } },
{ { 0, 0x04, 0x18 }, { 1, 0x00, 0x15 } },
{ { 0, 0x01, 0x1f }, { 1, 0x00, 0x16 } },
{ { 0, 0x01, 0x1f }, { 1, 0x00, 0x16 } },
{ { 0, 0x01, 0x1f }, { 1, 0x00, 0x16 } },
{ { 0, 0x02, 0x1e }, { 1, 0x00, 0x16 } },
{ { 0, 0x02, 0x1e }, { 1, 0x00, 0x17 } },
{ { 1, 0x00, 0x17 }, { 0, 0x02, 0x1e } },
{ { 0, 0x02, 0x1f }, { 1, 0x00, 0x17 } },
{ { 0, 0x04, 0x1b }, { 1, 0x00, 0x17 } },
{ { 0, 0x03, 0x1e }, { 1, 0x01, 0x17 } },
{ { 0, 0x03, 0x1e }, { 1, 0x01, 0x17 } },
{ { 0, 0x04, 0x1c }, { 1, 0x00, 0x18 } },
{ { 0, 0x03, 0x1f }, { 1, 0x00, 0x18 } },
{ { 0, 0x03, 0x1f }, { 1, 0x02, 0x17 } },
{ { 1, 0x02, 0x17 }, { 0, 0x03, 0x1f } },
{ { 1, 0x00, 0x19 }, { 0, 0x04, 0x1e } },
{ { 0, 0x04, 0x1e }, { 1, 0x00, 0x19 } },
{ { 0, 0x04, 0x1e }, { 1, 0x03, 0x17 } },
{ { 0, 0x06, 0x1b }, { 1, 0x03, 0x17 } },
{ { 0, 0x04, 0x1f }, { 1, 0x00, 0x1a } },
{ { 0, 0x04, 0x1f }, { 1, 0x00, 0x1a } },
{ { 0, 0x05, 0x1e }, { 1, 0x00, 0x1a } },
{ { 0, 0x08, 0x18 }, { 1, 0x00, 0x1b } },
{ { 1, 0x00, 0x1b }, { 0, 0x05, 0x1f } },
{ { 0, 0x05, 0x1f }, { 1, 0x00, 0x1b } },
{ { 0, 0x05, 0x1f }, { 1, 0x00, 0x1b } },
{ { 0, 0x06, 0x1e }, { 1, 0x00, 0x1c } },
{ { 0, 0x06, 0x1e }, { 1, 0x00, 0x1c } },
{ { 0, 0x06, 0x1e }, { 1, 0x00, 0x1c } },
{ { 0, 0x06, 0x1f }, { 1, 0x00, 0x1c } },
{ { 0, 0x08, 0x1b }, { 1, 0x00, 0x1d } },
{ { 1, 0x00, 0x1d }, { 0, 0x07, 0x1e } },
{ { 0, 0x07, 0x1e }, { 1, 0x00, 0x1d } },
{ { 0, 0x08, 0x1c }, { 1, 0x00, 0x1d } },
{ { 0, 0x07, 0x1f }, { 1, 0x00, 0x1e } },
{ { 0, 0x07, 0x1f }, { 1, 0x00, 0x1e } },
{ { 0, 0x07, 0x1f }, { 1, 0x00, 0x1e } },
{ { 0, 0x08, 0x1e }, { 1, 0x00, 0x1e } },
{ { 0, 0x08, 0x1e }, { 1, 0x00, 0x1f } },
{ { 1, 0x00, 0x1f }, { 0, 0x08, 0x1e } },
{ { 0, 0x0a, 0x1b }, { 1, 0x00, 0x1f } },
{ { 0, 0x08, 0x1f }, { 1, 0x00, 0x1f } },
{ { 0, 0x08, 0x1f }, { 1, 0x01, 0x1f } },
{ { 0, 0x09, 0x1e }, { 1, 0x01, 0x1f } },
{ { 0, 0x0c, 0x18 }, { 1, 0x04, 0x1c } },
{ { 0, 0x09, 0x1f }, { 1, 0x04, 0x1c } },
{ { 0, 0x09, 0x1f }, { 1, 0x02, 0x1f } },
{ { 1, 0x02, 0x1f }, { 0, 0x09, 0x1f } },
{ { 1, 0x04, 0x1d }, { 0, 0x0a, 0x1e } },
{ { 0, 0x0a, 0x1e }, { 1, 0x04, 0x1d } },
{ { 0, 0x0a, 0x1e }, { 1, 0x03, 0x1f } },
{ { 0, 0x0a, 0x1f }, { 1, 0x03, 0x1f } },
{ { 0, 0x0c, 0x1b }, { 1, 0x04, 0x1e } },
{ { 0, 0x0b, 0x1e }, { 1, 0x04, 0x1e } },
{ { 0, 0x0b, 0x1e }, { 1, 0x04, 0x1e } },
{ { 0, 0x0c, 0x1c }, { 1, 0x04, 0x1f } },
{ { 1, 0x04, 0x1f }, { 0, 0x0b, 0x1f } },
{ { 0, 0x0b, 0x1f }, { 1, 0x04, 0x1f } },
{ { 0, 0x0b, 0x1f }, { 1, 0x04, 0x1f } },
{ { 0, 0x0c, 0x1e }, { 1, 0x05, 0x1f } },
{ { 0, 0x0c, 0x1e }, { 1, 0x05, 0x1f } },
{ { 0, 0x0c, 0x1e }, { 1, 0x05, 0x1f } },
{ { 0, 0x0e, 0x1b }, { 1, 0x05, 0x1f } },
{ { 0, 0x0c, 0x1f }, { 1, 0x06, 0x1f } },
{ { 1, 0x06, 0x1f }, { 0, 0x0c, 0x1f } },
{ { 0, 0x0d, 0x1e }, { 1, 0x06, 0x1f } },
{ { 0, 0x10, 0x18 }, { 1, 0x06, 0x1f } },
{ { 0, 0x0d, 0x1f }, { 1, 0x07, 0x1f } },
{ { 0, 0x0d, 0x1f }, { 1, 0x07, 0x1f } },
{ { 0, 0x0d, 0x1f }, { 1, 0x07, 0x1f } },
{ { 0, 0x0e, 0x1e }, { 1, 0x07, 0x1f } },
{ { 0, 0x0e, 0x1e }, { 1, 0x08, 0x1f } },
{ { 1, 0x08, 0x1f }, { 0, 0x0e, 0x1e } },
{ { 0, 0x0e, 0x1f }, { 1, 0x08, 0x1f } },
{ { 0, 0x10, 0x1b }, { 1, 0x08, 0x1f } },
{ { 0, 0x0f, 0x1e }, { 1, 0x09, 0x1f } },
{ { 0, 0x0f, 0x1e }, { 1, 0x09, 0x1f } },
{ { 0, 0x10, 0x1c }, { 1, 0x0c, 0x1c } },
{ { 0, 0x0f, 0x1f }, { 1, 0x0c, 0x1c } },
{ { 0, 0x0f, 0x1f }, { 1, 0x0a, 0x1f } },
{ { 1, 0x0a, 0x1f }, { 0, 0x0f, 0x1f } },
{ { 1, 0x0c, 0x1d }, { 0, 0x10, 0x1e } },
{ { 0, 0x10, 0x1e }, { 1, 0x0c, 0x1d } },
{ { 0, 0x10, 0x1e }, { 1, 0x0b, 0x1f } },
{ { 0, 0x12, 0x1b }, { 1, 0x0b, 0x1f } },
{ { 0, 0x10, 0x1f }, { 1, 0x0c, 0x1e } },
{ { 0, 0x10, 0x1f }, { 1, 0x0c, 0x1e } },
{ { 0, 0x11, 0x1e }, { 1, 0x0c, 0x1e } },
{ { 0, 0x14, 0x18 }, { 1, 0x0c, 0x1f } },
{ { 1, 0x0c, 0x1f }, { 0, 0x11, 0x1f } },
{ { 0, 0x11, 0x1f }, { 1, 0x0c, 0x1f } },
{ { 0, 0x11, 0x1f }, { 1, 0x0c, 0x1f } },
{ { 0, 0x12, 0x1e }, { 1, 0x0d, 0x1f } },
{ { 0, 0x12, 0x1e }, { 1, 0x0d, 0x1f } },
{ { 0, 0x12, 0x1e }, { 1, 0x0d, 0x1f } },
{ { 0, 0x12, 0x1f }, { 1, 0x0d, 0x1f } },
{ { 0, 0x14, 0x1b }, { 1, 0x0e, 0x1f } },
{ { 1, 0x0e, 0x1f }, { 0, 0x13, 0x1e } },
{ { 0, 0x13, 0x1e }, { 1, 0x0e, 0x1f } },
{ { 0, 0x14, 0x1c }, { 1, 0x0e, 0x1f } },
{ { 0, 0x13, 0x1f }, { 1, 0x0f, 0x1f } },
{ { 0, 0x13, 0x1f }, { 1, 0x0f, 0x1f } },
{ { 0, 0x13, 0x1f }, { 1, 0x0f, 0x1f } },
{ { 0, 0x14, 0x1e }, { 1, 0x0f, 0x1f } },
{ { 0, 0x14, 0x1e }, { 1, 0x10, 0x1f } },
{ { 1, 0x10, 0x1f }, { 0, 0x14, 0x1e } },
{ { 0, 0x16, 0x1b }, { 1, 0x10, 0x1f } },
{ { 0, 0x14, 0x1f }, { 1, 0x10, 0x1f } },
{ { 0, 0x14, 0x1f }, { 1, 0x11, 0x1f } },
{ { 0, 0x15, 0x1e }, { 1, 0x11, 0x1f } },
{ { 0, 0x18, 0x18 }, { 1, 0x14, 0x1c } },
{ { 0, 0x15, 0x1f }, { 1, 0x14, 0x1c } },
{ { 0, 0x15, 0x1f }, { 1, 0x12, 0x1f } },
{ { 1, 0x12, 0x1f }, { 0, 0x15, 0x1f } },
{ { 1, 0x14, 0x1d }, { 0, 0x16, 0x1e } },
{ { 0, 0x16, 0x1e }, { 1, 0x14, 0x1d } },
{ { 0, 0x16, 0x1e }, { 1, 0x13, 0x1f } },
{ { 0, 0x16, 0x1f }, { 1, 0x13, 0x1f } },
{ { 0, 0x18, 0x1b }, { 1, 0x14, 0x1e } },
{ { 0, 0x17, 0x1e }, { 1, 0x14, 0x1e } },
{ { 0, 0x17, 0x1e }, { 1, 0x14, 0x1e } },
{ { 0, 0x18, 0x1c }, { 1, 0x14, 0x1f } },
{ { 1, 0x14, 0x1f }, { 0, 0x17, 0x1f } },
{ { 0, 0x17, 0x1f }, { 1, 0x14, 0x1f } },
{ { 0, 0x17, 0x1f }, { 1, 0x14, 0x1f } },
{ { 0, 0x18, 0x1e }, { 1, 0x15, 0x1f } },
{ { 0, 0x18, 0x1e }, { 1, 0x15, 0x1f } },
{ { 0, 0x18, 0x1e }, { 1, 0x15, 0x1f } },
{ { 0, 0x1a, 0x1b }, { 1, 0x15, 0x1f } },
{ { 0, 0x18, 0x1f }, { 1, 0x16, 0x1f } },
{ { 1, 0x16, 0x1f }, { 0, 0x18, 0x1f } },
{ { 0, 0x19, 0x1e }, { 1, 0x16, 0x1f } },
{ { 0, 0x19, 0x1e }, { 1, 0x16, 0x1f } },
{ { 0, 0x19, 0x1f }, { 1, 0x17, 0x1f } },
{ { 0, 0x19, 0x1f }, { 1, 0x17, 0x1f } },
{ { 0, 0x19, 0x1f }, { 1, 0x17, 0x1f } },
{ { 0, 0x1a, 0x1e }, { 1, 0x17, 0x1f } },
{ { 0, 0x1a, 0x1e }, { 1, 0x18, 0x1f } },
{ { 1, 0x18, 0x1f }, { 0, 0x1a, 0x1e } },
{ { 0, 0x1a, 0x1f }, { 1, 0x18, 0x1f } },
{ { 0, 0x1a, 0x1f }, { 1, 0x18, 0x1f } },
{ { 0, 0x1b, 0x1e }, { 1, 0x19, 0x1f } },
{ { 0, 0x1b, 0x1e }, { 1, 0x19, 0x1f } },
{ { 0, 0x1c, 0x1c }, { 1, 0x1c, 0x1c } },
{ { 0, 0x1b, 0x1f }, { 1, 0x1c, 0x1c } },
{ { 0, 0x1b, 0x1f }, { 1, 0x1a, 0x1f } },
{ { 1, 0x1a, 0x1f }, { 0, 0x1b, 0x1f } },
{ { 1, 0x1c, 0x1d }, { 0, 0x1c, 0x1e } },
{ { 0, 0x1c, 0x1e }, { 1, 0x1c, 0x1d } },
{ { 0, 0x1c, 0x1e }, { 1, 0x1b, 0x1f } },
{ { 1, 0x1b, 0x1f }, { 0, 0x1c, 0x1f } },
{ { 0, 0x1c, 0x1f }, { 1, 0x1c, 0x1e } },
{ { 0, 0x1c, 0x1f }, { 1, 0x1c, 0x1e } },
{ { 0, 0x1d, 0x1e }, { 1, 0x1c, 0x1e } },
{ { 0, 0x1d, 0x1e }, { 1, 0x1c, 0x1f } },
{ { 1, 0x1c, 0x1f }, { 0, 0x1d, 0x1f } },
{ { 0, 0x1d, 0x1f }, { 1, 0x1c, 0x1f } },
{ { 0, 0x1d, 0x1f }, { 1, 0x1c, 0x1f } },
{ { 0, 0x1e, 0x1e }, { 1, 0x1d, 0x1f } },
{ { 0, 0x1e, 0x1e }, { 1, 0x1d, 0x1f } },
{ { 0, 0x1e, 0x1e }, { 1, 0x1d, 0x1f } },
{ { 0, 0x1e, 0x1f }, { 1, 0x1d, 0x1f } },
{ { 0, 0x1e, 0x1f }, { 1, 0x1e, 0x1f } },
{ { 1, 0x1e, 0x1f }, { 0, 0x1e, 0x1f } },
{ { 1, 0x1e, 0x1f }, { 0, 0x1e, 0x1f } },
{ { 0, 0x1f, 0x1f }, { 1, 0x1e, 0x1f } },
{ { 0, 0x1f, 0x1f }, { 1, 0x1f, 0x1f } },
{ { 0, 0x1f, 0x1f }, { 1, 0x1f, 0x1f } }
};
static unsigned char Optimal6CompressDXT1[256][2][3] = {
{ { 0, 0x00, 0x00 }, { 1, 0x00, 0x00 } },
{ { 0, 0x00, 0x01 }, { 1, 0x00, 0x00 } },
{ { 0, 0x00, 0x02 }, { 1, 0x00, 0x01 } },
{ { 0, 0x00, 0x02 }, { 1, 0x00, 0x01 } },
{ { 0, 0x00, 0x03 }, { 1, 0x00, 0x02 } },
{ { 0, 0x00, 0x04 }, { 1, 0x00, 0x02 } },
{ { 0, 0x00, 0x05 }, { 1, 0x00, 0x03 } },
{ { 0, 0x00, 0x05 }, { 1, 0x00, 0x03 } },
{ { 0, 0x00, 0x06 }, { 1, 0x00, 0x04 } },
{ { 0, 0x00, 0x07 }, { 1, 0x00, 0x04 } },
{ { 0, 0x00, 0x08 }, { 1, 0x00, 0x05 } },
{ { 0, 0x00, 0x08 }, { 1, 0x00, 0x05 } },
{ { 0, 0x00, 0x09 }, { 1, 0x00, 0x06 } },
{ { 0, 0x00, 0x0a }, { 1, 0x00, 0x06 } },
{ { 0, 0x00, 0x0b }, { 1, 0x00, 0x07 } },
{ { 0, 0x00, 0x0b }, { 1, 0x00, 0x07 } },
{ { 0, 0x00, 0x0c }, { 1, 0x00, 0x08 } },
{ { 0, 0x00, 0x0d }, { 1, 0x00, 0x08 } },
{ { 0, 0x00, 0x0e }, { 1, 0x00, 0x09 } },
{ { 0, 0x00, 0x0e }, { 1, 0x00, 0x09 } },
{ { 0, 0x00, 0x0f }, { 1, 0x00, 0x0a } },
{ { 0, 0x00, 0x10 }, { 1, 0x00, 0x0a } },
{ { 0, 0x01, 0x0f }, { 1, 0x00, 0x0b } },
{ { 0, 0x00, 0x11 }, { 1, 0x00, 0x0b } },
{ { 0, 0x00, 0x12 }, { 1, 0x00, 0x0c } },
{ { 0, 0x00, 0x13 }, { 1, 0x00, 0x0c } },
{ { 0, 0x03, 0x0e }, { 1, 0x00, 0x0d } },
{ { 0, 0x00, 0x14 }, { 1, 0x00, 0x0d } },
{ { 0, 0x00, 0x15 }, { 1, 0x00, 0x0e } },
{ { 0, 0x00, 0x16 }, { 1, 0x00, 0x0e } },
{ { 0, 0x04, 0x0f }, { 1, 0x00, 0x0f } },
{ { 0, 0x00, 0x17 }, { 1, 0x00, 0x0f } },
{ { 0, 0x00, 0x18 }, { 1, 0x00, 0x10 } },
{ { 0, 0x00, 0x19 }, { 1, 0x00, 0x10 } },
{ { 0, 0x06, 0x0e }, { 1, 0x00, 0x11 } },
{ { 0, 0x00, 0x1a }, { 1, 0x00, 0x11 } },
{ { 0, 0x00, 0x1b }, { 1, 0x00, 0x12 } },
{ { 0, 0x00, 0x1c }, { 1, 0x00, 0x12 } },
{ { 0, 0x07, 0x0f }, { 1, 0x00, 0x13 } },
{ { 0, 0x00, 0x1d }, { 1, 0x00, 0x13 } },
{ { 0, 0x00, 0x1e }, { 1, 0x00, 0x14 } },
{ { 0, 0x00, 0x1f }, { 1, 0x00, 0x14 } },
{ { 0, 0x09, 0x0e }, { 1, 0x00, 0x15 } },
{ { 0, 0x00, 0x20 }, { 1, 0x00, 0x15 } },
{ { 0, 0x00, 0x21 }, { 1, 0x00, 0x16 } },
{ { 0, 0x02, 0x1e }, { 1, 0x00, 0x16 } },
{ { 0, 0x00, 0x22 }, { 1, 0x00, 0x17 } },
{ { 0, 0x00, 0x23 }, { 1, 0x00, 0x17 } },
{ { 0, 0x00, 0x24 }, { 1, 0x00, 0x18 } },
{ { 0, 0x03, 0x1f }, { 1, 0x00, 0x18 } },
{ { 0, 0x00, 0x25 }, { 1, 0x00, 0x19 } },
{ { 0, 0x00, 0x26 }, { 1, 0x00, 0x19 } },
{ { 0, 0x00, 0x27 }, { 1, 0x00, 0x1a } },
{ { 0, 0x05, 0x1e }, { 1, 0x00, 0x1a } },
{ { 0, 0x00, 0x28 }, { 1, 0x00, 0x1b } },
{ { 0, 0x00, 0x29 }, { 1, 0x00, 0x1b } },
{ { 0, 0x00, 0x2a }, { 1, 0x00, 0x1c } },
{ { 0, 0x06, 0x1f }, { 1, 0x00, 0x1c } },
{ { 0, 0x00, 0x2b }, { 1, 0x00, 0x1d } },
{ { 0, 0x00, 0x2c }, { 1, 0x00, 0x1d } },
{ { 0, 0x00, 0x2d }, { 1, 0x00, 0x1e } },
{ { 0, 0x08, 0x1e }, { 1, 0x00, 0x1e } },
{ { 0, 0x00, 0x2e }, { 1, 0x00, 0x1f } },
{ { 0, 0x00, 0x2f }, { 1, 0x00, 0x1f } },
{ { 0, 0x01, 0x2e }, { 1, 0x01, 0x1f } },
{ { 0, 0x00, 0x30 }, { 1, 0x00, 0x20 } },
{ { 0, 0x00, 0x31 }, { 1, 0x02, 0x1f } },
{ { 0, 0x00, 0x32 }, { 1, 0x00, 0x21 } },
{ { 0, 0x02, 0x2f }, { 1, 0x03, 0x1f } },
{ { 0, 0x00, 0x33 }, { 1, 0x00, 0x22 } },
{ { 0, 0x00, 0x34 }, { 1, 0x04, 0x1f } },
{ { 0, 0x00, 0x35 }, { 1, 0x00, 0x23 } },
{ { 0, 0x04, 0x2e }, { 1, 0x05, 0x1f } },
{ { 0, 0x00, 0x36 }, { 1, 0x00, 0x24 } },
{ { 0, 0x00, 0x37 }, { 1, 0x06, 0x1f } },
{ { 0, 0x00, 0x38 }, { 1, 0x00, 0x25 } },
{ { 0, 0x05, 0x2f }, { 1, 0x07, 0x1f } },
{ { 0, 0x00, 0x39 }, { 1, 0x00, 0x26 } },
{ { 0, 0x00, 0x3a }, { 1, 0x08, 0x1f } },
{ { 0, 0x00, 0x3b }, { 1, 0x00, 0x27 } },
{ { 0, 0x07, 0x2e }, { 1, 0x09, 0x1f } },
{ { 0, 0x00, 0x3c }, { 1, 0x00, 0x28 } },
{ { 0, 0x00, 0x3d }, { 1, 0x0a, 0x1f } },
{ { 0, 0x00, 0x3e }, { 1, 0x00, 0x29 } },
{ { 0, 0x08, 0x2f }, { 1, 0x0b, 0x1f } },
{ { 0, 0x00, 0x3f }, { 1, 0x00, 0x2a } },
{ { 0, 0x01, 0x3e }, { 1, 0x0c, 0x1f } },
{ { 0, 0x01, 0x3f }, { 1, 0x00, 0x2b } },
{ { 0, 0x0a, 0x2e }, { 1, 0x0d, 0x1f } },
{ { 0, 0x02, 0x3e }, { 1, 0x00, 0x2c } },
{ { 0, 0x02, 0x3f }, { 1, 0x0e, 0x1f } },
{ { 0, 0x03, 0x3e }, { 1, 0x00, 0x2d } },
{ { 0, 0x0b, 0x2f }, { 1, 0x0f, 0x1f } },
{ { 0, 0x03, 0x3f }, { 1, 0x00, 0x2e } },
{ { 0, 0x04, 0x3e }, { 1, 0x00, 0x2e } },
{ { 0, 0x04, 0x3f }, { 1, 0x00, 0x2f } },
{ { 0, 0x0d, 0x2e }, { 1, 0x00, 0x2f } },
{ { 0, 0x05, 0x3e }, { 1, 0x00, 0x30 } },
{ { 0, 0x05, 0x3f }, { 1, 0x00, 0x30 } },
{ { 0, 0x06, 0x3e }, { 1, 0x00, 0x31 } },
{ { 0, 0x0e, 0x2f }, { 1, 0x00, 0x31 } },
{ { 0, 0x06, 0x3f }, { 1, 0x00, 0x32 } },
{ { 0, 0x07, 0x3e }, { 1, 0x00, 0x32 } },
{ { 0, 0x07, 0x3f }, { 1, 0x00, 0x33 } },
{ { 0, 0x10, 0x2d }, { 1, 0x00, 0x33 } },
{ { 0, 0x08, 0x3e }, { 1, 0x00, 0x34 } },
{ { 0, 0x08, 0x3f }, { 1, 0x00, 0x34 } },
{ { 0, 0x09, 0x3e }, { 1, 0x00, 0x35 } },
{ { 0, 0x10, 0x30 }, { 1, 0x00, 0x35 } },
{ { 0, 0x09, 0x3f }, { 1, 0x00, 0x36 } },
{ { 0, 0x0a, 0x3e }, { 1, 0x00, 0x36 } },
{ { 0, 0x0a, 0x3f }, { 1, 0x00, 0x37 } },
{ { 0, 0x10, 0x33 }, { 1, 0x00, 0x37 } },
{ { 0, 0x0b, 0x3e }, { 1, 0x00, 0x38 } },
{ { 0, 0x0b, 0x3f }, { 1, 0x00, 0x38 } },
{ { 0, 0x0c, 0x3e }, { 1, 0x00, 0x39 } },
{ { 0, 0x10, 0x36 }, { 1, 0x00, 0x39 } },
{ { 0, 0x0c, 0x3f }, { 1, 0x00, 0x3a } },
{ { 0, 0x0d, 0x3e }, { 1, 0x00, 0x3a } },
{ { 0, 0x0d, 0x3f }, { 1, 0x00, 0x3b } },
{ { 0, 0x10, 0x39 }, { 1, 0x00, 0x3b } },
{ { 0, 0x0e, 0x3e }, { 1, 0x00, 0x3c } },
{ { 0, 0x0e, 0x3f }, { 1, 0x00, 0x3c } },
{ { 0, 0x0f, 0x3e }, { 1, 0x00, 0x3d } },
{ { 0, 0x10, 0x3c }, { 1, 0x00, 0x3d } },
{ { 0, 0x0f, 0x3f }, { 1, 0x00, 0x3e } },
{ { 0, 0x18, 0x2e }, { 1, 0x00, 0x3e } },
{ { 0, 0x10, 0x3e }, { 1, 0x00, 0x3f } },
{ { 0, 0x10, 0x3f }, { 1, 0x00, 0x3f } },
{ { 0, 0x11, 0x3e }, { 1, 0x01, 0x3f } },
{ { 0, 0x19, 0x2f }, { 1, 0x10, 0x30 } },
{ { 0, 0x11, 0x3f }, { 1, 0x02, 0x3f } },
{ { 0, 0x12, 0x3e }, { 1, 0x10, 0x31 } },
{ { 0, 0x12, 0x3f }, { 1, 0x03, 0x3f } },
{ { 0, 0x1b, 0x2e }, { 1, 0x10, 0x32 } },
{ { 0, 0x13, 0x3e }, { 1, 0x04, 0x3f } },
{ { 0, 0x13, 0x3f }, { 1, 0x10, 0x33 } },
{ { 0, 0x14, 0x3e }, { 1, 0x05, 0x3f } },
{ { 0, 0x1c, 0x2f }, { 1, 0x10, 0x34 } },
{ { 0, 0x14, 0x3f }, { 1, 0x06, 0x3f } },
{ { 0, 0x15, 0x3e }, { 1, 0x10, 0x35 } },
{ { 0, 0x15, 0x3f }, { 1, 0x07, 0x3f } },
{ { 0, 0x1e, 0x2e }, { 1, 0x10, 0x36 } },
{ { 0, 0x16, 0x3e }, { 1, 0x08, 0x3f } },
{ { 0, 0x16, 0x3f }, { 1, 0x10, 0x37 } },
{ { 0, 0x17, 0x3e }, { 1, 0x09, 0x3f } },
{ { 0, 0x1f, 0x2f }, { 1, 0x10, 0x38 } },
{ { 0, 0x17, 0x3f }, { 1, 0x0a, 0x3f } },
{ { 0, 0x18, 0x3e }, { 1, 0x10, 0x39 } },
{ { 0, 0x18, 0x3f }, { 1, 0x0b, 0x3f } },
{ { 0, 0x20, 0x2f }, { 1, 0x10, 0x3a } },
{ { 0, 0x19, 0x3e }, { 1, 0x0c, 0x3f } },
{ { 0, 0x19, 0x3f }, { 1, 0x10, 0x3b } },
{ { 0, 0x1a, 0x3e }, { 1, 0x0d, 0x3f } },
{ { 0, 0x20, 0x32 }, { 1, 0x10, 0x3c } },
{ { 0, 0x1a, 0x3f }, { 1, 0x0e, 0x3f } },
{ { 0, 0x1b, 0x3e }, { 1, 0x10, 0x3d } },
{ { 0, 0x1b, 0x3f }, { 1, 0x0f, 0x3f } },
{ { 0, 0x20, 0x35 }, { 1, 0x10, 0x3e } },
{ { 0, 0x1c, 0x3e }, { 1, 0x10, 0x3e } },
{ { 0, 0x1c, 0x3f }, { 1, 0x10, 0x3f } },
{ { 0, 0x1d, 0x3e }, { 1, 0x10, 0x3f } },
{ { 0, 0x20, 0x38 }, { 1, 0x11, 0x3f } },
{ { 0, 0x1d, 0x3f }, { 1, 0x11, 0x3f } },
{ { 0, 0x1e, 0x3e }, { 1, 0x12, 0x3f } },
{ { 0, 0x1e, 0x3f }, { 1, 0x12, 0x3f } },
{ { 0, 0x20, 0x3b }, { 1, 0x13, 0x3f } },
{ { 0, 0x1f, 0x3e }, { 1, 0x13, 0x3f } },
{ { 0, 0x1f, 0x3f }, { 1, 0x14, 0x3f } },
{ { 0, 0x20, 0x3d }, { 1, 0x14, 0x3f } },
{ { 0, 0x20, 0x3e }, { 1, 0x15, 0x3f } },
{ { 0, 0x20, 0x3f }, { 1, 0x15, 0x3f } },
{ { 0, 0x29, 0x2e }, { 1, 0x16, 0x3f } },
{ { 0, 0x21, 0x3e }, { 1, 0x16, 0x3f } },
{ { 0, 0x21, 0x3f }, { 1, 0x17, 0x3f } },
{ { 0, 0x22, 0x3e }, { 1, 0x17, 0x3f } },
{ { 0, 0x2a, 0x2f }, { 1, 0x18, 0x3f } },
{ { 0, 0x22, 0x3f }, { 1, 0x18, 0x3f } },
{ { 0, 0x23, 0x3e }, { 1, 0x19, 0x3f } },
{ { 0, 0x23, 0x3f }, { 1, 0x19, 0x3f } },
{ { 0, 0x2c, 0x2e }, { 1, 0x1a, 0x3f } },
{ { 0, 0x24, 0x3e }, { 1, 0x1a, 0x3f } },
{ { 0, 0x24, 0x3f }, { 1, 0x1b, 0x3f } },
{ { 0, 0x25, 0x3e }, { 1, 0x1b, 0x3f } },
{ { 0, 0x2d, 0x2f }, { 1, 0x1c, 0x3f } },
{ { 0, 0x25, 0x3f }, { 1, 0x1c, 0x3f } },
{ { 0, 0x26, 0x3e }, { 1, 0x1d, 0x3f } },
{ { 0, 0x26, 0x3f }, { 1, 0x1d, 0x3f } },
{ { 1, 0x1e, 0x3f }, { 0, 0x26, 0x3f } },
{ { 0, 0x27, 0x3e }, { 1, 0x1e, 0x3f } },
{ { 0, 0x27, 0x3f }, { 1, 0x1f, 0x3f } },
{ { 0, 0x28, 0x3e }, { 1, 0x1f, 0x3f } },
{ { 1, 0x20, 0x3f }, { 0, 0x28, 0x3e } },
{ { 0, 0x28, 0x3f }, { 1, 0x20, 0x3f } },
{ { 0, 0x29, 0x3e }, { 1, 0x21, 0x3f } },
{ { 0, 0x29, 0x3f }, { 1, 0x30, 0x30 } },
{ { 0, 0x30, 0x31 }, { 1, 0x22, 0x3f } },
{ { 0, 0x2a, 0x3e }, { 1, 0x30, 0x31 } },
{ { 0, 0x2a, 0x3f }, { 1, 0x23, 0x3f } },
{ { 0, 0x2b, 0x3e }, { 1, 0x30, 0x32 } },
{ { 0, 0x30, 0x34 }, { 1, 0x24, 0x3f } },
{ { 0, 0x2b, 0x3f }, { 1, 0x30, 0x33 } },
{ { 0, 0x2c, 0x3e }, { 1, 0x25, 0x3f } },
{ { 0, 0x2c, 0x3f }, { 1, 0x30, 0x34 } },
{ { 0, 0x30, 0x37 }, { 1, 0x26, 0x3f } },
{ { 0, 0x2d, 0x3e }, { 1, 0x30, 0x35 } },
{ { 0, 0x2d, 0x3f }, { 1, 0x27, 0x3f } },
{ { 0, 0x2e, 0x3e }, { 1, 0x30, 0x36 } },
{ { 0, 0x30, 0x3a }, { 1, 0x28, 0x3f } },
{ { 0, 0x2e, 0x3f }, { 1, 0x30, 0x37 } },
{ { 0, 0x2f, 0x3e }, { 1, 0x29, 0x3f } },
{ { 0, 0x2f, 0x3f }, { 1, 0x30, 0x38 } },
{ { 0, 0x30, 0x3d }, { 1, 0x2a, 0x3f } },
{ { 0, 0x30, 0x3e }, { 1, 0x30, 0x39 } },
{ { 1, 0x2b, 0x3f }, { 0, 0x30, 0x3e } },
{ { 0, 0x30, 0x3f }, { 1, 0x30, 0x3a } },
{ { 0, 0x31, 0x3e }, { 1, 0x2c, 0x3f } },
{ { 0, 0x31, 0x3f }, { 1, 0x30, 0x3b } },
{ { 1, 0x2d, 0x3f }, { 0, 0x31, 0x3f } },
{ { 0, 0x32, 0x3e }, { 1, 0x30, 0x3c } },
{ { 0, 0x32, 0x3f }, { 1, 0x2e, 0x3f } },
{ { 0, 0x33, 0x3e }, { 1, 0x30, 0x3d } },
{ { 1, 0x2f, 0x3f }, { 0, 0x33, 0x3e } },
{ { 0, 0x33, 0x3f }, { 1, 0x30, 0x3e } },
{ { 0, 0x34, 0x3e }, { 1, 0x30, 0x3e } },
{ { 0, 0x34, 0x3f }, { 1, 0x30, 0x3f } },
{ { 0, 0x34, 0x3f }, { 1, 0x30, 0x3f } },
{ { 0, 0x35, 0x3e }, { 1, 0x31, 0x3f } },
{ { 0, 0x35, 0x3f }, { 1, 0x31, 0x3f } },
{ { 0, 0x36, 0x3e }, { 1, 0x32, 0x3f } },
{ { 0, 0x36, 0x3e }, { 1, 0x32, 0x3f } },
{ { 0, 0x36, 0x3f }, { 1, 0x33, 0x3f } },
{ { 0, 0x37, 0x3e }, { 1, 0x33, 0x3f } },
{ { 0, 0x37, 0x3f }, { 1, 0x34, 0x3f } },
{ { 0, 0x37, 0x3f }, { 1, 0x34, 0x3f } },
{ { 0, 0x38, 0x3e }, { 1, 0x35, 0x3f } },
{ { 0, 0x38, 0x3f }, { 1, 0x35, 0x3f } },
{ { 0, 0x39, 0x3e }, { 1, 0x36, 0x3f } },
{ { 0, 0x39, 0x3e }, { 1, 0x36, 0x3f } },
{ { 0, 0x39, 0x3f }, { 1, 0x37, 0x3f } },
{ { 0, 0x3a, 0x3e }, { 1, 0x37, 0x3f } },
{ { 0, 0x3a, 0x3f }, { 1, 0x38, 0x3f } },
{ { 0, 0x3a, 0x3f }, { 1, 0x38, 0x3f } },
{ { 0, 0x3b, 0x3e }, { 1, 0x39, 0x3f } },
{ { 0, 0x3b, 0x3f }, { 1, 0x39, 0x3f } },
{ { 0, 0x3c, 0x3e }, { 1, 0x3a, 0x3f } },
{ { 0, 0x3c, 0x3e }, { 1, 0x3a, 0x3f } },
{ { 0, 0x3c, 0x3f }, { 1, 0x3b, 0x3f } },
{ { 0, 0x3d, 0x3e }, { 1, 0x3b, 0x3f } },
{ { 0, 0x3d, 0x3f }, { 1, 0x3c, 0x3f } },
{ { 0, 0x3d, 0x3f }, { 1, 0x3c, 0x3f } },
{ { 0, 0x3e, 0x3e }, { 1, 0x3d, 0x3f } },
{ { 0, 0x3e, 0x3f }, { 1, 0x3d, 0x3f } },
{ { 1, 0x3e, 0x3f }, { 0, 0x3e, 0x3f } },
{ { 0, 0x3f, 0x3f }, { 1, 0x3e, 0x3f } },
{ { 0, 0x3f, 0x3f }, { 1, 0x3f, 0x3f } }
};

115
BPTCEncoder/src/BitStream.h Executable file
View File

@ -0,0 +1,115 @@
//--------------------------------------------------------------------------------------
// Copyright 2011 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies. Intel makes no representations about the
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//
//--------------------------------------------------------------------------------------
#ifndef __BITSTREAM_H__
#define __BITSTREAM_H__
class BitStream {
public:
BitStream(unsigned char *ptr, int nBits, int start_offset) :
m_BitsWritten(0),
m_NumBits(nBits),
m_NumBytes((nBits + start_offset + 7) >> 3),
m_CurByte(ptr),
m_NextBit(start_offset % 8),
done(false)
{ }
int GetBitsWritten() const { return m_BitsWritten; }
~BitStream() { }
void WriteBitsR(unsigned int val, unsigned int nBits) {
for(unsigned int i = 0; i < nBits; i++) {
WriteBit((val >> (nBits - i - 1)) & 1);
}
}
void WriteBits(unsigned int val, unsigned int nBits) {
for(unsigned int i = 0; i < nBits; i++) {
WriteBit((val >> i) & 1);
}
}
private:
void WriteBit(int b) {
if(done) return;
const unsigned int mask = 1 << m_NextBit++;
// clear the bit
*m_CurByte &= ~mask;
// Write the bit, if necessary
if(b) *m_CurByte |= mask;
// Next byte?
if(m_NextBit >= 8) {
m_CurByte += 1;
m_NextBit = 0;
}
done = done || ++m_BitsWritten >= m_NumBits;
}
int m_BitsWritten;
int m_NextBit;
const int m_NumBytes;
const int m_NumBits;
unsigned char *m_CurByte;
bool done;
};
class BitStreamReadOnly {
public:
BitStreamReadOnly(const unsigned char *ptr) :
m_BitsRead(0),
m_CurByte(ptr),
m_NextBit(0)
{ }
int GetBitsRead() const { return m_BitsRead; }
~BitStreamReadOnly() { }
int ReadBit() {
int bit = *m_CurByte >> m_NextBit++;
while(m_NextBit >= 8) {
m_NextBit -= 8;
m_CurByte++;
}
m_BitsRead++;
return bit & 1;
}
unsigned int ReadBits(unsigned int nBits) {
unsigned int ret = 0;
for(unsigned int i = 0; i < nBits; i++) {
ret |= (ReadBit() & 1) << i;
}
return ret;
}
private:
int m_BitsRead;
int m_NextBit;
const unsigned char *m_CurByte;
};
#endif //__BITSTREAM_H__

509
BPTCEncoder/src/RGBAEndpoints.cpp Executable file
View File

@ -0,0 +1,509 @@
//--------------------------------------------------------------------------------------
// Copyright 2011 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies. Intel makes no representations about the
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//
//--------------------------------------------------------------------------------------
#include "BC7IntTypes.h"
#include "RGBAEndpoints.h"
#include "BC7Compressor.h"
#include "BC7CompressionMode.h"
#include <cassert>
#include <cstdlib>
#include <cstdio>
#include <cfloat>
#ifndef min
template <typename T>
static T min(const T &a, const T &b) {
return (a > b)? b : a;
}
#endif
#ifndef max
template <typename T>
static T max(const T &a, const T &b) {
return (a > b)? a : b;
}
#endif
static const double kPi = 3.141592653589793238462643383279502884197;
static const float kFloatConversion[256] = {
0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f,
16.0f, 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f, 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, 30.0f, 31.0f,
32.0f, 33.0f, 34.0f, 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, 40.0f, 41.0f, 42.0f, 43.0f, 44.0f, 45.0f, 46.0f, 47.0f,
48.0f, 49.0f, 50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f, 56.0f, 57.0f, 58.0f, 59.0f, 60.0f, 61.0f, 62.0f, 63.0f,
64.0f, 65.0f, 66.0f, 67.0f, 68.0f, 69.0f, 70.0f, 71.0f, 72.0f, 73.0f, 74.0f, 75.0f, 76.0f, 77.0f, 78.0f, 79.0f,
80.0f, 81.0f, 82.0f, 83.0f, 84.0f, 85.0f, 86.0f, 87.0f, 88.0f, 89.0f, 90.0f, 91.0f, 92.0f, 93.0f, 94.0f, 95.0f,
96.0f, 97.0f, 98.0f, 99.0f, 100.0f, 101.0f, 102.0f, 103.0f, 104.0f, 105.0f, 106.0f, 107.0f, 108.0f, 109.0f, 110.0f, 111.0f,
112.0f, 113.0f, 114.0f, 115.0f, 116.0f, 117.0f, 118.0f, 119.0f, 120.0f, 121.0f, 122.0f, 123.0f, 124.0f, 125.0f, 126.0f, 127.0f,
128.0f, 129.0f, 130.0f, 131.0f, 132.0f, 133.0f, 134.0f, 135.0f, 136.0f, 137.0f, 138.0f, 139.0f, 140.0f, 141.0f, 142.0f, 143.0f,
144.0f, 145.0f, 146.0f, 147.0f, 148.0f, 149.0f, 150.0f, 151.0f, 152.0f, 153.0f, 154.0f, 155.0f, 156.0f, 157.0f, 158.0f, 159.0f,
160.0f, 161.0f, 162.0f, 163.0f, 164.0f, 165.0f, 166.0f, 167.0f, 168.0f, 169.0f, 170.0f, 171.0f, 172.0f, 173.0f, 174.0f, 175.0f,
176.0f, 177.0f, 178.0f, 179.0f, 180.0f, 181.0f, 182.0f, 183.0f, 184.0f, 185.0f, 186.0f, 187.0f, 188.0f, 189.0f, 190.0f, 191.0f,
192.0f, 193.0f, 194.0f, 195.0f, 196.0f, 197.0f, 198.0f, 199.0f, 200.0f, 201.0f, 202.0f, 203.0f, 204.0f, 205.0f, 206.0f, 207.0f,
208.0f, 209.0f, 210.0f, 211.0f, 212.0f, 213.0f, 214.0f, 215.0f, 216.0f, 217.0f, 218.0f, 219.0f, 220.0f, 221.0f, 222.0f, 223.0f,
224.0f, 225.0f, 226.0f, 227.0f, 228.0f, 229.0f, 230.0f, 231.0f, 232.0f, 233.0f, 234.0f, 235.0f, 236.0f, 237.0f, 238.0f, 239.0f,
240.0f, 241.0f, 242.0f, 243.0f, 244.0f, 245.0f, 246.0f, 247.0f, 248.0f, 249.0f, 250.0f, 251.0f, 252.0f, 253.0f, 254.0f, 255.0f
};
///////////////////////////////////////////////////////////////////////////////
//
// Static helper functions
//
///////////////////////////////////////////////////////////////////////////////
static inline uint32 CountBitsInMask(uint8 n) {
#if _WIN64
if(!n) return 0; // no bits set
if(!(n & (n-1))) return 1; // power of two
uint32 c;
for(c = 0; n; c++) {
n &= n - 1;
}
return c;
#else
__asm
{
mov eax, 8
movzx ecx, n
bsf ecx, ecx
sub eax, ecx
}
#endif
}
template <typename ty>
static inline void clamp(ty &x, const ty &min, const ty &max) {
x = (x < min)? min : ((x > max)? max : x);
}
// absolute distance. It turns out the compiler does a much
// better job of optimizing this than we can, since we can't
// translate the values to/from registers
static uint8 sad(uint8 a, uint8 b) {
#if 0
__asm
{
movzx eax, a
movzx ecx, b
sub eax, ecx
jns done
neg eax
done:
}
#else
//const INT d = a - b;
//const INT mask = d >> 31;
//return (d ^ mask) - mask;
// return abs(a - b);
return (a > b)? a - b : b - a;
#endif
}
///////////////////////////////////////////////////////////////////////////////
//
// RGBAVector implementation
//
///////////////////////////////////////////////////////////////////////////////
uint8 QuantizeChannel(const uint8 val, const uint8 mask, const int pBit) {
// If the mask is all the bits, then we can just return the value.
if(mask == 0xFF) {
return val;
}
uint32 prec = CountBitsInMask(mask);
const uint32 step = 1 << (8 - prec);
assert(step-1 == uint8(~mask));
uint32 lval = val & mask;
uint32 hval = lval + step;
if(pBit >= 0) {
prec++;
lval |= !!(pBit) << (8 - prec);
hval |= !!(pBit) << (8 - prec);
}
if(lval > val) {
lval -= step;
hval -= step;
}
lval |= lval >> prec;
hval |= hval >> prec;
if(sad(val, lval) < sad(val, hval))
return lval;
else
return hval;
}
uint32 RGBAVector::ToPixel(const uint32 channelMask, const int pBit) const {
uint32 ret = 0;
uint8 *pRet = (uint8 *)&ret;
const uint8 *channelMaskBytes = (const uint8 *)&channelMask;
pRet[0] = QuantizeChannel(uint32(r + 0.5) & 0xFF, channelMaskBytes[0], pBit);
pRet[1] = QuantizeChannel(uint32(g + 0.5) & 0xFF, channelMaskBytes[1], pBit);
pRet[2] = QuantizeChannel(uint32(b + 0.5) & 0xFF, channelMaskBytes[2], pBit);
pRet[3] = QuantizeChannel(uint32(a + 0.5) & 0xFF, channelMaskBytes[3], pBit);
return ret;
}
///////////////////////////////////////////////////////////////////////////////
//
// RGBAMatrix implementation
//
///////////////////////////////////////////////////////////////////////////////
RGBAMatrix &RGBAMatrix::operator *=(const RGBAMatrix &mat) {
*this = ((*this) * mat);
return (*this);
}
RGBAMatrix RGBAMatrix::operator *(const RGBAMatrix &mat) const {
RGBAMatrix result;
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 4; j++) {
result(i, j) = 0.0f;
for(int k = 0; k < 4; k++) {
result(i, j) += m[i*4 + k] * mat.m[k*4 + j];
}
}
}
return result;
}
RGBAVector RGBAMatrix::operator *(const RGBAVector &p) const {
return RGBAVector (
p.x * m1 + p.y * m2 + p.z * m3 + p.w * m4,
p.x * m5 + p.y * m6 + p.z * m7 + p.w * m8,
p.x * m9 + p.y * m10 + p.z * m11 + p.w * m12,
p.x * m13 + p.y * m14 + p.z * m15 + p.w * m16
);
}
RGBAMatrix RGBAMatrix::RotateX(float rad) {
RGBAMatrix result;
result.m6 = result.m11 = cos(rad);
result.m10 = sin(rad);
result.m7 = -result.m10;
return result;
}
RGBAMatrix RGBAMatrix::RotateY(float rad) {
RGBAMatrix result;
result.m1 = result.m11 = cos(rad);
result.m3 = sin(rad);
result.m9 = -result.m3;
return result;
}
RGBAMatrix RGBAMatrix::RotateZ(float rad) {
RGBAMatrix result;
result.m1 = result.m6 = cos(rad);
result.m5 = sin(rad);
result.m2 = -result.m5;
return result;
}
RGBAMatrix RGBAMatrix::Translate(const RGBAVector &t) {
RGBAMatrix result;
result.m4 = t.x;
result.m8 = t.y;
result.m12 = t.z;
result.m16 = t.w;
return result;
}
bool RGBAMatrix::Identity() {
for(int i = 0; i < 4; i++) {
for(int j = 0; j < 4; j++) {
if(i == j) {
if(fabs(m[i*4 + j] - 1.0f) > 1e-5)
return false;
}
else {
if(fabs(m[i*4 + j]) > 1e-5)
return false;
}
}
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// Cluster implementation
//
///////////////////////////////////////////////////////////////////////////////
RGBACluster::RGBACluster(const RGBACluster &left, const RGBACluster &right) {
*this = left;
for(int i = 0; i < right.m_NumPoints; i++) {
const RGBAVector &p = right.m_DataPoints[i];
AddPoint(p);
}
m_PrincipalAxisCached = false;
}
void RGBACluster::AddPoint(const RGBAVector &p) {
assert(m_NumPoints < kMaxNumDataPoints);
m_Total += p;
m_DataPoints[m_NumPoints++] = p;
m_PointBitString |= 1 << p.GetIdx();
for(int i = 0; i < kNumColorChannels; i++) {
m_Min.c[i] = min(p.c[i], m_Min.c[i]);
m_Max.c[i] = max(p.c[i], m_Max.c[i]);
}
}
void RGBACluster::GetPrincipalAxis(RGBADir &axis) {
if(m_PrincipalAxisCached) {
axis = m_PrincipalAxis;
return;
}
RGBAVector avg = m_Total / float(m_NumPoints);
::GetPrincipalAxis(m_NumPoints, m_DataPoints, m_PrincipalAxis);
m_PrincipalAxisCached = true;
GetPrincipalAxis(axis);
}
double RGBACluster::QuantizedError(const RGBAVector &p1, const RGBAVector &p2, uint8 nBuckets, uint32 bitMask, const RGBAVector &errorMetricVec, const int pbits[2], int *indices) const {
// nBuckets should be a power of two.
assert(nBuckets == 3 || !(nBuckets & (nBuckets - 1)));
const uint8 indexPrec = (nBuckets == 3)? 3 : 8-CountBitsInMask(~(nBuckets - 1));
typedef uint32 tInterpPair[2];
typedef tInterpPair tInterpLevel[16];
const tInterpLevel *interpVals = (nBuckets == 3)? kBC7InterpolationValues : kBC7InterpolationValues + (indexPrec - 1);
assert(indexPrec >= 2 && indexPrec <= 4);
uint32 qp1, qp2;
if(pbits) {
qp1 = p1.ToPixel(bitMask, pbits[0]);
qp2 = p2.ToPixel(bitMask, pbits[1]);
}
else {
qp1 = p1.ToPixel(bitMask);
qp2 = p2.ToPixel(bitMask);
}
uint8 *pqp1 = (uint8 *)&qp1;
uint8 *pqp2 = (uint8 *)&qp2;
float totalError = 0.0;
for(int i = 0; i < m_NumPoints; i++) {
const uint32 pixel = m_DataPoints[i].ToPixel();
const uint8 *pb = (const uint8 *)(&pixel);
float minError = FLT_MAX;
int bestBucket = -1;
for(int j = 0; j < nBuckets; j++) {
uint32 interp0 = (*interpVals)[j][0];
uint32 interp1 = (*interpVals)[j][1];
RGBAVector errorVec (0.0f);
for(int k = 0; k < kNumColorChannels; k++) {
const uint8 ip = (((uint32(pqp1[k]) * interp0) + (uint32(pqp2[k]) * interp1) + 32) >> 6) & 0xFF;
const uint8 dist = sad(pb[k], ip);
errorVec.c[k] = kFloatConversion[dist];
}
errorVec *= errorMetricVec;
float error = errorVec * errorVec;
if(error < minError) {
minError = error;
bestBucket = j;
}
// Conceptually, once the error starts growing, it doesn't stop growing (we're moving
// farther away from the reference point along the line). Hence we can early out here.
// However, quanitzation artifacts mean that this is not ALWAYS the case, so we do suffer
// about 0.01 RMS error.
else if(error > minError) {
break;
}
}
totalError += minError;
assert(bestBucket >= 0);
if(indices) indices[i] = bestBucket;
}
return totalError;
}
///////////////////////////////////////////////////////////////////////////////
//
// Utility function implementation
//
///////////////////////////////////////////////////////////////////////////////
void ClampEndpoints(RGBAVector &p1, RGBAVector &p2) {
clamp(p1.r, 0.0f, 255.0f);
clamp(p1.g, 0.0f, 255.0f);
clamp(p1.b, 0.0f, 255.0f);
clamp(p1.a, 0.0f, 255.0f);
clamp(p2.r, 0.0f, 255.0f);
clamp(p2.g, 0.0f, 255.0f);
clamp(p2.b, 0.0f, 255.0f);
clamp(p2.a, 0.0f, 255.0f);
}
void GetPrincipalAxis(int nPts, const RGBAVector *pts, RGBADir &axis) {
assert(nPts > 0);
assert(nPts <= kMaxNumDataPoints);
RGBAVector avg (0.0f);
for(int i = 0; i < nPts; i++) {
avg += pts[i];
}
avg /= float(nPts);
// We use these vectors for calculating the covariance matrix...
RGBAVector toPts[kMaxNumDataPoints];
RGBAVector toPtsMax(-FLT_MAX);
for(int i = 0; i < nPts; i++) {
toPts[i] = pts[i] - avg;
for(int j = 0; j < kNumColorChannels; j++) {
toPtsMax.c[j] = max(toPtsMax.c[j], toPts[i].c[j]);
}
}
// Generate a list of unique points...
RGBAVector upts[kMaxNumDataPoints];
int uptsIdx = 0;
for(int i = 0; i < nPts; i++) {
bool hasPt = false;
for(int j = 0; j < uptsIdx; j++) {
if(upts[j] == pts[i])
hasPt = true;
}
if(!hasPt) {
upts[uptsIdx++] = pts[i];
}
}
assert(uptsIdx > 0);
if(uptsIdx == 1) {
axis.r = axis.g = axis.b = axis.a = 0.0f;
return;
}
// Collinear?
else {
RGBADir dir (upts[1] - upts[0]);
bool collinear = true;
for(int i = 2; i < nPts; i++) {
RGBAVector v = (upts[i] - upts[0]);
if(fabs(fabs(v*dir) - v.Length()) > 1e-7) {
collinear = false;
break;
}
}
if(collinear) {
axis = dir;
return;
}
}
RGBAMatrix covMatrix;
// Compute covariance.
for(int i = 0; i < kNumColorChannels; i++) {
for(int j = 0; j <= i; j++) {
float sum = 0.0;
for(int k = 0; k < nPts; k++) {
sum += toPts[k].c[i] * toPts[k].c[j];
}
covMatrix(i, j) = sum / kFloatConversion[kNumColorChannels - 1];
covMatrix(j, i) = covMatrix(i, j);
}
}
// !SPEED! Find eigenvectors by using the power method. This is good because the
// matrix is only 4x4, which allows us to use SIMD...
RGBAVector b = toPtsMax;
assert(b.Length() > 0);
b /= b.Length();
bool fixed = false;
int infLoopPrevention = 0;
const int kMaxNumIterations = 200;
while(!fixed && ++infLoopPrevention < kMaxNumIterations) {
RGBAVector newB = covMatrix * b;
// !HACK! If the principal eigenvector of the covariance matrix
// converges to zero, that means that the points lie equally
// spaced on a sphere in this space. In this (extremely rare)
// situation, just choose a point and use it as the principal
// direction.
const float newBlen = newB.Length();
if(newBlen < 1e-10) {
axis = toPts[0];
return;
}
newB /= newB.Length();
if(fabs(1.0f - (b * newB)) < 1e-5)
fixed = true;
b = newB;
}
assert(infLoopPrevention < kMaxNumIterations);
axis = b;
}

354
BPTCEncoder/src/RGBAEndpoints.h Executable file
View File

@ -0,0 +1,354 @@
//--------------------------------------------------------------------------------------
// Copyright 2011 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies. Intel makes no representations about the
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//
//--------------------------------------------------------------------------------------
#ifndef __RGBA_ENDPOINTS_H__
#define __RGBA_ENDPOINTS_H__
#include "BC7IntTypes.h"
#include <cmath>
#include <cfloat>
#include <cstring>
static const int kNumColorChannels = 4;
static const int kMaxNumDataPoints = 16;
class RGBAVector {
public:
union {
struct { float r, g, b, a; };
struct { float x, y, z, w; };
float c[4];
};
uint32 GetIdx() const { return idx; }
RGBAVector() : r(-1.0), g(-1.0), b(-1.0), a(-1.0) { }
RGBAVector(uint32 _idx, uint32 pixel) :
r(float(pixel & 0xFF)),
g(float((pixel >> 8) & 0xFF)),
b(float((pixel >> 16) & 0xFF)),
a(float((pixel >> 24) & 0xFF)),
idx(_idx)
{ }
RGBAVector(float _r, float _g, float _b, float _a) :
r(_r), g(_g), b(_b), a(_a) { }
explicit RGBAVector(float cc) : r(cc), g(cc), b(cc), a(cc) { }
RGBAVector &operator =(const RGBAVector &other) {
this->idx = other.idx;
memcpy(c, other.c, sizeof(c));
return (*this);
}
RGBAVector operator +(const RGBAVector &p) const {
return RGBAVector(r + p.r, g + p.g, b + p.b, a + p.a);
}
RGBAVector &operator +=(const RGBAVector &p) {
r += p.r; g += p.g; b += p.b; a += p.a;
return *this;
}
RGBAVector operator -(const RGBAVector &p) const {
return RGBAVector(r - p.r, g - p.g, b - p.b, a - p.a);
}
RGBAVector &operator -=(const RGBAVector &p) {
r -= p.r; g -= p.g; b -= p.b; a -= p.a;
return *this;
}
RGBAVector operator /(const float s) const {
return RGBAVector(r / s, g / s, b / s, a / s);
}
RGBAVector &operator /=(const float s) {
r /= s; g /= s; b /= s; a /= s;
return *this;
}
float operator *(const RGBAVector &p) const {
return r * p.r + g * p.g + b * p.b + a * p.a;
}
float Length() const {
return sqrt((*this) * (*this));
}
RGBAVector &operator *=(const RGBAVector &v) {
r *= v.r; g *= v.g; b *= v.b; a *= v.a;
return *this;
}
RGBAVector operator *(const float s) const {
return RGBAVector(r * s, g * s, b * s, a * s);
}
friend RGBAVector operator *(const float s, const RGBAVector &p) {
return RGBAVector(p.r * s, p.g * s, p.b * s, p.a * s);
}
RGBAVector &operator *=(const float s) {
r *= s; g *= s; b *= s; a *= s;
return *this;
}
float &operator [](const int i) {
return c[i];
}
friend bool operator ==(const RGBAVector &rhs, const RGBAVector &lhs) {
const RGBAVector d = rhs - lhs;
return fabs(d.r) < 1e-7 && fabs(d.g) < 1e-7 && fabs(d.b) < 1e-7 && fabs(d.a) < 1e-7;
}
friend bool operator !=(const RGBAVector &rhs, const RGBAVector &lhs) {
return !(rhs == lhs);
}
operator float *() {
return c;
}
RGBAVector Cross(const RGBAVector &rhs) {
return RGBAVector(
rhs.y * z - y * rhs.z,
rhs.z * x - z * rhs.x,
rhs.x * y - x * rhs.y,
1.0f
);
}
// Quantize this point.
uint32 ToPixel(const uint32 channelMask = 0xFFFFFFFF, const int pBit = -1) const;
private:
uint32 idx;
};
class RGBAMatrix {
private:
union {
float m[kNumColorChannels*kNumColorChannels];
struct {
float m1, m2, m3, m4;
float m5, m6, m7, m8;
float m9, m10, m11, m12;
float m13, m14, m15, m16;
};
};
RGBAMatrix(const float *arr) {
memcpy(m, arr, sizeof(m));
}
public:
RGBAMatrix() :
m1(1.0f), m2(0.0f), m3(0.0f), m4(0.0f),
m5(0.0f), m6(1.0f), m7(0.0f), m8(0.0f),
m9(0.0f), m10(0.0f), m11(1.0f), m12(0.0f),
m13(0.0f), m14(0.0f), m15(0.0f), m16(1.0f)
{ }
RGBAMatrix &operator =(const RGBAMatrix &other) {
memcpy(m, other.m, sizeof(m));
return (*this);
}
RGBAMatrix operator +(const RGBAMatrix &p) const {
float newm[kNumColorChannels*kNumColorChannels];
for(int i = 0; i < kNumColorChannels*kNumColorChannels; i++) newm[i] = m[i] + p.m[i];
return RGBAMatrix(newm);
}
RGBAMatrix &operator +=(const RGBAMatrix &p) {
for(int i = 0; i < kNumColorChannels*kNumColorChannels; i++) m[i] += p.m[i];
return *this;
}
RGBAMatrix operator -(const RGBAMatrix &p) const {
float newm[kNumColorChannels*kNumColorChannels];
for(int i = 0; i < kNumColorChannels*kNumColorChannels; i++) newm[i] = m[i] - p.m[i];
return RGBAMatrix(newm);
}
RGBAMatrix &operator -=(const RGBAMatrix &p) {
for(int i = 0; i < kNumColorChannels*kNumColorChannels; i++) m[i] -= p.m[i];
return *this;
}
RGBAMatrix operator /(const float s) const {
float newm[kNumColorChannels*kNumColorChannels];
for(int i = 0; i < kNumColorChannels*kNumColorChannels; i++) newm[i] = m[i] / s;
return RGBAMatrix(newm);
}
RGBAMatrix &operator /=(const float s) {
for(int i = 0; i < kNumColorChannels*kNumColorChannels; i++) m[i] /= s;
return *this;
}
RGBAMatrix operator *(const float s) const {
float newm[kNumColorChannels*kNumColorChannels];
for(int i = 0; i < kNumColorChannels*kNumColorChannels; i++) newm[i] = m[i] * s;
return RGBAMatrix(newm);
}
RGBAMatrix operator *(const double s) const {
float newm[kNumColorChannels*kNumColorChannels];
for(int i = 0; i < kNumColorChannels*kNumColorChannels; i++) newm[i] = float(double(m[i]) * s);
return RGBAMatrix(newm);
}
friend RGBAMatrix operator *(const float s, const RGBAMatrix &p) {
float newm[kNumColorChannels*kNumColorChannels];
for(int i = 0; i < kNumColorChannels*kNumColorChannels; i++) newm[i] = p.m[i] * s;
return RGBAMatrix(newm);
}
friend RGBAMatrix operator *(const double s, const RGBAMatrix &p) {
float newm[kNumColorChannels*kNumColorChannels];
for(int i = 0; i < kNumColorChannels*kNumColorChannels; i++) newm[i] = float(double(p.m[i]) * s);
return RGBAMatrix(newm);
}
RGBAMatrix &operator *=(const float s) {
for(int i = 0; i < kNumColorChannels*kNumColorChannels; i++) m[i] *= s;
return *this;
}
float &operator ()(const int i, const int j) {
return (*this)[i*4 + j];
}
float &operator [](const int i) {
return m[i];
}
friend bool operator ==(const RGBAMatrix &rhs, const RGBAMatrix &lhs) {
const RGBAMatrix d = rhs - lhs;
for(int i = 0; i < kNumColorChannels*kNumColorChannels; i++)
if(d.m[i] > 1e-10)
return false;
return true;
}
operator float *() {
return m;
}
RGBAVector operator *(const RGBAVector &p) const;
RGBAMatrix operator *(const RGBAMatrix &mat) const;
RGBAMatrix &operator *=(const RGBAMatrix &mat);
static RGBAMatrix RotateX(float rad);
static RGBAMatrix RotateY(float rad);
static RGBAMatrix RotateZ(float rad);
static RGBAMatrix Translate(const RGBAVector &t);
bool Identity();
};
class RGBADir : public RGBAVector {
public:
RGBADir() : RGBAVector() { }
RGBADir(const RGBAVector &p) : RGBAVector(p) {
*this /= Length();
}
};
// Makes sure that the values of the endpoints lie between 0 and 1.
extern void ClampEndpoints(RGBAVector &p1, RGBAVector &p2);
class RGBACluster {
public:
RGBACluster() :
m_NumPoints(0), m_Total(0),
m_PointBitString(0),
m_Min(FLT_MAX),
m_Max(-FLT_MAX),
m_PrincipalAxisCached(false)
{ }
RGBACluster(const RGBACluster &c) :
m_NumPoints(c.m_NumPoints),
m_Total(c.m_Total),
m_PointBitString(c.m_PointBitString),
m_Min(c.m_Min),
m_Max(c.m_Max),
m_PrincipalAxisCached(false)
{
memcpy(this->m_DataPoints, c.m_DataPoints, m_NumPoints * sizeof(RGBAVector));
}
RGBACluster(const RGBACluster &left, const RGBACluster &right);
RGBACluster(const RGBAVector &p) :
m_NumPoints(1),
m_Total(p),
m_PointBitString(0),
m_Min(p), m_Max(p),
m_PrincipalAxisCached(false)
{
m_DataPoints[0] = p;
m_PointBitString |= (1 << p.GetIdx());
}
RGBAVector GetTotal() const { return m_Total; }
const RGBAVector &GetPoint(int idx) const { return m_DataPoints[idx]; }
int GetNumPoints() const { return m_NumPoints; }
RGBAVector GetAvg() const { return m_Total / float(m_NumPoints); }
const RGBAVector *GetPoints() const { return m_DataPoints; }
void AddPoint(const RGBAVector &p);
void GetBoundingBox(RGBAVector &Min, RGBAVector &Max) const {
Min = m_Min, Max = m_Max;
}
// Returns the error if we were to quantize the colors right now with the given number of buckets and bit mask.
double QuantizedError(const RGBAVector &p1, const RGBAVector &p2, uint8 nBuckets, uint32 bitMask, const RGBAVector &errorMetricVec, const int pbits[2] = NULL, int *indices = NULL) const;
// Returns the principal axis for this point cluster.
void GetPrincipalAxis(RGBADir &axis);
bool AllSamePoint() const { return m_Max == m_Min; }
int GetPointBitString() const { return m_PointBitString; }
private:
// The number of points in the cluster.
int m_NumPoints;
RGBAVector m_Total;
// The points in the cluster.
RGBAVector m_DataPoints[kMaxNumDataPoints];
RGBAVector m_Min, m_Max;
int m_PointBitString;
RGBADir m_PrincipalAxis;
bool m_PrincipalAxisCached;
};
extern uint8 QuantizeChannel(const uint8 val, const uint8 mask, const int pBit = -1);
extern void GetPrincipalAxis(int nPts, const RGBAVector *pts, RGBADir &axis);
#endif //__RGBA_ENDPOINTS_H__

View File

@ -0,0 +1,420 @@
//--------------------------------------------------------------------------------------
// Copyright 2011 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies. Intel makes no representations about the
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//
//--------------------------------------------------------------------------------------
#include "BC7Config.h"
#include "RGBAEndpointsSIMD.h"
#include "BC7Compressor.h"
#include "BC7CompressionModeSIMD.h"
#include <cassert>
#include <cfloat>
#ifndef HAS_SSE_POPCNT
static inline uint32 popcnt32(uint32 x) {
uint32 m1 = 0x55555555;
uint32 m2 = 0x33333333;
uint32 m3 = 0x0f0f0f0f;
x -= (x>>1) & 1;
x = (x&m2) + ((x>>2)&m2);
x = (x+(x>>4))&m3;
x += x>>8;
return (x+(x>>16)) & 0x3f;
}
#endif
///////////////////////////////////////////////////////////////////////////////
//
// RGBAVectorSIMD implementation
//
///////////////////////////////////////////////////////////////////////////////
/* Original scalar implementation:
// If the mask is all the bits, then we can just return the value.
if(mask == 0xFF) {
return val;
}
uint32 prec = CountBitsInMask(mask);
const uint32 step = 1 << (8 - prec);
assert(step-1 == uint8(~mask));
uint32 lval = val & mask;
uint32 hval = lval + step;
if(pBit >= 0) {
prec++;
lval |= !!(pBit) << (8 - prec);
hval |= !!(pBit) << (8 - prec);
}
if(lval > val) {
lval -= step;
hval -= step;
}
lval |= lval >> prec;
hval |= hval >> prec;
if(sad(val, lval) < sad(val, hval))
return lval;
else
return hval;
*/
// !TODO! AVX2 supports an instruction known as vsllv, which shifts a vector
// by the values stored in another vector. I.e. you can do something like this:
//
// __m128i shiftVals = _mm_set_epi32(1, 2, 3, 4);
// __m128i someVector = _mm_set1_epi32(1) ;
// __m128i shifted = _mm_srav_epi32 (someVector, shiftVals);
//
// and the result will be the same as __mm_Set_epi32(1, 4, 8, 16);
//
// This is useful because our color channels may have different precisions
// when we're quantizing them, such as for BC7 modes 4 and 5. Hence, we would
// want to do our quantization as accurately as possible, but currently it would
// be very hard to vectorize.
#ifdef _MSC_VER
#define ALIGN_SSE __declspec ( align(16) )
#else
#define ALIGN_SSE __attribute__((aligned(16)))
#endif
// Constants. There are two ways to specify them: either by using the _mm_set*
// intrinsics, or by defining them as aligned arrays. You want to do the former
// when you use them infrequently, and the latter when you use them multiple times
// in a short time frame (like in an inner loop)
static const __m128 kZero = _mm_set1_ps(0.0f);
static const __m128 kByteMax = _mm_set1_ps(255.0f);
static const __m128 kHalfVector = _mm_set1_ps(0.5f);
static const __m128i kOneVector = _mm_set1_epi32(1);
static const __m128i kZeroVector = _mm_set1_epi32(0);
static const ALIGN_SSE uint32 kThirtyTwoVector[4] = { 32, 32, 32, 32 };
static const __m128i kByteValMask = _mm_set_epi32(0xFF, 0xFF, 0xFF, 0xFF);
static inline __m128i sad(const __m128i &a, const __m128i &b) {
const __m128i maxab = _mm_max_epu8(a, b);
const __m128i minab = _mm_min_epu8(a, b);
return _mm_and_si128( kByteValMask, _mm_subs_epu8( maxab, minab ) );
}
__m128i RGBAVectorSIMD::ToPixel(const __m128i &qmask) const {
// !SPEED! We should figure out a way to get rid of these scalar operations.
#ifdef HAS_SSE_POPCNT
const uint32 prec = _mm_popcnt32(((uint32 *)(&qmask))[0]);
#else
const uint32 prec = popcnt32(((uint32 *)(&qmask))[0]);
#endif
assert(r >= 0.0f && r <= 255.0f);
assert(g >= 0.0f && g <= 255.0f);
assert(b >= 0.0f && b <= 255.0f);
assert(a >= 0.0f && a <= 255.0f);
assert(((uint32 *)(&qmask))[3] == 0xFF || ((uint32 *)(&qmask))[3] == ((uint32 *)(&qmask))[0]);
assert(((uint32 *)(&qmask))[2] == ((uint32 *)(&qmask))[1] && ((uint32 *)(&qmask))[0] == ((uint32 *)(&qmask))[1]);
const __m128i val = _mm_cvtps_epi32( _mm_add_ps(kHalfVector, vec) );
const __m128i step = _mm_slli_epi32( kOneVector, 8 - prec );
const __m128i &mask = qmask;
__m128i lval = _mm_and_si128(val, mask);
__m128i hval = _mm_add_epi32(lval, step);
const __m128i lvalShift = _mm_srli_epi32(lval, prec);
const __m128i hvalShift = _mm_srli_epi32(hval, prec);
lval = _mm_or_si128(lval, lvalShift);
hval = _mm_or_si128(hval, hvalShift);
const __m128i lvald = _mm_sub_epi32( val, lval );
const __m128i hvald = _mm_sub_epi32( hval, val );
const __m128i vd = _mm_cmplt_epi32(lvald, hvald);
__m128i ans = _mm_blendv_epi8(hval, lval, vd);
const __m128i chanExact = _mm_cmpeq_epi32(mask, kByteValMask);
ans = _mm_blendv_epi8( ans, val, chanExact );
return ans;
}
__m128i RGBAVectorSIMD::ToPixel(const __m128i &qmask, const int pBit) const {
// !SPEED! We should figure out a way to get rid of these scalar operations.
#ifdef HAS_SSE_POPCNT
const uint32 prec = _mm_popcnt32(((uint32 *)(&qmask))[0]);
#else
const uint32 prec = popcnt32(((uint32 *)(&qmask))[0]);
#endif
assert(r >= 0.0f && r <= 255.0f);
assert(g >= 0.0f && g <= 255.0f);
assert(b >= 0.0f && b <= 255.0f);
assert(a >= 0.0f && a <= 255.0f);
assert(((uint32 *)(&qmask))[3] == 0xFF || ((uint32 *)(&qmask))[3] == ((uint32 *)(&qmask))[0]);
assert(((uint32 *)(&qmask))[2] == ((uint32 *)(&qmask))[1] && ((uint32 *)(&qmask))[0] == ((uint32 *)(&qmask))[1]);
const __m128i val = _mm_cvtps_epi32( _mm_add_ps(kHalfVector, vec) );
const __m128i pbit = _mm_set1_epi32(!!pBit);
const __m128i &mask = qmask; // _mm_set_epi32(alphaMask, channelMask, channelMask, channelMask);
const __m128i step = _mm_slli_epi32( kOneVector, 8 - prec );
__m128i lval = _mm_and_si128( val, mask );
__m128i hval = _mm_add_epi32( lval, step );
const __m128i pBitShifted = _mm_slli_epi32(pbit, 7 - prec);
lval = _mm_or_si128(lval, pBitShifted );
hval = _mm_or_si128(hval, pBitShifted);
// These next three lines we make sure that after adding the pbit that val is
// still in between lval and hval. If it isn't, then we subtract a
// step from both. Now, val should be larger than lval and less than
// hval, but certain situations make this not always the case (e.g. val
// is 0, precision is 4 bits, and pbit is 1). Hence, we add back the
// step if it goes below zero, making it equivalent to hval and so it
// doesn't matter which we choose.
{
__m128i cmp = _mm_cmpgt_epi32(lval, val);
cmp = _mm_mullo_epi32(cmp, step);
lval = _mm_add_epi32(lval, cmp);
hval = _mm_add_epi32(hval, cmp);
cmp = _mm_cmplt_epi32(lval, kZeroVector);
cmp = _mm_mullo_epi32(cmp, step);
lval = _mm_sub_epi32(lval, cmp);
}
const __m128i lvalShift = _mm_srli_epi32(lval, prec + 1);
const __m128i hvalShift = _mm_srli_epi32(hval, prec + 1);
lval = _mm_or_si128(lval, lvalShift);
hval = _mm_or_si128(hval, hvalShift);
const __m128i lvald = _mm_sub_epi32( val, lval );
const __m128i hvald = _mm_sub_epi32( hval, val );
const __m128i vd = _mm_cmplt_epi32(lvald, hvald);
__m128i ans = _mm_blendv_epi8(hval, lval, vd);
const __m128i chanExact = _mm_cmpeq_epi32(mask, kByteValMask);
ans = _mm_blendv_epi8( ans, val, chanExact );
return ans;
}
///////////////////////////////////////////////////////////////////////////////
//
// RGBAMatrixSIMD implementation
//
///////////////////////////////////////////////////////////////////////////////
RGBAVectorSIMD RGBAMatrixSIMD::operator *(const RGBAVectorSIMD &p) const {
__m128 xVec = _mm_set1_ps( p.x );
__m128 yVec = _mm_set1_ps( p.y );
__m128 zVec = _mm_set1_ps( p.z );
__m128 wVec = _mm_set1_ps( p.w );
__m128 vec1 = _mm_mul_ps( xVec, col[0] );
__m128 vec2 = _mm_mul_ps( yVec, col[1] );
__m128 vec3 = _mm_mul_ps( zVec, col[2] );
__m128 vec4 = _mm_mul_ps( wVec, col[3] );
return RGBAVectorSIMD( _mm_add_ps( _mm_add_ps( vec1, vec2 ), _mm_add_ps( vec3, vec4 ) ) );
}
///////////////////////////////////////////////////////////////////////////////
//
// Cluster implementation
//
///////////////////////////////////////////////////////////////////////////////
RGBAClusterSIMD::RGBAClusterSIMD(const RGBAClusterSIMD &left, const RGBAClusterSIMD &right) {
assert(!(left.m_PointBitString & right.m_PointBitString));
*this = left;
for(int i = 0; i < right.m_NumPoints; i++) {
const RGBAVectorSIMD &p = right.m_DataPoints[i];
assert(m_NumPoints < kMaxNumDataPoints);
m_Total += p;
m_DataPoints[m_NumPoints++] = p;
m_Min.vec = _mm_min_ps(m_Min.vec, p.vec);
m_Max.vec = _mm_max_ps(m_Max.vec, p.vec);
}
m_PointBitString = left.m_PointBitString | right.m_PointBitString;
m_PrincipalAxisCached = false;
}
void RGBAClusterSIMD::AddPoint(const RGBAVectorSIMD &p, int idx) {
assert(m_NumPoints < kMaxNumDataPoints);
m_Total += p;
m_DataPoints[m_NumPoints++] = p;
m_PointBitString |= 1 << idx;
m_Min.vec = _mm_min_ps(m_Min.vec, p.vec);
m_Max.vec = _mm_max_ps(m_Max.vec, p.vec);
}
float RGBAClusterSIMD::QuantizedError(const RGBAVectorSIMD &p1, const RGBAVectorSIMD &p2, const uint8 nBuckets, const __m128i &bitMask, const int pbits[2], __m128i *indices) const {
// nBuckets should be a power of two.
assert(!(nBuckets & (nBuckets - 1)));
const uint8 indexPrec = 8-_mm_popcnt_u32(~(nBuckets - 1) & 0xFF);
assert(indexPrec >= 2 && indexPrec <= 4);
typedef __m128i tInterpPair[2];
typedef tInterpPair tInterpLevel[16];
const tInterpLevel *interpVals = kBC7InterpolationValuesSIMD + (indexPrec - 1);
__m128i qp1, qp2;
if(pbits) {
qp1 = p1.ToPixel(bitMask, pbits[0]);
qp2 = p2.ToPixel(bitMask, pbits[1]);
}
else {
qp1 = p1.ToPixel(bitMask);
qp2 = p2.ToPixel(bitMask);
}
__m128 errorMetricVec = _mm_load_ps( BC7C::GetErrorMetric() );
__m128 totalError = kZero;
for(int i = 0; i < m_NumPoints; i++) {
const __m128i pixel = m_DataPoints[i].ToPixel( kByteValMask );
__m128 minError = _mm_set1_ps(FLT_MAX);
__m128i bestBucket = _mm_set1_epi32(-1);
for(int j = 0; j < nBuckets; j++) {
const __m128i jVec = _mm_set1_epi32(j);
const __m128i interp0 = (*interpVals)[j][0];
const __m128i interp1 = (*interpVals)[j][1];
const __m128i ip0 = _mm_mullo_epi32( qp1, interp0 );
const __m128i ip1 = _mm_mullo_epi32( qp2, interp1 );
const __m128i ip = _mm_add_epi32( *((const __m128i *)kThirtyTwoVector), _mm_add_epi32( ip0, ip1 ) );
const __m128i dist = sad( _mm_and_si128( _mm_srli_epi32( ip, 6 ), kByteValMask ), pixel );
__m128 errorVec = _mm_cvtepi32_ps( dist );
errorVec = _mm_mul_ps( errorVec, errorMetricVec );
errorVec = _mm_mul_ps( errorVec, errorVec );
errorVec = _mm_hadd_ps( errorVec, errorVec );
errorVec = _mm_hadd_ps( errorVec, errorVec );
const __m128 cmp = _mm_cmple_ps( errorVec, minError );
minError = _mm_blendv_ps( minError, errorVec, cmp );
bestBucket = _mm_blendv_epi8( bestBucket, jVec, _mm_castps_si128( cmp ) );
// Conceptually, once the error starts growing, it doesn't stop growing (we're moving
// farther away from the reference point along the line). Hence we can early out here.
// However, quanitzation artifacts mean that this is not ALWAYS the case, so we do suffer
// about 0.01 RMS error.
if(!((uint8 *)(&cmp))[0])
break;
}
totalError = _mm_add_ps(totalError, minError);
if(indices) ((uint32 *)indices)[i] = ((uint32 *)(&bestBucket))[0];
}
return ((float *)(&totalError))[0];
}
///////////////////////////////////////////////////////////////////////////////
//
// Utility function implementation
//
///////////////////////////////////////////////////////////////////////////////
void ClampEndpoints(RGBAVectorSIMD &p1, RGBAVectorSIMD &p2) {
p1.vec = _mm_min_ps( kByteMax, _mm_max_ps( p1.vec, kZero ) );
p2.vec = _mm_min_ps( kByteMax, _mm_max_ps( p2.vec, kZero ) );
}
void GetPrincipalAxis(const RGBAClusterSIMD &c, RGBADirSIMD &axis) {
if(c.GetNumPoints() == 2) {
axis = c.GetPoint(1) - c.GetPoint(0);
return;
}
RGBAVectorSIMD avg = c.GetTotal();
avg /= float(c.GetNumPoints());
// We use these vectors for calculating the covariance matrix...
RGBAVectorSIMD toPts[kMaxNumDataPoints];
RGBAVectorSIMD toPtsMax(-FLT_MAX);
for(int i = 0; i < c.GetNumPoints(); i++) {
toPts[i] = c.GetPoint(i) - avg;
toPtsMax.vec = _mm_max_ps(toPtsMax.vec, toPts[i].vec);
}
RGBAMatrixSIMD covMatrix;
// Compute covariance.
const float fNumPoints = float(c.GetNumPoints());
for(int i = 0; i < kNumColorChannels; i++) {
for(int j = 0; j <= i; j++) {
float sum = 0.0;
for(int k = 0; k < c.GetNumPoints(); k++) {
sum += toPts[k].c[i] * toPts[k].c[j];
}
covMatrix(i, j) = sum / fNumPoints;
covMatrix(j, i) = covMatrix(i, j);
}
}
// !SPEED! Find eigenvectors by using the power method. This is good because the
// matrix is only 4x4, which allows us to use SIMD...
RGBAVectorSIMD b = toPtsMax;
assert(b.Length() > 0);
b /= b.Length();
RGBAVectorSIMD newB = covMatrix * b;
// !HACK! If the principal eigenvector of the covariance matrix
// converges to zero, that means that the points lie equally
// spaced on a sphere in this space. In this (extremely rare)
// situation, just choose a point and use it as the principal
// direction.
const float newBlen = newB.Length();
if(newBlen < 1e-10) {
axis = toPts[0];
return;
}
for(int i = 0; i < 8; i++) {
newB = covMatrix * b;
newB.Normalize();
b = newB;
}
axis = b;
}

View File

@ -0,0 +1,374 @@
//--------------------------------------------------------------------------------------
// Copyright 2011 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies. Intel makes no representations about the
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//
//--------------------------------------------------------------------------------------
#ifndef __RGBA_SIMD_ENDPOINTS_H__
#define __RGBA_SIMD_ENDPOINTS_H__
#include "BC7IntTypes.h"
#include <cmath>
#include <cfloat>
#include <cstring>
#include <smmintrin.h>
static const int kNumColorChannels = 4;
static const int kMaxNumDataPoints = 16;
static const __m128 kEpsilonSIMD = _mm_set1_ps(1e-8f);
class RGBAVectorSIMD {
public:
union {
struct { float r, g, b, a; };
struct { float x, y, z, w; };
float c[4];
__m128 vec;
};
RGBAVectorSIMD() : r(-1.0), g(-1.0), b(-1.0), a(-1.0) { }
RGBAVectorSIMD(uint32 pixel) :
r(float(pixel & 0xFF)),
g(float((pixel >> 8) & 0xFF)),
b(float((pixel >> 16) & 0xFF)),
a(float((pixel >> 24) & 0xFF))
{ }
explicit RGBAVectorSIMD(float _r, float _g, float _b, float _a) :
r(_r), g(_g), b(_b), a(_a) { }
explicit RGBAVectorSIMD(float cc) : r(cc), g(cc), b(cc), a(cc) { }
RGBAVectorSIMD (const __m128 &newVec) : vec(newVec) { }
RGBAVectorSIMD (const RGBAVectorSIMD &other) : vec(other.vec) { }
RGBAVectorSIMD operator +(const RGBAVectorSIMD &p) const {
return RGBAVectorSIMD( _mm_add_ps(this->vec, p.vec) );
}
RGBAVectorSIMD &operator +=(const RGBAVectorSIMD &p) {
this->vec = _mm_add_ps(this->vec, p.vec);
return *this;
}
RGBAVectorSIMD operator -(const RGBAVectorSIMD &p) const {
return RGBAVectorSIMD( _mm_sub_ps(this->vec, p.vec) );
}
RGBAVectorSIMD &operator -=(const RGBAVectorSIMD &p) {
this->vec = _mm_sub_ps(this->vec, p.vec);
return *this;
}
RGBAVectorSIMD operator /(const float s) const {
return RGBAVectorSIMD( _mm_div_ps(this->vec, _mm_set1_ps(s) ) );
}
RGBAVectorSIMD &operator /=(const float s) {
this->vec = _mm_div_ps(this->vec, _mm_set1_ps(s) );
return *this;
}
float operator *(const RGBAVectorSIMD &p) const {
__m128 mul = _mm_mul_ps(this->vec, p.vec);
mul = _mm_hadd_ps(mul, mul);
mul = _mm_hadd_ps(mul, mul);
return ((float *)(&mul))[0];
}
void Normalize() {
__m128 rsqrt = _mm_rsqrt_ps( _mm_set1_ps( (*this) * (*this) ) );
vec = _mm_mul_ps( vec, rsqrt );
}
float Length() const {
return sqrt((*this) * (*this));
}
RGBAVectorSIMD &operator *=(const RGBAVectorSIMD &v) {
this->vec = _mm_mul_ps(this->vec, v.vec);
return *this;
}
RGBAVectorSIMD operator *(const float s) const {
return RGBAVectorSIMD( _mm_mul_ps( this->vec, _mm_set1_ps(s) ) );
}
friend RGBAVectorSIMD operator *(const float s, const RGBAVectorSIMD &p) {
return RGBAVectorSIMD( _mm_mul_ps( p.vec, _mm_set1_ps(s) ) );
}
RGBAVectorSIMD &operator *=(const float s) {
this->vec = _mm_mul_ps( this->vec, _mm_set1_ps(s) );
return *this;
}
float &operator [](const int i) {
return c[i];
}
friend bool operator ==(const RGBAVectorSIMD &rhs, const RGBAVectorSIMD &lhs) {
__m128 d = _mm_sub_ps(rhs.vec, lhs.vec);
d = _mm_mul_ps(d, d);
__m128 cmp = _mm_cmpgt_ps(d, kEpsilonSIMD);
cmp = _mm_hadd_ps(cmp, cmp);
cmp = _mm_hadd_ps(cmp, cmp);
return ((float *)(&cmp))[0] == 0.0f;
}
friend bool operator !=(const RGBAVectorSIMD &rhs, const RGBAVectorSIMD &lhs) {
return !(rhs == lhs);
}
operator float *() {
return c;
}
// Quantize this point.
__m128i ToPixel(const __m128i &channelMask, const int pBit) const;
__m128i ToPixel(const __m128i &channelMask) const;
};
class RGBAMatrixSIMD {
private:
union {
float m[kNumColorChannels*kNumColorChannels];
struct {
float m1, m5, m9, m13;
float m2, m6, m10, m14;
float m3, m7, m11, m15;
float m4, m8, m12, m16;
};
__m128 col[kNumColorChannels];
};
RGBAMatrixSIMD(const float *arr) {
memcpy(m, arr, sizeof(m));
}
RGBAMatrixSIMD(const __m128 newcol[kNumColorChannels]) {
for(int i = 0; i < kNumColorChannels; i++)
col[i] = newcol[i];
}
public:
RGBAMatrixSIMD() :
m1(1.0f), m2(0.0f), m3(0.0f), m4(0.0f),
m5(0.0f), m6(1.0f), m7(0.0f), m8(0.0f),
m9(0.0f), m10(0.0f), m11(1.0f), m12(0.0f),
m13(0.0f), m14(0.0f), m15(0.0f), m16(1.0f)
{ }
RGBAMatrixSIMD &operator =(const RGBAMatrixSIMD &other) {
memcpy(m, other.m, sizeof(m));
return (*this);
}
RGBAMatrixSIMD operator +(const RGBAMatrixSIMD &p) const {
RGBAMatrixSIMD newm;
for(int i = 0; i < kNumColorChannels; i++) {
newm.col[i] = _mm_add_ps(col[i], p.col[i]);
}
return newm;
}
RGBAMatrixSIMD &operator +=(const RGBAMatrixSIMD &p) {
for(int i = 0; i < kNumColorChannels; i++) {
col[i] = _mm_add_ps( col[i], p.col[i] );
}
return *this;
}
RGBAMatrixSIMD operator -(const RGBAMatrixSIMD &p) const {
RGBAMatrixSIMD newm;
for(int i = 0; i < kNumColorChannels; i++) {
newm.col[i] = _mm_sub_ps( col[i], p.col[i] );
}
return newm;
}
RGBAMatrixSIMD &operator -=(const RGBAMatrixSIMD &p) {
for(int i = 0; i < kNumColorChannels; i++) {
col[i] = _mm_sub_ps( col[i], p.col[i] );
}
return *this;
}
RGBAMatrixSIMD operator /(const float s) const {
__m128 f = _mm_set1_ps(s);
RGBAMatrixSIMD newm;
for(int i = 0; i < kNumColorChannels; i++) {
newm.col[i] = _mm_div_ps( col[i], f );
}
return newm;
}
RGBAMatrixSIMD &operator /=(const float s) {
__m128 f = _mm_set1_ps(s);
for(int i = 0; i < kNumColorChannels; i++) {
col[i] = _mm_div_ps(col[i], f);
}
return *this;
}
RGBAMatrixSIMD operator *(const float s) const {
__m128 f = _mm_set1_ps(s);
RGBAMatrixSIMD newm;
for(int i = 0; i < kNumColorChannels; i++) {
newm.col[i] = _mm_mul_ps( col[i], f );
}
return newm;
}
friend RGBAMatrixSIMD operator *(const float s, const RGBAMatrixSIMD &p) {
__m128 f = _mm_set1_ps(s);
RGBAMatrixSIMD newm;
for(int i = 0; i < kNumColorChannels; i++) {
newm.col[i] = _mm_mul_ps( p.col[i], f );
}
return newm;
}
RGBAMatrixSIMD &operator *=(const float s) {
__m128 f = _mm_set1_ps(s);
for(int i = 0; i < kNumColorChannels; i++)
col[i] = _mm_mul_ps(col[i], f);
return *this;
}
float &operator ()(const int i, const int j) {
return (*this)[j*4 + i];
}
float &operator [](const int i) {
return m[i];
}
friend bool operator ==(const RGBAMatrixSIMD &rhs, const RGBAMatrixSIMD &lhs) {
__m128 sum = _mm_set1_ps(0.0f);
for(int i = 0; i < kNumColorChannels; i++) {
__m128 d = _mm_sub_ps(rhs.col[i], lhs.col[i]);
d = _mm_mul_ps(d, d);
__m128 cmp = _mm_cmpgt_ps(d, kEpsilonSIMD);
cmp = _mm_hadd_ps(cmp, cmp);
cmp = _mm_hadd_ps(cmp, cmp);
sum = _mm_add_ps(sum, cmp);
}
if(((float *)(&sum))[0] != 0)
return false;
else
return true;
}
operator float *() {
return m;
}
RGBAVectorSIMD operator *(const RGBAVectorSIMD &p) const;
};
class RGBADirSIMD : public RGBAVectorSIMD {
public:
RGBADirSIMD() : RGBAVectorSIMD() { }
RGBADirSIMD(const RGBAVectorSIMD &p) : RGBAVectorSIMD(p) {
this->Normalize();
}
};
// Makes sure that the values of the endpoints lie between 0 and 1.
extern void ClampEndpoints(RGBAVectorSIMD &p1, RGBAVectorSIMD &p2);
class RGBAClusterSIMD {
public:
RGBAClusterSIMD() :
m_NumPoints(0), m_Total(0.0f),
m_PointBitString(0),
m_Min(FLT_MAX),
m_Max(-FLT_MAX),
m_PrincipalAxisCached(false)
{ }
RGBAClusterSIMD(const RGBAClusterSIMD &c) :
m_NumPoints(c.m_NumPoints),
m_Total(c.m_Total),
m_PointBitString(c.m_PointBitString),
m_Min(c.m_Min),
m_Max(c.m_Max),
m_PrincipalAxisCached(false)
{
memcpy(this->m_DataPoints, c.m_DataPoints, m_NumPoints * sizeof(RGBAVectorSIMD));
}
RGBAClusterSIMD(const RGBAClusterSIMD &left, const RGBAClusterSIMD &right);
RGBAClusterSIMD(const RGBAVectorSIMD &p, int idx) :
m_NumPoints(1),
m_Total(p),
m_PointBitString(0),
m_Min(p), m_Max(p),
m_PrincipalAxisCached(false)
{
m_DataPoints[0] = p;
m_PointBitString |= (1 << idx);
}
RGBAVectorSIMD GetTotal() const { return m_Total; }
const RGBAVectorSIMD &GetPoint(int idx) const { return m_DataPoints[idx]; }
int GetNumPoints() const { return m_NumPoints; }
RGBAVectorSIMD GetAvg() const { return m_Total / float(m_NumPoints); }
void AddPoint(const RGBAVectorSIMD &p, int idx);
void GetBoundingBox(RGBAVectorSIMD &Min, RGBAVectorSIMD &Max) const {
Min = m_Min, Max = m_Max;
}
// Returns the error if we were to quantize the colors right now with the given number of buckets and bit mask.
float QuantizedError(const RGBAVectorSIMD &p1, const RGBAVectorSIMD &p2, const uint8 nBuckets, const __m128i &bitMask, const int pbits[2] = NULL, __m128i *indices = NULL) const;
bool AllSamePoint() const { return m_Max == m_Min; }
int GetPointBitString() const { return m_PointBitString; }
private:
// The number of points in the cluster.
int m_NumPoints;
RGBAVectorSIMD m_Total;
// The points in the cluster.
RGBAVectorSIMD m_DataPoints[kMaxNumDataPoints];
RGBAVectorSIMD m_Min, m_Max;
int m_PointBitString;
RGBADirSIMD m_PrincipalAxis;
bool m_PrincipalAxisCached;
};
extern void GetPrincipalAxis(const RGBAClusterSIMD &c, RGBADirSIMD &axis);
#endif //__RGBA_SIMD_ENDPOINTS_H__

0
CLTool/CMakeLists.txt Normal file
View File

106
CLTool/StopWatch.cpp Executable file
View File

@ -0,0 +1,106 @@
//--------------------------------------------------------------------------------------
// Copyright 2011 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies. Intel makes no representations about the
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//
//--------------------------------------------------------------------------------------
#include "StopWatch.h"
#include <cassert>
// Initialize member variables.
StopWatch::StopWatch() :
frequency(0),
start(0),
stop(0),
affinityMask(0)
{
// Initialize the performance counter frequency.
LARGE_INTEGER perfQuery;
BOOL supported = QueryPerformanceFrequency(&perfQuery);
assert(supported == TRUE);
this->frequency = perfQuery.QuadPart;
}
// Start the stopwatch.
void StopWatch::Start()
{
// MSDN recommends setting the thread affinity to avoid bugs in the BIOS and HAL.
// Create an affinity mask for the current processor.
affinityMask = (DWORD_PTR)1 << GetCurrentProcessorNumber();
HANDLE currThread = GetCurrentThread();
DWORD_PTR prevAffinityMask = SetThreadAffinityMask(currThread, affinityMask);
assert(prevAffinityMask != 0);
// Query the performance counter.
LARGE_INTEGER perfQuery;
BOOL result = QueryPerformanceCounter(&perfQuery);
assert(result);
start = perfQuery.QuadPart;
// Restore the thread's affinity mask.
prevAffinityMask = SetThreadAffinityMask(currThread, prevAffinityMask);
assert(prevAffinityMask != 0);
}
// Stop the stopwatch.
void StopWatch::Stop()
{
// MSDN recommends setting the thread affinity to avoid bugs in the BIOS and HAL.
// Use the affinity mask that was created in the Start function.
HANDLE currThread = GetCurrentThread();
DWORD_PTR prevAffinityMask = SetThreadAffinityMask(currThread, affinityMask);
assert(prevAffinityMask != 0);
// Query the performance counter.
LARGE_INTEGER perfQuery;
BOOL result = QueryPerformanceCounter(&perfQuery);
assert(result);
stop = perfQuery.QuadPart;
// Restore the thread's affinity mask.
prevAffinityMask = SetThreadAffinityMask(currThread, prevAffinityMask);
assert(prevAffinityMask != 0);
}
// Reset the stopwatch.
void StopWatch::Reset()
{
start = 0;
stop = 0;
affinityMask = 0;
}
// Get the elapsed time in seconds.
double StopWatch::TimeInSeconds() const
{
// Return the elapsed time in seconds.
assert((stop - start) > 0);
return double(stop - start) / double(frequency);
}
// Get the elapsed time in milliseconds.
double StopWatch::TimeInMilliseconds() const
{
// Return the elapsed time in milliseconds.
assert((stop - start) > 0);
return double(stop - start) / double(frequency) * 1000.0;
}
// Get the elapsed time in microseconds.
double StopWatch::TimeInMicroseconds() const
{
// Return the elapsed time in microseconds.
assert((stop - start) > 0);
return double(stop - start) / double(frequency) * 1000000.0;
}

41
CLTool/StopWatch.h Executable file
View File

@ -0,0 +1,41 @@
//--------------------------------------------------------------------------------------
// Copyright 2011 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies. Intel makes no representations about the
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//
//--------------------------------------------------------------------------------------
#pragma once
#include "Windows.h"
// A simple stopwatch class using Windows' high-resolution performance counters.
class StopWatch
{
public:
StopWatch();
void Start();
void Stop();
void Reset();
double TimeInSeconds() const;
double TimeInMilliseconds() const;
double TimeInMicroseconds() const;
private:
LONGLONG frequency;
LONGLONG start;
LONGLONG stop;
DWORD_PTR affinityMask;
};

2126
CLTool/main.cpp Executable file

File diff suppressed because it is too large Load Diff

4
CMakeLists.txt Normal file
View File

@ -0,0 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
PROJECT(TexC)
ADD_SUBDIRECTORY(BPTCEncoder)

0
QtGUI/CMakeLists.txt Normal file
View File