private static byte[] DxtEncode(Bitmap img, bool dxt1, DxtAlphaMode dxtAlpha) { int width = img.Width; int height = img.Height; PixelFormat pixelFormat = img.PixelFormat; BitmapData imgData = img.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, pixelFormat); byte[] data = new byte[imgData.Height * imgData.Stride]; Marshal.Copy(imgData.Scan0, data, 0, data.Length); img.UnlockBits(imgData); return(DxtEncode(data, width, height, dxtAlpha, pixelFormat)); }
private static byte[] DxtEncode(byte[] data, int width, int height, DxtAlphaMode dxtAlpha = DxtAlphaMode.DXT5, PixelFormat pixelFormat = PixelFormat.Format32bppArgb) { int bpp = 3; if (pixelFormat == PixelFormat.Format32bppArgb) { bpp = 4; } byte[] Out = new byte[((width / 4 * (height / 4)) * (dxtAlpha != DxtAlphaMode.None ? 16 : 8))]; int outOffset = 0; for (int tileY = 0; tileY < height / 4; tileY++) { for (int tileX = 0; tileX < width / 4; tileX++) { byte[] block = new byte[8]; //Calculo de Luminância mín/máx byte minLuma = 0xff; byte maxLuma = 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 = ((tileX * 4) + x + (((tileY * 4) + y) * 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 < minLuma) { minR = r; minG = g; minB = b; minLuma = luma; } if (luma > maxLuma) { maxR = r; maxG = g; maxB = b; maxLuma = 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[] pixelColor = new Color[4]; ushort c0 = Read16(block, 0); ushort c1 = Read16(block, 2); pixelColor[0] = GetColorFromBgr565(c0); pixelColor[1] = GetColorFromBgr565(c1); pixelColor[2] = ProcessDxt1ColorChannel(2, c0, c1, true); pixelColor[3] = ProcessDxt1ColorChannel(3, c0, c1, true); for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { int imageOffset = ((tileX * 4) + x + (((tileY * 4) + y) * width)) * bpp; byte r = data[imageOffset + 2]; byte g = data[imageOffset + 1]; byte b = data[imageOffset]; int luma = (int)(0.257f * r + 0.504f * g + 0.098f * b + 16); int minDiff = 0xff; int index = 0; for (int i = 0; i < 4; i++) { int testLuma = (int)(0.257f * pixelColor[i].R + 0.504f * pixelColor[i].G + 0.098f * pixelColor[i].B + 16); int diff = Math.Abs(testLuma - luma); if (diff < minDiff) { minDiff = diff; index = i; } } block[4 + y] |= (byte)(index << (x * 2)); } } byte[] alphaBlock = new byte[8]; if (dxtAlpha == DxtAlphaMode.DXT3) { for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { int imageOffset = ((tileX * 4) + x + (((tileY * 4) + y) * width)) * bpp; byte a = (byte)(data[imageOffset + 3] >> 4); alphaBlock[(y * 2) + (x / 2)] |= (byte)(a << ((x % 2) * 4)); } } Buffer.BlockCopy(alphaBlock, 0, Out, outOffset, alphaBlock.Length); outOffset += alphaBlock.Length; } else if (dxtAlpha == DxtAlphaMode.DXT5) { byte minAlpha = 0xff; byte maxAlpha = 0; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { int offset = ((tileX * 4) + x + (((tileY * 4) + y) * width)) * bpp; byte a = data[offset + 3]; if (a < minAlpha) { minAlpha = a; } if (a > maxAlpha) { maxAlpha = a; } } } byte[] alpha = new byte[8]; alpha[0] = minAlpha; alpha[1] = maxAlpha; alphaBlock[0] = alpha[0]; alphaBlock[1] = alpha[1]; Dxt5CalculateAlphas(alpha); uint alphaVal = 0; byte shift = 0; int alphaBlockOffset = 2; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { int imageOffset = ((tileX * 4) + x + (((tileY * 4) + y) * width)) * bpp; byte a = data[imageOffset + 3]; int minDiff = 0xff; byte index = 0; for (int i = 0; i < 8; i++) { int diff = Math.Abs(alpha[i] - a); if (diff < minDiff) { minDiff = diff; index = (byte)i; } } alphaVal |= (uint)((index & 7) << shift); shift += 3; if (shift == 24) { Buffer.BlockCopy(BitConverter.GetBytes(alphaVal), 0, alphaBlock, alphaBlockOffset, 3); alphaVal = 0; shift = 0; alphaBlockOffset += 3; } } } Buffer.BlockCopy(alphaBlock, 0, Out, outOffset, alphaBlock.Length); outOffset += alphaBlock.Length; } Buffer.BlockCopy(block, 0, Out, outOffset, block.Length); outOffset += block.Length; } } return(Out); }