Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

514 lines
15 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // d3dutil.cpp
  4. //
  5. // Miscellanous utility functions.
  6. //
  7. // Copyright (C) Microsoft Corporation, 1997.
  8. //
  9. //----------------------------------------------------------------------------
  10. #include "pch.cpp"
  11. #pragma hdrstop
  12. #include <span.h>
  13. #include "cppdbg.hpp"
  14. DBG_DECLARE_FILE();
  15. // Declare TextureDiff as an out-of-line function.
  16. FLOAT FASTCALL
  17. TextureDiff(FLOAT fTb, FLOAT fTa, INT iMode)
  18. #include <texdiff.h>
  19. //----------------------------------------------------------------------------
  20. //
  21. // DebugBreakFn
  22. //
  23. // Stub function that should never be called. Prints a warning and
  24. // DebugBreaks. Can be inserted in any function table, although it
  25. // will destroy the stack frame with callconv or argument mismatch.
  26. // That's OK since if it's called something has gone wrong.
  27. //
  28. //----------------------------------------------------------------------------
  29. void FASTCALL
  30. DebugBreakFn(void)
  31. {
  32. GDPF(("!! DebugBreakFn called. Leaving this function may destroy\n"));
  33. GDPF((" the stack frame. !!\n"));
  34. DebugBreak();
  35. }
  36. //----------------------------------------------------------------------------
  37. //
  38. // OctagonNorm
  39. //
  40. // Returns a good approximation to sqrt(fX*fX + fY*fY)
  41. //
  42. //----------------------------------------------------------------------------
  43. FLOAT FASTCALL
  44. OctagonNorm(FLOAT fX, FLOAT fY)
  45. {
  46. fX = ABSF(fX);
  47. fY = ABSF(fY);
  48. return ((11.0f/32.0f)*(fX + fY) + (21.0f/32.0f)*max(fX, fY));
  49. }
  50. //----------------------------------------------------------------------------
  51. //
  52. // ComputeLOD
  53. //
  54. // Computes mipmap level for the given W by deriving U and V and
  55. // then computing LOD from the dU and dV gradients.
  56. //
  57. //----------------------------------------------------------------------------
  58. INT FASTCALL
  59. ComputeLOD(PCD3DI_RASTCTX pCtx,
  60. FLOAT fU, FLOAT fV, FLOAT fW,
  61. FLOAT fDUoWDX, FLOAT fDVoWDX, FLOAT fDOoWDX,
  62. FLOAT fDUoWDY, FLOAT fDVoWDY, FLOAT fDOoWDY)
  63. {
  64. // Compute coverage gradients.
  65. FLOAT fDUDX = ABSF(fW * (fDUoWDX - fU * fDOoWDX));
  66. FLOAT fDUDY = ABSF(fW * (fDUoWDY - fU * fDOoWDY));
  67. FLOAT fDVDX = ABSF(fW * (fDVoWDX - fV * fDOoWDX));
  68. FLOAT fDVDY = ABSF(fW * (fDVoWDY - fV * fDOoWDY));
  69. // Scale gradients to texture LOD 0 size.
  70. fDUDX *= (FLOAT)pCtx->pTexture[0]->iSizeU;
  71. fDUDY *= (FLOAT)pCtx->pTexture[0]->iSizeU;
  72. fDVDX *= (FLOAT)pCtx->pTexture[0]->iSizeV;
  73. fDVDY *= (FLOAT)pCtx->pTexture[0]->iSizeV;
  74. // Determine pixel coverage value to use.
  75. FLOAT fCoverage;
  76. // too fuzzy
  77. #ifdef COVERAGE_MAXGRAD
  78. fCoverage = max(fDUDX, fDUDY);
  79. fCoverage = max(fCoverage, fDVDX);
  80. fCoverage = max(fCoverage, fDVDY);
  81. #endif
  82. // too sharp, in particular, for aligned cases, fCoverage is always 0
  83. // which leads to iLOD of LOD_MIN regardless of orientation
  84. #ifdef COVERAGE_MINGRAD
  85. fCoverage = min(fDUDX, fDUDY);
  86. fCoverage = min(fCoverage, fDVDX);
  87. fCoverage = min(fCoverage, fDVDY);
  88. #endif
  89. #ifdef COVERAGE_AVERAGE
  90. // use OctagonNorm to approximate each length of parallelogram
  91. // approximating texture coverage, and arithmetically average those to
  92. // get the coverage.
  93. fCoverage = (OctagonNorm(fDUDX, fDVDX) + OctagonNorm(fDUDY, fDVDY))/2.0f;
  94. #endif
  95. #define MAX_LEN 1
  96. #ifdef MAX_LEN
  97. // use OctagonNorm to approximate each length of parallelogram
  98. // approximating texture coverage, and take the max of each length
  99. // like classic OpenGL and the current RefRast implementation
  100. fCoverage = max(OctagonNorm(fDUDX, fDVDX), OctagonNorm(fDUDY, fDVDY));
  101. #endif
  102. // Compute approximate log2 of coverage.
  103. FLOAT fLOD = APPXLG2F(fCoverage);
  104. // Apply LOD bias.
  105. fLOD += pCtx->pTexture[0]->fLODBias;
  106. INT iLOD = FTOI(fLOD * LOD_SCALE);
  107. // Clamp to available levels. Not clamped to zero so that the span
  108. // code can check for magnification cases with a sign check.
  109. iLOD = min(iLOD, pCtx->pTexture[0]->iMaxScaledLOD);
  110. return max(LOD_MIN, iLOD);
  111. }
  112. //----------------------------------------------------------------------------
  113. //
  114. // ComputeTableFog
  115. //
  116. // Computes table fog values based on render state and the given Z.
  117. // ATTENTION - Brute force for non-linear modes. Should be optimized
  118. // to use a table-based approximation.
  119. //
  120. //----------------------------------------------------------------------------
  121. UINT FASTCALL
  122. ComputeTableFog(PDWORD pdwRenderState,
  123. FLOAT fZ)
  124. {
  125. double dPow;
  126. switch(pdwRenderState[D3DRENDERSTATE_FOGTABLEMODE])
  127. {
  128. case D3DFOG_LINEAR:
  129. {
  130. FLOAT fFogStart = ASFLOAT(pdwRenderState[D3DRENDERSTATE_FOGSTART]);
  131. FLOAT fFogEnd = ASFLOAT(pdwRenderState[D3DRENDERSTATE_FOGEND]);
  132. if (fZ >= fFogEnd)
  133. {
  134. return 0;
  135. }
  136. if (fZ <= fFogStart)
  137. {
  138. return FTOI(FOG_ONE_SCALE-1.0F);
  139. }
  140. return FTOI(((fFogEnd - fZ) / (fFogEnd - fFogStart)) * (FOG_ONE_SCALE-1.0F));
  141. }
  142. case D3DFOG_EXP:
  143. dPow = (double)
  144. (ASFLOAT(pdwRenderState[D3DRENDERSTATE_FOGDENSITY]) * fZ);
  145. // note that exp(-x) returns a result in the range (0.0, 1.0]
  146. // for x >= 0
  147. dPow = exp(-dPow);
  148. return FTOI((FLOAT)dPow * (FOG_ONE_SCALE-1.0F));
  149. case D3DFOG_EXP2:
  150. dPow = (double)
  151. (ASFLOAT(pdwRenderState[D3DRENDERSTATE_FOGDENSITY]) * fZ);
  152. dPow = exp(-dPow * dPow);
  153. return FTOI((FLOAT)dPow * (FOG_ONE_SCALE-1.0F));
  154. }
  155. GASSERTMSG(FALSE, ("ComputeTableFog unreachable\n"));
  156. return 0;
  157. }
  158. //----------------------------------------------------------------------------
  159. //
  160. // pVecNormalize2
  161. //
  162. // Normalizes the given D3DVECTOR. Supports in-place operation.
  163. //
  164. //----------------------------------------------------------------------------
  165. void FASTCALL
  166. pVecNormalize2(LPD3DVECTOR pVec, LPD3DVECTOR pRes)
  167. {
  168. FLOAT fLen;
  169. fLen = pVecLenSq(pVec);
  170. if (FLOAT_CMP_POS(fLen, <=, g_fNearZero))
  171. {
  172. pVecSet(pRes, 0.0f, 0.0f, 0.0f);
  173. return;
  174. }
  175. fLen = ISQRTF(fLen);
  176. pVecScale(pVec, fLen, pRes);
  177. }
  178. //-----------------------------------------------------------------------------
  179. //
  180. // IntLog2
  181. //
  182. // Do a quick, integer log2 for exact powers of 2.
  183. //
  184. //-----------------------------------------------------------------------------
  185. UINT32 FASTCALL
  186. IntLog2(UINT32 x)
  187. {
  188. UINT32 y = 0;
  189. x >>= 1;
  190. while(x != 0)
  191. {
  192. x >>= 1;
  193. y++;
  194. }
  195. return y;
  196. }
  197. //---------------------------------------------------------------------
  198. // Builds normalized plane equations going through 3 points
  199. //
  200. // Returns:
  201. // 0 - if success
  202. // -1 - if can not build plane
  203. //
  204. int MakePlane(D3DVECTOR *v1, D3DVECTOR *v2, D3DVECTOR *v3, D3DVECTORH *plane)
  205. {
  206. D3DVECTOR a;
  207. D3DVECTOR b;
  208. pVecSub(v2, v1, &a);
  209. pVecSub(v3, v1, &b);
  210. plane->x = a.y*b.z - a.z*b.y;
  211. plane->y = a.z*b.x - a.x*b.z;
  212. plane->z = a.x*b.y - a.y*b.x;
  213. plane->w = - pVecDot(v1, plane);
  214. double tmp = pVecDot(plane, plane);
  215. if (tmp <= 0)
  216. return -1;
  217. tmp = 1.0/sqrt(tmp);
  218. plane->x = (D3DVALUE)(plane->x * tmp);
  219. plane->y = (D3DVALUE)(plane->y * tmp);
  220. plane->z = (D3DVALUE)(plane->z * tmp);
  221. plane->w = (D3DVALUE)(plane->w * tmp);
  222. return 0;
  223. }
  224. //---------------------------------------------------------------------
  225. // This function uses Cramer's Rule to calculate the matrix inverse.
  226. // See nt\private\windows\opengl\serever\soft\so_math.c
  227. //
  228. // Returns:
  229. // 0 - if success
  230. // -1 - if input matrix is singular
  231. //
  232. int Inverse4x4(D3DMATRIX *src, D3DMATRIX *inverse)
  233. {
  234. double x00, x01, x02;
  235. double x10, x11, x12;
  236. double x20, x21, x22;
  237. double rcp;
  238. double x30, x31, x32;
  239. double y01, y02, y03, y12, y13, y23;
  240. double z02, z03, z12, z13, z22, z23, z32, z33;
  241. #define x03 x01
  242. #define x13 x11
  243. #define x23 x21
  244. #define x33 x31
  245. #define z00 x02
  246. #define z10 x12
  247. #define z20 x22
  248. #define z30 x32
  249. #define z01 x03
  250. #define z11 x13
  251. #define z21 x23
  252. #define z31 x33
  253. /* read 1st two columns of matrix into registers */
  254. x00 = src->_11;
  255. x01 = src->_12;
  256. x10 = src->_21;
  257. x11 = src->_22;
  258. x20 = src->_31;
  259. x21 = src->_32;
  260. x30 = src->_41;
  261. x31 = src->_42;
  262. /* compute all six 2x2 determinants of 1st two columns */
  263. y01 = x00*x11 - x10*x01;
  264. y02 = x00*x21 - x20*x01;
  265. y03 = x00*x31 - x30*x01;
  266. y12 = x10*x21 - x20*x11;
  267. y13 = x10*x31 - x30*x11;
  268. y23 = x20*x31 - x30*x21;
  269. /* read 2nd two columns of matrix into registers */
  270. x02 = src->_13;
  271. x03 = src->_14;
  272. x12 = src->_23;
  273. x13 = src->_24;
  274. x22 = src->_33;
  275. x23 = src->_34;
  276. x32 = src->_43;
  277. x33 = src->_44;
  278. /* compute all 3x3 cofactors for 2nd two columns */
  279. z33 = x02*y12 - x12*y02 + x22*y01;
  280. z23 = x12*y03 - x32*y01 - x02*y13;
  281. z13 = x02*y23 - x22*y03 + x32*y02;
  282. z03 = x22*y13 - x32*y12 - x12*y23;
  283. z32 = x13*y02 - x23*y01 - x03*y12;
  284. z22 = x03*y13 - x13*y03 + x33*y01;
  285. z12 = x23*y03 - x33*y02 - x03*y23;
  286. z02 = x13*y23 - x23*y13 + x33*y12;
  287. /* compute all six 2x2 determinants of 2nd two columns */
  288. y01 = x02*x13 - x12*x03;
  289. y02 = x02*x23 - x22*x03;
  290. y03 = x02*x33 - x32*x03;
  291. y12 = x12*x23 - x22*x13;
  292. y13 = x12*x33 - x32*x13;
  293. y23 = x22*x33 - x32*x23;
  294. /* read 1st two columns of matrix into registers */
  295. x00 = src->_11;
  296. x01 = src->_12;
  297. x10 = src->_21;
  298. x11 = src->_22;
  299. x20 = src->_31;
  300. x21 = src->_32;
  301. x30 = src->_41;
  302. x31 = src->_42;
  303. /* compute all 3x3 cofactors for 1st column */
  304. z30 = x11*y02 - x21*y01 - x01*y12;
  305. z20 = x01*y13 - x11*y03 + x31*y01;
  306. z10 = x21*y03 - x31*y02 - x01*y23;
  307. z00 = x11*y23 - x21*y13 + x31*y12;
  308. /* compute 4x4 determinant & its reciprocal */
  309. rcp = x30*z30 + x20*z20 + x10*z10 + x00*z00;
  310. if (rcp == (float)0)
  311. return -1;
  312. rcp = (float)1/rcp;
  313. /* compute all 3x3 cofactors for 2nd column */
  314. z31 = x00*y12 - x10*y02 + x20*y01;
  315. z21 = x10*y03 - x30*y01 - x00*y13;
  316. z11 = x00*y23 - x20*y03 + x30*y02;
  317. z01 = x20*y13 - x30*y12 - x10*y23;
  318. /* multiply all 3x3 cofactors by reciprocal */
  319. inverse->_11 = (float)(z00*rcp);
  320. inverse->_21 = (float)(z01*rcp);
  321. inverse->_12 = (float)(z10*rcp);
  322. inverse->_31 = (float)(z02*rcp);
  323. inverse->_13 = (float)(z20*rcp);
  324. inverse->_41 = (float)(z03*rcp);
  325. inverse->_14 = (float)(z30*rcp);
  326. inverse->_22 = (float)(z11*rcp);
  327. inverse->_32 = (float)(z12*rcp);
  328. inverse->_23 = (float)(z21*rcp);
  329. inverse->_42 = (float)(z13*rcp);
  330. inverse->_24 = (float)(z31*rcp);
  331. inverse->_33 = (float)(z22*rcp);
  332. inverse->_43 = (float)(z23*rcp);
  333. inverse->_34 = (float)(z32*rcp);
  334. inverse->_44 = (float)(z33*rcp);
  335. return 0;
  336. }
  337. //---------------------------------------------------------------------
  338. #define MATRIX_PRODUCT(res, a, b) \
  339. res->_11 = a->_11*b->_11 + a->_12*b->_21 + a->_13*b->_31 + a->_14*b->_41; \
  340. res->_12 = a->_11*b->_12 + a->_12*b->_22 + a->_13*b->_32 + a->_14*b->_42; \
  341. res->_13 = a->_11*b->_13 + a->_12*b->_23 + a->_13*b->_33 + a->_14*b->_43; \
  342. res->_14 = a->_11*b->_14 + a->_12*b->_24 + a->_13*b->_34 + a->_14*b->_44; \
  343. \
  344. res->_21 = a->_21*b->_11 + a->_22*b->_21 + a->_23*b->_31 + a->_24*b->_41; \
  345. res->_22 = a->_21*b->_12 + a->_22*b->_22 + a->_23*b->_32 + a->_24*b->_42; \
  346. res->_23 = a->_21*b->_13 + a->_22*b->_23 + a->_23*b->_33 + a->_24*b->_43; \
  347. res->_24 = a->_21*b->_14 + a->_22*b->_24 + a->_23*b->_34 + a->_24*b->_44; \
  348. \
  349. res->_31 = a->_31*b->_11 + a->_32*b->_21 + a->_33*b->_31 + a->_34*b->_41; \
  350. res->_32 = a->_31*b->_12 + a->_32*b->_22 + a->_33*b->_32 + a->_34*b->_42; \
  351. res->_33 = a->_31*b->_13 + a->_32*b->_23 + a->_33*b->_33 + a->_34*b->_43; \
  352. res->_34 = a->_31*b->_14 + a->_32*b->_24 + a->_33*b->_34 + a->_34*b->_44; \
  353. \
  354. res->_41 = a->_41*b->_11 + a->_42*b->_21 + a->_43*b->_31 + a->_44*b->_41; \
  355. res->_42 = a->_41*b->_12 + a->_42*b->_22 + a->_43*b->_32 + a->_44*b->_42; \
  356. res->_43 = a->_41*b->_13 + a->_42*b->_23 + a->_43*b->_33 + a->_44*b->_43; \
  357. res->_44 = a->_41*b->_14 + a->_42*b->_24 + a->_43*b->_34 + a->_44*b->_44;
  358. //---------------------------------------------------------------------
  359. // result = a*b
  360. // result is the same as a or b
  361. //
  362. void MatrixProduct2(D3DMATRIX *result, D3DMATRIX *a, D3DMATRIX *b)
  363. {
  364. D3DMATRIX res;
  365. MATRIX_PRODUCT((&res), a, b);
  366. *result = res;
  367. }
  368. //---------------------------------------------------------------------
  369. // result = a*b.
  370. // "result" pointer could be equal to "a" or "b"
  371. //
  372. void MatrixProduct(D3DMATRIX *result, D3DMATRIX *a, D3DMATRIX *b)
  373. {
  374. if (result == a || result == b)
  375. {
  376. MatrixProduct2(result, a, b);
  377. return;
  378. }
  379. MATRIX_PRODUCT(result, a, b);
  380. }
  381. //---------------------------------------------------------------------
  382. // Checks the FVF flags for errors and returns the stride in bytes between
  383. // vertices.
  384. //
  385. // Returns:
  386. // HRESULT and stride in bytes between vertices
  387. //
  388. //---------------------------------------------------------------------
  389. HRESULT FASTCALL
  390. FVFCheckAndStride(DWORD dwFVF, DWORD* pdwStride)
  391. {
  392. if (NULL == pdwStride)
  393. {
  394. return DDERR_INVALIDPARAMS;
  395. }
  396. if ( (dwFVF & (D3DFVF_RESERVED0 | D3DFVF_RESERVED2 |
  397. D3DFVF_NORMAL)) ||
  398. ((dwFVF & (D3DFVF_XYZ | D3DFVF_XYZRHW)) == 0) )
  399. {
  400. // can't set reserved bits, shouldn't have normals in
  401. // output to rasterizers, and must have coordinates
  402. return DDERR_INVALIDPARAMS;
  403. }
  404. DWORD dwStride;
  405. if (dwFVF != D3DFVF_TLVERTEX)
  406. { // New (non TL)FVF vertex
  407. // XYZ
  408. dwStride = sizeof(D3DVALUE) * 3;
  409. if (dwFVF & D3DFVF_XYZRHW)
  410. {
  411. dwStride += sizeof(D3DVALUE);
  412. }
  413. if (dwFVF & D3DFVF_PSIZE)
  414. {
  415. dwStride += sizeof(D3DVALUE);
  416. }
  417. if (dwFVF & D3DFVF_DIFFUSE)
  418. {
  419. dwStride += sizeof(D3DCOLOR);
  420. }
  421. if (dwFVF & D3DFVF_SPECULAR)
  422. {
  423. dwStride += sizeof(D3DCOLOR);
  424. }
  425. INT iTexCount = (dwFVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
  426. for (INT i = 0; i < iTexCount; i++)
  427. {
  428. switch (D3DFVF_GETTEXCOORDSIZE(dwFVF, i))
  429. {
  430. case D3DFVF_TEXTUREFORMAT2: dwStride += sizeof(D3DVALUE) * 2; break;
  431. case D3DFVF_TEXTUREFORMAT1: dwStride += sizeof(D3DVALUE) * 1; break;
  432. case D3DFVF_TEXTUREFORMAT3: dwStride += sizeof(D3DVALUE) * 3; break;
  433. case D3DFVF_TEXTUREFORMAT4: dwStride += sizeof(D3DVALUE) * 4; break;
  434. }
  435. }
  436. }
  437. else
  438. { // (Legacy) TL vertex
  439. dwStride = sizeof(D3DTLVERTEX);
  440. }
  441. *pdwStride = dwStride;
  442. return D3D_OK;
  443. }
  444. //---------------------------------------------------------------------
  445. // Gets the value from DIRECT3D registry key
  446. // Returns TRUE if success
  447. // If fails value is not changed
  448. //
  449. BOOL GetD3DRegValue(DWORD type, char *valueName, LPVOID value, DWORD dwSize)
  450. {
  451. HKEY hKey = (HKEY) NULL;
  452. if (ERROR_SUCCESS == RegOpenKey(HKEY_LOCAL_MACHINE, RESPATH_D3D, &hKey))
  453. {
  454. DWORD dwType;
  455. LONG result;
  456. result = RegQueryValueEx(hKey, valueName, NULL, &dwType,
  457. (LPBYTE)value, &dwSize);
  458. RegCloseKey(hKey);
  459. return result == ERROR_SUCCESS && dwType == type;
  460. }
  461. else
  462. return FALSE;
  463. }