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