Direct2D基于Windows窗体,因此必须了解一些基本的Windows窗体编程:
首先,最基本的,可以使用Windows API写一个窗体:
#include <Windows.h>
typedef LRESULT (* message_callback)(HWND, WPARAM, LPARAM);
struct message_handler
{
UINT message;
message_callback handler;
};
static message_handler s_handlers[] =
{
{
WM_PAINT, [] (HWND window, WPARAM, LPARAM) -> LRESULT
{
PAINTSTRUCT ps;
BeginPaint(window, &ps);
OutputDebugString(L"PAINT!\r\n");
EndPaint(window, &ps);
return 0;
}
},
{
WM_DESTROY, [] (HWND, WPARAM, LPARAM) -> LRESULT
{
PostQuitMessage(0);
return 0;
}
}
};
int __stdcall wWinMain(HINSTANCE module, HINSTANCE, PWSTR, int)
{
WNDCLASS wc = {};
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hInstance = module;
wc.lpszClassName = L"window";
wc.lpfnWndProc = [] (HWND window, UINT message, WPARAM wparam, LPARAM lparam) -> LRESULT
{
for (auto h = s_handlers; h != s_handlers + _countof(s_handlers); ++h)
{
if (message == h->message)
{
return h->handler(window, wparam, lparam);
}
}
return DefWindowProc(window, message, wparam, lparam);
};
RegisterClass(&wc);
auto hwnd = CreateWindow(wc.lpszClassName, L"title", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
nullptr, nullptr, module, nullptr);
MSG message;
BOOL result;
while (result = GetMessage(&message, 0, 0, 0))
{
if (result != -1)
{
DispatchMessage(&message);
}
}
}
然后,加入ATL库后,窗体编程的事件过程可以简化很多:
#include <Windows.h>
#include <atlbase.h>
#include <atlwin.h>
struct SampleWindow :
CWindowImpl<SampleWindow, CWindow, CWinTraits<WS_OVERLAPPEDWINDOW | WS_VISIBLE>>
{
DECLARE_WND_CLASS_EX(L"window", CS_HREDRAW | CS_VREDRAW, -1);
BEGIN_MSG_MAP(SampleWindow)
MESSAGE_HANDLER(WM_PAINT, PaintHandler)
MESSAGE_HANDLER(WM_DESTROY, DestroyHandler)
END_MSG_MAP()
LRESULT PaintHandler(UINT, WPARAM, LPARAM, BOOL&)
{
PAINTSTRUCT ps;
BeginPaint(&ps);
EndPaint(&ps);
return 0;
}
LRESULT DestroyHandler(UINT, WPARAM, LPARAM, BOOL&)
{
PostQuitMessage(0);
return 0;
}
};
int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
SampleWindow window;
window.Create(nullptr, 0, L"Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE);
MSG message;
BOOL result;
while (result = GetMessage(&message, 0, 0, 0))
{
if (result != -1)
{
DispatchMessage(&message);
}
}
}
要加入D2D1,需要引入COM组件,然而,COM比较复杂,微软引用WRL来简化COM的一些引用计数之类的操作,以下是一个基本的D2D1示例(显示一个带颜色的窗体):
#include "Precompiled.h"
#include <d2d1.h>
#include <wrl.h>
#pragma comment(lib, "d2d1")
using namespace D2D1;
using namespace Microsoft::WRL;
struct SampleWindow
: CWindowImpl<SampleWindow, CWindow, CWinTraits<WS_OVERLAPPEDWINDOW | WS_VISIBLE>>
{
ComPtr<ID2D1Factory> m_factory;
ComPtr<ID2D1HwndRenderTarget> m_target;
DECLARE_WND_CLASS_EX(L"My D2D1 Window", CS_HREDRAW | CS_VREDRAW, -1);
BEGIN_MSG_MAP(SampleWindow)
MESSAGE_HANDLER(WM_PAINT, PaintHandler)
MESSAGE_HANDLER(WM_DESTROY, DestroyHandler)
MESSAGE_HANDLER(WM_SIZE, SizeHandler)
MESSAGE_HANDLER(WM_DISPLAYCHANGE, DisplayChangeHandler)
END_MSG_MAP()
LRESULT DisplayChangeHandler(UINT, WPARAM, LPARAM, BOOL&)
{
Invalidate();
return 0;
}
LRESULT SizeHandler(UINT, WPARAM, LPARAM lparam, BOOL&)
{
if (m_target)
{
if (m_target->Resize(SizeU(LOWORD(lparam), HIWORD(lparam))) != S_OK)
{
m_target.Reset();
}
}
return 0;
}
LRESULT PaintHandler(UINT, WPARAM, LPARAM, BOOL&)
{
PAINTSTRUCT ps;
VERIFY(BeginPaint(&ps));
Render();
EndPaint(&ps);
return 0;
}
LRESULT DestroyHandler(UINT, WPARAM, LPARAM, BOOL&)
{
PostQuitMessage(0);
return 0;
}
void Invalidate()
{
VERIFY(InvalidateRect(nullptr, false))
}
void Create()
{
D2D1_FACTORY_OPTIONS fo = {};
#ifdef DEBUG
fo.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION;
#endif
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED,
fo,
m_factory.GetAddressOf());
CreateDeviceIndependentResources();
VERIFY(__super::Create(nullptr, 0, L"title"));
}
void CreateDeviceIndependentResources()
{
}
void CreateDeviceResources()
{
}
void Render()
{
if (!m_target)
{
RECT rect;
VERIFY(GetClientRect(&rect));
auto size = SizeU(rect.right, rect.bottom);
m_factory->CreateHwndRenderTarget(RenderTargetProperties(),
HwndRenderTargetProperties(m_hWnd, size),
m_target.GetAddressOf());
CreateDeviceResources();
}
if (!(m_target->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED))
{
m_target->BeginDraw();
Draw();
if (m_target->EndDraw() == D2DERR_RECREATE_TARGET)
{
m_target.Reset();
}
}
}
void Draw()
{
m_target->Clear(ColorF(1.0f, 1.0f, 0.0f));
}
};
int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
{
SampleWindow window;
window.Create();
MSG msg;
BOOL result;
while (result = GetMessage(&msg, 0, 0, 0))
{
if (result != -1)
{
DispatchMessage(&msg);
}
}
}
不得不说的是,这些示例和我原来在网上和书上看到的很不一样,感觉他写的更加优雅,通过他的讲解,可以很容易理解。
More content at http://pluralsight.com, Direct2D Fundamentals