Direct2D: moving window turns gray

196 views Asked by At

I've started Direct2D from a very simple example. Acquire the factory and ID2D1HwndRenderTarget, then handle WM_PAINT message to draw just a background with a solid color using "Clear" function.

It's work fine, until I start to move the window. When the window is moving it turns gray like nothing is drawing. I've tried to draw an ellipse, and the result is the same.

How could one present the window content with the window moving?

P.S. In case the code is needed

#include <Windows.h>

#include <d2d1_1.h> 
#pragma comment(lib,"d2d1")

ID2D1Factory * d2factory_ptr = NULL;
ID2D1HwndRenderTarget * renderTarget_ptr = NULL;


LRESULT CALLBACK mainWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI wWinMain(
    HINSTANCE hInstance
    , HINSTANCE prevInstance
    , LPWSTR cmd
    , int nCmdShow
) {
    WNDCLASSEX wndClassStruct;
    ZeroMemory(&wndClassStruct, sizeof(WNDCLASSEX));
    wndClassStruct.cbSize = sizeof(WNDCLASSEX);
    wndClassStruct.hbrBackground = (HBRUSH)COLOR_WINDOW;
    wndClassStruct.style = CS_HREDRAW | CS_VREDRAW;
    wndClassStruct.hInstance = hInstance;
    wndClassStruct.lpfnWndProc = mainWinProc;
    wndClassStruct.lpszClassName = TEXT("MainWnd");

    RegisterClassEx(&wndClassStruct);

    RECT windowRect = { 0,0,640,480};
    AdjustWindowRectEx(&windowRect, WS_OVERLAPPEDWINDOW, 0, WS_EX_APPWINDOW);
    HWND hWnd = CreateWindowEx(WS_EX_APPWINDOW, TEXT("MainWnd"), TEXT("Direct 2D Test Window"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, CW_USEDEFAULT, 0, windowRect.right-windowRect.left, windowRect.bottom-windowRect.top, NULL, NULL, hInstance, 0);

    {
        D2D1_FACTORY_OPTIONS fo;
        ZeroMemory(&fo, sizeof(D2D1_FACTORY_OPTIONS));

        IID const factoryIID = IID_ID2D1Factory1;

        HRESULT res = S_OK;
        if (S_OK != (res = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factoryIID, &fo, &d2factory_ptr))) {
            return 0;
        }

        RECT clientRect;
        GetClientRect(hWnd, &clientRect);

        D2D1_RENDER_TARGET_PROPERTIES renderTargetProps;
        ZeroMemory(&renderTargetProps, sizeof(D2D1_RENDER_TARGET_PROPERTIES));
        renderTargetProps.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
        renderTargetProps.pixelFormat = (D2D1_PIXEL_FORMAT) { DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED };
        renderTargetProps.dpiX = 0;
        renderTargetProps.dpiY = 0;
        renderTargetProps.usage = D2D1_RENDER_TARGET_USAGE_FORCE_BITMAP_REMOTING;
        renderTargetProps.minLevel = D2D1_FEATURE_LEVEL_DEFAULT;

        D2D1_HWND_RENDER_TARGET_PROPERTIES hwndRenderProps;
        ZeroMemory(&hwndRenderProps, sizeof(D2D1_HWND_RENDER_TARGET_PROPERTIES));
        hwndRenderProps.hwnd = hWnd;
        hwndRenderProps.pixelSize = (D2D1_SIZE_U) { clientRect.right - clientRect.left, clientRect.bottom - clientRect.top };
        hwndRenderProps.presentOptions = D2D1_PRESENT_OPTIONS_NONE;

        if (S_OK != (res = d2factory_ptr->lpVtbl->CreateHwndRenderTarget(d2factory_ptr, &renderTargetProps, &hwndRenderProps, &renderTarget_ptr))) {
            return 0;
        }
    }

    ShowWindow(hWnd, nCmdShow);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    DestroyWindow(hWnd);

    if(NULL != renderTarget_ptr) 
        renderTarget_ptr->lpVtbl->Base.Base.Base.Release((IUnknown*)renderTarget_ptr);

    if (NULL != d2factory_ptr)
        d2factory_ptr->lpVtbl->Base.Release((IUnknown*)d2factory_ptr);

    return 0;
}

LRESULT onPaintMainWindow() {
    ID2D1RenderTargetVtbl renderTargetFuncs = renderTarget_ptr->lpVtbl->Base;
    ID2D1RenderTarget * This = (ID2D1RenderTarget*)renderTarget_ptr;
    D2D1_TAG tag1, tag2;

    D2D1_COLOR_F backgroundClr = (D2D1_COLOR_F) { 0.0, 0.5, 1.0, 1.0 };
    renderTargetFuncs.BeginDraw(This);
    renderTargetFuncs.Clear(This, &backgroundClr);
    renderTargetFuncs.EndDraw(This, &tag1, &tag2);

    return 0;
}

LRESULT CALLBACK mainWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

    if (WM_PAINT == uMsg)
        return onPaintMainWindow();

    if (WM_DESTROY == uMsg) {
        PostQuitMessage(0); return 0;
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
1

There are 1 answers

3
selbie On BEST ANSWER

Configure your WNDCLASSEX to not have a background brush.

Replace this line:

wndClassStruct.hbrBackground = (HBRUSH)COLOR_WINDOW;

With this:

wndClassStruct.hbrBackground = GetStockObject(NULL_BRUSH);

Alternatively, you can modify mainWndProc to swallow the WM_ERASEBKGND messages. It achieves the same effect by not allowing the window to erase itself before issuing a WM_PAINT.

LRESULT CALLBACK mainWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {

    if (WM_PAINT == uMsg)
        return onPaintMainWindow();

    if (uMsg == WM_ERASEBKGND)
    {
        // ignore requests to erase the background since the wm_paint
        // handler is going to redraw the entire window.
        return 0;
    }

    if (WM_DESTROY == uMsg) {
        PostQuitMessage(0); return 0;
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}