light.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. /*
  2. ** Command & Conquer Generals(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : WW3D *
  23. * *
  24. * $Archive:: /Commando/Code/ww3d2/light.cpp $*
  25. * *
  26. * $Author:: Ian_l $*
  27. * *
  28. * $Modtime:: 7/10/01 2:27p $*
  29. * *
  30. * $Revision:: 8 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * LightClass::LightClass -- Constructor *
  35. * LightClass::LightClass -- copy constructor *
  36. * LightClass::operator == -- assignment operator *
  37. * LightClass::~LightClass -- destructor *
  38. * LightClass::Clone -- virtual copy constructor *
  39. * LightClass::Get_Attenuation_Range -- returns a dist beyond which the light is attenuated *
  40. * LightClass::Get_Obj_Space_Bounding_Sphere -- returns the object space bounding sphere *
  41. * LightClass::Get_Obj_Space_Bounding_Box -- returns the object space bounding box *
  42. * LightClass::Vertex_Processor_Push -- pushes the light into the GERD *
  43. * LightClass::Vertex_Processor_Pop -- pops the light from the GERD *
  44. * LightClass::Set_Transform -- sets transform and marks srLight transform as dirty. *
  45. * LightClass::Set_Position -- sets position and marks srLight transform as dirty. *
  46. * LightClass::Notify_Added -- lights add themselves to the VP list when added *
  47. * LightClass::Notify_Removed -- lights remove themselves from the VP list when removed *
  48. * LightClass::Load_W3D -- Initialize this light from a W3D file *
  49. * LightClass::Save_W3D -- Save this light's settings into a W3D file *
  50. * LightClass::Get_Factory -- get the PersistFactory for LightClass *
  51. * LightClass::Save -- persistant object support *
  52. * LightClass::Load -- persistant object support *
  53. * LightImpClass::LightImpClass -- constructor *
  54. * LightImpClass::Process_Push -- exposes the "push" process for an srLight *
  55. * LightImpClass::Process_Pop -- exposes the "pop" process for an srLight *
  56. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  57. #include "light.h"
  58. #include "ww3d.h"
  59. #include "ww3dids.h"
  60. #include "w3d_file.h"
  61. #include "w3d_util.h"
  62. #include "w3derr.h"
  63. #include "chunkio.h"
  64. #include "rinfo.h"
  65. #include "scene.h"
  66. #include "persistfactory.h"
  67. #include "statistics.h"
  68. /*
  69. ** PersistFactory for LightClasses - lights have custom save-load support
  70. */
  71. SimplePersistFactoryClass<LightClass,WW3D_PERSIST_CHUNKID_LIGHT> _LightFactory;
  72. /*
  73. ** Chunk ID's used by LightClass's save-load support (different from the W3D file format...)
  74. */
  75. enum
  76. {
  77. LIGHT_CHUNK_W3DFILE = 0x02157100, // (w3d format light)
  78. LIGHT_CHUNK_VARIABLES, // other state not stored in the w3d format
  79. LIGHT_VARIABLE_TRANSFORM = 0x00, // transform for the light
  80. };
  81. /***********************************************************************************************
  82. * LightClass::LightClass -- Constructor *
  83. * *
  84. * INPUT: *
  85. * type - type of light to create. *
  86. * *
  87. * OUTPUT: *
  88. * *
  89. * WARNINGS: *
  90. * *
  91. * HISTORY: *
  92. * 3/21/98 GTH : Created. *
  93. *=============================================================================================*/
  94. LightClass::LightClass(LightType type) :
  95. Type(type),
  96. Flags(0),
  97. CastShadows(false),
  98. Intensity(1.0f),
  99. Ambient(1,1,1),
  100. Diffuse(1,1,1),
  101. Specular(1,1,1),
  102. NearAttenStart(0.0f),
  103. NearAttenEnd(0.0f),
  104. FarAttenStart(50.0f),
  105. FarAttenEnd(100.0f),
  106. SpotAngle(DEG_TO_RADF(45.0f)),
  107. SpotAngleCos(0.707f),
  108. SpotExponent(1.0f),
  109. SpotDirection(0,0,1)//,
  110. //Donut (false)
  111. {
  112. if (type == DIRECTIONAL) {
  113. Set_Force_Visible(true); // The light has no position so culling cant work.
  114. }
  115. }
  116. /***********************************************************************************************
  117. * LightClass::LightClass -- copy constructor *
  118. * *
  119. * INPUT: *
  120. * *
  121. * OUTPUT: *
  122. * *
  123. * WARNINGS: *
  124. * *
  125. * HISTORY: *
  126. * 3/21/98 GTH : Created. *
  127. *=============================================================================================*/
  128. LightClass::LightClass(const LightClass & src) :
  129. Type(src.Type),
  130. Flags(src.Flags),
  131. CastShadows(src.CastShadows),
  132. Intensity(src.Intensity),
  133. Ambient(src.Ambient),
  134. Diffuse(src.Diffuse),
  135. Specular(src.Specular),
  136. NearAttenStart(src.NearAttenStart),
  137. NearAttenEnd(src.NearAttenEnd),
  138. FarAttenStart(src.FarAttenStart),
  139. FarAttenEnd(src.FarAttenEnd),
  140. SpotAngle(src.SpotAngle),
  141. SpotAngleCos(src.SpotAngleCos),
  142. SpotExponent(src.SpotExponent),
  143. SpotDirection(src.SpotDirection)
  144. {
  145. }
  146. /***********************************************************************************************
  147. * LightClass::operator == -- assignment operator *
  148. * *
  149. * INPUT: *
  150. * *
  151. * OUTPUT: *
  152. * *
  153. * WARNINGS: *
  154. * *
  155. * HISTORY: *
  156. * 3/21/98 GTH : Created. *
  157. *=============================================================================================*/
  158. LightClass & LightClass::operator = (const LightClass & that)
  159. {
  160. if (this != &that) {
  161. RenderObjClass::operator = (that);
  162. Type = that.Type;
  163. Flags = that.Flags;
  164. CastShadows = that.CastShadows;
  165. Intensity = that.Intensity;
  166. Ambient = that.Ambient;
  167. Diffuse = that.Diffuse;
  168. Specular = that.Specular;
  169. NearAttenStart = that.NearAttenStart;
  170. NearAttenEnd = that.NearAttenEnd;
  171. FarAttenStart = that.FarAttenStart;
  172. FarAttenEnd = that.FarAttenEnd;
  173. SpotAngle = that.SpotAngle;
  174. SpotAngleCos = that.SpotAngleCos;
  175. SpotExponent = that.SpotExponent;
  176. SpotDirection = that.SpotDirection;
  177. }
  178. return * this;
  179. }
  180. /***********************************************************************************************
  181. * LightClass::~LightClass -- destructor *
  182. * *
  183. * INPUT: *
  184. * *
  185. * OUTPUT: *
  186. * *
  187. * WARNINGS: *
  188. * *
  189. * HISTORY: *
  190. * 3/21/98 GTH : Created. *
  191. *=============================================================================================*/
  192. LightClass::~LightClass(void)
  193. {
  194. }
  195. /***********************************************************************************************
  196. * LightClass::Clone -- virtual copy constructor *
  197. * *
  198. * INPUT: *
  199. * *
  200. * OUTPUT: *
  201. * *
  202. * WARNINGS: *
  203. * *
  204. * HISTORY: *
  205. * 3/21/98 GTH : Created. *
  206. *=============================================================================================*/
  207. RenderObjClass * LightClass::Clone(void) const
  208. {
  209. return W3DNEW LightClass(*this);
  210. }
  211. /***********************************************************************************************
  212. * LightClass::Notify_Added -- lights add themselves to the VP list when added *
  213. * *
  214. * INPUT: *
  215. * *
  216. * OUTPUT: *
  217. * *
  218. * WARNINGS: *
  219. * *
  220. * HISTORY: *
  221. * 2/26/99 GTH : Created. *
  222. *=============================================================================================*/
  223. void LightClass::Notify_Added(SceneClass * scene)
  224. {
  225. RenderObjClass::Notify_Added(scene);
  226. scene->Register(this,SceneClass::LIGHT);
  227. }
  228. /***********************************************************************************************
  229. * LightClass::Notify_Removed -- lights remove themselves from the VP list when removed *
  230. * *
  231. * INPUT: *
  232. * *
  233. * OUTPUT: *
  234. * *
  235. * WARNINGS: *
  236. * *
  237. * HISTORY: *
  238. * 2/26/99 GTH : Created. *
  239. *=============================================================================================*/
  240. void LightClass::Notify_Removed(SceneClass * scene)
  241. {
  242. scene->Unregister(this,SceneClass::LIGHT);
  243. RenderObjClass::Notify_Removed(scene);
  244. }
  245. /***********************************************************************************************
  246. * LightClass::Get_Obj_Space_Bounding_Sphere -- returns the object space bounding sphere *
  247. * *
  248. * INPUT: *
  249. * *
  250. * OUTPUT: *
  251. * *
  252. * WARNINGS: *
  253. * *
  254. * HISTORY: *
  255. * 12/8/98 GTH : Created. *
  256. *=============================================================================================*/
  257. void LightClass::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
  258. {
  259. sphere.Center.Set(0,0,0);
  260. sphere.Radius = Get_Attenuation_Range();
  261. }
  262. /***********************************************************************************************
  263. * LightClass::Get_Obj_Space_Bounding_Box -- returns the object space bounding box *
  264. * *
  265. * INPUT: *
  266. * *
  267. * OUTPUT: *
  268. * *
  269. * WARNINGS: *
  270. * *
  271. * HISTORY: *
  272. * 12/8/98 GTH : Created. *
  273. *=============================================================================================*/
  274. void LightClass::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
  275. {
  276. float r = Get_Attenuation_Range();
  277. box.Center.Set(0,0,0);
  278. box.Extent.Set(r,r,r);
  279. }
  280. /***********************************************************************************************
  281. * LightClass::Load_W3D -- Initialize this light from a W3D file *
  282. * *
  283. * INPUT: *
  284. * *
  285. * OUTPUT: *
  286. * *
  287. * WARNINGS: *
  288. * *
  289. * HISTORY: *
  290. * 9/23/99 GTH : Created. *
  291. *=============================================================================================*/
  292. WW3DErrorType LightClass::Load_W3D(ChunkLoadClass & cload)
  293. {
  294. W3dLightStruct lightinfo;
  295. cload.Open_Chunk();
  296. WWASSERT(cload.Cur_Chunk_ID() == W3D_CHUNK_LIGHT_INFO);
  297. cload.Read(&lightinfo,sizeof(lightinfo));
  298. cload.Close_Chunk();
  299. switch(lightinfo.Attributes & W3D_LIGHT_ATTRIBUTE_TYPE_MASK)
  300. {
  301. case W3D_LIGHT_ATTRIBUTE_POINT:
  302. Type = POINT;
  303. break;
  304. case W3D_LIGHT_ATTRIBUTE_DIRECTIONAL:
  305. Type = DIRECTIONAL;
  306. break;
  307. case W3D_LIGHT_ATTRIBUTE_SPOT:
  308. Type = SPOT;
  309. break;
  310. }
  311. Enable_Shadows((lightinfo.Attributes & W3D_LIGHT_ATTRIBUTE_CAST_SHADOWS) == W3D_LIGHT_ATTRIBUTE_CAST_SHADOWS);
  312. Set_Intensity(lightinfo.Intensity);
  313. Vector3 color;
  314. W3dUtilityClass::Convert_Color(lightinfo.Ambient,&color);
  315. Set_Ambient(color);
  316. W3dUtilityClass::Convert_Color(lightinfo.Diffuse,&color);
  317. Set_Diffuse(color);
  318. W3dUtilityClass::Convert_Color(lightinfo.Specular,&color);
  319. Set_Specular(color);
  320. W3dSpotLightStruct spotinfo;
  321. W3dLightAttenuationStruct atteninfo;
  322. Vector3 vec;
  323. while (cload.Open_Chunk()) {
  324. switch(cload.Cur_Chunk_ID())
  325. {
  326. case W3D_CHUNK_SPOT_LIGHT_INFO:
  327. cload.Read(&spotinfo,sizeof(spotinfo));
  328. Set_Spot_Angle(spotinfo.SpotAngle);
  329. Set_Spot_Exponent(spotinfo.SpotExponent);
  330. W3dUtilityClass::Convert_Vector(spotinfo.SpotDirection,&vec);
  331. Set_Spot_Direction(vec);
  332. break;
  333. case W3D_CHUNK_NEAR_ATTENUATION:
  334. cload.Read(&atteninfo,sizeof(atteninfo));
  335. Set_Flag(NEAR_ATTENUATION,true);
  336. Set_Near_Attenuation_Range(atteninfo.Start,atteninfo.End);
  337. break;
  338. case W3D_CHUNK_FAR_ATTENUATION:
  339. cload.Read(&atteninfo,sizeof(atteninfo));
  340. Set_Flag(FAR_ATTENUATION,true);
  341. Set_Far_Attenuation_Range(atteninfo.Start,atteninfo.End);
  342. break;
  343. }
  344. cload.Close_Chunk();
  345. }
  346. return WW3D_ERROR_OK;
  347. }
  348. /***********************************************************************************************
  349. * LightClass::Save_W3D -- Save this light's settings into a W3D file *
  350. * *
  351. * INPUT: *
  352. * *
  353. * OUTPUT: *
  354. * *
  355. * WARNINGS: *
  356. * *
  357. * HISTORY: *
  358. * 9/23/99 GTH : Created. *
  359. *=============================================================================================*/
  360. WW3DErrorType LightClass::Save_W3D(ChunkSaveClass & csave)
  361. {
  362. csave.Begin_Chunk(W3D_CHUNK_LIGHT);
  363. csave.Begin_Chunk(W3D_CHUNK_LIGHT_INFO);
  364. W3dLightStruct lightinfo;
  365. memset(&lightinfo,0,sizeof(lightinfo));
  366. switch (Type)
  367. {
  368. case POINT:
  369. lightinfo.Attributes |= W3D_LIGHT_ATTRIBUTE_POINT;
  370. break;
  371. case DIRECTIONAL:
  372. lightinfo.Attributes |= W3D_LIGHT_ATTRIBUTE_DIRECTIONAL;
  373. break;
  374. case SPOT:
  375. lightinfo.Attributes |= W3D_LIGHT_ATTRIBUTE_SPOT;
  376. break;
  377. }
  378. if (Are_Shadows_Enabled()) {
  379. lightinfo.Attributes |= W3D_LIGHT_ATTRIBUTE_CAST_SHADOWS;
  380. }
  381. Vector3 color;
  382. Get_Ambient(&color);
  383. W3dUtilityClass::Convert_Color(color,(&lightinfo.Ambient));
  384. Get_Diffuse(&color);
  385. W3dUtilityClass::Convert_Color(color,(&lightinfo.Diffuse));
  386. Get_Specular(&color);
  387. W3dUtilityClass::Convert_Color(color,(&lightinfo.Specular));
  388. lightinfo.Intensity = Get_Intensity();
  389. csave.Write(&lightinfo,sizeof(lightinfo));
  390. csave.End_Chunk();
  391. if (Type == SPOT) {
  392. csave.Begin_Chunk(W3D_CHUNK_SPOT_LIGHT_INFO);
  393. W3dSpotLightStruct spotinfo;
  394. memset(&spotinfo,0,sizeof(spotinfo));
  395. spotinfo.SpotAngle = SpotAngle;
  396. spotinfo.SpotExponent = SpotExponent;
  397. spotinfo.SpotDirection.X = SpotDirection.X;
  398. spotinfo.SpotDirection.Y = SpotDirection.Y;
  399. spotinfo.SpotDirection.Z = SpotDirection.Z;
  400. csave.Write(&spotinfo,sizeof(spotinfo));
  401. csave.End_Chunk();
  402. }
  403. if (Get_Flag(NEAR_ATTENUATION)) {
  404. csave.Begin_Chunk(W3D_CHUNK_NEAR_ATTENUATION);
  405. double start,end;
  406. Get_Near_Attenuation_Range(start,end);
  407. W3dLightAttenuationStruct atten;
  408. memset(&atten,0,sizeof(atten));
  409. atten.Start = start;
  410. atten.End = end;
  411. csave.Write(&atten,sizeof(atten));
  412. csave.End_Chunk();
  413. }
  414. if (Get_Flag(FAR_ATTENUATION)) {
  415. csave.Begin_Chunk(W3D_CHUNK_FAR_ATTENUATION);
  416. double start,end;
  417. Get_Far_Attenuation_Range(start,end);
  418. W3dLightAttenuationStruct atten;
  419. memset(&atten,0,sizeof(atten));
  420. atten.Start = start;
  421. atten.End = end;
  422. csave.Write(&atten,sizeof(atten));
  423. csave.End_Chunk();
  424. }
  425. csave.End_Chunk();
  426. return WW3D_ERROR_OK;
  427. }
  428. /***********************************************************************************************
  429. * LightClass::Get_Factory -- get the PersistFactory for LightClass *
  430. * *
  431. * INPUT: *
  432. * *
  433. * OUTPUT: *
  434. * *
  435. * WARNINGS: *
  436. * *
  437. * HISTORY: *
  438. * 9/23/99 GTH : Created. *
  439. *=============================================================================================*/
  440. const PersistFactoryClass & LightClass::Get_Factory (void) const
  441. {
  442. return _LightFactory;
  443. }
  444. /***********************************************************************************************
  445. * LightClass::Save -- persistant object support *
  446. * *
  447. * INPUT: *
  448. * *
  449. * OUTPUT: *
  450. * *
  451. * WARNINGS: *
  452. * *
  453. * HISTORY: *
  454. * 9/23/99 GTH : Created. *
  455. *=============================================================================================*/
  456. bool LightClass::Save (ChunkSaveClass &csave)
  457. {
  458. csave.Begin_Chunk(LIGHT_CHUNK_W3DFILE);
  459. Save_W3D(csave);
  460. csave.End_Chunk();
  461. Matrix3D tm = Get_Transform();
  462. csave.Begin_Chunk(LIGHT_CHUNK_VARIABLES);
  463. WRITE_MICRO_CHUNK(csave,LIGHT_VARIABLE_TRANSFORM,tm);
  464. csave.End_Chunk();
  465. return true;
  466. }
  467. /***********************************************************************************************
  468. * LightClass::Load -- persistant object support *
  469. * *
  470. * INPUT: *
  471. * *
  472. * OUTPUT: *
  473. * *
  474. * WARNINGS: *
  475. * *
  476. * HISTORY: *
  477. * 9/23/99 GTH : Created. *
  478. *=============================================================================================*/
  479. bool LightClass::Load (ChunkLoadClass &cload)
  480. {
  481. Matrix3D tm(1);
  482. while (cload.Open_Chunk()) {
  483. switch (cload.Cur_Chunk_ID()) {
  484. case LIGHT_CHUNK_W3DFILE:
  485. // The W3D code is non-symmetrical, the Save function writes a W3D_LIGHT chunk
  486. // but the load function expects the external user to have opened it. So open it here...
  487. cload.Open_Chunk();
  488. Load_W3D(cload);
  489. cload.Close_Chunk();
  490. break;
  491. case LIGHT_CHUNK_VARIABLES:
  492. while (cload.Open_Micro_Chunk()) {
  493. switch(cload.Cur_Micro_Chunk_ID()) {
  494. READ_MICRO_CHUNK(cload,LIGHT_VARIABLE_TRANSFORM,tm);
  495. }
  496. cload.Close_Micro_Chunk();
  497. }
  498. break;
  499. default:
  500. WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
  501. break;
  502. }
  503. cload.Close_Chunk();
  504. }
  505. Set_Transform(tm);
  506. return true;
  507. }