#region Using ステートメント using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Content.Pipeline.Graphics; using Microsoft.Xna.Framework.Graphics.PackedVector; #endregion namespace WpfFontPipeline { /// /// 単色テクスチャイメージに特化したDXT3テクスチャ圧縮クラス /// /// /// フォントなどの高周波成分を含んだ画像はDXT圧縮するべきではないが、 /// 乗算済みアルファの単色画像であればDXT圧縮ブロックを直接生成することで /// 劣化が少なく、かつテクスチャメモリ使用量を1/4にすることができる。 /// public static class SingleColorDxtCompressor { /// /// 指定された単色ビットマップ画像をDXT3テクスチャへ変換する /// /// 変換元画像 /// 単色カラー /// DXT3圧縮された画像 public static Dxt3BitmapContent Compress(PixelBitmapContent 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; } /// /// 圧縮ブロックの処理 /// /// 元画像 /// Xブロック位置 /// Yブロック位置 /// 単色カラー /// 出力先 /// 出力オフセット private static void CompressDxt3Block(PixelBitmapContent source, int blockX, int blockY, ushort color0, byte[] outputData, int outputIndex) { long alphaBits = 0; int rgbBits = 0; int pixelCount = 0; // 4x4ブロック内の処理 for (int y = 0; y < 4; ++y) { for (int x = 0; x < 4; ++x) { // 元のアルファ値の取得 int value = source.GetPixel(blockX + x, blockY + y).A; int alpha = 0; int rgb = 0; // アルファ値によって、出力値を決定。 // ここでは単純にアルファ値領域を4分割するのではなく、6分割にして // 1/6、1/2、5/6の非線形の閾値を使っている if (value < 256 / 6) { alpha = 0; rgb = 1; // c1色 = 0 } else if (value < 256 * 3 / 6) { alpha = 5; rgb = 3; // c3色 = 1/3(c0) + 2/3(c1) = 85 } else if (value < 256 * 5 / 6) { alpha = 10; rgb = 2; // c2色 = 1/2(c0) + 1/2(c1) = 127 } else { alpha = 15; rgb = 0; // c0色 = 255 } // 計算結果ビットを格納 alphaBits |= (long)alpha << (pixelCount * 4); rgbBits |= rgb << (pixelCount * 2); pixelCount++; } } // DXT3ブロック情報の出力 // アルファ 8バイト for (int i = 0; i < 8; ++i) { outputData[outputIndex + i] = (byte)(alphaBits >> (i * 8)); } // カラー値(c0, c1) 4バイト // c0 outputData[outputIndex + 8] = (byte)(color0 & 0xff); outputData[outputIndex + 9] = (byte)((color0 >> 8) & 0xff); // c1 outputData[outputIndex + 10] = 0x00; outputData[outputIndex + 11] = 0x00; // RGB情報 4バイト for (int i = 0; i < 4; ++i) { outputData[outputIndex + 12 + i] = (byte)(rgbBits >> (i * 8)); } } } }