Отсюда первый вопрос - как это отследить. LostFocus и Deactivate не помогает.
Хуже, когда D3D полноэкранный. Уже сворачивание формы, скажем при случайном нажатии WinKey и т. п., вызывает сбой. При этом событие Resize почему-то не происходит. Я нашел отсюда один, довольно корявый, выход - в процедуре рендер ставлю "On Local Error Resume Next".
Отсюда второй вопрос - можно ли это побороть более "корректно", ведь так я теряю возможность отследить ДРУГИЕ ошибки.
Далее. Как восстановить форму после сворачивания? Я не нашел другого варианта, кроме как уничтожить и заново создать D3DDevice, а значит и все его RenderState-ы и т. п. Это очень неудобно и явно неправильно. Кроме того приходится эти RenderState-ы при каждом изменении фиксировать в переменных. С этим я пока борюсь удалением из главного цикла DoEvents - без этого сворачивания не происходит, но теряется возможность использовать KeyDown, MouseDown, Timer и вообще ВСЕ СОБЫТИЯ.
Отсюда третий вопрос, пожалуй главный - как поступать тут, не отказываясь от DoEvents?
Я написал минимальный D3D проект и предлагаю на нем испытывать свои методы и предложения, стараясь все делать максимально коротко. Программа закрашивает бэкбуфер в разные цвета и показывает. Вставляем этот код в новую форму - и проект готов.
PS . Думаю, решение этих проблем нужны нам всем.
- Код: Выделить всё
Option Explicit
Dim dx As New DirectX8
Dim d3d As Direct3D8
Dim d3dDevice As Direct3DDevice8
Dim Running As Boolean
Dim RenderEnable As Boolean
Const FullScreen = True
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyEscape Then Running = False
End Sub
Private Sub Form_Load()
Me.Show
InitD3D
Running = True
RenderEnable = True
Do While Running
DoEvents
If RenderEnable Then Render
Loop
CloseD3D
Unload Me
End Sub
Private Sub Render()
On Local Error Resume Next
d3dDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET, Rnd * &HFFFFFF, 1, 0
d3dDevice.Present ByVal 0, ByVal 0, 0, ByVal 0
End Sub
Private Sub CloseD3D()
Set d3dDevice = Nothing
Set d3d = Nothing
Set dx = Nothing
End Sub
Private Sub InitD3D()
Dim DispMode As D3DDISPLAYMODE
Dim d3dpp As D3DPRESENT_PARAMETERS
Set d3d = dx.Direct3DCreate
d3d.GetAdapterDisplayMode D3DADAPTER_DEFAULT, DispMode
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD
d3dpp.BackBufferFormat = DispMode.Format
d3dpp.EnableAutoDepthStencil = True
d3dpp.AutoDepthStencilFormat = D3DFMT_D16
If FullScreen Then
d3dpp.Windowed = False
d3dpp.BackBufferWidth = DispMode.Width
d3dpp.BackBufferHeight = DispMode.Height
d3dpp.BackBufferFormat = D3DFMT_R5G6B5
Set d3dDevice = d3d.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Me.hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp)
Else
d3dpp.Windowed = True
Set d3dDevice = d3d.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Me.hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, d3dpp)
End If
End Sub
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
Running = False
End Sub
Private Sub Form_Resize()
If Me.WindowState <> vbMinimized Then
RenderEnable = True
Else
RenderEnable = False
End If
End Sub