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.

360 lines
14 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) Microsoft Corporation, 2000.
  3. //
  4. // ctexfilt.cpp
  5. //
  6. // Direct3D Reference Device - Cube Texture Map Filtering
  7. //
  8. ///////////////////////////////////////////////////////////////////////////////
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. //-----------------------------------------------------------------------------
  12. //
  13. //-----------------------------------------------------------------------------
  14. void
  15. RefRast::ComputeCubeTextureFilter( int iStage, FLOAT fCrd[] )
  16. {
  17. #define POS_NX 1
  18. #define POS_NY 2
  19. #define POS_NZ 3
  20. #define NEG_NORM 4
  21. #define NEG_NX (NEG_NORM | POS_NX)
  22. #define NEG_NY (NEG_NORM | POS_NY)
  23. #define NEG_NZ (NEG_NORM | POS_NZ)
  24. // determine which map face the texture coordinate normal is facing
  25. UINT uMap;
  26. if ( fabs(fCrd[0]) > fabs(fCrd[1]) )
  27. {
  28. if ( fabs(fCrd[0]) > fabs(fCrd[2]) )
  29. uMap = POS_NX | ((fCrd[0] < 0.0) ? (NEG_NORM) : 0);
  30. else
  31. uMap = POS_NZ | ((fCrd[2] < 0.0) ? (NEG_NORM) : 0);
  32. }
  33. else
  34. {
  35. if ( fabs(fCrd[1]) > fabs(fCrd[2]) )
  36. uMap = POS_NY | ((fCrd[1] < 0.0) ? (NEG_NORM) : 0);
  37. else
  38. uMap = POS_NZ | ((fCrd[2] < 0.0) ? (NEG_NORM) : 0);
  39. }
  40. // munged texture coordinate and gradient info for cubemaps
  41. D3DCUBEMAP_FACES Face; // face index (0..5) to which normal is (mostly) pointing
  42. FLOAT fMajor; // coord in major direction
  43. FLOAT fMapCrd[2]; // coords into 2D map
  44. FLOAT fMajorGrad[2]; // dMajor/d(X,Y)
  45. FLOAT fMapGrad[2][2]; // d(U/Major,V/Major)/d(X,Y)
  46. #define _MapFaceParams( _Face, _IM, _bFlipM, _IU, _bFlipU, _IV, _bFlipV ) \
  47. { \
  48. Face = D3DCUBEMAP_FACE_##_Face; \
  49. fMajor = (_bFlipM) ? (-fCrd[_IM]) : ( fCrd[_IM]); \
  50. fMapCrd[0] = (_bFlipU) ? (-fCrd[_IU]) : ( fCrd[_IU]); \
  51. fMapCrd[1] = (_bFlipV) ? (-fCrd[_IV]) : ( fCrd[_IV]); \
  52. fMajorGrad[0] = m_TexCvg[iStage].fGradients[_IM][0]; if (_bFlipM) fMajorGrad[0] = -fMajorGrad[0]; \
  53. fMajorGrad[1] = m_TexCvg[iStage].fGradients[_IM][1]; if (_bFlipM) fMajorGrad[1] = -fMajorGrad[1]; \
  54. fMapGrad[0][0] = m_TexCvg[iStage].fGradients[_IU][0]; if (_bFlipU) fMapGrad[0][0] = -fMapGrad[0][0]; \
  55. fMapGrad[0][1] = m_TexCvg[iStage].fGradients[_IU][1]; if (_bFlipU) fMapGrad[0][1] = -fMapGrad[0][1]; \
  56. fMapGrad[1][0] = m_TexCvg[iStage].fGradients[_IV][0]; if (_bFlipV) fMapGrad[1][0] = -fMapGrad[1][0]; \
  57. fMapGrad[1][1] = m_TexCvg[iStage].fGradients[_IV][1]; if (_bFlipV) fMapGrad[1][1] = -fMapGrad[1][1]; \
  58. }
  59. switch (uMap)
  60. {
  61. case POS_NX: _MapFaceParams( POSITIVE_X, 0,0, 2,1, 1,1 ); break;
  62. case POS_NY: _MapFaceParams( POSITIVE_Y, 1,0, 0,0, 2,0 ); break;
  63. case POS_NZ: _MapFaceParams( POSITIVE_Z, 2,0, 0,0, 1,1 ); break;
  64. case NEG_NX: _MapFaceParams( NEGATIVE_X, 0,1, 2,0, 1,1 ); break;
  65. case NEG_NY: _MapFaceParams( NEGATIVE_Y, 1,1, 0,0, 2,1 ); break;
  66. case NEG_NZ: _MapFaceParams( NEGATIVE_Z, 2,1, 0,1, 1,1 ); break;
  67. }
  68. // compute gradients prior to normalizing map coords
  69. FLOAT fInvMajor = 1.F/fMajor;
  70. if ( m_TexFlt[iStage].CvgFilter != D3DTEXF_NONE )
  71. {
  72. // Compute d(U/Major)/dx, d(U/Major)/dy, d(V/Major)/dx, d(V/Major)/dy.
  73. //
  74. // i.e., for d(U/Major))/dx
  75. // Given: U' = unprojected U0 coord (fMapCrd[0])
  76. // U0 = U'/Major (fMapCrd[0]/fMajor)
  77. // U1 = (U' + dU'/dX)/(Major + dMajor/dX)
  78. //
  79. // d(U/Major)/dx = U1 - U0
  80. // = (Major*(dU'/dX) - U'*(dMajor/dX)) / (Major * (Major + dMajor/dX))
  81. // (Use FLT_MAX if denominator is zero)
  82. float fDenom;
  83. fDenom = fMajor * (fMajor + fMajorGrad[0]);
  84. if( 0 == fDenom )
  85. {
  86. fMapGrad[0][0] = fMapGrad[1][0] = FLT_MAX;
  87. }
  88. else
  89. {
  90. fDenom = 1.F/fDenom;
  91. fMapGrad[0][0] = (fMajor*fMapGrad[0][0] - fMapCrd[0]*fMajorGrad[0])*fDenom;
  92. fMapGrad[1][0] = (fMajor*fMapGrad[1][0] - fMapCrd[1]*fMajorGrad[0])*fDenom;
  93. }
  94. fDenom = fMajor * (fMajor + fMajorGrad[1]);
  95. if( 0 == fDenom )
  96. {
  97. fMapGrad[0][1] = fMapGrad[1][1] = FLT_MAX;
  98. }
  99. else
  100. {
  101. fDenom = 1.F/fDenom;
  102. fMapGrad[0][1] = (fMajor*fMapGrad[0][1] - fMapCrd[0]*fMajorGrad[1])*fDenom;
  103. fMapGrad[1][1] = (fMajor*fMapGrad[1][1] - fMapCrd[1]*fMajorGrad[1])*fDenom;
  104. }
  105. // scale gradients to texture LOD 0 size; scale by .5F to match coord scale below
  106. fMapGrad[0][0] *= m_pRD->m_pTexture[iStage]->m_fTexels[0][0]*.5F;
  107. fMapGrad[0][1] *= m_pRD->m_pTexture[iStage]->m_fTexels[0][0]*.5F;
  108. fMapGrad[1][0] *= m_pRD->m_pTexture[iStage]->m_fTexels[0][1]*.5F;
  109. fMapGrad[1][1] *= m_pRD->m_pTexture[iStage]->m_fTexels[0][1]*.5F;
  110. ComputeCubeCoverage( fMapGrad, m_TexCvg[iStage].fLOD );
  111. ComputePerLODControls( iStage );
  112. }
  113. // normalize map coords (-1. to 1. range), then map to 0. to 1.
  114. fMapCrd[0] = (fMapCrd[0]*fInvMajor)*.5F + .5F;
  115. fMapCrd[1] = (fMapCrd[1]*fInvMajor)*.5F + .5F;
  116. int iL;
  117. D3DTEXTUREFILTERTYPE Filter =
  118. m_TexCvg[iStage].bMagnify ? m_TexFlt[iStage].MagFilter : m_TexFlt[iStage].MinFilter;
  119. switch ( Filter )
  120. {
  121. default:
  122. case D3DTEXF_POINT:
  123. for ( iL = 0; iL < m_TexCvg[iStage].cLOD; iL++ )
  124. {
  125. m_TexFlt[iStage].pSamples[iL].iLOD = Face + 6*m_TexCvg[iStage].iLODMap[iL];
  126. m_TexFlt[iStage].pSamples[iL].fWgt = m_TexCvg[iStage].fLODFrc[iL];
  127. ComputePointSampleCoords( iStage, m_TexFlt[iStage].pSamples[iL].iLOD,
  128. fMapCrd, m_TexFlt[iStage].pSamples[iL].iCrd );
  129. m_TexFlt[iStage].cSamples++;
  130. }
  131. break;
  132. case D3DTEXF_LINEAR:
  133. for ( iL = 0; iL < m_TexCvg[iStage].cLOD; iL++ )
  134. {
  135. if ( 0 == m_TexCvg[iStage].iLODMap[iL] )
  136. {
  137. // TODO: correct sampling position near edges on map 0
  138. }
  139. INT32 iCrdMap[2][2];
  140. FLOAT fCrdFrc[2][2];
  141. ComputeLinearSampleCoords(
  142. iStage, 6*m_TexCvg[iStage].iLODMap[iL]+Face, fMapCrd,
  143. iCrdMap[0], iCrdMap[1], fCrdFrc[0], fCrdFrc[1] );
  144. SetUpCubeMapLinearSample( iStage, Face,
  145. 6*m_TexCvg[iStage].iLODMap[iL]+Face, m_TexCvg[iStage].fLODFrc[iL],
  146. iCrdMap, fCrdFrc );
  147. }
  148. break;
  149. }
  150. }
  151. //-----------------------------------------------------------------------------
  152. //
  153. //-----------------------------------------------------------------------------
  154. void
  155. RefRast::SetUpCubeMapLinearSample(
  156. int iStage, D3DCUBEMAP_FACES Face,
  157. INT32 iLODMap, FLOAT fLODScale,
  158. INT32 (*iCrd)[2], FLOAT (*fFrc)[2] )
  159. {
  160. int iC,iS;
  161. INT32 iCrdMax[2];
  162. iCrdMax[0] = m_pRD->m_pTexture[iStage]->m_cTexels[iLODMap][0] - 1;
  163. iCrdMax[1] = m_pRD->m_pTexture[iStage]->m_cTexels[iLODMap][1] - 1;
  164. // form flags indicating if sample coordinate is out in either direction
  165. UINT uOut[2][2] = { 0, 0, 0, 0, };
  166. for ( iC = 0; iC < 2; iC++ )
  167. {
  168. if ( iCrd[iC][0] < 0 ) uOut[iC][0] = 1;
  169. if ( iCrd[iC][0] > iCrdMax[0] ) uOut[iC][0] = 2;
  170. if ( iCrd[iC][1] < 0 ) uOut[iC][1] = 1;
  171. if ( iCrd[iC][1] > iCrdMax[1] ) uOut[iC][1] = 2;
  172. }
  173. // compute sample weights and per-sample out flags
  174. FLOAT fWgtS[4]; BOOL bOutS[4];
  175. for ( iS = 0; iS < 4; iS ++ )
  176. {
  177. fWgtS[iS] = fLODScale*fFrc[iS&1][0]*fFrc[iS>>1][1];
  178. bOutS[iS] = uOut[iS&1][0] || uOut[iS>>1][1];
  179. }
  180. // compute per-sample coords; discard samples which are off in corner;
  181. // conditionally remap to adjacent face
  182. INT32 iCrdS[4][2];
  183. D3DCUBEMAP_FACES FaceS[4];
  184. for ( iS = 0; iS < 4; iS ++ )
  185. {
  186. iCrdS[iS][0] = iCrd[iS&1][0];
  187. iCrdS[iS][1] = iCrd[iS>>1][1];
  188. FaceS[iS] = Face;
  189. if ( uOut[iS&1][0] && uOut[iS>>1][1] )
  190. {
  191. // sample is out on both sides, so don't take this sample (set weight to
  192. // zero) and divide it's weight evenly between the two singly-out samples
  193. FLOAT fWgtDist = fWgtS[iS]*.5f;
  194. fWgtS[iS] = 0.f;
  195. for ( int iSp = 0; iSp < 4; iSp ++ )
  196. {
  197. if (iSp == iS) continue;
  198. if (bOutS[iSp]) fWgtS[iSp] += fWgtDist; // will hit 2 of 4
  199. }
  200. continue;
  201. }
  202. if ( bOutS[iS] )
  203. {
  204. // sample is out on one side - remap coordinate only adjacent face
  205. DoCubeRemap( iCrdS[iS], iCrdMax, FaceS[iS], uOut[iS&1][0], uOut[iS>>1][1] );
  206. }
  207. }
  208. // form the samples
  209. TextureSample* pS = &m_TexFlt[iStage].pSamples[m_TexFlt[iStage].cSamples];
  210. for ( iS = 0; iS < 4; iS ++ )
  211. {
  212. pS->iLOD = iLODMap - Face + FaceS[iS];
  213. pS->fWgt = fWgtS[iS];
  214. pS->iCrd[0] = iCrdS[iS][0];
  215. pS->iCrd[1] = iCrdS[iS][1];
  216. pS++; m_TexFlt[iStage].cSamples++;
  217. }
  218. }
  219. //
  220. // uCubeEdgeTable
  221. //
  222. // This table looks up how to map a given [0] and [1] that are out of range
  223. // on their primary face. The first (leftmost) index to the table is the current
  224. // face. The second index is 0 if [1] is in range, 1 if [1] is negative
  225. // and 2 if [1] is larger than the texture. Likewise, the last index is 0
  226. // if [0] is in range, 1 if [0] is negative, and 2 if [0] is larger than
  227. // than the texture.
  228. //
  229. // defines for the actions returned by the uCubeEdgeTable
  230. //
  231. #define CET_FACEMASK 0x0F // new face
  232. #define CET_0MASK 0x30 // coord [0] mask
  233. #define CET_00 0x00 // new face [0] is old face [0]
  234. #define CET_0c0 0x10 // new face [0] is old face ~[0]
  235. #define CET_01 0x20 // new face [0] is old face [1]
  236. #define CET_0c1 0x30 // new face [0] is old face ~[1]
  237. #define CET_1MASK 0xC0 // coord [1] mask
  238. #define CET_10 0x00 // new face [1] is old face [0]
  239. #define CET_1c0 0x40 // new face [1] is old face ~[0]
  240. #define CET_11 0x80 // new face [1] is old face [1]
  241. #define CET_1c1 0xC0 // new face [1] is old face ~[1]
  242. #define CET_INVALID 0xFF // invalid entry (out on two sides)
  243. #define _SetCET( _Face, _Crd0, _Crd1 ) (_Face)|(CET_0##_Crd0)|(CET_1##_Crd1)
  244. static UINT CubeEdgeTable[6][3][3] = {
  245. {
  246. { _SetCET( 0, 0, 1 ), _SetCET( 4, c0, 1 ), _SetCET( 5, c0, 1 ), },
  247. { _SetCET( 2, c1, c0 ), CET_INVALID, CET_INVALID, },
  248. { _SetCET( 3, 1, 0 ), CET_INVALID, CET_INVALID, },
  249. },
  250. {
  251. { _SetCET( 1, 0, 1 ), _SetCET( 5, c0, 1 ), _SetCET( 4, c0, 1 ), },
  252. { _SetCET( 2, 1, 0 ), CET_INVALID, CET_INVALID, },
  253. { _SetCET( 3, c1, c0 ), CET_INVALID, CET_INVALID, },
  254. },
  255. {
  256. { _SetCET( 2, 0, 1 ), _SetCET( 1, 1, 0 ), _SetCET( 0, c1, c0 ), },
  257. { _SetCET( 5, c0, 1 ), CET_INVALID, CET_INVALID, },
  258. { _SetCET( 4, 0, c1 ), CET_INVALID, CET_INVALID, },
  259. },
  260. {
  261. { _SetCET( 3, 0, 1 ), _SetCET( 1, c1, c0 ), _SetCET( 0, 1, 0 ), },
  262. { _SetCET( 4, 0, c1 ), CET_INVALID, CET_INVALID, },
  263. { _SetCET( 5, c0, 1 ), CET_INVALID, CET_INVALID, },
  264. },
  265. {
  266. { _SetCET( 4, 0, 1 ), _SetCET( 1, c0, 1 ), _SetCET( 0, c0, 1 ), },
  267. { _SetCET( 2, 0, c1 ), CET_INVALID, CET_INVALID, },
  268. { _SetCET( 3, 0, c1 ), CET_INVALID, CET_INVALID, },
  269. },
  270. {
  271. { _SetCET( 5, 0, 1 ), _SetCET( 0, c0, 1 ), _SetCET( 1, c0, 1 ), },
  272. { _SetCET( 2, c0, 1 ), CET_INVALID, CET_INVALID, },
  273. { _SetCET( 3, c0, 1 ), CET_INVALID, CET_INVALID, },
  274. },
  275. };
  276. //-----------------------------------------------------------------------------
  277. //
  278. // DoCubeRemap - Interprets the edge table and munges coords and face.
  279. //
  280. //-----------------------------------------------------------------------------
  281. void
  282. DoCubeRemap(
  283. INT32 iCrd[], INT32 iCrdMax[],
  284. D3DCUBEMAP_FACES& Face, UINT uOut0, UINT uOut1)
  285. {
  286. UINT Table = CubeEdgeTable[Face][uOut1][uOut0];
  287. _ASSERT( Table != CET_INVALID, "Illegal cube map lookup" );
  288. INT32 iCrdIn[2];
  289. iCrdIn[0] = iCrd[0];
  290. iCrdIn[1] = iCrd[1];
  291. switch ( Table & CET_0MASK )
  292. {
  293. default:
  294. case CET_00: iCrd[0] = iCrdIn[0]; break;
  295. case CET_0c0: iCrd[0] = iCrdMax[0]-iCrdIn[0]; break;
  296. case CET_01: iCrd[0] = iCrdIn[1]; break;
  297. case CET_0c1: iCrd[0] = iCrdMax[1]-iCrdIn[1]; break;
  298. }
  299. switch ( Table & CET_1MASK )
  300. {
  301. default:
  302. case CET_10: iCrd[1] = iCrdIn[0]; break;
  303. case CET_1c0: iCrd[1] = iCrdMax[0]-iCrdIn[0]; break;
  304. case CET_11: iCrd[1] = iCrdIn[1]; break;
  305. case CET_1c1: iCrd[1] = iCrdMax[1]-iCrdIn[1]; break;
  306. }
  307. Face = (D3DCUBEMAP_FACES)(Table & CET_FACEMASK);
  308. }
  309. //-----------------------------------------------------------------------------
  310. //
  311. // Computes level of detail for cube mapping, looks better if
  312. // we err on the side of fuzziness.
  313. //
  314. //-----------------------------------------------------------------------------
  315. void
  316. ComputeCubeCoverage( const FLOAT (*fGradients)[2], FLOAT& fLOD )
  317. {
  318. // compute length of coverage in U and V axis
  319. FLOAT fLenX = RR_LENGTH( fGradients[0][0], fGradients[1][0] );
  320. FLOAT fLenY = RR_LENGTH( fGradients[0][1], fGradients[1][1] );
  321. FLOAT fCoverage;
  322. #if 0
  323. // take average since one length can be pathologically small
  324. // for large areas of triangles when cube mapping
  325. fCoverage = (fLenX+fLenY)/2;
  326. #else
  327. // use the MAX of the lengths
  328. fCoverage = MAX(fLenX,fLenY);
  329. #endif
  330. // take log2 of coverage for LOD
  331. fLOD = RR_LOG2(fCoverage);
  332. }
  333. ///////////////////////////////////////////////////////////////////////////////
  334. // end