Leaked source code of windows server 2003
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.

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