void compressDXT5A_RGBM(ColorSet src, ColorBlock RGB, AlphaBlockDXT5 dst)
        {
            byte mina = 255;
            byte maxa = 0;

            byte mina_no01 = 255;
            byte maxa_no01 = 0;

            // Get min/max alpha.
            /*for (uint i = 0; i < 16; i++)
            {
                byte alpha = src.alpha[i];
                mina = min(mina, alpha);
                maxa = max(maxa, alpha);

                if (alpha != 0 && alpha != 255) {
                    mina_no01 = min(mina_no01, alpha);
                    maxa_no01 = max(maxa_no01, alpha);
                }
            }*/
            mina = 0;
            maxa = 255;
            mina_no01 = 0;
            maxa_no01 = 255;

            /*if (maxa - mina < 8) {
                dst.alpha0 = maxa;
                dst.alpha1 = mina;

                nvDebugCheck(computeAlphaError(src, dst) == 0);
            }
            else if (maxa_no01 - mina_no01 < 6) {
                dst.alpha0 = mina_no01;
                dst.alpha1 = maxa_no01;

                nvDebugCheck(computeAlphaError(src, dst) == 0);
            }
            else*/
            {
                float besterror = computeAlphaError_RGBM(src, RGB, dst);
                byte besta0 = maxa;
                byte besta1 = mina;

                // Expand search space a bit.
                int alphaExpand = 8;
                mina = (byte)((mina <= alphaExpand) ? 0 : mina - alphaExpand);
                maxa = (byte)((maxa >= 255 - alphaExpand) ? 255 : maxa + alphaExpand);

                for (byte a0 = (byte)(mina + 9); a0 < maxa; a0++)
                {
                    for (byte a1 = mina; a1 < a0 - 8; a1++)
                    {

                        dst.alpha0 = a0;
                        dst.alpha1 = a1;
                        float error = computeAlphaError_RGBM(src, RGB, dst, besterror);

                        if (error < besterror)
                        {
                            besterror = error;
                            besta0 = a0;
                            besta1 = a1;
                        }
                    }
                }

                // Try using the 6 step encoding.
                /*if (mina == 0 || maxa == 255)*/
                {

                    // Expand search space a bit.
                    alphaExpand = 6;
                    mina_no01 = (byte)((mina_no01 <= alphaExpand) ? 0 : mina_no01 - alphaExpand);
                    maxa_no01 = (byte)((maxa_no01 >= 255 - alphaExpand) ? 255 : maxa_no01 + alphaExpand);

                    for (byte a0 = (byte)(mina_no01 + 9); a0 < maxa_no01; a0++)
                    {
                        for (byte a1 = mina_no01; a1 < a0 - 8; a1++)
                        {
                            dst.alpha0 = a1;
                            dst.alpha1 = a0;
                            float error = computeAlphaError_RGBM(src, RGB, dst, besterror);

                            if (error < besterror)
                            {
                                besterror = error;
                                besta0 = a1;
                                besta1 = a0;
                            }
                        }
                    }
                }

                dst.alpha0 = besta0;
                dst.alpha1 = besta1;
            }

            computeAlphaIndices_RGBM(src, RGB, dst);
        }
        static void computeAlphaIndices_RGBM(ColorSet src, ColorBlock RGB, AlphaBlockDXT5 dst)
        {
            byte[] alphas = new byte[8];
            dst.evaluatePalette(alphas, /*d3d9=*/false); // @@ Use target decoder.

            for (uint i = 0; i < 16; i++)
            {
                float R = src.color[i].x;
                float G = src.color[i].y;
                float B = src.color[i].z;

                float r = (float)(RGB.color[i].r) / 255.0f;
                float g = (float)(RGB.color[i].g) / 255.0f;
                float b = (float)(RGB.color[i].b) / 255.0f;

                float minDist = float.MaxValue;
                uint bestIndex = 8;
                for (uint p = 0; p < 8; p++)
                {
                    // Compute M.
                    float M = (float)(alphas[p]) / 255.0f * (1 - threshold) + threshold;

                    // Decode color.
                    float fr = r * M;
                    float fg = g * M;
                    float fb = b * M;

                    // Measure error.
                    float error = Mathf.Pow(R - fr, 2) + Mathf.Pow(G - fg, 2) + Mathf.Pow(B - fb, 2);

                    if (error < minDist)
                    {
                        minDist = error;
                        bestIndex = p;
                    }
                }

                dst.setIndex(i, bestIndex);
            }
        }
        void compressDXT5A_RGBM(ColorSet src, ColorBlock RGB, AlphaBlockDXT5 dst)
        {
            byte mina = 255;
            byte maxa = 0;

            byte mina_no01 = 255;
            byte maxa_no01 = 0;

            // Get min/max alpha.

            /*for (uint i = 0; i < 16; i++)
             * {
             *  byte alpha = src.alpha[i];
             *  mina = min(mina, alpha);
             *  maxa = max(maxa, alpha);
             *
             *  if (alpha != 0 && alpha != 255) {
             *      mina_no01 = min(mina_no01, alpha);
             *      maxa_no01 = max(maxa_no01, alpha);
             *  }
             * }*/
            mina      = 0;
            maxa      = 255;
            mina_no01 = 0;
            maxa_no01 = 255;

            /*if (maxa - mina < 8) {
             *  dst.alpha0 = maxa;
             *  dst.alpha1 = mina;
             *
             *  nvDebugCheck(computeAlphaError(src, dst) == 0);
             * }
             * else if (maxa_no01 - mina_no01 < 6) {
             *  dst.alpha0 = mina_no01;
             *  dst.alpha1 = maxa_no01;
             *
             *  nvDebugCheck(computeAlphaError(src, dst) == 0);
             * }
             * else*/
            {
                float besterror = computeAlphaError_RGBM(src, RGB, dst);
                byte  besta0    = maxa;
                byte  besta1    = mina;

                // Expand search space a bit.
                int alphaExpand = 8;
                mina = (byte)((mina <= alphaExpand) ? 0 : mina - alphaExpand);
                maxa = (byte)((maxa >= 255 - alphaExpand) ? 255 : maxa + alphaExpand);

                for (byte a0 = (byte)(mina + 9); a0 < maxa; a0++)
                {
                    for (byte a1 = mina; a1 < a0 - 8; a1++)
                    {
                        dst.alpha0 = a0;
                        dst.alpha1 = a1;
                        float error = computeAlphaError_RGBM(src, RGB, dst, besterror);

                        if (error < besterror)
                        {
                            besterror = error;
                            besta0    = a0;
                            besta1    = a1;
                        }
                    }
                }

                // Try using the 6 step encoding.
                /*if (mina == 0 || maxa == 255)*/
                {
                    // Expand search space a bit.
                    alphaExpand = 6;
                    mina_no01   = (byte)((mina_no01 <= alphaExpand) ? 0 : mina_no01 - alphaExpand);
                    maxa_no01   = (byte)((maxa_no01 >= 255 - alphaExpand) ? 255 : maxa_no01 + alphaExpand);

                    for (byte a0 = (byte)(mina_no01 + 9); a0 < maxa_no01; a0++)
                    {
                        for (byte a1 = mina_no01; a1 < a0 - 8; a1++)
                        {
                            dst.alpha0 = a1;
                            dst.alpha1 = a0;
                            float error = computeAlphaError_RGBM(src, RGB, dst, besterror);

                            if (error < besterror)
                            {
                                besterror = error;
                                besta0    = a1;
                                besta1    = a0;
                            }
                        }
                    }
                }

                dst.alpha0 = besta0;
                dst.alpha1 = besta1;
            }

            computeAlphaIndices_RGBM(src, RGB, dst);
        }
        static float computeAlphaError_RGBM(ColorSet src, ColorBlock RGB, AlphaBlockDXT5 dst, float bestError = float.MaxValue)
        {
            byte[] alphas = new byte[8];
            dst.evaluatePalette(alphas, /*d3d9=*/false); // @@ Use target decoder.

            float totalError = 0;

            for (uint i = 0; i < 16; i++)
            {
                float R = src.color[i].x;
                float G = src.color[i].y;
                float B = src.color[i].z;

                float r = (float)(RGB.color[i].r) / 255.0f;
                float g = (float)(RGB.color[i].g) / 255.0f;
                float b = (float)(RGB.color[i].b) / 255.0f;

                float minDist = float.MaxValue;
                for (uint p = 0; p < 8; p++)
                {
                    // Compute M.
                    float M = (float)(alphas[p]) / 255.0f * (1 - threshold) + threshold;

                    // Decode color.
                    float fr = r * M;
                    float fg = g * M;
                    float fb = b * M;

                    // Measure error.
                    float error = Mathf.Pow(R - fr, 2) + Mathf.Pow(G - fg, 2) + Mathf.Pow(B - fb, 2);

                    minDist = Mathf.Min(error, minDist);
                }

                totalError += minDist * src.weights[i];

                if (totalError > bestError)
                {
                    // early out
                    return totalError;
                }
            }

            return totalError;
        }
Example #5
0
// maxColor and minColor are expected to be in the same range as the color set.
        static uint computeIndices4(ColorSet set, Vector3 maxColor, Vector3 minColor)
        {
            Vector3[] palette = new Vector3[4];
            palette[0] = maxColor;
            palette[1] = minColor;
            palette[2] = Vector3.Lerp(palette[0], palette[1], 1.0f / 3.0f);
            palette[3] = Vector3.Lerp(palette[0], palette[1], 2.0f / 3.0f);


            Vector3[] row0 = new Vector3[6];
            Vector3[] row1 = new Vector3[6];

            uint indices = 0;

            //for(int i = 0; i < 16; i++)
            for (uint y = 0; y < 4; y++)
            {
                for (uint x = 0; x < 4; x++)
                {
                    uint i = y * 4 + x;

                    if (!set.isValidIndex(i))
                    {
                        // Skip masked pixels and out of bounds.
                        continue;
                    }

                    Vector3 color = new Vector3(set.color[i].x, set.color[i].y, set.color[i].z);

                    // Add error.
                    color += row0[1 + x];

                    float d0 = colorDistance(palette[0], color);
                    float d1 = colorDistance(palette[1], color);
                    float d2 = colorDistance(palette[2], color);
                    float d3 = colorDistance(palette[3], color);

                    uint b0 = d0 > d3?(uint)1:(uint)0;
                    uint b1 = d1 > d2?(uint)1:(uint)0;
                    uint b2 = d0 > d2?(uint)1:(uint)0;
                    uint b3 = d1 > d3?(uint)1:(uint)0;
                    uint b4 = d2 > d3?(uint)1:(uint)0;

                    uint x0 = b1 & b2;
                    uint x1 = b0 & b3;
                    uint x2 = b0 & b4;

                    uint index = x2 | ((x0 | x1) << 1);
                    indices |= index << (int)(2 * i);

                    // Compute new error.
                    Vector3 diff = color - palette[index];

                    // Propagate new error.
                    //row0[1+x+1] += 7.0f / 16.0f * diff;
                    //row1[1+x-1] += 3.0f / 16.0f * diff;
                    //row1[1+x+0] += 5.0f / 16.0f * diff;
                    //row1[1+x+1] += 1.0f / 16.0f * diff;
                }

                swap(ref row0, ref row1);
                row1 = new Vector3[6];
            }

            return(indices);
        }