dev.nlited.com

>>

WM_PAINT and Direct2D

<<<< prev
next >>>>

2016-08-21 21:51:09 chip Page 1827 📢 PUBLIC

This is a simple example of using Direct2D to handle WM_PAINT messages in a Win32 program. It uses the "MyD2D" helper functions, repackaged into GraphicLib.h.

This code was lifted from DbgOut/1102/Viewer/CursorWnd.cpp.

The offscreen image can become corrupted if the window is moved partially offscreen and back without resizing. It may be that CreateCompatibleRenderTarget() is using the visible area of the window to create the backing bitmap, while the client area of the window never changes and DoRedraw is never set. When the window moves back onto the display, the dimensions of the offscreen image and the window are then mismatched. OR, this could be a strange behavior of VMware.

NOTE: The RenderTargets must be recreated whenever the window is resized. Failing to do this will result in unexpected scaling weirdness.


Simple.cpp: #include <Windows.h> #include "GraphicLib.h" //#pragma message(__FILE__": Optimizer disabled.") //#pragma optimize("",off) using namespace D2D1; class Simple { private: //Window message handlers static INT_PTR WINAPI DlgProc(HWND hDlg, UING Msg, WPARAM wParm, LPARAM lParm); static BOOL MsgResized(void); static BOOL MsgPaint(void); bool RedrawCreate(ID2D1HwndRenderTarget *&pWnd); void Redraw(void); //Data HWND hDlg; //This window bool DoRedraw; //Does the offscreen image need to be redrawn? int IsFailed; //Persistent error HD2D hD2D; //Direct2D helper ID2D1BitmapRenderTarget *pImg; //Offscreen image D2D1_RECT_F rDraw; //Dimensions of the offscreen image }; BOOL Simple::MsgResized(void) { RECT rWnd; GetClientRect(hDlg,&rWnd); if(RWID(rWnd)!=(int)RWID(rDraw) || RHGT(rWnd)!=(int)RHGT(rDraw)) { if(pImg) { pImg->Release(); pImg= 0; } SetRectF(rDraw,rWnd); DoRedraw= true; } return(1); } BOOL Simple::MsgPaint(void) { PAINTSTRUCT Pnt; bool IsDrawn= false; if(BeginPaint(hDlg,&Pnt)) { ID2D1HwndRenderTarget *pWnd; //Sometimes I won't know that I need to recreate the D2D resources //until after I try to draw the bitmap. for(UINT Tries=0;!IsDrawn && Tries<3 && RedrawCreate(pWnd);Tries++) { if(DoRedraw) Redraw(); ID2D1Bitmap *pBitmap; if(SUCCEEDED(pImg->GetBitmap(&pBitmap))) { pWnd->BeginDraw(); pWnd->DrawBitmap(pBitmap); if(!SUCCEEDED(pWnd->EndDraw())) { //May happen if the display is resized, hibernation, etc. pImg->Release(); pImg= 0; DoRedraw= true; } else { IsDrawn= true; } pBitmap->Release(); } } if(!IsDrawn) { //DirectDraw failed, paint it black. FillRect(Pnt.hdc,&Pnt.rcPaint,(HBRUSH)GetStockObject(BLACK_BRUSH)); } EndPaint(hDlg,&Pnt); } return(1); } //Create all the resources for the offscreen image. //This is called before every redraw and paint. //If everthing has already been created, this does nothing. bool Simple::RedrawCreate(ID2D1HwndRenderTarget *&pWnd) { bool IsOk= false; if(!hD2D && DbgErr(D2DCreate(&hD2D,ghInst))) { if(!IsFailed) IsFailed= Error(DBGERR_SYSCREATE,"RedrawCreate: Unable to create D2D helper."); } else if(DbgErr(D2DCreateResourcesWnd(hD2D,hDlg))) { if(!IsFailed) IsFailed= Error(DBGERR_SYSCREATE,"RedrawCreate: D2DCreateResourcesWnd() failed."); } else if(!(pWnd= D2DRenderWnd(hD2D,hDlg))) { if(!IsFailed) IsFailed= Error(DBGERR_SYSCREATE,"RedrawCreate: Unable to obtain window renderer."); } else { //pWnd is the renderer for the actual window. //Create a compatible renderer that draws to an implicit offscreen bitmap. HRESULT WinErr= pWnd->CreateCompatibleRenderTarget(0,0,0,D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE,&pImg); if(!SUCCEEDED(WinErr)) { IsFailed= Error(DBGERR_SYSCREATE,"RedrawCreate: Unable to create compatible renderer."); } else { IsOk= true; } } return(IsOk); } //Redraw the offscreen image, which is the same size as the onscreen window. void Simple::Redraw(void) { D2D_COLOR_F Color= ColorF(RGB(rand()%0xFF,rand()&0xFF,rand()&0xFF)); pImg->BeginDraw(); pImg->Clear(Color); pImg->EndDraw(); IsFailed= 0; DoRedraw= false; }


WebV7 (C)2018 nlited | Rendered by tikope in 33.774ms | 44.220.184.63