Example #1
0
        private static byte[] DXT_Encode(Bitmap Img, bool DXT1, Alpha_Mode Alpha)
        {
            BitmapData ImgData = Img.LockBits(new Rectangle(0, 0, Img.Width, Img.Height), ImageLockMode.ReadOnly, Img.PixelFormat);

            byte[] Data = new byte[ImgData.Height * ImgData.Stride];
            Marshal.Copy(ImgData.Scan0, Data, 0, Data.Length);
            Img.UnlockBits(ImgData);

            int BPP = 3;

            if (Img.PixelFormat == PixelFormat.Format32bppArgb)
            {
                BPP = 4;
            }

            byte[] Out        = new byte[(((Img.Width / 4) * (Img.Height / 4)) * (Alpha != Alpha_Mode.None ? 16 : 8))];
            int    Out_Offset = 0;

            for (int Tile_Y = 0; Tile_Y < Img.Height / 4; Tile_Y++)
            {
                for (int Tile_X = 0; Tile_X < Img.Width / 4; Tile_X++)
                {
                    byte[] Block = new byte[8];

                    //Calculo de Luminância mín/máx
                    byte Min_Luma = 0xff;
                    byte Max_Luma = 0;

                    byte minR = 0, maxR = 0;
                    byte minG = 0, maxG = 0;
                    byte minB = 0, maxB = 0;

                    for (int Y = 0; Y < 4; Y++)
                    {
                        for (int X = 0; X < 4; X++)
                        {
                            int Offset = ((Tile_X * 4) + X + (((Tile_Y * 4) + Y) * Img.Width)) * BPP;

                            byte R = Data[Offset + 2];
                            byte G = Data[Offset + 1];
                            byte B = Data[Offset];

                            byte Luma = (byte)(0.257f * R + 0.504f * G + 0.098f * B + 16);
                            if (Luma < Min_Luma)
                            {
                                minR = R;
                                minG = G;
                                minB = B;

                                Min_Luma = Luma;
                            }
                            if (Luma > Max_Luma)
                            {
                                maxR = R;
                                maxG = G;
                                maxB = B;

                                Max_Luma = Luma;
                            }
                        }
                    }

                    Block[2] = (byte)((minB >> 3) | ((minG & 0x1C) << 3));
                    Block[3] = (byte)(((minG & 0xE0) >> 5) | (minR & 0xF8));
                    Block[0] = (byte)((maxB >> 3) | ((maxG & 0x1C) << 3));
                    Block[1] = (byte)(((maxG & 0xE0) >> 5) | (maxR & 0xF8));

                    Color[] Pixel_Color = new Color[4];
                    ushort  c0          = Read16(Block, 0);
                    ushort  c1          = Read16(Block, 2);
                    Pixel_Color[0] = Get_Color_From_BGR565(c0);
                    Pixel_Color[1] = Get_Color_From_BGR565(c1);
                    Pixel_Color[2] = Process_DXT1_Color_Channel(2, c0, c1, true);
                    Pixel_Color[3] = Process_DXT1_Color_Channel(3, c0, c1, true);

                    for (int Y = 0; Y < 4; Y++)
                    {
                        for (int X = 0; X < 4; X++)
                        {
                            int Image_Offset = ((Tile_X * 4) + X + (((Tile_Y * 4) + Y) * Img.Width)) * BPP;

                            byte R = Data[Image_Offset + 2];
                            byte G = Data[Image_Offset + 1];
                            byte B = Data[Image_Offset];

                            int Luma = (int)(0.257f * R + 0.504f * G + 0.098f * B + 16);

                            int Min_Diff = 0xff;
                            int Index    = 0;
                            for (int i = 0; i < 4; i++)
                            {
                                int Test_Luma = (int)(0.257f * Pixel_Color[i].R + 0.504f * Pixel_Color[i].G + 0.098f * Pixel_Color[i].B + 16);
                                int Diff      = Math.Abs(Test_Luma - Luma);
                                if (Diff < Min_Diff)
                                {
                                    Min_Diff = Diff;
                                    Index    = i;
                                }
                            }

                            Block[4 + Y] |= (byte)(Index << (X * 2));
                        }
                    }

                    byte[] Alpha_Block = new byte[8];
                    if (Alpha == Alpha_Mode.DXT3)
                    {
                        for (int Y = 0; Y < 4; Y++)
                        {
                            for (int X = 0; X < 4; X++)
                            {
                                int Image_Offset = ((Tile_X * 4) + X + (((Tile_Y * 4) + Y) * Img.Width)) * BPP;

                                byte A = (byte)(Data[Image_Offset + 3] >> 4);

                                Alpha_Block[(Y * 2) + (X / 2)] |= (byte)(A << ((X % 2) * 4));
                            }
                        }

                        Buffer.BlockCopy(Alpha_Block, 0, Out, Out_Offset, Alpha_Block.Length);
                        Out_Offset += Alpha_Block.Length;
                    }
                    else if (Alpha == Alpha_Mode.DXT5)
                    {
                        byte Min_Alpha = 0xff;
                        byte Max_Alpha = 0;

                        for (int Y = 0; Y < 4; Y++)
                        {
                            for (int X = 0; X < 4; X++)
                            {
                                int Offset = ((Tile_X * 4) + X + (((Tile_Y * 4) + Y) * Img.Width)) * BPP;

                                byte A = Data[Offset + 3];

                                if (A < Min_Alpha)
                                {
                                    Min_Alpha = A;
                                }
                                if (A > Max_Alpha)
                                {
                                    Max_Alpha = A;
                                }
                            }
                        }

                        byte[] alpha = new byte[8];
                        alpha[0]       = Min_Alpha;
                        alpha[1]       = Max_Alpha;
                        Alpha_Block[0] = alpha[0];
                        Alpha_Block[1] = alpha[1];
                        DXT5_Calculate_Alphas(alpha);

                        uint alphaVal           = 0;
                        byte shift              = 0;
                        int  Alpha_Block_Offset = 2;
                        for (int Y = 0; Y < 4; Y++)
                        {
                            for (int X = 0; X < 4; X++)
                            {
                                int Image_Offset = ((Tile_X * 4) + X + (((Tile_Y * 4) + Y) * Img.Width)) * BPP;

                                byte A = Data[Image_Offset + 3];

                                int  Min_Diff = 0xff;
                                byte Index    = 0;
                                for (int i = 0; i < 8; i++)
                                {
                                    int Diff = Math.Abs(alpha[i] - A);
                                    if (Diff < Min_Diff)
                                    {
                                        Min_Diff = Diff;
                                        Index    = (byte)i;
                                    }
                                }

                                alphaVal |= (uint)((Index & 7) << shift);
                                shift    += 3;
                                if (shift == 24)
                                {
                                    Buffer.BlockCopy(BitConverter.GetBytes(alphaVal), 0, Alpha_Block, Alpha_Block_Offset, 3);
                                    alphaVal            = 0;
                                    shift               = 0;
                                    Alpha_Block_Offset += 3;
                                }
                            }
                        }

                        Buffer.BlockCopy(Alpha_Block, 0, Out, Out_Offset, Alpha_Block.Length);
                        Out_Offset += Alpha_Block.Length;
                    }

                    Buffer.BlockCopy(Block, 0, Out, Out_Offset, Block.Length);
                    Out_Offset += Block.Length;
                }
            }

            return(Out);
        }
Example #2
0
        private static byte[] DXT_Encode(Bitmap Img, bool DXT1, Alpha_Mode Alpha)
        {
            BitmapData ImgData = Img.LockBits(new Rectangle(0, 0, Img.Width, Img.Height), ImageLockMode.ReadOnly, Img.PixelFormat);
            byte[] Data = new byte[ImgData.Height * ImgData.Stride];
            Marshal.Copy(ImgData.Scan0, Data, 0, Data.Length);
            Img.UnlockBits(ImgData);

            int BPP = 3;
            if (Img.PixelFormat == PixelFormat.Format32bppArgb) BPP = 4;

            byte[] Out = new byte[(((Img.Width / 4) * (Img.Height / 4)) * (Alpha != Alpha_Mode.None ? 16 : 8))];
            int Out_Offset = 0;

            for (int Tile_Y = 0; Tile_Y < Img.Height / 4; Tile_Y++)
            {
                for (int Tile_X = 0; Tile_X < Img.Width / 4; Tile_X++)
                {
                    byte[] Block = new byte[8];

                    //Calculo de Luminância mín/máx
                    byte Min_Luma = 0xff;
                    byte Max_Luma = 0;

                    byte minR = 0, maxR = 0;
                    byte minG = 0, maxG = 0;
                    byte minB = 0, maxB = 0;

                    for (int Y = 0; Y < 4; Y++)
                    {
                        for (int X = 0; X < 4; X++)
                        {
                            int Offset = ((Tile_X * 4) + X + (((Tile_Y * 4) + Y) * Img.Width)) * BPP;

                            byte R = Data[Offset + 2];
                            byte G = Data[Offset + 1];
                            byte B = Data[Offset];

                            byte Luma = (byte)(0.257f * R + 0.504f * G + 0.098f * B + 16);
                            if (Luma < Min_Luma)
                            {
                                minR = R;
                                minG = G;
                                minB = B;

                                Min_Luma = Luma;
                            }
                            if (Luma > Max_Luma)
                            {
                                maxR = R;
                                maxG = G;
                                maxB = B;

                                Max_Luma = Luma;
                            }
                        }
                    }

                    Block[2] = (byte)((minB >> 3) | ((minG & 0x1C) << 3));
                    Block[3] = (byte)(((minG & 0xE0) >> 5) | (minR & 0xF8));
                    Block[0] = (byte)((maxB >> 3) | ((maxG & 0x1C) << 3));
                    Block[1] = (byte)(((maxG & 0xE0) >> 5) | (maxR & 0xF8));

                    Color[] Pixel_Color = new Color[4];
                    ushort c0 = Read16(Block, 0);
                    ushort c1 = Read16(Block, 2);
                    Pixel_Color[0] = Get_Color_From_BGR565(c0);
                    Pixel_Color[1] = Get_Color_From_BGR565(c1);
                    Pixel_Color[2] = Process_DXT1_Color_Channel(2, c0, c1, true);
                    Pixel_Color[3] = Process_DXT1_Color_Channel(3, c0, c1, true);

                    for (int Y = 0; Y < 4; Y++)
                    {
                        for (int X = 0; X < 4; X++)
                        {
                            int Image_Offset = ((Tile_X * 4) + X + (((Tile_Y * 4) + Y) * Img.Width)) * BPP;

                            byte R = Data[Image_Offset + 2];
                            byte G = Data[Image_Offset + 1];
                            byte B = Data[Image_Offset];

                            int Luma = (int)(0.257f * R + 0.504f * G + 0.098f * B + 16);

                            int Min_Diff = 0xff;
                            int Index = 0;
                            for (int i = 0; i < 4; i++)
                            {
                                int Test_Luma = (int)(0.257f * Pixel_Color[i].R + 0.504f * Pixel_Color[i].G + 0.098f * Pixel_Color[i].B + 16);
                                int Diff = Math.Abs(Test_Luma - Luma);
                                if (Diff < Min_Diff)
                                {
                                    Min_Diff = Diff;
                                    Index = i;
                                }
                            }

                            Block[4 + Y] |= (byte)(Index << (X * 2));
                        }
                    }

                    byte[] Alpha_Block = new byte[8];
                    if (Alpha == Alpha_Mode.DXT3)
                    {
                        for (int Y = 0; Y < 4; Y++)
                        {
                            for (int X = 0; X < 4; X++)
                            {
                                int Image_Offset = ((Tile_X * 4) + X + (((Tile_Y * 4) + Y) * Img.Width)) * BPP;

                                byte A = (byte)(Data[Image_Offset + 3] >> 4);

                                Alpha_Block[(Y * 2) + (X / 2)] |= (byte)(A << ((X % 2) * 4));
                            }
                        }

                        Buffer.BlockCopy(Alpha_Block, 0, Out, Out_Offset, Alpha_Block.Length);
                        Out_Offset += Alpha_Block.Length;
                    }
                    else if (Alpha == Alpha_Mode.DXT5)
                    {
                        byte Min_Alpha = 0xff;
                        byte Max_Alpha = 0;

                        for (int Y = 0; Y < 4; Y++)
                        {
                            for (int X = 0; X < 4; X++)
                            {
                                int Offset = ((Tile_X * 4) + X + (((Tile_Y * 4) + Y) * Img.Width)) * BPP;

                                byte A = Data[Offset + 3];

                                if (A < Min_Alpha) Min_Alpha = A;
                                if (A > Max_Alpha) Max_Alpha = A;
                            }
                        }

                        byte[] alpha = new byte[8];
                        alpha[0] = Min_Alpha;
                        alpha[1] = Max_Alpha;
                        Alpha_Block[0] = alpha[0];
                        Alpha_Block[1] = alpha[1];
                        DXT5_Calculate_Alphas(alpha);

                        uint alphaVal = 0;
                        byte shift = 0;
                        int Alpha_Block_Offset = 2;
                        for (int Y = 0; Y < 4; Y++)
                        {
                            for (int X = 0; X < 4; X++)
                            {
                                int Image_Offset = ((Tile_X * 4) + X + (((Tile_Y * 4) + Y) * Img.Width)) * BPP;

                                byte A = Data[Image_Offset + 3];

                                int Min_Diff = 0xff;
                                byte Index = 0;
                                for (int i = 0; i < 8; i++)
                                {
                                    int Diff = Math.Abs(alpha[i] - A);
                                    if (Diff < Min_Diff)
                                    {
                                        Min_Diff = Diff;
                                        Index = (byte)i;
                                    }
                                }

                                alphaVal |= (uint)((Index & 7) << shift);
                                shift += 3;
                                if (shift == 24)
                                {
                                    Buffer.BlockCopy(BitConverter.GetBytes(alphaVal), 0, Alpha_Block, Alpha_Block_Offset, 3);
                                    alphaVal = 0;
                                    shift = 0;
                                    Alpha_Block_Offset += 3;
                                }
                            }
                        }

                        Buffer.BlockCopy(Alpha_Block, 0, Out, Out_Offset, Alpha_Block.Length);
                        Out_Offset += Alpha_Block.Length;
                    }

                    Buffer.BlockCopy(Block, 0, Out, Out_Offset, Block.Length);
                    Out_Offset += Block.Length;
                }
            }

            return Out;
        }