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.

612 lines
25 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) Microsoft Corporation, 2000.
  3. //
  4. // texfilt.cpp
  5. //
  6. // Direct3D Reference Device - Texture Map Filtering Methods
  7. //
  8. ///////////////////////////////////////////////////////////////////////////////
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. void
  12. RefRast::UpdateTextureControls( void )
  13. {
  14. for (int iStage=0; iStage<m_pRD->m_cActiveTextureStages; iStage++)
  15. {
  16. // check for requirement to do level-of-detail (coverage) computation - either
  17. // for mipmap or per-pixel filter selection
  18. BOOL bComputeLOD =
  19. ( m_pRD->GetTSS(iStage)[D3DTSS_MIPFILTER] == D3DTEXF_POINT ) ||
  20. ( m_pRD->GetTSS(iStage)[D3DTSS_MIPFILTER] == D3DTEXF_LINEAR ) ||
  21. ( m_pRD->GetTSS(iStage)[D3DTSS_MAGFILTER] != m_pRD->GetTSS(iStage)[D3DTSS_MINFILTER] );
  22. // check for anisotropic filtering in either mag filter or in min filter
  23. BOOL bDoAniso =
  24. ( D3DTEXF_ANISOTROPIC == m_pRD->GetTSS(iStage)[D3DTSS_MAGFILTER] ) ||
  25. ( bComputeLOD && (D3DTEXF_ANISOTROPIC == m_pRD->GetTSS(iStage)[D3DTSS_MINFILTER]) );
  26. // compute filter type for coverage computation
  27. if (bDoAniso) m_TexFlt[iStage].CvgFilter = D3DTEXF_ANISOTROPIC;
  28. else if (bComputeLOD) m_TexFlt[iStage].CvgFilter = D3DTEXF_LINEAR;
  29. else m_TexFlt[iStage].CvgFilter = D3DTEXF_NONE;
  30. // compute filter type for magnify (also used for non-LOD case)
  31. switch ( m_pRD->GetTSS(iStage)[D3DTSS_MAGFILTER] )
  32. {
  33. default:
  34. case D3DTEXF_POINT: m_TexFlt[iStage].MagFilter = D3DTEXF_POINT; break;
  35. case D3DTEXF_FLATCUBIC:
  36. case D3DTEXF_GAUSSIANCUBIC:
  37. case D3DTEXF_LINEAR: m_TexFlt[iStage].MagFilter = D3DTEXF_LINEAR; break;
  38. case D3DTEXF_ANISOTROPIC: m_TexFlt[iStage].MagFilter = D3DTEXF_ANISOTROPIC; break;
  39. }
  40. // compute filter type(s) for minify
  41. switch ( m_pRD->GetTSS(iStage)[D3DTSS_MINFILTER] )
  42. {
  43. default:
  44. case D3DTEXF_POINT: m_TexFlt[iStage].MinFilter = D3DTEXF_POINT; break;
  45. case D3DTEXF_LINEAR: m_TexFlt[iStage].MinFilter = D3DTEXF_LINEAR; break;
  46. case D3DTEXF_ANISOTROPIC: m_TexFlt[iStage].MinFilter = D3DTEXF_ANISOTROPIC; break;
  47. }
  48. switch ( m_pRD->GetTSS(iStage)[D3DTSS_MIPFILTER] )
  49. {
  50. default:
  51. case D3DTEXF_NONE: m_TexFlt[iStage].MipFilter = D3DTEXF_NONE; break;
  52. case D3DTEXF_POINT: m_TexFlt[iStage].MipFilter = D3DTEXF_POINT; break;
  53. case D3DTEXF_LINEAR: m_TexFlt[iStage].MipFilter = D3DTEXF_LINEAR; break;
  54. }
  55. // set default state
  56. m_TexCvg[iStage].fLOD = 0.f;
  57. m_TexCvg[iStage].iLOD = 0;
  58. m_TexCvg[iStage].iLODMap[0] = 0;
  59. m_TexCvg[iStage].iLODMap[1] = 0;
  60. m_TexCvg[iStage].fLODFrc[0] = 1.f;
  61. m_TexCvg[iStage].fLODFrc[1] = 1.f;
  62. m_TexCvg[iStage].bMagnify = FALSE;
  63. m_TexCvg[iStage].cLOD = 1;
  64. }
  65. }
  66. //
  67. // called once per each set of 2x2 samples
  68. //
  69. void
  70. RefRast::ComputeTextureCoverage( int iStage, FLOAT (*fGradients)[2] )
  71. {
  72. if ( !m_pRD->m_pTexture[iStage] ) return;
  73. if ( m_pRD->m_pTexture[iStage]->m_uFlags & RR_TEXTURE_CUBEMAP )
  74. {
  75. // store gradients for cubemaps
  76. memcpy( m_TexCvg[iStage].fGradients, fGradients, 3*2*sizeof(FLOAT) );
  77. return;
  78. }
  79. if ( D3DTEXF_NONE == m_TexFlt[iStage].CvgFilter ) return;
  80. // scale gradients to texture LOD 0 size
  81. for (int iD=0; iD < m_pRD->m_pTexture[iStage]->m_cDimension; iD++ )
  82. {
  83. fGradients[iD][0] *= m_pRD->m_pTexture[iStage]->m_fTexels[0][iD];
  84. fGradients[iD][1] *= m_pRD->m_pTexture[iStage]->m_fTexels[0][iD];
  85. }
  86. if ( (m_TexFlt[iStage].CvgFilter == D3DTEXF_ANISOTROPIC) &&
  87. (m_pRD->m_pTexture[iStage]->m_cDimension == 2) ) // do aniso for 2D textures only
  88. {
  89. ComputeAnisoCoverage( fGradients, MIN( 16.f, (FLOAT)m_pRD->GetTSS(iStage)[D3DTSS_MAXANISOTROPY]),
  90. m_TexCvg[iStage].fLOD, m_TexCvg[iStage].fAnisoRatio, m_TexCvg[iStage].fAnisoLine );
  91. }
  92. else
  93. {
  94. ComputeMipCoverage( fGradients, m_TexCvg[iStage].fLOD, m_pRD->m_pTexture[iStage]->m_cDimension );
  95. m_TexCvg[iStage].fAnisoRatio = 1.f;
  96. }
  97. ComputePerLODControls( iStage );
  98. }
  99. //
  100. // called by ComputeTextureCoverage and ComputeCubeTextureFilter
  101. //
  102. void
  103. RefRast::ComputePerLODControls( int iStage )
  104. {
  105. m_TexCvg[iStage].fLOD += m_pRD->GetTSSf(iStage)[D3DTSS_MIPMAPLODBIAS];
  106. m_TexCvg[iStage].iLOD = AS_INT16( m_TexCvg[iStage].fLOD + FLOAT_5_SNAP );
  107. m_TexCvg[iStage].bMagnify = (m_TexCvg[iStage].iLOD <= 0);
  108. m_TexCvg[iStage].cLOD = 1;
  109. m_TexCvg[iStage].fLODFrc[0] = 1.f;
  110. if ( m_TexCvg[iStage].bMagnify || ( m_TexFlt[iStage].MipFilter == D3DTEXF_NONE ) )
  111. {
  112. m_TexCvg[iStage].iLODMap[0] = 0;
  113. // clamp to max LOD
  114. m_TexCvg[iStage].iLODMap[0] = MAX( m_TexCvg[iStage].iLODMap[0], (INT32)m_pRD->GetTSS(iStage)[D3DTSS_MAXMIPLEVEL] );
  115. // clamp to available maps
  116. m_TexCvg[iStage].iLODMap[0] = MIN( m_TexCvg[iStage].iLODMap[0], (INT32)m_pRD->m_pTexture[iStage]->m_cLOD );
  117. }
  118. else if ( m_TexFlt[iStage].MipFilter == D3DTEXF_POINT )
  119. {
  120. // round and truncate (add .5 and shift off fractional bits)
  121. m_TexCvg[iStage].iLODMap[0] = (m_TexCvg[iStage].iLOD + (1<<(RRTEX_LODFRAC-1))) >> RRTEX_LODFRAC;
  122. // clamp to max LOD
  123. m_TexCvg[iStage].iLODMap[0] = MAX( m_TexCvg[iStage].iLODMap[0], (INT32)m_pRD->GetTSS(iStage)[D3DTSS_MAXMIPLEVEL] );
  124. // clamp to available maps
  125. m_TexCvg[iStage].iLODMap[0] = MIN( m_TexCvg[iStage].iLODMap[0], (INT32)m_pRD->m_pTexture[iStage]->m_cLOD );
  126. }
  127. else // mip filter D3DTEXF_LINEAR
  128. {
  129. // compute index for two adjacent LODs
  130. m_TexCvg[iStage].iLODMap[0] = m_TexCvg[iStage].iLOD >> RRTEX_LODFRAC; // floor
  131. m_TexCvg[iStage].iLODMap[1] = m_TexCvg[iStage].iLODMap[0] + 1;
  132. // clamp to max LOD
  133. m_TexCvg[iStage].iLODMap[0] = MAX( m_TexCvg[iStage].iLODMap[0], (INT32)m_pRD->GetTSS(iStage)[D3DTSS_MAXMIPLEVEL] );
  134. m_TexCvg[iStage].iLODMap[1] = MAX( m_TexCvg[iStage].iLODMap[1], (INT32)m_pRD->GetTSS(iStage)[D3DTSS_MAXMIPLEVEL] );
  135. // clamp to available maps
  136. m_TexCvg[iStage].iLODMap[0] = MIN( m_TexCvg[iStage].iLODMap[0], (INT32)m_pRD->m_pTexture[iStage]->m_cLOD );
  137. m_TexCvg[iStage].iLODMap[1] = MIN( m_TexCvg[iStage].iLODMap[1], (INT32)m_pRD->m_pTexture[iStage]->m_cLOD );
  138. // check that both maps actually contribute to texel
  139. if ( (m_TexCvg[iStage].iLODMap[0] != m_TexCvg[iStage].iLODMap[1]) &&
  140. (m_TexCvg[iStage].iLOD & RRTEX_LODFRACMASK) )
  141. {
  142. m_TexCvg[iStage].fLODFrc[1] = (FLOAT)(m_TexCvg[iStage].iLOD & RRTEX_LODFRACMASK) * RRTEX_LODFRACF;
  143. m_TexCvg[iStage].fLODFrc[0] = 1.f - m_TexCvg[iStage].fLODFrc[1];
  144. m_TexCvg[iStage].cLOD = 2;
  145. }
  146. }
  147. }
  148. void
  149. RefRast::ComputePointSampleCoords(
  150. int iStage, INT32 iLOD, FLOAT fCrd[],
  151. INT32 iCrd[] )
  152. {
  153. for (int iD=0; iD<m_pRD->m_pTexture[iStage]->m_cDimension; iD++)
  154. {
  155. FLOAT fScaledCrd =
  156. ( fCrd[iD] * m_pRD->m_pTexture[iStage]->m_fTexels[iLOD][iD] ) - .5f;
  157. // truncate to -infinity to be compatible with ANDing off low order
  158. // bits of a fixed point fScaledCoord. This makes the generation of
  159. // iCoord more hardware like, and does not make a glitch at 0 for
  160. // a wrapped texture.
  161. if ( fCrd[iD] >= 0.f ) iCrd[iD] = (INT32)( fScaledCrd + .5f );
  162. else iCrd[iD] = (INT32)( fScaledCrd - .5f );
  163. }
  164. }
  165. void
  166. RefRast::ComputeLinearSampleCoords(
  167. int iStage, INT32 iLOD, FLOAT fCrd[],
  168. INT32 iCrdFlr[], INT32 iCrdClg[], FLOAT fCrdFrcF[], FLOAT fCrdFrcC[] )
  169. {
  170. for (int iD=0; iD<m_pRD->m_pTexture[iStage]->m_cDimension; iD++)
  171. {
  172. FLOAT fScaledCrd =
  173. ( fCrd[iD] * m_pRD->m_pTexture[iStage]->m_fTexels[iLOD][iD] ) - .5f;
  174. INT32 iCrd = FloatToNdot5(fScaledCrd);
  175. iCrdFlr[iD] = iCrd >> RRTEX_MAPFRAC;
  176. iCrdClg[iD] = iCrdFlr[iD] + 1;
  177. fCrdFrcC[iD] = (FLOAT)(iCrd & RRTEX_MAPFRACMASK) * RRTEX_MAPFRACF;
  178. fCrdFrcF[iD] = 1.f - fCrdFrcC[iD];
  179. }
  180. }
  181. void
  182. RefRast::SetUp1DTextureSample(
  183. int iStage, int Start,
  184. INT32 iLODMap, FLOAT fLODScale,
  185. INT32 iCrdF, INT32 iCrdC,
  186. FLOAT fCrdFrcF, FLOAT fCrdFrcC )
  187. {
  188. m_TexFlt[iStage].pSamples[Start+0].iLOD = iLODMap;
  189. m_TexFlt[iStage].pSamples[Start+1].iLOD = iLODMap;
  190. m_TexFlt[iStage].pSamples[Start+0].iCrd[0] = iCrdF;
  191. m_TexFlt[iStage].pSamples[Start+1].iCrd[0] = iCrdC;
  192. m_TexFlt[iStage].pSamples[Start+0].fWgt = fCrdFrcF*fLODScale;
  193. m_TexFlt[iStage].pSamples[Start+1].fWgt = fCrdFrcC*fLODScale;
  194. }
  195. #define _Set2( _DstAr, _Src0, _Src1 ) \
  196. _DstAr[0] = _Src0; _DstAr[1] = _Src1;
  197. void
  198. RefRast::SetUp2DTextureSample(
  199. int iStage, int Start,
  200. INT32 iLODMap, FLOAT fLODScale,
  201. INT32 iCrdF[], INT32 iCrdC[],
  202. FLOAT fCrdFrcF[], FLOAT fCrdFrcC[] )
  203. {
  204. m_TexFlt[iStage].pSamples[Start+0].iLOD = iLODMap;
  205. m_TexFlt[iStage].pSamples[Start+1].iLOD = iLODMap;
  206. m_TexFlt[iStage].pSamples[Start+2].iLOD = iLODMap;
  207. m_TexFlt[iStage].pSamples[Start+3].iLOD = iLODMap;
  208. _Set2( m_TexFlt[iStage].pSamples[Start+0].iCrd, iCrdF[0], iCrdF[1] )
  209. _Set2( m_TexFlt[iStage].pSamples[Start+1].iCrd, iCrdC[0], iCrdF[1] )
  210. _Set2( m_TexFlt[iStage].pSamples[Start+2].iCrd, iCrdC[0], iCrdC[1] )
  211. _Set2( m_TexFlt[iStage].pSamples[Start+3].iCrd, iCrdF[0], iCrdC[1] )
  212. m_TexFlt[iStage].pSamples[Start+0].fWgt = fCrdFrcF[0] * fCrdFrcF[1] * fLODScale;
  213. m_TexFlt[iStage].pSamples[Start+1].fWgt = fCrdFrcC[0] * fCrdFrcF[1] * fLODScale;
  214. m_TexFlt[iStage].pSamples[Start+2].fWgt = fCrdFrcC[0] * fCrdFrcC[1] * fLODScale;
  215. m_TexFlt[iStage].pSamples[Start+3].fWgt = fCrdFrcF[0] * fCrdFrcC[1] * fLODScale;
  216. }
  217. #define _Set3( _DstAr, _Src0, _Src1, _Src2 ) \
  218. _DstAr[0] = _Src0; _DstAr[1] = _Src1; _DstAr[2] = _Src2;
  219. void
  220. RefRast::SetUp3DTextureSample(
  221. int iStage, int Start,
  222. INT32 iLODMap, FLOAT fLODScale,
  223. INT32 iCrdF[], INT32 iCrdC[],
  224. FLOAT fCrdFrcF[], FLOAT fCrdFrcC[] )
  225. {
  226. m_TexFlt[iStage].pSamples[Start+0].iLOD = iLODMap;
  227. m_TexFlt[iStage].pSamples[Start+1].iLOD = iLODMap;
  228. m_TexFlt[iStage].pSamples[Start+2].iLOD = iLODMap;
  229. m_TexFlt[iStage].pSamples[Start+3].iLOD = iLODMap;
  230. m_TexFlt[iStage].pSamples[Start+4].iLOD = iLODMap;
  231. m_TexFlt[iStage].pSamples[Start+5].iLOD = iLODMap;
  232. m_TexFlt[iStage].pSamples[Start+6].iLOD = iLODMap;
  233. m_TexFlt[iStage].pSamples[Start+7].iLOD = iLODMap;
  234. m_TexFlt[iStage].pSamples[Start+0].fWgt = fCrdFrcF[0] * fCrdFrcF[1] * fCrdFrcF[2] * fLODScale;
  235. m_TexFlt[iStage].pSamples[Start+1].fWgt = fCrdFrcC[0] * fCrdFrcF[1] * fCrdFrcF[2] * fLODScale;
  236. m_TexFlt[iStage].pSamples[Start+2].fWgt = fCrdFrcC[0] * fCrdFrcC[1] * fCrdFrcF[2] * fLODScale;
  237. m_TexFlt[iStage].pSamples[Start+3].fWgt = fCrdFrcF[0] * fCrdFrcC[1] * fCrdFrcF[2] * fLODScale;
  238. m_TexFlt[iStage].pSamples[Start+4].fWgt = fCrdFrcF[0] * fCrdFrcF[1] * fCrdFrcC[2] * fLODScale;
  239. m_TexFlt[iStage].pSamples[Start+5].fWgt = fCrdFrcC[0] * fCrdFrcF[1] * fCrdFrcC[2] * fLODScale;
  240. m_TexFlt[iStage].pSamples[Start+6].fWgt = fCrdFrcC[0] * fCrdFrcC[1] * fCrdFrcC[2] * fLODScale;
  241. m_TexFlt[iStage].pSamples[Start+7].fWgt = fCrdFrcF[0] * fCrdFrcC[1] * fCrdFrcC[2] * fLODScale;
  242. _Set3( m_TexFlt[iStage].pSamples[Start+0].iCrd, iCrdF[0], iCrdF[1], iCrdF[2] )
  243. _Set3( m_TexFlt[iStage].pSamples[Start+1].iCrd, iCrdC[0], iCrdF[1], iCrdF[2] )
  244. _Set3( m_TexFlt[iStage].pSamples[Start+2].iCrd, iCrdC[0], iCrdC[1], iCrdF[2] )
  245. _Set3( m_TexFlt[iStage].pSamples[Start+3].iCrd, iCrdF[0], iCrdC[1], iCrdF[2] )
  246. _Set3( m_TexFlt[iStage].pSamples[Start+4].iCrd, iCrdF[0], iCrdF[1], iCrdC[2] )
  247. _Set3( m_TexFlt[iStage].pSamples[Start+5].iCrd, iCrdC[0], iCrdF[1], iCrdC[2] )
  248. _Set3( m_TexFlt[iStage].pSamples[Start+6].iCrd, iCrdC[0], iCrdC[1], iCrdC[2] )
  249. _Set3( m_TexFlt[iStage].pSamples[Start+7].iCrd, iCrdF[0], iCrdC[1], iCrdC[2] )
  250. }
  251. //
  252. // called once for each pixel
  253. //
  254. void
  255. RefRast::ComputeTextureFilter( int iStage, FLOAT fCrd[] )
  256. {
  257. m_TexFlt[iStage].cSamples = 0;
  258. if ( !m_pRD->m_pTexture[iStage] ) return;
  259. if ( m_pRD->m_pTexture[iStage]->m_uFlags & RR_TEXTURE_CUBEMAP )
  260. {
  261. ComputeCubeTextureFilter( iStage, fCrd );
  262. return;
  263. }
  264. // here for 1,2,3D texture
  265. int iL,iD;
  266. #define _PerDimension(_Par) for (_Par=0;_Par<m_pRD->m_pTexture[iStage]->m_cDimension;_Par++)
  267. D3DTEXTUREFILTERTYPE Filter =
  268. m_TexCvg[iStage].bMagnify ? m_TexFlt[iStage].MagFilter : m_TexFlt[iStage].MinFilter;
  269. switch ( Filter )
  270. {
  271. default:
  272. case D3DTEXF_POINT:
  273. for ( iL = 0; iL < m_TexCvg[iStage].cLOD; iL++ )
  274. {
  275. m_TexFlt[iStage].pSamples[m_TexFlt[iStage].cSamples].iLOD = m_TexCvg[iStage].iLODMap[iL];
  276. m_TexFlt[iStage].pSamples[m_TexFlt[iStage].cSamples].fWgt = m_TexCvg[iStage].fLODFrc[iL];
  277. ComputePointSampleCoords( iStage, m_TexCvg[iStage].iLODMap[iL], fCrd,
  278. m_TexFlt[iStage].pSamples[m_TexFlt[iStage].cSamples].iCrd );
  279. m_TexFlt[iStage].cSamples++;
  280. }
  281. break;
  282. case D3DTEXF_LINEAR:
  283. for ( iL = 0; iL < m_TexCvg[iStage].cLOD; iL++ )
  284. {
  285. INT32 iCrdFlr[3], iCrdClg[3];
  286. FLOAT fCrdFrcF[3], fCrdFrcC[3];
  287. ComputeLinearSampleCoords(
  288. iStage, m_TexCvg[iStage].iLODMap[iL], fCrd,
  289. iCrdFlr, iCrdClg, fCrdFrcF, fCrdFrcC );
  290. switch ( m_pRD->m_pTexture[iStage]->m_cDimension )
  291. {
  292. default:
  293. case 1:
  294. SetUp1DTextureSample( iStage, m_TexFlt[iStage].cSamples, m_TexCvg[iStage].iLODMap[iL], m_TexCvg[iStage].fLODFrc[iL],
  295. iCrdFlr[0], iCrdClg[0], fCrdFrcF[0], fCrdFrcC[0] );
  296. m_TexFlt[iStage].cSamples += 2;
  297. break;
  298. case 2:
  299. SetUp2DTextureSample( iStage, m_TexFlt[iStage].cSamples, m_TexCvg[iStage].iLODMap[iL], m_TexCvg[iStage].fLODFrc[iL],
  300. iCrdFlr, iCrdClg, fCrdFrcF, fCrdFrcC );
  301. m_TexFlt[iStage].cSamples += 4;
  302. break;
  303. case 3:
  304. SetUp3DTextureSample( iStage, m_TexFlt[iStage].cSamples, m_TexCvg[iStage].iLODMap[iL], m_TexCvg[iStage].fLODFrc[iL],
  305. iCrdFlr, iCrdClg, fCrdFrcF, fCrdFrcC );
  306. m_TexFlt[iStage].cSamples += 8;
  307. break;
  308. }
  309. }
  310. break;
  311. case D3DTEXF_ANISOTROPIC:
  312. for ( iL = 0; iL < m_TexCvg[iStage].cLOD; iL++ )
  313. {
  314. FLOAT fStepScale[3];
  315. fStepScale[0] = 1.f/m_pRD->m_pTexture[iStage]->m_fTexels[m_TexCvg[iStage].iLODMap[iL]][0];
  316. fStepScale[1] = 1.f/m_pRD->m_pTexture[iStage]->m_fTexels[m_TexCvg[iStage].iLODMap[iL]][1];
  317. fStepScale[2] = 0.f;
  318. FLOAT fUnitStep[3];
  319. _PerDimension(iD) { fUnitStep[iD] = fStepScale[iD]*m_TexCvg[iStage].fAnisoLine[iD]; }
  320. int cAnisoSamples;
  321. FLOAT fACrd[16][3];
  322. FLOAT fAScale[16];
  323. if ( m_TexCvg[iStage].fAnisoRatio <= 1.f )
  324. {
  325. // just like mip D3DTEXF_LINEAR
  326. cAnisoSamples = 1; fAScale[0] = 1.f;
  327. _PerDimension(iD) { fACrd[0][iD] = fCrd[iD]; }
  328. }
  329. else if ( m_TexCvg[iStage].fAnisoRatio <= 2.f )
  330. {
  331. // take two sets of samples and average
  332. cAnisoSamples = 2; fAScale[0] = fAScale[1] = .5f;
  333. FLOAT fStepSize = .5f*(m_TexCvg[iStage].fAnisoRatio - 1.f);
  334. _PerDimension(iD)
  335. {
  336. FLOAT fStep = fStepSize*fUnitStep[iD];
  337. fACrd[0][iD] = fCrd[iD] + fStep;
  338. fACrd[1][iD] = fCrd[iD] - fStep;
  339. }
  340. }
  341. else
  342. {
  343. // walk line of anisotropy in both directions from center point
  344. FLOAT fInvRatio = 1.f/m_TexCvg[iStage].fAnisoRatio;
  345. FLOAT fRatioRemainder = m_TexCvg[iStage].fAnisoRatio;
  346. // start steps centered 1/2 away
  347. _PerDimension(iD)
  348. {
  349. fACrd[0][iD] = fCrd[iD] + fUnitStep[iD]*.5f;
  350. fACrd[1][iD] = fCrd[iD] - fUnitStep[iD]*.5f;
  351. }
  352. cAnisoSamples = 0;
  353. do
  354. {
  355. fAScale[cAnisoSamples+0] = fInvRatio;
  356. fAScale[cAnisoSamples+1] = fInvRatio;
  357. if ( fRatioRemainder < 2.f )
  358. {
  359. fAScale[cAnisoSamples+0] *= .5f*fRatioRemainder;
  360. fAScale[cAnisoSamples+1] *= .5f*fRatioRemainder;
  361. }
  362. if ( fRatioRemainder > 2.f )
  363. {
  364. _PerDimension(iD)
  365. {
  366. fACrd[cAnisoSamples+2][iD] = fACrd[cAnisoSamples+0][iD] + fUnitStep[iD];
  367. fACrd[cAnisoSamples+3][iD] = fACrd[cAnisoSamples+1][iD] - fUnitStep[iD];
  368. }
  369. }
  370. cAnisoSamples += 2;
  371. fRatioRemainder -= 2.f;
  372. }
  373. while ( fRatioRemainder > 0.f );
  374. }
  375. for ( int iS = 0; iS < cAnisoSamples; iS ++ )
  376. {
  377. INT32 iCrdFlr[3], iCrdClg[3];
  378. FLOAT fCrdFrcF[3], fCrdFrcC[3];
  379. ComputeLinearSampleCoords(
  380. iStage, m_TexCvg[iStage].iLODMap[iL], fACrd[iS],
  381. iCrdFlr, iCrdClg, fCrdFrcF, fCrdFrcC );
  382. FLOAT fSampleScale = fAScale[iS]*m_TexCvg[iStage].fLODFrc[iL];
  383. switch ( m_pRD->m_pTexture[iStage]->m_cDimension )
  384. {
  385. default:
  386. case 1:
  387. SetUp1DTextureSample( iStage, m_TexFlt[iStage].cSamples, m_TexCvg[iStage].iLODMap[iL], fSampleScale,
  388. iCrdFlr[0], iCrdClg[0], fCrdFrcF[0], fCrdFrcC[0] );
  389. m_TexFlt[iStage].cSamples += 2;
  390. break;
  391. case 2:
  392. SetUp2DTextureSample( iStage, m_TexFlt[iStage].cSamples, m_TexCvg[iStage].iLODMap[iL], fSampleScale,
  393. iCrdFlr, iCrdClg, fCrdFrcF, fCrdFrcC );
  394. m_TexFlt[iStage].cSamples += 4;
  395. break;
  396. case 3:
  397. SetUp3DTextureSample( iStage, m_TexFlt[iStage].cSamples, m_TexCvg[iStage].iLODMap[iL], fSampleScale,
  398. iCrdFlr, iCrdClg, fCrdFrcF, fCrdFrcC );
  399. m_TexFlt[iStage].cSamples += 8;
  400. break;
  401. }
  402. }
  403. }
  404. break;
  405. }
  406. }
  407. const DWORD g_D3DTSS_ADDRESS_MAP[3] = { D3DTSS_ADDRESSU, D3DTSS_ADDRESSV, D3DTSS_ADDRESSW };
  408. void
  409. RefRast::SampleTexture( INT32 iStage, FLOAT fCol[] )
  410. {
  411. if ( m_pRD->m_pTexture[iStage] == NULL )
  412. {
  413. // return opaque black if no texture bound
  414. fCol[0] = fCol[1] = fCol[2] = 0.f;
  415. fCol[3] = 1.f;
  416. return;
  417. }
  418. fCol[0] = fCol[1] = fCol[2] = fCol[3] = 0.f;
  419. TextureSample* pS = m_TexFlt[iStage].pSamples;
  420. RDSurface2D* pTex = m_pRD->m_pTexture[iStage];
  421. for (int iS = 0; iS < m_TexFlt[iStage].cSamples; iS++, pS++ )
  422. {
  423. if ( pS->fWgt )
  424. {
  425. BOOL bUseBorder = FALSE;
  426. for (int iD=0; iD < pTex->m_cDimension; iD++)
  427. {
  428. INT32 iCrdMax = (pTex->m_cTexels[pS->iLOD][iD] - 1);
  429. if ( ( pS->iCrd[iD] < 0) || ( pS->iCrd[iD] > iCrdMax ) )
  430. {
  431. switch ( m_pRD->GetTSS(iStage)[g_D3DTSS_ADDRESS_MAP[iD]] )
  432. {
  433. case D3DTADDRESS_WRAP:
  434. // Pow-2 texture:
  435. // pS->iCrd[iD] = pS->iCrd[iD] & iCrdMax;
  436. // Non-Pow-2 texture:
  437. pS->iCrd[iD] %= (iCrdMax + 1);
  438. if( pS->iCrd[iD] < 0 )
  439. pS->iCrd[iD] = iCrdMax + 1 + pS->iCrd[iD];
  440. break;
  441. case D3DTADDRESS_MIRROR:
  442. // Pow-2 texture:
  443. // lop off non-fractional bits + flip index if LSB (non-fraction) is set
  444. // BOOL bFlip; bFlip = pS->iCrd[iD] & (iCrdMax+1);
  445. // pS->iCrd[iD] &= iCrdMax;
  446. // if (bFlip) { pS->iCrd[iD] = iCrdMax - pS->iCrd[iD]; }
  447. // Non-Pow-2 texture:
  448. if( pS->iCrd[iD] < 0 )
  449. pS->iCrd[iD] = -pS->iCrd[iD] - 1;
  450. BOOL bFlip; bFlip = ((pS->iCrd[iD]/(iCrdMax + 1)) & 1);
  451. pS->iCrd[iD] %= (iCrdMax + 1);
  452. if( bFlip ) pS->iCrd[iD] = iCrdMax - pS->iCrd[iD];
  453. break;
  454. case D3DTADDRESS_BORDER:
  455. bUseBorder = TRUE;
  456. break;
  457. case D3DTADDRESS_MIRRORONCE:
  458. if ( pS->iCrd[iD] < 0 ) pS->iCrd[iD] = (-pS->iCrd[iD]) - 1;
  459. // fall through to clamp for outside of -1 to +1 range
  460. case D3DTADDRESS_CLAMP:
  461. pS->iCrd[iD] = MAX( 0, MIN( pS->iCrd[iD], iCrdMax ) );
  462. break;
  463. }
  464. }
  465. }
  466. RDColor Texel;
  467. (bUseBorder)
  468. ? Texel = m_pRD->GetTSS(iStage)[D3DTSS_BORDERCOLOR]
  469. : pTex->ReadColor(
  470. pS->iCrd[0], pS->iCrd[1], pS->iCrd[2], pS->iLOD,
  471. Texel, m_bPixelDiscard[m_iPix] );
  472. fCol[0] += ( Texel.R * pS->fWgt );
  473. fCol[1] += ( Texel.G * pS->fWgt );
  474. fCol[2] += ( Texel.B * pS->fWgt );
  475. fCol[3] += ( Texel.A * pS->fWgt );
  476. }
  477. }
  478. }
  479. //-----------------------------------------------------------------------------
  480. //
  481. // Computes level of detail for standard trilinear mipmapping, in which
  482. // the four texture index gradients are consolidated into a single number
  483. // to select level of detail.
  484. //
  485. // The basic approach is to compute the lengths of the pixel coverage for
  486. // the per-dimensional extent of the approximate pixel coverage area. The
  487. // max of lengths are used for the single LOD result.
  488. //
  489. //-----------------------------------------------------------------------------
  490. void
  491. ComputeMipCoverage( const FLOAT (*fGradients)[2], FLOAT& fLOD, int cDim )
  492. {
  493. // compute length of coverage in each dimension
  494. FLOAT fLen[2];
  495. switch (cDim)
  496. {
  497. default:
  498. case 1: fLOD = 0.f; return;
  499. case 2:
  500. fLen[0] = RR_LENGTH( fGradients[0][0], fGradients[1][0] );
  501. fLen[1] = RR_LENGTH( fGradients[0][1], fGradients[1][1] );
  502. break;
  503. case 3:
  504. fLen[0] = RR_SQRT(
  505. (fGradients[0][0]*fGradients[0][0]) +
  506. (fGradients[1][0]*fGradients[1][0]) +
  507. (fGradients[2][0]*fGradients[2][0]) );
  508. fLen[1] = RR_SQRT(
  509. (fGradients[0][1]*fGradients[0][1]) +
  510. (fGradients[1][1]*fGradients[1][1]) +
  511. (fGradients[2][1]*fGradients[2][1]) );
  512. break;
  513. }
  514. // take the MAX for the coverage
  515. FLOAT fCoverage = MAX( fLen[0], fLen[1] );
  516. // take log2 of coverage for LOD
  517. fLOD = RR_LOG2(fCoverage);
  518. }
  519. //-----------------------------------------------------------------------------
  520. //
  521. // Computes level of detail and other factors in preparation for anisotropic
  522. // filtering. This is for 2D texture maps only.
  523. //
  524. //-----------------------------------------------------------------------------
  525. void
  526. ComputeAnisoCoverage(
  527. const FLOAT (*fGradients)[2], FLOAT fMaxAniso, // inputs
  528. FLOAT& fLOD, FLOAT& fRatio, FLOAT fDelta[] ) // outputs
  529. {
  530. // compute axis lengths and determinant
  531. FLOAT fLenX2 = (fGradients[0][0]*fGradients[0][0])+(fGradients[1][0]*fGradients[1][0]);
  532. FLOAT fLenY2 = (fGradients[0][1]*fGradients[0][1])+(fGradients[1][1]*fGradients[1][1]);
  533. FLOAT fDet = RR_ABSF((fGradients[0][0]*fGradients[1][1])-(fGradients[0][1]*fGradients[1][0]));
  534. // select major axis
  535. BOOL bXMajor = (fLenX2 > fLenY2);
  536. // select and normalize steps; compute aniso ratio
  537. FLOAT fMaj2 = (bXMajor) ? (fLenX2) : (fLenY2);
  538. FLOAT fMaj = RR_SQRT(fMaj2);
  539. FLOAT fMajNorm = 1./fMaj;
  540. fDelta[0] = ( bXMajor ? fGradients[0][0] : fGradients[0][1] ) * fMajNorm;
  541. fDelta[1] = ( bXMajor ? fGradients[1][0] : fGradients[1][1] ) * fMajNorm;
  542. if( !FLOAT_EQZ(fDet) )
  543. fRatio = fMaj2/fDet;
  544. else
  545. fRatio = FLT_MAX;
  546. // clamp ratio and compute LOD
  547. FLOAT fMin;
  548. if ( fRatio > fMaxAniso )
  549. {
  550. // ratio is clamped - LOD is based on ratio (preserves area)
  551. fRatio = fMaxAniso;
  552. fMin = fMaj/fRatio;
  553. }
  554. else
  555. {
  556. // ratio not clamped - LOD is based on area
  557. fMin = fDet/fMaj;
  558. }
  559. // clamp to top LOD
  560. if (fMin < 1.0)
  561. {
  562. fRatio = MAX( 1.0, fRatio*fMin );
  563. fMin = 1.0;
  564. }
  565. // take log2 of minor for LOD
  566. fLOD = RR_LOG2(fMin);
  567. }
  568. // end