アドベンチャーゲームなどではメッセージウィンドウが半透明になっていて 下の絵が透けているという画面が良く見られます。Direct X を使えば 簡単に出来そうですが(と言っていも Direct X は良く知らないので 出来るかどうかしりませんが)、GDI の場合はそんな API は無いので 自分でルーチンを書かなければなりません。
半透明処理の基本的な考え方は、元の絵とマスクしたい色を足して平均を 取るということです。つまり、元の絵のある座標(x,y) の点の色が RGB(r,g,b) で、マスクしたい色が RGB(R,G,B) だとしたら、半透明処理を した後の点(x,y) の色は RGB((r+R)/2,(g+G)/2,(b+B)/2) となります。
まあ、詳しくは下のソースをみて下さい。 CreateSemiTransBmp() が実際に半透明処理を行っている関数で、元の ビットマップ(hSrcBitmap) の矩形範囲(x,y)-(x+FWIDTH,y+FHEIGHT) に 対して半透明処理をして 24bitDIB(hDib)に保存しています。結果は こんなふうになります。
// 半透明処理サンプル 99/2/17
// (C) tokai@fides.dti.ne.jp
#include < windows.h>
#define WINWIDTH 480 // ウィンドウの幅
#define WINHEIGHT 180 // ウィンドウの高さ
#define FWIDTH 100 // 枠の幅
#define FHEIGHT 50 // 枠の高さ
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
VOID CreateSemiTransBmp(HDC,HBITMAP,HBITMAP,LPBYTE,LONG,LONG,RGBQUAD);
char szClassName[] = "HANTOMEI";
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPreInst,
LPSTR lpszCmdLine,int nCmdShow)
{
HWND hWnd;
MSG lpMsg;
WNDCLASS wndClass;
// ウィンドウ登録
if (!hPreInst) {
wndClass.style=CS_HREDRAW|CS_VREDRAW;
wndClass.lpfnWndProc=WndProc;
wndClass.cbClsExtra=0;
wndClass.cbWndExtra=0;
wndClass.hInstance=hInst;
wndClass.hIcon= NULL;
wndClass.hCursor=LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName=NULL;
wndClass.lpszClassName=szClassName;
if (!RegisterClass(&wndClass)) return FALSE;
}
// ウィンドウ作成
hWnd = CreateWindow(szClassName,
"半透明",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,
WINWIDTH,WINHEIGHT,NULL,NULL,hInst,NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// メッセージループ
while (GetMessage(&lpMsg, NULL, 0, 0)) {
TranslateMessage(&lpMsg);
DispatchMessage(&lpMsg);
}
return (lpMsg.wParam);
}
// プロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
static HINSTANCE hInst;
HDC hDC,hMemDC;
RECT rt;
static HDC hBufDC;
static HBITMAP hBufBit,hBgBitmap,hDib;
static LPBYTE lpDibBuf,lpDibData;
static LPBITMAPINFO lpBitInfo;
static RGBQUAD rgbMask;
CHAR szStr[256];
switch (msg) {
case WM_CREATE: // 初期化
// インスタンス取得
hInst = (HINSTANCE)GetWindowLong(hWnd,GWL_HINSTANCE);
// ビットマップロード(test.bmp)
hBgBitmap = (HBITMAP)LoadImage(hInst,"test.bmp",
IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
// 裏画面の作成
GetClientRect(hWnd,&rt);
hDC = GetDC(hWnd);
hBufBit = CreateCompatibleBitmap(hDC,rt.right - rt.left,
rt.bottom - rt.top);
hBufDC = CreateCompatibleDC(hDC);
SelectObject(hBufDC,hBufBit);
ReleaseDC(hWnd,hDC);
// ビットマップ貼り付け
hMemDC = CreateCompatibleDC(hBufDC);
SelectObject(hMemDC,hBgBitmap);
BitBlt(hBufDC,0,0,rt.right - rt.left,rt.bottom - rt.top,
hMemDC,0,0,SRCCOPY);
DeleteDC(hMemDC);
// 24bit DIB 作成
// ビットマップインフォ構造体設定
lpBitInfo = (LPBITMAPINFO)GlobalAlloc(GPTR,sizeof(BITMAPINFO));
lpBitInfo-> bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
lpBitInfo-> bmiHeader.biWidth=FWIDTH;
lpBitInfo-> bmiHeader.biHeight=FHEIGHT;
lpBitInfo-> bmiHeader.biPlanes=1;
lpBitInfo-> bmiHeader.biBitCount=24; // 24 bit
lpBitInfo-> bmiHeader.biCompression=BI_RGB; // 非圧縮
hDC = GetDC(hWnd);
hDib = CreateDIBSection(hDC,lpBitInfo,0,(VOID**)&lpDibData,
NULL, 0);
ReleaseDC(hWnd,hDC);
// マスクの色設定
rgbMask.rgbBlue=0;
rgbMask.rgbGreen=0;
rgbMask.rgbRed=0;
break;
case WM_PAINT: // 描画(再描画のみ)
PAINTSTRUCT ps;
hDC = BeginPaint(hWnd,&ps);
BitBlt(hDC,ps.rcPaint.left,ps.rcPaint.top,
ps.rcPaint.right-ps.rcPaint.left,
ps.rcPaint.bottom-ps.rcPaint.top,
hBufDC,ps.rcPaint.left,ps.rcPaint.top,SRCCOPY);
ReleaseDC(hWnd,hDC);
break;
case WM_LBUTTONDOWN: // 左ボタン押した
GetClientRect(hWnd,&rt);
// 半透明処理
CreateSemiTransBmp(hBufDC,hBgBitmap,hDib,lpDibData,
LOWORD(lp),HIWORD(lp),rgbMask);
hMemDC = CreateCompatibleDC(hBufDC);
// ビットマップ貼り付け
SelectObject(hMemDC,hBgBitmap);
BitBlt(hBufDC,0,0,rt.right - rt.left,rt.bottom - rt.top,
hMemDC,0,0,SRCCOPY);
// DIB 貼り付け
SelectObject(hMemDC,hDib);
BitBlt(hBufDC,LOWORD(lp),HIWORD(lp),FWIDTH,FHEIGHT,
hMemDC,0,0,SRCCOPY);
DeleteDC(hMemDC);
// 文字描画
SetBkMode(hBufDC,TRANSPARENT);
SetTextColor(hBufDC,RGB(255,255,0)) ;
rt.left = LOWORD(lp);
rt.top = HIWORD(lp);
rt.right = rt.left + FWIDTH;
rt.bottom = rt.top + FHEIGHT;
wsprintf(szStr,"半透明っす");
DrawText(hBufDC,szStr,strlen(szStr),&rt,
DT_CENTER|DT_SINGLELINE|DT_VCENTER);
InvalidateRect(hWnd,NULL,FALSE);
break;
case WM_CLOSE: // クローズ
// 裏画面開放
DeleteDC(hBufDC);
DeleteObject(hBufBit);
// ビットマップ開放
DeleteObject(hBgBitmap);
DeleteObject(hDib);
GlobalFree(lpBitInfo);
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return(DefWindowProc(hWnd, msg, wp, lp));
}
return (0L);
}
// hSrcBitmap の一部分を半透明処理して hDib にセットする関数
VOID CreateSemiTransBmp(HDC hDC,
HBITMAP hSrcBitmap, // 元のビットマップ
HBITMAP hDib, // DIB のハンドル
LPBYTE lpDibData, // DIB のデータ配列
LONG x, LONG y, // 座標
RGBQUAD rgbMask // マスク
){
HDC hSrcDC,hDestDC;
LONG dx,dy;
WORD r,g,b;
// 画像コピー
hSrcDC = CreateCompatibleDC(hDC);
hDestDC = CreateCompatibleDC(hDC);
SelectObject(hSrcDC,hSrcBitmap);
SelectObject(hDestDC,hDib);
BitBlt(hDestDC,0,0,FWIDTH,FHEIGHT,hSrcDC,x,y,SRCCOPY);
DeleteDC(hSrcDC);
DeleteDC(hDestDC);
// 半透明処理
for(dy = 0;dy< FHEIGHT;dy++)
for(dx = 0;dx< FWIDTH;dx++)
{
b = (WORD)lpDibData[(dy*FWIDTH+dx)*3];
g = (WORD)lpDibData[(dy*FWIDTH+dx)*3+1];
r = (WORD)lpDibData[(dy*FWIDTH+dx)*3+2];
lpDibData[(dy*FWIDTH+dx)*3] =
(BYTE)((b+(WORD)rgbMask.rgbBlue)>> 1);
lpDibData[(dy*FWIDTH+dx)*3+1] =
(BYTE)((g+(WORD)rgbMask.rgbGreen)>> 1);
lpDibData[(dy*FWIDTH+dx)*3+2] =
(BYTE)((r+(WORD)rgbMask.rgbRed)>> 1);
}
}