Теперь пришло время посмотреть, как в нашем приложении осуществляется вывод на экран. Функция Render() вызывается из функции RMApp::OnIdle() и отвечает за обновление поверхности вторичного буфера и выполнение переключения страниц. Код функции Render() приведен в листинге 10.14.
Листинг 10.14. Функция Render() |
void FullScreenWin::Render() { if (primsurf->IsLost() == DDERR_SURFACELOST) { TRACE("Restoring primsurf...\n"); primsurf->Restore(); } if (menusurf->IsLost() == DDERR_SURFACELOST) { TRACE("Restoring menusurf...\n"); menusurf->Restore(); UpdateMenuSurface(); } if (fpssurf->IsLost() == DDERR_SURFACELOST) { TRACE("Restoring fpssurf...\n"); fpssurf->Restore(); } DDBLTFX bltfx; memset(&bltfx, 0, sizeof(bltfx)); bltfx.dwSize = sizeof(bltfx); bltfx.dwFillColor = 0; backsurf->Blt(0, 0, 0, DDBLT_COLORFILL | DDBLT_WAIT, &bltfx); scene->Move(D3DVALUE(1.0)); viewport->Clear(); viewport->Render(scene); device->Update(); UpdateFPSSurface(); if (displayfps) { DWORD w, h, d; GetCurDisplayModeDims(w, h, d); backsurf->BltFast(w - fpsrect.right, h - fpsrect.bottom, fpssurf, &fpsrect, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); } backsurf->BltFast(0, 0, menusurf, &menurect, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); primsurf->Flip(0, DDFLIP_WAIT); } |
В первой части функции производится проверка потери поверхностей. Потеря поверхностей может произойти, если память, используемая поверхностью, потребуется Windows для других целей. Теряется только память поверхности, а не сама поверхность. Обычно потеря поверхностей происходит, когда пользователь нажимает комбинацию клавиш ALT+TAB для переключения на другую программу.
Функция IsLost() интерфейса DirectDrawSurface возвращает TRUE если память поверхности была потеряна. Восстановить память поверхности очень просто — достаточно вызвать функцию Restore() интерфейса DirectDrawSurface. Это возвратит утраченную память поверхности, но не восстановит содержимое памяти. Обратите внимание, как восстанавливается поверхность меню видеорежимов:
if (menusurf->IsLost() == DDERR_SURFACELOST) { TRACE("Restoring menusurf...\n"); menusurf->Restore(); UpdateMenuSurface(); }Если произошла потеря поверхности, вызывается функция Restore(). Она выполняет восстановление памяти поверхности, а вызов функции UpdateMenuSurface() необходим для восстановления содержимого поверхности.
Затем стирается содержимое поверхности backsurf:
DDBLTFX bltfx; memset(&bltfx, 0, sizeof(bltfx)); bltfx.dwSize = sizeof(bltfx); bltfx.dwFillColor = 0; backsurf->Blt(0, 0, 0, DDBLT_COLORFILL | DDBLT_WAIT, &bltfx);Аналогичный код используется в функции RMWin::ClearSurface(). Функция Blt() применяется для заливки поверхности указанным цветом. Поверхность заполняется нулевыми байтами, но для данной поверхности не был назначен цветовой ключ, так что все пиксели поверхности остаются нулевыми.
Теперь можно нарисовать часть сцены, относящуюся к Direct3D:
scene->Move(D3DVALUE(1.0)); viewport->Clear(); viewport->Render(scene); device->Update();Функция Move() интерфейса Direct3DRMFrame обновляет внутренние значения иерархии фреймов и выполняет вызов любых функций обратного вызова, выполняющих перемещение входящих в иерархию фреймов. Вызов функций интерфейса Direct3DRMViewport (Clear() и Render()) очищает содержимое порта просмотра (это не оказывает никакого действия на наши поверхности) и вычисляет новое выводимое изображение. Функция Update() интерфейса Direct3DRMDevice копирует сформированное изображение на поверхность backsurf. Это может ускользнуть от вашего взора, поскольку поверхность backsurf не упоминается в данном фрагменте кода. Однако, следует вспомнить, что поверхность backsurf была использована при создании устройства Direct3D. Эта связь объясняет, почему сформированное изображение передается функцией Update() непосредственно на поверхность backsurf.
Затем поверх сформированного Direct3D изображения выводится поверхность для вывода FPS:
UpdateFPSSurface(); if (displayfps) { DWORD w, h, d; GetCurDisplayModeDims(w, h, d); backsurf->BltFast(w - fpsrect.right, h - fpsrect.bottom, fpssurf, &fpsrect, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT); }Вызов функции UpdateFPSSurface() обновляет содержимое поверхности fpssurf. Затем, если значение логической переменной displayfps равно TRUE, содержимое поверхности копируется на поверхность backsurf функцией BltFast() (BltFast() — это оптимизированная версия функции Blt()).
Поверхность fpssurf размещается в нижнем правом углу экрана, поэтому при вычислении местоположения копируемой поверхности во вторичном буфере используются размеры экрана.
Потом на поверхность backsurf копируется поверхность меню видеорежимов:
backsurf->BltFast(0, 0, menusurf, &menurect, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT);Этот код очень простой, поскольку поверхность меню видеорежимов всегда видна и располагается в левом верхнем углу экрана.
В конце функции содержимое поверхности backsurf перемещается на первичную поверхность операцией переключения страниц:
primsurf->Flip(0, DDFLIP_WAIT);Этот вызов функции делает видимым содержимое поверхности backsurf.