Gfx_wrapper_Direct3D.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317
  1. /* Copyright (c) 2002-2012 Croteam Ltd.
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of version 2 of the GNU General Public License as published by
  4. the Free Software Foundation
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License along
  10. with this program; if not, write to the Free Software Foundation, Inc.,
  11. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
  12. #ifdef SE1_D3D
  13. // helper for keep user clip plane of D3D happy (i.e. updated as view matrix changes)
  14. static void UpdateClipPlane_D3D(void)
  15. {
  16. FLOAT afObjectClipPlane[4];
  17. // if view matrix is active
  18. if( GFX_bViewMatrix) {
  19. // need to back-transform user clip plane from view to object space
  20. FLOAT *pcp = &D3D_afClipPlane[0]; // (pl-v) * !m;
  21. FLOAT *pvm = &D3D_afViewMatrix[0];
  22. afObjectClipPlane[0] = pcp[0]*pvm[0] + pcp[1]*pvm[1] + pcp[2]*pvm[2];
  23. afObjectClipPlane[1] = pcp[0]*pvm[4] + pcp[1]*pvm[5] + pcp[2]*pvm[6];
  24. afObjectClipPlane[2] = pcp[0]*pvm[8] + pcp[1]*pvm[9] + pcp[2]*pvm[10];
  25. afObjectClipPlane[3] = pcp[3] + (pcp[0]*pvm[12] + pcp[1]*pvm[13] + pcp[2]*pvm[14]);
  26. } else {
  27. // just copy clip plane
  28. (ULONG&)afObjectClipPlane[0] = (ULONG&)D3D_afClipPlane[0];
  29. (ULONG&)afObjectClipPlane[1] = (ULONG&)D3D_afClipPlane[1];
  30. (ULONG&)afObjectClipPlane[2] = (ULONG&)D3D_afClipPlane[2];
  31. (ULONG&)afObjectClipPlane[3] = (ULONG&)D3D_afClipPlane[3];
  32. }
  33. // skip if the same as last time
  34. ULONG *pulThis = (ULONG*) afObjectClipPlane;
  35. ULONG *pulLast = (ULONG*)_afActiveClipPlane;
  36. if( pulLast[0]==pulThis[0] && pulLast[1]==pulThis[1]
  37. && pulLast[2]==pulThis[2] && pulLast[3]==pulThis[3]) return;
  38. // update (if supported!)
  39. if( _pGfx->gl_ulFlags&GLF_D3D_CLIPPLANE) {
  40. HRESULT hr = _pGfx->gl_pd3dDevice->SetClipPlane( 0, &afObjectClipPlane[0]);
  41. D3D_CHECKERROR(hr);
  42. }
  43. // keep it as current
  44. pulLast[0] = pulThis[0];
  45. pulLast[1] = pulThis[1];
  46. pulLast[2] = pulThis[2];
  47. pulLast[3] = pulThis[3];
  48. }
  49. // ENABLE/DISABLE FUNCTIONS
  50. static void d3d_EnableTexture(void)
  51. {
  52. // check consistency
  53. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  54. HRESULT hr;
  55. #ifndef NDEBUG
  56. BOOL bRes;
  57. hr = _pGfx->gl_pd3dDevice->GetTextureStageState( GFX_iActiveTexUnit, D3DTSS_COLOROP, (DWORD*)&bRes);
  58. if( bRes==D3DTOP_DISABLE) bRes = FALSE;
  59. D3D_CHECKERROR(hr);
  60. ASSERT( !bRes == !GFX_abTexture[GFX_iActiveTexUnit]);
  61. #endif
  62. // cached?
  63. if( GFX_abTexture[GFX_iActiveTexUnit] && gap_bOptimizeStateChanges) return;
  64. GFX_abTexture[GFX_iActiveTexUnit] = TRUE;
  65. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  66. D3DTEXTUREOP d3dTexOp = (GFX_iTexModulation[GFX_iActiveTexUnit]==2) ? D3DTOP_MODULATE2X : D3DTOP_MODULATE;
  67. hr = _pGfx->gl_pd3dDevice->SetTextureStageState( GFX_iActiveTexUnit, D3DTSS_COLOROP, d3dTexOp);
  68. D3D_CHECKERROR(hr);
  69. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  70. }
  71. static void d3d_DisableTexture(void)
  72. {
  73. // check consistency
  74. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  75. HRESULT hr;
  76. #ifndef NDEBUG
  77. BOOL bRes;
  78. hr = _pGfx->gl_pd3dDevice->GetTextureStageState( GFX_iActiveTexUnit, D3DTSS_COLOROP, (DWORD*)&bRes);
  79. if( bRes==D3DTOP_DISABLE) bRes = FALSE;
  80. D3D_CHECKERROR(hr);
  81. ASSERT( !bRes == !GFX_abTexture[GFX_iActiveTexUnit]);
  82. #endif
  83. // cached?
  84. if( !GFX_abTexture[GFX_iActiveTexUnit] && gap_bOptimizeStateChanges) return;
  85. GFX_abTexture[GFX_iActiveTexUnit] = FALSE;
  86. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  87. hr = _pGfx->gl_pd3dDevice->SetTextureStageState( GFX_iActiveTexUnit, D3DTSS_COLOROP, D3DTOP_DISABLE);
  88. D3D_CHECKERROR(hr);
  89. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  90. }
  91. static void d3d_EnableDepthTest(void)
  92. {
  93. // check consistency
  94. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  95. HRESULT hr;
  96. #ifndef NDEBUG
  97. BOOL bRes;
  98. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_ZENABLE, (DWORD*)&bRes);
  99. D3D_CHECKERROR(hr);
  100. ASSERT( !bRes == !GFX_bDepthTest);
  101. #endif
  102. // cached?
  103. if( GFX_bDepthTest && gap_bOptimizeStateChanges) return;
  104. GFX_bDepthTest = TRUE;
  105. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  106. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE);
  107. D3D_CHECKERROR(hr);
  108. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  109. }
  110. static void d3d_DisableDepthTest(void)
  111. {
  112. // check consistency
  113. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  114. HRESULT hr;
  115. #ifndef NDEBUG
  116. BOOL bRes;
  117. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_ZENABLE, (DWORD*)&bRes);
  118. D3D_CHECKERROR(hr);
  119. ASSERT( !bRes == !GFX_bDepthTest);
  120. #endif
  121. // cached?
  122. if( !GFX_bDepthTest && gap_bOptimizeStateChanges) return;
  123. GFX_bDepthTest = FALSE;
  124. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  125. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE);
  126. D3D_CHECKERROR(hr);
  127. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  128. }
  129. static void d3d_EnableDepthBias(void)
  130. {
  131. // only if supported
  132. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  133. if( !(_pGfx->gl_ulFlags&GLF_D3D_ZBIAS)) return;
  134. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  135. HRESULT hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_ZBIAS, 2);
  136. D3D_CHECKERROR(hr);
  137. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  138. }
  139. static void d3d_DisableDepthBias(void)
  140. {
  141. // only if supported
  142. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  143. if( !(_pGfx->gl_ulFlags&GLF_D3D_ZBIAS)) return;
  144. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  145. HRESULT hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_ZBIAS, 0);
  146. D3D_CHECKERROR(hr);
  147. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  148. }
  149. static void d3d_EnableDepthWrite(void)
  150. {
  151. // check consistency
  152. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  153. HRESULT hr;
  154. #ifndef NDEBUG
  155. BOOL bRes;
  156. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_ZWRITEENABLE, (DWORD*)&bRes);
  157. D3D_CHECKERROR(hr);
  158. ASSERT( !bRes == !GFX_bDepthWrite);
  159. #endif
  160. // cached?
  161. if( GFX_bDepthWrite && gap_bOptimizeStateChanges) return;
  162. GFX_bDepthWrite = TRUE;
  163. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  164. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE);
  165. D3D_CHECKERROR(hr);
  166. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  167. }
  168. static void d3d_DisableDepthWrite(void)
  169. {
  170. // check consistency
  171. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  172. HRESULT hr;
  173. #ifndef NDEBUG
  174. BOOL bRes;
  175. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_ZWRITEENABLE, (DWORD*)&bRes);
  176. D3D_CHECKERROR(hr);
  177. ASSERT( !bRes == !GFX_bDepthWrite);
  178. #endif
  179. // cached?
  180. if( !GFX_bDepthWrite && gap_bOptimizeStateChanges) return;
  181. GFX_bDepthWrite = FALSE;
  182. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  183. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE);
  184. D3D_CHECKERROR(hr);
  185. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  186. }
  187. static void d3d_EnableDither(void)
  188. {
  189. // check consistency
  190. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  191. HRESULT hr;
  192. #ifndef NDEBUG
  193. BOOL bRes;
  194. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_DITHERENABLE, (DWORD*)&bRes);
  195. D3D_CHECKERROR(hr);
  196. ASSERT( !bRes == !GFX_bDithering);
  197. #endif
  198. // cached?
  199. if( GFX_bDithering && gap_bOptimizeStateChanges) return;
  200. GFX_bDithering = TRUE;
  201. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  202. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, TRUE);
  203. D3D_CHECKERROR(hr);
  204. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  205. }
  206. static void d3d_DisableDither(void)
  207. {
  208. // check consistency
  209. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  210. HRESULT hr;
  211. #ifndef NDEBUG
  212. BOOL bRes;
  213. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_DITHERENABLE, (DWORD*)&bRes);
  214. D3D_CHECKERROR(hr);
  215. ASSERT( !bRes == !GFX_bDithering);
  216. #endif
  217. // cached?
  218. if( !GFX_bDithering && gap_bOptimizeStateChanges) return;
  219. GFX_bDithering = FALSE;
  220. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  221. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_DITHERENABLE, FALSE);
  222. D3D_CHECKERROR(hr);
  223. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  224. }
  225. static void d3d_EnableAlphaTest(void)
  226. {
  227. // check consistency
  228. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  229. HRESULT hr;
  230. #ifndef NDEBUG
  231. BOOL bRes;
  232. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_ALPHATESTENABLE, (DWORD*)&bRes);
  233. D3D_CHECKERROR(hr);
  234. ASSERT( !bRes == !GFX_bAlphaTest);
  235. #endif
  236. // cached?
  237. if( GFX_bAlphaTest && gap_bOptimizeStateChanges) return;
  238. GFX_bAlphaTest = TRUE;
  239. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  240. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, TRUE);
  241. D3D_CHECKERROR(hr);
  242. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  243. }
  244. static void d3d_DisableAlphaTest(void)
  245. {
  246. // check consistency
  247. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  248. HRESULT hr;
  249. #ifndef NDEBUG
  250. BOOL bRes;
  251. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_ALPHATESTENABLE, (DWORD*)&bRes);
  252. D3D_CHECKERROR(hr);
  253. ASSERT( !bRes == !GFX_bAlphaTest);
  254. #endif
  255. // cached?
  256. if( !GFX_bAlphaTest && gap_bOptimizeStateChanges) return;
  257. GFX_bAlphaTest = FALSE;
  258. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  259. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE, FALSE);
  260. D3D_CHECKERROR(hr);
  261. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  262. }
  263. static void d3d_EnableBlend(void)
  264. {
  265. // check consistency
  266. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  267. HRESULT hr;
  268. #ifndef NDEBUG
  269. BOOL bRes;
  270. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_ALPHABLENDENABLE, (DWORD*)&bRes);
  271. D3D_CHECKERROR(hr);
  272. ASSERT( !bRes == !GFX_bBlending);
  273. #endif
  274. // cached?
  275. if( GFX_bBlending && gap_bOptimizeStateChanges) return;
  276. GFX_bBlending = TRUE;
  277. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  278. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE);
  279. D3D_CHECKERROR(hr);
  280. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  281. // adjust dithering
  282. if( gap_iDithering==2) d3d_EnableDither();
  283. else d3d_DisableDither();
  284. }
  285. static void d3d_DisableBlend(void)
  286. {
  287. // check consistency
  288. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  289. HRESULT hr;
  290. #ifndef NDEBUG
  291. BOOL bRes;
  292. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_ALPHABLENDENABLE, (DWORD*)&bRes);
  293. D3D_CHECKERROR(hr);
  294. ASSERT( !bRes == !GFX_bBlending);
  295. #endif
  296. // cached?
  297. if( !GFX_bBlending && gap_bOptimizeStateChanges) return;
  298. GFX_bBlending = FALSE;
  299. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  300. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE);
  301. D3D_CHECKERROR(hr);
  302. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  303. // adjust dithering
  304. if( gap_iDithering==0) d3d_DisableDither();
  305. else d3d_EnableDither();
  306. }
  307. static void d3d_EnableClipping(void)
  308. {
  309. // check consistency
  310. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  311. HRESULT hr;
  312. #ifndef NDEBUG
  313. BOOL bRes = GFX_bClipping;
  314. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_CLIPPING, (DWORD*)&bRes);
  315. D3D_CHECKERROR(hr);
  316. ASSERT( !bRes == !GFX_bClipping);
  317. #endif
  318. // cached?
  319. if( GFX_bClipping && gap_bOptimizeStateChanges) return;
  320. GFX_bClipping = TRUE;
  321. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  322. _bWantsClipping = TRUE; // need to signal for custom clip plane
  323. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_CLIPPING, TRUE);
  324. D3D_CHECKERROR(hr);
  325. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  326. }
  327. static void d3d_DisableClipping(void)
  328. {
  329. // only if allowed
  330. if( gap_iOptimizeClipping<2) return;
  331. // check consistency
  332. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  333. HRESULT hr;
  334. #ifndef NDEBUG
  335. BOOL bRes;
  336. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_CLIPPING, (DWORD*)&bRes);
  337. D3D_CHECKERROR(hr);
  338. ASSERT( !bRes == !GFX_bClipping);
  339. #endif
  340. // cached?
  341. if( !GFX_bClipping && gap_bOptimizeStateChanges) return;
  342. GFX_bClipping = FALSE;
  343. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  344. // cannot disable clipping if clip-plane is enabled!
  345. if( GFX_bClipPlane) {
  346. GFX_bClipping = TRUE;
  347. _bWantsClipping = FALSE;
  348. } else {
  349. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_CLIPPING, FALSE);
  350. D3D_CHECKERROR(hr);
  351. }
  352. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  353. }
  354. static void d3d_EnableClipPlane(void)
  355. {
  356. // only if supported
  357. if( !(_pGfx->gl_ulFlags&GLF_D3D_CLIPPLANE)) return;
  358. // check consistency
  359. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  360. HRESULT hr;
  361. #ifndef NDEBUG
  362. BOOL bRes;
  363. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_CLIPPLANEENABLE, (DWORD*)&bRes);
  364. D3D_CHECKERROR(hr);
  365. ASSERT( !bRes == !GFX_bClipPlane);
  366. #endif
  367. // cached?
  368. if( GFX_bClipPlane && gap_bOptimizeStateChanges) return;
  369. GFX_bClipPlane = TRUE;
  370. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  371. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE, D3DCLIPPLANE0);
  372. D3D_CHECKERROR(hr);
  373. // (eventually) update clip plane, too
  374. UpdateClipPlane_D3D();
  375. // D3D needs to have clipping enabled for that matter
  376. if( !GFX_bClipping) {
  377. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_CLIPPING, TRUE);
  378. D3D_CHECKERROR(hr);
  379. GFX_bClipping = TRUE;
  380. _bWantsClipping = FALSE;
  381. }
  382. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  383. }
  384. static void d3d_DisableClipPlane(void)
  385. {
  386. // only if supported
  387. if( !(_pGfx->gl_ulFlags&GLF_D3D_CLIPPLANE)) return;
  388. // check consistency
  389. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  390. HRESULT hr;
  391. #ifndef NDEBUG
  392. BOOL bRes = GFX_bClipPlane;
  393. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_CLIPPLANEENABLE, (DWORD*)&bRes);
  394. D3D_CHECKERROR(hr);
  395. ASSERT( !bRes == !GFX_bClipPlane);
  396. #endif
  397. // cached?
  398. if( !GFX_bClipPlane && gap_bOptimizeStateChanges) return;
  399. GFX_bClipPlane = FALSE;
  400. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  401. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE, FALSE);
  402. D3D_CHECKERROR(hr);
  403. // maybe we can disable clipping in general (if was kept enabled just beacuse of clip plane)
  404. if( !_bWantsClipping && GFX_bClipping) {
  405. GFX_bClipping = FALSE;
  406. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_CLIPPING, FALSE);
  407. D3D_CHECKERROR(hr);
  408. }
  409. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  410. }
  411. static void d3d_EnableColorArray(void)
  412. {
  413. // check consistency
  414. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  415. HRESULT hr;
  416. #ifndef NDEBUG
  417. BOOL bRes;
  418. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_LIGHTING, (DWORD*)&bRes);
  419. D3D_CHECKERROR(hr);
  420. bRes = !bRes;
  421. ASSERT( !bRes == !GFX_bColorArray);
  422. #endif
  423. // cached?
  424. if( GFX_bColorArray && gap_bOptimizeStateChanges) return;
  425. GFX_bColorArray = TRUE;
  426. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  427. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE);
  428. D3D_CHECKERROR(hr);
  429. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  430. }
  431. // enable usage of constant color for subsequent rendering
  432. static void d3d_DisableColorArray(void)
  433. {
  434. // check consistency
  435. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  436. HRESULT hr;
  437. #ifndef NDEBUG
  438. BOOL bRes;
  439. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_LIGHTING, (DWORD*)&bRes);
  440. D3D_CHECKERROR(hr);
  441. bRes = !bRes;
  442. ASSERT( !bRes == !GFX_bColorArray);
  443. #endif
  444. // cached?
  445. if( !GFX_bColorArray && gap_bOptimizeStateChanges) return;
  446. GFX_bColorArray = FALSE;
  447. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  448. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_LIGHTING, TRUE);
  449. D3D_CHECKERROR(hr);
  450. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  451. }
  452. static void d3d_EnableTruform(void)
  453. {
  454. // skip if Truform isn't set
  455. if( truform_iLevel<1) return;
  456. // check consistency
  457. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  458. HRESULT hr;
  459. FLOAT fSegments;
  460. #ifndef NDEBUG
  461. BOOL bRes;
  462. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_PATCHSEGMENTS, (DWORD*)&fSegments);
  463. D3D_CHECKERROR(hr);
  464. bRes = (fSegments>1) ? TRUE : FALSE;
  465. ASSERT( !bRes == !GFX_bTruform);
  466. #endif
  467. if( GFX_bTruform && gap_bOptimizeStateChanges) return;
  468. GFX_bTruform = TRUE;
  469. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  470. fSegments = truform_iLevel+1;
  471. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_PATCHSEGMENTS, *((DWORD*)&fSegments));
  472. D3D_CHECKERROR(hr);
  473. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  474. }
  475. static void d3d_DisableTruform(void)
  476. {
  477. // skip if Truform isn't set
  478. if( truform_iLevel<1) return;
  479. // check consistency
  480. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  481. HRESULT hr;
  482. FLOAT fSegments;
  483. #ifndef NDEBUG
  484. BOOL bRes;
  485. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_PATCHSEGMENTS, (DWORD*)&fSegments);
  486. D3D_CHECKERROR(hr);
  487. bRes = (fSegments>1) ? TRUE : FALSE;
  488. ASSERT( !bRes == !GFX_bTruform);
  489. #endif
  490. if( !GFX_bTruform && gap_bOptimizeStateChanges) return;
  491. GFX_bTruform = FALSE;
  492. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  493. fSegments = 1.0f;
  494. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_PATCHSEGMENTS, *((DWORD*)&fSegments));
  495. D3D_CHECKERROR(hr);
  496. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  497. }
  498. __forceinline _D3DBLEND BlendToD3D( GfxBlend eFunc) {
  499. switch( eFunc) {
  500. case GFX_ZERO: return D3DBLEND_ZERO;
  501. case GFX_ONE: return D3DBLEND_ONE;
  502. case GFX_SRC_COLOR: return D3DBLEND_SRCCOLOR;
  503. case GFX_INV_SRC_COLOR: return D3DBLEND_INVSRCCOLOR;
  504. case GFX_DST_COLOR: return D3DBLEND_DESTCOLOR;
  505. case GFX_INV_DST_COLOR: return D3DBLEND_INVDESTCOLOR;
  506. case GFX_SRC_ALPHA: return D3DBLEND_SRCALPHA;
  507. case GFX_INV_SRC_ALPHA: return D3DBLEND_INVSRCALPHA;
  508. default: ASSERTALWAYS("Invalid GFX blending function!");
  509. } return D3DBLEND_ONE;
  510. }
  511. __forceinline GfxBlend BlendFromD3D( _D3DBLEND d3dbFunc) {
  512. switch( d3dbFunc) {
  513. case D3DBLEND_ZERO: return GFX_ZERO;
  514. case D3DBLEND_ONE: return GFX_ONE;
  515. case D3DBLEND_SRCCOLOR: return GFX_SRC_COLOR;
  516. case D3DBLEND_INVSRCCOLOR: return GFX_INV_SRC_COLOR;
  517. case D3DBLEND_DESTCOLOR: return GFX_DST_COLOR;
  518. case D3DBLEND_INVDESTCOLOR: return GFX_INV_DST_COLOR;
  519. case D3DBLEND_SRCALPHA: return GFX_SRC_ALPHA;
  520. case D3DBLEND_INVSRCALPHA: return GFX_INV_SRC_ALPHA;
  521. default: ASSERTALWAYS("Unsupported D3D blending function!");
  522. } return GFX_ONE;
  523. }
  524. // set blending operations
  525. static void d3d_BlendFunc( GfxBlend eSrc, GfxBlend eDst)
  526. {
  527. // check consistency
  528. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  529. HRESULT hr;
  530. #ifndef NDEBUG
  531. GfxBlend gfxSrc, gfxDst;
  532. _D3DBLEND d3dSrc, d3dDst;
  533. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_SRCBLEND, (DWORD*)&d3dSrc); D3D_CHECKERROR(hr);
  534. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_DESTBLEND, (DWORD*)&d3dDst); D3D_CHECKERROR(hr);
  535. gfxSrc = BlendFromD3D(d3dSrc);
  536. gfxDst = BlendFromD3D(d3dDst);
  537. ASSERT( gfxSrc==GFX_eBlendSrc && gfxDst==GFX_eBlendDst);
  538. #endif
  539. // cached?
  540. if( eSrc==GFX_eBlendSrc && eDst==GFX_eBlendDst && gap_bOptimizeStateChanges) return;
  541. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  542. if( eSrc!=GFX_eBlendSrc) {
  543. _D3DBLEND d3dSrc = BlendToD3D(eSrc);
  544. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_SRCBLEND, d3dSrc);
  545. D3D_CHECKERROR(hr);
  546. GFX_eBlendSrc = eSrc;
  547. }
  548. if( eDst!=GFX_eBlendDst) {
  549. _D3DBLEND d3dDst = BlendToD3D(eDst);
  550. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_DESTBLEND, d3dDst);
  551. D3D_CHECKERROR(hr);
  552. GFX_eBlendDst = eDst;
  553. }
  554. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  555. }
  556. static void d3d_SetColorMask( ULONG ulColorMask)
  557. {
  558. // only if supported
  559. _ulCurrentColorMask = ulColorMask; // keep for Get...()
  560. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  561. if( !(_pGfx->gl_ulFlags&GLF_D3D_COLORWRITES))
  562. { // emulate disabling of all channels
  563. if( ulColorMask==0) {
  564. d3d_EnableBlend();
  565. d3d_BlendFunc( GFX_ZERO, GFX_ONE);
  566. } // done
  567. return;
  568. }
  569. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  570. // no emulation
  571. ULONG ulBitMask = NONE;
  572. if( (ulColorMask&CT_RMASK) == CT_RMASK) ulBitMask |= D3DCOLORWRITEENABLE_RED;
  573. if( (ulColorMask&CT_GMASK) == CT_GMASK) ulBitMask |= D3DCOLORWRITEENABLE_GREEN;
  574. if( (ulColorMask&CT_BMASK) == CT_BMASK) ulBitMask |= D3DCOLORWRITEENABLE_BLUE;
  575. if( (ulColorMask&CT_AMASK) == CT_AMASK) ulBitMask |= D3DCOLORWRITEENABLE_ALPHA;
  576. HRESULT hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_COLORWRITEENABLE, ulBitMask);
  577. D3D_CHECKERROR(hr);
  578. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  579. }
  580. __forceinline _D3DCMPFUNC CompToD3D( GfxComp eFunc) {
  581. switch( eFunc) {
  582. case GFX_NEVER: return D3DCMP_NEVER;
  583. case GFX_LESS: return D3DCMP_LESS;
  584. case GFX_LESS_EQUAL: return D3DCMP_LESSEQUAL;
  585. case GFX_EQUAL: return D3DCMP_EQUAL;
  586. case GFX_NOT_EQUAL: return D3DCMP_NOTEQUAL;
  587. case GFX_GREATER_EQUAL: return D3DCMP_GREATEREQUAL;
  588. case GFX_GREATER: return D3DCMP_GREATER;
  589. case GFX_ALWAYS: return D3DCMP_ALWAYS;
  590. default: ASSERTALWAYS("Invalid GFX compare function!");
  591. } return D3DCMP_ALWAYS;
  592. }
  593. __forceinline GfxComp CompFromD3D( _D3DCMPFUNC d3dcFunc) {
  594. switch( d3dcFunc) {
  595. case D3DCMP_NEVER: return GFX_NEVER;
  596. case D3DCMP_LESS: return GFX_LESS;
  597. case D3DCMP_LESSEQUAL: return GFX_LESS_EQUAL;
  598. case D3DCMP_EQUAL: return GFX_EQUAL;
  599. case D3DCMP_NOTEQUAL: return GFX_NOT_EQUAL;
  600. case D3DCMP_GREATEREQUAL: return GFX_GREATER_EQUAL;
  601. case D3DCMP_GREATER: return GFX_GREATER;
  602. case D3DCMP_ALWAYS: return GFX_ALWAYS;
  603. default: ASSERTALWAYS("Invalid D3D compare function!");
  604. } return GFX_ALWAYS;
  605. }
  606. // set depth buffer compare mode
  607. static void d3d_DepthFunc( GfxComp eFunc)
  608. {
  609. // check consistency
  610. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  611. HRESULT hr;
  612. _D3DCMPFUNC d3dcFunc;
  613. #ifndef NDEBUG
  614. GfxComp gfxFunc;
  615. hr = _pGfx->gl_pd3dDevice->GetRenderState( D3DRS_ZFUNC, (DWORD*)&d3dcFunc);
  616. D3D_CHECKERROR(hr);
  617. gfxFunc = CompFromD3D( d3dcFunc);
  618. ASSERT( gfxFunc==GFX_eDepthFunc);
  619. #endif
  620. // cached?
  621. if( eFunc==GFX_eDepthFunc && gap_bOptimizeStateChanges) return;
  622. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  623. d3dcFunc = CompToD3D(eFunc);
  624. hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_ZFUNC, d3dcFunc);
  625. D3D_CHECKERROR(hr);
  626. GFX_eDepthFunc = eFunc;
  627. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  628. }
  629. // set depth buffer range
  630. static void d3d_DepthRange( FLOAT fMin, FLOAT fMax)
  631. {
  632. // D3D doesn't allow 0 for max value (no comment!)
  633. if( fMax<0.001f) fMax = 0.001f;
  634. // check consistency
  635. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  636. HRESULT hr;
  637. D3DVIEWPORT8 d3dViewport;
  638. #ifndef NDEBUG
  639. hr = _pGfx->gl_pd3dDevice->GetViewport( &d3dViewport);
  640. ASSERT( d3dViewport.MinZ==GFX_fMinDepthRange && d3dViewport.MaxZ==GFX_fMaxDepthRange);
  641. #endif
  642. // cached?
  643. if( GFX_fMinDepthRange==fMin && GFX_fMaxDepthRange==fMax && gap_bOptimizeStateChanges) return;
  644. GFX_fMinDepthRange = fMin;
  645. GFX_fMaxDepthRange = fMax;
  646. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  647. // get viewport
  648. hr = _pGfx->gl_pd3dDevice->GetViewport( &d3dViewport);
  649. D3D_CHECKERROR(hr);
  650. // update depth range and set the viewport back
  651. d3dViewport.MinZ = fMin;
  652. d3dViewport.MaxZ = fMax;
  653. hr = _pGfx->gl_pd3dDevice->SetViewport( &d3dViewport);
  654. D3D_CHECKERROR(hr);
  655. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  656. }
  657. static void d3d_CullFace( GfxFace eFace)
  658. {
  659. // check consistency and face
  660. ASSERT( eFace==GFX_FRONT || eFace==GFX_BACK || eFace==GFX_NONE);
  661. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  662. HRESULT hr;
  663. // must (re)assign faces for front-face emulation purposes
  664. GfxFace eFrontFace, eBackFace;
  665. if( GFX_bFrontFace) { eFrontFace = GFX_FRONT; eBackFace = GFX_BACK; }
  666. else { eFrontFace = GFX_BACK; eBackFace = GFX_FRONT; }
  667. // cached?
  668. if( gap_bOptimizeStateChanges) {
  669. if( GFX_eCullFace==D3DCULL_NONE && eFace==GFX_NONE) return;
  670. if( GFX_eCullFace==D3DCULL_CCW && eFace==eFrontFace) return;
  671. if( GFX_eCullFace==D3DCULL_CW && eFace==eBackFace) return;
  672. }
  673. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  674. if( eFace==eFrontFace) hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CCW);
  675. else if( eFace==eBackFace) hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_CW);
  676. else hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE);
  677. D3D_CHECKERROR(hr);
  678. GFX_eCullFace = eFace;
  679. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  680. }
  681. static void d3d_FrontFace( GfxFace eFace)
  682. {
  683. // check consistency and face
  684. ASSERT( eFace==GFX_CW || eFace==GFX_CCW);
  685. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  686. // cached?
  687. BOOL bFrontFace = (eFace==GFX_CCW);
  688. if( !bFrontFace==!GFX_bFrontFace && gap_bOptimizeStateChanges) return;
  689. // must emulate this by toggling cull face
  690. GFX_bFrontFace = bFrontFace;
  691. if( GFX_eCullFace!=GFX_NONE) d3d_CullFace(GFX_eCullFace);
  692. }
  693. static void d3d_ClipPlane( const DOUBLE *pdViewPlane)
  694. {
  695. // check API and plane
  696. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D && pdViewPlane!=NULL);
  697. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  698. // convert to floats, keep and update
  699. D3D_afClipPlane[0] = pdViewPlane[0];
  700. D3D_afClipPlane[1] = pdViewPlane[1];
  701. D3D_afClipPlane[2] = pdViewPlane[2];
  702. D3D_afClipPlane[3] = pdViewPlane[3];
  703. UpdateClipPlane_D3D();
  704. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  705. }
  706. static void d3d_SetTextureMatrix( const FLOAT *pfMatrix/*=NULL*/)
  707. {
  708. // check API
  709. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  710. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  711. HRESULT hr;
  712. D3DTRANSFORMSTATETYPE tsMatrixNo = (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + GFX_iActiveTexUnit);
  713. if( pfMatrix!=NULL) {
  714. hr = _pGfx->gl_pd3dDevice->SetTransform( tsMatrixNo, (_D3DMATRIX*)pfMatrix);
  715. } else {
  716. // load identity matrix
  717. extern const D3DMATRIX GFX_d3dIdentityMatrix;
  718. hr = _pGfx->gl_pd3dDevice->SetTransform( tsMatrixNo, &GFX_d3dIdentityMatrix);
  719. } // check
  720. D3D_CHECKERROR(hr);
  721. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  722. }
  723. static void d3d_SetViewMatrix( const FLOAT *pfMatrix/*=NULL*/)
  724. {
  725. // check API
  726. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  727. HRESULT hr;
  728. // cached? (only identity matrix)
  729. if( pfMatrix==NULL && GFX_bViewMatrix==NONE && gap_bOptimizeStateChanges) return;
  730. GFX_bViewMatrix = (pfMatrix!=NULL);
  731. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  732. if( pfMatrix!=NULL) {
  733. // need to keep it for clip plane
  734. CopyLongs( (ULONG*)pfMatrix, (ULONG*)D3D_afViewMatrix, 16);
  735. hr = _pGfx->gl_pd3dDevice->SetTransform( D3DTS_VIEW, (_D3DMATRIX*)D3D_afViewMatrix);
  736. } else {
  737. // load identity matrix
  738. extern const D3DMATRIX GFX_d3dIdentityMatrix;
  739. hr = _pGfx->gl_pd3dDevice->SetTransform( D3DTS_VIEW, &GFX_d3dIdentityMatrix);
  740. } // check
  741. D3D_CHECKERROR(hr);
  742. // update clip plane if enabled
  743. if( GFX_bClipPlane) UpdateClipPlane_D3D();
  744. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  745. }
  746. static void d3d_SetOrtho( const FLOAT fLeft, const FLOAT fRight, const FLOAT fTop,
  747. const FLOAT fBottom, const FLOAT fNear, const FLOAT fFar,
  748. const BOOL bSubPixelAdjust/*=FALSE*/)
  749. {
  750. // check API and matrix type
  751. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  752. // cached?
  753. if( GFX_fLastL==fLeft && GFX_fLastT==fTop && GFX_fLastN==fNear
  754. && GFX_fLastR==fRight && GFX_fLastB==fBottom && GFX_fLastF==fFar && gap_bOptimizeStateChanges) return;
  755. GFX_fLastL = fLeft; GFX_fLastT = fTop; GFX_fLastN = fNear;
  756. GFX_fLastR = fRight; GFX_fLastB = fBottom; GFX_fLastF = fFar;
  757. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  758. // adjust coords for sub-pixel precision
  759. // generate ortho matrix (+1 is because of sub-pixel adjustment!)
  760. FLOAT fAdj = bSubPixelAdjust ? 1 : 0;
  761. const FLOAT fRpL=fRight+fLeft+fAdj; const FLOAT fRmL=fRight-fLeft; const FLOAT fFpN=fFar+fNear;
  762. const FLOAT fTpB=fTop+fBottom+fAdj; const FLOAT fTmB=fTop-fBottom; const FLOAT fFmN=fFar-fNear;
  763. const FLOAT afMatrix[16] = { 2/fRmL, 0, 0, 0,
  764. 0, 2/fTmB, 0, 0,
  765. 0, 0, -1/fFmN, 0,
  766. -fRpL/fRmL, -fTpB/fTmB, -fNear/fFmN, 1 };
  767. HRESULT hr = _pGfx->gl_pd3dDevice->SetTransform( D3DTS_PROJECTION, (_D3DMATRIX*)afMatrix);
  768. D3D_CHECKERROR(hr);
  769. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  770. }
  771. static void d3d_SetFrustum( const FLOAT fLeft, const FLOAT fRight,
  772. const FLOAT fTop, const FLOAT fBottom,
  773. const FLOAT fNear, const FLOAT fFar)
  774. {
  775. // check API
  776. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  777. // cached?
  778. if( GFX_fLastL==-fLeft && GFX_fLastT==-fTop && GFX_fLastN==-fNear
  779. && GFX_fLastR==-fRight && GFX_fLastB==-fBottom && GFX_fLastF==-fFar && gap_bOptimizeStateChanges) return;
  780. GFX_fLastL = -fLeft; GFX_fLastT = -fTop; GFX_fLastN = -fNear;
  781. GFX_fLastR = -fRight; GFX_fLastB = -fBottom; GFX_fLastF = -fFar;
  782. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  783. // generate frustum matrix
  784. const FLOAT fRpL=fRight+fLeft; const FLOAT fTpB=fTop+fBottom; const FLOAT fFpN=fFar+fNear;
  785. const FLOAT fRmL=fRight-fLeft; const FLOAT fTmB=fTop-fBottom; const FLOAT fFmN=fFar-fNear;
  786. const FLOAT afMatrix[4][4] = {
  787. { 2*fNear/fRmL, 0, 0, 0 },
  788. { 0, 2*fNear/fTmB, 0, 0 },
  789. { fRpL/fRmL, fTpB/fTmB, -fFar/fFmN, -1 },
  790. { 0, 0, -fFar*fNear/fFmN, 0 }
  791. }; // set it
  792. HRESULT hr = _pGfx->gl_pd3dDevice->SetTransform( D3DTS_PROJECTION, (const _D3DMATRIX*)&afMatrix);
  793. D3D_CHECKERROR(hr);
  794. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  795. }
  796. static void d3d_PolygonMode( GfxPolyMode ePolyMode)
  797. {
  798. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  799. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  800. HRESULT hr;
  801. switch(ePolyMode) {
  802. case GFX_POINT: hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_POINT); break;
  803. case GFX_LINE: hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_WIREFRAME); break;
  804. case GFX_FILL: hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID); break;
  805. default: ASSERTALWAYS("Wrong polygon mode!");
  806. } // check
  807. D3D_CHECKERROR(hr);
  808. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  809. }
  810. // TEXTURE MANAGEMENT
  811. static void d3d_SetTextureWrapping( enum GfxWrap eWrapU, enum GfxWrap eWrapV)
  812. {
  813. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  814. HRESULT hr;
  815. #ifndef NDEBUG
  816. // check wrapping consistency
  817. D3DTEXTUREADDRESS d3dtaU, d3dtaV;
  818. hr = _pGfx->gl_pd3dDevice->GetTextureStageState( GFX_iActiveTexUnit, D3DTSS_ADDRESSU, (ULONG*)&d3dtaU); D3D_CHECKERROR(hr);
  819. hr = _pGfx->gl_pd3dDevice->GetTextureStageState( GFX_iActiveTexUnit, D3DTSS_ADDRESSV, (ULONG*)&d3dtaV); D3D_CHECKERROR(hr);
  820. ASSERT( (d3dtaU==D3DTADDRESS_WRAP && _tpGlobal[GFX_iActiveTexUnit].tp_eWrapU==GFX_REPEAT)
  821. || (d3dtaU==D3DTADDRESS_CLAMP && _tpGlobal[GFX_iActiveTexUnit].tp_eWrapU==GFX_CLAMP)
  822. || (_tpGlobal[GFX_iActiveTexUnit].tp_eWrapU==0));
  823. ASSERT( (d3dtaV==D3DTADDRESS_WRAP && _tpGlobal[GFX_iActiveTexUnit].tp_eWrapV==GFX_REPEAT)
  824. || (d3dtaV==D3DTADDRESS_CLAMP && _tpGlobal[GFX_iActiveTexUnit].tp_eWrapV==GFX_CLAMP)
  825. || (_tpGlobal[GFX_iActiveTexUnit].tp_eWrapV==0));
  826. #endif
  827. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  828. // adjust only those that differ
  829. if( _tpGlobal[GFX_iActiveTexUnit].tp_eWrapU!=eWrapU) {
  830. D3DTEXTUREADDRESS d3dta = (eWrapU==GFX_REPEAT) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP;
  831. hr = _pGfx->gl_pd3dDevice->SetTextureStageState( GFX_iActiveTexUnit, D3DTSS_ADDRESSU, d3dta);
  832. D3D_CHECKERROR(hr);
  833. _tpGlobal[GFX_iActiveTexUnit].tp_eWrapU = eWrapU;
  834. }
  835. if( _tpGlobal[GFX_iActiveTexUnit].tp_eWrapV!=eWrapV) {
  836. D3DTEXTUREADDRESS d3dta = (eWrapV==GFX_REPEAT) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP;
  837. hr = _pGfx->gl_pd3dDevice->SetTextureStageState( GFX_iActiveTexUnit, D3DTSS_ADDRESSV, d3dta);
  838. D3D_CHECKERROR(hr);
  839. _tpGlobal[GFX_iActiveTexUnit].tp_eWrapV = eWrapV;
  840. }
  841. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  842. }
  843. static void d3d_SetTextureModulation( INDEX iScale)
  844. {
  845. // check consistency
  846. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  847. HRESULT hr;
  848. #ifndef NDEBUG
  849. INDEX iRet;
  850. hr = _pGfx->gl_pd3dDevice->GetTextureStageState( GFX_iActiveTexUnit, D3DTSS_COLOROP, (DWORD*)&iRet);
  851. D3D_CHECKERROR(hr);
  852. if( iRet==D3DTOP_MODULATE2X) ASSERT( GFX_iTexModulation[GFX_iActiveTexUnit]==2);
  853. else if( iRet==D3DTOP_MODULATE) ASSERT( GFX_iTexModulation[GFX_iActiveTexUnit]==1);
  854. else ASSERT( iRet==D3DTOP_DISABLE);
  855. #endif
  856. // cached?
  857. ASSERT( iScale==1 || iScale==2);
  858. if( GFX_iTexModulation[GFX_iActiveTexUnit]==iScale) return;
  859. GFX_iTexModulation[GFX_iActiveTexUnit] = iScale;
  860. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  861. // set only if texturing is enabled - will be auto-set at gfxEnableTexture
  862. if( GFX_abTexture[GFX_iActiveTexUnit]) {
  863. D3DTEXTUREOP d3dTexOp = (iScale==2) ? D3DTOP_MODULATE2X : D3DTOP_MODULATE;
  864. hr = _pGfx->gl_pd3dDevice->SetTextureStageState( GFX_iActiveTexUnit, D3DTSS_COLOROP, d3dTexOp);
  865. D3D_CHECKERROR(hr);
  866. }
  867. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  868. }
  869. static void d3d_GenerateTexture( ULONG &ulTexObject)
  870. {
  871. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  872. _sfStats.StartTimer(CStatForm::STI_BINDTEXTURE);
  873. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  874. // generate one dummy texture that'll be entirely replaced upon 1st upload
  875. HRESULT hr = _pGfx->gl_pd3dDevice->CreateTexture( 1, 1, 0, 0, (D3DFORMAT)TS.ts_tfRGBA8, D3DPOOL_MANAGED, (LPDIRECT3DTEXTURE8*)&ulTexObject);
  876. D3D_CHECKERROR(hr);
  877. _sfStats.StopTimer(CStatForm::STI_BINDTEXTURE);
  878. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  879. }
  880. // unbind texture from API
  881. static void d3d_DeleteTexture( ULONG &ulTexObject)
  882. {
  883. // skip if already unbound
  884. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  885. if( ulTexObject==NONE) return;
  886. _sfStats.StartTimer(CStatForm::STI_BINDTEXTURE);
  887. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  888. D3DRELEASE( (LPDIRECT3DTEXTURE8&)ulTexObject, TRUE);
  889. ulTexObject = NONE;
  890. _sfStats.StopTimer(CStatForm::STI_BINDTEXTURE);
  891. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  892. }
  893. // VERTEX ARRAYS
  894. static void d3d_SetVertexArray( GFXVertex4 *pvtx, INDEX ctVtx)
  895. {
  896. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  897. ASSERT( ctVtx>0 && pvtx!=NULL && GFX_iActiveTexUnit==0);
  898. GFX_ctVertices = ctVtx;
  899. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  900. SetVertexArray_D3D( 0, (ULONG*)pvtx); // type 0 = vertices
  901. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  902. }
  903. static void d3d_SetNormalArray( GFXNormal *pnor)
  904. {
  905. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  906. ASSERT( pnor!=NULL);
  907. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  908. SetVertexArray_D3D( 1, (ULONG*)pnor); // type 1 = normals
  909. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  910. }
  911. static void d3d_SetColorArray( GFXColor *pcol)
  912. {
  913. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  914. ASSERT( pcol!=NULL);
  915. d3d_EnableColorArray();
  916. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  917. SetVertexArray_D3D( 2, (ULONG*)pcol); // type 2 = colors
  918. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  919. }
  920. static void d3d_SetTexCoordArray( GFXTexCoord *ptex, BOOL b4/*=FALSE*/)
  921. {
  922. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  923. ASSERT( ptex!=NULL);
  924. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  925. // type 3 = regular texture coordinates; type 4 = projective texture coordinates
  926. SetVertexArray_D3D( b4?4:3, (ULONG*)ptex);
  927. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  928. }
  929. static void d3d_SetConstantColor( COLOR col)
  930. {
  931. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  932. d3d_DisableColorArray();
  933. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  934. const ULONG d3dColor = rgba2argb(col);
  935. HRESULT hr = _pGfx->gl_pd3dDevice->SetRenderState( D3DRS_AMBIENT, d3dColor);
  936. D3D_CHECKERROR(hr);
  937. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  938. }
  939. static void d3d_DrawElements( INDEX ctElem, INDEX *pidx)
  940. {
  941. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  942. #ifndef NDEBUG
  943. // check if all indices are inside lock count (or smaller than 65536)
  944. if( pidx!=NULL) for( INDEX i=0; i<ctElem; i++) ASSERT( pidx[i] < GFX_ctVertices);
  945. #endif
  946. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  947. _pGfx->gl_ctTotalTriangles += ctElem/3; // for profiling
  948. ASSERT( pidx!=NULL);
  949. extern void DrawElements_D3D( INDEX ctElem, INDEX *pidx);
  950. DrawElements_D3D( ctElem, pidx);
  951. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  952. }
  953. // force finish of API rendering queue
  954. static void d3d_Finish(void)
  955. {
  956. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  957. _sfStats.StartTimer(CStatForm::STI_GFXAPI);
  958. // must "emulate" this by reading from back buffer :(
  959. HRESULT hr;
  960. D3DLOCKED_RECT rectLocked;
  961. LPDIRECT3DSURFACE8 pBackBuffer;
  962. // fetch back buffer (different for full screen and windowed mode)
  963. const BOOL bFullScreen = _pGfx->gl_ulFlags & GLF_FULLSCREEN;
  964. const RECT rectToLock = { 0,0, 1,1 };
  965. if( bFullScreen) hr = _pGfx->gl_pd3dDevice->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
  966. else hr = _pGfx->gl_pvpActive->vp_pSwapChain->GetBackBuffer( 0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
  967. if( hr==D3D_OK) {
  968. hr = pBackBuffer->LockRect( &rectLocked, &rectToLock, D3DLOCK_READONLY);
  969. if( hr==D3D_OK) pBackBuffer->UnlockRect();
  970. D3DRELEASE( pBackBuffer, TRUE);
  971. }
  972. _sfStats.StopTimer(CStatForm::STI_GFXAPI);
  973. }
  974. static void d3d_LockArrays(void)
  975. {
  976. // only for OpenGL
  977. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  978. ASSERT( GFX_ctVertices>0 && !_bCVAReallyLocked);
  979. }
  980. // SPECIAL FUNCTIONS FOR Direct3D ONLY !
  981. // set D3D vertex shader only if different than last time
  982. extern void d3dSetVertexShader( DWORD dwHandle)
  983. {
  984. ASSERT( _pGfx->gl_eCurrentAPI==GAT_D3D);
  985. if( _pGfx->gl_dwVertexShader==dwHandle) return;
  986. HRESULT hr = _pGfx->gl_pd3dDevice->SetVertexShader(dwHandle);
  987. D3D_CHECKERROR(hr);
  988. _pGfx->gl_dwVertexShader = dwHandle;
  989. }
  990. #endif // SE1_D3D