sceneLighting.cpp 31 KB

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