Программируем игры на DirectX: различия между версиями

Материал из Викиучебника — открытых книг для открытого мира
Содержимое удалено Содержимое добавлено
Строка 3: Строка 3:


== Урок 1 - Создание окна. Инициализация Direct3D ==
== Урок 1 - Создание окна. Инициализация Direct3D ==
<h1>Введение</h1>
Создадим проект с именем Lesson1. Добавляем в проект файл main.cpp и начинаем его заполнять.
Учебник называется "Программируем игры..." потому что мы будет говорить только о программном коде, а темы насчет моделирования, рисования и тд. мы не будем обсуждать.
Для работы приложения нам требуеться библиотеки d3d9.lib, d3dx9.lib, winmm.lib. Подключим их.
Для того чтобы начать читать этот учебник нужно знать хотя бы основы С++ и STL.
<source lang="cpp">
Программировать мы будем с вами для операционной системы Windows XP на С++. В этом учебнике мы охватим такие важные темы как графика, физика, музыка, искусственный интеллект, устройства ввода и по ходу обучения мы создадим пару игр для применения полученных знаний.
Код используемый в книге был написан мною на Microsoft Visual C++ 6.0 (далее MVC++) с использованием DirectX 9 SDK November 2009

<h1>Создание окна. Иницциализация Direct3D</h1>
Создадим проект с именем Lesson1. Добавим в него файл main.cpp, и начнем его заполнять.
Для работы приложения нам потребуется использовать разные библиотеки, их мы сейчас и подключим к нашему проекту.
[code=cpp]
//Подключаем библиотеки
//Подключаем библиотеки
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"d3dx9.lib")
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"winmm.lib")
[/code]
</source>

Также нам потребуетьс подключить заголовочные файлы, чтобы компилятор не выдавал ошибку. Подключаем.
Дальше мы должны подключить заголовочные файли, чтобы компилятор не выдавал ошибки.
<source lang="cpp">
[code=cpp]
//Подключаем закголовчные файлы
//Подключаем заголовчные файлы
#include <windows.h>
#include <windows.h>
#include <d3d9.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <d3dx9.h>
[/code]
</source>

Объявим глобальные переменные которые будут использованы в приложении
Объявим глобальные переменные которые мы будем использовать в нашей программе.
<source lang="cpp">
[code=cpp]
//Глобальные переменные
//Глобальные переменные
HWND g_hWnd = NULL; //Дескриптор окна
HINSTANCE g_hInstance = NULL; //Дескриптор приложения
int g_iWindowWidth = 800; //Ширина окна
HWND g_hWnd = NULL; //Дескриптор окна
int g_iWindowHeight = 600; //Высота окна
int g_iWindowWidth = 800; //Ширина окна
int g_iWindowHeight = 600; //Высота окна
bool g_bApplicationState = true; //Состояние приложения (true - работает/false - неработает)
bool g_bFullScreen = false; //Режим окна (true - полноэкранный/false - оконный)
bool g_bApplicationState = true; //Состояние приложения (true - работает/false - неработает)
IDirect3D9 *g_pDirect3D = NULL; //Интерфейс для создания устройства рендеринга
</source>
IDirect3DDevice9 *g_pDirect3DDevice = NULL; //Интерфейс устройства рендеринга
Объявим прототипы функции которые будут использоваться в приложении
[/code]
<source lang="cpp">

//Прототипы функций
Теперь объявим прототипы функций, которые мы с вами напишем.
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow);
[code=cpp]
long WINAPI WndProc(HWND hWnd,UINT iMsg,WPARAM wParam,LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow); //Точка старта приложения
</source>
long WINAPI WndProc(HWND hWnd,UINT iMsg,WPARAM wParam,LPARAM lParam);//Обработчик сообщений
Функция WinMain - это точка старта приложения, эта функция на подобии main в консольный приложениях.
bool InitDirect3D(D3DFORMAT ColorFormat,D3DFORMAT DepthFormat); //Инициализация Direct3D
Чтобы создать окно сначала требуется создать класс окна, зарегистрировать в Windows, создать само окно и создать обработчик сообщений, которые посылает Windows в зависимости от происходящего события.
void DrawFrame(); //Рисуем кадр
<source lang="cpp">
void Shutdown(); //Освобождаем память
[/code]

Поговорим о функции WinMain. Эта функция является точкой старта приложения, код который в ней написан начинает выполнение при запуске программы. В этой функции мы должны создать окно и отобразить его.
[code=cpp]
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow)
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow)
{
{
g_hInstance = GetModuleHandle(NULL);
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX); //Размер структуры
wc.style = CS_HREDRAW|CS_VREDRAW; //Стили класса окна
wc.lpfnWndProc = WndProc; //Функция обработки сообщений
wc.cbClsExtra = 0; //Количество выделяемой памяти при создании приложения
wc.cbWndExtra = 0; //Количество выделяемой памяти при создании приложения
wc.hInstance = hInstance; //Дескриптор приложения
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION); //Загружаем стандартную иконку
wc.hCursor = LoadCursor(0,IDC_ARROW); //Загружаем стандартный курсор
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //Окно будет закрашено в белый цвет
wc.lpszMenuName = 0; //Не используем меню
wc.lpszClassName = "Lesson 1"; //Названия класса
wc.hIconSm = LoadIcon(NULL,IDI_APPLICATION); //Загружаем стандартную иконку


WNDCLASSEX wc;
if(!RegisterClassEx(&wc)) //Регестрируем класс в Windows
wc.cbSize = sizeof(WNDCLASSEX); //Размер структуры
{
wc.style = CS_HREDRAW|CS_VREDRAW; //Стили класса окна
MessageBox(NULL,"Can`t register window class","Error",MB_OK|MB_ICONERROR); //Выводим сообщение
wc.lpfnWndProc = WndProc; //Функция обработки сообщений
return 0; //Завершаем работу приложения
wc.cbClsExtra = 0; //Количество выделяемой памяти при создании приложения
}
wc.cbWndExtra = 0; //Количество выделяемой памяти при создании приложения
wc.hInstance = g_hInstance; //Дескриптор приложения
wc.hIcon = LoadIcon(NULL,IDI_APPLICATION); //Загружаем стандартную иконку
wc.hCursor = LoadCursor(0,IDC_ARROW); //Загружаем стандартный курсор
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//Окно будет закрашено в белый цвет
wc.lpszMenuName = 0; //Не используем меню
wc.lpszClassName = "Lesson 1"; //Названия класса
wc.hIconSm = LoadIcon(NULL,IDI_APPLICATION); //Загружаем стандартную иконку


if(!RegisterClassEx(&wc)) //Регистрируем класс в Windows
DWORD iWindowStyleEx = 0;
{
DWORD iWindowStyle = 0;
Shutdown(); //Освобаждем память
MessageBox(NULL,"Can`t register window class","Error",MB_OK|MB_ICONERROR); //Выводим сообщение
return 0; //Завершаем работу приложения
}


g_hWnd = CreateWindowEx( //Создаем окно
if(g_bFullScreen) //Если у нас поноэкранный режим
WS_EX_APPWINDOW|WS_EX_WINDOWEDGE, //Расширенный стиль окна
{
"Lesson 1", //Названия класса окна
iWindowStyleEx = WS_EX_APPWINDOW;
"Lesson 1 - Create Window. Init Direct3D", //Названия окна
iWindowStyle = WS_POPUP;
WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,//Стиль окна
}
0, //Позиция окна по оси Х
else
0, //Позиция окна по оси У
{
g_iWindowWidth, //Ширина окна
iWindowStyleEx = WS_EX_APPWINDOW|WS_EX_WINDOWEDGE;
g_iWindowHeight, //Высота окна
iWindowStyle = WS_OVERLAPPEDWINDOW;
NULL, //Это наше главное окно
}
NULL, //Нету меню
g_hInstance, //Дескриптор приложения
NULL); //Дополнительный настроек не используем


g_hWnd = CreateWindowEx( //Создаем окно
if(g_hWnd == NULL) //Если не создали окно
{
iWindowStyleEx, //Расшыренный стиль окна
Shutdown();
"Lesson 1", //Названия класса окна
MessageBox(NULL,"Can`t create window","Error",MB_OK|MB_ICONERROR);//Выводим сообщение
"Lesson 1 - Create Window. Init Direct3D", //Названия окна
return 0; //Завершаем работу приложения
iWindowStyle|WS_CLIPCHILDREN|WS_CLIPSIBLINGS, //Стиль окна
}
0, //Позиция окна по оси Х
0, //Позиция окна по оси У
g_iWindowWidth, //Ширина окна
g_iWindowHeight, //Высота окна
NULL, //У нас это окно главное
NULL, //Нету меню
hInstance, //Дескриптор приложения
NULL); //Дополнительных настроек неиспользуем


if(!InitDirect3D(D3DFMT_R5G6B5,D3DFMT_D16)) //Если не смогли инициализировать Direct3D
if(g_hWnd == NULL) //Если не создали окно
{
{
Shutdown();
MessageBox(NULL,"Can`t create window","Error",MB_OK|MB_ICONERROR); //Выводим сообщение
MessageBox(NULL,"Can`t create direct3d","Error",MB_OK|MB_ICONERROR);//Выводим сообщение
return 0; //Завершаем работу приложения
return 0; //Завершаем работу приложения
}
}


ShowWindow(g_hWnd,SW_SHOW); //Отображаем окно
ShowWindow(g_hWnd,SW_SHOW); //Отображаем окно
UpdateWindow(g_hWnd); //Обновляем окно
UpdateWindow(g_hWnd); //Обновляем окно
SetFocus(g_hWnd); //Устанавливаем фокус на наше окно
SetFocus(g_hWnd); //Устанавливаем фокус на наше окно
SetForegroundWindow(g_hWnd); //Устанавливаем высший приоритет окна
SetForegroundWindow(g_hWnd); //Устанавливаем приоритет окна выше среднего


MSG msg;
MSG msg;
ZeroMemory(&msg,sizeof(msg));
ZeroMemory(&msg,sizeof(msg));


while(g_bApplicationState)
while(g_bApplicationState) //Начинаем бесконечный цикл обработки сообщений
{
{
if(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))
if(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))//Получаем сообщения
{
{
TranslateMessage(&msg);
TranslateMessage(&msg); //Обрабатываем сообщения
DispatchMessage(&msg);
DispatchMessage(&msg); //Обрабатываем сообщения
}
}
else
}
DrawFrame(); //Если сообщений нету рисуем кадры
}


Shutdown(); //Освобождаем память
return 0; //Завершаем работу приложения
return 0; //Завершаем работу приложения
}
}
[/code]


Теперь мы должны написать функцию которая у нас будет обрабатывать сообщения, принцип действия этой функции таков: если мы получили сообщения - перехватываем его, и делаем действия которые нам требуются.
[code=cpp]
long WINAPI WndProc(HWND hWnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
long WINAPI WndProc(HWND hWnd,UINT iMsg,WPARAM wParam,LPARAM lParam)
{
{
switch(iMsg)
switch(iMsg)
{
{
case WM_DESTROY: //Если получаем сообщение о разрушении окна
case WM_DESTROY:
{
{
g_bApplicationState = false; //Устанавливаем состояния приложения в false (это значит что цикл обработки сообщений остановиться)
g_bApplicationState = false;
return 0; //Говорим виндовс что мы это сообщение обработали
return 0;
}
}
}
}


return DefWindowProc(hWnd,iMsg,wParam,lParam);
return DefWindowProc(hWnd,iMsg,wParam,lParam); //Если нету для нас нужных сообщений, пусть это обрабатывает виндовс
}
}
[/code]
</source>

Сейчас наша задача написать функцию инициализации Direct3D. Эта тема для вас новая, постарайтесь сосредоточиться и внимательно просмотреть код.
[code=cpp]
bool InitDirect3D(D3DFORMAT ColorFormat,D3DFORMAT DepthFormat)
{
if((g_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)//Создаем интерфейс Direct3D
return false; //Иначе возвращяем false

D3DPRESENT_PARAMETERS PresParam; //Структура с помощью которой передаем информацию устройству рендеринга при его создании
ZeroMemory(&PresParam,sizeof(PresParam)); //Обнуляем

HRESULT hr = NULL; //Создаем переменную для записи в неё результатов работы функций

D3DDISPLAYMODE DisplayMode; //Структура для получения информации о режиме отображения в виндовс
hr = g_pDirect3D->GetAdapterDisplayMode( //Получаем режим отображения
D3DADAPTER_DEFAULT, //Используем первичную видеокарту
&DisplayMode); //Записываем режим отображения в DisplayMode
if(FAILED(hr)) //Если не получилось
return false; //Возвращяем false

PresParam.hDeviceWindow = g_hWnd; //Дескриптор окна
PresParam.Windowed = true; //Оконный режим?
PresParam.BackBufferWidth = g_iWindowWidth; //Ширина заднего буфера
PresParam.BackBufferHeight = g_iWindowHeight; //Высота заднего буфера
PresParam.BackBufferCount = 1; //Количество задних буферов
PresParam.EnableAutoDepthStencil = true; //Используем буфер глубины и стенцил буфер
PresParam.AutoDepthStencilFormat = DepthFormat; //Формат буфера глубины
PresParam.SwapEffect = D3DSWAPEFFECT_FLIP; //Режим смены кадров
PresParam.BackBufferFormat = DisplayMode.Format;//Устанавливаем формат пикселя определеный в виндовс

hr = g_pDirect3D->CreateDevice( //Создаем устройство рендеринга
D3DADAPTER_DEFAULT, //Используем первичную видеокарту
D3DDEVTYPE_HAL, //Устройства рендеринга использует возможности видеокарты
g_hWnd, //Дескриптор окна
D3DCREATE_HARDWARE_VERTEXPROCESSING, //Обрабатываем вершинны видеокартой
&PresParam, //Отдаем параметры устройства
&g_pDirect3DDevice); //Создаем устройство рендеринга
if(SUCCEEDED(hr)) //Если получилось
return true; //Возвращяем true

hr = g_pDirect3D->CreateDevice( //Создаем устройство рендеринга
D3DADAPTER_DEFAULT, //Используем первичную видеокарту
D3DDEVTYPE_HAL, //Устройства рендеринга использует возможности видеокарты
g_hWnd, //Дескриптор окна
D3DCREATE_MIXED_VERTEXPROCESSING, //Обрабатываем вершинны смешано (видеокартой и процессором)
&PresParam, //Отдаем параметры устройства
&g_pDirect3DDevice); //Создаем устройство рендеринга

if(SUCCEEDED(hr)) //Если получилось
return true; //Возвращяем true

hr = g_pDirect3D->CreateDevice( //Создаем устройство рендеринга
D3DADAPTER_DEFAULT, //Используем первичную видеокарту
D3DDEVTYPE_HAL, //Устройства рендеринга использует возможности видеокарты
g_hWnd, //Дескриптор окна
D3DCREATE_SOFTWARE_VERTEXPROCESSING, //Обрабатываем вершинны процесором
&PresParam, //Отдаем параметры устройства
&g_pDirect3DDevice); //Создаем устройство рендеринга

if(SUCCEEDED(hr)) //Если получилось
return true; //Возвращяем true

return false; //Возвращяем false
}
[/code]

Приступим к написанию функции, которая будет рисовать кадры. У устройства рендеринга есть свои недостатки - потеря устройства. потеря устройства возникает например в случаях когда полноэкранное окно не в фокусе и тд. После того как мы потеряли устройство надо его востановить, чтобы дальше можно было отображать сцену.
[code=cpp]
void DrawFrame()
{
HRESULT hr = g_pDirect3DDevice->TestCooperativeLevel();//Проверяем потерял ли Direct3DDevice устройство
if(hr == D3DERR_DEVICELOST) //Если да то
return; //Выходи из функции
g_pDirect3DDevice->Clear( //Очищаем задний буфер
0L, //Размер буфера, 0 - весь буфер
NULL, //Область которую будем очищать, NULL - весь буфер
D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, //Чистим задний буфер и буфер глубины
D3DCOLOR_XRGB(0,0,0), //Цвет в который очищаем задний буфер, в нашем случае черный
1.0f, //Очищаем буфер глубины, заполнив его единицами
0L); //Этот параметрт игнорируеться так как не выстовлен соответсвующий флаг

g_pDirect3DDevice->BeginScene(); //Начало сцены
g_pDirect3DDevice->EndScene(); //Конец сцены
g_pDirect3DDevice->Present(NULL,NULL,NULL,NULL);//Отображаем весь задний буфер
}
[/code]

Ну и последняя функция, которая будет освобождать выдуленеую память. Освобождать память надо в обратном порядке выделения памяти.
[code=cpp]
void Shutdown()
{
if(g_pDirect3DDevice != NULL) //Если мы еще не освободили интерфейс рендеринга
{
g_pDirect3DDevice->Release(); //То освобождаем его
g_pDirect3DDevice = NULL; //И устанавливаем в ноль
}

if(g_pDirect3D != NULL) //Если мы еще не освободили интерфейс d3d
{
g_pDirect3D->Release(); //То освобождаем его
g_pDirect3D = NULL; //И устанавливаем в ноль
}

if(!DestroyWindow(g_hWnd)) //Если не получилось разрушить окно
g_hWnd = NULL; //Устанавливаем дескриптор окна в ноль

if(!UnregisterClass("Lesson 1",g_hInstance)) //Если не получилось удалить наше зарегестрированое окно
g_hInstance = NULL; //Устанавливаем дескриптор приложения в ноль
}
[/code]

Теперь компилируем и смотрим что получилось)
Мы написали приложение которое инициализирует Direct3D в оконном режиме, а в полоэкранном режиме мы напишем когда наше приложение будет поддерживать клавиатуру.

Версия от 21:38, 29 ноября 2009

Введение

В этом учебнике я постараюсь научить вас программировать игры на языку С++ с помощью DirectX SDK. Программировать мы будем с вами для операционной системы Windows XP. В этом учебнике мы охватим такие важные темы как графика, музыка, физика, искусственный интеллект. Для применение полученных знаний мы напишем пару игр. Код используемый в книге был написан мною в среде Microsoft Visual C++ 6.0 с использованием DirectX SDK November 2009.

Урок 1 - Создание окна. Инициализация Direct3D

Введение

Учебник называется "Программируем игры..." потому что мы будет говорить только о программном коде, а темы насчет моделирования, рисования и тд. мы не будем обсуждать. Для того чтобы начать читать этот учебник нужно знать хотя бы основы С++ и STL. Программировать мы будем с вами для операционной системы Windows XP на С++. В этом учебнике мы охватим такие важные темы как графика, физика, музыка, искусственный интеллект, устройства ввода и по ходу обучения мы создадим пару игр для применения полученных знаний. Код используемый в книге был написан мною на Microsoft Visual C++ 6.0 (далее MVC++) с использованием DirectX 9 SDK November 2009

Создание окна. Иницциализация Direct3D

Создадим проект с именем Lesson1. Добавим в него файл main.cpp, и начнем его заполнять. Для работы приложения нам потребуется использовать разные библиотеки, их мы сейчас и подключим к нашему проекту. [code=cpp] //Подключаем библиотеки

  1. pragma comment(lib,"d3d9.lib")
  2. pragma comment(lib,"d3dx9.lib")
  3. pragma comment(lib,"winmm.lib")

[/code]

Дальше мы должны подключить заголовочные файли, чтобы компилятор не выдавал ошибки. [code=cpp] //Подключаем заголовчные файлы

  1. include <windows.h>
  2. include <d3d9.h>
  3. include <d3dx9.h>

[/code]

Объявим глобальные переменные которые мы будем использовать в нашей программе. [code=cpp] //Глобальные переменные HINSTANCE g_hInstance = NULL; //Дескриптор приложения HWND g_hWnd = NULL; //Дескриптор окна int g_iWindowWidth = 800; //Ширина окна int g_iWindowHeight = 600; //Высота окна bool g_bApplicationState = true; //Состояние приложения (true - работает/false - неработает) IDirect3D9 *g_pDirect3D = NULL; //Интерфейс для создания устройства рендеринга IDirect3DDevice9 *g_pDirect3DDevice = NULL; //Интерфейс устройства рендеринга [/code]

Теперь объявим прототипы функций, которые мы с вами напишем. [code=cpp] int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow); //Точка старта приложения long WINAPI WndProc(HWND hWnd,UINT iMsg,WPARAM wParam,LPARAM lParam);//Обработчик сообщений bool InitDirect3D(D3DFORMAT ColorFormat,D3DFORMAT DepthFormat); //Инициализация Direct3D void DrawFrame(); //Рисуем кадр void Shutdown(); //Освобождаем память [/code]

Поговорим о функции WinMain. Эта функция является точкой старта приложения, код который в ней написан начинает выполнение при запуске программы. В этой функции мы должны создать окно и отобразить его. [code=cpp] int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int iCmdShow) {

 g_hInstance = GetModuleHandle(NULL);
 WNDCLASSEX wc;
 wc.cbSize      = sizeof(WNDCLASSEX);        //Размер структуры
 wc.style           = CS_HREDRAW|CS_VREDRAW;      //Стили класса окна
 wc.lpfnWndProc    = WndProc;              //Функция обработки сообщений
 wc.cbClsExtra    = 0;                //Количество выделяемой памяти при создании приложения
 wc.cbWndExtra      = 0;                //Количество выделяемой памяти при создании приложения
 wc.hInstance    = g_hInstance;            //Дескриптор приложения
 wc.hIcon           = LoadIcon(NULL,IDI_APPLICATION);  //Загружаем стандартную иконку
 wc.hCursor         = LoadCursor(0,IDC_ARROW);      //Загружаем стандартный курсор
 wc.hbrBackground   = (HBRUSH)GetStockObject(WHITE_BRUSH);//Окно будет закрашено в белый цвет
 wc.lpszMenuName    = 0;                //Не используем меню
 wc.lpszClassName   = "Lesson 1";            //Названия класса
 wc.hIconSm       = LoadIcon(NULL,IDI_APPLICATION);  //Загружаем стандартную иконку
 if(!RegisterClassEx(&wc))                //Регистрируем класс в Windows
 {
   Shutdown();                    //Освобаждем память
   MessageBox(NULL,"Can`t register window class","Error",MB_OK|MB_ICONERROR); //Выводим сообщение
   return 0;                    //Завершаем работу приложения
 }
 g_hWnd = CreateWindowEx(              //Создаем окно
   WS_EX_APPWINDOW|WS_EX_WINDOWEDGE,        //Расширенный стиль окна
   "Lesson 1",                    //Названия класса окна
   "Lesson 1 - Create Window. Init Direct3D",    //Названия окна
   WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,//Стиль окна
   0,                      //Позиция окна по оси Х
   0,                      //Позиция окна по оси У
   g_iWindowWidth,                //Ширина окна
   g_iWindowHeight,              //Высота окна
   NULL,                    //Это наше главное окно
   NULL,                    //Нету меню
   g_hInstance,                //Дескриптор приложения
   NULL);                    //Дополнительный настроек не используем
 if(g_hWnd == NULL)                //Если не создали окно
 {
   Shutdown();
   MessageBox(NULL,"Can`t create window","Error",MB_OK|MB_ICONERROR);//Выводим сообщение
   return 0;                  //Завершаем работу приложения
 }
 if(!InitDirect3D(D3DFMT_R5G6B5,D3DFMT_D16))    //Если не смогли инициализировать Direct3D
 {
   Shutdown();
   MessageBox(NULL,"Can`t create direct3d","Error",MB_OK|MB_ICONERROR);//Выводим сообщение
   return 0;                  //Завершаем работу приложения
 }
 ShowWindow(g_hWnd,SW_SHOW);            //Отображаем окно  
 UpdateWindow(g_hWnd);              //Обновляем окно
 SetFocus(g_hWnd);                //Устанавливаем фокус на наше окно
 SetForegroundWindow(g_hWnd);          //Устанавливаем приоритет окна выше среднего
 MSG msg;
 ZeroMemory(&msg,sizeof(msg));
 while(g_bApplicationState)            //Начинаем бесконечный цикл обработки сообщений
 {
   if(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))//Получаем сообщения
   {
     TranslateMessage(&msg);          //Обрабатываем сообщения
     DispatchMessage(&msg);          //Обрабатываем сообщения
   }
   else
     DrawFrame();              //Если сообщений нету рисуем кадры
 }
 Shutdown();                    //Освобождаем память
 return 0;                    //Завершаем работу приложения

} [/code]

Теперь мы должны написать функцию которая у нас будет обрабатывать сообщения, принцип действия этой функции таков: если мы получили сообщения - перехватываем его, и делаем действия которые нам требуются. [code=cpp] long WINAPI WndProc(HWND hWnd,UINT iMsg,WPARAM wParam,LPARAM lParam) {

 switch(iMsg)
 {
   case WM_DESTROY:              //Если получаем сообщение о разрушении окна
   {
     g_bApplicationState = false;      //Устанавливаем состояния приложения в false (это значит что цикл обработки сообщений остановиться)
     return 0;                //Говорим виндовс что мы это сообщение обработали
   }
 }
 return DefWindowProc(hWnd,iMsg,wParam,lParam);  //Если нету для нас нужных сообщений, пусть это обрабатывает виндовс

} [/code]

Сейчас наша задача написать функцию инициализации Direct3D. Эта тема для вас новая, постарайтесь сосредоточиться и внимательно просмотреть код. [code=cpp] bool InitDirect3D(D3DFORMAT ColorFormat,D3DFORMAT DepthFormat) {

 if((g_pDirect3D = Direct3DCreate9(D3D_SDK_VERSION)) == NULL)//Создаем интерфейс Direct3D
   return false;                //Иначе возвращяем false
 D3DPRESENT_PARAMETERS PresParam;        //Структура с помощью которой передаем информацию устройству рендеринга при его создании
 ZeroMemory(&PresParam,sizeof(PresParam));    //Обнуляем
 HRESULT hr = NULL;                //Создаем переменную для записи в неё результатов работы функций
 D3DDISPLAYMODE DisplayMode;            //Структура для получения информации о режиме отображения в виндовс
 hr = g_pDirect3D->GetAdapterDisplayMode(    //Получаем режим отображения
   D3DADAPTER_DEFAULT,              //Используем первичную видеокарту
   &DisplayMode);                //Записываем режим отображения в DisplayMode
 
 if(FAILED(hr))                  //Если не получилось
   return false;                //Возвращяем false
 PresParam.hDeviceWindow = g_hWnd;        //Дескриптор окна
 PresParam.Windowed = true;            //Оконный режим?
 PresParam.BackBufferWidth = g_iWindowWidth;    //Ширина заднего буфера
 PresParam.BackBufferHeight = g_iWindowHeight;  //Высота заднего буфера
 PresParam.BackBufferCount = 1;          //Количество задних буферов
 PresParam.EnableAutoDepthStencil = true;    //Используем буфер глубины и стенцил буфер
 PresParam.AutoDepthStencilFormat = DepthFormat;  //Формат буфера глубины
 PresParam.SwapEffect = D3DSWAPEFFECT_FLIP;    //Режим смены кадров
 PresParam.BackBufferFormat = DisplayMode.Format;//Устанавливаем формат пикселя определеный в виндовс
  hr = g_pDirect3D->CreateDevice(        //Создаем устройство рендеринга
   D3DADAPTER_DEFAULT,              //Используем первичную видеокарту
   D3DDEVTYPE_HAL,                //Устройства рендеринга использует возможности видеокарты
   g_hWnd,                    //Дескриптор окна
   D3DCREATE_HARDWARE_VERTEXPROCESSING,    //Обрабатываем вершинны видеокартой
   &PresParam,                  //Отдаем параметры устройства
   &g_pDirect3DDevice);            //Создаем устройство рендеринга
 
 if(SUCCEEDED(hr))                //Если получилось 
   return true;                //Возвращяем true
 hr = g_pDirect3D->CreateDevice(          //Создаем устройство рендеринга
   D3DADAPTER_DEFAULT,              //Используем первичную видеокарту
   D3DDEVTYPE_HAL,                //Устройства рендеринга использует возможности видеокарты
   g_hWnd,                    //Дескриптор окна
   D3DCREATE_MIXED_VERTEXPROCESSING,      //Обрабатываем вершинны смешано (видеокартой и процессором)
   &PresParam,                  //Отдаем параметры устройства
   &g_pDirect3DDevice);            //Создаем устройство рендеринга
 if(SUCCEEDED(hr))                //Если получилось
   return true;                //Возвращяем true
 hr = g_pDirect3D->CreateDevice(          //Создаем устройство рендеринга
   D3DADAPTER_DEFAULT,              //Используем первичную видеокарту
   D3DDEVTYPE_HAL,                //Устройства рендеринга использует возможности видеокарты
   g_hWnd,                    //Дескриптор окна
   D3DCREATE_SOFTWARE_VERTEXPROCESSING,    //Обрабатываем вершинны процесором
   &PresParam,                  //Отдаем параметры устройства
   &g_pDirect3DDevice);            //Создаем устройство рендеринга
 if(SUCCEEDED(hr))                //Если получилось
   return true;                //Возвращяем true
 return false;                  //Возвращяем false

} [/code]

Приступим к написанию функции, которая будет рисовать кадры. У устройства рендеринга есть свои недостатки - потеря устройства. потеря устройства возникает например в случаях когда полноэкранное окно не в фокусе и тд. После того как мы потеряли устройство надо его востановить, чтобы дальше можно было отображать сцену. [code=cpp] void DrawFrame() {

 HRESULT hr = g_pDirect3DDevice->TestCooperativeLevel();//Проверяем потерял ли Direct3DDevice устройство
 
 if(hr == D3DERR_DEVICELOST)            //Если да то
   return;                   //Выходи из функции  
 
 g_pDirect3DDevice->Clear(            //Очищаем задний буфер
   0L,                     //Размер буфера, 0 - весь буфер
   NULL,                     //Область которую будем очищать, NULL - весь буфер
   D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,     //Чистим задний буфер и буфер глубины
   D3DCOLOR_XRGB(0,0,0),            //Цвет в который очищаем задний буфер, в нашем случае черный
   1.0f,                     //Очищаем буфер глубины, заполнив его единицами
   0L);                    //Этот параметрт игнорируеться так как не выстовлен соответсвующий флаг
 g_pDirect3DDevice->BeginScene();        //Начало сцены
 g_pDirect3DDevice->EndScene();          //Конец сцены
 g_pDirect3DDevice->Present(NULL,NULL,NULL,NULL);//Отображаем весь задний буфер

} [/code]

Ну и последняя функция, которая будет освобождать выдуленеую память. Освобождать память надо в обратном порядке выделения памяти. [code=cpp] void Shutdown() {

 if(g_pDirect3DDevice != NULL)          //Если мы еще не освободили интерфейс рендеринга
 {
   g_pDirect3DDevice->Release();        //То освобождаем его
   g_pDirect3DDevice = NULL;          //И устанавливаем в ноль
 }
 if(g_pDirect3D != NULL)              //Если мы еще не освободили интерфейс d3d
 {
   g_pDirect3D->Release();            //То освобождаем его
   g_pDirect3D = NULL;              //И устанавливаем в ноль
 }
 if(!DestroyWindow(g_hWnd))            //Если не получилось разрушить окно
   g_hWnd = NULL;                //Устанавливаем дескриптор окна в ноль
 if(!UnregisterClass("Lesson 1",g_hInstance))  //Если не получилось удалить наше зарегестрированое окно
   g_hInstance = NULL;              //Устанавливаем дескриптор приложения в ноль

} [/code]

Теперь компилируем и смотрим что получилось) Мы написали приложение которое инициализирует Direct3D в оконном режиме, а в полоэкранном режиме мы напишем когда наше приложение будет поддерживать клавиатуру.