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.

278 lines
10 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1998 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: rgblt.cpp
  6. * Content: Direct3D lighting
  7. *
  8. ***************************************************************************/
  9. #include "pch.cpp"
  10. #pragma hdrstop
  11. #include "light.h"
  12. #include "drawprim.hpp"
  13. // Functions to use when lighting is done in the camera space
  14. LIGHT_VERTEX_FUNC_TABLE lightVertexTable =
  15. {
  16. Directional7,
  17. PointSpot7,
  18. DirectionalFirst,
  19. DirectionalNext,
  20. PointSpotFirst,
  21. PointSpotNext
  22. };
  23. // Functions to use when lighting is done in the model space
  24. static LIGHT_VERTEX_FUNC_TABLE lightVertexTableModel =
  25. {
  26. Directional7Model,
  27. PointSpot7Model,
  28. DirectionalFirstModel,
  29. DirectionalNextModel,
  30. PointSpotFirstModel,
  31. PointSpotNextModel
  32. };
  33. //-------------------------------------------------------------------------
  34. SpecularTable* CreateSpecularTable(D3DVALUE power)
  35. {
  36. SpecularTable* spec;
  37. int i;
  38. float delta = 1.0f/255.0f;
  39. float v;
  40. D3DMalloc((void**)&spec, sizeof(SpecularTable));
  41. if (spec == NULL)
  42. return NULL;
  43. spec->power = power;
  44. v = 0.0;
  45. for (i = 0; i < 256; i++)
  46. {
  47. spec->table[i] = powf(v, power);
  48. v += delta;
  49. }
  50. for (; i < 260; i++)
  51. spec->table[i] = 1.0f;
  52. return spec;
  53. }
  54. //-------------------------------------------------------------------------
  55. static void inverseRotateVector(D3DVECTOR* d,
  56. D3DVECTOR* v, D3DMATRIXI* M)
  57. {
  58. D3DVALUE vx = v->x;
  59. D3DVALUE vy = v->y;
  60. D3DVALUE vz = v->z;
  61. d->x = RLDDIFMul16(vx, M->_11) + RLDDIFMul16(vy, M->_12) + RLDDIFMul16(vz, M->_13);
  62. d->y = RLDDIFMul16(vx, M->_21) + RLDDIFMul16(vy, M->_22) + RLDDIFMul16(vz, M->_23);
  63. d->z = RLDDIFMul16(vx, M->_31) + RLDDIFMul16(vy, M->_32) + RLDDIFMul16(vz, M->_33);
  64. }
  65. static void inverseTransformVector(D3DVECTOR* result,
  66. D3DVECTOR* v, D3DMATRIXI* M)
  67. {
  68. D3DVALUE vx = v->x;
  69. D3DVALUE vy = v->y;
  70. D3DVALUE vz = v->z;
  71. vx -= M->_41; vy -= M->_42; vz -= M->_43;
  72. result->x = RLDDIFMul16(vx, M->_11) + RLDDIFMul16(vy, M->_12) + RLDDIFMul16(vz, M->_13);
  73. result->y = RLDDIFMul16(vx, M->_21) + RLDDIFMul16(vy, M->_22) + RLDDIFMul16(vz, M->_23);
  74. result->z = RLDDIFMul16(vx, M->_31) + RLDDIFMul16(vy, M->_32) + RLDDIFMul16(vz, M->_33);
  75. }
  76. //-----------------------------------------------------------------------
  77. // Every time the world matrix is modified or lights data is changed the
  78. // lighting vectors have to change to match the model space of the new data
  79. // to be rendered.
  80. // Every time light data is changed or material data is changed or lighting
  81. // state is changed, some pre-computed lighting values sould be updated
  82. //
  83. void D3DFE_UpdateLights(LPD3DHAL lpDevI)
  84. {
  85. D3DFE_PROCESSVERTICES* pv = lpDevI->m_pv;
  86. D3DFE_LIGHTING& LIGHTING = pv->lighting;
  87. D3DI_LIGHT *light = LIGHTING.activeLights;
  88. D3DVECTOR t;
  89. BOOL specular; // TRUE, if specular component sould be computed
  90. D3DMATERIAL8 *mat = &LIGHTING.material;
  91. if (lpDevI->dwFEFlags & (D3DFE_MATERIAL_DIRTY | D3DFE_LIGHTS_DIRTY))
  92. {
  93. SpecularTable* spec;
  94. for (spec = LIST_FIRST(&lpDevI->specular_tables);
  95. spec;
  96. spec = LIST_NEXT(spec,list))
  97. {
  98. if (spec->power == pv->lighting.material.Power)
  99. break;
  100. }
  101. if (spec == NULL)
  102. {
  103. spec = CreateSpecularTable(pv->lighting.material.Power);
  104. if (spec == NULL)
  105. {
  106. D3D_ERR("Failed to allocate internal specular table");
  107. throw E_OUTOFMEMORY;
  108. }
  109. LIST_INSERT_ROOT(&lpDevI->specular_tables, spec, list);
  110. }
  111. lpDevI->specular_table = spec;
  112. if (pv->lighting.material.Power > D3DVAL(0.001))
  113. pv->lighting.specThreshold = D3DVAL(pow(0.001, 1.0/pv->lighting.material.Power));
  114. else
  115. pv->lighting.specThreshold = 0;
  116. if (lpDevI->specular_table && pv->dwDeviceFlags & D3DDEV_SPECULARENABLE)
  117. specular = TRUE;
  118. else
  119. specular = FALSE;
  120. LIGHTING.materialAlpha = FTOI(D3DVAL(255) * mat->Diffuse.a);
  121. if (LIGHTING.materialAlpha < 0)
  122. LIGHTING.materialAlpha = 0;
  123. else
  124. if (LIGHTING.materialAlpha > 255)
  125. LIGHTING.materialAlpha = 255 << 24;
  126. else LIGHTING.materialAlpha <<= 24;
  127. LIGHTING.materialAlphaS = FTOI(D3DVAL(255) * mat->Specular.a);
  128. if (LIGHTING.materialAlphaS < 0)
  129. LIGHTING.materialAlphaS = 0;
  130. else
  131. if (LIGHTING.materialAlphaS > 255)
  132. LIGHTING.materialAlphaS = 255 << 24;
  133. else LIGHTING.materialAlphaS <<= 24;
  134. LIGHTING.currentSpecTable = lpDevI->specular_table->table;
  135. LIGHTING.diffuse0.r = LIGHTING.ambientSceneScaled.r * mat->Ambient.r;
  136. LIGHTING.diffuse0.g = LIGHTING.ambientSceneScaled.g * mat->Ambient.g;
  137. LIGHTING.diffuse0.b = LIGHTING.ambientSceneScaled.b * mat->Ambient.b;
  138. LIGHTING.diffuse0.r += mat->Emissive.r * D3DVAL(255);
  139. LIGHTING.diffuse0.g += mat->Emissive.g * D3DVAL(255);
  140. LIGHTING.diffuse0.b += mat->Emissive.b * D3DVAL(255);
  141. int r,g,b;
  142. r = (int)FTOI(LIGHTING.diffuse0.r);
  143. g = (int)FTOI(LIGHTING.diffuse0.g);
  144. b = (int)FTOI(LIGHTING.diffuse0.b);
  145. if (r < 0) r = 0; else if (r > 255) r = 255;
  146. if (g < 0) g = 0; else if (g > 255) g = 255;
  147. if (b < 0) b = 0; else if (b > 255) b = 255;
  148. LIGHTING.dwDiffuse0 = (r << 16) + (g << 8) + b;
  149. }
  150. pv->lighting.model_eye.x = (D3DVALUE)0;
  151. pv->lighting.model_eye.y = (D3DVALUE)0;
  152. pv->lighting.model_eye.z = (D3DVALUE)0;
  153. pv->lighting.directionToCamera.x = 0;
  154. pv->lighting.directionToCamera.y = 0;
  155. pv->lighting.directionToCamera.z = -1;
  156. if (pv->dwDeviceFlags & D3DDEV_MODELSPACELIGHTING)
  157. {
  158. inverseTransformVector(&pv->lighting.model_eye,
  159. &pv->lighting.model_eye,
  160. &pv->mWV[0]);
  161. lpDevI->lightVertexFuncTable = &lightVertexTableModel;
  162. inverseRotateVector(&pv->lighting.directionToCamera,
  163. &pv->lighting.directionToCamera,
  164. &pv->mWV[0]);
  165. }
  166. else
  167. {
  168. lpDevI->lightVertexFuncTable = &lightVertexTable;
  169. }
  170. while (light)
  171. {
  172. // Whenever light type is changed the D3DFE_NEED_TRANSFORM_LIGHTS should be set
  173. if (lpDevI->dwFEFlags & D3DFE_NEED_TRANSFORM_LIGHTS)
  174. {
  175. if (light->type != D3DLIGHT_DIRECTIONAL)
  176. { // Point and Spot lights
  177. light->lightVertexFunc = lpDevI->lightVertexFuncTable->pfnPointSpot;
  178. light->pfnLightFirst = lpDevI->lightVertexFuncTable->pfnPointSpotFirst;
  179. light->pfnLightNext = lpDevI->lightVertexFuncTable->pfnPointSpotNext;
  180. if (!(pv->dwDeviceFlags & D3DDEV_MODELSPACELIGHTING))
  181. {
  182. // Transform light position to the camera space
  183. VecMatMul(&light->position,
  184. (D3DMATRIX*)&pv->view,
  185. &light->model_position);
  186. }
  187. else
  188. {
  189. inverseTransformVector(&light->model_position, &light->position,
  190. &pv->world[0]);
  191. }
  192. }
  193. else
  194. { // Directional light
  195. light->lightVertexFunc = lpDevI->lightVertexFuncTable->pfnDirectional;
  196. light->pfnLightFirst = lpDevI->lightVertexFuncTable->pfnDirectionalFirst;
  197. light->pfnLightNext = lpDevI->lightVertexFuncTable->pfnDirectionalNext;
  198. }
  199. if (light->type != D3DLIGHT_POINT)
  200. {
  201. // Light direction is flipped to be the direction TO the light
  202. if (!(pv->dwDeviceFlags & D3DDEV_MODELSPACELIGHTING))
  203. {
  204. // Transform light direction to the camera space
  205. VecMatMul3(&light->direction,
  206. (D3DMATRIX*)&pv->view,
  207. &light->model_direction);
  208. VecNormalizeFast(light->model_direction);
  209. }
  210. else
  211. {
  212. inverseRotateVector(&light->model_direction, &light->direction,
  213. &pv->world[0]);
  214. }
  215. VecNeg(light->model_direction, light->model_direction);
  216. // For the infinite viewer the half vector is constant
  217. if (!(pv->dwDeviceFlags & D3DDEV_LOCALVIEWER))
  218. {
  219. VecAdd(light->model_direction, pv->lighting.directionToCamera,
  220. light->halfway);
  221. VecNormalizeFast(light->halfway);
  222. }
  223. }
  224. }
  225. if (lpDevI->dwFEFlags & (D3DFE_MATERIAL_DIRTY | D3DFE_LIGHTS_DIRTY))
  226. {
  227. light->diffuseMat.r = D3DVAL(255) * mat->Diffuse.r * light->diffuse.r;
  228. light->diffuseMat.g = D3DVAL(255) * mat->Diffuse.g * light->diffuse.g;
  229. light->diffuseMat.b = D3DVAL(255) * mat->Diffuse.b * light->diffuse.b;
  230. if (!(light->flags & D3DLIGHTI_AMBIENT_IS_ZERO))
  231. {
  232. light->ambientMat.r = D3DVAL(255) * mat->Ambient.r * light->ambient.r;
  233. light->ambientMat.g = D3DVAL(255) * mat->Ambient.g * light->ambient.g;
  234. light->ambientMat.b = D3DVAL(255) * mat->Ambient.b * light->ambient.b;
  235. }
  236. if (specular && !(light->flags & D3DLIGHTI_SPECULAR_IS_ZERO))
  237. {
  238. light->flags |= D3DLIGHTI_COMPUTE_SPECULAR;
  239. light->specularMat.r = D3DVAL(255) * mat->Specular.r * light->specular.r;
  240. light->specularMat.g = D3DVAL(255) * mat->Specular.g * light->specular.g;
  241. light->specularMat.b = D3DVAL(255) * mat->Specular.b * light->specular.b;
  242. }
  243. else
  244. light->flags &= ~D3DLIGHTI_COMPUTE_SPECULAR;
  245. }
  246. light = light->next;
  247. }
  248. lpDevI->dwFEFlags &= ~(D3DFE_MATERIAL_DIRTY |
  249. D3DFE_NEED_TRANSFORM_LIGHTS |
  250. D3DFE_LIGHTS_DIRTY);
  251. } // end of updateLights()