前段时间稍微看了点Direct3D, 觉得挺有意思的,但是想着要有3D得先从2D开始。故开始了D2D旅行。
如标题所示,CreateHwndRenderTarget 是在用来创建一个渲染到窗口的渲染目标。
创建渲染目标并且可以使用硬件加速时,可以在计算机的GPU上分配资源。通过一次创建渲染目标并保留尽可能长的时间,您可以获得性能上的好处。您的应用程序应一次创建渲染目标,并在应用程序的生命周期内或在收到D2DERR_RECREATE_TARGET错误之前将其保留。收到此错误时,您需要重新创建渲染目标(及其创建的所有资源)。
它与CreateDCRenderTarget最大的区别,也就是GDI的绘图技巧与D2D的区别了。
我的个人理解是,前者是自己在GPU上创建渲染目标,并停留一段时间用来绘制,不用我们操心上下文的环境了。 而后者的作用是
创建一个绘制目标,以绘制到Windows图形设备接口(GDI)设备上下文。
很显然它是用来充当D2D与GDI的交互的。
这篇文档是介绍这个作用的, Direct2D and GDI Interoperability Overview
在代码上使用肯定也是有区别的。
前者的使用,可以先看D2D入门的代码,下面的代码是用来将图片绘制到窗口上,
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <Windows.h> #include <d2d1.h> #include <d2d1_1.h> #include <wincodec.h> #pragma comment(lib, "d2d1.lib") #pragma comment(lib, "Windowscodecs.lib") #define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;} extern "C" ID2D1Bitmap * mybitmapcreate(ID2D1DCRenderTarget*); float left = 5; float top = 10; float Bottom = 10; float Right = 30; ID2D1Bitmap* pBitmap = NULL; IWICImagingFactory* pIWICFactory = NULL; HWND hWnd; ID2D1HwndRenderTarget* m_pRenderTarget; void initize(); void draw(); D2D1_RECT_F myrect = D2D1::RectF(left, top, Bottom, Right); ID2D1Bitmap* mybitmap; ID2D1Factory* l; REFIID x = __uuidof(ID2D1Factory); HRESULT LoadBitmapFromFile( ID2D1RenderTarget* pRenderTarget, IWICImagingFactory* pIWICFactory, PCWSTR uri, UINT destinationWidth, UINT destinationHeight ) { HRESULT hr = S_OK; IWICBitmapDecoder* pDecoder = NULL; IWICBitmapFrameDecode* pSource = NULL; IWICStream* pStream = NULL; IWICFormatConverter* pConverter = NULL; IWICBitmapScaler* pScaler = NULL; hr = pIWICFactory->CreateDecoderFromFilename( uri, NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &pDecoder ); if (SUCCEEDED(hr)) { // Create the initial frame. hr = pDecoder->GetFrame(0, &pSource); } if (SUCCEEDED(hr)) { hr = pIWICFactory->CreateFormatConverter(&pConverter); } // If a new width or height was specified, create an // IWICBitmapScaler and use it to resize the image. if (destinationWidth != 0 || destinationHeight != 0) { UINT originalWidth, originalHeight; hr = pSource->GetSize(&originalWidth, &originalHeight); if (SUCCEEDED(hr)) { if (destinationWidth == 0) { FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight); destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth)); } else if (destinationHeight == 0) { FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth); destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight)); } hr = pIWICFactory->CreateBitmapScaler(&pScaler); if (SUCCEEDED(hr)) { hr = pScaler->Initialize( pSource, destinationWidth, destinationHeight, WICBitmapInterpolationModeCubic ); } if (SUCCEEDED(hr)) { hr = pConverter->Initialize( pScaler, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut ); } } } if (SUCCEEDED(hr)) { // Create a Direct2D bitmap from the WIC bitmap. hr = pRenderTarget->CreateBitmapFromWicBitmap( pConverter, NULL, &pBitmap ); } SAFE_RELEASE(pDecoder); SAFE_RELEASE(pSource); SAFE_RELEASE(pStream); SAFE_RELEASE(pConverter); SAFE_RELEASE(pScaler); return TRUE; } LRESULT CALLBACK WndProcFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { RECT rc; switch (message) { case WM_PAINT: { draw(); } break; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, message, wParam, lParam); } int main(int argc, char* argv[]) { WNDCLASS wc{}; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProcFunc; wc.hInstance = GetModuleHandle(NULL); wc.lpszClassName = L"Class_Name"; wc.hCursor = LoadCursor(nullptr, IDC_ARROW); RegisterClass(&wc); hWnd = CreateWindow(L"Class_Name", L"Test", WS_OVERLAPPEDWINDOW, 100, 100, 1000, 500, NULL, NULL, GetModuleHandle(NULL), NULL); initize(); ShowWindow(hWnd, 1); UpdateWindow(hWnd); MSG Msg; while (GetMessage(&Msg, NULL, 0, 0)) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return 0; } void initize() { CoInitializeEx(NULL, COINIT_MULTITHREADED); CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, reinterpret_cast<void**>(&pIWICFactory)); HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &l); RECT rc; GetClientRect(hWnd, &rc); D2D1_SIZE_U size = D2D1::SizeU( rc.right - rc.left, rc.bottom - rc.top ); // Create a Direct2D render target. hr = l->CreateHwndRenderTarget( D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties(hWnd, size), &m_pRenderTarget ); } void draw() { LoadBitmapFromFile(m_pRenderTarget, pIWICFactory, L"timg.bmp", 650, 400); m_pRenderTarget->BeginDraw(); m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White)); D2D1_SIZE_F size = pBitmap->GetSize(); D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(0.f, 0.f); // Draw bitmap m_pRenderTarget->DrawBitmap( pBitmap, D2D1::RectF( upperLeftCorner.x, upperLeftCorner.y, upperLeftCorner.x + size.width, upperLeftCorner.y + size.height) ); m_pRenderTarget->EndDraw(); }
后者则是需要使用ID2D1DCRenderTarget::BindDC 将渲染目标绑定到向其发出绘图命令的设备上下文。
需要更改的代码部分,
//创建DC的渲染目标 ID2D1DCRenderTarget* pow; ... void initize() { CoInitializeEx(NULL, COINIT_MULTITHREADED); CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, reinterpret_cast<void**>(&pIWICFactory)); HRESULT hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &l); D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties( D2D1_RENDER_TARGET_TYPE_DEFAULT, D2D1::PixelFormat( DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE), 0, 0, D2D1_RENDER_TARGET_USAGE_NONE, D2D1_FEATURE_LEVEL_DEFAULT ); l->CreateDCRenderTarget(&props, &pow); } void draw() { LoadBitmapFromFile(m_pRenderTarget, pIWICFactory, L"timg.bmp", 650, 400); pow->BeginDraw(); pow->Clear(D2D1::ColorF(D2D1::ColorF::White)); D2D1_SIZE_F size = pBitmap->GetSize(); D2D1_POINT_2F upperLeftCorner = D2D1::Point2F(0.f, 0.f); // Draw bitmap pow->DrawBitmap( pBitmap, D2D1::RectF( upperLeftCorner.x, upperLeftCorner.y, upperLeftCorner.x + size.width, upperLeftCorner.y + size.height) ); pow->EndDraw(); } case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rc); pow->BindDC(ps.hdc, &rc); draw(); EndPaint(hwnd, &ps); } break; ...