sceneLighting.cpp 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "lighting/common/sceneLighting.h"
  24. #include "T3D/gameBase/gameConnection.h"
  25. #include "console/consoleTypes.h"
  26. #include "scene/sceneManager.h"
  27. #include "lighting/common/shadowVolumeBSP.h"
  28. #include "T3D/shapeBase.h"
  29. #include "gui/core/guiCanvas.h"
  30. #include "ts/tsShape.h"
  31. #include "ts/tsShapeInstance.h"
  32. #include "T3D/staticShape.h"
  33. #include "T3D/tsStatic.h"
  34. #include "collision/concretePolyList.h"
  35. #include "lighting/lightingInterfaces.h"
  36. #include "terrain/terrData.h"
  37. #include "platform/platformVolume.h"
  38. #include "core/stream/fileStream.h"
  39. #include "core/crc.h"
  40. namespace
  41. {
  42. bool gTerminateLighting = false;
  43. F32 gLightingProgress = 0.0f;
  44. char * gCompleteCallback = NULL;
  45. U32 gConnectionMissionCRC = 0xffffffff;
  46. }
  47. SceneLighting *gLighting = NULL;
  48. F32 gParellelVectorThresh = 0.01f;
  49. F32 gPlaneNormThresh = 0.999f;
  50. F32 gPlaneDistThresh = 0.001f;
  51. void SceneLighting::sgNewEvent(U32 light, S32 object, U32 event)
  52. {
  53. Sim::postEvent(this, new sgSceneLightingProcessEvent(light, object, event), Sim::getTargetTime() + 1);
  54. // Paint canvas here?
  55. }
  56. //-----------------------------------------------
  57. /*
  58. * Called once per scenelighting - entry point for event system
  59. */
  60. void SceneLighting::sgLightingStartEvent()
  61. {
  62. Con::printf("");
  63. Con::printf("Starting scene lighting...");
  64. sgTimeTemp2 = Platform::getRealMilliseconds();
  65. // clear interior light maps
  66. for(ObjectProxy **proxyItr = mSceneObjects.begin(); proxyItr != mSceneObjects.end(); proxyItr++)
  67. {
  68. ObjectProxy* objprox;
  69. objprox = *proxyItr;
  70. // is there an object?
  71. if(!objprox->getObject())
  72. {
  73. AssertFatal(0, "SceneLighting:: missing sceneobject on light start");
  74. Con::errorf(ConsoleLogEntry::General, " SceneLighting:: missing sceneobject on light start");
  75. continue;
  76. }
  77. objprox->processLightingStart();
  78. }
  79. sgNewEvent(0, 0, sgSceneLightingProcessEvent::sgTGEPassSetupEventType);
  80. //sgNewEvent(0, 0, sgSceneLightingProcessEvent::sgSGPassSetupEventType);
  81. }
  82. /*
  83. * Called once per scenelighting - exit from event system
  84. */
  85. void SceneLighting::sgLightingCompleteEvent()
  86. {
  87. Vector<TerrainBlock *> terrBlocks;
  88. // initialize the objects for lighting
  89. for(ObjectProxy ** proxyItr = mSceneObjects.begin(); proxyItr != mSceneObjects.end(); proxyItr++)
  90. {
  91. ObjectProxy* objprox = *proxyItr;
  92. TerrainBlock *terr = dynamic_cast<TerrainBlock *>(objprox->getObject());
  93. if (terr)
  94. terrBlocks.push_back(terr);
  95. }
  96. for (S32 i = 0; i < terrBlocks.size(); i++)
  97. terrBlocks[i]->postLight(terrBlocks);
  98. // save out the lighting?
  99. if(Con::getBoolVariable("$sceneLighting::cacheLighting", true))
  100. {
  101. if(!savePersistInfo(mFileName))
  102. Con::errorf(ConsoleLogEntry::General, "SceneLighting::light: unable to persist lighting!");
  103. else
  104. Con::printf("Successfully saved mission lighting file: '%s'", mFileName);
  105. }
  106. Con::printf("Scene lighting complete (%3.3f seconds)", (Platform::getRealMilliseconds()-sgTimeTemp2)/1000.f);
  107. Con::printf("//-----------------------------------------------");
  108. Con::printf("");
  109. completed(true);
  110. deleteObject();
  111. }
  112. //-----------------------------------------------
  113. /*
  114. * Called once per scenelighting - used for prepping the
  115. * event system for TGE style scenelighting
  116. */
  117. void SceneLighting::sgTGEPassSetupEvent()
  118. {
  119. Con::printf(" Starting TGE based scene lighting...");
  120. sgNewEvent(0, 0, sgSceneLightingProcessEvent::sgTGELightStartEventType);
  121. }
  122. /*
  123. * Called once per light - used for calling preLight on all objects
  124. * Only TGE lights call prelight and continue on to the process event
  125. */
  126. void SceneLighting::sgTGELightStartEvent(U32 light)
  127. {
  128. // catch bad light index and jump to complete event
  129. if(light >= mLights.size())
  130. {
  131. sgNewEvent(light, 0, sgSceneLightingProcessEvent::sgTGELightCompleteEventType);
  132. return;
  133. }
  134. // can we use the light?
  135. if(mLights[light]->getType() != LightInfo::Vector)
  136. {
  137. sgNewEvent((light+1), 0, sgSceneLightingProcessEvent::sgTGELightStartEventType);
  138. return;
  139. }
  140. // process pre-lighting
  141. Con::printf(" Lighting with light #%d (TGE vector light)...", (light+1));
  142. LightInfo *lightobj = mLights[light];
  143. mLitObjects.clear();
  144. for(ObjectProxy **proxyItr = mSceneObjects.begin(); proxyItr != mSceneObjects.end(); proxyItr++)
  145. {
  146. ObjectProxy* objprox = *proxyItr;
  147. // is there an object?
  148. if(!objprox->getObject())
  149. {
  150. AssertFatal(0, "SceneLighting:: missing sceneobject on light start");
  151. Con::errorf(ConsoleLogEntry::General, " SceneLighting:: missing sceneobject on light start");
  152. continue;
  153. }
  154. if (objprox->tgePreLight(lightobj))
  155. mLitObjects.push_back(objprox);
  156. }
  157. // kick off lighting
  158. sgNewEvent(light, 0, sgSceneLightingProcessEvent::sgTGELightProcessEventType);
  159. }
  160. /*
  161. * Called once for each TGE light and object - used for calling light on an object
  162. */
  163. void SceneLighting::sgTGELightProcessEvent(U32 light, S32 object)
  164. {
  165. // catch bad light or object index
  166. if((light >= mLights.size()) || (object >= mLitObjects.size()))
  167. {
  168. sgNewEvent(light, 0, sgSceneLightingProcessEvent::sgTGELightCompleteEventType);
  169. return;
  170. }
  171. //process object and light
  172. S32 time = Platform::getRealMilliseconds();
  173. // light object
  174. LightInfo* li = mLights[light];
  175. mLitObjects[object]->processTGELightProcessEvent(object, mLitObjects.size(), li);
  176. sgTGESetProgress(light, object);
  177. Con::printf(" Object lighting complete (%3.3f seconds)", (Platform::getRealMilliseconds()-time)/1000.f);
  178. // kick off next object event
  179. sgNewEvent(light, (object+1), sgSceneLightingProcessEvent::sgTGELightProcessEventType);
  180. }
  181. /*
  182. * Called once per TGE light - used for calling postLight on all objects
  183. */
  184. void SceneLighting::sgTGELightCompleteEvent(U32 light)
  185. {
  186. // catch bad light index and move to the next pass event
  187. if(light >= mLights.size())
  188. {
  189. sgTGESetProgress(mLights.size(), mLitObjects.size());
  190. Con::printf(" TGE based scene lighting complete (%3.3f seconds)", (Platform::getRealMilliseconds()-sgTimeTemp2)/1000.f);
  191. sgNewEvent(0, 0, sgSceneLightingProcessEvent::sgSGPassSetupEventType);
  192. //sgNewEvent(0, 0, sgSceneLightingProcessEvent::sgLightingCompleteEventType);
  193. return;
  194. }
  195. // process post-lighting
  196. // don't do this, SG lighting events will copy terrain light map...
  197. /*bool islast = (light == (mLights.size() - 1));
  198. for(U32 o=0; o<mLitObjects.size(); o++)
  199. {
  200. if(dynamic_cast<TerrainProxy *>(mLitObjects[o]))
  201. mLitObjects[o]->postLight(islast);
  202. }*/
  203. // kick off next light event
  204. sgNewEvent((light+1), 0, sgSceneLightingProcessEvent::sgTGELightStartEventType);
  205. }
  206. void SceneLighting::sgTGESetProgress(U32 light, S32 object)
  207. {
  208. // TGE is light based...
  209. F32 val = (F32)(light * mLitObjects.size()) + object;
  210. F32 total = (F32)(mLights.size() * mLitObjects.size());
  211. if(total == 0.0f)
  212. return;
  213. val = getMin(val, total);
  214. // two passes...
  215. total *= 2.0f;
  216. gLightingProgress = val / total;
  217. }
  218. //-----------------------------------------------
  219. /*
  220. * Called once per scenelighting - used for prepping the
  221. * event system for SG style scenelighting
  222. */
  223. void SceneLighting::sgSGPassSetupEvent()
  224. {
  225. mLitObjects.clear();
  226. for(ObjectProxy **proxyItr = mSceneObjects.begin(); proxyItr != mSceneObjects.end(); proxyItr++)
  227. {
  228. // is there an object?
  229. if(!(*proxyItr)->getObject())
  230. {
  231. AssertFatal(0, "SceneLighting:: missing sceneobject on light start");
  232. Con::errorf(ConsoleLogEntry::General, " SceneLighting:: missing sceneobject on light start");
  233. continue;
  234. }
  235. // add all lights
  236. mLitObjects.push_back(*proxyItr);
  237. }
  238. sgNewEvent(0, 0, sgSceneLightingProcessEvent::sgSGObjectStartEventType);
  239. }
  240. /*
  241. * Called once per object - used for calling preLight on all SG lights
  242. */
  243. void SceneLighting::sgSGObjectStartEvent(S32 object)
  244. {
  245. // catch bad light index and jump to complete event
  246. if(object >= mLitObjects.size())
  247. {
  248. sgNewEvent(0, object, sgSceneLightingProcessEvent::sgSGObjectCompleteEventType);
  249. return;
  250. }
  251. ObjectProxy *obj = mLitObjects[object];
  252. bool bHandled = obj->processStartObjectLightingEvent(object, mLitObjects.size());
  253. if (!bHandled)
  254. {
  255. Con::printf(" Lighting object %d of %d... %s: %s", (object+1), mLitObjects.size(), obj->getObject()->getClassName(), obj->getObject()->getName());
  256. }
  257. for(U32 i=0; i<mLights.size(); i++)
  258. {
  259. // can we use the light?
  260. LightInfo *lightobj = mLights[i];
  261. //if((lightobj->mType == LightInfo::SGStaticPoint) || (lightobj->mType == LightInfo::SGStaticSpot))
  262. obj->preLight(lightobj);
  263. }
  264. sgTimeTemp = Platform::getRealMilliseconds();
  265. // kick off lighting
  266. // this is slow with multiple objects...
  267. //sgNewEvent(0, object, sgSceneLightingProcessEvent::sgSGObjectProcessEventType);
  268. // jump right to the method...
  269. sgSGObjectProcessEvent(0, object);
  270. }
  271. /*
  272. * Called once per object and SG light - used for calling light on an object
  273. */
  274. void SceneLighting::sgSGObjectProcessEvent(U32 light, S32 object)
  275. {
  276. // catch bad light or object index
  277. if((light >= mLights.size()) || (object >= mLitObjects.size()))
  278. {
  279. // this is slow with multiple objects...
  280. //sgNewEvent(0, object, sgSceneLightingProcessEvent::sgSGObjectCompleteEventType);
  281. // jump right to the method...
  282. sgSGObjectCompleteEvent(object);
  283. return;
  284. }
  285. // avoid the event overhead...
  286. // 80 lights == 0.6 seconds an interior without ANY lighting (events only)...
  287. U32 time = Platform::getRealMilliseconds();
  288. ObjectProxy* objprox = mLitObjects[object];
  289. while((light < mLights.size()) && ((Platform::getRealMilliseconds() - time) < 500))
  290. {
  291. // can we use the light?
  292. LightInfo *lightobj = mLights[light];
  293. objprox->processSGObjectProcessEvent(lightobj);
  294. sgSGSetProgress(light, object);
  295. light++;
  296. }
  297. light--;
  298. // kick off next light event
  299. sgNewEvent((light+1), object, sgSceneLightingProcessEvent::sgSGObjectProcessEventType);
  300. }
  301. /*
  302. * Called once per object - used for calling postLight on all SG lights
  303. */
  304. void SceneLighting::sgSGObjectCompleteEvent(S32 object)
  305. {
  306. // catch bad light index and move to the next pass event
  307. if(object >= mLitObjects.size())
  308. {
  309. sgSGSetProgress(mLights.size(), mLitObjects.size());
  310. sgNewEvent(0, 0, sgSceneLightingProcessEvent::sgLightingCompleteEventType);
  311. return;
  312. }
  313. // process post-lighting
  314. Con::printf(" Object lighting complete (%3.3f seconds)", (Platform::getRealMilliseconds()-sgTimeTemp)/1000.f);
  315. // in case Atlas turned off rendering...
  316. GFX->setAllowRender(true);
  317. // only the last light does something
  318. mLitObjects[object]->postLight(true);
  319. /*ObjectProxy *obj = mLitObjects[object];
  320. for(U32 i=0; i<mLights.size(); i++)
  321. {
  322. // can we use the light?
  323. LightInfo *lightobj = mLights[i];
  324. if((lightobj->mType == LightInfo::SGStaticPoint) || (lightobj->mType == LightInfo::SGStaticSpot))
  325. obj->postLight((i == (mLights.size() - 1)));
  326. }*/
  327. // kick off next light event
  328. // this is slow with multiple objects...
  329. //sgNewEvent(0, (object+1), sgSceneLightingProcessEvent::sgSGObjectStartEventType);
  330. // jump right to the method...
  331. sgSGObjectStartEvent((object+1));
  332. }
  333. void SceneLighting::sgSGSetProgress(U32 light, S32 object)
  334. {
  335. // SG is object based...
  336. F32 val = (F32)((object * mLights.size()) + light);
  337. F32 total = (F32)(mLights.size() * mLitObjects.size());
  338. if(total == 0.0f)
  339. return;
  340. val = getMin(val, total);
  341. // two passes...
  342. total *= 2.0f;
  343. gLightingProgress = (val / total) + 0.5f;
  344. }
  345. //-----------------------------------------------
  346. void SceneLighting::processEvent(U32 light, S32 object)
  347. {
  348. sgNewEvent(light, object, sgSceneLightingProcessEvent::sgLightingStartEventType);
  349. }
  350. //-----------------------------------------------
  351. SceneLighting::SceneLighting(AvailableSLInterfaces* lightingInterfaces)
  352. {
  353. mLightingInterfaces = lightingInterfaces;
  354. mStartTime = 0;
  355. mFileName[0] = '\0';
  356. mSceneManager = NULL;
  357. // Registering vars more than once doesn't hurt anything.
  358. Con::addVariable("$sceneLighting::terminateLighting", TypeBool, &gTerminateLighting);
  359. Con::addVariable("$sceneLighting::lightingProgress", TypeF32, &gLightingProgress);
  360. mLightingInterfaces->initInterfaces();
  361. }
  362. SceneLighting::~SceneLighting()
  363. {
  364. gLighting = NULL;
  365. gLightingProgress = 0.0f;
  366. ObjectProxy ** proxyItr;
  367. for(proxyItr = mSceneObjects.begin(); proxyItr != mSceneObjects.end(); proxyItr++)
  368. delete *proxyItr;
  369. }
  370. void SceneLighting::getMLName(const char* misName, const U32 missionCRC, const U32 buffSize, char* filenameBuffer)
  371. {
  372. dSprintf(filenameBuffer, buffSize, "%s_%x.ml", misName, missionCRC);
  373. }
  374. bool SceneLighting::light(BitSet32 flags)
  375. {
  376. if(!mSceneManager)
  377. return(false);
  378. mStartTime = Platform::getRealMilliseconds();
  379. // Register static lights
  380. if (!LIGHTMGR)
  381. return false; // This world doesn't need lighting.
  382. LIGHTMGR->registerGlobalLights(NULL,true);
  383. // Notify each system factory that we are beginning to light
  384. for(SceneLightingInterface** sitr = mLightingInterfaces->mAvailableSystemInterfaces.begin(); sitr != mLightingInterfaces->mAvailableSystemInterfaces.end(); sitr++)
  385. {
  386. SceneLightingInterface* si = (*sitr);
  387. si->processLightingBegin();
  388. }
  389. // grab all the lights
  390. mLights.clear();
  391. LIGHTMGR->getAllUnsortedLights(&mLights);
  392. LIGHTMGR->unregisterAllLights();
  393. if(!mLights.size())
  394. return(false);
  395. // get all the objects and create proxy's for them
  396. SimpleQueryList objects;
  397. gClientContainer.findObjects(mLightingInterfaces->mAvailableObjectTypes, &SimpleQueryList::insertionCallback, &objects);
  398. for(SceneObject ** itr = objects.mList.begin(); itr != objects.mList.end(); itr++)
  399. {
  400. ObjectProxy * proxy = NULL;
  401. SceneObject* obj = *itr;
  402. if (!obj)
  403. continue;
  404. // Create the right chunk for the system
  405. for(SceneLightingInterface** sitr = mLightingInterfaces->mAvailableSystemInterfaces.begin();
  406. sitr != mLightingInterfaces->mAvailableSystemInterfaces.end() && proxy == NULL; sitr++)
  407. {
  408. SceneLightingInterface* si = (*sitr);
  409. proxy = si->createObjectProxy(obj, &mSceneObjects);
  410. }
  411. if (proxy)
  412. {
  413. if(!proxy->calcValidation())
  414. {
  415. Con::errorf(ConsoleLogEntry::General, "Failed to calculate validation info for object. Skipped.");
  416. delete proxy;
  417. continue;
  418. }
  419. if(!proxy->loadResources())
  420. {
  421. Con::errorf(ConsoleLogEntry::General, "Failed to load resources for object. Skipped.");
  422. delete proxy;
  423. continue;
  424. }
  425. mSceneObjects.push_back(proxy);
  426. }
  427. }
  428. if(!mSceneObjects.size())
  429. return(false);
  430. // grab the missions crc
  431. U32 missionCRC = calcMissionCRC();
  432. // remove the '.mis' extension from the mission name
  433. char misName[256];
  434. dSprintf(misName, sizeof(misName), "%s", Con::getVariable("$Client::MissionFile"));
  435. char * dot = dStrstr((const char*)misName, ".mis");
  436. if(dot)
  437. *dot = '\0';
  438. // get the mission name
  439. getMLName(misName, missionCRC, 1023, mFileName);
  440. // check for some persisted data, check if being forced..
  441. if(!flags.test(ForceAlways|ForceWritable))
  442. {
  443. if(loadPersistInfo(mFileName))
  444. {
  445. Con::printf(" Successfully loaded mission lighting file: '%s'", mFileName);
  446. // touch this file...
  447. if(!Platform::FS::Touch(mFileName))
  448. Con::warnf(" Failed to touch file '%s'. File may be read only.", mFileName);
  449. return(false);
  450. }
  451. // texture manager must have lighting complete now
  452. if(flags.test(LoadOnly))
  453. {
  454. Con::errorf(ConsoleLogEntry::General, "Failed to load mission lighting!");
  455. return(false);
  456. }
  457. }
  458. // don't light if file is read-only?
  459. if(!flags.test(ForceAlways))
  460. {
  461. FileStream stream;
  462. stream.open( mFileName, Torque::FS::File::Write );
  463. if(stream.getStatus() != Stream::Ok)
  464. {
  465. Con::errorf(ConsoleLogEntry::General, "SceneLighting::Light: Failed to light mission. File '%s' cannot be written to.", mFileName);
  466. return(false);
  467. }
  468. }
  469. // initialize the objects for lighting
  470. for(ObjectProxy ** proxyItr = mSceneObjects.begin(); proxyItr != mSceneObjects.end(); proxyItr++)
  471. (*proxyItr)->init();
  472. // get things started
  473. Sim::postEvent(this, new sgSceneLightingProcessEvent(0, -1,
  474. sgSceneLightingProcessEvent::sgLightingStartEventType), Sim::getTargetTime() + 1);
  475. return(true);
  476. }
  477. void SceneLighting::completed(bool success)
  478. {
  479. // process the cached lighting files
  480. processCache();
  481. // Notify each system factory that we are have lit!
  482. for(SceneLightingInterface** sitr = mLightingInterfaces->mAvailableSystemInterfaces.begin(); sitr != mLightingInterfaces->mAvailableSystemInterfaces.end(); sitr++)
  483. {
  484. SceneLightingInterface* si = (*sitr);
  485. si->processLightingCompleted(success);
  486. }
  487. if(gCompleteCallback && gCompleteCallback[0])
  488. Con::executef(gCompleteCallback);
  489. dFree(gCompleteCallback);
  490. gCompleteCallback = NULL;
  491. }
  492. //------------------------------------------------------------------------------
  493. // Static access method: there can be only one SceneLighting object
  494. bool SceneLighting::lightScene(const char * callback, BitSet32 flags)
  495. {
  496. if(gLighting)
  497. {
  498. Con::errorf(ConsoleLogEntry::General, "Lighting is already in progress!");
  499. return false;
  500. }
  501. // register the object
  502. if(!registerObject())
  503. {
  504. AssertFatal(0, "SceneLighting:: Unable to register SceneLighting object!");
  505. Con::errorf(ConsoleLogEntry::General, "SceneLighting:: Unable to register SceneLighting object!");
  506. delete this;
  507. return(false);
  508. }
  509. // could have interior resources but no instances (hey, got this far didnt we...)
  510. GameConnection * con = dynamic_cast<GameConnection*>(NetConnection::getConnectionToServer());
  511. if(!con)
  512. {
  513. Con::errorf(ConsoleLogEntry::General, "SceneLighting:: no GameConnection");
  514. return(false);
  515. }
  516. con->addObject(this);
  517. // set the globals
  518. gLighting = this;
  519. gTerminateLighting = false;
  520. gLightingProgress = 0.0f;
  521. if (gCompleteCallback)
  522. dFree(gCompleteCallback);
  523. gCompleteCallback = dStrdup(callback);
  524. gConnectionMissionCRC = con->getMissionCRC();
  525. // assumes we are in the world that needs lighting...
  526. mSceneManager = gClientSceneGraph;
  527. if(!light(flags))
  528. {
  529. completed(true);
  530. deleteObject();
  531. return(false);
  532. }
  533. return(true);
  534. }
  535. bool SceneLighting::isLighting()
  536. {
  537. return(bool(gLighting));
  538. }
  539. /// adds TSStatic objects as shadow casters.
  540. void SceneLighting::addStatic(ShadowVolumeBSP *shadowVolume,
  541. SceneObject *sceneobject, LightInfo *light, S32 level)
  542. {
  543. if (!sceneobject)
  544. return;
  545. if(light->getType() != LightInfo::Vector)
  546. return;
  547. ConcretePolyList polylist;
  548. const Box3F box;
  549. const SphereF sphere;
  550. sceneobject->buildPolyList(PLC_Collision, &polylist, box, sphere);
  551. // retrieve the poly list (uses the collision mesh)...
  552. //sobj->sgAdvancedStaticOptionsData.sgBuildPolyList(sobj, &polylist);
  553. S32 i, count, vertind[3];
  554. ConcretePolyList::Poly *poly;
  555. count = polylist.mPolyList.size();
  556. // add the polys to the shadow volume...
  557. for(i=0; i<count; i++)
  558. {
  559. poly = (ConcretePolyList::Poly *)&polylist.mPolyList[i];
  560. AssertFatal((poly->vertexCount == 3), "Hmmm... vert count is greater than 3.");
  561. vertind[0] = polylist.mIndexList[poly->vertexStart];
  562. vertind[1] = polylist.mIndexList[poly->vertexStart + 1];
  563. vertind[2] = polylist.mIndexList[poly->vertexStart + 2];
  564. if(mDot(PlaneF(polylist.mVertexList[vertind[0]], polylist.mVertexList[vertind[1]],
  565. polylist.mVertexList[vertind[2]]), light->getDirection()) < gParellelVectorThresh)
  566. {
  567. ShadowVolumeBSP::SVPoly *svpoly = shadowVolume->createPoly();
  568. svpoly->mWindingCount = 3;
  569. svpoly->mWinding[0].set(polylist.mVertexList[vertind[0]]);
  570. svpoly->mWinding[1].set(polylist.mVertexList[vertind[1]]);
  571. svpoly->mWinding[2].set(polylist.mVertexList[vertind[2]]);
  572. svpoly->mPlane = PlaneF(svpoly->mWinding[0], svpoly->mWinding[1], svpoly->mWinding[2]);
  573. svpoly->mPlane.neg();
  574. shadowVolume->buildPolyVolume(svpoly, light);
  575. shadowVolume->insertPoly(svpoly);
  576. }
  577. }
  578. }
  579. //------------------------------------------------------------------------------
  580. bool SceneLighting::verifyMissionInfo(PersistInfo::PersistChunk * chunk)
  581. {
  582. PersistInfo::MissionChunk * info = dynamic_cast<PersistInfo::MissionChunk*>(chunk);
  583. if(!info)
  584. return(false);
  585. PersistInfo::MissionChunk curInfo;
  586. if(!getMissionInfo(&curInfo))
  587. return(false);
  588. return(curInfo.mChunkCRC == info->mChunkCRC);
  589. }
  590. bool SceneLighting::getMissionInfo(PersistInfo::PersistChunk * chunk)
  591. {
  592. PersistInfo::MissionChunk * info = dynamic_cast<PersistInfo::MissionChunk*>(chunk);
  593. if(!info)
  594. return(false);
  595. info->mChunkCRC = gConnectionMissionCRC ^ PersistInfo::smFileVersion;
  596. return(true);
  597. }
  598. //------------------------------------------------------------------------------
  599. bool SceneLighting::loadPersistInfo(const char * fileName)
  600. {
  601. FileStream stream;
  602. stream.open( fileName, Torque::FS::File::Read );
  603. if(stream.getStatus() != Stream::Ok)
  604. return false;
  605. PersistInfo persistInfo;
  606. bool success = persistInfo.read(stream);
  607. stream.close();
  608. if(!success)
  609. return(false);
  610. // verify the mission chunk
  611. if(!verifyMissionInfo(persistInfo.mChunks[0]))
  612. return(false);
  613. // Create the right chunk for the system
  614. for(SceneLightingInterface** sitr = mLightingInterfaces->mAvailableSystemInterfaces.begin(); sitr != mLightingInterfaces->mAvailableSystemInterfaces.end(); sitr++)
  615. {
  616. SceneLightingInterface* si = (*sitr);
  617. if (!si->postProcessLoad(&persistInfo, &mSceneObjects))
  618. {
  619. return false;
  620. }
  621. }
  622. if(mSceneObjects.size() != (persistInfo.mChunks.size() - 1))
  623. return(false);
  624. Vector<PersistInfo::PersistChunk*> chunks;
  625. // ensure that the scene objects are in the same order as the chunks
  626. // - different instances will depend on this
  627. U32 i;
  628. for(i = 0; i < mSceneObjects.size(); i++)
  629. {
  630. // 0th chunk is the mission chunk
  631. U32 chunkIdx = i+1;
  632. if(chunkIdx >= persistInfo.mChunks.size())
  633. return(false);
  634. if(!mSceneObjects[i]->isValidChunk(persistInfo.mChunks[chunkIdx]))
  635. return(false);
  636. chunks.push_back(persistInfo.mChunks[chunkIdx]);
  637. }
  638. // get the objects to load in the persisted chunks
  639. for(i = 0; i < mSceneObjects.size(); i++)
  640. if(!mSceneObjects[i]->setPersistInfo(chunks[i]))
  641. return(false);
  642. return(true);
  643. }
  644. bool SceneLighting::savePersistInfo(const char * fileName)
  645. {
  646. // open the file
  647. FileStream file;
  648. file.open( fileName, Torque::FS::File::Write );
  649. if(file.getStatus() != Stream::Ok)
  650. return false;
  651. PersistInfo persistInfo;
  652. // add in the mission chunk
  653. persistInfo.mChunks.push_back(new PersistInfo::MissionChunk);
  654. // get the mission info, will return false when there are 0 lights
  655. if(!getMissionInfo(persistInfo.mChunks[0]))
  656. return(false);
  657. // get all the persist chunks
  658. bool bChunkFound;
  659. for(U32 i = 0; i < mSceneObjects.size(); i++)
  660. {
  661. bChunkFound = false;
  662. // Create the right chunk for the system
  663. for(SceneLightingInterface** sitr = mLightingInterfaces->mAvailableSystemInterfaces.begin(); sitr != mLightingInterfaces->mAvailableSystemInterfaces.end() && !bChunkFound; sitr++)
  664. {
  665. SceneLightingInterface* si = (*sitr);
  666. PersistInfo::PersistChunk* chunk;
  667. if (si->createPersistChunkFromProxy(mSceneObjects[i], &chunk))
  668. {
  669. if (chunk)
  670. {
  671. persistInfo.mChunks.push_back(chunk);
  672. bChunkFound = true;
  673. }
  674. }
  675. }
  676. // Make sure the chunk worked.
  677. if (!mSceneObjects[i]->getPersistInfo(persistInfo.mChunks.last()))
  678. return false;
  679. }
  680. if(!persistInfo.write(file))
  681. return(false);
  682. file.close();
  683. return(true);
  684. }
  685. struct CacheEntry {
  686. Torque::FS::FileNodeRef mFileObject;
  687. const char *mFileName;
  688. CacheEntry() {
  689. mFileName = 0;
  690. };
  691. };
  692. // object list sort methods: want list in reverse
  693. static S32 QSORT_CALLBACK minSizeSort(const void * p1, const void * p2)
  694. {
  695. const CacheEntry * entry1 = (const CacheEntry *)p1;
  696. const CacheEntry * entry2 = (const CacheEntry *)p2;
  697. return(entry2->mFileObject->getSize() - entry1->mFileObject->getSize());
  698. }
  699. static S32 QSORT_CALLBACK maxSizeSort(const void * p1, const void * p2)
  700. {
  701. const CacheEntry * entry1 = (const CacheEntry *)p1;
  702. const CacheEntry * entry2 = (const CacheEntry *)p2;
  703. return(entry1->mFileObject->getSize() - entry2->mFileObject->getSize());
  704. }
  705. static S32 QSORT_CALLBACK lastCreatedSort(const void * p1, const void * p2)
  706. {
  707. const CacheEntry * entry1 = (const CacheEntry *)p1;
  708. const CacheEntry * entry2 = (const CacheEntry *)p2;
  709. FileTime create[2];
  710. FileTime modify;
  711. bool ret[2];
  712. ret[0] = Platform::getFileTimes(entry1->mFileName, &create[0], &modify);
  713. ret[1] = Platform::getFileTimes(entry2->mFileName, &create[1], &modify);
  714. // check return values
  715. if(!ret[0] && !ret[1])
  716. return(0);
  717. if(!ret[0])
  718. return(1);
  719. if(!ret[1])
  720. return(-1);
  721. return(Platform::compareFileTimes(create[1], create[0]));
  722. }
  723. static S32 QSORT_CALLBACK lastModifiedSort(const void * p1, const void * p2)
  724. {
  725. const CacheEntry * entry1 = (const CacheEntry *)p1;
  726. const CacheEntry * entry2 = (const CacheEntry *)p2;
  727. FileTime create;
  728. FileTime modify[2];
  729. bool ret[2];
  730. ret[0] = Platform::getFileTimes(entry1->mFileName, &create, &modify[0]);
  731. ret[1] = Platform::getFileTimes(entry2->mFileName, &create, &modify[1]);
  732. // check return values
  733. if(!ret[0] && !ret[1])
  734. return(0);
  735. if(!ret[0])
  736. return(1);
  737. if(!ret[1])
  738. return(-1);
  739. return(Platform::compareFileTimes(modify[1], modify[0]));
  740. }
  741. void SceneLighting::processCache()
  742. {
  743. // get size in kb
  744. S32 quota = Con::getIntVariable("$sceneLighting::cacheSize", -1);
  745. Vector<CacheEntry> files;
  746. Vector<String> fileNames;
  747. Torque::FS::FindByPattern(Torque::Path(Platform::getMainDotCsDir()), "*.ml", true, fileNames);
  748. S32 curCacheSize = 0;
  749. for(S32 i = 0;i < fileNames.size();++i)
  750. {
  751. if(! Torque::FS::IsFile(fileNames[i]))
  752. continue;
  753. Torque::FS::FileNodeRef fileNode = Torque::FS::GetFileNode(fileNames[i]);
  754. if(fileNode == NULL)
  755. continue;
  756. if(dStrstr(fileNames[i], mFileName) == 0)
  757. {
  758. // Don't allow the current file to be removed
  759. CacheEntry entry;
  760. entry.mFileObject = fileNode;
  761. entry.mFileName = StringTable->insert(fileNames[i]);
  762. files.push_back(entry);
  763. }
  764. else
  765. curCacheSize += fileNode->getSize();
  766. }
  767. // remove old files
  768. for(S32 i = files.size() - 1; i >= 0; i--)
  769. {
  770. FileStream *stream;
  771. if((stream = FileStream::createAndOpen( files[i].mFileObject->getName(), Torque::FS::File::Read )) == NULL)
  772. continue;
  773. // read in the version
  774. U32 version;
  775. bool ok = (stream->read(&version) && (version == PersistInfo::smFileVersion));
  776. delete stream;
  777. // ok?
  778. if(ok)
  779. continue;
  780. // no sneaky names
  781. if(!dStrstr(files[i].mFileName, ".."))
  782. {
  783. Con::warnf("Removing old lighting file '%s'.", files[i].mFileName);
  784. dFileDelete(files[i].mFileName);
  785. }
  786. files.pop_back();
  787. }
  788. // no size restriction?
  789. if(quota == -1 || !files.size())
  790. return;
  791. for(U32 i = 0; i < files.size(); i++)
  792. curCacheSize += files[i].mFileObject->getSize();
  793. // need to remove?
  794. if(quota > (curCacheSize >> 10))
  795. return;
  796. // sort the entries by the correct method
  797. const char * purgeMethod = Con::getVariable("$sceneLighting::purgeMethod");
  798. if(!purgeMethod)
  799. purgeMethod = "";
  800. // determine the method (default to least recently used)
  801. if(!dStricmp(purgeMethod, "minSize"))
  802. dQsort(files.address(), files.size(), sizeof(CacheEntry), minSizeSort);
  803. else if(!dStricmp(purgeMethod, "maxSize"))
  804. dQsort(files.address(), files.size(), sizeof(CacheEntry), maxSizeSort);
  805. else if(!dStricmp(purgeMethod, "lastCreated"))
  806. dQsort(files.address(), files.size(), sizeof(CacheEntry), lastCreatedSort);
  807. else
  808. dQsort(files.address(), files.size(), sizeof(CacheEntry), lastModifiedSort);
  809. // go through and remove the best candidate first (sorted reverse)
  810. while(((curCacheSize >> 10) > quota) && files.size())
  811. {
  812. curCacheSize -= files.last().mFileObject->getSize();
  813. // no sneaky names
  814. if(!dStrstr(files.last().mFileName, ".."))
  815. {
  816. Con::warnf("Removing lighting file '%s'.", files.last().mFileName);
  817. dFileDelete(files.last().mFileName);
  818. }
  819. files.pop_back();
  820. }
  821. }
  822. static S32 QSORT_CALLBACK compareS32(const void * a, const void * b)
  823. {
  824. return(*((S32 *)a) - *((S32 *)b));
  825. }
  826. U32 SceneLighting::calcMissionCRC()
  827. {
  828. // all the objects + mission chunk
  829. Vector<U32> crc;
  830. // grab the object crcs
  831. for(U32 i = 0; i < mSceneObjects.size(); i++)
  832. crc.push_back( mSceneObjects[i]->mChunkCRC );
  833. // grab the missions crc
  834. PersistInfo::MissionChunk curInfo;
  835. getMissionInfo(&curInfo);
  836. crc.push_back(curInfo.mChunkCRC);
  837. // sort them (order may not have been preserved)
  838. dQsort(crc.address(), crc.size(), sizeof(U32), compareS32);
  839. #ifdef TORQUE_BIG_ENDIAN
  840. // calculateCRC operates on 8-bit chunks of memory. The memory is a vector
  841. // of U32's, and so the result will be different on big/little endian hardware.
  842. // To fix this, swap endians on the CRC's in the vector. This must be done
  843. // _after_ the qsort.
  844. for( S32 i = 0; i < crc.size(); i++ )
  845. crc[i] = endianSwap( crc[i] );
  846. #endif
  847. return(CRC::calculateCRC(crc.address(), sizeof(U32) * crc.size(), 0xffffffff));
  848. }
  849. bool SceneLighting::ObjectProxy::calcValidation()
  850. {
  851. mChunkCRC = getResourceCRC();
  852. if(!mChunkCRC)
  853. return(false);
  854. return(true);
  855. }
  856. bool SceneLighting::ObjectProxy::isValidChunk(PersistInfo::PersistChunk * chunk)
  857. {
  858. return(chunk->mChunkCRC == mChunkCRC);
  859. }
  860. bool SceneLighting::ObjectProxy::getPersistInfo(PersistInfo::PersistChunk * chunk)
  861. {
  862. chunk->mChunkCRC = mChunkCRC;
  863. return(true);
  864. }
  865. bool SceneLighting::ObjectProxy::setPersistInfo(PersistInfo::PersistChunk * chunk)
  866. {
  867. mChunkCRC = chunk->mChunkCRC;
  868. return(true);
  869. }