描画Frameworkをつくってみた。
入手先
問題
WindowsXPでグラフィクスを描画するとき、3つの描画アーキテクチャがある。
- GDI
- GDI+
- DirectX9
これらは初期処理などの違いがあり、WndProc内の処理がかなり異なる。
初期化処理など毎回おなじ処理を書くのは面倒。Framework化したい。
WindowMessageを意識することなく描画を実装できるインタフェースがほしい。
解決
描画アーキテクチャ | インタフェース関数 | インタフェースclass |
---|---|---|
GDI | void Draw(HDC); |
IGdiDrawer |
GDI+ | void Draw(Gdiplus::Graphics*); |
IGdiPlusDrawer |
DirectX | void Draw(LPDIRECT3DDEVICE9); |
IDirectX9Drawer |
このインタフェースをFrameworkとして用意したい。 以後、これを継承して描画内容を実装できるようになれば、初期化処理などを書かずに済んで楽になる。
以下、Framework化したい枠組み。
GDI
LRESULT CALLBACK GdiWndProc::PartWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL* pIsReturn)
{
switch (uMsg) {
case WM_PAINT:
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd , &ps);
m_drawer->Draw(hdc);
EndPaint(hWnd , &ps);
break;
default:
break;
}
return (0L);
}
void GdiWndProc::Initialize() { m_drawer->Initialize(); }
void GdiWndProc::Finalize() { m_drawer->Finalize(); }
GDI+
LRESULT CALLBACK GdiPlusWndProc::PartWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL* pIsReturn)
{
switch (uMsg) {
case WM_CREATE:
Initialize();
break;
case WM_DESTROY:
Finalize();
break;
case WM_ERASEBKGND:
*pIsReturn = TRUE;
return TRUE;
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd , &ps);
Graphics g(hdc);
m_drawer->Draw(m_OffScreenGraphics);
g.DrawImage(m_OffScreenBitmap, 0, 0);
EndPaint(hWnd , &ps);
}
break;
default:
break;
}
return (0L);
}
void GdiPlusWndProc::Initialize()
{
if (NULL == m_gdiSI) {
m_gdiSI = new Gdiplus::GdiplusStartupInput;
GdiplusStartup(&m_gdiToken, m_gdiSI, NULL);
}
if (NULL == m_OffScreenBitmap) {
m_OffScreenBitmap = new Bitmap(GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
m_OffScreenGraphics = Graphics::FromImage(m_OffScreenBitmap);
}
if (NULL != m_drawer) { m_drawer->Initialize(); }
}
void GdiPlusWndProc::Finalize()
{
if (NULL != m_drawer) { m_drawer->Finalize(); }
if (NULL != m_OffScreenGraphics) {
m_OffScreenGraphics->Flush();
}
if (NULL != m_OffScreenBitmap) {;
delete m_OffScreenBitmap;
m_OffScreenBitmap = NULL;
}
if (NULL != m_OffScreenGraphics) {
delete m_OffScreenGraphics;
m_OffScreenGraphics = NULL;
}
if (NULL != m_gdiSI) {
delete m_gdiSI;
m_gdiSI = NULL;
GdiplusShutdown(m_gdiToken);
}
}
DirectX9
LRESULT CALLBACK DirectX9WndProc::PartWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL* pIsReturn)
{
switch (uMsg) {
case WM_CREATE:
Initialize();
break;
case WM_DESTROY:
Finalize();
break;
case WM_ERASEBKGND:
*pIsReturn = TRUE;
return TRUE;
default:
if (NULL == m_pD3DDev) { return (0L); }
m_drawer->Draw(m_pD3DDev);
break;
}
return (0L);
}
void DirectX9WndProc::Initialize()
{
// 事前にCreateWindow()されていなければDirectX9を初期化できない
HWND hWnd = GetActiveWindow();
if (NULL == hWnd) { return; }
if (NULL != m_pD3D) { return; }
if( !(m_pD3D = Direct3DCreate9( D3D_SDK_VERSION )) )
{
throw "Direct3DCreate9関数に失敗しました。";
}
D3DPRESENT_PARAMETERS d3dpp = { 0, 0, D3DFMT_UNKNOWN, 0, D3DMULTISAMPLE_NONE, 0, D3DSWAPEFFECT_DISCARD, NULL, TRUE, 0, D3DFMT_UNKNOWN, 0, 0 };
if( FAILED( m_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &m_pD3DDev ) ) )
{
m_pD3D->Release();
throw "DIRECT3D9.CreateDevice関数に失敗しました。";
}
if (NULL != m_drawer) { m_drawer->Initialize(); }
}
void DirectX9WndProc::Finalize()
{
if (NULL != m_drawer) { m_drawer->Finalize(); }
if (NULL != m_pD3DDev) {
m_pD3DDev->Release();
m_pD3DDev = NULL;
}
if (NULL != m_pD3D) {
m_pD3D->Release();
m_pD3D = NULL;
}
}
ソースコード一覧
課題
DrawerSetter
GraphicsArchitectureSetter
class で Drawer の生成や設定もしてしまっている。
しかも Drawer は固定である。
本来は Drawer も変動する。
この Drawer を任意につくることができるからこそFrameworkたりえるのに固定になってしまっている。
DrawerSetter
のような class を生成して変動することができるようにすべき。