Question

I am attempting to author a single buffered, windowed application using the original DirectDraw interface.

This is purely for educational purposes and the just because attitude. I'm playing around with the IDirectDraw interface (I stress this is the original version, as in DirectX 1.0).

Now, the documentation contains group of tutorials on creating a back-buffer and flipping between the primary surface and the back-buffer surface.

However, it gives no description about writing a windowed, single buffer application. In fact I can find little reference to the idea at all. There's nothing that indicates its not possible.

By setting the cooperation level with to DDSCL_NORMAL the application behaves within a window.

hr = IDirectDraw_SetCooperativeLevel(lpDirectDraw, hWnd_, DDSCL_NORMAL);
if (hr != DD_OK)
    return -1;

Followed by creating the primary surface after success.

ZeroMemory(&ddSurfaceDesc, sizeof ddSurfaceDesc);
ddSurfaceDesc.dwSize            = sizeof ddSurfaceDesc;
ddSurfaceDesc.dwFlags           = DDSD_CAPS;
ddSurfaceDesc.ddsCaps.dwCaps    = DDSCAPS_PRIMARYSURFACE;

hr = IDirectDraw_CreateSurface(lpDirectDraw, &ddSurfaceDesc, &lpDirectDrawPrimarySurface, (IUnknown *) NULL);
if (hr != DD_OK)
    return -1;

This function also succeeds. Note that I do not create a back-buffer.

However, in my main loop:

while (fIterateLoop)
{
    for (ZeroMemory(&msg, sizeof msg); PeekMessage(&msg, (HWND) NULL, 0, 0, PM_REMOVE); DispatchMessage(&msg))
        fIterateLoop = msg.message == WM_QUIT ? FALSE : TRUE;

    if (fDraw && lpDirectDrawPrimarySurface != (LPDIRECTDRAWSURFACE) NULL)
    {
        HDC hdc;

        hr = IDirectDrawSurface_GetDC(lpDirectDrawPrimarySurface, &hdc);
        if (hr == DD_OK)
        {
            SetBkColor(hdc, RGB(0, 0, 0));
            SetTextColor(hdc, RGB(255, 255, 255));
            TextOut(hdc, 15, 15, "hello, world!", sizeof "hello, world!" - 1);

            hr = IDirectDrawSurface_ReleaseDC(lpDirectDrawPrimarySurface, hdc);
        }
    }
}

Nothing is drawn to the window at all. My original code (a fullscreen buffered application) correctly shows "hello, world!" in the top left-hand side of the screen and the only modifications are the tiny edits to stop the back-buffer creation, and to write directly to the primary surface.

If I call CreateSurface with the options for a back-buffer after calling SetCooperativeLevel with DDSCL_NORMAL then it returns and error. This I understand because the documentation states:

If you were using IDirectDraw::SetCooperativeLevel to set the mode to DDSCL_NORMAL, you could create only surfaces that blit between the surfaces.

Have I missed something? Have I fundamentally misunderstood DirectDraw? I was under the impression that using buffers was for:

  • Performance benefits, and
  • To prevent screen tearing.

I care about neither of these right not. What can I do?

Was it helpful?

Solution 2

This is perfectly achievable. What is required is a primary surface to write to and a clipper to trim the surface to the window.

Create a clipper of type IDirectDrawClipper and use IDirectDrawClipper_SetHWnd to match the clipper to the window. Next and then use IDirectDrawSurface_SetClipper to attach the clipper to the memory controlled by the primary surface.

Make sure you re-call IDirectDraw_SetDisplayMode and then restore the surface each time the window changes size if you aren't locking the window size.

Also remember that you are required to blit to the surface and not flip as if you had a backbuffer.

Several good points are made in this blog post.

OTHER TIPS

Technically there is no issue. The commands are actually drawing text to the screen. The issue, however, is that the commands are drawing relative to the entire display and not to the client area.

I found this out when I was trying to integrate support for real-time changing of the client-area size and accidentally set the application to SIZE_MAXIMIZED and restored the surface through IDirectDrawSurface_Restore. With hind-sight I should have put a little more effort in and draw to the center of the screen and not the top left.

I have yet to find out how to modify the program to draw relative to the client area but the core of this question is about drawing using a single buffer and a window and it is this I have solved.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top