27 января 2010 в 20:38
Уроки Direct3D - 2.0. Организация проекта
До сих пор все наши проекты состояли из одной единственной формы. Весь код проекта не был распределен по модулям. Это, конечно, неправильный подход, он применялся для более легкого освоения начальных понятий программирования с использованием Direct3D, ведь пока вы не уясните основные принципы такого программирования, не будет понятна и логика деления кода на модули.
<h2>2. Часть 2. Технологии</h2>
<h2>2.1. Организация проекта</h2>
Однако постепенно у нас выделились процедуры, которые мы переносили из проекта в проект практически не меняя. В первую очередь это D3DInit – инициализация Direct3D. Создадим новый модуль, в котором будем собирать самые необходимые процедуры, относящиеся к Direct3D. Объявим в нем глобальные переменные:
Public dx8 As New DirectX8 Public d3d As Direct3D8 Public d3dx As New D3DX8 Public d3dDevice As Direct3DDevice8
Также имеет смысл объявить константу Pi:
Public Const Pi = 3.141593
И сама процедура D3DInit:
Public Sub D3DInit(hWnd As Long) Dim DispMode As D3DDISPLAYMODE Dim d3dpp As D3DPRESENT_PARAMETERS Set d3d = dx8.Direct3DCreate d3d.GetAdapterDisplayMode D3DADAPTER_DEFAULT, DispMode d3dpp.Windowed = True d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD d3dpp.BackBufferFormat = DispMode.Format d3dpp.BackBufferCount = 1 d3dpp.EnableAutoDepthStencil = True d3dpp.AutoDepthStencilFormat = D3DFMT_D16 Set d3dDevice = d3d.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd _ , D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp) End Sub
Для уничтожения объектных переменных, созданных в модуле, послужит процедура D3DTerminate:
Public Sub D3DTerminate() Set d3dx = Nothing Set d3dDevice = Nothing Set d3d = Nothing Set dx8 = Nothing End Sub
Так же сюда может войти неизменная функция vec3:
Public Function vec3(x As Single, y As Single, z As Single) As D3DVECTOR vec3.x = x vec3.y = y vec3.z = z End Function
В форме желательно держать только код обработки событий контролов формы. Один из них – таймер, поместим на форму соответствующий контрол и настроим его на 1000 мс интервал. С помощью таймера мы будем в дальнейшем замерять быстродействие. Еще одно важнейшее событие формы – ее закрытие. Немного изменим код его обработки:
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer) If Running Then Cancel = 1: Running = False End Sub
А вот для синхронизации движения таймер применять мы больше не будем, он применялся для простоты в самых начальных проектах. Дело в том, что таймер обладает невысокой точностью при измерении небольших интервалов времени, теперь для этого мы применим более современную API функцию – QueryPerformanceCounter.
Для функций API можно создать отдельный модуль и поместить туда такой код:
Option Explicit Private Type int64 dw1 As Long dw2 As Long End Type Private Declare Function QueryPerformanceCounter Lib "kernel32" (lpPerformanceCount As int64) As Long Private Declare Function QueryPerformanceFrequency Lib "kernel32" (lpFrequency As int64) As Long Dim QSpeed As Double Public Function QTime() As Double Dim QD As int64, t As Double QueryPerformanceCounter QD If QD.dw1 < 0& Then t = QD.dw1 + 4294967296# Else t = QD.dw1 If QD.dw2 < 0& Then t = t + (QD.dw2 + 4294967296#) * 4294967296# _ Else t = t + QD.dw2 * 4294967296# QTime = t * QSpeed End Function Public Sub QFreqIni() Dim QD As int64 QueryPerformanceFrequency QD If QD.dw1 < 0& Then QSpeed = QD.dw1 + 4294967296# Else QSpeed = QD.dw1 If QD.dw2 < 0& Then QSpeed = QSpeed + (QD.dw2 + 4294967296#) * 4294967296# _ Else QSpeed = QSpeed + QD.dw2 * 4294967296# QSpeed = 1# / QSpeed End Sub
В начале работы программы однократно вызываем QFreqIni, и для получения значения текущего времени в секундах пользуемся функцией QTime.
И создадим еще один, пока последний, модуль – modMain, в свойствах проекта укажем, что стартовым должен быть именно этот модуль, а не форма. В этом модуле будут находиться все наши «эксперименты» до тех пор, пока они не удостоятся переноса в уже существующий или вновь созданный модуль. Если поместить в modMain такой код:
Option Explicit Public Running As Boolean Public FPS As Long Public Sub Main() frmD3D.Show QFreqIni D3DInit frmD3D.hWnd Running = True Do While Running DoEvents Render FPS = FPS + 1 Loop Unload frmD3D ClearAll End Sub Private Sub Render() d3dDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER, &HFFFFFF * Rnd, 1, 0 d3dDevice.Present ByVal 0, ByVal 0, 0, ByVal 0 End Sub Private Sub ClearAll() D3DTerminate End Sub
Мы получим приблизительный аналог нашего первого проекта, где мы закрашивали форму в разные цвета.
Можно в обработчик события Timer формы поместить следующий код, чтобы измерять быстродействие нашей программы:
Private Sub TimerFPS_Timer() Me.Caption = FPS FPS = 0 End Sub
Этот проект находится в папке Pr12.
Теперь, когда наша «перестройка» завершена, продолжим заниматься изучением Direct3D.
комментарии отсутствуют
авторизуйтесь