Lightscape.cpp 118 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681
  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. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : LightMap *
  23. * *
  24. * $Archive:: /Commando/Code/Tool $*
  25. * *
  26. * $Author:: Ian_l $*
  27. * *
  28. * $Modtime:: 8/24/01 9:24p $*
  29. * *
  30. * $Revision:: 60 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. // Includes.
  36. #include "StdAfx.h"
  37. #include "LightMap.h"
  38. #include "Lightscape.h"
  39. #include "LightMapPacker.h"
  40. #include "OptionsDialog.h"
  41. #include "PerlinNoise.h"
  42. #include "StringBuilder.h"
  43. #include "TextureNameNode.h"
  44. #include "matrix3.h"
  45. #include "matrix3d.h"
  46. #include "lightexclude.h"
  47. #include "tri.h"
  48. #include "vector3.h"
  49. #include "wwmath.h"
  50. #include <float.h>
  51. #include <math.h>
  52. #include <typeinfo.h>
  53. // Static data.
  54. LightscapeSolve *LightscapeSolve::_ActiveImporter = NULL;
  55. /***********************************************************************************************
  56. * LightscapeSolve::LightscapeSolve -- *
  57. * *
  58. * INPUT: *
  59. * *
  60. * OUTPUT: *
  61. * *
  62. * WARNINGS: *
  63. * *
  64. * HISTORY: *
  65. * 7/27/99 IML : Created. *
  66. *=============================================================================================*/
  67. LightscapeSolve::LightscapeSolve (const char *solvedirectoryname, const char *solvefilenamelist, CStatusBar* statusptr, const char *statusbarmessage, bool blendnoise)
  68. : LightmapPacker()
  69. {
  70. const char *notsolutiontext =
  71. "One or more solve files are not solution (.ls) files.";
  72. const int materialtexturenamegrowthstep = 256;
  73. const int patchfacegrowthstep = 1024;
  74. const int vertexgrowthstep = 2048;
  75. const int lightgrowthstep = 32;
  76. static char _messagebuffer [1024];
  77. CRect srect, trect;
  78. BOOL success;
  79. StringBuilder errormessage (_messagebuffer, sizeof (_messagebuffer));
  80. const char *solvefilename;
  81. LtTBuilderFactory *factory = NULL;
  82. OptionsDialog options;
  83. // Initialize.
  84. SmoothingAngle = DEG_TO_RAD (options.Get_Smoothing_Angle()); // Convert from degrees to radians.
  85. SpatialTolerance = options.Get_Spatial_Tolerance(); // No mapping required.
  86. FilterSharpness = pow (options.Get_Filter_Sharpness() / 50.0l, 5.0l); // Map from linear to exponential scale.
  87. // If noise has been requested create a Perlin Noise generator.
  88. if (blendnoise) {
  89. ProceduralTexture = new PerlinNoise;
  90. ASSERT (ProceduralTexture != NULL);
  91. } else {
  92. ProceduralTexture = NULL;
  93. }
  94. if (options.Get_Light_Export_Selective()) {
  95. LightExclusionString = options.Get_Light_Exclusion_String();
  96. } else {
  97. LightExclusionString = NULL;
  98. }
  99. statusptr->GetItemRect (0, &srect);
  100. statusptr->SetPaneText (0, statusbarmessage);
  101. statusptr->GetDC()->DrawText (statusbarmessage, -1, &trect, DT_CALCRECT);
  102. CRect prect (srect.TopLeft().x + trect.Width(), srect.TopLeft().y, srect.BottomRight().x, srect.BottomRight().y);
  103. ProgressBar = new CProgressCtrl;
  104. ASSERT (ProgressBar != NULL);
  105. success = ProgressBar->Create (WS_CHILD | WS_VISIBLE | PBS_SMOOTH, prect, statusptr, 0);
  106. ASSERT (success);
  107. // Specify how many elements should be added to dynamic arrays when they are resized.
  108. MaterialTextureNames.Set_Growth_Step (materialtexturenamegrowthstep);
  109. PatchFaces.Set_Growth_Step (patchfacegrowthstep);
  110. Vertices.Set_Growth_Step (vertexgrowthstep);
  111. VertexIndices.Set_Growth_Step (vertexgrowthstep);
  112. Lights.Set_Growth_Step (lightgrowthstep);
  113. _ActiveImporter = this;
  114. try {
  115. char solvepathname [_MAX_PATH];
  116. int totalpatchclustercount = 0;
  117. // Parse the files, check that they are solve files and sum the patch cluster count for the progress bar.
  118. solvefilename = solvefilenamelist;
  119. while (strlen (solvefilename) > 0) {
  120. strcpy (solvepathname, solvedirectoryname);
  121. strcat (solvepathname, solvefilename);
  122. factory = new LsInformationFactory;
  123. ASSERT (factory != NULL);
  124. ::LtSolutionImport (solvepathname, *factory);
  125. if (!IsSolution) throw (notsolutiontext);
  126. totalpatchclustercount += PatchClusterCount;
  127. errormessage.Copy (factory->GetErrorMsg());
  128. delete factory;
  129. factory = NULL;
  130. if (strlen (errormessage.String()) > 0) throw (errormessage.String());
  131. // Advance to next solve file.
  132. solvefilename += strlen (solvefilename) + 1;
  133. }
  134. // Set-up the progress bar so that it can be updated for every patch cluster.
  135. ProgressBar->SetRange32 (0, totalpatchclustercount);
  136. ProgressBar->SetStep (1);
  137. // For each solve filename in the list...
  138. solvefilename = solvefilenamelist;
  139. while (strlen (solvefilename) > 0) {
  140. strcpy (solvepathname, solvedirectoryname);
  141. strcat (solvepathname, solvefilename);
  142. // Parse the Lightscape solve file and process materials.
  143. // NOTE: Material processing must be done first because mesh processing is dependant on it.
  144. // In order to guarantee this, the solution file is parsed twice, so that there is no
  145. // implicit reliance on the material data preceeding the mesh data in the file.
  146. factory = new LsPreparationFactory;
  147. ASSERT (factory != NULL);
  148. ::LtSolutionImport (solvepathname, *factory);
  149. errormessage.Copy (factory->GetErrorMsg());
  150. delete factory;
  151. factory = NULL;
  152. if (strlen (errormessage.String()) > 0) throw (errormessage.String());
  153. // Sort the material-texture names by a key defined by the comparison function Compare_Material_Names().
  154. // NOTE: qsort MUST (and does) allow for duplicate keys.
  155. if (MaterialTextureNames.Count() > 0) {
  156. qsort (&MaterialTextureNames [0], MaterialTextureNames.Count(), sizeof (char*), Compare_Material_Texture_Names);
  157. }
  158. // Parse the Lightscape solve file and add all vertices and faces that have been
  159. // processed by Mesh to Texture.
  160. factory = new LsMainFactory;
  161. ASSERT (factory != NULL);
  162. ::LtSolutionImport (solvepathname, *factory);
  163. errormessage.Copy (factory->GetErrorMsg());
  164. delete factory;
  165. factory = NULL;
  166. if (strlen (errormessage.String()) > 0) throw (errormessage.String());
  167. // Clean-up the the material-texture names. They are no longer required.
  168. for (int i = 0; i < MaterialTextureNames.Count(); i++) {
  169. delete [] MaterialTextureNames [i];
  170. }
  171. MaterialTextureNames.Clear();
  172. // Advance to next solve file.
  173. solvefilename += strlen (solvefilename) + 1;
  174. }
  175. if (Vertices.Count() > 0) {
  176. // Create a vertex index table and initialize the indices to identity.
  177. for (int v = 0; v < Vertices.Count(); v++) {
  178. VertexIndices.Insert (v, v);
  179. }
  180. // Sort the vertex pointers by a key defined by the comparison function Compare_Vertices().
  181. // NOTE: qsort MUST (and does) allow for duplicate keys.
  182. qsort (&VertexIndices [0], VertexIndices.Count(), sizeof (unsigned), Compare_Vertices);
  183. }
  184. // Sort the patch faces by a key defined by the comparison function Compare_Patch_Faces().
  185. // NOTE: qsort MUST (and does) allow for duplicate keys.
  186. if (PatchFaces.Count() > 0) {
  187. qsort (&PatchFaces [0], PatchFaces.Count(), sizeof (PatchFaceStruct), Compare_Patch_Faces);
  188. }
  189. } catch (const char *errormessage) {
  190. // Clean-up.
  191. if (factory != NULL) delete factory;
  192. if (ProgressBar != NULL) {
  193. delete ProgressBar;
  194. ProgressBar = NULL;
  195. }
  196. // Re-throw the message to the caller.
  197. throw (errormessage);
  198. }
  199. _ActiveImporter = NULL;
  200. delete ProgressBar;
  201. ProgressBar = NULL;
  202. }
  203. /***********************************************************************************************
  204. * LightscapeSolve::Finish -- *
  205. * *
  206. * INPUT: *
  207. * *
  208. * OUTPUT: *
  209. * *
  210. * WARNINGS: *
  211. * *
  212. * HISTORY: *
  213. * 7/27/99 IML : Created. *
  214. *=============================================================================================*/
  215. LightscapeSolve::Finish()
  216. {
  217. LightmapPacker::Finish();
  218. }
  219. /***********************************************************************************************
  220. * LightscapeSolve::~LightscapeSolve -- *
  221. * *
  222. * INPUT: *
  223. * *
  224. * OUTPUT: *
  225. * *
  226. * WARNINGS: Do not throw any exceptions in this (and any other) destructor because this *
  227. * destructor can itself be called during the exception as part of its 'clean-up'. *
  228. * *
  229. * HISTORY: *
  230. * 7/27/99 IML : Created. *
  231. *=============================================================================================*/
  232. LightscapeSolve::~LightscapeSolve()
  233. {
  234. int i, l;
  235. // Clean-up anything that didn't get cleaned up before because an exception was thrown.
  236. for (i = 0; i < MaterialTextureNames.Count(); i++) {
  237. delete [] MaterialTextureNames [i];
  238. }
  239. _ActiveImporter = NULL;
  240. // Clean-up the texture names.
  241. for (i = 0; i < TextureNames.Length(); i++) {
  242. TextureNameNode *texturenamenode, *removalnode;
  243. texturenamenode = TextureNames [i];
  244. while (texturenamenode != NULL) {
  245. removalnode = texturenamenode;
  246. texturenamenode = texturenamenode->Next;
  247. delete removalnode;
  248. }
  249. }
  250. // Release references to lights.
  251. for (l = 0; l < Lights.Count(); l++) {
  252. Lights [l]->Release_Ref();
  253. }
  254. if (ProceduralTexture != NULL) delete ProceduralTexture;
  255. }
  256. /***********************************************************************************************
  257. * LightscapeSolve::Add_Material_Texture_Name -- *
  258. * *
  259. * INPUT: *
  260. * *
  261. * OUTPUT: *
  262. * *
  263. * WARNINGS: *
  264. * *
  265. * HISTORY: *
  266. * 7/27/99 IML : Created. *
  267. *=============================================================================================*/
  268. void LightscapeSolve::Add_Material_Texture_Name (const char *materialname, const char *texturepathname)
  269. {
  270. const char *invalidtexturepathname = "";
  271. unsigned materialnamelength, texturepathnamelength;
  272. char *name;
  273. // The material name must exist.
  274. ASSERT (materialname != NULL);
  275. // If the material has no associated texture use the invalid texture pathname.
  276. if (texturepathname == NULL) texturepathname = invalidtexturepathname;
  277. // Calculate length of strings including terminator.
  278. materialnamelength = strlen (materialname) + 1;
  279. texturepathnamelength = strlen (texturepathname) + 1;
  280. name = new char [materialnamelength + texturepathnamelength];
  281. ASSERT (name != NULL);
  282. strcpy (name, materialname);
  283. // Append the texture name to the material name but leave the material name's terminator
  284. // intact so that conventional string functions only 'see' the material name.
  285. strcpy (name + materialnamelength, texturepathname);
  286. MaterialTextureNames.Add (name);
  287. }
  288. /***********************************************************************************************
  289. * LightscapeSolve::Add_Texture_Name -- *
  290. * *
  291. * INPUT: *
  292. * *
  293. * OUTPUT: *
  294. * *
  295. * WARNINGS: *
  296. * *
  297. * HISTORY: *
  298. * 9/16/99 IML : Created. *
  299. *=============================================================================================*/
  300. void LightscapeSolve::Add_Texture_Name (unsigned patchindex, const char *materialname)
  301. {
  302. const char *materialnotfoundtext =
  303. "There is a face in the model that has a material name that cannot be found.";
  304. int length;
  305. char **materialnameptr;
  306. char *texturepathname;
  307. unsigned texturepathnamelength;
  308. // Can the texture name data be accomodated by the texture name array?
  309. length = TextureNames.Length();
  310. if ((int) patchindex >= length) {
  311. const int growthstep = 1024; // Add this many elements if the vector array runs out of room.
  312. bool success = TextureNames.Resize (patchindex + growthstep);
  313. ASSERT (success);
  314. // Null out the new elements.
  315. for (int i = length; i < TextureNames.Length(); i++) {
  316. TextureNames [i] = NULL;
  317. }
  318. }
  319. // NOTE: The material-texture names MUST have been sorted prior to calling bsearch().
  320. if (MaterialTextureNames.Count() > 0) {
  321. const char **keyptr;
  322. const char *key;
  323. key = materialname;
  324. keyptr = &key;
  325. materialnameptr = (char**) bsearch (keyptr, &MaterialTextureNames [0], MaterialTextureNames.Count(), sizeof (char*), Compare_Material_Texture_Names);
  326. } else {
  327. materialnameptr = NULL;
  328. }
  329. // If the material cannot be found then either the database has malfunctioned or the solve
  330. // file is corrupt.
  331. if (materialnameptr == NULL) {
  332. ASSERT (FALSE);
  333. throw (materialnotfoundtext);
  334. }
  335. // Extract the texture name.
  336. texturepathname = *materialnameptr + strlen (*materialnameptr) + 1;
  337. texturepathnamelength = strlen (texturepathname) + 1;
  338. // Add the name to the database only if it exists (has non-zero length excluding terminator).
  339. if (texturepathnamelength > 1) {
  340. TextureNameNode *node;
  341. node = new TextureNameNode (texturepathname);
  342. ASSERT (node != NULL);
  343. // Add the texture name to the database.
  344. node->Next = TextureNames [patchindex];
  345. TextureNames [patchindex] = node;
  346. }
  347. }
  348. /***********************************************************************************************
  349. * LightscapeSolve::Add_Light -- *
  350. * *
  351. * INPUT: *
  352. * *
  353. * OUTPUT: *
  354. * *
  355. * WARNINGS: *
  356. * *
  357. * HISTORY: *
  358. * 3/24/00 IML : Created. *
  359. *=============================================================================================*/
  360. void LightscapeSolve::Add_Light (LightClass *light)
  361. {
  362. Lights.Add (light);
  363. light->Add_Ref();
  364. }
  365. /***********************************************************************************************
  366. * LightscapeSolve::Add_Vertex -- *
  367. * *
  368. * INPUT: *
  369. * *
  370. * OUTPUT: *
  371. * *
  372. * WARNINGS: *
  373. * *
  374. * HISTORY: *
  375. * 1/25/00 IML : Created. *
  376. *=============================================================================================*/
  377. bool LightscapeSolve::Add_Vertex (unsigned vertexindex, const Vector3 &p, const Vector3 &n, unsigned patchindex, const Vector2 &t)
  378. {
  379. bool success;
  380. // If adding a M2T vertex, ensure that this is a M2T solve.
  381. ASSERT (Importer()->Is_M2T_Solve());
  382. // Has the element already been inserted?
  383. if (((int) vertexindex) < Vertices.Count()) {
  384. // Check that the new element data matches the existing data.
  385. success = (Vertices [vertexindex].Point == p) &&
  386. (Vertices [vertexindex].FaceNormal == n) &&
  387. (Vertices [vertexindex].PatchIndex == patchindex);
  388. } else {
  389. VerticesStruct vertex;
  390. vertex.Point = p;
  391. vertex.FaceNormal = n;
  392. vertex.PatchIndex = patchindex;
  393. vertex.ValidColor = false;
  394. vertex.ValidUV = false;
  395. success = Vertices.Insert (vertexindex, vertex);
  396. }
  397. if (success) {
  398. Vertices [vertexindex].UV = t;
  399. Vertices [vertexindex].ValidUV = true;
  400. }
  401. return (success);
  402. }
  403. /***********************************************************************************************
  404. * LightscapeSolve::Add_Vertex -- *
  405. * *
  406. * INPUT: *
  407. * *
  408. * OUTPUT: *
  409. * *
  410. * WARNINGS: *
  411. * *
  412. * HISTORY: *
  413. * 1/25/00 IML : Created. *
  414. *=============================================================================================*/
  415. bool LightscapeSolve::Add_Vertex (unsigned vertexindex, const Vector3 &p, const Vector3 &n, unsigned patchindex, const ColorVector &c)
  416. {
  417. bool success;
  418. // Has the element already been inserted?
  419. if (((int) vertexindex) < Vertices.Count()) {
  420. // Check that the new element data matches the existing data.
  421. success = (Vertices [vertexindex].Point == p) &&
  422. (Vertices [vertexindex].FaceNormal == n) &&
  423. (Vertices [vertexindex].PatchIndex == patchindex);
  424. } else {
  425. VerticesStruct vertex;
  426. vertex.Point = p;
  427. vertex.FaceNormal = n;
  428. vertex.PatchIndex = patchindex;
  429. vertex.ValidColor = false;
  430. vertex.ValidUV = false;
  431. success = Vertices.Insert (vertexindex, vertex);
  432. }
  433. if (success) {
  434. // Only add/set the color if this is not a M2T solve.
  435. if (!Importer()->Is_M2T_Solve()) {
  436. // Add or set the color?
  437. if (Vertices [vertexindex].ValidColor) {
  438. const ColorVector clamp (1.0f, 1.0f, 1.0f);
  439. // Add and clamp.
  440. Vertices [vertexindex].Color += c;
  441. Vertices [vertexindex].Color.Update_Min (clamp);
  442. } else {
  443. Vertices [vertexindex].Color = c;
  444. Vertices [vertexindex].ValidColor = true;
  445. }
  446. }
  447. }
  448. return (success);
  449. }
  450. /***********************************************************************************************
  451. * LightscapeSolve::Add_Patch_Face -- *
  452. * *
  453. * INPUT: *
  454. * *
  455. * OUTPUT: *
  456. * *
  457. * WARNINGS: *
  458. * *
  459. * HISTORY: *
  460. * 9/16/99 IML : Created. *
  461. *=============================================================================================*/
  462. bool LightscapeSolve::Add_Patch_Face (unsigned patchfaceindex, unsigned patchindex, unsigned vertexindexcount, unsigned *vertexindices)
  463. {
  464. bool success;
  465. // Only 3 or 4 vertex indices are supported.
  466. ASSERT (vertexindexcount == 3 || vertexindexcount == 4);
  467. // Has the element already been inserted?
  468. if (((int) patchfaceindex) < PatchFaces.Count()) {
  469. // Check that the new element data matches the existing data.
  470. success = (patchindex == PatchFaces [patchfaceindex].PatchIndex) &&
  471. (vertexindices [0] == PatchFaces [patchfaceindex].VertexIndices [0]) &&
  472. (vertexindices [1] == PatchFaces [patchfaceindex].VertexIndices [1]) &&
  473. (vertexindices [2] == PatchFaces [patchfaceindex].VertexIndices [2]);
  474. if (vertexindexcount == 4) {
  475. success &= (vertexindices [3] == PatchFaces [patchfaceindex].VertexIndices [3]);
  476. }
  477. } else {
  478. PatchFaceStruct patchface;
  479. patchface.PatchIndex = patchindex;
  480. patchface.VertexIndices [0] = vertexindices [0];
  481. patchface.VertexIndices [1] = vertexindices [1];
  482. patchface.VertexIndices [2] = vertexindices [2];
  483. if (vertexindexcount == 4) {
  484. patchface.VertexIndices [3] = vertexindices [3];
  485. } else {
  486. patchface.VertexIndices [3] = PatchFaceStruct::VERTEX_INDEX_INVALID;
  487. }
  488. success = PatchFaces.Insert (patchfaceindex, patchface);
  489. }
  490. return (success);
  491. }
  492. /***********************************************************************************************
  493. * LightscapeSolve::Find_Vertex -- *
  494. * *
  495. * INPUT: *
  496. * *
  497. * OUTPUT: *
  498. * *
  499. * WARNINGS: *
  500. * *
  501. * HISTORY: *
  502. * 1/07/00 IML : Created. *
  503. *=============================================================================================*/
  504. void LightscapeSolve::Find_Vertex (const Vector3 &point, const Vector3 *smoothingnormalptr, W3dRGBStruct &vertexcolor, SolveStatistics &solvestatistics)
  505. {
  506. const int growthstep = 256;
  507. const W3dRGBStruct pink (255, 0, 255);
  508. DynamicVectorClass <VerticesStruct*> vertexset;
  509. ColorVector color;
  510. unsigned count;
  511. vertexset.Set_Growth_Step (growthstep);
  512. Find_Vertices (point, SpatialTolerance, vertexset);
  513. if (vertexset.Count() > 0) {
  514. color.Set (0.0f, 0.0f, 0.0f);
  515. count = 0;
  516. if (smoothingnormalptr != NULL) {
  517. // Sum the colors of all vertices that lie within the smoothing normal.
  518. for (int v = 0; v < vertexset.Count(); v++) {
  519. if (vertexset [v]->ValidColor) {
  520. float angle;
  521. // Is the face that is associated with this vertex within the smoothing angle
  522. // of the supplied vertex normal?
  523. angle = acosf (Vector3::Dot_Product (*smoothingnormalptr, vertexset [v]->FaceNormal));
  524. if (angle <= SmoothingAngle) {
  525. color += vertexset [v]->Color;
  526. count++;
  527. }
  528. }
  529. }
  530. if (count > 0) {
  531. color /= ((float) count);
  532. vertexcolor.Set (color.X, color.Y, color.Z);
  533. return;
  534. }
  535. }
  536. // Sum the colors of all vertices regardless of smoothing normal.
  537. for (int v = 0; v < vertexset.Count(); v++) {
  538. if (vertexset [v]->ValidColor) {
  539. color += vertexset [v]->Color;
  540. count++;
  541. }
  542. }
  543. if (count > 0) {
  544. color /= ((float) count);
  545. vertexcolor.Set (color.X, color.Y, color.Z);
  546. solvestatistics.Count [SolveStatistics::VERTEX_NOT_SMOOTH]++;
  547. return;
  548. } else {
  549. // There are no vertices with a valid color. Return a place-holder color.
  550. vertexcolor = pink;
  551. solvestatistics.Count [SolveStatistics::VERTEX_NO_COLOR]++;
  552. return;
  553. }
  554. }
  555. // Vertex not found. Return a place-holder color.
  556. vertexcolor = pink;
  557. solvestatistics.Count [SolveStatistics::VERTEX_NOT_FOUND]++;
  558. return;
  559. }
  560. /***********************************************************************************************
  561. * LightscapeSolve::Find_Triangle -- *
  562. * *
  563. * INPUT: *
  564. * *
  565. * OUTPUT: *
  566. * *
  567. * WARNINGS: *
  568. * *
  569. * HISTORY: *
  570. * 06/07/00 IML : Created. *
  571. *=============================================================================================*/
  572. void LightscapeSolve::Find_Triangle (const Vector3 *points, const Vector3 &normal, PackingTriangle &triangle, SolveStatistics &solvestatistics)
  573. {
  574. const unsigned notextureid = 0xffffffff; // Arbitrary ID used to indicate that there is no associated texture.
  575. VerticesStruct trianglevertices [Triangle::VERTICES_COUNT];
  576. FaceResultEnum faceresult;
  577. bool notexture;
  578. unsigned v;
  579. ASSERT (points != NULL);
  580. // First, attempt a match with the face itself.
  581. switch (Face_Size (points, Triangle::VERTICES_COUNT)) {
  582. case FACE_UNDERSIZED:
  583. case FACE_NOT_UNDERSIZED:
  584. Find_Triangle (points, normal, trianglevertices, faceresult);
  585. break;
  586. case FACE_DEGENERATE:
  587. solvestatistics.Count [SolveStatistics::FACE_DEGENERATE]++;
  588. faceresult = FACE_NOT_FOUND;
  589. break;
  590. }
  591. notexture = false;
  592. switch (faceresult) {
  593. case FACE_AMBIGUOUS:
  594. solvestatistics.Count [SolveStatistics::FACE_AMBIGUOUS]++;
  595. // No break.
  596. case FACE_FOUND:
  597. {
  598. TextureNameNode *texturenamenodeptr;
  599. bool validuvs;
  600. // Check that texture exists and that all UV's are valid.
  601. texturenamenodeptr = (TextureNameNode*) Texture_Name (trianglevertices [0].PatchIndex);
  602. if (texturenamenodeptr != NULL) {
  603. validuvs = true;
  604. for (v = 0; v < Triangle::VERTICES_COUNT; v++) {
  605. validuvs &= trianglevertices [v].ValidUV;
  606. }
  607. if (validuvs) {
  608. triangle.TextureNameNodePtr = texturenamenodeptr;
  609. triangle.TextureID = trianglevertices [0].PatchIndex;
  610. triangle.Normal = trianglevertices [0].FaceNormal;
  611. for (v = 0; v < Triangle::VERTICES_COUNT; v++) {
  612. triangle.Vertices [v].Point = trianglevertices [v].Point;
  613. triangle.Vertices [v].UV = trianglevertices [v].UV;
  614. }
  615. break;
  616. }
  617. }
  618. notexture = true;
  619. solvestatistics.Count [SolveStatistics::FACE_NO_LIGHTMAP]++;
  620. break;
  621. }
  622. case FACE_NOT_FOUND:
  623. notexture = true;
  624. solvestatistics.Count [SolveStatistics::FACE_NOT_FOUND]++;
  625. break;
  626. }
  627. if (notexture) {
  628. // Return the original triangle with no associated texture.
  629. triangle.Normal = normal;
  630. for (v = 0; v < Triangle::VERTICES_COUNT; v++) {
  631. triangle.Vertices [v].Point = points [v];
  632. }
  633. triangle.TextureNameNodePtr = NULL;
  634. triangle.TextureID = notextureid;
  635. }
  636. }
  637. /***********************************************************************************************
  638. * LightscapeSolve::Submit_Triangle -- *
  639. * *
  640. * INPUT: *
  641. * *
  642. * OUTPUT: *
  643. * *
  644. * WARNINGS: *
  645. * *
  646. * HISTORY: *
  647. * 06/07/00 IML : Created. *
  648. *=============================================================================================*/
  649. void LightscapeSolve::Submit_Triangle (PackingTriangle &triangle)
  650. {
  651. DynamicVectorClass <Triangle> adjtriangles;
  652. adjtriangles.Set_Growth_Step (32);
  653. Find_Adjacent_Triangles (triangle, adjtriangles);
  654. Submit (&triangle, adjtriangles);
  655. }
  656. /***********************************************************************************************
  657. * LightscapeSolve::Find_Adjacent_Triangles -- *
  658. * *
  659. * INPUT: *
  660. * *
  661. * OUTPUT: *
  662. * *
  663. * WARNINGS: *
  664. * *
  665. * HISTORY: *
  666. * 6/05/00 IML : Created. *
  667. *=============================================================================================*/
  668. void LightscapeSolve::Find_Adjacent_Triangles (const PackingTriangle &principaltriangle, DynamicVectorClass <Triangle> &adjtriangles)
  669. {
  670. DynamicVectorClass <VerticesStruct*> spatialvertexset;
  671. // For each principal triangle vertex...
  672. for (unsigned v = 0; v < Triangle::VERTICES_COUNT; v++) {
  673. // Find all vertices that lie within spatial tolerance of this principal triangle vertex.
  674. spatialvertexset.Clear();
  675. Find_Vertices (principaltriangle.Vertices [v].Point, SpatialTolerance, spatialvertexset);
  676. for (int s = 0; s < spatialvertexset.Count(); s++) {
  677. Vector3 normal;
  678. float angle;
  679. // Is the face that is associated with this spatial vertex within the smoothing angle of the principal triangle's normal?
  680. normal = spatialvertexset [s]->FaceNormal;
  681. angle = acosf (Vector3::Dot_Product (principaltriangle.Normal, normal));
  682. if (angle <= SmoothingAngle) {
  683. TextureNameNode *texturenamenodeptr;
  684. unsigned textureid;
  685. // Is the texture name valid?
  686. texturenamenodeptr = (TextureNameNode*) Texture_Name (spatialvertexset [s]->PatchIndex);
  687. textureid = spatialvertexset [s]->PatchIndex;
  688. if (texturenamenodeptr != NULL) {
  689. PatchFaceStruct p, *patchfaceptr;
  690. // Find a patch face in the database with patch index that matches the patch index of the spatial vertex.
  691. p.PatchIndex = spatialvertexset [s]->PatchIndex;
  692. patchfaceptr = (PatchFaceStruct*) bsearch (&p, &PatchFaces [0], PatchFaces.Count(), sizeof (PatchFaceStruct), Compare_Patch_Faces);
  693. // Does a patch exist?
  694. if (patchfaceptr != NULL) {
  695. // Step backwards in the database to the first patch that matches.
  696. // NOTE: bsearch() does not necessarily return the first key in the array that matches when there are duplicate keys.
  697. while (patchfaceptr > &PatchFaces [0]) {
  698. if (Compare_Patch_Faces (&p, patchfaceptr - 1) != 0) break;
  699. patchfaceptr--;
  700. }
  701. // Step forwards in the database while there is a patch match.
  702. while ((patchfaceptr < &PatchFaces [0] + PatchFaces.Count()) && (Compare_Patch_Faces (&p, patchfaceptr) == 0)) {
  703. unsigned trianglecount;
  704. // Is this patch face a triangle or a quadrilateral?
  705. trianglecount = (patchfaceptr->VertexIndices [PatchFaceStruct::VERTICES_PER_PATCH_FACE - 1] == PatchFaceStruct::VERTEX_INDEX_INVALID) ? 1 : 2;
  706. // For each triangle...
  707. for (unsigned t = 0; t < trianglecount; t++) {
  708. const unsigned _vertexindex [2][3] = {{0, 1, 2}, {0, 2, 3}};
  709. bool validuvs;
  710. unsigned v;
  711. validuvs = true;
  712. for (v = 0; v < Triangle::VERTICES_COUNT; v++) {
  713. validuvs &= Vertices [patchfaceptr->VertexIndices [_vertexindex [t][v]]].ValidUV;
  714. }
  715. if (validuvs) {
  716. Triangle triangle;
  717. bool hasequivalent;
  718. triangle.TextureNameNodePtr = texturenamenodeptr;
  719. triangle.TextureID = textureid;
  720. triangle.Normal = normal;
  721. for (v = 0; v < Triangle::VERTICES_COUNT; v++) {
  722. triangle.Vertices [v].Point = Vertices [patchfaceptr->VertexIndices [_vertexindex [t][v]]].Point;
  723. triangle.Vertices [v].UV = Vertices [patchfaceptr->VertexIndices [_vertexindex [t][v]]].UV;
  724. }
  725. // Linearly search the existing adjacent triangles to see if this triangle already exists.
  726. hasequivalent = false;
  727. for (int a = 0; a < adjtriangles.Count(); a++) {
  728. if (triangle.Is_Equivalent (adjtriangles [a])) {
  729. hasequivalent = true;
  730. break;
  731. }
  732. }
  733. if (!hasequivalent) adjtriangles.Add (triangle);
  734. }
  735. }
  736. // Advance to next patch face.
  737. patchfaceptr++;
  738. }
  739. }
  740. }
  741. }
  742. }
  743. }
  744. }
  745. /***********************************************************************************************
  746. * LightscapeSolve::Find_Triangle -- *
  747. * *
  748. * INPUT: *
  749. * *
  750. * OUTPUT: *
  751. * *
  752. * WARNINGS: *
  753. * *
  754. * HISTORY: *
  755. * 7/27/99 IML : Created. *
  756. *=============================================================================================*/
  757. void LightscapeSolve::Find_Triangle (const Vector3 *points, const Vector3 &facenormal, VerticesStruct *vertices, FaceResultEnum &faceresult)
  758. {
  759. const unsigned attemptcount = 14; // No. of binary search attempts (see note below).
  760. ASSERT (points != NULL);
  761. // Attempt to find the face with zero tolerance.
  762. Find_Triangle (points, 0.0f, true, &facenormal, vertices, faceresult);
  763. // If the face was not found then attempt to find a face by iterating over a range of
  764. // tolerances using a binary search technique.
  765. if (faceresult == FACE_NOT_FOUND) {
  766. bool faceambiguous;
  767. float maxtolerance = SpatialTolerance;
  768. float mintolerance = 0.00f;
  769. float tolerance;
  770. tolerance = (maxtolerance + mintolerance) * 0.5f;
  771. // NOTE: The tolerance will be increased or decreased, depending upon whether the
  772. // current result is 'not found' or 'ambiguous'. On each iteration the tolerance
  773. // range (max tolerance - min tolerance) is halved. Thus, after n iterations, the
  774. // tolerance range will be (max tolerance - min tolerance) / 2 ^ n. I have purposely
  775. // set n, the number of attempts, to yield a range at the limit of floating point
  776. // accuracy.
  777. faceambiguous = false;
  778. for (unsigned attempt = 0; attempt < attemptcount; attempt++) {
  779. Find_Triangle (points, tolerance, false, NULL, vertices, faceresult);
  780. if (faceresult == FACE_AMBIGUOUS) {
  781. // Flag that an ambiguous result occured.
  782. faceambiguous = true;
  783. // Decrease the tolerance.
  784. maxtolerance = tolerance;
  785. tolerance = (tolerance + mintolerance) * 0.5f;
  786. } else {
  787. if (faceresult == FACE_NOT_FOUND) {
  788. // Increase the tolerance.
  789. mintolerance = tolerance;
  790. tolerance = (tolerance + maxtolerance) * 0.5f;
  791. } else {
  792. // The face has been found.
  793. ASSERT (faceresult == FACE_FOUND);
  794. break;
  795. }
  796. }
  797. }
  798. // If an ambiguous result occured on ANY iteration then the maximum tolerance is the
  799. // smallest tolerance at which the ambiguity exists. Try to resolve the ambiguity
  800. // using the centroid and normal tests.
  801. if ((faceresult != FACE_FOUND) && faceambiguous) {
  802. Find_Triangle (points, maxtolerance, true, &facenormal, vertices, faceresult);
  803. }
  804. }
  805. }
  806. /***********************************************************************************************
  807. * LightscapeSolve::Find_Triangle -- *
  808. * *
  809. * INPUT: *
  810. * *
  811. * OUTPUT: *
  812. * *
  813. * WARNINGS: *
  814. * *
  815. * HISTORY: *
  816. * 7/27/99 IML : Created. *
  817. *=============================================================================================*/
  818. void LightscapeSolve::Find_Triangle (const Vector3 *points, float tolerance, bool centroidtest, const Vector3 *facenormal, VerticesStruct *vertices, FaceResultEnum &faceresult)
  819. {
  820. const int growthstep = 256;
  821. DynamicVectorClass <VerticesStruct*> vertexset [Triangle::VERTICES_COUNT];
  822. DynamicVectorClass <VerticesStruct*> *candidatevertexset = &vertexset [0];
  823. unsigned patchindex;
  824. int n, c, v;
  825. bool success;
  826. ASSERT (points != NULL);
  827. // Create a set of vertex indices that correspond to the zeroth point.
  828. candidatevertexset->Set_Growth_Step (growthstep);
  829. Find_Vertices (points [0], tolerance, *candidatevertexset);
  830. // Remove any duplicate patches from the candidate set.
  831. c = 0;
  832. while (c < candidatevertexset->Count()) {
  833. patchindex = (*candidatevertexset) [c]->PatchIndex;
  834. v = c + 1;
  835. while (v < candidatevertexset->Count()) {
  836. if (patchindex == (*candidatevertexset) [v]->PatchIndex) {
  837. success = candidatevertexset->Delete (v);
  838. ASSERT (success);
  839. } else {
  840. v++;
  841. }
  842. }
  843. c++;
  844. }
  845. // For all other points...
  846. for (n = 1; n < Triangle::VERTICES_COUNT; n++) {
  847. // Create a set of vertex indices that correspond to n'th <point, normal> pair.
  848. vertexset [n].Set_Growth_Step (growthstep);
  849. Find_Vertices (points [n], tolerance, vertexset [n]);
  850. // Delete all indexes in the candidate index set that have materials that DO NOT occur in the vertex index set.
  851. c = 0;
  852. while (c < candidatevertexset->Count()) {
  853. bool found;
  854. patchindex = (*candidatevertexset) [c]->PatchIndex;
  855. found = false;
  856. for (v = 0; v < vertexset [n].Count(); v++) {
  857. if (patchindex == vertexset [n][v]->PatchIndex) {
  858. found = true;
  859. break;
  860. }
  861. }
  862. if (!found) {
  863. success = candidatevertexset->Delete (c);
  864. ASSERT (success);
  865. } else {
  866. c++;
  867. }
  868. }
  869. }
  870. // If there is more than one candidate and the centroid test can be applied then apply it.
  871. if ((candidatevertexset->Count() > 1) && centroidtest) {
  872. // If there is a patch-face database...
  873. if (PatchFaces.Count() > 0) {
  874. // Attempt to eliminate the ambiguity by applying a centroid test.
  875. Vector3 centroid;
  876. centroid = points [0];
  877. for (n = 1; n < Triangle::VERTICES_COUNT; n++) {
  878. centroid += points [n];
  879. }
  880. centroid /= (float) Triangle::VERTICES_COUNT;
  881. // For each candidate...
  882. c = 0;
  883. while (c < candidatevertexset->Count()) {
  884. bool contained;
  885. PatchFaceStruct p;
  886. PatchFaceStruct *patchfaceptr;
  887. unsigned trianglecount;
  888. patchindex = (*candidatevertexset) [c]->PatchIndex;
  889. contained = false;
  890. // Find a face in the array that matches the patch.
  891. p.PatchIndex = patchindex;
  892. patchfaceptr = (PatchFaceStruct*) bsearch (&p, &PatchFaces [0], PatchFaces.Count(), sizeof (PatchFaceStruct), Compare_Patch_Faces);
  893. if (patchfaceptr != NULL) {
  894. // Step backwards in the array to the first patch that matches.
  895. // NOTE: bsearch() does not necessarily return the first key in the array that matches when there are duplicate keys.
  896. while (patchfaceptr > &PatchFaces [0]) {
  897. if (Compare_Patch_Faces (&p, patchfaceptr - 1) != 0) break;
  898. patchfaceptr--;
  899. }
  900. // Step forwards in the array while there is a patch match.
  901. // Find all vertices whose points and normals approximately match the requested normal and add their patch indices to the patch array.
  902. while ((patchfaceptr < &PatchFaces [0] + PatchFaces.Count()) && (Compare_Patch_Faces (&p, patchfaceptr) == 0)) {
  903. // NOTE: The candidate point may not match the any of the material face
  904. // points because Lightscape may have changed the topology. Thus it is
  905. // necessary to search ALL of the faces that have this material.
  906. // For each triangle in the patch face...
  907. // NOTE: Define the first triangle to be the points 0-1-2. If the patch face is a quadrilateral,
  908. // then define the second triangle to be the points 0-2-3.
  909. trianglecount = (patchfaceptr->VertexIndices [3] == PatchFaceStruct::VERTEX_INDEX_INVALID) ? 1 : 2;
  910. for (unsigned t = 0; t < trianglecount; t++) {
  911. // Create a triangle from the material face and test it against the centroid for containment.
  912. TriClass triangle;
  913. Vector3 normal;
  914. triangle.V [0] = &Vertices [patchfaceptr->VertexIndices [0]].Point;
  915. triangle.V [1] = &Vertices [patchfaceptr->VertexIndices [1 + t]].Point;
  916. triangle.V [2] = &Vertices [patchfaceptr->VertexIndices [2 + t]].Point;
  917. triangle.N = &normal;
  918. triangle.Compute_Normal();
  919. if (triangle.Contains_Point (centroid)) {
  920. contained = true;
  921. break;
  922. }
  923. }
  924. if (contained) break;
  925. // Advance to next patch face.
  926. patchfaceptr++;
  927. }
  928. }
  929. if (!contained) {
  930. success = candidatevertexset->Delete (c);
  931. ASSERT (success);
  932. } else {
  933. c++;
  934. }
  935. }
  936. }
  937. }
  938. // If there is still more than one candidate and the normal exists then apply the normal test.
  939. if ((candidatevertexset->Count() > 1) && (facenormal != NULL)) {
  940. float largestdp;
  941. // Find the smallest angle (largest dot product) between the vertex face normal and the target face normal.
  942. largestdp = (*facenormal) * ((*candidatevertexset) [0]->FaceNormal);
  943. for (c = 1; c < candidatevertexset->Count(); c++) {
  944. largestdp = MAX (largestdp, (*facenormal) * ((*candidatevertexset) [c]->FaceNormal));
  945. }
  946. // Delete all candidates that do not have the largest dot product.
  947. c = 0;
  948. while (c < candidatevertexset->Count()) {
  949. float dp = (*facenormal) * ((*candidatevertexset) [c]->FaceNormal);
  950. if (dp < largestdp) {
  951. success = candidatevertexset->Delete (c);
  952. ASSERT (success);
  953. } else {
  954. c++;
  955. }
  956. }
  957. }
  958. // Now if there are no candidates then return failure.
  959. if (candidatevertexset->Count() == 0) {
  960. faceresult = FACE_NOT_FOUND;
  961. } else {
  962. unsigned candidateindex = 0;
  963. // NOTE: If there is >1 candidate at this point the result is still ambiguous.
  964. // If the face normal has been supplied, select the candidate with closest
  965. // face normal - otherwise select the zeroth candidate.
  966. if (facenormal != NULL) {
  967. float mindistance = FLT_MAX;
  968. for (n = 0; n < candidatevertexset->Count(); n++) {
  969. float distance;
  970. distance = Manhatten_Distance (*facenormal - (*candidatevertexset) [n]->FaceNormal);
  971. if (distance < mindistance) {
  972. mindistance = distance;
  973. candidateindex = n;
  974. }
  975. }
  976. }
  977. // For the zeroth point...
  978. patchindex = (*candidatevertexset) [candidateindex]->PatchIndex;
  979. vertices [0] = *((*candidatevertexset) [candidateindex]);
  980. // For all other points...
  981. for (n = 1; n < Triangle::VERTICES_COUNT; n++) {
  982. bool assigned = false;
  983. for (v = 0; v < vertexset [n].Count(); v++) {
  984. if (vertexset [n][v]->PatchIndex == patchindex) {
  985. vertices [n] = *(vertexset [n][v]);
  986. assigned = true;
  987. break;
  988. }
  989. }
  990. ASSERT (assigned);
  991. }
  992. // Flag if the result was ambiguous.
  993. if (candidatevertexset->Count() > 1) {
  994. faceresult = FACE_AMBIGUOUS;
  995. } else {
  996. // There must be exactly one candidate.
  997. ASSERT (candidatevertexset->Count() == 1);
  998. faceresult = FACE_FOUND;
  999. }
  1000. }
  1001. }
  1002. /***********************************************************************************************
  1003. * LightscapeSolve::Find_Vertices -- *
  1004. * *
  1005. * INPUT: *
  1006. * *
  1007. * OUTPUT: *
  1008. * *
  1009. * WARNINGS: *
  1010. * *
  1011. * HISTORY: *
  1012. * 7/27/99 IML : Created. *
  1013. *=============================================================================================*/
  1014. void LightscapeSolve::Find_Vertices (const Vector3 &point, float tolerance, DynamicVectorClass <VerticesStruct*> &vertices)
  1015. {
  1016. if (VertexIndices.Count() > 0) {
  1017. unsigned *vertexindexptr = NULL;
  1018. int b0, b1, b;
  1019. float x;
  1020. // There should be a 1-1 mapping between vertex indices and vertices.
  1021. ASSERT (VertexIndices.Count() == Vertices.Count());
  1022. // Find a vertex that matches point to within tolerance using binary search technique.
  1023. b0 = 0;
  1024. b1 = VertexIndices.Count() - 1;
  1025. do {
  1026. b = (b0 + b1) >> 1;
  1027. x = Vertices [VertexIndices [b]].Point.X;
  1028. if (point.X - x < -tolerance) {
  1029. b1 = b - 1;
  1030. } else {
  1031. if (point.X - x > tolerance) {
  1032. b0 = b + 1;
  1033. } else {
  1034. vertexindexptr = &VertexIndices [b];
  1035. break;
  1036. }
  1037. }
  1038. } while (b0 <= b1);
  1039. // Step backwards in the array to the first vertex that meets the match criteria defined by Compare_Vertices().
  1040. // NOTE: Above search did not necessarily return the first key in the array that matches when there are duplicate keys.
  1041. if (vertexindexptr != NULL) {
  1042. while (vertexindexptr > &VertexIndices [0]) {
  1043. x = Vertices [*(vertexindexptr - 1)].Point.X;
  1044. if (point.X - x > tolerance) break;
  1045. vertexindexptr--;
  1046. }
  1047. // Step forwards in the array while there is an approximate vertex match.
  1048. // Add all vertices that are valid and whose points match the requested point within tolerance.
  1049. while (vertexindexptr < &VertexIndices [0] + VertexIndices.Count()) {
  1050. VerticesStruct *vertexptr;
  1051. vertexptr = &Vertices [*vertexindexptr];
  1052. if (point.X - vertexptr->Point.X < -tolerance) break;
  1053. if (Manhatten_Distance (vertexptr->Point - point) <= tolerance) {
  1054. vertices.Add (vertexptr);
  1055. }
  1056. // Advance to next vertex index.
  1057. vertexindexptr++;
  1058. }
  1059. }
  1060. }
  1061. }
  1062. /***********************************************************************************************
  1063. * LightscapeSolve::Face_Size -- *
  1064. * *
  1065. * INPUT: *
  1066. * *
  1067. * OUTPUT: *
  1068. * *
  1069. * WARNINGS: *
  1070. * *
  1071. * HISTORY: *
  1072. * 9/17/99 IML : Created. *
  1073. *=============================================================================================*/
  1074. LightscapeSolve::FaceSizeEnum LightscapeSolve::Face_Size (const Vector3 *points, unsigned count)
  1075. {
  1076. const float undersizedarea = 0.0016f; // An area << the area of a lightmap lumel (assuming
  1077. // that lumel density is less than 625 lumels/metre).
  1078. float area;
  1079. // Test for degeneracy.
  1080. // NOTE: Assume that the points are ordered (for triangles this is guaranteed).
  1081. for (unsigned n = 0; n < count; n++) {
  1082. if (points [n] == points [(n + 1) % count]) return (FACE_DEGENERATE);
  1083. }
  1084. // Currently, the area calculation requires that the polygon is a triangle.
  1085. ASSERT (count == 3);
  1086. // Test for a small area.
  1087. area = 0.5f * Vector3::Cross_Product (points [1] - points [0], points [2] - points [0]).Length();
  1088. if (area < undersizedarea) return (FACE_UNDERSIZED);
  1089. return (FACE_NOT_UNDERSIZED);
  1090. }
  1091. /***********************************************************************************************
  1092. * LightscapeSolve::Longest_Edge -- *
  1093. * *
  1094. * INPUT: *
  1095. * *
  1096. * OUTPUT: *
  1097. * *
  1098. * WARNINGS: *
  1099. * *
  1100. * HISTORY: *
  1101. * 9/17/99 IML : Created. *
  1102. *=============================================================================================*/
  1103. unsigned LightscapeSolve::Longest_Edge (const Vector3 *points, unsigned count, bool *usededges)
  1104. {
  1105. float maxlength = -1.0f;
  1106. float length;
  1107. unsigned edgeindex;
  1108. for (unsigned e = 0; e < count; e++) {
  1109. if (!usededges [e]) {
  1110. length = (points [(e + 1) % count] - points [e]).Length();
  1111. if (length > maxlength) {
  1112. maxlength = length;
  1113. edgeindex = e;
  1114. }
  1115. }
  1116. }
  1117. // An edge must have been found.
  1118. ASSERT (maxlength >= 0.0f);
  1119. usededges [edgeindex] = true;
  1120. return (edgeindex);
  1121. }
  1122. /***********************************************************************************************
  1123. * LightscapeSolve::Texture_Name -- *
  1124. * *
  1125. * INPUT: *
  1126. * *
  1127. * OUTPUT: *
  1128. * *
  1129. * WARNINGS: *
  1130. * *
  1131. * HISTORY: *
  1132. * 7/27/99 IML : Created. *
  1133. *=============================================================================================*/
  1134. const TextureNameNode *LightscapeSolve::Texture_Name (unsigned patchindex)
  1135. {
  1136. // If the array element does not exist yet then the name has not been set.
  1137. if ((int) patchindex >= TextureNames.Length()) return (NULL);
  1138. return TextureNames [patchindex];
  1139. }
  1140. /***********************************************************************************************
  1141. * LightscapeSolve::Compare_Material_Texture_Names -- *
  1142. * *
  1143. * INPUT: *
  1144. * *
  1145. * OUTPUT: *
  1146. * *
  1147. * WARNINGS: *
  1148. * *
  1149. * HISTORY: *
  1150. * 7/27/99 IML : Created. *
  1151. *=============================================================================================*/
  1152. int LightscapeSolve::Compare_Material_Texture_Names (const void *materialname0, const void *materialname1)
  1153. {
  1154. return (strcmp (*((const char**) materialname0), *((const char**) materialname1)));
  1155. }
  1156. /***********************************************************************************************
  1157. * LightscapeSolve::Compare_Vertices *
  1158. * *
  1159. * INPUT: *
  1160. * *
  1161. * OUTPUT: *
  1162. * *
  1163. * WARNINGS: *
  1164. * *
  1165. * HISTORY: *
  1166. * 7/27/99 IML : Created. *
  1167. *=============================================================================================*/
  1168. int LightscapeSolve::Compare_Vertices (const void *vertexindexptr0, const void *vertexindexptr1)
  1169. {
  1170. float x0, x1;
  1171. ASSERT (_ActiveImporter != NULL);
  1172. x0 = _ActiveImporter->Vertices [*((unsigned*) vertexindexptr0)].Point.X;
  1173. x1 = _ActiveImporter->Vertices [*((unsigned*) vertexindexptr1)].Point.X;
  1174. if (x0 < x1) {
  1175. return (-1);
  1176. } else {
  1177. if (x0 > x1) {
  1178. return (1);
  1179. } else {
  1180. return (0);
  1181. }
  1182. }
  1183. }
  1184. /***********************************************************************************************
  1185. * LightscapeSolve::Compare_Patch_Faces -- *
  1186. * *
  1187. * INPUT: *
  1188. * *
  1189. * OUTPUT: *
  1190. * *
  1191. * WARNINGS: *
  1192. * *
  1193. * HISTORY: *
  1194. * 9/17/99 IML : Created. *
  1195. *=============================================================================================*/
  1196. int LightscapeSolve::Compare_Patch_Faces (const void *patchface0, const void *patchface1)
  1197. {
  1198. unsigned patchindex0 = ((PatchFaceStruct*) patchface0)->PatchIndex;
  1199. unsigned patchindex1 = ((PatchFaceStruct*) patchface1)->PatchIndex;
  1200. if (patchindex0 < patchindex1) {
  1201. return (-1);
  1202. } else {
  1203. if (patchindex0 > patchindex1) {
  1204. return (1);
  1205. } else {
  1206. return (0);
  1207. }
  1208. }
  1209. }
  1210. /***********************************************************************************************
  1211. * LightscapeSolve::Pack -- *
  1212. * *
  1213. * INPUT: *
  1214. * *
  1215. * OUTPUT: *
  1216. * *
  1217. * WARNINGS: *
  1218. * *
  1219. * HISTORY: *
  1220. * 09/07/00 IML : Created. *
  1221. *=============================================================================================*/
  1222. void LightscapeSolve::Pack()
  1223. {
  1224. LightmapPacker::Pack (ProceduralTexture);
  1225. }
  1226. /***********************************************************************************************
  1227. * LsInformationFactory::OnGet*Builder -- *
  1228. * *
  1229. * INPUT: *
  1230. * *
  1231. * OUTPUT: *
  1232. * *
  1233. * WARNINGS: *
  1234. * *
  1235. * HISTORY: *
  1236. * 9/16/99 IML : Created. *
  1237. *=============================================================================================*/
  1238. LtTInfoBuilderApi* LsInformationFactory::OnGetInfoBuilder()
  1239. {
  1240. return (new LsInfoBuilder (this));
  1241. }
  1242. LtTParameterBuilderApi* LsInformationFactory::OnGetParameterBuilder()
  1243. {
  1244. return (new LsParameterBuilder (this));
  1245. }
  1246. /***********************************************************************************************
  1247. * LsPreparationFactory::OnGet*Builder -- *
  1248. * *
  1249. * INPUT: *
  1250. * *
  1251. * OUTPUT: *
  1252. * *
  1253. * WARNINGS: *
  1254. * *
  1255. * HISTORY: *
  1256. * 7/27/99 IML : Created. *
  1257. *=============================================================================================*/
  1258. LtTInfoBuilderApi *LsPreparationFactory::OnGetInfoBuilder()
  1259. {
  1260. return (new LsInfoBuilder (this));
  1261. }
  1262. LtTParameterBuilderApi *LsPreparationFactory::OnGetParameterBuilder()
  1263. {
  1264. return (new LsParameterBuilder (this));
  1265. }
  1266. LtTMaterialBuilderApi *LsPreparationFactory::OnGetMaterialBuilder()
  1267. {
  1268. return (new LsMaterialBuilder (this));
  1269. }
  1270. LtTLampBuilderApi *LsPreparationFactory::OnGetLampBuilder()
  1271. {
  1272. return (new LsLampBuilder (this));
  1273. }
  1274. LtTMeshBuilderApi *LsPreparationFactory::OnGetMeshBuilder()
  1275. {
  1276. return (new LsMeshInquirer (this));
  1277. }
  1278. /***********************************************************************************************
  1279. * LsMainFactory::LsMainFactory -- *
  1280. * *
  1281. * INPUT: *
  1282. * *
  1283. * OUTPUT: *
  1284. * *
  1285. * WARNINGS: *
  1286. * *
  1287. * HISTORY: *
  1288. * 7/23/99 IML : Created. *
  1289. *=============================================================================================*/
  1290. LsMainFactory::LsMainFactory()
  1291. : LtTBuilderFactory()
  1292. {
  1293. PatchFaceIndex = 0;
  1294. VertexIndex = 0;
  1295. PatchIndex = 0;
  1296. }
  1297. /***********************************************************************************************
  1298. * LsMainFactory::OnGet*Builder -- *
  1299. * *
  1300. * INPUT: *
  1301. * *
  1302. * OUTPUT: *
  1303. * *
  1304. * WARNINGS: *
  1305. * *
  1306. * HISTORY: *
  1307. * 7/23/99 IML : Created. *
  1308. *=============================================================================================*/
  1309. LtTInfoBuilderApi* LsMainFactory::OnGetInfoBuilder()
  1310. {
  1311. return (new LsInfoBuilder (this));
  1312. }
  1313. LtTParameterBuilderApi* LsMainFactory::OnGetParameterBuilder()
  1314. {
  1315. return (new LsParameterBuilder (this));
  1316. }
  1317. LtTMeshBuilderApi* LsMainFactory::OnGetMeshBuilder()
  1318. {
  1319. return (new LsMeshBuilder (this));
  1320. }
  1321. /***********************************************************************************************
  1322. * LsInfoBuilder::LsInfoBuilder -- *
  1323. * *
  1324. * INPUT: *
  1325. * *
  1326. * OUTPUT: *
  1327. * *
  1328. * WARNINGS: *
  1329. * *
  1330. * HISTORY: *
  1331. * 9/17/99 IML : Created. *
  1332. *=============================================================================================*/
  1333. LsInfoBuilder::LsInfoBuilder (LtTBuilderFactory *factory)
  1334. : LtTBaseInfoBuilder (factory)
  1335. {
  1336. // Do any special initialization here.
  1337. }
  1338. /***********************************************************************************************
  1339. * LsInfoBuilder::Finish -- *
  1340. * *
  1341. * INPUT: *
  1342. * *
  1343. * OUTPUT: *
  1344. * *
  1345. * WARNINGS: *
  1346. * *
  1347. * HISTORY: *
  1348. * 9/17/99 IML : Created. *
  1349. *=============================================================================================*/
  1350. LtTBool LsInfoBuilder::Finish()
  1351. {
  1352. // Read any info values here.
  1353. LightscapeSolve::Importer()->Set_Is_Solution (IsSolution() ? true : false);
  1354. LightscapeSolve::Importer()->Set_Patch_Cluster_Count (GetNumGroups());
  1355. LightscapeSolve::Importer()->Set_Brightness (GetBrightness());
  1356. LightscapeSolve::Importer()->Set_Contrast (GetContrast());
  1357. // Return success.
  1358. return (TRUE);
  1359. }
  1360. /***********************************************************************************************
  1361. * LsParameterBuilder::LsParameterBuilder -- *
  1362. * *
  1363. * INPUT: *
  1364. * *
  1365. * OUTPUT: *
  1366. * *
  1367. * WARNINGS: *
  1368. * *
  1369. * HISTORY: *
  1370. * 9/17/99 IML : Created. *
  1371. *=============================================================================================*/
  1372. LsParameterBuilder::LsParameterBuilder (LtTBuilderFactory *factory)
  1373. : LtTBaseParameterBuilder (factory)
  1374. {
  1375. // Do any special initialization here.
  1376. }
  1377. /***********************************************************************************************
  1378. * LsParameterBuilder::Finish -- *
  1379. * *
  1380. * INPUT: *
  1381. * *
  1382. * OUTPUT: *
  1383. * *
  1384. * WARNINGS: *
  1385. * *
  1386. * HISTORY: *
  1387. * 9/17/99 IML : Created. *
  1388. *=============================================================================================*/
  1389. LtTBool LsParameterBuilder::Finish()
  1390. {
  1391. // Read any parameter values here.
  1392. LightscapeSolve::Importer()->Set_Is_Daylight ((GetFlags() & LT_PROCESS_DAYLIGHT) != 0);
  1393. LightscapeSolve::Importer()->Set_Is_Exterior ((GetFlags() & LT_PROCESS_EXTERIOR) != 0);
  1394. // Return success.
  1395. return (TRUE);
  1396. }
  1397. /***********************************************************************************************
  1398. * LsMateriaBuilder::LsMaterialBuilder -- *
  1399. * *
  1400. * INPUT: *
  1401. * *
  1402. * OUTPUT: *
  1403. * *
  1404. * WARNINGS: *
  1405. * *
  1406. * HISTORY: *
  1407. * 7/27/99 IML : Created. *
  1408. *=============================================================================================*/
  1409. LsMaterialBuilder::LsMaterialBuilder (LtTBuilderFactory *factory)
  1410. : LtTBaseMaterialBuilder (factory)
  1411. {
  1412. // Do any special initialization here.
  1413. }
  1414. /***********************************************************************************************
  1415. * LsMateriaBuilder::Finish -- *
  1416. * *
  1417. * INPUT: *
  1418. * *
  1419. * OUTPUT: *
  1420. * *
  1421. * WARNINGS: *
  1422. * *
  1423. * HISTORY: *
  1424. * 7/27/99 IML : Created. *
  1425. *=============================================================================================*/
  1426. LtTBool LsMaterialBuilder::Finish()
  1427. {
  1428. ASSERT (LightscapeSolve::Importer() != NULL);
  1429. LightscapeSolve::Importer()->Add_Material_Texture_Name (GetName(), GetTextureName());
  1430. // Return success.
  1431. return (TRUE);
  1432. }
  1433. /***********************************************************************************************
  1434. * LsLampBuilder::LsLampBuilder -- *
  1435. * *
  1436. * INPUT: *
  1437. * *
  1438. * OUTPUT: *
  1439. * *
  1440. * WARNINGS: *
  1441. * *
  1442. * HISTORY: *
  1443. * 3/24/00 IML : Created. *
  1444. *=============================================================================================*/
  1445. LsLampBuilder::LsLampBuilder (LtTBuilderFactory *factory)
  1446. : LtTBaseLampBuilder (factory)
  1447. {
  1448. // Do any special initialization here.
  1449. }
  1450. /***********************************************************************************************
  1451. * LsLampBuilder::Finish -- *
  1452. * *
  1453. * INPUT: *
  1454. * *
  1455. * OUTPUT: *
  1456. * *
  1457. * WARNINGS: *
  1458. * *
  1459. * HISTORY: *
  1460. * 3/24/00 IML : Created. *
  1461. *=============================================================================================*/
  1462. LtTBool LsLampBuilder::Finish()
  1463. {
  1464. const char *unknownlighttext =
  1465. "There is a light in the solve with unknown type.";
  1466. const Vector3 oodistancesquaredfactors (0.0f, 0.0f, 1.0f);
  1467. const Vector3 zaxis (0.0f, 0.0f, 1.0f);
  1468. const ColorVector black (0.0f, 0.0f, 0.0f);
  1469. const ColorVector white (1.0f, 1.0f, 1.0f);
  1470. float dir [3][3];
  1471. LightClass *light;
  1472. Vector3 position;
  1473. ColorVector color;
  1474. Matrix3D transform;
  1475. ASSERT (LightscapeSolve::Importer() != NULL);
  1476. // If the light name begins with a '@' skip it - it is not intended for export.
  1477. if (LightscapeSolve::Importer()->Light_Exclusion_String() != NULL) {
  1478. if (strstr (GetName(), LightscapeSolve::Importer()->Light_Exclusion_String())) return (TRUE);
  1479. }
  1480. // Skip skylight - it cannot be meaningfully translated into a LightClass object.
  1481. if ((GetType() == LT_LAMP_DAYLIGHT) && (strcmp (GetName(), "Skylight") == 0)) return (TRUE);
  1482. // If the lamp does not store direct illumination and has not been raytraced then
  1483. // it has not been included in the solve - skip it.
  1484. if ((GetFlags() & LT_LAMP_CAST_NO_DIRECT) && !(GetFlags() & LT_LAMP_RAY_TRACE_DIRECT)) return (TRUE);
  1485. // If this light has non-zero intensity then add the light to the solve database.
  1486. if (GetIntensity() > 0.0f) {
  1487. // NOTE 0: Lightscape uses a right-handed coordinate system.
  1488. // NOTE 1: For directional lights (including sunlight), multiplying the direction matrix
  1489. // by (0, 0, 1) will yield the direction of the light rays.
  1490. GetDirection (dir);
  1491. Matrix3 direction (dir [0][0], dir [0][1], dir [0][2],
  1492. dir [1][0], dir [1][1], dir [1][2],
  1493. dir [2][0], dir [2][1], dir [2][2]);
  1494. // Create light of appropriate type.
  1495. switch (GetType()) {
  1496. case LT_LAMP_ISOTROPIC: // Spherical equal intensity distribution.
  1497. light = new LightClass (LightClass::POINT);
  1498. ASSERT (light != NULL);
  1499. break;
  1500. case LT_LAMP_DIFFUSE: // Hemispherical distribution with intensity proportional to the cosine to the direction of light.
  1501. // Interpret this light as a spotlight with a 180 degree spot angle.
  1502. light = new LightClass (LightClass::SPOT);
  1503. ASSERT (light != NULL);
  1504. light->Set_Spot_Angle (WWMATH_PI);
  1505. light->Set_Spot_Direction (zaxis);
  1506. // For efficiency, use unity as exponent.
  1507. light->Set_Spot_Exponent (1.0f);
  1508. break;
  1509. case LT_LAMP_SPOTLIGHT: // Spotlight distribution. Intensity at beam angle is one-half maximum intensity. Intensity is truncated to 0 at field angle.
  1510. light = new LightClass (LightClass::SPOT);
  1511. ASSERT (light != NULL);
  1512. // NOTE: Field angle is defined as angle swept from center of beam to outside.
  1513. light->Set_Spot_Angle (GetFieldAngle() * 2.0f);
  1514. light->Set_Spot_Direction (zaxis);
  1515. // For efficiency, use unity as exponent.
  1516. light->Set_Spot_Exponent (1.0f);
  1517. break;
  1518. case LT_LAMP_GENERAL: // General distribution is determined from table if intensities in given directions.
  1519. {
  1520. float angle;
  1521. // Get the widest angle - this is normally, but not always, the field angle.
  1522. angle = MAX (GetBeamAngle(), GetFieldAngle());
  1523. if (angle > WWMATH_PI / 2.0f) {
  1524. // Interpret light as an isometric light.
  1525. light = new LightClass (LightClass::POINT);
  1526. ASSERT (light != NULL);
  1527. } else {
  1528. // Interpret light as a spotlight.
  1529. light = new LightClass (LightClass::SPOT);
  1530. ASSERT (light != NULL);
  1531. light->Set_Spot_Angle (angle * 2.0f);
  1532. light->Set_Spot_Direction (zaxis);
  1533. // For efficiency, use unity as exponent.
  1534. light->Set_Spot_Exponent (1.0f);
  1535. }
  1536. }
  1537. break;
  1538. case LT_LAMP_DAYLIGHT: // Special value used to flag daylight when import an LS file.
  1539. light = new LightClass (LightClass::DIRECTIONAL);
  1540. ASSERT (light != NULL);
  1541. break;
  1542. default:
  1543. ASSERT (FALSE);
  1544. throw (unknownlighttext);
  1545. break;
  1546. }
  1547. // Set transform matrix that defines direction and position of light source.
  1548. position.Set (GetLocation().GetX(), GetLocation().GetY(), GetLocation().GetZ());
  1549. transform.Set (direction, position);
  1550. light->Set_Transform (transform);
  1551. // Set intensity.
  1552. light->Set_Intensity (1.0f);
  1553. RadianceMap radiancemap (LightscapeSolve::Importer()->Get_Brightness(), LightscapeSolve::Importer()->Get_Contrast(), LightscapeSolve::Importer()->Is_Daylight(), LightscapeSolve::Importer()->Is_Exterior());
  1554. float i = GetIntensity();
  1555. LtTRGBColor irradiance (i * GetFilterColor().GetR(), i * GetFilterColor().GetG(), i * GetFilterColor().GetB());
  1556. // Set colors.
  1557. color.Set (irradiance, radiancemap);
  1558. // Clamp to white.
  1559. color.Update_Min (white);
  1560. light->Set_Ambient (black);
  1561. light->Set_Diffuse (color);
  1562. light->Set_Specular (color);
  1563. // Set attenuation model.
  1564. if (GetType() != LT_LAMP_DAYLIGHT) {
  1565. const float oocutoff = 1.0f / 0.025f; // Reciprocal of light intensity at far attenuation.
  1566. // NOTE: Convert Lightscape 1/d^2 attenuation to an equivalent MAX type light.
  1567. light->Set_Flag (LightClass::NEAR_ATTENUATION, false);
  1568. light->Set_Near_Attenuation_Range (0.0f, 0.0f);
  1569. light->Set_Flag (LightClass::FAR_ATTENUATION, true);
  1570. // Calculate attenuation range.
  1571. // The far attenuation is calculated as the distance at which intensity falls to a given
  1572. // ratio (cut-off), assuming an attenuation of c/d^2, where c = monochrome intensity of light source.
  1573. float d = sqrt (oocutoff * color.Length());
  1574. light->Set_Far_Attenuation_Range (d * 0.25f, d);
  1575. } else {
  1576. light->Set_Flag (LightClass::NEAR_ATTENUATION, false);
  1577. light->Set_Flag (LightClass::FAR_ATTENUATION, false);
  1578. }
  1579. // Miscellaneous attributes.
  1580. light->Enable_Shadows ((GetFlags() & LT_LAMP_CAST_NO_SHADOWS) ? false : true);
  1581. LightscapeSolve::Importer()->Add_Light (light);
  1582. // Clean-up.
  1583. light->Release_Ref();
  1584. }
  1585. // Return success.
  1586. return (TRUE);
  1587. }
  1588. /***********************************************************************************************
  1589. * LsMeshInquirer::LsMeshInquirer -- *
  1590. * *
  1591. * INPUT: *
  1592. * *
  1593. * OUTPUT: *
  1594. * *
  1595. * WARNINGS: *
  1596. * *
  1597. * HISTORY: *
  1598. * 04/19/00 IML : Created. *
  1599. *=============================================================================================*/
  1600. LsMeshInquirer::LsMeshInquirer (LtTBuilderFactory *factory)
  1601. : LtTBaseMeshBuilder (factory)
  1602. {
  1603. // Assume initially that the solve is NOT an M2T solve.
  1604. LightscapeSolve::Importer()->Set_Is_M2T_Solve (false);
  1605. }
  1606. /***********************************************************************************************
  1607. * LsMeshInquirer::LsMeshInquirer -- *
  1608. * *
  1609. * INPUT: *
  1610. * *
  1611. * OUTPUT: *
  1612. * *
  1613. * WARNINGS: *
  1614. * *
  1615. * HISTORY: *
  1616. * 04/19/00 IML : Created. *
  1617. *=============================================================================================*/
  1618. LtTBool LsMeshInquirer::Finish()
  1619. {
  1620. if (GetProperties() & LT_MESH_RAWTEXTURE) {
  1621. LightscapeSolve::Importer()->Set_Is_M2T_Solve (true);
  1622. }
  1623. // Return success.
  1624. return (TRUE);
  1625. }
  1626. /***********************************************************************************************
  1627. * LsMeshBuilder::LsMeshBuilder -- *
  1628. * *
  1629. * INPUT: *
  1630. * *
  1631. * OUTPUT: *
  1632. * *
  1633. * WARNINGS: *
  1634. * *
  1635. * HISTORY: *
  1636. * 7/23/99 IML : Created. *
  1637. *=============================================================================================*/
  1638. LsMeshBuilder::LsMeshBuilder (LtTBuilderFactory *factory)
  1639. : LtTBaseMeshBuilder (factory)
  1640. {
  1641. ASSERT (strcmp (typeid (*factory).name(), "class LsMainFactory") == 0);
  1642. FactoryPtr = (LsMainFactory*) factory;
  1643. Faces = NULL;
  1644. FaceCount = 0;
  1645. AllocatedCount = 0;
  1646. }
  1647. /***********************************************************************************************
  1648. * LsMeshBuilder::~LsMeshBuilder -- *
  1649. * *
  1650. * INPUT: *
  1651. * *
  1652. * OUTPUT: *
  1653. * *
  1654. * WARNINGS: *
  1655. * *
  1656. * HISTORY: *
  1657. * 9/16/99 IML : Created. *
  1658. *=============================================================================================*/
  1659. LsMeshBuilder::~LsMeshBuilder()
  1660. {
  1661. if (Faces != NULL) delete [] Faces;
  1662. }
  1663. /***********************************************************************************************
  1664. * LsMeshBuilder::SetFaces -- *
  1665. * *
  1666. * INPUT: *
  1667. * *
  1668. * OUTPUT: *
  1669. * *
  1670. * WARNINGS: *
  1671. * *
  1672. * HISTORY: *
  1673. * 9/16/99 IML : Created. *
  1674. *=============================================================================================*/
  1675. void LsMeshBuilder::SetFaces (const int facecount, const LtTFace *faces)
  1676. {
  1677. int topcount, f, g;
  1678. // Count the number of faces in the top-level hierarchy.
  1679. topcount = 0;
  1680. for (f = 0; f < facecount; f++) {
  1681. topcount++;
  1682. f += faces [f].GetDescendents();
  1683. }
  1684. // If the block allocated for faces is not big enough delete it and allocate a new one.
  1685. if (topcount > AllocatedCount) {
  1686. if (Faces != NULL) delete [] Faces;
  1687. Faces = new LtTFace [topcount];
  1688. ASSERT (Faces != NULL);
  1689. AllocatedCount = topcount;
  1690. }
  1691. // Copy the faces in the top-level hierarchy into the block allocated for faces.
  1692. g = 0;
  1693. for (f = 0; f < facecount; f++) {
  1694. Faces [g] = faces [f];
  1695. g++;
  1696. f += faces [f].GetDescendents();
  1697. }
  1698. ASSERT (g == topcount);
  1699. FaceCount = topcount;
  1700. }
  1701. /***********************************************************************************************
  1702. * LsMeshBuilder::GetFaceCount -- *
  1703. * *
  1704. * INPUT: *
  1705. * *
  1706. * OUTPUT: *
  1707. * *
  1708. * WARNINGS: *
  1709. * *
  1710. * HISTORY: *
  1711. * 9/16/99 IML : Created. *
  1712. *=============================================================================================*/
  1713. int LsMeshBuilder::GetFaceCount() const
  1714. {
  1715. return (FaceCount);
  1716. }
  1717. /***********************************************************************************************
  1718. * LsMeshBuilder::GetFaces -- *
  1719. * *
  1720. * INPUT: *
  1721. * *
  1722. * OUTPUT: *
  1723. * *
  1724. * WARNINGS: *
  1725. * *
  1726. * HISTORY: *
  1727. * 9/16/99 IML : Created. *
  1728. *=============================================================================================*/
  1729. const LtTFace* LsMeshBuilder::GetFaces() const
  1730. {
  1731. return (Faces);
  1732. }
  1733. /***********************************************************************************************
  1734. * LsMeshBuilder::Finish -- Called by the Lightscape framework after each patch cluster read. *
  1735. * *
  1736. * Called by the Lightscape framework after each patch cluster read from a .ls file. The file *
  1737. * read is initiated by a LtSolutionImport() call. The clustering and the mesh structure is *
  1738. * entirely under the control of Lightscape. Each patch cluster may or may not reference a *
  1739. * texture and may or may not contain a radiosity mesh. If the .ls file has been produced by *
  1740. * Lightscape's 'Mesh to Texture' tool (M2T) with the "Generate Illumination Map" option *
  1741. * enabled then the material definition will (should) reference a lightmap texture. *
  1742. * *
  1743. * INPUT: *
  1744. * *
  1745. * OUTPUT: *
  1746. * *
  1747. * WARNINGS: *
  1748. * *
  1749. * HISTORY: *
  1750. * 7/23/99 IML : Created. *
  1751. *=============================================================================================*/
  1752. LtTBool LsMeshBuilder::Finish()
  1753. {
  1754. const char *invalidmappingtext =
  1755. "There is a face in the model with an invalid texture mapping. Please ensure that the\
  1756. Mesh to Texture option called 'Convert each surface to a single texture per surface' was\
  1757. used.";
  1758. const char *notnormalizedtext =
  1759. "There is a vertex in the model with a valid texture mapping but a non-normalized texture\
  1760. coordinate.";
  1761. const char *unmatchedmodeltext =
  1762. "The solve files do not contain the same model information. For any 2 solve files, the first\
  1763. n patches must match, where n is the smallest patch count of the two files.";
  1764. VertexUser usedvertices (*this);
  1765. bool success;
  1766. ASSERT (LightscapeSolve::Importer() != NULL);
  1767. // Add the vertices to the Lightscape solve database.
  1768. // If this mesh is an M2T patch...
  1769. if (GetProperties() & LT_MESH_RAWTEXTURE) {
  1770. int vertexindex;
  1771. LtTVector lsv; // Lightscape scratch vertex.
  1772. Vector3 v; // Scratch vertex.
  1773. Vector3 origin, du, dv; // Definition of texture projection.
  1774. Vector2 length; //
  1775. bool normalized;
  1776. LtTUnitVector lsn;
  1777. Vector3 n;
  1778. // Lightscape definition of texture projection.
  1779. LtTTextureProjection lsprojection = GetTextureProjection();
  1780. // If the texture mapping is invalid (ie. not orthographic)...
  1781. if ((lsprojection.GetFlags() & LT_PROJECTION_TYPE_MASK) != LT_PROJECTION_ORTHOGRAPHIC) {
  1782. throw (invalidmappingtext);
  1783. }
  1784. // Define origin and texture vectors for a planar mapping.
  1785. lsv = lsprojection.GetOrigin();
  1786. origin.Set (lsv.GetX(), lsv.GetY(), lsv.GetZ());
  1787. lsv = lsprojection.GetDu();
  1788. du.Set (lsv.GetX(), lsv.GetY(), lsv.GetZ());
  1789. lsv = lsprojection.GetDv();
  1790. dv.Set (lsv.GetX(), lsv.GetY(), lsv.GetZ());
  1791. // Normalize the texture vectors.
  1792. length.U = du.Length();
  1793. length.V = dv.Length();
  1794. du /= length.U;
  1795. dv /= length.V;
  1796. // Step thru the vertices, calculate UV from the texture projection and add the information
  1797. // to the Lightscape solve database.
  1798. GetPlane (lsn);
  1799. n.Set (lsn.GetX(), lsn.GetY(), lsn.GetZ());
  1800. for (vertexindex = 0; vertexindex < GetVertexCount(); vertexindex++) {
  1801. // Add only if the vertex is referenced by a face.
  1802. if (usedvertices.Is_Used (vertexindex)) {
  1803. LtTPoint lsp = GetVertices() [vertexindex];
  1804. Vector3 p (lsp.GetX(), lsp.GetY(), lsp.GetZ());
  1805. Vector2 t;
  1806. v = p - origin;
  1807. t.U = (du * v) / length.U;
  1808. t.V = (dv * v) / length.V;
  1809. // UV's must be normalized (in the range 0..1) in order to reference the lightmap properly.
  1810. normalized = ((t.U >= 0.0f) && (t.U <= 1.0f));
  1811. normalized &= ((t.V >= 0.0f) && (t.V <= 1.0f));
  1812. if (!normalized) throw (notnormalizedtext);
  1813. // Assign an index for this vertex which will uniquely identify it in the vertex database.
  1814. usedvertices.Set_Index (vertexindex, FactoryPtr->Vertex_Count());
  1815. // Add the vertex to the database.
  1816. success = LightscapeSolve::Importer()->Add_Vertex (FactoryPtr->Vertex_Count(), p, n, FactoryPtr->Patch_Count(), t);
  1817. if (!success) throw (unmatchedmodeltext);
  1818. // Advance vertex index counter.
  1819. FactoryPtr->Vertex_Increment();
  1820. }
  1821. }
  1822. // Find the texture name that corresponds to the material name and add it for this patch.
  1823. LightscapeSolve::Importer()->Add_Texture_Name (FactoryPtr->Patch_Count(), GetMaterial());
  1824. } else {
  1825. const double filtersharpness = LightscapeSolve::Importer()->Filter_Sharpness();
  1826. ProceduralTexture *blendtexture;
  1827. DynamicVectorClass <FaceVertexStruct> facevertices;
  1828. double *distanceratios;
  1829. int vertexindex;
  1830. int facevertexindex;
  1831. RadianceMap radiancemap (LightscapeSolve::Importer()->Get_Brightness(), LightscapeSolve::Importer()->Get_Contrast(), LightscapeSolve::Importer()->Is_Daylight(), LightscapeSolve::Importer()->Is_Exterior());
  1832. LtTPoint lsp;
  1833. LtTRGBColor irradiance;
  1834. LtTUnitVector lsn;
  1835. Vector3 n;
  1836. blendtexture = LightscapeSolve::Importer()->Procedural_Texture();
  1837. // NOTE: This mesh is not an M2T patch so it must instead contain valid vertex color information.
  1838. // Build an array of face vertices initialized to their respective vertex colors.
  1839. for (vertexindex = 0; vertexindex < GetVertexCount(); vertexindex++) {
  1840. if (usedvertices.Is_Used (vertexindex)) {
  1841. FaceVertexStruct facevertex;
  1842. lsp = GetVertices() [vertexindex];
  1843. irradiance = GetIrradiances() [vertexindex];
  1844. facevertex.Point.Set (lsp.GetX(), lsp.GetY(), lsp.GetZ());
  1845. facevertex.Color.Set (irradiance, radiancemap);
  1846. // Should the vertex color be blended with a sample from a procedural texture?
  1847. if (blendtexture != NULL) {
  1848. facevertex.Color *= blendtexture->Value (facevertex.Point);
  1849. }
  1850. facevertex.Weight = 1.0f;
  1851. facevertices.Add (facevertex);
  1852. }
  1853. }
  1854. // There must be at least one face vertex.
  1855. ASSERT (facevertices.Count() > 0);
  1856. // For every non-face vertex calculate its color contribution to each face vertex.
  1857. distanceratios = new double [facevertices.Count()];
  1858. ASSERT (distanceratios != NULL);
  1859. for (vertexindex = 0; vertexindex < GetVertexCount(); vertexindex++) {
  1860. if (!usedvertices.Is_Used (vertexindex)) {
  1861. Vector3 point;
  1862. ColorVector color;
  1863. double d, s;
  1864. lsp = GetVertices() [vertexindex];
  1865. irradiance = GetIrradiances() [vertexindex];
  1866. point.Set (lsp.GetX(), lsp.GetY(), lsp.GetZ());
  1867. color.Set (irradiance, radiancemap);
  1868. // Should the vertex color be blended with a sample from a procedural texture?
  1869. if (blendtexture != NULL) {
  1870. color *= blendtexture->Value (point);
  1871. }
  1872. d = (point - facevertices [0].Point).Length();
  1873. distanceratios [0] = s = 1.0f;
  1874. for (facevertexindex = 1; facevertexindex < facevertices.Count(); facevertexindex++) {
  1875. distanceratios [facevertexindex] = d / (point - facevertices [facevertexindex].Point).Length();
  1876. // Raise the distance ratio to the user specified filter sharpness.
  1877. distanceratios [facevertexindex] = pow (distanceratios [facevertexindex], filtersharpness);
  1878. s += distanceratios [facevertexindex];
  1879. }
  1880. for (facevertexindex = 0; facevertexindex < facevertices.Count(); facevertexindex++) {
  1881. float weight;
  1882. weight = distanceratios [facevertexindex] / s;
  1883. facevertices [facevertexindex].Color += color * weight;
  1884. facevertices [facevertexindex].Weight += weight;
  1885. }
  1886. }
  1887. }
  1888. // Add the face vertices to the solve database.
  1889. GetPlane (lsn);
  1890. n.Set (lsn.GetX(), lsn.GetY(), lsn.GetZ());
  1891. facevertexindex = 0;
  1892. for (vertexindex = 0; vertexindex < GetVertexCount(); vertexindex++) {
  1893. if (usedvertices.Is_Used (vertexindex)) {
  1894. ColorVector c = facevertices [facevertexindex].Color;
  1895. c /= facevertices [facevertexindex].Weight;
  1896. // Assign an index for this vertex which will uniquely identify it in the vertex database.
  1897. usedvertices.Set_Index (vertexindex, FactoryPtr->Vertex_Count());
  1898. // Add the vertex to the database.
  1899. success = LightscapeSolve::Importer()->Add_Vertex (FactoryPtr->Vertex_Count(), facevertices [facevertexindex].Point, n, FactoryPtr->Patch_Count(), c);
  1900. if (!success) {
  1901. delete [] distanceratios;
  1902. throw (unmatchedmodeltext);
  1903. }
  1904. // Advance the vertex index counters.
  1905. FactoryPtr->Vertex_Increment();
  1906. facevertexindex++;
  1907. }
  1908. }
  1909. // Clean-up.
  1910. delete [] distanceratios;
  1911. }
  1912. // Add the faces to the Lightscape solve database.
  1913. for (int faceindex = 0; faceindex < GetFaceCount(); faceindex++) {
  1914. const unsigned facevertexindexcount = 4;
  1915. LtTFace face;
  1916. int vertexindex, facevertexcount;
  1917. unsigned facevertexindices [facevertexindexcount];
  1918. ASSERT (faceindex >= 0 && faceindex < GetFaceCount());
  1919. face = GetFaces() [faceindex];
  1920. // If the face is not a triangle then it must be a quadrilateral. It is safe to assume
  1921. // that these are the only polygon types that Lightscape supports.
  1922. facevertexcount = face.IsTriangle() ? 3 : 4;
  1923. for (int v = 0; v < facevertexcount; v++) {
  1924. vertexindex = face.GetVert (v);
  1925. ASSERT (vertexindex >= 0 && vertexindex < GetVertexCount());
  1926. facevertexindices [v] = usedvertices.Get_Index (vertexindex);
  1927. }
  1928. success = LightscapeSolve::Importer()->Add_Patch_Face (FactoryPtr->Patch_Face_Count(), FactoryPtr->Patch_Count(), facevertexcount, facevertexindices);
  1929. if (!success) throw (unmatchedmodeltext);
  1930. // Advance patch face counter.
  1931. FactoryPtr->Patch_Face_Increment();
  1932. }
  1933. // Advance the patch index counter.
  1934. FactoryPtr->Patch_Increment();
  1935. // Return success.
  1936. return (TRUE);
  1937. }
  1938. /***********************************************************************************************
  1939. * VertexUser::VertexUser -- *
  1940. * *
  1941. * INPUT: *
  1942. * *
  1943. * OUTPUT: *
  1944. * *
  1945. * WARNINGS: *
  1946. * *
  1947. * HISTORY: *
  1948. * 1/05/00 IML : Created. *
  1949. *=============================================================================================*/
  1950. VertexUser::VertexUser (const LsMeshBuilder &meshbuilder)
  1951. {
  1952. LtTFace face;
  1953. unsigned v, vertexindex, facevertexcount;
  1954. Count = meshbuilder.GetVertexCount();
  1955. UsedVertexIndices = new int [Count];
  1956. ASSERT (UsedVertexIndices != NULL);
  1957. // Initialize. All vertices unused.
  1958. for (v = 0; v < Count; v++) {
  1959. UsedVertexIndices [v] = UNUSED;
  1960. }
  1961. // For each face...
  1962. for (int faceindex = 0; faceindex < meshbuilder.GetFaceCount(); faceindex++) {
  1963. face = meshbuilder.GetFaces() [faceindex];
  1964. // If the face is not a triangle then it must be a quadrilateral. It is safe to assume
  1965. // that these are the only polygon types that Lightscape supports.
  1966. facevertexcount = face.IsTriangle() ? 3 : 4;
  1967. // For each vertex in the face, flag that the vertex is referenced by a face.
  1968. for (v = 0; v < facevertexcount; v++) {
  1969. vertexindex = face.GetVert (v);
  1970. ASSERT (vertexindex >= 0 && vertexindex < Count);
  1971. UsedVertexIndices [vertexindex] = USED;
  1972. }
  1973. }
  1974. }
  1975. /***********************************************************************************************
  1976. * LightscapeMeshSolve::LightscapeMeshSolve -- *
  1977. * *
  1978. * INPUT: *
  1979. * *
  1980. * OUTPUT: *
  1981. * *
  1982. * WARNINGS: *
  1983. * *
  1984. * HISTORY: *
  1985. * 7/30/99 IML : Created. *
  1986. *=============================================================================================*/
  1987. LightscapeMeshSolve::LightscapeMeshSolve (LightscapeSolve &solve, ChunkClass &trianglechunk, ChunkClass &vertexchunk)
  1988. : Statistics (vertexchunk.Get_Size() / sizeof (W3dVectorStruct), trianglechunk.Get_Size() / sizeof (W3dTriStruct))
  1989. {
  1990. const unsigned verticesperface = 3; // No. of vertices in a triangle.
  1991. PackingTriangle *triangles;
  1992. W3dTriStruct *w3dfaces;
  1993. W3dVectorStruct *w3dvertices;
  1994. unsigned f, v;
  1995. // Calculate no. of faces and face-vertices from triangle chunk.
  1996. VertexCount = vertexchunk.Get_Size() / sizeof (W3dVectorStruct);
  1997. FaceCount = trianglechunk.Get_Size() / sizeof (W3dTriStruct);
  1998. FaceVertexCount = FaceCount * verticesperface;
  1999. // Allocate data tables for this mesh.
  2000. VertexColors = new W3dRGBStruct [VertexCount];
  2001. ASSERT (VertexColors != NULL);
  2002. FaceVertexUVs = new Vector2 [FaceVertexCount];
  2003. ASSERT (FaceVertexUVs != NULL);
  2004. FaceRemapLightmapIndices = new unsigned [FaceCount];
  2005. ASSERT (FaceRemapLightmapIndices != NULL);
  2006. LightmapIndices = new unsigned [FaceCount];
  2007. ASSERT (LightmapIndices != NULL);
  2008. triangles = new PackingTriangle [FaceCount];
  2009. ASSERT (triangles != NULL);
  2010. w3dfaces = (W3dTriStruct*) trianglechunk.Get_Data();
  2011. ASSERT (w3dfaces != NULL);
  2012. w3dvertices = (W3dVectorStruct*) vertexchunk.Get_Data();
  2013. ASSERT (w3dvertices != NULL);
  2014. // For each vertex in the vertex chunk...
  2015. for (unsigned vertexindex = 0; vertexindex < VertexCount; vertexindex++) {
  2016. const Vector3 zero (0.0f, 0.0f, 0.0f);
  2017. Vector3 *smoothingnormalptr;
  2018. Vector3 point;
  2019. W3dVectorStruct *w3dvertexptr;
  2020. W3dRGBStruct vertexcolor;
  2021. // Iterate over the faces and calculate a smoothing normal for this vertex based on
  2022. // the faces that reference this vertex.
  2023. smoothingnormalptr = NULL;
  2024. for (f = 0; f < FaceCount; f++) {
  2025. for (v = 0; v < verticesperface; v++) {
  2026. if (w3dfaces [f].Vindex [v] == vertexindex) {
  2027. Vector3 facenormal;
  2028. // Do not consider face normals that are zero (face is degenerate).
  2029. facenormal.Set (w3dfaces [f].Normal.X, w3dfaces [f].Normal.Y, w3dfaces [f].Normal.Z);
  2030. if (facenormal != zero) smoothingnormalptr = &facenormal;
  2031. break;
  2032. }
  2033. }
  2034. if (smoothingnormalptr != NULL) break;
  2035. }
  2036. w3dvertexptr = w3dvertices + vertexindex;
  2037. point.Set (w3dvertexptr->X, w3dvertexptr->Y, w3dvertexptr->Z);
  2038. solve.Find_Vertex (point, smoothingnormalptr, vertexcolor, Statistics);
  2039. VertexColors [vertexindex] = vertexcolor;
  2040. }
  2041. // For each face in the w3d triangle chunk, match it up with a face in the Lightscape solve database.
  2042. for (f = 0; f < FaceCount; f++) {
  2043. Vector3 points [verticesperface];
  2044. Vector3 facenormal;
  2045. Vector2 uvs [verticesperface];
  2046. PackingTriangle triangle;
  2047. // Extract points and face normal from vertex chunk.
  2048. for (v = 0; v < verticesperface; v++) {
  2049. W3dVectorStruct *w3dvertexptr;
  2050. unsigned vindex;
  2051. vindex = w3dfaces [f].Vindex [v];
  2052. w3dvertexptr = w3dvertices + vindex;
  2053. points [v].Set (w3dvertexptr->X, w3dvertexptr->Y, w3dvertexptr->Z);
  2054. }
  2055. facenormal.Set (w3dfaces [f].Normal.X, w3dfaces [f].Normal.Y, w3dfaces [f].Normal.Z);
  2056. solve.Find_Triangle (points, facenormal, triangles [f], Statistics);
  2057. }
  2058. if (Statistics.Valid_Lightmap_Solve()) {
  2059. unsigned lightmapindex, remaplightmapindex;
  2060. bool found;
  2061. // Submit the triangles for packing.
  2062. for (f = 0; f < FaceCount; f++) {
  2063. solve.Submit_Triangle (triangles [f]);
  2064. }
  2065. // Now pack.
  2066. solve.Pack();
  2067. // Extract the lightmap UV's from the triangles.
  2068. v = 0;
  2069. for (f = 0; f < FaceCount; f++) {
  2070. FaceVertexUVs [v + 0] = triangles [f].PackedUVs [0];
  2071. FaceVertexUVs [v + 1] = triangles [f].PackedUVs [1];
  2072. FaceVertexUVs [v + 2] = triangles [f].PackedUVs [2];
  2073. v += verticesperface;
  2074. }
  2075. // The face-lightmap indices are currently non-zero based, unordered, non-contiguous indices
  2076. // ie. an unknown list of indexes that have been returned from the packing process.
  2077. // The mesh requires face-lightmap indices that are zero-based, ordered, contiguous indices
  2078. // so remap the indices to create face-remaplightmap indices. Also, create a table of 'real'
  2079. // lightmap indices that will be indexed by the face-remaplightmap table.
  2080. remaplightmapindex = 0;
  2081. for (f = 0; f < FaceCount; f++) {
  2082. int g;
  2083. lightmapindex = triangles [f].PackedTextureID;
  2084. // Look backwards thru the face-lightmap table to see if this index has already occured?
  2085. found = false;
  2086. g = ((int) f) - 1;
  2087. while (g >= 0) {
  2088. if (triangles [g].PackedTextureID == lightmapindex) {
  2089. found = true;
  2090. break;
  2091. }
  2092. g--;
  2093. }
  2094. // Was the index found?
  2095. if (found) {
  2096. FaceRemapLightmapIndices [f] = FaceRemapLightmapIndices [g];
  2097. } else {
  2098. FaceRemapLightmapIndices [f] = remaplightmapindex;
  2099. ASSERT (remaplightmapindex < FaceCount);
  2100. LightmapIndices [remaplightmapindex] = lightmapindex;
  2101. remaplightmapindex++;
  2102. }
  2103. }
  2104. ASSERT (remaplightmapindex > 0);
  2105. LightmapCount = remaplightmapindex;
  2106. } else {
  2107. LightmapCount = 0;
  2108. }
  2109. // Clean-up.
  2110. delete [] triangles;
  2111. }
  2112. /***********************************************************************************************
  2113. * LightscapeMeshSolve::~LightscapeMeshSolve -- *
  2114. * *
  2115. * INPUT: *
  2116. * *
  2117. * OUTPUT: *
  2118. * *
  2119. * WARNINGS: *
  2120. * *
  2121. * HISTORY: *
  2122. * 7/30/99 IML : Created. *
  2123. *=============================================================================================*/
  2124. LightscapeMeshSolve::~LightscapeMeshSolve()
  2125. {
  2126. // Clean-up.
  2127. delete [] VertexColors;
  2128. delete [] LightmapIndices;
  2129. delete [] FaceRemapLightmapIndices;
  2130. delete [] FaceVertexUVs;
  2131. }
  2132. /***********************************************************************************************
  2133. * LightscapeMeshSolve::Vertex_Color -- *
  2134. * *
  2135. * INPUT: *
  2136. * *
  2137. * OUTPUT: *
  2138. * *
  2139. * WARNINGS: *
  2140. * *
  2141. * HISTORY: *
  2142. * 1/06/00 IML : Created. *
  2143. *=============================================================================================*/
  2144. W3dRGBStruct LightscapeMeshSolve::Vertex_Color (unsigned vertexindex) const
  2145. {
  2146. ASSERT (Statistics.Valid_Vertex_Solve());
  2147. ASSERT (vertexindex < VertexCount);
  2148. return (VertexColors [vertexindex]);
  2149. }
  2150. /***********************************************************************************************
  2151. * LightscapeMeshSolve::LightscapeMeshSolve -- *
  2152. * *
  2153. * INPUT: *
  2154. * *
  2155. * OUTPUT: *
  2156. * *
  2157. * WARNINGS: *
  2158. * *
  2159. * HISTORY: *
  2160. * 7/30/99 IML : Created. *
  2161. *=============================================================================================*/
  2162. const char *LightscapeMeshSolve::Lightmap_Pathname (unsigned lightmapindex) const
  2163. {
  2164. ASSERT (Statistics.Valid_Lightmap_Solve());
  2165. ASSERT (lightmapindex < FaceCount);
  2166. return (LightscapeSolve::Lightmap_Pathname (LightmapIndices [lightmapindex]));
  2167. }
  2168. /***********************************************************************************************
  2169. * LightscapeMeshSolve::LightscapeMeshSolve -- *
  2170. * *
  2171. * INPUT: *
  2172. * *
  2173. * OUTPUT: *
  2174. * *
  2175. * WARNINGS: *
  2176. * *
  2177. * HISTORY: *
  2178. * 7/30/99 IML : Created. *
  2179. *=============================================================================================*/
  2180. unsigned LightscapeMeshSolve::Lightmap_Index (unsigned faceindex) const
  2181. {
  2182. ASSERT (Statistics.Valid_Lightmap_Solve());
  2183. ASSERT (faceindex < FaceCount);
  2184. return (FaceRemapLightmapIndices [faceindex]);
  2185. }
  2186. /***********************************************************************************************
  2187. * LightscapeMeshSolve::LightscapeMeshSolve -- *
  2188. * *
  2189. * INPUT: *
  2190. * *
  2191. * OUTPUT: *
  2192. * *
  2193. * WARNINGS: *
  2194. * *
  2195. * HISTORY: *
  2196. * 7/30/99 IML : Created. *
  2197. *=============================================================================================*/
  2198. W3dTexCoordStruct LightscapeMeshSolve::Lightmap_UV (unsigned facevertexindex) const
  2199. {
  2200. W3dTexCoordStruct w3duv;
  2201. ASSERT (Statistics.Valid_Lightmap_Solve());
  2202. ASSERT (facevertexindex < FaceVertexCount);
  2203. w3duv.U = FaceVertexUVs [facevertexindex].U;
  2204. w3duv.V = FaceVertexUVs [facevertexindex].V;
  2205. return (w3duv);
  2206. }