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