ポインタを++したら次のピクセルってあたりが直感的で良いですね。
その前にとりあえずウィンドウを適当に表示するところから。
#include <windows.h>
LRESULT CALLBACK wndProc(
HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam )
{
switch (msg)
{
case WM_DESTROY:
ShowWindow( hWnd, SW_HIDE );
PostQuitMessage(0);
break;
case WM_CREATE:
break;
case WM_PAINT:
{
PAINTSTRUCT ps = {0};
HDC hdc = BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
}
break;
default:
return DefWindowProc( hWnd, msg, wParam, lParam );
}
return 0;
}
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PSTR lpCmdLine,
int nCmdShow )
{
LPCTSTR WINDOW_NAME = TEXT("sample");
WNDCLASSEX wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = reinterpret_cast<WNDPROC>( wndProc );
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.cbSize = sizeof( WNDCLASSEX );
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground= reinterpret_cast<HBRUSH>( GetStockObject(WHITE_BRUSH) );
wc.lpszMenuName = NULL;
wc.lpszClassName= WINDOW_NAME;
if ( !RegisterClassEx(&wc) ) return 0;
LONG winWidth = 640
+ GetSystemMetrics(SM_CXEDGE)
+ GetSystemMetrics(SM_CXBORDER)
+ GetSystemMetrics(SM_CXDLGFRAME);
LONG winHeight = 480
+ GetSystemMetrics(SM_CYEDGE)
+ GetSystemMetrics(SM_CYBORDER)
+ GetSystemMetrics(SM_CYDLGFRAME)
+ GetSystemMetrics(SM_CYCAPTION);
HWND hWnd = CreateWindowEx(
0, WINDOW_NAME, NULL,
WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME,
CW_USEDEFAULT, CW_USEDEFAULT,
winWidth, winHeight,
NULL, NULL, hInstance, NULL);
if ( !hWnd ) return -1;
ShowWindow( hWnd, SW_SHOWNORMAL );
UpdateWindow( hWnd );
MSG msg;
for (;;)
{
if ( !GetMessage(&msg, NULL, 0, 0) ) break;
TranslateMessage( &msg );
DispatchMessage( &msg );
}
UnregisterClass( WINDOW_NAME, hInstance );
return msg.wParam;
}
クライアント領域が640x480のなんもないウィンドウが出てきたところで本題。
■初期化処理、終了処理
DIBはメモリを確保してパラメータをちょちょいと設定してやればすぐ使えます。
扱いやすくクラスにしています。
class DIB32
{
public:
DIB32()
: m_pixel( NULL )
{
ZeroMemory( &m_bmi, sizeof(m_bmi) );
}
~DIB32()
{
release();
}
bool create( LONG width, LONG height )
{
if ( width <= 0 || height <= 0 )
{
return false;
}
release();
m_pixel = new DWORD[ width * height ];
if ( !m_pixel ) return false;
m_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_bmi.bmiHeader.biWidth = width;
m_bmi.bmiHeader.biHeight = height;
m_bmi.bmiHeader.biPlanes = 1;
m_bmi.bmiHeader.biBitCount = 32; //32bit固定にする
m_bmi.bmiHeader.biCompression = BI_RGB;
m_bmi.bmiHeader.biXPelsPerMeter = 3780; //96dpiだと3780らしい。0の場合もあるとのこと
m_bmi.bmiHeader.biYPelsPerMeter = 3780;
return true;
}
void release()
{
if ( m_pixel )
{
delete [] m_pixel;
m_pixel = NULL;
}
ZeroMemory( &m_bmi, sizeof(m_bmi) );
}
private:
LPDWORD m_pixel;
BITMAPINFO m_bmi;
};
生成処理のcreate()と解放処理のrelease()、あとコンストラクタとデストラクタのみのクラスです。
create()にてm_pixelにピクセルデータ用のメモリを、m_bmiにDIB情報をセットします。
release()ではピクセルデータの解放をするぐらいです。
32bitDIB限定なので、BITMAPINFOでなく横幅と高さだけ情報があればどうにでもなるんですが、レンダリングするときにBITMAPINFOがあると楽なのでBITMAPINFOを使用しています。
■レンダリング
HDCにDIBを描画するときはStretchDIBitsあたりを使うと楽チンです。拡大縮小もばっちり。
#include <windows.h>
class DIB32
{
public:
DIB32()
: m_pixel( NULL )
{
ZeroMemory( &m_bmi, sizeof(m_bmi) );
}
~DIB32()
{
release();
}
bool create( LONG width, LONG height )
{
if ( width <= 0 || height <= 0 )
{
return false;
}
release();
m_pixel = new DWORD[ width * height ];
if ( !m_pixel ) return false;
m_bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_bmi.bmiHeader.biWidth = width;
m_bmi.bmiHeader.biHeight = height;
m_bmi.bmiHeader.biPlanes = 1;
m_bmi.bmiHeader.biBitCount = 32; //32bit固定にする
m_bmi.bmiHeader.biCompression = BI_RGB;
m_bmi.bmiHeader.biXPelsPerMeter = 3780; //96dpiだと3780らしい。0の場合もあるとのこと
m_bmi.bmiHeader.biYPelsPerMeter = 3780;
return true;
}
void release()
{
if ( m_pixel )
{
delete [] m_pixel;
m_pixel = NULL;
}
ZeroMemory( &m_bmi, sizeof(m_bmi) );
}
bool render(
HDC hdc,
LONG destX, LONG destY,
LONG destWidth, LONG destHeight,
LONG srcX, LONG srcY,
LONG srcWidth, LONG srcHeight ) const
{
return GDI_ERROR != StretchDIBits(
hdc, destX, destY, destWidth, destHeight,
srcX, srcY, srcWidth, srcHeight,
m_pixel, &m_bmi, DIB_RGB_COLORS, SRCCOPY );
}
LONG getWidth() const { return m_bmi.bmiHeader.biWidth; }
LONG getHeight() const { return m_bmi.bmiHeader.biHeight; }
private:
LPDWORD m_pixel;
BITMAPINFO m_bmi;
};
LRESULT CALLBACK wndProc(
HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam )
{
static DIB32 image;
switch (msg)
{
case WM_DESTROY:
ShowWindow( hWnd, SW_HIDE );
PostQuitMessage(0);
break;
case WM_CREATE:
image.create( 320, 240 );
break;
case WM_PAINT:
{
PAINTSTRUCT ps = {0};
HDC hdc = BeginPaint( hWnd, &ps );
image.render( hdc );
EndPaint( hWnd, &ps );
}
break;
default:
return DefWindowProc( hWnd, msg, wParam, lParam );
}
return 0;
}
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PSTR lpCmdLine,
int nCmdShow )
{
LPCTSTR WINDOW_NAME = TEXT("sample");
WNDCLASSEX wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = reinterpret_cast<WNDPROC>( wndProc );
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.cbSize = sizeof( WNDCLASSEX );
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground= reinterpret_cast<HBRUSH>( GetStockObject(WHITE_BRUSH) );
wc.lpszMenuName = NULL;
wc.lpszClassName= WINDOW_NAME;
if ( !RegisterClassEx(&wc) ) return 0;
LONG winWidth = 640
+ GetSystemMetrics(SM_CXEDGE)
+ GetSystemMetrics(SM_CXBORDER)
+ GetSystemMetrics(SM_CXDLGFRAME);
LONG winHeight = 480
+ GetSystemMetrics(SM_CYEDGE)
+ GetSystemMetrics(SM_CYBORDER)
+ GetSystemMetrics(SM_CYDLGFRAME)
+ GetSystemMetrics(SM_CYCAPTION);
HWND hWnd = CreateWindowEx(
0, WINDOW_NAME, NULL,
WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME,
CW_USEDEFAULT, CW_USEDEFAULT,
winWidth, winHeight,
NULL, NULL, hInstance, NULL);
if ( !hWnd ) return -1;
ShowWindow( hWnd, SW_SHOWNORMAL );
UpdateWindow( hWnd );
MSG msg;
for (;;)
{
if ( !GetMessage(&msg, NULL, 0, 0) ) break;
TranslateMessage( &msg );
DispatchMessage( &msg );
}
UnregisterClass( WINDOW_NAME, hInstance );
return msg.wParam;
}
確保したメモリを初期化してないので変な色がでてますが、仕様です。
さらっとgetWidth()、getHeight()を追加しています。
ウィンドいっぱいにレンダリングしたいときは
bool render( HWND hWnd, HDC hdc ) const
{
RECT rect;
if ( GetClientRect( hWnd, &rect ) )
{
return render( hdc,
0, 0, rect.right, rect.bottom,
0, 0, getWidth(), getHeight() );
}
return false;
}
といった関数を用意すると便利です。
■関連記事:
生産がす: 32bitDIB(1) 作成と破棄
生産がす: 32bitDIB(2) 画像読み込み
生産がす: 32bitDIB(3) 塗りつぶし
生産がす: 32bitDIB(4) DIBに描画
生産がす: 32bitDIB(5) ファイルに出力
生産がす: 32bitDIB(6) 拡大縮小描画
生産がす: 32bitDIB(7) DIBSection
生産がす: DIB(8) - 直線描画
生産がす: DIB(9) - 回転描画
生産がす: DIB(10) - 三角形描画
生産がす: 日記ちゃん半透明合成
生産がす: 32bitDIBから無圧縮AVI2.0
0 件のコメント:
コメントを投稿