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.

336 lines
12 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) Microsoft Corporation, 2000.
  3. //
  4. // scancnv.cpp
  5. //
  6. // Direct3D Reference Device - Primitive Scan Conversion
  7. //
  8. ///////////////////////////////////////////////////////////////////////////////
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. ///////////////////////////////////////////////////////////////////////////////
  12. // //
  13. // Scan Conversion Utilities //
  14. // //
  15. ///////////////////////////////////////////////////////////////////////////////
  16. //-----------------------------------------------------------------------------
  17. //
  18. // ComputeFogIntensity - Computes scalar fog intensity value and writes it to
  19. // the RDPixel.FogIntensity value.
  20. //
  21. //-----------------------------------------------------------------------------
  22. FLOAT
  23. RefRast::ComputeFogIntensity( FLOAT fX, FLOAT fY )
  24. {
  25. if ( !m_pRD->GetRS()[D3DRS_FOGENABLE] )
  26. {
  27. // fog blending not enabled, so don't need to compute fog intensity
  28. return 0.;
  29. }
  30. // compute fog intensity
  31. // select between vertex and table fog - vertex fog is selected if
  32. // fog is enabled but the renderstate fog table mode is disabled
  33. if ( D3DFOG_NONE == m_pRD->GetRS()[D3DRS_FOGTABLEMODE] )
  34. {
  35. // table fog disabled, so use interpolated vertex fog value for fog intensity
  36. FLOAT tmpFloat[4];
  37. m_Attr[RDATTR_FOG].Sample( tmpFloat, fX, fY );
  38. return tmpFloat[0];
  39. }
  40. // here for table fog, so compute fog from Z or W
  41. FLOAT fFogDensity, fPow;
  42. FLOAT fFogStart, fFogEnd;
  43. // select fog index - this is either Z or W depending on the W range
  44. //
  45. // use Z if projection matrix is set to an affine projection, else use W
  46. // (both for perspective projection and an unset projection matrix - the
  47. // latter is preferred for legacy content which uses TLVERTEX)
  48. //
  49. FLOAT fFogIndex =
  50. ( ( 1.f == m_pRD->m_pRenderTarget->m_fWRange[0] ) &&
  51. ( 1.f == m_pRD->m_pRenderTarget->m_fWRange[1] ) )
  52. ? ( m_Attr[RDATTR_DEPTH].Sample( fX, fY ) )
  53. : ( SampleAndInvertRHW( fX, fY ) ); // use W for non-affine projection
  54. FLOAT fFogIntensity;
  55. switch ( m_pRD->GetRS()[D3DRS_FOGTABLEMODE] )
  56. {
  57. case D3DFOG_LINEAR:
  58. fFogStart = m_pRD->GetRSf()[D3DRS_FOGSTART];
  59. fFogEnd = m_pRD->GetRSf()[D3DRS_FOGEND];
  60. if (fFogIndex >= fFogEnd)
  61. {
  62. fFogIntensity = 0.0f;
  63. }
  64. else if (fFogIndex <= fFogStart)
  65. {
  66. fFogIntensity = 1.0f;
  67. }
  68. else
  69. {
  70. fFogIntensity = ( fFogEnd - fFogIndex ) / ( fFogEnd - fFogStart );
  71. }
  72. break;
  73. case D3DFOG_EXP:
  74. fFogDensity = m_pRD->GetRSf()[D3DRS_FOGDENSITY];
  75. fPow = fFogDensity * fFogIndex;
  76. // note that exp(-x) returns a result in the range (0.0, 1.0]
  77. // for x >= 0
  78. fFogIntensity = (float)exp( -fPow );
  79. break;
  80. case D3DFOG_EXP2:
  81. fFogDensity = m_pRD->GetRSf()[D3DRS_FOGDENSITY];
  82. fPow = fFogDensity * fFogIndex;
  83. fFogIntensity = (float)exp( -(fPow*fPow) );
  84. break;
  85. }
  86. return fFogIntensity;
  87. }
  88. //-----------------------------------------------------------------------------
  89. //
  90. // SnapDepth - Snap off extra depth bits by converting to/from buffer format
  91. // - necessary to make depth buffer equality tests function correctly
  92. //
  93. //-----------------------------------------------------------------------------
  94. void RefRast::SnapDepth()
  95. {
  96. if (m_pRD->m_pRenderTarget->m_pDepth)
  97. {
  98. switch ( m_pRD->m_pRenderTarget->m_pDepth->GetSurfaceFormat() )
  99. {
  100. case RD_SF_Z16S0: m_Depth[m_iPix] = UINT16( m_Depth[m_iPix] ); break;
  101. case RD_SF_Z24X4S4:
  102. case RD_SF_Z24X8:
  103. case RD_SF_Z24S8: m_Depth[m_iPix] = UINT32( m_Depth[m_iPix] ); break;
  104. case RD_SF_Z15S1: m_Depth[m_iPix] = UINT16( m_Depth[m_iPix] ); break;
  105. case RD_SF_Z32S0: m_Depth[m_iPix] = UINT32( m_Depth[m_iPix] ); break;
  106. case RD_SF_S1Z15: m_Depth[m_iPix] = UINT16( m_Depth[m_iPix] ); break;
  107. case RD_SF_X4S4Z24:
  108. case RD_SF_X8Z24:
  109. case RD_SF_S8Z24: m_Depth[m_iPix] = UINT32( m_Depth[m_iPix] ); break;
  110. }
  111. }
  112. }
  113. //-----------------------------------------------------------------------------
  114. //
  115. // DoScanCnvGenPixel - This is called for each 2x2 grid of pixels, and extracts and
  116. // processes attributes from the interpolator state, and passes the pixels on to
  117. // the pixel processing module.
  118. //
  119. //-----------------------------------------------------------------------------
  120. void
  121. RefRast::DoScanCnvGenPixels( void )
  122. {
  123. for ( m_iPix = 0; m_iPix < 4; m_iPix++ )
  124. {
  125. FLOAT fPixX = (FLOAT)m_iX[m_iPix];
  126. FLOAT fPixY = (FLOAT)m_iY[m_iPix];
  127. m_fW[m_iPix] = SampleAndInvertRHW( fPixX, fPixY );
  128. // RHW needed for non-in pixels, but nothing else so bail
  129. if ( !m_bPixelIn[m_iPix] ) continue;
  130. // get depth from clamp interpolator and clamp
  131. if ( m_pRD->GetRS()[D3DRS_ZENABLE] ||
  132. m_pRD->GetRS()[D3DRS_FOGENABLE])
  133. {
  134. if (m_pRD->m_pRenderTarget->m_pDepth)
  135. m_Depth[m_iPix].SetSType(m_pRD->m_pRenderTarget->m_pDepth->GetSurfaceFormat());
  136. // evaluate depth at all sample locations
  137. do
  138. {
  139. // compute sample location
  140. FLOAT fSampX = GetCurrentSamplefX(m_iPix);
  141. FLOAT fSampY = GetCurrentSamplefY(m_iPix);
  142. if ( D3DZB_USEW == m_pRD->GetRS()[D3DRS_ZENABLE] )
  143. {
  144. // depth buffering with W value
  145. FLOAT fW = SampleAndInvertRHW( fSampX, fSampY );
  146. // apply normalization to get to 0. to 1. range
  147. fW = (fW - m_pRD->m_fWBufferNorm[0]) * m_pRD->m_fWBufferNorm[1];
  148. m_Depth[m_iPix] = fW;
  149. }
  150. else
  151. {
  152. // depth buffering with Z value
  153. m_Depth[m_iPix] =
  154. m_Attr[RDATTR_DEPTH].Sample( fSampX, fSampY );
  155. }
  156. // snap off extra bits by converting to/from buffer format - necessary
  157. // to make depth buffer equality tests function correctly
  158. SnapDepth();
  159. m_SampleDepth[m_CurrentSample][m_iPix] = m_Depth[m_iPix];
  160. } while (NextSample());
  161. }
  162. // set pixel diffuse and specular color from clamped interpolator values
  163. m_Attr[RDATTR_COLOR].Sample( m_InputReg[0][m_iPix], fPixX, fPixY );
  164. m_Attr[RDATTR_SPECULAR].Sample( m_InputReg[1][m_iPix], fPixX, fPixY );
  165. // compute fog intensity
  166. m_FogIntensity[m_iPix] = ComputeFogIntensity( fPixX, fPixY );
  167. }
  168. DoPixels();
  169. }
  170. ///////////////////////////////////////////////////////////////////////////////
  171. // //
  172. // Triangle Scan Conversion //
  173. // //
  174. ///////////////////////////////////////////////////////////////////////////////
  175. //-----------------------------------------------------------------------------
  176. //
  177. // DoScanCnvTri - Scans the bounding box of the triangle and generates pixels.
  178. //
  179. // Does 4 pixels at a time in a 2x2 grid.
  180. //
  181. //-----------------------------------------------------------------------------
  182. void
  183. RefRast::DoScanCnvTri( int iEdgeCount )
  184. {
  185. m_iEdgeCount = iEdgeCount;
  186. //
  187. // do simple scan of surface-intersected triangle bounding box
  188. //
  189. for ( m_iY[0] = m_iYMin;
  190. m_iY[0] <= m_iYMax;
  191. m_iY[0] += 2 )
  192. {
  193. m_iY[1] = m_iY[0]+0;
  194. m_iY[2] = m_iY[0]+1;
  195. m_iY[3] = m_iY[0]+1;
  196. BOOL bPartialY = (m_iY[3] > m_iYMax);
  197. for ( m_iX[0] = m_iXMin;
  198. m_iX[0] <= m_iXMax;
  199. m_iX[0] += 2 )
  200. {
  201. m_iX[1] = m_iX[0]+1;
  202. m_iX[2] = m_iX[0]+0;
  203. m_iX[3] = m_iX[0]+1;
  204. BOOL bPartialX = (m_iX[3] > m_iXMax);
  205. m_bPixelIn[0] = EvalPixelPosition(0);
  206. m_bPixelIn[1] = ( bPartialX ) ? ( FALSE ) : EvalPixelPosition(1);
  207. m_bPixelIn[2] = ( bPartialY ) ? ( FALSE ) : EvalPixelPosition(2);
  208. m_bPixelIn[3] = ( bPartialX || bPartialY ) ? ( FALSE ) : EvalPixelPosition(3);
  209. if ( m_bPixelIn[0] ||
  210. m_bPixelIn[1] ||
  211. m_bPixelIn[2] ||
  212. m_bPixelIn[3] )
  213. {
  214. // at least one pixel in
  215. DoScanCnvGenPixels();
  216. }
  217. }
  218. }
  219. }
  220. ///////////////////////////////////////////////////////////////////////////////
  221. // //
  222. // Line Scan Conversion //
  223. // //
  224. ///////////////////////////////////////////////////////////////////////////////
  225. //----------------------------------------------------------------------------
  226. //
  227. // LinePatternStateMachine
  228. //
  229. // Runs the line pattern state machine and returns TRUE if the pixel is to be
  230. // drawn, false otherwise. Always returns true if wRepeatFactor is 0, which
  231. // means pattern is disabled.
  232. //
  233. //----------------------------------------------------------------------------
  234. // NOTE: The implementation of LinePattern in RefDev is incorrect. Please refer
  235. // to the DDK documentation for the right implementation.
  236. static BOOL
  237. LinePatternStateMachine(DWORD dwLinePattern, WORD& wRepeati, WORD& wPatterni)
  238. {
  239. union
  240. {
  241. D3DLINEPATTERN LPat;
  242. DWORD dwLPat;
  243. } LinePat;
  244. LinePat.dwLPat = dwLinePattern;
  245. if (LinePat.LPat.wRepeatFactor)
  246. {
  247. WORD wBit = (LinePat.LPat.wLinePattern >> wPatterni) & 1;
  248. if (++wRepeati >= LinePat.LPat.wRepeatFactor)
  249. {
  250. wRepeati = 0;
  251. wPatterni = (wPatterni+1) & 0xf;
  252. }
  253. return (BOOL)wBit;
  254. }
  255. else
  256. {
  257. return TRUE;
  258. }
  259. }
  260. //-----------------------------------------------------------------------------
  261. //
  262. // DoScanCnvLine - Walks the line major axis, computes the appropriate minor
  263. // axis coordinate, and generates pixels.
  264. //
  265. //-----------------------------------------------------------------------------
  266. void
  267. RefRast::DoScanCnvLine( void )
  268. {
  269. // state for line pattern state machine
  270. WORD wRepeati = 0;
  271. WORD wPatterni = 0;
  272. m_bPixelIn[0] = TRUE;
  273. m_bPixelIn[1] =
  274. m_bPixelIn[2] =
  275. m_bPixelIn[3] = FALSE;
  276. for ( int cStep = 0; cStep <= m_cLineSteps; cStep++ )
  277. {
  278. // compute next x,y location in line
  279. StepLine();
  280. // if (m_pDbgMon->ScreenMask(m_iX[0], m_iY[0]))
  281. // continue;
  282. // check if the point is inside the viewport
  283. if ( ( m_iX[0] >= m_pRD->m_pRenderTarget->m_Clip.left ) &&
  284. ( m_iX[0] <= m_pRD->m_pRenderTarget->m_Clip.right ) &&
  285. ( m_iY[0] >= m_pRD->m_pRenderTarget->m_Clip.top ) &&
  286. ( m_iY[0] <= m_pRD->m_pRenderTarget->m_Clip.bottom ) )
  287. {
  288. // The line pattern should have been walked in from its origin, which may have been
  289. // offscreen, to be completely correct.
  290. if (LinePatternStateMachine(m_pRD->GetRS()[D3DRS_LINEPATTERN], wRepeati, wPatterni))
  291. {
  292. DoScanCnvGenPixels();
  293. }
  294. }
  295. }
  296. }
  297. ///////////////////////////////////////////////////////////////////////////////
  298. // end