/// <summary> /// 指定された単色ビットマップ画像をDXT3テクスチャへ変換する /// </summary> /// <param name="source">変換元画像</param> /// <param name="color0">単色カラー</param> /// <returns>DXT3圧縮された画像</returns> public static Dxt3BitmapContent Compress(PixelBitmapContent<Color> source, Color color0) { // DXT3ブロックデータを格納するためのバッファを確保 byte[] outputData = new byte[source.Width * source.Height]; // 単色カラーをBGR565に変換する ushort packedColor = new Bgr565(color0.ToVector3()).PackedValue; // 指定された画像を圧縮ブロック単位に処理をする int outputIndex = 0; for (int blockY = 0; blockY < source.Height; blockY += 4) { for (int blockX = 0; blockX < source.Width; blockX += 4) { CompressDxt3Block(source, blockX, blockY, packedColor, outputData, outputIndex); outputIndex += 16; } } // DXT3テクスチャの生成と圧縮したブロックデータの設定 var result = new Dxt3BitmapContent(source.Width, source.Height); result.SetPixelData(outputData); return result; }
// Compress the greyscale font texture page using a specially-formulated DXT3 mode static public unsafe void CompressFontDXT3(TextureContent content) { if (content.Faces.Count > 1) { throw new PipelineException("Font textures should only have one face"); } var block = new Vector4[16]; for (int i = 0; i < content.Faces[0].Count; ++i) { var face = content.Faces[0][i]; var xBlocks = (face.Width + 3) / 4; var yBlocks = (face.Height + 3) / 4; var dxt3Size = xBlocks * yBlocks * 16; var buffer = new byte[dxt3Size]; var bytes = face.GetPixelData(); fixed(byte *b = bytes) { Vector4 *colors = (Vector4 *)b; int w = 0; int h = 0; int x = 0; int y = 0; while (h < (face.Height & ~3)) { w = 0; x = 0; var h0 = h * face.Width; var h1 = h0 + face.Width; var h2 = h1 + face.Width; var h3 = h2 + face.Width; while (w < (face.Width & ~3)) { block[0] = colors[w + h0]; block[1] = colors[w + h0 + 1]; block[2] = colors[w + h0 + 2]; block[3] = colors[w + h0 + 3]; block[4] = colors[w + h1]; block[5] = colors[w + h1 + 1]; block[6] = colors[w + h1 + 2]; block[7] = colors[w + h1 + 3]; block[8] = colors[w + h2]; block[9] = colors[w + h2 + 1]; block[10] = colors[w + h2 + 2]; block[11] = colors[w + h2 + 3]; block[12] = colors[w + h3]; block[13] = colors[w + h3 + 1]; block[14] = colors[w + h3 + 2]; block[15] = colors[w + h3 + 3]; int offset = (x + y * xBlocks) * 16; CompressFontDXT3Block(block, buffer, offset); w += 4; ++x; } // Do partial block at end of row if (w < face.Width) { var cols = face.Width - w; Array.Clear(block, 0, 16); for (int r = 0; r < 4; ++r) { h0 = (h + r) * face.Width; for (int c = 0; c < cols; ++c) { block[(r * 4) + c] = colors[w + h0 + c]; } } int offset = (x + y * xBlocks) * 16; CompressFontDXT3Block(block, buffer, offset); } h += 4; ++y; } // Do last partial row if (h < face.Height) { var rows = face.Height - h; w = 0; x = 0; while (w < (face.Width & ~3)) { Array.Clear(block, 0, 16); for (int r = 0; r < rows; ++r) { var h0 = (h + r) * face.Width; block[(r * 4) + 0] = colors[w + h0 + 0]; block[(r * 4) + 1] = colors[w + h0 + 1]; block[(r * 4) + 2] = colors[w + h0 + 2]; block[(r * 4) + 3] = colors[w + h0 + 3]; } int offset = (x + y * xBlocks) * 16; CompressFontDXT3Block(block, buffer, offset); w += 4; ++x; } // Do last partial block if (w < face.Width) { var cols = face.Width - w; Array.Clear(block, 0, 16); for (int r = 0; r < rows; ++r) { var h0 = (h + r) * face.Width; for (int c = 0; c < cols; ++c) { block[(r * 4) + c] = colors[w + h0 + c]; } } int offset = (x + y * xBlocks) * 16; CompressFontDXT3Block(block, buffer, offset); } } } var dxt3 = new Dxt3BitmapContent(face.Width, face.Height); dxt3.SetPixelData(buffer); content.Faces[0][i] = dxt3; } }