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.

385 lines
12 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 "ddibase.h"
  12. //---------------------------------------------------------------------
  13. #undef DPF_MODNAME
  14. #define DPF_MODNAME "CheckLightParams"
  15. void CheckLightParams(CONST D3DLIGHT8* lpData)
  16. {
  17. if (lpData->Type != D3DLIGHT_POINT &&
  18. lpData->Type != D3DLIGHT_SPOT &&
  19. lpData->Type != D3DLIGHT_DIRECTIONAL)
  20. {
  21. D3D_ERR( "Invalid D3DLIGHT type" );
  22. throw D3DERR_INVALIDCALL;
  23. }
  24. if (lpData->Range < 0.0f || lpData->Range > D3DLIGHT_RANGE_MAX)
  25. {
  26. D3D_ERR( "Invalid D3DLIGHT range" );
  27. throw D3DERR_INVALIDCALL;
  28. }
  29. if (lpData->Type == D3DLIGHT_SPOT || lpData->Type == D3DLIGHT_DIRECTIONAL)
  30. {
  31. float magnitude;
  32. magnitude = lpData->Direction.x * lpData->Direction.x +
  33. lpData->Direction.y * lpData->Direction.y +
  34. lpData->Direction.z * lpData->Direction.z;
  35. if (magnitude < 0.00001f)
  36. {
  37. D3D_ERR( "Invalid D3DLIGHT direction" );
  38. throw D3DERR_INVALIDCALL;
  39. }
  40. if (lpData->Type == D3DLIGHT_SPOT)
  41. {
  42. if (lpData->Phi < 0.0f)
  43. {
  44. D3D_ERR( "Invalid D3DLIGHT Phi angle, must be >= 0" );
  45. throw D3DERR_INVALIDCALL;
  46. }
  47. if (lpData->Phi > 3.1415927f)
  48. {
  49. D3D_ERR( "Invalid D3DLIGHT Phi angle, must be <= pi" );
  50. throw D3DERR_INVALIDCALL;
  51. }
  52. if (lpData->Theta < 0.0f)
  53. {
  54. D3D_ERR( "Invalid D3DLIGHT Theta angle, must be >= 0" );
  55. throw D3DERR_INVALIDCALL;
  56. }
  57. if (lpData->Theta > lpData->Phi)
  58. {
  59. D3D_ERR( "Invalid D3DLIGHT Theta angle, must be <= Phi" );
  60. throw D3DERR_INVALIDCALL;
  61. }
  62. }
  63. }
  64. if (lpData->Type != D3DLIGHT_DIRECTIONAL)
  65. {
  66. if (lpData->Attenuation0 < 0 ||
  67. lpData->Attenuation1 < 0 ||
  68. lpData->Attenuation2 < 0)
  69. {
  70. D3D_ERR( "Attenuation factor can not be negative" );
  71. throw D3DERR_INVALIDCALL;
  72. }
  73. if (lpData->Attenuation0 == 0 &&
  74. lpData->Attenuation1 == 0 &&
  75. lpData->Attenuation2 == 0)
  76. {
  77. D3D_ERR("All attenuation factors are 0 for non-directional light");
  78. throw D3DERR_INVALIDCALL;
  79. }
  80. }
  81. return;
  82. }
  83. //=====================================================================
  84. //
  85. // CD3DHal interface
  86. //
  87. //=====================================================================
  88. //---------------------------------------------------------------------
  89. #undef DPF_MODNAME
  90. #define DPF_MODNAME "CD3DHal::SetMaterialFast"
  91. HRESULT D3DAPI
  92. CD3DHal::SetMaterialFast(CONST D3DMATERIAL8* lpData)
  93. {
  94. #if DBG
  95. if (!VALID_PTR(lpData, sizeof(*lpData)))
  96. {
  97. D3D_ERR("Invalid D3DMATERIAL pointer. SetMaterial failed.");
  98. return D3DERR_INVALIDCALL;
  99. }
  100. #endif
  101. m_pv->lighting.material = *lpData;
  102. this->dwFEFlags |= D3DFE_MATERIAL_DIRTY | D3DFE_FRONTEND_DIRTY;
  103. if (!(m_dwRuntimeFlags & (D3DRT_EXECUTESTATEMODE |
  104. D3DRT_RSSOFTWAREPROCESSING)))
  105. {
  106. try
  107. {
  108. m_pDDI->SetMaterial(lpData);
  109. }
  110. catch(HRESULT ret)
  111. {
  112. D3D_ERR("SetMaterial failed.");
  113. return ret;
  114. }
  115. }
  116. return S_OK;
  117. }
  118. //---------------------------------------------------------------------
  119. #undef DPF_MODNAME
  120. #define DPF_MODNAME "CD3DHal::GetMaterial"
  121. HRESULT D3DAPI CD3DHal::GetMaterial(D3DMATERIAL8* lpData)
  122. {
  123. API_ENTER(this); // Takes D3D Lock if necessary
  124. if (!VALID_WRITEPTR(lpData, sizeof(*lpData)))
  125. {
  126. D3D_ERR( "Invalid D3DMATERIAL pointer. GetMaterial failed." );
  127. return D3DERR_INVALIDCALL;
  128. }
  129. *lpData = m_pv->lighting.material;
  130. return D3D_OK;
  131. }
  132. //---------------------------------------------------------------------
  133. #undef DPF_MODNAME
  134. #define DPF_MODNAME "CD3DHal::SetLightI"
  135. void CD3DHal::SetLightI(DWORD dwLightIndex, CONST D3DLIGHT8* lpData)
  136. {
  137. if( m_pLightArray->Check( dwLightIndex ) == FALSE )
  138. {
  139. if( FAILED( m_pLightArray->Grow( dwLightIndex ) ) )
  140. {
  141. D3D_ERR("Not enough memory to grow light array");
  142. throw E_OUTOFMEMORY;
  143. }
  144. LIST_INITIALIZE(&m_ActiveLights); // Clear active light list
  145. for (DWORD i = 0; i < m_pLightArray->GetSize(); i++)
  146. {
  147. if ((*m_pLightArray)[i].m_pObj)
  148. {
  149. DIRECT3DLIGHTI* pLight =
  150. static_cast<DIRECT3DLIGHTI *>((*m_pLightArray)[i].m_pObj);
  151. if (pLight->Enabled())
  152. {
  153. LIST_INSERT_ROOT(&m_ActiveLights, pLight, m_List);
  154. }
  155. }
  156. }
  157. }
  158. if( (*m_pLightArray)[dwLightIndex].m_pObj == NULL )
  159. {
  160. // Create light has been already sent to the driver
  161. (*m_pLightArray)[dwLightIndex].m_pObj =
  162. (CD3DBaseObj *)new DIRECT3DLIGHTI;
  163. if( (*m_pLightArray)[dwLightIndex].m_pObj == NULL )
  164. {
  165. D3D_ERR("Not enough memory to grow light array");
  166. throw E_OUTOFMEMORY;
  167. }
  168. }
  169. LPDIRECT3DLIGHTI pLight =
  170. static_cast<DIRECT3DLIGHTI *>((*m_pLightArray)[dwLightIndex].m_pObj);
  171. pLight->m_Light = *lpData;
  172. if (!(this->m_dwRuntimeFlags & D3DRT_EXECUTESTATEMODE))
  173. {
  174. if (m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING)
  175. pLight->SetDirtyForDDI();
  176. else
  177. m_pDDI->SetLight(dwLightIndex, &pLight->m_Light);
  178. }
  179. dwFEFlags |= D3DFE_LIGHTS_DIRTY | D3DFE_NEED_TRANSFORM_LIGHTS | D3DFE_FRONTEND_DIRTY;
  180. pLight->m_LightI.flags |= D3DLIGHTI_DIRTY;
  181. }
  182. //---------------------------------------------------------------------
  183. #undef DPF_MODNAME
  184. #define DPF_MODNAME "CD3DHal::GetLight"
  185. HRESULT D3DAPI CD3DHal::GetLight(DWORD dwLightIndex, D3DLIGHT8* lpData)
  186. {
  187. API_ENTER(this); // Takes D3D Lock if necessary
  188. if (!VALID_WRITEPTR(lpData, sizeof(*lpData)))
  189. {
  190. D3D_ERR( "Invalid D3DLIGHT pointer. GetLight failed." );
  191. return D3DERR_INVALIDCALL;
  192. }
  193. if (m_pLightArray->Check( dwLightIndex ) == FALSE )
  194. {
  195. D3D_ERR( "Invalid light index. GetLight failed." );
  196. return D3DERR_INVALIDCALL;
  197. }
  198. LPDIRECT3DLIGHTI pLight =
  199. static_cast<DIRECT3DLIGHTI *>((*m_pLightArray)[dwLightIndex].m_pObj);
  200. if (pLight == NULL)
  201. {
  202. D3D_ERR( "Invalid light index. GetLight failed." );
  203. return D3DERR_INVALIDCALL;
  204. }
  205. *lpData = pLight->m_Light;
  206. return D3D_OK;
  207. }
  208. //---------------------------------------------------------------------
  209. #undef DPF_MODNAME
  210. #define DPF_MODNAME "CD3DHal::LightEnableI"
  211. void CD3DHal::LightEnableI(DWORD dwLightIndex, BOOL bEnable)
  212. {
  213. LPDIRECT3DLIGHTI pLight =
  214. static_cast<DIRECT3DLIGHTI *>((*m_pLightArray)[dwLightIndex].m_pObj);
  215. if (bEnable)
  216. {
  217. if (!pLight->Enabled())
  218. {
  219. LIST_INSERT_ROOT(&m_ActiveLights, pLight, m_List);
  220. pLight->m_LightI.flags |= D3DLIGHTI_ENABLED;
  221. dwFEFlags |= D3DFE_LIGHTS_DIRTY | D3DFE_NEED_TRANSFORM_LIGHTS | D3DFE_FRONTEND_DIRTY;
  222. }
  223. }
  224. else
  225. {
  226. if (pLight->Enabled())
  227. {
  228. LIST_DELETE(pLight, m_List);
  229. pLight->m_LightI.flags &= ~D3DLIGHTI_ENABLED;
  230. dwFEFlags |= D3DFE_LIGHTS_DIRTY | D3DFE_NEED_TRANSFORM_LIGHTS | D3DFE_FRONTEND_DIRTY;
  231. }
  232. }
  233. // Update driver state
  234. if (!(this->m_dwRuntimeFlags & D3DRT_EXECUTESTATEMODE))
  235. {
  236. if (this->m_dwRuntimeFlags & D3DRT_RSSOFTWAREPROCESSING)
  237. pLight->SetEnableDirtyForDDI();
  238. else
  239. m_pDDI->LightEnable(dwLightIndex, bEnable);
  240. }
  241. }
  242. //---------------------------------------------------------------------
  243. #undef DPF_MODNAME
  244. #define DPF_MODNAME "CD3DHal::LightEnable"
  245. HRESULT D3DAPI CD3DHal::GetLightEnable(DWORD dwLightIndex, BOOL *pbEnable)
  246. {
  247. API_ENTER(this); // Takes D3D Lock if necessary
  248. if (!VALID_WRITEPTR(pbEnable, sizeof(BOOL)))
  249. {
  250. D3D_ERR( "Invalid enable pointer. GetLightEnable failed." );
  251. throw D3DERR_INVALIDCALL;
  252. }
  253. if ((m_pLightArray->Check( dwLightIndex ) == FALSE)
  254. ||
  255. ((*m_pLightArray)[dwLightIndex].m_pObj == NULL))
  256. {
  257. D3D_ERR("Invalid light index OR light is not initialized. GetLightEnable failed.");
  258. return D3DERR_INVALIDCALL;
  259. }
  260. LPDIRECT3DLIGHTI pLight =
  261. static_cast<DIRECT3DLIGHTI *>((*m_pLightArray)[dwLightIndex].m_pObj);
  262. *pbEnable = pLight->Enabled();
  263. return D3D_OK;
  264. }
  265. //---------------------------------------------------------------------
  266. // Update internal light state
  267. //
  268. #undef DPF_MODNAME
  269. #define DPF_MODNAME "DIRECT3DLIGHTI::SetInternalData"
  270. HRESULT DIRECT3DLIGHTI::SetInternalData()
  271. {
  272. m_LightI.type = m_Light.Type;
  273. m_LightI.flags &= ~D3DLIGHTI_OPTIMIZATIONFLAGS;
  274. if (FLOAT_EQZ(m_Light.Specular.r) &&
  275. FLOAT_EQZ(m_Light.Specular.g) &&
  276. FLOAT_EQZ(m_Light.Specular.b))
  277. {
  278. m_LightI.flags |= D3DLIGHTI_SPECULAR_IS_ZERO;
  279. }
  280. if (FLOAT_EQZ(m_Light.Ambient.r) &&
  281. FLOAT_EQZ(m_Light.Ambient.g) &&
  282. FLOAT_EQZ(m_Light.Ambient.b))
  283. {
  284. m_LightI.flags |= D3DLIGHTI_AMBIENT_IS_ZERO;
  285. }
  286. m_LightI.ambient.r = m_Light.Ambient.r;
  287. m_LightI.ambient.g = m_Light.Ambient.g;
  288. m_LightI.ambient.b = m_Light.Ambient.b;
  289. m_LightI.specular.r = m_Light.Specular.r;
  290. m_LightI.specular.g = m_Light.Specular.g;
  291. m_LightI.specular.b = m_Light.Specular.b;
  292. m_LightI.diffuse.r = m_Light.Diffuse.r;
  293. m_LightI.diffuse.g = m_Light.Diffuse.g;
  294. m_LightI.diffuse.b = m_Light.Diffuse.b;
  295. m_LightI.position.x = m_Light.Position.x;
  296. m_LightI.position.y = m_Light.Position.y;
  297. m_LightI.position.z = m_Light.Position.z;
  298. m_LightI.direction.x = m_Light.Direction.x;
  299. m_LightI.direction.y = m_Light.Direction.y;
  300. m_LightI.direction.z = m_Light.Direction.z;
  301. m_LightI.attenuation0 = m_Light.Attenuation0;
  302. m_LightI.attenuation1 = m_Light.Attenuation1;
  303. m_LightI.attenuation2 = m_Light.Attenuation2;
  304. m_LightI.range = m_Light.Range;
  305. m_LightI.range_squared = m_Light.Range * m_Light.Range;
  306. if (m_Light.Type == D3DLIGHT_SPOT)
  307. {
  308. m_LightI.cos_theta_by_2 = (float)cos(m_Light.Theta / 2.0);
  309. m_LightI.cos_phi_by_2 = (float)cos(m_Light.Phi / 2.0);
  310. m_LightI.falloff = m_Light.Falloff;
  311. m_LightI.inv_theta_minus_phi = m_LightI.cos_theta_by_2 -
  312. m_LightI.cos_phi_by_2;
  313. if (m_LightI.inv_theta_minus_phi != 0.0)
  314. {
  315. m_LightI.inv_theta_minus_phi = 1.0f/m_LightI.inv_theta_minus_phi;
  316. }
  317. else
  318. {
  319. m_LightI.inv_theta_minus_phi = 1.0f;
  320. }
  321. }
  322. if (m_Light.Type == D3DLIGHT_DIRECTIONAL ||
  323. m_Light.Type == D3DLIGHT_SPOT)
  324. {
  325. VecNormalize(m_LightI.direction);
  326. }
  327. // set internal flags
  328. if (m_LightI.attenuation0 != 0.0)
  329. {
  330. m_LightI.flags |= D3DLIGHTI_ATT0_IS_NONZERO;
  331. }
  332. if (m_LightI.attenuation1 != 0.0)
  333. {
  334. m_LightI.flags |= D3DLIGHTI_ATT1_IS_NONZERO;
  335. }
  336. if (m_LightI.attenuation2 != 0.0)
  337. {
  338. m_LightI.flags |= D3DLIGHTI_ATT2_IS_NONZERO;
  339. }
  340. if (m_LightI.falloff == 1.0)
  341. {
  342. m_LightI.flags |= D3DLIGHTI_LINEAR_FALLOFF;
  343. }
  344. m_LightI.flags &= ~D3DLIGHTI_DIRTY;
  345. return D3D_OK;
  346. }