Создание простого приложения с одним буфером (IDirectDraw)

Я пытаюсь создать одно оконное приложение с буферизацией, используя оригинальный интерфейс 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, вы могли бы создавать только поверхности, которые вспыхивают между поверхностями.

Я что-то пропустил? Я в корне неправильно понял DirectDraw? У меня сложилось впечатление, что использование буферов было для:

  • Преимущества производительности и
  • Чтобы предотвратить разрыв экрана.

Я не забочусь ни об этом, ни о праве. Что я могу сделать?

2 ответа

Решение

Это вполне достижимо. Для этого требуется первичная поверхность для записи и клипер для обрезки поверхности до окна.

Создать клипер типа IDirectDrawClipper и использовать IDirectDrawClipper_SetHWnd сопоставить клипер с окном. Далее, а затем использовать IDirectDrawSurface_SetClipper прикрепить клипер к памяти, управляемой первичной поверхностью.

Убедитесь, что вы перезвоните IDirectDraw_SetDisplayMode и затем восстанавливайте поверхность каждый раз, когда окно меняет размер, если вы не блокируете размер окна.

Также помните, что вы должны прыгать на поверхность, а не переворачивать, как если бы у вас был backbuffer.

Несколько хороших замечаний сделано в этом сообщении в блоге.

Технически это не проблема. Команды фактически рисуют текст на экране. Проблема, однако, заключается в том, что команды рисуются относительно всего дисплея, а не в клиентской области.

Я узнал об этом, когда пытался интегрировать поддержку изменения размера клиентской области в реальном времени и случайно установил приложение на SIZE_MAXIMIZED и восстановил поверхность через IDirectDrawSurface_Restore, С задним взглядом я должен был приложить немного больше усилий и нарисовать центр экрана, а не верхнюю левую часть.

Мне еще предстоит выяснить, как изменить программу для рисования относительно клиентской области, но суть этого вопроса заключается в рисовании с использованием одного буфера и окна, и именно это я и решил.

Другие вопросы по тегам