Direct2D禁止图像随窗口缩放

Direct2D取代DirectDraw已经有几年了,网上的中文资料还是少之又少,所幸找到了这位大佬的文章:https://www.cnblogs.com/graphics/category/412802.html
先是做完了环境配置,结果编译运行,发现图像会随着窗口缩放而被拉伸:
Direct2D禁止图像随窗口缩放_第1张图片
这和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);

这里调用Rendertargetresize()函数是为了使渲染目标与窗口大小保持一致,这样渲染区域就不会被拉伸。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;
}

Direct2D禁止图像随窗口缩放_第2张图片

你可能感兴趣的:(c++)