描画関係をDirec3Dでやるようになってすぐ、プログラムの起動が異様に遅くなった。調べてみるとBitmapからテクスチャを生成する際にえらく時間がかかっていた。うちの環境では512x512のテクスチャ生成するのに40秒以上かかる。Bitmapのコンストラクタや、Graphics.DrawImageでも一瞬で終わるのに・・・。
調べてみると、やっぱりTexture.FromBitmapはあまりにも遅いとの評判だった(内部的にはGDI+のGetPixel→SetPixelをやってるとか。あほか。)。で、じゃあどうやって速くすんねんということで・・・。
ビットマップからテクスチャーを作る-山に生きる
http://d.hatena.ne.jp/pmoky/20040811↑を参考にさしてもらって、SurfaceからGraphicsを取得し、DrawImageで描画。おお!速い!けど、アルファ入りのフォーマット扱えないのは辛いなあ・・・。
ということで、同じ記事の
NyaRuRu氏のコメントを参考に、Bitmap.LockBitsとTexture.LockRectangleを使って、データ丸写しという危ない橋を渡る事に・・・。
以下、Bitmapを元にテクスチャを生成するメソッド。
//テクスチャ読み込みメソッド
Texture LoadTexture(Bitmap src)
{
//Direct3Dのテクスチャの幅・高さは2の累乗でないといけないので、
//元となるBitmapが収まるテクスチャサイズを算出。
int h = 1;
int w = 1;
while (w < src.Width) { w *= 2; }
while (h < src.Height) { h *= 2; }
width = w;
height = h;
//サイズを考慮したBitmapに移す
Bitmap bmp = new Bitmap(w, h);
Graphics g = Graphics.FromImage(bmp);
g.Clear(Color.Transparent);
g.DrawImage(src, 0, 0);
g.Dispose();
//空のテクスチャ用意
Texture tex = new Texture(dev,w,h,0,Usage.Dynamic,Format.A8R8G8B8,Pool.Default);
//上記テクスチャをロック
//Bitmapのデータとタテヨコが逆になってるようなのでHeight、Widthの順
SurfaceDescription desc = tex.GetLevelDescription(0);
UInt32[,] buf = (UInt32[,])tex.LockRectangle(typeof(UInt32), 0,
LockFlags.None, desc.Height, desc.Width);
//元となるBitmapをロックしてbyteの配列に移す
BitmapData bmpdata = bmp.LockBits(new Rectangle(0,0,w , h),ImageLockMode.ReadWrite,PixelFormat.Format32bppArgb);
IntPtr ptr = bmpdata.Scan0;
byte[] temp = new byte[bmpdata.Width * bmpdata.Height * 4];
Marshal.Copy(ptr,temp,0,bmpdata.Width * bmpdata.Height * 4);
//データ取得できたのでBitmapアンロック
bmp.UnlockBits(bmpdata);
//取得したBitmapのデータをテクスチャに移す
for (int y = 0; y <= bmpdata.Height - 1; y++)
{
for (int x = 0; x <= bmpdata.Width - 1; x++)
{
//Byte×4をUInt32×1にしつつ、
//タテ・ヨコを逆にしてコピーしていく
buf[y,x] = (UInt32)temp[y * bmpdata.Width * 4 + x * 4]
+ (UInt32)temp[y * bmpdata.Width * 4 + x * 4 + 1] * 256
+ (UInt32)temp[y * bmpdata.Width * 4 + x * 4 + 2] * 65536
+ (UInt32)temp[y * bmpdata.Width * 4 + x * 4 + 3] * 256 * 65536;
}
}
//テクスチャをアンロック
tex.UnlockRectangle(0);
return tex;
}
例外処理とか一切無いので注意。
なお、昨日アップしたファイルでは、サイズの変更が片手落ちだったので、新しいのをアップしときます。
PenzSDK20080205.cs