/
d3d9graphics.bmx
463 lines (355 loc) · 10.6 KB
/
d3d9graphics.bmx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
Strict
Import BRL.Graphics
Import Pub.DirectX
Import BRL.LinkedList
Private
Global _wndClass$="BBDX9Device Window Class"
Global _driver:TD3D9graphicsDriver
Global _d3d:IDirect3D9
Global _d3dCaps:D3DCAPS9
Global _modes:TGraphicsMode[]
Global _d3dDev:IDirect3DDevice9
Global _d3dDevRefs
Global _presentParams:D3DPRESENT_PARAMETERS
Global _graphics:TD3D9Graphics
Global _autoRelease:TList
Global _d3dOccQuery:IDirect3DQuery9
Type TD3D9AutoRelease
Field unk:IUnknown
End Type
Function D3D9WndProc( hwnd,msg,wp,lp ) "win32"
bbSystemEmitOSEvent hwnd,msg,wp,lp,Null
Select msg
Case WM_CLOSE
Return
Case WM_SYSKEYDOWN
If wp<>KEY_F4 Return
End Select
Return DefWindowProcW( hwnd,msg,wp,lp )
End Function
Function OpenD3DDevice( hwnd,width,height,depth,hertz,flags )
If _d3dDevRefs
If Not _presentParams.Windowed Return False
If depth<>0 Return False
_d3dDevRefs:+1
Return True
EndIf
Local windowed=(depth=0)
Local fullscreen=(depth<>0)
Local pp:D3DPRESENT_PARAMETERS=New D3DPRESENT_PARAMETERS
pp.BackBufferWidth=width
pp.BackBufferHeight=height
pp.BackBufferCount=1
pp.BackBufferFormat=(D3DFMT_X8R8G8B8 * fullscreen) + (D3DFMT_UNKNOWN * windowed)
pp.MultiSampleType=D3DMULTISAMPLE_NONE
pp.SwapEffect=(D3DSWAPEFFECT_DISCARD * fullscreen) + (D3DSWAPEFFECT_COPY * windowed)
pp.hDeviceWindow=hwnd
pp.Windowed=windowed
pp.Flags=D3DPRESENTFLAG_LOCKABLE_BACKBUFFER
pp.FullScreen_RefreshRateInHz=(hertz * fullscreen)
pp.PresentationInterval=D3DPRESENT_INTERVAL_ONE 'IMMEDIATE
Function CheckDepthFormat(format)
Return _d3d.CheckDeviceFormat(0,D3DDEVTYPE_HAL,D3DFMT_X8R8G8B8,D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,format)=D3D_OK
End Function
If flags&GRAPHICS_DEPTHBUFFER Or flags&GRAPHICS_STENCILBUFFER
pp.EnableAutoDepthStencil = True
If flags&GRAPHICS_STENCILBUFFER
If Not CheckDepthFormat( D3DFMT_D24S8 )
If Not CheckDepthFormat( D3DFMT_D24FS8 )
If Not CheckDepthFormat( D3DFMT_D24X4S4 )
If Not CheckDepthFormat( D3DFMT_D15S1 )
Return False
Else
pp.AutoDepthStencilFormat = D3DFMT_D15S1
EndIf
Else
pp.AutoDepthStencilFormat = D3DFMT_D24X4S4
EndIf
Else
pp.AutoDepthStencilFormat = D3DFMT_D24FS8
EndIf
Else
pp.AutoDepthStencilFormat = D3DFMT_D24S8
EndIf
Else
If Not CheckDepthFormat( D3DFMT_D32 )
If Not CheckDepthFormat( D3DFMT_D24X8 )
If Not CheckDepthFormat( D3DFMT_D16 )
Return False
Else
pp.AutoDepthStencilFormat = D3DFMT_D16
EndIf
Else
pp.AutoDepthStencilFormat = D3DFMT_D24X8
EndIf
Else
pp.AutoDepthStencilFormat = D3DFMT_D32
EndIf
EndIf
EndIf
Local cflags=D3DCREATE_FPU_PRESERVE
'OK, try hardware vertex processing...
Local tflags=D3DCREATE_PUREDEVICE|D3DCREATE_HARDWARE_VERTEXPROCESSING|cflags
If _d3d.CreateDevice( 0,D3DDEVTYPE_HAL,hwnd,tflags,pp,_d3dDev )<0
'Failed! Try mixed vertex processing...
tflags=D3DCREATE_MIXED_VERTEXPROCESSING|cflags
If _d3d.CreateDevice( 0,D3DDEVTYPE_HAL,hwnd,tflags,pp,_d3dDev )<0
'Failed! Try software vertex processing...
tflags=D3DCREATE_SOFTWARE_VERTEXPROCESSING|cflags
If _d3d.CreateDevice( 0,D3DDEVTYPE_HAL,hwnd,tflags,pp,_d3dDev )<0
'Failed! Go home and watch family guy instead...
Return False
EndIf
EndIf
EndIf
_presentParams=pp
_d3dDevRefs:+1
_autoRelease=New TList
'Occlusion Query
If Not _d3dOccQuery
If _d3ddev.CreateQuery(9,_d3dOccQuery)<0 '9 hardcoded for D3DQUERYTYPE_OCCLUSION
DebugLog "Cannot create Occlussion Query!"
EndIf
EndIf
If _d3dOccQuery _d3dOccQuery.Issue(2) 'D3DISSUE_BEGIN
Return True
End Function
Function CloseD3DDevice()
_d3dDevRefs:-1
If Not _d3dDevRefs
For Local t:TD3D9AutoRelease=EachIn _autoRelease
t.unk.Release_
Next
_autoRelease=Null
If _d3dOccQuery _d3dOccQuery.Release_
_d3dOccQuery = Null
_d3dDev.Release_
_d3dDev=Null
_presentParams=Null
EndIf
End Function
Function ResetD3DDevice()
If _d3dOccQuery _d3dOccQuery.Release_
If _d3dDev.Reset( _presentParams )<0
Throw "_d3dDev.Reset failed"
EndIf
If _d3ddev.CreateQuery(9,_d3dOccQuery)<0
DebugLog "Cannot create Occlussion Query!"
EndIf
If _d3dOccQuery _d3dOccQuery.Issue(2) 'D3DISSUE_BEGIN
End Function
Public
Global UseDX9RenderLagFix:Int = 0
Type TD3D9Graphics Extends TGraphics
Method Attach:TD3D9Graphics( hwnd,flags )
Local rect[4]
GetClientRect hwnd,rect
Local width=rect[2]-rect[0]
Local height=rect[3]-rect[1]
OpenD3DDevice hwnd,width,height,0,0,flags
_hwnd=hwnd
_width=width
_height=height
_flags=flags
_attached=True
Return Self
End Method
Method Create:TD3D9Graphics( width,height,depth,hertz,flags )
Local wstyle
If depth
wstyle=WS_VISIBLE|WS_POPUP
Else
wstyle=WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX
EndIf
Local rect[4]
If Not depth
Local desktopRect[4]
GetWindowRect GetDesktopWindow(),desktopRect
rect[0]=desktopRect[2]/2-width/2;
rect[1]=desktopRect[3]/2-height/2;
rect[2]=rect[0]+width;
rect[3]=rect[1]+height;
AdjustWindowRect rect,wstyle,0
EndIf
Local hwnd=CreateWindowExW( 0,_wndClass,AppTitle,wstyle,rect[0],rect[1],rect[2]-rect[0],rect[3]-rect[1],0,0,GetModuleHandleA(Null),Null )
If Not hwnd Return Null
If Not depth
GetClientRect hwnd,rect
width=rect[2]-rect[0]
height=rect[3]-rect[1]
EndIf
If Not OpenD3DDevice( hwnd,width,height,depth,hertz,flags )
DestroyWindow hwnd
Return Null
EndIf
_hwnd=hwnd
_width=width
_height=height
_depth=depth
_hertz=hertz
_flags=flags
Return Self
End Method
Method GetDirect3DDevice:IDirect3DDevice9()
Return _d3dDev
End Method
Method ValidateSize()
If _attached
Local rect[4]
GetClientRect _hwnd,rect
_width=rect[2]-rect[0]
_height=rect[3]-rect[1]
If _width>_presentParams.BackBufferWidth Or _height>_presentParams.BackBufferHeight
_presentParams.BackBufferWidth=Max( _width,_presentParams.BackBufferWidth )
_presentParams.BackBufferHeight=Max( _height,_presentParams.BackbufferHeight )
ResetD3DDevice
EndIf
EndIf
End Method
'NOTE: Returns 1 if flip was successful, otherwise device lost or reset...
Method Flip( sync )
Local reset
If sync sync=D3DPRESENT_INTERVAL_ONE Else sync=D3DPRESENT_INTERVAL_IMMEDIATE
If sync<>_presentParams.PresentationInterval
_presentParams.PresentationInterval=sync
reset=True
EndIf
Select _d3dDev.TestCooperativeLevel()
Case D3DERR_DRIVERINTERNALERROR
Throw "D3D Internal Error"
Case D3D_OK
If reset
ResetD3DDevice
Else If _attached
Local rect[]=[0,0,_width,_height]
Return _d3dDev.Present( rect,rect,_hwnd,Null )>=0
Else
Return _d3dDev.Present( Null,Null,_hwnd,Null )>=0
EndIf
Case D3DERR_DEVICENOTRESET
ResetD3DDevice
End Select
End Method
Method Driver:TGraphicsDriver()
Return _driver
End Method
Method GetSettings( width Var,height Var,depth Var,hertz Var,flags Var )
'
ValidateSize
'
width=_width
height=_height
depth=_depth
hertz=_hertz
flags=_flags
End Method
Method Close()
If Not _hwnd Return
CloseD3DDevice
If Not _attached DestroyWindow( _hwnd )
_hwnd=0
End Method
Method AutoRelease( unk:IUnknown )
Local t:TD3D9AutoRelease=New TD3D9AutoRelease
t.unk=unk
_autoRelease.AddLast t
End Method
Method ReleaseNow( unk:IUnknown )
For Local t:TD3D9AutoRelease=EachIn _autoRelease
If t.unk=unk
unk.Release_
_autoRelease.Remove t
Return
EndIf
Next
End Method
Field _hwnd
Field _width
Field _height
Field _depth
Field _hertz
Field _flags
Field _attached
End Type
Type TD3D9GraphicsDriver Extends TGraphicsDriver
Method Create:TD3D9GraphicsDriver()
'create d3d9
If Not d3d9Lib Return Null
_d3d=Direct3DCreate9( 32 )
If Not _d3d Return Null
'get caps
_d3dCaps=New D3DCAPS9
If _d3d.GetDeviceCaps( D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,_d3dCaps )<0
_d3d.Release_
_d3d=Null
Return Null
EndIf
'enum graphics modes
Local n=_d3d.GetAdapterModeCount( D3DADAPTER_DEFAULT,D3DFMT_X8R8G8B8 )
_modes=New TGraphicsMode[n]
Local j
For Local i=0 Until n
Local d3dmode:D3DDISPLAYMODE=New D3DDISPLAYMODE
If _d3d.EnumAdapterModes( D3DADAPTER_DEFAULT,D3DFMT_X8R8G8B8,i,d3dmode )<0
Continue
EndIf
Local Mode:TGraphicsMode=New TGraphicsMode
Mode.width=d3dmode.Width
Mode.height=d3dmode.Height
Mode.hertz=d3dmode.RefreshRate
Mode.depth=32
_modes[j]=Mode
j:+1
Next
_modes=_modes[..j]
'register wndclass
Local wndclass:WNDCLASSW=New WNDCLASSW
wndclass.hInstance=GetModuleHandleW( Null )
wndclass.lpfnWndProc=D3D9WndProc
wndclass.hCursor=LoadCursorW( Null,Short Ptr IDC_ARROW )
wndclass.lpszClassName=_wndClass.ToWString()
RegisterClassW wndclass
MemFree wndclass.lpszClassName
Return Self
End Method
Method GraphicsModes:TGraphicsMode[]()
Return _modes
End Method
Method AttachGraphics:TD3D9Graphics( widget,flags )
Return New TD3D9Graphics.Attach( widget,flags )
End Method
Method CreateGraphics:TD3D9Graphics( width,height,depth,hertz,flags )
Return New TD3D9Graphics.Create( width,height,depth,hertz,flags )
End Method
Method Graphics:TD3D9Graphics()
Return _graphics
End Method
Method SetGraphics( g:TGraphics )
_graphics=TD3D9Graphics( g )
End Method
Method Flip( sync )
Local present:Int = _graphics.Flip(sync)
If UseDX9RenderLagFix Then
Local pixelsdrawn:Int
If _d3dOccQuery
_d3dOccQuery.Issue(1) 'D3DISSUE_END
While _d3dOccQuery.GetData( Varptr pixelsdrawn,4,1 )=1 'D3DGETDATA_FLUSH
If _d3dOccQuery.GetData( Varptr pixelsdrawn,4,1 )<0 Exit
Wend
_d3dOccQuery.Issue(2) 'D3DISSUE_BEGIN
EndIf
End If
Return present
End Method
Method GetDirect3D:IDirect3D9()
Return _d3d
End Method
End Type
Function D3D9GraphicsDriver:TD3D9GraphicsDriver()
Global _done
If Not _done
_driver=New TD3D9GraphicsDriver.Create()
_done=True
EndIf
Return _driver
End Function