Самое главное, что нам потребуется для работы с DirectX это заголовочные файлы и библиотеки. Можно взять их из Microsoft DirectX SDK 8.1. Все, что нам оттуда нужно, это только папка LIB. У меня не было возможности взять SDK с компакта, а качать более 100 метров ради пары десятков файлов полный идиотизм. Хоть мелгомягкие и запрещают выкладывать какие либо части их SDK, находятся еще добрые люди на свете и набрав в поисковике искомое мы всегда получим парочку адресов. Все ленивые могут посмотреть по адресу упомянутому мною в предыдущем уроке. До последнего момента там было то что нам нужно.
Так как SDK рассчитан на работу с языком C++, то заголовочные файлы необходимо адаптировать. Не переживайте. Для данных уроков я уже адаптировал все необходимые файлы и надеюсь, работа будет продолжена. Адаптированные INC файлы включены в исходник уроков, забирайте и пользуйтесь. Формат библиотек является родным и для С++ и для MASM, поэтому библиотеки подходят без проблем. Ну вот и все приготовления и прежде, чем мы перейдем собственно к нашему уроку, хотелось бы еще упомянуть, что все относящееся к DirectX я буду сопровождать подробной справкой. Справка является моим корявым переводом справочника из SDK, поэтому не ругайте меня за возможные ошибки.
Все что у нас сейчас имеется это приложение, при запуске выводящее на экран окошко размером 320х240, и нам надо заставить работать в этом окне Direct3D. Как это сделать? Нет ничего проще!
Первое что мы добавим это подключение необходимых файлов:
include d3d8.inc
include d3d8caps.inc
include d3d8types.inc
includelib d3d8.lib
Теперь обьявим необходимые переменные и структуры:
Clearcolor DWORD 0 ; Переменная для очистки экрана цветом
Zvalue REAL4 1.0 ; Значение для Z буфера ( см.ниже )
pd3d DWORD ? ; Указатель на Direct3D
pd3dDevice DWORD ? ; Указатель на Direct3DDevice
d3ddm D3DDISPLAYMODE <> ; Структура для параметров экрана
d3dpp D3DPRESENT_PARAMETERS <> ; Структура для параметров нашего Direct3Ddevice
Справка
D3DDISPLAYMODE STRUC
Width1 UINT ? ; Ширина экрана в пикселях
Height UINT ? ; Высота экрана в пикселях
RefreshRate UINT ? ; Частота обновления. 0 означает частота по умолчанию
Format DWORD ? ; Формат использ. поверхности ( см. D3d8Types.inc )
D3DDISPLAYMODE ENDS
D3DPRESENT_PARAMETERS STRUC
BackBufferWidth UINT ? ; Ширина BackBuffer. 0 если работаем в окне.
BackBufferHeight UINT ? ; Высота BackBuffer. 0 если работаем в окне.
BackBufferFormat DWORD ? ; Формат использ. поверхности ( см. D3d8Types.inc )
BackBufferCount UINT ? ; 0,1,2 или 3 - число буферов. 0 трактуется как 1.
; Если указанное число буферов не может быть
; создано то помещается число буферов которые
; были реально созданы
MultiSampleType DWORD ? ; 2-16 уровни мультисэмплинга картинки.
; 1 не используется, а 0 равносилен отсутствию
; мультисэмплинга ( D3DMULTISAMPLE_NONE )
; Мультисэмплинг возможен только если установлен
; D3DSWAPEFFECT_DISCARD. В противном случае
; здесь должен быть 0.
SwapEffect DWORD ? ; Эффект обмена поверхностей.
; Если мы работаем в окне и используем
; D3DSWAPEFFECT_FLIP, тогда будет создан один
; дополнительный BackBuffer. Пока один буфер
; показывается на экране можно рисовать в другой.
; Потом они меняются местами и т.д
; D3DSWAPEFFECT_COPY и
; D3DSWAPEFFECT_COPY_VSYNC требуют чтобы
; BackBufferCount был установлен в 1. ( содержимое
; буфера копируется на экран без ожидания
; обратного хода луча и с ожиданием соответственно)
; D3DSWAPEFFECT_DISCARD сначала буфер
; заполняется а потом показывается на экран
hDeviceWindow HWND ? ; ID нашего окошка
Windowed BOOL ? ; Режим работы. 0 - полноэкранный, 1 - в окошке
EnableAutoDepthStencil BOOL ? ; Если значение установить в 1, то Direct3D будет управлять
; для приложения буфером глубины. Будет создан Z-Stencil
; буфер. При этом в AutoDepthStencilFormat должен быть
; установлен правильный формат поверхности.
; Если 0 - ничего не будет создано
AutoDepthStencilFormat DWORD ? ; Формат использ. поверхности ( см. D3d8Types.inc )
; Игнорир. если EnableAutoDepthStencil не равен 1
Flags DWORD ? ; 0 или D3DPRESENTFLAG_LOCKABLE_BACKBUFFER=1
; Нужен если мы будем блокировать BackBuffer
FullScreen_RefreshRateInHz UINT ? ; Частота обновления экрана в Hz.
; Должно быть 0 если мы работаем в оконном режиме
; Если указать D3DPRESENT_RATE_DEFAULT, то
; берется текущее значение, если в окошке, и по
; умолчанию ( обычно 60 Hz ), если в полноэкранном
FullScreen_PresentationInterval UINT ? ; Интервал показа на экране backbufferа
; Должно быть 0 если мы работаем в оконном режиме
; D3DPRESENT_INTERVAL_IMMEDIATE - рисуем немедленно
; не ждя обратного хода луча
; 1 - рисуем ждя обратный ход луча ( FPS - не будет
; превышать Hz экрана )
; 2 - FPS равен половине Hz
; 3 - FPS равен трети Hz
; 4 - FPS равен четверти Hz
D3DPRESENT_PARAMETERS ENDS
Далее создадим три процедуры Init_Direct3D, Destroy_Direct3D и Render_Scene
итак Init_Direct3D
Создаем обьект Direct3D8:
invoke Direct3DCreate8, D3D_SDK_VERSION
mov pd3d, eax
Справка
Direct3DCreate8 передается в качестве параметра версия SDK.
Метод возвращает указатель на обьект если все прошло успешно.
Если ошибка, то в EAX возвращается код ошибки, какой именно я не знаю :( ( возможно 0 )
Затем мы получаем информацию о текущих параметрах экрана:
d3d8 GetAdapterDisplayMode, pd3d, D3DADAPTER_DEFAULT, ADDR d3ddm
Справка
1. Номер видеоадаптера. D3DADAPTER_DEFAULT - всегда главный адаптер ( под номером 0 ) можно вставить цифру
нужного адаптера если в системе их несколько
2. Указатель на структуру параметров экрана ( см. выше )
Возвращает в случае успеха D3D_OK. Если нет то D3DERR_INVALIDCALL - недействительный вызов.
Заполняем только те поля структуры которые нам необходимы:
mov d3dpp.Windowed, TRUE ; Работаем в окошке
mov d3dpp.SwapEffect, D3DSWAPEFFECT_FLIP ; Будем менять буфера
mov eax, d3ddm.Format ; Берем формат экрана
mov d3dpp.BackBufferFormat, eax ; Сохраняем в структуре
А сейчас делаем самое главное ! Создаем устройство Direct3DDevice8.
Создавать Direct3DDevice в сообщении WM_Create нельзя ! ( проверено опытным путем :) )
То же самое можно найти в документации по Direct3D8.
CreateDevice мы должны передать hwnd полностью созданного окна на экране которое находится в фокусе.
d3d8 CreateDevice, pd3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd , \
D3DCREATE_HARDWARE_VERTEXPROCESSING, ADDR d3dpp, ADDR pd3dDevice
Справка
1. Номер видеоадаптера. D3DADAPTER_DEFAULT - всегда главный адаптер ( под номером 0 ) можно вставить цифру
нужного адаптера если в системе их несколько.
2. Тип устройства рендеринга. D3DDEVTYPE_HAL - аппаратный рендеринг. D3DDEVTYPE_REF - програмный рендеринг.
3. Hwnd - ID нашего окошка.
4. Комбинация флагов. D3DCREATE_FPU_PRESERVE - нам нужна двойная точность вычисления
с плавающей запятой.
D3DCREATE_HARDWARE_VERTEXPROCESSING - аппаратная обработка вершин
D3DCREATE_SOFTWARE_VERTEXPROCESSING - программная обработка вершин
D3DCREATE_MIXED_VERTEXPROCESSING - аппаратная + программная обработка вершин
D3DCREATE_MULTITHREADED - многопоточность приложения ( direct3D создает глобальный
критический раздел это может привести к падению FPS )
D3DCREATE_PUREDEVICE - не поддерживать Get вызовы. Также не обеспечивать эмуляцию
каких- либо сервисов связанных с Vertex processing. Имеется в виду
что если устройство не поддерживает vertex processing тогда
приложение может использовать только post трансформацию вершин.
D3DCREATE_DISABLE_DRIVER_MANAGEMENT - D3D будет управлять ресурсами вместо драйвера.
Флаги SOFTWARE_VERTEXPROCESSING, HARDWARE_VERTEXPROCESSING и MIXED_VERTEXPROCESSING недопустимы
для совместного использования.
5. Указатель на структуру D3DPRESENT_PARAMETERS. ( см. выше )
6. Адрес переменной куда будет помещен указатель на D3DDevice
Возвращает в случае успеха D3D_OK.
Если нет то D3DERR_INVALIDCALL - недействительный вызов, D3DERR_NOTAVAILABLE
- устройством требуемое не поддерживается или D3DERR_OUTOFVIDEOMEMORY -
не хватает видео памяти для данной операции.
Теперь наше устройство создано и настало время написать функцию Render_Scene !
итак Render_Scene
Для простого примера применим очистку backbuffer`а цветом и показа его на экране:
d3dev8 Clear, pd3dDevice, 0 , NULL , D3DCLEAR_TARGET, clearcolor, Zvalue, 0
Справка
1. Число структур прямоугольников в массиве. ( см. Параметр 2 )
2. Указатель на массив структур прямоугольников. Каждый прямоугольник
указывает какое место в поверхности рендеринга очищать.
Если 0 то очищается вся поверхность. При этом в первом параметре тоже должен быть 0.
3. Комбинация флагов.
D3DCLEAR_STENCIL - очищать стенсель буфер стенсель значением. ( см.параметр 6 )
D3DCLEAR_TARGET - очищать поверхность рендеринга цветовым значением. ( см.параметр 4 )
D3DCLEAR_ZBUFFER - очищать Z буфер z значением. ( см.параметр 5 )
4. Цветовое значение. 32bit-ное значение в формате ARGB
5. Z значение. Может быть в диапазоне от 0.0 до 1.0
( для z основного или w основного буфера глубины ) 0.0 - ближняя гараница. 1.0 - дальняя граница.
6. Stencil значение. Может быть в диапазоне от 0 до 2^n-1 где n это глубина бит стенсель буфера.
Возвращает в случае успеха D3D_OK. Если нет то D3DERR_INVALIDCALL,
D3DERR_NOTAVAILABLE или D3DERR_OUTOFVIDEOMEMORY. ( расшифровку см. выше )
А теперь все покажем этой функцией
d3dev8 Present, pd3dDevice, NULL, NULL, NULL, NULL
Справка
1. Указатель на структуру источник типа RECT. Должно быть 0 если
поверхности не были созданы с флагами
D3DSWAPEFFECT_COPY и D3DSWAPEFFECT_COPY_VSYNC.
2. Указатель на структуру назначение типа RECT. Должно быть 0 если
поверхности не были созданы с флагами
D3DSWAPEFFECT_COPY и D3DSWAPEFFECT_COPY_VSYNC.
3. ID окошка куда показывать результат. Если мы указали его ранее в
структуре D3DPRESENT_PARAMETERS, то здесь 0
4. Не используется и должен быть 0.
Откомпилировав и запустив это приложение, вы увидите, что оно работает.
Но это еще не все. После того как наше приложение будет закрыто, нам необходимо удалить все созданные нами интерфейсы и занятые ими ресурсы. Для этого создадим функцию Destroy_Direct3D.
итак Destroy_Direct3D
d3dev8 Release, pd3dDevice ; Метод специально для Direct3DDevice8
d3d8 Release, pd3d ; Метод специально для Direct3D8
На этом позволю себе откланяться. До следующих встреч !
Исходник прилагается.
PS
В следующем уроке мы рассмотрим запуск приложения в полноэкранном режиме, а также связанную с этим проблему потерянного устройства.
Авторство принадлежит Пономареву Михаилу ака keYMax.
Все вопросы и ругательства слать по адресу mybox@aib.ru
|