/*
Real-time DXT1 & YCoCg DXT5 compression (Cg 2.0)
Copyright (c) NVIDIA Corporation.
Written by: Ignacio Castano <icastano@nvidia.com>

Thanks to JMP van Waveren, Simon Green, Eric Werness, Simon Brown

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.
*/

const char* pDXTCompressorShaderSource =
"	\n"
"// vertex program	\n"
"void compress_vp(float4 pos : POSITION,	\n"
"                      float2 texcoord : TEXCOORD0,	\n"
"                      out float4 hpos : POSITION,	\n"
"                      out float2 o_texcoord : TEXCOORD0	\n"
"                      )	\n"
"{	\n"
"    o_texcoord = texcoord;	\n"
"    hpos = pos;	\n"
"}	\n"
"	\n"
"typedef unsigned int uint;	\n"
"typedef unsigned int2 uint2;	\n"
"typedef unsigned int3 uint3;	\n"
"typedef unsigned int4 uint4;	\n"
"	\n"
"const float offset = 128.0 / 255.0;	\n"
"	\n"
"// Use dot product to minimize RMS instead absolute distance like in the CPU compressor.	\n"
"float colorDistance(float3 c0, float3 c1)	\n"
"{	\n"
"    return dot(c0-c1, c0-c1);	\n"
"}	\n"
"float colorDistance(float2 c0, float2 c1)	\n"
"{	\n"
"    return dot(c0-c1, c0-c1);	\n"
"}	\n"
"	\n"
"	\n"
"void ExtractColorBlockRGB(out float3 col[16], sampler2D image, float2 texcoord, float2 imageSize)	\n"
"{	\n"
"    // use TXF instruction (integer coordinates with offset)	\n"
"    // note offsets must be constant	\n"
"    //int4 base = int4(wpos*4-2, 0, 0);	\n"
"    int4 base = int4(texcoord * imageSize - 1.5, 0, 0);	\n"
"    col[0] = tex2Dfetch(image, base, int2(0, 0)).rgb;	\n"
"    col[1] = tex2Dfetch(image, base, int2(1, 0)).rgb;	\n"
"    col[2] = tex2Dfetch(image, base, int2(2, 0)).rgb;	\n"
"    col[3] = tex2Dfetch(image, base, int2(3, 0)).rgb;	\n"
"    col[4] = tex2Dfetch(image, base, int2(0, 1)).rgb;	\n"
"    col[5] = tex2Dfetch(image, base, int2(1, 1)).rgb;	\n"
"    col[6] = tex2Dfetch(image, base, int2(2, 1)).rgb;	\n"
"    col[7] = tex2Dfetch(image, base, int2(3, 1)).rgb;	\n"
"    col[8] = tex2Dfetch(image, base, int2(0, 2)).rgb;	\n"
"    col[9] = tex2Dfetch(image, base, int2(1, 2)).rgb;	\n"
"    col[10] = tex2Dfetch(image, base, int2(2, 2)).rgb;	\n"
"    col[11] = tex2Dfetch(image, base, int2(3, 2)).rgb;	\n"
"    col[12] = tex2Dfetch(image, base, int2(0, 3)).rgb;	\n"
"    col[13] = tex2Dfetch(image, base, int2(1, 3)).rgb;	\n"
"    col[14] = tex2Dfetch(image, base, int2(2, 3)).rgb;	\n"
"    col[15] = tex2Dfetch(image, base, int2(3, 3)).rgb;	\n"
"}	\n"
"	\n"
"void ExtractColorBlockBGR(out float3 col[16], sampler2D image, float2 texcoord, float2 imageSize)	\n"
"{	\n"
"    // use TXF instruction (integer coordinates with offset)	\n"
"    // note offsets must be constant	\n"
"    //int4 base = int4(wpos*4-2, 0, 0);	\n"
"    int4 base = int4(texcoord * imageSize - 1.5, 0, 0);	\n"
"    col[0] = tex2Dfetch(image, base, int2(0, 0)).bgr;	\n"
"    col[1] = tex2Dfetch(image, base, int2(1, 0)).bgr;	\n"
"    col[2] = tex2Dfetch(image, base, int2(2, 0)).bgr;	\n"
"    col[3] = tex2Dfetch(image, base, int2(3, 0)).bgr;	\n"
"    col[4] = tex2Dfetch(image, base, int2(0, 1)).bgr;	\n"
"    col[5] = tex2Dfetch(image, base, int2(1, 1)).bgr;	\n"
"    col[6] = tex2Dfetch(image, base, int2(2, 1)).bgr;	\n"
"    col[7] = tex2Dfetch(image, base, int2(3, 1)).bgr;	\n"
"    col[8] = tex2Dfetch(image, base, int2(0, 2)).bgr;	\n"
"    col[9] = tex2Dfetch(image, base, int2(1, 2)).bgr;	\n"
"    col[10] = tex2Dfetch(image, base, int2(2, 2)).bgr;	\n"
"    col[11] = tex2Dfetch(image, base, int2(3, 2)).bgr;	\n"
"    col[12] = tex2Dfetch(image, base, int2(0, 3)).bgr;	\n"
"    col[13] = tex2Dfetch(image, base, int2(1, 3)).bgr;	\n"
"    col[14] = tex2Dfetch(image, base, int2(2, 3)).bgr;	\n"
"    col[15] = tex2Dfetch(image, base, int2(3, 3)).bgr;	\n"
"}	\n"
"	\n"
"float3 toYCoCg(float3 c)	\n"
"{	\n"
"    float Y = (c.r + 2 * c.g + c.b) * 0.25;	\n"
"    float Co = ( ( 2 * c.r - 2 * c.b      ) * 0.25 + offset );	\n"
"    float Cg = ( (    -c.r + 2 * c.g - c.b) * 0.25 + offset );	\n"
"	\n"
"    return float3(Y, Co, Cg);	\n"
"}	\n"
"	\n"
"void ExtractColorBlockYCoCg_RGB(out float3 col[16], sampler2D image, float2 texcoord, float2 imageSize)	\n"
"{	\n"
"    // use TXF instruction (integer coordinates with offset)	\n"
"    // note offsets must be constant	\n"
"    //int4 base = int4(wpos*4-2, 0, 0);	\n"
"    int4 base = int4(texcoord * imageSize - 1.5, 0, 0);	\n"
"    col[0] = toYCoCg(tex2Dfetch(image, base, int2(0, 0)).rgb);	\n"
"    col[1] = toYCoCg(tex2Dfetch(image, base, int2(1, 0)).rgb);	\n"
"    col[2] = toYCoCg(tex2Dfetch(image, base, int2(2, 0)).rgb);	\n"
"    col[3] = toYCoCg(tex2Dfetch(image, base, int2(3, 0)).rgb);	\n"
"    col[4] = toYCoCg(tex2Dfetch(image, base, int2(0, 1)).rgb);	\n"
"    col[5] = toYCoCg(tex2Dfetch(image, base, int2(1, 1)).rgb);	\n"
"    col[6] = toYCoCg(tex2Dfetch(image, base, int2(2, 1)).rgb);	\n"
"    col[7] = toYCoCg(tex2Dfetch(image, base, int2(3, 1)).rgb);	\n"
"    col[8] = toYCoCg(tex2Dfetch(image, base, int2(0, 2)).rgb);	\n"
"    col[9] = toYCoCg(tex2Dfetch(image, base, int2(1, 2)).rgb);	\n"
"    col[10] = toYCoCg(tex2Dfetch(image, base, int2(2, 2)).rgb);	\n"
"    col[11] = toYCoCg(tex2Dfetch(image, base, int2(3, 2)).rgb);	\n"
"    col[12] = toYCoCg(tex2Dfetch(image, base, int2(0, 3)).rgb);	\n"
"    col[13] = toYCoCg(tex2Dfetch(image, base, int2(1, 3)).rgb);	\n"
"    col[14] = toYCoCg(tex2Dfetch(image, base, int2(2, 3)).rgb);	\n"
"    col[15] = toYCoCg(tex2Dfetch(image, base, int2(3, 3)).rgb);	\n"
"}	\n"
"	\n"
"void ExtractColorBlockYCoCg_BGR(out float3 col[16], sampler2D image, float2 texcoord, float2 imageSize)	\n"
"{	\n"
"    // use TXF instruction (integer coordinates with offset)	\n"
"    // note offsets must be constant	\n"
"    //int4 base = int4(wpos*4-2, 0, 0);	\n"
"    int4 base = int4(texcoord * imageSize - 1.5, 0, 0);	\n"
"    col[0] = toYCoCg(tex2Dfetch(image, base, int2(0, 0)).bgr);	\n"
"    col[1] = toYCoCg(tex2Dfetch(image, base, int2(1, 0)).bgr);	\n"
"    col[2] = toYCoCg(tex2Dfetch(image, base, int2(2, 0)).bgr);	\n"
"    col[3] = toYCoCg(tex2Dfetch(image, base, int2(3, 0)).bgr);	\n"
"    col[4] = toYCoCg(tex2Dfetch(image, base, int2(0, 1)).bgr);	\n"
"    col[5] = toYCoCg(tex2Dfetch(image, base, int2(1, 1)).bgr);	\n"
"    col[6] = toYCoCg(tex2Dfetch(image, base, int2(2, 1)).bgr);	\n"
"    col[7] = toYCoCg(tex2Dfetch(image, base, int2(3, 1)).bgr);	\n"
"    col[8] = toYCoCg(tex2Dfetch(image, base, int2(0, 2)).bgr);	\n"
"    col[9] = toYCoCg(tex2Dfetch(image, base, int2(1, 2)).bgr);	\n"
"    col[10] = toYCoCg(tex2Dfetch(image, base, int2(2, 2)).bgr);	\n"
"    col[11] = toYCoCg(tex2Dfetch(image, base, int2(3, 2)).bgr);	\n"
"    col[12] = toYCoCg(tex2Dfetch(image, base, int2(0, 3)).bgr);	\n"
"    col[13] = toYCoCg(tex2Dfetch(image, base, int2(1, 3)).bgr);	\n"
"    col[14] = toYCoCg(tex2Dfetch(image, base, int2(2, 3)).bgr);	\n"
"    col[15] = toYCoCg(tex2Dfetch(image, base, int2(3, 3)).bgr);	\n"
"}	\n"
"	\n"
"// find minimum and maximum colors based on bounding box in color space	\n"
"void FindMinMaxColorsBox(float3 block[16], out float3 mincol, out float3 maxcol)	\n"
"{	\n"
"    mincol = block[0];	\n"
"    maxcol = block[0];	\n"
"    	\n"
"    for (int i = 1; i < 16; i++) {	\n"
"        mincol = min(mincol, block[i]);	\n"
"        maxcol = max(maxcol, block[i]);	\n"
"    }	\n"
"}	\n"
"	\n"
"void InsetBBox(in out float3 mincol, in out float3 maxcol)	\n"
"{	\n"
"    float3 inset = (maxcol - mincol) / 16.0 - (8.0 / 255.0) / 16;	\n"
"    mincol = saturate(mincol + inset);	\n"
"    maxcol = saturate(maxcol - inset);	\n"
"}	\n"
"void InsetYBBox(in out float mincol, in out float maxcol)	\n"
"{	\n"
"    float inset = (maxcol - mincol) / 32.0 - (16.0 / 255.0) / 32.0;	\n"
"    mincol = saturate(mincol + inset);	\n"
"    maxcol = saturate(maxcol - inset);	\n"
"}	\n"
"void InsetCoCgBBox(in out float2 mincol, in out float2 maxcol)	\n"
"{	\n"
"    float2 inset = (maxcol - mincol) / 16.0 - (8.0 / 255.0) / 16;	\n"
"    mincol = saturate(mincol + inset);	\n"
"    maxcol = saturate(maxcol - inset);	\n"
"}	\n"
"	\n"
"void SelectDiagonal(float3 block[16], in out float3 mincol, in out float3 maxcol)	\n"
"{	\n"
"    float3 center = (mincol + maxcol) * 0.5;	\n"
"	\n"
"    float2 cov = 0;	\n"
"    for (int i = 0; i < 16; i++)	\n"
"    {	\n"
"        float3 t = block[i] - center;	\n"
"        cov.x += t.x * t.z;	\n"
"        cov.y += t.y * t.z;	\n"
"    }	\n"
"	\n"
"    if (cov.x < 0) {	\n"
"        float temp = maxcol.x;	\n"
"        maxcol.x = mincol.x;	\n"
"        mincol.x = temp;	\n"
"    }	\n"
"    if (cov.y < 0) {	\n"
"        float temp = maxcol.y;	\n"
"        maxcol.y = mincol.y;	\n"
"        mincol.y = temp;	\n"
"    }	\n"
"}	\n"
"	\n"
"float3 RoundAndExpand(float3 v, out uint w)	\n"
"{	\n"
"    int3 c = round(v * float3(31, 63, 31));	\n"
"    w = (c.r << 11) | (c.g << 5) | c.b;	\n"
"	\n"
"    c.rb = (c.rb << 3) | (c.rb >> 2);	\n"
"    c.g = (c.g << 2) | (c.g >> 4);	\n"
"	\n"
"    return (float3)c * (1.0 / 255.0);	\n"
"}	\n"
"	\n"
"uint EmitEndPointsDXT1(in out float3 mincol, in out float3 maxcol)	\n"
"{	\n"
"    uint2 output;	\n"
"    maxcol = RoundAndExpand(maxcol, output.x);	\n"
"    mincol = RoundAndExpand(mincol, output.y);	\n"
"	\n"
"    // We have to do this in case we select an alternate diagonal.	\n"
"    if (output.x < output.y)	\n"
"    {	\n"
"        float3 tmp = mincol;	\n"
"        mincol = maxcol;	\n"
"        maxcol = tmp;	\n"
"        return output.y | (output.x << 16);	\n"
"    }	\n"
"	\n"
"    return output.x | (output.y << 16);	\n"
"}	\n"
"	\n"
"uint EmitIndicesDXT1(float3 block[16], float3 mincol, float3 maxcol)	\n"
"{	\n"
"    const float RGB_RANGE = 3;	\n"
"	\n"
"    float3 dir = (maxcol - mincol);	\n"
"    float3 origin = maxcol + dir / (2.0 * RGB_RANGE);	\n"
"    dir /= dot(dir, dir);	\n"
"	\n"
"    // Compute indices	\n"
"    uint indices = 0;	\n"
"    for (int i = 0; i < 16; i++)	\n"
"    {	\n"
"        uint index = saturate(dot(origin - block[i], dir)) * RGB_RANGE;	\n"
"        indices |= index << (i * 2);	\n"
"    }	\n"
"	\n"
"    uint i0 = (indices & 0x55555555);	\n"
"    uint i1 = (indices & 0xAAAAAAAA) >> 1;	\n"
"    indices = ((i0 ^ i1) << 1) | i1;	\n"
"	\n"
"    // Output indices	\n"
"    return indices;	\n"
"}	\n"
"	\n"
"int ScaleYCoCg(float2 minColor, float2 maxColor)	\n"
"{	\n"
"    float2 m0 = abs(minColor - offset);	\n"
"    float2 m1 = abs(maxColor - offset);	\n"
"	\n"
"    float m = max(max(m0.x, m0.y), max(m1.x, m1.y));	\n"
"	\n"
"    const float s0 = 64.0 / 255.0;	\n"
"    const float s1 = 32.0 / 255.0;	\n"
"	\n"
"    int scale = 1;	\n"
"    if (m < s0) scale = 2;	\n"
"    if (m < s1) scale = 4;	\n"
"	\n"
"    return scale;	\n"
"}	\n"
"	\n"
"void SelectYCoCgDiagonal(const float3 block[16], in out float2 minColor, in out float2 maxColor)	\n"
"{	\n"
"    float2 mid = (maxColor + minColor) * 0.5;	\n"
"	\n"
"    float cov = 0;	\n"
"    for (int i = 0; i < 16; i++)	\n"
"    {	\n"
"        float2 t = block[i].yz - mid;	\n"
"        cov += t.x * t.y;	\n"
"    }	\n"
"    if (cov < 0) {	\n"
"        float tmp = maxColor.y;	\n"
"        maxColor.y = minColor.y;	\n"
"        minColor.y = tmp;	\n"
"    }	\n"
"}	\n"
"	\n"
"	\n"
"uint EmitEndPointsYCoCgDXT5(in out float2 mincol, in out float2 maxcol, int scale)	\n"
"{	\n"
"    maxcol = (maxcol - offset) * scale + offset;	\n"
"    mincol = (mincol - offset) * scale + offset;	\n"
"	\n"
"    InsetCoCgBBox(mincol, maxcol);	\n"
"	\n"
"    maxcol = round(maxcol * float2(31, 63));	\n"
"    mincol = round(mincol * float2(31, 63));	\n"
"	\n"
"    int2 imaxcol = maxcol;	\n"
"    int2 imincol = mincol;	\n"
"	\n"
"    uint2 output;	\n"
"    output.x = (imaxcol.r << 11) | (imaxcol.g << 5) | (scale - 1);	\n"
"    output.y = (imincol.r << 11) | (imincol.g << 5) | (scale - 1);	\n"
"	\n"
"    imaxcol.r = (imaxcol.r << 3) | (imaxcol.r >> 2);	\n"
"    imaxcol.g = (imaxcol.g << 2) | (imaxcol.g >> 4);	\n"
"    imincol.r = (imincol.r << 3) | (imincol.r >> 2);	\n"
"    imincol.g = (imincol.g << 2) | (imincol.g >> 4);	\n"
"	\n"
"    maxcol = (float2)imaxcol * (1.0 / 255.0);	\n"
"    mincol = (float2)imincol * (1.0 / 255.0);	\n"
"	\n"
"    // Undo rescale.	\n"
"    maxcol = (maxcol - offset) / scale + offset;	\n"
"    mincol = (mincol - offset) / scale + offset;	\n"
"	\n"
"    return output.x | (output.y << 16);	\n"
"}	\n"
"	\n"
"uint EmitIndicesYCoCgDXT5(float3 block[16], float2 mincol, float2 maxcol)	\n"
"{	\n"
"    const float COCG_RANGE = 3;	\n"
"	\n"
"    float2 dir = (maxcol - mincol);	\n"
"    float2 origin = maxcol + dir / (2.0 * COCG_RANGE);	\n"
"    dir /= dot(dir, dir);	\n"
"	\n"
"    // Compute indices	\n"
"    uint indices = 0;	\n"
"    for (int i = 0; i < 16; i++)	\n"
"    {	\n"
"        uint index = saturate(dot(origin - block[i].yz, dir)) * COCG_RANGE;	\n"
"        indices |= index << (i * 2);	\n"
"    }	\n"
"	\n"
"    uint i0 = (indices & 0x55555555);	\n"
"    uint i1 = (indices & 0xAAAAAAAA) >> 1;	\n"
"    indices = ((i0 ^ i1) << 1) | i1;	\n"
"	\n"
"    // Output indices	\n"
"    return indices;	\n"
"}	\n"
"	\n"
"uint EmitAlphaEndPointsYCoCgDXT5(float mincol, float maxcol)	\n"
"{	\n"
"    uint c0 = round(mincol * 255);	\n"
"    uint c1 = round(maxcol * 255);	\n"
"	\n"
"    return (c0 << 8) | c1;	\n"
"}	\n"
"	\n"
"// Optimized index selection.	\n"
"uint2 EmitAlphaIndicesYCoCgDXT5(float3 block[16], float minAlpha, float maxAlpha)	\n"
"{	\n"
"    const int ALPHA_RANGE = 7;	\n"
"	\n"
"    float bias = maxAlpha + (maxAlpha - minAlpha) / (2.0 * ALPHA_RANGE);	\n"
"    float scale = 1.0f / (maxAlpha - minAlpha);	\n"
"	\n"
"    uint2 indices = 0;	\n"
"	\n"
"    for (int i = 0; i < 6; i++)	\n"
"    {	\n"
"        uint index = saturate((bias - block[i].x) * scale) * ALPHA_RANGE;	\n"
"        indices.x |= index << (3 * i);	\n"
"    }	\n"
"	\n"
"    for (int i = 6; i < 16; i++)	\n"
"    {	\n"
"        uint index = saturate((bias - block[i].x) * scale) * ALPHA_RANGE;	\n"
"        indices.y |= index << (3 * i - 18);	\n"
"    }	\n"
"	\n"
"    uint2 i0 = (indices >> 0) & 0x09249249;	\n"
"    uint2 i1 = (indices >> 1) & 0x09249249;	\n"
"    uint2 i2 = (indices >> 2) & 0x09249249;	\n"
"	\n"
"    i2 ^= i0 & i1;	\n"
"    i1 ^= i0;	\n"
"    i0 ^= (i1 | i2);	\n"
"	\n"
"    indices.x = (i2.x << 2) | (i1.x << 1) | i0.x;	\n"
"    indices.y = (((i2.y << 2) | (i1.y << 1) | i0.y) << 2) | (indices.x >> 16);	\n"
"    indices.x <<= 16;	\n"
"	\n"
"    return indices;	\n"
"}	\n"
"	\n"
"// compress a 4x4 block to DXT1 format	\n"
"// integer version, renders to 2 x int32 buffer	\n"
"uint4 compress_DXT1_RGBA_fp(float2 texcoord : TEXCOORD0,	\n"
"                      uniform sampler2D image,	\n"
"                      uniform float2 imageSize = { 512.0, 512.0 }	\n"
"                      ) : COLOR	\n"
"{	\n"
"    // read block	\n"
"    float3 block[16];	\n"
"    ExtractColorBlockRGB(block, image, texcoord, imageSize);	\n"
"	\n"
"    // find min and max colors	\n"
"    float3 mincol, maxcol;	\n"
"    FindMinMaxColorsBox(block, mincol, maxcol);	\n"
"	\n"
"    SelectDiagonal(block, mincol, maxcol);	\n"
"	\n"
"    InsetBBox(mincol, maxcol);	\n"
"	\n"
"    uint4 output;	\n"
"    output.x = EmitEndPointsDXT1(mincol, maxcol);	\n"
"    output.w = EmitIndicesDXT1(block, mincol, maxcol);	\n"
"	\n"
"    return output;	\n"
"}	\n"
"   \n"
"uint4 compress_DXT1_BGRA_fp(float2 texcoord : TEXCOORD0,	\n"
"                      uniform sampler2D image,	\n"
"                      uniform float2 imageSize = { 512.0, 512.0 }	\n"
"                      ) : COLOR	\n"
"{	\n"
"    // read block	\n"
"    float3 block[16];	\n"
"    ExtractColorBlockBGR(block, image, texcoord, imageSize);	\n"
"	\n"
"    // find min and max colors	\n"
"    float3 mincol, maxcol;	\n"
"    FindMinMaxColorsBox(block, mincol, maxcol);	\n"
"	\n"
"    SelectDiagonal(block, mincol, maxcol);	\n"
"	\n"
"    InsetBBox(mincol, maxcol);	\n"
"	\n"
"    uint4 output;	\n"
"    output.x = EmitEndPointsDXT1(mincol, maxcol);	\n"
"    output.w = EmitIndicesDXT1(block, mincol, maxcol);	\n"
"	\n"
"   return output;	\n"
"}	\n"
"	\n"
"	\n"
"// compress a 4x4 block to YCoCg DXT5 format	\n"
"// integer version, renders to 4 x int32 buffer	\n"
"uint4 compress_YCoCgDXT5_RGBA_fp(float2 texcoord : TEXCOORD0,	\n"
"                      uniform sampler2D image,	\n"
"                      uniform float2 imageSize = { 512.0, 512.0 }	\n"
"                      ) : COLOR	\n"
"{	\n"
"    //imageSize = tex2Dsize(image, texcoord);	\n"
"	\n"
"    // read block	\n"
"    float3 block[16];	\n"
"    ExtractColorBlockYCoCg_RGB(block, image, texcoord, imageSize);	\n"
"	\n"
"    // find min and max colors	\n"
"    float3 mincol, maxcol;	\n"
"    FindMinMaxColorsBox(block, mincol, maxcol);	\n"
"	\n"
"    SelectYCoCgDiagonal(block, mincol.yz, maxcol.yz);	\n"
"	\n"
"    int scale = ScaleYCoCg(mincol.yz, maxcol.yz);	\n"
"	\n"
"    // Output CoCg in DXT1 block.	\n"
"    uint4 output;	\n"
"    output.z = EmitEndPointsYCoCgDXT5(mincol.yz, maxcol.yz, scale);	\n"
"    output.w = EmitIndicesYCoCgDXT5(block, mincol.yz, maxcol.yz);	\n"
"	\n"
"    InsetYBBox(mincol.x, maxcol.x);	\n"
"	\n"
"    // Output Y in DXT5 alpha block.	\n"
"    output.x = EmitAlphaEndPointsYCoCgDXT5(mincol.x, maxcol.x);	\n"
"	\n"
"    uint2 indices = EmitAlphaIndicesYCoCgDXT5(block, mincol.x, maxcol.x);	\n"
"    output.x |= indices.x;	\n"
"    output.y = indices.y;	\n"
"	\n"
"    return output;	\n"
"}	\n"
"	\n"
"uint4 compress_YCoCgDXT5_BGRA_fp(float2 texcoord : TEXCOORD0,	\n"
"                      uniform sampler2D image,	\n"
"                      uniform float2 imageSize = { 512.0, 512.0 }	\n"
"                      ) : COLOR	\n"
"{	\n"
"    //imageSize = tex2Dsize(image, texcoord);	\n"
"	\n"
"    // read block	\n"
"    float3 block[16];	\n"
"    ExtractColorBlockYCoCg_BGR(block, image, texcoord, imageSize);	\n"
"	\n"
"    // find min and max colors	\n"
"    float3 mincol, maxcol;	\n"
"    FindMinMaxColorsBox(block, mincol, maxcol);	\n"
"	\n"
"    SelectYCoCgDiagonal(block, mincol.yz, maxcol.yz);	\n"
"	\n"
"    int scale = ScaleYCoCg(mincol.yz, maxcol.yz);	\n"
"	\n"
"    // Output CoCg in DXT1 block.	\n"
"    uint4 output;	\n"
"    output.z = EmitEndPointsYCoCgDXT5(mincol.yz, maxcol.yz, scale);	\n"
"    output.w = EmitIndicesYCoCgDXT5(block, mincol.yz, maxcol.yz);	\n"
"	\n"
"    InsetYBBox(mincol.x, maxcol.x);	\n"
"	\n"
"    // Output Y in DXT5 alpha block.	\n"
"    output.x = EmitAlphaEndPointsYCoCgDXT5(mincol.x, maxcol.x);	\n"
"	\n"
"    uint2 indices = EmitAlphaIndicesYCoCgDXT5(block, mincol.x, maxcol.x);	\n"
"    output.x |= indices.x;	\n"
"    output.y = indices.y;	\n"
"	\n"
"    return output;	\n"
"}	\n"
"	\n"
"uniform bool reconstructColor = false;	\n"
"uniform bool displayError = false;	\n"
"uniform float errorScale = 4.0f;	\n"
"	\n"
"uniform sampler2D image : TEXUNIT0;	\n"
"uniform sampler2D originalImage : TEXUNIT1;	\n"
"	\n"
"float4 display_fp(float2 texcoord : TEXCOORD0) : COLOR	\n"
"{	\n"
"    float4 rgba = tex2D(image, texcoord);	\n"
"    	\n"
"    if (reconstructColor)	\n"
"    {	\n"
"        float Y = rgba.a;	\n"
"        float scale = 1.0 / ((255.0 / 8.0) * rgba.b + 1);	\n"
"        float Co = (rgba.r - offset) * scale;	\n"
"        float Cg = (rgba.g - offset) * scale;	\n"
"	\n"
"        float R = Y + Co - Cg;	\n"
"        float G = Y + Cg;	\n"
"        float B = Y - Co - Cg;	\n"
"	\n"
"        rgba = float4(R, G, B, 1);	\n"
"    }	\n"
"	\n"
"    if (displayError)	\n"
"    {	\n"
"        float3 originalColor = tex2D(originalImage, texcoord).rgb;	\n"
"        float3 diff = abs(rgba.rgb - originalColor) * errorScale;	\n"
"        return float4(diff, 1);	\n"
"    }	\n"
"    else	\n"
"    {	\n"
"        return rgba;	\n"
"    }	\n"
"}	\n"
"	\n";