创建一个简单的单缓冲区应用程序(IDirectDraw)

时间:2013-05-31 21:00:22

标签: c winapi buffer directdraw windowed

我正在尝试使用原始的DirectDraw界面创建一个缓冲的窗口化应用程序。

这纯粹是为了教育目的而仅仅因为的态度。我正在使用IDirectDraw界面(我强调这是原始版本,就像在DirectX 1.0中一样)。

现在,该文档包含一组关于创建后缓冲区以及在主表面和后缓冲区表面之间翻转的教程

但是,它没有给出关于编写窗口化单缓冲区应用程序的描述。事实上,我根本无法找到这个想法。没有任何迹象表明它不可能。

通过将合作级别设置为DDSCL_NORMAL,应用程序在窗口内运行。

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

然后在成功后创建主要表面。

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;

此功能也成功。请注意,我创建后备缓冲区。

然而,在我的主循环中:

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);
        }
    }
}

根本没有任何东西被吸引到窗户上。我的原始代码(全屏缓冲应用程序)正确显示“你好,世界!”在屏幕的左上角,唯一的修改是微小的编辑,以停止创建后缓冲区,并直接写入主表面。

如果在使用CreateSurface调用SetCooperativeLevel之后使用后缓冲区选项调用DDSCL_NORMAL,则返回错误。我理解这一点,因为文档说明:

  

如果您使用IDirectDraw :: SetCooperativeLevel将模式设置为DDSCL_NORMAL,则只能创建表面之间的blit表面。

我错过了什么吗?我是否从根本上误解了DirectDraw?我的印象是使用缓冲区是为了:

  • 性能优势,
  • 防止屏幕撕裂。

我不关心这些都没有。我该怎么办?

2 个答案:

答案 0 :(得分:0)

技术上没有问题。这些命令实际上是将文本绘制到屏幕上。但问题是,命令是相对于整个显示绘制的,而不是绘制到客户区

当我尝试集成支持实时更改客户端区域大小并意外将应用程序设置为SIZE_MAXIMIZED并通过IDirectDrawSurface_Restore恢复表面时,我发现了这一点。有了后视,我应该多花一些力气,然后画到屏幕的中心而不是左上角。

我还没有找到如何修改相对于客户区绘制的程序,但这个问题的核心是关于使用单个缓冲区和窗口进行绘制,这是我已经解决的问题。

答案 1 :(得分:0)

这是完全可以实现的。所需要的是要写入的主要表面和用于将表面修剪到窗口的限幅器。

创建IDirectDrawClipper类型的限幅器并使用IDirectDrawClipper_SetHWnd将限幅器与窗口匹配。接下来,然后使用IDirectDrawSurface_SetClipper将限幅器附加到主表面控制的内存中。

确保重新调用 IDirectDraw_SetDisplayMode,然后在每次窗口更改大小时恢复曲面,如果您没有锁定窗口大小。

另外请记住,你需要对表面进行blit而不是像后背缓冲一样翻转。

this博文中提出了几点好处。