Загрузка...
 
Печать

DirectX Graphics (DirectX 8). Начало работы

  • Является одним из компонентов DirectX (версии 8 и более поздних), отвечающим за вывод на экран 2D и 3D-графики.1

Прежде чем начать работать с DirectX Graphics, его необходимо грамотно инициализировать. До появления DirectX 8 за отрисовку 2D-графики отвечал специальный компонент DirectDraw. В версии 8 компоненты Direct3D и DirectDraw объединили в один - DirectX Graphics.1

Закрыть
noteОбрати внимание

В более ранних версиях DirectX компонент DirectX Graphics состоял из двух отдельных компонентов: Direct3D и DirectDraw.
Несмотря на это, в литературе и в исходных кодах примеров можно встретить множество отсылок к Direct3D. Множество "ушей" в DirectX Graphics растёт именно из этого, казалось бы, преданного забвению, компонента. Поэтому разом забыть о Direct3D вряд ли получится.

С выходом DirectX 8 даже ветеранам игрокодинга потребовалось время для ознакомления со всеми прибамбасами нового API.
Для компиляции примеров на понадобится:

    • MS Visual C++ 2010 Express,
    • Microsoft DirectX SDK 8.

Всё легко гуглится + есть в разделе "Софт" нашего сайта.
Перед началом работы (в нашем случае) с DirectX 8 всегда проделывай следующие шаги:

  • Включай в топовый заголовочный файл директиву #include D3D8.H.
  • Добавляй в Решение/Проект файл библиотеки D3D8.LIB.
  • Указывай корректные пути к каталогам включения (include) и библиотечных файлов (LIB) DirectX SDK при создании каждого нового Решения/Проекта.

Эти два файла являются основными (и часто единственными), которые требуются для создания простых приложений под DirectX Graphics. При компиляции они автоматически "подтянут" в Решение/Проект другие (вспомогательные) файлы из каталога DirectX SDK. Это нормально.
Весь процесс неплохо расписан в статьях:


Содержание

Компоненты Direct3D (DirectX 8)

Конструктивно Direct3D состоит из нескольких COM-объектов, у каждого из которых своё назначение. Так объект IDirect3D8 применяется для общего контроля графической системы, а IDirect3DDevice8 применяется для контроля процесса вывода графики на экран. Вот далеко неполный их список:

Компонент Описание
IDirect3D8 Применяется для сбора информации о графическом адаптере и настройке его программных интерфейсов.
IDirect3DDevice8 Имеет дело напрямую с 3D-ускорителем графического адаптера. Рендерит графику, управляет графическими ресурсами, создаёт и назначает рендер-стейты (render states) и фильтры затенения (shade filters) + делает много чего ещё.
IDirect3DVertexBuffer8 Содержит массив информации о вершинах, используемых для построения полигонов.
IDirect3DTexture8 Применяется для хранения всех изображений, используемых для окрашивания граней (faces) 2D и 3D-объектов.

Инициализация Direct3D (DirectX 8)

  • Выполняется в 4 шага:
  1. Назначаем интерфейс Direct3D.
  2. Выбираем режим дисплея (display mode).
  3. Назначаем метод презентации (presentation method).
  4. Создаём интерфейс устройства (device interface) и инициализируем экран.

Назначаем интерфейс Direct3D (Obtaining the Direct3D Interface)

Здесь мы инициализируем объект IDirect3D8. Для этого есть специальная функция Direct3DCreate8:

IDirect3D8 *Direct3DCreate8(UINT SDKVersion);  // Версия DirectX SDK

Да, в единственном параметре указываем версию DirectX SDK. При успешном выполнении функция возвращает значение - указатель на только что созданный объект IDirect3D8. В случае неудачи возвращается NULL.
Вот пример её применения:

IDirect3D g_D3D;  // Глобальный IDirect3D8 объект
if((g_D3D = Direct3DCreate8(D3D_SDK_VERSION)) == NULL)
{
 // Завершить работу, выдав ошибку.
}

Выбираем режима дисплея (Selecting a Display Mode)

После того, как объект IDirect3D создан, можно приступать к сбору информации о графической системе компьютера. В частности создаётся список видеорежимов (display modes), поддерживаемых Direct3D. Можно также запросить инфу о текущем видеорежиме экрана.
Каждый видеорежим состоит из трёх компонентов:

  • Разрешение экрана (ширина (width) и высота (height) в пикселях)
  • Глубина цвета (color depth; число цветов, одновременно отображаемое на экране)
  • Частота обновления (refresh rate) экрана.

Например, ты выбрал видеорежим с разрешением 640х480, глубиной цвета 16 бит и частотой обновления видеоадаптера по умолчанию.
Вся инфа о видеорежиме содержится в специальной структуре D3DDISPLAYMODE:

Структура D3DDISPLAYMODE
typdef struct _D3DDISPLAYMODE
{
 UINT Width;  // Ширина экрана в пикселях.
 UINT Height;  // Высота экрана в пикселях.
 UINT RefreshRate;  // Частота обновления (0 - частота обновления по умолчанию).
 D3DFORMAT Format;  // Формат цветности.
} D3DDISPLAYMODE;

Если с разрешением и частотой обновления всё ясно, то формат цветности рассмотрим подробнее.

Режимы цветности (Color modes)
В графических редакторах обычно можно выбирать число бит на пиксель (16, 24, 32) при сохранении изображения. Чем больше бит на пиксель ты используешь, тем больше цветов можно одновременно отобразить и тем больше для этого потребуется памяти. При этом чаще всего обращаются к т.н. режимам цветности (color modes), называемым по кол-ву бит на каждый из цветовых компонентов (red, green, blue и иногда alpha-канал). Например, допустим, я выбрал режим цветности 16 бит (16-bit color mode): 5 бит на красный (red), 5 на зелёный (green), 5 на синий (blue) и 1 бит - альфа-канал (обычно это канал прозрачности). Имя в своём распоряжении 5 бит, каждый цветовой компонент может сохранить до 32 своих оттенков. Альфа-канал здесь располагает всего одним битом (т.е. вкл. и выкл.).
При рендеринге в реальном рендеринге мы не обращаемся ко всей 16-битной палитре, а указываем число бит на каждый компонент (1 alpha, 5 red, 5 green, 5 blue). Стандартным принят цветовой режим 555 (5 бит на красный, 5 на зелёный, 5 на синий), 565 (5 бит на красный, 6 на зелёный, 5 на синий) и 888 (по 8 бит на каждый цветовой компонент). Обрати внимание, что альфа-канал здесь вообще не фигурирует, т.к. используется далеко не всегда.
Direct3D определяет эти режимы цветности в виде специальных макросов, которые на деле представляют собой обычные перечисления (массивы типа enum). Вот наиболее часто применяемые:
Таблица 1. Макросы цветовых режимов Direct3D (Direct3D Color Mode Macros)
IDirect3DDevice8 применяется для контроля процесса вывода графики на экран. Вот далеко неполный их список:

Значение Описание формата
D3DFMT_R8G8B8 (24-bit) 8 бит на красный, 8 на зелёный и 8 на синий компонент.
D3DFMT_A8R8G8B8 (32-bit) 8 бит на альфа-канал, 8 на красный, 8 на зелёный и 8 на синий компонент.
D3DFMT_X8R8G8B8 (32-bit) 8 бит на неиспользуемый (unused) канал, 8 на красный, 8 на зелёный и 8 на синий компонент.
D3DFMT_R5G6B5 (16-bit) 5 бит на красный, 6 на зелёный и 5 на синий компонент.
D3DFMT_X1R5G5B5 (16-bit) 1 бит на неиспользуемый (unused) канал, 5 бит на красный, 5 на зелёный и 5 на синий компонент.
D3DFMT_A1R5G5B5 (16-bit) 1 бит на альфа-канал, 5 бит на красный, 5 на зелёный и 5 на синий компонент.


Вот пример инициализации структуры D3DDISPLAYMODE, устанавливающей видеорежим с разрешением 640х480 и использующий формат цветности D3DFMT_R5G6B5:

D3DDISPLAYMODE d3ddm;
d3ddm.Width   = 640;
d3ddm.Height  = 480;
d3ddm.RefreshRate = 0;  // Используем то, которое стоит по умолчанию
d3ddm.format  = D3DFMT_R5G6B5;

Для проверки того, поддерживается ли выбранный цветовой формат текущим видеоадаптером, надо просто заполнить структуру D3DDISPLAYMODE необходимой инфой и вызвать функцию CheckDeviceType:

// g_pD3D - предварительно проинициализированный объект Direct3D
// d3dmm - предварительно проинициализированная структура D3DDISPLAYMODE

// Проверяем, существует ли выбранный видеорежим.
if(FAILED(m_pD3D->CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &d3dmm, &d3dmm, FALSE)))
{
 // Ошибка. Данный режим цветности не поддерживается видеоадаптером.
}

Закрыть
noteОбрати внимание

Ключевые слова FAILED и SUCCEDED являются макросами и соответствуют возвращаемым Direct3D значениям типа HRESULT. Почти все функции Direct3D в случае успеха возвращают значение D3D_OK. В случае неудачи - любое другое значение.

Закрыть
noteОбрати внимание

Есть видеорежимы, которые многие видеоадаптеры не поддерживают в принципе. Проверка и отсечение таких режимов - задача игрокодера. В случае оконного режима (windowed mode) - это не является проблемой, т.к. в этом случае Direct3D управляет установками цветности самостоятельно.

Закрыть
noteОбрати внимание

Сбор информации о поддерживаемых видеорежимах делают только для полноэкранного режима (fullscreen mode).


Часто в игру дополнительно встраивают поддержку оконного режима (windowed mode). Такие игры напоминают обычные оконные приложения: всё действо происходит в стандартном окне Windows. В этом случае Direct3D заполняет информацию о текущем видеорежиме автоматически путём вызова функции GetDisplayMode. В коде это выглядит так:

// g_pD3D - предварительно проинициализированный объект Direct3D
D3DDISPLAYMODE d3ddm;
if(FAILED(g_pD3D->GetDisplayMode(D3DADAPTER_DEFAULT, &d3dmm)))
{
 // Ошибка.
}

В случае успешного выполнения вышеуказанный вызов метода IDirect3D8::GetDisplayMode возвращает корректную структуру D3DDISPLAYMODE с данными о текущем видеорежиме ОС Windows.

Назначаем метод презентации (Setting the Presentation Method)

Следующий шаг - указать Direct3D, каким образом представить отрендеренную графику игроку. Будет ли это оконный (windowed) режим или полноэкранный (fullscreen) или будем сначала выводить в бэкбуфер (backbuffer) а затем свопить? Какую частоту обновления (refresh rate) использовать? Вся эта информация (и многое другое) содержится в структуре D3DPRESENT_PARAMETERS:

Структура D3DPRESENT_PARAMETERS
typedef struct _D3DPRESENT_PARAMETERS
{
 UINT BackBufferWidth;  // Ширина бэкбуфера.
 UINT BackBufferHeight;  // Высота бэкбуфера.
 D3DFORMAT BackBufferFormat;  // То же самое, что и формат видеорежима (display mode format)
 UINT BackBufferCount;  // Обычно 1
 D3DMULTISAMPLE_TYPE MultiSampleType // Тип мультисэмплирования. Обычно 0.
 D3DSWAPEFFECT SwapEffect;  // Как будут сменяться бэкбуферы (swap - это тот же flip) и выводиться на экран.
 HWND hDeviceWindow;  // NULL
 BOOL Windowed;  // TRUE - оконный режим. FALSE - полноэкранный режим.
 BOOL EnableAutoDepthStencil;  // FALSE
 D3DFORMAT AutoDepthStencilFormat;  // 0
 DWORD Flags;  // 0
 UINT FullScreen_RefreshRateHz;  // 0
 UINT FullScreen_PresentationInterval;  // 0
} D3DPRESENT_PARAMETERS;

Здесь многие параметры можно тупо выставить в 0 (или NULL) или пропустить. Тем не менее, элементы, связанные с бэкбуферами, надо знать и уметь в них разбираться.

Рис.1 Рендеринг в бэкбуфер невидим для пользователя до тех пор, пока не произойдёт флип
Рис.1 Рендеринг в бэкбуфер невидим для пользователя до тех пор, пока не произойдёт флип

Бэкбуфер (Backbuffer)

С методом презентации тесно связано понятие бэкбуфера.
Для вывода изображения на экран Direct3D использует так называемые бэкбуферы (от англ. "back buffer" - задний буфер, закадровый буфер) - специальные области в памяти, где готовится очередой кадр изображения. Обычно есть два буфера:

  • передний (front buffer)
  • задний (back buffer; иногда их бывает несколько).

Передний буфер - это кадр который ты видишь на экране в определенный момент времени. Всё выглядит так, как будто изображение напрямую выводится на экран. Однако графический конвейер DirectX рендерит изображение не сразу на экран, а в задний буфер (back buffer) - внеэкранную текстуру, поверхность для рисования, размещаемую в памяти компьютера (её размеры всегда равны размеру экрана монитора или разрешению экрана), на которой происходят все операции по прорисовке кадра. (Та же технология применяется и в OpenGL.) Именно поэтому бэкбуфер часто называют "целью рендеринга по умолчанию" графического конвейера (default render target; в последних версиях DirectX render target может указывать не на бэкбуфер). Когда все команды рендеринга данного кадра в бэкбуфере закончились, вызывается специальная команда Flip (от англ. "перевернуть", быстро поменять местами; в последних версиях DirectX для этого используют функцию Present), которая просто копирует содержимое заднего буфера в передний. И всё то, что рисовали в задний буфер, моментально оказывается в переднем буфере, то есть на экране (см. Рис.1). Содержимое экрана - наоборот, помещается в бэкбуфер. (Впрочем, далеко не всегда.) Таким образом DirectX формирует изображение не напрямую на экран, а "рисует" в специальную текстуру (расположенную в бэкбуфере, в памяти), а затем эта текстура в полностью готовом виде выводится на экран. И так со скоростью 30-60 раз в секунду! Это сделано для того, чтобы движущаяся картинка на экране всегда оставалась плавной, чтобы зритель (игрок) не видел как на экране строится сцена. Ввиду такой колоссальной скорости в большинстве видеокарт работа с бэкбуферами изображения реализована на аппаратном уровне, что, безусловно, увеличивает быстродействие и качество выводимой картинки.

Закрыть
noteОбрати внимание

В литературе передний буфер часто называют вторым бэкбуфером или экранным бэкбуфером. Его суть от этого не меняется, но под термином "двойная буферизация" подразумевается именно наличие одного переднего и одного заднего буфера. Этой терминологии будем придерживаться и мы.

Рис.2 Использование бэкбуферов для вывода сцены на экран
Рис.2 Использование бэкбуферов для вывода сцены на экран

Так вот, чаще всего полноэкранные приложения используют 2 бэкбуфера (т.н. двойная буферизация) - 1 передний и 1 задний буфер. Оконное приложение (даже игра под Direct3D!) имеет в своём распоряжении всего 1 бэкбуфер (т.е. изображение рендерится напрямую в область видимости). При двойной буферизации в то время как Direc3D рендерит текущий кадр в один из бэкбуферов (с точки зрения Direct3D они вообще не подразделяются на передний и задний), другой бэкбуфер (который содержит последний кадр, "отрисованный" на нём) показывается на экране. Как только Direct3D закончит рендеринг во внеэкранный бэкбуфер, он быстро меняет бэкбуферы местами, выводя на экран только что отрендеренный кадр (см. Рис.2). Этот процесс продолжается на протяжении всей жизни приложения (по крайней мере, пока в рендеринге участвует Direct3D). Если приложение работает на скорости 40 fps, то это означает, что Direct3D рендерит, показывает и меняет местами бэкбуферы 40 раз в секунду, что даёт на экране чёткое и плавное изображение в движении.
Существует несколько различных способов использования бэкбуферов для вывода сцены на экран, но мы не будем сейчас подробно рассматривать этот процесс. В данный момент нас интересует лишь способ изменения количества используемых бэк-буферов. Когда ты создаёшь оконное приложение, Direct3D игнорирует любые указанные значения данного параметра, так как в оконном режиме он может использовать всего один бэкбуфер. И напротив, при выборе полноэкранного режима ты можешь использовать столько бэкбуферов, сколько пожелаешь. Наиболее часто указывают число бэк-буферов равное:

  • 2 (т.н. "двойная буферизация", "double buffering");
  • 3 (т.н. "тройная буферизация", "triple buffering").

Чем больше бэкбуферов ты используешь, тем (теоретически) более сглаженными выглядят переходы между кадрами, что даёт более плавную анимацию. В то же время, в большинстве случаев, когда число бэкбуферов больше двух, разница в качестве анимации часто просто неуловима для человеческого глаза.
Указание слишком большого числа бэкбуферов влечёт за собой повышенный расход памяти.
Рассмотрим пример. При запуске приложения в полноэкранном режиме в разрешении 1280х1024 и глубиной цветности 32 бита, то в этом случае 1 бэк-буфер займёт 1280 х 1024 х 32 = 41 943 040 бит памяти. Так как в одном байте 8 бит, получившийся результат соответствует 5 242 880 байт, или 5,2 мегабайта. При использовании 3-х таких бэкбуферов потребуется почти 16 Мб памяти видеокарты (бэкбуферы хранятся именно там). А ведь ещё нам потребуется загрузить в видеопамять текстуры, полигональные сетки (меши), данные вершин и многое другое. Таким образом, как видишь, если система располагает достаточным объёмом видеопамяти, ты можешь без труда использовать 3 и более бэкбуферов. Как вариант, можно снизить разрешение и/или глубину цветности, что уменьшит количество требуемой памяти.

Закрыть
noteОбрати внимание

Если установить слишком большое значение числа бэкбуферов, процесс создания устройства Direct3D может завершиться неудачей. Число бэкбуферов, которое поддерживается приложением, зависит от видеоадаптера и объёма доступной видеопамяти. Для лучшей совместимости желательно всегда использовать не более трёх бэкбуферов. Как вариант, эту опцию можно указать в меню графических настроек, чтобы дать пользователю возможность самостоятельно указывать этот параметр. Это также улучшит совместимость игры со старыми и более слабыми видеокартами, которые часто не поддерживают более двух бэкбуферов.

Рис.3 Swap chain (цепочка перелистывыния) бэкбуферов в деле
Рис.3 Swap chain (цепочка перелистывыния) бэкбуферов в деле

Бэкбуферы выводятся на экран в порядке зацикленной очереди (весь процесс называется swap chain - от англ. "быстро сменяемая цепочка, очередь"). Когда ты командуешь Direct3D вывести очередной кадр на экран, вся цепочка бэкбуферов смещается на одну позицию (просиходит т.н. flip или flipping - от англ. "щелчок, схлопывание"). Таким образом первый бэкбуфер становится последним, а второй бэкбуфер становится первым (см. Рис.3).

Варианты структуры D3DPRESENT_PARAMETERS для оконного и полноэкранного приложений

Часто в окне настроек игры игрок самостоятельно может выбирать оконный или полноэкранный режим, ставя галку напротив соответствующего пункта. Вот примерный код заполнения структуры D3DPRESENT_PARAMETERS для обоих случаев:

// d3dmm - предварительно проинициализированная структура D3DDISPLAYMODE
D3DPRESENT_PARAMETERS d3dpp;

// Очищаем содержимое структуры
ZeroMemory(&d3dpp, sizeof(D3DPRESENT_PARAMETERS));

// Для оконного (windowed) режима.
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = d3dmm.Format;  // Использовать формат текущего видеорежима.

// Для полноэкранного (fullscreen) режима.
d3dpp.Windowed = FALSE;
d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;
d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
d3dpp.FullScreen_PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;
d3dpp.BackBufferFormat = d3dmm.Format;  // Использовать формат цветности выбранного видеорежима.

Создание интерфейса устройства (Device Interface) и инициализация экрана (Initializing the Display)

И вот теперь, в завершающем третьем шаге мы можем создать интерфейс устройства Direct3D (Direct3D device inteface), являющийся "раброчей лошадкой" всей 3D-системы. Предварительно заполнив структуры D3DDISPLAYMODE и D3DPRESENT_PARAMETERS, вызываем функцию IDirect3D8::CreateDevice, создающую и инициализирующую интерфейс устройства Direct3D. Вот её прототип:

HRESULT IDirect3D8::CreateDevice(
 UINT Adapter,  // D3DADAPTER_DEFAULT
 D3DDEVTYPE DeviceType,  // D3DDEVTYPE_HAL
 HWND hFocusWindow,  // Дескриптор окна, в которое всё будет рендериться.
 DWORD BehaviorFlags, // D3DCREATE_SOFTWARE_VERTEXPROCESSING
 D3DPRESENT_PARAMETERS *pPresentationParameters,  // d3dpp
 IDirect3DDevice8 *ppReturnedDeviceInterface);  // объект устройства

Как видим, в многочисленных параметрах данной функции мы передаём указатель на предварительно заполненную структуру D3DPRESENT_PARAMETERS. Также указываем дескриптор окна, куда всё будет рендериться. Остальные параметры вполне очевидны и изменяются редко. В последнем параметре создаём указатель на только что созданный объект устройства Direct3D (Direct3D device object).
Вот пример вызова функции IDirect3D8::CreateDevice:

// g_pD3D - предварительно проинициализированный объект Direct3D.
// hWnd - дескриптор окна, куда всё бкдет рендериться.
// d3dpp - предварительно заполненная структура презентации (D3DPRESENT_PARAMETERS).
IDirect3DDevice8 *g_pD3DDevice;

if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING,
 &d3dpp, &g_pD3DDevice)))
{
 // Ошибка.
}

Утрата контроля над объектом устройства (Losing the Device). Функция Reset.

Как правило, программный объект устройства Direct3D работает как надо: графика рендерится, идёт обычная работа с ресурсами памяти. Но иногда происходит т.н. утрата объекта устройства (losing the device).
Утраченный объект устройства по той или иной причине лишился контроля над графическими ресурсами. Такое может произойти из-за того, что другое приложение "захватило" (gained) контроль над графическим адаптером и сдампило (damped) всю память, содержащую графические данные твоего приложения. Иногда это происходит из-за уход Windows в спящий режим (sleep mode). Во всех случаях необходимо вернуть контроль над графическим адаптером.
Но как узнать, что контроль утрачен? Путём проверки (examining) возвращаемых значений вызываемых функций. Чуть ниже в главе "Презентация сцены" (Presenting the scene) мы рассмотрим вывод отрендеренного изображения на экран. При вызове описанной там функции, в случае, когда объект устройства возвращает значение D3DERR_DEVICELOST, устройство утрачено.
Восстановление контроля осуществляется путём вызова функции IDirect3D8::Reset. Вот её прототип:

Прототип функции Reset
HRESULT IDirect3DDevice8::Reset(D3DPRESENT_PARAMETERS *pPresentationParameters);

Здесь в единственном параметре указывается структура презентации (D3DPRESENT_PARAMETERS), созданная ранее. В нашем случае пример использования функции Reset выглядит так:

// g_pD3D - предварительно проинициализированный объект Direct3D
// d3dpp - предварительно заполненная структура презентации (D3DPRESENT_PARAMETERS).
g_pD3DDevice->Reset(&d3dpp);

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

Пример приложения, опрашивающего устройство Direct3D на наличие поддерживаемых видеорежимов.

Создадим простой Проект, опрашивающего устройство Direct3D на наличие поддерживаемых видеорежимов. Само собой, опрашивать его будет DirectX, поэтому понадобится DirectX SDK.
Программа отображает список устрйоств/видеорежимов через стандартные компоненты интерфейса Windows, которые кодятся как двоичные (.rc) ресурсы типа Диалоговое окно. Подробнее о двоичных ресурсах читай в статье Работа с двоичными ресурсами (.rc) в MS Visual C plus plus 2010 Express.

Перед началом проверь, что у тебя установлены следующие программные компоненты:

  • MS Visual C++ 2010 Express;
  • DirectX SDK 8.1;
  • Windows SDK 7.0 или новее;
  • ResEdit(external link).

Все эти штуки:

  • + инструкции по их установке ты найдёшь в разделе "Софт" нашего сайта;
  • Бесплатны;
  • Без труда гуглятся.

Создаём Проект приложения Enum01

  • Создай пустой Проект с именем Enum01. Проект автоматически разместится внутри Решения с таким же именем.

Весь процесс подробно расписан в статье Настройка MS Visual C plus plus 2010 и DirectX SDK.

Добавляем в Проект WinMain.cpp

Для чистоты эксперимента мы создали пустой Проект, т.е. без каких-либо файлов в нём. Создадим единственный файл с исходным кодом WinMain.cpp.

  • В "Обозревателе решений" главного окна MSVC++2010 щёлкни правой кнопкой мыши по папке (в терминологии Майкрософт это не папки, а фильтры!) "Файлы исходного кода" Проекта Enum01.
  • Во всплывающем меню Добавить->Создать элемент...
Добавляем исходный файл
Добавляем исходный файл
  • В появившемся окне выбери "Файл С++ (.cpp)" и в поле "Имя" введи WinMain.cpp.
  • Жмём "Добавить".

Image
Добавленный файл сразу откроется в правой части MSVC++2010.

  • В только что созданном и открытом файле WinMain.cpp набираем следующий код:
WinMain.cpp
/**************************************************
WinMain.cpp
Chapter 6 Enum Demo

Programming Role-Playing Games with DirectX
by Jim Adams (01 Jan 2002)

Required libraries:
  D3D8.LIB
**************************************************/

#include <windows.h>
#include <stdio.h>

#include <d3d8.h>
#include "resource.h"

// Application variables ////////////////////////////////////////////
HWND g_hWnd;                    // Window handle
char g_szClass[] = "EnumDemo";  // Class name

IDirect3D8       *g_pD3D;        // Direct3D component
IDirect3DDevice8 *g_pD3DDevice;  // Direct3D Device component

// Application prototypes ///////////////////////////////////////////
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow);
long FAR PASCAL WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

BOOL InitD3D();
void ReleaseD3D();
void EnumAdapters();
void EnumModes(long AdapterNum);

// Application //////////////////////////////////////////////////////
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int nCmdShow)
{
  WNDCLASS wc;
  MSG      Msg;

  // Register window class
  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = WindowProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = DLGWINDOWEXTRA;
  wc.hInstance     = hInst;
  wc.hIcon         = LoadIcon(hInst, IDI_APPLICATION);
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  wc.lpszMenuName  = NULL;
  wc.lpszClassName = g_szClass;
  RegisterClass(&wc);

  // Create the dialog box window and show it
  g_hWnd = CreateDialog(hInst, MAKEINTRESOURCE(IDD_ENUM), 0, NULL);

  // Initialize Direct3D and enumerate adapters
  if(InitD3D() == TRUE)
    EnumAdapters();
  else {
    MessageBox(NULL, "Error initializing Direct3D.",          \
               "ERROR", MB_OK | MB_ICONEXCLAMATION);
    return FALSE;
  }

  UpdateWindow(g_hWnd);
  ShowWindow(g_hWnd, nCmdShow);

  // Message loop
  while(GetMessage(&Msg, NULL, 0, 0)) {
    TranslateMessage(&Msg);
    DispatchMessage(&Msg);
  }

  // Clean up
  UnregisterClass(g_szClass, hInst);

  return 0;
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  int Num;

  switch(uMsg) {
    case WM_COMMAND:
      // If user clicked on an adapter, enumerate modes
      if(LOWORD(wParam)==IDC_ADAPTERS && HIWORD(wParam)==LBN_SELCHANGE) {

        // Get selection number
        Num = SendMessage(GetDlgItem(hWnd, IDC_ADAPTERS), LB_GETCURSEL, 0, 0);

        // Enumerate modes
        EnumModes(Num);
      }
      break;

    case WM_DESTROY:
      ReleaseD3D();
      PostQuitMessage(0);
      break;

    default: return DefWindowProc(hWnd, uMsg, wParam, lParam);
  }

  return 0;
}

BOOL InitD3D()
{
  // Create Direct3D component
  if((g_pD3D = Direct3DCreate8(D3D_SDK_VERSION)) == NULL)
    return FALSE;

  return TRUE;
}

void ReleaseD3D()
{
  // Release Direct3D component
  if(g_pD3D != NULL)
    g_pD3D->Release();
  g_pD3D = NULL;
}

void EnumAdapters()
{
  D3DADAPTER_IDENTIFIER8 d3dai;
  long Num, i;
  
  // Clear the list box
  SendMessage(GetDlgItem(g_hWnd, IDC_ADAPTERS), LB_RESETCONTENT, 0, 0);

  // Get the number of adapters
  Num = g_pD3D->GetAdapterCount();

  // Enumerator adapters and add them to list box
  for(i=0;i<Num;i++) {
    // Get the adapter description
    g_pD3D->GetAdapterIdentifier(i, D3DENUM_NO_WHQL_LEVEL, &d3dai);

    // Add adapter description to list box
    SendMessage(GetDlgItem(g_hWnd, IDC_ADAPTERS), LB_INSERTSTRING, i, (LPARAM)d3dai.Description);
  }
}

void EnumModes(long AdapterNum)
{
  D3DDISPLAYMODE d3ddm;
  char Text[256];
  long Num, i;

  // Clear the list box
  SendMessage(GetDlgItem(g_hWnd, IDC_MODES), LB_RESETCONTENT, 0, 0);

  // Get the number of adapters
  Num = g_pD3D->GetAdapterModeCount(AdapterNum);

  // Enumerator modes and add them to display
  for(i=0;i<Num;i++) {
    // Enumerate the mode info
    g_pD3D->EnumAdapterModes(AdapterNum, i, &d3ddm);

    // Build a text string of mode format
    sprintf(Text, "%lu x %lu x ", d3ddm.Width, d3ddm.Height);
    switch(d3ddm.Format) {

      // Add 8-bit identifier
      case D3DFMT_A8:
      case D3DFMT_R3G3B2:
      case D3DFMT_P8:
        strcat(Text, "8");
        break;

      // Add 16-bit identifier
      case D3DFMT_R5G6B5:
      case D3DFMT_A1R5G5B5:
      case D3DFMT_X1R5G5B5:
      case D3DFMT_A4R4G4B4:
      case D3DFMT_A8R3G3B2:
      case D3DFMT_X4R4G4B4:
      case D3DFMT_A8P8:
        strcat(Text, "16");
        break;

      // Add 24-bit identifier
      case D3DFMT_R8G8B8:
        strcat(Text, "24");
        break;

      // Add 32-bit identifier
      case D3DFMT_A8R8G8B8:
      case D3DFMT_X8R8G8B8:
        strcat(Text, "32");
        break;
    }

    // Add mode description to list box
    SendMessage(GetDlgItem(g_hWnd, IDC_MODES), LB_INSERTSTRING, i, (LPARAM)Text);
  }
}
  • Сохрани Решение (Файл -> Сохранить все).

Данный исходный код целиком взят из примера к книге Programming Role-Playing Games with DirectX by Jim Adams (01 Jan 2002). С момента выхода MS Visual C++ 6.0, на котором прогал Jim Adams, прошло немало времени. С MSVC++2010 Express их разделяют аж 12 лет. Кроме того, в начале листинга стоит директива

Фрагмент WinMain.cpp
...
#include <d3d8.h>
...

, требующая указания путей к файлам вложений (include) и статичным библиотекам (lib) DirectX SDK.
Из-за этого вышеприведённый код (написанный в начале 2002 г.) на данном этапе в MSVC++2010 Express компилироваться не будет, выдавая многочисленные ошибки.
Ниже мы это исправим. Но сперва создадим и добавим в текущий Проект .rc-скрипт (скрипт ресурсов) с описанием двоичных ресурсов. В одном скрипте ресурсов может содержаться описание нескольких ресурсов разных видов. В нашем случае это ресурс типа диалоговое окно (Dialog).

Создаём двоичный ресурс типа Диалоговое окно в программе ResEdit

Напомним, что подробно работа с редактором двоичных ресурсов описана в статье Работа с двоичными ресурсами (.rc) в MS Visual C plus plus 2010 Express. В бесплатной MSVC++2010 Express редактор ресурсов вырезан напрочь. Но можно добавлять готовые двоичные ресурсы и даже их редактировать (клик правой кнопкой мыши по .rc-файлу -> Перейти к коду). Для их создания применим бесплатную программу ResEdit.
Физически двоичные ресурсы содержатся (часто в одном) т.н. скрипте ресурсов (.rc-файл). Для их добавления в текущий Проект также понадобится создать отдельный заголовочный файл Resource.h (название произвольное) + указать в WinMain.cpp директиву на его включение. В нашем случае это уже сделано:

Фрагмент WinMain.cpp
...
#include <windows.h>
#include <stdio.h>

#include <d3d8.h>
#include "resource.h"
...

Таким образом, создадим:

  • скрипт ресурсов Resource.rc;
  • заголовочный файл ресурсов Resource.h.

И добавим оба файла в Проект Enum.h .

Создаём скрипт ресурсов. Редактор скриптов ресурсов (RC) ResEdit.

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

Если у тебя 64-разрядная версия ОС Windows, то сильно желательно выбрать 7z-архив с пометкой "x64". Распаковщик 7z-архивов нетрудно найти в Интернете (WinRar также поддерживает распаковку 7z-архивов).

  • Распакуй содержимое архива в любую папку на жёстком диске. В нашем случае это будет C:\ResEdit .
  • Перейди в каталог с программой и запусти ResEdit.exe .

Программа на английском языке. После запуска автоматически запускается мастер (Wizzard) с вопросом, что мы собираемся сделать (What do you want to do?)

  • Выбираем первый пункт Developer mode (режим разработчика).
  • На следующей странице мастера отмечаем пункт Resource script (*.rc) (скрипт ресурсов), в строке Location выбираем папку с Проектом Enum01 (по умолчанию C:\Users\User1\Documents\Visual Studio 2010\Projects\Enum01\Enum01\).
  • В поле Name вводим имя файла скрипта. В нашем случае Enum01.
  • Убери галку с пункта "Создать отдельный подкаталог проекта" (Create project folder).

Пусть скрипт ресурсов будут расположены в одной папке с текущим Проектом. Для наглядности.

  • Жмём Finish
  • В появившемся диалоговом окне о том, что программа не может найти windows.h (windows.h could not be found in any include path. Continue anyway?) жмём "Да" (=всё равно продолжить).
  • В появившемся диалоговом окне о том, что программа не может найти commctrl.h (commctrl.h could not be found in any include path. Continue anyway?) жмём "Да" (=всё равно продолжить).
  • В появившемся диалоговом окне о том, что программа не может найти richedit.h (richedit.h could not be found in any include path. Continue anyway?) жмём "Да" (=всё равно продолжить).

Сейчас нам не нужны эти файлы.

  • На запрос программы сконфигурировать пути к include-файлам жмём "No" (отказ).

Откроется с пустым проектом скрипта.

  • Открой папку с Проектом Enum01 (по умолчанию C:\Users\User1\Documents\Visual Studio 2010\Projects\Enum01\Enum01\).

При создании нового проекта скрипа программа ResEdit автоматически создала в выбранном каталоге файлы:

  • Enum01.rc
  • resource.h

...И даже разместила в них какой-то текст. По старой традиции в resource.h прописываются т.н. IDI (идентификационные номера) ресурсов.

  • Открой оба файла в любом текстовом редакторе. Ознакомься с их содержимым.

Но вернёмся к программе ResEdit. В левой части её главного окна расположена колонка с т.н. "отстыковываемыми" (docked) окнами Resources (Ресурсы) и Properties (Свойства).
Как ни странно, ResEdit не открыла только что созданный файл Enum01.rc для редактирования, из-за чего мы не можем добавлять новые ресурсы. Поэтому...

  • В Главном меню ResEdit жми: File -> Open project... и выбери только что созданный скрипт ресурсов Enum01.rc.

В нашем случае путь до него такой: C:\Users\User1\Documents\Visual Studio 2010\Projects\Enum01\Enum01\Enum01.rc. Теперь можно добавлять новые ресурсы.

  • В окне Resources щёлкни правой кнопкой мыши.
  • Во всплывающем меню выбери Add Resource... (Добавить ресурс) -> Dialog.

В окне ResEdit появится форма с кнопакми "OK" и "Отмена" на ней.

Готовим Проект Enum01 к компиляции

Для успешной компиляции изменим настройки (=свойства) текущего Проекта Enum01, созданного в MSVC++2010. При этом сам код из книги 2002 года останется нетронутым.

Закрыть
noteОбрати внимание

Напомним, что такую настройку необходимо повторно проделывать при создании каждого нового Проекта. Ниже представлен алгоритм действий по настройке Проекта Enum01, созданного в MSVC++2010 Express с применением DirectX SDK 8.1 . При создании приложений под платформы, отличные от Win32, либо применении более новых версий DirectX SDK, процесс конфигурирования Проекта может отличаться от приведённого ниже.

Указываем пути к DirectX SDK 8.1

Если попытаться скомпилировать Проект Enum01 в таком виде, то ничего не выйдет.
В единственном файле исходного кода WinMain.cpp можно увидеть инклуды различных заголовочных файлов DirectX (весии 8).

Фрагмент WinMain.cpp
...
#include <windows.h>
#include <stdio.h>

#include <d3d8.h>
#include "resource.h"
...

На данном этапе MSVC++2010 ничего не знает об их местоположении. В статье Настройка MS Visual C plus plus 2010 и DirectX SDK мы указывали пути к DirectX SDK (версии 9 и выше). Для DirectX SDK 8 это делается аналогично. Начнём.

  • Убедись, что MSVC++2010 запущена и в ней открыт и активен (отмечен кликом мыши в Обозревателе решений и его имя выделено жирным шрифтом) наш текущий Проект Enum01.
  • Убедись, что DirectX SDK 8.1 установлен на компьютере и ты уверенно можешь назвать полный путь к его каталогу.

В Обозревателе решений видим: "Решение "Enum01"", а строкой ниже жирным шрифтом название Проекта (тоже Enum01).

  • Жмём правой кнопкой мыши по названию Проекта Enum01. Во всплывающем меню выбираем пункт "Свойства". Или в Главном меню выбираем Проект->Свойства. Или нажимаем Alt+F7.

Image

  • В появившемся меню свойств проекта выбираем Свойства конфигурации -> Каталоги VC++. В правой части этой страницы расположены пути ко всевозможным каталогам. Здесь нас интересуют только 2 строки: Каталоги включения и Каталоги библиотек.


Указываем каталог включений (include) DirectX SDK 8.1

  • В меню свойств Проекта щёлкаем левой кнопкой мыши по пункту Каталоги включения. В правой части этой строки видим кнопку с чёрным треугольником, указывающим на наличие выпадающего меню. Нажимаем на неё -> выбираем "Изменить..."

Image

  • В появившемся меню "Каталоги включения" жмём кнопку "Создать строку" (с жёлтой папкой) и указываем полный путь к заголовочным файлам DirectX SDK 8.1 (include). В нашем случае это C:\DXSDK8\include. Можно просто выбрать каталог из дерева каталогов, нажав кнопку с троеточием, расположенную справа от строки ввода.

Image

  • Жмём "ОК".


Указываем каталог библиотек (lib) DirectX SDK 8.1

  • В меню свойств Проекта щёлкаем левой кнопкой мыши по пункту Каталоги библиотек. В правой части этой строки видим кнопку с чёрным треугольником, указывающим на наличие выпадающего меню. Нажимаем на неё -> выбираем "Изменить..."
  • В появившемся меню "Каталоги библиотек" жмём кнопку "Создать строку" (с жёлтой папкой) и указываем полный путь к 32-разрядным версиям файлов библиотек DirectX SDK 8.1 (lib). В нашем случае это c:\DXSDK8\lib\. Можно просто выбрать каталог из дерева каталогов, нажав кнопку с троеточием, расположенную справа от строки ввода.
  • Жмём "ОК".

Image

  • На Странице свойств тоже жмём "ОК".
  • Сохрани Решение (File -> Save All).

Готово.

Указываем пути к Windows SDK

Помимо указания путей к заголовкам (include) и библиотекам (lib) DirectX SDK, для любого DirectX-Проекта также необходимо указать пути к заголовкам (include) и библиотекам (lib) Windows SDK. Самое смешное, что в MS Visual C++ 2010 эти пути указываются по умолчанию для каждого создаваемого Проекта. В этом нетрудно убедиться, если ещё раз открыть Проект -> Свойства -> Свойства конфигурации - >Каталоги VC++ -> Каталоги включения -> Изменить. В окне "Каталоги включения" в нижней (недоступной для редактирования) части видим список "Унаследованные значения", где в третьей строке стоит значение:

$(WindowsSdkDir)include

В результате видим, что добавленные пути к DirectX SDK (в обоих окнах: include и lib) расположены вверху списка, а пути к Windows SDK - в недоступной области, на несколько строк ниже.
Но заголовочным файлам DirectX SDK 8.1 "жизненно важно", чтобы они включались после включений заголовков Windows SDK.

Закрыть
noteВажно!

Каталоги, пути к которым указаны в окнах "Каталоги включения" и "Каталоги библиотек" при компиляции считываются один за другим по списку сверху вниз. Поэтому для корректного указания путей надо разместить пути к Windows SDK выше, а к DirectX SDK 8.1 - ниже по списку (чтобы они считывались последними).

В данной ситуации мы не можем поднять пути к Windows SDK, прописанные по умолчанию при создании Проекта, т.к. они расположены в специальной нередактируемой области (ограничение бесплатной версии MSVC++2010 Express).
Но можем схитрить и добавить ещё раз пути к тем же самым каталогам Windows SDK, подняв эти строки выше строк DirectX SDK.
Выше мы указывали пути к DirectX SDK 8.1. Для путей к Windows SDK это делается аналогично. Начнём.

  • Убедись, что MSVC++2010 запущена и в ней открыт и активен (отмечен кликом мыши в Обозревателе решений и его имя выделено жирным шрифтом) наш текущий Проект Enum01.
  • Убедись, что Windows SDK (в нашем случае версия 7) установлен на компьютере и ты уверенно можешь назвать полный путь к его каталогу.

В Обозревателе решений видим: "Решение "Enum01"", а строкой ниже жирным шрифтом название Проекта (тоже Enum01).

  • Жмём правой кнопкой мыши по названию Проекта Enum01. Во всплывающем меню выбираем пункт "Свойства". Или в Главном меню выбираем Проект->Свойства. Или нажимаем Alt+F7.

Image

  • В появившемся меню свойств проекта выбираем Свойства конфигурации -> Каталоги VC++. В правой части этой страницы расположены пути ко всевозможным каталогам. Здесь нас интересуют только 2 строки: Каталоги включения и Каталоги библиотек.


Указываем каталог включений (include) Windows SDK

  • В меню свойств Проекта щёлкаем левой кнопкой мыши по пункту Каталоги включения. В правой части этой строки видим кнопку с чёрным треугольником, указывающим на наличие выпадающего меню. Нажимаем на неё -> выбираем "Изменить..."

Image

  • В появившемся меню "Каталоги включения" жмём кнопку "Создать строку" (с жёлтой папкой) и указываем полный путь к заголовочным (include) файлам Windows SDK. В нашем случае (Win7 x64) это C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include. Можно просто выбрать каталог из дерева каталогов, нажав кнопку с троеточием, расположенную справа от строки ввода.

Image

  • Меняй порядок считывания каталогов включений с помощью кнопок с чёрными стрелками в верхней части окна "Каталоги вложений".

Каталог включений DirectX SDK 8.1 должен всегда стоять в самом конце списка, как на этом скриншоте:
Image

  • Жмём "ОК".


Указываем каталог библиотек (lib) Windows SDK

  • В меню свойств Проекта щёлкаем левой кнопкой мыши по пункту Каталоги библиотек. В правой части этой строки видим кнопку с чёрным треугольником, указывающим на наличие выпадающего меню. Нажимаем на неё -> выбираем "Изменить..."
  • В появившемся меню "Каталоги библиотек" жмём кнопку "Создать строку" (с жёлтой папкой) и указываем полный путь к папке с файлами библиотек (lib) Windows SDK. В нашем случае (Win7 x64) это C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Lib. Можно просто выбрать каталог из дерева каталогов, нажав кнопку с троеточием, расположенную справа от строки ввода.

Image

  • Меняй порядок считывания каталогов вложений с помощью кнопок с чёрными стрелками в верхней части окна "Каталоги вложений".

Каталог библиотек DirectX SDK 8.1 должен всегда стоять в самом конце списка, как на этом скриншоте:
Image

  • Жмём "ОК".
  • На Странице свойств тоже жмём "ОК".

  • Сохрани Решение (File -> Save All).

Готово.

Выбираем многобайтовую кодировку

Закрыть
noteПримечание

В MS Visual C++ 2010 в настройках по умолчанию стоит набор (кодировка) символов UNICODE. В MS Visual C++ 6.0 - напротив, по умолчанию стоит кодировка ANSI (многобайтовая). Данная настройка сильно влияет на типы используемых переменных, что приводит к заметным различиям в исходном коде.
Несмотря на то, что во всех случаях рекомендуется использовать кодировку UNICODE, поддерживаемую во всех современных ОС семейства MS Windows (начиная с Win 2000/XP), большинство книг по программированию игр на классическом C++ придерживаются именно многобайтовой кодировки. Чтобы сильно не переделывать исходные коды под UNICODE, все наши игровые Проекты мы настроим под многобайтовую кодировку. Для этого...

  • Убедись, что MSVC++2010 запущена и в ней открыт и активен (отмечен кликом мыши в Обозревателе решений и его имя выделено жирным шрифтом) наш текущий Проект Enum01.
  • В Обозревателе решений щёлкаем правой кнопкой мыши по названию Проекта Enum01.
  • Во всплывающем контекстном меню выбираем "Свойства".
  • В появившемся окне установки свойств Проекта жмём Свойства конфигурации->Общие, в правой части в строке "Набор символов" выставляем значение "Использовать многобайтовую кодировку".

Image

  • Жмём ОК.
  • Сохрани Решение (Файл->Сохранить все)

Отключаем инкрементную компоновку (incremental linking)

Инкрементная компоновка призвана сократить время компилирования. Но на деле её присутствие часто вызывает ошибки вроде этой:

Error LNK1123: сбой при преобразовании в COFF: файл недопустим или поврежден

Отключается в свойствах открытого Проекта. Для MS Visual C++ 2010 порядок следующий:

  • Убедись, что MSVC++2010 запущена и в ней открыт и активен (отмечен кликом мыши в Обозревателе решений и его имя выделено жирным шрифтом) наш текущий Проект Enum01.
  • В Главном меню MS Visual C++ 2010 выбираем Проект -> Свойства (Project -> Properties).
  • В появившемся окне установки свойств Проекта жмём Свойства конфигурации -> Компоновщик -> Общие (Configuration Properties -> Linker -> General), в правой части в строке "Включить инкрементную компоновку" ставим значение Нет (/INCREMENTAL:NO).
  • Жмём ОК.

Прописываем библиотеку d3d8.lib в окне "Дополнительные зависимости" (Additional dependencies) компоновщика (Linker)

Данный этап проходил даже автор кода Jim Adams в 2002 году, прогая на MSVC++6.0. В начальных комментариях листинга WinMain.cpp он намекнул, что библиотеку D3D8.LIB необходимо явно указывать в списке дополнительных зависимостей линкера (=компоновщика):

Фрагмент WinMain.cpp
/**************************************************
WinMain.cpp
Chapter 6 Enum Demo

Programming Role-Playing Games with DirectX
by Jim Adams (01 Jan 2002)

Required libraries:
  D3D8.LIB
...

Библиотека D3D8.LIB и расположена в папке с установленным DirectX SDK 8 (в нашем случае по пути C:\DXSDK8\lib\), пути к которой мы прописали выше.
Т.к. мы создаём исполняемое приложение (исполняемый .exe-файл), а не библиотеку, то после компиляции полученный объектный модуль сразу линкуется путём вызова компоновщика (=linker). Так вот, этот самый компоновщик по ранее прописанным каталогам данные библиотеки не ищет. Поэтому их необходимо указывать отдельно в окне настроек Проекта, в разделе "Компоновщик".
ОК, начинаем.

  • Убедись, что MSVC++2010 запущена и в ней открыт и активен (отмечен кликом мыши в Обозревателе решений и его имя выделено жирным шрифтом) наш текущий Проект Enum01.
  • В Главном меню MS Visual C++ 2010 выбираем Проект -> Свойства (Project -> Properties).
  • В появившемся окне установки свойств Проекта последовательно щёлкаем по раскрывающимся ветвям иерархического дерева: Свойства конфигурации -> Компоновщик -> Ввод (Configuration Properties -> Linker -> Input).
  • В правой части, напротив строки "Дополнительные зависимости" жмём кнопку с чёрным треугольником.
  • В всплывающем списке жмём "Изменить".
  • В появившемся окне "Дополнительные зависимости" в верхнем поле ввода прописываем имя библиотеки:

d3d8.lib
Image

  • Жмём ОК, ОК.
  • Сохрани Решение (Файл->Сохранить все)

Отключаем использование компоновщиком библиотеки libci.dll

Да, даже на данном этапе при компиляции Проект Billboard01 выдаст ошибку. Библиотека libci.dll использовалась в VisualStudio когда-то очень давно. И в современных версях IDE её нет. Тем не менее компоновщик почти всегда вызывает её при компиляции, ругаясь на её отсутствие. Самый простой способ это исправить - запретить использовать libci.dll по умолчанию.
ОК, начнём.

  • Убедись, что MSVC++2010 запущена и в ней открыт и активен (отмечен кликом мыши в Обозревателе решений и его имя выделено жирным шрифтом) наш текущий Проект Enum01.
  • В Главном меню MS Visual C++ 2010 выбираем Проект -> Свойства (Project -> Properties).
  • В появившемся окне установки свойств Проекта последовательно щёлкаем по раскрывающимся ветвям иерархического дерева: Свойства конфигурации -> Компоновщик -> Командная строка (Configuration Properties -> Linker -> Command Promt).

В правой части, внизу, видим поле ввода "Дополнительные параметры".

  • Пишем в него строку: /NODEFAULTLIB:libci
  • Жмём ОК.
  • Сохрани Решение (Файл->Сохранить все).

Компилируем Проект Enum01

Наконец, наш тестовый Проект готов к компиляции.

  • Жми кнопку с зелёным треугольником на панели инструментов главного окна MSVC++2010 или F5 нак лавиатуре.

После компилирования приложение Enum01 автоматически запустится и покажет диалогове окно...

...

Работа над статьёй приостановлена. Причина: код WinMain.cpp из примеров к книге Jim Adams "Programming Role Playing Games with DirectX 8.0" компилируется и стартует. Но по клику по устройству Direct3D (из списка слева) видеорежимы в правом списке не отображаются. Кроме того окно программы не закрывается по нажатию на крестик. В коде применяются двоичный ресурс типа Dialog. Опытным путём было выяснено:

  • Проект успешно компилируется под полновесной MSVC++6.0.

При этом приложение отлично работает.

  • Jim Adams сделал форму с применением MFC, которая отсутствует в MSVC++2010.

Об этом свидетельствует следуюущее включение заголовка в скрипте ресурсов:

#include "afxres.h"

Источники:


1. Adams J. Programming Role Playing Games with DirectX 8.0. - Premier Press. 2002

Contributors to this page: slymentat .
Последнее изменение страницы Четверг 18 / Февраль, 2021 16:58:10 MSK автор slymentat.

Помочь проекту

yoomoney.ru (бывший Яндекс-деньги): 410011791055108