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.

1006 lines
29 KiB

  1. #include "pch.cpp"
  2. #pragma hdrstop
  3. ///////////////////////////////////////////////////////////////////////////////
  4. // Vertex Lighting function implementations
  5. ///////////////////////////////////////////////////////////////////////////////
  6. //---------------------------------------------------------------------
  7. void
  8. RDLV_Directional(
  9. RDLIGHTINGDATA& LData,
  10. D3DLIGHT7 *pLight,
  11. RDLIGHTI *pLightI,
  12. RDLIGHTINGELEMENT *in,
  13. DWORD dwFlags,
  14. UINT64 qwFVFIn)
  15. {
  16. // ATTENTION: Need to heed the specular flag set per light here!!
  17. BOOL bDoSpecular = dwFlags & RDPV_DOSPECULAR;
  18. BOOL bDoLocalViewer = dwFlags & RDPV_LOCALVIEWER;
  19. BOOL bDoColVertexAmbient = dwFlags & RDPV_COLORVERTEXAMB;
  20. BOOL bDoColVertexDiffuse = dwFlags & RDPV_COLORVERTEXDIFF;
  21. BOOL bDoColVertexSpecular = dwFlags & RDPV_COLORVERTEXSPEC;
  22. //
  23. // Add the material's ambient component
  24. //
  25. if (!bDoColVertexAmbient)
  26. {
  27. LData.diffuse.r += pLightI->Ma_La.r;
  28. LData.diffuse.g += pLightI->Ma_La.g;
  29. LData.diffuse.b += pLightI->Ma_La.b;
  30. }
  31. else
  32. {
  33. //
  34. // Note:
  35. // In case ColorVertexAmbient is enabled, note that it uses
  36. // VertexSpecular instead of VertexDiffuse
  37. //
  38. LData.diffuse.r += pLightI->La.r * LData.pAmbientSrc->r;
  39. LData.diffuse.g += pLightI->La.g * LData.pAmbientSrc->g;
  40. LData.diffuse.b += pLightI->La.b * LData.pAmbientSrc->b;
  41. }
  42. //
  43. // If no normals are present, bail out since we cannot perform the
  44. // normal-dependent computations
  45. //
  46. if( (qwFVFIn & D3DFVF_NORMAL) == 0 )
  47. {
  48. return;
  49. }
  50. D3DVALUE dot = DotProduct( pLightI->direction_in_eye, in->dvNormal );
  51. if (FLOAT_GTZ(dot))
  52. {
  53. if (!bDoColVertexDiffuse)
  54. {
  55. LData.diffuse.r += pLightI->Md_Ld.r * dot;
  56. LData.diffuse.g += pLightI->Md_Ld.g * dot;
  57. LData.diffuse.b += pLightI->Md_Ld.b * dot;
  58. }
  59. else
  60. {
  61. LData.diffuse.r += pLightI->Ld.r * LData.pDiffuseSrc->r * dot;
  62. LData.diffuse.g += pLightI->Ld.g * LData.pDiffuseSrc->g * dot;
  63. LData.diffuse.b += pLightI->Ld.b * LData.pDiffuseSrc->b * dot;
  64. }
  65. if (bDoSpecular)
  66. {
  67. RDVECTOR3 h; // halfway vector
  68. RDVECTOR3 eye; // incident vector ie vector from eye
  69. if (bDoLocalViewer)
  70. {
  71. // calc vector from vertex to the eye
  72. SubtractVector( LData.eye_in_eye, in->dvPosition, eye );
  73. // normalize
  74. Normalize( eye );
  75. }
  76. else
  77. {
  78. eye.x = D3DVALUE( 0.0 );
  79. eye.y = D3DVALUE( 0.0 );
  80. eye.z = D3DVALUE(-1.0 );
  81. }
  82. // calc halfway vector
  83. AddVector( pLightI->direction_in_eye, eye, h );
  84. // normalize
  85. Normalize( h );
  86. dot = DotProduct( h, in->dvNormal );
  87. if (FLOAT_GTZ(dot))
  88. {
  89. if (FLOAT_CMP_POS(dot, >=, LData.specThreshold))
  90. {
  91. D3DVALUE coeff = pow( dot, LData.material.power );
  92. if (!bDoColVertexSpecular)
  93. {
  94. LData.specular.r += pLightI->Ms_Ls.r * coeff;
  95. LData.specular.g += pLightI->Ms_Ls.g * coeff;
  96. LData.specular.b += pLightI->Ms_Ls.b * coeff;
  97. }
  98. else
  99. {
  100. LData.specular.r += (pLightI->Ls.r *
  101. LData.pSpecularSrc->r * coeff);
  102. LData.specular.g += (pLightI->Ls.g *
  103. LData.pSpecularSrc->g * coeff);
  104. LData.specular.b += (pLightI->Ls.b *
  105. LData.pSpecularSrc->b * coeff);
  106. }
  107. }
  108. }
  109. }
  110. }
  111. return;
  112. }
  113. void
  114. RDLV_PointAndSpot(
  115. RDLIGHTINGDATA &LData,
  116. D3DLIGHT7 *pLight,
  117. RDLIGHTI *pLightI,
  118. RDLIGHTINGELEMENT *in,
  119. DWORD dwFlags,
  120. UINT64 qwFVFIn)
  121. {
  122. // ATTENTION: Need to heed the specular flag set per light here!!
  123. BOOL bDoSpecular = dwFlags & RDPV_DOSPECULAR;
  124. BOOL bDoLocalViewer = dwFlags & RDPV_LOCALVIEWER;
  125. BOOL bDoColVertexAmbient = dwFlags & RDPV_COLORVERTEXAMB;
  126. BOOL bDoColVertexDiffuse = dwFlags & RDPV_COLORVERTEXDIFF;
  127. BOOL bDoColVertexSpecular = dwFlags & RDPV_COLORVERTEXSPEC;
  128. RDVECTOR3 d; // Direction to light
  129. D3DVALUE att;
  130. D3DVALUE dist;
  131. D3DVALUE dot;
  132. SubtractVector( pLightI->position_in_eye, in->dvPosition, d );
  133. // early out if out of range or exactly on the vertex
  134. D3DVALUE distSquared = SquareMagnitude( d );
  135. if (FLOAT_CMP_POS(distSquared, >=, pLightI->range_squared) ||
  136. FLOAT_EQZ(distSquared))
  137. {
  138. return;
  139. }
  140. //
  141. // Compute the attenuation
  142. //
  143. dist = SQRTF( distSquared );
  144. att = pLight->dvAttenuation0 + pLight->dvAttenuation1 * dist +
  145. pLight->dvAttenuation2 * distSquared;
  146. if (FLOAT_EQZ(att))
  147. att = FLT_MAX;
  148. else
  149. att = (D3DVALUE)1.0/att;
  150. dist = D3DVAL(1)/dist;
  151. //
  152. // If the light is a spotlight compute the spot-light factor
  153. //
  154. if (pLight->dltType == D3DLIGHT_SPOT)
  155. {
  156. // Calc dot product of direction to light with light direction to
  157. // be compared anganst the cone angles to see if we are in the
  158. // light.
  159. // Note that cone_dot is still scaled by dist
  160. D3DVALUE cone_dot = DotProduct(d, pLightI->direction_in_eye) * dist;
  161. if (FLOAT_CMP_POS(cone_dot, <=, pLightI->cos_phi_by_2))
  162. {
  163. return;
  164. }
  165. // modify att if in the region between phi and theta
  166. if (FLOAT_CMP_POS(cone_dot, <, pLightI->cos_theta_by_2))
  167. {
  168. D3DVALUE val = (cone_dot - pLightI->cos_phi_by_2) *
  169. pLightI->inv_theta_minus_phi;
  170. if (!FLOAT_EQZ( pLight->dvFalloff - 1.0 ))
  171. {
  172. val = POWF( val, pLight->dvFalloff );
  173. }
  174. att *= val;
  175. }
  176. }
  177. //
  178. // Add the material's ambient component
  179. //
  180. if (!bDoColVertexAmbient)
  181. {
  182. LData.diffuse.r += att*pLightI->Ma_La.r;
  183. LData.diffuse.g += att*pLightI->Ma_La.g;
  184. LData.diffuse.b += att*pLightI->Ma_La.b;
  185. }
  186. else
  187. {
  188. //
  189. // Note:
  190. // In case ColorVertexAmbient is enabled, note that it uses
  191. // VertexSpecular instead of VertexDiffuse
  192. //
  193. LData.diffuse.r += att*pLightI->La.r * LData.pAmbientSrc->r;
  194. LData.diffuse.g += att*pLightI->La.g * LData.pAmbientSrc->g;
  195. LData.diffuse.b += att*pLightI->La.b * LData.pAmbientSrc->b;
  196. }
  197. // Calc dot product of light dir with normal. Note that since we
  198. // didn't normalize the direction the result is scaled by the distance.
  199. if( (qwFVFIn & D3DFVF_NORMAL) == 0)
  200. {
  201. // If no normals are present, bail out since we cannot perform the
  202. // normal-dependent computations
  203. return;
  204. }
  205. else
  206. {
  207. dot = DotProduct( d, in->dvNormal );
  208. }
  209. if (FLOAT_GTZ( dot ))
  210. {
  211. dot *= dist*att;
  212. if (!bDoColVertexDiffuse)
  213. {
  214. LData.diffuse.r += pLightI->Md_Ld.r * dot;
  215. LData.diffuse.g += pLightI->Md_Ld.g * dot;
  216. LData.diffuse.b += pLightI->Md_Ld.b * dot;
  217. }
  218. else
  219. {
  220. LData.diffuse.r += pLightI->Ld.r * LData.pDiffuseSrc->r * dot;
  221. LData.diffuse.g += pLightI->Ld.g * LData.pDiffuseSrc->g * dot;
  222. LData.diffuse.b += pLightI->Ld.b * LData.pDiffuseSrc->b * dot;
  223. }
  224. if (bDoSpecular)
  225. {
  226. RDVECTOR3 h; // halfway vector
  227. RDVECTOR3 eye; // incident vector ie vector from eye
  228. // normalize light direction
  229. d.x *= dist;
  230. d.y *= dist;
  231. d.z *= dist;
  232. if (bDoLocalViewer)
  233. {
  234. // calc vector from vertex to the eye
  235. SubtractVector( LData.eye_in_eye, in->dvPosition, eye );
  236. // normalize
  237. Normalize( eye );
  238. }
  239. else
  240. {
  241. eye.x = D3DVALUE( 0.0 );
  242. eye.y = D3DVALUE( 0.0 );
  243. eye.z = D3DVALUE(-1.0 );
  244. }
  245. // calc halfway vector
  246. AddVector( d, eye, h );
  247. Normalize( h );
  248. dot = DotProduct( h, in->dvNormal );
  249. if (FLOAT_CMP_POS(dot, >=, LData.specThreshold))
  250. {
  251. D3DVALUE coeff = pow( dot, LData.material.power ) * att;
  252. if (!bDoColVertexSpecular)
  253. {
  254. LData.specular.r += pLightI->Ms_Ls.r * coeff;
  255. LData.specular.g += pLightI->Ms_Ls.g * coeff;
  256. LData.specular.b += pLightI->Ms_Ls.b * coeff;
  257. }
  258. else
  259. {
  260. LData.specular.r += (pLightI->Ls.r *
  261. LData.pSpecularSrc->r * coeff);
  262. LData.specular.g += (pLightI->Ls.g *
  263. LData.pSpecularSrc->g * coeff);
  264. LData.specular.b += (pLightI->Ls.b *
  265. LData.pSpecularSrc->b * coeff);
  266. }
  267. }
  268. }
  269. }
  270. return;
  271. }
  272. ///////////////////////////////////////////////////////////////////////////////
  273. // RDLight
  274. ///////////////////////////////////////////////////////////////////////////////
  275. RDLight::RDLight()
  276. {
  277. m_dwFlags = RDLIGHT_NEEDSPROCESSING;
  278. m_Next = NULL;
  279. ZeroMemory(&m_Light, sizeof(m_Light));
  280. ZeroMemory(&m_LightI, sizeof(m_LightI));
  281. // Initialize the light to some default values
  282. m_Light.dltType = D3DLIGHT_DIRECTIONAL;
  283. m_Light.dcvDiffuse.r = 1;
  284. m_Light.dcvDiffuse.g = 1;
  285. m_Light.dcvDiffuse.b = 1;
  286. m_Light.dcvDiffuse.a = 0;
  287. m_Light.dvDirection.x = 0;
  288. m_Light.dvDirection.y = 0;
  289. m_Light.dvDirection.z = 1;
  290. // m_Light.dcvSpecular = {0,0,0,0};
  291. // m_Light.dcvAmbient = {0,0,0,0};
  292. // m_Light.dvPosition = {0,0,0};
  293. // m_Light.dvRange = 0;
  294. // m_Light.dvFalloff = 0;
  295. // m_Light.dvAttenuation0 = 0;
  296. // m_Light.dvAttenuation1 = 0;
  297. // m_Light.dvAttenuation2 = 0;
  298. // m_Light.dvTheta = 0;
  299. // m_Light.dvPhi = 0;
  300. return;
  301. }
  302. HRESULT
  303. RDLight::SetLight(LPD3DLIGHT7 pLight)
  304. {
  305. // Validate the parameters passed
  306. switch (pLight->dltType)
  307. {
  308. case D3DLIGHT_POINT:
  309. case D3DLIGHT_SPOT:
  310. case D3DLIGHT_DIRECTIONAL:
  311. break;
  312. default:
  313. // No other light types are allowed
  314. DPFRR(0, "Invalid light type passed");
  315. return DDERR_INVALIDPARAMS;
  316. }
  317. if (pLight)
  318. m_Light = *pLight;
  319. // Mark it for processing later
  320. m_dwFlags |= (RDLIGHT_NEEDSPROCESSING | RDLIGHT_REFERED);
  321. return DD_OK;
  322. }
  323. HRESULT
  324. RDLight::GetLight(LPD3DLIGHT7 pLight)
  325. {
  326. if (pLight == NULL) return DDERR_GENERIC;
  327. *pLight = m_Light;
  328. return D3D_OK;
  329. }
  330. void
  331. RDLight::ProcessLight(D3DMATERIAL7 *mat, RDLIGHTVERTEX_FUNC_TABLE *pTbl)
  332. {
  333. //
  334. // If it is already processed, return
  335. //
  336. if (!NeedsProcessing()) return;
  337. //
  338. // Save the ambient light (0-1)
  339. //
  340. m_LightI.La.r = m_Light.dcvAmbient.r;
  341. m_LightI.La.g = m_Light.dcvAmbient.g;
  342. m_LightI.La.b = m_Light.dcvAmbient.b;
  343. //
  344. // Save the diffuse light (0-1)
  345. //
  346. m_LightI.Ld.r = m_Light.dcvDiffuse.r;
  347. m_LightI.Ld.g = m_Light.dcvDiffuse.g;
  348. m_LightI.Ld.b = m_Light.dcvDiffuse.b;
  349. //
  350. // Save the specular light (0-1)
  351. //
  352. m_LightI.Ls.r = m_Light.dcvSpecular.r;
  353. m_LightI.Ls.g = m_Light.dcvSpecular.g;
  354. m_LightI.Ls.b = m_Light.dcvSpecular.b;
  355. //
  356. // Material Ambient times Light Ambient
  357. //
  358. m_LightI.Ma_La.r = m_LightI.La.r * mat->ambient.r * D3DVALUE(255.0);
  359. m_LightI.Ma_La.g = m_LightI.La.g * mat->ambient.g * D3DVALUE(255.0);
  360. m_LightI.Ma_La.b = m_LightI.La.b * mat->ambient.b * D3DVALUE(255.0);
  361. //
  362. // Material Diffuse times Light Diffuse
  363. //
  364. m_LightI.Md_Ld.r = m_LightI.Ld.r * mat->diffuse.r * D3DVALUE(255.0);
  365. m_LightI.Md_Ld.g = m_LightI.Ld.g * mat->diffuse.g * D3DVALUE(255.0);
  366. m_LightI.Md_Ld.b = m_LightI.Ld.b * mat->diffuse.b * D3DVALUE(255.0);
  367. //
  368. // Material Specular times Light Specular
  369. //
  370. m_LightI.Ms_Ls.r = m_LightI.Ls.r * mat->specular.r * D3DVALUE(255.0);
  371. m_LightI.Ms_Ls.g = m_LightI.Ls.g * mat->specular.g * D3DVALUE(255.0);
  372. m_LightI.Ms_Ls.b = m_LightI.Ls.b * mat->specular.b * D3DVALUE(255.0);
  373. //
  374. // Assign the actual lighting function pointer, in addition to
  375. // performing some precomputation of light-type specific data
  376. //
  377. m_pfnLightVertex = NULL;
  378. switch (m_Light.dltType)
  379. {
  380. case D3DLIGHT_DIRECTIONAL:
  381. m_pfnLightVertex = pTbl->pfnDirectional;
  382. break;
  383. case D3DLIGHT_POINT:
  384. m_LightI.range_squared = m_Light.dvRange * m_Light.dvRange;
  385. m_LightI.inv_theta_minus_phi = 1.0f;
  386. m_pfnLightVertex = pTbl->pfnPoint;
  387. break;
  388. case D3DLIGHT_SPOT:
  389. m_LightI.range_squared = m_Light.dvRange * m_Light.dvRange;
  390. m_LightI.cos_theta_by_2 = (float)cos(m_Light.dvTheta / 2.0);
  391. m_LightI.cos_phi_by_2 = (float)cos(m_Light.dvPhi / 2.0);
  392. m_LightI.inv_theta_minus_phi = m_LightI.cos_theta_by_2 -
  393. m_LightI.cos_phi_by_2;
  394. if (m_LightI.inv_theta_minus_phi != 0.0)
  395. {
  396. m_LightI.inv_theta_minus_phi = 1.0f/m_LightI.inv_theta_minus_phi;
  397. }
  398. else
  399. {
  400. m_LightI.inv_theta_minus_phi = 1.0f;
  401. }
  402. m_pfnLightVertex = pTbl->pfnSpot;
  403. break;
  404. default:
  405. DPFRR( 0, "Cannot process light of unknown type" );
  406. break;
  407. }
  408. // Mark it as been processed
  409. m_dwFlags &= ~RDLIGHT_NEEDSPROCESSING;
  410. return;
  411. }
  412. void
  413. RDLight::Enable(RDLight **ppRoot)
  414. {
  415. // Assert that it is not already enabled
  416. if (IsEnabled()) return;
  417. // Assert that Root Ptr is not Null
  418. if (ppRoot == NULL) return;
  419. RDLight *pTmp = *ppRoot;
  420. *ppRoot = this;
  421. m_Next = pTmp;
  422. m_dwFlags |= (RDLIGHT_ENABLED | RDLIGHT_REFERED);
  423. return;
  424. }
  425. void
  426. RDLight::Disable(RDLight **ppRoot)
  427. {
  428. // Assert that the light is enabled
  429. if (!IsEnabled()) return;
  430. // Assert that Root Ptr is not Null
  431. if (ppRoot == NULL) return;
  432. RDLight *pLightPrev = *ppRoot;
  433. // If this is the first light in the active list
  434. if (pLightPrev == this)
  435. {
  436. *ppRoot = m_Next;
  437. m_dwFlags &= ~RDLIGHT_ENABLED;
  438. return;
  439. }
  440. while (pLightPrev->m_Next != this)
  441. {
  442. // Though this light was marked as enabled, it is not on
  443. // the active list. Assert this.
  444. if (pLightPrev->m_Next == NULL)
  445. {
  446. m_dwFlags &= ~RDLIGHT_ENABLED;
  447. return;
  448. }
  449. // Else get the next pointer
  450. pLightPrev = pLightPrev->m_Next;
  451. }
  452. pLightPrev->m_Next = m_Next;
  453. m_dwFlags &= ~RDLIGHT_ENABLED;
  454. m_dwFlags |= RDLIGHT_REFERED;
  455. return;
  456. }
  457. void
  458. RDLight::XformLight( RDMATRIX *mView )
  459. {
  460. // If the light is not a directional light,
  461. // tranform its position to camera space
  462. if (m_Light.dltType != D3DLIGHT_DIRECTIONAL)
  463. {
  464. XformBy4x3((RDVECTOR3*)&m_Light.dvPosition, mView,
  465. &m_LightI.position_in_eye);
  466. }
  467. if (m_Light.dltType != D3DLIGHT_POINT)
  468. {
  469. // Transform light direction to the eye space
  470. Xform3VecBy3x3( (RDVECTOR3*)&m_Light.dvDirection, mView,
  471. &m_LightI.direction_in_eye );
  472. // Normalize it
  473. Normalize( m_LightI.direction_in_eye );
  474. // Reverse it such that the direction is to the light
  475. ReverseVector( m_LightI.direction_in_eye, m_LightI.direction_in_eye );
  476. }
  477. return;
  478. }
  479. //---------------------------------------------------------------------
  480. // ScaleRGBColorTo255: Scales colors from 0-1 range to 0-255 range
  481. //---------------------------------------------------------------------
  482. void
  483. ScaleRGBColorTo255( const D3DCOLORVALUE& src, RDCOLOR3& dest )
  484. {
  485. dest.r = D3DVALUE(255.0) * src.r;
  486. dest.g = D3DVALUE(255.0) * src.g;
  487. dest.b = D3DVALUE(255.0) * src.b;
  488. }
  489. //---------------------------------------------------------------------
  490. // RefVP::GrowLightArray
  491. // Grows the light array and recreated the active-list
  492. // if a realloc has taken place.
  493. //---------------------------------------------------------------------
  494. HRESULT
  495. RefVP::GrowLightArray( DWORD dwIndex )
  496. {
  497. HRESULT hr = S_OK;
  498. BOOL bRealloc = FALSE;
  499. HR_RET(m_LightArray.Grow( dwIndex, &bRealloc ));
  500. if( bRealloc == TRUE )
  501. {
  502. m_lighting.pActiveLights = NULL;
  503. for( DWORD i = 0; i < m_LightArray.GetSize(); i++ )
  504. {
  505. if( m_LightArray[i].IsEnabled() )
  506. {
  507. m_LightArray[i].m_Next = m_lighting.pActiveLights;
  508. m_lighting.pActiveLights = &(m_LightArray[i]);
  509. }
  510. }
  511. }
  512. return S_OK;
  513. }
  514. //---------------------------------------------------------------------
  515. // RefVP::UpdateLightingData
  516. // Updates lighting data used by ProcessVertices
  517. //---------------------------------------------------------------------
  518. HRESULT
  519. RefVP::UpdateLightingData()
  520. {
  521. HRESULT hr = D3D_OK;
  522. RDLIGHTINGDATA& LData = m_lighting;
  523. RDLight *pLight = m_lighting.pActiveLights;
  524. RDVECTOR3 t;
  525. D3DMATERIAL7 *mat = &m_Material;
  526. //
  527. // Eye in eye space
  528. //
  529. LData.eye_in_eye.x = (D3DVALUE)0;
  530. LData.eye_in_eye.y = (D3DVALUE)0;
  531. LData.eye_in_eye.z = (D3DVALUE)0;
  532. // ATTENTION: Colorvertex may have changed the values of the
  533. // material alphas
  534. if (m_dwDirtyFlags & RDPV_DIRTY_MATERIAL)
  535. {
  536. //
  537. // Save the material to be used to light vertices
  538. //
  539. LData.material = *mat;
  540. ScaleRGBColorTo255( mat->ambient, LData.matAmb );
  541. ScaleRGBColorTo255( mat->diffuse, LData.matDiff );
  542. ScaleRGBColorTo255( mat->specular, LData.matSpec );
  543. ScaleRGBColorTo255( mat->emissive, LData.matEmis );
  544. //
  545. // Compute the Material Diffuse Alpha
  546. //
  547. LData.materialDiffAlpha = mat->diffuse.a * D3DVALUE(255);
  548. if (mat->diffuse.a < 0)
  549. LData.materialDiffAlpha = 0;
  550. else if (LData.materialDiffAlpha > 255)
  551. LData.materialDiffAlpha = 255 << 24;
  552. else LData.materialDiffAlpha <<= 24;
  553. //
  554. // Compute the Material Specular Alpha
  555. //
  556. LData.materialSpecAlpha = mat->specular.a * D3DVALUE(255);
  557. if (mat->specular.a < 0)
  558. LData.materialSpecAlpha = 0;
  559. else if (LData.materialSpecAlpha > 255)
  560. LData.materialSpecAlpha = 255 << 24;
  561. else LData.materialSpecAlpha <<= 24;
  562. //
  563. // Precompute the ambient and emissive components that are
  564. // not dependent on any contribution by the lights themselves
  565. //
  566. LData.ambEmiss.r = LData.ambient_red * LData.matAmb.r +
  567. LData.matEmis.r;
  568. LData.ambEmiss.g = LData.ambient_green * LData.matAmb.g +
  569. LData.matEmis.g;
  570. LData.ambEmiss.b = LData.ambient_blue * LData.matAmb.b +
  571. LData.matEmis.b;
  572. //
  573. // If the dot product is less than this
  574. // value, specular factor is zero
  575. //
  576. if (mat->power > D3DVAL(0.001))
  577. {
  578. LData.specThreshold = D3DVAL(pow(0.001, 1.0/mat->power));
  579. }
  580. }
  581. while (pLight)
  582. {
  583. if ((m_dwDirtyFlags & RDPV_DIRTY_MATERIAL) ||
  584. pLight->NeedsProcessing())
  585. {
  586. // If the material is dirty, light needs processing, regardless
  587. if (m_dwDirtyFlags & RDPV_DIRTY_MATERIAL)
  588. {
  589. pLight->m_dwFlags |= RDLIGHT_NEEDSPROCESSING;
  590. }
  591. // If the light has been set, or some material paramenters
  592. // changed, re-process the light.
  593. pLight->ProcessLight( &m_Material, &m_LightVertexTable );
  594. // Transform the light to Eye space
  595. // Lights are defined in world space, so simply apply the
  596. // Viewing transform
  597. pLight->XformLight( &m_xfmView );
  598. }
  599. else if (m_dwDirtyFlags & RDPV_DIRTY_NEEDXFMLIGHT)
  600. {
  601. pLight->XformLight( &m_xfmView );
  602. }
  603. pLight = pLight->m_Next;
  604. }
  605. // Clear Lighting dirty flags
  606. m_dwDirtyFlags &= ~RDPV_DIRTY_LIGHTING;
  607. return hr;
  608. }
  609. //---------------------------------------------------------------------
  610. // RefVP::UpdateFogData
  611. // Updates Fog data used by ProcessVertices
  612. //---------------------------------------------------------------------
  613. HRESULT
  614. RefVP::UpdateFogData()
  615. {
  616. HRESULT hr = D3D_OK;
  617. if (m_lighting.fog_end == m_lighting.fog_start)
  618. m_lighting.fog_factor = D3DVAL(0.0);
  619. else
  620. m_lighting.fog_factor = D3DVAL(255) / (m_lighting.fog_end -
  621. m_lighting.fog_start);
  622. // Clear Fog dirty flags
  623. m_dwDirtyFlags &= ~RDPV_DIRTY_FOG;
  624. return hr;
  625. }
  626. //---------------------------------------------------------------------
  627. // RefVP::LightVertex
  628. // Actual lighting computation takes place here
  629. //---------------------------------------------------------------------
  630. void
  631. RefVP::LightVertex(RDLIGHTINGELEMENT *pLE)
  632. {
  633. RDLIGHTINGDATA &LData = m_lighting;
  634. RDLight *pLight;
  635. //
  636. // Initialize Diffuse color with the Ambient and Emissive component
  637. // independent of the light (Ma*La + Me)
  638. //
  639. if (m_dwTLState & (RDPV_COLORVERTEXEMIS | RDPV_COLORVERTEXAMB))
  640. {
  641. // If the material values need to be replaced, compute
  642. LData.diffuse.r = LData.ambient_red * LData.pAmbientSrc->r +
  643. LData.pEmissiveSrc->r;
  644. LData.diffuse.g = LData.ambient_green * LData.pAmbientSrc->g +
  645. LData.pEmissiveSrc->g;
  646. LData.diffuse.b = LData.ambient_blue * LData.pAmbientSrc->b +
  647. LData.pEmissiveSrc->b;
  648. }
  649. else
  650. {
  651. // If none of the material values needs to be replaced
  652. LData.diffuse = LData.ambEmiss;
  653. }
  654. //
  655. // Initialize the Specular to Zero
  656. //
  657. LData.specular.r = D3DVAL(0);
  658. LData.specular.g = D3DVAL(0);
  659. LData.specular.b = D3DVAL(0);
  660. //
  661. // In a loop accumulate color from the activated lights
  662. //
  663. pLight = LData.pActiveLights;
  664. while (pLight)
  665. {
  666. if (pLight->m_pfnLightVertex)
  667. (*pLight->m_pfnLightVertex)(m_lighting,
  668. &pLight->m_Light,
  669. &pLight->m_LightI,
  670. pLE,
  671. m_dwTLState,
  672. m_qwFVFIn);
  673. pLight = pLight->m_Next;
  674. }
  675. //
  676. // Compute the diffuse color of the vertex
  677. //
  678. int r = FTOI(LData.diffuse.r);
  679. int g = FTOI(LData.diffuse.g);
  680. int b = FTOI(LData.diffuse.b);
  681. DWORD a = *LData.pDiffuseAlphaSrc;
  682. //
  683. // Clamp the r, g, b, components
  684. //
  685. if (r < 0) r = 0; else if (r > 255) r = 255;
  686. if (g < 0) g = 0; else if (g > 255) g = 255;
  687. if (b < 0) b = 0; else if (b > 255) b = 255;
  688. LData.outDiffuse = a + (r<<16) + (g<<8) + b;
  689. //
  690. // Obtain the specular Alpha
  691. //
  692. a = *(LData.pSpecularAlphaSrc);
  693. //
  694. // Compute the RGB part of the specular color
  695. //
  696. if (m_dwTLState & RDPV_DOSPECULAR)
  697. {
  698. r = FTOI(LData.specular.r);
  699. g = FTOI(LData.specular.g);
  700. b = FTOI(LData.specular.b);
  701. //
  702. // Clamp the r, g, b, components
  703. //
  704. if (r < 0) r = 0; else if (r > 255) r = 255;
  705. if (g < 0) g = 0; else if (g > 255) g = 255;
  706. if (b < 0) b = 0; else if (b > 255) b = 255;
  707. }
  708. // Need another render-state to control if the
  709. // the specular color (color2) needs to be passed down to
  710. // the rasterizer.
  711. //
  712. // If SPECULAR is not enabled but the specular color
  713. // had been provided in the input vertex, simply copy.
  714. //
  715. else if (m_qwFVFOut & D3DFVF_SPECULAR )
  716. {
  717. r = FTOI(LData.vertexSpecular.r);
  718. g = FTOI(LData.vertexSpecular.g);
  719. b = FTOI(LData.vertexSpecular.b);
  720. a = LData.vertexSpecAlpha;
  721. }
  722. //
  723. // If SpecularColor is not enabled
  724. //
  725. else
  726. {
  727. r = g = b = 0;
  728. }
  729. LData.outSpecular = a + (r<<16) + (g<<8) + b;
  730. return;
  731. }
  732. //---------------------------------------------------------------------
  733. // RefVP::FogVertex
  734. // Vertex Fog computation
  735. // Input:
  736. // v - input vertex in the model space
  737. // le - vertex, transformed to the camera space
  738. // Output:
  739. // Alpha component of pv->lighting.outSpecular is set
  740. //---------------------------------------------------------------------
  741. void
  742. RefVP::FogVertex( RDVertex& Vout, RDVECTOR3 &v, RDLIGHTINGELEMENT *pLE,
  743. int numVertexBlends, float *pBlendFactors,
  744. BOOL bVertexInEyeSpace )
  745. {
  746. D3DVALUE dist = 0.0f;
  747. //
  748. // Calculate the distance
  749. //
  750. if (bVertexInEyeSpace)
  751. {
  752. // Vertex is already transformed to the camera space
  753. if (m_dwTLState & RDPV_RANGEFOG)
  754. {
  755. dist = SQRTF(pLE->dvPosition.x*pLE->dvPosition.x +
  756. pLE->dvPosition.y*pLE->dvPosition.y +
  757. pLE->dvPosition.z*pLE->dvPosition.z);
  758. }
  759. else
  760. {
  761. dist = ABSF( pLE->dvPosition.z );
  762. }
  763. }
  764. else if (m_dwTLState & RDPV_RANGEFOG)
  765. {
  766. D3DVALUE x = 0, y = 0, z = 0;
  767. float cumulBlend = 0.0f;
  768. for( int j=0; j<=numVertexBlends; j++)
  769. {
  770. float blend;
  771. if( numVertexBlends == 0 )
  772. {
  773. blend = 1.0f;
  774. }
  775. else if( j == numVertexBlends )
  776. {
  777. blend = 1.0f - cumulBlend;
  778. }
  779. else
  780. {
  781. blend = pBlendFactors[j];
  782. cumulBlend += pBlendFactors[j];
  783. }
  784. if( m_dwTLState & RDPV_DOINDEXEDVERTEXBLEND )
  785. {
  786. BYTE m = ((BYTE *)&pBlendFactors[numVertexBlends])[j];
  787. UpdateWorld( m );
  788. x += (v.x*m_xfmToEye[m]._11 +
  789. v.y*m_xfmToEye[m]._21 +
  790. v.z*m_xfmToEye[m]._31 +
  791. m_xfmToEye[m]._41) * blend;
  792. y += (v.x*m_xfmToEye[m]._12 +
  793. v.y*m_xfmToEye[m]._22 +
  794. v.z*m_xfmToEye[m]._32 +
  795. m_xfmToEye[m]._42) * blend;
  796. z += (v.x*m_xfmToEye[m]._13 +
  797. v.y*m_xfmToEye[m]._23 +
  798. v.z*m_xfmToEye[m]._33 +
  799. m_xfmToEye[m]._43) * blend;
  800. }
  801. else
  802. {
  803. x += (v.x*m_xfmToEye[j]._11 +
  804. v.y*m_xfmToEye[j]._21 +
  805. v.z*m_xfmToEye[j]._31 +
  806. m_xfmToEye[j]._41) * blend;
  807. y += (v.x*m_xfmToEye[j]._12 +
  808. v.y*m_xfmToEye[j]._22 +
  809. v.z*m_xfmToEye[j]._32 +
  810. m_xfmToEye[j]._42) * blend;
  811. z += (v.x*m_xfmToEye[j]._13 +
  812. v.y*m_xfmToEye[j]._23 +
  813. v.z*m_xfmToEye[j]._33 +
  814. m_xfmToEye[j]._43) * blend;
  815. }
  816. }
  817. dist = SQRTF(x*x + y*y + z*z);
  818. }
  819. else
  820. {
  821. float cumulBlend = 0.0f;
  822. for( int j=0; j<=numVertexBlends; j++)
  823. {
  824. float blend;
  825. if( numVertexBlends == 0 )
  826. {
  827. blend = 1.0f;
  828. }
  829. else if( j == numVertexBlends )
  830. {
  831. blend = 1.0f - cumulBlend;
  832. }
  833. else
  834. {
  835. blend = pBlendFactors[j];
  836. cumulBlend += pBlendFactors[j];
  837. }
  838. if( m_dwTLState & RDPV_DOINDEXEDVERTEXBLEND )
  839. {
  840. BYTE m = ((BYTE *)&pBlendFactors[numVertexBlends])[j];
  841. UpdateWorld( m );
  842. dist += (v.x*m_xfmToEye[m]._13 +
  843. v.y*m_xfmToEye[m]._23 +
  844. v.z*m_xfmToEye[m]._33 +
  845. m_xfmToEye[m]._43) * blend;
  846. }
  847. else
  848. {
  849. dist += (v.x*m_xfmToEye[j]._13 +
  850. v.y*m_xfmToEye[j]._23 +
  851. v.z*m_xfmToEye[j]._33 +
  852. m_xfmToEye[j]._43) * blend;
  853. }
  854. }
  855. dist = ABSF( dist );
  856. }
  857. if (m_lighting.fog_mode == D3DFOG_LINEAR)
  858. {
  859. if (dist < m_lighting.fog_start)
  860. {
  861. Vout.m_fog = 1.0f;
  862. }
  863. else if (dist >= m_lighting.fog_end)
  864. {
  865. Vout.m_fog = 0.0f;
  866. }
  867. else
  868. {
  869. Vout.m_fog = (m_lighting.fog_end - dist) *
  870. m_lighting.fog_factor / 255.0f ;
  871. }
  872. }
  873. else
  874. {
  875. D3DVALUE tmp = dist * m_lighting.fog_density;
  876. if (m_lighting.fog_mode == D3DFOG_EXP2)
  877. {
  878. tmp *= tmp;
  879. }
  880. Vout.m_fog = (FLOAT)exp(-tmp);
  881. }
  882. return;
  883. }