Программирование графики с использованием Direct3D
Функция InitMainSurfaces()
Пришло время взглянуть на функцию InitMainSurfaces(). Хочу напомнить, что функция InitMainSurfaces() вызывается из функции OnCreate() сразу после обращения к функции InitDisplayMode(). Функция InitMainSurfaces() создает первичную и вторичную поверхности вместе с Z-буфером. Код функции приведен в листинге10.5.
Листинг 10.5. Функция InitMainSurfaces()
BOOL RMWin::InitMainSurfaces() { if (primsurf) { primsurf->Release(); primsurf = 0; } if (zbufsurf) { zbufsurf->Release(); zbufsurf = 0; }
Сначала функция InitMainSurfaces() освобождает любые существующие первичные поверхности и Z-буферы:
if (primsurf) { primsurf->Release(); primsurf = 0; } if (zbufsurf) { zbufsurf->Release(); zbufsurf = 0; }
Функция OnCreate() (которая вызывает функцию InitMainSurfaces()) вызывается только однажды — когда создается окно программы — а в этот момент не существует ни первичной поверхности, ни Z-буфера. Однако функция InitMainSurfaces() используется другими функциями для изменения видеорежима. Поэтому существующие первичная поверхность и Z-буфер должны быть освобождены перед созданием новых. Вторичную поверхность освобождать не требуется, поскольку она будет уничтожена вместе с первичной поверхностью.
Поверхность, которую мы хотим создать, должна быть описана в структуре DDSURFACEDESC. Поле dwSize этой структуры должно содержать размер структуры. Поле dwFlags используется для хранения набора флагов, указывающих, какие поля структуры мы будем инициализировать. В нашем случае используются поля dwBackBufferCount и ddsCaps, поэтому мы указываем флаги DDSD_BACKBUFFERCOUNT и DDSD_CAPS.
Флаги возможностей поверхности (DDSCAPS_PRIMARYSURFACE, DDSCAPS_FLIP и DDSCAPS_COMPLEX) указывают, что мы создаем первичную поверхность с возможностью переключения страниц. Флаг DDSCAPS_3DDEVICE сообщает DirectDraw, что мы будем использовать новую поверхность для создания устройства Direct3D.
Фактическое создание поверхностей выполняет функция CreateSurface() интерфейса DirectDraw. В качестве первого аргумента мы передаем подготовленную ранее структуру DDSURFACEDESC. Во втором аргументе передается адрес указателя на интерфейс DirectDrawSurface. Указатель (primsurf) является членом класса RMWin и будет использоваться в дальнейшем для выполнения переключения страниц.
Обратите внимание, что значение поля dwBackBufferCount структуры DDSURFACEDESC равно единице. Это означает, что мы проинформировали DirectDraw о наличии у первичной поверхности одного вторичного буфера. Фактически, DirectDraw создает вторичный буфер вместе с первичной поверхностью. Все что нам остается сделать — получить указатель на вторичный буфер:
Позднее мы будем использовать указатель backsurf для сохранения выводимого изображения перед его перемещением, или переключением, на первичную поверхность.
Теперь мы создаем Z-буфер и присоединяем его к поверхности backsurf:
Для описания поверхности Z- буфера нам потребуется экземпляр структуры DDSURFACEDESC. Вместо того, чтобы объявлять еще одну копию, воспользуемся уже существующим экземпляром desc, который использовался при создании первичной поверхности. Очистим структуру с помощью функции memset(), присвоив всем ее полям нулевые значения. Затем присвоим требуемые значения полям dwSize и dwFlags.
Флаги, присвоенные полю dwFlags указывают, что мы будем задавать ширину и высоту поверхности, ее возможности, а также глубину Z-буфера. Соответствующим полям структуры присваиваются значения. Размеры Z-буфера должны быть равны размерам первичного и вторичного буферов. Поскольку размеры первичного и вторичного буферов всегда равны размеру экрана в текущем видеорежиме, для присваивания значений полям dwWidth и dwHeight можно использовать переменные modewidth и modeheight.
Мы создаем 16-разрядный Z-буфер, присваивая соответствующее значение полю. Глубина Z-буфера определяет точность работы кода удаления невидимых поверхностей. 8-разрядный Z-буфер может хранить только 256 различных значений Z, или расстояний, поэтому его возможности весьма ограничены. 16-разрядный Z-буфер предоставляет 65 535 различных значений и подходит для большинства случаев Z-буферизации. Сложные сцены могут потребовать наличия 24- или 32-разрядного Z-буфера.
Константа DDSCAPS_SYSTEMMEMORY используется для указания, что Z-буфер должен размещаться в системной памяти, а не в памяти видеокарты. Видеопамяти может не хватать для трехмерной графики (особенно на видеокартах с 2 мегабайтами памяти).Хранение Z-буфера в системной памяти освобождает память видеокарты для хранения отображаемых поверхностей, таких как спрайты и фоновые изображения. Хранение отображаемых данных в видеопамяти более предпочтительно, поскольку ускоряет работу приложения так как видеокарты обычно выполняют копирование блоков видеопамяти гораздо быстрее, чем копирование из системной памяти в видеопамять.
На последнем этапе выполняется создание поверхности Z-буфера и ее присоединение к поверхности backsurf: