public static void GetDXT(Texture2D texture, int i, byte[] bytes, TextureFormat format)
        {
            Color32[] colors = texture.GetPixels32(i);
            uint w = (uint) texture.width>>i;
            uint h = (uint) texture.height>>i;

            ColorBlock rgba = new ColorBlock();
            BlockDXT1 block1 = new BlockDXT1();
            BlockDXT5 block5 = new BlockDXT5();

            int blocksize = format == TextureFormat.DXT1 ? 8 : 16;
            int index = 0;
            for (uint y = 0; y < h; y += 4) {
                for (uint x = 0; x < w; x += 4) {
                    rgba.init(w, h, colors, x, y);

                    if (format == TextureFormat.DXT1)
                    {
                        QuickCompress.compressDXT1(rgba, block1);
                        block1.WriteBytes(bytes, index);
                    }
                    else
                    {
                        QuickCompress.compressDXT5(rgba, block5, 0);
                        block5.WriteBytes(bytes, index);
                    }

                    index += blocksize;
                }
            }
        }
예제 #2
0
        public void init(ColorBlock src, uint channel)
        {
            // Colors are in BGRA format.
            if (channel == 0) channel = 2;
            else if (channel == 2) channel = 0;

            for (uint i = 0; i < 16; i++)
            {
                alpha[i] = src.color[i].component()[channel];
                weights[i] = 1.0f;
            }
        }
        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);
        }
 void compressDXT5A(ColorBlock src, AlphaBlockDXT5 dst)
 {
     AlphaBlock4x4 tmp = new AlphaBlock4x4();
     tmp.init(src, 3);
     compressDXT5A(tmp, dst);
 }
        /*void OptimalCompress::initLumaTables() {

            // For all possible color pairs:
            for (int c0 = 0; c0 < 65536; c0++) {
                for (int c1 = 0; c1 < 65536; c1++) {

                    // Compute

                }
            }

            for (int r = 0; r < 1<<5; r++) {
                for (int g = 0; g < 1<<6; g++) {
                    for (int b = 0; b < 1<<5; b++) {

                    }
                }
            }
        }*/
        // Brute force Luma compressor
        void compressDXT1_Luma(ColorBlock rgba, BlockDXT1 block)
        {
            // F_YR = 19595/65536.0f, F_YG = 38470/65536.0f, F_YB = 7471/65536.0f;
            // 195841
            //if (

            /*
                byte ming = 63;
                byte maxg = 0;

                bool isSingleColor = true;
                byte singleColor = rgba.color(0).g;

                // Get min/max green.
                for (uint i = 0; i < 16; i++)
                {
                        byte green = (rgba.color[i].g + 1) >> 2;
                        ming = min(ming, green);
                        maxg = max(maxg, green);

                        if (rgba.color[i].g != singleColor) isSingleColor = false;
                }

                if (isSingleColor)
                {
                        compressDXT1G(singleColor, block);
                        return;
                }

                block.col0.r = 31;
                block.col1.r = 31;
                block.col0.g = maxg;
                block.col1.g = ming;
                block.col0.b = 0;
                block.col1.b = 0;

                int bestError = computeGreenError(rgba, block);
                int bestg0 = maxg;
                int bestg1 = ming;

                // Expand search space a bit.
                 int greenExpand = 4;
                ming = (ming <= greenExpand) ? 0 : ming - greenExpand;
                maxg = (maxg >= 63-greenExpand) ? 63 : maxg + greenExpand;

                for (int g0 = ming+1; g0 <= maxg; g0++)
                {
                        for (int g1 = ming; g1 < g0; g1++)
                        {
                                block.col0.g = g0;
                                block.col1.g = g1;
                                int error = computeGreenError(rgba, block, bestError);

                                if (error < bestError)
                                {
                                        bestError = error;
                                        bestg0 = g0;
                                        bestg1 = g1;
                                }
                        }
                }

                block.col0.g = bestg0;
                block.col1.g = bestg1;

                nvDebugCheck(bestg0 == bestg1 || block.isFourColorMode());
            */

            Color32[] palette = new Color32[4];
            block.evaluatePalette(palette, false); // @@ Use target decoder.
            block.indices = computeGreenIndices(rgba, palette);
        }
        // Brute force green channel compressor
        void compressDXT1G(ColorBlock rgba, BlockDXT1 block)
        {
            byte ming = 63;
            byte maxg = 0;

            bool isSingleColor = true;
            byte singleColor = rgba.color[0].g;

            // Get min/max green.
            for (uint i = 0; i < 16; i++)
            {
                byte green = (byte)((rgba.color[i].g + 1) >> 2);
                ming = Math.Min(ming, green);
                maxg = Math.Max(maxg, green);

                if (rgba.color[i].g != singleColor) isSingleColor = false;
            }

            if (isSingleColor)
            {
                compressDXT1G(singleColor, block);
                return;
            }

            block.col0.r = 31;
            block.col1.r = 31;
            block.col0.g = maxg;
            block.col1.g = ming;
            block.col0.b = 0;
            block.col1.b = 0;

            uint bestError = computeGreenError(rgba, block);
            byte bestg0 = maxg;
            byte bestg1 = ming;

            // Expand search space a bit.
            int greenExpand = 4;
            ming = (byte)((ming <= greenExpand) ? 0 : ming - greenExpand);
            maxg = (byte)((maxg >= 63 - greenExpand) ? 63 : maxg + greenExpand);

            for (byte g0 = (byte)(ming + 1); g0 <= maxg; g0++)
            {
                for (byte g1 = ming; g1 < g0; g1++)
                {
                    block.col0.g = g0;
                    block.col1.g = g1;
                    uint error = computeGreenError(rgba, block, bestError);

                    if (error < bestError)
                    {
                        bestError = error;
                        bestg0 = g0;
                        bestg1 = g1;
                    }
                }
            }

            block.col0.g = bestg0;
            block.col1.g = bestg1;

            Color32[] palette = new Color32[4];
            block.evaluatePalette(palette, false); // @@ Use target decoder.
            block.indices = computeGreenIndices(rgba, palette);
        }
        static uint computeGreenIndices(ColorBlock rgba, Color32[] palette)
        {
            int color0 = palette[0].g;
            int color1 = palette[1].g;
            int color2 = palette[2].g;
            int color3 = palette[3].g;

            uint indices = 0;
            for (uint i = 0; i < 16; i++)
            {
                int color = rgba.color[i].g;

                uint d0 = greenDistance(color0, color);
                uint d1 = greenDistance(color1, color);
                uint d2 = greenDistance(color2, color);
                uint d3 = greenDistance(color3, 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;

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

            return indices;
        }
        /*static uint nearestGreen4(uint green, uint maxGreen, uint minGreen)
        {
                uint bias = maxGreen + (maxGreen - minGreen) / 6;

                uint index = 0;
                if (maxGreen - minGreen != 0) index = clamp(3 * (bias - green) / (maxGreen - minGreen), 0U, 3U);

                return (index * minGreen + (3 - index) * maxGreen) / 3;
        }*/
        static uint computeGreenError(ColorBlock rgba, BlockDXT1 block, uint bestError = uint.MaxValue)
        {
            //      uint g0 = (block.col0.g << 2) | (block.col0.g >> 4);
            //      uint g1 = (block.col1.g << 2) | (block.col1.g >> 4);

            int[] palette = new int[4];
            palette[0] = (block.col0.g << 2) | (block.col0.g >> 4);
            palette[1] = (block.col1.g << 2) | (block.col1.g >> 4);
            palette[2] = (2 * palette[0] + palette[1]) / 3;
            palette[3] = (2 * palette[1] + palette[0]) / 3;

            uint totalError = 0;
            for (uint i = 0; i < 16; i++)
            {
                int green = rgba.color[i].g;

                uint error = greenDistance(green, palette[0]);
                error = Math.Min(error, greenDistance(green, palette[1]));
                error = Math.Min(error, greenDistance(green, palette[2]));
                error = Math.Min(error, greenDistance(green, palette[3]));

                totalError += error;

                //      totalError += nearestGreen4(green, g0, g1);

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

            return totalError;
        }
        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);
            }
        }
        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;
        }