До сих пор все наши проекты состояли из одной единственной формы. Весь код проекта не был распределен по модулям. Это, конечно, неправильный подход, он применялся для более легкого освоения начальных понятий программирования с использованием Direct3D, ведь пока вы не уясните основные принципы такого программирования, не будет понятна и логика деления кода на модули.

<h2>2. Часть 2. Технологии</h2>
<h2>2.1. Организация проекта</h2>
Однако постепенно у нас выделились процедуры, которые мы переносили из проекта в проект практически не меняя. В первую очередь это D3DInit – инициализация Direct3D. Создадим новый модуль, в котором будем собирать самые необходимые процедуры, относящиеся к Direct3D. Объявим в нем глобальные переменные:

код на языке vb
 
Public dx8 As New DirectX8
Public d3d As Direct3D8
Public d3dx As New D3DX8
Public d3dDevice As Direct3DDevice8
 

Также имеет смысл объявить константу Pi:

код на языке vb
 
Public Const Pi = 3.141593
 

И сама процедура D3DInit:

код на языке vb
 
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:

код на языке vb
 
Public Sub D3DTerminate()
  Set d3dx = Nothing
  Set d3dDevice = Nothing
  Set d3d = Nothing
  Set dx8 = Nothing
End Sub
 

Так же сюда может войти неизменная функция vec3:

код на языке vb
 
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 мс интервал. С помощью таймера мы будем в дальнейшем замерять быстродействие. Еще одно важнейшее событие формы – ее закрытие. Немного изменим код его обработки:

код на языке vb
 
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
  If Running Then Cancel = 1: Running = False
End Sub
 

А вот для синхронизации движения таймер применять мы больше не будем, он применялся для простоты в самых начальных проектах. Дело в том, что таймер обладает невысокой точностью при измерении небольших интервалов времени, теперь для этого мы применим более современную API функцию – QueryPerformanceCounter.

Для функций API можно создать отдельный модуль и поместить туда такой код:

код на языке vb
 
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 такой код:

код на языке vb
 
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 формы поместить следующий код, чтобы измерять быстродействие нашей программы:

код на языке vb
 
Private Sub TimerFPS_Timer()
  Me.Caption = FPS
  FPS = 0
End Sub
 

Этот проект находится в папке Pr12.
Теперь, когда наша «перестройка» завершена, продолжим заниматься изучением Direct3D.