d3d7graphics.bmx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
  1. Strict
  2. Import BRL.Graphics
  3. Import BRL.LinkedList
  4. Import Pub.DirectX
  5. Private
  6. Extern
  7. Global _bbusew
  8. End Extern
  9. Const DLOG_ENABLED=False
  10. Const DDERR=$88760000
  11. Const DDERR_OK=0
  12. Const DDERR_PRIMARYSURFACEALREADYEXISTS=DDERR|564
  13. Const DDERR_WRONGMODE=DDERR|587
  14. Const DDERR_NOEXCLUSIVEMODE=DDERR|225
  15. Const DDERR_EXCLUSIVEMODEALREADYSET=DDERR|581
  16. Const DDERR_UNSUPPORTEDMODE=DDERR|590
  17. Const DDERR_SURFACELOST=DDERR|450
  18. Type TD3D7Surface
  19. Field surf:IDirectDrawSurface7
  20. End Type
  21. Global _driver:TD3D7GraphicsDriver
  22. Global _wndClass:Byte Ptr="BBDX7Device Window Class".ToCString()
  23. Global _wndClassW:Short Ptr="BBDX7Device Window Class".ToWString()
  24. Function dderrstr:String( code:Int )
  25. Select code
  26. Case DDERR_OK Return "OK"
  27. Case DDERR_PRIMARYSURFACEALREADYEXISTS Return "PRIMARYSURFACEALREADYEXISTS"
  28. Case DDERR_WRONGMODE Return "WRONGMODE"
  29. Case DDERR_NOEXCLUSIVEMODE Return "NOEXCLUSIVEMODE"
  30. Case DDERR_EXCLUSIVEMODEALREADYSET Return "EXCLUSIVEMODEALREADYSET"
  31. Case DDERR_UNSUPPORTEDMODE Return "UNSUPPORTEDMODE"
  32. Case DDERR_SURFACELOST Return "SURFACELOST"
  33. End Select
  34. ' Return "UNKNOWN:"+Hex( code )+" "+(code & 65535)
  35. Return "UNKNOWN:"+( code )+" "+(code & 65535)
  36. End Function
  37. Function dlog( t:String )
  38. If Not DLOG_ENABLED Return
  39. WriteStdout t+"~n"
  40. End Function
  41. Function WndProc( hwnd,message,wp,lp ) "win32"
  42. bbSystemEmitOSEvent hwnd,message,wp,lp,Null
  43. Select message
  44. Case WM_CLOSE
  45. Return
  46. Case WM_SYSKEYDOWN
  47. If wp<>KEY_F4 Return
  48. Case WM_SETFOCUS
  49. dlog "WM_SETFOCUS"
  50. _driver.ValidateGraphics
  51. Case WM_KILLFOCUS
  52. dlog "WM_KILLFOCUS"
  53. _driver.ValidateGraphics
  54. End Select
  55. If _bbusew Return DefWindowProcW( hwnd,message,wp,lp )
  56. Return DefWindowProcA( hwnd,message,wp,lp )
  57. End Function
  58. Function EnumModesCallback( desc:Byte Ptr,context:Object ) "win32"
  59. Local p:Int Ptr=Int Ptr(desc)
  60. Local t:TGraphicsMode=New TGraphicsMode
  61. t.width=p[3]
  62. t.height=p[2]
  63. t.depth=p[21]
  64. t.hertz=p[6]
  65. If t.depth>=16 TList(context).AddLast t
  66. Return D3DENUMRET_OK
  67. End Function
  68. Function DXASS( n,msg:String="DXERROR" )
  69. If n>=0 Return
  70. WriteStdout msg+" err="+dderrstr( n )+"~n"
  71. ?Debug
  72. DebugStop
  73. ?
  74. End
  75. End Function
  76. Function FindMode:TGraphicsMode( width,height,depth,hertz,modes:TGraphicsMode[] )
  77. Local mode:TGraphicsMode,md=$7fff
  78. For Local t:TGraphicsMode=EachIn modes
  79. If width=t.width And height=t.height And depth=t.depth
  80. Local d=Abs(hertz-t.hertz)
  81. If d<md
  82. md=d
  83. mode=t
  84. EndIf
  85. EndIf
  86. Next
  87. Return mode
  88. End Function
  89. Function BestMode:TGraphicsMode( width,height,depth,hertz,modes:TGraphicsMode[] )
  90. Local mode:TGraphicsMode
  91. mode=FindMode( width,height,depth,hertz,modes )
  92. If mode Return mode
  93. mode=FindMode( width,height,32,hertz,modes )
  94. If mode Return mode
  95. mode=FindMode( width,height,24,hertz,modes )
  96. If mode Return mode
  97. mode=FindMode( width,height,16,hertz,modes )
  98. If mode Return mode
  99. End Function
  100. Public
  101. Type TD3D7Graphics Extends TGraphics
  102. Method Driver:TGraphicsDriver()
  103. Return _driver
  104. End Method
  105. Method GetSettings( width Var,height Var,depth Var,hertz Var,flags Var )
  106. width=_width
  107. height=_height
  108. depth=_depth
  109. hertz=_hertz
  110. flags=_flags
  111. End Method
  112. Method Close()
  113. If Not _hwnd Return
  114. Local dd7:IDirectDraw7=_driver.DirectDraw7()
  115. If _depth dd7.SetCooperativeLevel Null,DDSCL_NORMAL|DDSCL_FPUPRESERVE
  116. _driver.CloseGraphics( Self )
  117. DestroyWindow _hwnd
  118. _hwnd=Null
  119. End Method
  120. Method Flip( sync )
  121. Local dd7:IDirectDraw7=_driver.DirectDraw7()
  122. 'Ugly kludge to prevent 'render ahead'...
  123. Local desc:DDSURFACEDESC2=New DDSURFACEDESC2
  124. desc.dwSize=SizeOf(desc)
  125. If _renderSurf.Lock( Null,desc,DDLOCK_READONLY|DDLOCK_WAIT,Null )>=0 _renderSurf.Unlock Null
  126. If _depth
  127. Local flags
  128. If Not sync flags=DDFLIP_NOVSYNC
  129. _primSurf.Flip Null,flags
  130. Else
  131. Local src[]=[0,0,_width,_height]
  132. Local dest[]=[0,0,_width,_height]
  133. ClientToScreen _hwnd,dest
  134. dest[2]:+dest[0]
  135. dest[3]:+dest[1]
  136. If sync dd7.WaitForVerticalBlank DDWAITVB_BLOCKBEGIN,0
  137. _primSurf.SetClipper( _clipper )
  138. _primSurf.Blt( dest,_renderSurf,src,0,Null )
  139. _primSurf.SetClipper( Null )
  140. EndIf
  141. End Method
  142. Method RenderSurface:IDirectDrawSurface7()
  143. ValidateSize
  144. Return _renderSurf
  145. End Method
  146. Method CreateRenderSurface:IDirectDrawSurface7()
  147. Local dd7:IDirectDraw7=_driver.DirectDraw7()
  148. If _depth
  149. DXASS dd7.SetCooperativeLevel( _hwnd,DDSCL_FULLSCREEN|DDSCL_EXCLUSIVE|DDSCL_ALLOWREBOOT|DDSCL_FPUPRESERVE )
  150. DXASS dd7.SetDisplayMode( _width,_height,_depth,_hertz,0 )
  151. Local desc:DDSURFACEDESC2=New DDSURFACEDESC2
  152. desc.dwSize=SizeOf(desc)
  153. desc.dwFlags=DDSD_CAPS|DDSD_BACKBUFFERCOUNT
  154. desc.ddsCaps=DDSCAPS_PRIMARYSURFACE|DDSCAPS_COMPLEX|DDSCAPS_FLIP|DDSCAPS_3DDEVICE
  155. desc.dwBackBufferCount=1
  156. DXASS dd7.CreateSurface( desc,Varptr _primSurf,Null )
  157. Local caps:DDSCAPS2=New DDSCAPS2
  158. caps.dwCaps=DDSCAPS_BACKBUFFER
  159. DXASS _primSurf.GetAttachedSurface( caps,Varptr _renderSurf )
  160. Else
  161. If _primSurf
  162. _primSurf.AddRef
  163. Else
  164. Local desc:DDSURFACEDESC2=New DDSURFACEDESC2
  165. desc.dwSize=SizeOf(desc)
  166. desc.dwFlags=DDSD_CAPS
  167. desc.ddsCaps=DDSCAPS_PRIMARYSURFACE
  168. DXASS dd7.CreateSurface( desc,Varptr _primSurf,Null )
  169. EndIf
  170. Local desc:DDSURFACEDESC2=New DDSURFACEDESC2
  171. desc.dwSize=SizeOf(desc)
  172. desc.dwFlags=DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS
  173. desc.dwWidth=_width
  174. desc.dwHeight=_height
  175. desc.ddsCaps=DDSCAPS_OFFSCREENPLAIN|DDSCAPS_3DDEVICE
  176. dlog "CreateRenderSurface _width="+_width+" _height="+_height
  177. DXASS dd7.CreateSurface( desc,Varptr _renderSurf,Null )
  178. DXASS dd7.CreateClipper( 0,Varptr _clipper,Null )
  179. DXASS _clipper.SetHWnd( 0,_hwnd )
  180. EndIf
  181. _primRefs:+1
  182. Return _renderSurf
  183. End Method
  184. Method DestroyRenderSurface()
  185. If _clipper
  186. dlog "_clipper.Release_="+_clipper.Release_()
  187. _clipper=Null
  188. EndIf
  189. If _renderSurf
  190. dlog "_renderSurf.Release_="+_renderSurf.Release_()
  191. _renderSurf=Null
  192. EndIf
  193. If _primSurf
  194. dlog "_primSurf.Release_="+_primSurf.Release_()
  195. _primRefs:-1
  196. If Not _primRefs _primSurf=Null
  197. EndIf
  198. End Method
  199. Function Attach:TD3D7Graphics( hwnd,flags )
  200. Local rect[4]
  201. GetClientRect( hwnd,rect )
  202. Local t:TD3D7Graphics=New TD3D7Graphics
  203. t._hwnd=hwnd
  204. t._width=rect[2]
  205. t._height=rect[3]
  206. t._flags=flags
  207. Return t
  208. End Function
  209. Function Create:TD3D7Graphics( width,height,depth,hertz,flags )
  210. Global _reg
  211. If Not _reg
  212. If _bbusew
  213. Local wc:WNDCLASSW=New WNDCLASSW
  214. wc.hInstance=GetModuleHandleA( Null )
  215. wc.lpfnWndProc=WndProc
  216. wc.hCursor=LoadCursorA( Null,Byte Ptr IDC_ARROW )
  217. wc.lpszClassName=_wndClassW
  218. RegisterClassW( wc )
  219. _reg=True
  220. Else
  221. Local wc:WNDCLASS=New WNDCLASS
  222. wc.hInstance=GetModuleHandleA( Null )
  223. wc.lpfnWndProc=WndProc
  224. wc.hCursor=LoadCursorA( Null,Byte Ptr IDC_ARROW )
  225. wc.lpszClassName=_wndClass
  226. RegisterClassA( wc )
  227. _reg=True
  228. EndIf
  229. EndIf
  230. Local hinst=GetModuleHandleA( Null )
  231. Local title:Byte Ptr=AppTitle.ToCString()
  232. Local titleW:String=AppTitle
  233. Local _wndClassW:String=String.FromCString( _wndClass )
  234. Local hwnd
  235. If depth
  236. If _bbusew
  237. hwnd=CreateWindowExW( 0,_wndClassW,titleW,WS_VISIBLE|WS_POPUP,0,0,width,height,0,0,hinst,Null )
  238. Else
  239. hwnd=CreateWindowExA( 0,_wndClass,title,WS_VISIBLE|WS_POPUP,0,0,width,height,0,0,hinst,Null )
  240. EndIf
  241. Else
  242. Local style=WS_VISIBLE|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX
  243. Local rect[]=[32,32,width+32,height+32]
  244. Local desktopHWND:Int=GetDesktopWindow()
  245. Local desktopRect:Int[]=New Int[4]
  246. GetWindowRect( desktopHWND,desktopRect)
  247. rect[0]=desktopRect[2]/2-width/2;
  248. rect[1]=desktopRect[3]/2-height/2;
  249. rect[2]=rect[0]+width;
  250. rect[3]=rect[1]+height;
  251. AdjustWindowRect rect,style,0
  252. If _bbusew
  253. hwnd=CreateWindowExW( 0,_wndClassW,titleW,style,rect[0],rect[1],rect[2]-rect[0],rect[3]-rect[1],0,0,hinst,Null )
  254. Else
  255. hwnd=CreateWindowExA( 0,_wndClass,title,style,rect[0],rect[1],rect[2]-rect[0],rect[3]-rect[1],0,0,hinst,Null )
  256. EndIf
  257. GetClientRect hwnd,rect
  258. width=rect[2]-rect[0]
  259. height=rect[3]-rect[1]
  260. EndIf
  261. MemFree title
  262. If Not hwnd Return
  263. Local t:TD3D7Graphics=New TD3D7Graphics
  264. t._hwnd=hwnd
  265. t._width=width
  266. t._height=height
  267. t._depth=depth
  268. t._hertz=hertz
  269. t._flags=flags
  270. Return t
  271. End Function
  272. Method ValidateSize()
  273. If _depth Return
  274. Local rect[4]
  275. GetClientRect _hwnd,rect
  276. Local width=rect[2],height=rect[3]
  277. If width<=0 Or height<=0 Return
  278. If width=_width And height=_height Return
  279. dlog "Size invalidated"
  280. DestroyRenderSurface
  281. _width=width
  282. _height=height
  283. End Method
  284. Field _width,_height,_depth,_hertz,_flags
  285. Field _hwnd
  286. Field _clipper:IDirectDrawClipper
  287. Field _renderSurf:IDirectDrawSurface7
  288. Global _primSurf:IDirectDrawSurface7,_primRefs
  289. End Type
  290. Type TD3D7GraphicsDriver Extends TGraphicsDriver
  291. Method GraphicsModes:TGraphicsMode[]()
  292. Return _modes
  293. End Method
  294. Method AttachGraphics:TD3D7Graphics( hwnd,flags )
  295. If _n_fullscreen Return
  296. Local g:TD3D7graphics=TD3D7Graphics.Attach( hwnd,flags )
  297. If g _n_graphics:+1
  298. _graphicss.AddLast g
  299. Return g
  300. End Method
  301. Method CreateGraphics:TD3D7Graphics( width,height,depth,hertz,flags )
  302. If _n_fullscreen Return
  303. If depth
  304. If _n_graphics Return
  305. Local mode:TGraphicsMode=BestMode( width,height,depth,hertz,_modes )
  306. If Not mode Return
  307. depth=mode.depth
  308. hertz=mode.hertz
  309. EndIf
  310. Local g:TD3D7Graphics=TD3D7Graphics.Create( width,height,depth,hertz,flags )
  311. If Not g Return
  312. _graphicss.AddLast g
  313. If depth _n_fullscreen:+1
  314. _n_graphics:+1
  315. Return g
  316. End Method
  317. 'Internal use only...
  318. Method CloseGraphics( g:TD3D7Graphics )
  319. If _n_graphics=1
  320. _Destroy
  321. Else
  322. g.DestroyRenderSurface
  323. EndIf
  324. _graphicss.Remove g
  325. If g=_graphics
  326. _graphics=Null
  327. IsValid=False
  328. EndIf
  329. _n_graphics:-1
  330. _n_fullscreen=0
  331. End Method
  332. Method SetGraphics( g:TGraphics )
  333. _graphics=TD3D7Graphics( g )
  334. ValidateGraphics True
  335. End Method
  336. Method Graphics:TD3D7Graphics()
  337. Return _graphics
  338. End Method
  339. Method Flip( sync )
  340. If IsValid
  341. If _inScene _d3ddev7.EndScene
  342. _graphics.Flip sync
  343. EndIf
  344. ValidateGraphics True
  345. End Method
  346. Method DirectDraw7:IDirectDraw7()
  347. Return _dd7
  348. End Method
  349. Method Direct3D7:IDirect3D7()
  350. Return _d3d7
  351. End Method
  352. Method Direct3DDevice7:IDirect3DDevice7()
  353. Return _d3ddev7
  354. End Method
  355. Method BeginScene()
  356. _inScene=True
  357. If IsValid _d3ddev7.BeginScene
  358. End Method
  359. Method EndScene()
  360. If IsValid _d3ddev7.EndScene
  361. _inScene=False
  362. End Method
  363. Method CreateSurface:IDirectDrawSurface7( desc:DDSURFACEDESC2 )
  364. Local surf:IDirectDrawSurface7
  365. Local err=_dd7.CreateSurface( desc,Varptr surf,Null )
  366. If err<0
  367. dlog "CreateSurface failed:"+dderrstr(err)
  368. Return Null
  369. EndIf
  370. Local t:TD3D7Surface=New TD3D7Surface
  371. t.surf=surf
  372. _surfaces.AddLast t
  373. dlog "CreateSurface OK"
  374. Return surf
  375. End Method
  376. Method DestroySurface( surf:IDirectDrawSurface7 )
  377. For Local t:TD3D7Surface=EachIn _surfaces
  378. If t.surf<>surf Continue
  379. dlog "Destroy surface="+surf.Release_()
  380. _surfaces.Remove t
  381. Return
  382. Next
  383. End Method
  384. Method _ValidateGraphics()
  385. If Not _graphics Return False
  386. Local coop
  387. If _dd7
  388. coop=_dd7.TestCooperativeLevel()
  389. If coop=DDERR_WRONGMODE
  390. dlog "DDERR_WRONGMODE"
  391. _Destroy
  392. EndIf
  393. EndIf
  394. If Not _dd7
  395. If Not _Create() Return False
  396. coop=_dd7.TestCooperativeLevel()
  397. EndIf
  398. If coop<0 Return False
  399. Local renderSurf:IDirectDrawSurface7=_graphics.RenderSurface()
  400. If renderSurf
  401. If renderSurf.IsLost()<0
  402. DXASS _dd7.RestoreAllSurfaces()
  403. EndIf
  404. DXASS _d3ddev7.SetRenderTarget( renderSurf,0 )
  405. Else
  406. renderSurf=_graphics.CreateRenderSurface()
  407. If _d3ddev7
  408. DXASS _d3ddev7.SetRenderTarget( renderSurf,0 )
  409. Else
  410. If _d3d7.CreateDevice( IID_IDirect3DTnLDevice,renderSurf,Varptr _d3ddev7 )<0
  411. DXASS _d3d7.CreateDevice( IID_IDirect3DHALDevice,renderSurf,Varptr _d3ddev7 )
  412. EndIf
  413. EndIf
  414. EndIf
  415. Return True
  416. End Method
  417. Method ValidateGraphics( force=False )
  418. Global _busy
  419. If _busy
  420. dlog "busy: Valid="+IsValid
  421. Return IsValid
  422. EndIf
  423. _busy=True
  424. Local valid=IsValid
  425. If valid Or force valid=_ValidateGraphics()
  426. If valid<>IsValid
  427. dlog "Valid="+valid
  428. If valid And _inScene _d3ddev7.BeginScene()
  429. EndIf
  430. IsValid=valid
  431. _busy=False
  432. Return IsValid
  433. End Method
  434. Function Create:TD3D7GraphicsDriver()
  435. If _driver Return _driver
  436. _driver=New TD3D7GraphicsDriver._Create()
  437. If Not _driver Return
  438. Local mlist:TList=New TList
  439. _driver._dd7.EnumDisplayModes( DDEDM_REFRESHRATES,Null,mlist,EnumModesCallback )
  440. Local i
  441. _driver._modes=New TGraphicsMode[mlist.Count()]
  442. For Local mode:TGraphicsMode=EachIn mlist
  443. _driver._modes[i]=mode
  444. i:+1
  445. Next
  446. _driver._Destroy
  447. Return _driver
  448. End Function
  449. Method _Create:TD3D7GraphicsDriver()
  450. If Not DirectDrawCreateEx Return Null
  451. If DirectDrawCreateEx( Null,Varptr _dd7,IID_IDirectDraw7,Null )<0 Return _Destroy()
  452. If _dd7.SetCooperativeLevel( 0,DDSCL_NORMAL|DDSCL_FPUPRESERVE )<0 Return _Destroy()
  453. Local caps:DDCAPS_DX7=New DDCAPS_DX7
  454. caps.dwSize=SizeOf( DDCAPS_DX7 )
  455. If _dd7.GetCaps( caps,Null )<0 Return _Destroy()
  456. If Not (caps.dwCaps & DDCAPS_3D) Return _Destroy()
  457. If _dd7.QueryInterface( IID_IDirect3D7,Byte Ptr Ptr(Varptr _d3d7) )<0 Return _Destroy()
  458. BumpGraphicsSeq
  459. dlog "_Created"
  460. Return Self
  461. End Method
  462. Method _Destroy:TD3D7GraphicsDriver()
  463. dlog "_Destroying"
  464. BumpGraphicsSeq
  465. 'have to destroy device before renderSurfs or crash in fullscreen
  466. If _d3ddev7 _d3ddev7.Release_
  467. For Local t:TD3D7Surface=EachIn _surfaces
  468. dlog "Destroy surface="+t.surf.Release_()
  469. Next
  470. For Local t:TD3D7Graphics=EachIn _graphicss
  471. t.DestroyRenderSurface
  472. Next
  473. If _d3d7 _d3d7.Release_
  474. If _dd7 dlog "Release dd7="+_dd7.Release_()
  475. _dd7=Null
  476. _d3d7=Null
  477. _d3ddev7=Null
  478. _surfaces.Clear
  479. Return Null
  480. End Method
  481. Global IsValid
  482. Field _modes:TGraphicsMode[]
  483. Field _dd7:IDirectDraw7
  484. Field _d3d7:IDirect3D7
  485. Field _d3ddev7:IDirect3DDevice7
  486. Field _graphics:TD3D7Graphics
  487. Field _n_graphics,_n_fullscreen,_inScene
  488. Field _surfaces:TList=New TList
  489. Field _graphicss:TList=New TList
  490. End Type
  491. Function D3D7GraphicsDriver:TD3D7GraphicsDriver()
  492. Return TD3D7GraphicsDriver.Create()
  493. End Function