Direct2D取代DirectDraw已经有几年了,网上的中文资料还是少之又少,所幸找到了这位大佬的文章:https://www.cnblogs.com/graphics/category/412802.html
先是做完了环境配置,结果编译运行,发现图像会随着窗口缩放而被拉伸:
这和GDI大有不同,于是开始在网上找答案,结果发现自己不能用,最后自己摸索了一下,写了几行代码搞定了。
这是zdd大佬文章里的代码:
#include
#include // header for Direct2D
#define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;}
ID2D1Factory* pD2DFactory = NULL ; // Direct2D factory
ID2D1HwndRenderTarget* pRenderTarget = NULL; // Render target
ID2D1SolidColorBrush* pBlackBrush = NULL ; // A black brush, reflect the line color
RECT rc ; // Render area
HWND g_Hwnd ; // Window handle
VOID CreateD2DResource(HWND hWnd)
{
if (!pRenderTarget)
{
HRESULT hr ;
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory) ;
if (FAILED(hr))
{
MessageBox(hWnd, "Create D2D factory failed!", "Error", 0) ;
return ;
}
// Obtain the size of the drawing area
GetClientRect(hWnd, &rc) ;
// Create a Direct2D render target
hr = pD2DFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hWnd,
D2D1::SizeU(rc.right - rc.left,rc.bottom - rc.top)
),
&pRenderTarget
) ;
if (FAILED(hr))
{
MessageBox(hWnd, "Create render target failed!", "Error", 0) ;
return ;
}
// Create a brush
hr = pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&pBlackBrush
) ;
if (FAILED(hr))
{
MessageBox(hWnd, "Create brush failed!", "Error", 0) ;
return ;
}
}
}
VOID DrawRectangle()
{
CreateD2DResource(g_Hwnd) ;
pRenderTarget->BeginDraw() ;
// Clear background color white
pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
// Draw Rectangle
pRenderTarget->DrawRectangle(
D2D1::RectF(100.f, 100.f, 500.f, 500.f),
pBlackBrush
);
HRESULT hr = pRenderTarget->EndDraw() ;
if (FAILED(hr))
{
MessageBox(NULL, "Draw failed!", "Error", 0) ;
return ;
}
}
VOID Cleanup()
{
SAFE_RELEASE(pRenderTarget) ;
SAFE_RELEASE(pBlackBrush) ;
SAFE_RELEASE(pD2DFactory) ;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
DrawRectangle() ;
ValidateRect(g_Hwnd, NULL) ;
return0 ;
case WM_KEYDOWN:
{
switch( wParam )
{
case VK_ESCAPE:
SendMessage( hwnd, WM_CLOSE, 0, 0 );
break ;
default:
break ;
}
}
break ;
case WM_DESTROY:
Cleanup();
PostQuitMessage( 0 );
return0;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow )
{
WNDCLASSEX winClass ;
winClass.lpszClassName ="Direct2D";
winClass.cbSize =sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW;
winClass.lpfnWndProc = WndProc;
winClass.hInstance = hInstance;
winClass.hIcon = NULL ;
winClass.hIconSm = NULL ;
winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
winClass.hbrBackground = NULL ;
winClass.lpszMenuName = NULL;
winClass.cbClsExtra =0;
winClass.cbWndExtra =0;
if (!RegisterClassEx (&winClass))
{
MessageBox ( NULL, TEXT( "This program requires Windows NT!" ), "error", MB_ICONERROR) ;
return 0 ;
}
g_Hwnd = CreateWindowEx(NULL,
"Direct2D", // window class name
"Draw Rectangle", // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
600, // initial x size
600, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (g_Hwnd, iCmdShow) ;
UpdateWindow (g_Hwnd) ;
MSG msg ;
ZeroMemory(&msg, sizeof(msg)) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
可以看到在WndProc()
里面并没有处理窗口大小改变的代码,那就来写一下:
case WM_SIZE:
D2D1_SIZE_U resize;
resize.height = HIWORD(lParam);
resize.width = LOWORD(lParam);
pRenderTarget->Resize(&resize);
这里调用Rendertarget
的resize()
函数是为了使渲染目标与窗口大小保持一致,这样渲染区域就不会被拉伸。lParam的高位字节为窗口高度,低位字节为窗口宽度。
最后的成品代码:
#include
#include "D2DCore.h"
#define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;}
ID2D1Factory* pD2DFactory = NULL; // Direct2D factory
ID2D1HwndRenderTarget* pRenderTarget = NULL; // Render target
ID2D1SolidColorBrush* pBlackBrush = NULL; // A black brush, reflect the line color
RECT rc; // Render area
HWND g_Hwnd; // Window handle
VOID CreateD2DResource(HWND hWnd)
{
if (!pRenderTarget)
{
HRESULT hr;
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &pD2DFactory);
if (FAILED(hr))
{
MessageBox(hWnd, "Create D2D factory failed!", "Error", 0);
return;
}
// Obtain the size of the drawing area
GetClientRect(hWnd, &rc);
// Create a Direct2D render target
hr = pD2DFactory->CreateHwndRenderTarget(
D2D1::RenderTargetProperties(),
D2D1::HwndRenderTargetProperties(
hWnd,
D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)
),
&pRenderTarget
);
if (FAILED(hr))
{
MessageBox(hWnd, "Create render target failed!", "Error", 0);
return;
}
// Create a brush
hr = pRenderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Black),
&pBlackBrush
);
if (FAILED(hr))
{
MessageBox(hWnd, "Create brush failed!", "Error", 0);
return;
}
}
}
VOID DrawRectangle()
{
CreateD2DResource(g_Hwnd);
pRenderTarget->BeginDraw();
// Clear background color white
pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));
// Draw Rectangle
pRenderTarget->DrawRectangle(
D2D1::RectF(100.f, 100.f, 500.f, 500.f),
pBlackBrush
);
HRESULT hr = pRenderTarget->EndDraw();
if (FAILED(hr))
{
MessageBox(NULL, "Draw failed!", "Error", 0);
return;
}
}
VOID Cleanup()
{
SAFE_RELEASE(pRenderTarget);
SAFE_RELEASE(pBlackBrush);
SAFE_RELEASE(pD2DFactory);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
printf("WM_PAINT");
DrawRectangle();
ValidateRect(g_Hwnd, NULL);
return 0;
case WM_KEYDOWN:
{
switch (wParam)
{
case VK_ESCAPE:
SendMessage(hwnd, WM_CLOSE, 0, 0);
break;
default:
break;
}
}
break;
case WM_DESTROY:
Cleanup();
PostQuitMessage(0);
return 0;
case WM_SIZE:
D2D1_SIZE_U resize;
resize.height = HIWORD(lParam);
resize.width = LOWORD(lParam);
pRenderTarget->Resize(&resize);
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
WNDCLASSEX winClass;
winClass.lpszClassName = "Direct2D";
winClass.cbSize = sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW;
winClass.lpfnWndProc = WndProc;
winClass.hInstance = hInstance;
winClass.hIcon = NULL;
winClass.hIconSm = NULL;
winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
winClass.hbrBackground = NULL;
winClass.lpszMenuName = NULL;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
if (!RegisterClassEx(&winClass))
{
MessageBox(NULL, TEXT("This program requires Windows NT!"), "error", MB_ICONERROR);
return 0;
}
g_Hwnd = CreateWindowEx(NULL,
"Direct2D", // window class name
"Draw Rectangle", // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
600, // initial x size
600, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL); // creation parameters
ShowWindow(g_Hwnd, iCmdShow);
UpdateWindow(g_Hwnd);
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}