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 32.877ms | 3.145.99.58