Программируем игры на 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] |
|||
//Глобальные переменные |
//Глобальные переменные |
||
HINSTANCE g_hInstance = NULL; //Дескриптор приложения |
|||
HWND g_hWnd = NULL; //Дескриптор окна |
|||
int |
int g_iWindowWidth = 800; //Ширина окна |
||
int g_iWindowHeight = 600; //Высота окна |
|||
bool g_bApplicationState = true; //Состояние приложения (true - работает/false - неработает) |
|||
bool |
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); //Дополнительный настроек не используем |
|||
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); //Отображаем окно |
|||
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; //Завершаем работу приложения |
|||
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) |
|||
{ |
|||
case WM_DESTROY: //Если получаем сообщение о разрушении окна |
|||
case WM_DESTROY: |
|||
{ |
|||
{ |
|||
g_bApplicationState = false; //Устанавливаем состояния приложения в false (это значит что цикл обработки сообщений остановиться) |
|||
g_bApplicationState = false; |
|||
return 0; //Говорим виндовс что мы это сообщение обработали |
|||
return 0; |
|||
} |
|||
} |
|||
} |
|||
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] //Подключаем библиотеки
- pragma comment(lib,"d3d9.lib")
- pragma comment(lib,"d3dx9.lib")
- pragma comment(lib,"winmm.lib")
[/code]
Дальше мы должны подключить заголовочные файли, чтобы компилятор не выдавал ошибки. [code=cpp] //Подключаем заголовчные файлы
- include <windows.h>
- include <d3d9.h>
- 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 в оконном режиме, а в полоэкранном режиме мы напишем когда наше приложение будет поддерживать клавиатуру.