Direct2D is based on Windows Forms, so you must understand some basic Windows Forms programming:
First, you can use Windows API to write a form:
View Code
#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); } }}
After the ATL library is added, the event process of form programming can be much simpler:
View Code
#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); } }}
To add D2D1, the COM component needs to be introduced. However, COM is complicated. Microsoft uses WRL to simplify operations such as reference counting of COM, the following is a basic D2D1 example (displaying a colored form ):
View Code
#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); } }}
I have to say that these examples are very different from what I have seen on the Internet and in books. I feel that he is writing more elegantly. It is easy to understand through his explanations.
More content at http://pluralsight.com, Direct2D Fundamentals