Создание простого приложения с одним буфером (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? У меня создалось впечатление, что использование буферов предназначено для:

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

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


person Community    schedule 31.05.2013    source источник


Ответы (2)


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

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

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

person Community    schedule 03.06.2013

Это вполне достижимо. Что требуется, так это основная поверхность, на которой можно писать, и машинка для стрижки, чтобы обрезать поверхность до окна.

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

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

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

В this сообщение в блоге.

person Community    schedule 15.06.2013