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.

817 lines
31 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) Microsoft Corporation, 1998.
  3. //
  4. // setup.cpp
  5. //
  6. // Direct3D Reference Rasterizer - Primitive Setup
  7. //
  8. ///////////////////////////////////////////////////////////////////////////////
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. //-----------------------------------------------------------------------------
  12. //
  13. // SetPrimitiveAttributeFunctions - Common routine to compute attribute
  14. // functions used for triangles, lines, and points. (This could be done more
  15. // efficiently for lines and points...).
  16. //
  17. //-----------------------------------------------------------------------------
  18. void
  19. ReferenceRasterizer::SetPrimitiveAttributeFunctions(
  20. const RRFVFExtractor& Vtx0,
  21. const RRFVFExtractor& Vtx1,
  22. const RRFVFExtractor& Vtx2,
  23. const RRFVFExtractor& VtxFlat )
  24. {
  25. // compute depth function
  26. m_pSCS->AttribFuncs[ATTRFUNC_Z].SetLinearFunc( Vtx0.GetZ(), Vtx1.GetZ(), Vtx2.GetZ() );
  27. // compute depth range for primitive (needed because we may sample slightly outside
  28. // the primitive when antialiasing which is generally OK for color and texture indices
  29. // but not for depth buffering)
  30. if ( D3DZB_USEW == m_dwRenderState[D3DRENDERSTATE_ZENABLE] )
  31. {
  32. // using W for depth buffering
  33. FLOAT fW0 = 1./Vtx0.GetRHW();
  34. FLOAT fW1 = 1./Vtx1.GetRHW();
  35. FLOAT fW2 = 1./Vtx2.GetRHW();
  36. m_pSCS->fDepthMin = MIN( fW0, fW1 );
  37. m_pSCS->fDepthMin = MIN( m_pSCS->fDepthMin, fW2 );
  38. m_pSCS->fDepthMax = MAX( fW0, fW1 );
  39. m_pSCS->fDepthMax = MAX( m_pSCS->fDepthMax, fW2 );
  40. }
  41. else
  42. {
  43. // using Z for depth buffering
  44. m_pSCS->fDepthMin = MIN( Vtx0.GetZ(), Vtx1.GetZ() );
  45. m_pSCS->fDepthMin = MIN( m_pSCS->fDepthMin, Vtx2.GetZ() );
  46. m_pSCS->fDepthMax = MAX( Vtx0.GetZ(), Vtx1.GetZ() );
  47. m_pSCS->fDepthMax = MAX( m_pSCS->fDepthMax, Vtx2.GetZ() );
  48. }
  49. // compute diffuse color functions
  50. if ( D3DSHADE_FLAT != m_dwRenderState[D3DRENDERSTATE_SHADEMODE] )
  51. {
  52. RRColor VtxColor0( Vtx0.GetDiffuse() );
  53. RRColor VtxColor1( Vtx1.GetDiffuse() );
  54. RRColor VtxColor2( Vtx2.GetDiffuse() );
  55. m_pSCS->AttribFuncs[ATTRFUNC_R].SetPerspFunc( VtxColor0.R, VtxColor1.R, VtxColor2.R );
  56. m_pSCS->AttribFuncs[ATTRFUNC_G].SetPerspFunc( VtxColor0.G, VtxColor1.G, VtxColor2.G );
  57. m_pSCS->AttribFuncs[ATTRFUNC_B].SetPerspFunc( VtxColor0.B, VtxColor1.B, VtxColor2.B );
  58. m_pSCS->AttribFuncs[ATTRFUNC_A].SetPerspFunc( VtxColor0.A, VtxColor1.A, VtxColor2.A );
  59. }
  60. else
  61. {
  62. RRColor VtxColor0( VtxFlat.GetDiffuse() );
  63. m_pSCS->AttribFuncs[ATTRFUNC_R].SetConstant( VtxColor0.R );
  64. m_pSCS->AttribFuncs[ATTRFUNC_G].SetConstant( VtxColor0.G );
  65. m_pSCS->AttribFuncs[ATTRFUNC_B].SetConstant( VtxColor0.B );
  66. m_pSCS->AttribFuncs[ATTRFUNC_A].SetConstant( VtxColor0.A );
  67. }
  68. // compute specular functions
  69. if ( m_qwFVFControl & D3DFVF_SPECULAR )
  70. {
  71. if ( D3DSHADE_FLAT != m_dwRenderState[D3DRENDERSTATE_SHADEMODE] )
  72. {
  73. RRColor VtxSpecular0( Vtx0.GetSpecular() );
  74. RRColor VtxSpecular1( Vtx1.GetSpecular() );
  75. RRColor VtxSpecular2( Vtx2.GetSpecular() );
  76. m_pSCS->AttribFuncs[ATTRFUNC_SR].SetPerspFunc( VtxSpecular0.R, VtxSpecular1.R, VtxSpecular2.R );
  77. m_pSCS->AttribFuncs[ATTRFUNC_SG].SetPerspFunc( VtxSpecular0.G, VtxSpecular1.G, VtxSpecular2.G );
  78. m_pSCS->AttribFuncs[ATTRFUNC_SB].SetPerspFunc( VtxSpecular0.B, VtxSpecular1.B, VtxSpecular2.B );
  79. m_pSCS->AttribFuncs[ATTRFUNC_SA].SetPerspFunc( VtxSpecular0.A, VtxSpecular1.A, VtxSpecular2.A );
  80. }
  81. else
  82. {
  83. RRColor VtxSpecular0( VtxFlat.GetSpecular() );
  84. m_pSCS->AttribFuncs[ATTRFUNC_SR].SetConstant( VtxSpecular0.R );
  85. m_pSCS->AttribFuncs[ATTRFUNC_SG].SetConstant( VtxSpecular0.G );
  86. m_pSCS->AttribFuncs[ATTRFUNC_SB].SetConstant( VtxSpecular0.B );
  87. m_pSCS->AttribFuncs[ATTRFUNC_SA].SetConstant( VtxSpecular0.A );
  88. }
  89. }
  90. // compute vertex fog function
  91. if ( m_dwRenderState[D3DRENDERSTATE_FOGENABLE] &&
  92. ( m_dwRenderState[D3DRENDERSTATE_FOGTABLEMODE] == D3DFOG_NONE ) )
  93. {
  94. FLOAT fF0 = (1/255.F)*(FLOAT)RGBA_GETALPHA( Vtx0.GetSpecular() );
  95. FLOAT fF1 = (1/255.F)*(FLOAT)RGBA_GETALPHA( Vtx1.GetSpecular() );
  96. FLOAT fF2 = (1/255.F)*(FLOAT)RGBA_GETALPHA( Vtx2.GetSpecular() );
  97. m_pSCS->AttribFuncs[ATTRFUNC_F].SetPerspFunc( fF0, fF1, fF2 );
  98. }
  99. // compute functions for all potential texture coordinates
  100. for(INT32 iStage = 0; iStage < m_cActiveTextureStages; iStage++)
  101. {
  102. for(INT32 i = 0; i < 4; i++)
  103. {
  104. if (m_pTexture[iStage])
  105. {
  106. m_pSCS->TextureFuncs[iStage][TEXFUNC_0 + i].SetPerspFunc(
  107. m_pSCS->fTexCoord[iStage][0][i],
  108. m_pSCS->fTexCoord[iStage][1][i],
  109. m_pSCS->fTexCoord[iStage][2][i], m_pSCS->bWrap[iStage][i],
  110. ((m_pTexture[iStage]->m_uFlags & RR_TEXTURE_SHADOWMAP) != 0));
  111. }
  112. }
  113. }
  114. }
  115. ///////////////////////////////////////////////////////////////////////////////
  116. // //
  117. // Triangle Drawing //
  118. // //
  119. ///////////////////////////////////////////////////////////////////////////////
  120. //-----------------------------------------------------------------------------
  121. //
  122. // DoAreaCalcs - Takes 3 vertices and does screen area computations.
  123. // Saves x, y, w's in RRSCANCNVSTATE, computes determinant, and does
  124. // screen bounding box calculations. Returns TRUE if the triangle is visible,
  125. // FALSE otherwise.
  126. //
  127. //-----------------------------------------------------------------------------
  128. BOOL ReferenceRasterizer::DoAreaCalcs(FLOAT* pfDet, RRFVFExtractor* pVtx0,
  129. RRFVFExtractor* pVtx1, RRFVFExtractor* pVtx2)
  130. {
  131. // set vertex data
  132. m_pSCS->fX0 = pVtx0->GetX();
  133. m_pSCS->fY0 = pVtx0->GetY();
  134. m_pSCS->fRHW0 = pVtx0->GetRHW();
  135. m_pSCS->fX1 = pVtx1->GetX();
  136. m_pSCS->fY1 = pVtx1->GetY();
  137. m_pSCS->fRHW1 = pVtx1->GetRHW();
  138. m_pSCS->fX2 = pVtx2->GetX();
  139. m_pSCS->fY2 = pVtx2->GetY();
  140. m_pSCS->fRHW2 = pVtx2->GetRHW();
  141. // compute determinant
  142. *pfDet = ComputeDeterminant(
  143. m_pSCS->fX0, m_pSCS->fY0,
  144. m_pSCS->fX1, m_pSCS->fY1,
  145. m_pSCS->fX2, m_pSCS->fY2 );
  146. if ( 0. == *pfDet ) { return FALSE; } // bail out if degenerate (no area)
  147. //
  148. // compute bounding box for scan area
  149. //
  150. FLOAT fXMin = MIN( m_pSCS->fX0, MIN( m_pSCS->fX1, m_pSCS->fX2 ) );
  151. FLOAT fXMax = MAX( m_pSCS->fX0, MAX( m_pSCS->fX1, m_pSCS->fX2 ) );
  152. FLOAT fYMin = MIN( m_pSCS->fY0, MIN( m_pSCS->fY1, m_pSCS->fY2 ) );
  153. FLOAT fYMax = MAX( m_pSCS->fY0, MAX( m_pSCS->fY1, m_pSCS->fY2 ) );
  154. // convert to integer (round to +inf)
  155. m_pSCS->iXMin = (INT16)(fXMin+.5);
  156. m_pSCS->iXMax = (INT16)(fXMax+.5);
  157. m_pSCS->iYMin = (INT16)(fYMin+.5);
  158. m_pSCS->iYMax = (INT16)(fYMax+.5);
  159. // clip bbox to rendering surface
  160. m_pSCS->iXMin = MAX( m_pSCS->iXMin, m_pRenderTarget->m_Clip.left );
  161. m_pSCS->iXMax = MIN( m_pSCS->iXMax, m_pRenderTarget->m_Clip.right );
  162. m_pSCS->iYMin = MAX( m_pSCS->iYMin, m_pRenderTarget->m_Clip.top );
  163. m_pSCS->iYMax = MIN( m_pSCS->iYMax, m_pRenderTarget->m_Clip.bottom );
  164. // reject if no coverage
  165. if ( ( m_pSCS->iXMin < m_pRenderTarget->m_Clip.left ) ||
  166. ( m_pSCS->iXMax > m_pRenderTarget->m_Clip.right ) ||
  167. ( m_pSCS->iYMin < m_pRenderTarget->m_Clip.top ) ||
  168. ( m_pSCS->iYMax > m_pRenderTarget->m_Clip.bottom ) )
  169. {
  170. return FALSE;
  171. }
  172. return TRUE;
  173. }
  174. //-----------------------------------------------------------------------------
  175. //
  176. // DoTexCoordCalcs - Takes 2 or 3 vertices and does texture coordinate setup.
  177. // Sets up wrap flags, and conditionally does texture transform.
  178. //
  179. //-----------------------------------------------------------------------------
  180. void ReferenceRasterizer::DoTexCoordCalcs(INT32 iStage, RRFVFExtractor* pVtx0,
  181. RRFVFExtractor* pVtx1, RRFVFExtractor* pVtx2)
  182. {
  183. INT32 iCoordSet = m_pTexture[iStage]->m_pStageState[iStage].m_dwVal[D3DTSS_TEXCOORDINDEX];
  184. INT32 iTexGen = iCoordSet & 0xffff0000;
  185. iCoordSet &= 0xffff;
  186. // map per-coordinate set WRAP controls into per-stage WRAP controls
  187. m_pSCS->bWrap[iStage][0] = (m_dwRenderState[D3DRENDERSTATE_WRAP0+iCoordSet] & (1<<0))?TRUE:FALSE;
  188. m_pSCS->bWrap[iStage][1] = (m_dwRenderState[D3DRENDERSTATE_WRAP0+iCoordSet] & (1<<1))?TRUE:FALSE;
  189. m_pSCS->bWrap[iStage][2] = (m_dwRenderState[D3DRENDERSTATE_WRAP0+iCoordSet] & (1<<2))?TRUE:FALSE;
  190. m_pSCS->bWrap[iStage][3] = (m_dwRenderState[D3DRENDERSTATE_WRAP0+iCoordSet] & (1<<3))?TRUE:FALSE;
  191. INT32 iNumCoords = 0;
  192. switch (D3DFVF_GETTEXCOORDSIZE(m_qwFVFControl, iCoordSet))
  193. {
  194. case D3DFVF_TEXTUREFORMAT1: iNumCoords = 1; break;
  195. case D3DFVF_TEXTUREFORMAT2: iNumCoords = 2; break;
  196. case D3DFVF_TEXTUREFORMAT3: iNumCoords = 3; break;
  197. case D3DFVF_TEXTUREFORMAT4: iNumCoords = 4; break;
  198. }
  199. FLOAT fTexGen[3][3];
  200. if (iTexGen != D3DTSS_TCI_PASSTHRU)
  201. {
  202. iNumCoords = 3;
  203. RRFVFExtractor* ppVtx[3] = { pVtx0, pVtx1, pVtx2 };
  204. for (INT32 i = 0; i < 3; i++)
  205. {
  206. if (ppVtx[i])
  207. {
  208. switch (iTexGen)
  209. {
  210. case D3DTSS_TCI_CAMERASPACENORMAL:
  211. fTexGen[i][0] = ppVtx[i]->GetEyeNormal(0);
  212. fTexGen[i][1] = ppVtx[i]->GetEyeNormal(1);
  213. fTexGen[i][2] = ppVtx[i]->GetEyeNormal(2);
  214. break;
  215. case D3DTSS_TCI_CAMERASPACEPOSITION:
  216. fTexGen[i][0] = ppVtx[i]->GetEyeXYZ(0);
  217. fTexGen[i][1] = ppVtx[i]->GetEyeXYZ(1);
  218. fTexGen[i][2] = ppVtx[i]->GetEyeXYZ(2);
  219. break;
  220. case D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR:
  221. {
  222. FLOAT fNX = ppVtx[i]->GetEyeNormal(0);
  223. FLOAT fNY = ppVtx[i]->GetEyeNormal(1);
  224. FLOAT fNZ = ppVtx[i]->GetEyeNormal(2);
  225. if( GetRenderState()[D3DRENDERSTATE_LOCALVIEWER] == TRUE )
  226. {
  227. FLOAT fX = ppVtx[i]->GetEyeXYZ(0);
  228. FLOAT fY = ppVtx[i]->GetEyeXYZ(1);
  229. FLOAT fZ = ppVtx[i]->GetEyeXYZ(2);
  230. // have to normalize before we reflect,
  231. // result will be normalized
  232. FLOAT fNorm = 1.0f/(FLOAT)sqrt(fX*fX + fY*fY + fZ*fZ);
  233. fX *= fNorm; fY *= fNorm; fZ *= fNorm;
  234. FLOAT fDot2 = 2.0f*(fX*fNX + fY*fNY + fZ*fNZ);
  235. fTexGen[i][0] = fX - fNX*fDot2;
  236. fTexGen[i][1] = fY - fNY*fDot2;
  237. fTexGen[i][2] = fZ - fNZ*fDot2;
  238. }
  239. else
  240. {
  241. FLOAT fDot2 = 2.0f*fNZ;
  242. fTexGen[i][0] = -fNX*fDot2;
  243. fTexGen[i][1] = -fNY*fDot2;
  244. fTexGen[i][2] = 1.f - fNZ*fDot2;
  245. }
  246. }
  247. break;
  248. }
  249. }
  250. }
  251. }
  252. FLOAT fC[3][4];
  253. for (INT32 i = 0; i < 4; i++)
  254. {
  255. if (i < iNumCoords)
  256. {
  257. if (iTexGen != D3DTSS_TCI_PASSTHRU)
  258. {
  259. fC[0][i] = fTexGen[0][i];
  260. fC[1][i] = fTexGen[1][i];
  261. fC[2][i] = fTexGen[2][i];
  262. }
  263. else
  264. {
  265. fC[0][i] = pVtx0->GetTexCrd(i, iCoordSet);
  266. fC[1][i] = pVtx1->GetTexCrd(i, iCoordSet);
  267. if (pVtx2)
  268. {
  269. fC[2][i] = pVtx2->GetTexCrd(i, iCoordSet);
  270. }
  271. }
  272. }
  273. else
  274. {
  275. if (i == iNumCoords)
  276. {
  277. fC[0][i] = 1.0f;
  278. fC[1][i] = 1.0f;
  279. fC[2][i] = 1.0f;
  280. }
  281. else
  282. {
  283. fC[0][i] = 0.0f;
  284. fC[1][i] = 0.0f;
  285. fC[2][i] = 0.0f;
  286. }
  287. }
  288. }
  289. // Do texture transform only if the original
  290. // vertices passed to the refrast were untransformed
  291. BOOL bAlreadyXfmd = FVF_TRANSFORMED( m_dwFVFIn );
  292. if (m_bPointSprite)
  293. {
  294. // disable texture transform if in point sprite mode
  295. bAlreadyXfmd = TRUE;
  296. }
  297. m_pTexture[iStage]->DoTextureTransform( iStage, bAlreadyXfmd, fC[0],
  298. m_pSCS->fTexCoord[iStage][0], &m_pSCS->fRHQW[iStage][0] );
  299. m_pTexture[iStage]->DoTextureTransform( iStage, bAlreadyXfmd, fC[1],
  300. m_pSCS->fTexCoord[iStage][1], &m_pSCS->fRHQW[iStage][1] );
  301. if (pVtx2)
  302. {
  303. m_pTexture[iStage]->DoTextureTransform( iStage, bAlreadyXfmd, fC[2],
  304. m_pSCS->fTexCoord[iStage][2], &m_pSCS->fRHQW[iStage][2] );
  305. }
  306. // shadow map interpolation must not envolve the W of the current
  307. // (viewing) perspective transform
  308. if ((m_pTexture[iStage]->m_uFlags & RR_TEXTURE_SHADOWMAP) == 0)
  309. {
  310. m_pSCS->fRHQW[iStage][0] *= m_pSCS->fRHW0;
  311. m_pSCS->fRHQW[iStage][1] *= m_pSCS->fRHW1;
  312. if (pVtx2)
  313. {
  314. m_pSCS->fRHQW[iStage][2] *= m_pSCS->fRHW2;
  315. }
  316. }
  317. }
  318. //-----------------------------------------------------------------------------
  319. //
  320. // DrawTriangle - Takes three vertices and does triangle setup, setting the
  321. // primitive structure which is input to the triangle scanner, then
  322. // invokes the scan conversion.
  323. //
  324. // This computes the triangle determinant (for culling and normalization) and
  325. // the normalized edge distance and attribute functions.
  326. //
  327. // wFlags - Edge (and other) flags.
  328. //
  329. //-----------------------------------------------------------------------------
  330. void
  331. ReferenceRasterizer::DrawTriangle(
  332. void* pvV0, void* pvV1, void* pvV2, WORD wFlags )
  333. {
  334. DPFM(3, SETUP, ("DrawTriangle:\n"));
  335. // encase FVF vertex pointer and control in class to extract fields
  336. RRFVFExtractor Vtx0( pvV0, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
  337. RRFVFExtractor Vtx1( pvV1, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
  338. RRFVFExtractor Vtx2( pvV2, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
  339. FLOAT fDet;
  340. if (DoAreaCalcs(&fDet, &Vtx0, &Vtx1, &Vtx2) == FALSE)
  341. {
  342. return;
  343. }
  344. // do culling
  345. if (!m_bPointSprite)
  346. {
  347. switch ( m_dwRenderState[D3DRENDERSTATE_CULLMODE] )
  348. {
  349. case D3DCULL_NONE: break;
  350. case D3DCULL_CW: if ( fDet > 0. ) { return; } break;
  351. case D3DCULL_CCW: if ( fDet < 0. ) { return; } break;
  352. }
  353. }
  354. //
  355. // process point and wireframe fill mode
  356. //
  357. if (!m_bPointSprite)
  358. {
  359. if ( m_dwRenderState[D3DRENDERSTATE_FILLMODE] == D3DFILL_POINT )
  360. {
  361. DrawPoint( pvV0, pvV0 );
  362. DrawPoint( pvV1, pvV0 );
  363. DrawPoint( pvV2, pvV0 );
  364. return;
  365. }
  366. else if ( m_dwRenderState[D3DRENDERSTATE_FILLMODE] == D3DFILL_WIREFRAME )
  367. {
  368. if ( wFlags & D3DTRIFLAG_EDGEENABLE1 ) { DrawLine( pvV0, pvV1, pvV0 ); }
  369. if ( wFlags & D3DTRIFLAG_EDGEENABLE2 ) { DrawLine( pvV1, pvV2, pvV0 ); }
  370. if ( wFlags & D3DTRIFLAG_EDGEENABLE3 ) { DrawLine( pvV2, pvV0, pvV0 ); }
  371. return;
  372. }
  373. }
  374. //
  375. // compute edge functions
  376. //
  377. m_pSCS->EdgeFuncs[0].Set( m_pSCS->fX0, m_pSCS->fY0, m_pSCS->fX1, m_pSCS->fY1,
  378. fDet, m_bFragmentProcessingEnabled );
  379. m_pSCS->EdgeFuncs[1].Set( m_pSCS->fX1, m_pSCS->fY1, m_pSCS->fX2, m_pSCS->fY2,
  380. fDet, m_bFragmentProcessingEnabled );
  381. m_pSCS->EdgeFuncs[2].Set( m_pSCS->fX2, m_pSCS->fY2, m_pSCS->fX0, m_pSCS->fY0,
  382. fDet, m_bFragmentProcessingEnabled );
  383. // compute functions for texture coordinates
  384. if (m_cActiveTextureStages)
  385. {
  386. for ( INT32 iStage=0; iStage<m_cActiveTextureStages; iStage++ )
  387. {
  388. if (m_pTexture[iStage])
  389. {
  390. DoTexCoordCalcs(iStage, &Vtx0, &Vtx1, &Vtx2);
  391. }
  392. }
  393. }
  394. // set attribute function static data to values for this triangle
  395. m_pSCS->AttribFuncStatic.SetPerTriangleData(
  396. m_pSCS->fX0, m_pSCS->fY0, m_pSCS->fRHW0,
  397. m_pSCS->fX1, m_pSCS->fY1, m_pSCS->fRHW1,
  398. m_pSCS->fX2, m_pSCS->fY2, m_pSCS->fRHW2,
  399. m_cActiveTextureStages,
  400. (FLOAT*)&m_pSCS->fRHQW[0][0],
  401. fDet );
  402. // set attribute functions
  403. SetPrimitiveAttributeFunctions( Vtx0, Vtx1, Vtx2, Vtx0 );
  404. // not culled, so rasterize it
  405. DoScanCnvTri(3);
  406. }
  407. ///////////////////////////////////////////////////////////////////////////////
  408. // //
  409. // Line Drawing //
  410. // //
  411. ///////////////////////////////////////////////////////////////////////////////
  412. //-----------------------------------------------------------------------------
  413. //
  414. // PointDiamondCheck - Tests if vertex is within diamond of nearest candidate
  415. // position. The +.5 (lower-right) tests are used because this is pixel-relative
  416. // test - this corresponds to an upper-left test for a vertex-relative position.
  417. //
  418. //-----------------------------------------------------------------------------
  419. BOOL
  420. PointDiamondCheck(
  421. INT32 iXFrac, INT32 iYFrac,
  422. BOOL bSlopeIsOne, BOOL bSlopeIsPosOne )
  423. {
  424. const INT32 iPosHalf = 0x8;
  425. const INT32 iNegHalf = -0x8;
  426. INT32 iFracAbsSum = labs( iXFrac ) + labs( iYFrac );
  427. // return TRUE if point is in fully-exclusive diamond
  428. if ( iFracAbsSum < iPosHalf ) return TRUE;
  429. // else return TRUE if diamond is on left or top extreme of point
  430. if ( ( iXFrac == ( bSlopeIsPosOne ? iNegHalf : iPosHalf ) ) &&
  431. ( iYFrac == 0 ) )
  432. return TRUE;
  433. if ( ( iYFrac == iPosHalf ) &&
  434. ( iXFrac == 0 ) )
  435. return TRUE;
  436. // return true if slope is one, vertex is on edge, and (other conditions...)
  437. if ( bSlopeIsOne && ( iFracAbsSum == iPosHalf ) )
  438. {
  439. if ( bSlopeIsPosOne && ( iXFrac < 0 ) && ( iYFrac > 0 ) )
  440. return TRUE;
  441. if ( !bSlopeIsPosOne && ( iXFrac > 0 ) && ( iYFrac > 0 ) )
  442. return TRUE;
  443. }
  444. return FALSE;
  445. }
  446. //-----------------------------------------------------------------------------
  447. //
  448. // DrawLine - Takes two vertices and draws a line.
  449. //
  450. // This implements the Grid Intersect Quanization (GIQ) convention (which is
  451. // also used in Windows).
  452. //
  453. //-----------------------------------------------------------------------------
  454. void
  455. ReferenceRasterizer::DrawLine(
  456. void* pvV0, void* pvV1, void* pvVFlat )
  457. {
  458. DPFM(3, SETUP, ("DrawLine:\n"));
  459. // encase FVF vertex pointer and control in class to extract fields
  460. RRFVFExtractor Vtx0( pvV0, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
  461. RRFVFExtractor Vtx1( pvV1, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
  462. RRFVFExtractor VtxFlat( ( ( NULL != pvVFlat ) ? pvVFlat : pvV0 ),
  463. m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
  464. // set vertex data
  465. m_pSCS->fX0 = Vtx0.GetX();
  466. m_pSCS->fY0 = Vtx0.GetY();
  467. m_pSCS->fRHW0 = Vtx0.GetRHW();
  468. m_pSCS->fX1 = Vtx1.GetX();
  469. m_pSCS->fY1 = Vtx1.GetY();
  470. m_pSCS->fRHW1 = Vtx1.GetRHW();
  471. // compute n.4 fixed point vertex values
  472. INT32 iX0 = AS_INT32( (DOUBLE)m_pSCS->fX0 + DOUBLE_4_SNAP );
  473. INT32 iX1 = AS_INT32( (DOUBLE)m_pSCS->fX1 + DOUBLE_4_SNAP );
  474. INT32 iY0 = AS_INT32( (DOUBLE)m_pSCS->fY0 + DOUBLE_4_SNAP );
  475. INT32 iY1 = AS_INT32( (DOUBLE)m_pSCS->fY1 + DOUBLE_4_SNAP );
  476. // compute x,y extents of the line (fixed point)
  477. INT32 iXSize = iX1 - iX0;
  478. INT32 iYSize = iY1 - iY0;
  479. // TODO: is this right???
  480. if ( ( iXSize == 0 ) && ( iYSize == 0 ) ) { return; }
  481. // determine major direction and compute line function
  482. FLOAT fLineMajorExtent; // signed extent from V0 to V1 in major direction
  483. // use GreaterEqual compare here so X major will be used when slope is
  484. // exactly one - this forces the per-pixel evaluation to be done on the
  485. // Y axis and thus adheres to the rule of inclusive right (instead of
  486. // inclusive left) for slope == 1 cases
  487. if ( labs( iXSize ) >= labs( iYSize ) )
  488. {
  489. // here for X major
  490. m_pSCS->bXMajor = TRUE;
  491. fLineMajorExtent = (FLOAT)iXSize * (1./16.);
  492. // line function: y = F(x) = ( [0]*x + [1] ) / [2]
  493. m_pSCS->iLineEdgeFunc[0] = iYSize;
  494. m_pSCS->iLineEdgeFunc[1] = (INT64)iY0*(INT64)iX1 - (INT64)iY1*(INT64)iX0;
  495. m_pSCS->iLineEdgeFunc[2] = iXSize;
  496. }
  497. else
  498. {
  499. // here for Y major
  500. m_pSCS->bXMajor = FALSE;
  501. fLineMajorExtent = (FLOAT)iYSize * (1./16.);
  502. // line function: x = F(y) = ( [0]*y + [1] ) / [2]
  503. m_pSCS->iLineEdgeFunc[0] = iXSize;
  504. m_pSCS->iLineEdgeFunc[1] = (INT64)iX0*(INT64)iY1 - (INT64)iX1*(INT64)iY0;
  505. m_pSCS->iLineEdgeFunc[2] = iYSize;
  506. }
  507. BOOL bSlopeIsOne = ( labs( iXSize ) == labs( iYSize ) );
  508. BOOL bSlopeIsPosOne =
  509. bSlopeIsOne &&
  510. ( ( (FLOAT)m_pSCS->iLineEdgeFunc[0]/(FLOAT)m_pSCS->iLineEdgeFunc[2] ) > 0. );
  511. // compute candidate pixel location for line endpoints
  512. //
  513. // n n
  514. // O-------* *-------O
  515. // n-.5 n+.5 n-.5 n+.5
  516. //
  517. // Nearest Ceiling Nearest Floor
  518. //
  519. // always nearest ceiling for Y; use nearest floor for X for exception (slope == +1)
  520. // case else use nearest ceiling
  521. //
  522. // nearest ceiling of Y is ceil( Y - .5), and is done by converting to floor via:
  523. //
  524. // ceil( A/B ) = floor( (A+B-1)/B )
  525. //
  526. // where A is coordinate - .5, and B is 0x10 (thus A/B is an n.4 fixed point number)
  527. //
  528. // A+B-1 = ( (Y - half) + B - 1 = ( (Y-0x8) + 0x10 - 0x1 = Y + 0x7
  529. // since B is 2**4, divide by B is right shift by 4
  530. //
  531. INT32 iPixX0 = ( iX0 + ( bSlopeIsPosOne ? 0x8 : 0x7 ) ) >> 4;
  532. INT32 iPixX1 = ( iX1 + ( bSlopeIsPosOne ? 0x8 : 0x7 ) ) >> 4;
  533. INT32 iPixY0 = ( iY0 + 0x7 ) >> 4;
  534. INT32 iPixY1 = ( iY1 + 0x7 ) >> 4;
  535. // check for vertices in/out of diamond
  536. BOOL bV0InDiamond = PointDiamondCheck( iX0 - (iPixX0<<4), iY0 - (iPixY0<<4), bSlopeIsOne, bSlopeIsPosOne );
  537. BOOL bV1InDiamond = PointDiamondCheck( iX1 - (iPixX1<<4), iY1 - (iPixY1<<4), bSlopeIsOne, bSlopeIsPosOne );
  538. // compute step value
  539. m_pSCS->iLineStep = ( fLineMajorExtent > 0 ) ? ( +1 ) : ( -1 );
  540. // compute float and integer major start (V0) and end (V1) positions
  541. INT32 iLineMajor0 = ( m_pSCS->bXMajor ) ? ( iX0 ) : ( iY0 );
  542. INT32 iLineMajor1 = ( m_pSCS->bXMajor ) ? ( iX1 ) : ( iY1 );
  543. m_pSCS->iLineMin = ( m_pSCS->bXMajor ) ? ( iPixX0 ) : ( iPixY0 );
  544. m_pSCS->iLineMax = ( m_pSCS->bXMajor ) ? ( iPixX1 ) : ( iPixY1 );
  545. // need to do lots of compares which are flipped if major direction is negative
  546. #define LINEDIR_CMP( _A, _B ) \
  547. ( ( fLineMajorExtent > 0 ) ? ( (_A) < (_B) ) : ( (_A) > (_B) ) )
  548. // do first pixel handling - keep first pixel if not in or behind diamond
  549. if ( !( bV0InDiamond || LINEDIR_CMP( iLineMajor0, (m_pSCS->iLineMin<<4) ) ) )
  550. {
  551. m_pSCS->iLineMin += m_pSCS->iLineStep;
  552. }
  553. // do last-pixel handling - keep last pixel if past diamond (in which case
  554. // the pixel is always filled) or if in diamond and rendering last pixel
  555. if ( !( ( !bV1InDiamond && LINEDIR_CMP( (m_pSCS->iLineMax<<4), iLineMajor1 ) ) ||
  556. ( bV1InDiamond && m_dwRenderState[D3DRENDERSTATE_LASTPIXEL] ) ) )
  557. {
  558. m_pSCS->iLineMax -= m_pSCS->iLineStep;
  559. }
  560. // return if no (major) extent (both before and after clamping to render buffer)
  561. if ( LINEDIR_CMP( m_pSCS->iLineMax, m_pSCS->iLineMin ) ) return;
  562. // snap major extent to render buffer
  563. INT16 iRendBufMajorMin = m_pSCS->bXMajor ? m_pRenderTarget->m_Clip.left : m_pRenderTarget->m_Clip.top;
  564. INT16 iRendBufMajorMax = m_pSCS->bXMajor ? m_pRenderTarget->m_Clip.right : m_pRenderTarget->m_Clip.bottom;
  565. if ( ( ( m_pSCS->iLineMin < iRendBufMajorMin ) &&
  566. ( m_pSCS->iLineMax < iRendBufMajorMin ) ) ||
  567. ( ( m_pSCS->iLineMin > iRendBufMajorMax ) &&
  568. ( m_pSCS->iLineMax > iRendBufMajorMax ) ) ) { return; }
  569. m_pSCS->iLineMin = MAX( 0, MIN( iRendBufMajorMax, m_pSCS->iLineMin ) );
  570. m_pSCS->iLineMax = MAX( 0, MIN( iRendBufMajorMax, m_pSCS->iLineMax ) );
  571. // return if no (major) extent
  572. if ( LINEDIR_CMP( m_pSCS->iLineMax, m_pSCS->iLineMin ) ) return;
  573. // reject if line does not cross surface
  574. {
  575. // TODO
  576. }
  577. // compute functions for texture coordinates
  578. if (m_cActiveTextureStages)
  579. {
  580. for ( INT32 iStage=0; iStage<m_cActiveTextureStages; iStage++ )
  581. {
  582. if (m_pTexture[iStage])
  583. {
  584. DoTexCoordCalcs(iStage, &Vtx0, &Vtx1, NULL);
  585. }
  586. }
  587. }
  588. // set attribute function static data to values for this line
  589. m_pSCS->AttribFuncStatic.SetPerLineData(
  590. m_pSCS->fX0, m_pSCS->fY0, m_pSCS->fRHW0,
  591. m_pSCS->fX1, m_pSCS->fY1, m_pSCS->fRHW1,
  592. m_cActiveTextureStages,
  593. (FLOAT*)&m_pSCS->fRHQW[0][0],
  594. fLineMajorExtent, m_pSCS->bXMajor );
  595. // set attribute functions
  596. SetPrimitiveAttributeFunctions( Vtx0, Vtx1, Vtx1, VtxFlat );
  597. // rasterize it
  598. DoScanCnvLine();
  599. }
  600. ///////////////////////////////////////////////////////////////////////////////
  601. // //
  602. // Point Drawing //
  603. // //
  604. ///////////////////////////////////////////////////////////////////////////////
  605. void
  606. ReferenceRasterizer::DrawPoint(
  607. void* pvV0Public, void* pvVFlat )
  608. {
  609. DPFM(3, SETUP, ("DrawPoint:\n"));
  610. DWORD dwStride = GetFVFVertexSize(m_qwFVFControl);
  611. void *pvV0 = MEMALLOC( dwStride );
  612. void *pvV1 = MEMALLOC( dwStride );
  613. void *pvV2 = MEMALLOC( dwStride );
  614. _ASSERTa( ( NULL != pvV0 ) && ( NULL != pvV1 ) && ( NULL != pvV2),
  615. "malloc failure on ReferenceRasterizer::DrawPoint", return; );
  616. memcpy(pvV0, pvV0Public, dwStride);
  617. memcpy(pvV1, pvV0Public, dwStride);
  618. memcpy(pvV2, pvV0Public, dwStride);
  619. // encase FVF vertex pointer and control in class to extract fields
  620. RRFVFExtractor Vtx0( pvV0, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
  621. RRFVFExtractor Vtx1( pvV1, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
  622. RRFVFExtractor Vtx2( pvV2, m_qwFVFControl, m_dwRenderState[D3DRENDERSTATE_TEXTUREPERSPECTIVE] );
  623. // use per vertex S if it exists, otherwise use D3DRENDERSTATE_POINTSIZE
  624. BOOL bAlreadyXfmd = FVF_TRANSFORMED( m_dwFVFIn );
  625. FLOAT fS = 1.0f;
  626. #ifdef __POINTSPRITES
  627. if (m_qwFVFControl & D3DFVF_S)
  628. {
  629. fS = Vtx0.GetS();
  630. }
  631. else if( m_dwDriverType > RRTYPE_DP2HAL )
  632. {
  633. fS = m_fRenderState[D3DRENDERSTATE_POINTSIZE];
  634. }
  635. #endif
  636. // divide point size by 2 to get delta
  637. fS *= .5f;
  638. // Move points based on point size
  639. FLOAT *pXY = Vtx0.GetPtrXYZ();
  640. FLOAT fX3 = pXY[0] + fS;
  641. FLOAT fY3 = pXY[1] + fS;
  642. pXY[0] += -fS;
  643. pXY[1] += -fS;
  644. pXY = Vtx1.GetPtrXYZ();
  645. pXY[0] += fS;
  646. pXY[1] += -fS;
  647. pXY = Vtx2.GetPtrXYZ();
  648. pXY[0] += -fS;
  649. pXY[1] += fS;
  650. FLOAT fDet;
  651. if (DoAreaCalcs(&fDet, &Vtx0, &Vtx1, &Vtx2) == FALSE)
  652. {
  653. goto PointCleanupAndExit;
  654. }
  655. //
  656. // compute edge functions
  657. //
  658. m_pSCS->EdgeFuncs[0].Set( m_pSCS->fX0, m_pSCS->fY0, m_pSCS->fX1, m_pSCS->fY1,
  659. fDet, m_bFragmentProcessingEnabled );
  660. m_pSCS->EdgeFuncs[1].Set( m_pSCS->fX1, m_pSCS->fY1, fX3, fY3,
  661. fDet, m_bFragmentProcessingEnabled );
  662. m_pSCS->EdgeFuncs[2].Set( fX3, fY3, m_pSCS->fX2, m_pSCS->fY2,
  663. fDet, m_bFragmentProcessingEnabled );
  664. m_pSCS->EdgeFuncs[3].Set( m_pSCS->fX2, m_pSCS->fY2, m_pSCS->fX0, m_pSCS->fY0,
  665. fDet, m_bFragmentProcessingEnabled );
  666. // compute functions for texture coordinates
  667. if (m_cActiveTextureStages)
  668. {
  669. for ( INT32 iStage=0; iStage<m_cActiveTextureStages; iStage++ )
  670. {
  671. if (m_pTexture[iStage])
  672. {
  673. DoTexCoordCalcs(iStage, &Vtx0, &Vtx1, &Vtx2);
  674. #ifdef __POINTSPRITES
  675. if (m_dwRenderState[D3DRENDERSTATE_POINTSPRITEENABLE])
  676. {
  677. // vtx0
  678. m_pSCS->fTexCoord[iStage][0][0] = 0.0f;
  679. m_pSCS->fTexCoord[iStage][0][1] = 0.0f;
  680. m_pSCS->fTexCoord[iStage][0][2] = 1.0f;
  681. m_pSCS->fTexCoord[iStage][0][3] = 0.0f;
  682. m_pSCS->fRHQW[iStage][0] = m_pSCS->fRHW0;
  683. // vtx1
  684. m_pSCS->fTexCoord[iStage][1][0] = SPRITETEXCOORDMAX;
  685. m_pSCS->fTexCoord[iStage][1][1] = 0.0f;
  686. m_pSCS->fTexCoord[iStage][1][2] = 1.0f;
  687. m_pSCS->fTexCoord[iStage][1][3] = 0.0f;
  688. m_pSCS->fRHQW[iStage][1] = m_pSCS->fRHW1;
  689. // vtx2
  690. m_pSCS->fTexCoord[iStage][2][0] = 0.0f;
  691. m_pSCS->fTexCoord[iStage][2][1] = SPRITETEXCOORDMAX;
  692. m_pSCS->fTexCoord[iStage][2][2] = 1.0f;
  693. m_pSCS->fTexCoord[iStage][2][3] = 0.0f;
  694. m_pSCS->fRHQW[iStage][2] = m_pSCS->fRHW2;
  695. }
  696. #endif //__POINTSPRITES
  697. }
  698. }
  699. }
  700. // set attribute function static data to values for this quad
  701. // (since slopes are constant for quad, any triangle can be used
  702. // to set them).
  703. m_pSCS->AttribFuncStatic.SetPerTriangleData(
  704. m_pSCS->fX0, m_pSCS->fY0, m_pSCS->fRHW0,
  705. m_pSCS->fX1, m_pSCS->fY1, m_pSCS->fRHW1,
  706. m_pSCS->fX2, m_pSCS->fY2, m_pSCS->fRHW2,
  707. m_cActiveTextureStages,
  708. (FLOAT*)&m_pSCS->fRHQW[0][0],
  709. fDet );
  710. // set attribute functions
  711. SetPrimitiveAttributeFunctions( Vtx0, Vtx1, Vtx2, Vtx0 );
  712. // not culled, so rasterize it
  713. DoScanCnvTri(4);
  714. PointCleanupAndExit:
  715. MEMFREE(pvV0);
  716. MEMFREE(pvV1);
  717. MEMFREE(pvV2);
  718. }
  719. ///////////////////////////////////////////////////////////////////////////////
  720. // end