Windows Desktop Application (1-2-4-4th) Your first Direct2D program

Keywords: Windows

Let's create our first Direct2D program. There's nothing special about this program -- it just draws a circle that fills the client area of the window. But this program introduces many important Direct2D concepts.

Screen capture of Circle program.

This is the code list of Circle programs. The program is reused in Managing application state BaseWindow class defined in the topic. Later topics will examine the code in detail.

#include<windows.h>
#include<d2d1.h>
#pragma comment(lib, "d2d1")
#include"basewin.h"
template<class T>
void SafeRelease(T **ppT){
    if(*ppT){
        (*ppT)->Release();
        *ppT=NULL;
    }
}
class MainWindow:public BaseWindow<MainWindow>{
    ID2D1Factory *pFactory;
    ID2D1HwndRenderTarget *pRenderTarget;
    ID2D1SolidColorBrush *pBrush;
    D2D1_ELLIPSE ellipse;
    void CalculateLayout();
    HRESULT CreateGraphicsResources();
    void DiscardGraphicsResources();
    void OnPaint();
    void Resize();
    public:
    MainWindow():pFactory(NULL),pRenderTarget(NULL),pBrush(NULL){}
    PCWSTR ClassName()const{
        return L"Circle Window Class";
    }
    LRESULT HandleMessage(UINT uMsg,WPARAM wParam,LPARAM lParam);
};
// Recalculate drawing layout when the size of the window changes.
void MainWindow::CalculateLayout(){
    if(pRenderTarget!=NULL){
        D2D1_SIZE_F size=pRenderTarget->GetSize();
        const float x=size.width/2;
        const float y=size.height/2;
        const float radius=min(x,y);
        ellipse=D2D1::Ellipse(D2D1::Point2F(x,y),radius,radius);
    }
}
HRESULT MainWindow::CreateGraphicsResources(){
    HRESULT hr=S_OK;
    if(pRenderTarget==NULL){
        RECT rc;
        GetClientRect(m_hwnd,&rc);
        D2D1_SIZE_U size=D2D1::SizeU(rc.right,rc.bottom);
        hr=pFactory->CreateHwndRenderTarget(
            D2D1::RenderTargetProperties(),
            D2D1::HwndRenderTargetProperties(m_hwnd,size),
            &pRenderTarget
        );
        if(SUCCEEDED(hr)){
            const D2D1_COLOR_F color=D2D1::ColorF(1.0f,1.0f,0);
            hr=pRenderTarget->CreateSolidColorBrush(color,&pBrush);
            if(SUCCEEDED(hr))
                CalculateLayout();
        }
    }
    return hr;
}
void MainWindow::DiscardGraphicsResources(){
    SafeRelease(&pRenderTarget);
    SafeRelease(&pBrush);
}
void MainWindow::OnPaint(){
    HRESULT hr=CreateGraphicsResources();
    if(SUCCEEDED(hr)){
        PAINTSTRUCT ps;
        BeginPaint(m_hwnd,&ps);
        pRenderTarget->BeginDraw();
        pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::SkyBlue));
        pRenderTarget->FillEllipse(ellipse,pBrush);
        hr=pRenderTarget->EndDraw();
        if(FAILED(hr)||hr==D2DERR_RECREATE_TARGET)
            DiscardGraphicsResources();
        EndPaint(m_hwnd,&ps);
    }
}
void MainWindow::Resize(){
    if(pRenderTarget!=NULL){
        RECT rc;
        GetClientRect(m_hwnd,&rc);
        D2D1_SIZE_U size=D2D1::SizeU(rc.right,rc.bottom);
        pRenderTarget->Resize(size);
        CalculateLayout();
        InvalidateRect(m_hwnd,NULL,FALSE);
    }
}
int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE,PWSTR,int nCmdShow){
    MainWindow win;
    if(!win.Create(L"Circle",WS_OVERLAPPEDWINDOW))
        return 0;
    ShowWindow(win.Window(),nCmdShow);
    // Run the message loop.
    MSG msg={};
    while(GetMessage(&msg,NULL,0,0)){
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return 0;
}
LRESULT MainWindow::HandleMessage(UINT uMsg,WPARAM wParam,LPARAM lParam){
    switch(uMsg){
        case WM_CREATE:
            if(FAILED(D2D1CreateFactory(
                D2D1_FACTORY_TYPE_SINGLE_THREADED,&pFactory
            )))
                return -1;// Fail CreateWindowEx.
            return 0;
        case WM_DESTROY:
            DiscardGraphicsResources();
            SafeRelease(&pFactory);
            PostQuitMessage(0);
            return 0;
        case WM_PAINT:
            OnPaint();
            return 0;
        case WM_SIZE:
            Resize();
            return 0;
    }
    return DefWindowProc(m_hwnd,uMsg,wParam,lParam);
}

You can learn from Direct2D Circle Sample Download the complete Visual Studio project.
D2D1 namespace
The D2D1 namespace contains helper functions and classes. These are not part of the Direct2D API -- you can program them without using Direct2D -- but they help simplify your code. The D2D1 namespace contains:

  • Used to construct color values ColorF Class.
  • For constructing transformation matrices Matrix3x2F.
  • A set of functions to initialize the Direct2D structure.

You will see an example of the D2D1 namespace throughout the module.
Next
Presentation objectives, equipment and resources
Related topics
Direct2D Circle Sample

Links to the original text: Your First Direct2D Program

Posted by filn on Wed, 06 Feb 2019 21:48:16 -0800