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.

607 lines
21 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) Microsoft Corporation, 2000.
  3. //
  4. // pixproc.cpp
  5. //
  6. // Direct3D Reference Device - Pixel Processor
  7. //
  8. ///////////////////////////////////////////////////////////////////////////////
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. //-----------------------------------------------------------------------------
  12. //
  13. // WritePixel - Writes pixel and (maybe) depth to current render target.
  14. //
  15. //-----------------------------------------------------------------------------
  16. void
  17. RefRast::WritePixel(
  18. INT32 iX, INT32 iY, UINT Sample,
  19. const RDColor& Color, const RDDepth& Depth)
  20. {
  21. m_pRD->m_pRenderTarget->WritePixelColor( iX, iY, Sample, Color,
  22. m_pRD->GetRS()[D3DRS_DITHERENABLE]);
  23. // don't write if Z buffering disabled or Z write disabled
  24. if ( !( m_pRD->GetRS()[D3DRS_ZENABLE ] ) ||
  25. !( m_pRD->GetRS()[D3DRS_ZWRITEENABLE] ) ) { return; }
  26. m_pRD->m_pRenderTarget->WritePixelDepth( iX, iY, Sample, Depth );
  27. }
  28. //-----------------------------------------------------------------------------
  29. //
  30. // DoPixels - Invoked for each set of 2x2 pixels by the scan converter, applies
  31. // texture, specular, fog, alpha blend, and writes result to surface. Also
  32. // implements depth, alpha, and stencil tests.
  33. //
  34. //-----------------------------------------------------------------------------
  35. void
  36. RefRast::DoPixels( void )
  37. {
  38. #if DBG
  39. for ( m_iPix = 0; m_iPix < 4; m_iPix++ )
  40. {
  41. if ( !m_bPixelIn[m_iPix] ) continue;
  42. if (m_pRD->m_pDbgMon) m_pRD->m_pDbgMon->NextEvent( D3DDM_EVENT_PIXEL );
  43. }
  44. #endif
  45. // pixel shader executed for all 4 pixels of 2x2 grid at one time
  46. if (m_pCurrentPixelShader)
  47. ExecShader();
  48. for ( m_iPix = 0; m_iPix < 4; m_iPix++ )
  49. {
  50. if ( !m_bPixelIn[m_iPix] ) continue;
  51. if ( m_bPixelDiscard[m_iPix] ) continue;
  52. RDColor PixelColor;
  53. if ( !m_bLegacyPixelShade )
  54. {
  55. // pixel shader final color always left in temp register 0
  56. PixelColor = m_TempReg[0][m_iPix];
  57. // saturate before blend and FB access
  58. PixelColor.Clamp();
  59. }
  60. else
  61. {
  62. // apply legacy pixel shading (texture lookups already done by ExecShader)
  63. PixelColor = m_InputReg[0][m_iPix];
  64. RDColor PixelSpecular( m_InputReg[1][m_iPix] );
  65. RDColor LastStageColor( PixelColor );
  66. RDColor ResultColor( PixelColor );
  67. RDColor TempColor( (DWORD)0x0 );
  68. for ( int iStage=0; iStage<m_pRD->m_cActiveTextureStages; iStage++ )
  69. {
  70. if ( m_pRD->GetTSS(iStage)[D3DTSS_COLOROP] == D3DTOP_DISABLE )
  71. {
  72. ResultColor = LastStageColor; // pass result of previous stage
  73. break;
  74. }
  75. // no blend if texture bound to stage is bumpmap
  76. if ( ( m_pRD->GetTSS(iStage)[D3DTSS_COLOROP] == D3DTOP_BUMPENVMAP ) ||
  77. ( m_pRD->GetTSS(iStage)[D3DTSS_COLOROP] == D3DTOP_BUMPENVMAPLUMINANCE ) )
  78. {
  79. continue;
  80. }
  81. RDColor TextureColor( m_TextReg[iStage][m_iPix] );
  82. DoTextureBlendStage( iStage, PixelColor, PixelSpecular,
  83. LastStageColor, TextureColor, TempColor, ResultColor );
  84. // set color for next stage
  85. LastStageColor = ResultColor;
  86. }
  87. PixelColor = ResultColor;
  88. // add specular and saturate
  89. if ( m_pRD->GetRS()[D3DRS_SPECULARENABLE] )
  90. {
  91. PixelColor.R += PixelSpecular.R;
  92. PixelColor.G += PixelSpecular.G;
  93. PixelColor.B += PixelSpecular.B;
  94. PixelColor.Saturate();
  95. }
  96. }
  97. // do alpha test - bail out if failed
  98. if ( m_pRD->GetRS()[D3DRS_ALPHATESTENABLE] &&
  99. !AlphaTest( PixelColor.A ) )
  100. {
  101. continue;
  102. }
  103. // apply fog
  104. if ( m_pRD->GetRS()[D3DRS_FOGENABLE] )
  105. {
  106. RDColor FogColor = m_pRD->GetRS()[D3DRS_FOGCOLOR];
  107. // (TODO: account for pre-multiplied alpha here??)
  108. FLOAT ObjColorFrac = m_FogIntensity[m_iPix];
  109. FLOAT FogColorFrac = 1.f - m_FogIntensity[m_iPix];
  110. PixelColor.R = (ObjColorFrac * PixelColor.R) + (FogColorFrac * FogColor.R);
  111. PixelColor.G = (ObjColorFrac * PixelColor.G) + (FogColorFrac * FogColor.G);
  112. PixelColor.B = (ObjColorFrac * PixelColor.B) + (FogColorFrac * FogColor.B);
  113. }
  114. //
  115. // remainder is done per-sample for multisample buffers
  116. //
  117. INT32 iX = m_iX[m_iPix];
  118. INT32 iY = m_iY[m_iPix];
  119. do
  120. {
  121. RDColor FinalPixelColor = PixelColor;
  122. UINT iSample = GetCurrentSample();
  123. if ( !m_bIsLine &&
  124. ( !GetCurrentSampleMask() ||
  125. !m_bSampleCovered[iSample][m_iPix] ) )
  126. {
  127. // iSample not covered by this geometry
  128. continue;
  129. }
  130. //
  131. // read current depth for this pixel and do depth test - cannot
  132. // bail out if failed because stencil may need to be updated
  133. //
  134. BOOL bDepthTestPassed = TRUE;
  135. if ( m_pRD->GetRS()[D3DRS_ZENABLE] )
  136. {
  137. m_Depth[m_iPix] = m_SampleDepth[iSample][m_iPix];
  138. RDDepth BufferDepth( m_Depth[m_iPix].GetSType() );
  139. m_pRD->m_pRenderTarget->ReadPixelDepth( iX, iY, iSample, BufferDepth );
  140. bDepthTestPassed = DepthCloser( m_Depth[m_iPix], BufferDepth );
  141. }
  142. //
  143. // do stencil operation
  144. //
  145. BOOL bStencilTestPassed = TRUE;
  146. if ( m_pRD->GetRS()[D3DRS_STENCILENABLE] )
  147. {
  148. // read stencil buffer and do stencil operation
  149. UINT8 uStncBuf = 0x0;
  150. m_pRD->m_pRenderTarget->ReadPixelStencil( iX, iY, iSample, uStncBuf );
  151. UINT8 uStncNew;
  152. bStencilTestPassed =
  153. DoStencil( uStncBuf, bDepthTestPassed, m_pRD->m_pRenderTarget->m_pDepth->GetSurfaceFormat(), uStncNew );
  154. // update stencil only if changed
  155. if ( uStncNew != uStncBuf )
  156. {
  157. // compute new buffer value based on write mask
  158. UINT8 uStncWMask = m_pRD->GetRS()[D3DRS_STENCILWRITEMASK];
  159. UINT8 uStncBufNew = (uStncBuf & ~uStncWMask) | (uStncNew & uStncWMask);
  160. m_pRD->m_pRenderTarget->WritePixelStencil( iX, iY, iSample, uStncBufNew );
  161. }
  162. }
  163. if ( !(bDepthTestPassed && bStencilTestPassed) )
  164. {
  165. continue;
  166. }
  167. //
  168. // do alpha blend and write mask
  169. //
  170. if ( ( ( m_pRD->GetRS()[D3DRS_COLORWRITEENABLE] & 0xF) != 0xF ) ||
  171. ( m_pRD->GetRS()[D3DRS_ALPHABLENDENABLE] ) )
  172. {
  173. RDColor BufferColor;
  174. m_pRD->m_pRenderTarget->ReadPixelColor( iX, iY, iSample, BufferColor );
  175. if ( m_pRD->GetRS()[D3DRS_ALPHABLENDENABLE] )
  176. {
  177. DoAlphaBlend( FinalPixelColor, BufferColor, FinalPixelColor );
  178. }
  179. if ( !(m_pRD->GetRS()[D3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_RED) )
  180. FinalPixelColor.R = BufferColor.R;
  181. if ( !(m_pRD->GetRS()[D3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_GREEN) )
  182. FinalPixelColor.G = BufferColor.G;
  183. if ( !(m_pRD->GetRS()[D3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_BLUE) )
  184. FinalPixelColor.B = BufferColor.B;
  185. if ( !(m_pRD->GetRS()[D3DRS_COLORWRITEENABLE] & D3DCOLORWRITEENABLE_ALPHA) )
  186. FinalPixelColor.A = BufferColor.A;
  187. }
  188. #if 0
  189. {
  190. extern float g_GammaTable[];
  191. FinalPixelColor.R = g_GammaTable[ (UINT8)(255.f*FinalPixelColor.R) ];
  192. FinalPixelColor.G = g_GammaTable[ (UINT8)(255.f*FinalPixelColor.G) ];
  193. FinalPixelColor.B = g_GammaTable[ (UINT8)(255.f*FinalPixelColor.B) ];
  194. }
  195. #endif
  196. //
  197. // update color and depth buffers
  198. //
  199. WritePixel( iX, iY, iSample, FinalPixelColor, m_Depth[m_iPix] );
  200. } while (NextSample());
  201. }
  202. }
  203. ///////////////////////////////////////////////////////////////////////////////
  204. // //
  205. // Pixel Processing Utility Functions //
  206. // //
  207. ///////////////////////////////////////////////////////////////////////////////
  208. //-----------------------------------------------------------------------------
  209. //
  210. // Depth compare method used for Z buffering and fragment processing.
  211. //
  212. // Returns TRUE if DepthVal is closer than DepthBuf. DepthA is the generated
  213. // value and DepthB
  214. //
  215. //-----------------------------------------------------------------------------
  216. BOOL
  217. RefRast::DepthCloser(
  218. const RDDepth& DepthVal,
  219. const RDDepth& DepthBuf )
  220. {
  221. if ( !m_pRD->GetRS()[D3DRS_ZENABLE] ) { return TRUE; }
  222. switch ( m_pRD->GetRS()[D3DRS_ZFUNC] )
  223. {
  224. case D3DCMP_NEVER: return FALSE;
  225. case D3DCMP_LESS: return ( DOUBLE(DepthVal) < DOUBLE(DepthBuf) );
  226. case D3DCMP_EQUAL: return ( DOUBLE(DepthVal) == DOUBLE(DepthBuf) );
  227. case D3DCMP_LESSEQUAL: return ( DOUBLE(DepthVal) <= DOUBLE(DepthBuf) );
  228. case D3DCMP_GREATER: return ( DOUBLE(DepthVal) > DOUBLE(DepthBuf) );
  229. case D3DCMP_NOTEQUAL: return ( DOUBLE(DepthVal) != DOUBLE(DepthBuf) );
  230. case D3DCMP_GREATEREQUAL: return ( DOUBLE(DepthVal) >= DOUBLE(DepthBuf) );
  231. case D3DCMP_ALWAYS: return TRUE;
  232. }
  233. return TRUE;
  234. }
  235. //-----------------------------------------------------------------------------
  236. //
  237. // Alpha test method for pixel processing.
  238. //
  239. // Returns TRUE if alpha test passes.
  240. //
  241. //-----------------------------------------------------------------------------
  242. BOOL
  243. RefRast::AlphaTest( FLOAT fAlpha )
  244. {
  245. // grab 8 bit unsigned alpha value
  246. UINT8 uAlpha = (UINT8)(255.f*fAlpha);
  247. // form 8 bit alpha reference value
  248. UINT8 uAlphaRef8 = m_pRD->GetRS()[D3DRS_ALPHAREF];
  249. // do alpha test and either return directly or pass through
  250. switch ( m_pRD->GetRS()[D3DRS_ALPHAFUNC] )
  251. {
  252. case D3DCMP_NEVER: return FALSE;
  253. case D3DCMP_LESS: return (uAlpha < uAlphaRef8);
  254. case D3DCMP_EQUAL: return (uAlpha == uAlphaRef8);
  255. case D3DCMP_LESSEQUAL: return (uAlpha <= uAlphaRef8);
  256. case D3DCMP_GREATER: return (uAlpha > uAlphaRef8);
  257. case D3DCMP_NOTEQUAL: return (uAlpha != uAlphaRef8);
  258. case D3DCMP_GREATEREQUAL: return (uAlpha >= uAlphaRef8);
  259. case D3DCMP_ALWAYS: return TRUE;
  260. }
  261. return TRUE;
  262. }
  263. //-----------------------------------------------------------------------------
  264. //
  265. // DoStencil - Performs stencil test. Returns TRUE if stencil test passed.
  266. // Also computes stencil result value (to be written back to stencil planes
  267. // if test passes, subject to stencil write mask).
  268. //
  269. //-----------------------------------------------------------------------------
  270. BOOL
  271. RefRast::DoStencil(
  272. UINT8 uStncBuf, // in: stencil buffer value
  273. BOOL bDepthTest, // in: boolean result of depth test
  274. RDSurfaceFormat DepthSType, // in: surface type of Z buffer
  275. UINT8& uStncRet) // out: stencil value result
  276. {
  277. // support 8 bit stencil only, so do everything as UINT8's
  278. // max value for masking and saturation ops
  279. UINT8 uStncMax;
  280. switch(DepthSType)
  281. {
  282. case RD_SF_Z24S8:
  283. case RD_SF_S8Z24: uStncMax = 0xff; break;
  284. case RD_SF_Z15S1:
  285. case RD_SF_S1Z15: uStncMax = 0x1; break;
  286. case RD_SF_Z24X4S4:
  287. case RD_SF_X4S4Z24: uStncMax = 0xf; break;
  288. default: uStncMax = 0; break; // don't let stencil become non 0
  289. }
  290. // get reference from renderstate
  291. UINT8 uStncRef = (UINT8)(m_pRD->GetRS()[D3DRS_STENCILREF]);
  292. // mask to use only bits possibly present in stencil buffer
  293. uStncRef &= uStncMax;
  294. // form masked values for test
  295. UINT8 uStncMask = (UINT8)(m_pRD->GetRS()[D3DRS_STENCILMASK]);
  296. UINT8 uStncBufM = uStncBuf & uStncMask;
  297. UINT8 uStncRefM = uStncRef & uStncMask;
  298. // do stencil compare function
  299. BOOL bStncTest = FALSE;
  300. switch ( m_pRD->GetRS()[D3DRS_STENCILFUNC] )
  301. {
  302. case D3DCMP_NEVER: bStncTest = FALSE; break;
  303. case D3DCMP_LESS: bStncTest = (uStncRefM < uStncBufM); break;
  304. case D3DCMP_EQUAL: bStncTest = (uStncRefM == uStncBufM); break;
  305. case D3DCMP_LESSEQUAL: bStncTest = (uStncRefM <= uStncBufM); break;
  306. case D3DCMP_GREATER: bStncTest = (uStncRefM > uStncBufM); break;
  307. case D3DCMP_NOTEQUAL: bStncTest = (uStncRefM != uStncBufM); break;
  308. case D3DCMP_GREATEREQUAL: bStncTest = (uStncRefM >= uStncBufM); break;
  309. case D3DCMP_ALWAYS: bStncTest = TRUE; break;
  310. }
  311. // determine which stencil operation to perform
  312. DWORD dwStencilOp;
  313. if ( !bStncTest )
  314. {
  315. // stencil test failed - depth test does not matter
  316. dwStencilOp = m_pRD->GetRS()[D3DRS_STENCILFAIL];
  317. }
  318. else
  319. {
  320. // stencil test passed - select based on depth pass/fail
  321. dwStencilOp = ( !bDepthTest )
  322. ? ( m_pRD->GetRS()[D3DRS_STENCILZFAIL] )
  323. : ( m_pRD->GetRS()[D3DRS_STENCILPASS] );
  324. }
  325. uStncRet = 0x0;
  326. switch ( dwStencilOp )
  327. {
  328. case D3DSTENCILOP_KEEP: uStncRet = uStncBuf; break;
  329. case D3DSTENCILOP_ZERO: uStncRet = 0x00; break;
  330. case D3DSTENCILOP_REPLACE: uStncRet = uStncRef; break;
  331. case D3DSTENCILOP_INCRSAT:
  332. uStncRet = (uStncBuf==uStncMax)?(uStncMax):(uStncBuf+1); break;
  333. case D3DSTENCILOP_DECRSAT:
  334. uStncRet = (uStncBuf==0x00)?(0x00):(uStncBuf-1); break;
  335. case D3DSTENCILOP_INVERT: uStncRet = ~uStncBuf; break;
  336. case D3DSTENCILOP_INCR: uStncRet = uStncBuf+1; break;
  337. case D3DSTENCILOP_DECR: uStncRet = uStncBuf-1; break;
  338. }
  339. return bStncTest;
  340. }
  341. //-----------------------------------------------------------------------------
  342. //
  343. // DoAlphaBlend - Performs color blending of source and destination colors
  344. // producing a result color.
  345. //
  346. //-----------------------------------------------------------------------------
  347. void
  348. RefRast::DoAlphaBlend(
  349. const RDColor& SrcColor, // in: source pixel color
  350. const RDColor& DstColor, // in: destination (buffer) color
  351. RDColor& ResColor) // out: result (blended) color
  352. {
  353. RDColor SrcColorFactor;
  354. RDColor DstColorFactor;
  355. BOOL bDestBlendOverride = FALSE;
  356. // no SRC/DST blend (or clamp) required for MIN or MAX BLENDOP
  357. switch ( m_pRD->GetRS()[D3DRS_BLENDOP] )
  358. {
  359. case D3DBLENDOP_MIN:
  360. ResColor.R = MIN(SrcColor.R,DstColor.R);
  361. ResColor.G = MIN(SrcColor.G,DstColor.G);
  362. ResColor.B = MIN(SrcColor.B,DstColor.B);
  363. ResColor.A = MIN(SrcColor.A,DstColor.A);
  364. return;
  365. case D3DBLENDOP_MAX:
  366. ResColor.R = MAX(SrcColor.R,DstColor.R);
  367. ResColor.G = MAX(SrcColor.G,DstColor.G);
  368. ResColor.B = MAX(SrcColor.B,DstColor.B);
  369. ResColor.A = MAX(SrcColor.A,DstColor.A);
  370. return;
  371. }
  372. // compute source blend factors
  373. switch ( m_pRD->GetRS()[D3DRS_SRCBLEND] )
  374. {
  375. default:
  376. case D3DBLEND_ZERO:
  377. SrcColorFactor.SetAllChannels( 0.F );
  378. break;
  379. case D3DBLEND_ONE:
  380. SrcColorFactor.SetAllChannels( 1.F );
  381. break;
  382. case D3DBLEND_SRCCOLOR:
  383. SrcColorFactor.R = SrcColor.R;
  384. SrcColorFactor.G = SrcColor.G;
  385. SrcColorFactor.B = SrcColor.B;
  386. SrcColorFactor.A = SrcColor.A;
  387. break;
  388. case D3DBLEND_INVSRCCOLOR:
  389. SrcColorFactor.R = ( 1.f - SrcColor.R );
  390. SrcColorFactor.G = ( 1.f - SrcColor.G );
  391. SrcColorFactor.B = ( 1.f - SrcColor.B );
  392. SrcColorFactor.A = ( 1.f - SrcColor.A );
  393. break;
  394. case D3DBLEND_SRCALPHA:
  395. SrcColorFactor.SetAllChannels( SrcColor.A );
  396. break;
  397. case D3DBLEND_INVSRCALPHA:
  398. SrcColorFactor.SetAllChannels( 1.f - SrcColor.A );
  399. break;
  400. case D3DBLEND_DESTALPHA:
  401. SrcColorFactor.SetAllChannels( DstColor.A );
  402. break;
  403. case D3DBLEND_INVDESTALPHA:
  404. SrcColorFactor.SetAllChannels( 1.f - DstColor.A );
  405. break;
  406. case D3DBLEND_DESTCOLOR:
  407. SrcColorFactor.R = DstColor.R;
  408. SrcColorFactor.G = DstColor.G;
  409. SrcColorFactor.B = DstColor.B;
  410. SrcColorFactor.A = DstColor.A;
  411. break;
  412. case D3DBLEND_INVDESTCOLOR:
  413. SrcColorFactor.R = ( 1.f - DstColor.R );
  414. SrcColorFactor.G = ( 1.f - DstColor.G );
  415. SrcColorFactor.B = ( 1.f - DstColor.B );
  416. SrcColorFactor.A = ( 1.f - DstColor.A );
  417. break;
  418. case D3DBLEND_SRCALPHASAT:
  419. {
  420. FLOAT F = MIN( SrcColor.A, 1.f - DstColor.A );
  421. SrcColorFactor.R = F;
  422. SrcColorFactor.G = F;
  423. SrcColorFactor.B = F;
  424. }
  425. SrcColorFactor.A = 1.F;
  426. break;
  427. // these are for SRCBLEND only and override DESTBLEND
  428. case D3DBLEND_BOTHSRCALPHA:
  429. bDestBlendOverride = TRUE;
  430. SrcColorFactor.SetAllChannels( SrcColor.A );
  431. DstColorFactor.SetAllChannels( 1.f - SrcColor.A );
  432. break;
  433. case D3DBLEND_BOTHINVSRCALPHA:
  434. bDestBlendOverride = TRUE;
  435. SrcColorFactor.SetAllChannels( 1.f - SrcColor.A );
  436. DstColorFactor.SetAllChannels( SrcColor.A );
  437. break;
  438. }
  439. // compute destination blend factors
  440. if ( !bDestBlendOverride )
  441. {
  442. switch ( m_pRD->GetRS()[D3DRS_DESTBLEND] )
  443. {
  444. default:
  445. case D3DBLEND_ZERO:
  446. DstColorFactor.SetAllChannels( 0.F );
  447. break;
  448. case D3DBLEND_ONE:
  449. DstColorFactor.SetAllChannels( 1.F );
  450. break;
  451. case D3DBLEND_SRCCOLOR:
  452. DstColorFactor.R = SrcColor.R;
  453. DstColorFactor.G = SrcColor.G;
  454. DstColorFactor.B = SrcColor.B;
  455. DstColorFactor.A = SrcColor.A;
  456. break;
  457. case D3DBLEND_INVSRCCOLOR:
  458. DstColorFactor.R = ( 1.f - SrcColor.R );
  459. DstColorFactor.G = ( 1.f - SrcColor.G );
  460. DstColorFactor.B = ( 1.f - SrcColor.B );
  461. DstColorFactor.A = ( 1.f - SrcColor.A );
  462. break;
  463. case D3DBLEND_SRCALPHA:
  464. DstColorFactor.SetAllChannels( SrcColor.A );
  465. break;
  466. case D3DBLEND_INVSRCALPHA:
  467. DstColorFactor.SetAllChannels( 1.f - SrcColor.A );
  468. break;
  469. case D3DBLEND_DESTALPHA:
  470. DstColorFactor.SetAllChannels( DstColor.A );
  471. break;
  472. case D3DBLEND_INVDESTALPHA:
  473. DstColorFactor.SetAllChannels( 1.f - DstColor.A );
  474. break;
  475. case D3DBLEND_DESTCOLOR:
  476. DstColorFactor.R = DstColor.R;
  477. DstColorFactor.G = DstColor.G;
  478. DstColorFactor.B = DstColor.B;
  479. DstColorFactor.A = DstColor.A;
  480. break;
  481. case D3DBLEND_INVDESTCOLOR:
  482. DstColorFactor.R = ( 1.f - DstColor.R );
  483. DstColorFactor.G = ( 1.f - DstColor.G );
  484. DstColorFactor.B = ( 1.f - DstColor.B );
  485. DstColorFactor.A = ( 1.f - DstColor.A );
  486. break;
  487. case D3DBLEND_SRCALPHASAT:
  488. {
  489. FLOAT F = MIN( SrcColor.A, 1.f - DstColor.A );
  490. DstColorFactor.R = F;
  491. DstColorFactor.G = F;
  492. DstColorFactor.B = F;
  493. }
  494. DstColorFactor.A = 1.F;
  495. break;
  496. }
  497. }
  498. // apply blend factors to update pixel color (MIN and MAX handled above)
  499. RDColor SclSrc, SclDst;
  500. SclSrc.R = SrcColorFactor.R * SrcColor.R;
  501. SclSrc.G = SrcColorFactor.G * SrcColor.G;
  502. SclSrc.B = SrcColorFactor.B * SrcColor.B;
  503. SclSrc.A = SrcColorFactor.A * SrcColor.A;
  504. SclDst.R = DstColorFactor.R * DstColor.R;
  505. SclDst.G = DstColorFactor.G * DstColor.G;
  506. SclDst.B = DstColorFactor.B * DstColor.B;
  507. SclDst.A = DstColorFactor.A * DstColor.A;
  508. switch ( m_pRD->GetRS()[D3DRS_BLENDOP] )
  509. {
  510. default:
  511. case D3DBLENDOP_ADD:
  512. ResColor.R = SclSrc.R + SclDst.R;
  513. ResColor.G = SclSrc.G + SclDst.G;
  514. ResColor.B = SclSrc.B + SclDst.B;
  515. ResColor.A = SclSrc.A + SclDst.A;
  516. break;
  517. case D3DBLENDOP_SUBTRACT:
  518. ResColor.R = SclSrc.R - SclDst.R;
  519. ResColor.G = SclSrc.G - SclDst.G;
  520. ResColor.B = SclSrc.B - SclDst.B;
  521. ResColor.A = SclSrc.A - SclDst.A;
  522. break;
  523. case D3DBLENDOP_REVSUBTRACT:
  524. ResColor.R = SclDst.R - SclSrc.R;
  525. ResColor.G = SclDst.G - SclSrc.G;
  526. ResColor.B = SclDst.B - SclSrc.B;
  527. ResColor.A = SclDst.A - SclSrc.A;
  528. break;
  529. }
  530. // clamp result
  531. ResColor.Clamp();
  532. }
  533. ///////////////////////////////////////////////////////////////////////////////
  534. // end