| 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 | < Назад | Оглавление | Далее > |