directdraw 2D example code

다이얼로그 박스에 그림을 그릴 때 DC대신 directdraw를 사용한 간단한 예제다. 

1.다이얼로그 박스에 picture control을 추가한다. 



2. CStatic을 기본으로 하는 mfc class를 생성한다. 

DDraw2DCtrl.h

class CDDraw2DCtrl : public CStatic
{
       DECLARE_DYNAMIC(CDDraw2DCtrl)

private:
       user_lock                  m_lock;

       ID2D1Factory               *m_pD2DFactory;
       IDWriteFactory             *m_pDWriteFactory;
       ID2D1HwndRenderTarget       *m_pRenderTarget;
       ID2D1SolidColorBrush        *m_pBrush;
       IDWriteTextFormat           *m_pTextFormat;

       void DestoryD2D();
       BOOL CreateD2D();
       void Draw();

public:
       CDDraw2DCtrl();
       virtual ~CDDraw2DCtrl();

       afx_msg void OnPaint();
       afx_msg BOOL OnEraseBkgnd(CDC* pDC);
protected:
       DECLARE_MESSAGE_MAP()
};


DDraw2DCtrl.cpp

#include "stdafx.h"
#include "DDraw2DCtrl.h"

#ifndef SAFE_RELEASE
#define SAFE_RELEASE(x) if (x) { x->Release(); x = NULL;}
#endif

// CDDraw2DCtrl

IMPLEMENT_DYNAMIC(CDDraw2DCtrl, CStatic)

CDDraw2DCtrl::CDDraw2DCtrl()
{
       m_pD2DFactory = NULL;
       m_pDWriteFactory = NULL;
       m_pRenderTarget = NULL;
       m_pBrush = NULL;
       m_pTextFormat = NULL;
}

CDDraw2DCtrl::~CDDraw2DCtrl()
{
       DestoryD2D();
}


BEGIN_MESSAGE_MAP(CDDraw2DCtrl, CStatic)
       ON_WM_PAINT()
       ON_WM_ERASEBKGND()
END_MESSAGE_MAP()


// CDDraw2DCtrl 메시지 처리기입니다.

void CDDraw2DCtrl::OnPaint()
{
       CPaintDC dc(this); // device context for painting
       // TODO: Add your message handler code here
       // Do not call CStatic::OnPaint() for painting messages
       CUserAutoLock lock(&m_lock);
       Draw();
}

BOOL CDDraw2DCtrl::OnEraseBkgnd(CDC* pDC)
{
       return TRUE;
       //return CStatic::OnEraseBkgnd(pDC);
}

void CDDraw2DCtrl::DestoryD2D()
{
       SAFE_RELEASE(m_pBrush);
       SAFE_RELEASE(m_pTextFormat);
       SAFE_RELEASE(m_pRenderTarget);
       SAFE_RELEASE(m_pDWriteFactory);
       SAFE_RELEASE(m_pD2DFactory);
}

BOOL CDDraw2DCtrl::CreateD2D()
{
       HRESULT hr;
       RECT rc;

       if (m_pD2DFactory || !GetSafeHwnd())
             return FALSE;

       hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);
       if (FAILED(hr))
       {
             MessageBox(TEXT("D2D1CreateFactory fail"));
             return FALSE;
       }

       GetClientRect(&rc);

       D2D1_SIZE_U size = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);

       hr = m_pD2DFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(),
             D2D1::HwndRenderTargetProperties(GetSafeHwnd(), size),
             &m_pRenderTarget);

       if (FAILED(hr))
       {
             MessageBox(TEXT("m_pD2DFactory->CreateHwndRenderTarget fail"));
             DestoryD2D();
             return FALSE;
       }

       hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
             __uuidof(m_pDWriteFactory),
             reinterpret_cast<IUnknown **>(&m_pDWriteFactory)
             );

       if (FAILED(hr))
       {
             MessageBox(TEXT("DWriteCreateFactory fail"));
             DestoryD2D();
             return FALSE;
       }

       hr = m_pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &m_pBrush);
       if (FAILED(hr))
       {
             MessageBox(TEXT("m_pD2DFactory->CreateSolidColorBrush fail"));
             DestoryD2D();
             return FALSE;
       }

       hr = m_pDWriteFactory->CreateTextFormat(TEXT("Consolas"),
             NULL,
             DWRITE_FONT_WEIGHT_BOLD,
             DWRITE_FONT_STYLE_NORMAL,
             DWRITE_FONT_STRETCH_NORMAL,
             25,
             L"", //locale
             &m_pTextFormat
             );
       if (FAILED(hr))
       {
             MessageBox(TEXT("m_pD2DFactory->CreateSolidColorBrush fail"));
             DestoryD2D();
             return FALSE;
       }

       m_pTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
       m_pTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER);

       return TRUE;
}

void CDDraw2DCtrl::Draw()
{
       CRect rect;
       HRESULT hr;

       if (!m_pRenderTarget)
       {
             if (!CreateD2D())
             {
                    return;
             }
       }

       // Resize
       GetClientRect(&rect);
       D2D1_SIZE_U size = D2D1::SizeU(rect.Width(), rect.Height());
       m_pRenderTarget->Resize(size);

       // Begin Draw
       m_pRenderTarget->BeginDraw();

       m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
       m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));

       /* Draw Rect
       */
       m_pBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Red));
       m_pRenderTarget->DrawRectangle(
             D2D1::RectF(rect.left + rect.Width() / 10, rect.top + rect.Height() / 10, rect.right - rect.Width() / 10, rect.bottom - rect.Height() / 10),
             m_pBrush
             );

       /*DrawText
       */
       m_pBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Black));
       CString csText = TEXT("사장님 나빠요");
       m_pRenderTarget->DrawText(
             csText.GetString(),
             wcslen(csText.GetString()),
             m_pTextFormat,
             D2D1::RectF(rect.left, rect.top, rect.right, rect.bottom),
             m_pBrush
             );


       hr = m_pRenderTarget->EndDraw();
}


BOOL CreateD2D()에서 DDraw 2D관련 리소스를 생성하고, void DestoryD2D()에서 해제한다. 실제 그림을 그리는 함수는 void Draw()이다.


3. 다이얼로그 클래스에 1에서 생성한 picture control의 컨트롤 변수를 추가한다. 변수 형식은 위 2에서 만든 class를 사용한다.


4. 실행화면은 아래 그림과 같다. 1에서 생성한 picture control 윈도우에 박스와 글이 써진 것을 볼 수 있다.

댓글

이 블로그의 인기 게시물

간단한 cfar 알고리즘에 대해

windows에서 간단하게 크롬캐스트(Chromecast)를 통해 윈도우 화면 미러링 방법

간단한 칼만 필터(Kalman Filter) 소스 코드와 사용 예제

안드로이드(android) 전체 화면 시계 앱(clock app) 예제 코드

mkfs.fat Device or resource busy 에러 해결법