<!DOCUMENT HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">

<html>

<head>
<meta http-equiv="Content-Language" content="ja">
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<link rel="stylesheet" type="text/css" href="../../default.css">
<title>ImageListでスプライト</title>
</head>


<body>
<!--#include virtual="../../menu2.html"-->
<div class="contents">
<h4>contents</h4>
<ol>
	<li><a href="#bitblt">BitBltでスプライト</a></li>
	<li><a href="#imagelist">ImageListでスプライト</a></li>
	<li><a href="#dnd">ImageListでDnD</a></li>
</ol>
</div>

<h1>ImageListでスプライト</h1>

<!--- Summary --->
<div>
<p>
ImageListは、複数のビットマップを管理するクラスです。
ToolbarやTreeCtrlなどに使われますが、あまり知られていない機能があり、ビットマップを描画させるだけに使っても便利です。
</p>
</div>

<h2 id="bitblt">BitBltでスプライト</h2>
<div>
<p>
	スプライトとは、透過色を指定できるビットマップ描画のことです。
	通常、WindowsGDIを使ってスプライトを行うには、ラスタオペレーションを用いて、以下のような処理を行います。
</p>
<ol>
<li>描画したい画像と、マスク画像（透過：白、非透過：黒）を用意する</li>
<li>マスク画像をSRCAND（AND演算）でBitBlt()する</li>
<li>描画したい画像をSRCPAINT（OR演算）でBitBlt()する</li>
</ol>
<p>
	また、マスク画像をカラーキーを指定して自動生成することもできます。
	そのための簡単な関数を作ってみました（<a href="SetColorKey.h">SetColorKey.h</a>, <a href="SetColorKey.zip">サンプルプロジェクト</a>）。
	BitBlt()とMaskBlt()の両方を使ってみました。
	マスク生成に関する詳しい情報は、<a href="http://homepage1.nifty.com/CavalierLab/">キャバリア研究所</a>さんの<a href="http://homepage1.nifty.com/CavalierLab/lab/win/transparent.html">画像の透過転送とマスクの自動生成</a>で解説されています。
</p>
</div>

<h2 id="imagelist">ImageListでスプライト</h2>
<div>
<p>
上記の方法は、けっこう面倒です。
CreateCompatibleDC()やらSelectObject()やら、ただビットマップを描画するだけでも関数がいくつか必要ですし。
ですが、ImageListを使うと非常に簡単に同様のことが行えます。
</p>
<p>
いまさら生のHIMAGELISTを使うことも無いので、MFC/WTLにあるCImageListを使います。
以下はWTLを想定していますが、MFCでもほとんど変わらないと思います。</p>
<p><pre><code>CImageList imagelist;

// 作成する
CBitmap bmp;	// 描画したい画像
COLORREF colorkey;	// カラーキー
CSize size;
bmp.GetSize(size);
imagelist.Create(size.cx, size.cy, ILC_COLOR??? | ILC_MASK, 8, 4);	// ???は4, 8, 16, 24, DDB
imagelist.SetBkColor(colorkey);	// or CLR_NONE
imagelist.Add(bmp, colorkey);

// 描画する
HDC hDC;	// 描画先
int index;	// イメージ番号
CPoint pos;	// 座標
imagelist.Draw(hDC, index, pos, ILD_TRANSPARENT);	// CLR_NONEならばILD_NORMALでもよい</code></pre></p>

<p>作成時もカラーキーを指定するだけですし、描画時もDraw()一発で済んでしまいます。
欠点は、同じ大きさの画像でないとImageListに保持できないことですが、GDIで作るようなゲーム（2DRPGやパズルゲーム？）ではタイル敷き詰め型だろうので、十分でしょう。</p>
<p>Bitmapリソースを引数に取るタイプのCreate()では自動的に16色（色数は環境依存）のImageListが作成されてしまいます。
空のImageListを作成したあと、Add()したほうが良いでしょう。</p>
<p>描画速度は、やはりILC_COLORDDBがもっとも高速です。
ただし、画面モードが変わった場合はDIBに変換されてしまいます。
（これは、普通のDDBitmapも同様です。）
引き続いてDDBを使いたい場合は、作り直さないといけません。
ゲームなどで、ウィンドウモード⇔フルスクリーンモードの切り替え機能をつけるときは注意が必要です。</p>
</div>

<h2 id="dnd">ImageListでDnD</h2>
<div>
<p>アプリケーション間ではなく、自分のアプリケーション内だけのドラッグ＆ドロップについてです。
使用目的は、ユニット配置シーンなどを想定しています。</p>
<p>以下は、CWnd もしくは CWindowImpl 内でのコードです。</p>
<p><pre><code>bool m_isDragging;

void OnLButtonDown(UINT key, CPoint pos)
{
    SetCapture();
    m_images.BeginDrag(0, 32, 32);
    ClientToScreen(&pos);
    m_images.DragShowNolock(TRUE);
    m_images.DragMove(pos);
    m_isDragging = true;
}
void OnMouseMove(UINT key, CPoint pos)
{
    if(m_isDragging)
    {
        // スナッピングなどを行いたい場合は、ここで。
        // pos.x = (pos.x % CellWidth) * CellWidth + CellWidth/2; とか。
        ClientToScreen(&pos);
        m_images.DragMove(pos);
    }
}
void OnLButtonUp(UINT key, CPoint pos)
{
    if(m_isDragging)
    {
        OnDrop(pos); // ドロップされたときの処理をする。
        m_isDragging = false;
        m_images.DragShowNolock(FALSE);
        m_images.EndDrag();
        ReleaseCapture();
    }
}</code></pre></p>
</div>

<hr>
<!--#config timefmt="%Y/%m/%d"-->
<p align="right"><!--#echo var='LAST_MODIFIED'--></p>

</body>
</html>
