netlib.narod.ru | < Назад | Оглавление | Далее > |
В рассматриваемом в этой главе примере мы выполним инициализацию Direct3D-приложения и очистим экран, заполнив его черным цветом (рис. 1.7).
Рис. 1.7. Окно программы, рассматриваемой в этой главе
Этот пример, как и все другие примеры в этой книге, использует код из файлов d3dUtility.h и d3dUtility.cpp, которые можно скачать с веб-сайта, посвященного этой книге. Эти файлы содержат функции, реализующие общие задачи, которые должно выполнять каждое Direct3D-приложение, такие как создание окна, инициализация Direct3D и вход в цикл обработки сообщений. Благодаря созданию функций-оберток для этих задач, в коде примеров мы можем сосредоточиться на рассматриваемой в соответствующей главе теме. Кроме того, на протяжении книги мы будем добавлять к этим файлам полезный вспомогательный код.
Перед тем, как перейти к примеру из этой главы, давайте потратим немного времени, чтобы познакомиться с функциями, предоставляемыми файлами d3dUtility.h/cpp. Вот как выглядит код из файла d3dUtility.h:
// Включение основного заголовочного файла Direct3DX. В нем осуществляется // включение других, необходимых нам заголовочных файлов Direct3D. #include <d3dx9.h> namespace d3d { bool InitD3D( HINSTANCE hInstance, // [in] Экземпляр приложения. int width, int height, // [in] Размеры вторичного буфера. bool windowed, // [in] Оконный (true) или // полноэкранный (false) режим. D3DDEVTYPE deviceType, // [in] HAL или REF IDirect3DDevice9** device); // [out] Созданное устройство. int EnterMsgLoop( bool (*ptr_display)(float timeDelta)); LRESULT CALLBACK WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); template<class T> void Release(T t) { if(t) { t->Release(); t = 0; } } template<class T> void Delete(T t) { if(t) { delete t; t = 0; } } }
InitD3D — Эта функция инициализирует главное окно приложения и содержит код инициализации Direct3D, который обсуждался в разделе 1.4. Если функция завершается нормально, она возвращает указатель на созданный интерфейс IDirect3DDevice9. Обратите внимание, что параметры функции позволяют задать размеры окна и то, в каком режиме — оконном или полноэкранном — будет работать приложение. Чтобы познакомиться с деталями реализации, посмотрите код примера.
EnterMsgLoop — Эта функция является оберткой для цикла обработки сообщений приложения. Она получает указатель на функцию визуализации. Функция визуализации — это функция в которой находится код для вывода создаваемого в примере изображения. Циклу сообщений необходимо знать, какая функция используется для визуализации, чтобы он мог вызывать ее и отображать сцену во время ожидания сообщений.
int d3d::EnterMsgLoop(bool(*ptr_display)(float timeDelta)) { MSG msg; ::ZeroMemory(&msg, sizeof(MSG)); static float lastTime = (float)timeGetTime(); while(msg.message != WM_QUIT) { if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); } else { float currTime = (float)timeGetTime(); float timeDelta = (currTime - lastTime) * 0.001f; ptr_display(timeDelta); // вызов функции визуализации lastTime = currTime; } } return msg.wParam; }
Часть кода занимается вычислением времени, прошедшего между обращениями к функции ptr_display, то есть времени между кадрами.
Release — Этот шаблон разработан в качестве вспомогательной функции для освобождения COM-интерфейсов и присваивания указателям на них нулевых значений.
Delete — Этот шаблон разработан в качестве вспомогательной функции для удаления объектов, освобождения занимаемой ими памяти и присваивания указателям на них нулевых значений.
WndProc — Объявление оконной процедуры для главного окна приложения.
Под каркасом примера мы подразумеваем общую структуру кода, которой придерживаются все рассматриваемые в этой книге примеры программ. Для каждого приложения мы в обязательном порядке будем реализовать три функции, не считая процедуры обработки сообщений и функции WinMain. В этих трех функциях будет реализоваться код, специфичный для конкретного приложения. Вот эти функции:
bool Setup() — Это функция в которой инициализируется все, что должно быть инициализировано для данного приложения. В ней осуществляется выделение ресурсов, проверка возможностей устройств и установка состояний приложения.
void Cleanup() — В этой функции мы освобождаем все ресурсы, выделенные для приложения в функции Setup, в основном это освобождение памяти.
bool Display(float timeDelta) — В эту функцию мы помещаем весь код, отвечающий за рисование и код, который должен выполняться при переходе от кадра к кадру, например выполняющий изменение местоположения объектов. Параметр timeDelta — это время, прощедшее с момента вывода предыдущего кадра и используется он для синхронизации анимации с частотой смены кадров.
Как было сказано, рассматриваемый пример приложения создает и инициализирует Direct3D-приложение и очищает экран, заполняя его черным цветом. Обратите внимание, что для упрощения инициализации мы используем наши вспомогательные функции. Полный код проекта можно скачать с веб-сайта этой книги.
Мы начинаем с включения заголовочного файла d3dUtility.h и объявления глобальной переменной для устройства:
#include "d3dUtility.h" IDirect3DDevice9* Device = 0;
Затем мы реализуем функции, входящие в каркас приложения:
bool Setup() { return true; } void Cleanup() { }
В данном примере нам не требуются никакие ресурсы, так что методы Setup и Cleanup остаются пустыми.
bool Display(float timeDelta) { if(Device) { Device->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0); Device->Present(0, 0, 0, 0); // показ вторичного буфера } return true; }
Метод Display вызывает метод IDirect3DDevice9::Clear, который очищает вторичный буфер и буфер глубины/трафарета, заполняя их черным цветом и константой 1.0 соответственно. Обратите внимание, что если приложение не остановлено, мы выполняем только код рисования. Объявление функции IDirect3DDevice9::Clear выглядит так:
HRESULT IDirect3DDevice9::Clear( DWORD Count, const D3DRECT* pRects, DWORD Flags, D3DCOLOR Color, float Z, DWORD Stencil );
Count — Количество прямоугольников в массиве pRects.
pRects — Массив очищаемых прямоугольных областей экрана. Он позволяет очищать отдельные фрагменты поверхности.
Flags — Указывает, какую поверхность очищать. Можно указывать одну или несколько из следующих поверхностей:
Color — Цвет, которым будет заполнена поверхность визуализации.
Z — Значение, которым будет заполнен буфер глубины (z-буфер).
Stencil — Значение, которым будет заполнен буфер трафарета.
После того, как поверхность очищена, мы показываем вторичный буфер, вызвав метод IDirect3DDevice9::Present.
Оконная процедура обрабатывает пару событий, а именно позволяет выходить из приложения, нажав клавишу Esc.
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch( msg ) { case WM_DESTROY: ::PostQuitMessage(0); break; case WM_KEYDOWN: if( wParam == VK_ESCAPE ) ::DestroyWindow(hwnd); break; } return ::DefWindowProc(hwnd, msg, wParam, lParam); }
Функция WinMain выполняет следующие действия:
int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE prevInstance, LPSTR cmdLine, int showCmd) { if(!d3d::InitD3D(hinstance, 800, 600, true, D3DDEVTYPE_HAL, &Device)) { ::MessageBox(0, "InitD3D() - FAILED", 0, 0); return 0; } if(!Setup()) { ::MessageBox(0, "Setup() - FAILED", 0, 0); return 0; } d3d::EnterMsgLoop( Display ); Cleanup(); Device->Release(); return 0; }
Как видите, благодаря вспомогательным функциям выполняющим обработку сообщений и инициализацию Direct3D, структура шаблона приложения получилась исключительно прозрачной.
Для большинства примеров из этой книги наша задача будет заключаться в написании реализаций функций Setup, Cleanup и Display.
netlib.narod.ru | < Назад | Оглавление | Далее > |