Романтика GameDev'а

DirectX с разных сторон

Итак, дамы и господа, давайте продолжим наш разговор о компьютерных играх. Точнее, не столько о самих играх, сколько о способах и путях их изготовления.

Сегодня я рассказу вам кратко о технологии, без которой сложно представить современную индустрию GameDev'а. Хотя, конечно, если бы не было DirectX, то её место заняла бы какая-нибудь другая технология или же целая их совокупность. Для графики это вполне могла бы быть OpenGL, для звука - OpenAL, да и для остальных частей DirectX наверняка нашлась бы неплохая замена в качестве индустриального стандарта... Впрочем, говорят, что история не терпит сослагательного наклонения, а поэтому, коль скоро стандартом является DirectX, то о нём и будем вести речь.

Итак, что же такое этот самый DirectX? Вообще говоря, определения разнятся даже на официальном сайте "Майкрософт" в разделе, посвящённом DirectX (www.microsoft.com/windows/directx). Однако, поскольку мы с вами говорим сейчас преимущественно о программировании, то и взгляд на DirectX будет соответствующим. DirectX - это коллекция API, разработанных для простого и эффективного решения задач, связанных с игровым и мультимедийным программированием под Windows. Этих API в DirectX изрядное количество, поэтому они, в свою очередь, разделяются на несколько категорий. DirectX Graphics ответственен за графику, что и видно из названия. Direct3D - это компоненты DirectX, отвечающие за трёхмерную графику. DirectMusic и DirectSound - компоненты, ответственные за проигрывание музыки и звука. К последним двум наборам интерфейсов непосредственно примыкают ещё два: Direct Media Objects - интерфейсы, отвечающие за поддержку потоковых объектов (то есть, например, потокового аудио и видео для его компрессии/декомпрессии), и DirectShow - компонент, обеспечивающий вывод потокового видео. Есть в DirectX и компонент, обеспечивающий взаимодействие других программных частей с "железом". Это DirectInput - интерфейсы, используемые для обработки данных, поступающих с клавиатуры, мыши, джойстика и прочих различных игровых контроллеров. За коммуникацию между удалёнными друг от друга компьютерами в процессе игры отвечает компонент DirectPlay. DirectX Diagnostics нужен для диагностики работы программных компонентов DirectX. Есть ещё небольшой компонент под названием DirectSetup. Он нужен для того, чтобы упростить установку компонентов DirectX на компьютер пользователя.

Теперь, с вашего позволения, немного истории. Думаю, многие из читающих эти строки помнят ещё славные времена, когда DirectX не был необходимым атрибутом каждой новой игры. Но уже в те годы назрела необходимость в общей библиотеке для создания "игрушек". Естественно, корпорация Microsoft не могла остаться в стороне от такого заманчивого проекта и выпустила WinG API - набор интерфейсов для 2-мерной растровой графики для Windows. Однако этот продукт не пользовался особой популярностью среди разработчиков игр (первый блин, как водится, вышел комом), поэтому вскоре появился новый набор API для игроделов - Game SDK. Произошло это в 1995 году. В скором времени не слишком звучное название было заменено на другое, под которым технология и вошла в историю - DirectX. Во второй версии DirectX появилась какая-никакая поддержка трёхмерной графики. При этом четвёртая версия DirectX так и не увидела свет - в 1997 году была выпущена сразу пятая версия, в которой DirectInput стал самостоятельным компонентом. В каждой новой версии DirectX имел собственный логотип. Логотип DirectX 9.0 вы можете увидеть на иллюстрации к статье.

В настоящее время в DirectX уже нет как таковой поддержки двухмерной растровой графики. Хотя ещё совсем недавно в DirectX 8.0 присутствовал набор интерфейсов DirectDraw, который как раз с растровой графикой и работал. Но индустрия развивается и меняется, поэтому растровая графика, уже не такая актуальная, полностью отдана на откуп GDI и GDI+.

Итак, за что отвечает DirectX, вроде, стало понятно. Теперь поговорим о том, как этим пользоваться. Все интерфейсы DirectX представлены в виде COM-объектов. Конечно, это не прибавляет скорости работы программам, использующим данные интерфейсы, поскольку технология COM сама по себе не слишком шустрая, но, в целом, на современных компьютерах снижение скорости практически не заметно. Зато благодаря объектно-ориентированному подходу существенно повышается скорость программирования конечного продукта. Собственно, основное преимущество DirectX состоит именно в этом: благодаря единому объектно-ориентированному API для всех марок оборудования разработчик получает возможность заниматься только логикой программы, реализацией правдоподобных законов игровой физики и прочим, чем заниматься гораздо приятнее, чем совместимостью игры с каждой моделью видеокарты каждого производителя.

Итак, что нужно для работы с DirectX? Во-первых, неплохо бы заиметь Microsoft Visual Studio 2005, хотя для разработки не слишком сложных приложений можно обойтись и любой другой средой разработки с хорошим компилятором C++. Но, коль скоро теперь существует Visual Studio Express, за которую у вас никто не потребует денег, то не вижу особого смысла в том, чтобы пользоваться чем-то другим. Во-вторых, нужен DirectX SDK. Его можно взять здесь: www.microsoft.com/downloads/details.aspx?FamilyID=86CF7FA2-E953-475C-ABDE-F016E4F7B61A&displaylang=en. Качать нужно будет около 440 Мб, так что по dial-up время скачивания составит порядка 20 часов. В принципе, можно постараться и найти CD с DirectX SDK, но там явно будет не самая последняя версия. В состав DirectX SDK входят компоненты, необходимые для работы с объектами DirectX из приложений на C++ (заголовочные файлы), разнообразные утилиты, сборки .NET для Managed DirectX (об этом феномене, если не забуду, ещё будет чуть ниже). Также в составе SDK присутствуют документация, примеры и, собственно, сам DirectX.

Хотя не так давно вышел DirectX 10, большей части пользователей он недоступен из-за того, что работает только под Windows Vista. О DirectX 10 мы ещё поговорим сейчас или потом, как и о Managed DirectX, - право слово, и тот, и другой весьма интересные темы для разговора. Но поскольку Vista стоит мало у кого, а на CD продаётся SDK для 9-й версии DirectX, то на неё мы и будем ориентироваться. Поэтому сейчас позвольте предложить вашему вниманию пример, демонстрирующий логику работы DirectX-приложений и архитектуру некоторых компонентов DirectX. На мой взгляд, пусть это и банально, самый интересный для примера компонент - Direct3D.

Для простого примера можно не использовать специальные библиотеки для построения программ, а обойтись средствами Direct3D и WindowsAPI. Создайте пустой оконный проект (для Visual Studio это будет Win32 Application). Подключите к проекту d3d9.h и соответствующую этому заголовочному файлу статически компонуемую библиотеку d3d9.lib. В них содержатся основные интерфейсы и классы, необходимые для работы с Direct3D 9. Главным же среди всех иінтерфейсов, относящихся к Direct3D, является IDirect3D9. Код, инициализирующий переменную этого интерфейсного типа и создающий контекст, на который будет выводиться изображение, приводится ниже.

IDirect3D9 * pD3D;
IDirect3DDevice9 * pDevice;
pD3D = Direct3DCreate9(D3D_SDK_VERSION);
D3DPRESENT_PARAMETERS d3dpp = {0};
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
HRESULT hr;
hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pDevice);

Поясню суть некоторых выполняемых этой программой действий. Сначала создаётся и инициализируется собственно упомянутая интерфейсная переменная. Дальше идёт инициализация параметров рендерера: указывается, что приложение будет работать в оконном режиме (а не в полноэкранном), разрешаем выводить случайные значения, заполняющие буфер, и указываем на то, что формат буфера изображения берётся из настроек системы, т.к. наше приложение будет работать в оконном режиме. Последний оператор создаёт непосредственно контекст вывода графики с поддержкой аппаратного ускорения её расчётов.

Но инициализация есть инициализация, и, ясное дело, для вывода изображений её явно недостаточно. Поэтому перейдём к следующему куску кода, который должен рисовать кадры на экране.

pDevice->Clear(0, NULL, D3DCLEAR_TARGET,
 D3DCOLOR_XRGB(0,0,0), 1.0f, 0);
pDevice->BeginScene();
/* ... */
pDevice->EndScene();
pDevice->Present(NULL, NULL, NULL, NULL);

Тут всё просто. Первой строкой очищаем всё, что у нас уже было нарисовано в буфере. Далее методом BeginScene начинаем рисовать сцену, а методом EndScene заканчиваем это действие. Чтобы всё, что нарисовано в буфере, вывести на экран, используется метод Present. Код вместо содержательного комментария с многоточием и должен отрисовывать объекты на контексте устройства. Обратите внимание на макрос D3DCOLOR_XRGB, который переводит цвет из RGB-представления, задаваемого, соответственно, тремя компонентами, во внутреннее представление Direct3D. То есть, фон у нас будет заполнен чёрным цветом.

После того, как мы долго и тщательно создавали контекст и инициализировали Direct3D, становится ясно, что и обратный процесс без шаманства не обойдётся. Завершить работу программы с Direct3D можно с помощью следующего кода:

if(pDevice) pDevice->Release();
if(pD3D) pD3D->Release();

Думаю, тут всё предельно просто, и дополнительные объяснения не так уж необходимы.

В качестве тренинга можете попробовать написать код, который будет рисовать что-нибудь на экране, кроме чёрного фона. Думаю, изучив примеры из DirectX SDK, вам будет не слишком сложно написать соответствующий код.

Что ж, пока что на сегодня про DirectX достаточно. Я помню, что с меня ещё рассказ о DirectX 10 и Managed DirectX. Но об этом чуть позже, договорились?

(Продолжение следует)

Вадим СТАНКЕВИЧ

Версия для печатиВерсия для печати

Номер: 

18 за 2007 год

Рубрика: 

Software
Заметили ошибку? Выделите ее мышкой и нажмите Ctrl+Enter!