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:
I care about neither of these right not. What can I do?
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.