<|start_filename|>src/nvimage/PixelFormat.h<|end_filename|>
// Copyright NVIDIA Corporation 2007 -- <NAME> <<EMAIL>>
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#pragma once
#ifndef NV_IMAGE_PIXELFORMAT_H
#define NV_IMAGE_PIXELFORMAT_H

#include "nvimage.h"


namespace nv
{
    namespace PixelFormat
    {

        // Convert component @a c having @a inbits to the returned value having @a outbits.
        inline uint convert(uint c, uint inbits, uint outbits)
        {
            if (inbits == 0)
            {
            	return 0;
            }
            else if (inbits >= outbits)
            {
            	// truncate
            	return c >> (inbits - outbits);
            }
            else
            {
            	// bitexpand
                return (c << (outbits - inbits)) | convert(c, inbits, outbits - inbits);
            }
        }

        // Get pixel component shift and size given its mask.
        inline void maskShiftAndSize(uint mask, uint * shift, uint * size)
        {
            if (!mask)
            {
                *shift = 0;
                *size = 0;
                return;
            }
        
            *shift = 0;
            while((mask & 1) == 0) {
                ++(*shift);
                mask >>= 1;
            }
        
            *size = 0;
            while((mask & 1) == 1) {
                ++(*size);
                mask >>= 1;
            }
        }

        inline float quantizeCeil(float f, int inbits, int outbits)
        {
            nvDebugCheck(f >= 0.0f && f <= 1.0f);
            //uint i = f * (float(1 << inbits) - 1);
            //i = convert(i, inbits, outbits);
            //float result = float(i) / (float(1 << outbits) - 1);
            //nvCheck(result >= f);
            float result;
            int offset = 0;
            do {
                uint i = offset + uint(f * (float(1 << inbits) - 1));
                i = convert(i, inbits, outbits);
                result = float(i) / (float(1 << outbits) - 1);
                offset++;
            } while (result < f);

            return result;
        }

        /*
        inline float quantizeRound(float f, int bits)
        {
            nvDebugCheck(f >= 0.0f && f <= 1.0f);
            float scale = float(1 << bits);
            return fround(f * scale) / scale;
        }

        inline float quantizeFloor(float f, int bits)
        {
            nvDebugCheck(f >= 0.0f && f <= 1.0f);
            float scale = float(1 << bits);
            return floor(f * scale) / scale;
        }
        */

    } // PixelFormat namespace

} // nv namespace


#endif // NV_IMAGE_PIXELFORMAT_H


<|start_filename|>src/nvimage/nvimage.h<|end_filename|>
// This code is in the public domain -- <EMAIL>
#pragma once

#include "nvcore/nvcore.h"
#include "nvcore/Debug.h" // nvDebugCheck
#include "nvcore/Utils.h" // isPowerOfTwo

namespace nv {

    // Some utility functions:
    inline uint computeBitPitch(uint w, uint bitsize, uint alignmentInBits)
    {
        nvDebugCheck(isPowerOfTwo(alignmentInBits));

        return ((w * bitsize +  alignmentInBits - 1) / alignmentInBits) * alignmentInBits;
    }

    inline uint computeBytePitch(uint w, uint bitsize, uint alignmentInBytes)
    {
        uint pitch = computeBitPitch(w, bitsize, 8*alignmentInBytes);
        nvDebugCheck((pitch & 7) == 0);

        return (pitch + 7) / 8;
    }

} // nv namespace


<|start_filename|>cmake/OptimalOptions.cmake<|end_filename|>

# Set optimal options for gcc:
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
	SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
	SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
ENDIF()

IF(MSVC)
	# Code generation flags.
#	SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /arch:SSE2 /fp:fast")
#	SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:SSE2 /fp:fast")

	# Optimization flags.
	SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} /O2 /Ob2 /Oi /Ot /Oy /GL")
	SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} /O2 /Ob2 /Oi /Ot /Oy /GL")
	SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
	SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG")
	SET(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} /LTCG")

	# Definitions.
	ADD_DEFINITIONS(-D__SSE2__ -D__SSE__ -D__MMX__)
ENDIF(MSVC)


<|start_filename|>src/nvcore/Memory.h<|end_filename|>
// This code is in the public domain -- <NAME> <<EMAIL>>

#pragma once
#ifndef NV_CORE_MEMORY_H
#define NV_CORE_MEMORY_H

#include "nvcore.h"

#include <stdlib.h> // malloc(), realloc() and free()
#include <string.h> // memset
//#include <stddef.h> // size_t

#if NV_OS_LINUX
#include <malloc.h> // memalign()
#endif

//#include <new>	// new and delete

#define TRACK_MEMORY_LEAKS 0
#if TRACK_MEMORY_LEAKS
#include <vld.h>
#endif


#if NV_CC_GNUC
#   define NV_ALIGN_16 __attribute__ ((__aligned__ (16)))
#else
#   define NV_ALIGN_16 __declspec(align(16))
#endif


#define NV_OVERRIDE_ALLOC 0

#if NV_OVERRIDE_ALLOC

// Custom memory allocator
extern "C" {
    NVCORE_API void * malloc(size_t size);
    NVCORE_API void * debug_malloc(size_t size, const char * file, int line);
    NVCORE_API void free(void * ptr);
    NVCORE_API void * realloc(void * ptr, size_t size);
}

/*
#ifdef _DEBUG
#define new new(__FILE__, __LINE__)
#define malloc(i) debug_malloc(i, __FILE__, __LINE__)
#endif
*/

#endif

namespace nv {
    NVCORE_API void * aligned_malloc(size_t size, size_t alignment);
    NVCORE_API void aligned_free(void * );

    // C++ helpers.
    template <typename T> NV_FORCEINLINE T * malloc(size_t count) {
        return (T *)::malloc(sizeof(T) * count);
    }

    template <typename T> NV_FORCEINLINE T * realloc(T * ptr, size_t count) {
        return (T *)::realloc(ptr, sizeof(T) * count);
    }

    template <typename T> NV_FORCEINLINE void free(const T * ptr) {
        ::free((void *)ptr);
    }

    template <typename T> NV_FORCEINLINE void zero(T & data) {
        memset(&data, 0, sizeof(T));
    }

} // nv namespace

#endif // NV_CORE_MEMORY_H


<|start_filename|>src/nvtt/icbc.cpp<|end_filename|>
#define ICBC_IMPLEMENTATION
//#define ICBC_SIMD 2 // SSE4.1
#include "icbc.h"


<|start_filename|>src/bc6h/zoh.cpp<|end_filename|>
/*
Copyright 2007 nVidia, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 

You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

See the License for the specific language governing permissions and limitations under the License.
*/

// the zoh compressor and decompressor

#include "tile.h"
#include "zoh.h"

#include <string.h> // memcpy

using namespace ZOH;


bool ZOH::isone(const char *block)
{
	char code = block[0] & 0x1F;

	return (code == 0x03 || code == 0x07 || code == 0x0b || code == 0x0f);
}

void ZOH::compress(const Tile &t, char *block)
{
	char oneblock[ZOH::BLOCKSIZE], twoblock[ZOH::BLOCKSIZE];

	float mseone = ZOH::compressone(t, oneblock);
	float msetwo = ZOH::compresstwo(t, twoblock);

	if (mseone <= msetwo)
		memcpy(block, oneblock, ZOH::BLOCKSIZE);
	else
		memcpy(block, twoblock, ZOH::BLOCKSIZE);
}

void ZOH::decompress(const char *block, Tile &t)
{
	if (ZOH::isone(block))
		ZOH::decompressone(block, t);
	else
		ZOH::decompresstwo(block, t);
}

/*
void ZOH::compress(string inf, string zohf)
{
	Array2D<Rgba> pixels;
	int w, h;
	char block[ZOH::BLOCKSIZE];

	Exr::readRgba(inf, pixels, w, h);
	FILE *zohfile = fopen(zohf.c_str(), "wb");
	if (zohfile == NULL) throw "Unable to open .zoh file for write";

	// stuff for progress bar O.o
	int ntiles = ((h+Tile::TILE_H-1)/Tile::TILE_H)*((w+Tile::TILE_W-1)/Tile::TILE_W);
	int tilecnt = 0;
	int ndots = 25;
	int dotcnt = 0;
	printf("Progress [");
	for (int i=0; i<ndots;++i) printf(" ");
	printf("]\rProgress ["); fflush(stdout);

	// convert to tiles and compress each tile
	for (int y=0; y<h; y+=Tile::TILE_H)
	{
		int ysize = min(Tile::TILE_H, h-y);
		for (int x=0; x<w; x+=Tile::TILE_W)
		{
			int xsize = min(Tile::TILE_W, w-x);
			Tile t(xsize, ysize);

			t.insert(pixels, x, y);

			ZOH::compress(t, block);
			if (fwrite(block, sizeof(char), ZOH::BLOCKSIZE, zohfile) != ZOH::BLOCKSIZE)
				throw "File error on write";

			// progress bar
			++tilecnt;
			if (tilecnt > (ntiles * dotcnt)/ndots) { printf("."); fflush(stdout); ++dotcnt; }
		}
	}

	printf("]\n");		// advance to next line finally

	if (fclose(zohfile)) throw "Close failed on .zoh file";
}

static int str2int(std::string s)
{
	int thing;
	std::stringstream str (stringstream::in | stringstream::out);
	str << s;
	str >> thing;
	return thing;
}

// zoh file name is ...-w-h.zoh, extract width and height
static void extract(string zohf, int &w, int &h)
{
	size_t n = zohf.rfind('.', zohf.length()-1);
	size_t n1 = zohf.rfind('-', n-1);
	size_t n2 = zohf.rfind('-', n1-1);
	string width = zohf.substr(n2+1, n1-n2-1);
	w = str2int(width);
	string height = zohf.substr(n1+1, n-n1-1);
	h = str2int(height);
}

static int mode_to_prec[] = {
	10,7,11,10,
	10,7,11,11,
	10,7,11,12,
	10,7,9,16,
	10,7,8,-1,
	10,7,8,-1,
	10,7,8,-1,
	10,7,6,-1,
};

static int shapeindexhist[32], modehist[32], prechistone[16], prechisttwo[16], oneregion, tworegions;

static void stats(char block[ZOH::BLOCKSIZE])
{
	char mode = block[0] & 0x1F; if ((mode & 0x3) == 0) mode = 0; if ((mode & 0x3) == 1) mode = 1; modehist[mode]++;
	int prec = mode_to_prec[mode];
	nvAssert (prec != -1);
	if (!ZOH::isone(block))
	{
		tworegions++;
		prechisttwo[prec]++;
		int shapeindex = ((block[0] & 0xe0) >> 5) | ((block[1] & 0x3) << 3);
		shapeindexhist[shapeindex]++;
	}
	else
	{
		oneregion++;
		prechistone[prec]++;
	}
}

static void printstats()
{
	printf("\nPrecision histogram 10b to 16b one region: "); for (int i=10; i<=16; ++i) printf("%d,", prechistone[i]);
	printf("\nPrecision histogram 6b to 11b two regions: "); for (int i=6; i<=11; ++i) printf("%d,", prechisttwo[i]);
	printf("\nMode histogram: "); for (int i=0; i<32; ++i) printf("%d,", modehist[i]);
	printf("\nShape index histogram: "); for (int i=0; i<32; ++i) printf("%d,", shapeindexhist[i]);
	printf("\nOne region %5.2f%%  Two regions %5.2f%%", 100.0*oneregion/float(oneregion+tworegions), 100.0*tworegions/float(oneregion+tworegions));
	printf("\n");
}

void ZOH::decompress(string zohf, string outf)
{
	Array2D<Rgba> pixels;
	int w, h;
	char block[ZOH::BLOCKSIZE];

	extract(zohf, w, h);
	FILE *zohfile = fopen(zohf.c_str(), "rb");
	if (zohfile == NULL) throw "Unable to open .zoh file for read";
	pixels.resizeErase(h, w);

	// convert to tiles and decompress each tile
	for (int y=0; y<h; y+=Tile::TILE_H)
	{
		int ysize = min(Tile::TILE_H, h-y);
		for (int x=0; x<w; x+=Tile::TILE_W)
		{
			int xsize = min(Tile::TILE_W, w-x);
			Tile t(xsize, ysize);

			if (fread(block, sizeof(char), ZOH::BLOCKSIZE, zohfile) != ZOH::BLOCKSIZE)
				throw "File error on read";

			stats(block);	// collect statistics

			ZOH::decompress(block, t);

			t.extract(pixels, x, y);
		}
	}
	if (fclose(zohfile)) throw "Close failed on .zoh file";
	Exr::writeRgba(outf, pixels, w, h);

#ifndef EXTERNAL_RELEASE
	printstats();	// print statistics
#endif
}
*/


<|start_filename|>data/bugs/85/tables.cpp<|end_filename|>

#include <stdio.h>
#include <stdlib.h>

typedef unsigned char uint8;


static int Mul8Bit(int a, int b)
{
	int t = a * b + 128;
	return (t + (t >> 8)) >> 8;
}

// this exactly matches the (fm*2 + to)/3
static inline int Lerp13_16bit(int fm, int to)
{
	int t = fm * (2 * 0xAAAB) + to * 0xAAAB;
	return t >> 17;
}

static inline int Lerp13(int fm, int to)
{
	return (fm * 2 + to) / 3;
}


static void PrepareOptTable(uint8 * Table, const uint8 * expand, int size)
{
	for (int i = 0; i < 256; i++)
	{
		float bestErr = 256;

		for (int min = 0; min < size; min++)
		{
			for (int max = 0; max < size; max++)
			{
				int mine = expand[min];
				int maxe = expand[max];
				//if (maxe - mine < 32)
				{
					//printf("%d <-> %d\n", maxe + Mul8Bit(mine-maxe, 0x55), Lerp13(maxe, mine));
					//int err = abs(Lerp13_16bit(mine, maxe) - i);
					//int err = abs(maxe + Mul8Bit(mine-maxe, 0x55) - i);
					float err = abs(Lerp13(maxe, mine) - i);
					//err += 0.03f * abs(maxe - mine);
					err += 0.03f * abs(max - min);

					if (err < bestErr)
					{
						Table[i*2+0] = max;
						Table[i*2+1] = min;
						bestErr = err;
					}
				}
			}
		}
		printf("%d: %f %d\n", i, bestErr, abs(Table[i*2+0] - Table[i*2+1]));
	}
}


int main()
{
	uint8 OMatch5[256*2];
	uint8 OMatch6[256*2];
	
	uint8 Expand5[32];
	uint8 Expand6[64];

	for (int i=0; i<32; i++)
		Expand5[i] = (i<<3)|(i>>2);

	for (int i=0; i<64; i++)
		Expand6[i] = (i<<2)|(i>>4);

	PrepareOptTable(OMatch5, Expand5, 32);
	PrepareOptTable(OMatch6, Expand6, 64);

	printf("const static uint8 OMatch5[256][2] = {\n");
	for (int i = 0; i < 256; i++)
	{
		printf("\t{0x%.2X, 0x%.2X},\n", OMatch5[2*i+0], OMatch5[2*i+1]);
	}
	printf("}\n");

	printf("const static uint8 OMatch6[256][2] = {\n");
	for (int i = 0; i < 256; i++)
	{
		printf("\t{0x%.2X, 0x%.2X},\n", OMatch6[2*i+0], OMatch6[2*i+1]);
	}
	printf("}\n");

	return 0;
}



<|start_filename|>src/nvmath/SphericalHarmonic.h<|end_filename|>
// This code is in the public domain -- <EMAIL>

#ifndef NV_MATH_SPHERICALHARMONIC_H
#define NV_MATH_SPHERICALHARMONIC_H

#include "nvmath.h"
#include "Vector.h"

#include <string.h> // memcpy


namespace nv
{
    class Vector3;
    class Matrix;

    float legendrePolynomial( int l, int m, float x ) NV_CONST;
    float shBasis( int l, int m, float theta, float phi ) NV_CONST;
    float shBasis( int l, int m, const Vector3 & v ) NV_CONST;
    float hshBasis( int l, int m, float theta, float phi ) NV_CONST;
    float hshBasis( int l, int m, const Vector3 & v ) NV_CONST;

    class Sh;
    float dot(const Sh & a, const Sh & b) NV_CONST;


    /// Spherical harmonic class.
    class Sh
    {
        friend class Sh2;
        friend class ShMatrix;
    public:

        /// Construct a spherical harmonic of the given order.
        Sh(int o) : order(o)
        {
            coef = new float[basisNum()];
        }

        /// Copy constructor.
        Sh(const Sh & sh) : order(sh.order)
        {
            coef = new float[basisNum()];
            memcpy(coef, sh.coef, sizeof(float) * basisNum());
        }

        /// Destructor.
        ~Sh()
        {
            delete [] coef;
            coef = NULL;
        }

        /// Get number of bands.
        static int bandNum(int order) {
            return order + 1;
        }

        /// Get number of sh basis.
        static int basisNum(int order) {
            return (order + 1) * (order + 1);
        }

        /// Get the index for the given coefficients.
        static int index( int l, int m ) {
            return l * l + l + m;
        }

        /// Get sh order.
        int bandNum() const
        {
            return bandNum(order);
        }

        /// Get sh order.
        int basisNum() const
        {
            return basisNum(order);
        }

        /// Get sh coefficient indexed by l,m.
        float elem( int l, int m ) const
        {
            return coef[index(l, m)];
        }

        /// Get sh coefficient indexed by l,m.
        float & elem( int l, int m )
        {
            return coef[index(l, m)];
        }


        /// Get sh coefficient indexed by i.
        float elemAt( int i ) const {
            return coef[i];
        }

        /// Get sh coefficient indexed by i.
        float & elemAt( int i )
        {
            return coef[i];
        }


        /// Reset the sh coefficients.
        void reset()
        {
            for( int i = 0; i < basisNum(); i++ ) {
                coef[i] = 0.0f;
            }
        }

        /// Copy spherical harmonic.
        void operator= ( const Sh & sh )
        {
            nvDebugCheck(order <= sh.order);

            for(int i = 0; i < basisNum(); i++) {
                coef[i] = sh.coef[i];
            }
        }

        /// Add spherical harmonics.
        void operator+= ( const Sh & sh )
        {
            nvDebugCheck(order == sh.order);

            for(int i = 0; i < basisNum(); i++) {
                coef[i] += sh.coef[i];
            }
        }

        /// Substract spherical harmonics.
        void operator-= ( const Sh & sh )
        {
            nvDebugCheck(order == sh.order);

            for(int i = 0; i < basisNum(); i++) {
                coef[i] -= sh.coef[i];
            }
        }

        // Not exactly convolution, nor product.
        void operator*= ( const Sh & sh )
        {
            nvDebugCheck(order == sh.order);

            for(int i = 0; i < basisNum(); i++) {
                coef[i] *= sh.coef[i];
            }
        }

        /// Scale spherical harmonics.
        void operator*= ( float f )
        {
            for(int i = 0; i < basisNum(); i++) {
                coef[i] *= f;
            }
        }

        /// Add scaled spherical harmonics.
        void addScaled( const Sh & sh, float f )
        {
            nvDebugCheck(order == sh.order);

            for(int i = 0; i < basisNum(); i++) {
                coef[i] += sh.coef[i] * f;
            }
        }


        /*/// Add a weighted sample to the sh coefficients.
        void AddSample( const Vec3 & dir, const Color3f & color, float w=1.0f ) {
        for(int l = 0; l <= order; l++) {
        for(int m = -l; m <= l; m++) {
        Color3f & elem = GetElem(l, m);
        elem.Mad( elem, color, w * shBasis(l, m, dir) );
        }
        }
        }*/

        /// Evaluate 
        void eval(const Vector3 & dir)
        {
            for(int l = 0; l <= order; l++) {
                for(int m = -l; m <= l; m++) {
                    elem(l, m) = shBasis(l, m, dir);
                }
            }
        }


        /// Evaluate the spherical harmonic function.
        float sample(const Vector3 & dir) const
        {
            Sh sh(order);
            sh.eval(dir);

            return dot(sh, *this);
        }


        const int order;
        float * coef;

    };


    /// Compute dot product of the spherical harmonics.
    inline float dot(const Sh & a, const Sh & b)
    {
        nvDebugCheck(a.order == b.order);

        float sum = 0;
        for( int i = 0; i < Sh::basisNum(a.order); i++ ) {
            sum += a.elemAt(i) * b.elemAt(i);
        }

        return sum;
    }


    /// Second order spherical harmonic.
    class Sh2 : public Sh
    {
    public:

        /// Constructor.
        Sh2() : Sh(2) {}

        /// Copy constructor.
        Sh2(const Sh2 & sh) : Sh(sh) {}

        // Fast evaluation from: PPS' Efficient Spherical Harmonic Evaluation http://jcgt.org/published/0002/02/06/
        void eval(const Vector3 & dir) {
            float fZ2 = dir.z * dir.z;
            coef[0] = 0.2820947917738781f;
            coef[2] = 0.4886025119029199f * dir.z;
            coef[6] = 0.9461746957575601f * fZ2 + -0.3153915652525201f;

            float fC0 = dir.x;
            float fS0 = dir.y;

            float fTmpA = -0.48860251190292f;
            coef[3] = fTmpA * fC0;
            coef[1] = fTmpA * fS0;
            
            float fTmpB = -1.092548430592079f * dir.z;
            coef[7] = fTmpB * fC0;
            coef[5] = fTmpB * fS0;

            float fC1 = dir.x * fC0 - dir.y * fS0;
            float fS1 = dir.x * fS0 + dir.y * fC0;

            float fTmpC = 0.5462742152960395f;
            coef[8] = fTmpC * fC1;
            coef[4] = fTmpC * fS1;
        }

        /// Spherical harmonic resulting from projecting the clamped cosine transfer function to the SH basis.
        void cosineTransfer() {
            const float c1 = 0.282095f;	// K(0, 0)
            const float c2 = 0.488603f; // K(1, 0)
            const float c3 = 1.092548f; // sqrt(15.0f / PI) / 2.0f = K(2, -2)
            const float c4 = 0.315392f; // sqrt(5.0f / PI) / 4.0f) = K(2, 0)
            const float c5 = 0.546274f; // sqrt(15.0f / PI) / 4.0f) = K(2, 2)

            const float normalization = PI * 16.0f / 17.0f;

            const float const1 = c1 * normalization * 1.0f;
            const float const2 = c2 * normalization * (2.0f / 3.0f);
            const float const3 = c3 * normalization * (1.0f / 4.0f);
            const float const4 = c4 * normalization * (1.0f / 4.0f);
            const float const5 = c5 * normalization * (1.0f / 4.0f);

            coef[0] = const1;

            coef[1] = -const2;
            coef[2] = const2;
            coef[3] = -const2;

            coef[4] = const3;
            coef[5] = -const3;
            coef[6] = const4;
            coef[7] = -const3;
            coef[8] = const5;
        }
    };



    /// Spherical harmonic matrix.
    class ShMatrix
    {
    public:

        /// Create an identity matrix of the given order.
        ShMatrix(int o = 2) : m_order(o), m_identity(true)
        {
            nvCheck(m_order > 0);
            m_e = new float[size()];
            m_band = new float *[bandNum()];		
            setupBands();
        }

        /// Destroy and free matrix elements.
        ~ShMatrix()
        {
            delete m_e;
            delete m_band;
        }

        /// Set identity matrix.
        void setIdentity()
        {
            m_identity = true;
        }

        /// Return true if this is an identity matrix, false in other case.
        bool isIdentity() const {
            return m_identity;
        }

        /// Get number of bands of this matrix.
        int bandNum() const
        {
            return m_order+1;
        }

        /// Get total number of elements in the matrix.
        int size() const
        {
            int size = 0;
            for (int i = 0; i < bandNum(); i++) {
                size += square(i * 2 + 1);
            }
            return size;
        }

        /// Get element at the given raw index.
        float element(int idx) const
        {
            return m_e[idx];
        }

        /// Get element at the given with the given indices.
        float & element(int b, int x, int y)
        {
            nvDebugCheck(b >= 0);
            nvDebugCheck(b < bandNum());
            return m_band[b][(b + y) * (b * 2 + 1) + (b + x)];
        }

        /// Get element at the given with the given indices.
        float element(int b, int x, int y) const
        {
            nvDebugCheck(b >= 0);
            nvDebugCheck(b < bandNum());
            return m_band[b][(b + y) * (b * 2 + 1) + (b + x)];
        }

        /// Copy matrix.
        void copy(const ShMatrix & m)
        {
            nvDebugCheck(m_order == m.m_order);
            memcpy(m_e, m.m_e, size() * sizeof(float));
        }

        /// Rotate the given coefficients.
        /*void transform( const Sh & restrict source,  Sh * restrict dest ) const {
            nvCheck( &source != dest );	// Make sure there's no aliasing.
            nvCheck( dest->order <= order );
            nvCheck( order <= source.order );

            if (m_identity) {
                *dest = source;
                return;
            }

            // Loop through each band.
            for (int l = 0; l <= dest->order; l++) {

                for (int mo = -l; mo <= l; mo++) {

                    Color3f rgb = Color3f::Black;

                    for( int mi = -l; mi <= l; mi++ ) {
                        rgb.Mad( rgb, source.elem(l, mi), elem(l, mo, mi) );
                    }

                    dest->elem(l, mo) = rgb;
                }
            }
        }*/


        void multiply( const ShMatrix &A, const ShMatrix &B );
        void rotation( const Matrix & m );
        void rotation( int axis, float angles );
        void print();


    private:

        // @@ These could be static indices precomputed only once.
        /// Setup the band pointers.
        void setupBands()
        {
            int size = 0;
            for( int i = 0; i < bandNum(); i++ ) {
                m_band[i] = &m_e[size];
                size += square(i * 2 + 1);
            }
        }


    private:

        // Matrix order.
        const int m_order;

        // Identity flag for quick transform.
        bool m_identity;

        // Array of elements.
        float * m_e;

        // Band pointers.
        float ** m_band;

    };


} // nv namespace

#endif // NV_MATH_SPHERICALHARMONIC_H


<|start_filename|>src/bc7/avpcl.h<|end_filename|>
/*
Copyright 2007 nVidia, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 

You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

See the License for the specific language governing permissions and limitations under the License.
*/

#ifndef _AVPCL_H
#define _AVPCL_H

#include "tile.h"
#include "bits.h"

#define	DISABLE_EXHAUSTIVE	1	// define this if you don't want to spend a lot of time on exhaustive compression
#define	USE_ZOH_INTERP		1	// use zoh interpolator, otherwise use exact avpcl interpolators
#define	USE_ZOH_INTERP_ROUNDED 1	// use the rounded versions!

namespace AVPCL {

static const int NREGIONS_TWO	= 2;
static const int NREGIONS_THREE	= 3;

static const int BLOCKSIZE=16;
static const int BITSIZE=128;

// global flags
extern bool flag_premult;
extern bool flag_nonuniform;
extern bool flag_nonuniform_ati;

// global mode
extern bool mode_rgb;		// true if image had constant alpha = 255

void compress(const Tile &t, char *block);
void decompress(const char *block, Tile &t);

float compress_mode0(const Tile &t, char *block);
void decompress_mode0(const char *block, Tile &t);

float compress_mode1(const Tile &t, char *block);
void decompress_mode1(const char *block, Tile &t);

float compress_mode2(const Tile &t, char *block);
void decompress_mode2(const char *block, Tile &t);

float compress_mode3(const Tile &t, char *block);
void decompress_mode3(const char *block, Tile &t);

float compress_mode4(const Tile &t, char *block);
void decompress_mode4(const char *block, Tile &t);

float compress_mode5(const Tile &t, char *block);
void decompress_mode5(const char *block, Tile &t);

float compress_mode6(const Tile &t, char *block);
void decompress_mode6(const char *block, Tile &t);

float compress_mode7(const Tile &t, char *block);
void decompress_mode7(const char *block, Tile &t);

inline int getmode(Bits &in)
{
	int mode = 0;

	if (in.read(1))			mode = 0;
	else if (in.read(1))	mode = 1;
	else if (in.read(1))	mode = 2;
	else if (in.read(1))	mode = 3;
	else if (in.read(1))	mode = 4;
	else if (in.read(1))	mode = 5;
	else if (in.read(1))	mode = 6;
	else if (in.read(1))	mode = 7;
	else mode = 8;	// reserved
	return mode;
}
inline int getmode(const char *block)
{
	int bits = block[0], mode = 0;

	if (bits & 1) mode = 0;
	else if ((bits&3) == 2) mode = 1;
	else if ((bits&7) == 4) mode = 2;
	else if ((bits & 0xF) == 8) mode = 3;
	else if ((bits & 0x1F) == 16) mode = 4;
	else if ((bits & 0x3F) == 32) mode = 5;
	else if ((bits & 0x7F) == 64) mode = 6;
	else if ((bits & 0xFF) == 128) mode = 7;
	else mode = 8;	// reserved
	return mode;
}

}

#endif


<|start_filename|>src/nvimage/ColorSpace.h<|end_filename|>
// This code is in the public domain -- <EMAIL>

#pragma once
#ifndef NV_IMAGE_COLORSPACE_H
#define NV_IMAGE_COLORSPACE_H

namespace nv 
{
	class Image;
	
	// Defines simple mappings between different color spaces and encodes them in the 
	// input image.
	namespace ColorSpace
	{
		void RGBtoYCoCg_R(Image* img);
		void YCoCg_RtoRGB(Image* img);
	}
}



#endif


<|start_filename|>src/nvimage/NormalMap.cpp<|end_filename|>
// Copyright NVIDIA Corporation 2007 -- <NAME> <<EMAIL>>
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include "NormalMap.h"
#include "Filter.h"
#include "FloatImage.h"
#include "Image.h"

#include "nvmath/Color.inl"
#include "nvmath/Vector.h"

#include "nvcore/Ptr.h"

#include <string.h> // memcpy


using namespace nv;

// Create normal map using the given kernels.
static FloatImage * createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, const Kernel2 * kdu, const Kernel2 * kdv)
{
    nvDebugCheck(kdu != NULL);
    nvDebugCheck(kdv != NULL);
    nvDebugCheck(img != NULL);

    const uint w = img->width;
    const uint h = img->height;

    AutoPtr<FloatImage> fimage(new FloatImage());
    fimage->allocate(4, w, h);

    // Compute height and store in alpha channel:
    float * alphaChannel = fimage->channel(3);
    for(uint i = 0; i < w * h; i++)
    {
        Vector4 color = toVector4(img->pixel(i));
        alphaChannel[i] = dot(color, heightWeights);
    }

    float heightScale = 1.0f / 16.0f;	// @@ Use a user defined factor.

    for(uint y = 0; y < h; y++)
    {
        for(uint x = 0; x < w; x++)
        {
            const float du = fimage->applyKernelXY(kdu, x, y, 0, 3, wm);
            const float dv = fimage->applyKernelXY(kdv, x, y, 0, 3, wm);

            Vector3 n = normalize(Vector3(du, dv, heightScale));

            fimage->pixel(0, x, y, 0) = 0.5f * n.x + 0.5f;
            fimage->pixel(1, x, y, 0) = 0.5f * n.y + 0.5f;
            fimage->pixel(2, x, y, 0) = 0.5f * n.z + 0.5f;
        }
    }

    return fimage.release();
}


// Create normal map using the given kernels.
static FloatImage * createNormalMap(const FloatImage * img, FloatImage::WrapMode wm, const Kernel2 * kdu, const Kernel2 * kdv)
{
    nvDebugCheck(kdu != NULL);
    nvDebugCheck(kdv != NULL);
    nvDebugCheck(img != NULL);

#pragma NV_MESSAGE("FIXME: Height scale parameter should go away. It should be a sensible value that produces good results when the heightmap is in the [0, 1] range.")
    const float heightScale = 1.0f / 16.0f;

    const uint w = img->width();
    const uint h = img->height();

    AutoPtr<FloatImage> img_out(new FloatImage());
    img_out->allocate(4, w, h);

    for (uint y = 0; y < h; y++)
    {
        for (uint x = 0; x < w; x++)
        {
            const float du = img->applyKernelXY(kdu, x, y, 0, 3, wm);
            const float dv = img->applyKernelXY(kdv, x, y, 0, 3, wm);

            Vector3 n = normalize(Vector3(du, dv, heightScale));

            img_out->pixel(0, x, y, 0) = n.x;
            img_out->pixel(1, x, y, 0) = n.y;
            img_out->pixel(2, x, y, 0) = n.z;
        }
    }

    // Copy alpha channel.
    /*for (uint y = 0; y < h; y++)
    {
        for (uint x = 0; x < w; x++)
        {
            
            img_out->pixel(3, x, y, 0) = img->pixel(3, x, y, 0);
        }
    }*/
    memcpy(img_out->channel(3), img->channel(3), w * h * sizeof(float));

    return img_out.release();
}


/// Create normal map using the given filter.
FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, NormalMapFilter filter /*= Sobel3x3*/)
{
    nvDebugCheck(img != NULL);

    // Init the kernels.
    Kernel2 * kdu = NULL;
    Kernel2 * kdv = NULL;

    switch(filter)
    {
        case NormalMapFilter_Sobel3x3:
            kdu = new Kernel2(3);
            break;
        case NormalMapFilter_Sobel5x5:
            kdu = new Kernel2(5);
            break;
        case NormalMapFilter_Sobel7x7:
            kdu = new Kernel2(7);
            break;
        case NormalMapFilter_Sobel9x9:
            kdu = new Kernel2(9);
            break;
        default:
            nvDebugCheck(false);
    };

    kdu->initSobel();
    kdu->normalize();

    kdv = new Kernel2(*kdu);
    kdv->transpose();

    return ::createNormalMap(img, wm, heightWeights, kdu, kdv);
}


/// Create normal map combining multiple sobel filters.
FloatImage * nv::createNormalMap(const Image * img, FloatImage::WrapMode wm, Vector4::Arg heightWeights, Vector4::Arg filterWeights)
{
    nvDebugCheck(img != NULL);

    Kernel2 * kdu = NULL;
    Kernel2 * kdv = NULL;

    kdu = new Kernel2(9);
    kdu->initBlendedSobel(filterWeights);
    kdu->normalize();

    kdv = new Kernel2(*kdu);
    kdv->transpose();

    return ::createNormalMap(img, wm, heightWeights, kdu, kdv);
}


FloatImage * nv::createNormalMap(const FloatImage * img, FloatImage::WrapMode wm, Vector4::Arg filterWeights)
{
    nvDebugCheck(img != NULL);

    Kernel2 * kdu = NULL;
    Kernel2 * kdv = NULL;

    kdu = new Kernel2(9);
    kdu->initBlendedSobel(filterWeights);
    kdu->normalize();

    kdv = new Kernel2(*kdu);
    kdv->transpose();

    return ::createNormalMap(img, wm, kdu, kdv);
}


/// Normalize the given image in place.
void nv::normalizeNormalMap(FloatImage * img)
{
    nvDebugCheck(img != NULL);

    img->normalize(0);
}



<|start_filename|>src/nvtt/TaskDispatcher.h<|end_filename|>

#include "nvtt.h"

// OpenMP
// http://en.wikipedia.org/wiki/OpenMP
#if defined(HAVE_OPENMP)
#include <omp.h>
#endif

// Gran Central Dispatch (GCD/libdispatch)
// http://developer.apple.com/mac/library/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
#if NV_OS_DARWIN && defined(HAVE_DISPATCH_H)
//#define HAVE_GCD 1
//#include <dispatch/dispatch.h>
#endif

// Parallel Patterns Library (PPL) is part of Microsoft's concurrency runtime: 
// http://msdn.microsoft.com/en-us/library/dd504870.aspx
#if NV_OS_WIN32 && _MSC_VER >= 1600
//#define HAVE_PPL 1
#include <ppl.h>
#endif

// Intel Thread Building Blocks (TBB).
// http://www.threadingbuildingblocks.org/
#if defined(HAVE_TBB)
#include <tbb/parallel_for.h>
#endif

#include "nvthread/ParallelFor.h"


namespace nvtt {

    struct SequentialTaskDispatcher : public TaskDispatcher
    {
        virtual void dispatch(Task * task, void * context, int count) {
            for (int i = 0; i < count; i++) {
                task(context, i);
            }
        }
    };

    struct ParallelTaskDispatcher : public TaskDispatcher
    {
        virtual void dispatch(Task * task, void * context, int count) {
            nv::ParallelFor parallelFor(task, context);
            parallelFor.run(count); // @@ Add support for custom grain.
        }
    };


#if defined(HAVE_OPENMP)

    struct OpenMPTaskDispatcher : public TaskDispatcher
    {
        virtual void dispatch(Task * task, void * context, int count) {
            #pragma omp parallel for
            for (int i = 0; i < count; i++) {
                task(context, i);
            }
        }
    };

#endif

#if HAVE_GCD

    // Task dispatcher using Apple's Grand Central Dispatch.
    struct AppleTaskDispatcher : public TaskDispatcher
    {
        // @@ This is really lame, but I refuse to use size_t in the public API.
        struct BlockContext {
            Task * task;
            void * context;
        };

        static void block(void * context, size_t id) {
            BlockContext * ctx = (BlockContext *)context;
            ctx->task(ctx->context, int(id));
        }

        virtual void dispatch(Task * task, void * context, int count) {
            dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
            BlockContext blockCtx = { task, context };
            dispatch_apply_f(count, q, &blockCtx, block);
        }
    };

#endif

#if defined(HAVE_PPL)

    struct TaskFunctor {
        TaskFunctor(Task * task, void * context) : task(task), context(context) {}
        void operator()(int n) const {
            task(context, n);
        }
        Task * task;
        void * context;
    };

    // Task dispatcher using Microsoft's concurrency runtime.
    struct MicrosoftTaskDispatcher : public TaskDispatcher
    {
        virtual void dispatch(Task * task, void * context, int count)
        {
            TaskFunctor func(task, context);
            Concurrency::parallel_for(0, count, func);
        }
    };

#endif

#if defined(HAVE_TBB)

    struct TaskFunctor {
        TaskFunctor(Task * task, void * context) : task(task), context(context) {}
        void operator()(int & n) const {
            task(context, n);
        }
        Task * task;
        void * context;
    };

    // Task dispatcher using Inte's Thread Building Blocks.
    struct IntelTaskDispatcher : public TaskDispatcher
    {
        virtual void dispatch(Task * task, void * context, int count) {
            parallel_for(blocked_range<int>(0, count, 1), TaskFunctor(task, context));
        }
    };

#endif

#if defined(HAVE_OPENMP)
    typedef OpenMPTaskDispatcher        ConcurrentTaskDispatcher;
#elif defined(HAVE_TBB)
    typedef IntelTaskDispatcher         ConcurrentTaskDispatcher;
#elif defined(HAVE_PPL)
    typedef MicrosoftTaskDispatcher     ConcurrentTaskDispatcher;
#elif defined(HAVE_GCD)
    typedef AppleTaskDispatcher         ConcurrentTaskDispatcher;
#else
    //typedef SequentialTaskDispatcher    ConcurrentTaskDispatcher;
    typedef ParallelTaskDispatcher        ConcurrentTaskDispatcher;
#endif

} // namespace nvtt


<|start_filename|>src/nvmath/ftoi.h<|end_filename|>
// This code is in the public domain -- <EMAIL>

#pragma once

#include "nvmath/nvmath.h"

#if NV_USE_SSE
    #include <xmmintrin.h>
#endif

#include <math.h>

namespace nv
{
    // Optimized float to int conversions. See:
    // http://cbloomrants.blogspot.com/2009/01/01-17-09-float-to-int.html
    // http://www.stereopsis.com/sree/fpu2006.html
    // http://assemblyrequired.crashworks.org/2009/01/12/why-you-should-never-cast-floats-to-ints/
    // http://chrishecker.com/Miscellaneous_Technical_Articles#Floating_Point


    union DoubleAnd64 {
        uint64    i;
        double    d;
    };

    static const double floatutil_xs_doublemagic = (6755399441055744.0);                            // 2^52 * 1.5
    static const double floatutil_xs_doublemagicdelta = (1.5e-8);                                   // almost .5f = .5f + 1e^(number of exp bit)
    static const double floatutil_xs_doublemagicroundeps = (0.5f - floatutil_xs_doublemagicdelta);  // almost .5f = .5f - 1e^(number of exp bit)

    NV_FORCEINLINE int ftoi_round_xs(double val, double magic) {
#if 1
        DoubleAnd64 dunion;
        dunion.d = val + magic;
        return (int32) dunion.i; // just cast to grab the bottom bits
#else
        val += magic;
        return ((int*)&val)[0]; // @@ Assumes little endian.
#endif
    }

    NV_FORCEINLINE int ftoi_round_xs(float val) {
        return ftoi_round_xs(val, floatutil_xs_doublemagic);
    }

    NV_FORCEINLINE int ftoi_floor_xs(float val) {
        return ftoi_round_xs(val - floatutil_xs_doublemagicroundeps, floatutil_xs_doublemagic);
    }

    NV_FORCEINLINE int ftoi_ceil_xs(float val) {
        return ftoi_round_xs(val + floatutil_xs_doublemagicroundeps, floatutil_xs_doublemagic);
    }

    NV_FORCEINLINE int ftoi_trunc_xs(float val) {
        return (val<0) ? ftoi_ceil_xs(val) : ftoi_floor_xs(val);
    }

#if NV_USE_SSE

    NV_FORCEINLINE int ftoi_round_sse(float f) {
        return _mm_cvt_ss2si(_mm_set_ss(f));
    }

    NV_FORCEINLINE int ftoi_trunc_sse(float f) {
      return _mm_cvtt_ss2si(_mm_set_ss(f));
    }

    NV_FORCEINLINE int ftoi_round(float val) {
        return ftoi_round_sse(val);
    }

    NV_FORCEINLINE int ftoi_trunc(float f) {
      return ftoi_trunc_sse(f);
    }

    // We can probably do better than this. See for example:
    // http://dss.stephanierct.com/DevBlog/?p=8
    NV_FORCEINLINE int ftoi_floor(float val) {
        return ftoi_round(floorf(val));
    }

    NV_FORCEINLINE int ftoi_ceil(float val) {
        return ftoi_round(ceilf(val));
    }

#else

    // In theory this should work with any double floating point math implementation, but it appears that MSVC produces incorrect code
    // when SSE2 is targeted and fast math is enabled (/arch:SSE2 & /fp:fast). These problems go away with /fp:precise, which is the default mode.

    NV_FORCEINLINE int ftoi_round(float val) {
        return ftoi_round_xs(val);
    }

    NV_FORCEINLINE int ftoi_floor(float val) {
        return ftoi_floor_xs(val);
    }

    NV_FORCEINLINE int ftoi_ceil(float val) {
        return ftoi_ceil_xs(val);
    }

    NV_FORCEINLINE int ftoi_trunc(float f) {
      return ftoi_trunc_xs(f);
    }

#endif


    inline void test_ftoi() {

        // Round to nearest integer.
        nvCheck(ftoi_round(0.1f) == 0);
        nvCheck(ftoi_round(0.6f) == 1);
        nvCheck(ftoi_round(-0.2f) == 0);
        nvCheck(ftoi_round(-0.7f) == -1);
        nvCheck(ftoi_round(10.1f) == 10);
        nvCheck(ftoi_round(10.6f) == 11);
        nvCheck(ftoi_round(-90.1f) == -90);
        nvCheck(ftoi_round(-90.6f) == -91);

        nvCheck(ftoi_round(0) == 0);
        nvCheck(ftoi_round(1) == 1);
        nvCheck(ftoi_round(-1) == -1);
        
        nvCheck(ftoi_round(0.5f) == 0);  // How are midpoints rounded? Bankers rounding.
        nvCheck(ftoi_round(1.5f) == 2);
        nvCheck(ftoi_round(2.5f) == 2);
        nvCheck(ftoi_round(3.5f) == 4);
        nvCheck(ftoi_round(4.5f) == 4);
        nvCheck(ftoi_round(-0.5f) == 0);
        nvCheck(ftoi_round(-1.5f) == -2);
                

        // Truncation (round down if > 0, round up if < 0).
        nvCheck(ftoi_trunc(0.1f) == 0);
        nvCheck(ftoi_trunc(0.6f) == 0);
        nvCheck(ftoi_trunc(-0.2f) == 0);
        nvCheck(ftoi_trunc(-0.7f) == 0);    // @@ When using /arch:SSE2 in Win32, msvc produce wrong code for this one. It is skipping the addition.
        nvCheck(ftoi_trunc(1.99f) == 1);
        nvCheck(ftoi_trunc(-1.2f) == -1);

        // Floor (round down).
        nvCheck(ftoi_floor(0.1f) == 0);
        nvCheck(ftoi_floor(0.6f) == 0);
        nvCheck(ftoi_floor(-0.2f) == -1);
        nvCheck(ftoi_floor(-0.7f) == -1);
        nvCheck(ftoi_floor(1.99f) == 1);
        nvCheck(ftoi_floor(-1.2f) == -2);

        nvCheck(ftoi_floor(0) == 0);
        nvCheck(ftoi_floor(1) == 1);
        nvCheck(ftoi_floor(-1) == -1);
        nvCheck(ftoi_floor(2) == 2);
        nvCheck(ftoi_floor(-2) == -2);

        // Ceil (round up).
        nvCheck(ftoi_ceil(0.1f) == 1);
        nvCheck(ftoi_ceil(0.6f) == 1);
        nvCheck(ftoi_ceil(-0.2f) == 0);
        nvCheck(ftoi_ceil(-0.7f) == 0);
        nvCheck(ftoi_ceil(1.99f) == 2);
        nvCheck(ftoi_ceil(-1.2f) == -1);

        nvCheck(ftoi_ceil(0) == 0);
        nvCheck(ftoi_ceil(1) == 1);
        nvCheck(ftoi_ceil(-1) == -1);
        nvCheck(ftoi_ceil(2) == 2);
        nvCheck(ftoi_ceil(-2) == -2);
    }





    // Safe versions using standard casts.

    inline int iround(float f)
    {
        return int(floorf(f + 0.5f));
    }

    inline int iround(double f)
    {
        return int(::floor(f + 0.5));
    }

    inline int ifloor(float f)
    {
        return int(floorf(f));
    }

    inline int iceil(float f)
    {
        return int(ceilf(f));
    }



    // I'm always confused about which quantizer to use. I think we should choose a quantizer based on how the values are expanded later and this is generally using the 'exact endpoints' rule.
    // Some notes from cbloom: http://cbloomrants.blogspot.com/2011/07/07-26-11-pixel-int-to-float-options.html

    // Quantize a float in the [0,1] range, using exact end points or uniform bins.
    inline float quantizeFloat(float x, uint bits, bool exactEndPoints = true) {
        nvDebugCheck(bits <= 16);

        float range = float(1 << bits);
        if (exactEndPoints) {
            return floorf(x * (range-1) + 0.5f) / (range-1);
        }
        else {
            return (floorf(x * range) + 0.5f) / range;
        }
    }


    // This is the most common rounding mode:
    // 
    //   0     1       2     3
    // |___|_______|_______|___|
    // 0                       1
    //
    // You get that if you take the unit floating point number multiply by 'N-1' and round to nearest. That is, `i = round(f * (N-1))`.
    // You reconstruct the original float dividing by 'N-1': `f = i / (N-1)`


    //    0     1     2     3
    // |_____|_____|_____|_____|
    // 0                       1

    /*enum BinningMode {
        RoundMode_ExactEndPoints,       
        RoundMode_UniformBins,
    };*/

    template <int N>
    inline uint unitFloatToFixed(float f) {
        return ftoi_round(f * ((1<<N)-1));
    }

    inline uint8 unitFloatToFixed8(float f) {
        return (uint8)unitFloatToFixed<8>(f);
    }

    inline uint16 unitFloatToFixed16(float f) {
        return (uint16)unitFloatToFixed<16>(f);
    }


} // nv


<|start_filename|>extern/CMP_Core/test/CompressonatorTests.h<|end_filename|>
#ifndef COMPRESSONATOR_TESTS_H
#define COMPRESSONATOR_TESTS_H

void AssignExpectedColorsToBlocks();

#endif

<|start_filename|>src/nvtt/squish/fastclusterlookup.inl<|end_filename|>
struct Precomp {
	float alpha2_sum;
	float beta2_sum;
	float alphabeta_sum;
	float factor;
};

static const SQUISH_ALIGN_16 Precomp s_threeElement[153] = {
	{ 0.000000f, 16.000000f, 0.000000f, FLT_MAX }, // 0 (0 0 16)
	{ 0.250000f, 15.250000f, 0.250000f, 0.266667f }, // 1 (0 1 15)
	{ 0.500000f, 14.500000f, 0.500000f, 0.142857f }, // 2 (0 2 14)
	{ 0.750000f, 13.750000f, 0.750000f, 0.102564f }, // 3 (0 3 13)
	{ 1.000000f, 13.000000f, 1.000000f, 0.083333f }, // 4 (0 4 12)
	{ 1.250000f, 12.250000f, 1.250000f, 0.072727f }, // 5 (0 5 11)
	{ 1.500000f, 11.500000f, 1.500000f, 0.066667f }, // 6 (0 6 10)
	{ 1.750000f, 10.750000f, 1.750000f, 0.063492f }, // 7 (0 7 9)
	{ 2.000000f, 10.000000f, 2.000000f, 0.062500f }, // 8 (0 8 8)
	{ 2.250000f, 9.250000f, 2.250000f, 0.063492f }, // 9 (0 9 7)
	{ 2.500000f, 8.500000f, 2.500000f, 0.066667f }, // 10 (0 10 6)
	{ 2.750000f, 7.750000f, 2.750000f, 0.072727f }, // 11 (0 11 5)
	{ 3.000000f, 7.000000f, 3.000000f, 0.083333f }, // 12 (0 12 4)
	{ 3.250000f, 6.250000f, 3.250000f, 0.102564f }, // 13 (0 13 3)
	{ 3.500000f, 5.500000f, 3.500000f, 0.142857f }, // 14 (0 14 2)
	{ 3.750000f, 4.750000f, 3.750000f, 0.266667f }, // 15 (0 15 1)
	{ 4.000000f, 4.000000f, 4.000000f, FLT_MAX }, // 16 (0 16 0)
	{ 1.000000f, 15.000000f, 0.000000f, 0.066667f }, // 17 (1 0 15)
	{ 1.250000f, 14.250000f, 0.250000f, 0.056338f }, // 18 (1 1 14)
	{ 1.500000f, 13.500000f, 0.500000f, 0.050000f }, // 19 (1 2 13)
	{ 1.750000f, 12.750000f, 0.750000f, 0.045977f }, // 20 (1 3 12)
	{ 2.000000f, 12.000000f, 1.000000f, 0.043478f }, // 21 (1 4 11)
	{ 2.250000f, 11.250000f, 1.250000f, 0.042105f }, // 22 (1 5 10)
	{ 2.500000f, 10.500000f, 1.500000f, 0.041667f }, // 23 (1 6 9)
	{ 2.750000f, 9.750000f, 1.750000f, 0.042105f }, // 24 (1 7 8)
	{ 3.000000f, 9.000000f, 2.000000f, 0.043478f }, // 25 (1 8 7)
	{ 3.250000f, 8.250000f, 2.250000f, 0.045977f }, // 26 (1 9 6)
	{ 3.500000f, 7.500000f, 2.500000f, 0.050000f }, // 27 (1 10 5)
	{ 3.750000f, 6.750000f, 2.750000f, 0.056338f }, // 28 (1 11 4)
	{ 4.000000f, 6.000000f, 3.000000f, 0.066667f }, // 29 (1 12 3)
	{ 4.250000f, 5.250000f, 3.250000f, 0.085106f }, // 30 (1 13 2)
	{ 4.500000f, 4.500000f, 3.500000f, 0.125000f }, // 31 (1 14 1)
	{ 4.750000f, 3.750000f, 3.750000f, 0.266667f }, // 32 (1 15 0)
	{ 2.000000f, 14.000000f, 0.000000f, 0.035714f }, // 33 (2 0 14)
	{ 2.250000f, 13.250000f, 0.250000f, 0.033613f }, // 34 (2 1 13)
	{ 2.500000f, 12.500000f, 0.500000f, 0.032258f }, // 35 (2 2 12)
	{ 2.750000f, 11.750000f, 0.750000f, 0.031496f }, // 36 (2 3 11)
	{ 3.000000f, 11.000000f, 1.000000f, 0.031250f }, // 37 (2 4 10)
	{ 3.250000f, 10.250000f, 1.250000f, 0.031496f }, // 38 (2 5 9)
	{ 3.500000f, 9.500000f, 1.500000f, 0.032258f }, // 39 (2 6 8)
	{ 3.750000f, 8.750000f, 1.750000f, 0.033613f }, // 40 (2 7 7)
	{ 4.000000f, 8.000000f, 2.000000f, 0.035714f }, // 41 (2 8 6)
	{ 4.250000f, 7.250000f, 2.250000f, 0.038835f }, // 42 (2 9 5)
	{ 4.500000f, 6.500000f, 2.500000f, 0.043478f }, // 43 (2 10 4)
	{ 4.750000f, 5.750000f, 2.750000f, 0.050633f }, // 44 (2 11 3)
	{ 5.000000f, 5.000000f, 3.000000f, 0.062500f }, // 45 (2 12 2)
	{ 5.250000f, 4.250000f, 3.250000f, 0.085106f }, // 46 (2 13 1)
	{ 5.500000f, 3.500000f, 3.500000f, 0.142857f }, // 47 (2 14 0)
	{ 3.000000f, 13.000000f, 0.000000f, 0.025641f }, // 48 (3 0 13)
	{ 3.250000f, 12.250000f, 0.250000f, 0.025157f }, // 49 (3 1 12)
	{ 3.500000f, 11.500000f, 0.500000f, 0.025000f }, // 50 (3 2 11)
	{ 3.750000f, 10.750000f, 0.750000f, 0.025157f }, // 51 (3 3 10)
	{ 4.000000f, 10.000000f, 1.000000f, 0.025641f }, // 52 (3 4 9)
	{ 4.250000f, 9.250000f, 1.250000f, 0.026490f }, // 53 (3 5 8)
	{ 4.500000f, 8.500000f, 1.500000f, 0.027778f }, // 54 (3 6 7)
	{ 4.750000f, 7.750000f, 1.750000f, 0.029630f }, // 55 (3 7 6)
	{ 5.000000f, 7.000000f, 2.000000f, 0.032258f }, // 56 (3 8 5)
	{ 5.250000f, 6.250000f, 2.250000f, 0.036036f }, // 57 (3 9 4)
	{ 5.500000f, 5.500000f, 2.500000f, 0.041667f }, // 58 (3 10 3)
	{ 5.750000f, 4.750000f, 2.750000f, 0.050633f }, // 59 (3 11 2)
	{ 6.000000f, 4.000000f, 3.000000f, 0.066667f }, // 60 (3 12 1)
	{ 6.250000f, 3.250000f, 3.250000f, 0.102564f }, // 61 (3 13 0)
	{ 4.000000f, 12.000000f, 0.000000f, 0.020833f }, // 62 (4 0 12)
	{ 4.250000f, 11.250000f, 0.250000f, 0.020942f }, // 63 (4 1 11)
	{ 4.500000f, 10.500000f, 0.500000f, 0.021277f }, // 64 (4 2 10)
	{ 4.750000f, 9.750000f, 0.750000f, 0.021858f }, // 65 (4 3 9)
	{ 5.000000f, 9.000000f, 1.000000f, 0.022727f }, // 66 (4 4 8)
	{ 5.250000f, 8.250000f, 1.250000f, 0.023952f }, // 67 (4 5 7)
	{ 5.500000f, 7.500000f, 1.500000f, 0.025641f }, // 68 (4 6 6)
	{ 5.750000f, 6.750000f, 1.750000f, 0.027972f }, // 69 (4 7 5)
	{ 6.000000f, 6.000000f, 2.000000f, 0.031250f }, // 70 (4 8 4)
	{ 6.250000f, 5.250000f, 2.250000f, 0.036036f }, // 71 (4 9 3)
	{ 6.500000f, 4.500000f, 2.500000f, 0.043478f }, // 72 (4 10 2)
	{ 6.750000f, 3.750000f, 2.750000f, 0.056338f }, // 73 (4 11 1)
	{ 7.000000f, 3.000000f, 3.000000f, 0.083333f }, // 74 (4 12 0)
	{ 5.000000f, 11.000000f, 0.000000f, 0.018182f }, // 75 (5 0 11)
	{ 5.250000f, 10.250000f, 0.250000f, 0.018605f }, // 76 (5 1 10)
	{ 5.500000f, 9.500000f, 0.500000f, 0.019231f }, // 77 (5 2 9)
	{ 5.750000f, 8.750000f, 0.750000f, 0.020101f }, // 78 (5 3 8)
	{ 6.000000f, 8.000000f, 1.000000f, 0.021277f }, // 79 (5 4 7)
	{ 6.250000f, 7.250000f, 1.250000f, 0.022857f }, // 80 (5 5 6)
	{ 6.500000f, 6.500000f, 1.500000f, 0.025000f }, // 81 (5 6 5)
	{ 6.750000f, 5.750000f, 1.750000f, 0.027972f }, // 82 (5 7 4)
	{ 7.000000f, 5.000000f, 2.000000f, 0.032258f }, // 83 (5 8 3)
	{ 7.250000f, 4.250000f, 2.250000f, 0.038835f }, // 84 (5 9 2)
	{ 7.500000f, 3.500000f, 2.500000f, 0.050000f }, // 85 (5 10 1)
	{ 7.750000f, 2.750000f, 2.750000f, 0.072727f }, // 86 (5 11 0)
	{ 6.000000f, 10.000000f, 0.000000f, 0.016667f }, // 87 (6 0 10)
	{ 6.250000f, 9.250000f, 0.250000f, 0.017316f }, // 88 (6 1 9)
	{ 6.500000f, 8.500000f, 0.500000f, 0.018182f }, // 89 (6 2 8)
	{ 6.750000f, 7.750000f, 0.750000f, 0.019324f }, // 90 (6 3 7)
	{ 7.000000f, 7.000000f, 1.000000f, 0.020833f }, // 91 (6 4 6)
	{ 7.250000f, 6.250000f, 1.250000f, 0.022857f }, // 92 (6 5 5)
	{ 7.500000f, 5.500000f, 1.500000f, 0.025641f }, // 93 (6 6 4)
	{ 7.750000f, 4.750000f, 1.750000f, 0.029630f }, // 94 (6 7 3)
	{ 8.000000f, 4.000000f, 2.000000f, 0.035714f }, // 95 (6 8 2)
	{ 8.250000f, 3.250000f, 2.250000f, 0.045977f }, // 96 (6 9 1)
	{ 8.500000f, 2.500000f, 2.500000f, 0.066667f }, // 97 (6 10 0)
	{ 7.000000f, 9.000000f, 0.000000f, 0.015873f }, // 98 (7 0 9)
	{ 7.250000f, 8.250000f, 0.250000f, 0.016736f }, // 99 (7 1 8)
	{ 7.500000f, 7.500000f, 0.500000f, 0.017857f }, // 100 (7 2 7)
	{ 7.750000f, 6.750000f, 0.750000f, 0.019324f }, // 101 (7 3 6)
	{ 8.000000f, 6.000000f, 1.000000f, 0.021277f }, // 102 (7 4 5)
	{ 8.250000f, 5.250000f, 1.250000f, 0.023952f }, // 103 (7 5 4)
	{ 8.500000f, 4.500000f, 1.500000f, 0.027778f }, // 104 (7 6 3)
	{ 8.750000f, 3.750000f, 1.750000f, 0.033613f }, // 105 (7 7 2)
	{ 9.000000f, 3.000000f, 2.000000f, 0.043478f }, // 106 (7 8 1)
	{ 9.250000f, 2.250000f, 2.250000f, 0.063492f }, // 107 (7 9 0)
	{ 8.000000f, 8.000000f, 0.000000f, 0.015625f }, // 108 (8 0 8)
	{ 8.250000f, 7.250000f, 0.250000f, 0.016736f }, // 109 (8 1 7)
	{ 8.500000f, 6.500000f, 0.500000f, 0.018182f }, // 110 (8 2 6)
	{ 8.750000f, 5.750000f, 0.750000f, 0.020101f }, // 111 (8 3 5)
	{ 9.000000f, 5.000000f, 1.000000f, 0.022727f }, // 112 (8 4 4)
	{ 9.250000f, 4.250000f, 1.250000f, 0.026490f }, // 113 (8 5 3)
	{ 9.500000f, 3.500000f, 1.500000f, 0.032258f }, // 114 (8 6 2)
	{ 9.750000f, 2.750000f, 1.750000f, 0.042105f }, // 115 (8 7 1)
	{ 10.000000f, 2.000000f, 2.000000f, 0.062500f }, // 116 (8 8 0)
	{ 9.000000f, 7.000000f, 0.000000f, 0.015873f }, // 117 (9 0 7)
	{ 9.250000f, 6.250000f, 0.250000f, 0.017316f }, // 118 (9 1 6)
	{ 9.500000f, 5.500000f, 0.500000f, 0.019231f }, // 119 (9 2 5)
	{ 9.750000f, 4.750000f, 0.750000f, 0.021858f }, // 120 (9 3 4)
	{ 10.000000f, 4.000000f, 1.000000f, 0.025641f }, // 121 (9 4 3)
	{ 10.250000f, 3.250000f, 1.250000f, 0.031496f }, // 122 (9 5 2)
	{ 10.500000f, 2.500000f, 1.500000f, 0.041667f }, // 123 (9 6 1)
	{ 10.750000f, 1.750000f, 1.750000f, 0.063492f }, // 124 (9 7 0)
	{ 10.000000f, 6.000000f, 0.000000f, 0.016667f }, // 125 (10 0 6)
	{ 10.250000f, 5.250000f, 0.250000f, 0.018605f }, // 126 (10 1 5)
	{ 10.500000f, 4.500000f, 0.500000f, 0.021277f }, // 127 (10 2 4)
	{ 10.750000f, 3.750000f, 0.750000f, 0.025157f }, // 128 (10 3 3)
	{ 11.000000f, 3.000000f, 1.000000f, 0.031250f }, // 129 (10 4 2)
	{ 11.250000f, 2.250000f, 1.250000f, 0.042105f }, // 130 (10 5 1)
	{ 11.500000f, 1.500000f, 1.500000f, 0.066667f }, // 131 (10 6 0)
	{ 11.000000f, 5.000000f, 0.000000f, 0.018182f }, // 132 (11 0 5)
	{ 11.250000f, 4.250000f, 0.250000f, 0.020942f }, // 133 (11 1 4)
	{ 11.500000f, 3.500000f, 0.500000f, 0.025000f }, // 134 (11 2 3)
	{ 11.750000f, 2.750000f, 0.750000f, 0.031496f }, // 135 (11 3 2)
	{ 12.000000f, 2.000000f, 1.000000f, 0.043478f }, // 136 (11 4 1)
	{ 12.250000f, 1.250000f, 1.250000f, 0.072727f }, // 137 (11 5 0)
	{ 12.000000f, 4.000000f, 0.000000f, 0.020833f }, // 138 (12 0 4)
	{ 12.250000f, 3.250000f, 0.250000f, 0.025157f }, // 139 (12 1 3)
	{ 12.500000f, 2.500000f, 0.500000f, 0.032258f }, // 140 (12 2 2)
	{ 12.750000f, 1.750000f, 0.750000f, 0.045977f }, // 141 (12 3 1)
	{ 13.000000f, 1.000000f, 1.000000f, 0.083333f }, // 142 (12 4 0)
	{ 13.000000f, 3.000000f, 0.000000f, 0.025641f }, // 143 (13 0 3)
	{ 13.250000f, 2.250000f, 0.250000f, 0.033613f }, // 144 (13 1 2)
	{ 13.500000f, 1.500000f, 0.500000f, 0.050000f }, // 145 (13 2 1)
	{ 13.750000f, 0.750000f, 0.750000f, 0.102564f }, // 146 (13 3 0)
	{ 14.000000f, 2.000000f, 0.000000f, 0.035714f }, // 147 (14 0 2)
	{ 14.250000f, 1.250000f, 0.250000f, 0.056338f }, // 148 (14 1 1)
	{ 14.500000f, 0.500000f, 0.500000f, 0.142857f }, // 149 (14 2 0)
	{ 15.000000f, 1.000000f, 0.000000f, 0.066667f }, // 150 (15 0 1)
	{ 15.250000f, 0.250000f, 0.250000f, 0.266667f }, // 151 (15 1 0)
	{ 16.000000f, 0.000000f, 0.000000f, FLT_MAX }, // 152 (16 0 0)
}; // 153 three cluster elements

static const SQUISH_ALIGN_16 Precomp s_fourElement[969] = {
	{ 0.000000f, 16.000000f, 0.000000f, FLT_MAX }, // 0 (0 0 0 16)
	{ 0.111111f, 15.444445f, 0.222222f, 0.600000f }, // 1 (0 0 1 15)
	{ 0.222222f, 14.888889f, 0.444444f, 0.321429f }, // 2 (0 0 2 14)
	{ 0.333333f, 14.333333f, 0.666667f, 0.230769f }, // 3 (0 0 3 13)
	{ 0.444444f, 13.777778f, 0.888889f, 0.187500f }, // 4 (0 0 4 12)
	{ 0.555556f, 13.222222f, 1.111111f, 0.163636f }, // 5 (0 0 5 11)
	{ 0.666667f, 12.666667f, 1.333333f, 0.150000f }, // 6 (0 0 6 10)
	{ 0.777778f, 12.111111f, 1.555556f, 0.142857f }, // 7 (0 0 7 9)
	{ 0.888889f, 11.555555f, 1.777778f, 0.140625f }, // 8 (0 0 8 8)
	{ 1.000000f, 11.000000f, 2.000000f, 0.142857f }, // 9 (0 0 9 7)
	{ 1.111111f, 10.444445f, 2.222222f, 0.150000f }, // 10 (0 0 10 6)
	{ 1.222222f, 9.888889f, 2.444444f, 0.163636f }, // 11 (0 0 11 5)
	{ 1.333333f, 9.333333f, 2.666667f, 0.187500f }, // 12 (0 0 12 4)
	{ 1.444444f, 8.777778f, 2.888889f, 0.230769f }, // 13 (0 0 13 3)
	{ 1.555556f, 8.222222f, 3.111111f, 0.321429f }, // 14 (0 0 14 2)
	{ 1.666667f, 7.666667f, 3.333333f, 0.600000f }, // 15 (0 0 15 1)
	{ 1.777778f, 7.111111f, 3.555556f, FLT_MAX }, // 16 (0 0 16 0)
	{ 0.444444f, 15.111111f, 0.222222f, 0.150000f }, // 17 (0 1 0 15)
	{ 0.555556f, 14.555555f, 0.444444f, 0.126761f }, // 18 (0 1 1 14)
	{ 0.666667f, 14.000000f, 0.666667f, 0.112500f }, // 19 (0 1 2 13)
	{ 0.777778f, 13.444445f, 0.888889f, 0.103448f }, // 20 (0 1 3 12)
	{ 0.888889f, 12.888889f, 1.111111f, 0.097826f }, // 21 (0 1 4 11)
	{ 1.000000f, 12.333333f, 1.333333f, 0.094737f }, // 22 (0 1 5 10)
	{ 1.111111f, 11.777778f, 1.555556f, 0.093750f }, // 23 (0 1 6 9)
	{ 1.222222f, 11.222222f, 1.777778f, 0.094737f }, // 24 (0 1 7 8)
	{ 1.333333f, 10.666667f, 2.000000f, 0.097826f }, // 25 (0 1 8 7)
	{ 1.444444f, 10.111111f, 2.222222f, 0.103448f }, // 26 (0 1 9 6)
	{ 1.555556f, 9.555555f, 2.444444f, 0.112500f }, // 27 (0 1 10 5)
	{ 1.666667f, 9.000000f, 2.666667f, 0.126761f }, // 28 (0 1 11 4)
	{ 1.777778f, 8.444445f, 2.888889f, 0.150000f }, // 29 (0 1 12 3)
	{ 1.888889f, 7.888889f, 3.111111f, 0.191489f }, // 30 (0 1 13 2)
	{ 2.000000f, 7.333333f, 3.333333f, 0.281250f }, // 31 (0 1 14 1)
	{ 2.111111f, 6.777778f, 3.555556f, 0.600000f }, // 32 (0 1 15 0)
	{ 0.888889f, 14.222222f, 0.444444f, 0.080357f }, // 33 (0 2 0 14)
	{ 1.000000f, 13.666667f, 0.666667f, 0.075630f }, // 34 (0 2 1 13)
	{ 1.111111f, 13.111111f, 0.888889f, 0.072581f }, // 35 (0 2 2 12)
	{ 1.222222f, 12.555555f, 1.111111f, 0.070866f }, // 36 (0 2 3 11)
	{ 1.333333f, 12.000000f, 1.333333f, 0.070313f }, // 37 (0 2 4 10)
	{ 1.444444f, 11.444445f, 1.555556f, 0.070866f }, // 38 (0 2 5 9)
	{ 1.555556f, 10.888889f, 1.777778f, 0.072581f }, // 39 (0 2 6 8)
	{ 1.666667f, 10.333333f, 2.000000f, 0.075630f }, // 40 (0 2 7 7)
	{ 1.777778f, 9.777778f, 2.222222f, 0.080357f }, // 41 (0 2 8 6)
	{ 1.888889f, 9.222222f, 2.444444f, 0.087379f }, // 42 (0 2 9 5)
	{ 2.000000f, 8.666667f, 2.666667f, 0.097826f }, // 43 (0 2 10 4)
	{ 2.111111f, 8.111111f, 2.888889f, 0.113924f }, // 44 (0 2 11 3)
	{ 2.222222f, 7.555556f, 3.111111f, 0.140625f }, // 45 (0 2 12 2)
	{ 2.333333f, 7.000000f, 3.333333f, 0.191489f }, // 46 (0 2 13 1)
	{ 2.444444f, 6.444445f, 3.555556f, 0.321429f }, // 47 (0 2 14 0)
	{ 1.333333f, 13.333333f, 0.666667f, 0.057692f }, // 48 (0 3 0 13)
	{ 1.444444f, 12.777778f, 0.888889f, 0.056604f }, // 49 (0 3 1 12)
	{ 1.555556f, 12.222222f, 1.111111f, 0.056250f }, // 50 (0 3 2 11)
	{ 1.666667f, 11.666667f, 1.333333f, 0.056604f }, // 51 (0 3 3 10)
	{ 1.777778f, 11.111111f, 1.555556f, 0.057692f }, // 52 (0 3 4 9)
	{ 1.888889f, 10.555555f, 1.777778f, 0.059603f }, // 53 (0 3 5 8)
	{ 2.000000f, 10.000000f, 2.000000f, 0.062500f }, // 54 (0 3 6 7)
	{ 2.111111f, 9.444445f, 2.222222f, 0.066667f }, // 55 (0 3 7 6)
	{ 2.222222f, 8.888889f, 2.444444f, 0.072581f }, // 56 (0 3 8 5)
	{ 2.333333f, 8.333333f, 2.666667f, 0.081081f }, // 57 (0 3 9 4)
	{ 2.444444f, 7.777778f, 2.888889f, 0.093750f }, // 58 (0 3 10 3)
	{ 2.555556f, 7.222222f, 3.111111f, 0.113924f }, // 59 (0 3 11 2)
	{ 2.666667f, 6.666667f, 3.333333f, 0.150000f }, // 60 (0 3 12 1)
	{ 2.777778f, 6.111111f, 3.555556f, 0.230769f }, // 61 (0 3 13 0)
	{ 1.777778f, 12.444445f, 0.888889f, 0.046875f }, // 62 (0 4 0 12)
	{ 1.888889f, 11.888889f, 1.111111f, 0.047120f }, // 63 (0 4 1 11)
	{ 2.000000f, 11.333333f, 1.333333f, 0.047872f }, // 64 (0 4 2 10)
	{ 2.111111f, 10.777778f, 1.555556f, 0.049180f }, // 65 (0 4 3 9)
	{ 2.222222f, 10.222222f, 1.777778f, 0.051136f }, // 66 (0 4 4 8)
	{ 2.333333f, 9.666667f, 2.000000f, 0.053892f }, // 67 (0 4 5 7)
	{ 2.444444f, 9.111111f, 2.222222f, 0.057692f }, // 68 (0 4 6 6)
	{ 2.555556f, 8.555555f, 2.444444f, 0.062937f }, // 69 (0 4 7 5)
	{ 2.666667f, 8.000000f, 2.666667f, 0.070313f }, // 70 (0 4 8 4)
	{ 2.777778f, 7.444445f, 2.888889f, 0.081081f }, // 71 (0 4 9 3)
	{ 2.888889f, 6.888889f, 3.111111f, 0.097826f }, // 72 (0 4 10 2)
	{ 3.000000f, 6.333333f, 3.333333f, 0.126761f }, // 73 (0 4 11 1)
	{ 3.111111f, 5.777778f, 3.555556f, 0.187500f }, // 74 (0 4 12 0)
	{ 2.222222f, 11.555555f, 1.111111f, 0.040909f }, // 75 (0 5 0 11)
	{ 2.333333f, 11.000000f, 1.333333f, 0.041860f }, // 76 (0 5 1 10)
	{ 2.444444f, 10.444445f, 1.555556f, 0.043269f }, // 77 (0 5 2 9)
	{ 2.555556f, 9.888889f, 1.777778f, 0.045226f }, // 78 (0 5 3 8)
	{ 2.666667f, 9.333333f, 2.000000f, 0.047872f }, // 79 (0 5 4 7)
	{ 2.777778f, 8.777778f, 2.222222f, 0.051429f }, // 80 (0 5 5 6)
	{ 2.888889f, 8.222222f, 2.444444f, 0.056250f }, // 81 (0 5 6 5)
	{ 3.000000f, 7.666667f, 2.666667f, 0.062937f }, // 82 (0 5 7 4)
	{ 3.111111f, 7.111111f, 2.888889f, 0.072581f }, // 83 (0 5 8 3)
	{ 3.222222f, 6.555556f, 3.111111f, 0.087379f }, // 84 (0 5 9 2)
	{ 3.333333f, 6.000000f, 3.333333f, 0.112500f }, // 85 (0 5 10 1)
	{ 3.444444f, 5.444445f, 3.555556f, 0.163636f }, // 86 (0 5 11 0)
	{ 2.666667f, 10.666667f, 1.333333f, 0.037500f }, // 87 (0 6 0 10)
	{ 2.777778f, 10.111111f, 1.555556f, 0.038961f }, // 88 (0 6 1 9)
	{ 2.888889f, 9.555555f, 1.777778f, 0.040909f }, // 89 (0 6 2 8)
	{ 3.000000f, 9.000000f, 2.000000f, 0.043478f }, // 90 (0 6 3 7)
	{ 3.111111f, 8.444445f, 2.222222f, 0.046875f }, // 91 (0 6 4 6)
	{ 3.222222f, 7.888889f, 2.444444f, 0.051429f }, // 92 (0 6 5 5)
	{ 3.333333f, 7.333333f, 2.666667f, 0.057692f }, // 93 (0 6 6 4)
	{ 3.444444f, 6.777778f, 2.888889f, 0.066667f }, // 94 (0 6 7 3)
	{ 3.555556f, 6.222222f, 3.111111f, 0.080357f }, // 95 (0 6 8 2)
	{ 3.666667f, 5.666667f, 3.333333f, 0.103448f }, // 96 (0 6 9 1)
	{ 3.777778f, 5.111111f, 3.555556f, 0.150000f }, // 97 (0 6 10 0)
	{ 3.111111f, 9.777778f, 1.555556f, 0.035714f }, // 98 (0 7 0 9)
	{ 3.222222f, 9.222222f, 1.777778f, 0.037657f }, // 99 (0 7 1 8)
	{ 3.333333f, 8.666667f, 2.000000f, 0.040179f }, // 100 (0 7 2 7)
	{ 3.444444f, 8.111111f, 2.222222f, 0.043478f }, // 101 (0 7 3 6)
	{ 3.555556f, 7.555555f, 2.444444f, 0.047872f }, // 102 (0 7 4 5)
	{ 3.666667f, 7.000000f, 2.666667f, 0.053892f }, // 103 (0 7 5 4)
	{ 3.777778f, 6.444445f, 2.888889f, 0.062500f }, // 104 (0 7 6 3)
	{ 3.888889f, 5.888889f, 3.111111f, 0.075630f }, // 105 (0 7 7 2)
	{ 4.000000f, 5.333333f, 3.333333f, 0.097826f }, // 106 (0 7 8 1)
	{ 4.111111f, 4.777778f, 3.555556f, 0.142857f }, // 107 (0 7 9 0)
	{ 3.555556f, 8.888889f, 1.777778f, 0.035156f }, // 108 (0 8 0 8)
	{ 3.666667f, 8.333333f, 2.000000f, 0.037657f }, // 109 (0 8 1 7)
	{ 3.777778f, 7.777778f, 2.222222f, 0.040909f }, // 110 (0 8 2 6)
	{ 3.888889f, 7.222222f, 2.444444f, 0.045226f }, // 111 (0 8 3 5)
	{ 4.000000f, 6.666667f, 2.666667f, 0.051136f }, // 112 (0 8 4 4)
	{ 4.111111f, 6.111111f, 2.888889f, 0.059603f }, // 113 (0 8 5 3)
	{ 4.222222f, 5.555555f, 3.111111f, 0.072581f }, // 114 (0 8 6 2)
	{ 4.333333f, 5.000000f, 3.333333f, 0.094737f }, // 115 (0 8 7 1)
	{ 4.444445f, 4.444445f, 3.555556f, 0.140625f }, // 116 (0 8 8 0)
	{ 4.000000f, 8.000000f, 2.000000f, 0.035714f }, // 117 (0 9 0 7)
	{ 4.111111f, 7.444445f, 2.222222f, 0.038961f }, // 118 (0 9 1 6)
	{ 4.222222f, 6.888889f, 2.444444f, 0.043269f }, // 119 (0 9 2 5)
	{ 4.333333f, 6.333333f, 2.666667f, 0.049180f }, // 120 (0 9 3 4)
	{ 4.444445f, 5.777778f, 2.888889f, 0.057692f }, // 121 (0 9 4 3)
	{ 4.555556f, 5.222222f, 3.111111f, 0.070866f }, // 122 (0 9 5 2)
	{ 4.666667f, 4.666667f, 3.333333f, 0.093750f }, // 123 (0 9 6 1)
	{ 4.777778f, 4.111111f, 3.555556f, 0.142857f }, // 124 (0 9 7 0)
	{ 4.444445f, 7.111111f, 2.222222f, 0.037500f }, // 125 (0 10 0 6)
	{ 4.555556f, 6.555555f, 2.444444f, 0.041860f }, // 126 (0 10 1 5)
	{ 4.666667f, 6.000000f, 2.666667f, 0.047872f }, // 127 (0 10 2 4)
	{ 4.777778f, 5.444445f, 2.888889f, 0.056604f }, // 128 (0 10 3 3)
	{ 4.888889f, 4.888889f, 3.111111f, 0.070313f }, // 129 (0 10 4 2)
	{ 5.000000f, 4.333333f, 3.333333f, 0.094737f }, // 130 (0 10 5 1)
	{ 5.111111f, 3.777778f, 3.555556f, 0.150000f }, // 131 (0 10 6 0)
	{ 4.888889f, 6.222222f, 2.444444f, 0.040909f }, // 132 (0 11 0 5)
	{ 5.000000f, 5.666667f, 2.666667f, 0.047120f }, // 133 (0 11 1 4)
	{ 5.111111f, 5.111111f, 2.888889f, 0.056250f }, // 134 (0 11 2 3)
	{ 5.222222f, 4.555555f, 3.111111f, 0.070866f }, // 135 (0 11 3 2)
	{ 5.333333f, 4.000000f, 3.333333f, 0.097826f }, // 136 (0 11 4 1)
	{ 5.444445f, 3.444444f, 3.555556f, 0.163636f }, // 137 (0 11 5 0)
	{ 5.333333f, 5.333333f, 2.666667f, 0.046875f }, // 138 (0 12 0 4)
	{ 5.444445f, 4.777778f, 2.888889f, 0.056604f }, // 139 (0 12 1 3)
	{ 5.555556f, 4.222222f, 3.111111f, 0.072581f }, // 140 (0 12 2 2)
	{ 5.666667f, 3.666667f, 3.333333f, 0.103448f }, // 141 (0 12 3 1)
	{ 5.777778f, 3.111111f, 3.555556f, 0.187500f }, // 142 (0 12 4 0)
	{ 5.777778f, 4.444445f, 2.888889f, 0.057692f }, // 143 (0 13 0 3)
	{ 5.888889f, 3.888889f, 3.111111f, 0.075630f }, // 144 (0 13 1 2)
	{ 6.000000f, 3.333333f, 3.333333f, 0.112500f }, // 145 (0 13 2 1)
	{ 6.111111f, 2.777778f, 3.555556f, 0.230769f }, // 146 (0 13 3 0)
	{ 6.222222f, 3.555556f, 3.111111f, 0.080357f }, // 147 (0 14 0 2)
	{ 6.333333f, 3.000000f, 3.333333f, 0.126761f }, // 148 (0 14 1 1)
	{ 6.444445f, 2.444444f, 3.555556f, 0.321429f }, // 149 (0 14 2 0)
	{ 6.666667f, 2.666667f, 3.333333f, 0.150000f }, // 150 (0 15 0 1)
	{ 6.777778f, 2.111111f, 3.555556f, 0.600000f }, // 151 (0 15 1 0)
	{ 7.111111f, 1.777778f, 3.555556f, FLT_MAX }, // 152 (0 16 0 0)
	{ 1.000000f, 15.000000f, 0.000000f, 0.066667f }, // 153 (1 0 0 15)
	{ 1.111111f, 14.444445f, 0.222222f, 0.062500f }, // 154 (1 0 1 14)
	{ 1.222222f, 13.888889f, 0.444444f, 0.059603f }, // 155 (1 0 2 13)
	{ 1.333333f, 13.333333f, 0.666667f, 0.057692f }, // 156 (1 0 3 12)
	{ 1.444444f, 12.777778f, 0.888889f, 0.056604f }, // 157 (1 0 4 11)
	{ 1.555556f, 12.222222f, 1.111111f, 0.056250f }, // 158 (1 0 5 10)
	{ 1.666667f, 11.666667f, 1.333333f, 0.056604f }, // 159 (1 0 6 9)
	{ 1.777778f, 11.111111f, 1.555556f, 0.057692f }, // 160 (1 0 7 8)
	{ 1.888889f, 10.555555f, 1.777778f, 0.059603f }, // 161 (1 0 8 7)
	{ 2.000000f, 10.000000f, 2.000000f, 0.062500f }, // 162 (1 0 9 6)
	{ 2.111111f, 9.444445f, 2.222222f, 0.066667f }, // 163 (1 0 10 5)
	{ 2.222222f, 8.888889f, 2.444444f, 0.072581f }, // 164 (1 0 11 4)
	{ 2.333333f, 8.333333f, 2.666667f, 0.081081f }, // 165 (1 0 12 3)
	{ 2.444444f, 7.777778f, 2.888889f, 0.093750f }, // 166 (1 0 13 2)
	{ 2.555556f, 7.222222f, 3.111111f, 0.113924f }, // 167 (1 0 14 1)
	{ 2.666667f, 6.666667f, 3.333333f, 0.150000f }, // 168 (1 0 15 0)
	{ 1.444444f, 14.111111f, 0.222222f, 0.049180f }, // 169 (1 1 0 14)
	{ 1.555556f, 13.555555f, 0.444444f, 0.047872f }, // 170 (1 1 1 13)
	{ 1.666667f, 13.000000f, 0.666667f, 0.047120f }, // 171 (1 1 2 12)
	{ 1.777778f, 12.444445f, 0.888889f, 0.046875f }, // 172 (1 1 3 11)
	{ 1.888889f, 11.888889f, 1.111111f, 0.047120f }, // 173 (1 1 4 10)
	{ 2.000000f, 11.333333f, 1.333333f, 0.047872f }, // 174 (1 1 5 9)
	{ 2.111111f, 10.777778f, 1.555556f, 0.049180f }, // 175 (1 1 6 8)
	{ 2.222222f, 10.222222f, 1.777778f, 0.051136f }, // 176 (1 1 7 7)
	{ 2.333333f, 9.666667f, 2.000000f, 0.053892f }, // 177 (1 1 8 6)
	{ 2.444444f, 9.111111f, 2.222222f, 0.057692f }, // 178 (1 1 9 5)
	{ 2.555556f, 8.555555f, 2.444444f, 0.062937f }, // 179 (1 1 10 4)
	{ 2.666667f, 8.000000f, 2.666667f, 0.070313f }, // 180 (1 1 11 3)
	{ 2.777778f, 7.444445f, 2.888889f, 0.081081f }, // 181 (1 1 12 2)
	{ 2.888889f, 6.888889f, 3.111111f, 0.097826f }, // 182 (1 1 13 1)
	{ 3.000000f, 6.333333f, 3.333333f, 0.126761f }, // 183 (1 1 14 0)
	{ 1.888889f, 13.222222f, 0.444444f, 0.040359f }, // 184 (1 2 0 13)
	{ 2.000000f, 12.666667f, 0.666667f, 0.040179f }, // 185 (1 2 1 12)
	{ 2.111111f, 12.111111f, 0.888889f, 0.040359f }, // 186 (1 2 2 11)
	{ 2.222222f, 11.555555f, 1.111111f, 0.040909f }, // 187 (1 2 3 10)
	{ 2.333333f, 11.000000f, 1.333333f, 0.041860f }, // 188 (1 2 4 9)
	{ 2.444444f, 10.444445f, 1.555556f, 0.043269f }, // 189 (1 2 5 8)
	{ 2.555556f, 9.888889f, 1.777778f, 0.045226f }, // 190 (1 2 6 7)
	{ 2.666667f, 9.333333f, 2.000000f, 0.047872f }, // 191 (1 2 7 6)
	{ 2.777778f, 8.777778f, 2.222222f, 0.051429f }, // 192 (1 2 8 5)
	{ 2.888889f, 8.222222f, 2.444444f, 0.056250f }, // 193 (1 2 9 4)
	{ 3.000000f, 7.666667f, 2.666667f, 0.062937f }, // 194 (1 2 10 3)
	{ 3.111111f, 7.111111f, 2.888889f, 0.072581f }, // 195 (1 2 11 2)
	{ 3.222222f, 6.555556f, 3.111111f, 0.087379f }, // 196 (1 2 12 1)
	{ 3.333333f, 6.000000f, 3.333333f, 0.112500f }, // 197 (1 2 13 0)
	{ 2.333333f, 12.333333f, 0.666667f, 0.035294f }, // 198 (1 3 0 12)
	{ 2.444444f, 11.777778f, 0.888889f, 0.035714f }, // 199 (1 3 1 11)
	{ 2.555556f, 11.222222f, 1.111111f, 0.036437f }, // 200 (1 3 2 10)
	{ 2.666667f, 10.666667f, 1.333333f, 0.037500f }, // 201 (1 3 3 9)
	{ 2.777778f, 10.111111f, 1.555556f, 0.038961f }, // 202 (1 3 4 8)
	{ 2.888889f, 9.555555f, 1.777778f, 0.040909f }, // 203 (1 3 5 7)
	{ 3.000000f, 9.000000f, 2.000000f, 0.043478f }, // 204 (1 3 6 6)
	{ 3.111111f, 8.444445f, 2.222222f, 0.046875f }, // 205 (1 3 7 5)
	{ 3.222222f, 7.888889f, 2.444444f, 0.051429f }, // 206 (1 3 8 4)
	{ 3.333333f, 7.333333f, 2.666667f, 0.057692f }, // 207 (1 3 9 3)
	{ 3.444444f, 6.777778f, 2.888889f, 0.066667f }, // 208 (1 3 10 2)
	{ 3.555556f, 6.222222f, 3.111111f, 0.080357f }, // 209 (1 3 11 1)
	{ 3.666667f, 5.666667f, 3.333333f, 0.103448f }, // 210 (1 3 12 0)
	{ 2.777778f, 11.444445f, 0.888889f, 0.032258f }, // 211 (1 4 0 11)
	{ 2.888889f, 10.888889f, 1.111111f, 0.033088f }, // 212 (1 4 1 10)
	{ 3.000000f, 10.333333f, 1.333333f, 0.034221f }, // 213 (1 4 2 9)
	{ 3.111111f, 9.777778f, 1.555556f, 0.035714f }, // 214 (1 4 3 8)
	{ 3.222222f, 9.222222f, 1.777778f, 0.037657f }, // 215 (1 4 4 7)
	{ 3.333333f, 8.666667f, 2.000000f, 0.040179f }, // 216 (1 4 5 6)
	{ 3.444444f, 8.111111f, 2.222222f, 0.043478f }, // 217 (1 4 6 5)
	{ 3.555556f, 7.555555f, 2.444444f, 0.047872f }, // 218 (1 4 7 4)
	{ 3.666667f, 7.000000f, 2.666667f, 0.053892f }, // 219 (1 4 8 3)
	{ 3.777778f, 6.444445f, 2.888889f, 0.062500f }, // 220 (1 4 9 2)
	{ 3.888889f, 5.888889f, 3.111111f, 0.075630f }, // 221 (1 4 10 1)
	{ 4.000000f, 5.333333f, 3.333333f, 0.097826f }, // 222 (1 4 11 0)
	{ 3.222222f, 10.555555f, 1.111111f, 0.030508f }, // 223 (1 5 0 10)
	{ 3.333333f, 10.000000f, 1.333333f, 0.031690f }, // 224 (1 5 1 9)
	{ 3.444444f, 9.444445f, 1.555556f, 0.033210f }, // 225 (1 5 2 8)
	{ 3.555556f, 8.888889f, 1.777778f, 0.035156f }, // 226 (1 5 3 7)
	{ 3.666667f, 8.333333f, 2.000000f, 0.037657f }, // 227 (1 5 4 6)
	{ 3.777778f, 7.777778f, 2.222222f, 0.040909f }, // 228 (1 5 5 5)
	{ 3.888889f, 7.222222f, 2.444444f, 0.045226f }, // 229 (1 5 6 4)
	{ 4.000000f, 6.666667f, 2.666667f, 0.051136f }, // 230 (1 5 7 3)
	{ 4.111111f, 6.111111f, 2.888889f, 0.059603f }, // 231 (1 5 8 2)
	{ 4.222222f, 5.555556f, 3.111111f, 0.072581f }, // 232 (1 5 9 1)
	{ 4.333333f, 5.000000f, 3.333333f, 0.094737f }, // 233 (1 5 10 0)
	{ 3.666667f, 9.666667f, 1.333333f, 0.029703f }, // 234 (1 6 0 9)
	{ 3.777778f, 9.111111f, 1.555556f, 0.031250f }, // 235 (1 6 1 8)
	{ 3.888889f, 8.555555f, 1.777778f, 0.033210f }, // 236 (1 6 2 7)
	{ 4.000000f, 8.000000f, 2.000000f, 0.035714f }, // 237 (1 6 3 6)
	{ 4.111111f, 7.444445f, 2.222222f, 0.038961f }, // 238 (1 6 4 5)
	{ 4.222222f, 6.888889f, 2.444444f, 0.043269f }, // 239 (1 6 5 4)
	{ 4.333333f, 6.333333f, 2.666667f, 0.049180f }, // 240 (1 6 6 3)
	{ 4.444445f, 5.777778f, 2.888889f, 0.057692f }, // 241 (1 6 7 2)
	{ 4.555555f, 5.222222f, 3.111111f, 0.070866f }, // 242 (1 6 8 1)
	{ 4.666667f, 4.666667f, 3.333333f, 0.093750f }, // 243 (1 6 9 0)
	{ 4.111111f, 8.777778f, 1.555556f, 0.029703f }, // 244 (1 7 0 8)
	{ 4.222222f, 8.222222f, 1.777778f, 0.031690f }, // 245 (1 7 1 7)
	{ 4.333333f, 7.666667f, 2.000000f, 0.034221f }, // 246 (1 7 2 6)
	{ 4.444445f, 7.111111f, 2.222222f, 0.037500f }, // 247 (1 7 3 5)
	{ 4.555555f, 6.555555f, 2.444444f, 0.041860f }, // 248 (1 7 4 4)
	{ 4.666667f, 6.000000f, 2.666667f, 0.047872f }, // 249 (1 7 5 3)
	{ 4.777778f, 5.444445f, 2.888889f, 0.056604f }, // 250 (1 7 6 2)
	{ 4.888889f, 4.888889f, 3.111111f, 0.070313f }, // 251 (1 7 7 1)
	{ 5.000000f, 4.333333f, 3.333333f, 0.094737f }, // 252 (1 7 8 0)
	{ 4.555555f, 7.888889f, 1.777778f, 0.030508f }, // 253 (1 8 0 7)
	{ 4.666667f, 7.333333f, 2.000000f, 0.033088f }, // 254 (1 8 1 6)
	{ 4.777778f, 6.777778f, 2.222222f, 0.036437f }, // 255 (1 8 2 5)
	{ 4.888889f, 6.222222f, 2.444444f, 0.040909f }, // 256 (1 8 3 4)
	{ 5.000000f, 5.666667f, 2.666667f, 0.047120f }, // 257 (1 8 4 3)
	{ 5.111111f, 5.111111f, 2.888889f, 0.056250f }, // 258 (1 8 5 2)
	{ 5.222222f, 4.555555f, 3.111111f, 0.070866f }, // 259 (1 8 6 1)
	{ 5.333333f, 4.000000f, 3.333333f, 0.097826f }, // 260 (1 8 7 0)
	{ 5.000000f, 7.000000f, 2.000000f, 0.032258f }, // 261 (1 9 0 6)
	{ 5.111111f, 6.444445f, 2.222222f, 0.035714f }, // 262 (1 9 1 5)
	{ 5.222222f, 5.888889f, 2.444444f, 0.040359f }, // 263 (1 9 2 4)
	{ 5.333333f, 5.333333f, 2.666667f, 0.046875f }, // 264 (1 9 3 3)
	{ 5.444445f, 4.777778f, 2.888889f, 0.056604f }, // 265 (1 9 4 2)
	{ 5.555556f, 4.222222f, 3.111111f, 0.072581f }, // 266 (1 9 5 1)
	{ 5.666667f, 3.666667f, 3.333333f, 0.103448f }, // 267 (1 9 6 0)
	{ 5.444445f, 6.111111f, 2.222222f, 0.035294f }, // 268 (1 10 0 5)
	{ 5.555556f, 5.555555f, 2.444444f, 0.040179f }, // 269 (1 10 1 4)
	{ 5.666667f, 5.000000f, 2.666667f, 0.047120f }, // 270 (1 10 2 3)
	{ 5.777778f, 4.444445f, 2.888889f, 0.057692f }, // 271 (1 10 3 2)
	{ 5.888889f, 3.888889f, 3.111111f, 0.075630f }, // 272 (1 10 4 1)
	{ 6.000000f, 3.333333f, 3.333333f, 0.112500f }, // 273 (1 10 5 0)
	{ 5.888889f, 5.222222f, 2.444444f, 0.040359f }, // 274 (1 11 0 4)
	{ 6.000000f, 4.666667f, 2.666667f, 0.047872f }, // 275 (1 11 1 3)
	{ 6.111111f, 4.111111f, 2.888889f, 0.059603f }, // 276 (1 11 2 2)
	{ 6.222222f, 3.555556f, 3.111111f, 0.080357f }, // 277 (1 11 3 1)
	{ 6.333333f, 3.000000f, 3.333333f, 0.126761f }, // 278 (1 11 4 0)
	{ 6.333333f, 4.333333f, 2.666667f, 0.049180f }, // 279 (1 12 0 3)
	{ 6.444445f, 3.777778f, 2.888889f, 0.062500f }, // 280 (1 12 1 2)
	{ 6.555556f, 3.222222f, 3.111111f, 0.087379f }, // 281 (1 12 2 1)
	{ 6.666667f, 2.666667f, 3.333333f, 0.150000f }, // 282 (1 12 3 0)
	{ 6.777778f, 3.444444f, 2.888889f, 0.066667f }, // 283 (1 13 0 2)
	{ 6.888889f, 2.888889f, 3.111111f, 0.097826f }, // 284 (1 13 1 1)
	{ 7.000000f, 2.333333f, 3.333333f, 0.191489f }, // 285 (1 13 2 0)
	{ 7.222222f, 2.555556f, 3.111111f, 0.113924f }, // 286 (1 14 0 1)
	{ 7.333333f, 2.000000f, 3.333333f, 0.281250f }, // 287 (1 14 1 0)
	{ 7.666667f, 1.666667f, 3.333333f, 0.600000f }, // 288 (1 15 0 0)
	{ 2.000000f, 14.000000f, 0.000000f, 0.035714f }, // 289 (2 0 0 14)
	{ 2.111111f, 13.444445f, 0.222222f, 0.035294f }, // 290 (2 0 1 13)
	{ 2.222222f, 12.888889f, 0.444444f, 0.035156f }, // 291 (2 0 2 12)
	{ 2.333333f, 12.333333f, 0.666667f, 0.035294f }, // 292 (2 0 3 11)
	{ 2.444444f, 11.777778f, 0.888889f, 0.035714f }, // 293 (2 0 4 10)
	{ 2.555556f, 11.222222f, 1.111111f, 0.036437f }, // 294 (2 0 5 9)
	{ 2.666667f, 10.666667f, 1.333333f, 0.037500f }, // 295 (2 0 6 8)
	{ 2.777778f, 10.111111f, 1.555556f, 0.038961f }, // 296 (2 0 7 7)
	{ 2.888889f, 9.555555f, 1.777778f, 0.040909f }, // 297 (2 0 8 6)
	{ 3.000000f, 9.000000f, 2.000000f, 0.043478f }, // 298 (2 0 9 5)
	{ 3.111111f, 8.444445f, 2.222222f, 0.046875f }, // 299 (2 0 10 4)
	{ 3.222222f, 7.888889f, 2.444444f, 0.051429f }, // 300 (2 0 11 3)
	{ 3.333333f, 7.333333f, 2.666667f, 0.057692f }, // 301 (2 0 12 2)
	{ 3.444444f, 6.777778f, 2.888889f, 0.066667f }, // 302 (2 0 13 1)
	{ 3.555556f, 6.222222f, 3.111111f, 0.080357f }, // 303 (2 0 14 0)
	{ 2.444444f, 13.111111f, 0.222222f, 0.031250f }, // 304 (2 1 0 13)
	{ 2.555556f, 12.555555f, 0.444444f, 0.031359f }, // 305 (2 1 1 12)
	{ 2.666667f, 12.000000f, 0.666667f, 0.031690f }, // 306 (2 1 2 11)
	{ 2.777778f, 11.444445f, 0.888889f, 0.032258f }, // 307 (2 1 3 10)
	{ 2.888889f, 10.888889f, 1.111111f, 0.033088f }, // 308 (2 1 4 9)
	{ 3.000000f, 10.333333f, 1.333333f, 0.034221f }, // 309 (2 1 5 8)
	{ 3.111111f, 9.777778f, 1.555556f, 0.035714f }, // 310 (2 1 6 7)
	{ 3.222222f, 9.222222f, 1.777778f, 0.037657f }, // 311 (2 1 7 6)
	{ 3.333333f, 8.666667f, 2.000000f, 0.040179f }, // 312 (2 1 8 5)
	{ 3.444444f, 8.111111f, 2.222222f, 0.043478f }, // 313 (2 1 9 4)
	{ 3.555556f, 7.555556f, 2.444444f, 0.047872f }, // 314 (2 1 10 3)
	{ 3.666667f, 7.000000f, 2.666667f, 0.053892f }, // 315 (2 1 11 2)
	{ 3.777778f, 6.444445f, 2.888889f, 0.062500f }, // 316 (2 1 12 1)
	{ 3.888889f, 5.888889f, 3.111111f, 0.075630f }, // 317 (2 1 13 0)
	{ 2.888889f, 12.222222f, 0.444444f, 0.028481f }, // 318 (2 2 0 12)
	{ 3.000000f, 11.666667f, 0.666667f, 0.028939f }, // 319 (2 2 1 11)
	{ 3.111111f, 11.111111f, 0.888889f, 0.029605f }, // 320 (2 2 2 10)
	{ 3.222222f, 10.555555f, 1.111111f, 0.030508f }, // 321 (2 2 3 9)
	{ 3.333333f, 10.000000f, 1.333333f, 0.031690f }, // 322 (2 2 4 8)
	{ 3.444444f, 9.444445f, 1.555556f, 0.033210f }, // 323 (2 2 5 7)
	{ 3.555556f, 8.888889f, 1.777778f, 0.035156f }, // 324 (2 2 6 6)
	{ 3.666667f, 8.333333f, 2.000000f, 0.037657f }, // 325 (2 2 7 5)
	{ 3.777778f, 7.777778f, 2.222222f, 0.040909f }, // 326 (2 2 8 4)
	{ 3.888889f, 7.222222f, 2.444444f, 0.045226f }, // 327 (2 2 9 3)
	{ 4.000000f, 6.666667f, 2.666667f, 0.051136f }, // 328 (2 2 10 2)
	{ 4.111111f, 6.111111f, 2.888889f, 0.059603f }, // 329 (2 2 11 1)
	{ 4.222222f, 5.555556f, 3.111111f, 0.072581f }, // 330 (2 2 12 0)
	{ 3.333333f, 11.333333f, 0.666667f, 0.026786f }, // 331 (2 3 0 11)
	{ 3.444444f, 10.777778f, 0.888889f, 0.027523f }, // 332 (2 3 1 10)
	{ 3.555556f, 10.222222f, 1.111111f, 0.028481f }, // 333 (2 3 2 9)
	{ 3.666667f, 9.666667f, 1.333333f, 0.029703f }, // 334 (2 3 3 8)
	{ 3.777778f, 9.111111f, 1.555556f, 0.031250f }, // 335 (2 3 4 7)
	{ 3.888889f, 8.555555f, 1.777778f, 0.033210f }, // 336 (2 3 5 6)
	{ 4.000000f, 8.000000f, 2.000000f, 0.035714f }, // 337 (2 3 6 5)
	{ 4.111111f, 7.444445f, 2.222222f, 0.038961f }, // 338 (2 3 7 4)
	{ 4.222222f, 6.888889f, 2.444444f, 0.043269f }, // 339 (2 3 8 3)
	{ 4.333333f, 6.333333f, 2.666667f, 0.049180f }, // 340 (2 3 9 2)
	{ 4.444445f, 5.777778f, 2.888889f, 0.057692f }, // 341 (2 3 10 1)
	{ 4.555555f, 5.222222f, 3.111111f, 0.070866f }, // 342 (2 3 11 0)
	{ 3.777778f, 10.444445f, 0.888889f, 0.025862f }, // 343 (2 4 0 10)
	{ 3.888889f, 9.888889f, 1.111111f, 0.026866f }, // 344 (2 4 1 9)
	{ 4.000000f, 9.333333f, 1.333333f, 0.028125f }, // 345 (2 4 2 8)
	{ 4.111111f, 8.777778f, 1.555556f, 0.029703f }, // 346 (2 4 3 7)
	{ 4.222222f, 8.222222f, 1.777778f, 0.031690f }, // 347 (2 4 4 6)
	{ 4.333333f, 7.666667f, 2.000000f, 0.034221f }, // 348 (2 4 5 5)
	{ 4.444445f, 7.111111f, 2.222222f, 0.037500f }, // 349 (2 4 6 4)
	{ 4.555555f, 6.555555f, 2.444444f, 0.041860f }, // 350 (2 4 7 3)
	{ 4.666667f, 6.000000f, 2.666667f, 0.047872f }, // 351 (2 4 8 2)
	{ 4.777778f, 5.444445f, 2.888889f, 0.056604f }, // 352 (2 4 9 1)
	{ 4.888889f, 4.888889f, 3.111111f, 0.070313f }, // 353 (2 4 10 0)
	{ 4.222222f, 9.555555f, 1.111111f, 0.025568f }, // 354 (2 5 0 9)
	{ 4.333333f, 9.000000f, 1.333333f, 0.026866f }, // 355 (2 5 1 8)
	{ 4.444445f, 8.444445f, 1.555556f, 0.028481f }, // 356 (2 5 2 7)
	{ 4.555555f, 7.888889f, 1.777778f, 0.030508f }, // 357 (2 5 3 6)
	{ 4.666667f, 7.333333f, 2.000000f, 0.033088f }, // 358 (2 5 4 5)
	{ 4.777778f, 6.777778f, 2.222222f, 0.036437f }, // 359 (2 5 5 4)
	{ 4.888889f, 6.222222f, 2.444444f, 0.040909f }, // 360 (2 5 6 3)
	{ 5.000000f, 5.666667f, 2.666667f, 0.047120f }, // 361 (2 5 7 2)
	{ 5.111111f, 5.111111f, 2.888889f, 0.056250f }, // 362 (2 5 8 1)
	{ 5.222222f, 4.555556f, 3.111111f, 0.070866f }, // 363 (2 5 9 0)
	{ 4.666667f, 8.666667f, 1.333333f, 0.025862f }, // 364 (2 6 0 8)
	{ 4.777778f, 8.111111f, 1.555556f, 0.027523f }, // 365 (2 6 1 7)
	{ 4.888889f, 7.555555f, 1.777778f, 0.029605f }, // 366 (2 6 2 6)
	{ 5.000000f, 7.000000f, 2.000000f, 0.032258f }, // 367 (2 6 3 5)
	{ 5.111111f, 6.444445f, 2.222222f, 0.035714f }, // 368 (2 6 4 4)
	{ 5.222222f, 5.888889f, 2.444444f, 0.040359f }, // 369 (2 6 5 3)
	{ 5.333333f, 5.333333f, 2.666667f, 0.046875f }, // 370 (2 6 6 2)
	{ 5.444445f, 4.777778f, 2.888889f, 0.056604f }, // 371 (2 6 7 1)
	{ 5.555555f, 4.222222f, 3.111111f, 0.072581f }, // 372 (2 6 8 0)
	{ 5.111111f, 7.777778f, 1.555556f, 0.026786f }, // 373 (2 7 0 7)
	{ 5.222222f, 7.222222f, 1.777778f, 0.028939f }, // 374 (2 7 1 6)
	{ 5.333333f, 6.666667f, 2.000000f, 0.031690f }, // 375 (2 7 2 5)
	{ 5.444445f, 6.111111f, 2.222222f, 0.035294f }, // 376 (2 7 3 4)
	{ 5.555555f, 5.555555f, 2.444444f, 0.040179f }, // 377 (2 7 4 3)
	{ 5.666667f, 5.000000f, 2.666667f, 0.047120f }, // 378 (2 7 5 2)
	{ 5.777778f, 4.444445f, 2.888889f, 0.057692f }, // 379 (2 7 6 1)
	{ 5.888889f, 3.888889f, 3.111111f, 0.075630f }, // 380 (2 7 7 0)
	{ 5.555555f, 6.888889f, 1.777778f, 0.028481f }, // 381 (2 8 0 6)
	{ 5.666667f, 6.333333f, 2.000000f, 0.031359f }, // 382 (2 8 1 5)
	{ 5.777778f, 5.777778f, 2.222222f, 0.035156f }, // 383 (2 8 2 4)
	{ 5.888889f, 5.222222f, 2.444444f, 0.040359f }, // 384 (2 8 3 3)
	{ 6.000000f, 4.666667f, 2.666667f, 0.047872f }, // 385 (2 8 4 2)
	{ 6.111111f, 4.111111f, 2.888889f, 0.059603f }, // 386 (2 8 5 1)
	{ 6.222222f, 3.555556f, 3.111111f, 0.080357f }, // 387 (2 8 6 0)
	{ 6.000000f, 6.000000f, 2.000000f, 0.031250f }, // 388 (2 9 0 5)
	{ 6.111111f, 5.444445f, 2.222222f, 0.035294f }, // 389 (2 9 1 4)
	{ 6.222222f, 4.888889f, 2.444444f, 0.040909f }, // 390 (2 9 2 3)
	{ 6.333333f, 4.333333f, 2.666667f, 0.049180f }, // 391 (2 9 3 2)
	{ 6.444445f, 3.777778f, 2.888889f, 0.062500f }, // 392 (2 9 4 1)
	{ 6.555556f, 3.222222f, 3.111111f, 0.087379f }, // 393 (2 9 5 0)
	{ 6.444445f, 5.111111f, 2.222222f, 0.035714f }, // 394 (2 10 0 4)
	{ 6.555556f, 4.555555f, 2.444444f, 0.041860f }, // 395 (2 10 1 3)
	{ 6.666667f, 4.000000f, 2.666667f, 0.051136f }, // 396 (2 10 2 2)
	{ 6.777778f, 3.444444f, 2.888889f, 0.066667f }, // 397 (2 10 3 1)
	{ 6.888889f, 2.888889f, 3.111111f, 0.097826f }, // 398 (2 10 4 0)
	{ 6.888889f, 4.222222f, 2.444444f, 0.043269f }, // 399 (2 11 0 3)
	{ 7.000000f, 3.666667f, 2.666667f, 0.053892f }, // 400 (2 11 1 2)
	{ 7.111111f, 3.111111f, 2.888889f, 0.072581f }, // 401 (2 11 2 1)
	{ 7.222222f, 2.555556f, 3.111111f, 0.113924f }, // 402 (2 11 3 0)
	{ 7.333333f, 3.333333f, 2.666667f, 0.057692f }, // 403 (2 12 0 2)
	{ 7.444445f, 2.777778f, 2.888889f, 0.081081f }, // 404 (2 12 1 1)
	{ 7.555556f, 2.222222f, 3.111111f, 0.140625f }, // 405 (2 12 2 0)
	{ 7.777778f, 2.444444f, 2.888889f, 0.093750f }, // 406 (2 13 0 1)
	{ 7.888889f, 1.888889f, 3.111111f, 0.191489f }, // 407 (2 13 1 0)
	{ 8.222222f, 1.555556f, 3.111111f, 0.321429f }, // 408 (2 14 0 0)
	{ 3.000000f, 13.000000f, 0.000000f, 0.025641f }, // 409 (3 0 0 13)
	{ 3.111111f, 12.444445f, 0.222222f, 0.025862f }, // 410 (3 0 1 12)
	{ 3.222222f, 11.888889f, 0.444444f, 0.026239f }, // 411 (3 0 2 11)
	{ 3.333333f, 11.333333f, 0.666667f, 0.026786f }, // 412 (3 0 3 10)
	{ 3.444444f, 10.777778f, 0.888889f, 0.027523f }, // 413 (3 0 4 9)
	{ 3.555556f, 10.222222f, 1.111111f, 0.028481f }, // 414 (3 0 5 8)
	{ 3.666667f, 9.666667f, 1.333333f, 0.029703f }, // 415 (3 0 6 7)
	{ 3.777778f, 9.111111f, 1.555556f, 0.031250f }, // 416 (3 0 7 6)
	{ 3.888889f, 8.555555f, 1.777778f, 0.033210f }, // 417 (3 0 8 5)
	{ 4.000000f, 8.000000f, 2.000000f, 0.035714f }, // 418 (3 0 9 4)
	{ 4.111111f, 7.444445f, 2.222222f, 0.038961f }, // 419 (3 0 10 3)
	{ 4.222222f, 6.888889f, 2.444444f, 0.043269f }, // 420 (3 0 11 2)
	{ 4.333333f, 6.333333f, 2.666667f, 0.049180f }, // 421 (3 0 12 1)
	{ 4.444445f, 5.777778f, 2.888889f, 0.057692f }, // 422 (3 0 13 0)
	{ 3.444444f, 12.111111f, 0.222222f, 0.024000f }, // 423 (3 1 0 12)
	{ 3.555556f, 11.555555f, 0.444444f, 0.024457f }, // 424 (3 1 1 11)
	{ 3.666667f, 11.000000f, 0.666667f, 0.025070f }, // 425 (3 1 2 10)
	{ 3.777778f, 10.444445f, 0.888889f, 0.025862f }, // 426 (3 1 3 9)
	{ 3.888889f, 9.888889f, 1.111111f, 0.026866f }, // 427 (3 1 4 8)
	{ 4.000000f, 9.333333f, 1.333333f, 0.028125f }, // 428 (3 1 5 7)
	{ 4.111111f, 8.777778f, 1.555556f, 0.029703f }, // 429 (3 1 6 6)
	{ 4.222222f, 8.222222f, 1.777778f, 0.031690f }, // 430 (3 1 7 5)
	{ 4.333333f, 7.666667f, 2.000000f, 0.034221f }, // 431 (3 1 8 4)
	{ 4.444445f, 7.111111f, 2.222222f, 0.037500f }, // 432 (3 1 9 3)
	{ 4.555555f, 6.555556f, 2.444444f, 0.041860f }, // 433 (3 1 10 2)
	{ 4.666667f, 6.000000f, 2.666667f, 0.047872f }, // 434 (3 1 11 1)
	{ 4.777778f, 5.444445f, 2.888889f, 0.056604f }, // 435 (3 1 12 0)
	{ 3.888889f, 11.222222f, 0.444444f, 0.023018f }, // 436 (3 2 0 11)
	{ 4.000000f, 10.666667f, 0.666667f, 0.023684f }, // 437 (3 2 1 10)
	{ 4.111111f, 10.111111f, 0.888889f, 0.024523f }, // 438 (3 2 2 9)
	{ 4.222222f, 9.555555f, 1.111111f, 0.025568f }, // 439 (3 2 3 8)
	{ 4.333333f, 9.000000f, 1.333333f, 0.026866f }, // 440 (3 2 4 7)
	{ 4.444445f, 8.444445f, 1.555556f, 0.028481f }, // 441 (3 2 5 6)
	{ 4.555555f, 7.888889f, 1.777778f, 0.030508f }, // 442 (3 2 6 5)
	{ 4.666667f, 7.333333f, 2.000000f, 0.033088f }, // 443 (3 2 7 4)
	{ 4.777778f, 6.777778f, 2.222222f, 0.036437f }, // 444 (3 2 8 3)
	{ 4.888889f, 6.222222f, 2.444444f, 0.040909f }, // 445 (3 2 9 2)
	{ 5.000000f, 5.666667f, 2.666667f, 0.047120f }, // 446 (3 2 10 1)
	{ 5.111111f, 5.111111f, 2.888889f, 0.056250f }, // 447 (3 2 11 0)
	{ 4.333333f, 10.333333f, 0.666667f, 0.022556f }, // 448 (3 3 0 10)
	{ 4.444445f, 9.777778f, 0.888889f, 0.023438f }, // 449 (3 3 1 9)
	{ 4.555555f, 9.222222f, 1.111111f, 0.024523f }, // 450 (3 3 2 8)
	{ 4.666667f, 8.666667f, 1.333333f, 0.025862f }, // 451 (3 3 3 7)
	{ 4.777778f, 8.111111f, 1.555556f, 0.027523f }, // 452 (3 3 4 6)
	{ 4.888889f, 7.555555f, 1.777778f, 0.029605f }, // 453 (3 3 5 5)
	{ 5.000000f, 7.000000f, 2.000000f, 0.032258f }, // 454 (3 3 6 4)
	{ 5.111111f, 6.444445f, 2.222222f, 0.035714f }, // 455 (3 3 7 3)
	{ 5.222222f, 5.888889f, 2.444444f, 0.040359f }, // 456 (3 3 8 2)
	{ 5.333333f, 5.333333f, 2.666667f, 0.046875f }, // 457 (3 3 9 1)
	{ 5.444445f, 4.777778f, 2.888889f, 0.056604f }, // 458 (3 3 10 0)
	{ 4.777778f, 9.444445f, 0.888889f, 0.022556f }, // 459 (3 4 0 9)
	{ 4.888889f, 8.888889f, 1.111111f, 0.023684f }, // 460 (3 4 1 8)
	{ 5.000000f, 8.333333f, 1.333333f, 0.025070f }, // 461 (3 4 2 7)
	{ 5.111111f, 7.777778f, 1.555556f, 0.026786f }, // 462 (3 4 3 6)
	{ 5.222222f, 7.222222f, 1.777778f, 0.028939f }, // 463 (3 4 4 5)
	{ 5.333333f, 6.666667f, 2.000000f, 0.031690f }, // 464 (3 4 5 4)
	{ 5.444445f, 6.111111f, 2.222222f, 0.035294f }, // 465 (3 4 6 3)
	{ 5.555555f, 5.555555f, 2.444444f, 0.040179f }, // 466 (3 4 7 2)
	{ 5.666667f, 5.000000f, 2.666667f, 0.047120f }, // 467 (3 4 8 1)
	{ 5.777778f, 4.444445f, 2.888889f, 0.057692f }, // 468 (3 4 9 0)
	{ 5.222222f, 8.555555f, 1.111111f, 0.023018f }, // 469 (3 5 0 8)
	{ 5.333333f, 8.000000f, 1.333333f, 0.024457f }, // 470 (3 5 1 7)
	{ 5.444445f, 7.444445f, 1.555556f, 0.026239f }, // 471 (3 5 2 6)
	{ 5.555555f, 6.888889f, 1.777778f, 0.028481f }, // 472 (3 5 3 5)
	{ 5.666667f, 6.333333f, 2.000000f, 0.031359f }, // 473 (3 5 4 4)
	{ 5.777778f, 5.777778f, 2.222222f, 0.035156f }, // 474 (3 5 5 3)
	{ 5.888889f, 5.222222f, 2.444444f, 0.040359f }, // 475 (3 5 6 2)
	{ 6.000000f, 4.666667f, 2.666667f, 0.047872f }, // 476 (3 5 7 1)
	{ 6.111111f, 4.111111f, 2.888889f, 0.059603f }, // 477 (3 5 8 0)
	{ 5.666667f, 7.666667f, 1.333333f, 0.024000f }, // 478 (3 6 0 7)
	{ 5.777778f, 7.111111f, 1.555556f, 0.025862f }, // 479 (3 6 1 6)
	{ 5.888889f, 6.555555f, 1.777778f, 0.028213f }, // 480 (3 6 2 5)
	{ 6.000000f, 6.000000f, 2.000000f, 0.031250f }, // 481 (3 6 3 4)
	{ 6.111111f, 5.444445f, 2.222222f, 0.035294f }, // 482 (3 6 4 3)
	{ 6.222222f, 4.888889f, 2.444444f, 0.040909f }, // 483 (3 6 5 2)
	{ 6.333333f, 4.333333f, 2.666667f, 0.049180f }, // 484 (3 6 6 1)
	{ 6.444445f, 3.777778f, 2.888889f, 0.062500f }, // 485 (3 6 7 0)
	{ 6.111111f, 6.777778f, 1.555556f, 0.025641f }, // 486 (3 7 0 6)
	{ 6.222222f, 6.222222f, 1.777778f, 0.028125f }, // 487 (3 7 1 5)
	{ 6.333333f, 5.666667f, 2.000000f, 0.031359f }, // 488 (3 7 2 4)
	{ 6.444445f, 5.111111f, 2.222222f, 0.035714f }, // 489 (3 7 3 3)
	{ 6.555555f, 4.555555f, 2.444444f, 0.041860f }, // 490 (3 7 4 2)
	{ 6.666667f, 4.000000f, 2.666667f, 0.051136f }, // 491 (3 7 5 1)
	{ 6.777778f, 3.444444f, 2.888889f, 0.066667f }, // 492 (3 7 6 0)
	{ 6.555555f, 5.888889f, 1.777778f, 0.028213f }, // 493 (3 8 0 5)
	{ 6.666667f, 5.333333f, 2.000000f, 0.031690f }, // 494 (3 8 1 4)
	{ 6.777778f, 4.777778f, 2.222222f, 0.036437f }, // 495 (3 8 2 3)
	{ 6.888889f, 4.222222f, 2.444444f, 0.043269f }, // 496 (3 8 3 2)
	{ 7.000000f, 3.666667f, 2.666667f, 0.053892f }, // 497 (3 8 4 1)
	{ 7.111111f, 3.111111f, 2.888889f, 0.072581f }, // 498 (3 8 5 0)
	{ 7.000000f, 5.000000f, 2.000000f, 0.032258f }, // 499 (3 9 0 4)
	{ 7.111111f, 4.444445f, 2.222222f, 0.037500f }, // 500 (3 9 1 3)
	{ 7.222222f, 3.888889f, 2.444444f, 0.045226f }, // 501 (3 9 2 2)
	{ 7.333333f, 3.333333f, 2.666667f, 0.057692f }, // 502 (3 9 3 1)
	{ 7.444445f, 2.777778f, 2.888889f, 0.081081f }, // 503 (3 9 4 0)
	{ 7.444445f, 4.111111f, 2.222222f, 0.038961f }, // 504 (3 10 0 3)
	{ 7.555556f, 3.555556f, 2.444444f, 0.047872f }, // 505 (3 10 1 2)
	{ 7.666667f, 3.000000f, 2.666667f, 0.062937f }, // 506 (3 10 2 1)
	{ 7.777778f, 2.444444f, 2.888889f, 0.093750f }, // 507 (3 10 3 0)
	{ 7.888889f, 3.222222f, 2.444444f, 0.051429f }, // 508 (3 11 0 2)
	{ 8.000000f, 2.666667f, 2.666667f, 0.070313f }, // 509 (3 11 1 1)
	{ 8.111111f, 2.111111f, 2.888889f, 0.113924f }, // 510 (3 11 2 0)
	{ 8.333333f, 2.333333f, 2.666667f, 0.081081f }, // 511 (3 12 0 1)
	{ 8.444445f, 1.777778f, 2.888889f, 0.150000f }, // 512 (3 12 1 0)
	{ 8.777778f, 1.444444f, 2.888889f, 0.230769f }, // 513 (3 13 0 0)
	{ 4.000000f, 12.000000f, 0.000000f, 0.020833f }, // 514 (4 0 0 12)
	{ 4.111111f, 11.444445f, 0.222222f, 0.021277f }, // 515 (4 0 1 11)
	{ 4.222222f, 10.888889f, 0.444444f, 0.021845f }, // 516 (4 0 2 10)
	{ 4.333333f, 10.333333f, 0.666667f, 0.022556f }, // 517 (4 0 3 9)
	{ 4.444445f, 9.777778f, 0.888889f, 0.023438f }, // 518 (4 0 4 8)
	{ 4.555555f, 9.222222f, 1.111111f, 0.024523f }, // 519 (4 0 5 7)
	{ 4.666667f, 8.666667f, 1.333333f, 0.025862f }, // 520 (4 0 6 6)
	{ 4.777778f, 8.111111f, 1.555556f, 0.027523f }, // 521 (4 0 7 5)
	{ 4.888889f, 7.555555f, 1.777778f, 0.029605f }, // 522 (4 0 8 4)
	{ 5.000000f, 7.000000f, 2.000000f, 0.032258f }, // 523 (4 0 9 3)
	{ 5.111111f, 6.444445f, 2.222222f, 0.035714f }, // 524 (4 0 10 2)
	{ 5.222222f, 5.888889f, 2.444444f, 0.040359f }, // 525 (4 0 11 1)
	{ 5.333333f, 5.333333f, 2.666667f, 0.046875f }, // 526 (4 0 12 0)
	{ 4.444445f, 11.111111f, 0.222222f, 0.020270f }, // 527 (4 1 0 11)
	{ 4.555555f, 10.555555f, 0.444444f, 0.020882f }, // 528 (4 1 1 10)
	{ 4.666667f, 10.000000f, 0.666667f, 0.021635f }, // 529 (4 1 2 9)
	{ 4.777778f, 9.444445f, 0.888889f, 0.022556f }, // 530 (4 1 3 8)
	{ 4.888889f, 8.888889f, 1.111111f, 0.023684f }, // 531 (4 1 4 7)
	{ 5.000000f, 8.333333f, 1.333333f, 0.025070f }, // 532 (4 1 5 6)
	{ 5.111111f, 7.777778f, 1.555556f, 0.026786f }, // 533 (4 1 6 5)
	{ 5.222222f, 7.222222f, 1.777778f, 0.028939f }, // 534 (4 1 7 4)
	{ 5.333333f, 6.666667f, 2.000000f, 0.031690f }, // 535 (4 1 8 3)
	{ 5.444445f, 6.111111f, 2.222222f, 0.035294f }, // 536 (4 1 9 2)
	{ 5.555555f, 5.555556f, 2.444444f, 0.040179f }, // 537 (4 1 10 1)
	{ 5.666667f, 5.000000f, 2.666667f, 0.047120f }, // 538 (4 1 11 0)
	{ 4.888889f, 10.222222f, 0.444444f, 0.020089f }, // 539 (4 2 0 10)
	{ 5.000000f, 9.666667f, 0.666667f, 0.020882f }, // 540 (4 2 1 9)
	{ 5.111111f, 9.111111f, 0.888889f, 0.021845f }, // 541 (4 2 2 8)
	{ 5.222222f, 8.555555f, 1.111111f, 0.023018f }, // 542 (4 2 3 7)
	{ 5.333333f, 8.000000f, 1.333333f, 0.024457f }, // 543 (4 2 4 6)
	{ 5.444445f, 7.444445f, 1.555556f, 0.026239f }, // 544 (4 2 5 5)
	{ 5.555555f, 6.888889f, 1.777778f, 0.028481f }, // 545 (4 2 6 4)
	{ 5.666667f, 6.333333f, 2.000000f, 0.031359f }, // 546 (4 2 7 3)
	{ 5.777778f, 5.777778f, 2.222222f, 0.035156f }, // 547 (4 2 8 2)
	{ 5.888889f, 5.222222f, 2.444444f, 0.040359f }, // 548 (4 2 9 1)
	{ 6.000000f, 4.666667f, 2.666667f, 0.047872f }, // 549 (4 2 10 0)
	{ 5.333333f, 9.333333f, 0.666667f, 0.020270f }, // 550 (4 3 0 9)
	{ 5.444445f, 8.777778f, 0.888889f, 0.021277f }, // 551 (4 3 1 8)
	{ 5.555555f, 8.222222f, 1.111111f, 0.022500f }, // 552 (4 3 2 7)
	{ 5.666667f, 7.666667f, 1.333333f, 0.024000f }, // 553 (4 3 3 6)
	{ 5.777778f, 7.111111f, 1.555556f, 0.025862f }, // 554 (4 3 4 5)
	{ 5.888889f, 6.555555f, 1.777778f, 0.028213f }, // 555 (4 3 5 4)
	{ 6.000000f, 6.000000f, 2.000000f, 0.031250f }, // 556 (4 3 6 3)
	{ 6.111111f, 5.444445f, 2.222222f, 0.035294f }, // 557 (4 3 7 2)
	{ 6.222222f, 4.888889f, 2.444444f, 0.040909f }, // 558 (4 3 8 1)
	{ 6.333333f, 4.333333f, 2.666667f, 0.049180f }, // 559 (4 3 9 0)
	{ 5.777778f, 8.444445f, 0.888889f, 0.020833f }, // 560 (4 4 0 8)
	{ 5.888889f, 7.888889f, 1.111111f, 0.022113f }, // 561 (4 4 1 7)
	{ 6.000000f, 7.333333f, 1.333333f, 0.023684f }, // 562 (4 4 2 6)
	{ 6.111111f, 6.777778f, 1.555556f, 0.025641f }, // 563 (4 4 3 5)
	{ 6.222222f, 6.222222f, 1.777778f, 0.028125f }, // 564 (4 4 4 4)
	{ 6.333333f, 5.666667f, 2.000000f, 0.031359f }, // 565 (4 4 5 3)
	{ 6.444445f, 5.111111f, 2.222222f, 0.035714f }, // 566 (4 4 6 2)
	{ 6.555555f, 4.555555f, 2.444444f, 0.041860f }, // 567 (4 4 7 1)
	{ 6.666667f, 4.000000f, 2.666667f, 0.051136f }, // 568 (4 4 8 0)
	{ 6.222222f, 7.555555f, 1.111111f, 0.021845f }, // 569 (4 5 0 7)
	{ 6.333333f, 7.000000f, 1.333333f, 0.023499f }, // 570 (4 5 1 6)
	{ 6.444445f, 6.444445f, 1.555556f, 0.025568f }, // 571 (4 5 2 5)
	{ 6.555555f, 5.888889f, 1.777778f, 0.028213f }, // 572 (4 5 3 4)
	{ 6.666667f, 5.333333f, 2.000000f, 0.031690f }, // 573 (4 5 4 3)
	{ 6.777778f, 4.777778f, 2.222222f, 0.036437f }, // 574 (4 5 5 2)
	{ 6.888889f, 4.222222f, 2.444444f, 0.043269f }, // 575 (4 5 6 1)
	{ 7.000000f, 3.666667f, 2.666667f, 0.053892f }, // 576 (4 5 7 0)
	{ 6.666667f, 6.666667f, 1.333333f, 0.023438f }, // 577 (4 6 0 6)
	{ 6.777778f, 6.111111f, 1.555556f, 0.025641f }, // 578 (4 6 1 5)
	{ 6.888889f, 5.555555f, 1.777778f, 0.028481f }, // 579 (4 6 2 4)
	{ 7.000000f, 5.000000f, 2.000000f, 0.032258f }, // 580 (4 6 3 3)
	{ 7.111111f, 4.444445f, 2.222222f, 0.037500f }, // 581 (4 6 4 2)
	{ 7.222222f, 3.888889f, 2.444444f, 0.045226f }, // 582 (4 6 5 1)
	{ 7.333333f, 3.333333f, 2.666667f, 0.057692f }, // 583 (4 6 6 0)
	{ 7.111111f, 5.777778f, 1.555556f, 0.025862f }, // 584 (4 7 0 5)
	{ 7.222222f, 5.222222f, 1.777778f, 0.028939f }, // 585 (4 7 1 4)
	{ 7.333333f, 4.666667f, 2.000000f, 0.033088f }, // 586 (4 7 2 3)
	{ 7.444445f, 4.111111f, 2.222222f, 0.038961f }, // 587 (4 7 3 2)
	{ 7.555555f, 3.555556f, 2.444444f, 0.047872f }, // 588 (4 7 4 1)
	{ 7.666667f, 3.000000f, 2.666667f, 0.062937f }, // 589 (4 7 5 0)
	{ 7.555555f, 4.888889f, 1.777778f, 0.029605f }, // 590 (4 8 0 4)
	{ 7.666667f, 4.333333f, 2.000000f, 0.034221f }, // 591 (4 8 1 3)
	{ 7.777778f, 3.777778f, 2.222222f, 0.040909f }, // 592 (4 8 2 2)
	{ 7.888889f, 3.222222f, 2.444444f, 0.051429f }, // 593 (4 8 3 1)
	{ 8.000000f, 2.666667f, 2.666667f, 0.070313f }, // 594 (4 8 4 0)
	{ 8.000000f, 4.000000f, 2.000000f, 0.035714f }, // 595 (4 9 0 3)
	{ 8.111111f, 3.444444f, 2.222222f, 0.043478f }, // 596 (4 9 1 2)
	{ 8.222222f, 2.888889f, 2.444444f, 0.056250f }, // 597 (4 9 2 1)
	{ 8.333333f, 2.333333f, 2.666667f, 0.081081f }, // 598 (4 9 3 0)
	{ 8.444445f, 3.111111f, 2.222222f, 0.046875f }, // 599 (4 10 0 2)
	{ 8.555555f, 2.555556f, 2.444444f, 0.062937f }, // 600 (4 10 1 1)
	{ 8.666667f, 2.000000f, 2.666667f, 0.097826f }, // 601 (4 10 2 0)
	{ 8.888889f, 2.222222f, 2.444444f, 0.072581f }, // 602 (4 11 0 1)
	{ 9.000000f, 1.666667f, 2.666667f, 0.126761f }, // 603 (4 11 1 0)
	{ 9.333333f, 1.333333f, 2.666667f, 0.187500f }, // 604 (4 12 0 0)
	{ 5.000000f, 11.000000f, 0.000000f, 0.018182f }, // 605 (5 0 0 11)
	{ 5.111111f, 10.444445f, 0.222222f, 0.018750f }, // 606 (5 0 1 10)
	{ 5.222222f, 9.888889f, 0.444444f, 0.019438f }, // 607 (5 0 2 9)
	{ 5.333333f, 9.333333f, 0.666667f, 0.020270f }, // 608 (5 0 3 8)
	{ 5.444445f, 8.777778f, 0.888889f, 0.021277f }, // 609 (5 0 4 7)
	{ 5.555555f, 8.222222f, 1.111111f, 0.022500f }, // 610 (5 0 5 6)
	{ 5.666667f, 7.666667f, 1.333333f, 0.024000f }, // 611 (5 0 6 5)
	{ 5.777778f, 7.111111f, 1.555556f, 0.025862f }, // 612 (5 0 7 4)
	{ 5.888889f, 6.555555f, 1.777778f, 0.028213f }, // 613 (5 0 8 3)
	{ 6.000000f, 6.000000f, 2.000000f, 0.031250f }, // 614 (5 0 9 2)
	{ 6.111111f, 5.444445f, 2.222222f, 0.035294f }, // 615 (5 0 10 1)
	{ 6.222222f, 4.888889f, 2.444444f, 0.040909f }, // 616 (5 0 11 0)
	{ 5.444445f, 10.111111f, 0.222222f, 0.018182f }, // 617 (5 1 0 10)
	{ 5.555555f, 9.555555f, 0.444444f, 0.018908f }, // 618 (5 1 1 9)
	{ 5.666667f, 9.000000f, 0.666667f, 0.019780f }, // 619 (5 1 2 8)
	{ 5.777778f, 8.444445f, 0.888889f, 0.020833f }, // 620 (5 1 3 7)
	{ 5.888889f, 7.888889f, 1.111111f, 0.022113f }, // 621 (5 1 4 6)
	{ 6.000000f, 7.333333f, 1.333333f, 0.023684f }, // 622 (5 1 5 5)
	{ 6.111111f, 6.777778f, 1.555556f, 0.025641f }, // 623 (5 1 6 4)
	{ 6.222222f, 6.222222f, 1.777778f, 0.028125f }, // 624 (5 1 7 3)
	{ 6.333333f, 5.666667f, 2.000000f, 0.031359f }, // 625 (5 1 8 2)
	{ 6.444445f, 5.111111f, 2.222222f, 0.035714f }, // 626 (5 1 9 1)
	{ 6.555555f, 4.555556f, 2.444444f, 0.041860f }, // 627 (5 1 10 0)
	{ 5.888889f, 9.222222f, 0.444444f, 0.018480f }, // 628 (5 2 0 9)
	{ 6.000000f, 8.666667f, 0.666667f, 0.019397f }, // 629 (5 2 1 8)
	{ 6.111111f, 8.111111f, 0.888889f, 0.020501f }, // 630 (5 2 2 7)
	{ 6.222222f, 7.555555f, 1.111111f, 0.021845f }, // 631 (5 2 3 6)
	{ 6.333333f, 7.000000f, 1.333333f, 0.023499f }, // 632 (5 2 4 5)
	{ 6.444445f, 6.444445f, 1.555556f, 0.025568f }, // 633 (5 2 5 4)
	{ 6.555555f, 5.888889f, 1.777778f, 0.028213f }, // 634 (5 2 6 3)
	{ 6.666667f, 5.333333f, 2.000000f, 0.031690f }, // 635 (5 2 7 2)
	{ 6.777778f, 4.777778f, 2.222222f, 0.036437f }, // 636 (5 2 8 1)
	{ 6.888889f, 4.222222f, 2.444444f, 0.043269f }, // 637 (5 2 9 0)
	{ 6.333333f, 8.333333f, 0.666667f, 0.019108f }, // 638 (5 3 0 8)
	{ 6.444445f, 7.777778f, 0.888889f, 0.020270f }, // 639 (5 3 1 7)
	{ 6.555555f, 7.222222f, 1.111111f, 0.021687f }, // 640 (5 3 2 6)
	{ 6.666667f, 6.666667f, 1.333333f, 0.023438f }, // 641 (5 3 3 5)
	{ 6.777778f, 6.111111f, 1.555556f, 0.025641f }, // 642 (5 3 4 4)
	{ 6.888889f, 5.555555f, 1.777778f, 0.028481f }, // 643 (5 3 5 3)
	{ 7.000000f, 5.000000f, 2.000000f, 0.032258f }, // 644 (5 3 6 2)
	{ 7.111111f, 4.444445f, 2.222222f, 0.037500f }, // 645 (5 3 7 1)
	{ 7.222222f, 3.888889f, 2.444444f, 0.045226f }, // 646 (5 3 8 0)
	{ 6.777778f, 7.444445f, 0.888889f, 0.020134f }, // 647 (5 4 0 7)
	{ 6.888889f, 6.888889f, 1.111111f, 0.021635f }, // 648 (5 4 1 6)
	{ 7.000000f, 6.333333f, 1.333333f, 0.023499f }, // 649 (5 4 2 5)
	{ 7.111111f, 5.777778f, 1.555556f, 0.025862f }, // 650 (5 4 3 4)
	{ 7.222222f, 5.222222f, 1.777778f, 0.028939f }, // 651 (5 4 4 3)
	{ 7.333333f, 4.666667f, 2.000000f, 0.033088f }, // 652 (5 4 5 2)
	{ 7.444445f, 4.111111f, 2.222222f, 0.038961f }, // 653 (5 4 6 1)
	{ 7.555555f, 3.555556f, 2.444444f, 0.047872f }, // 654 (5 4 7 0)
	{ 7.222222f, 6.555555f, 1.111111f, 0.021687f }, // 655 (5 5 0 6)
	{ 7.333333f, 6.000000f, 1.333333f, 0.023684f }, // 656 (5 5 1 5)
	{ 7.444445f, 5.444445f, 1.555556f, 0.026239f }, // 657 (5 5 2 4)
	{ 7.555555f, 4.888889f, 1.777778f, 0.029605f }, // 658 (5 5 3 3)
	{ 7.666667f, 4.333333f, 2.000000f, 0.034221f }, // 659 (5 5 4 2)
	{ 7.777778f, 3.777778f, 2.222222f, 0.040909f }, // 660 (5 5 5 1)
	{ 7.888889f, 3.222222f, 2.444444f, 0.051429f }, // 661 (5 5 6 0)
	{ 7.666667f, 5.666667f, 1.333333f, 0.024000f }, // 662 (5 6 0 5)
	{ 7.777778f, 5.111111f, 1.555556f, 0.026786f }, // 663 (5 6 1 4)
	{ 7.888889f, 4.555555f, 1.777778f, 0.030508f }, // 664 (5 6 2 3)
	{ 8.000000f, 4.000000f, 2.000000f, 0.035714f }, // 665 (5 6 3 2)
	{ 8.111111f, 3.444444f, 2.222222f, 0.043478f }, // 666 (5 6 4 1)
	{ 8.222222f, 2.888889f, 2.444444f, 0.056250f }, // 667 (5 6 5 0)
	{ 8.111111f, 4.777778f, 1.555556f, 0.027523f }, // 668 (5 7 0 4)
	{ 8.222222f, 4.222222f, 1.777778f, 0.031690f }, // 669 (5 7 1 3)
	{ 8.333333f, 3.666667f, 2.000000f, 0.037657f }, // 670 (5 7 2 2)
	{ 8.444445f, 3.111111f, 2.222222f, 0.046875f }, // 671 (5 7 3 1)
	{ 8.555555f, 2.555556f, 2.444444f, 0.062937f }, // 672 (5 7 4 0)
	{ 8.555555f, 3.888889f, 1.777778f, 0.033210f }, // 673 (5 8 0 3)
	{ 8.666667f, 3.333333f, 2.000000f, 0.040179f }, // 674 (5 8 1 2)
	{ 8.777778f, 2.777778f, 2.222222f, 0.051429f }, // 675 (5 8 2 1)
	{ 8.888889f, 2.222222f, 2.444444f, 0.072581f }, // 676 (5 8 3 0)
	{ 9.000000f, 3.000000f, 2.000000f, 0.043478f }, // 677 (5 9 0 2)
	{ 9.111111f, 2.444444f, 2.222222f, 0.057692f }, // 678 (5 9 1 1)
	{ 9.222222f, 1.888889f, 2.444444f, 0.087379f }, // 679 (5 9 2 0)
	{ 9.444445f, 2.111111f, 2.222222f, 0.066667f }, // 680 (5 10 0 1)
	{ 9.555555f, 1.555556f, 2.444444f, 0.112500f }, // 681 (5 10 1 0)
	{ 9.888889f, 1.222222f, 2.444444f, 0.163636f }, // 682 (5 11 0 0)
	{ 6.000000f, 10.000000f, 0.000000f, 0.016667f }, // 683 (6 0 0 10)
	{ 6.111111f, 9.444445f, 0.222222f, 0.017341f }, // 684 (6 0 1 9)
	{ 6.222222f, 8.888889f, 0.444444f, 0.018145f }, // 685 (6 0 2 8)
	{ 6.333333f, 8.333333f, 0.666667f, 0.019108f }, // 686 (6 0 3 7)
	{ 6.444445f, 7.777778f, 0.888889f, 0.020270f }, // 687 (6 0 4 6)
	{ 6.555555f, 7.222222f, 1.111111f, 0.021687f }, // 688 (6 0 5 5)
	{ 6.666667f, 6.666667f, 1.333333f, 0.023438f }, // 689 (6 0 6 4)
	{ 6.777778f, 6.111111f, 1.555556f, 0.025641f }, // 690 (6 0 7 3)
	{ 6.888889f, 5.555555f, 1.777778f, 0.028481f }, // 691 (6 0 8 2)
	{ 7.000000f, 5.000000f, 2.000000f, 0.032258f }, // 692 (6 0 9 1)
	{ 7.111111f, 4.444445f, 2.222222f, 0.037500f }, // 693 (6 0 10 0)
	{ 6.444445f, 9.111111f, 0.222222f, 0.017045f }, // 694 (6 1 0 9)
	{ 6.555555f, 8.555555f, 0.444444f, 0.017893f }, // 695 (6 1 1 8)
	{ 6.666667f, 8.000000f, 0.666667f, 0.018908f }, // 696 (6 1 2 7)
	{ 6.777778f, 7.444445f, 0.888889f, 0.020134f }, // 697 (6 1 3 6)
	{ 6.888889f, 6.888889f, 1.111111f, 0.021635f }, // 698 (6 1 4 5)
	{ 7.000000f, 6.333333f, 1.333333f, 0.023499f }, // 699 (6 1 5 4)
	{ 7.111111f, 5.777778f, 1.555556f, 0.025862f }, // 700 (6 1 6 3)
	{ 7.222222f, 5.222222f, 1.777778f, 0.028939f }, // 701 (6 1 7 2)
	{ 7.333333f, 4.666667f, 2.000000f, 0.033088f }, // 702 (6 1 8 1)
	{ 7.444445f, 4.111111f, 2.222222f, 0.038961f }, // 703 (6 1 9 0)
	{ 6.888889f, 8.222222f, 0.444444f, 0.017717f }, // 704 (6 2 0 8)
	{ 7.000000f, 7.666667f, 0.666667f, 0.018789f }, // 705 (6 2 1 7)
	{ 7.111111f, 7.111111f, 0.888889f, 0.020089f }, // 706 (6 2 2 6)
	{ 7.222222f, 6.555555f, 1.111111f, 0.021687f }, // 707 (6 2 3 5)
	{ 7.333333f, 6.000000f, 1.333333f, 0.023684f }, // 708 (6 2 4 4)
	{ 7.444445f, 5.444445f, 1.555556f, 0.026239f }, // 709 (6 2 5 3)
	{ 7.555555f, 4.888889f, 1.777778f, 0.029605f }, // 710 (6 2 6 2)
	{ 7.666667f, 4.333333f, 2.000000f, 0.034221f }, // 711 (6 2 7 1)
	{ 7.777778f, 3.777778f, 2.222222f, 0.040909f }, // 712 (6 2 8 0)
	{ 7.333333f, 7.333333f, 0.666667f, 0.018750f }, // 713 (6 3 0 7)
	{ 7.444445f, 6.777778f, 0.888889f, 0.020134f }, // 714 (6 3 1 6)
	{ 7.555555f, 6.222222f, 1.111111f, 0.021845f }, // 715 (6 3 2 5)
	{ 7.666667f, 5.666667f, 1.333333f, 0.024000f }, // 716 (6 3 3 4)
	{ 7.777778f, 5.111111f, 1.555556f, 0.026786f }, // 717 (6 3 4 3)
	{ 7.888889f, 4.555555f, 1.777778f, 0.030508f }, // 718 (6 3 5 2)
	{ 8.000000f, 4.000000f, 2.000000f, 0.035714f }, // 719 (6 3 6 1)
	{ 8.111111f, 3.444444f, 2.222222f, 0.043478f }, // 720 (6 3 7 0)
	{ 7.777778f, 6.444445f, 0.888889f, 0.020270f }, // 721 (6 4 0 6)
	{ 7.888889f, 5.888889f, 1.111111f, 0.022113f }, // 722 (6 4 1 5)
	{ 8.000000f, 5.333333f, 1.333333f, 0.024457f }, // 723 (6 4 2 4)
	{ 8.111111f, 4.777778f, 1.555556f, 0.027523f }, // 724 (6 4 3 3)
	{ 8.222222f, 4.222222f, 1.777778f, 0.031690f }, // 725 (6 4 4 2)
	{ 8.333333f, 3.666667f, 2.000000f, 0.037657f }, // 726 (6 4 5 1)
	{ 8.444445f, 3.111111f, 2.222222f, 0.046875f }, // 727 (6 4 6 0)
	{ 8.222222f, 5.555555f, 1.111111f, 0.022500f }, // 728 (6 5 0 5)
	{ 8.333333f, 5.000000f, 1.333333f, 0.025070f }, // 729 (6 5 1 4)
	{ 8.444445f, 4.444445f, 1.555556f, 0.028481f }, // 730 (6 5 2 3)
	{ 8.555555f, 3.888889f, 1.777778f, 0.033210f }, // 731 (6 5 3 2)
	{ 8.666667f, 3.333333f, 2.000000f, 0.040179f }, // 732 (6 5 4 1)
	{ 8.777778f, 2.777778f, 2.222222f, 0.051429f }, // 733 (6 5 5 0)
	{ 8.666667f, 4.666667f, 1.333333f, 0.025862f }, // 734 (6 6 0 4)
	{ 8.777778f, 4.111111f, 1.555556f, 0.029703f }, // 735 (6 6 1 3)
	{ 8.888889f, 3.555556f, 1.777778f, 0.035156f }, // 736 (6 6 2 2)
	{ 9.000000f, 3.000000f, 2.000000f, 0.043478f }, // 737 (6 6 3 1)
	{ 9.111111f, 2.444444f, 2.222222f, 0.057692f }, // 738 (6 6 4 0)
	{ 9.111111f, 3.777778f, 1.555556f, 0.031250f }, // 739 (6 7 0 3)
	{ 9.222222f, 3.222222f, 1.777778f, 0.037657f }, // 740 (6 7 1 2)
	{ 9.333333f, 2.666667f, 2.000000f, 0.047872f }, // 741 (6 7 2 1)
	{ 9.444445f, 2.111111f, 2.222222f, 0.066667f }, // 742 (6 7 3 0)
	{ 9.555555f, 2.888889f, 1.777778f, 0.040909f }, // 743 (6 8 0 2)
	{ 9.666667f, 2.333333f, 2.000000f, 0.053892f }, // 744 (6 8 1 1)
	{ 9.777778f, 1.777778f, 2.222222f, 0.080357f }, // 745 (6 8 2 0)
	{ 10.000000f, 2.000000f, 2.000000f, 0.062500f }, // 746 (6 9 0 1)
	{ 10.111111f, 1.444444f, 2.222222f, 0.103448f }, // 747 (6 9 1 0)
	{ 10.444445f, 1.111111f, 2.222222f, 0.150000f }, // 748 (6 10 0 0)
	{ 7.000000f, 9.000000f, 0.000000f, 0.015873f }, // 749 (7 0 0 9)
	{ 7.111111f, 8.444445f, 0.222222f, 0.016667f }, // 750 (7 0 1 8)
	{ 7.222222f, 7.888889f, 0.444444f, 0.017613f }, // 751 (7 0 2 7)
	{ 7.333333f, 7.333333f, 0.666667f, 0.018750f }, // 752 (7 0 3 6)
	{ 7.444445f, 6.777778f, 0.888889f, 0.020134f }, // 753 (7 0 4 5)
	{ 7.555555f, 6.222222f, 1.111111f, 0.021845f }, // 754 (7 0 5 4)
	{ 7.666667f, 5.666667f, 1.333333f, 0.024000f }, // 755 (7 0 6 3)
	{ 7.777778f, 5.111111f, 1.555556f, 0.026786f }, // 756 (7 0 7 2)
	{ 7.888889f, 4.555555f, 1.777778f, 0.030508f }, // 757 (7 0 8 1)
	{ 8.000000f, 4.000000f, 2.000000f, 0.035714f }, // 758 (7 0 9 0)
	{ 7.444445f, 8.111111f, 0.222222f, 0.016575f }, // 759 (7 1 0 8)
	{ 7.555555f, 7.555555f, 0.444444f, 0.017578f }, // 760 (7 1 1 7)
	{ 7.666667f, 7.000000f, 0.666667f, 0.018789f }, // 761 (7 1 2 6)
	{ 7.777778f, 6.444445f, 0.888889f, 0.020270f }, // 762 (7 1 3 5)
	{ 7.888889f, 5.888889f, 1.111111f, 0.022113f }, // 763 (7 1 4 4)
	{ 8.000000f, 5.333333f, 1.333333f, 0.024457f }, // 764 (7 1 5 3)
	{ 8.111111f, 4.777778f, 1.555556f, 0.027523f }, // 765 (7 1 6 2)
	{ 8.222222f, 4.222222f, 1.777778f, 0.031690f }, // 766 (7 1 7 1)
	{ 8.333333f, 3.666667f, 2.000000f, 0.037657f }, // 767 (7 1 8 0)
	{ 7.888889f, 7.222222f, 0.444444f, 0.017613f }, // 768 (7 2 0 7)
	{ 8.000000f, 6.666667f, 0.666667f, 0.018908f }, // 769 (7 2 1 6)
	{ 8.111111f, 6.111111f, 0.888889f, 0.020501f }, // 770 (7 2 2 5)
	{ 8.222222f, 5.555555f, 1.111111f, 0.022500f }, // 771 (7 2 3 4)
	{ 8.333333f, 5.000000f, 1.333333f, 0.025070f }, // 772 (7 2 4 3)
	{ 8.444445f, 4.444445f, 1.555556f, 0.028481f }, // 773 (7 2 5 2)
	{ 8.555555f, 3.888889f, 1.777778f, 0.033210f }, // 774 (7 2 6 1)
	{ 8.666667f, 3.333333f, 2.000000f, 0.040179f }, // 775 (7 2 7 0)
	{ 8.333333f, 6.333333f, 0.666667f, 0.019108f }, // 776 (7 3 0 6)
	{ 8.444445f, 5.777778f, 0.888889f, 0.020833f }, // 777 (7 3 1 5)
	{ 8.555555f, 5.222222f, 1.111111f, 0.023018f }, // 778 (7 3 2 4)
	{ 8.666667f, 4.666667f, 1.333333f, 0.025862f }, // 779 (7 3 3 3)
	{ 8.777778f, 4.111111f, 1.555556f, 0.029703f }, // 780 (7 3 4 2)
	{ 8.888889f, 3.555556f, 1.777778f, 0.035156f }, // 781 (7 3 5 1)
	{ 9.000000f, 3.000000f, 2.000000f, 0.043478f }, // 782 (7 3 6 0)
	{ 8.777778f, 5.444445f, 0.888889f, 0.021277f }, // 783 (7 4 0 5)
	{ 8.888889f, 4.888889f, 1.111111f, 0.023684f }, // 784 (7 4 1 4)
	{ 9.000000f, 4.333333f, 1.333333f, 0.026866f }, // 785 (7 4 2 3)
	{ 9.111111f, 3.777778f, 1.555556f, 0.031250f }, // 786 (7 4 3 2)
	{ 9.222222f, 3.222222f, 1.777778f, 0.037657f }, // 787 (7 4 4 1)
	{ 9.333333f, 2.666667f, 2.000000f, 0.047872f }, // 788 (7 4 5 0)
	{ 9.222222f, 4.555555f, 1.111111f, 0.024523f }, // 789 (7 5 0 4)
	{ 9.333333f, 4.000000f, 1.333333f, 0.028125f }, // 790 (7 5 1 3)
	{ 9.444445f, 3.444444f, 1.555556f, 0.033210f }, // 791 (7 5 2 2)
	{ 9.555555f, 2.888889f, 1.777778f, 0.040909f }, // 792 (7 5 3 1)
	{ 9.666667f, 2.333333f, 2.000000f, 0.053892f }, // 793 (7 5 4 0)
	{ 9.666667f, 3.666667f, 1.333333f, 0.029703f }, // 794 (7 6 0 3)
	{ 9.777778f, 3.111111f, 1.555556f, 0.035714f }, // 795 (7 6 1 2)
	{ 9.888889f, 2.555556f, 1.777778f, 0.045226f }, // 796 (7 6 2 1)
	{ 10.000000f, 2.000000f, 2.000000f, 0.062500f }, // 797 (7 6 3 0)
	{ 10.111111f, 2.777778f, 1.555556f, 0.038961f }, // 798 (7 7 0 2)
	{ 10.222222f, 2.222222f, 1.777778f, 0.051136f }, // 799 (7 7 1 1)
	{ 10.333333f, 1.666667f, 2.000000f, 0.075630f }, // 800 (7 7 2 0)
	{ 10.555555f, 1.888889f, 1.777778f, 0.059603f }, // 801 (7 8 0 1)
	{ 10.666667f, 1.333333f, 2.000000f, 0.097826f }, // 802 (7 8 1 0)
	{ 11.000000f, 1.000000f, 2.000000f, 0.142857f }, // 803 (7 9 0 0)
	{ 8.000000f, 8.000000f, 0.000000f, 0.015625f }, // 804 (8 0 0 8)
	{ 8.111111f, 7.444445f, 0.222222f, 0.016575f }, // 805 (8 0 1 7)
	{ 8.222222f, 6.888889f, 0.444444f, 0.017717f }, // 806 (8 0 2 6)
	{ 8.333333f, 6.333333f, 0.666667f, 0.019108f }, // 807 (8 0 3 5)
	{ 8.444445f, 5.777778f, 0.888889f, 0.020833f }, // 808 (8 0 4 4)
	{ 8.555555f, 5.222222f, 1.111111f, 0.023018f }, // 809 (8 0 5 3)
	{ 8.666667f, 4.666667f, 1.333333f, 0.025862f }, // 810 (8 0 6 2)
	{ 8.777778f, 4.111111f, 1.555556f, 0.029703f }, // 811 (8 0 7 1)
	{ 8.888889f, 3.555556f, 1.777778f, 0.035156f }, // 812 (8 0 8 0)
	{ 8.444445f, 7.111111f, 0.222222f, 0.016667f }, // 813 (8 1 0 7)
	{ 8.555555f, 6.555555f, 0.444444f, 0.017893f }, // 814 (8 1 1 6)
	{ 8.666667f, 6.000000f, 0.666667f, 0.019397f }, // 815 (8 1 2 5)
	{ 8.777778f, 5.444445f, 0.888889f, 0.021277f }, // 816 (8 1 3 4)
	{ 8.888889f, 4.888889f, 1.111111f, 0.023684f }, // 817 (8 1 4 3)
	{ 9.000000f, 4.333333f, 1.333333f, 0.026866f }, // 818 (8 1 5 2)
	{ 9.111111f, 3.777778f, 1.555556f, 0.031250f }, // 819 (8 1 6 1)
	{ 9.222222f, 3.222222f, 1.777778f, 0.037657f }, // 820 (8 1 7 0)
	{ 8.888889f, 6.222222f, 0.444444f, 0.018145f }, // 821 (8 2 0 6)
	{ 9.000000f, 5.666667f, 0.666667f, 0.019780f }, // 822 (8 2 1 5)
	{ 9.111111f, 5.111111f, 0.888889f, 0.021845f }, // 823 (8 2 2 4)
	{ 9.222222f, 4.555555f, 1.111111f, 0.024523f }, // 824 (8 2 3 3)
	{ 9.333333f, 4.000000f, 1.333333f, 0.028125f }, // 825 (8 2 4 2)
	{ 9.444445f, 3.444444f, 1.555556f, 0.033210f }, // 826 (8 2 5 1)
	{ 9.555555f, 2.888889f, 1.777778f, 0.040909f }, // 827 (8 2 6 0)
	{ 9.333333f, 5.333333f, 0.666667f, 0.020270f }, // 828 (8 3 0 5)
	{ 9.444445f, 4.777778f, 0.888889f, 0.022556f }, // 829 (8 3 1 4)
	{ 9.555555f, 4.222222f, 1.111111f, 0.025568f }, // 830 (8 3 2 3)
	{ 9.666667f, 3.666667f, 1.333333f, 0.029703f }, // 831 (8 3 3 2)
	{ 9.777778f, 3.111111f, 1.555556f, 0.035714f }, // 832 (8 3 4 1)
	{ 9.888889f, 2.555556f, 1.777778f, 0.045226f }, // 833 (8 3 5 0)
	{ 9.777778f, 4.444445f, 0.888889f, 0.023438f }, // 834 (8 4 0 4)
	{ 9.888889f, 3.888889f, 1.111111f, 0.026866f }, // 835 (8 4 1 3)
	{ 10.000000f, 3.333333f, 1.333333f, 0.031690f }, // 836 (8 4 2 2)
	{ 10.111111f, 2.777778f, 1.555556f, 0.038961f }, // 837 (8 4 3 1)
	{ 10.222222f, 2.222222f, 1.777778f, 0.051136f }, // 838 (8 4 4 0)
	{ 10.222222f, 3.555556f, 1.111111f, 0.028481f }, // 839 (8 5 0 3)
	{ 10.333333f, 3.000000f, 1.333333f, 0.034221f }, // 840 (8 5 1 2)
	{ 10.444445f, 2.444444f, 1.555556f, 0.043269f }, // 841 (8 5 2 1)
	{ 10.555555f, 1.888889f, 1.777778f, 0.059603f }, // 842 (8 5 3 0)
	{ 10.666667f, 2.666667f, 1.333333f, 0.037500f }, // 843 (8 6 0 2)
	{ 10.777778f, 2.111111f, 1.555556f, 0.049180f }, // 844 (8 6 1 1)
	{ 10.888889f, 1.555556f, 1.777778f, 0.072581f }, // 845 (8 6 2 0)
	{ 11.111111f, 1.777778f, 1.555556f, 0.057692f }, // 846 (8 7 0 1)
	{ 11.222222f, 1.222222f, 1.777778f, 0.094737f }, // 847 (8 7 1 0)
	{ 11.555555f, 0.888889f, 1.777778f, 0.140625f }, // 848 (8 8 0 0)
	{ 9.000000f, 7.000000f, 0.000000f, 0.015873f }, // 849 (9 0 0 7)
	{ 9.111111f, 6.444445f, 0.222222f, 0.017045f }, // 850 (9 0 1 6)
	{ 9.222222f, 5.888889f, 0.444444f, 0.018480f }, // 851 (9 0 2 5)
	{ 9.333333f, 5.333333f, 0.666667f, 0.020270f }, // 852 (9 0 3 4)
	{ 9.444445f, 4.777778f, 0.888889f, 0.022556f }, // 853 (9 0 4 3)
	{ 9.555555f, 4.222222f, 1.111111f, 0.025568f }, // 854 (9 0 5 2)
	{ 9.666667f, 3.666667f, 1.333333f, 0.029703f }, // 855 (9 0 6 1)
	{ 9.777778f, 3.111111f, 1.555556f, 0.035714f }, // 856 (9 0 7 0)
	{ 9.444445f, 6.111111f, 0.222222f, 0.017341f }, // 857 (9 1 0 6)
	{ 9.555555f, 5.555555f, 0.444444f, 0.018908f }, // 858 (9 1 1 5)
	{ 9.666667f, 5.000000f, 0.666667f, 0.020882f }, // 859 (9 1 2 4)
	{ 9.777778f, 4.444445f, 0.888889f, 0.023438f }, // 860 (9 1 3 3)
	{ 9.888889f, 3.888889f, 1.111111f, 0.026866f }, // 861 (9 1 4 2)
	{ 10.000000f, 3.333333f, 1.333333f, 0.031690f }, // 862 (9 1 5 1)
	{ 10.111111f, 2.777778f, 1.555556f, 0.038961f }, // 863 (9 1 6 0)
	{ 9.888889f, 5.222222f, 0.444444f, 0.019438f }, // 864 (9 2 0 5)
	{ 10.000000f, 4.666667f, 0.666667f, 0.021635f }, // 865 (9 2 1 4)
	{ 10.111111f, 4.111111f, 0.888889f, 0.024523f }, // 866 (9 2 2 3)
	{ 10.222222f, 3.555556f, 1.111111f, 0.028481f }, // 867 (9 2 3 2)
	{ 10.333333f, 3.000000f, 1.333333f, 0.034221f }, // 868 (9 2 4 1)
	{ 10.444445f, 2.444444f, 1.555556f, 0.043269f }, // 869 (9 2 5 0)
	{ 10.333333f, 4.333333f, 0.666667f, 0.022556f }, // 870 (9 3 0 4)
	{ 10.444445f, 3.777778f, 0.888889f, 0.025862f }, // 871 (9 3 1 3)
	{ 10.555555f, 3.222222f, 1.111111f, 0.030508f }, // 872 (9 3 2 2)
	{ 10.666667f, 2.666667f, 1.333333f, 0.037500f }, // 873 (9 3 3 1)
	{ 10.777778f, 2.111111f, 1.555556f, 0.049180f }, // 874 (9 3 4 0)
	{ 10.777778f, 3.444444f, 0.888889f, 0.027523f }, // 875 (9 4 0 3)
	{ 10.888889f, 2.888889f, 1.111111f, 0.033088f }, // 876 (9 4 1 2)
	{ 11.000000f, 2.333333f, 1.333333f, 0.041860f }, // 877 (9 4 2 1)
	{ 11.111111f, 1.777778f, 1.555556f, 0.057692f }, // 878 (9 4 3 0)
	{ 11.222222f, 2.555556f, 1.111111f, 0.036437f }, // 879 (9 5 0 2)
	{ 11.333333f, 2.000000f, 1.333333f, 0.047872f }, // 880 (9 5 1 1)
	{ 11.444445f, 1.444444f, 1.555556f, 0.070866f }, // 881 (9 5 2 0)
	{ 11.666667f, 1.666667f, 1.333333f, 0.056604f }, // 882 (9 6 0 1)
	{ 11.777778f, 1.111111f, 1.555556f, 0.093750f }, // 883 (9 6 1 0)
	{ 12.111111f, 0.777778f, 1.555556f, 0.142857f }, // 884 (9 7 0 0)
	{ 10.000000f, 6.000000f, 0.000000f, 0.016667f }, // 885 (10 0 0 6)
	{ 10.111111f, 5.444445f, 0.222222f, 0.018182f }, // 886 (10 0 1 5)
	{ 10.222222f, 4.888889f, 0.444444f, 0.020089f }, // 887 (10 0 2 4)
	{ 10.333333f, 4.333333f, 0.666667f, 0.022556f }, // 888 (10 0 3 3)
	{ 10.444445f, 3.777778f, 0.888889f, 0.025862f }, // 889 (10 0 4 2)
	{ 10.555555f, 3.222222f, 1.111111f, 0.030508f }, // 890 (10 0 5 1)
	{ 10.666667f, 2.666667f, 1.333333f, 0.037500f }, // 891 (10 0 6 0)
	{ 10.444445f, 5.111111f, 0.222222f, 0.018750f }, // 892 (10 1 0 5)
	{ 10.555555f, 4.555555f, 0.444444f, 0.020882f }, // 893 (10 1 1 4)
	{ 10.666667f, 4.000000f, 0.666667f, 0.023684f }, // 894 (10 1 2 3)
	{ 10.777778f, 3.444444f, 0.888889f, 0.027523f }, // 895 (10 1 3 2)
	{ 10.888889f, 2.888889f, 1.111111f, 0.033088f }, // 896 (10 1 4 1)
	{ 11.000000f, 2.333333f, 1.333333f, 0.041860f }, // 897 (10 1 5 0)
	{ 10.888889f, 4.222222f, 0.444444f, 0.021845f }, // 898 (10 2 0 4)
	{ 11.000000f, 3.666667f, 0.666667f, 0.025070f }, // 899 (10 2 1 3)
	{ 11.111111f, 3.111111f, 0.888889f, 0.029605f }, // 900 (10 2 2 2)
	{ 11.222222f, 2.555556f, 1.111111f, 0.036437f }, // 901 (10 2 3 1)
	{ 11.333333f, 2.000000f, 1.333333f, 0.047872f }, // 902 (10 2 4 0)
	{ 11.333333f, 3.333333f, 0.666667f, 0.026786f }, // 903 (10 3 0 3)
	{ 11.444445f, 2.777778f, 0.888889f, 0.032258f }, // 904 (10 3 1 2)
	{ 11.555555f, 2.222222f, 1.111111f, 0.040909f }, // 905 (10 3 2 1)
	{ 11.666667f, 1.666667f, 1.333333f, 0.056604f }, // 906 (10 3 3 0)
	{ 11.777778f, 2.444444f, 0.888889f, 0.035714f }, // 907 (10 4 0 2)
	{ 11.888889f, 1.888889f, 1.111111f, 0.047120f }, // 908 (10 4 1 1)
	{ 12.000000f, 1.333333f, 1.333333f, 0.070313f }, // 909 (10 4 2 0)
	{ 12.222222f, 1.555556f, 1.111111f, 0.056250f }, // 910 (10 5 0 1)
	{ 12.333333f, 1.000000f, 1.333333f, 0.094737f }, // 911 (10 5 1 0)
	{ 12.666667f, 0.666667f, 1.333333f, 0.150000f }, // 912 (10 6 0 0)
	{ 11.000000f, 5.000000f, 0.000000f, 0.018182f }, // 913 (11 0 0 5)
	{ 11.111111f, 4.444445f, 0.222222f, 0.020270f }, // 914 (11 0 1 4)
	{ 11.222222f, 3.888889f, 0.444444f, 0.023018f }, // 915 (11 0 2 3)
	{ 11.333333f, 3.333333f, 0.666667f, 0.026786f }, // 916 (11 0 3 2)
	{ 11.444445f, 2.777778f, 0.888889f, 0.032258f }, // 917 (11 0 4 1)
	{ 11.555555f, 2.222222f, 1.111111f, 0.040909f }, // 918 (11 0 5 0)
	{ 11.444445f, 4.111111f, 0.222222f, 0.021277f }, // 919 (11 1 0 4)
	{ 11.555555f, 3.555556f, 0.444444f, 0.024457f }, // 920 (11 1 1 3)
	{ 11.666667f, 3.000000f, 0.666667f, 0.028939f }, // 921 (11 1 2 2)
	{ 11.777778f, 2.444444f, 0.888889f, 0.035714f }, // 922 (11 1 3 1)
	{ 11.888889f, 1.888889f, 1.111111f, 0.047120f }, // 923 (11 1 4 0)
	{ 11.888889f, 3.222222f, 0.444444f, 0.026239f }, // 924 (11 2 0 3)
	{ 12.000000f, 2.666667f, 0.666667f, 0.031690f }, // 925 (11 2 1 2)
	{ 12.111111f, 2.111111f, 0.888889f, 0.040359f }, // 926 (11 2 2 1)
	{ 12.222222f, 1.555556f, 1.111111f, 0.056250f }, // 927 (11 2 3 0)
	{ 12.333333f, 2.333333f, 0.666667f, 0.035294f }, // 928 (11 3 0 2)
	{ 12.444445f, 1.777778f, 0.888889f, 0.046875f }, // 929 (11 3 1 1)
	{ 12.555555f, 1.222222f, 1.111111f, 0.070866f }, // 930 (11 3 2 0)
	{ 12.777778f, 1.444444f, 0.888889f, 0.056604f }, // 931 (11 4 0 1)
	{ 12.888889f, 0.888889f, 1.111111f, 0.097826f }, // 932 (11 4 1 0)
	{ 13.222222f, 0.555556f, 1.111111f, 0.163636f }, // 933 (11 5 0 0)
	{ 12.000000f, 4.000000f, 0.000000f, 0.020833f }, // 934 (12 0 0 4)
	{ 12.111111f, 3.444444f, 0.222222f, 0.024000f }, // 935 (12 0 1 3)
	{ 12.222222f, 2.888889f, 0.444444f, 0.028481f }, // 936 (12 0 2 2)
	{ 12.333333f, 2.333333f, 0.666667f, 0.035294f }, // 937 (12 0 3 1)
	{ 12.444445f, 1.777778f, 0.888889f, 0.046875f }, // 938 (12 0 4 0)
	{ 12.444445f, 3.111111f, 0.222222f, 0.025862f }, // 939 (12 1 0 3)
	{ 12.555555f, 2.555556f, 0.444444f, 0.031359f }, // 940 (12 1 1 2)
	{ 12.666667f, 2.000000f, 0.666667f, 0.040179f }, // 941 (12 1 2 1)
	{ 12.777778f, 1.444444f, 0.888889f, 0.056604f }, // 942 (12 1 3 0)
	{ 12.888889f, 2.222222f, 0.444444f, 0.035156f }, // 943 (12 2 0 2)
	{ 13.000000f, 1.666667f, 0.666667f, 0.047120f }, // 944 (12 2 1 1)
	{ 13.111111f, 1.111111f, 0.888889f, 0.072581f }, // 945 (12 2 2 0)
	{ 13.333333f, 1.333333f, 0.666667f, 0.057692f }, // 946 (12 3 0 1)
	{ 13.444445f, 0.777778f, 0.888889f, 0.103448f }, // 947 (12 3 1 0)
	{ 13.777778f, 0.444444f, 0.888889f, 0.187500f }, // 948 (12 4 0 0)
	{ 13.000000f, 3.000000f, 0.000000f, 0.025641f }, // 949 (13 0 0 3)
	{ 13.111111f, 2.444444f, 0.222222f, 0.031250f }, // 950 (13 0 1 2)
	{ 13.222222f, 1.888889f, 0.444444f, 0.040359f }, // 951 (13 0 2 1)
	{ 13.333333f, 1.333333f, 0.666667f, 0.057692f }, // 952 (13 0 3 0)
	{ 13.444445f, 2.111111f, 0.222222f, 0.035294f }, // 953 (13 1 0 2)
	{ 13.555555f, 1.555556f, 0.444444f, 0.047872f }, // 954 (13 1 1 1)
	{ 13.666667f, 1.000000f, 0.666667f, 0.075630f }, // 955 (13 1 2 0)
	{ 13.888889f, 1.222222f, 0.444444f, 0.059603f }, // 956 (13 2 0 1)
	{ 14.000000f, 0.666667f, 0.666667f, 0.112500f }, // 957 (13 2 1 0)
	{ 14.333333f, 0.333333f, 0.666667f, 0.230769f }, // 958 (13 3 0 0)
	{ 14.000000f, 2.000000f, 0.000000f, 0.035714f }, // 959 (14 0 0 2)
	{ 14.111111f, 1.444444f, 0.222222f, 0.049180f }, // 960 (14 0 1 1)
	{ 14.222222f, 0.888889f, 0.444444f, 0.080357f }, // 961 (14 0 2 0)
	{ 14.444445f, 1.111111f, 0.222222f, 0.062500f }, // 962 (14 1 0 1)
	{ 14.555555f, 0.555556f, 0.444444f, 0.126761f }, // 963 (14 1 1 0)
	{ 14.888889f, 0.222222f, 0.444444f, 0.321429f }, // 964 (14 2 0 0)
	{ 15.000000f, 1.000000f, 0.000000f, 0.066667f }, // 965 (15 0 0 1)
	{ 15.111111f, 0.444444f, 0.222222f, 0.150000f }, // 966 (15 0 1 0)
	{ 15.444445f, 0.111111f, 0.222222f, 0.600000f }, // 967 (15 1 0 0)
	{ 16.000000f, 0.000000f, 0.000000f, FLT_MAX }, // 968 (16 0 0 0)
}; // 969 four cluster elements



<|start_filename|>src/nvthread/ThreadPool.cpp<|end_filename|>
// This code is in the public domain -- <EMAIL>

#include "ThreadPool.h"
#include "Mutex.h"
#include "Thread.h"
#include "Atomic.h"

#include "nvcore/Utils.h"
#include "nvcore/StrLib.h"

#if NV_USE_TELEMETRY3
#include <rad_tm.h>
#elif NV_USE_TELEMETRY
#include <telemetry.h>
extern HTELEMETRY tmContext;
#endif


// Most of the time it's not necessary to protect the thread pool, but if it doesn't add a significant overhead, then it'd be safer to do it.
#define PROTECT_THREAD_POOL 1


using namespace nv;

#if PROTECT_THREAD_POOL 
Mutex s_pool_mutex("thread pool");
#endif

AutoPtr<ThreadPool> s_pool;


/*static*/ void ThreadPool::setup(uint workerCount, bool useThreadAffinity, bool useCallingThread) {
#if PROTECT_THREAD_POOL 
    Lock<Mutex> lock(s_pool_mutex);
#endif

    s_pool = new ThreadPool(workerCount, useThreadAffinity, useCallingThread);
}

/*static*/ ThreadPool * ThreadPool::acquire()
{
#if PROTECT_THREAD_POOL 
    s_pool_mutex.lock();    // @@ If same thread tries to lock twice, this should assert.
#endif

    if (s_pool == NULL) {
        ThreadPool * p = new ThreadPool;
        nvDebugCheck(s_pool == p);
    }

    return s_pool.ptr();
}

/*static*/ void ThreadPool::release(ThreadPool * pool)
{
    nvDebugCheck(pool == s_pool);

    // Make sure the threads of the pool are idle.
    s_pool->wait();

#if PROTECT_THREAD_POOL 
    s_pool_mutex.unlock();
#endif
}




/*static*/ void ThreadPool::workerFunc(void * arg) {
    uint i = U32((uintptr_t)arg); // This is OK, because workerCount should always be much smaller than 2^32

    //ThreadPool::threadId = i;

    if (s_pool->useThreadAffinity) {
        lockThreadToProcessor(s_pool->useCallingThread + i);
    }

    while(true) 
    {
        s_pool->startEvents[i].wait();

        ThreadTask * func = loadAcquirePointer(&s_pool->func);

        if (func == NULL) {
            return;
        }
        
        {
#if NV_USE_TELEMETRY3
            tmZone(0, TMZF_NONE, "worker");
#elif NV_USE_TELEMETRY
            tmZoneFiltered(tmContext, 20, TMZF_NONE, "worker");
#endif
            func(s_pool->arg, s_pool->useCallingThread + i);
        }

        s_pool->finishEvents[i].post();
    }
}


ThreadPool::ThreadPool(uint workerCount/*=processorCount()*/, bool useThreadAffinity/*=true*/, bool useCallingThread/*=false*/)
{
    s_pool = this;  // Worker threads need this to be initialized before they start.

    this->useThreadAffinity = useThreadAffinity;
    this->workerCount = workerCount;
    this->useCallingThread = useCallingThread;

    uint threadCount = workerCount - useCallingThread;

    workers = new Thread[threadCount];

    startEvents = new Event[threadCount];
    finishEvents = new Event[threadCount];

    nvCompilerWriteBarrier(); // @@ Use a memory fence?

    if (useCallingThread && useThreadAffinity) {
        lockThreadToProcessor(0);   // Calling thread always locked to processor 0.
    }

    StringBuilder name;
    for (uint i = 0; i < threadCount; i++) {
        name.format("worker %d", i);
        workers[i].setName(name.release());     // @Leak
        workers[i].start(workerFunc, (void *)(uintptr_t)i);
    }

    allIdle = true;
}

ThreadPool::~ThreadPool()
{
    // Set threads to terminate.
    start(NULL, NULL);

    // Wait until threads actually exit.
    Thread::wait(workers, workerCount - useCallingThread);

    delete [] workers;
    delete [] startEvents;
    delete [] finishEvents;
}

void ThreadPool::run(ThreadTask * func, void * arg)
{
    start(func, arg);

    if (useCallingThread) {
        func(arg, 0);
    }

    wait();
}

void ThreadPool::start(ThreadTask * func, void * arg)
{
    // Wait until threads are idle.
    wait();

    // Set our desired function.
    storeReleasePointer(&this->func, func);
    storeReleasePointer(&this->arg, arg);

    allIdle = false;

    // Resume threads.
    Event::post(startEvents, workerCount - useCallingThread);
}

void ThreadPool::wait()
{
    if (!allIdle)
    {
        // Wait for threads to complete.
        Event::wait(finishEvents, workerCount - useCallingThread);

        allIdle = true;
    }
}


<|start_filename|>src/nvcore/FileSystem.h<|end_filename|>
// This code is in the public domain -- <EMAIL>

#pragma once
#ifndef NV_CORE_FILESYSTEM_H
#define NV_CORE_FILESYSTEM_H

#include "nvcore.h"

namespace nv
{

    namespace FileSystem
    {
        NVCORE_API bool exists(const char * path);
        NVCORE_API bool createDirectory(const char * path);
        NVCORE_API bool changeDirectory(const char * path);
        NVCORE_API bool removeFile(const char * path);
        NVCORE_API bool copyFile(const char * src, const char * dst);
    } // FileSystem namespace

} // nv namespace


#endif // NV_CORE_FILESYSTEM_H


<|start_filename|>src/nvthread/ThreadPool.h<|end_filename|>
// This code is in the public domain -- <EMAIL>

#pragma once
#ifndef NV_THREAD_THREADPOOL_H
#define NV_THREAD_THREADPOOL_H

#include "nvthread.h"

#include "Event.h"
#include "Thread.h"

// The thread pool creates one worker thread for each physical core. 
// The threads are idle waiting for their start events so that they do not consume any resources while inactive. 
// The thread pool runs the same function in all worker threads, the idea is to use this as the foundation of a custom task scheduler.
// When the thread pool starts, the main thread continues running, but the common use case is to inmmediately wait for the termination events of the worker threads.
// @@ The start and wait methods could probably be merged.
// It may be running the thread function on the invoking thread to avoid thread switches.

namespace nv {

    class Thread;
    class Event;

    typedef void ThreadTask(void * context, int id);

    class ThreadPool {
        NV_FORBID_COPY(ThreadPool);
    public:

        static void setup(uint workerCount, bool useThreadAffinity, bool useCallingThread);

        static ThreadPool * acquire();
        static void release(ThreadPool *);

        ThreadPool(uint workerCount = processorCount(), bool useThreadAffinity = true, bool useCallingThread = false);
        ~ThreadPool();

        void run(ThreadTask * func, void * arg);

        void start(ThreadTask * func, void * arg);
        void wait();

        //NV_THREAD_LOCAL static uint threadId;

    private:

        static void workerFunc(void * arg);

        bool useThreadAffinity;
        bool useCallingThread;
        uint workerCount;

        Thread * workers;
        Event * startEvents;
        Event * finishEvents;

        uint allIdle;

        // Current function:
        ThreadTask * func;
        void * arg;
    };


#if NV_CC_CPP11

    template <typename F>
    void thread_pool_run(F f) {
        // Transform lambda into function pointer.
        auto lambda = [](void* context, int id) {
            F & f = *reinterpret_cast<F *>(context);
            f(id);
        };

        ThreadPool * pool = ThreadPool::acquire();
        pool->run(lambda, &f);
        ThreadPool::release(pool);
    }

#endif // NV_CC_CPP11


} // namespace nv


#endif // NV_THREAD_THREADPOOL_H


<|start_filename|>extern/CMP_Core/test/BlockConstants.h<|end_filename|>
#ifndef BLOCKCONSTANTS_H
#define BLOCKCONSTANTS_H
#include <string>
#include <unordered_map>
struct Block { const unsigned char* data; const unsigned char* color; };
struct BlockBC6 { const unsigned char* data; const float* color; };

static const unsigned char BC1_Red_Ignore_Alpha [] {0x0 , 0xf8, 0x0 , 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC1_Blue_Half_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_White_Half_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_Black_Half_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_Red_Blue_Half_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_Red_Green_Half_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_Green_Blue_Half_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_Red_Full_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_Green_Full_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_Blue_Full_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_White_Full_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_Green_Ignore_Alpha [] {0xe0, 0x7 , 0xe0, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC1_Black_Full_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_Red_Blue_Full_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_Red_Green_Full_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_Green_Blue_Full_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_Blue_Ignore_Alpha [] {0x1f, 0x0 , 0x1f, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC1_White_Ignore_Alpha [] {0xff, 0xff, 0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC1_Black_Ignore_Alpha [] {0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC1_Red_Blue_Ignore_Alpha [] {0x1f, 0xf8, 0x1f, 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC1_Red_Green_Ignore_Alpha [] {0xe0, 0xff, 0xe0, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC1_Green_Blue_Ignore_Alpha [] {0xff, 0x7 , 0xff, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC1_Red_Half_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC1_Green_Half_Alpha [] {0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static const unsigned char BC2_Red_Ignore_Alpha [] {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0 , 0xf8, 0x0 , 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Blue_Half_Alpha [] {0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x1f, 0x0 , 0x1f, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_White_Half_Alpha [] {0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0xff, 0xff, 0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Black_Half_Alpha [] {0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Red_Blue_Half_Alpha [] {0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x1f, 0xf8, 0x1f, 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Red_Green_Half_Alpha [] {0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0xe0, 0xff, 0xe0, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Green_Blue_Half_Alpha [] {0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0xff, 0x7 , 0xff, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Red_Full_Alpha [] {0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xf8, 0x0 , 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Green_Full_Alpha [] {0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xe0, 0x7 , 0xe0, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Blue_Full_Alpha [] {0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x1f, 0x0 , 0x1f, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_White_Full_Alpha [] {0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Green_Ignore_Alpha [] {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7 , 0xe0, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Black_Full_Alpha [] {0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Red_Blue_Full_Alpha [] {0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x1f, 0xf8, 0x1f, 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Red_Green_Full_Alpha [] {0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xe0, 0xff, 0xe0, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Green_Blue_Full_Alpha [] {0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x7 , 0xff, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Blue_Ignore_Alpha [] {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x0 , 0x1f, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_White_Ignore_Alpha [] {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Black_Ignore_Alpha [] {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Red_Blue_Ignore_Alpha [] {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xf8, 0x1f, 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Red_Green_Ignore_Alpha [] {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xe0, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Green_Blue_Ignore_Alpha [] {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7 , 0xff, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Red_Half_Alpha [] {0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x0 , 0xf8, 0x0 , 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC2_Green_Half_Alpha [] {0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0xe0, 0x7 , 0xe0, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Red_Ignore_Alpha [] {0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xf8, 0x0 , 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Blue_Half_Alpha [] {0x7b, 0x7b, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x1f, 0x0 , 0x1f, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_White_Half_Alpha [] {0x7b, 0x7b, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Black_Half_Alpha [] {0x7b, 0x7b, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Red_Blue_Half_Alpha [] {0x7b, 0x7b, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x1f, 0xf8, 0x1f, 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Red_Green_Half_Alpha [] {0x7b, 0x7b, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xe0, 0xff, 0xe0, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Green_Blue_Half_Alpha [] {0x7b, 0x7b, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x7 , 0xff, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Red_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0x0 , 0xf8, 0x0 , 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Green_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xe0, 0x7 , 0xe0, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Blue_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0x1f, 0x0 , 0x1f, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_White_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0xff, 0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Green_Ignore_Alpha [] {0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xe0, 0x7 , 0xe0, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Black_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Red_Blue_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0x1f, 0xf8, 0x1f, 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Red_Green_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xe0, 0xff, 0xe0, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Green_Blue_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0x7 , 0xff, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Blue_Ignore_Alpha [] {0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x1f, 0x0 , 0x1f, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_White_Ignore_Alpha [] {0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0xff, 0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Black_Ignore_Alpha [] {0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Red_Blue_Ignore_Alpha [] {0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x1f, 0xf8, 0x1f, 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Red_Green_Ignore_Alpha [] {0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xe0, 0xff, 0xe0, 0xff, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Green_Blue_Ignore_Alpha [] {0xff, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x7 , 0xff, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Red_Half_Alpha [] {0x7b, 0x7b, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xf8, 0x0 , 0xf8, 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC3_Green_Half_Alpha [] {0x7b, 0x7b, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xe0, 0x7 , 0xe0, 0x7 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC4_Red_Ignore_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC4_Blue_Half_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC4_White_Half_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC4_Black_Half_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC4_Red_Blue_Half_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC4_Red_Green_Half_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC4_Green_Blue_Half_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC4_Red_Full_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC4_Green_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC4_Blue_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC4_White_Full_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC4_Green_Ignore_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC4_Black_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC4_Red_Blue_Full_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC4_Red_Green_Full_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC4_Green_Blue_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC4_Blue_Ignore_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC4_White_Ignore_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC4_Black_Ignore_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC4_Red_Blue_Ignore_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC4_Red_Green_Ignore_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC4_Green_Blue_Ignore_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC4_Red_Half_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC4_Green_Half_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC5_Red_Ignore_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC5_Blue_Half_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC5_White_Half_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC5_Black_Half_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC5_Red_Blue_Half_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC5_Red_Green_Half_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC5_Green_Blue_Half_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC5_Red_Full_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC5_Green_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC5_Blue_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC5_White_Full_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC5_Green_Ignore_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC5_Black_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC5_Red_Blue_Full_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC5_Red_Green_Full_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC5_Green_Blue_Full_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC5_Blue_Ignore_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC5_White_Ignore_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC5_Black_Ignore_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC5_Red_Blue_Ignore_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC5_Red_Green_Ignore_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC5_Green_Blue_Ignore_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC5_Red_Half_Alpha [] {0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24};
static const unsigned char BC5_Green_Half_Alpha [] {0xff, 0x0 , 0x49, 0x92, 0x24, 0x49, 0x92, 0x24, 0xff, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Red_Ignore_Alpha [] {0xe3, 0x3d, 0x0 , 0x0 , 0x78, 0xf , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Blue_Half_Alpha [] {0x3 , 0x0 , 0x0 , 0xde, 0x3 , 0x0 , 0x80, 0xf7, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_White_Half_Alpha [] {0xe3, 0xbd, 0xf7, 0xde, 0x7b, 0xef, 0xbd, 0xf7, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Black_Half_Alpha [] {0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Red_Blue_Half_Alpha [] {0xe3, 0x3d, 0x0 , 0xde, 0x7b, 0xf , 0x80, 0xf7, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Red_Green_Half_Alpha [] {0xe3, 0xbd, 0xf7, 0x0 , 0x78, 0xef, 0x3d, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Green_Blue_Half_Alpha [] {0x3 , 0x80, 0xf7, 0xde, 0x3 , 0xe0, 0xbd, 0xf7, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Red_Full_Alpha [] {0xe3, 0x3d, 0x0 , 0x0 , 0x78, 0xf , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Green_Full_Alpha [] {0x3 , 0x80, 0xf7, 0x0 , 0x0 , 0xe0, 0x3d, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Blue_Full_Alpha [] {0x3 , 0x0 , 0x0 , 0xde, 0x3 , 0x0 , 0x80, 0xf7, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_White_Full_Alpha [] {0xe3, 0xbd, 0xf7, 0xde, 0x7b, 0xef, 0xbd, 0xf7, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Green_Ignore_Alpha [] {0x3 , 0x80, 0xf7, 0x0 , 0x0 , 0xe0, 0x3d, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Black_Full_Alpha [] {0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Red_Blue_Full_Alpha [] {0xe3, 0x3d, 0x0 , 0xde, 0x7b, 0xf , 0x80, 0xf7, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Red_Green_Full_Alpha [] {0xe3, 0xbd, 0xf7, 0x0 , 0x78, 0xef, 0x3d, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Green_Blue_Full_Alpha [] {0x3 , 0x80, 0xf7, 0xde, 0x3 , 0xe0, 0xbd, 0xf7, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Blue_Ignore_Alpha [] {0x3 , 0x0 , 0x0 , 0xde, 0x3 , 0x0 , 0x80, 0xf7, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_White_Ignore_Alpha [] {0xe3, 0xbd, 0xf7, 0xde, 0x7b, 0xef, 0xbd, 0xf7, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Black_Ignore_Alpha [] {0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Red_Blue_Ignore_Alpha [] {0xe3, 0x3d, 0x0 , 0xde, 0x7b, 0xf , 0x80, 0xf7, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Red_Green_Ignore_Alpha [] {0xe3, 0xbd, 0xf7, 0x0 , 0x78, 0xef, 0x3d, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Green_Blue_Ignore_Alpha [] {0x3 , 0x80, 0xf7, 0xde, 0x3 , 0xe0, 0xbd, 0xf7, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Red_Half_Alpha [] {0xe3, 0x3d, 0x0 , 0x0 , 0x78, 0xf , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC6_Green_Half_Alpha [] {0x3 , 0x80, 0xf7, 0x0 , 0x0 , 0xe0, 0x3d, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Red_Ignore_Alpha [] {0x10, 0xff, 0x3 , 0x0 , 0xc0, 0xff, 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Blue_Half_Alpha [] {0x20, 0x0 , 0x0 , 0x0 , 0xf0, 0xff, 0xef, 0xed, 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_White_Half_Alpha [] {0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xed, 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Black_Half_Alpha [] {0x20, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0xec, 0xed, 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Red_Blue_Half_Alpha [] {0x20, 0xff, 0x3f, 0x0 , 0xf0, 0xff, 0xef, 0xed, 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Red_Green_Half_Alpha [] {0x20, 0xff, 0xff, 0xff, 0xf , 0x0 , 0xec, 0xed, 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Green_Blue_Half_Alpha [] {0x20, 0x0 , 0xc0, 0xff, 0xff, 0xff, 0xef, 0xed, 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Red_Full_Alpha [] {0x10, 0xff, 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Green_Full_Alpha [] {0x10, 0x0 , 0xfc, 0xf , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Blue_Full_Alpha [] {0x10, 0x0 , 0x0 , 0xf0, 0x3f, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_White_Full_Alpha [] {0x10, 0xff, 0xff, 0xff, 0x3f, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Green_Ignore_Alpha [] {0x10, 0x0 , 0xfc, 0xf , 0xc0, 0xff, 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Black_Full_Alpha [] {0x10, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Red_Blue_Full_Alpha [] {0x10, 0xff, 0x3 , 0xf0, 0x3f, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Red_Green_Full_Alpha [] {0x10, 0xff, 0xff, 0xf , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Green_Blue_Full_Alpha [] {0x10, 0x0 , 0xfc, 0xff, 0x3f, 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Blue_Ignore_Alpha [] {0x10, 0x0 , 0x0 , 0xf0, 0xff, 0xff, 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_White_Ignore_Alpha [] {0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Black_Ignore_Alpha [] {0x10, 0x0 , 0x0 , 0x0 , 0xc0, 0xff, 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Red_Blue_Ignore_Alpha [] {0x10, 0xff, 0x3 , 0xf0, 0xff, 0xff, 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Red_Green_Ignore_Alpha [] {0x10, 0xff, 0xff, 0xf , 0xc0, 0xff, 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Green_Blue_Ignore_Alpha [] {0x10, 0x0 , 0xfc, 0xff, 0xff, 0xff, 0x3 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Red_Half_Alpha [] {0x20, 0xff, 0x3f, 0x0 , 0x0 , 0x0 , 0xec, 0xed, 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };
static const unsigned char BC7_Green_Half_Alpha [] {0x20, 0x0 , 0xc0, 0xff, 0xf , 0x0 , 0xec, 0xed, 0x1 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 , 0x0 };

Block BC1_Red_Ignore_Alpha_Block = {BC1_Red_Ignore_Alpha, nullptr};
Block BC1_Blue_Half_Alpha_Block = {BC1_Blue_Half_Alpha, nullptr};
Block BC1_White_Half_Alpha_Block = {BC1_White_Half_Alpha, nullptr};
Block BC1_Black_Half_Alpha_Block = {BC1_Black_Half_Alpha, nullptr};
Block BC1_Red_Blue_Half_Alpha_Block = {BC1_Red_Blue_Half_Alpha, nullptr};
Block BC1_Red_Green_Half_Alpha_Block = {BC1_Red_Green_Half_Alpha, nullptr};
Block BC1_Green_Blue_Half_Alpha_Block = {BC1_Green_Blue_Half_Alpha, nullptr};
Block BC1_Red_Full_Alpha_Block = {BC1_Red_Full_Alpha, nullptr};
Block BC1_Green_Full_Alpha_Block = {BC1_Green_Full_Alpha, nullptr};
Block BC1_Blue_Full_Alpha_Block = {BC1_Blue_Full_Alpha, nullptr};
Block BC1_White_Full_Alpha_Block = {BC1_White_Full_Alpha, nullptr};
Block BC1_Green_Ignore_Alpha_Block = {BC1_Green_Ignore_Alpha, nullptr};
Block BC1_Black_Full_Alpha_Block = {BC1_Black_Full_Alpha, nullptr};
Block BC1_Red_Blue_Full_Alpha_Block = {BC1_Red_Blue_Full_Alpha, nullptr};
Block BC1_Red_Green_Full_Alpha_Block = {BC1_Red_Green_Full_Alpha, nullptr};
Block BC1_Green_Blue_Full_Alpha_Block = {BC1_Green_Blue_Full_Alpha, nullptr};
Block BC1_Blue_Ignore_Alpha_Block = {BC1_Blue_Ignore_Alpha, nullptr};
Block BC1_White_Ignore_Alpha_Block = {BC1_White_Ignore_Alpha, nullptr};
Block BC1_Black_Ignore_Alpha_Block = {BC1_Black_Ignore_Alpha, nullptr};
Block BC1_Red_Blue_Ignore_Alpha_Block = {BC1_Red_Blue_Ignore_Alpha, nullptr};
Block BC1_Red_Green_Ignore_Alpha_Block = {BC1_Red_Green_Ignore_Alpha, nullptr};
Block BC1_Green_Blue_Ignore_Alpha_Block = {BC1_Green_Blue_Ignore_Alpha, nullptr};
Block BC1_Red_Half_Alpha_Block = {BC1_Red_Half_Alpha, nullptr};
Block BC1_Green_Half_Alpha_Block = {BC1_Green_Half_Alpha, nullptr};
Block BC2_Red_Ignore_Alpha_Block = {BC2_Red_Ignore_Alpha, nullptr};
Block BC2_Blue_Half_Alpha_Block = {BC2_Blue_Half_Alpha, nullptr};
Block BC2_White_Half_Alpha_Block = {BC2_White_Half_Alpha, nullptr};
Block BC2_Black_Half_Alpha_Block = {BC2_Black_Half_Alpha, nullptr};
Block BC2_Red_Blue_Half_Alpha_Block = {BC2_Red_Blue_Half_Alpha, nullptr};
Block BC2_Red_Green_Half_Alpha_Block = {BC2_Red_Green_Half_Alpha, nullptr};
Block BC2_Green_Blue_Half_Alpha_Block = {BC2_Green_Blue_Half_Alpha, nullptr};
Block BC2_Red_Full_Alpha_Block = {BC2_Red_Full_Alpha, nullptr};
Block BC2_Green_Full_Alpha_Block = {BC2_Green_Full_Alpha, nullptr};
Block BC2_Blue_Full_Alpha_Block = {BC2_Blue_Full_Alpha, nullptr};
Block BC2_White_Full_Alpha_Block = {BC2_White_Full_Alpha, nullptr};
Block BC2_Green_Ignore_Alpha_Block = {BC2_Green_Ignore_Alpha, nullptr};
Block BC2_Black_Full_Alpha_Block = {BC2_Black_Full_Alpha, nullptr};
Block BC2_Red_Blue_Full_Alpha_Block = {BC2_Red_Blue_Full_Alpha, nullptr};
Block BC2_Red_Green_Full_Alpha_Block = {BC2_Red_Green_Full_Alpha, nullptr};
Block BC2_Green_Blue_Full_Alpha_Block = {BC2_Green_Blue_Full_Alpha, nullptr};
Block BC2_Blue_Ignore_Alpha_Block = {BC2_Blue_Ignore_Alpha, nullptr};
Block BC2_White_Ignore_Alpha_Block = {BC2_White_Ignore_Alpha, nullptr};
Block BC2_Black_Ignore_Alpha_Block = {BC2_Black_Ignore_Alpha, nullptr};
Block BC2_Red_Blue_Ignore_Alpha_Block = {BC2_Red_Blue_Ignore_Alpha, nullptr};
Block BC2_Red_Green_Ignore_Alpha_Block = {BC2_Red_Green_Ignore_Alpha, nullptr};
Block BC2_Green_Blue_Ignore_Alpha_Block = {BC2_Green_Blue_Ignore_Alpha, nullptr};
Block BC2_Red_Half_Alpha_Block = {BC2_Red_Half_Alpha, nullptr};
Block BC2_Green_Half_Alpha_Block = {BC2_Green_Half_Alpha, nullptr};
Block BC3_Red_Ignore_Alpha_Block = {BC3_Red_Ignore_Alpha, nullptr};
Block BC3_Blue_Half_Alpha_Block = {BC3_Blue_Half_Alpha, nullptr};
Block BC3_White_Half_Alpha_Block = {BC3_White_Half_Alpha, nullptr};
Block BC3_Black_Half_Alpha_Block = {BC3_Black_Half_Alpha, nullptr};
Block BC3_Red_Blue_Half_Alpha_Block = {BC3_Red_Blue_Half_Alpha, nullptr};
Block BC3_Red_Green_Half_Alpha_Block = {BC3_Red_Green_Half_Alpha, nullptr};
Block BC3_Green_Blue_Half_Alpha_Block = {BC3_Green_Blue_Half_Alpha, nullptr};
Block BC3_Red_Full_Alpha_Block = {BC3_Red_Full_Alpha, nullptr};
Block BC3_Green_Full_Alpha_Block = {BC3_Green_Full_Alpha, nullptr};
Block BC3_Blue_Full_Alpha_Block = {BC3_Blue_Full_Alpha, nullptr};
Block BC3_White_Full_Alpha_Block = {BC3_White_Full_Alpha, nullptr};
Block BC3_Green_Ignore_Alpha_Block = {BC3_Green_Ignore_Alpha, nullptr};
Block BC3_Black_Full_Alpha_Block = {BC3_Black_Full_Alpha, nullptr};
Block BC3_Red_Blue_Full_Alpha_Block = {BC3_Red_Blue_Full_Alpha, nullptr};
Block BC3_Red_Green_Full_Alpha_Block = {BC3_Red_Green_Full_Alpha, nullptr};
Block BC3_Green_Blue_Full_Alpha_Block = {BC3_Green_Blue_Full_Alpha, nullptr};
Block BC3_Blue_Ignore_Alpha_Block = {BC3_Blue_Ignore_Alpha, nullptr};
Block BC3_White_Ignore_Alpha_Block = {BC3_White_Ignore_Alpha, nullptr};
Block BC3_Black_Ignore_Alpha_Block = {BC3_Black_Ignore_Alpha, nullptr};
Block BC3_Red_Blue_Ignore_Alpha_Block = {BC3_Red_Blue_Ignore_Alpha, nullptr};
Block BC3_Red_Green_Ignore_Alpha_Block = {BC3_Red_Green_Ignore_Alpha, nullptr};
Block BC3_Green_Blue_Ignore_Alpha_Block = {BC3_Green_Blue_Ignore_Alpha, nullptr};
Block BC3_Red_Half_Alpha_Block = {BC3_Red_Half_Alpha, nullptr};
Block BC3_Green_Half_Alpha_Block = {BC3_Green_Half_Alpha, nullptr};
Block BC4_Red_Ignore_Alpha_Block = {BC4_Red_Ignore_Alpha, nullptr};
Block BC4_Blue_Half_Alpha_Block = {BC4_Blue_Half_Alpha, nullptr};
Block BC4_White_Half_Alpha_Block = {BC4_White_Half_Alpha, nullptr};
Block BC4_Black_Half_Alpha_Block = {BC4_Black_Half_Alpha, nullptr};
Block BC4_Red_Blue_Half_Alpha_Block = {BC4_Red_Blue_Half_Alpha, nullptr};
Block BC4_Red_Green_Half_Alpha_Block = {BC4_Red_Green_Half_Alpha, nullptr};
Block BC4_Green_Blue_Half_Alpha_Block = {BC4_Green_Blue_Half_Alpha, nullptr};
Block BC4_Red_Full_Alpha_Block = {BC4_Red_Full_Alpha, nullptr};
Block BC4_Green_Full_Alpha_Block = {BC4_Green_Full_Alpha, nullptr};
Block BC4_Blue_Full_Alpha_Block = {BC4_Blue_Full_Alpha, nullptr};
Block BC4_White_Full_Alpha_Block = {BC4_White_Full_Alpha, nullptr};
Block BC4_Green_Ignore_Alpha_Block = {BC4_Green_Ignore_Alpha, nullptr};
Block BC4_Black_Full_Alpha_Block = {BC4_Black_Full_Alpha, nullptr};
Block BC4_Red_Blue_Full_Alpha_Block = {BC4_Red_Blue_Full_Alpha, nullptr};
Block BC4_Red_Green_Full_Alpha_Block = {BC4_Red_Green_Full_Alpha, nullptr};
Block BC4_Green_Blue_Full_Alpha_Block = {BC4_Green_Blue_Full_Alpha, nullptr};
Block BC4_Blue_Ignore_Alpha_Block = {BC4_Blue_Ignore_Alpha, nullptr};
Block BC4_White_Ignore_Alpha_Block = {BC4_White_Ignore_Alpha, nullptr};
Block BC4_Black_Ignore_Alpha_Block = {BC4_Black_Ignore_Alpha, nullptr};
Block BC4_Red_Blue_Ignore_Alpha_Block = {BC4_Red_Blue_Ignore_Alpha, nullptr};
Block BC4_Red_Green_Ignore_Alpha_Block = {BC4_Red_Green_Ignore_Alpha, nullptr};
Block BC4_Green_Blue_Ignore_Alpha_Block = {BC4_Green_Blue_Ignore_Alpha, nullptr};
Block BC4_Red_Half_Alpha_Block = {BC4_Red_Half_Alpha, nullptr};
Block BC4_Green_Half_Alpha_Block = {BC4_Green_Half_Alpha, nullptr};
Block BC5_Red_Ignore_Alpha_Block = {BC5_Red_Ignore_Alpha, nullptr};
Block BC5_Blue_Half_Alpha_Block = {BC5_Blue_Half_Alpha, nullptr};
Block BC5_White_Half_Alpha_Block = {BC5_White_Half_Alpha, nullptr};
Block BC5_Black_Half_Alpha_Block = {BC5_Black_Half_Alpha, nullptr};
Block BC5_Red_Blue_Half_Alpha_Block = {BC5_Red_Blue_Half_Alpha, nullptr};
Block BC5_Red_Green_Half_Alpha_Block = {BC5_Red_Green_Half_Alpha, nullptr};
Block BC5_Green_Blue_Half_Alpha_Block = {BC5_Green_Blue_Half_Alpha, nullptr};
Block BC5_Red_Full_Alpha_Block = {BC5_Red_Full_Alpha, nullptr};
Block BC5_Green_Full_Alpha_Block = {BC5_Green_Full_Alpha, nullptr};
Block BC5_Blue_Full_Alpha_Block = {BC5_Blue_Full_Alpha, nullptr};
Block BC5_White_Full_Alpha_Block = {BC5_White_Full_Alpha, nullptr};
Block BC5_Green_Ignore_Alpha_Block = {BC5_Green_Ignore_Alpha, nullptr};
Block BC5_Black_Full_Alpha_Block = {BC5_Black_Full_Alpha, nullptr};
Block BC5_Red_Blue_Full_Alpha_Block = {BC5_Red_Blue_Full_Alpha, nullptr};
Block BC5_Red_Green_Full_Alpha_Block = {BC5_Red_Green_Full_Alpha, nullptr};
Block BC5_Green_Blue_Full_Alpha_Block = {BC5_Green_Blue_Full_Alpha, nullptr};
Block BC5_Blue_Ignore_Alpha_Block = {BC5_Blue_Ignore_Alpha, nullptr};
Block BC5_White_Ignore_Alpha_Block = {BC5_White_Ignore_Alpha, nullptr};
Block BC5_Black_Ignore_Alpha_Block = {BC5_Black_Ignore_Alpha, nullptr};
Block BC5_Red_Blue_Ignore_Alpha_Block = {BC5_Red_Blue_Ignore_Alpha, nullptr};
Block BC5_Red_Green_Ignore_Alpha_Block = {BC5_Red_Green_Ignore_Alpha, nullptr};
Block BC5_Green_Blue_Ignore_Alpha_Block = {BC5_Green_Blue_Ignore_Alpha, nullptr};
Block BC5_Red_Half_Alpha_Block = {BC5_Red_Half_Alpha, nullptr};
Block BC5_Green_Half_Alpha_Block = {BC5_Green_Half_Alpha, nullptr};
BlockBC6 BC6_Red_Ignore_Alpha_Block = {BC6_Red_Ignore_Alpha, nullptr};
BlockBC6 BC6_Blue_Half_Alpha_Block = {BC6_Blue_Half_Alpha, nullptr};
BlockBC6 BC6_White_Half_Alpha_Block = {BC6_White_Half_Alpha, nullptr};
BlockBC6 BC6_Black_Half_Alpha_Block = {BC6_Black_Half_Alpha, nullptr};
BlockBC6 BC6_Red_Blue_Half_Alpha_Block = {BC6_Red_Blue_Half_Alpha, nullptr};
BlockBC6 BC6_Red_Green_Half_Alpha_Block = {BC6_Red_Green_Half_Alpha, nullptr};
BlockBC6 BC6_Green_Blue_Half_Alpha_Block = {BC6_Green_Blue_Half_Alpha, nullptr};
BlockBC6 BC6_Red_Full_Alpha_Block = {BC6_Red_Full_Alpha, nullptr};
BlockBC6 BC6_Green_Full_Alpha_Block = {BC6_Green_Full_Alpha, nullptr};
BlockBC6 BC6_Blue_Full_Alpha_Block = {BC6_Blue_Full_Alpha, nullptr};
BlockBC6 BC6_White_Full_Alpha_Block = {BC6_White_Full_Alpha, nullptr};
BlockBC6 BC6_Green_Ignore_Alpha_Block = {BC6_Green_Ignore_Alpha, nullptr};
BlockBC6 BC6_Black_Full_Alpha_Block = {BC6_Black_Full_Alpha, nullptr};
BlockBC6 BC6_Red_Blue_Full_Alpha_Block = {BC6_Red_Blue_Full_Alpha, nullptr};
BlockBC6 BC6_Red_Green_Full_Alpha_Block = {BC6_Red_Green_Full_Alpha, nullptr};
BlockBC6 BC6_Green_Blue_Full_Alpha_Block = {BC6_Green_Blue_Full_Alpha, nullptr};
BlockBC6 BC6_Blue_Ignore_Alpha_Block = {BC6_Blue_Ignore_Alpha, nullptr};
BlockBC6 BC6_White_Ignore_Alpha_Block = {BC6_White_Ignore_Alpha, nullptr};
BlockBC6 BC6_Black_Ignore_Alpha_Block = {BC6_Black_Ignore_Alpha, nullptr};
BlockBC6 BC6_Red_Blue_Ignore_Alpha_Block = {BC6_Red_Blue_Ignore_Alpha, nullptr};
BlockBC6 BC6_Red_Green_Ignore_Alpha_Block = {BC6_Red_Green_Ignore_Alpha, nullptr};
BlockBC6 BC6_Green_Blue_Ignore_Alpha_Block = {BC6_Green_Blue_Ignore_Alpha, nullptr};
BlockBC6 BC6_Red_Half_Alpha_Block = {BC6_Red_Half_Alpha, nullptr};
BlockBC6 BC6_Green_Half_Alpha_Block = {BC6_Green_Half_Alpha, nullptr};
Block BC7_Red_Ignore_Alpha_Block = {BC7_Red_Ignore_Alpha, nullptr};
Block BC7_Blue_Half_Alpha_Block = {BC7_Blue_Half_Alpha, nullptr};
Block BC7_White_Half_Alpha_Block = {BC7_White_Half_Alpha, nullptr};
Block BC7_Black_Half_Alpha_Block = {BC7_Black_Half_Alpha, nullptr};
Block BC7_Red_Blue_Half_Alpha_Block = {BC7_Red_Blue_Half_Alpha, nullptr};
Block BC7_Red_Green_Half_Alpha_Block = {BC7_Red_Green_Half_Alpha, nullptr};
Block BC7_Green_Blue_Half_Alpha_Block = {BC7_Green_Blue_Half_Alpha, nullptr};
Block BC7_Red_Full_Alpha_Block = {BC7_Red_Full_Alpha, nullptr};
Block BC7_Green_Full_Alpha_Block = {BC7_Green_Full_Alpha, nullptr};
Block BC7_Blue_Full_Alpha_Block = {BC7_Blue_Full_Alpha, nullptr};
Block BC7_White_Full_Alpha_Block = {BC7_White_Full_Alpha, nullptr};
Block BC7_Green_Ignore_Alpha_Block = {BC7_Green_Ignore_Alpha, nullptr};
Block BC7_Black_Full_Alpha_Block = {BC7_Black_Full_Alpha, nullptr};
Block BC7_Red_Blue_Full_Alpha_Block = {BC7_Red_Blue_Full_Alpha, nullptr};
Block BC7_Red_Green_Full_Alpha_Block = {BC7_Red_Green_Full_Alpha, nullptr};
Block BC7_Green_Blue_Full_Alpha_Block = {BC7_Green_Blue_Full_Alpha, nullptr};
Block BC7_Blue_Ignore_Alpha_Block = {BC7_Blue_Ignore_Alpha, nullptr};
Block BC7_White_Ignore_Alpha_Block = {BC7_White_Ignore_Alpha, nullptr};
Block BC7_Black_Ignore_Alpha_Block = {BC7_Black_Ignore_Alpha, nullptr};
Block BC7_Red_Blue_Ignore_Alpha_Block = {BC7_Red_Blue_Ignore_Alpha, nullptr};
Block BC7_Red_Green_Ignore_Alpha_Block = {BC7_Red_Green_Ignore_Alpha, nullptr};
Block BC7_Green_Blue_Ignore_Alpha_Block = {BC7_Green_Blue_Ignore_Alpha, nullptr};
Block BC7_Red_Half_Alpha_Block = {BC7_Red_Half_Alpha, nullptr};
Block BC7_Green_Half_Alpha_Block = {BC7_Green_Half_Alpha, nullptr};

static std::unordered_map<std::string, Block> blocks {
	{ "BC1_Red_Ignore_Alpha", BC1_Red_Ignore_Alpha_Block},
	{ "BC1_Blue_Half_Alpha", BC1_Blue_Half_Alpha_Block},
	{ "BC1_White_Half_Alpha", BC1_White_Half_Alpha_Block},
	{ "BC1_Black_Half_Alpha", BC1_Black_Half_Alpha_Block},
	{ "BC1_Red_Blue_Half_Alpha", BC1_Red_Blue_Half_Alpha_Block},
	{ "BC1_Red_Green_Half_Alpha", BC1_Red_Green_Half_Alpha_Block},
	{ "BC1_Green_Blue_Half_Alpha", BC1_Green_Blue_Half_Alpha_Block},
	{ "BC1_Red_Full_Alpha", BC1_Red_Full_Alpha_Block},
	{ "BC1_Green_Full_Alpha", BC1_Green_Full_Alpha_Block},
	{ "BC1_Blue_Full_Alpha", BC1_Blue_Full_Alpha_Block},
	{ "BC1_White_Full_Alpha", BC1_White_Full_Alpha_Block},
	{ "BC1_Green_Ignore_Alpha", BC1_Green_Ignore_Alpha_Block},
	{ "BC1_Black_Full_Alpha", BC1_Black_Full_Alpha_Block},
	{ "BC1_Red_Blue_Full_Alpha", BC1_Red_Blue_Full_Alpha_Block},
	{ "BC1_Red_Green_Full_Alpha", BC1_Red_Green_Full_Alpha_Block},
	{ "BC1_Green_Blue_Full_Alpha", BC1_Green_Blue_Full_Alpha_Block},
	{ "BC1_Blue_Ignore_Alpha", BC1_Blue_Ignore_Alpha_Block},
	{ "BC1_White_Ignore_Alpha", BC1_White_Ignore_Alpha_Block},
	{ "BC1_Black_Ignore_Alpha", BC1_Black_Ignore_Alpha_Block},
	{ "BC1_Red_Blue_Ignore_Alpha", BC1_Red_Blue_Ignore_Alpha_Block},
	{ "BC1_Red_Green_Ignore_Alpha", BC1_Red_Green_Ignore_Alpha_Block},
	{ "BC1_Green_Blue_Ignore_Alpha", BC1_Green_Blue_Ignore_Alpha_Block},
	{ "BC1_Red_Half_Alpha", BC1_Red_Half_Alpha_Block},
	{ "BC1_Green_Half_Alpha", BC1_Green_Half_Alpha_Block},
	{ "BC2_Red_Ignore_Alpha", BC2_Red_Ignore_Alpha_Block},
	{ "BC2_Blue_Half_Alpha", BC2_Blue_Half_Alpha_Block},
	{ "BC2_White_Half_Alpha", BC2_White_Half_Alpha_Block},
	{ "BC2_Black_Half_Alpha", BC2_Black_Half_Alpha_Block},
	{ "BC2_Red_Blue_Half_Alpha", BC2_Red_Blue_Half_Alpha_Block},
	{ "BC2_Red_Green_Half_Alpha", BC2_Red_Green_Half_Alpha_Block},
	{ "BC2_Green_Blue_Half_Alpha", BC2_Green_Blue_Half_Alpha_Block},
	{ "BC2_Red_Full_Alpha", BC2_Red_Full_Alpha_Block},
	{ "BC2_Green_Full_Alpha", BC2_Green_Full_Alpha_Block},
	{ "BC2_Blue_Full_Alpha", BC2_Blue_Full_Alpha_Block},
	{ "BC2_White_Full_Alpha", BC2_White_Full_Alpha_Block},
	{ "BC2_Green_Ignore_Alpha", BC2_Green_Ignore_Alpha_Block},
	{ "BC2_Black_Full_Alpha", BC2_Black_Full_Alpha_Block},
	{ "BC2_Red_Blue_Full_Alpha", BC2_Red_Blue_Full_Alpha_Block},
	{ "BC2_Red_Green_Full_Alpha", BC2_Red_Green_Full_Alpha_Block},
	{ "BC2_Green_Blue_Full_Alpha", BC2_Green_Blue_Full_Alpha_Block},
	{ "BC2_Blue_Ignore_Alpha", BC2_Blue_Ignore_Alpha_Block},
	{ "BC2_White_Ignore_Alpha", BC2_White_Ignore_Alpha_Block},
	{ "BC2_Black_Ignore_Alpha", BC2_Black_Ignore_Alpha_Block},
	{ "BC2_Red_Blue_Ignore_Alpha", BC2_Red_Blue_Ignore_Alpha_Block},
	{ "BC2_Red_Green_Ignore_Alpha", BC2_Red_Green_Ignore_Alpha_Block},
	{ "BC2_Green_Blue_Ignore_Alpha", BC2_Green_Blue_Ignore_Alpha_Block},
	{ "BC2_Red_Half_Alpha", BC2_Red_Half_Alpha_Block},
	{ "BC2_Green_Half_Alpha", BC2_Green_Half_Alpha_Block},
	{ "BC3_Red_Ignore_Alpha", BC3_Red_Ignore_Alpha_Block},
	{ "BC3_Blue_Half_Alpha", BC3_Blue_Half_Alpha_Block},
	{ "BC3_White_Half_Alpha", BC3_White_Half_Alpha_Block},
	{ "BC3_Black_Half_Alpha", BC3_Black_Half_Alpha_Block},
	{ "BC3_Red_Blue_Half_Alpha", BC3_Red_Blue_Half_Alpha_Block},
	{ "BC3_Red_Green_Half_Alpha", BC3_Red_Green_Half_Alpha_Block},
	{ "BC3_Green_Blue_Half_Alpha", BC3_Green_Blue_Half_Alpha_Block},
	{ "BC3_Red_Full_Alpha", BC3_Red_Full_Alpha_Block},
	{ "BC3_Green_Full_Alpha", BC3_Green_Full_Alpha_Block},
	{ "BC3_Blue_Full_Alpha", BC3_Blue_Full_Alpha_Block},
	{ "BC3_White_Full_Alpha", BC3_White_Full_Alpha_Block},
	{ "BC3_Green_Ignore_Alpha", BC3_Green_Ignore_Alpha_Block},
	{ "BC3_Black_Full_Alpha", BC3_Black_Full_Alpha_Block},
	{ "BC3_Red_Blue_Full_Alpha", BC3_Red_Blue_Full_Alpha_Block},
	{ "BC3_Red_Green_Full_Alpha", BC3_Red_Green_Full_Alpha_Block},
	{ "BC3_Green_Blue_Full_Alpha", BC3_Green_Blue_Full_Alpha_Block},
	{ "BC3_Blue_Ignore_Alpha", BC3_Blue_Ignore_Alpha_Block},
	{ "BC3_White_Ignore_Alpha", BC3_White_Ignore_Alpha_Block},
	{ "BC3_Black_Ignore_Alpha", BC3_Black_Ignore_Alpha_Block},
	{ "BC3_Red_Blue_Ignore_Alpha", BC3_Red_Blue_Ignore_Alpha_Block},
	{ "BC3_Red_Green_Ignore_Alpha", BC3_Red_Green_Ignore_Alpha_Block},
	{ "BC3_Green_Blue_Ignore_Alpha", BC3_Green_Blue_Ignore_Alpha_Block},
	{ "BC3_Red_Half_Alpha", BC3_Red_Half_Alpha_Block},
	{ "BC3_Green_Half_Alpha", BC3_Green_Half_Alpha_Block},
	{ "BC4_Red_Ignore_Alpha", BC4_Red_Ignore_Alpha_Block},
	{ "BC4_Blue_Half_Alpha", BC4_Blue_Half_Alpha_Block},
	{ "BC4_White_Half_Alpha", BC4_White_Half_Alpha_Block},
	{ "BC4_Black_Half_Alpha", BC4_Black_Half_Alpha_Block},
	{ "BC4_Red_Blue_Half_Alpha", BC4_Red_Blue_Half_Alpha_Block},
	{ "BC4_Red_Green_Half_Alpha", BC4_Red_Green_Half_Alpha_Block},
	{ "BC4_Green_Blue_Half_Alpha", BC4_Green_Blue_Half_Alpha_Block},
	{ "BC4_Red_Full_Alpha", BC4_Red_Full_Alpha_Block},
	{ "BC4_Green_Full_Alpha", BC4_Green_Full_Alpha_Block},
	{ "BC4_Blue_Full_Alpha", BC4_Blue_Full_Alpha_Block},
	{ "BC4_White_Full_Alpha", BC4_White_Full_Alpha_Block},
	{ "BC4_Green_Ignore_Alpha", BC4_Green_Ignore_Alpha_Block},
	{ "BC4_Black_Full_Alpha", BC4_Black_Full_Alpha_Block},
	{ "BC4_Red_Blue_Full_Alpha", BC4_Red_Blue_Full_Alpha_Block},
	{ "BC4_Red_Green_Full_Alpha", BC4_Red_Green_Full_Alpha_Block},
	{ "BC4_Green_Blue_Full_Alpha", BC4_Green_Blue_Full_Alpha_Block},
	{ "BC4_Blue_Ignore_Alpha", BC4_Blue_Ignore_Alpha_Block},
	{ "BC4_White_Ignore_Alpha", BC4_White_Ignore_Alpha_Block},
	{ "BC4_Black_Ignore_Alpha", BC4_Black_Ignore_Alpha_Block},
	{ "BC4_Red_Blue_Ignore_Alpha", BC4_Red_Blue_Ignore_Alpha_Block},
	{ "BC4_Red_Green_Ignore_Alpha", BC4_Red_Green_Ignore_Alpha_Block},
	{ "BC4_Green_Blue_Ignore_Alpha", BC4_Green_Blue_Ignore_Alpha_Block},
	{ "BC4_Red_Half_Alpha", BC4_Red_Half_Alpha_Block},
	{ "BC4_Green_Half_Alpha", BC4_Green_Half_Alpha_Block},
	{ "BC5_Red_Ignore_Alpha", BC5_Red_Ignore_Alpha_Block},
	{ "BC5_Blue_Half_Alpha", BC5_Blue_Half_Alpha_Block},
	{ "BC5_White_Half_Alpha", BC5_White_Half_Alpha_Block},
	{ "BC5_Black_Half_Alpha", BC5_Black_Half_Alpha_Block},
	{ "BC5_Red_Blue_Half_Alpha", BC5_Red_Blue_Half_Alpha_Block},
	{ "BC5_Red_Green_Half_Alpha", BC5_Red_Green_Half_Alpha_Block},
	{ "BC5_Green_Blue_Half_Alpha", BC5_Green_Blue_Half_Alpha_Block},
	{ "BC5_Red_Full_Alpha", BC5_Red_Full_Alpha_Block},
	{ "BC5_Green_Full_Alpha", BC5_Green_Full_Alpha_Block},
	{ "BC5_Blue_Full_Alpha", BC5_Blue_Full_Alpha_Block},
	{ "BC5_White_Full_Alpha", BC5_White_Full_Alpha_Block},
	{ "BC5_Green_Ignore_Alpha", BC5_Green_Ignore_Alpha_Block},
	{ "BC5_Black_Full_Alpha", BC5_Black_Full_Alpha_Block},
	{ "BC5_Red_Blue_Full_Alpha", BC5_Red_Blue_Full_Alpha_Block},
	{ "BC5_Red_Green_Full_Alpha", BC5_Red_Green_Full_Alpha_Block},
	{ "BC5_Green_Blue_Full_Alpha", BC5_Green_Blue_Full_Alpha_Block},
	{ "BC5_Blue_Ignore_Alpha", BC5_Blue_Ignore_Alpha_Block},
	{ "BC5_White_Ignore_Alpha", BC5_White_Ignore_Alpha_Block},
	{ "BC5_Black_Ignore_Alpha", BC5_Black_Ignore_Alpha_Block},
	{ "BC5_Red_Blue_Ignore_Alpha", BC5_Red_Blue_Ignore_Alpha_Block},
	{ "BC5_Red_Green_Ignore_Alpha", BC5_Red_Green_Ignore_Alpha_Block},
	{ "BC5_Green_Blue_Ignore_Alpha", BC5_Green_Blue_Ignore_Alpha_Block},
	{ "BC5_Red_Half_Alpha", BC5_Red_Half_Alpha_Block},
	{ "BC5_Green_Half_Alpha", BC5_Green_Half_Alpha_Block},
	{ "BC7_Red_Ignore_Alpha", BC7_Red_Ignore_Alpha_Block},
	{ "BC7_Blue_Half_Alpha", BC7_Blue_Half_Alpha_Block},
	{ "BC7_White_Half_Alpha", BC7_White_Half_Alpha_Block},
	{ "BC7_Black_Half_Alpha", BC7_Black_Half_Alpha_Block},
	{ "BC7_Red_Blue_Half_Alpha", BC7_Red_Blue_Half_Alpha_Block},
	{ "BC7_Red_Green_Half_Alpha", BC7_Red_Green_Half_Alpha_Block},
	{ "BC7_Green_Blue_Half_Alpha", BC7_Green_Blue_Half_Alpha_Block},
	{ "BC7_Red_Full_Alpha", BC7_Red_Full_Alpha_Block},
	{ "BC7_Green_Full_Alpha", BC7_Green_Full_Alpha_Block},
	{ "BC7_Blue_Full_Alpha", BC7_Blue_Full_Alpha_Block},
	{ "BC7_White_Full_Alpha", BC7_White_Full_Alpha_Block},
	{ "BC7_Green_Ignore_Alpha", BC7_Green_Ignore_Alpha_Block},
	{ "BC7_Black_Full_Alpha", BC7_Black_Full_Alpha_Block},
	{ "BC7_Red_Blue_Full_Alpha", BC7_Red_Blue_Full_Alpha_Block},
	{ "BC7_Red_Green_Full_Alpha", BC7_Red_Green_Full_Alpha_Block},
	{ "BC7_Green_Blue_Full_Alpha", BC7_Green_Blue_Full_Alpha_Block},
	{ "BC7_Blue_Ignore_Alpha", BC7_Blue_Ignore_Alpha_Block},
	{ "BC7_White_Ignore_Alpha", BC7_White_Ignore_Alpha_Block},
	{ "BC7_Black_Ignore_Alpha", BC7_Black_Ignore_Alpha_Block},
	{ "BC7_Red_Blue_Ignore_Alpha", BC7_Red_Blue_Ignore_Alpha_Block},
	{ "BC7_Red_Green_Ignore_Alpha", BC7_Red_Green_Ignore_Alpha_Block},
	{ "BC7_Green_Blue_Ignore_Alpha", BC7_Green_Blue_Ignore_Alpha_Block},
	{ "BC7_Red_Half_Alpha", BC7_Red_Half_Alpha_Block},
	{ "BC7_Green_Half_Alpha", BC7_Green_Half_Alpha_Block}
};

static std::unordered_map<std::string, BlockBC6> blocksBC6 {
	{ "BC6_Red_Ignore_Alpha", BC6_Red_Ignore_Alpha_Block},
	{ "BC6_Blue_Half_Alpha", BC6_Blue_Half_Alpha_Block},
	{ "BC6_White_Half_Alpha", BC6_White_Half_Alpha_Block},
	{ "BC6_Black_Half_Alpha", BC6_Black_Half_Alpha_Block},
	{ "BC6_Red_Blue_Half_Alpha", BC6_Red_Blue_Half_Alpha_Block},
	{ "BC6_Red_Green_Half_Alpha", BC6_Red_Green_Half_Alpha_Block},
	{ "BC6_Green_Blue_Half_Alpha", BC6_Green_Blue_Half_Alpha_Block},
	{ "BC6_Red_Full_Alpha", BC6_Red_Full_Alpha_Block},
	{ "BC6_Green_Full_Alpha", BC6_Green_Full_Alpha_Block},
	{ "BC6_Blue_Full_Alpha", BC6_Blue_Full_Alpha_Block},
	{ "BC6_White_Full_Alpha", BC6_White_Full_Alpha_Block},
	{ "BC6_Green_Ignore_Alpha", BC6_Green_Ignore_Alpha_Block},
	{ "BC6_Black_Full_Alpha", BC6_Black_Full_Alpha_Block},
	{ "BC6_Red_Blue_Full_Alpha", BC6_Red_Blue_Full_Alpha_Block},
	{ "BC6_Red_Green_Full_Alpha", BC6_Red_Green_Full_Alpha_Block},
	{ "BC6_Green_Blue_Full_Alpha", BC6_Green_Blue_Full_Alpha_Block},
	{ "BC6_Blue_Ignore_Alpha", BC6_Blue_Ignore_Alpha_Block},
	{ "BC6_White_Ignore_Alpha", BC6_White_Ignore_Alpha_Block},
	{ "BC6_Black_Ignore_Alpha", BC6_Black_Ignore_Alpha_Block},
	{ "BC6_Red_Blue_Ignore_Alpha", BC6_Red_Blue_Ignore_Alpha_Block},
	{ "BC6_Red_Green_Ignore_Alpha", BC6_Red_Green_Ignore_Alpha_Block},
	{ "BC6_Green_Blue_Ignore_Alpha", BC6_Green_Blue_Ignore_Alpha_Block},
	{ "BC6_Red_Half_Alpha", BC6_Red_Half_Alpha_Block},
	{ "BC6_Green_Half_Alpha", BC6_Green_Half_Alpha_Block}
};

#endif

<|start_filename|>src/nvcore/DefsGnucWin32.h<|end_filename|>
#ifndef NV_CORE_H
#error "Do not include this file directly."
#endif

//#include <cstddef> // size_t, NULL

// Function linkage
#define DLL_IMPORT	__declspec(dllimport)
#define DLL_EXPORT	__declspec(dllexport)
#define DLL_EXPORT_CLASS DLL_EXPORT

// Function calling modes
#if NV_CPU_X86
#	define NV_CDECL 	__attribute__((cdecl))
#	define NV_STDCALL	__attribute__((stdcall))
#else
#	define NV_CDECL 
#	define NV_STDCALL
#endif

#define NV_FASTCALL		__attribute__((fastcall))
#define NV_FORCEINLINE	__attribute__((always_inline))
#define NV_DEPRECATED   __attribute__((deprecated))

#if __GNUC__ > 2
#define NV_PURE		__attribute__((pure))
#define NV_CONST	__attribute__((const))
#else
#define NV_PURE
#define NV_CONST
#endif

#define NV_NOINLINE __attribute__((noinline))

// Define __FUNC__ properly.
#if __STDC_VERSION__ < 199901L
#	if __GNUC__ >= 2
#		define __FUNC__ __PRETTY_FUNCTION__	// __FUNCTION__
#	else
#		define __FUNC__ "<unknown>"
#	endif
#else
#	define __FUNC__ __PRETTY_FUNCTION__
#endif

#define restrict	__restrict__

/*
// Type definitions
typedef unsigned char		uint8;
typedef signed char			int8;

typedef unsigned short		uint16;
typedef signed short		int16;

typedef unsigned int		uint32;
typedef signed int			int32;

typedef unsigned long long	uint64;
typedef signed long long	int64;

// Aliases
typedef uint32				uint;
*/



<|start_filename|>src/nvimage/BlockDXT.h<|end_filename|>
// Copyright NVIDIA Corporation 2007 -- <NAME> <<EMAIL>>
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#pragma once
#ifndef NV_IMAGE_BLOCKDXT_H
#define NV_IMAGE_BLOCKDXT_H

#include "nvimage.h"

#include "nvmath/Color.h"

namespace nv
{
    struct ColorBlock;
    struct ColorSet;
    struct AlphaBlock4x4;
    class Stream;
    class Vector3;
    class Vector4;


    /// DXT1 block.
    struct BlockDXT1
    {
        Color16 col0;
        Color16 col1;
        union {
            uint8 row[4];
            uint indices;
        };

        bool isFourColorMode() const;

        uint evaluatePalette(Color32 color_array[4], bool d3d9) const;
        uint evaluatePaletteNV5x(Color32 color_array[4]) const;

        void evaluatePalette3(Color32 color_array[4], bool d3d9) const;
        void evaluatePalette4(Color32 color_array[4], bool d3d9) const;

        void decodeBlock(ColorBlock * block, bool d3d9 = false) const;
        void decodeBlockNV5x(ColorBlock * block) const;

        void setIndices(int * idx);

        void flip4();
        void flip2();
    };

    /// Return true if the block uses four color mode, false otherwise.
    inline bool BlockDXT1::isFourColorMode() const
    {
        return col0.u > col1.u;
    }


    /// DXT3 alpha block with explicit alpha.
    struct AlphaBlockDXT3
    {
        union {
            struct {
                uint alpha0 : 4;
                uint alpha1 : 4;
                uint alpha2 : 4;
                uint alpha3 : 4;
                uint alpha4 : 4;
                uint alpha5 : 4;
                uint alpha6 : 4;
                uint alpha7 : 4;
                uint alpha8 : 4;
                uint alpha9 : 4;
                uint alphaA : 4;
                uint alphaB : 4;
                uint alphaC : 4;
                uint alphaD : 4;
                uint alphaE : 4;
                uint alphaF : 4;
            };
            uint16 row[4];
        };

        void decodeBlock(ColorBlock * block, bool d3d9 = false) const;

        void flip4();
        void flip2();
    };


    /// DXT3 block.
    struct BlockDXT3
    {
        AlphaBlockDXT3 alpha;
        BlockDXT1 color;

        void decodeBlock(ColorBlock * block, bool d3d9 = false) const;
        void decodeBlockNV5x(ColorBlock * block) const;

        void flip4();
        void flip2();
    };


    /// DXT5 alpha block.
    struct AlphaBlockDXT5
    {
        union {
            struct {
                uint64 alpha0 : 8;	// 8
                uint64 alpha1 : 8;	// 16
                uint64 bits0 : 3;	// 3 - 19
                uint64 bits1 : 3; 	// 6 - 22
                uint64 bits2 : 3; 	// 9 - 25
                uint64 bits3 : 3;	// 12 - 28
                uint64 bits4 : 3;	// 15 - 31
                uint64 bits5 : 3;	// 18 - 34
                uint64 bits6 : 3;	// 21 - 37
                uint64 bits7 : 3;	// 24 - 40
                uint64 bits8 : 3;	// 27 - 43
                uint64 bits9 : 3; 	// 30 - 46
                uint64 bitsA : 3; 	// 33 - 49
                uint64 bitsB : 3;	// 36 - 52
                uint64 bitsC : 3;	// 39 - 55
                uint64 bitsD : 3;	// 42 - 58
                uint64 bitsE : 3;	// 45 - 61
                uint64 bitsF : 3;	// 48 - 64
            };
            uint64 u;
        };

        void evaluatePalette(uint8 alpha[8], bool d3d9) const;
        void evaluatePalette8(uint8 alpha[8], bool d3d9) const;
        void evaluatePalette6(uint8 alpha[8], bool d3d9) const;
        void indices(uint8 index_array[16]) const;

        uint index(uint index) const;
        void setIndex(uint index, uint value);

        void decodeBlock(ColorBlock * block, bool d3d9 = false) const;
        void decodeBlock(AlphaBlock4x4 * block, bool d3d9 = false) const;

        void flip4();
        void flip2();
    };


    /// DXT5 block.
    struct BlockDXT5
    {
        AlphaBlockDXT5 alpha;
        BlockDXT1 color;

        void decodeBlock(ColorBlock * block, bool d3d9 = false) const;
        void decodeBlockNV5x(ColorBlock * block) const;

        void flip4();
        void flip2();
    };

    /// ATI1 block.
    struct BlockATI1
    {
        AlphaBlockDXT5 alpha;

        void decodeBlock(ColorBlock * block, bool d3d9 = false) const;

        void flip4();
        void flip2();
    };

    /// ATI2 block.
    struct BlockATI2
    {
        AlphaBlockDXT5 x;
        AlphaBlockDXT5 y;

        void decodeBlock(ColorBlock * block, bool d3d9 = false) const;

        void flip4();
        void flip2();
    };

    /// CTX1 block.
    struct BlockCTX1
    {
        uint8 col0[2];
        uint8 col1[2];
        union {
            uint8 row[4];
            uint indices;
        };

        void evaluatePalette(Color32 color_array[4]) const;
        void setIndices(int * idx);

        void decodeBlock(ColorBlock * block) const;

        void flip4();
        void flip2();
    };

	/// BC6 block.
	struct BlockBC6
	{
		uint8 data[16];		// Not even going to try to write a union for this thing.
        void decodeBlock(Vector4 colors[16]) const;
	};

	/// BC7 block.
	struct BlockBC7
	{
		uint8 data[16];		// Not even going to try to write a union for this thing.
		void decodeBlock(ColorBlock * block) const;
	};



    // Serialization functions.
    Stream & operator<<(Stream & stream, BlockDXT1 & block);
    Stream & operator<<(Stream & stream, AlphaBlockDXT3 & block);
    Stream & operator<<(Stream & stream, BlockDXT3 & block);
    Stream & operator<<(Stream & stream, AlphaBlockDXT5 & block);
    Stream & operator<<(Stream & stream, BlockDXT5 & block);
    Stream & operator<<(Stream & stream, BlockATI1 & block);
    Stream & operator<<(Stream & stream, BlockATI2 & block);
    Stream & operator<<(Stream & stream, BlockCTX1 & block);
    Stream & operator<<(Stream & stream, BlockBC6 & block);
    Stream & operator<<(Stream & stream, BlockBC7 & block);

} // nv namespace

#endif // NV_IMAGE_BLOCKDXT_H


<|start_filename|>extern/CMP_Core/shaders/Common_Def.h<|end_filename|>
//===============================================================================
// Copyright (c) 2007-2020 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2004-2006 ATI Technologies Inc.
//===============================================================================
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
//
//  File Name:   Common_Def
//  Description: common definitions used for CPU/HPC/GPU
//
//////////////////////////////////////////////////////////////////////////////

#ifndef _COMMON_DEFINITIONS_H
#define _COMMON_DEFINITIONS_H

// The shaders for UE4 require extension in the form of .ush in place of standard .h
// this directive is used to make the change without users requiring to modify all of the include extensions
// specific to UE4

#ifdef ASPM_HLSL_UE4
#pragma once
#define INC_cmp_math_vec4   "cmp_math_vec4.ush"
#define INC_cmp_math_func   "cmp_math_func.ush"
#else
#define INC_cmp_math_vec4   "cmp_math_vec4.h"
#define INC_cmp_math_func   "cmp_math_func.h"
#endif

// Features
#ifdef _WIN32
//#define USE_ASPM_CODE
#endif

// Proxy ISPC compiler (Warning! Not all ASPM features will be available : expect build errors for specialized ASPM code!
#ifdef ISPC
#define ASPM
#endif

// Using OpenCL Compiler
#ifdef __OPENCL_VERSION__
#define  ASPM_GPU
#define  ASPM_OPENCL
#endif

// Using DirectX fxc Compiler
// Note use the /DASPM_HLSL command line to define this 
#ifdef ASPM_HLSL
#define  ASPM_GPU
#endif

#ifdef _LINUX
#undef ASPM_GPU
#undef ASPM_OPENCL
#ifndef ASPM_HLSL
#include <cstring>
#include <cmath>
#include <stdio.h>
#include INC_cmp_math_vec4
#endif
#endif

#ifndef CMP_MAX
#define CMP_MAX(x, y) (((x) > (y)) ? (x) : (y))
#endif

#ifndef CMP_MIN
#define CMP_MIN(x, y) (((x) < (y)) ? (x) : (y))
#endif

#ifndef ASPM_GPU
#define CMP_STATIC_CAST(x,y) static_cast<x>(y)
#else
#define CMP_STATIC_CAST(x,y) (x)(y)
#endif


#define CMP_SET_BC13_DECODER_RGBA       //  Sets mapping BC1, BC2 & BC3 to decode Red,Green,Blue and Alpha 
                                        //       RGBA to channels [0,1,2,3] else BGRA maps to [0,1,2,3]
                                        //  BC4 alpha always maps as AAAA to channels [0,1,2,3] 
                                        //  BC5 decoded (Red&Green) maps R,G,B=0,A=255 to [0,1,2,3] else  maps [B=0,G,R,A=255] to [0,1,2,3]

//#define USE_BLOCK_LINEAR

#define CMP_FLOAT_MAX                   3.402823466e+38F // max value used to detect an Error in processing
#define CMP_FLOAT_MAX_EXP               38
#define USE_PROCESS_SEPERATE_ALPHA          // Enable this to use higher quality code using CompressDualIndexBlock
#define COMPRESSED_BLOCK_SIZE           16  // Size of a compressed block in bytes
#define MAX_DIMENSION_BIG               4   // Max number of channels  (RGBA)
#define MAX_SUBSETS                     3   // Maximum number of possible subsets
#define MAX_SUBSET_SIZE                 16  // Largest possible size for an individual subset
#define BLOCK_SIZE_4X4X4                64
#define BLOCK_SIZE_4X4                  16
#define BlockX                          4
#define BlockY                          4
//#define USE_BLOCK_LINEAR    // Source Data is organized in linear form for each block : Experimental Code not fully developed 
//#define USE_DOUBLE          // Default is to use float, enable to use double data types only for float definitions

//---------------------------------------------
// Predefinitions for GPU and CPU compiled code
//---------------------------------------------

#ifdef ASPM_HLSL
       // ==== Vectors ====
       typedef float2  CGU_Vec2f;
       typedef float2  CGV_Vec2f;
       typedef float3  CGU_Vec3f;
       typedef float3  CGV_Vec3f;
       typedef float4  CGU_Vec4f;
       typedef float4  CGV_Vec4f;

       typedef int2    CGU_Vec2i;
       typedef int2    CGV_Vec2i;
       typedef uint2   CGU_Vec2ui;
       typedef uint2   CGV_Vec2ui;

       typedef int3    CGU_Vec3i;
       typedef int3    CGV_Vec3i;
       typedef uint3   CGU_Vec3ui;
       typedef uint3   CGV_Vec3ui;

       typedef uint4   CGU_Vec4ui;
       typedef uint4   CGV_Vec4ui;

       // ==== Scalar Types ==== to remove from code
       typedef int                  CGU_INT8;
       typedef uint                 CGU_INT;
       typedef int                  CGV_INT;
       typedef uint                 CGU_UINT8;
       typedef uint                 CGU_UINT;

       // ==== Scalar Types ====
       typedef int                  CGU_BOOL;
       typedef int                  CGV_BOOL;
       typedef int                  CGU_INT32;
       typedef int                  CGV_INT32;
       typedef uint                 CGU_UINT32;
       typedef uint                 CGV_UINT32;
       typedef float                CGV_FLOAT;
       typedef float                CGU_FLOAT;
       typedef min16float           CGU_MIN16_FLOAT;    // FP16 GPU support defaults to 32 bit if no HW support

        #define TRUE  1
        #define FALSE 0
        #define CMP_CDECL

        #define BC7_ENCODECLASS
        #define CMP_EXPORT
        #define INLINE
        #define uniform
        #define varying
        #define CMP_GLOBAL
        #define CMP_KERNEL
        #define CMP_CONSTANT
        #define CMP_STATIC
        #define CMP_REFINOUT
        #define CMP_PTRINOUT
        #define CMP_INOUT       inout
        #define CMP_OUT         out
        #define CMP_IN          in
        #define CMP_UNUSED(x)   (x);
        #define CMP_UNROLL      [unroll]



#else

typedef enum {
    CGU_CORE_OK = 0,                          // No errors, call was successfull
    CGU_CORE_ERR_UNKOWN,                      // An unknown error occurred
    CGU_CORE_ERR_NEWMEM,                      // New Memory Allocation Failed
    CGU_CORE_ERR_INVALIDPTR,                  // The pointer value used is invalid or null
    CGU_CORE_ERR_RANGERED,                    // values for Red   Channel is out of range (too high or too low)
    CGU_CORE_ERR_RANGEGREEN,                  // values for Green Channel is out of range (too high or too low)
    CGU_CORE_ERR_RANGEBLUE,                   // values for Blue  Channel is out of range (too high or too low)
} CGU_ERROR_CODES;


#ifdef ASPM_OPENCL  // GPU Based code using OpenCL
        // ==== Vectors ====
        typedef float2  CGU_Vec2f;
        typedef float2  CGV_Vec2f;
        typedef float3  CMP_Vec3f;
        typedef float3  CGU_Vec3f;
        typedef float3  CGV_Vec3f;
        typedef float4  CGU_Vec4f;
        typedef float4  CGV_Vec4f;

        typedef uchar3  CGU_Vec3uc;
        typedef uchar3  CGV_Vec3uc;

        typedef uchar4  CMP_Vec4uc;
        typedef uchar4  CGU_Vec4uc;
        typedef uchar4  CGV_Vec4uc;

        typedef int2   CGU_Vec2i;
        typedef int2   CGV_Vec2i;
        typedef int3   CGU_Vec3i;
        typedef int3   CGV_Vec3i;
        typedef int4   CGU_Vec4i;
        typedef int4   CGV_Vec4i;

        typedef uint2  CGU_Vec2ui;
        typedef uint2  CGV_Vec2ui;
        typedef uint3  CGU_Vec3ui;
        typedef uint3  CGV_Vec3ui;
        typedef uint4  CGU_Vec4ui;
        typedef uint4  CGV_Vec4ui;


        #define USE_BC7_SP_ERR_IDX
        #define BC7_ENCODECLASS
        #define ASPM_PRINT(args)      printf args

        #define CMP_EXPORT
        #define INLINE
        #define uniform
        #define varying
        #define CMP_GLOBAL          __global
        #define CMP_KERNEL          __kernel
        #define CMP_CONSTANT        __constant
        #define CMP_STATIC
        #define CMP_REFINOUT        &
        #define CMP_PTRINOUT        *
        #define CMP_INOUT
        #define CMP_OUT
        #define CMP_IN
        #define CMP_UNUSED(x)
        #define CMP_UNROLL

        typedef unsigned int        CGU_DWORD;      //32bits
        typedef int                 CGU_INT;        //32bits
        typedef bool                CGU_BOOL;
        typedef unsigned short      CGU_SHORT;      //16bits
        typedef float               CGU_FLOAT;
        typedef half                CGU_MIN16_FLOAT;    // FP16 GPU support defaults to 32 bit if no HW support
        typedef unsigned int        uint32;     // need to remove this def

        typedef int                 CGV_INT;
        typedef unsigned int        CGU_UINT;
        typedef int                 CGUV_INT;
        typedef int                 CGV_BOOL;

        typedef char                CGU_INT8;
        typedef unsigned char       CGU_UINT8;
        typedef short               CGU_INT16;
        typedef unsigned short      CGU_UINT16;
        typedef int                 CGU_INT32;
        typedef unsigned int        CGU_UINT32;
        typedef unsigned long       CGU_UINT64;

        typedef char                CGV_INT8;
        typedef unsigned char       CGV_UINT8;
        typedef short               CGV_INT16;
        typedef unsigned short      CGV_UINT16;
        typedef int                 CGV_INT32;
        typedef unsigned int        CGV_UINT32;
        typedef unsigned long       CGV_UINT64;

        typedef float               CGV_FLOAT;

        #define TRUE  1
        #define FALSE 0
        #define CMP_CDECL

#else
    // CPU & ASPM definitions

    #define CMP_REFINOUT        &
    #define CMP_PTRINOUT        *
    #define CMP_INOUT
    #define CMP_OUT
    #define CMP_IN
    #define CMP_UNUSED(x)       (void)(x);
    #define CMP_UNROLL


    #ifdef ASPM // SPMD ,SIMD CPU code
        // using hybrid (CPU/GPU) aspm compiler 
        #define ASPM_PRINT(args)       print args
        #define CMP_USE_FOREACH_ASPM
        #define __ASPM__
        #define BC7_ENCODECLASS

        #define USE_BC7_SP_ERR_IDX
        //#define USE_BC7_RAMP

        #define CMP_EXPORT          export
        #define TRUE            true
        #define FALSE           false
        typedef uniform bool    CGU_BOOL;
        typedef bool            CGV_BOOL;

        typedef unsigned int8   uint8;
        typedef unsigned int16  uint16;
        typedef unsigned int32  uint32;
        typedef unsigned int64  uint64;
        typedef uniform float   CGU_FLOAT;
        typedef varying float   CGV_FLOAT;
        typedef uniform float   CGU_MIN16_FLOAT;

        typedef uniform uint8   CGU_UINT8;
        typedef varying uint8   CGV_UINT8;


        typedef CGV_UINT8<4> CGV_Vec4uc;
        typedef CGU_UINT8<4> CGU_Vec4uc;

        typedef CGU_FLOAT<2> CGU_Vec2f;
        typedef CGV_FLOAT<2> CGV_Vec2f;
        typedef CGU_FLOAT<3> CGU_Vec3f;
        typedef CGV_FLOAT<3> CGV_Vec3f;
        typedef CGU_FLOAT<4> CGU_Vec4f;
        typedef CGV_FLOAT<4> CGV_Vec4f;

        typedef CGU_UINT32<3> CGU_Vec3ui;
        typedef CGV_UINT32<3> CGV_Vec3ui;

        typedef CGU_UINT32<4> CGU_Vec4ui;
        typedef CGV_UINT32<4> CGV_Vec4ui;

        #define CMP_CDECL
    #else   // standard CPU code
        #include <stdio.h>
        #include <string>
        #include INC_cmp_math_vec4

        // using CPU compiler
        #define ASPM_PRINT(args)  printf args
        #define USE_BC7_RAMP
        #define USE_BC7_SP_ERR_IDX

        #define CMP_EXPORT
        #define BC7_ENCODECLASS BC7_EncodeClass::
        #define TRUE            1
        #define FALSE           0
        #define uniform
        #define varying

        typedef char            int8;
        typedef short           int16;
        typedef int             int32;
        typedef long            int64;
        typedef unsigned char   uint8;
        typedef unsigned short  uint16;
        typedef unsigned int    uint32;
        typedef unsigned long   uint64;

        typedef int8            CGV_BOOL;
        typedef bool            CGU_BOOL;
        typedef int16           CGU_WORD;
        typedef uint8           CGU_SHORT;
        typedef int64           CGU_LONG;
        typedef uint64          CGU_ULONG;

        typedef uniform float   CGU_FLOAT;
        typedef varying float   CGV_FLOAT;
        typedef uniform float   CGU_MIN16_FLOAT;

        typedef uniform uint8   CGU_UINT8;
        typedef varying uint8   CGV_UINT8;

        typedef CMP_Vec3ui      CGU_Vec3ui;
        typedef CMP_Vec3ui      CGV_Vec3ui;

        typedef CMP_Vec4ui      CGU_Vec4ui;
        typedef CMP_Vec4ui      CGV_Vec4ui;
        typedef CMP_Vec4f       CGU_Vec4f;
        typedef CMP_Vec4f       CGV_Vec4f;

        #if defined(WIN32) || defined(_WIN64)
        #define CMP_CDECL __cdecl
        #else
        #define CMP_CDECL
        #endif
    #endif

    // Common CPU & ASPM definitions
    #define CMP_ASSERT(arg)

    #define CMP_GLOBAL

    #define CMP_KERNEL
    #define __local                 const
    #define __constant              const
    #define CMP_CONSTANT            const
    #define INLINE                  inline
    #define CMP_STATIC              static


    typedef uniform int32           CGU_DWORD;
    typedef uniform uint8           CGU_UBYTE;
    typedef uniform int             CGU_INT;
    typedef uniform int8            CGU_INT8;

    typedef uniform int16           CGU_INT16;
    typedef uniform uint16          CGU_UINT16;
    typedef uniform int32           CGU_INT32;
    typedef uniform uint32          CGU_UINT32;
    typedef uniform uint64          CGU_UINT64;

    typedef int                     CGV_INT;
    typedef int8                    CGV_INT8;
    typedef int16                   CGV_INT16;
    typedef int32                   CGV_INT32;
    typedef uint16                  CGV_UINT16;
    typedef uint32                  CGV_UINT32;
    typedef uint64                  CGV_UINT64;


#endif // else ASPM_GPU

typedef struct 
{
    CGU_UINT32     m_src_width;
    CGU_UINT32     m_src_height;
    CGU_UINT32     m_width_in_blocks;
    CGU_UINT32     m_height_in_blocks;
    CGU_FLOAT      m_fquality;
} Source_Info;

typedef unsigned char*  CGU_PTR;

// Ref Compute_CPU_HPC
struct texture_surface
{
    CGU_PTR     ptr;
    CGU_INT     width,
                height,
                stride;
    CGU_INT     channels;
};


#endif // else ASPM_HLSL

#endif // Common_Def.h
 

<|start_filename|>src/nvcore/Library.h<|end_filename|>
// This code is in the public domain -- <EMAIL>

#pragma once
#ifndef NV_CORE_LIBRARY_H
#define NV_CORE_LIBRARY_H

#include "nvcore.h"

#if NV_OS_WIN32
#define LIBRARY_NAME(name)	#name ".dll"
#elif NV_OS_DARWIN
#define NV_LIBRARY_NAME(name)	"lib" #name ".dylib"
#else
#define NV_LIBRARY_NAME(name)	"lib" #name ".so"
#endif

NVCORE_API void * nvLoadLibrary(const char * name);
NVCORE_API void nvUnloadLibrary(void * lib);
NVCORE_API void * nvBindSymbol(void * lib, const char * symbol);

class NVCORE_CLASS Library
{
public:
    Library(const char * name)
    {
        handle = nvLoadLibrary(name);
    }
    ~Library()
    {
        if (isValid())
        {
            nvUnloadLibrary(handle);
        }
    }

    bool isValid() const
    {
        return handle != NULL;
    }

    void * bindSymbol(const char * symbol)
    {
        return nvBindSymbol(handle, symbol);
    }

private:
    void * handle;
};


#endif // NV_CORE_LIBRARY_H

<|start_filename|>src/nvtt/cuda/CudaCompressorDXT.cpp<|end_filename|>
// Copyright (c) 2009-2011 <NAME> <<EMAIL>>
// Copyright (c) 2007-2009 NVIDIA Corporation -- <NAME> <<EMAIL>>
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include "CudaCompressorDXT.h"
#include "CudaUtils.h"

#include "nvcore/Debug.h"
#include "nvmath/Color.h"
#include "nvmath/Vector.inl"
#include "nvimage/Image.h"
#include "nvimage/ColorBlock.h"
#include "nvimage/BlockDXT.h"
#include "nvtt/CompressionOptions.h"
#include "nvtt/OutputOptions.h"
#include "nvtt/QuickCompressDXT.h"
#include "nvtt/OptimalCompressDXT.h"

#include <time.h>
#include <stdio.h>

#if defined HAVE_CUDA
#include <cuda_runtime_api.h>

#define MAX_BLOCKS 8192U // 32768, 65535 // @@ Limit number of blocks on slow devices to prevent hitting the watchdog timer.

extern "C" void setupOMatchTables(const void * OMatch5Src, size_t OMatch5Size, const void * OMatch6Src, size_t OMatch6Size);
extern "C" void setupCompressKernel(const float weights[3]);
extern "C" void bindTextureToArray(cudaArray * d_data);

extern "C" void compressKernelDXT1(uint firstBlock, uint blockNum, uint w, uint * d_result, uint * d_bitmaps);
extern "C" void compressKernelDXT1_Level4(uint blockNum, uint * d_data, uint * d_result, uint * d_bitmaps);
extern "C" void compressWeightedKernelDXT1(uint blockNum, uint * d_data, uint * d_result, uint * d_bitmaps);
extern "C" void compressKernelDXT3(uint firstBlock, uint blockNum, uint w, uint * d_result, uint * d_bitmaps);
//extern "C" void compressNormalKernelDXT1(uint blockNum, uint * d_data, uint * d_result, uint * d_bitmaps);
//extern "C" void compressKernelCTX1(uint blockNum, uint * d_data, uint * d_result, uint * d_bitmaps);

#include "BitmapTable.h"
#include "nvtt/SingleColorLookup.h"

#endif

using namespace nv;
using namespace nvtt;


CudaContext::CudaContext() : 
	bitmapTable(NULL), 
	bitmapTableCTX(NULL), 
	data(NULL), 
	result(NULL)
{
#if defined HAVE_CUDA
    // Allocate and upload bitmaps.
    cudaMalloc((void**) &bitmapTable, 992 * sizeof(uint));
    if (bitmapTable != NULL)
    {
        cudaMemcpy(bitmapTable, s_bitmapTable, 992 * sizeof(uint), cudaMemcpyHostToDevice);
    }

    cudaMalloc((void**) &bitmapTableCTX, 704 * sizeof(uint));
    if (bitmapTableCTX != NULL)
    {
        cudaMemcpy(bitmapTableCTX, s_bitmapTableCTX, 704 * sizeof(uint), cudaMemcpyHostToDevice);
    }

    // Allocate scratch buffers.
    cudaMalloc((void**) &data, MAX_BLOCKS * 64U);
    cudaMalloc((void**) &result, MAX_BLOCKS * 8U);

    // Init single color lookup contant tables.
	setupOMatchTables(OMatch5, sizeof(OMatch5), OMatch6, sizeof(OMatch6));
#endif
}

CudaContext::~CudaContext()
{
#if defined HAVE_CUDA
    // Free device mem allocations.
    cudaFree(bitmapTableCTX);
    cudaFree(bitmapTable);
    cudaFree(data);
    cudaFree(result);
#endif
}

bool CudaContext::isValid() const
{
#if defined HAVE_CUDA
    cudaError_t err = cudaGetLastError();
    if (err != cudaSuccess)
    {
        nvDebug("*** CUDA Error: %s\n", cudaGetErrorString(err));
        return false;
    }
#endif
    return bitmapTable != NULL && bitmapTableCTX != NULL && data != NULL && result != NULL;
}


#if defined HAVE_CUDA

CudaCompressor::CudaCompressor(CudaContext & ctx) : m_ctx(ctx)
{

}

void CudaCompressor::compress(nvtt::AlphaMode alphaMode, uint w, uint h, uint d, const float * data, nvtt::TaskDispatcher * dispatcher, const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions)
{
    nvDebugCheck(d == 1);
    nvDebugCheck(cuda::isHardwarePresent());

#if defined HAVE_CUDA

    // Allocate image as a cuda array.
    const uint count = w * h;
    Color32 * tmp = malloc<Color32>(count);
    for (uint i = 0; i < count; i++) {
        tmp[i].r = uint8(clamp(data[i + count*0], 0.0f, 1.0f) * 255);
        tmp[i].g = uint8(clamp(data[i + count*1], 0.0f, 1.0f) * 255);
        tmp[i].b = uint8(clamp(data[i + count*2], 0.0f, 1.0f) * 255);
        tmp[i].a = uint8(clamp(data[i + count*3], 0.0f, 1.0f) * 255);
    }

    cudaArray * d_image;
    cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(8, 8, 8, 8, cudaChannelFormatKindUnsigned);
    cudaMallocArray(&d_image, &channelDesc, w, h);

    cudaMemcpyToArray(d_image, 0, 0, tmp, count * sizeof(Color32), cudaMemcpyHostToDevice);

    free(tmp);

    // To avoid the copy we could keep the data in floating point format, but the channels are not interleaved like the kernel expects.
    /*
    cudaChannelFormatDesc channelDesc = cudaCreateChannelDesc(32, 32, 32, 32, cudaChannelFormatKindFloat);
    cudaMallocArray(&d_image, &channelDesc, w, h);

    const int imageSize = w * h * sizeof(float) * 4;
    cudaMemcpyToArray(d_image, 0, 0, data, imageSize, cudaMemcpyHostToDevice);
    */

    // Image size in blocks.
    const uint bw = (w + 3) / 4;
    const uint bh = (h + 3) / 4;
    const uint bs = blockSize();
    const uint blockNum = bw * bh;
    //const uint compressedSize = blockNum * bs;

    void * h_result = ::malloc(min(blockNum, MAX_BLOCKS) * bs);

    setup(d_image, compressionOptions);

    // Timer timer;
    // timer.start();

    uint bn = 0;
    while (bn != blockNum)
    {
        uint count = min(blockNum - bn, MAX_BLOCKS);

        compressBlocks(bn, count, bw, bh, alphaMode, compressionOptions, h_result);

        // Check for errors.
        cudaError_t err = cudaGetLastError();
        if (err != cudaSuccess)
        {
            //nvDebug("CUDA Error: %s\n", cudaGetErrorString(err));
            outputOptions.error(Error_CudaError);
        }

        // Output result.
        outputOptions.writeData(h_result, count * bs);

        bn += count;
    }

    //timer.stop();
    //printf("\rCUDA time taken: %.3f seconds\n", timer.elapsed() / CLOCKS_PER_SEC);

    free(h_result);
    cudaFreeArray(d_image);

#else
    outputOptions.error(Error_CudaError);
#endif
}

#if defined HAVE_CUDA

void CudaCompressorDXT1::setup(cudaArray * image, const nvtt::CompressionOptions::Private & compressionOptions)
{
    setupCompressKernel(compressionOptions.colorWeight.ptr());
    bindTextureToArray(image);
}

void CudaCompressorDXT1::compressBlocks(uint first, uint count, uint bw, uint bh, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
    // Launch kernel.
    compressKernelDXT1(first, count, bw, m_ctx.result, m_ctx.bitmapTable);

    // Copy result to host.
    cudaMemcpy(output, m_ctx.result, count * 8, cudaMemcpyDeviceToHost);
}


void CudaCompressorDXT3::setup(cudaArray * image, const nvtt::CompressionOptions::Private & compressionOptions)
{
    setupCompressKernel(compressionOptions.colorWeight.ptr());
    bindTextureToArray(image);
}

void CudaCompressorDXT3::compressBlocks(uint first, uint count, uint bw, uint bh, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
    // Launch kernel.
    compressKernelDXT3(first, count, bw, m_ctx.result, m_ctx.bitmapTable);

    // Copy result to host.
    cudaMemcpy(output, m_ctx.result, count * 16, cudaMemcpyDeviceToHost);
}


void CudaCompressorDXT5::setup(cudaArray * image, const nvtt::CompressionOptions::Private & compressionOptions)
{
    setupCompressKernel(compressionOptions.colorWeight.ptr());
    bindTextureToArray(image);
}

void CudaCompressorDXT5::compressBlocks(uint first, uint count, uint bw, uint bh, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
    /*// Launch kernel.
    compressKernelDXT5(first, count, bw, m_ctx.result, m_ctx.bitmapTable);

    // Copy result to host.
    cudaMemcpy(output, m_ctx.result, count * 16, cudaMemcpyDeviceToHost);*/

    // Launch kernel.
    if (alphaMode == AlphaMode_Transparency)
    {
    //	compressWeightedKernelDXT1(first, count, bw, m_ctx.result, m_ctx.bitmapTable);
    }
    else
    {
    //	compressKernelDXT1_Level4(first, count, w, m_ctx.result, m_ctx.bitmapTable);
    }

    // Compress alpha in parallel with the GPU.
    for (uint i = 0; i < count; i++)
    {
        //ColorBlock rgba(blockLinearImage + (first + i) * 16);
        //OptimalCompress::compressDXT3A(rgba, alphaBlocks + i);
    }

    // Copy result to host.
    cudaMemcpy(output, m_ctx.result, count * 8, cudaMemcpyDeviceToHost);

    // @@ Interleave color and alpha blocks.

}

#endif // defined HAVE_CUDA




// @@ This code is very repetitive and needs to be cleaned up.

#if 0


/*
// Convert linear image to block linear.
static void convertToBlockLinear(const Image * image, uint * blockLinearImage)
{
	const uint w = (image->width() + 3) / 4;
	const uint h = (image->height() + 3) / 4;

	for(uint by = 0; by < h; by++) {
		for(uint bx = 0; bx < w; bx++) {
			const uint bw = min(image->width() - bx * 4, 4U);
			const uint bh = min(image->height() - by * 4, 4U);

			for (uint i = 0; i < 16; i++) {
				const int x = (i % 4) % bw;
				const int y = (i / 4) % bh;
				blockLinearImage[(by * w + bx) * 16 + i] = image->pixel(bx * 4 + x, by * 4 + y).u;
			}
		}
	}
}
*/


/// Compress image using CUDA.
void CudaCompressor::compressDXT3(const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions)
{
	nvDebugCheck(cuda::isHardwarePresent());
#if defined HAVE_CUDA

	// Image size in blocks.
	const uint w = (m_image->width() + 3) / 4;
	const uint h = (m_image->height() + 3) / 4;

	uint imageSize = w * h * 16 * sizeof(Color32);
    uint * blockLinearImage = (uint *) malloc(imageSize);
	convertToBlockLinear(m_image, blockLinearImage);

	const uint blockNum = w * h;
	const uint compressedSize = blockNum * 8;

	AlphaBlockDXT3 * alphaBlocks = NULL;
	alphaBlocks = (AlphaBlockDXT3 *)malloc(min(compressedSize, MAX_BLOCKS * 8U));

	setupCompressKernel(compressionOptions.colorWeight.ptr());
	
	clock_t start = clock();

	uint bn = 0;
	while(bn != blockNum)
	{
		uint count = min(blockNum - bn, MAX_BLOCKS);

	    cudaMemcpy(m_ctx.data, blockLinearImage + bn * 16, count * 64, cudaMemcpyHostToDevice);

		// Launch kernel.
		if (m_alphaMode == AlphaMode_Transparency)
		{
			compressWeightedKernelDXT1(count, m_ctx.data, m_ctx.result, m_ctx.bitmapTable);
		}
		else
		{
			compressKernelDXT1_Level4(count, m_ctx.data, m_ctx.result, m_ctx.bitmapTable);
		}

		// Compress alpha in parallel with the GPU.
		for (uint i = 0; i < count; i++)
		{
			ColorBlock rgba(blockLinearImage + (bn + i) * 16);
			OptimalCompress::compressDXT3A(rgba, alphaBlocks + i);
		}

		// Check for errors.
		cudaError_t err = cudaGetLastError();
		if (err != cudaSuccess)
		{
			nvDebug("CUDA Error: %s\n", cudaGetErrorString(err));
			outputOptions.error(Error_CudaError);
		}

		// Copy result to host, overwrite swizzled image.
		cudaMemcpy(blockLinearImage, m_ctx.result, count * 8, cudaMemcpyDeviceToHost);

		// Output result.
		for (uint i = 0; i < count; i++)
		{
			outputOptions.writeData(alphaBlocks + i, 8);
			outputOptions.writeData(blockLinearImage + i * 2, 8);
		}

		bn += count;
	}

	clock_t end = clock();
	//printf("\rCUDA time taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC);

	free(alphaBlocks);
	free(blockLinearImage);

#else
	outputOptions.error(Error_CudaError);
#endif
}


/// Compress image using CUDA.
void CudaCompressor::compressDXT5(const CompressionOptions::Private & compressionOptions, const OutputOptions::Private & outputOptions)
{
	nvDebugCheck(cuda::isHardwarePresent());
#if defined HAVE_CUDA

	// Image size in blocks.
	const uint w = (m_image->width() + 3) / 4;
	const uint h = (m_image->height() + 3) / 4;

	uint imageSize = w * h * 16 * sizeof(Color32);
    uint * blockLinearImage = (uint *) malloc(imageSize);
	convertToBlockLinear(m_image, blockLinearImage);

	const uint blockNum = w * h;
	const uint compressedSize = blockNum * 8;

	AlphaBlockDXT5 * alphaBlocks = NULL;
	alphaBlocks = (AlphaBlockDXT5 *)malloc(min(compressedSize, MAX_BLOCKS * 8U));

	setupCompressKernel(compressionOptions.colorWeight.ptr());
	
	clock_t start = clock();

	uint bn = 0;
	while(bn != blockNum)
	{
		uint count = min(blockNum - bn, MAX_BLOCKS);

	    cudaMemcpy(m_ctx.data, blockLinearImage + bn * 16, count * 64, cudaMemcpyHostToDevice);

		// Launch kernel.
		if (m_alphaMode == AlphaMode_Transparency)
		{
			compressWeightedKernelDXT1(count, m_ctx.data, m_ctx.result, m_ctx.bitmapTable);
		}
		else
		{
			compressKernelDXT1_Level4(count, m_ctx.data, m_ctx.result, m_ctx.bitmapTable);
		}

		// Compress alpha in parallel with the GPU.
		for (uint i = 0; i < count; i++)
		{
			ColorBlock rgba(blockLinearImage + (bn + i) * 16);
			QuickCompress::compressDXT5A(rgba, alphaBlocks + i);
		}

		// Check for errors.
		cudaError_t err = cudaGetLastError();
		if (err != cudaSuccess)
		{
			nvDebug("CUDA Error: %s\n", cudaGetErrorString(err));
			outputOptions.error(Error_CudaError);
		}

		// Copy result to host, overwrite swizzled image.
		cudaMemcpy(blockLinearImage, m_ctx.result, count * 8, cudaMemcpyDeviceToHost);

		// Output result.
		for (uint i = 0; i < count; i++)
		{
			outputOptions.writeData(alphaBlocks + i, 8);
			outputOptions.writeData(blockLinearImage + i * 2, 8);
		}

		bn += count;
	}

	clock_t end = clock();
	//printf("\rCUDA time taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC);

	free(alphaBlocks);
	free(blockLinearImage);

#else
	outputOptions.error(Error_CudaError);
#endif
}


void CudaCompressor::compressDXT1n(const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions)
{
	nvDebugCheck(cuda::isHardwarePresent());
#if defined HAVE_CUDA

	// Image size in blocks.
	const uint w = (m_image->width() + 3) / 4;
	const uint h = (m_image->height() + 3) / 4;

	uint imageSize = w * h * 16 * sizeof(Color32);
    uint * blockLinearImage = (uint *) malloc(imageSize);
	convertToBlockLinear(m_image, blockLinearImage);	// @@ Do this in parallel with the GPU, or in the GPU!

	const uint blockNum = w * h;
	const uint compressedSize = blockNum * 8;

	clock_t start = clock();

	setupCompressKernel(compressionOptions.colorWeight.ptr());
	
	// TODO: Add support for multiple GPUs.
	uint bn = 0;
	while(bn != blockNum)
	{
		uint count = min(blockNum - bn, MAX_BLOCKS);

	    cudaMemcpy(m_ctx.data, blockLinearImage + bn * 16, count * 64, cudaMemcpyHostToDevice);

		// Launch kernel.
		compressNormalKernelDXT1(count, m_ctx.data, m_ctx.result, m_ctx.bitmapTable);

		// Check for errors.
		cudaError_t err = cudaGetLastError();
		if (err != cudaSuccess)
		{
			nvDebug("CUDA Error: %s\n", cudaGetErrorString(err));
			outputOptions.error(Error_CudaError);
		}

		// Copy result to host, overwrite swizzled image.
		cudaMemcpy(blockLinearImage, m_ctx.result, count * 8, cudaMemcpyDeviceToHost);

		// Output result.
		outputOptions.writeData(blockLinearImage, count * 8);

		bn += count;
	}

	clock_t end = clock();
	//printf("\rCUDA time taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC);

	free(blockLinearImage);

#else
	outputOptions.error(Error_CudaError);
#endif
}


void CudaCompressor::compressCTX1(const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions)
{
	nvDebugCheck(cuda::isHardwarePresent());
#if defined HAVE_CUDA

	// Image size in blocks.
	const uint w = (m_image->width() + 3) / 4;
	const uint h = (m_image->height() + 3) / 4;

	uint imageSize = w * h * 16 * sizeof(Color32);
    uint * blockLinearImage = (uint *) malloc(imageSize);
	convertToBlockLinear(m_image, blockLinearImage);	// @@ Do this in parallel with the GPU, or in the GPU!

	const uint blockNum = w * h;
	const uint compressedSize = blockNum * 8;

	clock_t start = clock();

	setupCompressKernel(compressionOptions.colorWeight.ptr());
	
	// TODO: Add support for multiple GPUs.
	uint bn = 0;
	while(bn != blockNum)
	{
		uint count = min(blockNum - bn, MAX_BLOCKS);

	    cudaMemcpy(m_ctx.data, blockLinearImage + bn * 16, count * 64, cudaMemcpyHostToDevice);

		// Launch kernel.
		compressKernelCTX1(count, m_ctx.data, m_ctx.result, m_ctx.bitmapTableCTX);

		// Check for errors.
		cudaError_t err = cudaGetLastError();
		if (err != cudaSuccess)
		{
			nvDebug("CUDA Error: %s\n", cudaGetErrorString(err));

			outputOptions.error(Error_CudaError);
		}

		// Copy result to host, overwrite swizzled image.
		cudaMemcpy(blockLinearImage, m_ctx.result, count * 8, cudaMemcpyDeviceToHost);

		// Output result.
		outputOptions.writeData(blockLinearImage, count * 8);

		bn += count;
	}

	clock_t end = clock();
	//printf("\rCUDA time taken: %.3f seconds\n", float(end-start) / CLOCKS_PER_SEC);

	free(blockLinearImage);

#else
	outputOptions.error(Error_CudaError);
#endif
}


void CudaCompressor::compressDXT5n(const nvtt::CompressionOptions::Private & compressionOptions, const nvtt::OutputOptions::Private & outputOptions)
{
	nvDebugCheck(cuda::isHardwarePresent());
#if defined HAVE_CUDA

	// @@ TODO

#else
	outputOptions.error(Error_CudaError);
#endif
}

#endif // 0

#endif // defined HAVE_CUDA


<|start_filename|>src/bc7/shapes_two.h<|end_filename|>
/*
Copyright 2007 nVidia, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 

You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

See the License for the specific language governing permissions and limitations under the License.
*/

#ifndef _AVPCL_SHAPES_TWO_H
#define _AVPCL_SHAPES_TWO_H

// shapes for two regions

#define NREGIONS 2
#define NSHAPES 64
#define SHAPEBITS 6

static int shapes[NSHAPES*16] = 
{
0, 0, 1, 1,   0, 0, 0, 1,   0, 1, 1, 1,   0, 0, 0, 1,   
0, 0, 1, 1,   0, 0, 0, 1,   0, 1, 1, 1,   0, 0, 1, 1,   
0, 0, 1, 1,   0, 0, 0, 1,   0, 1, 1, 1,   0, 0, 1, 1,   
0, 0, 1, 1,   0, 0, 0, 1,   0, 1, 1, 1,   0, 1, 1, 1,   

0, 0, 0, 0,   0, 0, 1, 1,   0, 0, 0, 1,   0, 0, 0, 0,   
0, 0, 0, 1,   0, 1, 1, 1,   0, 0, 1, 1,   0, 0, 0, 1,   
0, 0, 0, 1,   0, 1, 1, 1,   0, 1, 1, 1,   0, 0, 1, 1,   
0, 0, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1,   0, 1, 1, 1,   

0, 0, 0, 0,   0, 0, 1, 1,   0, 0, 0, 0,   0, 0, 0, 0,   
0, 0, 0, 0,   0, 1, 1, 1,   0, 0, 0, 1,   0, 0, 0, 0,   
0, 0, 0, 1,   1, 1, 1, 1,   0, 1, 1, 1,   0, 0, 0, 1,   
0, 0, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1,   0, 1, 1, 1,   

0, 0, 0, 1,   0, 0, 0, 0,   0, 0, 0, 0,   0, 0, 0, 0,   
0, 1, 1, 1,   0, 0, 0, 0,   1, 1, 1, 1,   0, 0, 0, 0,   
1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1,   0, 0, 0, 0,   
1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1,   1, 1, 1, 1,   

0, 0, 0, 0,   0, 1, 1, 1,   0, 0, 0, 0,   0, 1, 1, 1,   
1, 0, 0, 0,   0, 0, 0, 1,   0, 0, 0, 0,   0, 0, 1, 1,   
1, 1, 1, 0,   0, 0, 0, 0,   1, 0, 0, 0,   0, 0, 0, 1,   
1, 1, 1, 1,   0, 0, 0, 0,   1, 1, 1, 0,   0, 0, 0, 0,   

0, 0, 1, 1,   0, 0, 0, 0,   0, 0, 0, 0,   0, 1, 1, 1,   
0, 0, 0, 1,   1, 0, 0, 0,   0, 0, 0, 0,   0, 0, 1, 1,   
0, 0, 0, 0,   1, 1, 0, 0,   1, 0, 0, 0,   0, 0, 1, 1,   
0, 0, 0, 0,   1, 1, 1, 0,   1, 1, 0, 0,   0, 0, 0, 1,   

0, 0, 1, 1,   0, 0, 0, 0,   0, 1, 1, 0,   0, 0, 1, 1,   
0, 0, 0, 1,   1, 0, 0, 0,   0, 1, 1, 0,   0, 1, 1, 0,   
0, 0, 0, 1,   1, 0, 0, 0,   0, 1, 1, 0,   0, 1, 1, 0,   
0, 0, 0, 0,   1, 1, 0, 0,   0, 1, 1, 0,   1, 1, 0, 0,   

0, 0, 0, 1,   0, 0, 0, 0,   0, 1, 1, 1,   0, 0, 1, 1,   
0, 1, 1, 1,   1, 1, 1, 1,   0, 0, 0, 1,   1, 0, 0, 1,   
1, 1, 1, 0,   1, 1, 1, 1,   1, 0, 0, 0,   1, 0, 0, 1,   
1, 0, 0, 0,   0, 0, 0, 0,   1, 1, 1, 0,   1, 1, 0, 0,   

0, 1, 0, 1,   0, 0, 0, 0,   0, 1, 0, 1,   0, 0, 1, 1,   
0, 1, 0, 1,   1, 1, 1, 1,   1, 0, 1, 0,   0, 0, 1, 1,   
0, 1, 0, 1,   0, 0, 0, 0,   0, 1, 0, 1,   1, 1, 0, 0,   
0, 1, 0, 1,   1, 1, 1, 1,   1, 0, 1, 0,   1, 1, 0, 0,   

0, 0, 1, 1,   0, 1, 0, 1,   0, 1, 1, 0,   0, 1, 0, 1,   
1, 1, 0, 0,   0, 1, 0, 1,   1, 0, 0, 1,   1, 0, 1, 0,   
0, 0, 1, 1,   1, 0, 1, 0,   0, 1, 1, 0,   1, 0, 1, 0,   
1, 1, 0, 0,   1, 0, 1, 0,   1, 0, 0, 1,   0, 1, 0, 1,   

0, 1, 1, 1,   0, 0, 0, 1,   0, 0, 1, 1,   0, 0, 1, 1,   
0, 0, 1, 1,   0, 0, 1, 1,   0, 0, 1, 0,   1, 0, 1, 1,   
1, 1, 0, 0,   1, 1, 0, 0,   0, 1, 0, 0,   1, 1, 0, 1,   
1, 1, 1, 0,   1, 0, 0, 0,   1, 1, 0, 0,   1, 1, 0, 0,   

0, 1, 1, 0,   0, 0, 1, 1,   0, 1, 1, 0,   0, 0, 0, 0,   
1, 0, 0, 1,   1, 1, 0, 0,   0, 1, 1, 0,   0, 1, 1, 0,   
1, 0, 0, 1,   1, 1, 0, 0,   1, 0, 0, 1,   0, 1, 1, 0,   
0, 1, 1, 0,   0, 0, 1, 1,   1, 0, 0, 1,   0, 0, 0, 0,   

0, 1, 0, 0,   0, 0, 1, 0,   0, 0, 0, 0,   0, 0, 0, 0,   
1, 1, 1, 0,   0, 1, 1, 1,   0, 0, 1, 0,   0, 1, 0, 0,   
0, 1, 0, 0,   0, 0, 1, 0,   0, 1, 1, 1,   1, 1, 1, 0,   
0, 0, 0, 0,   0, 0, 0, 0,   0, 0, 1, 0,   0, 1, 0, 0,   

0, 1, 1, 0,   0, 0, 1, 1,   0, 1, 1, 0,   0, 0, 1, 1,   
1, 1, 0, 0,   0, 1, 1, 0,   0, 0, 1, 1,   1, 0, 0, 1,   
1, 0, 0, 1,   1, 1, 0, 0,   1, 0, 0, 1,   1, 1, 0, 0,   
0, 0, 1, 1,   1, 0, 0, 1,   1, 1, 0, 0,   0, 1, 1, 0,   

0, 1, 1, 0,   0, 1, 1, 0,   0, 1, 1, 1,   0, 0, 0, 1,   
1, 1, 0, 0,   0, 0, 1, 1,   1, 1, 1, 0,   1, 0, 0, 0,   
1, 1, 0, 0,   0, 0, 1, 1,   1, 0, 0, 0,   1, 1, 1, 0,   
1, 0, 0, 1,   1, 0, 0, 1,   0, 0, 0, 1,   0, 1, 1, 1,   

0, 0, 0, 0,   0, 0, 1, 1,   0, 0, 1, 0,   0, 1, 0, 0,   
1, 1, 1, 1,   0, 0, 1, 1,   0, 0, 1, 0,   0, 1, 0, 0,   
0, 0, 1, 1,   1, 1, 1, 1,   1, 1, 1, 0,   0, 1, 1, 1,   
0, 0, 1, 1,   0, 0, 0, 0,   1, 1, 1, 0,   0, 1, 1, 1,   

};

#define	REGION(x,y,si)	shapes[((si)&3)*4+((si)>>2)*64+(x)+(y)*16]

static int shapeindex_to_compressed_indices[NSHAPES*2] = 
{
	0,15,  0,15,  0,15,  0,15,
	0,15,  0,15,  0,15,  0,15,
	0,15,  0,15,  0,15,  0,15,
	0,15,  0,15,  0,15,  0,15,

	0,15,  0, 2,  0, 8,  0, 2,
	0, 2,  0, 8,  0, 8,  0,15,
	0, 2,  0, 8,  0, 2,  0, 2,
	0, 8,  0, 8,  0, 2,  0, 2,

	0,15,  0,15,  0, 6,  0, 8,
	0, 2,  0, 8,  0,15,  0,15,
	0, 2,  0, 8,  0, 2,  0, 2,
	0, 2,  0,15,  0,15,  0, 6,

	0, 6,  0, 2,  0, 6,  0, 8,
	0,15,  0,15,  0, 2,  0, 2,
	0,15,  0,15,  0,15,  0,15,
	0,15,  0, 2,  0, 2,  0,15

};
#define SHAPEINDEX_TO_COMPRESSED_INDICES(si,region)  shapeindex_to_compressed_indices[(si)*2+(region)]

#endif


<|start_filename|>src/nvcore/DefsGnucLinux.h<|end_filename|>
#ifndef NV_CORE_H
#error "Do not include this file directly."
#endif

#include <stdint.h> // uint8_t, int8_t, ... uintptr_t
#include <stddef.h> // operator new, size_t, NULL

// Function linkage
#define DLL_IMPORT
#if __GNUC__ >= 4
#   define DLL_EXPORT   __attribute__((visibility("default")))
#   define DLL_EXPORT_CLASS DLL_EXPORT
#else
#   define DLL_EXPORT
#   define DLL_EXPORT_CLASS
#endif

// Function calling modes
#if NV_CPU_X86
#   define NV_CDECL     __attribute__((cdecl))
#   define NV_STDCALL   __attribute__((stdcall))
#else
#   define NV_CDECL 
#   define NV_STDCALL
#endif

#define NV_FASTCALL     __attribute__((fastcall))
//#if __GNUC__ > 3
// It seems that GCC does not assume always_inline implies inline. I think this depends on the GCC version :(
#define NV_FORCEINLINE  inline __attribute__((always_inline))
//#else
// Some compilers complain that inline and always_inline are redundant.
//#define NV_FORCEINLINE  __attribute__((always_inline))
//#endif
#define NV_DEPRECATED   __attribute__((deprecated))
#define NV_THREAD_LOCAL __thread 

#if __GNUC__ > 2
#define NV_PURE     __attribute__((pure))
#define NV_CONST    __attribute__((const))
#else
#define NV_PURE
#define NV_CONST
#endif

#define NV_NOINLINE __attribute__((noinline))

// Define __FUNC__ properly.
#if __STDC_VERSION__ < 199901L
#   if __GNUC__ >= 2
#       define __FUNC__ __PRETTY_FUNCTION__ // __FUNCTION__
#   else
#       define __FUNC__ "<unknown>"
#   endif
#else
#   define __FUNC__ __PRETTY_FUNCTION__
#endif

#define restrict    __restrict__


<|start_filename|>project/vc2017/buildpkg.bat<|end_filename|>

mkdir dist

mkdir dist\lib
mkdir dist\lib64
mkdir dist\bin
mkdir dist\bin64
mkdir dist\include
mkdir dist\include\nvtt

copy Release.Win32\bin\nvcompress.exe dist\bin
copy Release.Win32\bin\nvdecompress.exe dist\bin
copy Release.Win32\bin\nvtt.dll dist\bin
copy Release.Win32\bin\nvtt.pdb dist\bin
copy Release.Win32\lib\nvtt.lib dist\lib

copy Release.x64\bin\nvcompress.exe dist\bin64
copy Release.x64\bin\nvdecompress.exe dist\bin64
copy Release.x64\bin\nvtt.dll dist\bin64
copy Release.x64\bin\nvtt.pdb dist\bin64
copy Release.x64\lib\nvtt.lib dist\lib64

copy Release.Win32\include\nvtt\nvtt.h dist\include\nvtt\nvtt.h


<|start_filename|>extern/pvrtextool/Include/PVRTextureDefines.h<|end_filename|>
/******************************************************************************

 @File         PVRTextureDefines.h

 @Title        

 @Version      

 @Copyright    Copyright (c) Imagination Technologies Limited. All Rights Reserved. Strictly Confidential.

 @Platform     

 @Description  

******************************************************************************/
#ifndef _PVRTEXTURE_DEFINES_H
#define _PVRTEXTURE_DEFINES_H

//To use the PVRTexLib .dll on Windows, you need to define _WINDLL_IMPORT
#ifndef PVR_DLL
#if defined(_WINDLL_EXPORT)
#define PVR_DLL __declspec(dllexport)
//Forward declaration of PVRTexture Header and CPVRTMap. This exports their interfaces for DLLs.
struct PVR_DLL PVRTextureHeaderV3;
template <typename KeyType, typename DataType>
class PVR_DLL CPVRTMap;
template<typename T>
class PVR_DLL CPVRTArray;
#elif defined(_WINDLL_IMPORT)
#define PVR_DLL __declspec(dllimport)
//Forward declaration of PVRTexture Header and CPVRTMap. This imports their interfaces for DLLs.
struct PVR_DLL PVRTextureHeaderV3;
template <typename KeyType, typename DataType>
class PVR_DLL CPVRTMap;
template<typename T>
class PVR_DLL CPVRTArray;
#else
#define PVR_DLL
#endif
#endif


#include "PVRTTexture.h"

namespace pvrtexture
{
	/*****************************************************************************
	* Type defines for standard variable sizes.
	*****************************************************************************/
	typedef	signed char			int8;
	typedef	signed short		int16;
	typedef	signed int			int32;
	typedef	signed long long    int64;
	typedef unsigned char		uint8;
	typedef unsigned short		uint16;
	typedef unsigned int		uint32;
	typedef	unsigned long long	uint64;
	
	/*****************************************************************************
	* Texture related constants and enumerations. 
	*****************************************************************************/
	enum ECompressorQuality
	{
		ePVRTCFast=0,
		ePVRTCNormal,
		ePVRTCHigh,
		ePVRTCBest,
		eNumPVRTCModes,

		eETCFast=0,
		eETCFastPerceptual,
		eETCSlow,
		eETCSlowPerceptual,
		eNumETCModes
	};

	enum EResizeMode
	{
		eResizeNearest,
		eResizeLinear,
		eResizeCubic,
		eNumResizeModes
	};

	// Legacy - API enums.
	enum ELegacyApi
	{
		eOGLES=1,
		eOGLES2,
		eD3DM,
		eOGL,
		eDX9,
		eDX10,
		eOVG,
		eMGL,
	};

	/*****************************************************************************
	* Useful macros.
	*****************************************************************************/
	#define TEXOFFSET2D(x,y,width) ( ((x)+(y)*(width)) )
	#define TEXOFFSET3D(x,y,z,width,height) ( ((x)+(y)*(width)+(z)*(width)*(height)) )

	/*****************************************************************************
	* Useful typedef for Meta Data Maps
	*****************************************************************************/
	typedef CPVRTMap<uint32, CPVRTMap<uint32,MetaDataBlock> > MetaDataMap;
};
#endif //_PVRTEXTURE_DEFINES_H


<|start_filename|>extern/pvrtextool/Include/PVRTexture.h<|end_filename|>
/******************************************************************************

 @File         PVRTexture.h

 @Title        

 @Version      

 @Copyright    Copyright (c) Imagination Technologies Limited. All Rights Reserved. Strictly Confidential.

 @Platform     

 @Description  

******************************************************************************/
#ifndef _PVRTEXTURE_H
#define _PVRTEXTURE_H

#include "PVRTextureDefines.h"
#include "PVRTextureHeader.h"
//ACS: removed unneccesary includes:
//#include "PVRTString.h"

namespace pvrtexture
{
	class PVR_DLL CPVRTexture : public CPVRTextureHeader
	{		
	public:
	/*******************************************************************************
	* Construction methods for a texture.
	*******************************************************************************/
		/*!***********************************************************************
		 @Function		CPVRTexture
		 @Return		CPVRTexture A new texture.
		 @Description	Creates a new empty texture
		*************************************************************************/
		CPVRTexture();
		/*!***********************************************************************
		 @Function		CPVRTexture
		 @Input			sHeader
		 @Input			pData
		 @Return		CPVRTexture A new texture.
		 @Description	Creates a new texture based on a texture header, 
						pre-allocating the correct amount of memory. If data is
						supplied, it will be copied into memory.
		*************************************************************************/
		CPVRTexture(const CPVRTextureHeader& sHeader, const void* pData=NULL);

		/*!***********************************************************************
		 @Function		CPVRTexture
		 @Input			szFilePath
		 @Return		CPVRTexture A new texture.
		 @Description	Creates a new texture from a filepath.
		*************************************************************************/
		CPVRTexture(const char* szFilePath);

		/*!***********************************************************************
		 @Function		CPVRTexture
		 @Input			pTexture
		 @Return		CPVRTexture A new texture.
		 @Description	Creates a new texture from a pointer that includes a header
						structure, meta data and texture data as laid out in a file.
						This functionality is primarily for user defined file loading.
						Header may be any version of pvr.
		*************************************************************************/
		CPVRTexture( const void* pTexture );

		/*!***********************************************************************
		 @Function		CPVRTexture
		 @Input			texture
		 @Return		CPVRTexture A new texture
		 @Description	Creates a new texture as a copy of another.
		*************************************************************************/
		CPVRTexture(const CPVRTexture& texture);

		/*!***********************************************************************
		 @Function		~CPVRTexture
		 @Description	Deconstructor for CPVRTextures.
		*************************************************************************/
		~CPVRTexture();

		/*!***********************************************************************
		 @Function		operator=
		 @Input			rhs
		 @Return		CPVRTexture& This texture.
		 @Description	Will copy the contents and information of another texture into this one.
		*************************************************************************/
		CPVRTexture& operator=(const CPVRTexture& rhs);
		
	/*******************************************************************************
	* Texture accessor functions - others are inherited from CPVRTextureHeader.
	*******************************************************************************/
		/*!***********************************************************************
		 @Function		getDataPtr
		 @Input			uiMIPLevel
		 @Input			uiArrayMember
		 @Input			uiFaceNumber
		 @Return		void* Pointer to a location in the texture.
		 @Description	Returns a pointer into the texture's data. 
						It is possible to specify an offset to specific array members, 
						faces and MIP Map levels.
		*************************************************************************/
		void* getDataPtr(uint32 uiMIPLevel = 0, uint32 uiArrayMember = 0, uint32 uiFaceNumber = 0) const;

		/*!***********************************************************************
		 @Function		getHeader
		 @Return		const CPVRTextureHeader& Returns the header only for this texture.
		 @Description	Gets the header for this texture, allowing you to create a new
						texture based on this one with some changes. Useful for passing
						information about a texture without passing all of its data.
		*************************************************************************/
		const CPVRTextureHeader& getHeader() const;

	/*******************************************************************************
	* File io.
	*******************************************************************************/

		/*!***********************************************************************
		 @Function		setPaddedMetaData
		 @Input			uiPadding
		 @Description	When writing the texture out to a PVR file, it is often
						desirable to pad the meta data so that the start of the
						texture data aligns to a given boundary.
						This function pads to a boundary value equal to "uiPadding".
						For example setting uiPadding=8 will align the start of the
						texture data to an 8 byte boundary.
						Note - this should be called immediately before saving as
						the value is worked out based on the current meta data size.
		*************************************************************************/
		void addPaddingMetaData( uint32 uiPadding );

		/*!***********************************************************************
		 @Function		saveFile
		 @Input			filepath
		 @Return		bool Whether the method succeeds or not.
		 @Description	Writes out to a file, given a filename and path. 
						File type will be determined by the extension present in the string. 
						If no extension is present, PVR format will be selected. 
						Unsupported formats will result in failure.
		*************************************************************************/
		bool saveFile(const CPVRTString& filepath) const;
	
		/*!***********************************************************************
		 @Function		saveFileLegacyPVR
		 @Input			filepath
		 @Input			eApi
		 @Return		bool Whether the method succeeds or not.
		 @Description	Writes out to a file, stripping any extensions specified
						and appending .pvr. This function is for legacy support only
						and saves out to PVR Version 2 file. The target api must be
						specified in order to save to this format.
		*************************************************************************/
		bool saveFileLegacyPVR(const CPVRTString& filepath, ELegacyApi eApi) const;

	private:
		size_t	m_stDataSize;		// Size of the texture data.
		uint8*	m_pTextureData;		// Pointer to texture data.

	/*******************************************************************************
	* Private IO functions
	*******************************************************************************/
		/*!***********************************************************************
		 @Function		loadPVRFile
		 @Input			pTextureFile
		 @Description	Loads a PVR file.
		*************************************************************************/
		bool privateLoadPVRFile(FILE* pTextureFile);

		/*!***********************************************************************
		 @Function		privateSavePVRFile
		 @Input			pTextureFile
		 @Description	Saves a PVR File.
		*************************************************************************/
		bool privateSavePVRFile(FILE* pTextureFile) const;

		/*!***********************************************************************
		 @Function		loadKTXFile
		 @Input			pTextureFile
		 @Description	Loads a KTX file.
		*************************************************************************/
		bool privateLoadKTXFile(FILE* pTextureFile);

		/*!***********************************************************************
		 @Function		privateSaveKTXFile
		 @Input			pTextureFile
		 @Description	Saves a KTX File.
		*************************************************************************/
		bool privateSaveKTXFile(FILE* pTextureFile) const;

		/*!***********************************************************************
		 @Function		loadDDSFile
		 @Input			pTextureFile
		 @Description	Loads a DDS file.
		 *************************************************************************/
		bool privateLoadDDSFile(FILE* pTextureFile);
		bool privateLoadDDS10File(FILE* pTextureFile);

		/*!***********************************************************************
		 @Function		privateSaveDDSFile
		 @Input			pTextureFile
		 @Description	Saves a DDS File.
		*************************************************************************/
		bool privateSaveDDSFile(FILE* pTextureFile) const;

		//Legacy IO
		/*!***********************************************************************
		 @Function		privateSavePVRFile
		 @Input			pTextureFile
		 @Input			filename
		 @Description	Saves a .h File.
		*************************************************************************/
		bool privateSaveCHeaderFile(FILE* pTextureFile, CPVRTString filename) const;

		/*!***********************************************************************
		 @Function		privateSaveLegacyPVRFile
		 @Input			pTextureFile
		 @Input			eApi
		 @Description	Saves a legacy PVR File - Uses version 2 file format.
		*************************************************************************/
		bool privateSaveLegacyPVRFile(FILE* pTextureFile, ELegacyApi eApi) const;
	};
};

#endif //_PVRTEXTURE_H



<|start_filename|>src/nvmath/Half.cpp<|end_filename|>
// Branch-free implementation of half-precision (16 bit) floating point
// Copyright 2006 <NAME> <<EMAIL>>
// 
// Permission is hereby granted, free of charge, to any person obtaining a 
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, 
// and/or sell copies of the Software, and to permit persons to whom the 
// Software is furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included 
// in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE
//
// Half-precision floating point format
// ------------------------------------
//
//   | Field    | Last | First | Note
//   |----------|------|-------|----------
//   | Sign     | 15   | 15    |
//   | Exponent | 14   | 10    | Bias = 15
//   | Mantissa | 9    | 0     |
//
// Compiling
// ---------
//
//  Preferred compile flags for GCC: 
//     -O3 -fstrict-aliasing -std=c99 -pedantic -Wall -Wstrict-aliasing
//
//     This file is a C99 source file, intended to be compiled with a C99 
//     compliant compiler. However, for the moment it remains combatible
//     with C++98. Therefore if you are using a compiler that poorly implements
//     C standards (e.g. MSVC), it may be compiled as C++. This is not
//     guaranteed for future versions. 
//
// Features
// --------
//
//  * QNaN + <x>  = QNaN
//  * <x>  + +INF = +INF
//  * <x>  - -INF = -INF
//  * INF  - INF  = SNaN
//  * Denormalized values
//  * Difference of ZEROs is always +ZERO
//  * Sum round with guard + round + sticky bit (grs)
//  * And of course... no branching
// 
// Precision of Sum
// ----------------
//
//  (SUM)        uint16 z = half_add( x, y );
//  (DIFFERENCE) uint16 z = half_add( x, -y );
//
//     Will have exactly (0 ulps difference) the same result as:
//     (For 32 bit IEEE 784 floating point and same rounding mode)
//
//     union FLOAT_32
//     {
//       float    f32;
//       uint32 u32;
//     };
//
//     union FLOAT_32 fx = { .u32 = half_to_float( x ) };
//     union FLOAT_32 fy = { .u32 = half_to_float( y ) };
//     union FLOAT_32 fz = { .f32 = fx.f32 + fy.f32    };
//     uint16       z  = float_to_half( fz );
//

#include "Half.h"
#include <stdio.h>


// Load immediate
static inline uint32 _uint32_li( uint32 a )
{
    return (a);
}

// Decrement
static inline uint32 _uint32_dec( uint32 a )
{
    return (a - 1);
}

// Increment
static inline uint32 _uint32_inc( uint32 a )
{
  return (a + 1);
}

// Complement
static inline uint32 _uint32_not( uint32 a )
{
    return (~a);
}

// Negate
static inline uint32 _uint32_neg( uint32 a )
{
#pragma warning(disable : 4146)     // unary minus operator applied to unsigned type, result still unsigned
    return (-a);
#pragma warning(default : 4146)
}

// Extend sign
static inline uint32 _uint32_ext( uint32 a )
{
    return (((int32)a)>>31);
}

// And
static inline uint32 _uint32_and( uint32 a, uint32 b )
{
    return (a & b);
}

// And with Complement
static inline uint32 _uint32_andc( uint32 a, uint32 b )
{
    return (a & ~b);
}

// Or
static inline uint32 _uint32_or( uint32 a, uint32 b )
{
    return (a | b);
}

// Shift Right Logical
static inline uint32 _uint32_srl( uint32 a, int sa )
{
    return (a >> sa);
}

// Shift Left Logical
static inline uint32 _uint32_sll( uint32 a, int sa )
{
    return (a << sa);
}

// Add
static inline uint32 _uint32_add( uint32 a, uint32 b )
{
    return (a + b);
}

// Subtract
static inline uint32 _uint32_sub( uint32 a, uint32 b )
{
    return (a - b);
}

// Select on Sign bit
static inline uint32 _uint32_sels( uint32 test, uint32 a, uint32 b )
{
    const uint32 mask   = _uint32_ext( test );
    const uint32 sel_a  = _uint32_and(  a,     mask  );
    const uint32 sel_b  = _uint32_andc( b,     mask  );
    const uint32 result = _uint32_or(   sel_a, sel_b );

    return (result);
}

// Load Immediate
static inline uint16 _uint16_li( uint16 a )
{
    return (a);
}

// Extend sign
static inline uint16 _uint16_ext( uint16 a )
{
    return (((int16)a)>>15);
}

// Negate
static inline uint16 _uint16_neg( uint16 a )
{
    return (-a);
}

// Complement
static inline uint16 _uint16_not( uint16 a )
{
    return (~a);
}

// Decrement
static inline uint16 _uint16_dec( uint16 a )
{
    return (a - 1);
}

// Shift Left Logical
static inline uint16 _uint16_sll( uint16 a, int sa )
{
    return (a << sa);
}

// Shift Right Logical
static inline uint16 _uint16_srl( uint16 a, int sa )
{
    return (a >> sa);
}

// Add
static inline uint16 _uint16_add( uint16 a, uint16 b )
{
    return (a + b);
}

// Subtract
static inline uint16 _uint16_sub( uint16 a, uint16 b )
{
    return (a - b);
}

// And
static inline uint16 _uint16_and( uint16 a, uint16 b )
{
    return (a & b);
}

// Or
static inline uint16 _uint16_or( uint16 a, uint16 b )
{
    return (a | b);
}

// Exclusive Or
static inline uint16 _uint16_xor( uint16 a, uint16 b )
{
    return (a ^ b);
}

// And with Complement
static inline uint16 _uint16_andc( uint16 a, uint16 b )
{
    return (a & ~b);
}

// And then Shift Right Logical
static inline uint16 _uint16_andsrl( uint16 a, uint16 b, int sa )
{
    return ((a & b) >> sa);
}

// Shift Right Logical then Mask
static inline uint16 _uint16_srlm( uint16 a, int sa, uint16 mask )
{
    return ((a >> sa) & mask);
}

// Add then Mask
static inline uint16 _uint16_addm( uint16 a, uint16 b, uint16 mask )
{
    return ((a + b) & mask);
}


// Select on Sign bit
static inline uint16 _uint16_sels( uint16 test, uint16 a, uint16 b )
{
    const uint16 mask   = _uint16_ext( test );
    const uint16 sel_a  = _uint16_and(  a,     mask  );
    const uint16 sel_b  = _uint16_andc( b,     mask  );
    const uint16 result = _uint16_or(   sel_a, sel_b );

    return (result);
}

#if NV_OS_XBOX
#include <PPCIntrinsics.h>
#elif NV_CC_MSVC

#include <intrin.h>
#pragma intrinsic(_BitScanReverse)

uint32 _uint32_nlz( uint32 x ) {
    unsigned long index;
    _BitScanReverse(&index, x);
    return 31 - index;
}
#endif


// Count Leading Zeros
static inline uint32 _uint32_cntlz( uint32 x )
{
#if NV_CC_GNUC
    /* On PowerPC, this will map to insn: cntlzw */
    /* On Pentium, this will map to insn: clz    */
    uint32 is_x_nez_msb = _uint32_neg( x );
    uint32 nlz          = __builtin_clz( x );
    uint32 result       = _uint32_sels( is_x_nez_msb, nlz, 0x00000020 );
    return (result);
#elif NV_OS_XBOX
    // Xbox PPC has this as an intrinsic.
    return _CountLeadingZeros(x);
#elif NV_CC_MSVC
    uint32 is_x_nez_msb = _uint32_neg( x );
    uint32 nlz          = _uint32_nlz( x );
    uint32 result       = _uint32_sels( is_x_nez_msb, nlz, 0x00000020 );
    return (result);
#else
    const uint32 x0  = _uint32_srl(  x,  1 );
    const uint32 x1  = _uint32_or(   x,  x0 );
    const uint32 x2  = _uint32_srl(  x1, 2 );
    const uint32 x3  = _uint32_or(   x1, x2 );
    const uint32 x4  = _uint32_srl(  x3, 4 );
    const uint32 x5  = _uint32_or(   x3, x4 );
    const uint32 x6  = _uint32_srl(  x5, 8 );
    const uint32 x7  = _uint32_or(   x5, x6 );
    const uint32 x8  = _uint32_srl(  x7, 16 );
    const uint32 x9  = _uint32_or(   x7, x8 );
    const uint32 xA  = _uint32_not(  x9 );
    const uint32 xB  = _uint32_srl(  xA, 1 );
    const uint32 xC  = _uint32_and(  xB, 0x55555555 );
    const uint32 xD  = _uint32_sub(  xA, xC );
    const uint32 xE  = _uint32_and(  xD, 0x33333333 );
    const uint32 xF  = _uint32_srl(  xD, 2 );
    const uint32 x10 = _uint32_and(  xF, 0x33333333 );
    const uint32 x11 = _uint32_add(  xE, x10 );
    const uint32 x12 = _uint32_srl(  x11, 4 );
    const uint32 x13 = _uint32_add(  x11, x12 );
    const uint32 x14 = _uint32_and(  x13, 0x0f0f0f0f );
    const uint32 x15 = _uint32_srl(  x14, 8 );
    const uint32 x16 = _uint32_add(  x14, x15 );
    const uint32 x17 = _uint32_srl(  x16, 16 );
    const uint32 x18 = _uint32_add(  x16, x17 );
    const uint32 x19 = _uint32_and(  x18, 0x0000003f );
    return ( x19 );
#endif
}

// Count Leading Zeros
static inline uint16 _uint16_cntlz( uint16 x )
{
#ifdef __GNUC__
    /* On PowerPC, this will map to insn: cntlzw */
    /* On Pentium, this will map to insn: clz    */
    uint16 nlz32 = (uint16)_uint32_cntlz( (uint32)x );
    uint32 nlz   = _uint32_sub( nlz32, 16 );
    return (nlz);
#elif _NV_OS_XBOX_
    uint16 nlz32 = (uint16)_CountLeadingZeros( (uint32)x );
    return _uint32_sub( nlz32, 16);
#else
    const uint16 x0  = _uint16_srl(  x,  1 );
    const uint16 x1  = _uint16_or(   x,  x0 );
    const uint16 x2  = _uint16_srl(  x1, 2 );
    const uint16 x3  = _uint16_or(   x1, x2 );
    const uint16 x4  = _uint16_srl(  x3, 4 );
    const uint16 x5  = _uint16_or(   x3, x4 );
    const uint16 x6  = _uint16_srl(  x5, 8 );
    const uint16 x7  = _uint16_or(   x5, x6 );
    const uint16 x8  = _uint16_not(  x7 );
    const uint16 x9  = _uint16_srlm( x8, 1, 0x5555 );
    const uint16 xA  = _uint16_sub(  x8, x9 );
    const uint16 xB  = _uint16_and(  xA, 0x3333 );
    const uint16 xC  = _uint16_srlm( xA, 2, 0x3333 );
    const uint16 xD  = _uint16_add(  xB, xC );
    const uint16 xE  = _uint16_srl(  xD, 4 );
    const uint16 xF  = _uint16_addm( xD, xE, 0x0f0f );
    const uint16 x10 = _uint16_srl(  xF, 8 );
    const uint16 x11 = _uint16_addm( xF, x10, 0x001f );
    return ( x11 );
#endif
}

uint16
nv::half_from_float( uint32 f )
{
    const uint32 one                        = _uint32_li( 0x00000001 );
    const uint32 f_s_mask                   = _uint32_li( 0x80000000 );
    const uint32 f_e_mask                   = _uint32_li( 0x7f800000 );
    const uint32 f_m_mask                   = _uint32_li( 0x007fffff );
    const uint32 f_m_hidden_bit             = _uint32_li( 0x00800000 );
    const uint32 f_m_round_bit              = _uint32_li( 0x00001000 );
    const uint32 f_snan_mask                = _uint32_li( 0x7fc00000 );
    const uint32 f_e_pos                    = _uint32_li( 0x00000017 );
    const uint32 h_e_pos                    = _uint32_li( 0x0000000a );
    const uint32 h_e_mask                   = _uint32_li( 0x00007c00 );
    const uint32 h_snan_mask                = _uint32_li( 0x00007e00 );
    const uint32 h_e_mask_value             = _uint32_li( 0x0000001f );
    const uint32 f_h_s_pos_offset           = _uint32_li( 0x00000010 );
    const uint32 f_h_bias_offset            = _uint32_li( 0x00000070 );
    const uint32 f_h_m_pos_offset           = _uint32_li( 0x0000000d );
    const uint32 h_nan_min                  = _uint32_li( 0x00007c01 );
    const uint32 f_h_e_biased_flag          = _uint32_li( 0x0000008f );
    const uint32 f_s                        = _uint32_and( f,               f_s_mask         );
    const uint32 f_e                        = _uint32_and( f,               f_e_mask         );
    const uint16 h_s                        = _uint32_srl( f_s,             f_h_s_pos_offset );
    const uint32 f_m                        = _uint32_and( f,               f_m_mask         );
    const uint16 f_e_amount                 = _uint32_srl( f_e,             f_e_pos          );
    const uint32 f_e_half_bias              = _uint32_sub( f_e_amount,      f_h_bias_offset  );
    const uint32 f_snan                     = _uint32_and( f,               f_snan_mask      );
    const uint32 f_m_round_mask             = _uint32_and( f_m,             f_m_round_bit    );
    const uint32 f_m_round_offset           = _uint32_sll( f_m_round_mask,  one              );
    const uint32 f_m_rounded                = _uint32_add( f_m,             f_m_round_offset );
    const uint32 f_m_denorm_sa              = _uint32_sub( one,             f_e_half_bias    );
    const uint32 f_m_with_hidden            = _uint32_or(  f_m_rounded,     f_m_hidden_bit   );
    const uint32 f_m_denorm                 = _uint32_srl( f_m_with_hidden, f_m_denorm_sa    );
    const uint32 h_m_denorm                 = _uint32_srl( f_m_denorm,      f_h_m_pos_offset );
    const uint32 f_m_rounded_overflow       = _uint32_and( f_m_rounded,     f_m_hidden_bit   );
    const uint32 m_nan                      = _uint32_srl( f_m,             f_h_m_pos_offset );
    const uint32 h_em_nan                   = _uint32_or(  h_e_mask,        m_nan            );
    const uint32 h_e_norm_overflow_offset   = _uint32_inc( f_e_half_bias );
    const uint32 h_e_norm_overflow          = _uint32_sll( h_e_norm_overflow_offset, h_e_pos          );
    const uint32 h_e_norm                   = _uint32_sll( f_e_half_bias,            h_e_pos          );
    const uint32 h_m_norm                   = _uint32_srl( f_m_rounded,              f_h_m_pos_offset );
    const uint32 h_em_norm                  = _uint32_or(  h_e_norm,                 h_m_norm         );
    const uint32 is_h_ndenorm_msb           = _uint32_sub( f_h_bias_offset,   f_e_amount    );
    const uint32 is_f_e_flagged_msb         = _uint32_sub( f_h_e_biased_flag, f_e_half_bias );
    const uint32 is_h_denorm_msb            = _uint32_not( is_h_ndenorm_msb );
    const uint32 is_f_m_eqz_msb             = _uint32_dec( f_m   );
    const uint32 is_h_nan_eqz_msb           = _uint32_dec( m_nan );
    const uint32 is_f_inf_msb               = _uint32_and( is_f_e_flagged_msb, is_f_m_eqz_msb   );
    const uint32 is_f_nan_underflow_msb     = _uint32_and( is_f_e_flagged_msb, is_h_nan_eqz_msb );
    const uint32 is_e_overflow_msb          = _uint32_sub( h_e_mask_value,     f_e_half_bias    );
    const uint32 is_h_inf_msb               = _uint32_or(  is_e_overflow_msb,  is_f_inf_msb     );
    const uint32 is_f_nsnan_msb             = _uint32_sub( f_snan,             f_snan_mask      );
    const uint32 is_m_norm_overflow_msb     = _uint32_neg( f_m_rounded_overflow );
    const uint32 is_f_snan_msb              = _uint32_not( is_f_nsnan_msb );
    const uint32 h_em_overflow_result       = _uint32_sels( is_m_norm_overflow_msb, h_e_norm_overflow, h_em_norm                 );
    const uint32 h_em_nan_result            = _uint32_sels( is_f_e_flagged_msb,     h_em_nan,          h_em_overflow_result      );
    const uint32 h_em_nan_underflow_result  = _uint32_sels( is_f_nan_underflow_msb, h_nan_min,         h_em_nan_result           );
    const uint32 h_em_inf_result            = _uint32_sels( is_h_inf_msb,           h_e_mask,          h_em_nan_underflow_result );
    const uint32 h_em_denorm_result         = _uint32_sels( is_h_denorm_msb,        h_m_denorm,        h_em_inf_result           );
    const uint32 h_em_snan_result           = _uint32_sels( is_f_snan_msb,          h_snan_mask,       h_em_denorm_result        );
    const uint32 h_result                   = _uint32_or( h_s, h_em_snan_result );

    return (uint16)(h_result);
}

uint32 
nv::half_to_float( uint16 h )
{
    const uint32 h_e_mask              = _uint32_li( 0x00007c00 );
    const uint32 h_m_mask              = _uint32_li( 0x000003ff );
    const uint32 h_s_mask              = _uint32_li( 0x00008000 );
    const uint32 h_f_s_pos_offset      = _uint32_li( 0x00000010 );
    const uint32 h_f_e_pos_offset      = _uint32_li( 0x0000000d );
    const uint32 h_f_bias_offset       = _uint32_li( 0x0001c000 );
    const uint32 f_e_mask              = _uint32_li( 0x7f800000 );
    const uint32 f_m_mask              = _uint32_li( 0x007fffff );
    const uint32 h_f_e_denorm_bias     = _uint32_li( 0x0000007e );
    const uint32 h_f_m_denorm_sa_bias  = _uint32_li( 0x00000008 );
    const uint32 f_e_pos               = _uint32_li( 0x00000017 );
    const uint32 h_e_mask_minus_one    = _uint32_li( 0x00007bff );
    const uint32 h_e                   = _uint32_and( h, h_e_mask );
    const uint32 h_m                   = _uint32_and( h, h_m_mask );
    const uint32 h_s                   = _uint32_and( h, h_s_mask );
    const uint32 h_e_f_bias            = _uint32_add( h_e, h_f_bias_offset );
    const uint32 h_m_nlz               = _uint32_cntlz( h_m );
    const uint32 f_s                   = _uint32_sll( h_s,        h_f_s_pos_offset );
    const uint32 f_e                   = _uint32_sll( h_e_f_bias, h_f_e_pos_offset );
    const uint32 f_m                   = _uint32_sll( h_m,        h_f_e_pos_offset );
    const uint32 f_em                  = _uint32_or(  f_e,        f_m              );
    const uint32 h_f_m_sa              = _uint32_sub( h_m_nlz,             h_f_m_denorm_sa_bias );
    const uint32 f_e_denorm_unpacked   = _uint32_sub( h_f_e_denorm_bias,   h_f_m_sa             );
    const uint32 h_f_m                 = _uint32_sll( h_m,                 h_f_m_sa             );
    const uint32 f_m_denorm            = _uint32_and( h_f_m,               f_m_mask             );
    const uint32 f_e_denorm            = _uint32_sll( f_e_denorm_unpacked, f_e_pos              );
    const uint32 f_em_denorm           = _uint32_or(  f_e_denorm,          f_m_denorm           );
    const uint32 f_em_nan              = _uint32_or(  f_e_mask,            f_m                  );
    const uint32 is_e_eqz_msb          = _uint32_dec(  h_e );
    const uint32 is_m_nez_msb          = _uint32_neg(  h_m );
    const uint32 is_e_flagged_msb      = _uint32_sub(  h_e_mask_minus_one, h_e );
    const uint32 is_zero_msb           = _uint32_andc( is_e_eqz_msb,       is_m_nez_msb );
    const uint32 is_inf_msb            = _uint32_andc( is_e_flagged_msb,   is_m_nez_msb );
    const uint32 is_denorm_msb         = _uint32_and(  is_m_nez_msb,       is_e_eqz_msb );
    const uint32 is_nan_msb            = _uint32_and(  is_e_flagged_msb,   is_m_nez_msb ); 
    const uint32 is_zero               = _uint32_ext(  is_zero_msb );
    const uint32 f_zero_result         = _uint32_andc( f_em, is_zero );
    const uint32 f_denorm_result       = _uint32_sels( is_denorm_msb, f_em_denorm, f_zero_result );
    const uint32 f_inf_result          = _uint32_sels( is_inf_msb,    f_e_mask,    f_denorm_result );
    const uint32 f_nan_result          = _uint32_sels( is_nan_msb,    f_em_nan,    f_inf_result    );
    const uint32 f_result              = _uint32_or( f_s, f_nan_result );

    return (f_result);
}


#if !NV_OS_IOS && (defined(__i386__) || defined(__x86_64__))

#if NV_CC_GNUC
#if defined(__i386__) || defined(__x86_64__)
#include <xmmintrin.h>
#endif
#endif

#include "nvcore/Memory.h" // NV_ALIGN_16

static __m128 half_to_float4_SSE2(__m128i h)
{
#define SSE_CONST4(name, val) static const NV_ALIGN_16 uint name[4] = { (val), (val), (val), (val) }
    
#define CONST(name) *(const __m128i *)&name

    SSE_CONST4(mask_nosign,         0x7fff);
    SSE_CONST4(mask_justsign,       0x8000);
    SSE_CONST4(mask_shifted_exp,    0x7c00 << 13);
    SSE_CONST4(expadjust_normal,    (127 - 15) << 23);
    SSE_CONST4(expadjust_infnan,    (128 - 16) << 23);
    SSE_CONST4(expadjust_denorm,    1 << 23);
    SSE_CONST4(magic_denorm,        113 << 23);

    __m128i mnosign     = CONST(mask_nosign);
    __m128i expmant     = _mm_and_si128(mnosign, h);
    __m128i justsign    = _mm_and_si128(h, CONST(mask_justsign));
    __m128i mshiftexp   = CONST(mask_shifted_exp);
    __m128i eadjust     = CONST(expadjust_normal);
    __m128i shifted     = _mm_slli_epi32(expmant, 13);
    __m128i adjusted    = _mm_add_epi32(eadjust, shifted);
    __m128i justexp     = _mm_and_si128(shifted, mshiftexp);

    __m128i zero        = _mm_setzero_si128();
    __m128i b_isinfnan  = _mm_cmpeq_epi32(mshiftexp, justexp);
    __m128i b_isdenorm  = _mm_cmpeq_epi32(zero, justexp);

    __m128i adj_infnan  = _mm_and_si128(b_isinfnan, CONST(expadjust_infnan));
    __m128i adjusted2   = _mm_add_epi32(adjusted, adj_infnan);

    __m128i adj_den     = CONST(expadjust_denorm);
    __m128i den1        = _mm_add_epi32(adj_den, adjusted2);
    __m128  den2        = _mm_sub_ps(_mm_castsi128_ps(den1), *(const __m128 *)&magic_denorm);
    __m128  adjusted3   = _mm_and_ps(den2, _mm_castsi128_ps(b_isdenorm));
    __m128  adjusted4   = _mm_andnot_ps(_mm_castsi128_ps(b_isdenorm), _mm_castsi128_ps(adjusted2));
    __m128  adjusted5   = _mm_or_ps(adjusted3, adjusted4);
    __m128i sign        = _mm_slli_epi32(justsign, 16);
    __m128  final       = _mm_or_ps(adjusted5, _mm_castsi128_ps(sign));

    // ~21 SSE2 ops.
    return final;

#undef SSE_CONST4
#undef CONST
}


void nv::half_to_float_array_SSE2(const uint16 * vin, float * vout, int count) {
    nvDebugCheck((intptr_t(vin) & 15) == 0);
    nvDebugCheck((intptr_t(vout) & 15) == 0);
    nvDebugCheck((count & 7) == 0);

    __m128i zero = _mm_setzero_si128();

    for (int i = 0; i < count; i += 8)
    {
        __m128i in = _mm_loadu_si128((const __m128i *)(vin + i));
        __m128i a = _mm_unpacklo_epi16(in, zero);
        __m128i b = _mm_unpackhi_epi16(in, zero);
        
        __m128 outa = half_to_float4_SSE2(a);
        _mm_storeu_ps((float *)(vout + i), outa);
        
        __m128 outb = half_to_float4_SSE2(b);
        _mm_storeu_ps((float *)(vout + i + 4), outb);
    }
}

#endif 


// @@ These tables could be smaller.
namespace nv {
    uint32 mantissa_table[2048] = { 0xDEADBEEF };
    uint32 exponent_table[64];
    uint32 offset_table[64];
}

void nv::half_init_tables()
{
    // Init mantissa table.
    mantissa_table[0] = 0;

    // denormals
    for (int i = 1; i < 1024; i++) {
        uint m = i << 13;
        uint e = 0;

        while ((m & 0x00800000) == 0) {
            e -= 0x00800000;
            m <<= 1;
        }
        m &= ~0x00800000;
        e += 0x38800000;
        mantissa_table[i] = m | e;
    }

    // normals
    for (int i = 1024; i < 2048; i++) {
        mantissa_table[i] = (i - 1024) << 13;
    }


    // Init exponent table.
    exponent_table[0] = 0;

    for (int i = 1; i < 31; i++) {
        exponent_table[i] = 0x38000000 + (i << 23);
    }

    exponent_table[31] = 0x7f800000;
    exponent_table[32] = 0x80000000;

    for (int i = 33; i < 63; i++) {
        exponent_table[i] = 0xb8000000 + ((i - 32) << 23);
    }

    exponent_table[63] = 0xff800000;


    // Init offset table.
    offset_table[0] = 0;

    for (int i = 1; i < 32; i++) {
        offset_table[i] = 1024;
    }

    offset_table[32] = 0;

    for (int i = 33; i < 64; i++) {
        offset_table[i] = 1024;
    }
}


#if 0

// Inaccurate conversion suggested at the ffmpeg mailing list:
// http://lists.mplayerhq.hu/pipermail/ffmpeg-devel/2009-July/068949.html
uint32 nv::fast_half_to_float(uint16 v)
{
    if (v & 0x8000) return 0;
    uint exp = v >> 10;
    if (!exp) return (v>>9)&1;
    if (exp >= 15) return 0xffff;
    v <<= 6;
    return (v+(1<<16)) >> (15-exp);
}

#endif

#if 0

// Some more from a gamedev thread:
// http://www.devmaster.net/forums/showthread.php?t=10924

// I believe it does not handle specials either.

// Mike Acton's code should be fairly easy to vectorize and that would handle all cases too, the table method might still be faster, though.


static __declspec(align(16)) unsigned half_sign[4]    = {0x00008000, 0x00008000, 0x00008000, 0x00008000};
static __declspec(align(16)) unsigned half_exponent[4]    = {0x00007C00, 0x00007C00, 0x00007C00, 0x00007C00};
static __declspec(align(16)) unsigned half_mantissa[4]    = {0x000003FF, 0x000003FF, 0x000003FF, 0x000003FF};
static __declspec(align(16)) unsigned half_bias_offset[4] = {0x0001C000, 0x0001C000, 0x0001C000, 0x0001C000};

__asm
{
    movaps  xmm1, xmm0  // Input in xmm0
    movaps  xmm2, xmm0

    andps   xmm0, half_sign
    andps   xmm1, half_exponent
    andps   xmm2, half_mantissa
    paddd   xmm1, half_bias_offset

    pslld   xmm0, 16
    pslld   xmm1, 13
    pslld   xmm2, 13

    orps    xmm1, xmm2
    orps    xmm0, xmm1  // Result in xmm0
}


#endif

#if 0
// These version computes the tables at compile time:
// http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a

/* This method is faster than the OpenEXR implementation (very often
 * used, eg. in Ogre), with the additional benefit of rounding, inspired
 * by <NAME>s half-precision code. */
static inline uint16_t float_to_half_branch(uint32_t x)
{
    uint16_t bits = (x >> 16) & 0x8000; /* Get the sign */
    uint16_t m = (x >> 12) & 0x07ff; /* Keep one extra bit for rounding */
    unsigned int e = (x >> 23) & 0xff; /* Using int is faster here */

    /* If zero, or denormal, or exponent underflows too much for a denormal
     * half, return signed zero. */
    if (e < 103)
        return bits;

    /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */
    if (e > 142)
    {
        bits |= 0x7c00u;
        /* If exponent was 0xff and one mantissa bit was set, it means NaN,
         * not Inf, so make sure we set one mantissa bit too. */
        bits |= e == 255 && (x & 0x007fffffu);
        return bits;
    }

    /* If exponent underflows but not too much, return a denormal */
    if (e < 113)
    {
        m |= 0x0800u;
        /* Extra rounding may overflow and set mantissa to 0 and exponent
         * to 1, which is OK. */
        bits |= (m >> (114 - e)) + ((m >> (113 - e)) & 1);
        return bits;
    }

    bits |= ((e - 112) << 10) | (m >> 1);
    /* Extra rounding. An overflow will set mantissa to 0 and increment
     * the exponent, which is OK. */
    bits += m & 1;
    return bits;
}

/* These macros implement a finite iterator useful to build lookup
 * tables. For instance, S64(0) will call S1(x) for all values of x
 * between 0 and 63.
 * Due to the exponential behaviour of the calls, the stress on the
 * compiler may be important. */
#define S4(x)    S1((x)),   S1((x)+1),     S1((x)+2),     S1((x)+3)
#define S16(x)   S4((x)),   S4((x)+4),     S4((x)+8),     S4((x)+12)
#define S64(x)   S16((x)),  S16((x)+16),   S16((x)+32),   S16((x)+48)
#define S256(x)  S64((x)),  S64((x)+64),   S64((x)+128),  S64((x)+192)
#define S1024(x) S256((x)), S256((x)+256), S256((x)+512), S256((x)+768)

/* Lookup table-based algorithm from Fast Half Float Conversions
 * by <NAME>, November 2008. No rounding is performed,
 * and some NaN values may be incorrectly converted to Inf. */
static inline uint16_t float_to_half_nobranch(uint32_t x)
{
    static uint16_t const basetable[512] =
    {
#define S1(i) (((i) < 103) ? 0x0000 : \
               ((i) < 113) ? 0x0400 >> (113 - (i)) : \
               ((i) < 143) ? ((i) - 112) << 10 : 0x7c00)
        S256(0),
#undef S1
#define S1(i) (0x8000 | (((i) < 103) ? 0x0000 : \
                         ((i) < 113) ? 0x0400 >> (113 - (i)) : \
                         ((i) < 143) ? ((i) - 112) << 10 : 0x7c00))
        S256(0),
#undef S1
    };

    static uint8_t const shifttable[512] =
    {
#define S1(i) (((i) < 103) ? 24 : \
               ((i) < 113) ? 126 - (i) : \
               ((i) < 143 || (i) == 255) ? 13 : 24)
        S256(0), S256(0),
#undef S1
    };

    uint16_t bits = basetable[(x >> 23) & 0x1ff];
    bits |= (x & 0x007fffff) >> shifttable[(x >> 23) & 0x1ff];
    return bits;
}
#endif


<|start_filename|>src/nvtt/tests/bc1enc.cpp<|end_filename|>

#define  _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>

//#define STBI_ASSERT(x)
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

#define STB_DXT_IMPLEMENTATION
#include "stb_dxt.h"

#define RGBCX_IMPLEMENTATION
#include "../extern/rg/rgbcx.h"

#define ICBC_IMPLEMENTATION
#include "nvtt/icbc.h"

#define ICETC_IMPLEMENTATION
#include "nvtt/icetc.h"

//#define GOOFYTC_IMPLEMENTATION
//#include "../extern/goofy_tc.h"

#include "../extern/rg_etc1_v104/rg_etc1.h"
#include "../extern/rg_etc1_v104/rg_etc1.cpp"



#include "../extern/libsquish-1.15/squish.h"

#include "../extern/CMP_Core/source/CMP_Core.h"

#include "nvmath/Vector.inl"
#include "nvmath/Color.h"

#include "nvcore/Timer.h"
#include "nvcore/Array.inl"

using namespace nv;

typedef unsigned char u8;
typedef unsigned int u32;


#define TEST_STB 0
#define TEST_STB_HQ 0

#define TEST_GOOFY 0

#define TEST_RGBCX_FAST 0  // Level 0-3
#define TEST_RGBCX_ALL 0

#define TEST_ICBC_FAST 1
#define TEST_ICBC 0
#define TEST_ICBC_HQ 0
#define TEST_ICBC_ALL 0

#define TEST_IC_ETC 0
#define TEST_RG_ETC 0

#define TEST_SQUISH 1
#define TEST_SQUISH_HQ 0

#define TEST_AMD_CMP 1




// Returns mse.
float evaluate_dxt1_mse(uint8 * rgba, uint8 * block, int block_count, icbc::Decoder decoder = icbc::Decoder_D3D10) {
    double total = 0.0f;
    for (int b = 0; b < block_count; b++) {
        total += icbc::evaluate_dxt1_error(rgba, block, decoder);
        rgba += 4 * 4 * 4;
        block += 8;
    }
    return float(total / (16 * block_count));
}

float evaluate_etc2_mse(uint8 * rgba, uint8 * block, int block_count) {
    double total = 0.0f;
    for (int b = 0; b < block_count; b++) {
        total += icetc::evaluate_etc2_error(rgba, block);
        rgba += 4 * 4 * 4;
        block += 8;
    }
    return float(total / (16 * block_count));
}


#define MAKEFOURCC(str) (uint(str[0]) | (uint(str[1]) << 8) | (uint(str[2]) << 16) | (uint(str[3]) << 24 ))


bool output_dxt_dds (u32 w, u32 h, const u8* data, const char * filename) {

    const u32 DDSD_CAPS = 0x00000001;
    const u32 DDSD_PIXELFORMAT = 0x00001000;
    const u32 DDSD_WIDTH = 0x00000004;
    const u32 DDSD_HEIGHT = 0x00000002;
    const u32 DDSD_LINEARSIZE = 0x00080000;
    const u32 DDPF_FOURCC = 0x00000004;
    const u32 DDSCAPS_TEXTURE = 0x00001000;

    struct DDS {
        u32 fourcc = MAKEFOURCC("DDS ");
        u32 size = 124;
        u32 flags = DDSD_CAPS|DDSD_PIXELFORMAT|DDSD_WIDTH|DDSD_HEIGHT|DDSD_LINEARSIZE;
        u32 height;
        u32 width;
        u32 pitch;
        u32 depth;
        u32 mipmapcount;
        u32 reserved [11];
        struct {
            u32 size = 32;
            u32 flags = DDPF_FOURCC;
            u32 fourcc = MAKEFOURCC("DXT1");
            u32 bitcount;
            u32 rmask;
            u32 gmask;
            u32 bmask;
            u32 amask;
        } pf;
        struct {
            u32 caps1 = DDSCAPS_TEXTURE;
            u32 caps2;
            u32 caps3;
            u32 caps4;
        } caps;
        u32 notused;
    } dds;
    static_assert(sizeof(DDS) == 128, "DDS size must be 128");

    dds.width = w;
    dds.height = h;
    dds.pitch = 8 * (((w+3)/4) * ((h+3)/4)); // linear size

    FILE * fp = fopen(filename, "wb");
    if (fp == nullptr) return false;

    // Write header:
    fwrite(&dds, sizeof(dds), 1, fp);

    // Write dxt data:
    fwrite(data, dds.pitch, 1, fp);

    fclose(fp);

    return true;
}

bool output_etc(u32 bw, u32 bh, const u8* block_data, const char *filename) {

    u8 * rgba_data = (u8 *)malloc(bw * bh * 4);

    for (u32 by = 0; by < bh; by += 4) {
        for (u32 bx = 0; bx < bw; bx += 4) {

            u8 rgba_block[64];
            icetc::decompress_etc(block_data, rgba_block);

            block_data += 8;

            for (u32 y = 0; y < 4; y++) {
                for (u32 x = 0; x < 4; x++) {
                    u32 idx = ((by + y) * bw + (bx + x)) * 4;
                    rgba_data[idx + 0] = rgba_block[4 * (4 * y + x) + 0];
                    rgba_data[idx + 1] = rgba_block[4 * (4 * y + x) + 1];
                    rgba_data[idx + 2] = rgba_block[4 * (4 * y + x) + 2];
                    rgba_data[idx + 3] = rgba_block[4 * (4 * y + x) + 3];
                }
            }
        }
    }

    return stbi_write_png(filename, bw, bh, 4, rgba_data, bw * 4) != 0;
}


struct Stats {
    const char * compressorName;
    Array<float> mseArray;
    Array<float> timeArray;
};


bool test_bc1(const char * inputFileName, int index, Stats * stats) {

    int w, h, n;
    unsigned char *input_data = stbi_load(inputFileName, &w, &h, &n, 4);
    defer { stbi_image_free(input_data); };

    if (input_data == nullptr) {
        printf("Failed to load input image '%s'.\n", inputFileName);
        return false;
    }


    int block_count = (w / 4) * (h / 4);
    u8 * rgba_block_data = (u8 *)malloc(block_count * 4 * 4 * 4);
    defer { free(rgba_block_data); };

    int bw = 4 * (w / 4); // Round down.
    int bh = 4 * (h / 4);

    // Convert to block layout.
    for (int y = 0, b = 0; y < bh; y += 4) {
        for (int x = 0; x < bw; x += 4, b++) {
            for (int yy = 0; yy < 4; yy++) {
                for (int xx = 0; xx < 4; xx++) {
                    if (x + xx < w && y + yy < h) {
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 0] = input_data[((y + yy) * w + x + xx) * 4 + 0];
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 1] = input_data[((y + yy) * w + x + xx) * 4 + 1];
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 2] = input_data[((y + yy) * w + x + xx) * 4 + 2];
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 3] = input_data[((y + yy) * w + x + xx) * 4 + 3];
                    }
                    else {
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 0] = 0;
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 1] = 0;
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 2] = 0;
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 3] = 0;
                    }
                }
            }
        }
    }

    u8 * block_data = (u8 *)malloc(block_count * 8);

    Timer timer;

    // Warmup.
    for (int b = 0; b < block_count; b++) {
        stb_compress_dxt_block(block_data + b * 8, rgba_block_data + b * 4 * 4 * 4, 0, STB_DXT_NORMAL);
    }

#if _DEBUG
    const int repeat_count = 1;
#else
    const int repeat_count = 1; // 8
#endif

    if (TEST_STB) {
        memset(block_data, 0, block_count * 8);

        timer.start();
        for (int i = 0; i < repeat_count; i++) {
            for (int b = 0; b < block_count; b++) {
                stb_compress_dxt_block(block_data + b * 8, rgba_block_data + b * 4 * 4 * 4, 0, STB_DXT_NORMAL);
            }
        }
        timer.stop();

        float mse = evaluate_dxt1_mse(rgba_block_data, block_data, block_count);

        if (stats) {
            stats->compressorName = "stb";
            stats->mseArray[index] = mse;
            stats->timeArray[index] = timer.elapsed() / repeat_count;
            stats++;
        }
        else {
            output_dxt_dds(bw, bh, block_data, "stb_dxt.dds");
        }
    }

    if (TEST_STB_HQ) {
        memset(block_data, 0, block_count * 8);

        timer.start();
        for (int i = 0; i < repeat_count; i++) {
            for (int b = 0; b < block_count; b++) {
                stb_compress_dxt_block(block_data + b * 8, rgba_block_data + b * 4 * 4 * 4, 0, STB_DXT_HIGHQUAL);
            }
        }
        timer.stop();

        float mse = evaluate_dxt1_mse(rgba_block_data, block_data, block_count);
        
        if (stats) {
            stats->compressorName = "stb-hq";
            stats->mseArray[index] = mse;
            stats->timeArray[index] = timer.elapsed() / repeat_count;
            stats++;
        }
        else {
            output_dxt_dds(bw, bh, block_data, "stb_dxt_hq.dds");
        }
    }

    if (TEST_GOOFY) {
        memset(block_data, 0, block_count * 8);

        timer.start();
        for (int i = 0; i < repeat_count; i++) {
            goofy::compressDXT1(block_data, input_data, w, h, w * 4);
        }
        timer.stop();

        float mse = evaluate_dxt1_mse(rgba_block_data, block_data, block_count);

        if (stats) {
            stats->compressorName = "goofy-dxt";
            stats->mseArray[index] = mse;
            stats->timeArray[index] = timer.elapsed() / repeat_count;
            stats++;
        }
        else {
            output_dxt_dds(bw, bh, block_data, "goofy_dxt.dds");
        }

        timer.start();
        for (int i = 0; i < repeat_count; i++) {
            goofy::compressETC1(block_data, input_data, w, h, w * 4);
        }
        timer.stop();

        mse = evaluate_dxt1_mse(rgba_block_data, block_data, block_count);

        if (stats) {
            stats->compressorName = "goofy-etc";
            stats->mseArray[index] = mse;
            stats->timeArray[index] = timer.elapsed() / repeat_count;
            stats++;
        }
        else {
            output_etc(bw, bh, block_data, "goofy_etc.png");
        }
    }

    if (TEST_RGBCX_FAST) {
        memset(block_data, 0, block_count * 8);

        rgbcx::init();

        for (int l = 0; l < 4; l++) {
            timer.start();
            for (int i = 0; i < repeat_count; i++) {
                for (int b = 0; b < block_count; b++) {
                    rgbcx::encode_bc1(l, (block_data + b * 8), rgba_block_data + b * 4 * 4 * 4, /*allow_3color=*/true, /*use_transparent_texels_for_black=*/true);
                }
            }
            timer.stop();

            float mse = evaluate_dxt1_mse(rgba_block_data, block_data, block_count);

            if (stats) {
                stats->compressorName = "rgbcx";
                stats->mseArray[index] = mse;
                stats->timeArray[index] = timer.elapsed() / repeat_count;
                stats++;
            }
            else {
                output_dxt_dds(bw, bh, block_data, "rgbcx.dds");
            }
        }
    }

    if (TEST_RGBCX_ALL) {
        memset(block_data, 0, block_count * 8);

        rgbcx::init();

        for (int l = 0; l < 19; l++) {
            timer.start();
            for (int i = 0; i < repeat_count; i++) {
                for (int b = 0; b < block_count; b++) {
                    rgbcx::encode_bc1(l, (block_data + b * 8), rgba_block_data + b * 4 * 4 * 4, /*allow_3color=*/true, /*use_transparent_texels_for_black=*/true);
                }
            }
            timer.stop();

            float mse = evaluate_dxt1_mse(rgba_block_data, block_data, block_count);

            if (stats) {
                stats->compressorName = "rgbcx";
                stats->mseArray[index] = mse;
                stats->timeArray[index] = timer.elapsed() / repeat_count;
                stats++;
            }
            else {
                output_dxt_dds(bw, bh, block_data, "rgbcx.dds");
            }
        }
    }

    bool three_color_mode = true;
    bool three_color_black = true;

    if (TEST_ICBC_FAST) {
        memset(block_data, 0, block_count * 8);
        float color_weights[3] = { 1, 1, 1 };

        timer.start();
        for (int i = 0; i < repeat_count; i++) {
            for (int b = 0; b < block_count; b++) {
                float input_colors[16*4];
                float input_weights[16];
                for (int j = 0; j < 16; j++) {
                    input_colors[4*j+0] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 0] / 255.0f;
                    input_colors[4*j+1] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 1] / 255.0f;
                    input_colors[4*j+2] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 2] / 255.0f;
                    input_colors[4*j+3] = 1.0f;
                    input_weights[j] = 1.0f;
                }

                icbc::compress_dxt1(icbc::Quality_Fast, input_colors, input_weights, color_weights, three_color_mode, three_color_black, (block_data + b * 8));
            }
        }
        timer.stop();

        float mse = evaluate_dxt1_mse(rgba_block_data, block_data, block_count);
        
        if (stats) {
            stats->compressorName = "icbc-fast";
            stats->mseArray[index] = mse;
            stats->timeArray[index] = timer.elapsed() / repeat_count;
            stats++;
        }
        else {
            output_dxt_dds(bw, bh, block_data, "icbc_fast.dds");
        }
    }

    if (TEST_ICBC) {
        memset(block_data, 0, block_count * 8);
        float color_weights[3] = { 1, 1, 1 };

        timer.start();
        for (int i = 0; i < repeat_count; i++) {
            for (int b = 0; b < block_count; b++) {
                float input_colors[16*4];
                float input_weights[16];
                for (int j = 0; j < 16; j++) {
                    input_colors[4*j+0] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 0] / 255.0f;
                    input_colors[4*j+1] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 1] / 255.0f;
                    input_colors[4*j+2] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 2] / 255.0f;
                    input_colors[4*j+3] = 1.0f;
                    input_weights[j] = 1.0f;
                }

                icbc::compress_dxt1(icbc::Quality_Default, input_colors, input_weights, color_weights, three_color_mode, three_color_black, (block_data + b * 8));
            }
        }
        timer.stop();

        float mse = evaluate_dxt1_mse(rgba_block_data, block_data, block_count);

        if (stats) {
            stats->compressorName = "icbc";
            stats->mseArray[index] = mse;
            stats->timeArray[index] = timer.elapsed() / repeat_count;
            stats++;
        }
        else {
            output_dxt_dds(bw, bh, block_data, "icbc.dds");
        }
    }

    if (TEST_ICBC_HQ) {
        memset(block_data, 0, block_count * 8);
        float color_weights[3] = { 1, 1, 1 };

        timer.start();
        for (int i = 0; i < repeat_count; i++) {
            for (int b = 0; b < block_count; b++) {
                float input_colors[16 * 4];
                float input_weights[16];
                for (int j = 0; j < 16; j++) {
                    input_colors[4 * j + 0] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 0] / 255.0f;
                    input_colors[4 * j + 1] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 1] / 255.0f;
                    input_colors[4 * j + 2] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 2] / 255.0f;
                    input_colors[4 * j + 3] = 1.0f;
                    input_weights[j] = 1.0f;
                }

                icbc::compress_dxt1(icbc::Quality_Max, input_colors, input_weights, color_weights, three_color_mode, three_color_black, (block_data + b * 8));
            }
        }
        timer.stop();

        float mse = evaluate_dxt1_mse(rgba_block_data, block_data, block_count);

        if (stats) {
            stats->compressorName = "icbc-hq";
            stats->mseArray[index] = mse;
            stats->timeArray[index] = timer.elapsed() / repeat_count;
            stats++;
        }
        else {
            output_dxt_dds(bw, bh, block_data, "icbc_hq.dds");
        }
    }

    if (TEST_ICBC_ALL) {
        memset(block_data, 0, block_count * 8);
        float color_weights[3] = { 1, 1, 1 };

        for (int l = 0; l <= icbc::Quality_Max; l++) {
            timer.start();
            for (int i = 0; i < repeat_count; i++) {
                for (int b = 0; b < block_count; b++) {
                    float input_colors[16 * 4];
                    float input_weights[16];
                    for (int j = 0; j < 16; j++) {
                        input_colors[4 * j + 0] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 0] / 255.0f;
                        input_colors[4 * j + 1] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 1] / 255.0f;
                        input_colors[4 * j + 2] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 2] / 255.0f;
                        input_colors[4 * j + 3] = 1.0f;
                        input_weights[j] = 1.0f;
                    }

                    icbc::compress_dxt1((icbc::Quality)l, input_colors, input_weights, color_weights, true, true, (block_data + b * 8));
                }
            }
            timer.stop();

            float mse = evaluate_dxt1_mse(rgba_block_data, block_data, block_count);

            if (stats) {
                stats->compressorName = "icbc";
                stats->mseArray[index] = mse;
                stats->timeArray[index] = timer.elapsed() / repeat_count;
                stats++;
            }
            else {
                output_dxt_dds(bw, bh, block_data, "icbc.dds");
            }
        }
    }

    if (TEST_IC_ETC) {
        memset(block_data, 0, block_count * 8);
        float color_weights[3] = { 1, 1, 1 };

        //int b_stop = (1132 / 4) * (bw / 4) + 1028 / 4;

        timer.start();
        for (int i = 0; i < repeat_count; i++) {
            for (int b = 0; b < block_count; b++) {
                float input_colors[16 * 4];
                float input_weights[16];
                for (int j = 0; j < 16; j++) {
                    input_colors[4 * j + 0] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 0] / 255.0f;
                    input_colors[4 * j + 1] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 1] / 255.0f;
                    input_colors[4 * j + 2] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 2] / 255.0f;
                    input_colors[4 * j + 3] = 1.0f;
                    input_weights[j] = 1.0f;
                }

                icetc::compress_etc2(input_colors, input_weights, color_weights, (block_data + b * 8));
            }
        }
        timer.stop();

        float mse = evaluate_etc2_mse(rgba_block_data, block_data, block_count);

        if (stats) {
            stats->compressorName = "ic_etc";
            stats->mseArray[index] = mse;
            stats->timeArray[index] = timer.elapsed() / repeat_count;
            stats++;
        }
        else {
            output_etc(bw, bh, block_data, "ic_etc.png");
        }
    }

    if (TEST_RG_ETC) {
        memset(block_data, 0, block_count * 8);
        float color_weights[3] = { 1, 1, 1 };

        rg_etc1::etc1_pack_params pack_params;
        pack_params.m_quality = rg_etc1::cLowQuality;
        //pack_params.m_quality = rg_etc1::cMediumQuality;
        //pack_params.m_quality = rg_etc1::cHighQuality;

        //int b_stop = (1132 / 4) * (bw / 4) + 1028 / 4;

        timer.start();
        for (int i = 0; i < repeat_count; i++) {
            for (int b = 0; b < block_count; b++) {
                float input_colors[16 * 4];
                float input_weights[16];
                for (int j = 0; j < 16; j++) {
                    input_colors[4 * j + 0] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 0] / 255.0f;
                    input_colors[4 * j + 1] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 1] / 255.0f;
                    input_colors[4 * j + 2] = rgba_block_data[b * 4 * 4 * 4 + j * 4 + 2] / 255.0f;
                    input_colors[4 * j + 3] = 1.0f;
                    input_weights[j] = 1.0f;
                }

                rg_etc1::pack_etc1_block((block_data + b * 8), (const uint*)rgba_block_data + b * 4 * 4, pack_params);
            }
        }
        timer.stop();

        float mse = evaluate_etc2_mse(rgba_block_data, block_data, block_count);

        if (stats) {
            stats->compressorName = "rg_etc";
            stats->mseArray[index] = mse;
            stats->timeArray[index] = timer.elapsed() / repeat_count;
            stats++;
        }
        else {
            output_etc(bw, bh, block_data, "rg_etc.png");
        }
    }

    if (TEST_SQUISH) {
        memset(block_data, 0, block_count * 8);

        timer.start();
        for (int i = 0; i < repeat_count; i++) {
            for (int b = 0; b < block_count; b++) {
                squish::Compress(rgba_block_data + b * 4 * 4 * 4, block_data + b * 8, squish::kDxt1);
            }
        }
        timer.stop();

        float mse = evaluate_dxt1_mse(rgba_block_data, block_data, block_count);

        if (stats) {
            stats->compressorName = "squish";
            stats->mseArray[index] = mse;
            stats->timeArray[index] = timer.elapsed() / repeat_count;
            stats++;
        }
        else {
            output_dxt_dds(bw, bh, block_data, "squish.dds");
        }
    }

    if (TEST_SQUISH_HQ) {
        memset(block_data, 0, block_count * 8);

        timer.start();
        for (int i = 0; i < repeat_count; i++) {
            for (int b = 0; b < block_count; b++) {
                squish::Compress(rgba_block_data + b * 4 * 4 * 4, block_data + b * 8, squish::kDxt1 | squish::kColourIterativeClusterFit);
            }
        }
        timer.stop();

        float mse = evaluate_dxt1_mse(rgba_block_data, block_data, block_count);

        if (stats) {
            stats->compressorName = "squish-hq";
            stats->mseArray[index] = mse;
            stats->timeArray[index] = timer.elapsed() / repeat_count;
            stats++;
        }
        else {
            output_dxt_dds(bw, bh, block_data, "squish_hq.dds");
        }
    }

    if (TEST_AMD_CMP) {
        memset(block_data, 0, block_count * 8);

        void *options;
        CreateOptionsBC1(&options);
        SetQualityBC1(options, 1.0); // It seems AMD has only two compressors for 0.0 and 1.0 values.

        timer.start();
        for (int i = 0; i < repeat_count; i++) {
            for (int b = 0; b < block_count; b++) {
                CompressBlockBC1(rgba_block_data + b * 4 * 4 * 4, 16, block_data + b * 8, options);
            }
        }
        timer.stop();

        DestroyOptionsBC1(options);

        float mse = evaluate_dxt1_mse(rgba_block_data, block_data, block_count);

        if (stats) {
            stats->compressorName = "cmp";
            stats->mseArray[index] = mse;
            stats->timeArray[index] = timer.elapsed() / repeat_count;
            stats++;
        }
        else {
            output_dxt_dds(bw, bh, block_data, "squish.dds");
        }
    }

    return false;
}



bool analyze_bc1(const char * inputFileName) {

    int w, h, n;
    unsigned char *input_data = stbi_load(inputFileName, &w, &h, &n, 4);
    defer { stbi_image_free(input_data); };

    if (input_data == nullptr) {
        printf("Failed to load input image '%s'.\n", inputFileName);
        return false;
    }

    int block_count = (w / 4) * (h / 4);
    u8 * rgba_block_data = (u8 *)malloc(block_count * 4 * 4 * 4);
    defer { free(rgba_block_data); };

    int bw = 4 * (w / 4); // Round down.
    int bh = 4 * (h / 4);

    // Convert to block layout.
    for (int y = 0, b = 0; y < bh; y += 4) {
        for (int x = 0; x < bw; x += 4, b++) {
            for (int yy = 0; yy < 4; yy++) {
                for (int xx = 0; xx < 4; xx++) {
                    if (x + xx < w && y + yy < h) {
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 0] = input_data[((y + yy) * w + x + xx) * 4 + 0];
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 1] = input_data[((y + yy) * w + x + xx) * 4 + 1];
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 2] = input_data[((y + yy) * w + x + xx) * 4 + 2];
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 3] = input_data[((y + yy) * w + x + xx) * 4 + 3];
                    }
                    else {
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 0] = 0;
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 1] = 0;
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 2] = 0;
                        rgba_block_data[b * 4 * 4 * 4 + (yy * 4 + xx) * 4 + 3] = 0;
                    }
                }
            }
        }
    }

    u8 * block_data = (u8 *)malloc(block_count * 8);
    memset(block_data, 0, block_count * 8);

    Timer timer;

    int stb_better_than_icbc_fast = 0;
    int stb_better_than_icbc = 0;
    int stb_better_than_icbc_hq = 0;
    int squish_better_than_icbc_hq = 0;

    int icbc_hq_wins = 0;

    int this_should_never_happen = 0;
        
    float color_weights[3] = { 1, 1, 1 };

    for (int b = 0; b < block_count; b++) {

        uint8 * rgba_block = rgba_block_data + b * 4 * 4 * 4;
        uint8 * dxt_block = block_data + b * 8;

        float input_colors[16*4];
        float input_weights[16];
        for (int j = 0; j < 16; j++) {
            input_colors[4*j+0] = rgba_block[j * 4 + 0] / 255.0f;
            input_colors[4*j+1] = rgba_block[j * 4 + 1] / 255.0f;
            input_colors[4*j+2] = rgba_block[j * 4 + 2] / 255.0f;
            input_colors[4*j+3] = 255.0f;
            input_weights[j] = 1.0f;
        }

        // Compare all the different modes on the same block:

        stb_compress_dxt_block(dxt_block, rgba_block, 0, STB_DXT_NORMAL);
        float mse_stb = icbc::evaluate_dxt1_error(rgba_block, dxt_block);

        stb_compress_dxt_block(dxt_block, rgba_block, 0, STB_DXT_HIGHQUAL);
        float mse_stb_hq = icbc::evaluate_dxt1_error(rgba_block, dxt_block);

        icbc::compress_dxt1(icbc::Quality_Fast, input_colors, input_weights, color_weights, true, true, dxt_block);
        float mse_icbc_fast = icbc::evaluate_dxt1_error(rgba_block, dxt_block);

        icbc::compress_dxt1(icbc::Quality_Default, input_colors, input_weights, color_weights, true, true, dxt_block);
        float mse_icbc = icbc::evaluate_dxt1_error(rgba_block, dxt_block);

        icbc::compress_dxt1(icbc::Quality_Max, input_colors, input_weights, color_weights, true, true, dxt_block);
        float mse_icbc_hq = icbc::evaluate_dxt1_error(rgba_block, dxt_block);

        squish::Compress(rgba_block, dxt_block, squish::kDxt1);
        float mse_squish = icbc::evaluate_dxt1_error(rgba_block, dxt_block);

        squish::Compress(rgba_block, dxt_block, squish::kDxt1 | squish::kColourIterativeClusterFit);
        float mse_squish_hq = icbc::evaluate_dxt1_error(rgba_block, dxt_block);

        if (mse_stb < mse_icbc_fast) {
            stb_better_than_icbc_fast++;
        }
        if (mse_stb < mse_icbc) {
            stb_better_than_icbc++;
        }
        if (mse_stb < mse_icbc_hq) {
            stb_better_than_icbc_hq++;
        }
        if (mse_icbc_hq < mse_icbc) {
            icbc_hq_wins++;
        }
        if (mse_squish < mse_icbc_hq) {
            squish_better_than_icbc_hq++;
        }
        if (mse_icbc_fast < mse_icbc_hq) {
            this_should_never_happen++;
        }
    }

    return true;
}



static float mse_to_psnr(float mse) {
    float rms = sqrtf(mse);
    float psnr = rms ? (float)clamp(log10(255.0 / rms) * 20.0, 0.0, 300.0) : 1e+10f;
    return psnr;
}


const char * image_set[] = {
    "testsuite/kodak/kodim01.png",
    "testsuite/kodak/kodim02.png",
    "testsuite/kodak/kodim03.png",
    "testsuite/kodak/kodim04.png",
    "testsuite/kodak/kodim05.png",
    "testsuite/kodak/kodim06.png",
    "testsuite/kodak/kodim07.png",
    "testsuite/kodak/kodim08.png",
    "testsuite/kodak/kodim09.png",
    "testsuite/kodak/kodim10.png",
    "testsuite/kodak/kodim11.png",
    "testsuite/kodak/kodim12.png",
    "testsuite/kodak/kodim13.png",
    "testsuite/kodak/kodim14.png",
    "testsuite/kodak/kodim15.png",
    "testsuite/kodak/kodim16.png",
    "testsuite/kodak/kodim17.png",
    "testsuite/kodak/kodim18.png",
    "testsuite/kodak/kodim19.png",
    "testsuite/kodak/kodim20.png",
    "testsuite/kodak/kodim21.png",
    "testsuite/kodak/kodim22.png",
    "testsuite/kodak/kodim23.png",
    "testsuite/kodak/kodim24.png",
    "testsuite/waterloo/clegg.png",
    "testsuite/waterloo/frymire.png",
    "testsuite/waterloo/lena.png",
    "testsuite/waterloo/monarch.png",
    "testsuite/waterloo/peppers.png",
    "testsuite/waterloo/sail.png",
    "testsuite/waterloo/serrano.png",
    "testsuite/waterloo/tulips.png",
    //"testsuite/artificial.png",
};

const char * roblox_set[] = {
    "Roblox/asphalt_side/diffuse.tga",
    "Roblox/asphalt_top/diffuse.tga",
    "Roblox/basalt/diffuse.tga",
    "Roblox/brick/diffuse.tga",
    "Roblox/cobblestone_side/diffuse.tga",
    "Roblox/cobblestone_top/diffuse.tga",
    "Roblox/concrete_side/diffuse.tga",
    "Roblox/concrete_top/diffuse.tga",
    "Roblox/crackedlava/diffuse.tga",
    "Roblox/glacier_bottom/diffuse.tga",
    "Roblox/glacier_side/diffuse.tga",
    "Roblox/glacier_top/diffuse.tga",
    "Roblox/grass_bottom/diffuse.tga",
    "Roblox/grass_side/diffuse.tga",
    "Roblox/grass_top/diffuse.tga",
    "Roblox/ground/diffuse.tga",
    "Roblox/ice_side/diffuse.tga",
    "Roblox/ice_top/diffuse.tga",
    "Roblox/leafygrass_side/diffuse.tga",
    "Roblox/leafygrass_top/diffuse.tga",
    "Roblox/limestone_side/diffuse.tga",
    "Roblox/limestone_top/diffuse.tga",
    "Roblox/mud/diffuse.tga",
    "Roblox/pavement_side/diffuse.tga",
    "Roblox/pavement_top/diffuse.tga",
    "Roblox/rock/diffuse.tga",
    "Roblox/salt_side/diffuse.tga",
    "Roblox/salt_top/diffuse.tga",
    "Roblox/sand_side/diffuse.tga",
    "Roblox/sand_top/diffuse.tga",
    "Roblox/sandstone_bottom/diffuse.tga",
    "Roblox/sandstone_side/diffuse.tga",
    "Roblox/sandstone_top/diffuse.tga",
    "Roblox/slate/diffuse.tga",
    "Roblox/snow/diffuse.tga",
    "Roblox/woodplanks/diffuse.tga",
};


int main(int argc, char *argv[])
{
    //const char * inputFileName = "testsuite/artificial.png";
    //const char * inputFileName = "testsuite/kodak/kodim14.png";
    const char * inputFileName = "testsuite/kodak/kodim18.png";
    //const char * inputFileName = "testsuite/kodak/kodim15.png";
    //const char * inputFileName = "testsuite/waterloo/frymire.png";
    //const char * inputFileName = "Roblox/leafygrass_top/diffuse.tga";

    icbc::init_dxt1();
    icetc::init();
    rgbcx::init();
    rg_etc1::pack_etc1_block_init();

    //test_bc1(inputFileName, 0, NULL);
    //analyze_bc1(inputFileName);

    //const char ** set = roblox_set;
    //int count = sizeof(roblox_set) / sizeof(char*);

    const char ** set = image_set;
    int count = sizeof(image_set) / sizeof(char*);

    const int MAX_COMPRESSOR_COUNT = 64;
    Stats stats[MAX_COMPRESSOR_COUNT];

    for (int i = 0; i < MAX_COMPRESSOR_COUNT; i++) {
        stats[i].compressorName = nullptr;
        stats[i].mseArray.resize(count, 0.0f);
        stats[i].timeArray.resize(count, 0.0f);
    }

    for (int i = 0; i < count; i++) {
        printf("\nImage '%s'\n", set[i]);

        test_bc1(set[i], i, stats);

        for (int c = 0; c < MAX_COMPRESSOR_COUNT; c++) {
            if (stats[c].compressorName) {
                printf("%-16s %f\t%f\t%f\n", stats[c].compressorName, sqrtf(stats[c].mseArray[i]), mse_to_psnr(stats[c].mseArray[i]), stats[c].timeArray[i]);
            }
        }
    }

    // Print stats.
    printf("\nAverage Results:\n");
    for (int c = 0; c < MAX_COMPRESSOR_COUNT; c++) {
        if (stats[c].compressorName) {
            float sum = 0.0f;
            for (float it : stats[c].mseArray) {
                sum += it;
            }
            sum /= count;

            float time = 0.0f;
            for (float it : stats[c].timeArray) {
                time += it;
            }

            printf("%-16s %f\t%f\t%f\n", stats[c].compressorName, sqrtf(sum), mse_to_psnr(sum), time);
        }
    }

    for (int i = 0; i < 16; i++) {
        printf("%d, ", icbc::s_fourClusterTotal[i]);
    }
    printf("\n");

    for (int i = 0; i < 16; i++) {
        printf("%d, ", icbc::s_threeClusterTotal[i]);
    }
    printf("\n\n");

    /*
    for (int i = 0; i < 968; i++) {
        printf("%lld, ", icbc::s_fourClusterHistogram[i]);
    } printf("\n\n");

    for (int i = 0; i < 968; i++) {
        printf("%d, ", icbc::s_fourCluster[i].c0);
    } printf("\n\n");
    
    for (int i = 0; i < 968; i++) {
        printf("%d, ", icbc::s_fourCluster[i].c1 - icbc::s_fourCluster[i].c0);
    } printf("\n\n");
    
    for (int i = 0; i < 968; i++) {
        printf("%d, ", icbc::s_fourCluster[i].c2 - icbc::s_fourCluster[i].c1);
    }
    */
    printf("\n");


    /*for (int c = 0; c < MAX_COMPRESSOR_COUNT; c++) {
        if (stats[c].compressorName) {
            printf("%s:\n", stats[c].compressorName);
            for (int i = 0; i < count; i++) {
                printf("%f, ", mse_to_psnr(stats[c].mseArray[i]));
            }
            puts("\n");
            
            for (int i = 0; i < count; i++) {
                printf("%f, ", stats[c].timeArray[i]);
            }
            puts("\n");
        }
    }*/


    return EXIT_SUCCESS;
}


<|start_filename|>src/nvimage/TgaFile.h<|end_filename|>
// This code is in the public domain -- <EMAIL>

#pragma once
#ifndef NV_IMAGE_TGAFILE_H
#define NV_IMAGE_TGAFILE_H

#include "nvcore/Stream.h"

namespace nv
{
	
// TGA types
enum TGAType {
    TGA_TYPE_INDEXED		= 1,
    TGA_TYPE_RGB			= 2,
    TGA_TYPE_GREY			= 3,
    TGA_TYPE_RLE_INDEXED	= 9,
    TGA_TYPE_RLE_RGB		= 10,
    TGA_TYPE_RLE_GREY		= 11
};

#define TGA_INTERLEAVE_MASK	0xc0
#define TGA_INTERLEAVE_NONE	0x00
#define TGA_INTERLEAVE_2WAY	0x40
#define TGA_INTERLEAVE_4WAY	0x80

#define TGA_ORIGIN_MASK		0x30
#define TGA_ORIGIN_LEFT		0x00
#define TGA_ORIGIN_RIGHT	0x10
#define TGA_ORIGIN_LOWER	0x00
#define TGA_ORIGIN_UPPER	0x20

#define TGA_HAS_ALPHA		0x0F


/// Tga Header.
struct TgaHeader {
	uint8	id_length;
	uint8	colormap_type;
	uint8	image_type;
	uint16	colormap_index;
	uint16	colormap_length;
	uint8	colormap_size;
	uint16	x_origin;
	uint16	y_origin;
	uint16	width;
	uint16	height;
	uint8	pixel_size;
	uint8	flags;

	enum { Size = 18 };		//const static int SIZE = 18;
};


/// Tga File.
struct TgaFile {

	TgaFile() {
		mem = NULL;
	}
	~TgaFile() {
		free();
	}

	uint size() const {
		return head.width * head.height * (head.pixel_size / 8);
	}
	void allocate() {
		nvCheck( mem == NULL );
		mem = new uint8[size()];
	}
	void free() {
		delete [] mem;
		mem = NULL;
	}

	TgaHeader head;
	uint8 * mem;
};


inline Stream & operator<< (Stream & s, TgaHeader & head)
{
	s << head.id_length << head.colormap_type << head.image_type;
	s << head.colormap_index << head.colormap_length << head.colormap_size;
	s << head.x_origin << head.y_origin << head.width << head.height;
	s << head.pixel_size << head.flags;
	return s;
}

inline Stream & operator<< (Stream & s, TgaFile & tga)
{
	s << tga.head;

	if( s.isLoading() ) {
		tga.allocate();
	}

	s.serialize( tga.mem, tga.size() );

	return s;
}



// @@ Move to BMP file?

const int BITMAPFILEHEADER_SIZE = 14;
const int BITMAPINFOHEADER_SIZE = 40;
const int BM_TYPE = ((unsigned int)'M') << 8 | ((unsigned int)'B');

// BMP Header.
struct BmpFileHeader {
    uint16 type;
    uint32 size;
    uint16 reserved1;
    uint16 reserved2;
    uint32 offBits;
};

struct BmpInfoHeader {
    uint32 size;
    uint32 width;
    uint32 height;
    uint16 planes;
    uint16 bitCount;
    uint32 compression;
    uint32 sizeImage;
    uint32 xPelsPerMeter;
    uint32 yPelsPerMeter;
    uint32 clrUsed;
    uint32 clrImportant;
};

inline Stream & operator<< (Stream & s, BmpFileHeader & bmp) {
    return s << bmp.type << bmp.size << bmp.reserved1 << bmp.reserved2 << bmp.offBits;
}

inline Stream & operator<< (Stream & s, BmpInfoHeader & bmp) {
    s << bmp.size << bmp.width << bmp.height << bmp.planes << bmp.bitCount << bmp.compression << bmp.sizeImage;
    s << bmp.xPelsPerMeter << bmp.yPelsPerMeter << bmp.clrUsed << bmp.clrImportant;
    return s;
}


} // nv namespace

#endif // NV_IMAGE_TGAFILE_H


<|start_filename|>src/bc7/endpts.h<|end_filename|>
/*
Copyright 2007 nVidia, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 

You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

See the License for the specific language governing permissions and limitations under the License.
*/

#ifndef _AVPCL_ENDPTS_H
#define _AVPCL_ENDPTS_H

// endpoint definitions and routines to search through endpoint space

#include "nvmath/Vector.h"

namespace AVPCL {

static const int NCHANNELS_RGB	= 3;
static const int NCHANNELS_RGBA	= 4;
static const int CHANNEL_R		= 0;
static const int CHANNEL_G		= 1;
static const int CHANNEL_B		= 2;
static const int CHANNEL_A		= 3;

struct FltEndpts
{
	nv::Vector4	A;
	nv::Vector4	B;
};

struct IntEndptsRGB
{
	int		A[NCHANNELS_RGB];
	int		B[NCHANNELS_RGB];
};

struct IntEndptsRGB_1
{
	int		A[NCHANNELS_RGB];
	int		B[NCHANNELS_RGB];
	int		lsb;				// shared lsb for A and B
};

struct IntEndptsRGB_2
{
	int		A[NCHANNELS_RGB];
	int		B[NCHANNELS_RGB];
	int		a_lsb;				// lsb for A
	int		b_lsb;				// lsb for B
};


struct IntEndptsRGBA
{
	int		A[NCHANNELS_RGBA];
	int		B[NCHANNELS_RGBA];
};

struct IntEndptsRGBA_2
{
	int		A[NCHANNELS_RGBA];
	int		B[NCHANNELS_RGBA];
	int		a_lsb;				// lsb for A
	int		b_lsb;				// lsb for B
};

struct IntEndptsRGBA_2a
{
	int		A[NCHANNELS_RGBA];
	int		B[NCHANNELS_RGBA];
	int		a_lsb;				// lsb for RGB channels of A
	int		b_lsb;				// lsb for RGB channels of A
};

}

#endif


<|start_filename|>src/bc6h/zohtwo.cpp<|end_filename|>
/*
Copyright 2007 nVidia, Inc.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 

You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

See the License for the specific language governing permissions and limitations under the License.
*/

// two regions zoh compress/decompress code
// Thanks to <NAME> (<EMAIL>) for the shortcut of using SVD to do the equivalent of principal components analysis

/* optimization algorithm

	get initial float endpoints
	convert endpoints using 16 bit precision, transform, and get bit delta. choose likely endpoint compression candidates.
		note that there will be 1 or 2 candidates; 2 will be chosen when the delta values are close to the max possible.
	for each EC candidate in order from max precision to smaller precision
		convert endpoints using the appropriate precision.
		optimize the endpoints and minimize square error. save the error and index assignments. apply index compression as well.
			(thus the endpoints and indices are in final form.)
		transform and get bit delta.
		if the bit delta fits, exit
	if we ended up with no candidates somehow, choose the tail set of EC candidates and retry. this should happen hardly ever.
		add a state variable to nvDebugCheck we only do this once.
	convert to bit stream.
	return the error.

	Global optimization
		order all tiles based on their errors
		do something special for high-error tiles
			the goal here is to try to avoid tiling artifacts. but I think this is a research problem. let's just generate an error image...

	display an image that shows partitioning and precision selected for each tile
*/

#include "bits.h"
#include "tile.h"
#include "zoh.h"
#include "zoh_utils.h"

#include "nvmath/Fitting.h"
#include "nvmath/Vector.inl"

#include <string.h> // strlen
#include <float.h> // FLT_MAX

using namespace nv;
using namespace ZOH;

#define NINDICES	8
#define	INDEXBITS	3
#define	HIGH_INDEXBIT	(1<<(INDEXBITS-1))
#define	DENOM		(NINDICES-1)

// WORK: determine optimal traversal pattern to search for best shape -- what does the error curve look like?
// i.e. can we search shapes in a particular order so we can see the global error minima easily and
// stop without having to touch all shapes?

#include "shapes_two.h"
// use only the first 32 available shapes
#undef NSHAPES
#undef SHAPEBITS
#define NSHAPES 32
#define SHAPEBITS 5

#define	POS_TO_X(pos)	((pos)&3)
#define	POS_TO_Y(pos)	(((pos)>>2)&3)

#define	NDELTA	4

struct Chanpat
{
    int prec[NDELTA];		// precision pattern for one channel
};

struct Pattern
{
    Chanpat chan[NCHANNELS];    // allow different bit patterns per channel -- but we still want constant precision per channel
    int transformed;            // if 0, deltas are unsigned and no transform; otherwise, signed and transformed
    int mode;                   // associated mode value
    int modebits;               // number of mode bits
    const char *encoding;       // verilog description of encoding for this mode
};

#define MAXMODEBITS	5
#define	MAXMODES (1<<MAXMODEBITS)

#define	NPATTERNS 10

static const Pattern patterns[NPATTERNS] =
{
    11,5,5,5,	11,4,4,4,	11,4,4,4,	1,	0x02, 5, "d[4:0],bz[3],rz[4:0],bz[2],ry[4:0],by[3:0],bz[1],bw[10],bx[3:0],gz[3:0],bz[0],gw[10],gx[3:0],gy[3:0],rw[10],rx[4:0],bw[9:0],gw[9:0],rw[9:0],m[4:0]",
    11,4,4,4,	11,5,5,5,	11,4,4,4,	1,	0x06, 5, "d[4:0],bz[3],gy[4],rz[3:0],bz[2],bz[0],ry[3:0],by[3:0],bz[1],bw[10],bx[3:0],gz[3:0],gw[10],gx[4:0],gy[3:0],gz[4],rw[10],rx[3:0],bw[9:0],gw[9:0],rw[9:0],m[4:0]",
    11,4,4,4,	11,4,4,4,	11,5,5,5,	1,	0x0a, 5, "d[4:0],bz[3],bz[4],rz[3:0],bz[2:1],ry[3:0],by[3:0],bw[10],bx[4:0],gz[3:0],bz[0],gw[10],gx[3:0],gy[3:0],by[4],rw[10],rx[3:0],bw[9:0],gw[9:0],rw[9:0],m[4:0]",
    10,5,5,5,	10,5,5,5,	10,5,5,5,	1,	0x00, 2, "d[4:0],bz[3],rz[4:0],bz[2],ry[4:0],by[3:0],bz[1],bx[4:0],gz[3:0],bz[0],gx[4:0],gy[3:0],gz[4],rx[4:0],bw[9:0],gw[9:0],rw[9:0],bz[4],by[4],gy[4],m[1:0]",
    9,5,5,5,	9,5,5,5,	9,5,5,5,	1,	0x0e, 5, "d[4:0],bz[3],rz[4:0],bz[2],ry[4:0],by[3:0],bz[1],bx[4:0],gz[3:0],bz[0],gx[4:0],gy[3:0],gz[4],rx[4:0],bz[4],bw[8:0],gy[4],gw[8:0],by[4],rw[8:0],m[4:0]",
    8,6,6,6,	8,5,5,5,	8,5,5,5,	1,	0x12, 5, "d[4:0],rz[5:0],ry[5:0],by[3:0],bz[1],bx[4:0],gz[3:0],bz[0],gx[4:0],gy[3:0],rx[5:0],bz[4:3],bw[7:0],gy[4],bz[2],gw[7:0],by[4],gz[4],rw[7:0],m[4:0]",
    8,5,5,5,	8,6,6,6,	8,5,5,5,	1,	0x16, 5, "d[4:0],bz[3],rz[4:0],bz[2],ry[4:0],by[3:0],bz[1],bx[4:0],gz[3:0],gx[5:0],gy[3:0],gz[4],rx[4:0],bz[4],gz[5],bw[7:0],gy[4],gy[5],gw[7:0],by[4],bz[0],rw[7:0],m[4:0]",
    8,5,5,5,	8,5,5,5,	8,6,6,6,	1,	0x1a, 5, "d[4:0],bz[3],rz[4:0],bz[2],ry[4:0],by[3:0],bx[5:0],gz[3:0],bz[0],gx[4:0],gy[3:0],gz[4],rx[4:0],bz[4],bz[5],bw[7:0],gy[4],by[5],gw[7:0],by[4],bz[1],rw[7:0],m[4:0]",
    7,6,6,6,	7,6,6,6,	7,6,6,6,	1,	0x01, 2, "d[4:0],rz[5:0],ry[5:0],by[3:0],bx[5:0],gz[3:0],gx[5:0],gy[3:0],rx[5:0],bz[4],bz[5],bz[3],bw[6:0],gy[4],bz[2],by[5],gw[6:0],by[4],bz[1:0],rw[6:0],gz[5:4],gy[5],m[1:0]",
    6,6,6,6,	6,6,6,6,	6,6,6,6,	0,	0x1e, 5, "d[4:0],rz[5:0],ry[5:0],by[3:0],bx[5:0],gz[3:0],gx[5:0],gy[3:0],rx[5:0],bz[4],bz[5],bz[3],gz[5],bw[5:0],gy[4],bz[2],by[5],gy[5],gw[5:0],by[4],bz[1:0],gz[4],rw[5:0],m[4:0]",
};

// mapping of mode to the corresponding index in pattern
// UNUSED ZOH MODES are 0x13, 0x17, 0x1b, 0x1f -- return -2 for these
static const int mode_to_pat[MAXMODES] = {	
    3,	// 0x00
    8,	// 0x01
    0,	// 0x02
    -1,-1,-1,
    1,	// 0x06
    -1,-1,-1,
    2,	// 0x0a
    -1,-1,-1,
    4,	// 0x0e
    -1,-1,-1,
    5,	// 0x12
    -2,-1,-1,
    6,	// 0x16
    -2,-1,-1,
    7,	// 0x1a
    -2,-1,-1,
    9,	// 0x1e
    -2
};

#define	R_0(ep)	(ep)[0].A[i]
#define	R_1(ep)	(ep)[0].B[i]
#define	R_2(ep)	(ep)[1].A[i]
#define	R_3(ep)	(ep)[1].B[i]
#define	MASK(n)	((1<<(n))-1)

// compress endpoints
static void compress_endpts(const IntEndpts in[NREGIONS_TWO], ComprEndpts out[NREGIONS_TWO], const Pattern &p)
{
    if (p.transformed)
    {
        for (int i=0; i<NCHANNELS; ++i)
        {
            R_0(out) = R_0(in) & MASK(p.chan[i].prec[0]);
            R_1(out) = (R_1(in) - R_0(in)) & MASK(p.chan[i].prec[1]);
            R_2(out) = (R_2(in) - R_0(in)) & MASK(p.chan[i].prec[2]);
            R_3(out) = (R_3(in) - R_0(in)) & MASK(p.chan[i].prec[3]);
        }
    }
    else
    {
        for (int i=0; i<NCHANNELS; ++i)
        {
            R_0(out) = R_0(in) & MASK(p.chan[i].prec[0]);
            R_1(out) = R_1(in) & MASK(p.chan[i].prec[1]);
            R_2(out) = R_2(in) & MASK(p.chan[i].prec[2]);
            R_3(out) = R_3(in) & MASK(p.chan[i].prec[3]);
        }
    }
}

// decompress endpoints
static void decompress_endpts(const ComprEndpts in[NREGIONS_TWO], IntEndpts out[NREGIONS_TWO], const Pattern &p)
{
    bool issigned = Utils::FORMAT == SIGNED_F16;

    if (p.transformed)
    {
        for (int i=0; i<NCHANNELS; ++i)
        {
            R_0(out) = issigned ? SIGN_EXTEND(R_0(in),p.chan[i].prec[0]) : R_0(in);
            int t;
            t = SIGN_EXTEND(R_1(in), p.chan[i].prec[1]);
            t = (t + R_0(in)) & MASK(p.chan[i].prec[0]);
            R_1(out) = issigned ? SIGN_EXTEND(t,p.chan[i].prec[0]) : t;
            t = SIGN_EXTEND(R_2(in), p.chan[i].prec[2]);
            t = (t + R_0(in)) & MASK(p.chan[i].prec[0]);
            R_2(out) = issigned ? SIGN_EXTEND(t,p.chan[i].prec[0]) : t;
            t = SIGN_EXTEND(R_3(in), p.chan[i].prec[3]);
            t = (t + R_0(in)) & MASK(p.chan[i].prec[0]);
            R_3(out) = issigned ? SIGN_EXTEND(t,p.chan[i].prec[0]) : t;
        }
    }
    else
    {
        for (int i=0; i<NCHANNELS; ++i)
        {
            R_0(out) = issigned ? SIGN_EXTEND(R_0(in),p.chan[i].prec[0]) : R_0(in);
            R_1(out) = issigned ? SIGN_EXTEND(R_1(in),p.chan[i].prec[1]) : R_1(in);
            R_2(out) = issigned ? SIGN_EXTEND(R_2(in),p.chan[i].prec[2]) : R_2(in);
            R_3(out) = issigned ? SIGN_EXTEND(R_3(in),p.chan[i].prec[3]) : R_3(in);
        }
    }
}

static void quantize_endpts(const FltEndpts endpts[NREGIONS_TWO], int prec, IntEndpts q_endpts[NREGIONS_TWO])
{
    for (int region = 0; region < NREGIONS_TWO; ++region)
    {
        q_endpts[region].A[0] = Utils::quantize(endpts[region].A.x, prec);
        q_endpts[region].A[1] = Utils::quantize(endpts[region].A.y, prec);
        q_endpts[region].A[2] = Utils::quantize(endpts[region].A.z, prec);
        q_endpts[region].B[0] = Utils::quantize(endpts[region].B.x, prec);
        q_endpts[region].B[1] = Utils::quantize(endpts[region].B.y, prec);
        q_endpts[region].B[2] = Utils::quantize(endpts[region].B.z, prec);
    }
}

// swap endpoints as needed to ensure that the indices at index_positions have a 0 high-order bit
static void swap_indices(IntEndpts endpts[NREGIONS_TWO], int indices[Tile::TILE_H][Tile::TILE_W], int shapeindex)
{
    for (int region = 0; region < NREGIONS_TWO; ++region)
    {
        int position = SHAPEINDEX_TO_COMPRESSED_INDICES(shapeindex,region);

        int x = POS_TO_X(position);
        int y = POS_TO_Y(position);
        nvDebugCheck(REGION(x,y,shapeindex) == region);		// double check the table
        if (indices[y][x] & HIGH_INDEXBIT)
        {
            // high bit is set, swap the endpts and indices for this region
            int t;
            for (int i=0; i<NCHANNELS; ++i)
            {
                t = endpts[region].A[i]; endpts[region].A[i] = endpts[region].B[i]; endpts[region].B[i] = t;
            }

            for (int y = 0; y < Tile::TILE_H; y++)
                for (int x = 0; x < Tile::TILE_W; x++)
                    if (REGION(x,y,shapeindex) == region)
                        indices[y][x] = NINDICES - 1 - indices[y][x];
        }
    }
}

// endpoints fit only if the compression was lossless
static bool endpts_fit(const IntEndpts orig[NREGIONS_TWO], const ComprEndpts compressed[NREGIONS_TWO], const Pattern &p)
{
    IntEndpts uncompressed[NREGIONS_TWO];

    decompress_endpts(compressed, uncompressed, p);

    for (int j=0; j<NREGIONS_TWO; ++j)
    {
	for (int i=0; i<NCHANNELS; ++i)
	{
            if (orig[j].A[i] != uncompressed[j].A[i]) return false;
            if (orig[j].B[i] != uncompressed[j].B[i]) return false;
        }
    }
    return true;
}

static void write_header(const ComprEndpts endpts[NREGIONS_TWO], int shapeindex, const Pattern &p, Bits &out)
{
    // interpret the verilog backwards and process it
    int m = p.mode;
    int d = shapeindex;
    int rw = endpts[0].A[0], rx = endpts[0].B[0], ry = endpts[1].A[0], rz = endpts[1].B[0];
    int gw = endpts[0].A[1], gx = endpts[0].B[1], gy = endpts[1].A[1], gz = endpts[1].B[1];
    int bw = endpts[0].A[2], bx = endpts[0].B[2], by = endpts[1].A[2], bz = endpts[1].B[2];
    int ptr = int(strlen(p.encoding));
    while (ptr)
    {
        Field field;
        int endbit, len;

		// !!!UNDONE: get rid of string parsing!!!
        Utils::parse(p.encoding, ptr, field, endbit, len);
        switch(field)
        {
        case FIELD_M:	out.write( m >> endbit, len); break;
        case FIELD_D:	out.write( d >> endbit, len); break;
        case FIELD_RW:	out.write(rw >> endbit, len); break;
        case FIELD_RX:	out.write(rx >> endbit, len); break;
        case FIELD_RY:	out.write(ry >> endbit, len); break;
        case FIELD_RZ:	out.write(rz >> endbit, len); break;
        case FIELD_GW:	out.write(gw >> endbit, len); break;
        case FIELD_GX:	out.write(gx >> endbit, len); break;
        case FIELD_GY:	out.write(gy >> endbit, len); break;
        case FIELD_GZ:	out.write(gz >> endbit, len); break;
        case FIELD_BW:	out.write(bw >> endbit, len); break;
        case FIELD_BX:	out.write(bx >> endbit, len); break;
        case FIELD_BY:	out.write(by >> endbit, len); break;
        case FIELD_BZ:	out.write(bz >> endbit, len); break;
        default: nvUnreachable();
        }
    }
}

static bool read_header(Bits &in, ComprEndpts endpts[NREGIONS_TWO], int &shapeindex, Pattern &p)
{
    // reading isn't quite symmetric with writing -- we don't know the encoding until we decode the mode
    int mode = in.read(2);
    if (mode != 0x00 && mode != 0x01)
        mode = (in.read(3) << 2) | mode;

    int pat_index = mode_to_pat[mode];

    if (pat_index == -2)
        return false;		// reserved mode found

    nvDebugCheck (pat_index >= 0 && pat_index < NPATTERNS);
    nvDebugCheck (in.getptr() == patterns[pat_index].modebits);

    p = patterns[pat_index];

    int d;
    int rw, rx, ry, rz;
    int gw, gx, gy, gz;
    int bw, bx, by, bz;

    d = 0;
    rw = rx = ry = rz = 0;
    gw = gx = gy = gz = 0;
    bw = bx = by = bz = 0;

    int ptr = int(strlen(p.encoding));

    while (ptr)
    {
        Field field;
        int endbit, len;

		// !!!UNDONE: get rid of string parsing!!!
        Utils::parse(p.encoding, ptr, field, endbit, len);

        switch(field)
        {
        case FIELD_M:	break;	// already processed so ignore
        case FIELD_D:	 d |= in.read(len) << endbit; break;
        case FIELD_RW:	rw |= in.read(len) << endbit; break;
        case FIELD_RX:	rx |= in.read(len) << endbit; break;
        case FIELD_RY:	ry |= in.read(len) << endbit; break;
        case FIELD_RZ:	rz |= in.read(len) << endbit; break;
        case FIELD_GW:	gw |= in.read(len) << endbit; break;
        case FIELD_GX:	gx |= in.read(len) << endbit; break;
        case FIELD_GY:	gy |= in.read(len) << endbit; break;
        case FIELD_GZ:	gz |= in.read(len) << endbit; break;
        case FIELD_BW:	bw |= in.read(len) << endbit; break;
        case FIELD_BX:	bx |= in.read(len) << endbit; break;
        case FIELD_BY:	by |= in.read(len) << endbit; break;
        case FIELD_BZ:	bz |= in.read(len) << endbit; break;
        default: nvUnreachable();
        }
    }

    nvDebugCheck (in.getptr() == 128 - 46);

    shapeindex = d;
    endpts[0].A[0] = rw; endpts[0].B[0] = rx; endpts[1].A[0] = ry; endpts[1].B[0] = rz;
    endpts[0].A[1] = gw; endpts[0].B[1] = gx; endpts[1].A[1] = gy; endpts[1].B[1] = gz;
    endpts[0].A[2] = bw; endpts[0].B[2] = bx; endpts[1].A[2] = by; endpts[1].B[2] = bz;

    return true;
}

static void write_indices(const int indices[Tile::TILE_H][Tile::TILE_W], int shapeindex, Bits &out)
{
    int positions[NREGIONS_TWO];

    for (int r = 0; r < NREGIONS_TWO; ++r)
        positions[r] = SHAPEINDEX_TO_COMPRESSED_INDICES(shapeindex,r);

    for (int pos = 0; pos < Tile::TILE_TOTAL; ++pos)
    {
        int x = POS_TO_X(pos);
        int y = POS_TO_Y(pos);

        bool match = false;

        for (int r = 0; r < NREGIONS_TWO; ++r)
            if (positions[r] == pos) { match = true; break; }

        out.write(indices[y][x], INDEXBITS - (match ? 1 : 0));
    }
}

static void emit_block(const ComprEndpts compr_endpts[NREGIONS_TWO], int shapeindex, const Pattern &p, const int indices[Tile::TILE_H][Tile::TILE_W], char *block)
{
    Bits out(block, ZOH::BITSIZE);

    write_header(compr_endpts, shapeindex, p, out);

    write_indices(indices, shapeindex, out);

    nvDebugCheck(out.getptr() == ZOH::BITSIZE);
}

static void generate_palette_quantized(const IntEndpts &endpts, int prec, Vector3 palette[NINDICES])
{
    // scale endpoints
    int a, b;			// really need a IntVector3...

    a = Utils::unquantize(endpts.A[0], prec);
    b = Utils::unquantize(endpts.B[0], prec);

    // interpolate
    for (int i = 0; i < NINDICES; ++i)
        palette[i].x = float(Utils::finish_unquantize(Utils::lerp(a, b, i, DENOM), prec));

    a = Utils::unquantize(endpts.A[1], prec);
    b = Utils::unquantize(endpts.B[1], prec);

    // interpolate
    for (int i = 0; i < NINDICES; ++i)
        palette[i].y = float(Utils::finish_unquantize(Utils::lerp(a, b, i, DENOM), prec));

    a = Utils::unquantize(endpts.A[2], prec);
    b = Utils::unquantize(endpts.B[2], prec);

    // interpolate
    for (int i = 0; i < NINDICES; ++i)
        palette[i].z = float(Utils::finish_unquantize(Utils::lerp(a, b, i, DENOM), prec));
}

static void read_indices(Bits &in, int shapeindex, int indices[Tile::TILE_H][Tile::TILE_W])
{
    int positions[NREGIONS_TWO];

    for (int r = 0; r < NREGIONS_TWO; ++r)
        positions[r] = SHAPEINDEX_TO_COMPRESSED_INDICES(shapeindex,r);

    for (int pos = 0; pos < Tile::TILE_TOTAL; ++pos)
    {
        int x = POS_TO_X(pos);
        int y = POS_TO_Y(pos);

        bool match = false;

        for (int r = 0; r < NREGIONS_TWO; ++r)
            if (positions[r] == pos) { match = true; break; }

        indices[y][x]= in.read(INDEXBITS - (match ? 1 : 0));
    }
}

void ZOH::decompresstwo(const char *block, Tile &t)
{
    Bits in(block, ZOH::BITSIZE);

    Pattern p;
    IntEndpts endpts[NREGIONS_TWO];
    ComprEndpts compr_endpts[NREGIONS_TWO];
    int shapeindex;

    if (!read_header(in, compr_endpts, shapeindex, p))
    {
        // reserved mode, return all zeroes
        for (int y = 0; y < Tile::TILE_H; y++)
            for (int x = 0; x < Tile::TILE_W; x++)
                t.data[y][x] = Vector3(0.0f);

        return;
    }

    decompress_endpts(compr_endpts, endpts, p);

    Vector3 palette[NREGIONS_TWO][NINDICES];
    for (int r = 0; r < NREGIONS_TWO; ++r)
        generate_palette_quantized(endpts[r], p.chan[0].prec[0], &palette[r][0]);

    int indices[Tile::TILE_H][Tile::TILE_W];

    read_indices(in, shapeindex, indices);

    nvDebugCheck(in.getptr() == ZOH::BITSIZE);

    // lookup
    for (int y = 0; y < Tile::TILE_H; y++)
	for (int x = 0; x < Tile::TILE_W; x++)
        t.data[y][x] = palette[REGION(x,y,shapeindex)][indices[y][x]];
}

// given a collection of colors and quantized endpoints, generate a palette, choose best entries, and return a single toterr
static float map_colors(const Vector3 colors[], const float importance[], int np, const IntEndpts &endpts, int prec)
{
    Vector3 palette[NINDICES];
    float toterr = 0;
    Vector3 err;

    generate_palette_quantized(endpts, prec, palette);

    for (int i = 0; i < np; ++i)
    {
        float err, besterr;

        besterr = Utils::norm(colors[i], palette[0]) * importance[i];

        for (int j = 1; j < NINDICES && besterr > 0; ++j)
        {
            err = Utils::norm(colors[i], palette[j]) * importance[i];

            if (err > besterr)	// error increased, so we're done searching
                break;
            if (err < besterr)
                besterr = err;
        }
        toterr += besterr;
    }
    return toterr;
}

// assign indices given a tile, shape, and quantized endpoints, return toterr for each region
static void assign_indices(const Tile &tile, int shapeindex, IntEndpts endpts[NREGIONS_TWO], int prec, 
                           int indices[Tile::TILE_H][Tile::TILE_W], float toterr[NREGIONS_TWO])
{
    // build list of possibles
    Vector3 palette[NREGIONS_TWO][NINDICES];

    for (int region = 0; region < NREGIONS_TWO; ++region)
    {
        generate_palette_quantized(endpts[region], prec, &palette[region][0]);
        toterr[region] = 0;
    }

    Vector3 err;

    for (int y = 0; y < tile.size_y; y++)
	for (int x = 0; x < tile.size_x; x++)
	{
        int region = REGION(x,y,shapeindex);
        float err, besterr;

        besterr = Utils::norm(tile.data[y][x], palette[region][0]);
        indices[y][x] = 0;

        for (int i = 1; i < NINDICES && besterr > 0; ++i)
        {
            err = Utils::norm(tile.data[y][x], palette[region][i]);

            if (err > besterr)	// error increased, so we're done searching
                break;
            if (err < besterr)
            {
                besterr = err;
                indices[y][x] = i;
            }
        }
        toterr[region] += besterr;
    }
}

static float perturb_one(const Vector3 colors[], const float importance[], int np, int ch, int prec, const IntEndpts &old_endpts, IntEndpts &new_endpts,
                          float old_err, int do_b)
{
    // we have the old endpoints: old_endpts
    // we have the perturbed endpoints: new_endpts
    // we have the temporary endpoints: temp_endpts

    IntEndpts temp_endpts;
    float min_err = old_err;		// start with the best current error
    int beststep;

    // copy real endpoints so we can perturb them
    for (int i=0; i<NCHANNELS; ++i) { temp_endpts.A[i] = new_endpts.A[i] = old_endpts.A[i]; temp_endpts.B[i] = new_endpts.B[i] = old_endpts.B[i]; }

    // do a logarithmic search for the best error for this endpoint (which)
    for (int step = 1 << (prec-1); step; step >>= 1)
    {
        bool improved = false;
        for (int sign = -1; sign <= 1; sign += 2)
        {
            if (do_b == 0)
            {
                temp_endpts.A[ch] = new_endpts.A[ch] + sign * step;
                if (temp_endpts.A[ch] < 0 || temp_endpts.A[ch] >= (1 << prec))
                    continue;
            }
            else
            {
                temp_endpts.B[ch] = new_endpts.B[ch] + sign * step;
                if (temp_endpts.B[ch] < 0 || temp_endpts.B[ch] >= (1 << prec))
                    continue;
            }

            float err = map_colors(colors, importance, np, temp_endpts, prec);

            if (err < min_err)
            {
                improved = true;
                min_err = err;
                beststep = sign * step;
            }
        }
        // if this was an improvement, move the endpoint and continue search from there
        if (improved)
        {
            if (do_b == 0)
                new_endpts.A[ch] += beststep;
            else
                new_endpts.B[ch] += beststep;
        }
    }
    return min_err;
}

static void optimize_one(const Vector3 colors[], const float importance[], int np, float orig_err, const IntEndpts &orig_endpts, int prec, IntEndpts &opt_endpts)
{
    float opt_err = orig_err;
    for (int ch = 0; ch < NCHANNELS; ++ch)
    {
        opt_endpts.A[ch] = orig_endpts.A[ch];
        opt_endpts.B[ch] = orig_endpts.B[ch];
    }
    /*
        err0 = perturb(rgb0, delta0)
        err1 = perturb(rgb1, delta1)
        if (err0 < err1)
            if (err0 >= initial_error) break
            rgb0 += delta0
            next = 1
        else
            if (err1 >= initial_error) break
            rgb1 += delta1
            next = 0
        initial_err = map()
        for (;;)
            err = perturb(next ? rgb1:rgb0, delta)
            if (err >= initial_err) break
            next? rgb1 : rgb0 += delta
            initial_err = err
    */
    IntEndpts new_a, new_b;
    IntEndpts new_endpt;
    int do_b;

    // now optimize each channel separately
    for (int ch = 0; ch < NCHANNELS; ++ch)
    {
        // figure out which endpoint when perturbed gives the most improvement and start there
        // if we just alternate, we can easily end up in a local minima
        float err0 = perturb_one(colors, importance, np, ch, prec, opt_endpts, new_a, opt_err, 0);	// perturb endpt A
        float err1 = perturb_one(colors, importance, np, ch, prec, opt_endpts, new_b, opt_err, 1);	// perturb endpt B

        if (err0 < err1)
        {
            if (err0 >= opt_err)
                continue;

            opt_endpts.A[ch] = new_a.A[ch];
            opt_err = err0;
            do_b = 1;		// do B next
        }
        else
        {
            if (err1 >= opt_err)
                continue;
            opt_endpts.B[ch] = new_b.B[ch];
            opt_err = err1;
            do_b = 0;		// do A next
        }

        // now alternate endpoints and keep trying until there is no improvement
        for (;;)
        {
            float err = perturb_one(colors, importance, np, ch, prec, opt_endpts, new_endpt, opt_err, do_b);
            if (err >= opt_err)
                break;
            if (do_b == 0)
                opt_endpts.A[ch] = new_endpt.A[ch];
            else
                opt_endpts.B[ch] = new_endpt.B[ch];
            opt_err = err;
            do_b = 1 - do_b;	// now move the other endpoint
        }
    }
}

static void optimize_endpts(const Tile &tile, int shapeindex, const float orig_err[NREGIONS_TWO], 
                            const IntEndpts orig_endpts[NREGIONS_TWO], int prec, IntEndpts opt_endpts[NREGIONS_TWO])
{
    Vector3 pixels[Tile::TILE_TOTAL];
    float importance[Tile::TILE_TOTAL];
    //float err = 0;

    for (int region=0; region<NREGIONS_TWO; ++region)
    {
        // collect the pixels in the region
        int np = 0;

        for (int y = 0; y < tile.size_y; y++)
            for (int x = 0; x < tile.size_x; x++)
                if (REGION(x,y,shapeindex) == region)
                {
            pixels[np] = tile.data[y][x];
            importance[np] = tile.importance_map[y][x];
            ++np;
        }

        optimize_one(pixels, importance, np, orig_err[region], orig_endpts[region], prec, opt_endpts[region]);
    }
}

/* optimization algorithm
    for each pattern
        convert endpoints using pattern precision
        assign indices and get initial error
        compress indices (and possibly reorder endpoints)
        transform endpoints
        if transformed endpoints fit pattern
            get original endpoints back
            optimize endpoints, get new endpoints, new indices, and new error // new error will almost always be better
            compress new indices
            transform new endpoints
            if new endpoints fit pattern AND if error is improved
                emit compressed block with new data
            else
                emit compressed block with original data // to try to preserve maximum endpoint precision
*/

float ZOH::refinetwo(const Tile &tile, int shapeindex_best, const FltEndpts endpts[NREGIONS_TWO], char *block)
{
    float orig_err[NREGIONS_TWO], opt_err[NREGIONS_TWO], orig_toterr, opt_toterr;
    IntEndpts orig_endpts[NREGIONS_TWO], opt_endpts[NREGIONS_TWO];
    ComprEndpts compr_orig[NREGIONS_TWO], compr_opt[NREGIONS_TWO];
    int orig_indices[Tile::TILE_H][Tile::TILE_W], opt_indices[Tile::TILE_H][Tile::TILE_W];

    for (int sp = 0; sp < NPATTERNS; ++sp)
    {
        // precisions for all channels need to be the same
        for (int i=1; i<NCHANNELS; ++i) nvDebugCheck (patterns[sp].chan[0].prec[0] == patterns[sp].chan[i].prec[0]);

        quantize_endpts(endpts, patterns[sp].chan[0].prec[0], orig_endpts);
        assign_indices(tile, shapeindex_best, orig_endpts, patterns[sp].chan[0].prec[0], orig_indices, orig_err);
        swap_indices(orig_endpts, orig_indices, shapeindex_best);
        compress_endpts(orig_endpts, compr_orig, patterns[sp]);
        if (endpts_fit(orig_endpts, compr_orig, patterns[sp]))
        {
            optimize_endpts(tile, shapeindex_best, orig_err, orig_endpts, patterns[sp].chan[0].prec[0], opt_endpts);
            assign_indices(tile, shapeindex_best, opt_endpts, patterns[sp].chan[0].prec[0], opt_indices, opt_err);
            swap_indices(opt_endpts, opt_indices, shapeindex_best);
            compress_endpts(opt_endpts, compr_opt, patterns[sp]);
            orig_toterr = opt_toterr = 0;
            for (int i=0; i < NREGIONS_TWO; ++i) { orig_toterr += orig_err[i]; opt_toterr += opt_err[i]; }
            if (endpts_fit(opt_endpts, compr_opt, patterns[sp]) && opt_toterr < orig_toterr)
            {
                emit_block(compr_opt, shapeindex_best, patterns[sp], opt_indices, block);
                return opt_toterr;
            }
            else
            {
                // either it stopped fitting when we optimized it, or there was no improvement
                // so go back to the unoptimized endpoints which we know will fit
                emit_block(compr_orig, shapeindex_best, patterns[sp], orig_indices, block);
                return orig_toterr;
            }
        }
    }
    nvAssert(false); //throw "No candidate found, should never happen (refinetwo.)";
	return FLT_MAX;
}

static void generate_palette_unquantized(const FltEndpts endpts[NREGIONS_TWO], Vector3 palette[NREGIONS_TWO][NINDICES])
{
    for (int region = 0; region < NREGIONS_TWO; ++region)
	for (int i = 0; i < NINDICES; ++i)
            palette[region][i] = Utils::lerp(endpts[region].A, endpts[region].B, i, DENOM);
}

// generate a palette from unquantized endpoints, then pick best palette color for all pixels in each region, return toterr for all regions combined
static float map_colors(const Tile &tile, int shapeindex, const FltEndpts endpts[NREGIONS_TWO])
{
    // build list of possibles
    Vector3 palette[NREGIONS_TWO][NINDICES];

    generate_palette_unquantized(endpts, palette);

    float toterr = 0;
    Vector3 err;

    for (int y = 0; y < tile.size_y; y++)
	for (int x = 0; x < tile.size_x; x++)
	{
        int region = REGION(x,y,shapeindex);
        float err, besterr;

        besterr = Utils::norm(tile.data[y][x], palette[region][0]) * tile.importance_map[y][x];

        for (int i = 1; i < NINDICES && besterr > 0; ++i)
        {
            err = Utils::norm(tile.data[y][x], palette[region][i]) * tile.importance_map[y][x];

            if (err > besterr)	// error increased, so we're done searching
                break;
            if (err < besterr)
                besterr = err;
        }
        toterr += besterr;
    }
    return toterr;
}

float ZOH::roughtwo(const Tile &tile, int shapeindex, FltEndpts endpts[NREGIONS_TWO])
{
    for (int region=0; region<NREGIONS_TWO; ++region)
    {
        int np = 0;
        Vector3 colors[Tile::TILE_TOTAL];
        Vector3 mean(0,0,0);

        for (int y = 0; y < tile.size_y; y++)
            for (int x = 0; x < tile.size_x; x++)
                if (REGION(x,y,shapeindex) == region)
                {
            colors[np] = tile.data[y][x];
            mean += tile.data[y][x];
            ++np;
        }

        // handle simple cases
        if (np == 0)
        {
            Vector3 zero(0,0,0);
            endpts[region].A = zero;
            endpts[region].B = zero;
            continue;
        }
        else if (np == 1)
        {
            endpts[region].A = colors[0];
            endpts[region].B = colors[0];
            continue;
        }
        else if (np == 2)
        {
            endpts[region].A = colors[0];
            endpts[region].B = colors[1];
            continue;
        }

        mean /= float(np);

        Vector3 direction = Fit::computePrincipalComponent_EigenSolver(np, colors);

        // project each pixel value along the principal direction
        float minp = FLT_MAX, maxp = -FLT_MAX;
        for (int i = 0; i < np; i++)
        {
            float dp = dot(colors[i]-mean, direction);
            if (dp < minp) minp = dp;
            if (dp > maxp) maxp = dp;
        }

        // choose as endpoints 2 points along the principal direction that span the projections of all of the pixel values
        endpts[region].A = mean + minp*direction;
        endpts[region].B = mean + maxp*direction;

        // clamp endpoints
        // the argument for clamping is that the actual endpoints need to be clamped and thus we need to choose the best
        // shape based on endpoints being clamped
        Utils::clamp(endpts[region].A);
        Utils::clamp(endpts[region].B);
    }

    return map_colors(tile, shapeindex, endpts);
}

float ZOH::compresstwo(const Tile &t, char *block)
{
    int shapeindex_best = 0;
    FltEndpts endptsbest[NREGIONS_TWO], tempendpts[NREGIONS_TWO];
    float msebest = FLT_MAX;

    /*
    collect the mse values that are within 5% of the best values
    optimize each one and choose the best
    */
    // hack for now -- just use the best value WORK
    for (int i=0; i<NSHAPES && msebest>0.0; ++i)
    {
        float mse = roughtwo(t, i, tempendpts);
        if (mse < msebest)
        {
            msebest = mse;
            shapeindex_best = i;
            memcpy(endptsbest, tempendpts, sizeof(endptsbest));
        }

    }
    return refinetwo(t, shapeindex_best, endptsbest, block);
}



<|start_filename|>src/nvtt/CompressorDX9.cpp<|end_filename|>
// Copyright (c) 2009-2011 <NAME> <<EMAIL>>
// Copyright (c) 2007-2009 NVIDIA Corporation -- <NAME> <<EMAIL>>
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include "CompressorDX9.h"
#include "QuickCompressDXT.h"
#include "OptimalCompressDXT.h"
#include "CompressionOptions.h"
#include "OutputOptions.h"
#include "CompressorDXT5_RGBM.h"

// squish
#include "squish/colourset.h"
#include "squish/weightedclusterfit.h"

#include "nvtt.h"

#include "nvimage/Image.h"
#include "nvimage/ColorBlock.h"
#include "nvimage/BlockDXT.h"

#include "nvmath/Vector.inl"
#include "nvmath/Color.inl"

#include "nvcore/Memory.h"

#include <new> // placement new


using namespace nv;
using namespace nvtt;



void FastCompressorDXT1a::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
    BlockDXT1 * block = new(output) BlockDXT1;
    QuickCompress::compressDXT1a(rgba, block);
}

void FastCompressorDXT3::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
    BlockDXT3 * block = new(output) BlockDXT3;
    QuickCompress::compressDXT3(rgba, block);
}

void FastCompressorDXT5::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
    BlockDXT5 * block = new(output) BlockDXT5;
    QuickCompress::compressDXT5(rgba, block);
}

void FastCompressorDXT5n::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
    rgba.swizzle(4, 1, 5, 0); // 0xFF, G, 0, R

    BlockDXT5 * block = new(output) BlockDXT5;
    QuickCompress::compressDXT5(rgba, block);
}



void CompressorDXT1a::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
    uint alphaMask = 0;
    for (uint i = 0; i < 16; i++)
    {
        if (rgba.color(i).a == 0) alphaMask |= (3U << (i * 2U)); // Set two bits for each color.
    }

    const bool isSingleColor = rgba.isSingleColor();

    if (isSingleColor)
    {
        BlockDXT1 * block = new(output) BlockDXT1;
        OptimalCompress::compressDXT1a(rgba.color(0), alphaMask, block);
    }
    else
    {
        nvsquish::WeightedClusterFit fit;
        fit.SetMetric(compressionOptions.colorWeight.x, compressionOptions.colorWeight.y, compressionOptions.colorWeight.z);

        int flags = nvsquish::kDxt1;
        if (alphaMode == nvtt::AlphaMode_Transparency) flags |= nvsquish::kWeightColourByAlpha;

        nvsquish::ColourSet colours((uint8 *)rgba.colors(), flags);
        fit.SetColourSet(&colours, nvsquish::kDxt1);

        fit.Compress(output);
    }
}

void CompressorDXT1_Luma::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
    BlockDXT1 * block = new(output) BlockDXT1;
    OptimalCompress::compressDXT1_Luma(rgba, block);
}

void CompressorDXT3::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
    BlockDXT3 * block = new(output) BlockDXT3;

    // Compress explicit alpha.
    OptimalCompress::compressDXT3A(rgba, &block->alpha);

    // Compress color.
    if (rgba.isSingleColor())
    {
        OptimalCompress::compressDXT1(rgba.color(0), &block->color);
    }
    else
    {
        nvsquish::WeightedClusterFit fit;
        fit.SetMetric(compressionOptions.colorWeight.x, compressionOptions.colorWeight.y, compressionOptions.colorWeight.z);

        int flags = 0;
        if (alphaMode == nvtt::AlphaMode_Transparency) flags |= nvsquish::kWeightColourByAlpha;

        nvsquish::ColourSet colours((uint8 *)rgba.colors(), flags);
        fit.SetColourSet(&colours, 0);
        fit.Compress(&block->color);
    }
}

void CompressorDXT5::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
    BlockDXT5 * block = new(output) BlockDXT5;

    // Compress alpha.
    if (compressionOptions.quality == Quality_Highest)
    {
        OptimalCompress::compressDXT5A(rgba, &block->alpha);
    }
    else
    {
        QuickCompress::compressDXT5A(rgba, &block->alpha);
    }

    // Compress color.
    if (rgba.isSingleColor())
    {
        OptimalCompress::compressDXT1(rgba.color(0), &block->color);
    }
    else
    {
        nvsquish::WeightedClusterFit fit;
        fit.SetMetric(compressionOptions.colorWeight.x, compressionOptions.colorWeight.y, compressionOptions.colorWeight.z);

        int flags = 0;
        if (alphaMode == nvtt::AlphaMode_Transparency) flags |= nvsquish::kWeightColourByAlpha;

        nvsquish::ColourSet colours((uint8 *)rgba.colors(), flags);
        fit.SetColourSet(&colours, 0);
        fit.Compress(&block->color);
    }
}


void CompressorDXT5n::compressBlock(ColorBlock & rgba, nvtt::AlphaMode alphaMode, const nvtt::CompressionOptions::Private & compressionOptions, void * output)
{
    BlockDXT5 * block = new(output) BlockDXT5;

    // Compress Y.
    if (compressionOptions.quality == Quality_Highest)
    {
        OptimalCompress::compressDXT1G(rgba, &block->color);
    }
    else
    {
        if (rgba.isSingleColor(Color32(0, 0xFF, 0, 0))) // Mask all but green channel.
        {
                OptimalCompress::compressDXT1G(rgba.color(0).g, &block->color);
        }
        else
        {
            ColorBlock tile = rgba;
            tile.swizzle(4, 1, 5, 3); // leave alpha in alpha channel.

            nvsquish::WeightedClusterFit fit;
            fit.SetMetric(0, 1, 0);

            int flags = 0;
            if (alphaMode == nvtt::AlphaMode_Transparency) flags |= nvsquish::kWeightColourByAlpha;

            nvsquish::ColourSet colours((uint8 *)tile.colors(), flags);
            fit.SetColourSet(&colours, 0);
            fit.Compress(&block->color);
        }
    }

    rgba.swizzle(4, 1, 5, 0); // 1, G, 0, R

    // Compress X.
    if (compressionOptions.quality == Quality_Highest)
    {
        OptimalCompress::compressDXT5A(rgba, &block->alpha);
    }
    else
    {
        QuickCompress::compressDXT5A(rgba, &block->alpha);
    }
}







<|start_filename|>extern/pvrtextool/Include/PVRTextureVersion.h<|end_filename|>
/******************************************************************************

 @File         PVRTextureVersion.h

 @Title        

 @Version      

 @Copyright    Copyright (c) Imagination Technologies Limited. All Rights Reserved. Strictly Confidential.

 @Platform     ANSI

 @Description  Texture processing routines.

******************************************************************************/
#ifndef PVRTEXLIBVERSION_H
#define PVRTEXLIBVERSION_H
#define PVRTLMAJORVERSION 4
#define PVRTLMINORVERSION 2
#define PVRTLSTRINGVERSION "4.2"
#define PVRTLVERSIONDESCRIPTOR "" //"BETA" //"ALPHA" //"ENGINEERING DROP"
#endif



<|start_filename|>extern/pvrtextool/Include/PVRTTypes.h<|end_filename|>
/******************************************************************************

 @File         PVRTTypes.h

 @Title        PVRTTypes

 @Version      

 @Copyright    Copyright (c) Imagination Technologies Limited. All Rights Reserved. Strictly Confidential.

 @Platform     ANSI compatible

 @Description  Global enums and typedefs for PVRTools

******************************************************************************/

//ACS: I split this out of PVRTGlobal.h

#ifndef _PVRTTYPES_H_
#define _PVRTTYPES_H_

/*!***************************************************************************
 Macros
*****************************************************************************/
//#include <stdio.h>

// This macro is used to check at compile time that types are of a certain size
// If the size does not equal the expected size, this typedefs an array of size 0
// which causes a compile error
#define PVRTSIZEASSERT(T, size) typedef int (sizeof_##T)[sizeof(T) == (size)]
#define PVRTCOMPILEASSERT(T, expr)	typedef int (assert_##T)[expr]


/****************************************************************************
** Integer types
****************************************************************************/

typedef char				PVRTchar8;
typedef signed char			PVRTint8;
typedef signed short		PVRTint16;
typedef signed int			PVRTint32;
typedef unsigned char		PVRTuint8;
typedef unsigned short		PVRTuint16;
typedef unsigned int		PVRTuint32;

typedef float				PVRTfloat32;

#if (defined(__int64) || defined(_WIN32))
typedef signed __int64     PVRTint64;
typedef unsigned __int64   PVRTuint64;
#elif defined(TInt64)
typedef TInt64             PVRTint64;
typedef TUInt64            PVRTuint64;
#else
typedef signed long long   PVRTint64;
typedef unsigned long long PVRTuint64;
#endif

#if __SIZEOF_WCHAR_T__  == 4 || __WCHAR_MAX__ > 0x10000
	#define PVRTSIZEOFWCHAR 4
#else
	#define PVRTSIZEOFWCHAR 2
#endif

PVRTSIZEASSERT(PVRTchar8,   1);
PVRTSIZEASSERT(PVRTint8,   1);
PVRTSIZEASSERT(PVRTuint8,  1);
PVRTSIZEASSERT(PVRTint16,  2);
PVRTSIZEASSERT(PVRTuint16, 2);
PVRTSIZEASSERT(PVRTint32,  4);
PVRTSIZEASSERT(PVRTuint32, 4);
PVRTSIZEASSERT(PVRTint64,  8);
PVRTSIZEASSERT(PVRTuint64, 8);
PVRTSIZEASSERT(PVRTfloat32, 4);

/*!**************************************************************************
@Enum   ETextureFilter
@Brief  Enum values for defining texture filtering
****************************************************************************/
enum ETextureFilter
{
	eFilter_Nearest,
	eFilter_Linear,
	eFilter_None,

	eFilter_Size,
	eFilter_Default		= eFilter_Nearest,
	eFilter_MipDefault	= eFilter_None
};

/*!**************************************************************************
@Enum   ETextureWrap
@Brief  Enum values for defining texture wrapping
****************************************************************************/
enum ETextureWrap
{
	eWrap_Clamp,
	eWrap_Repeat,

	eWrap_Size,
	eWrap_Default = eWrap_Repeat
};

/*****************************************************************************
 ACS: Handle missing assert macros.
      Maybe you needed to include PVRTGlobal.h after all?
*****************************************************************************/
#ifndef _ASSERT
# define _ASSERT(X)
#endif
#ifndef _ASSERTE
# define _ASSERTE(X)
#endif

#endif // _PVRTTYPES_H_

/*****************************************************************************
 End of file
*****************************************************************************/



<|start_filename|>src/nvtt/OutputOptions.cpp<|end_filename|>
// Copyright (c) 2009-2011 <NAME> <<EMAIL>>
// Copyright (c) 2007-2009 NVIDIA Corporation -- <NAME> <<EMAIL>>
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

#include "OutputOptions.h"

using namespace nvtt;


OutputOptions::OutputOptions() : m(*new OutputOptions::Private())
{
    reset();
}

OutputOptions::~OutputOptions()
{
    // Cleanup output handler.
    setOutputHandler(NULL);

    delete &m;
}

/// Set default output options.
void OutputOptions::reset()
{
    m.fileName.reset();
    m.fileHandle = NULL;

    m.outputHandler = NULL;
    m.errorHandler = NULL;

    m.outputHeader = true;
    m.container = Container_DDS;
    m.version = 0;
    m.srgb = false;
    m.deleteOutputHandler = false;
}


/// Set output file name.
void OutputOptions::setFileName(const char * fileName)
{
    if (m.deleteOutputHandler)
    {
        delete m.outputHandler;
    }

    m.fileName = fileName;
    m.fileHandle = NULL;
    m.outputHandler = NULL;
    m.deleteOutputHandler = false;

    DefaultOutputHandler * oh = new DefaultOutputHandler(fileName);
    if (oh->stream.isError()) {
        delete oh;
    }
    else {
        m.deleteOutputHandler = true;
        m.outputHandler = oh;
    }
}

/// Set output file handle.
void OutputOptions::setFileHandle(void * fp)
{
    if (m.deleteOutputHandler) {
        delete m.outputHandler;
    }

    m.fileName.reset();
    m.fileHandle = (FILE *)fp;
    m.outputHandler = NULL;
    m.deleteOutputHandler = false;

    DefaultOutputHandler * oh = new DefaultOutputHandler(m.fileHandle);
    if (oh->stream.isError()) {
        delete oh;
    }
    else {
        m.deleteOutputHandler = true;
        m.outputHandler = oh;
    }
}


/// Set output handler.
void OutputOptions::setOutputHandler(OutputHandler * outputHandler)
{
    if (m.deleteOutputHandler) {
        delete m.outputHandler;
    }

    m.fileName.reset();
    m.fileHandle = NULL;
    m.outputHandler = outputHandler;
    m.deleteOutputHandler = false;
}

/// Set error handler.
void OutputOptions::setErrorHandler(ErrorHandler * errorHandler)
{
    m.errorHandler = errorHandler;
}

/// Set output header.
void OutputOptions::setOutputHeader(bool outputHeader)
{
    m.outputHeader = outputHeader;
}

/// Set container.
void OutputOptions::setContainer(Container container)
{
    m.container = container;
}

/// Set user version.
void OutputOptions::setUserVersion(int version)
{
    m.version = version;
}

/// Set SRGB flag.
void OutputOptions::setSrgbFlag(bool b)
{
    m.srgb = b;
}

bool OutputOptions::Private::hasValidOutputHandler() const
{
    if (!fileName.isNull() || fileHandle != NULL)
    {
        return outputHandler != NULL;
    }

    return true;
}

void OutputOptions::Private::beginImage(int size, int width, int height, int depth, int face, int miplevel) const
{
    if (outputHandler != NULL) outputHandler->beginImage(size, width, height, depth, face, miplevel);
}

bool OutputOptions::Private::writeData(const void * data, int size) const
{
    return outputHandler == NULL || outputHandler->writeData(data, size);
}

void OutputOptions::Private::endImage() const
{
    if (outputHandler != NULL) outputHandler->endImage();
}

void OutputOptions::Private::error(Error e) const
{
    if (errorHandler != NULL) errorHandler->error(e);
}


<|start_filename|>src/nvtt/experimental/nvtt_experimental.h<|end_filename|>

#ifndef NVTT_EXPERIMENTAL_H
#define NVTT_EXPERIMENTAL_H

#include <nvtt/nvtt.h>

typedef struct NvttTexture NvttTexture;
typedef struct NvttOutputOptions NvttOutputOptions;


// Global functions
void nvttInitialize(...);
unsigned int nvttGetVersion();
const char * nvttGetErrorString(unsigned int error);


// Texture functions
NvttTexture * nvttCreateTexture();
void nvttDestroyTexture(NvttTexture * tex);

void nvttSetTexture2D(NvttTexture * tex, NvttInputFormat format, uint w, uint h, uint idx, void * data);

void nvttResize(NvttTexture * img, uint w, uint h);
unsigned int nvttDownsample(NvttTexture * img);

void nvttOutputCompressed(NvttTexture * img, NvttOutputFormat format);
void nvttOutputPixelFormat(NvttTexture * img, NvttOutputFormat format);




// How to control the compression parameters?

// Using many arguments:
// void nvttCompressImage(img, format, quality, r, g, b, a, ...);

// Using existing compression option class:
// compressionOptions = nvttCreateCompressionOptions();
// nvttSetCompressionOptionsFormat(compressionOptions, format);
// nvttSetCompressionOptionsQuality(compressionOptions, quality);
// nvttSetCompressionOptionsQuality(compressionOptions, quality);
// nvttSetCompressionOptionsColorWeights(compressionOptions, r, g, b, a);
// ...
// nvttCompressImage(img, compressionOptions);

// Using thread local context state:
// void nvttSetCompressionFormat(format);
// void nvttSetCompressionQuality(quality);
// void nvttSetCompressionColorWeights(r, g, b, a);
// ...
// nvttCompressImage(img);

// Using thread local context state, but with GL style function arguments:
// nvttCompressorParameteri(NVTT_FORMAT, format);
// nvttCompressorParameteri(NVTT_QUALITY, quality);
// nvttCompressorParameterf(NVTT_COLOR_WEIGHT_RED, r);
// nvttCompressorParameterf(NVTT_COLOR_WEIGHT_GREEN, g);
// nvttCompressorParameterf(NVTT_COLOR_WEIGHT_BLUE, b);
// nvttCompressorParameterf(NVTT_COLOR_WEIGHT_ALPHA, a);
// or nvttCompressorParameter4f(NVTT_COLOR_WEIGHTS, r, g, b, a);
// ...
// nvttCompressImage(img);

// How do we get the compressed output?
// - Using callbacks. (via new entrypoints, or through outputOptions)
// - Return it explicitely from nvttCompressImage.
// - Store it along the image, retrieve later explicitely with 'nvttGetCompressedData(img, ...)'

/*

// Global functions
void nvttInitialize(...);
unsigned int nvttGetVersion();
const char * nvttGetErrorString(unsigned int error);

// Context object
void nvttCreateContext();
void nvttDestroyContext();

void nvttSetParameter1i(unsigned int name, int value);

void nvttSetParameter1f(unsigned int name, float value);
void nvttSetParameter2f(unsigned int name, float v0, float v1);
void nvttSetParameter3f(unsigned int name, float v0, float v1, float v2);
void nvttSetParameter4f(unsigned int name, float v0, float v1, float v2, float v3);

// Image object
NvttImage * nvttCreateImage();
void nvttDestroyImage(NvttImage * img);

void nvttSetImageData(NvttImage * image, NvttInputFormat format, unsigned int w, unsigned int h, void * data);

void nvttSetImageParameter1i(NvttImage * image, unsigned int name, int value);
void nvttSetImageParameter1f(NvttImage * image, unsigned int name, float value);

void nvttResizeImage(NvttImage * image, unsigned int w, unsigned int h);
void nvttQuantizeImage(NvttImage * image, bool dither, unsigned int rbits, unsigned int gbits, unsigned int bbits, unsigned int abits);
void nvttCompressImage(NvttImage * image, void * buffer, int size);

*/


#endif // NVTT_EXPERIMENTAL_H


<|start_filename|>extern/pvrtextool/Include/PVRTextureHeader.h<|end_filename|>
/******************************************************************************

 @File         PVRTextureHeader.h

 @Title        

 @Version      

 @Copyright    Copyright (c) Imagination Technologies Limited. All Rights Reserved. Strictly Confidential.

 @Platform     

 @Description  

******************************************************************************/
#ifndef _PVRTEXTURE_HEADER_H
#define _PVRTEXTURE_HEADER_H

#include "PVRTextureDefines.h"
#include "PVRTextureFormat.h"
#include "PVRTMap.h"
#include "PVRTString.h"

namespace pvrtexture
{
	//Wrapper class for PVRTextureHeaderV3, adds 'smart' accessor functions.
	class PVR_DLL CPVRTextureHeader
	{	
	protected:
		PVRTextureHeaderV3											m_sHeader;		//Texture header as laid out in a file.
		mutable CPVRTMap<uint32, CPVRTMap<uint32,MetaDataBlock> >	m_MetaData;		//Map of all the meta data stored for a texture.

	public:
	/*******************************************************************************
	* Construction methods for a texture header.
	*******************************************************************************/
		/*!***********************************************************************
		 @Function		CPVRTextureHeader
		 @Return		CPVRTextureHeader A new texture header.
		 @Description	Default constructor for a CPVRTextureHeader. Returns an empty header.
		*************************************************************************/
		CPVRTextureHeader();

		/*!***********************************************************************
		 @Function		CPVRTextureHeader
		 @Input			fileHeader
		 @Input			metaDataCount
		 @Input			metaData
		 @Return		CPVRTextureHeader A new texture header.
		 @Description	Creates a new texture header from a PVRTextureHeaderV3, 
						and appends Meta data if any is supplied.
		*************************************************************************/
		CPVRTextureHeader(	PVRTextureHeaderV3	fileHeader,
							uint32				metaDataCount=0,
							MetaDataBlock*		metaData=NULL);

		/*!***********************************************************************
		 @Function		CPVRTextureHeader
		 @Input			u64PixelFormat
		 @Input			u32Height
		 @Input			u32Width
		 @Input			u32Depth
		 @Input			u32NumMipMaps
		 @Input			u32NumArrayMembers
		 @Input			u32NumFaces
		 @Input			eColourSpace
		 @Input			eChannelType
		 @Input			bPreMultiplied
		 @Return		CPVRTextureHeader A new texture header.
		 @Description	Creates a new texture header based on individual header
						variables.
		*************************************************************************/
		CPVRTextureHeader(	uint64				u64PixelFormat,
							uint32				u32Height=1,
							uint32				u32Width=1,
							uint32				u32Depth=1,
							uint32				u32NumMipMaps=1,
							uint32				u32NumArrayMembers=1,
							uint32				u32NumFaces=1,
							EPVRTColourSpace	eColourSpace=ePVRTCSpacelRGB,
							EPVRTVariableType	eChannelType=ePVRTVarTypeUnsignedByteNorm,
							bool				bPreMultiplied=false);

		/*!***********************************************************************
		 @Function		operator=
		 @Input			rhs
		 @Return		CPVRTextureHeader& This header.
		 @Description	Will copy the contents and information of another header into this one.
		*************************************************************************/
		CPVRTextureHeader& operator=(const CPVRTextureHeader& rhs);
		
	/*******************************************************************************
	* Accessor Methods for a texture's properties - getters.
	*******************************************************************************/

		/*!***********************************************************************
		 @Function		getFileHeader
		 @Return		PVRTextureHeaderV3		The file header.
		 @Description	Gets the file header structure.
		*************************************************************************/
		const PVRTextureHeaderV3 getFileHeader() const;

		/*!***********************************************************************
		 @Function		getPixelType
		 @Return		PixelType		64-bit pixel type ID.
		 @Description	Gets the 64-bit pixel type ID of the texture.
		*************************************************************************/
		const PixelType getPixelType() const;

		/*!***********************************************************************
		 @Function		getBitsPerPixel
		 @Return		uint32		Number of bits per pixel
		 @Description	Gets the bits per pixel of the texture format.
		*************************************************************************/
		const uint32 getBitsPerPixel() const;

		/*!***********************************************************************
		 @Function		getColourSpace
		 @Return		EPVRTColourSpace	enum representing colour space.
		 @Description	Returns the colour space of the texture.
		*************************************************************************/
		const EPVRTColourSpace getColourSpace() const;

		/*!***********************************************************************
		 @Function		getChannelType
		 @Return		EPVRTVariableType	enum representing the type of the texture.
		 @Description	Returns the variable type that the texture's data is stored in.
		*************************************************************************/
		const EPVRTVariableType getChannelType() const;

		/*!***********************************************************************
		 @Function		getWidth
		 @Input				uiMipLevel	MIP level that user is interested in.
		 @Return		uint32		Width of the specified MIP-Map level.
		 @Description	Gets the width of the user specified MIP-Map 
						level for the texture
		*************************************************************************/
		const uint32 getWidth(uint32 uiMipLevel=PVRTEX_TOPMIPLEVEL) const;

		/*!***********************************************************************
		 @Function		getHeight
		 @Input				uiMipLevel	MIP level that user is interested in.
		 @Return		uint32		Height of the specified MIP-Map level.
		 @Description	Gets the height of the user specified MIP-Map 
						level for the texture
		*************************************************************************/
		const uint32 getHeight(uint32 uiMipLevel=PVRTEX_TOPMIPLEVEL) const;

		/*!***********************************************************************
		 @Function		getDepth
		 @Input				uiMipLevel	MIP level that user is interested in.
		 @Return		Depth of the specified MIP-Map level.
		 @Description	Gets the depth of the user specified MIP-Map 
						level for the texture
		*************************************************************************/
		const uint32 getDepth(uint32 uiMipLevel=PVRTEX_TOPMIPLEVEL) const;

		/*!***********************************************************************
		 @Function		getTextureSize
		 @Input				iMipLevel		Specifies a MIP level to check, 
										'PVRTEX_ALLMIPLEVELS' can be passed to get 
										the size of all MIP levels. 
		 @Input				bAllSurfaces	Size of all surfaces is calculated if true, 
										only a single surface if false.
		 @Input				bAllFaces		Size of all faces is calculated if true, 
										only a single face if false.
		 @Return		uint32			Size in PIXELS of the specified texture area.
		 @Description	Gets the size in PIXELS of the texture, given various input 
						parameters.	User can retrieve the total size of either all 
						surfaces or a single surface, all faces or a single face and
						all MIP-Maps or a single specified MIP level. All of these
		*************************************************************************/
		const uint32 getTextureSize(int32 iMipLevel=PVRTEX_ALLMIPLEVELS, bool bAllSurfaces = true, bool bAllFaces = true) const;

		/*!***********************************************************************
		 @Function		getDataSize
		 @Input				iMipLevel		Specifies a mip level to check, 
										'PVRTEX_ALLMIPLEVELS' can be passed to get 
										the size of all MIP levels. 
		 @Input				bAllSurfaces	Size of all surfaces is calculated if true, 
										only a single surface if false.
		 @Input				bAllFaces		Size of all faces is calculated if true, 
										only a single face if false.
		 @Return		uint32			Size in BYTES of the specified texture area.
		 @Description	Gets the size in BYTES of the texture, given various input 
						parameters.	User can retrieve the size of either all 
						surfaces or a single surface, all faces or a single face 
						and all MIP-Maps or a single specified MIP level.
		*************************************************************************/
		const uint32 getDataSize(int32 iMipLevel=PVRTEX_ALLMIPLEVELS, bool bAllSurfaces = true, bool bAllFaces = true) const;

		/*!***********************************************************************
		 @Function		getNumArrayMembers
		 @Return		uint32		Number of array members in this texture.
		 @Description	Gets the number of array members stored in this texture.
		*************************************************************************/
		const uint32 getNumArrayMembers() const;

		/*!***********************************************************************
		 @Function		getNumMIPLevels
		 @Return		uint32		Number of MIP-Map levels in this texture.
		 @Description	Gets the number of MIP-Map levels stored in this texture.
		*************************************************************************/
		const uint32 getNumMIPLevels() const;

		/*!***********************************************************************
		 @Function		getNumFaces
		 @Return		uint32		Number of faces in this texture.
		 @Description	Gets the number of faces stored in this texture.
		*************************************************************************/
		const uint32 getNumFaces() const;

		/*!***********************************************************************
		 @Function		getOrientation
		 @Input				axis			EPVRTAxis type specifying the axis to examine.
		 @Return		EPVRTOrientation	Enum orientation of the axis.
		 @Description	Gets the data orientation for this texture.
		*************************************************************************/
		const EPVRTOrientation getOrientation(EPVRTAxis axis) const;

		/*!***********************************************************************
		 @Function		isFileCompressed
		 @Return		bool	True if it is file compressed.
		 @Description	Returns whether or not the texture is compressed using
						PVRTexLib's FILE compression - this is independent of 
						any texture compression.
		*************************************************************************/
		const bool isFileCompressed() const;
				
		/*!***********************************************************************
		 @Function		isPreMultiplied
		 @Return		bool	True if texture is premultiplied.
		 @Description	Returns whether or not the texture's colour has been
						pre-multiplied by the alpha values.
		*************************************************************************/
		const bool isPreMultiplied() const;

		/*!***********************************************************************
		 @Function		getMetaDataSize
		 @Return		const uint32 Size, in bytes, of the meta data stored in the header.
		 @Description	Returns the total size of the meta data stored in the header. 
						This includes the size of all information stored in all MetaDataBlocks.
		*************************************************************************/
		const uint32 getMetaDataSize() const;

		/*!***********************************************************************
		@Function		getOGLFormat
		@Modified		internalformat
		@Modified		format
		@Modified		type
		@Description	Gets the OpenGL equivalent values of internal format, format
						and type for this texture. This will return any supported
						OpenGL texture values, it is up to the user to decide if 
						these are valid for their current platform.
		*************************************************************************/
		const void getOGLFormat(uint32& internalformat, uint32& format, uint32& type) const;

		/*!***********************************************************************
		 @Function		getOGLESFormat
		 @Modified		internalformat
		 @Modified		format
		 @Modified		type
		 @Description	Gets the OpenGLES equivalent values of internal format, 
						format and type for this texture. This will return any 
						supported OpenGLES texture values, it is up to the user 
						to decide if these are valid for their current platform.
		*************************************************************************/
		const void getOGLESFormat(uint32& internalformat, uint32& format, uint32& type) const;

		/*!***********************************************************************
		 @Function		getD3DFormat
		 @Return		const uint32 
		 @Description	Gets the D3DFormat (up to DirectX 9 and Direct 3D Mobile)
						equivalent values for this texture. This will return any 
						supported D3D texture formats, it is up to the user to
						decide if this is valid for their current platform.
		*************************************************************************/
		const uint32 getD3DFormat() const;
		
		/*!***********************************************************************
		 @Function		getDXGIFormat
		 @Return		const uint32 
		 @Description	Gets the DXGIFormat (DirectX 10 onward) equivalent values 
						for this texture. This will return any supported DX texture
						formats, it is up to the user to decide if this is valid 
						for their current platform.
		*************************************************************************/
		const uint32 getDXGIFormat() const;

	/*!***********************************************************************
	* Accessor Methods for a texture's properties - setters.
	*************************************************************************/

		/*!***********************************************************************
		 @Function		setPixelFormat
		 @Input				uPixelFormat	The format of the pixel.
		 @Description	Sets the pixel format for this texture.
		*************************************************************************/
		void setPixelFormat(PixelType uPixelFormat);

		/*!***********************************************************************
		 @Function		setColourSpace
		 @Input				eColourSpace	A colour space enum.
		 @Description	Sets the colour space for this texture. Default is lRGB.
		*************************************************************************/
		void setColourSpace(EPVRTColourSpace eColourSpace);

		/*!***********************************************************************
		 @Function		setChannelType
		 @Input				eVarType	A variable type enum.
		 @Description	Sets the variable type for the channels in this texture.
		*************************************************************************/
		void setChannelType(EPVRTVariableType eVarType);

		/*!***********************************************************************
		 @Function		setOGLFormat
		 @Input			internalformat
		 @Input			format
		 @Input			type
		 @Return		bool Whether the format is valid or not.
		 @Description	Sets the format of the texture to PVRTexLib's internal
						representation of the OGL format.
		*************************************************************************/
		bool setOGLFormat(const uint32& internalformat, const uint32& format, const uint32& type);

		/*!***********************************************************************
		 @Function		setOGLESFormat
		 @Input			internalformat
		 @Input			format
		 @Input			type
		 @Return		bool Whether the format is valid or not.
		 @Description	Sets the format of the texture to PVRTexLib's internal
						representation of the OGLES format.
		*************************************************************************/
		bool setOGLESFormat(const uint32& internalformat, const uint32& format, const uint32& type);

		/*!***********************************************************************
		 @Function		setD3DFormat
		 @Return		bool Whether the format is valid or not.
		 @Description	Sets the format of the texture to PVRTexLib's internal
						representation of the D3D format.
		*************************************************************************/
		bool setD3DFormat(const uint32& DWORD_D3D_FORMAT);
		
		/*!***********************************************************************
		 @Function		setDXGIFormat
		 @Return		bool Whether the format is valid or not.
		 @Description	Sets the format of the texture to PVRTexLib's internal
						representation of the DXGI format.
		*************************************************************************/
		bool setDXGIFormat(const uint32& DWORD_DXGI_FORMAT);

		/*!***********************************************************************
		 @Function		setWidth
		 @Input				newWidth	The new width.
		 @Description	Sets the width.
		*************************************************************************/
		void setWidth(uint32 newWidth);

		/*!***********************************************************************
		 @Function		setHeight
		 @Input				newHeight	The new height.
		 @Description	Sets the height.
		*************************************************************************/
		void setHeight(uint32 newHeight);

		/*!***********************************************************************
		 @Function		setDepth
		 @Input				newDepth	The new depth.
		 @Description	Sets the depth.
		*************************************************************************/
		void setDepth(uint32 newDepth);

		/*!***********************************************************************
		 @Function		setNumArrayMembers
		 @Input				newNumMembers	The new number of members in this array.
		 @Description	Sets the depth.
		*************************************************************************/
		void setNumArrayMembers(uint32 newNumMembers);

		/*!***********************************************************************
		 @Function		setNumMIPLevels
		 @Input				newNumMIPLevels		New number of MIP-Map levels.
		 @Description	Sets the number of MIP-Map levels in this texture.
		*************************************************************************/
		void setNumMIPLevels(uint32 newNumMIPLevels);

		/*!***********************************************************************
		 @Function		setNumFaces
		 @Input				newNumFaces New number of faces for this texture.
		 @Description	Sets the number of faces stored in this texture.
		*************************************************************************/
		void setNumFaces(uint32 newNumFaces);

		/*!***********************************************************************
		 @Function		setOrientation
		 @Input				eAxisOrientation Enum specifying axis and orientation.
		 @Description	Sets the data orientation for a given axis in this texture.
		*************************************************************************/
		void setOrientation(EPVRTOrientation eAxisOrientation);

		/*!***********************************************************************
		 @Function		setIsFileCompressed
		 @Input				isFileCompressed	Sets file compression to true/false.
		 @Description	Sets whether or not the texture is compressed using
						PVRTexLib's FILE compression - this is independent of 
						any texture compression. Currently unsupported.
		*************************************************************************/
		void setIsFileCompressed(bool isFileCompressed);
		
		/*!***********************************************************************
		 @Function		isPreMultiplied
		 @Return		isPreMultiplied	Sets if texture is premultiplied.
		 @Description	Sets whether or not the texture's colour has been
						pre-multiplied by the alpha values.
		*************************************************************************/
		void setIsPreMultiplied(bool isPreMultiplied);

	/*!***********************************************************************
	 Meta Data functions - Getters.
	*************************************************************************/	

		/*!***********************************************************************
		 @Function		isBumpMap
		 @Return		bool	True if it is a bump map.
		 @Description	Returns whether the texture is a bump map or not.
		*************************************************************************/
		const bool isBumpMap() const;

		/*!***********************************************************************
		 @Function		getBumpMapScale
		 @Return		float	Returns the bump map scale.
		 @Description	Gets the bump map scaling value for this texture. If the
						texture is not a bump map, 0.0f is returned. If the
						texture is a bump map but no meta data is stored to
						specify its scale, then 1.0f is returned.
		*************************************************************************/
		const float getBumpMapScale() const;

		/*!***********************************************************************
		 @Function		getBumpMapOrder
		 @Return		CPVRTString		Returns bump map order relative to rgba.
		 @Description	Gets the bump map channel order relative to rgba. For
						example, an RGB texture with bumps mapped to XYZ returns 
						'xyz'. A BGR texture with bumps in the order ZYX will also 
						return 'xyz' as the mapping is the same: R=X, G=Y, B=Z.
						If the letter 'h' is present in the string, it means that
						the height map has been stored here.
						Other characters are possible if the bump map was created
						manually, but PVRTexLib will ignore these characters. They
						are returned simply for completeness.
		*************************************************************************/
		const CPVRTString getBumpMapOrder() const;

		/*!***********************************************************************
		 @Function		getNumTextureAtlasMembers
		 @Return		int		Returns number of sub textures defined by meta data.
		 @Description	Works out the number of possible texture atlas members in
						the texture based on the w/h/d and the data size.
						TODO: Is this the right way to do things? Should I return number of floats? Or just data size? Hmm. Also need to make it TWO floats per dimension, and also possibly a rotated value. Not sure.
		*************************************************************************/
		const int getNumTextureAtlasMembers() const;

		/*!***********************************************************************
		 @Function		getTextureAtlasData
		 @Return		float*		Returns a pointer directly to the texture atlas data.
		 @Description	Returns a pointer to the texture atlas data.
						TODO: Maybe I should return a copy rather than the original.
		*************************************************************************/
		const float* getTextureAtlasData() const;

		/*!***********************************************************************
		 @Function		getCubeMapOrder
		 @Return		CPVRTString		Returns cube map order.
		 @Description	Gets the cube map face order. Returned string will be in 
						the form "ZzXxYy" with capitals representing positive and
						small letters representing negative. I.e. Z=Z-Positive,
						z=Z-Negative.
		*************************************************************************/
		const CPVRTString getCubeMapOrder() const;

		/*!***********************************************************************
		 @Function		getBorder
		 @Input			uiBorderWidth
		 @Input			uiBorderHeight
		 @Input			uiBorderDepth
		 @Description	Obtains the border size in each dimension for this texture.
		*************************************************************************/
		void getBorder(uint32& uiBorderWidth, uint32& uiBorderHeight, uint32& uiBorderDepth) const;

		/*!***********************************************************************
		 @Function		getMetaData
		 @Input			DevFOURCC
		 @Input			u32Key
		 @Return		pvrtexture::MetaDataBlock A copy of the meta data from the texture.
		 @Description	Returns a block of meta data from the texture. If the meta data doesn't exist, a block with data size 0 will be returned.
		*************************************************************************/
		MetaDataBlock getMetaData(uint32 DevFOURCC, uint32 u32Key) const;

		/*!***********************************************************************
		 @Function		hasMetaData
		 @Input			DevFOURCC
		 @Input			u32Key
		 @Return		bool Whether or not the meta data bock specified exists
		 @Description	Returns whether or not the specified meta data exists as 
						part of this texture header.
		*************************************************************************/
		bool hasMetaData(uint32 DevFOURCC, uint32 u32Key) const;

		/*!***********************************************************************
		 @Function		getMetaDataMap
		 @Return		MetaDataMap* A direct pointer to the MetaData map.
		 @Description	A pointer directly to the Meta Data Map, to allow users to read out data.
		*************************************************************************/
		const MetaDataMap* const getMetaDataMap() const;

	/*!***********************************************************************
	 Meta Data functions - Setters.
	*************************************************************************/	
		
		/*!***********************************************************************
		 @Function		setBumpMap
		 @Input				bumpScale	Floating point "height" value to scale the bump map.
		 @Input				bumpOrder	Up to 4 character string, with values x,y,z,h in 
									some combination. Not all values need to be present.
									Denotes channel order; x,y,z refer to the 
									corresponding axes, h indicates presence of the
									original height map. It is possible to have only some
									of these values rather than all. For example if 'h'
									is present alone it will be considered a height map.
									The values should be presented in RGBA order, regardless
									of the texture format, so a zyxh order in a bgra texture
									should still be passed as 'xyzh'. Capitals are allowed.
									Any character stored here that is not one of x,y,z,h
									or a NULL character	will be ignored when PVRTexLib 
									reads the data,	but will be preserved. This is useful
									if you wish to define a custom data channel for instance.
									In these instances PVRTexLib will assume it is simply
									colour data.
		 @Description	Sets a texture's bump map data.
		*************************************************************************/
		void setBumpMap(float bumpScale, CPVRTString bumpOrder="xyz");

		/*!***********************************************************************
		 @Function		setTextureAtlas
		 @Input				pAtlasData	Pointer to an array of atlas data.
		 @Input				dataSize	Number of floats that the data pointer contains.
		 @Description	Sets the texture atlas coordinate meta data for later display.
						It is up to the user to make sure that this texture atlas
						data actually makes sense in the context of the header. It is
						suggested that the "generateTextureAtlas" method in the tools
						is used to create a texture atlas, manually setting one up is 
						possible but should be done with care.
		*************************************************************************/
		void setTextureAtlas(float* pAtlasData, uint32 dataSize);

		/*!***********************************************************************
		 @Function		setCubeMapOrder
		 @Input				cubeMapOrder	Up to 6 character string, with values 
										x,X,y,Y,z,Z in some combination. Not all 
										values need to be present. Denotes face 
										order; Capitals refer to positive axis 
										positions and small letters refer to 
										negative axis positions. E.g. x=X-Negative,
										X=X-Positive. It is possible to have only 
										some of these values rather than all, as 
										long as they are NULL terminated.
										NB: Values past the 6th character are not read.
		 @Description	Sets a texture's bump map data.
		*************************************************************************/
		void setCubeMapOrder(CPVRTString cubeMapOrder="XxYyZz");

		/*!***********************************************************************
		 @Function		setBorder
		 @Input			uiBorderWidth
		 @Input			uiBorderHeight
		 @Input			uiBorderDepth
		 @Return		void 
		 @Description	Sets a texture's border size data. This value is subtracted 
						from the current texture height/width/depth to get the valid 
						texture data.
		*************************************************************************/
		void setBorder(uint32 uiBorderWidth, uint32 uiBorderHeight, uint32 uiBorderDepth);

		/*!***********************************************************************
		 @Function		addMetaData
		 @Input				MetaBlock	Meta data block to be added.
		 @Description	Adds an arbitrary piece of meta data.
		*************************************************************************/
		void addMetaData(const MetaDataBlock& MetaBlock);
				
		/*!***********************************************************************
		 @Function		removeMetaData
		 @Input			DevFourCC
		 @Input			u32Key
		 @Return		void 
		 @Description	Removes a specified piece of meta data, if it exists.
		*************************************************************************/
		void removeMetaData(const uint32& DevFourCC, const uint32& u32Key);
	};
};

#endif


<|start_filename|>src/nvimage/ErrorMetric.cpp<|end_filename|>

#include "ErrorMetric.h"
#include "FloatImage.h"
#include "Filter.h"

#include "nvmath/Matrix.h"
#include "nvmath/Vector.inl"

#include <float.h> // FLT_MAX

using namespace nv;

float nv::rmsColorError(const FloatImage * ref, const FloatImage * img, bool alphaWeight)
{
    if (!sameLayout(img, ref)) {
        return FLT_MAX;
    }
    nvDebugCheck(img->componentCount() == 4);
    nvDebugCheck(ref->componentCount() == 4);

    double mse = 0;

    const uint count = img->pixelCount();
    for (uint i = 0; i < count; i++)
    {
        float r0 = ref->pixel(i + count * 0);
        float g0 = ref->pixel(i + count * 1);
        float b0 = ref->pixel(i + count * 2);
        float a0 = ref->pixel(i + count * 3);
        float r1 = img->pixel(i + count * 0);
        float g1 = img->pixel(i + count * 1);
        float b1 = img->pixel(i + count * 2);
        //float a1 = img->pixel(i + count * 3);

        float r = r0 - r1;
        float g = g0 - g1;
        float b = b0 - b1;

        float a = 1;
        if (alphaWeight) a = a0 * a0; // @@ a0*a1 or a0*a0 ?

        mse += (r * r) * a;
        mse += (g * g) * a;
        mse += (b * b) * a;
    }

    return float(sqrt(mse / count));
}

float nv::rmsAlphaError(const FloatImage * ref, const FloatImage * img)
{
    if (!sameLayout(img, ref)) {
        return FLT_MAX;
    }
    nvDebugCheck(img->componentCount() == 4 && ref->componentCount() == 4);

    double mse = 0;

    const uint count = img->pixelCount();
    for (uint i = 0; i < count; i++)
    {
        float a0 = img->pixel(i + count * 3);
        float a1 = ref->pixel(i + count * 3);

        float a = a0 - a1;

        mse += a * a;
    }

    return float(sqrt(mse / count));
}


float nv::averageColorError(const FloatImage * ref, const FloatImage * img, bool alphaWeight)
{
    if (!sameLayout(img, ref)) {
        return FLT_MAX;
    }
    nvDebugCheck(img->componentCount() == 4);
    nvDebugCheck(ref->componentCount() == 4);

    double mae = 0;

    const uint count = img->pixelCount();
    for (uint i = 0; i < count; i++)
    {
        float r0 = img->pixel(i + count * 0);
        float g0 = img->pixel(i + count * 1);
        float b0 = img->pixel(i + count * 2);
        //float a0 = img->pixel(i + count * 3);
        float r1 = ref->pixel(i + count * 0);
        float g1 = ref->pixel(i + count * 1);
        float b1 = ref->pixel(i + count * 2);
        float a1 = ref->pixel(i + count * 3);

        float r = fabsf(r0 - r1);
        float g = fabsf(g0 - g1);
        float b = fabsf(b0 - b1);

        float a = 1;
        if (alphaWeight) a = a1;

        mae += r * a;
        mae += g * a;
        mae += b * a;
    }

    return float(mae / count);
}

float nv::averageAlphaError(const FloatImage * ref, const FloatImage * img)
{
    if (img == NULL || ref == NULL || img->width() != ref->width() || img->height() != ref->height()) {
        return FLT_MAX;
    }
    nvDebugCheck(img->componentCount() == 4 && ref->componentCount() == 4);

    double mae = 0;

    const uint count = img->width() * img->height();
    for (uint i = 0; i < count; i++)
    {
        float a0 = img->pixel(i + count * 3);
        float a1 = ref->pixel(i + count * 3);

        float a = a0 - a1;

        mae += fabsf(a);
    }

    return float(mae / count);
}


float nv::rmsBilinearColorError(const FloatImage * ref, const FloatImage * img, FloatImage::WrapMode wm, bool alphaWeight)
{
    nvDebugCheck(img->componentCount() == 4);
    nvDebugCheck(ref->componentCount() == 4);

    double mse = 0;

    const uint w0 = ref->width();
    const uint h0 = ref->height();
    const uint d0 = ref->depth();

    const uint w1 = img->width();
    const uint h1 = img->height();
    const uint d1 = img->depth();

    for (uint z = 0; z < d0; z++) {
        for (uint y = 0; y < h0; y++) {
            for (uint x = 0; x < w0; x++) {
                float r0 = ref->pixel(0, x, y, z);
                float g0 = ref->pixel(1, x, y, z);
                float b0 = ref->pixel(2, x, y, z);
                float a0 = ref->pixel(3, x, y, z);

                float fx = float(x) / w0;
                float fy = float(y) / h0;
                float fz = float(z) / d0;

                float r1 = img->sampleLinear(0, fx, fy, fz, wm);
                float g1 = img->sampleLinear(1, fx, fy, fz, wm);
                float b1 = img->sampleLinear(2, fx, fy, fz, wm);
                float a1 = img->sampleLinear(2, fx, fy, fz, wm);

                float dr = r0 - r1;
                float dg = g0 - g1;
                float db = b0 - b1;
                float da = a0 - a1;

                float w = 1;
                if (alphaWeight) w = a0 * a0; // @@ a0*a1 or a0*a0 ?

                mse += (dr * dr) * w;
                mse += (dg * dg) * w;
                mse += (db * db) * w;
                mse += (da * da);
            }
        }
    }

    int count = w0 * h0 * d0;
    return float(sqrt(mse / count));
}


// Color space conversions based on:
// http://www.brucelindbloom.com/

// Assumes input is in *linear* sRGB color space.
static Vector3 rgbToXyz(Vector3::Arg c)
{
    Vector3 xyz;
    xyz.x = 0.412453f * c.x + 0.357580f * c.y + 0.180423f * c.z;
    xyz.y = 0.212671f * c.x + 0.715160f * c.y + 0.072169f * c.z;
    xyz.z = 0.019334f * c.x + 0.119193f * c.y + 0.950227f * c.z;
    return xyz;
}

static Vector3 xyzToRgb(Vector3::Arg c)
{
    Vector3 rgb;
    rgb.x =  3.2404542f * c.x - 1.5371385f * c.y - 0.4985314f * c.z;
    rgb.y = -0.9692660f * c.x + 1.8760108f * c.y + 0.0415560f * c.z;
    rgb.z =  0.0556434f * c.x - 0.2040259f * c.y + 1.0572252f * c.z;
    return rgb;
}

static float toLinear(float f)
{
    return powf(f, 2.2f);
}

static float toGamma(float f)
{
    // @@ Use sRGB space?
    return powf(f, 1.0f/2.2f);
}

static Vector3 toLinear(Vector3::Arg c)
{
    return Vector3(toLinear(c.x), toLinear(c.y), toLinear(c.z));
}

static Vector3 toGamma(Vector3::Arg c)
{
    return Vector3(toGamma(c.x), toGamma(c.y), toGamma(c.z));
}

static float f(float t)
{
    const float epsilon = powf(6.0f/29.0f, 3);

    if (t > epsilon) {
        return powf(t, 1.0f/3.0f);
    }
    else {
        return 1.0f/3.0f * powf(29.0f/6.0f, 2) * t + 4.0f / 29.0f;
    }
}

static float finv(float t)
{
    if (t > 6.0f / 29.0f) {
        return 3.0f * powf(6.0f / 29.0f, 2) * (t - 4.0f / 29.0f);
    }
    else {
        return powf(t, 3.0f);
    }
}

static Vector3 xyzToCieLab(Vector3::Arg c)
{
    // Normalized white point.
    const float Xn = 0.950456f;
    const float Yn = 1.0f;
    const float Zn = 1.088754f;

    float Xr = c.x / Xn;
    float Yr = c.y / Yn;
    float Zr = c.z / Zn;

    float fx = f(Xr);
    float fy = f(Yr);
    float fz = f(Zr);

    float L = 116 * fx - 16;
    float a = 500 * (fx - fy);
    float b = 200 * (fy - fz);

    return Vector3(L, a, b);
}

static Vector3 rgbToCieLab(Vector3::Arg c)
{
    return xyzToCieLab(rgbToXyz(toLinear(c)));
}

// h is hue-angle in radians
static Vector3 cieLabToLCh(Vector3::Arg c)
{
    return Vector3(c.x, sqrtf(c.y*c.y + c.z*c.z), atan2f(c.y, c.z));
}

static void rgbToCieLab(const FloatImage * rgbImage, FloatImage * LabImage)
{
    nvDebugCheck(rgbImage != NULL && LabImage != NULL);
    nvDebugCheck(rgbImage->width() == LabImage->width() && rgbImage->height() == LabImage->height());
    nvDebugCheck(rgbImage->componentCount() >= 3 && LabImage->componentCount() >= 3);

    const uint w = rgbImage->width();
    const uint h = LabImage->height();

    const float * R = rgbImage->channel(0);
    const float * G = rgbImage->channel(1);
    const float * B = rgbImage->channel(2);

    float * L = LabImage->channel(0);
    float * a = LabImage->channel(1);
    float * b = LabImage->channel(2);

    const uint count = w*h;
    for (uint i = 0; i < count; i++)
    {
        Vector3 Lab = rgbToCieLab(Vector3(R[i], G[i], B[i]));
        L[i] = Lab.x;
        a[i] = Lab.y;
        b[i] = Lab.z;
    }
}


// Assumes input images are in linear sRGB space.
float nv::cieLabError(const FloatImage * img0, const FloatImage * img1)
{
    if (!sameLayout(img0, img1)) return FLT_MAX;
    nvDebugCheck(img0->componentCount() == 4 && img1->componentCount() == 4);

    const float * r0 = img0->channel(0);
    const float * g0 = img0->channel(1);
    const float * b0 = img0->channel(2);

    const float * r1 = img1->channel(0);
    const float * g1 = img1->channel(1);
    const float * b1 = img1->channel(2);

    double error = 0.0f;

    const uint count = img0->pixelCount();
    for (uint i = 0; i < count; i++)
    {
        Vector3 lab0 = rgbToCieLab(Vector3(r0[i], g0[i], b0[i]));
        Vector3 lab1 = rgbToCieLab(Vector3(r1[i], g1[i], b1[i]));

        // @@ Measure Delta E.
        Vector3 delta = lab0 - lab1;
        
        error += length(delta);
    }

    return float(error / count);
}

// Assumes input images are in linear sRGB space.
float nv::cieLab94Error(const FloatImage * img0, const FloatImage * img1)
{
    if (!sameLayout(img0, img1)) return FLT_MAX;
    nvDebugCheck(img0->componentCount() == 4 && img1->componentCount() == 4);

    const float kL = 1;
    const float kC = 1;
    const float kH = 1;
    const float k1 = 0.045f;
    const float k2 = 0.015f;

    const float sL = 1;

    const float * r0 = img0->channel(0);
    const float * g0 = img0->channel(1);
    const float * b0 = img0->channel(2);

    const float * r1 = img1->channel(0);
    const float * g1 = img1->channel(1);
    const float * b1 = img1->channel(2);

    double error = 0.0f;

    const uint count = img0->pixelCount();
    for (uint i = 0; i < count; ++i)
    {
        Vector3 lab0 = rgbToCieLab(Vector3(r0[i], g0[i], b0[i]));
        Vector3 lch0 = cieLabToLCh(lab0);
        Vector3 lab1 = rgbToCieLab(Vector3(r1[i], g1[i], b1[i]));
        Vector3 lch1 = cieLabToLCh(lab1);

        const float sC = 1 + k1*lch0.x;
        const float sH = 1 + k2*lch0.x;

        // @@ Measure Delta E using the 1994 definition
        Vector3 labDelta = lab0 - lab1;
        Vector3 lchDelta = lch0 - lch1;

        double deltaLsq = powf(lchDelta.x / (kL*sL), 2);
        double deltaCsq = powf(lchDelta.y / (kC*sC), 2);

        // avoid possible sqrt of negative value by computing (deltaH/(kH*sH))^2
        double deltaHsq = powf(labDelta.y, 2) + powf(labDelta.z, 2) - powf(lchDelta.y, 2);
        deltaHsq /= powf(kH*sH, 2);

        error += sqrt(deltaLsq + deltaCsq + deltaHsq);
    }

    return float(error / count);
}

float nv::spatialCieLabError(const FloatImage * img0, const FloatImage * img1)
{
    if (img0 == NULL || img1 == NULL || img0->width() != img1->width() || img0->height() != img1->height()) {
        return FLT_MAX;
    }
    nvDebugCheck(img0->componentCount() == 4 && img1->componentCount() == 4);

    uint w = img0->width();
    uint h = img0->height();
    uint d = img0->depth();

    FloatImage lab0, lab1; // Original images in CIE-Lab space.
    lab0.allocate(3, w, h, d);
    lab1.allocate(3, w, h, d);

    // Convert input images to CIE-Lab.
    rgbToCieLab(img0, &lab0);
    rgbToCieLab(img1, &lab1);

    // @@ Convolve each channel by the corresponding filter.
    /*
    GaussianFilter LFilter(5);
    GaussianFilter aFilter(5);
    GaussianFilter bFilter(5);

    lab0.convolve(0, LFilter);
    lab0.convolve(1, aFilter);
    lab0.convolve(2, bFilter);

    lab1.convolve(0, LFilter);
    lab1.convolve(1, aFilter);
    lab1.convolve(2, bFilter);
    */
    // @@ Measure Delta E between lab0 and lab1.

    return 0.0f;
}


// Assumes input images are normal maps.
float nv::averageAngularError(const FloatImage * img0, const FloatImage * img1)
{
    if (img0 == NULL || img1 == NULL || img0->width() != img1->width() || img0->height() != img1->height()) {
        return FLT_MAX;
    }
    nvDebugCheck(img0->componentCount() == 4 && img1->componentCount() == 4);

    uint w = img0->width();
    uint h = img0->height();

    const float * x0 = img0->channel(0);
    const float * y0 = img0->channel(1);
    const float * z0 = img0->channel(2);

    const float * x1 = img1->channel(0);
    const float * y1 = img1->channel(1);
    const float * z1 = img1->channel(2);

    double error = 0.0f;

    const uint count = w*h;
    for (uint i = 0; i < count; i++)
    {
        Vector3 n0 = Vector3(x0[i], y0[i], z0[i]);
        Vector3 n1 = Vector3(x1[i], y1[i], z1[i]);

        n0 = 2.0f * n0 - Vector3(1);
        n1 = 2.0f * n1 - Vector3(1);

        n0 = normalizeSafe(n0, Vector3(0), 0.0f);
        n1 = normalizeSafe(n1, Vector3(0), 0.0f);

        error += acos(clamp(dot(n0, n1), -1.0f, 1.0f));
    }

    return float(error / count);
}

float nv::rmsAngularError(const FloatImage * img0, const FloatImage * img1)
{
    if (img0 == NULL || img1 == NULL || img0->width() != img1->width() || img0->height() != img1->height()) {
        return FLT_MAX;
    }
    nvDebugCheck(img0->componentCount() == 4 && img1->componentCount() == 4);

    uint w = img0->width();
    uint h = img0->height();

    const float * x0 = img0->channel(0);
    const float * y0 = img0->channel(1);
    const float * z0 = img0->channel(2);

    const float * x1 = img1->channel(0);
    const float * y1 = img1->channel(1);
    const float * z1 = img1->channel(2);

    double error = 0.0f;

    const uint count = w*h;
    for (uint i = 0; i < count; i++)
    {
        Vector3 n0 = Vector3(x0[i], y0[i], z0[i]);
        Vector3 n1 = Vector3(x1[i], y1[i], z1[i]);

        n0 = 2.0f * n0 - Vector3(1);
        n1 = 2.0f * n1 - Vector3(1);

        n0 = normalizeSafe(n0, Vector3(0), 0.0f);
        n1 = normalizeSafe(n1, Vector3(0), 0.0f);

        float angle = acosf(clamp(dot(n0, n1), -1.0f, 1.0f));
        error += angle * angle;
    }

    return float(sqrt(error / count));
}



<|start_filename|>project/vc2017/Nvidia.TextureTools/TextureTools.cs<|end_filename|>
using System;
using System.Security;
using System.Runtime.InteropServices;

namespace Nvidia.TextureTools
{
	#region Enums

	#region public enum Format
	/// <summary>
	/// Compression format.
	/// </summary>
	public enum Format
	{
		// No compression.
		RGB,
		RGBA = RGB,

		// DX9 formats.
		DXT1,
		DXT1a,
		DXT3,
		DXT5,
		DXT5n,

		// DX10 formats.
		BC1 = DXT1,
		BC1a = DXT1a,
		BC2 = DXT3,
		BC3 = DXT5,
		BC3n = DXT5n,
		BC4,
		BC5,

		DXT1n,   // Not supported on CPU yet.
		CTX1,    // Not supported on CPU yet.

		BC6,
		BC7,     // Not supported yet.

		DXT1_Luma,
	}
	#endregion

	#region public enum Quality
	/// <summary>
	/// Quality modes.
	/// </summary>
	public enum Quality
	{
		Fastest,
		Normal,
		Production,
		Highest,
	}
	#endregion

	#region public enum WrapMode
	/// <summary>
	/// Wrap modes.
	/// </summary>
	public enum WrapMode
	{
		Clamp,
		Repeat,
		Mirror,
	}
	#endregion

	#region public enum TextureType
	/// <summary>
	/// Texture types.
	/// </summary>
	public enum TextureType
	{
		Texture2D,
		TextureCube,
	}
	#endregion

	#region public enum InputFormat
	/// <summary>
	/// Input formats.
	/// </summary>
	public enum InputFormat
	{
		BGRA_8UB
	}
	#endregion

	#region public enum MipmapFilter
	/// <summary>
	/// Mipmap downsampling filters.
	/// </summary>
	public enum MipmapFilter
	{
		Box,
		Triangle,
		Kaiser
	}
	#endregion

	#region public enum ColorTransform
	/// <summary>
	/// Color transformation.
	/// </summary>
	public enum ColorTransform
	{
		None,
		Linear
	}
	#endregion

	#region public enum RoundMode
	/// <summary>
	/// Extents rounding mode.
	/// </summary>
	public enum RoundMode
	{
		None,
		ToNextPowerOfTwo,
		ToNearestPowerOfTwo,
		ToPreviousPowerOfTwo
	}
	#endregion

	#region public enum AlphaMode
	/// <summary>
	/// Alpha mode.
	/// </summary>
	public enum AlphaMode
	{
		None,
		Transparency,
		Premultiplied
	}
	#endregion

	#region public enum Error
	/// <summary>
	/// Error codes.
	/// </summary>
	public enum Error
	{
		InvalidInput,
		UserInterruption,
		UnsupportedFeature,
		CudaError,
		Unknown,
		FileOpen,
		FileWrite,
	}
	#endregion

	#endregion

	#region public class InputOptions
	/// <summary>
	/// Input options.
	/// </summary>
	public class InputOptions
	{
		#region Bindings
		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static IntPtr nvttCreateInputOptions();

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttDestroyInputOptions(IntPtr inputOptions);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsTextureLayout(IntPtr inputOptions, TextureType type, int w, int h, int d);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttResetInputOptionsTextureLayout(IntPtr inputOptions);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static bool nvttSetInputOptionsMipmapData(IntPtr inputOptions, IntPtr data, int w, int h, int d, int face, int mipmap);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsFormat(IntPtr inputOptions, InputFormat format);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsAlphaMode(IntPtr inputOptions, AlphaMode alphaMode);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsGamma(IntPtr inputOptions, float inputGamma, float outputGamma);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsWrapMode(IntPtr inputOptions, WrapMode mode);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsMipmapFilter(IntPtr inputOptions, MipmapFilter filter);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsMipmapGeneration(IntPtr inputOptions, bool generateMipmaps, int maxLevel);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsKaiserParameters(IntPtr inputOptions, float width, float alpha, float stretch);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsNormalMap(IntPtr inputOptions, bool b);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsConvertToNormalMap(IntPtr inputOptions, bool convert);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsHeightEvaluation(IntPtr inputOptions, float redScale, float greenScale, float blueScale, float alphaScale);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsNormalFilter(IntPtr inputOptions, float small, float medium, float big, float large);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsNormalizeMipmaps(IntPtr inputOptions, bool b);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsColorTransform(IntPtr inputOptions, ColorTransform t);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsLinearTransfrom(IntPtr inputOptions, int channel, float w0, float w1, float w2, float w3);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsMaxExtents(IntPtr inputOptions, int d);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetInputOptionsRoundMode(IntPtr inputOptions, RoundMode mode);
		#endregion

		internal IntPtr options;

		public InputOptions()
		{
			options = nvttCreateInputOptions();
		}
		~InputOptions()
		{
			nvttDestroyInputOptions(options);
		}

		public void SetTextureLayout(TextureType type, int w, int h, int d)
		{
			nvttSetInputOptionsTextureLayout(options, type, w, h, d);
		}
		public void ResetTextureLayout()
		{
			nvttResetInputOptionsTextureLayout(options);
		}

		public void SetMipmapData(IntPtr data, int width, int height, int depth, int face, int mipmap)
		{
			nvttSetInputOptionsMipmapData(options, data, width, height, depth, face, mipmap);
		}

		public void SetFormat(InputFormat format)
		{
			nvttSetInputOptionsFormat(options, format);
		}

		public void SetAlphaMode(AlphaMode alphaMode)
		{
			nvttSetInputOptionsAlphaMode(options, alphaMode);
		}

		public void SetGamma(float inputGamma, float outputGamma)
		{
			nvttSetInputOptionsGamma(options, inputGamma, outputGamma);
		}

		public void SetWrapMode(WrapMode wrapMode)
		{
			nvttSetInputOptionsWrapMode(options, wrapMode);
		}

		public void SetMipmapFilter(MipmapFilter filter)
		{
			nvttSetInputOptionsMipmapFilter(options, filter);
		}

		public void SetMipmapGeneration(bool enabled)
		{
			nvttSetInputOptionsMipmapGeneration(options, enabled, -1);
		}

		public void SetMipmapGeneration(bool enabled, int maxLevel)
		{
			nvttSetInputOptionsMipmapGeneration(options, enabled, maxLevel);
		}

		public void SetKaiserParameters(float width, float alpha, float stretch)
		{
			nvttSetInputOptionsKaiserParameters(options, width, alpha, stretch);
		}

		public void SetNormalMap(bool b)
		{
			nvttSetInputOptionsNormalMap(options, b);
		}

		public void SetConvertToNormalMap(bool convert)
		{
			nvttSetInputOptionsConvertToNormalMap(options, convert);
		}

		public void SetHeightEvaluation(float redScale, float greenScale, float blueScale, float alphaScale)
		{
			nvttSetInputOptionsHeightEvaluation(options, redScale, greenScale, blueScale, alphaScale);
		}

		public void SetNormalFilter(float small, float medium, float big, float large)
		{
			nvttSetInputOptionsNormalFilter(options, small, medium, big, large);
		}

		public void SetNormalizeMipmaps(bool b)
		{
			nvttSetInputOptionsNormalizeMipmaps(options, b);
		}

		public void SetColorTransform(ColorTransform t)
		{
			nvttSetInputOptionsColorTransform(options, t);
		}

		public void SetLinearTransfrom(int channel, float w0, float w1, float w2, float w3)
		{
			nvttSetInputOptionsLinearTransfrom(options, channel, w0, w1, w2, w3);
		}

		public void SetMaxExtents(int dim)
		{
			nvttSetInputOptionsMaxExtents(options, dim);
		}

		public void SetRoundMode(RoundMode mode)
		{
			nvttSetInputOptionsRoundMode(options, mode);
		}
	}
	#endregion

	#region public class CompressionOptions
	/// <summary>
	/// Compression options.
	/// </summary>
	public class CompressionOptions
	{
		#region Bindings
		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static IntPtr nvttCreateCompressionOptions();

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttDestroyCompressionOptions(IntPtr compressionOptions);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetCompressionOptionsFormat(IntPtr compressionOptions, Format format);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetCompressionOptionsQuality(IntPtr compressionOptions, Quality quality);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetCompressionOptionsColorWeights(IntPtr compressionOptions, float red, float green, float blue, float alpha);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetCompressionOptionsPixelFormat(IntPtr compressionOptions, uint bitcount, uint rmask, uint gmask, uint bmask, uint amask);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetCompressionOptionsQuantization(IntPtr compressionOptions, bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold);
		#endregion

		internal IntPtr options;

		public CompressionOptions()
		{
			options = nvttCreateCompressionOptions();
		}
		~CompressionOptions()
		{
			nvttDestroyCompressionOptions(options);
		}

		public void SetFormat(Format format)
		{
			nvttSetCompressionOptionsFormat(options, format);
		}
		
		public void SetQuality(Quality quality)
		{
			nvttSetCompressionOptionsQuality(options, quality);
		}

		public void SetColorWeights(float red, float green, float blue)
		{
			nvttSetCompressionOptionsColorWeights(options, red, green, blue, 1.0f);
		}

		public void SetColorWeights(float red, float green, float blue, float alpha)
		{
			nvttSetCompressionOptionsColorWeights(options, red, green, blue, alpha);
		}

		public void SetPixelFormat(uint bitcount, uint rmask, uint gmask, uint bmask, uint amask)
		{
			nvttSetCompressionOptionsPixelFormat(options, bitcount, rmask, gmask, bmask, amask);
		}

		public void SetQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha)
		{
			nvttSetCompressionOptionsQuantization(options, colorDithering, alphaDithering, binaryAlpha, 127);
		}

		public void SetQuantization(bool colorDithering, bool alphaDithering, bool binaryAlpha, int alphaThreshold)
		{
			nvttSetCompressionOptionsQuantization(options, colorDithering, alphaDithering, binaryAlpha, alphaThreshold);
		}
	}
	#endregion

	#region public class OutputOptions
	/// <summary>
	/// Output options.
	/// </summary>
	public class OutputOptions
	{
		#region Delegates
		public delegate void ErrorHandler(Error error);
		private delegate void WriteDataDelegate(IntPtr data, int size);
		private delegate void ImageDelegate(int size, int width, int height, int depth, int face, int miplevel);
		#endregion

		#region Bindings
		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static IntPtr nvttCreateOutputOptions();

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttDestroyOutputOptions(IntPtr outputOptions);

		[DllImport("nvtt", CharSet = CharSet.Ansi), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetOutputOptionsFileName(IntPtr outputOptions, string fileName);

		//[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		//private extern static void nvttSetOutputOptionsErrorHandler(IntPtr outputOptions, ErrorHandler errorHandler);

		private void ErrorCallback(Error error)
		{
			if (Error != null) Error(error);
		}

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttSetOutputOptionsOutputHeader(IntPtr outputOptions, bool b);

		//[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		//private extern static void nvttSetOutputOptionsOutputHandler(IntPtr outputOptions, WriteDataDelegate writeData, ImageDelegate image);

		#endregion

		internal IntPtr options;

		public OutputOptions()
		{
			options = nvttCreateOutputOptions();
			//nvttSetOutputOptionsErrorHandler(options, new ErrorHandler(ErrorCallback));
		}
		~OutputOptions()
		{
			nvttDestroyOutputOptions(options);
		}

		public void SetFileName(string fileName)
		{
			nvttSetOutputOptionsFileName(options, fileName);
		}

		public event ErrorHandler Error;

		public void SetOutputHeader(bool b)
		{
			nvttSetOutputOptionsOutputHeader(options, b);
		}

		// @@ Add OutputHandler interface.
	}
	#endregion

	#region public static class Compressor
	public class Compressor
	{
		#region Bindings
		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static IntPtr nvttCreateCompressor();

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static void nvttDestroyCompressor(IntPtr compressor);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static bool nvttCompress(IntPtr compressor, IntPtr inputOptions, IntPtr compressionOptions, IntPtr outputOptions);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private extern static int nvttEstimateSize(IntPtr compressor, IntPtr inputOptions, IntPtr compressionOptions);

		[DllImport("nvtt"), SuppressUnmanagedCodeSecurity]
		private static extern IntPtr nvttErrorString(Error error);

		#endregion

		internal IntPtr compressor;

		public Compressor()
		{
			compressor = nvttCreateCompressor();
		}

		~Compressor()
		{
			nvttDestroyCompressor(compressor);
		}

		public bool Compress(InputOptions input, CompressionOptions compression, OutputOptions output)
		{
			return nvttCompress(compressor, input.options, compression.options, output.options);
		}

		public int EstimateSize(InputOptions input, CompressionOptions compression)
		{
			return nvttEstimateSize(compressor, input.options, compression.options);
		}

		public static string ErrorString(Error error)
		{
			return Marshal.PtrToStringAnsi(nvttErrorString(error));
		}

	}
	#endregion

} // Nvidia.TextureTools namespace


<|start_filename|>project/vc2017/nvconfig.h<|end_filename|>
#ifndef NV_CONFIG
#define NV_CONFIG

//#cmakedefine HAVE_UNISTD_H
//#define HAVE_STDARG_H
//#cmakedefine HAVE_SIGNAL_H
//#cmakedefine HAVE_EXECINFO_H
//#define HAVE_MALLOC_H

#if defined(_OPENMP)
#define HAVE_OPENMP
#endif

#define NV_HAVE_STBIMAGE
/*#if !defined(_M_X64)
//#define NV_HAVE_FREEIMAGE
#define NV_HAVE_PNG
#define NV_HAVE_JPEG
#define NV_HAVE_TIFF
#endif*/

#endif // NV_CONFIG


<|start_filename|>src/nvthread/Win32.h<|end_filename|>
// This code is in the public domain -- <EMAIL>

// Never include this from a header file.

#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#define _WIN32_WINNT 0x0400 // for SwitchToThread, TryEnterCriticalSection
#include <windows.h>
//#include <process.h> // for _beginthreadex

<|start_filename|>src/nvtt/experimental/nvtt_experimental.cpp<|end_filename|>

#include "nvtt_experimental.h"

struct NvttTexture
{
	NvttTexture() :
		m_constant(false),
		m_image(NULL),
		m_floatImage(NULL)
	{
	}
	
	~NvttTexture()
	{
		if (m_constant && m_image) m_image->unwrap();
		delete m_image;
		delete m_floatImage;
	}
	
	bool m_constant;
	Image * m_image;
	FloatImage * m_floatImage;
};

NvttTexture * nvttCreateTexture() 
{
	return new NvttTexture();
}
	
void nvttDestroyTexture(NvttTexture * tex)
{
	delete tex;
}

void nvttSetImageData(NvttImage * img, NvttInputFormat format, uint w, uint h, void * data)
{
	nvCheck(img != NULL);
	
	if (format == NVTT_InputFormat_BGRA_8UB)
	{
		img->m_constant = false;
		img->m_image->allocate(w, h);
		memcpy(img->m_image->pixels(), data, w * h * 4);
	}
	else
	{
		nvCheck(false);
	}
}

void nvttCompressImage(NvttImage * img, NvttFormat format)
{
	nvCheck(img != NULL);

	// @@ Invoke appropriate compressor.
}



<|start_filename|>src/nvtt/cuda/BitmapTable.h<|end_filename|>


/*
static void doPrecomputation()
{
	uint bitmaps[1024];

	int indices[16];
	int num = 0;

	// Compute bitmaps with 3 clusters:

	// first cluster [0,i) is at the start
	for( int m = 0; m < 16; ++m )
	{
		indices[m] = 0;
	}
	const int imax = 15;
	for( int i = imax; i >= 0; --i )
	{
		// second cluster [i,j) is half along
		for( int m = i; m < 16; ++m )
		{
			indices[m] = 2;
		}
		const int jmax = ( i == 0 ) ? 15 : 16;
		for( int j = jmax; j >= i; --j )
		{
			// last cluster [j,k) is at the end
			if( j < 16 )
			{
				indices[j] = 1;
			}
			
			uint bitmap = 0;
			
			for(int p = 0; p < 16; p++) {
				bitmap |= indices[p] << (p * 2);
			}
				
			bitmaps[num] = bitmap;
			
			num++;
		}
	}
	nvDebugCheck(num == 151);

	// Align to 160.
	for(int i = 0; i < 9; i++)
	{
		bitmaps[num] = 0x555AA000;
		num++;
	}
	nvDebugCheck(num == 160);

	// Append bitmaps with 4 clusters:

	// first cluster [0,i) is at the start
	for( int m = 0; m < 16; ++m )
	{
		indices[m] = 0;
	}
	for( int i = imax; i >= 0; --i )
	{
		// second cluster [i,j) is one third along
		for( int m = i; m < 16; ++m )
		{
			indices[m] = 2;
		}
		const int jmax = ( i == 0 ) ? 15 : 16;
		for( int j = jmax; j >= i; --j )
		{
			// third cluster [j,k) is two thirds along
			for( int m = j; m < 16; ++m )
			{
				indices[m] = 3;
			}
			
			int kmax = ( j == 0 ) ? 15 : 16;
			for( int k = kmax; k >= j; --k )
			{
				// last cluster [k,n) is at the end
				if( k < 16 )
				{
					indices[k] = 1;
				}
				
				uint bitmap = 0;
				
				bool hasThree = false;
				for(int p = 0; p < 16; p++) {
					bitmap |= indices[p] << (p * 2);
					
					if (indices[p] == 3) hasThree = true;
				}
				
				if (hasThree) {
					bitmaps[num] = bitmap;
					num++;
				}
			}
		}
	}
	nvDebugCheck(num == 975);
	
	// Align to 1024.
	for(int i = 0; i < 49; i++)
	{
		bitmaps[num] = 0x555AA000;
		num++;
	}

	nvDebugCheck(num == 1024);

	printf("uint bitmaps[992] =\n{\n");
	for (int i = 0; i < 992; i++)
	{
		printf("\t0x%.8X,\n", bitmaps[i]);
	}
	printf("};\n");
}
*/


const static uint s_bitmapTable[992] =
{
	0x80000000,
	0x40000000,
	0xA0000000,
	0x60000000,
	0x50000000,
	0xA8000000,
	0x68000000,
	0x58000000,
	0x54000000,
	0xAA000000,
	0x6A000000,
	0x5A000000,
	0x56000000,
	0x55000000,
	0xAA800000,
	0x6A800000,
	0x5A800000,
	0x56800000,
	0x55800000,
	0x55400000,
	0xAAA00000,
	0x6AA00000,
	0x5AA00000,
	0x56A00000,
	0x55A00000,
	0x55600000,
	0x55500000,
	0xAAA80000,
	0x6AA80000,
	0x5AA80000,
	0x56A80000,
	0x55A80000,
	0x55680000,
	0x55580000,
	0x55540000,
	0xAAAA0000,
	0x6AAA0000,
	0x5AAA0000,
	0x56AA0000,
	0x55AA0000,
	0x556A0000,
	0x555A0000,
	0x55560000,
	0x55550000,
	0xAAAA8000,
	0x6AAA8000,
	0x5AAA8000,
	0x56AA8000,
	0x55AA8000,
	0x556A8000,
	0x555A8000,
	0x55568000,
	0x55558000,
	0x55554000,
	0xAAAAA000,
	0x6AAAA000,
	0x5AAAA000,
	0x56AAA000,
	0x55AAA000,
	0x556AA000,
	0x555AA000,
	0x5556A000,
	0x5555A000,
	0x55556000,
	0x55555000,
	0xAAAAA800,
	0x6AAAA800,
	0x5AAAA800,
	0x56AAA800,
	0x55AAA800,
	0x556AA800,
	0x555AA800,
	0x5556A800,
	0x5555A800,
	0x55556800,
	0x55555800,
	0x55555400,
	0xAAAAAA00,
	0x6AAAAA00,
	0x5AAAAA00,
	0x56AAAA00,
	0x55AAAA00,
	0x556AAA00,
	0x555AAA00,
	0x5556AA00,
	0x5555AA00,
	0x55556A00,
	0x55555A00,
	0x55555600,
	0x55555500,
	0xAAAAAA80,
	0x6AAAAA80,
	0x5AAAAA80,
	0x56AAAA80,
	0x55AAAA80,
	0x556AAA80,
	0x555AAA80,
	0x5556AA80,
	0x5555AA80,
	0x55556A80,
	0x55555A80,
	0x55555680,
	0x55555580,
	0x55555540,
	0xAAAAAAA0,
	0x6AAAAAA0,
	0x5AAAAAA0,
	0x56AAAAA0,
	0x55AAAAA0,
	0x556AAAA0,
	0x555AAAA0,
	0x5556AAA0,
	0x5555AAA0,
	0x55556AA0,
	0x55555AA0,
	0x555556A0,
	0x555555A0,
	0x55555560,
	0x55555550,
	0xAAAAAAA8,
	0x6AAAAAA8,
	0x5AAAAAA8,
	0x56AAAAA8,
	0x55AAAAA8,
	0x556AAAA8,
	0x555AAAA8,
	0x5556AAA8,
	0x5555AAA8,
	0x55556AA8,
	0x55555AA8,
	0x555556A8,
	0x555555A8,
	0x55555568,
	0x55555558,
	0x55555554,
	0x6AAAAAAA,
	0x5AAAAAAA,
	0x56AAAAAA,
	0x55AAAAAA,
	0x556AAAAA,
	0x555AAAAA,
	0x5556AAAA,
	0x5555AAAA,
	0x55556AAA,
	0x55555AAA,
	0x555556AA,
	0x555555AA,
	0x5555556A,
	0x5555555A,
	0x55555556,
	0x55555555,
	0x55555555,
	0x55555555,
	0x55555555,
	0x55555555,
	0x55555555,
	0x55555555,
	0x55555555,
	0x55555555,
	0x55555555,
	0xC0000000,
	0xE0000000,
	0xF0000000,
	0x70000000,
	0xE8000000,
	0xF8000000,
	0x78000000,
	0xFC000000,
	0x7C000000,
	0x5C000000,
	0xEA000000,
	0xFA000000,
	0x7A000000,
	0xFE000000,
	0x7E000000,
	0x5E000000,
	0xFF000000,
	0x7F000000,
	0x5F000000,
	0x57000000,
	0xEA800000,
	0xFA800000,
	0x7A800000,
	0xFE800000,
	0x7E800000,
	0x5E800000,
	0xFF800000,
	0x7F800000,
	0x5F800000,
	0x57800000,
	0xFFC00000,
	0x7FC00000,
	0x5FC00000,
	0x57C00000,
	0x55C00000,
	0xEAA00000,
	0xFAA00000,
	0x7AA00000,
	0xFEA00000,
	0x7EA00000,
	0x5EA00000,
	0xFFA00000,
	0x7FA00000,
	0x5FA00000,
	0x57A00000,
	0xFFE00000,
	0x7FE00000,
	0x5FE00000,
	0x57E00000,
	0x55E00000,
	0xFFF00000,
	0x7FF00000,
	0x5FF00000,
	0x57F00000,
	0x55F00000,
	0x55700000,
	0xEAA80000,
	0xFAA80000,
	0x7AA80000,
	0xFEA80000,
	0x7EA80000,
	0x5EA80000,
	0xFFA80000,
	0x7FA80000,
	0x5FA80000,
	0x57A80000,
	0xFFE80000,
	0x7FE80000,
	0x5FE80000,
	0x57E80000,
	0x55E80000,
	0xFFF80000,
	0x7FF80000,
	0x5FF80000,
	0x57F80000,
	0x55F80000,
	0x55780000,
	0xFFFC0000,
	0x7FFC0000,
	0x5FFC0000,
	0x57FC0000,
	0x55FC0000,
	0x557C0000,
	0x555C0000,
	0xEAAA0000,
	0xFAAA0000,
	0x7AAA0000,
	0xFEAA0000,
	0x7EAA0000,
	0x5EAA0000,
	0xFFAA0000,
	0x7FAA0000,
	0x5FAA0000,
	0x57AA0000,
	0xFFEA0000,
	0x7FEA0000,
	0x5FEA0000,
	0x57EA0000,
	0x55EA0000,
	0xFFFA0000,
	0x7FFA0000,
	0x5FFA0000,
	0x57FA0000,
	0x55FA0000,
	0x557A0000,
	0xFFFE0000,
	0x7FFE0000,
	0x5FFE0000,
	0x57FE0000,
	0x55FE0000,
	0x557E0000,
	0x555E0000,
	0xFFFF0000,
	0x7FFF0000,
	0x5FFF0000,
	0x57FF0000,
	0x55FF0000,
	0x557F0000,
	0x555F0000,
	0x55570000,
	0xEAAA8000,
	0xFAAA8000,
	0x7AAA8000,
	0xFEAA8000,
	0x7EAA8000,
	0x5EAA8000,
	0xFFAA8000,
	0x7FAA8000,
	0x5FAA8000,
	0x57AA8000,
	0xFFEA8000,
	0x7FEA8000,
	0x5FEA8000,
	0x57EA8000,
	0x55EA8000,
	0xFFFA8000,
	0x7FFA8000,
	0x5FFA8000,
	0x57FA8000,
	0x55FA8000,
	0x557A8000,
	0xFFFE8000,
	0x7FFE8000,
	0x5FFE8000,
	0x57FE8000,
	0x55FE8000,
	0x557E8000,
	0x555E8000,
	0xFFFF8000,
	0x7FFF8000,
	0x5FFF8000,
	0x57FF8000,
	0x55FF8000,
	0x557F8000,
	0x555F8000,
	0x55578000,
	0xFFFFC000,
	0x7FFFC000,
	0x5FFFC000,
	0x57FFC000,
	0x55FFC000,
	0x557FC000,
	0x555FC000,
	0x5557C000,
	0x5555C000,
	0xEAAAA000,
	0xFAAAA000,
	0x7AAAA000,
	0xFEAAA000,
	0x7EAAA000,
	0x5EAAA000,
	0xFFAAA000,
	0x7FAAA000,
	0x5FAAA000,
	0x57AAA000,
	0xFFEAA000,
	0x7FEAA000,
	0x5FEAA000,
	0x57EAA000,
	0x55EAA000,
	0xFFFAA000,
	0x7FFAA000,
	0x5FFAA000,
	0x57FAA000,
	0x55FAA000,
	0x557AA000,
	0xFFFEA000,
	0x7FFEA000,
	0x5FFEA000,
	0x57FEA000,
	0x55FEA000,
	0x557EA000,
	0x555EA000,
	0xFFFFA000,
	0x7FFFA000,
	0x5FFFA000,
	0x57FFA000,
	0x55FFA000,
	0x557FA000,
	0x555FA000,
	0x5557A000,
	0xFFFFE000,
	0x7FFFE000,
	0x5FFFE000,
	0x57FFE000,
	0x55FFE000,
	0x557FE000,
	0x555FE000,
	0x5557E000,
	0x5555E000,
	0xFFFFF000,
	0x7FFFF000,
	0x5FFFF000,
	0x57FFF000,
	0x55FFF000,
	0x557FF000,
	0x555FF000,
	0x5557F000,
	0x5555F000,
	0x55557000,
	0xEAAAA800,
	0xFAAAA800,
	0x7AAAA800,
	0xFEAAA800,
	0x7EAAA800,
	0x5EAAA800,
	0xFFAAA800,
	0x7FAAA800,
	0x5FAAA800,
	0x57AAA800,
	0xFFEAA800,
	0x7FEAA800,
	0x5FEAA800,
	0x57EAA800,
	0x55EAA800,
	0xFFFAA800,
	0x7FFAA800,
	0x5FFAA800,
	0x57FAA800,
	0x55FAA800,
	0x557AA800,
	0xFFFEA800,
	0x7FFEA800,
	0x5FFEA800,
	0x57FEA800,
	0x55FEA800,
	0x557EA800,
	0x555EA800,
	0xFFFFA800,
	0x7FFFA800,
	0x5FFFA800,
	0x57FFA800,
	0x55FFA800,
	0x557FA800,
	0x555FA800,
	0x5557A800,
	0xFFFFE800,
	0x7FFFE800,
	0x5FFFE800,
	0x57FFE800,
	0x55FFE800,
	0x557FE800,
	0x555FE800,
	0x5557E800,
	0x5555E800,
	0xFFFFF800,
	0x7FFFF800,
	0x5FFFF800,
	0x57FFF800,
	0x55FFF800,
	0x557FF800,
	0x555FF800,
	0x5557F800,
	0x5555F800,
	0x55557800,
	0xFFFFFC00,
	0x7FFFFC00,
	0x5FFFFC00,
	0x57FFFC00,
	0x55FFFC00,
	0x557FFC00,
	0x555FFC00,
	0x5557FC00,
	0x5555FC00,
	0x55557C00,
	0x55555C00,
	0xEAAAAA00,
	0xFAAAAA00,
	0x7AAAAA00,
	0xFEAAAA00,
	0x7EAAAA00,
	0x5EAAAA00,
	0xFFAAAA00,
	0x7FAAAA00,
	0x5FAAAA00,
	0x57AAAA00,
	0xFFEAAA00,
	0x7FEAAA00,
	0x5FEAAA00,
	0x57EAAA00,
	0x55EAAA00,
	0xFFFAAA00,
	0x7FFAAA00,
	0x5FFAAA00,
	0x57FAAA00,
	0x55FAAA00,
	0x557AAA00,
	0xFFFEAA00,
	0x7FFEAA00,
	0x5FFEAA00,
	0x57FEAA00,
	0x55FEAA00,
	0x557EAA00,
	0x555EAA00,
	0xFFFFAA00,
	0x7FFFAA00,
	0x5FFFAA00,
	0x57FFAA00,
	0x55FFAA00,
	0x557FAA00,
	0x555FAA00,
	0x5557AA00,
	0xFFFFEA00,
	0x7FFFEA00,
	0x5FFFEA00,
	0x57FFEA00,
	0x55FFEA00,
	0x557FEA00,
	0x555FEA00,
	0x5557EA00,
	0x5555EA00,
	0xFFFFFA00,
	0x7FFFFA00,
	0x5FFFFA00,
	0x57FFFA00,
	0x55FFFA00,
	0x557FFA00,
	0x555FFA00,
	0x5557FA00,
	0x5555FA00,
	0x55557A00,
	0xFFFFFE00,
	0x7FFFFE00,
	0x5FFFFE00,
	0x57FFFE00,
	0x55FFFE00,
	0x557FFE00,
	0x555FFE00,
	0x5557FE00,
	0x5555FE00,
	0x55557E00,
	0x55555E00,
	0xFFFFFF00,
	0x7FFFFF00,
	0x5FFFFF00,
	0x57FFFF00,
	0x55FFFF00,
	0x557FFF00,
	0x555FFF00,
	0x5557FF00,
	0x5555FF00,
	0x55557F00,
	0x55555F00,
	0x55555700,
	0xEAAAAA80,
	0xFAAAAA80,
	0x7AAAAA80,
	0xFEAAAA80,
	0x7EAAAA80,
	0x5EAAAA80,
	0xFFAAAA80,
	0x7FAAAA80,
	0x5FAAAA80,
	0x57AAAA80,
	0xFFEAAA80,
	0x7FEAAA80,
	0x5FEAAA80,
	0x57EAAA80,
	0x55EAAA80,
	0xFFFAAA80,
	0x7FFAAA80,
	0x5FFAAA80,
	0x57FAAA80,
	0x55FAAA80,
	0x557AAA80,
	0xFFFEAA80,
	0x7FFEAA80,
	0x5FFEAA80,
	0x57FEAA80,
	0x55FEAA80,
	0x557EAA80,
	0x555EAA80,
	0xFFFFAA80,
	0x7FFFAA80,
	0x5FFFAA80,
	0x57FFAA80,
	0x55FFAA80,
	0x557FAA80,
	0x555FAA80,
	0x5557AA80,
	0xFFFFEA80,
	0x7FFFEA80,
	0x5FFFEA80,
	0x57FFEA80,
	0x55FFEA80,
	0x557FEA80,
	0x555FEA80,
	0x5557EA80,
	0x5555EA80,
	0xFFFFFA80,
	0x7FFFFA80,
	0x5FFFFA80,
	0x57FFFA80,
	0x55FFFA80,
	0x557FFA80,
	0x555FFA80,
	0x5557FA80,
	0x5555FA80,
	0x55557A80,
	0xFFFFFE80,
	0x7FFFFE80,
	0x5FFFFE80,
	0x57FFFE80,
	0x55FFFE80,
	0x557FFE80,
	0x555FFE80,
	0x5557FE80,
	0x5555FE80,
	0x55557E80,
	0x55555E80,
	0xFFFFFF80,
	0x7FFFFF80,
	0x5FFFFF80,
	0x57FFFF80,
	0x55FFFF80,
	0x557FFF80,
	0x555FFF80,
	0x5557FF80,
	0x5555FF80,
	0x55557F80,
	0x55555F80,
	0x55555780,
	0xFFFFFFC0,
	0x7FFFFFC0,
	0x5FFFFFC0,
	0x57FFFFC0,
	0x55FFFFC0,
	0x557FFFC0,
	0x555FFFC0,
	0x5557FFC0,
	0x5555FFC0,
	0x55557FC0,
	0x55555FC0,
	0x555557C0,
	0x555555C0,
	0xEAAAAAA0,
	0xFAAAAAA0,
	0x7AAAAAA0,
	0xFEAAAAA0,
	0x7EAAAAA0,
	0x5EAAAAA0,
	0xFFAAAAA0,
	0x7FAAAAA0,
	0x5FAAAAA0,
	0x57AAAAA0,
	0xFFEAAAA0,
	0x7FEAAAA0,
	0x5FEAAAA0,
	0x57EAAAA0,
	0x55EAAAA0,
	0xFFFAAAA0,
	0x7FFAAAA0,
	0x5FFAAAA0,
	0x57FAAAA0,
	0x55FAAAA0,
	0x557AAAA0,
	0xFFFEAAA0,
	0x7FFEAAA0,
	0x5FFEAAA0,
	0x57FEAAA0,
	0x55FEAAA0,
	0x557EAAA0,
	0x555EAAA0,
	0xFFFFAAA0,
	0x7FFFAAA0,
	0x5FFFAAA0,
	0x57FFAAA0,
	0x55FFAAA0,
	0x557FAAA0,
	0x555FAAA0,
	0x5557AAA0,
	0xFFFFEAA0,
	0x7FFFEAA0,
	0x5FFFEAA0,
	0x57FFEAA0,
	0x55FFEAA0,
	0x557FEAA0,
	0x555FEAA0,
	0x5557EAA0,
	0x5555EAA0,
	0xFFFFFAA0,
	0x7FFFFAA0,
	0x5FFFFAA0,
	0x57FFFAA0,
	0x55FFFAA0,
	0x557FFAA0,
	0x555FFAA0,
	0x5557FAA0,
	0x5555FAA0,
	0x55557AA0,
	0xFFFFFEA0,
	0x7FFFFEA0,
	0x5FFFFEA0,
	0x57FFFEA0,
	0x55FFFEA0,
	0x557FFEA0,
	0x555FFEA0,
	0x5557FEA0,
	0x5555FEA0,
	0x55557EA0,
	0x55555EA0,
	0xFFFFFFA0,
	0x7FFFFFA0,
	0x5FFFFFA0,
	0x57FFFFA0,
	0x55FFFFA0,
	0x557FFFA0,
	0x555FFFA0,
	0x5557FFA0,
	0x5555FFA0,
	0x55557FA0,
	0x55555FA0,
	0x555557A0,
	0xFFFFFFE0,
	0x7FFFFFE0,
	0x5FFFFFE0,
	0x57FFFFE0,
	0x55FFFFE0,
	0x557FFFE0,
	0x555FFFE0,
	0x5557FFE0,
	0x5555FFE0,
	0x55557FE0,
	0x55555FE0,
	0x555557E0,
	0x555555E0,
	0xFFFFFFF0,
	0x7FFFFFF0,
	0x5FFFFFF0,
	0x57FFFFF0,
	0x55FFFFF0,
	0x557FFFF0,
	0x555FFFF0,
	0x5557FFF0,
	0x5555FFF0,
	0x55557FF0,
	0x55555FF0,
	0x555557F0,
	0x555555F0,
	0x55555570,
	0xEAAAAAA8,
	0xFAAAAAA8,
	0x7AAAAAA8,
	0xFEAAAAA8,
	0x7EAAAAA8,
	0x5EAAAAA8,
	0xFFAAAAA8,
	0x7FAAAAA8,
	0x5FAAAAA8,
	0x57AAAAA8,
	0xFFEAAAA8,
	0x7FEAAAA8,
	0x5FEAAAA8,
	0x57EAAAA8,
	0x55EAAAA8,
	0xFFFAAAA8,
	0x7FFAAAA8,
	0x5FFAAAA8,
	0x57FAAAA8,
	0x55FAAAA8,
	0x557AAAA8,
	0xFFFEAAA8,
	0x7FFEAAA8,
	0x5FFEAAA8,
	0x57FEAAA8,
	0x55FEAAA8,
	0x557EAAA8,
	0x555EAAA8,
	0xFFFFAAA8,
	0x7FFFAAA8,
	0x5FFFAAA8,
	0x57FFAAA8,
	0x55FFAAA8,
	0x557FAAA8,
	0x555FAAA8,
	0x5557AAA8,
	0xFFFFEAA8,
	0x7FFFEAA8,
	0x5FFFEAA8,
	0x57FFEAA8,
	0x55FFEAA8,
	0x557FEAA8,
	0x555FEAA8,
	0x5557EAA8,
	0x5555EAA8,
	0xFFFFFAA8,
	0x7FFFFAA8,
	0x5FFFFAA8,
	0x57FFFAA8,
	0x55FFFAA8,
	0x557FFAA8,
	0x555FFAA8,
	0x5557FAA8,
	0x5555FAA8,
	0x55557AA8,
	0xFFFFFEA8,
	0x7FFFFEA8,
	0x5FFFFEA8,
	0x57FFFEA8,
	0x55FFFEA8,
	0x557FFEA8,
	0x555FFEA8,
	0x5557FEA8,
	0x5555FEA8,
	0x55557EA8,
	0x55555EA8,
	0xFFFFFFA8,
	0x7FFFFFA8,
	0x5FFFFFA8,
	0x57FFFFA8,
	0x55FFFFA8,
	0x557FFFA8,
	0x555FFFA8,
	0x5557FFA8,
	0x5555FFA8,
	0x55557FA8,
	0x55555FA8,
	0x555557A8,
	0xFFFFFFE8,
	0x7FFFFFE8,
	0x5FFFFFE8,
	0x57FFFFE8,
	0x55FFFFE8,
	0x557FFFE8,
	0x555FFFE8,
	0x5557FFE8,
	0x5555FFE8,
	0x55557FE8,
	0x55555FE8,
	0x555557E8,
	0x555555E8,
	0xFFFFFFF8,
	0x7FFFFFF8,
	0x5FFFFFF8,
	0x57FFFFF8,
	0x55FFFFF8,
	0x557FFFF8,
	0x555FFFF8,
	0x5557FFF8,
	0x5555FFF8,
	0x55557FF8,
	0x55555FF8,
	0x555557F8,
	0x555555F8,
	0x55555578,
	0xFFFFFFFC,
	0x7FFFFFFC,
	0x5FFFFFFC,
	0x57FFFFFC,
	0x55FFFFFC,
	0x557FFFFC,
	0x555FFFFC,
	0x5557FFFC,
	0x5555FFFC,
	0x55557FFC,
	0x55555FFC,
	0x555557FC,
	0x555555FC,
	0x5555557C,
	0x5555555C,
	0xEAAAAAAA,
	0xFAAAAAAA,
	0x7AAAAAAA,
	0xFEAAAAAA,
	0x7EAAAAAA,
	0x5EAAAAAA,
	0xFFAAAAAA,
	0x7FAAAAAA,
	0x5FAAAAAA,
	0x57AAAAAA,
	0xFFEAAAAA,
	0x7FEAAAAA,
	0x5FEAAAAA,
	0x57EAAAAA,
	0x55EAAAAA,
	0xFFFAAAAA,
	0x7FFAAAAA,
	0x5FFAAAAA,
	0x57FAAAAA,
	0x55FAAAAA,
	0x557AAAAA,
	0xFFFEAAAA,
	0x7FFEAAAA,
	0x5FFEAAAA,
	0x57FEAAAA,
	0x55FEAAAA,
	0x557EAAAA,
	0x555EAAAA,
	0xFFFFAAAA,
	0x7FFFAAAA,
	0x5FFFAAAA,
	0x57FFAAAA,
	0x55FFAAAA,
	0x557FAAAA,
	0x555FAAAA,
	0x5557AAAA,
	0xFFFFEAAA,
	0x7FFFEAAA,
	0x5FFFEAAA,
	0x57FFEAAA,
	0x55FFEAAA,
	0x557FEAAA,
	0x555FEAAA,
	0x5557EAAA,
	0x5555EAAA,
	0xFFFFFAAA,
	0x7FFFFAAA,
	0x5FFFFAAA,
	0x57FFFAAA,
	0x55FFFAAA,
	0x557FFAAA,
	0x555FFAAA,
	0x5557FAAA,
	0x5555FAAA,
	0x55557AAA,
	0xFFFFFEAA,
	0x7FFFFEAA,
	0x5FFFFEAA,
	0x57FFFEAA,
	0x55FFFEAA,
	0x557FFEAA,
	0x555FFEAA,
	0x5557FEAA,
	0x5555FEAA,
	0x55557EAA,
	0x55555EAA,
	0xFFFFFFAA,
	0x7FFFFFAA,
	0x5FFFFFAA,
	0x57FFFFAA,
	0x55FFFFAA,
	0x557FFFAA,
	0x555FFFAA,
	0x5557FFAA,
	0x5555FFAA,
	0x55557FAA,
	0x55555FAA,
	0x555557AA,
	0xFFFFFFEA,
	0x7FFFFFEA,
	0x5FFFFFEA,
	0x57FFFFEA,
	0x55FFFFEA,
	0x557FFFEA,
	0x555FFFEA,
	0x5557FFEA,
	0x5555FFEA,
	0x55557FEA,
	0x55555FEA,
	0x555557EA,
	0x555555EA,
	0xFFFFFFFA,
	0x7FFFFFFA,
	0x5FFFFFFA,
	0x57FFFFFA,
	0x55FFFFFA,
	0x557FFFFA,
	0x555FFFFA,
	0x5557FFFA,
	0x5555FFFA,
	0x55557FFA,
	0x55555FFA,
	0x555557FA,
	0x555555FA,
	0x5555557A,
	0xFFFFFFFE,
	0x7FFFFFFE,
	0x5FFFFFFE,
	0x57FFFFFE,
	0x55FFFFFE,
	0x557FFFFE,
	0x555FFFFE,
	0x5557FFFE,
	0x5555FFFE,
	0x55557FFE,
	0x55555FFE,
	0x555557FE,
	0x555555FE,
	0x5555557E,
	0x5555555E,
	0x7FFFFFFF,
	0x5FFFFFFF,
	0x57FFFFFF,
	0x55FFFFFF,
	0x557FFFFF,
	0x555FFFFF,
	0x5557FFFF,
	0x5555FFFF,
	0x55557FFF,
	0x55555FFF,
	0x555557FF,
	0x555555FF,
	0x5555557F,
	0x5555555F,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
	0x55555557,
 	0x55555557,
};


/*
void precomp()
{
	unsigned int bitmaps[1024];

	int num = 0;

	printf("const static uint s_bitmapTableCTX[704] =\n{\n");

	for (int a = 1; a <= 15; a++)
	{
		  for (int b = a; b <= 15; b++)
		  {
				for (int c = b; c <= 15; c++)
				{
					int indices[16];

					int i = 0;
					for(; i < a; i++) {
						indices[i] = 0;
					}
					for(; i < a+b; i++) {
						indices[i] = 2;
					}
					for(; i < a+b+c; i++) {
						indices[i] = 3;
					}
					for(; i < 16; i++) {
						indices[i] = 1;
					}

					unsigned int bm = 0;
					for(i = 0; i < 16; i++) {
						bm |= indices[i] << (i * 2);
					}

					printf("\t0x%8X, // %d %d %d %d\n", bm, a-0, b-a, c-b, 16-c);

					bitmaps[num] = bm;
					num++;
				}
		  }
	}

	// Align to 32: 680 -> 704
	while (num < 704)
	{
		printf("\t0x80000000,\n");

		bitmaps[num] = 0x80000000; // 15 0 0 1;
		num++;
	}

	printf("}; // num = %d\n", num);
}
*/

const static uint s_bitmapTableCTX[704] =
{
	0x55555578, // 1 0 0 15
	0x555555F8, // 1 0 1 14
	0x555557F8, // 1 0 2 13
	0x55555FF8, // 1 0 3 12
	0x55557FF8, // 1 0 4 11
	0x5555FFF8, // 1 0 5 10
	0x5557FFF8, // 1 0 6 9
	0x555FFFF8, // 1 0 7 8
	0x557FFFF8, // 1 0 8 7
	0x55FFFFF8, // 1 0 9 6
	0x57FFFFF8, // 1 0 10 5
	0x5FFFFFF8, // 1 0 11 4
	0x7FFFFFF8, // 1 0 12 3
	0xFFFFFFF8, // 1 0 13 2
	0xFFFFFFF8, // 1 0 14 1
	0x555557E8, // 1 1 0 14
	0x55555FE8, // 1 1 1 13
	0x55557FE8, // 1 1 2 12
	0x5555FFE8, // 1 1 3 11
	0x5557FFE8, // 1 1 4 10
	0x555FFFE8, // 1 1 5 9
	0x557FFFE8, // 1 1 6 8
	0x55FFFFE8, // 1 1 7 7
	0x57FFFFE8, // 1 1 8 6
	0x5FFFFFE8, // 1 1 9 5
	0x7FFFFFE8, // 1 1 10 4
	0xFFFFFFE8, // 1 1 11 3
	0xFFFFFFE8, // 1 1 12 2
	0xFFFFFFE8, // 1 1 13 1
	0x55557FA8, // 1 2 0 13
	0x5555FFA8, // 1 2 1 12
	0x5557FFA8, // 1 2 2 11
	0x555FFFA8, // 1 2 3 10
	0x557FFFA8, // 1 2 4 9
	0x55FFFFA8, // 1 2 5 8
	0x57FFFFA8, // 1 2 6 7
	0x5FFFFFA8, // 1 2 7 6
	0x7FFFFFA8, // 1 2 8 5
	0xFFFFFFA8, // 1 2 9 4
	0xFFFFFFA8, // 1 2 10 3
	0xFFFFFFA8, // 1 2 11 2
	0xFFFFFFA8, // 1 2 12 1
	0x5557FEA8, // 1 3 0 12
	0x555FFEA8, // 1 3 1 11
	0x557FFEA8, // 1 3 2 10
	0x55FFFEA8, // 1 3 3 9
	0x57FFFEA8, // 1 3 4 8
	0x5FFFFEA8, // 1 3 5 7
	0x7FFFFEA8, // 1 3 6 6
	0xFFFFFEA8, // 1 3 7 5
	0xFFFFFEA8, // 1 3 8 4
	0xFFFFFEA8, // 1 3 9 3
	0xFFFFFEA8, // 1 3 10 2
	0xFFFFFEA8, // 1 3 11 1
	0x557FFAA8, // 1 4 0 11
	0x55FFFAA8, // 1 4 1 10
	0x57FFFAA8, // 1 4 2 9
	0x5FFFFAA8, // 1 4 3 8
	0x7FFFFAA8, // 1 4 4 7
	0xFFFFFAA8, // 1 4 5 6
	0xFFFFFAA8, // 1 4 6 5
	0xFFFFFAA8, // 1 4 7 4
	0xFFFFFAA8, // 1 4 8 3
	0xFFFFFAA8, // 1 4 9 2
	0xFFFFFAA8, // 1 4 10 1
	0x57FFEAA8, // 1 5 0 10
	0x5FFFEAA8, // 1 5 1 9
	0x7FFFEAA8, // 1 5 2 8
	0xFFFFEAA8, // 1 5 3 7
	0xFFFFEAA8, // 1 5 4 6
	0xFFFFEAA8, // 1 5 5 5
	0xFFFFEAA8, // 1 5 6 4
	0xFFFFEAA8, // 1 5 7 3
	0xFFFFEAA8, // 1 5 8 2
	0xFFFFEAA8, // 1 5 9 1
	0x7FFFAAA8, // 1 6 0 9
	0xFFFFAAA8, // 1 6 1 8
	0xFFFFAAA8, // 1 6 2 7
	0xFFFFAAA8, // 1 6 3 6
	0xFFFFAAA8, // 1 6 4 5
	0xFFFFAAA8, // 1 6 5 4
	0xFFFFAAA8, // 1 6 6 3
	0xFFFFAAA8, // 1 6 7 2
	0xFFFFAAA8, // 1 6 8 1
	0xFFFEAAA8, // 1 7 0 8
	0xFFFEAAA8, // 1 7 1 7
	0xFFFEAAA8, // 1 7 2 6
	0xFFFEAAA8, // 1 7 3 5
	0xFFFEAAA8, // 1 7 4 4
	0xFFFEAAA8, // 1 7 5 3
	0xFFFEAAA8, // 1 7 6 2
	0xFFFEAAA8, // 1 7 7 1
	0xFFFAAAA8, // 1 8 0 7
	0xFFFAAAA8, // 1 8 1 6
	0xFFFAAAA8, // 1 8 2 5
	0xFFFAAAA8, // 1 8 3 4
	0xFFFAAAA8, // 1 8 4 3
	0xFFFAAAA8, // 1 8 5 2
	0xFFFAAAA8, // 1 8 6 1
	0xFFEAAAA8, // 1 9 0 6
	0xFFEAAAA8, // 1 9 1 5
	0xFFEAAAA8, // 1 9 2 4
	0xFFEAAAA8, // 1 9 3 3
	0xFFEAAAA8, // 1 9 4 2
	0xFFEAAAA8, // 1 9 5 1
	0xFFAAAAA8, // 1 10 0 5
	0xFFAAAAA8, // 1 10 1 4
	0xFFAAAAA8, // 1 10 2 3
	0xFFAAAAA8, // 1 10 3 2
	0xFFAAAAA8, // 1 10 4 1
	0xFEAAAAA8, // 1 11 0 4
	0xFEAAAAA8, // 1 11 1 3
	0xFEAAAAA8, // 1 11 2 2
	0xFEAAAAA8, // 1 11 3 1
	0xFAAAAAA8, // 1 12 0 3
	0xFAAAAAA8, // 1 12 1 2
	0xFAAAAAA8, // 1 12 2 1
	0xEAAAAAA8, // 1 13 0 2
	0xEAAAAAA8, // 1 13 1 1
	0xAAAAAAA8, // 1 14 0 1
	0x55555FA0, // 2 0 0 14
	0x55557FA0, // 2 0 1 13
	0x5555FFA0, // 2 0 2 12
	0x5557FFA0, // 2 0 3 11
	0x555FFFA0, // 2 0 4 10
	0x557FFFA0, // 2 0 5 9
	0x55FFFFA0, // 2 0 6 8
	0x57FFFFA0, // 2 0 7 7
	0x5FFFFFA0, // 2 0 8 6
	0x7FFFFFA0, // 2 0 9 5
	0xFFFFFFA0, // 2 0 10 4
	0xFFFFFFA0, // 2 0 11 3
	0xFFFFFFA0, // 2 0 12 2
	0xFFFFFFA0, // 2 0 13 1
	0x5555FEA0, // 2 1 0 13
	0x5557FEA0, // 2 1 1 12
	0x555FFEA0, // 2 1 2 11
	0x557FFEA0, // 2 1 3 10
	0x55FFFEA0, // 2 1 4 9
	0x57FFFEA0, // 2 1 5 8
	0x5FFFFEA0, // 2 1 6 7
	0x7FFFFEA0, // 2 1 7 6
	0xFFFFFEA0, // 2 1 8 5
	0xFFFFFEA0, // 2 1 9 4
	0xFFFFFEA0, // 2 1 10 3
	0xFFFFFEA0, // 2 1 11 2
	0xFFFFFEA0, // 2 1 12 1
	0x555FFAA0, // 2 2 0 12
	0x557FFAA0, // 2 2 1 11
	0x55FFFAA0, // 2 2 2 10
	0x57FFFAA0, // 2 2 3 9
	0x5FFFFAA0, // 2 2 4 8
	0x7FFFFAA0, // 2 2 5 7
	0xFFFFFAA0, // 2 2 6 6
	0xFFFFFAA0, // 2 2 7 5
	0xFFFFFAA0, // 2 2 8 4
	0xFFFFFAA0, // 2 2 9 3
	0xFFFFFAA0, // 2 2 10 2
	0xFFFFFAA0, // 2 2 11 1
	0x55FFEAA0, // 2 3 0 11
	0x57FFEAA0, // 2 3 1 10
	0x5FFFEAA0, // 2 3 2 9
	0x7FFFEAA0, // 2 3 3 8
	0xFFFFEAA0, // 2 3 4 7
	0xFFFFEAA0, // 2 3 5 6
	0xFFFFEAA0, // 2 3 6 5
	0xFFFFEAA0, // 2 3 7 4
	0xFFFFEAA0, // 2 3 8 3
	0xFFFFEAA0, // 2 3 9 2
	0xFFFFEAA0, // 2 3 10 1
	0x5FFFAAA0, // 2 4 0 10
	0x7FFFAAA0, // 2 4 1 9
	0xFFFFAAA0, // 2 4 2 8
	0xFFFFAAA0, // 2 4 3 7
	0xFFFFAAA0, // 2 4 4 6
	0xFFFFAAA0, // 2 4 5 5
	0xFFFFAAA0, // 2 4 6 4
	0xFFFFAAA0, // 2 4 7 3
	0xFFFFAAA0, // 2 4 8 2
	0xFFFFAAA0, // 2 4 9 1
	0xFFFEAAA0, // 2 5 0 9
	0xFFFEAAA0, // 2 5 1 8
	0xFFFEAAA0, // 2 5 2 7
	0xFFFEAAA0, // 2 5 3 6
	0xFFFEAAA0, // 2 5 4 5
	0xFFFEAAA0, // 2 5 5 4
	0xFFFEAAA0, // 2 5 6 3
	0xFFFEAAA0, // 2 5 7 2
	0xFFFEAAA0, // 2 5 8 1
	0xFFFAAAA0, // 2 6 0 8
	0xFFFAAAA0, // 2 6 1 7
	0xFFFAAAA0, // 2 6 2 6
	0xFFFAAAA0, // 2 6 3 5
	0xFFFAAAA0, // 2 6 4 4
	0xFFFAAAA0, // 2 6 5 3
	0xFFFAAAA0, // 2 6 6 2
	0xFFFAAAA0, // 2 6 7 1
	0xFFEAAAA0, // 2 7 0 7
	0xFFEAAAA0, // 2 7 1 6
	0xFFEAAAA0, // 2 7 2 5
	0xFFEAAAA0, // 2 7 3 4
	0xFFEAAAA0, // 2 7 4 3
	0xFFEAAAA0, // 2 7 5 2
	0xFFEAAAA0, // 2 7 6 1
	0xFFAAAAA0, // 2 8 0 6
	0xFFAAAAA0, // 2 8 1 5
	0xFFAAAAA0, // 2 8 2 4
	0xFFAAAAA0, // 2 8 3 3
	0xFFAAAAA0, // 2 8 4 2
	0xFFAAAAA0, // 2 8 5 1
	0xFEAAAAA0, // 2 9 0 5
	0xFEAAAAA0, // 2 9 1 4
	0xFEAAAAA0, // 2 9 2 3
	0xFEAAAAA0, // 2 9 3 2
	0xFEAAAAA0, // 2 9 4 1
	0xFAAAAAA0, // 2 10 0 4
	0xFAAAAAA0, // 2 10 1 3
	0xFAAAAAA0, // 2 10 2 2
	0xFAAAAAA0, // 2 10 3 1
	0xEAAAAAA0, // 2 11 0 3
	0xEAAAAAA0, // 2 11 1 2
	0xEAAAAAA0, // 2 11 2 1
	0xAAAAAAA0, // 2 12 0 2
	0xAAAAAAA0, // 2 12 1 1
	0xAAAAAAA0, // 2 13 0 1
	0x5557FA80, // 3 0 0 13
	0x555FFA80, // 3 0 1 12
	0x557FFA80, // 3 0 2 11
	0x55FFFA80, // 3 0 3 10
	0x57FFFA80, // 3 0 4 9
	0x5FFFFA80, // 3 0 5 8
	0x7FFFFA80, // 3 0 6 7
	0xFFFFFA80, // 3 0 7 6
	0xFFFFFA80, // 3 0 8 5
	0xFFFFFA80, // 3 0 9 4
	0xFFFFFA80, // 3 0 10 3
	0xFFFFFA80, // 3 0 11 2
	0xFFFFFA80, // 3 0 12 1
	0x557FEA80, // 3 1 0 12
	0x55FFEA80, // 3 1 1 11
	0x57FFEA80, // 3 1 2 10
	0x5FFFEA80, // 3 1 3 9
	0x7FFFEA80, // 3 1 4 8
	0xFFFFEA80, // 3 1 5 7
	0xFFFFEA80, // 3 1 6 6
	0xFFFFEA80, // 3 1 7 5
	0xFFFFEA80, // 3 1 8 4
	0xFFFFEA80, // 3 1 9 3
	0xFFFFEA80, // 3 1 10 2
	0xFFFFEA80, // 3 1 11 1
	0x57FFAA80, // 3 2 0 11
	0x5FFFAA80, // 3 2 1 10
	0x7FFFAA80, // 3 2 2 9
	0xFFFFAA80, // 3 2 3 8
	0xFFFFAA80, // 3 2 4 7
	0xFFFFAA80, // 3 2 5 6
	0xFFFFAA80, // 3 2 6 5
	0xFFFFAA80, // 3 2 7 4
	0xFFFFAA80, // 3 2 8 3
	0xFFFFAA80, // 3 2 9 2
	0xFFFFAA80, // 3 2 10 1
	0x7FFEAA80, // 3 3 0 10
	0xFFFEAA80, // 3 3 1 9
	0xFFFEAA80, // 3 3 2 8
	0xFFFEAA80, // 3 3 3 7
	0xFFFEAA80, // 3 3 4 6
	0xFFFEAA80, // 3 3 5 5
	0xFFFEAA80, // 3 3 6 4
	0xFFFEAA80, // 3 3 7 3
	0xFFFEAA80, // 3 3 8 2
	0xFFFEAA80, // 3 3 9 1
	0xFFFAAA80, // 3 4 0 9
	0xFFFAAA80, // 3 4 1 8
	0xFFFAAA80, // 3 4 2 7
	0xFFFAAA80, // 3 4 3 6
	0xFFFAAA80, // 3 4 4 5
	0xFFFAAA80, // 3 4 5 4
	0xFFFAAA80, // 3 4 6 3
	0xFFFAAA80, // 3 4 7 2
	0xFFFAAA80, // 3 4 8 1
	0xFFEAAA80, // 3 5 0 8
	0xFFEAAA80, // 3 5 1 7
	0xFFEAAA80, // 3 5 2 6
	0xFFEAAA80, // 3 5 3 5
	0xFFEAAA80, // 3 5 4 4
	0xFFEAAA80, // 3 5 5 3
	0xFFEAAA80, // 3 5 6 2
	0xFFEAAA80, // 3 5 7 1
	0xFFAAAA80, // 3 6 0 7
	0xFFAAAA80, // 3 6 1 6
	0xFFAAAA80, // 3 6 2 5
	0xFFAAAA80, // 3 6 3 4
	0xFFAAAA80, // 3 6 4 3
	0xFFAAAA80, // 3 6 5 2
	0xFFAAAA80, // 3 6 6 1
	0xFEAAAA80, // 3 7 0 6
	0xFEAAAA80, // 3 7 1 5
	0xFEAAAA80, // 3 7 2 4
	0xFEAAAA80, // 3 7 3 3
	0xFEAAAA80, // 3 7 4 2
	0xFEAAAA80, // 3 7 5 1
	0xFAAAAA80, // 3 8 0 5
	0xFAAAAA80, // 3 8 1 4
	0xFAAAAA80, // 3 8 2 3
	0xFAAAAA80, // 3 8 3 2
	0xFAAAAA80, // 3 8 4 1
	0xEAAAAA80, // 3 9 0 4
	0xEAAAAA80, // 3 9 1 3
	0xEAAAAA80, // 3 9 2 2
	0xEAAAAA80, // 3 9 3 1
	0xAAAAAA80, // 3 10 0 3
	0xAAAAAA80, // 3 10 1 2
	0xAAAAAA80, // 3 10 2 1
	0xAAAAAA80, // 3 11 0 2
	0xAAAAAA80, // 3 11 1 1
	0xAAAAAA80, // 3 12 0 1
	0x55FFAA00, // 4 0 0 12
	0x57FFAA00, // 4 0 1 11
	0x5FFFAA00, // 4 0 2 10
	0x7FFFAA00, // 4 0 3 9
	0xFFFFAA00, // 4 0 4 8
	0xFFFFAA00, // 4 0 5 7
	0xFFFFAA00, // 4 0 6 6
	0xFFFFAA00, // 4 0 7 5
	0xFFFFAA00, // 4 0 8 4
	0xFFFFAA00, // 4 0 9 3
	0xFFFFAA00, // 4 0 10 2
	0xFFFFAA00, // 4 0 11 1
	0x5FFEAA00, // 4 1 0 11
	0x7FFEAA00, // 4 1 1 10
	0xFFFEAA00, // 4 1 2 9
	0xFFFEAA00, // 4 1 3 8
	0xFFFEAA00, // 4 1 4 7
	0xFFFEAA00, // 4 1 5 6
	0xFFFEAA00, // 4 1 6 5
	0xFFFEAA00, // 4 1 7 4
	0xFFFEAA00, // 4 1 8 3
	0xFFFEAA00, // 4 1 9 2
	0xFFFEAA00, // 4 1 10 1
	0xFFFAAA00, // 4 2 0 10
	0xFFFAAA00, // 4 2 1 9
	0xFFFAAA00, // 4 2 2 8
	0xFFFAAA00, // 4 2 3 7
	0xFFFAAA00, // 4 2 4 6
	0xFFFAAA00, // 4 2 5 5
	0xFFFAAA00, // 4 2 6 4
	0xFFFAAA00, // 4 2 7 3
	0xFFFAAA00, // 4 2 8 2
	0xFFFAAA00, // 4 2 9 1
	0xFFEAAA00, // 4 3 0 9
	0xFFEAAA00, // 4 3 1 8
	0xFFEAAA00, // 4 3 2 7
	0xFFEAAA00, // 4 3 3 6
	0xFFEAAA00, // 4 3 4 5
	0xFFEAAA00, // 4 3 5 4
	0xFFEAAA00, // 4 3 6 3
	0xFFEAAA00, // 4 3 7 2
	0xFFEAAA00, // 4 3 8 1
	0xFFAAAA00, // 4 4 0 8
	0xFFAAAA00, // 4 4 1 7
	0xFFAAAA00, // 4 4 2 6
	0xFFAAAA00, // 4 4 3 5
	0xFFAAAA00, // 4 4 4 4
	0xFFAAAA00, // 4 4 5 3
	0xFFAAAA00, // 4 4 6 2
	0xFFAAAA00, // 4 4 7 1
	0xFEAAAA00, // 4 5 0 7
	0xFEAAAA00, // 4 5 1 6
	0xFEAAAA00, // 4 5 2 5
	0xFEAAAA00, // 4 5 3 4
	0xFEAAAA00, // 4 5 4 3
	0xFEAAAA00, // 4 5 5 2
	0xFEAAAA00, // 4 5 6 1
	0xFAAAAA00, // 4 6 0 6
	0xFAAAAA00, // 4 6 1 5
	0xFAAAAA00, // 4 6 2 4
	0xFAAAAA00, // 4 6 3 3
	0xFAAAAA00, // 4 6 4 2
	0xFAAAAA00, // 4 6 5 1
	0xEAAAAA00, // 4 7 0 5
	0xEAAAAA00, // 4 7 1 4
	0xEAAAAA00, // 4 7 2 3
	0xEAAAAA00, // 4 7 3 2
	0xEAAAAA00, // 4 7 4 1
	0xAAAAAA00, // 4 8 0 4
	0xAAAAAA00, // 4 8 1 3
	0xAAAAAA00, // 4 8 2 2
	0xAAAAAA00, // 4 8 3 1
	0xAAAAAA00, // 4 9 0 3
	0xAAAAAA00, // 4 9 1 2
	0xAAAAAA00, // 4 9 2 1
	0xAAAAAA00, // 4 10 0 2
	0xAAAAAA00, // 4 10 1 1
	0xAAAAAA00, // 4 11 0 1
	0x7FFAA800, // 5 0 0 11
	0xFFFAA800, // 5 0 1 10
	0xFFFAA800, // 5 0 2 9
	0xFFFAA800, // 5 0 3 8
	0xFFFAA800, // 5 0 4 7
	0xFFFAA800, // 5 0 5 6
	0xFFFAA800, // 5 0 6 5
	0xFFFAA800, // 5 0 7 4
	0xFFFAA800, // 5 0 8 3
	0xFFFAA800, // 5 0 9 2
	0xFFFAA800, // 5 0 10 1
	0xFFEAA800, // 5 1 0 10
	0xFFEAA800, // 5 1 1 9
	0xFFEAA800, // 5 1 2 8
	0xFFEAA800, // 5 1 3 7
	0xFFEAA800, // 5 1 4 6
	0xFFEAA800, // 5 1 5 5
	0xFFEAA800, // 5 1 6 4
	0xFFEAA800, // 5 1 7 3
	0xFFEAA800, // 5 1 8 2
	0xFFEAA800, // 5 1 9 1
	0xFFAAA800, // 5 2 0 9
	0xFFAAA800, // 5 2 1 8
	0xFFAAA800, // 5 2 2 7
	0xFFAAA800, // 5 2 3 6
	0xFFAAA800, // 5 2 4 5
	0xFFAAA800, // 5 2 5 4
	0xFFAAA800, // 5 2 6 3
	0xFFAAA800, // 5 2 7 2
	0xFFAAA800, // 5 2 8 1
	0xFEAAA800, // 5 3 0 8
	0xFEAAA800, // 5 3 1 7
	0xFEAAA800, // 5 3 2 6
	0xFEAAA800, // 5 3 3 5
	0xFEAAA800, // 5 3 4 4
	0xFEAAA800, // 5 3 5 3
	0xFEAAA800, // 5 3 6 2
	0xFEAAA800, // 5 3 7 1
	0xFAAAA800, // 5 4 0 7
	0xFAAAA800, // 5 4 1 6
	0xFAAAA800, // 5 4 2 5
	0xFAAAA800, // 5 4 3 4
	0xFAAAA800, // 5 4 4 3
	0xFAAAA800, // 5 4 5 2
	0xFAAAA800, // 5 4 6 1
	0xEAAAA800, // 5 5 0 6
	0xEAAAA800, // 5 5 1 5
	0xEAAAA800, // 5 5 2 4
	0xEAAAA800, // 5 5 3 3
	0xEAAAA800, // 5 5 4 2
	0xEAAAA800, // 5 5 5 1
	0xAAAAA800, // 5 6 0 5
	0xAAAAA800, // 5 6 1 4
	0xAAAAA800, // 5 6 2 3
	0xAAAAA800, // 5 6 3 2
	0xAAAAA800, // 5 6 4 1
	0xAAAAA800, // 5 7 0 4
	0xAAAAA800, // 5 7 1 3
	0xAAAAA800, // 5 7 2 2
	0xAAAAA800, // 5 7 3 1
	0xAAAAA800, // 5 8 0 3
	0xAAAAA800, // 5 8 1 2
	0xAAAAA800, // 5 8 2 1
	0xAAAAA800, // 5 9 0 2
	0xAAAAA800, // 5 9 1 1
	0xAAAAA800, // 5 10 0 1
	0xFFAAA000, // 6 0 0 10
	0xFFAAA000, // 6 0 1 9
	0xFFAAA000, // 6 0 2 8
	0xFFAAA000, // 6 0 3 7
	0xFFAAA000, // 6 0 4 6
	0xFFAAA000, // 6 0 5 5
	0xFFAAA000, // 6 0 6 4
	0xFFAAA000, // 6 0 7 3
	0xFFAAA000, // 6 0 8 2
	0xFFAAA000, // 6 0 9 1
	0xFEAAA000, // 6 1 0 9
	0xFEAAA000, // 6 1 1 8
	0xFEAAA000, // 6 1 2 7
	0xFEAAA000, // 6 1 3 6
	0xFEAAA000, // 6 1 4 5
	0xFEAAA000, // 6 1 5 4
	0xFEAAA000, // 6 1 6 3
	0xFEAAA000, // 6 1 7 2
	0xFEAAA000, // 6 1 8 1
	0xFAAAA000, // 6 2 0 8
	0xFAAAA000, // 6 2 1 7
	0xFAAAA000, // 6 2 2 6
	0xFAAAA000, // 6 2 3 5
	0xFAAAA000, // 6 2 4 4
	0xFAAAA000, // 6 2 5 3
	0xFAAAA000, // 6 2 6 2
	0xFAAAA000, // 6 2 7 1
	0xEAAAA000, // 6 3 0 7
	0xEAAAA000, // 6 3 1 6
	0xEAAAA000, // 6 3 2 5
	0xEAAAA000, // 6 3 3 4
	0xEAAAA000, // 6 3 4 3
	0xEAAAA000, // 6 3 5 2
	0xEAAAA000, // 6 3 6 1
	0xAAAAA000, // 6 4 0 6
	0xAAAAA000, // 6 4 1 5
	0xAAAAA000, // 6 4 2 4
	0xAAAAA000, // 6 4 3 3
	0xAAAAA000, // 6 4 4 2
	0xAAAAA000, // 6 4 5 1
	0xAAAAA000, // 6 5 0 5
	0xAAAAA000, // 6 5 1 4
	0xAAAAA000, // 6 5 2 3
	0xAAAAA000, // 6 5 3 2
	0xAAAAA000, // 6 5 4 1
	0xAAAAA000, // 6 6 0 4
	0xAAAAA000, // 6 6 1 3
	0xAAAAA000, // 6 6 2 2
	0xAAAAA000, // 6 6 3 1
	0xAAAAA000, // 6 7 0 3
	0xAAAAA000, // 6 7 1 2
	0xAAAAA000, // 6 7 2 1
	0xAAAAA000, // 6 8 0 2
	0xAAAAA000, // 6 8 1 1
	0xAAAAA000, // 6 9 0 1
	0xFAAA8000, // 7 0 0 9
	0xFAAA8000, // 7 0 1 8
	0xFAAA8000, // 7 0 2 7
	0xFAAA8000, // 7 0 3 6
	0xFAAA8000, // 7 0 4 5
	0xFAAA8000, // 7 0 5 4
	0xFAAA8000, // 7 0 6 3
	0xFAAA8000, // 7 0 7 2
	0xFAAA8000, // 7 0 8 1
	0xEAAA8000, // 7 1 0 8
	0xEAAA8000, // 7 1 1 7
	0xEAAA8000, // 7 1 2 6
	0xEAAA8000, // 7 1 3 5
	0xEAAA8000, // 7 1 4 4
	0xEAAA8000, // 7 1 5 3
	0xEAAA8000, // 7 1 6 2
	0xEAAA8000, // 7 1 7 1
	0xAAAA8000, // 7 2 0 7
	0xAAAA8000, // 7 2 1 6
	0xAAAA8000, // 7 2 2 5
	0xAAAA8000, // 7 2 3 4
	0xAAAA8000, // 7 2 4 3
	0xAAAA8000, // 7 2 5 2
	0xAAAA8000, // 7 2 6 1
	0xAAAA8000, // 7 3 0 6
	0xAAAA8000, // 7 3 1 5
	0xAAAA8000, // 7 3 2 4
	0xAAAA8000, // 7 3 3 3
	0xAAAA8000, // 7 3 4 2
	0xAAAA8000, // 7 3 5 1
	0xAAAA8000, // 7 4 0 5
	0xAAAA8000, // 7 4 1 4
	0xAAAA8000, // 7 4 2 3
	0xAAAA8000, // 7 4 3 2
	0xAAAA8000, // 7 4 4 1
	0xAAAA8000, // 7 5 0 4
	0xAAAA8000, // 7 5 1 3
	0xAAAA8000, // 7 5 2 2
	0xAAAA8000, // 7 5 3 1
	0xAAAA8000, // 7 6 0 3
	0xAAAA8000, // 7 6 1 2
	0xAAAA8000, // 7 6 2 1
	0xAAAA8000, // 7 7 0 2
	0xAAAA8000, // 7 7 1 1
	0xAAAA8000, // 7 8 0 1
	0xAAAA0000, // 8 0 0 8
	0xAAAA0000, // 8 0 1 7
	0xAAAA0000, // 8 0 2 6
	0xAAAA0000, // 8 0 3 5
	0xAAAA0000, // 8 0 4 4
	0xAAAA0000, // 8 0 5 3
	0xAAAA0000, // 8 0 6 2
	0xAAAA0000, // 8 0 7 1
	0xAAAA0000, // 8 1 0 7
	0xAAAA0000, // 8 1 1 6
	0xAAAA0000, // 8 1 2 5
	0xAAAA0000, // 8 1 3 4
	0xAAAA0000, // 8 1 4 3
	0xAAAA0000, // 8 1 5 2
	0xAAAA0000, // 8 1 6 1
	0xAAAA0000, // 8 2 0 6
	0xAAAA0000, // 8 2 1 5
	0xAAAA0000, // 8 2 2 4
	0xAAAA0000, // 8 2 3 3
	0xAAAA0000, // 8 2 4 2
	0xAAAA0000, // 8 2 5 1
	0xAAAA0000, // 8 3 0 5
	0xAAAA0000, // 8 3 1 4
	0xAAAA0000, // 8 3 2 3
	0xAAAA0000, // 8 3 3 2
	0xAAAA0000, // 8 3 4 1
	0xAAAA0000, // 8 4 0 4
	0xAAAA0000, // 8 4 1 3
	0xAAAA0000, // 8 4 2 2
	0xAAAA0000, // 8 4 3 1
	0xAAAA0000, // 8 5 0 3
	0xAAAA0000, // 8 5 1 2
	0xAAAA0000, // 8 5 2 1
	0xAAAA0000, // 8 6 0 2
	0xAAAA0000, // 8 6 1 1
	0xAAAA0000, // 8 7 0 1
	0xAAA80000, // 9 0 0 7
	0xAAA80000, // 9 0 1 6
	0xAAA80000, // 9 0 2 5
	0xAAA80000, // 9 0 3 4
	0xAAA80000, // 9 0 4 3
	0xAAA80000, // 9 0 5 2
	0xAAA80000, // 9 0 6 1
	0xAAA80000, // 9 1 0 6
	0xAAA80000, // 9 1 1 5
	0xAAA80000, // 9 1 2 4
	0xAAA80000, // 9 1 3 3
	0xAAA80000, // 9 1 4 2
	0xAAA80000, // 9 1 5 1
	0xAAA80000, // 9 2 0 5
	0xAAA80000, // 9 2 1 4
	0xAAA80000, // 9 2 2 3
	0xAAA80000, // 9 2 3 2
	0xAAA80000, // 9 2 4 1
	0xAAA80000, // 9 3 0 4
	0xAAA80000, // 9 3 1 3
	0xAAA80000, // 9 3 2 2
	0xAAA80000, // 9 3 3 1
	0xAAA80000, // 9 4 0 3
	0xAAA80000, // 9 4 1 2
	0xAAA80000, // 9 4 2 1
	0xAAA80000, // 9 5 0 2
	0xAAA80000, // 9 5 1 1
	0xAAA80000, // 9 6 0 1
	0xAAA00000, // 10 0 0 6
	0xAAA00000, // 10 0 1 5
	0xAAA00000, // 10 0 2 4
	0xAAA00000, // 10 0 3 3
	0xAAA00000, // 10 0 4 2
	0xAAA00000, // 10 0 5 1
	0xAAA00000, // 10 1 0 5
	0xAAA00000, // 10 1 1 4
	0xAAA00000, // 10 1 2 3
	0xAAA00000, // 10 1 3 2
	0xAAA00000, // 10 1 4 1
	0xAAA00000, // 10 2 0 4
	0xAAA00000, // 10 2 1 3
	0xAAA00000, // 10 2 2 2
	0xAAA00000, // 10 2 3 1
	0xAAA00000, // 10 3 0 3
	0xAAA00000, // 10 3 1 2
	0xAAA00000, // 10 3 2 1
	0xAAA00000, // 10 4 0 2
	0xAAA00000, // 10 4 1 1
	0xAAA00000, // 10 5 0 1
	0xAA800000, // 11 0 0 5
	0xAA800000, // 11 0 1 4
	0xAA800000, // 11 0 2 3
	0xAA800000, // 11 0 3 2
	0xAA800000, // 11 0 4 1
	0xAA800000, // 11 1 0 4
	0xAA800000, // 11 1 1 3
	0xAA800000, // 11 1 2 2
	0xAA800000, // 11 1 3 1
	0xAA800000, // 11 2 0 3
	0xAA800000, // 11 2 1 2
	0xAA800000, // 11 2 2 1
	0xAA800000, // 11 3 0 2
	0xAA800000, // 11 3 1 1
	0xAA800000, // 11 4 0 1
	0xAA000000, // 12 0 0 4
	0xAA000000, // 12 0 1 3
	0xAA000000, // 12 0 2 2
	0xAA000000, // 12 0 3 1
	0xAA000000, // 12 1 0 3
	0xAA000000, // 12 1 1 2
	0xAA000000, // 12 1 2 1
	0xAA000000, // 12 2 0 2
	0xAA000000, // 12 2 1 1
	0xAA000000, // 12 3 0 1
	0xA8000000, // 13 0 0 3
	0xA8000000, // 13 0 1 2
	0xA8000000, // 13 0 2 1
	0xA8000000, // 13 1 0 2
	0xA8000000, // 13 1 1 1
	0xA8000000, // 13 2 0 1
	0xA0000000, // 14 0 0 2
	0xA0000000, // 14 0 1 1
	0xA0000000, // 14 1 0 1
	0x80000000, // 15 0 0 1
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
	0x80000000,
};



<|start_filename|>src/nvcore/Timer.h<|end_filename|>
// This code is in the public domain -- <EMAIL>

#pragma once
#ifndef NV_CORE_TIMER_H
#define NV_CORE_TIMER_H

#include "nvcore.h"

#if NV_CC_MSVC
#include <intrin.h>
#endif

namespace nv {

#if NV_CC_MSVC
    NV_FORCEINLINE uint64 fastCpuClock() { return __rdtsc(); }
#elif NV_CC_GNUC && NV_CPU_X86
    NV_FORCEINLINE uint64 fastCpuClock() {
        uint64 val;
        __asm__ volatile (".byte 0x0f, 0x31" : "=A" (val));
        return val;
    }
#elif NV_CC_GNUC && NV_CPU_X86_64
    NV_FORCEINLINE uint64 fastCpuClock() {
        uint hi, lo;
        __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
        return uint64(lo) | (uint64(hi) << 32);
    }
#else
    NV_FORCEINLINE uint64 fastCpuClock() { return 0; }    
#endif
    
    uint64 systemClockFrequency();
    uint64 systemClock();

    class NVCORE_CLASS Timer
    {
    public:
        Timer() {}

        void start() { m_start = systemClock(); }
        void stop() { m_stop = systemClock(); }

        float elapsed() const { return float(m_stop - m_start) / systemClockFrequency(); }

    private:
        uint64 m_start;
        uint64 m_stop;
    };

} // nv namespace

#endif // NV_CORE_TIMER_H
