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.

419 lines
13 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1998 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: lighting.cpp
  6. * Content: Direct3D material/light management
  7. *
  8. ***************************************************************************/
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. #include "tlhal.h"
  12. //---------------------------------------------------------------------
  13. #undef DPF_MODNAME
  14. #define DPF_MODNAME "CheckLightParams"
  15. void CheckLightParams(LPD3DLIGHT7 lpData)
  16. {
  17. if (!VALID_D3DLIGHT_PTR(lpData))
  18. {
  19. D3D_ERR( "Invalid D3DLIGHT pointer" );
  20. throw DDERR_INVALIDPARAMS;
  21. }
  22. if (lpData->dltType != D3DLIGHT_POINT &&
  23. lpData->dltType != D3DLIGHT_SPOT &&
  24. lpData->dltType != D3DLIGHT_DIRECTIONAL)
  25. {
  26. D3D_ERR( "Invalid D3DLIGHT type" );
  27. throw DDERR_INVALIDPARAMS;
  28. }
  29. if (lpData->dvRange < 0.0f || lpData->dvRange > D3DLIGHT_RANGE_MAX)
  30. {
  31. D3D_ERR( "Invalid D3DLIGHT range" );
  32. throw DDERR_INVALIDPARAMS;
  33. }
  34. if (lpData->dltType == D3DLIGHT_SPOT || lpData->dltType == D3DLIGHT_DIRECTIONAL)
  35. {
  36. float magnitude;
  37. magnitude = lpData->dvDirection.x * lpData->dvDirection.x +
  38. lpData->dvDirection.y * lpData->dvDirection.y +
  39. lpData->dvDirection.z * lpData->dvDirection.z;
  40. if (magnitude < 0.00001f)
  41. {
  42. D3D_ERR( "Invalid D3DLIGHT direction" );
  43. throw DDERR_INVALIDPARAMS;
  44. }
  45. if (lpData->dltType == D3DLIGHT_SPOT)
  46. {
  47. if (lpData->dvPhi < 0.0f)
  48. {
  49. D3D_ERR( "Invalid D3DLIGHT Phi angle, must be >= 0" );
  50. throw DDERR_INVALIDPARAMS;
  51. }
  52. if (lpData->dvPhi > 3.1415927f)
  53. {
  54. D3D_ERR( "Invalid D3DLIGHT Phi angle, must be <= pi" );
  55. throw DDERR_INVALIDPARAMS;
  56. }
  57. if (lpData->dvTheta < 0.0f)
  58. {
  59. D3D_ERR( "Invalid D3DLIGHT Theta angle, must be >= 0" );
  60. throw DDERR_INVALIDPARAMS;
  61. }
  62. if (lpData->dvTheta > lpData->dvPhi)
  63. {
  64. D3D_ERR( "Invalid D3DLIGHT Theta angle, must be <= Phi" );
  65. throw DDERR_INVALIDPARAMS;
  66. }
  67. if (lpData->dvAttenuation0 < 0 ||
  68. lpData->dvAttenuation1 < 0 ||
  69. lpData->dvAttenuation2 < 0)
  70. {
  71. D3D_ERR( "Attenuation factor can not be negative" );
  72. throw DDERR_INVALIDPARAMS;
  73. }
  74. }
  75. }
  76. return;
  77. }
  78. //=====================================================================
  79. //
  80. // DIRECT3DDEVICEI interface
  81. //
  82. //=====================================================================
  83. //---------------------------------------------------------------------
  84. #undef DPF_MODNAME
  85. #define DPF_MODNAME "DIRECT3DDEVICEI::SetMaterialI"
  86. void DIRECT3DDEVICEI::SetMaterialI(LPD3DMATERIAL7 lpData)
  87. {
  88. this->lighting.material = *lpData;
  89. this->MaterialChanged();
  90. }
  91. //---------------------------------------------------------------------
  92. #undef DPF_MODNAME
  93. #define DPF_MODNAME "DIRECT3DDEVICEI::SetMaterial"
  94. HRESULT D3DAPI DIRECT3DDEVICEI::SetMaterial(LPD3DMATERIAL7 lpData)
  95. {
  96. if (!VALID_D3DMATERIAL_PTR(lpData))
  97. {
  98. D3D_ERR( "Invalid D3DMATERIAL pointer" );
  99. return DDERR_INVALIDPARAMS;
  100. }
  101. try
  102. {
  103. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  104. if (this->dwFEFlags & D3DFE_RECORDSTATEMODE)
  105. m_pStateSets->InsertMaterial(lpData);
  106. else
  107. this->SetMaterialI(lpData);
  108. return D3D_OK;
  109. }
  110. catch(HRESULT ret)
  111. {
  112. return ret;
  113. }
  114. }
  115. //---------------------------------------------------------------------
  116. #undef DPF_MODNAME
  117. #define DPF_MODNAME "DIRECT3DDEVICEI::GetMaterial"
  118. HRESULT D3DAPI DIRECT3DDEVICEI::GetMaterial(LPD3DMATERIAL7 lpData)
  119. {
  120. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  121. if (!VALID_D3DMATERIAL_PTR(lpData))
  122. {
  123. D3D_ERR( "Invalid D3DMATERIAL pointer" );
  124. return DDERR_INVALIDPARAMS;
  125. }
  126. *lpData = this->lighting.material;
  127. return D3D_OK;
  128. }
  129. //---------------------------------------------------------------------
  130. #undef DPF_MODNAME
  131. #define DPF_MODNAME "DIRECT3DDEVICEI::SetLightI"
  132. void DIRECT3DDEVICEI::SetLightI(DWORD dwLightIndex, LPD3DLIGHT7 lpData)
  133. {
  134. if (dwLightIndex >= m_dwNumLights)
  135. {
  136. // Now we have to grow the light array. We create new array and copy
  137. // old lights there.
  138. DIRECT3DLIGHTI *pLights = new DIRECT3DLIGHTI[dwLightIndex + 10];
  139. if (pLights == NULL)
  140. {
  141. D3D_ERR("Not enough memory to grow light array");
  142. throw DDERR_OUTOFMEMORY;
  143. }
  144. LIST_INITIALIZE(&m_ActiveLights); // Clear active light list
  145. for (DWORD i = 0; i < m_dwNumLights; i++)
  146. {
  147. if (m_pLights[i].Valid())
  148. {
  149. pLights[i] = m_pLights[i];
  150. if (pLights[i].Enabled())
  151. LIST_INSERT_ROOT(&m_ActiveLights, &pLights[i], m_List);
  152. }
  153. }
  154. m_dwNumLights = dwLightIndex + 10;
  155. DIRECT3DLIGHTI *pLightsTemp = m_pLights;
  156. m_pLights = pLights;
  157. delete [] pLightsTemp;
  158. }
  159. LPDIRECT3DLIGHTI pLight = &m_pLights[dwLightIndex];
  160. pLight->m_Light = *lpData;
  161. this->LightChanged(dwLightIndex);
  162. }
  163. //---------------------------------------------------------------------
  164. #undef DPF_MODNAME
  165. #define DPF_MODNAME "DIRECT3DDEVICEI::SetLight"
  166. HRESULT D3DAPI DIRECT3DDEVICEI::SetLight(DWORD dwLightIndex, LPD3DLIGHT7 lpData)
  167. {
  168. try
  169. {
  170. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  171. CheckLightParams(lpData);
  172. if (this->dwFEFlags & D3DFE_RECORDSTATEMODE)
  173. m_pStateSets->InsertLight(dwLightIndex, lpData);
  174. else
  175. this->SetLightI(dwLightIndex, lpData);
  176. return D3D_OK;
  177. }
  178. catch(HRESULT ret)
  179. {
  180. return ret;
  181. }
  182. }
  183. //---------------------------------------------------------------------
  184. #undef DPF_MODNAME
  185. #define DPF_MODNAME "DIRECT3DDEVICEI::GetLight"
  186. HRESULT D3DAPI DIRECT3DDEVICEI::GetLight(DWORD dwLightIndex, LPD3DLIGHT7 lpData)
  187. {
  188. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  189. if (!VALID_D3DLIGHT_PTR(lpData))
  190. {
  191. D3D_ERR( "Invalid D3DLIGHT pointer" );
  192. return DDERR_INVALIDPARAMS;
  193. }
  194. if (dwLightIndex >= m_dwNumLights)
  195. {
  196. D3D_ERR( "Invalid light index" );
  197. return DDERR_INVALIDPARAMS;
  198. }
  199. DIRECT3DLIGHTI *pLight = &m_pLights[dwLightIndex];
  200. if (!pLight->Valid())
  201. {
  202. return DDERR_INVALIDPARAMS;
  203. }
  204. *lpData = pLight->m_Light;
  205. return D3D_OK;
  206. }
  207. //---------------------------------------------------------------------
  208. #undef DPF_MODNAME
  209. #define DPF_MODNAME "DIRECT3DDEVICEI::MaterialChanged"
  210. void DIRECT3DDEVICEI::MaterialChanged()
  211. {
  212. this->dwFEFlags |= D3DFE_MATERIAL_DIRTY | D3DFE_FRONTEND_DIRTY;
  213. }
  214. //---------------------------------------------------------------------
  215. #undef DPF_MODNAME
  216. #define DPF_MODNAME "DIRECT3DDEVICEI::LightChanged"
  217. void DIRECT3DDEVICEI::LightChanged(DWORD dwLightIndex)
  218. {
  219. dwFEFlags |= D3DFE_LIGHTS_DIRTY | D3DFE_NEED_TRANSFORM_LIGHTS | D3DFE_FRONTEND_DIRTY;
  220. // Valid flag should be set in this function, because
  221. // CDirect3DDeviceTL uses this flag to check if the light is set
  222. // first time
  223. m_pLights[dwLightIndex].m_LightI.flags |= D3DLIGHTI_VALID | D3DLIGHTI_DIRTY;
  224. }
  225. //---------------------------------------------------------------------
  226. #undef DPF_MODNAME
  227. #define DPF_MODNAME "DIRECT3DDEVICEI::LightEnableI"
  228. void DIRECT3DDEVICEI::LightEnableI(DWORD dwLightIndex, BOOL bEnable)
  229. {
  230. if (dwLightIndex >= m_dwNumLights ||
  231. !m_pLights[dwLightIndex].Valid())
  232. {
  233. // Set default value to the light
  234. D3DLIGHT7 light;
  235. memset(&light, 0, sizeof(light));
  236. light.dltType = D3DLIGHT_DIRECTIONAL;
  237. light.dvDirection.x = D3DVAL(0);
  238. light.dvDirection.y = D3DVAL(0);
  239. light.dvDirection.z = D3DVAL(1);
  240. light.dcvDiffuse.r = D3DVAL(1);
  241. light.dcvDiffuse.g = D3DVAL(1);
  242. light.dcvDiffuse.b = D3DVAL(1);
  243. SetLightI(dwLightIndex, &light);
  244. }
  245. LPDIRECT3DLIGHTI pLight = &m_pLights[dwLightIndex];
  246. if (bEnable)
  247. {
  248. if (!pLight->Enabled())
  249. {
  250. LIST_INSERT_ROOT(&m_ActiveLights, pLight, m_List);
  251. pLight->m_LightI.flags |= D3DLIGHTI_ENABLED;
  252. dwFEFlags |= D3DFE_LIGHTS_DIRTY | D3DFE_NEED_TRANSFORM_LIGHTS | D3DFE_FRONTEND_DIRTY;
  253. }
  254. }
  255. else
  256. {
  257. if (pLight->Enabled())
  258. {
  259. LIST_DELETE(pLight, m_List);
  260. pLight->m_LightI.flags &= ~D3DLIGHTI_ENABLED;
  261. dwFEFlags |= D3DFE_LIGHTS_DIRTY | D3DFE_NEED_TRANSFORM_LIGHTS | D3DFE_FRONTEND_DIRTY;
  262. }
  263. }
  264. }
  265. //---------------------------------------------------------------------
  266. #undef DPF_MODNAME
  267. #define DPF_MODNAME "DIRECT3DDEVICEI::LightEnable"
  268. HRESULT D3DAPI DIRECT3DDEVICEI::LightEnable(DWORD dwLightIndex, BOOL bEnable)
  269. {
  270. try
  271. {
  272. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  273. if (this->dwFEFlags & D3DFE_RECORDSTATEMODE)
  274. m_pStateSets->InsertLightEnable(dwLightIndex, bEnable);
  275. else
  276. LightEnableI(dwLightIndex, bEnable);
  277. return D3D_OK;
  278. }
  279. catch (HRESULT ret)
  280. {
  281. return ret;
  282. }
  283. }
  284. //---------------------------------------------------------------------
  285. #undef DPF_MODNAME
  286. #define DPF_MODNAME "DIRECT3DDEVICEI::GetLightEnable"
  287. HRESULT D3DAPI DIRECT3DDEVICEI::GetLightEnable(DWORD dwLightIndex, BOOL *pbEnable)
  288. {
  289. CLockD3D lockObject(DPF_MODNAME, REMIND("")); // Takes D3D lock.
  290. if (dwLightIndex >= m_dwNumLights ||
  291. !m_pLights[dwLightIndex].Valid())
  292. {
  293. D3D_ERR("Invalid light index OR light is not initialized");
  294. return DDERR_INVALIDPARAMS;
  295. }
  296. *pbEnable = m_pLights[dwLightIndex].Enabled();
  297. return D3D_OK;
  298. }
  299. //---------------------------------------------------------------------
  300. // Update internal light state
  301. //
  302. #undef DPF_MODNAME
  303. #define DPF_MODNAME "DIRECT3DLIGHTI::SetInternalData"
  304. HRESULT DIRECT3DLIGHTI::SetInternalData()
  305. {
  306. m_LightI.type = m_Light.dltType;
  307. m_LightI.flags &= ~D3DLIGHTI_OPTIMIZATIONFLAGS;
  308. if (FLOAT_EQZ(m_Light.dcvSpecular.r) &&
  309. FLOAT_EQZ(m_Light.dcvSpecular.g) &&
  310. FLOAT_EQZ(m_Light.dcvSpecular.b))
  311. {
  312. m_LightI.flags |= D3DLIGHTI_SPECULAR_IS_ZERO;
  313. }
  314. if (FLOAT_EQZ(m_Light.dcvAmbient.r) &&
  315. FLOAT_EQZ(m_Light.dcvAmbient.g) &&
  316. FLOAT_EQZ(m_Light.dcvAmbient.b))
  317. {
  318. m_LightI.flags |= D3DLIGHTI_AMBIENT_IS_ZERO;
  319. }
  320. m_LightI.ambient.r = m_Light.dcvAmbient.r;
  321. m_LightI.ambient.g = m_Light.dcvAmbient.g;
  322. m_LightI.ambient.b = m_Light.dcvAmbient.b;
  323. m_LightI.specular.r = m_Light.dcvSpecular.r;
  324. m_LightI.specular.g = m_Light.dcvSpecular.g;
  325. m_LightI.specular.b = m_Light.dcvSpecular.b;
  326. m_LightI.diffuse.r = m_Light.dcvDiffuse.r;
  327. m_LightI.diffuse.g = m_Light.dcvDiffuse.g;
  328. m_LightI.diffuse.b = m_Light.dcvDiffuse.b;
  329. m_LightI.position.x = m_Light.dvPosition.x;
  330. m_LightI.position.y = m_Light.dvPosition.y;
  331. m_LightI.position.z = m_Light.dvPosition.z;
  332. m_LightI.direction.x = m_Light.dvDirection.x;
  333. m_LightI.direction.y = m_Light.dvDirection.y;
  334. m_LightI.direction.z = m_Light.dvDirection.z;
  335. m_LightI.attenuation0 = m_Light.dvAttenuation0;
  336. m_LightI.attenuation1 = m_Light.dvAttenuation1;
  337. m_LightI.attenuation2 = m_Light.dvAttenuation2;
  338. m_LightI.range = m_Light.dvRange;
  339. m_LightI.range_squared = m_Light.dvRange * m_Light.dvRange;
  340. if (m_Light.dltType == D3DLIGHT_SPOT)
  341. {
  342. m_LightI.cos_theta_by_2 = (float)cos(m_Light.dvTheta / 2.0);
  343. m_LightI.cos_phi_by_2 = (float)cos(m_Light.dvPhi / 2.0);
  344. m_LightI.falloff = m_Light.dvFalloff;
  345. m_LightI.inv_theta_minus_phi = m_LightI.cos_theta_by_2 -
  346. m_LightI.cos_phi_by_2;
  347. if (m_LightI.inv_theta_minus_phi != 0.0)
  348. {
  349. m_LightI.inv_theta_minus_phi = 1.0f/m_LightI.inv_theta_minus_phi;
  350. }
  351. else
  352. {
  353. m_LightI.inv_theta_minus_phi = 1.0f;
  354. }
  355. }
  356. if (m_Light.dltType == D3DLIGHT_DIRECTIONAL ||
  357. m_Light.dltType == D3DLIGHT_SPOT)
  358. {
  359. VecNormalize(m_LightI.direction);
  360. }
  361. // set internal flags
  362. if (m_LightI.attenuation0 != 0.0)
  363. {
  364. m_LightI.flags |= D3DLIGHTI_ATT0_IS_NONZERO;
  365. }
  366. if (m_LightI.attenuation1 != 0.0)
  367. {
  368. m_LightI.flags |= D3DLIGHTI_ATT1_IS_NONZERO;
  369. }
  370. if (m_LightI.attenuation2 != 0.0)
  371. {
  372. m_LightI.flags |= D3DLIGHTI_ATT2_IS_NONZERO;
  373. }
  374. if (m_LightI.falloff == 1.0)
  375. {
  376. m_LightI.flags |= D3DLIGHTI_LINEAR_FALLOFF;
  377. }
  378. m_LightI.flags &= ~D3DLIGHTI_DIRTY;
  379. return D3D_OK;
  380. }