light.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. /*
  2. ** Command & Conquer Renegade(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:: Greg_h $*
  27. * *
  28. * $Modtime:: 2/13/02 6:41p $*
  29. * *
  30. * $Revision:: 9 $*
  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. * LightClass::Compute_Lighting -- Compute lighting for a vertex *
  57. * LightClass::Is_Within_Attenuation_Radius -- is the point within the atten radius of this *
  58. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  59. #include "light.h"
  60. #include "ww3d.h"
  61. #include "ww3dids.h"
  62. #include "w3d_file.h"
  63. #include "w3d_util.h"
  64. #include "w3derr.h"
  65. #include "chunkio.h"
  66. #include "rinfo.h"
  67. #include "scene.h"
  68. #include "persistfactory.h"
  69. #include "statistics.h"
  70. /*
  71. ** PersistFactory for LightClasses - lights have custom save-load support
  72. */
  73. SimplePersistFactoryClass<LightClass,WW3D_PERSIST_CHUNKID_LIGHT> _LightFactory;
  74. /*
  75. ** Chunk ID's used by LightClass's save-load support (different from the W3D file format...)
  76. */
  77. enum
  78. {
  79. LIGHT_CHUNK_W3DFILE = 0x02157100, // (w3d format light)
  80. LIGHT_CHUNK_VARIABLES, // other state not stored in the w3d format
  81. LIGHT_VARIABLE_TRANSFORM = 0x00, // transform for the light
  82. };
  83. /***********************************************************************************************
  84. * LightClass::LightClass -- Constructor *
  85. * *
  86. * INPUT: *
  87. * type - type of light to create. *
  88. * *
  89. * OUTPUT: *
  90. * *
  91. * WARNINGS: *
  92. * *
  93. * HISTORY: *
  94. * 3/21/98 GTH : Created. *
  95. *=============================================================================================*/
  96. LightClass::LightClass(LightType type) :
  97. Type(type),
  98. Flags(0),
  99. CastShadows(false),
  100. Intensity(1.0f),
  101. Ambient(1,1,1),
  102. Diffuse(1,1,1),
  103. Specular(1,1,1),
  104. NearAttenStart(0.0f),
  105. NearAttenEnd(0.0f),
  106. FarAttenStart(50.0f),
  107. FarAttenEnd(100.0f),
  108. SpotAngle(DEG_TO_RADF(45.0f)),
  109. SpotAngleCos(0.707f),
  110. SpotExponent(1.0f),
  111. SpotDirection(0,0,1)
  112. {
  113. if (type == DIRECTIONAL) {
  114. Set_Force_Visible(true); // The light has no position so culling cant work.
  115. }
  116. }
  117. /***********************************************************************************************
  118. * LightClass::LightClass -- copy constructor *
  119. * *
  120. * INPUT: *
  121. * *
  122. * OUTPUT: *
  123. * *
  124. * WARNINGS: *
  125. * *
  126. * HISTORY: *
  127. * 3/21/98 GTH : Created. *
  128. *=============================================================================================*/
  129. LightClass::LightClass(const LightClass & src) :
  130. Type(src.Type),
  131. Flags(src.Flags),
  132. CastShadows(src.CastShadows),
  133. Intensity(src.Intensity),
  134. Ambient(src.Ambient),
  135. Diffuse(src.Diffuse),
  136. Specular(src.Specular),
  137. NearAttenStart(src.NearAttenStart),
  138. NearAttenEnd(src.NearAttenEnd),
  139. FarAttenStart(src.FarAttenStart),
  140. FarAttenEnd(src.FarAttenEnd),
  141. SpotAngle(src.SpotAngle),
  142. SpotAngleCos(src.SpotAngleCos),
  143. SpotExponent(src.SpotExponent),
  144. SpotDirection(src.SpotDirection)
  145. {
  146. }
  147. /***********************************************************************************************
  148. * LightClass::operator == -- assignment operator *
  149. * *
  150. * INPUT: *
  151. * *
  152. * OUTPUT: *
  153. * *
  154. * WARNINGS: *
  155. * *
  156. * HISTORY: *
  157. * 3/21/98 GTH : Created. *
  158. *=============================================================================================*/
  159. LightClass & LightClass::operator = (const LightClass & that)
  160. {
  161. if (this != &that) {
  162. RenderObjClass::operator = (that);
  163. Type = that.Type;
  164. Flags = that.Flags;
  165. CastShadows = that.CastShadows;
  166. Intensity = that.Intensity;
  167. Ambient = that.Ambient;
  168. Diffuse = that.Diffuse;
  169. Specular = that.Specular;
  170. NearAttenStart = that.NearAttenStart;
  171. NearAttenEnd = that.NearAttenEnd;
  172. FarAttenStart = that.FarAttenStart;
  173. FarAttenEnd = that.FarAttenEnd;
  174. SpotAngle = that.SpotAngle;
  175. SpotAngleCos = that.SpotAngleCos;
  176. SpotExponent = that.SpotExponent;
  177. SpotDirection = that.SpotDirection;
  178. }
  179. return * this;
  180. }
  181. /***********************************************************************************************
  182. * LightClass::~LightClass -- destructor *
  183. * *
  184. * INPUT: *
  185. * *
  186. * OUTPUT: *
  187. * *
  188. * WARNINGS: *
  189. * *
  190. * HISTORY: *
  191. * 3/21/98 GTH : Created. *
  192. *=============================================================================================*/
  193. LightClass::~LightClass(void)
  194. {
  195. }
  196. /***********************************************************************************************
  197. * LightClass::Clone -- virtual copy constructor *
  198. * *
  199. * INPUT: *
  200. * *
  201. * OUTPUT: *
  202. * *
  203. * WARNINGS: *
  204. * *
  205. * HISTORY: *
  206. * 3/21/98 GTH : Created. *
  207. *=============================================================================================*/
  208. RenderObjClass * LightClass::Clone(void) const
  209. {
  210. return new LightClass(*this);
  211. }
  212. /***********************************************************************************************
  213. * LightClass::Notify_Added -- lights add themselves to the VP list when added *
  214. * *
  215. * INPUT: *
  216. * *
  217. * OUTPUT: *
  218. * *
  219. * WARNINGS: *
  220. * *
  221. * HISTORY: *
  222. * 2/26/99 GTH : Created. *
  223. *=============================================================================================*/
  224. void LightClass::Notify_Added(SceneClass * scene)
  225. {
  226. RenderObjClass::Notify_Added(scene);
  227. scene->Register(this,SceneClass::LIGHT);
  228. }
  229. /***********************************************************************************************
  230. * LightClass::Notify_Removed -- lights remove themselves from the VP list when removed *
  231. * *
  232. * INPUT: *
  233. * *
  234. * OUTPUT: *
  235. * *
  236. * WARNINGS: *
  237. * *
  238. * HISTORY: *
  239. * 2/26/99 GTH : Created. *
  240. *=============================================================================================*/
  241. void LightClass::Notify_Removed(SceneClass * scene)
  242. {
  243. scene->Unregister(this,SceneClass::LIGHT);
  244. RenderObjClass::Notify_Removed(scene);
  245. }
  246. /***********************************************************************************************
  247. * LightClass::Get_Obj_Space_Bounding_Sphere -- returns the object space bounding sphere *
  248. * *
  249. * INPUT: *
  250. * *
  251. * OUTPUT: *
  252. * *
  253. * WARNINGS: *
  254. * *
  255. * HISTORY: *
  256. * 12/8/98 GTH : Created. *
  257. *=============================================================================================*/
  258. void LightClass::Get_Obj_Space_Bounding_Sphere(SphereClass & sphere) const
  259. {
  260. sphere.Center.Set(0,0,0);
  261. sphere.Radius = Get_Attenuation_Range();
  262. }
  263. /***********************************************************************************************
  264. * LightClass::Get_Obj_Space_Bounding_Box -- returns the object space bounding box *
  265. * *
  266. * INPUT: *
  267. * *
  268. * OUTPUT: *
  269. * *
  270. * WARNINGS: *
  271. * *
  272. * HISTORY: *
  273. * 12/8/98 GTH : Created. *
  274. *=============================================================================================*/
  275. void LightClass::Get_Obj_Space_Bounding_Box(AABoxClass & box) const
  276. {
  277. float r = Get_Attenuation_Range();
  278. box.Center.Set(0,0,0);
  279. box.Extent.Set(r,r,r);
  280. }
  281. /***********************************************************************************************
  282. * LightClass::Is_Within_Attenuation_Radius -- is the point within the atten radius of this li *
  283. * *
  284. * INPUT: *
  285. * *
  286. * OUTPUT: *
  287. * *
  288. * WARNINGS: *
  289. * *
  290. * HISTORY: *
  291. * 2/13/2002 gth : Created. *
  292. *=============================================================================================*/
  293. bool LightClass::Is_Within_Attenuation_Radius(const Vector3 & pos)
  294. {
  295. if (Get_Flag(FAR_ATTENUATION) == false) {
  296. return true;
  297. } else {
  298. Vector3 dir = Get_Position() - pos;
  299. float dist2 = dir.Length2();
  300. return (dist2 < FarAttenEnd*FarAttenEnd);
  301. }
  302. }
  303. /***********************************************************************************************
  304. * LightClass::Compute_Lighting -- Compute lighting for a vertex *
  305. * *
  306. * INPUT: *
  307. * *
  308. * OUTPUT: *
  309. * *
  310. * WARNINGS: *
  311. * *
  312. * HISTORY: *
  313. * 2/13/2002 gth : Created. *
  314. *=============================================================================================*/
  315. void LightClass::Compute_Lighting(const Vector3 & pos,const Vector3 & norm, Vector3 * set_ambient, Vector3 * set_diffuse)
  316. {
  317. Matrix3D tm = Get_Transform();
  318. /*
  319. ** Compute direction vector and distance
  320. */
  321. Vector3 dir = tm.Get_Translation() - pos;
  322. float dist = dir.Length();
  323. if (dist > 0.0f) {
  324. dir /= dist;
  325. }
  326. /*
  327. ** Compute attenuation
  328. */
  329. float atten = 1.0f;
  330. if (Get_Flag(FAR_ATTENUATION)) {
  331. atten = 1.0f - (dist - FarAttenStart) / (FarAttenEnd - FarAttenStart);
  332. atten = WWMath::Clamp(atten,0.0f,1.0f);
  333. }
  334. if (Type == LightClass::SPOT) {
  335. Vector3 spot_dir = -tm.Get_Z_Vector();
  336. float spot_atten = (Vector3::Dot_Product(spot_dir,dir) - SpotAngleCos) / (1.0f - SpotAngleCos);
  337. atten *= spot_atten;
  338. atten = WWMath::Clamp(atten,0.0f,1.0f);
  339. }
  340. /*
  341. ** Ambient:
  342. */
  343. *set_ambient = atten * Ambient * Intensity;
  344. /*
  345. ** Diffuse:
  346. */
  347. switch (Type)
  348. {
  349. case LightClass::POINT:
  350. {
  351. *set_diffuse = atten * Intensity * Diffuse * Vector3::Dot_Product(norm,dir);
  352. break;
  353. }
  354. case LightClass::DIRECTIONAL:
  355. case LightClass::SPOT:
  356. {
  357. Vector3 light_dir = -tm.Get_Z_Vector();
  358. *set_diffuse = atten * Intensity * Diffuse * Vector3::Dot_Product(norm,light_dir);
  359. break;
  360. }
  361. }
  362. set_diffuse->X = WWMath::Clamp(set_diffuse->X);
  363. set_diffuse->Y = WWMath::Clamp(set_diffuse->Y);
  364. set_diffuse->Z = WWMath::Clamp(set_diffuse->Z);
  365. }
  366. /***********************************************************************************************
  367. * LightClass::Load_W3D -- Initialize this light from a W3D file *
  368. * *
  369. * INPUT: *
  370. * *
  371. * OUTPUT: *
  372. * *
  373. * WARNINGS: *
  374. * *
  375. * HISTORY: *
  376. * 9/23/99 GTH : Created. *
  377. *=============================================================================================*/
  378. WW3DErrorType LightClass::Load_W3D(ChunkLoadClass & cload)
  379. {
  380. W3dLightStruct lightinfo;
  381. cload.Open_Chunk();
  382. WWASSERT(cload.Cur_Chunk_ID() == W3D_CHUNK_LIGHT_INFO);
  383. cload.Read(&lightinfo,sizeof(lightinfo));
  384. cload.Close_Chunk();
  385. switch(lightinfo.Attributes & W3D_LIGHT_ATTRIBUTE_TYPE_MASK)
  386. {
  387. case W3D_LIGHT_ATTRIBUTE_POINT:
  388. Type = POINT;
  389. break;
  390. case W3D_LIGHT_ATTRIBUTE_DIRECTIONAL:
  391. Type = DIRECTIONAL;
  392. break;
  393. case W3D_LIGHT_ATTRIBUTE_SPOT:
  394. Type = SPOT;
  395. break;
  396. }
  397. Enable_Shadows((lightinfo.Attributes & W3D_LIGHT_ATTRIBUTE_CAST_SHADOWS) == W3D_LIGHT_ATTRIBUTE_CAST_SHADOWS);
  398. Set_Intensity(lightinfo.Intensity);
  399. Vector3 color;
  400. W3dUtilityClass::Convert_Color(lightinfo.Ambient,&color);
  401. Set_Ambient(color);
  402. W3dUtilityClass::Convert_Color(lightinfo.Diffuse,&color);
  403. Set_Diffuse(color);
  404. W3dUtilityClass::Convert_Color(lightinfo.Specular,&color);
  405. Set_Specular(color);
  406. W3dSpotLightStruct spotinfo;
  407. W3dLightAttenuationStruct atteninfo;
  408. Vector3 vec;
  409. while (cload.Open_Chunk()) {
  410. switch(cload.Cur_Chunk_ID())
  411. {
  412. case W3D_CHUNK_SPOT_LIGHT_INFO:
  413. cload.Read(&spotinfo,sizeof(spotinfo));
  414. Set_Spot_Angle(spotinfo.SpotAngle);
  415. Set_Spot_Exponent(spotinfo.SpotExponent);
  416. W3dUtilityClass::Convert_Vector(spotinfo.SpotDirection,&vec);
  417. Set_Spot_Direction(vec);
  418. break;
  419. case W3D_CHUNK_NEAR_ATTENUATION:
  420. cload.Read(&atteninfo,sizeof(atteninfo));
  421. Set_Flag(NEAR_ATTENUATION,true);
  422. Set_Near_Attenuation_Range(atteninfo.Start,atteninfo.End);
  423. break;
  424. case W3D_CHUNK_FAR_ATTENUATION:
  425. cload.Read(&atteninfo,sizeof(atteninfo));
  426. Set_Flag(FAR_ATTENUATION,true);
  427. Set_Far_Attenuation_Range(atteninfo.Start,atteninfo.End);
  428. break;
  429. }
  430. cload.Close_Chunk();
  431. }
  432. return WW3D_ERROR_OK;
  433. }
  434. /***********************************************************************************************
  435. * LightClass::Save_W3D -- Save this light's settings into a W3D file *
  436. * *
  437. * INPUT: *
  438. * *
  439. * OUTPUT: *
  440. * *
  441. * WARNINGS: *
  442. * *
  443. * HISTORY: *
  444. * 9/23/99 GTH : Created. *
  445. *=============================================================================================*/
  446. WW3DErrorType LightClass::Save_W3D(ChunkSaveClass & csave)
  447. {
  448. csave.Begin_Chunk(W3D_CHUNK_LIGHT);
  449. csave.Begin_Chunk(W3D_CHUNK_LIGHT_INFO);
  450. W3dLightStruct lightinfo;
  451. memset(&lightinfo,0,sizeof(lightinfo));
  452. switch (Type)
  453. {
  454. case POINT:
  455. lightinfo.Attributes |= W3D_LIGHT_ATTRIBUTE_POINT;
  456. break;
  457. case DIRECTIONAL:
  458. lightinfo.Attributes |= W3D_LIGHT_ATTRIBUTE_DIRECTIONAL;
  459. break;
  460. case SPOT:
  461. lightinfo.Attributes |= W3D_LIGHT_ATTRIBUTE_SPOT;
  462. break;
  463. }
  464. if (Are_Shadows_Enabled()) {
  465. lightinfo.Attributes |= W3D_LIGHT_ATTRIBUTE_CAST_SHADOWS;
  466. }
  467. Vector3 color;
  468. Get_Ambient(&color);
  469. W3dUtilityClass::Convert_Color(color,(&lightinfo.Ambient));
  470. Get_Diffuse(&color);
  471. W3dUtilityClass::Convert_Color(color,(&lightinfo.Diffuse));
  472. Get_Specular(&color);
  473. W3dUtilityClass::Convert_Color(color,(&lightinfo.Specular));
  474. lightinfo.Intensity = Get_Intensity();
  475. csave.Write(&lightinfo,sizeof(lightinfo));
  476. csave.End_Chunk();
  477. if (Type == SPOT) {
  478. csave.Begin_Chunk(W3D_CHUNK_SPOT_LIGHT_INFO);
  479. W3dSpotLightStruct spotinfo;
  480. memset(&spotinfo,0,sizeof(spotinfo));
  481. spotinfo.SpotAngle = SpotAngle;
  482. spotinfo.SpotExponent = SpotExponent;
  483. spotinfo.SpotDirection.X = SpotDirection.X;
  484. spotinfo.SpotDirection.Y = SpotDirection.Y;
  485. spotinfo.SpotDirection.Z = SpotDirection.Z;
  486. csave.Write(&spotinfo,sizeof(spotinfo));
  487. csave.End_Chunk();
  488. }
  489. if (Get_Flag(NEAR_ATTENUATION)) {
  490. csave.Begin_Chunk(W3D_CHUNK_NEAR_ATTENUATION);
  491. double start,end;
  492. Get_Near_Attenuation_Range(start,end);
  493. W3dLightAttenuationStruct atten;
  494. memset(&atten,0,sizeof(atten));
  495. atten.Start = start;
  496. atten.End = end;
  497. csave.Write(&atten,sizeof(atten));
  498. csave.End_Chunk();
  499. }
  500. if (Get_Flag(FAR_ATTENUATION)) {
  501. csave.Begin_Chunk(W3D_CHUNK_FAR_ATTENUATION);
  502. double start,end;
  503. Get_Far_Attenuation_Range(start,end);
  504. W3dLightAttenuationStruct atten;
  505. memset(&atten,0,sizeof(atten));
  506. atten.Start = start;
  507. atten.End = end;
  508. csave.Write(&atten,sizeof(atten));
  509. csave.End_Chunk();
  510. }
  511. csave.End_Chunk();
  512. return WW3D_ERROR_OK;
  513. }
  514. /***********************************************************************************************
  515. * LightClass::Get_Factory -- get the PersistFactory for LightClass *
  516. * *
  517. * INPUT: *
  518. * *
  519. * OUTPUT: *
  520. * *
  521. * WARNINGS: *
  522. * *
  523. * HISTORY: *
  524. * 9/23/99 GTH : Created. *
  525. *=============================================================================================*/
  526. const PersistFactoryClass & LightClass::Get_Factory (void) const
  527. {
  528. return _LightFactory;
  529. }
  530. /***********************************************************************************************
  531. * LightClass::Save -- persistant object support *
  532. * *
  533. * INPUT: *
  534. * *
  535. * OUTPUT: *
  536. * *
  537. * WARNINGS: *
  538. * *
  539. * HISTORY: *
  540. * 9/23/99 GTH : Created. *
  541. *=============================================================================================*/
  542. bool LightClass::Save (ChunkSaveClass &csave)
  543. {
  544. csave.Begin_Chunk(LIGHT_CHUNK_W3DFILE);
  545. Save_W3D(csave);
  546. csave.End_Chunk();
  547. Matrix3D tm = Get_Transform();
  548. csave.Begin_Chunk(LIGHT_CHUNK_VARIABLES);
  549. WRITE_MICRO_CHUNK(csave,LIGHT_VARIABLE_TRANSFORM,tm);
  550. csave.End_Chunk();
  551. return true;
  552. }
  553. /***********************************************************************************************
  554. * LightClass::Load -- persistant object support *
  555. * *
  556. * INPUT: *
  557. * *
  558. * OUTPUT: *
  559. * *
  560. * WARNINGS: *
  561. * *
  562. * HISTORY: *
  563. * 9/23/99 GTH : Created. *
  564. *=============================================================================================*/
  565. bool LightClass::Load (ChunkLoadClass &cload)
  566. {
  567. Matrix3D tm(1);
  568. while (cload.Open_Chunk()) {
  569. switch (cload.Cur_Chunk_ID()) {
  570. case LIGHT_CHUNK_W3DFILE:
  571. // The W3D code is non-symmetrical, the Save function writes a W3D_LIGHT chunk
  572. // but the load function expects the external user to have opened it. So open it here...
  573. cload.Open_Chunk();
  574. Load_W3D(cload);
  575. cload.Close_Chunk();
  576. break;
  577. case LIGHT_CHUNK_VARIABLES:
  578. while (cload.Open_Micro_Chunk()) {
  579. switch(cload.Cur_Micro_Chunk_ID()) {
  580. READ_MICRO_CHUNK(cload,LIGHT_VARIABLE_TRANSFORM,tm);
  581. }
  582. cload.Close_Micro_Chunk();
  583. }
  584. break;
  585. default:
  586. WWDEBUG_SAY(("Unhandled Chunk: 0x%X File: %s Line: %d\r\n",__FILE__,__LINE__));
  587. break;
  588. }
  589. cload.Close_Chunk();
  590. }
  591. Set_Transform(tm);
  592. return true;
  593. }