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.

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