| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681 |
- /*
- ** Command & Conquer Renegade(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- /***********************************************************************************************
- *** Confidential - Westwood Studios ***
- ***********************************************************************************************
- * *
- * Project Name : LightMap *
- * *
- * $Archive:: /Commando/Code/Tool $*
- * *
- * $Author:: Ian_l $*
- * *
- * $Modtime:: 8/24/01 9:24p $*
- * *
- * $Revision:: 60 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- // Includes.
- #include "StdAfx.h"
- #include "LightMap.h"
- #include "Lightscape.h"
- #include "LightMapPacker.h"
- #include "OptionsDialog.h"
- #include "PerlinNoise.h"
- #include "StringBuilder.h"
- #include "TextureNameNode.h"
- #include "matrix3.h"
- #include "matrix3d.h"
- #include "lightexclude.h"
- #include "tri.h"
- #include "vector3.h"
- #include "wwmath.h"
- #include <float.h>
- #include <math.h>
- #include <typeinfo.h>
- // Static data.
- LightscapeSolve *LightscapeSolve::_ActiveImporter = NULL;
- /***********************************************************************************************
- * LightscapeSolve::LightscapeSolve -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/27/99 IML : Created. *
- *=============================================================================================*/
- LightscapeSolve::LightscapeSolve (const char *solvedirectoryname, const char *solvefilenamelist, CStatusBar* statusptr, const char *statusbarmessage, bool blendnoise)
- : LightmapPacker()
- {
- const char *notsolutiontext =
- "One or more solve files are not solution (.ls) files.";
- const int materialtexturenamegrowthstep = 256;
- const int patchfacegrowthstep = 1024;
- const int vertexgrowthstep = 2048;
- const int lightgrowthstep = 32;
- static char _messagebuffer [1024];
- CRect srect, trect;
- BOOL success;
- StringBuilder errormessage (_messagebuffer, sizeof (_messagebuffer));
- const char *solvefilename;
- LtTBuilderFactory *factory = NULL;
- OptionsDialog options;
- // Initialize.
- SmoothingAngle = DEG_TO_RAD (options.Get_Smoothing_Angle()); // Convert from degrees to radians.
- SpatialTolerance = options.Get_Spatial_Tolerance(); // No mapping required.
- FilterSharpness = pow (options.Get_Filter_Sharpness() / 50.0l, 5.0l); // Map from linear to exponential scale.
-
- // If noise has been requested create a Perlin Noise generator.
- if (blendnoise) {
- ProceduralTexture = new PerlinNoise;
- ASSERT (ProceduralTexture != NULL);
- } else {
- ProceduralTexture = NULL;
- }
- if (options.Get_Light_Export_Selective()) {
- LightExclusionString = options.Get_Light_Exclusion_String();
- } else {
- LightExclusionString = NULL;
- }
- statusptr->GetItemRect (0, &srect);
- statusptr->SetPaneText (0, statusbarmessage);
- statusptr->GetDC()->DrawText (statusbarmessage, -1, &trect, DT_CALCRECT);
- CRect prect (srect.TopLeft().x + trect.Width(), srect.TopLeft().y, srect.BottomRight().x, srect.BottomRight().y);
-
- ProgressBar = new CProgressCtrl;
- ASSERT (ProgressBar != NULL);
- success = ProgressBar->Create (WS_CHILD | WS_VISIBLE | PBS_SMOOTH, prect, statusptr, 0);
- ASSERT (success);
-
- // Specify how many elements should be added to dynamic arrays when they are resized.
- MaterialTextureNames.Set_Growth_Step (materialtexturenamegrowthstep);
- PatchFaces.Set_Growth_Step (patchfacegrowthstep);
- Vertices.Set_Growth_Step (vertexgrowthstep);
- VertexIndices.Set_Growth_Step (vertexgrowthstep);
- Lights.Set_Growth_Step (lightgrowthstep);
- _ActiveImporter = this;
- try {
- char solvepathname [_MAX_PATH];
- int totalpatchclustercount = 0;
- // Parse the files, check that they are solve files and sum the patch cluster count for the progress bar.
- solvefilename = solvefilenamelist;
- while (strlen (solvefilename) > 0) {
- strcpy (solvepathname, solvedirectoryname);
- strcat (solvepathname, solvefilename);
- factory = new LsInformationFactory;
- ASSERT (factory != NULL);
- ::LtSolutionImport (solvepathname, *factory);
- if (!IsSolution) throw (notsolutiontext);
- totalpatchclustercount += PatchClusterCount;
- errormessage.Copy (factory->GetErrorMsg());
- delete factory;
- factory = NULL;
- if (strlen (errormessage.String()) > 0) throw (errormessage.String());
-
- // Advance to next solve file.
- solvefilename += strlen (solvefilename) + 1;
- }
- // Set-up the progress bar so that it can be updated for every patch cluster.
- ProgressBar->SetRange32 (0, totalpatchclustercount);
- ProgressBar->SetStep (1);
- // For each solve filename in the list...
- solvefilename = solvefilenamelist;
- while (strlen (solvefilename) > 0) {
- strcpy (solvepathname, solvedirectoryname);
- strcat (solvepathname, solvefilename);
- // Parse the Lightscape solve file and process materials.
- // NOTE: Material processing must be done first because mesh processing is dependant on it.
- // In order to guarantee this, the solution file is parsed twice, so that there is no
- // implicit reliance on the material data preceeding the mesh data in the file.
- factory = new LsPreparationFactory;
- ASSERT (factory != NULL);
-
- ::LtSolutionImport (solvepathname, *factory);
- errormessage.Copy (factory->GetErrorMsg());
- delete factory;
- factory = NULL;
- if (strlen (errormessage.String()) > 0) throw (errormessage.String());
-
- // Sort the material-texture names by a key defined by the comparison function Compare_Material_Names().
- // NOTE: qsort MUST (and does) allow for duplicate keys.
- if (MaterialTextureNames.Count() > 0) {
- qsort (&MaterialTextureNames [0], MaterialTextureNames.Count(), sizeof (char*), Compare_Material_Texture_Names);
- }
- // Parse the Lightscape solve file and add all vertices and faces that have been
- // processed by Mesh to Texture.
- factory = new LsMainFactory;
- ASSERT (factory != NULL);
-
- ::LtSolutionImport (solvepathname, *factory);
- errormessage.Copy (factory->GetErrorMsg());
- delete factory;
- factory = NULL;
- if (strlen (errormessage.String()) > 0) throw (errormessage.String());
- // Clean-up the the material-texture names. They are no longer required.
- for (int i = 0; i < MaterialTextureNames.Count(); i++) {
- delete [] MaterialTextureNames [i];
- }
- MaterialTextureNames.Clear();
- // Advance to next solve file.
- solvefilename += strlen (solvefilename) + 1;
- }
- if (Vertices.Count() > 0) {
- // Create a vertex index table and initialize the indices to identity.
- for (int v = 0; v < Vertices.Count(); v++) {
- VertexIndices.Insert (v, v);
- }
- // Sort the vertex pointers by a key defined by the comparison function Compare_Vertices().
- // NOTE: qsort MUST (and does) allow for duplicate keys.
- qsort (&VertexIndices [0], VertexIndices.Count(), sizeof (unsigned), Compare_Vertices);
- }
- // Sort the patch faces by a key defined by the comparison function Compare_Patch_Faces().
- // NOTE: qsort MUST (and does) allow for duplicate keys.
- if (PatchFaces.Count() > 0) {
- qsort (&PatchFaces [0], PatchFaces.Count(), sizeof (PatchFaceStruct), Compare_Patch_Faces);
- }
- } catch (const char *errormessage) {
-
- // Clean-up.
- if (factory != NULL) delete factory;
- if (ProgressBar != NULL) {
- delete ProgressBar;
- ProgressBar = NULL;
- }
- // Re-throw the message to the caller.
- throw (errormessage);
- }
-
- _ActiveImporter = NULL;
- delete ProgressBar;
- ProgressBar = NULL;
- }
- /***********************************************************************************************
- * LightscapeSolve::Finish -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/27/99 IML : Created. *
- *=============================================================================================*/
- LightscapeSolve::Finish()
- {
- LightmapPacker::Finish();
- }
- /***********************************************************************************************
- * LightscapeSolve::~LightscapeSolve -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: Do not throw any exceptions in this (and any other) destructor because this *
- * destructor can itself be called during the exception as part of its 'clean-up'. *
- * *
- * HISTORY: *
- * 7/27/99 IML : Created. *
- *=============================================================================================*/
- LightscapeSolve::~LightscapeSolve()
- {
- int i, l;
- // Clean-up anything that didn't get cleaned up before because an exception was thrown.
- for (i = 0; i < MaterialTextureNames.Count(); i++) {
- delete [] MaterialTextureNames [i];
- }
- _ActiveImporter = NULL;
- // Clean-up the texture names.
- for (i = 0; i < TextureNames.Length(); i++) {
-
- TextureNameNode *texturenamenode, *removalnode;
- texturenamenode = TextureNames [i];
- while (texturenamenode != NULL) {
- removalnode = texturenamenode;
- texturenamenode = texturenamenode->Next;
- delete removalnode;
- }
- }
- // Release references to lights.
- for (l = 0; l < Lights.Count(); l++) {
- Lights [l]->Release_Ref();
- }
- if (ProceduralTexture != NULL) delete ProceduralTexture;
- }
- /***********************************************************************************************
- * LightscapeSolve::Add_Material_Texture_Name -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/27/99 IML : Created. *
- *=============================================================================================*/
- void LightscapeSolve::Add_Material_Texture_Name (const char *materialname, const char *texturepathname)
- {
- const char *invalidtexturepathname = "";
- unsigned materialnamelength, texturepathnamelength;
- char *name;
- // The material name must exist.
- ASSERT (materialname != NULL);
- // If the material has no associated texture use the invalid texture pathname.
- if (texturepathname == NULL) texturepathname = invalidtexturepathname;
- // Calculate length of strings including terminator.
- materialnamelength = strlen (materialname) + 1;
- texturepathnamelength = strlen (texturepathname) + 1;
-
- name = new char [materialnamelength + texturepathnamelength];
- ASSERT (name != NULL);
- strcpy (name, materialname);
- // Append the texture name to the material name but leave the material name's terminator
- // intact so that conventional string functions only 'see' the material name.
- strcpy (name + materialnamelength, texturepathname);
- MaterialTextureNames.Add (name);
- }
- /***********************************************************************************************
- * LightscapeSolve::Add_Texture_Name -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/16/99 IML : Created. *
- *=============================================================================================*/
- void LightscapeSolve::Add_Texture_Name (unsigned patchindex, const char *materialname)
- {
- const char *materialnotfoundtext =
- "There is a face in the model that has a material name that cannot be found.";
-
- int length;
- char **materialnameptr;
- char *texturepathname;
- unsigned texturepathnamelength;
- // Can the texture name data be accomodated by the texture name array?
- length = TextureNames.Length();
- if ((int) patchindex >= length) {
-
- const int growthstep = 1024; // Add this many elements if the vector array runs out of room.
- bool success = TextureNames.Resize (patchindex + growthstep);
- ASSERT (success);
- // Null out the new elements.
- for (int i = length; i < TextureNames.Length(); i++) {
- TextureNames [i] = NULL;
- }
- }
- // NOTE: The material-texture names MUST have been sorted prior to calling bsearch().
- if (MaterialTextureNames.Count() > 0) {
- const char **keyptr;
- const char *key;
- key = materialname;
- keyptr = &key;
- materialnameptr = (char**) bsearch (keyptr, &MaterialTextureNames [0], MaterialTextureNames.Count(), sizeof (char*), Compare_Material_Texture_Names);
- } else {
- materialnameptr = NULL;
- }
- // If the material cannot be found then either the database has malfunctioned or the solve
- // file is corrupt.
- if (materialnameptr == NULL) {
- ASSERT (FALSE);
- throw (materialnotfoundtext);
- }
- // Extract the texture name.
- texturepathname = *materialnameptr + strlen (*materialnameptr) + 1;
- texturepathnamelength = strlen (texturepathname) + 1;
- // Add the name to the database only if it exists (has non-zero length excluding terminator).
- if (texturepathnamelength > 1) {
- TextureNameNode *node;
-
- node = new TextureNameNode (texturepathname);
- ASSERT (node != NULL);
- // Add the texture name to the database.
- node->Next = TextureNames [patchindex];
- TextureNames [patchindex] = node;
- }
- }
- /***********************************************************************************************
- * LightscapeSolve::Add_Light -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/24/00 IML : Created. *
- *=============================================================================================*/
- void LightscapeSolve::Add_Light (LightClass *light)
- {
- Lights.Add (light);
- light->Add_Ref();
- }
- /***********************************************************************************************
- * LightscapeSolve::Add_Vertex -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/25/00 IML : Created. *
- *=============================================================================================*/
- bool LightscapeSolve::Add_Vertex (unsigned vertexindex, const Vector3 &p, const Vector3 &n, unsigned patchindex, const Vector2 &t)
- {
- bool success;
- // If adding a M2T vertex, ensure that this is a M2T solve.
- ASSERT (Importer()->Is_M2T_Solve());
- // Has the element already been inserted?
- if (((int) vertexindex) < Vertices.Count()) {
- // Check that the new element data matches the existing data.
- success = (Vertices [vertexindex].Point == p) &&
- (Vertices [vertexindex].FaceNormal == n) &&
- (Vertices [vertexindex].PatchIndex == patchindex);
- } else {
- VerticesStruct vertex;
- vertex.Point = p;
- vertex.FaceNormal = n;
- vertex.PatchIndex = patchindex;
- vertex.ValidColor = false;
- vertex.ValidUV = false;
- success = Vertices.Insert (vertexindex, vertex);
- }
- if (success) {
- Vertices [vertexindex].UV = t;
- Vertices [vertexindex].ValidUV = true;
- }
- return (success);
- }
- /***********************************************************************************************
- * LightscapeSolve::Add_Vertex -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/25/00 IML : Created. *
- *=============================================================================================*/
- bool LightscapeSolve::Add_Vertex (unsigned vertexindex, const Vector3 &p, const Vector3 &n, unsigned patchindex, const ColorVector &c)
- {
- bool success;
- // Has the element already been inserted?
- if (((int) vertexindex) < Vertices.Count()) {
- // Check that the new element data matches the existing data.
- success = (Vertices [vertexindex].Point == p) &&
- (Vertices [vertexindex].FaceNormal == n) &&
- (Vertices [vertexindex].PatchIndex == patchindex);
- } else {
- VerticesStruct vertex;
- vertex.Point = p;
- vertex.FaceNormal = n;
- vertex.PatchIndex = patchindex;
- vertex.ValidColor = false;
- vertex.ValidUV = false;
- success = Vertices.Insert (vertexindex, vertex);
- }
- if (success) {
-
- // Only add/set the color if this is not a M2T solve.
- if (!Importer()->Is_M2T_Solve()) {
-
- // Add or set the color?
- if (Vertices [vertexindex].ValidColor) {
- const ColorVector clamp (1.0f, 1.0f, 1.0f);
-
- // Add and clamp.
- Vertices [vertexindex].Color += c;
- Vertices [vertexindex].Color.Update_Min (clamp);
- } else {
- Vertices [vertexindex].Color = c;
- Vertices [vertexindex].ValidColor = true;
- }
- }
- }
- return (success);
- }
- /***********************************************************************************************
- * LightscapeSolve::Add_Patch_Face -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/16/99 IML : Created. *
- *=============================================================================================*/
- bool LightscapeSolve::Add_Patch_Face (unsigned patchfaceindex, unsigned patchindex, unsigned vertexindexcount, unsigned *vertexindices)
- {
- bool success;
- // Only 3 or 4 vertex indices are supported.
- ASSERT (vertexindexcount == 3 || vertexindexcount == 4);
- // Has the element already been inserted?
- if (((int) patchfaceindex) < PatchFaces.Count()) {
- // Check that the new element data matches the existing data.
- success = (patchindex == PatchFaces [patchfaceindex].PatchIndex) &&
- (vertexindices [0] == PatchFaces [patchfaceindex].VertexIndices [0]) &&
- (vertexindices [1] == PatchFaces [patchfaceindex].VertexIndices [1]) &&
- (vertexindices [2] == PatchFaces [patchfaceindex].VertexIndices [2]);
- if (vertexindexcount == 4) {
- success &= (vertexindices [3] == PatchFaces [patchfaceindex].VertexIndices [3]);
- }
-
- } else {
- PatchFaceStruct patchface;
- patchface.PatchIndex = patchindex;
- patchface.VertexIndices [0] = vertexindices [0];
- patchface.VertexIndices [1] = vertexindices [1];
- patchface.VertexIndices [2] = vertexindices [2];
- if (vertexindexcount == 4) {
- patchface.VertexIndices [3] = vertexindices [3];
- } else {
- patchface.VertexIndices [3] = PatchFaceStruct::VERTEX_INDEX_INVALID;
- }
- success = PatchFaces.Insert (patchfaceindex, patchface);
- }
- return (success);
- }
- /***********************************************************************************************
- * LightscapeSolve::Find_Vertex -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/07/00 IML : Created. *
- *=============================================================================================*/
- void LightscapeSolve::Find_Vertex (const Vector3 &point, const Vector3 *smoothingnormalptr, W3dRGBStruct &vertexcolor, SolveStatistics &solvestatistics)
- {
- const int growthstep = 256;
- const W3dRGBStruct pink (255, 0, 255);
- DynamicVectorClass <VerticesStruct*> vertexset;
- ColorVector color;
- unsigned count;
- vertexset.Set_Growth_Step (growthstep);
- Find_Vertices (point, SpatialTolerance, vertexset);
- if (vertexset.Count() > 0) {
- color.Set (0.0f, 0.0f, 0.0f);
- count = 0;
- if (smoothingnormalptr != NULL) {
-
- // Sum the colors of all vertices that lie within the smoothing normal.
- for (int v = 0; v < vertexset.Count(); v++) {
- if (vertexset [v]->ValidColor) {
- float angle;
- // Is the face that is associated with this vertex within the smoothing angle
- // of the supplied vertex normal?
- angle = acosf (Vector3::Dot_Product (*smoothingnormalptr, vertexset [v]->FaceNormal));
- if (angle <= SmoothingAngle) {
- color += vertexset [v]->Color;
- count++;
- }
- }
- }
- if (count > 0) {
- color /= ((float) count);
- vertexcolor.Set (color.X, color.Y, color.Z);
- return;
- }
- }
-
- // Sum the colors of all vertices regardless of smoothing normal.
- for (int v = 0; v < vertexset.Count(); v++) {
- if (vertexset [v]->ValidColor) {
- color += vertexset [v]->Color;
- count++;
- }
- }
- if (count > 0) {
- color /= ((float) count);
- vertexcolor.Set (color.X, color.Y, color.Z);
- solvestatistics.Count [SolveStatistics::VERTEX_NOT_SMOOTH]++;
- return;
- } else {
-
- // There are no vertices with a valid color. Return a place-holder color.
- vertexcolor = pink;
- solvestatistics.Count [SolveStatistics::VERTEX_NO_COLOR]++;
- return;
- }
- }
-
- // Vertex not found. Return a place-holder color.
- vertexcolor = pink;
- solvestatistics.Count [SolveStatistics::VERTEX_NOT_FOUND]++;
- return;
- }
- /***********************************************************************************************
- * LightscapeSolve::Find_Triangle -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 06/07/00 IML : Created. *
- *=============================================================================================*/
- void LightscapeSolve::Find_Triangle (const Vector3 *points, const Vector3 &normal, PackingTriangle &triangle, SolveStatistics &solvestatistics)
- {
- const unsigned notextureid = 0xffffffff; // Arbitrary ID used to indicate that there is no associated texture.
- VerticesStruct trianglevertices [Triangle::VERTICES_COUNT];
- FaceResultEnum faceresult;
- bool notexture;
- unsigned v;
- ASSERT (points != NULL);
- // First, attempt a match with the face itself.
- switch (Face_Size (points, Triangle::VERTICES_COUNT)) {
- case FACE_UNDERSIZED:
- case FACE_NOT_UNDERSIZED:
- Find_Triangle (points, normal, trianglevertices, faceresult);
- break;
- case FACE_DEGENERATE:
- solvestatistics.Count [SolveStatistics::FACE_DEGENERATE]++;
- faceresult = FACE_NOT_FOUND;
- break;
- }
- notexture = false;
- switch (faceresult) {
- case FACE_AMBIGUOUS:
- solvestatistics.Count [SolveStatistics::FACE_AMBIGUOUS]++;
- // No break.
- case FACE_FOUND:
- {
- TextureNameNode *texturenamenodeptr;
- bool validuvs;
- // Check that texture exists and that all UV's are valid.
- texturenamenodeptr = (TextureNameNode*) Texture_Name (trianglevertices [0].PatchIndex);
- if (texturenamenodeptr != NULL) {
- validuvs = true;
- for (v = 0; v < Triangle::VERTICES_COUNT; v++) {
- validuvs &= trianglevertices [v].ValidUV;
- }
- if (validuvs) {
- triangle.TextureNameNodePtr = texturenamenodeptr;
- triangle.TextureID = trianglevertices [0].PatchIndex;
- triangle.Normal = trianglevertices [0].FaceNormal;
- for (v = 0; v < Triangle::VERTICES_COUNT; v++) {
- triangle.Vertices [v].Point = trianglevertices [v].Point;
- triangle.Vertices [v].UV = trianglevertices [v].UV;
- }
- break;
- }
- }
- notexture = true;
- solvestatistics.Count [SolveStatistics::FACE_NO_LIGHTMAP]++;
- break;
- }
- case FACE_NOT_FOUND:
- notexture = true;
- solvestatistics.Count [SolveStatistics::FACE_NOT_FOUND]++;
- break;
- }
- if (notexture) {
- // Return the original triangle with no associated texture.
- triangle.Normal = normal;
- for (v = 0; v < Triangle::VERTICES_COUNT; v++) {
- triangle.Vertices [v].Point = points [v];
- }
- triangle.TextureNameNodePtr = NULL;
- triangle.TextureID = notextureid;
- }
- }
- /***********************************************************************************************
- * LightscapeSolve::Submit_Triangle -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 06/07/00 IML : Created. *
- *=============================================================================================*/
- void LightscapeSolve::Submit_Triangle (PackingTriangle &triangle)
- {
- DynamicVectorClass <Triangle> adjtriangles;
-
- adjtriangles.Set_Growth_Step (32);
- Find_Adjacent_Triangles (triangle, adjtriangles);
- Submit (&triangle, adjtriangles);
- }
- /***********************************************************************************************
- * LightscapeSolve::Find_Adjacent_Triangles -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 6/05/00 IML : Created. *
- *=============================================================================================*/
- void LightscapeSolve::Find_Adjacent_Triangles (const PackingTriangle &principaltriangle, DynamicVectorClass <Triangle> &adjtriangles)
- {
- DynamicVectorClass <VerticesStruct*> spatialvertexset;
- // For each principal triangle vertex...
- for (unsigned v = 0; v < Triangle::VERTICES_COUNT; v++) {
- // Find all vertices that lie within spatial tolerance of this principal triangle vertex.
- spatialvertexset.Clear();
- Find_Vertices (principaltriangle.Vertices [v].Point, SpatialTolerance, spatialvertexset);
- for (int s = 0; s < spatialvertexset.Count(); s++) {
-
- Vector3 normal;
- float angle;
- // Is the face that is associated with this spatial vertex within the smoothing angle of the principal triangle's normal?
- normal = spatialvertexset [s]->FaceNormal;
- angle = acosf (Vector3::Dot_Product (principaltriangle.Normal, normal));
- if (angle <= SmoothingAngle) {
- TextureNameNode *texturenamenodeptr;
- unsigned textureid;
- // Is the texture name valid?
- texturenamenodeptr = (TextureNameNode*) Texture_Name (spatialvertexset [s]->PatchIndex);
- textureid = spatialvertexset [s]->PatchIndex;
- if (texturenamenodeptr != NULL) {
- PatchFaceStruct p, *patchfaceptr;
- // Find a patch face in the database with patch index that matches the patch index of the spatial vertex.
- p.PatchIndex = spatialvertexset [s]->PatchIndex;
- patchfaceptr = (PatchFaceStruct*) bsearch (&p, &PatchFaces [0], PatchFaces.Count(), sizeof (PatchFaceStruct), Compare_Patch_Faces);
-
- // Does a patch exist?
- if (patchfaceptr != NULL) {
- // Step backwards in the database to the first patch that matches.
- // NOTE: bsearch() does not necessarily return the first key in the array that matches when there are duplicate keys.
- while (patchfaceptr > &PatchFaces [0]) {
- if (Compare_Patch_Faces (&p, patchfaceptr - 1) != 0) break;
- patchfaceptr--;
- }
- // Step forwards in the database while there is a patch match.
- while ((patchfaceptr < &PatchFaces [0] + PatchFaces.Count()) && (Compare_Patch_Faces (&p, patchfaceptr) == 0)) {
- unsigned trianglecount;
- // Is this patch face a triangle or a quadrilateral?
- trianglecount = (patchfaceptr->VertexIndices [PatchFaceStruct::VERTICES_PER_PATCH_FACE - 1] == PatchFaceStruct::VERTEX_INDEX_INVALID) ? 1 : 2;
- // For each triangle...
- for (unsigned t = 0; t < trianglecount; t++) {
- const unsigned _vertexindex [2][3] = {{0, 1, 2}, {0, 2, 3}};
- bool validuvs;
- unsigned v;
- validuvs = true;
- for (v = 0; v < Triangle::VERTICES_COUNT; v++) {
- validuvs &= Vertices [patchfaceptr->VertexIndices [_vertexindex [t][v]]].ValidUV;
- }
-
- if (validuvs) {
-
- Triangle triangle;
- bool hasequivalent;
- triangle.TextureNameNodePtr = texturenamenodeptr;
- triangle.TextureID = textureid;
- triangle.Normal = normal;
- for (v = 0; v < Triangle::VERTICES_COUNT; v++) {
- triangle.Vertices [v].Point = Vertices [patchfaceptr->VertexIndices [_vertexindex [t][v]]].Point;
- triangle.Vertices [v].UV = Vertices [patchfaceptr->VertexIndices [_vertexindex [t][v]]].UV;
- }
-
- // Linearly search the existing adjacent triangles to see if this triangle already exists.
- hasequivalent = false;
- for (int a = 0; a < adjtriangles.Count(); a++) {
- if (triangle.Is_Equivalent (adjtriangles [a])) {
- hasequivalent = true;
- break;
- }
- }
- if (!hasequivalent) adjtriangles.Add (triangle);
- }
- }
- // Advance to next patch face.
- patchfaceptr++;
- }
- }
- }
- }
- }
- }
- }
- /***********************************************************************************************
- * LightscapeSolve::Find_Triangle -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/27/99 IML : Created. *
- *=============================================================================================*/
- void LightscapeSolve::Find_Triangle (const Vector3 *points, const Vector3 &facenormal, VerticesStruct *vertices, FaceResultEnum &faceresult)
- {
- const unsigned attemptcount = 14; // No. of binary search attempts (see note below).
- ASSERT (points != NULL);
- // Attempt to find the face with zero tolerance.
- Find_Triangle (points, 0.0f, true, &facenormal, vertices, faceresult);
-
- // If the face was not found then attempt to find a face by iterating over a range of
- // tolerances using a binary search technique.
- if (faceresult == FACE_NOT_FOUND) {
-
- bool faceambiguous;
- float maxtolerance = SpatialTolerance;
- float mintolerance = 0.00f;
- float tolerance;
-
- tolerance = (maxtolerance + mintolerance) * 0.5f;
-
- // NOTE: The tolerance will be increased or decreased, depending upon whether the
- // current result is 'not found' or 'ambiguous'. On each iteration the tolerance
- // range (max tolerance - min tolerance) is halved. Thus, after n iterations, the
- // tolerance range will be (max tolerance - min tolerance) / 2 ^ n. I have purposely
- // set n, the number of attempts, to yield a range at the limit of floating point
- // accuracy.
- faceambiguous = false;
- for (unsigned attempt = 0; attempt < attemptcount; attempt++) {
- Find_Triangle (points, tolerance, false, NULL, vertices, faceresult);
- if (faceresult == FACE_AMBIGUOUS) {
-
- // Flag that an ambiguous result occured.
- faceambiguous = true;
- // Decrease the tolerance.
- maxtolerance = tolerance;
- tolerance = (tolerance + mintolerance) * 0.5f;
- } else {
- if (faceresult == FACE_NOT_FOUND) {
-
- // Increase the tolerance.
- mintolerance = tolerance;
- tolerance = (tolerance + maxtolerance) * 0.5f;
- } else {
-
- // The face has been found.
- ASSERT (faceresult == FACE_FOUND);
- break;
- }
- }
- }
- // If an ambiguous result occured on ANY iteration then the maximum tolerance is the
- // smallest tolerance at which the ambiguity exists. Try to resolve the ambiguity
- // using the centroid and normal tests.
- if ((faceresult != FACE_FOUND) && faceambiguous) {
- Find_Triangle (points, maxtolerance, true, &facenormal, vertices, faceresult);
- }
- }
- }
- /***********************************************************************************************
- * LightscapeSolve::Find_Triangle -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/27/99 IML : Created. *
- *=============================================================================================*/
- void LightscapeSolve::Find_Triangle (const Vector3 *points, float tolerance, bool centroidtest, const Vector3 *facenormal, VerticesStruct *vertices, FaceResultEnum &faceresult)
- {
- const int growthstep = 256;
- DynamicVectorClass <VerticesStruct*> vertexset [Triangle::VERTICES_COUNT];
- DynamicVectorClass <VerticesStruct*> *candidatevertexset = &vertexset [0];
- unsigned patchindex;
- int n, c, v;
- bool success;
- ASSERT (points != NULL);
- // Create a set of vertex indices that correspond to the zeroth point.
- candidatevertexset->Set_Growth_Step (growthstep);
- Find_Vertices (points [0], tolerance, *candidatevertexset);
- // Remove any duplicate patches from the candidate set.
- c = 0;
- while (c < candidatevertexset->Count()) {
- patchindex = (*candidatevertexset) [c]->PatchIndex;
- v = c + 1;
- while (v < candidatevertexset->Count()) {
- if (patchindex == (*candidatevertexset) [v]->PatchIndex) {
- success = candidatevertexset->Delete (v);
- ASSERT (success);
- } else {
- v++;
- }
- }
- c++;
- }
- // For all other points...
- for (n = 1; n < Triangle::VERTICES_COUNT; n++) {
-
- // Create a set of vertex indices that correspond to n'th <point, normal> pair.
- vertexset [n].Set_Growth_Step (growthstep);
- Find_Vertices (points [n], tolerance, vertexset [n]);
- // Delete all indexes in the candidate index set that have materials that DO NOT occur in the vertex index set.
- c = 0;
- while (c < candidatevertexset->Count()) {
-
- bool found;
- patchindex = (*candidatevertexset) [c]->PatchIndex;
- found = false;
- for (v = 0; v < vertexset [n].Count(); v++) {
- if (patchindex == vertexset [n][v]->PatchIndex) {
- found = true;
- break;
- }
- }
- if (!found) {
- success = candidatevertexset->Delete (c);
- ASSERT (success);
- } else {
- c++;
- }
- }
- }
- // If there is more than one candidate and the centroid test can be applied then apply it.
- if ((candidatevertexset->Count() > 1) && centroidtest) {
-
- // If there is a patch-face database...
- if (PatchFaces.Count() > 0) {
- // Attempt to eliminate the ambiguity by applying a centroid test.
- Vector3 centroid;
- centroid = points [0];
- for (n = 1; n < Triangle::VERTICES_COUNT; n++) {
- centroid += points [n];
- }
- centroid /= (float) Triangle::VERTICES_COUNT;
- // For each candidate...
- c = 0;
- while (c < candidatevertexset->Count()) {
- bool contained;
- PatchFaceStruct p;
- PatchFaceStruct *patchfaceptr;
- unsigned trianglecount;
- patchindex = (*candidatevertexset) [c]->PatchIndex;
- contained = false;
-
- // Find a face in the array that matches the patch.
- p.PatchIndex = patchindex;
- patchfaceptr = (PatchFaceStruct*) bsearch (&p, &PatchFaces [0], PatchFaces.Count(), sizeof (PatchFaceStruct), Compare_Patch_Faces);
-
- if (patchfaceptr != NULL) {
-
- // Step backwards in the array to the first patch that matches.
- // NOTE: bsearch() does not necessarily return the first key in the array that matches when there are duplicate keys.
- while (patchfaceptr > &PatchFaces [0]) {
- if (Compare_Patch_Faces (&p, patchfaceptr - 1) != 0) break;
- patchfaceptr--;
- }
- // Step forwards in the array while there is a patch match.
- // Find all vertices whose points and normals approximately match the requested normal and add their patch indices to the patch array.
- while ((patchfaceptr < &PatchFaces [0] + PatchFaces.Count()) && (Compare_Patch_Faces (&p, patchfaceptr) == 0)) {
-
- // NOTE: The candidate point may not match the any of the material face
- // points because Lightscape may have changed the topology. Thus it is
- // necessary to search ALL of the faces that have this material.
- // For each triangle in the patch face...
- // NOTE: Define the first triangle to be the points 0-1-2. If the patch face is a quadrilateral,
- // then define the second triangle to be the points 0-2-3.
- trianglecount = (patchfaceptr->VertexIndices [3] == PatchFaceStruct::VERTEX_INDEX_INVALID) ? 1 : 2;
- for (unsigned t = 0; t < trianglecount; t++) {
- // Create a triangle from the material face and test it against the centroid for containment.
- TriClass triangle;
- Vector3 normal;
- triangle.V [0] = &Vertices [patchfaceptr->VertexIndices [0]].Point;
- triangle.V [1] = &Vertices [patchfaceptr->VertexIndices [1 + t]].Point;
- triangle.V [2] = &Vertices [patchfaceptr->VertexIndices [2 + t]].Point;
- triangle.N = &normal;
- triangle.Compute_Normal();
- if (triangle.Contains_Point (centroid)) {
- contained = true;
- break;
- }
- }
- if (contained) break;
- // Advance to next patch face.
- patchfaceptr++;
- }
- }
- if (!contained) {
- success = candidatevertexset->Delete (c);
- ASSERT (success);
- } else {
- c++;
- }
- }
- }
- }
- // If there is still more than one candidate and the normal exists then apply the normal test.
- if ((candidatevertexset->Count() > 1) && (facenormal != NULL)) {
- float largestdp;
-
- // Find the smallest angle (largest dot product) between the vertex face normal and the target face normal.
- largestdp = (*facenormal) * ((*candidatevertexset) [0]->FaceNormal);
- for (c = 1; c < candidatevertexset->Count(); c++) {
- largestdp = MAX (largestdp, (*facenormal) * ((*candidatevertexset) [c]->FaceNormal));
- }
-
- // Delete all candidates that do not have the largest dot product.
- c = 0;
- while (c < candidatevertexset->Count()) {
- float dp = (*facenormal) * ((*candidatevertexset) [c]->FaceNormal);
-
- if (dp < largestdp) {
- success = candidatevertexset->Delete (c);
- ASSERT (success);
- } else {
- c++;
- }
- }
- }
- // Now if there are no candidates then return failure.
- if (candidatevertexset->Count() == 0) {
- faceresult = FACE_NOT_FOUND;
- } else {
- unsigned candidateindex = 0;
- // NOTE: If there is >1 candidate at this point the result is still ambiguous.
- // If the face normal has been supplied, select the candidate with closest
- // face normal - otherwise select the zeroth candidate.
- if (facenormal != NULL) {
- float mindistance = FLT_MAX;
- for (n = 0; n < candidatevertexset->Count(); n++) {
-
- float distance;
- distance = Manhatten_Distance (*facenormal - (*candidatevertexset) [n]->FaceNormal);
- if (distance < mindistance) {
- mindistance = distance;
- candidateindex = n;
- }
- }
- }
-
- // For the zeroth point...
- patchindex = (*candidatevertexset) [candidateindex]->PatchIndex;
- vertices [0] = *((*candidatevertexset) [candidateindex]);
- // For all other points...
- for (n = 1; n < Triangle::VERTICES_COUNT; n++) {
-
- bool assigned = false;
-
- for (v = 0; v < vertexset [n].Count(); v++) {
- if (vertexset [n][v]->PatchIndex == patchindex) {
- vertices [n] = *(vertexset [n][v]);
- assigned = true;
- break;
- }
- }
- ASSERT (assigned);
- }
- // Flag if the result was ambiguous.
- if (candidatevertexset->Count() > 1) {
- faceresult = FACE_AMBIGUOUS;
- } else {
-
- // There must be exactly one candidate.
- ASSERT (candidatevertexset->Count() == 1);
- faceresult = FACE_FOUND;
- }
- }
- }
- /***********************************************************************************************
- * LightscapeSolve::Find_Vertices -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/27/99 IML : Created. *
- *=============================================================================================*/
- void LightscapeSolve::Find_Vertices (const Vector3 &point, float tolerance, DynamicVectorClass <VerticesStruct*> &vertices)
- {
- if (VertexIndices.Count() > 0) {
- unsigned *vertexindexptr = NULL;
- int b0, b1, b;
- float x;
- // There should be a 1-1 mapping between vertex indices and vertices.
- ASSERT (VertexIndices.Count() == Vertices.Count());
- // Find a vertex that matches point to within tolerance using binary search technique.
- b0 = 0;
- b1 = VertexIndices.Count() - 1;
- do {
- b = (b0 + b1) >> 1;
- x = Vertices [VertexIndices [b]].Point.X;
- if (point.X - x < -tolerance) {
- b1 = b - 1;
- } else {
- if (point.X - x > tolerance) {
- b0 = b + 1;
- } else {
- vertexindexptr = &VertexIndices [b];
- break;
- }
- }
-
- } while (b0 <= b1);
- // Step backwards in the array to the first vertex that meets the match criteria defined by Compare_Vertices().
- // NOTE: Above search did not necessarily return the first key in the array that matches when there are duplicate keys.
- if (vertexindexptr != NULL) {
- while (vertexindexptr > &VertexIndices [0]) {
- x = Vertices [*(vertexindexptr - 1)].Point.X;
- if (point.X - x > tolerance) break;
- vertexindexptr--;
- }
- // Step forwards in the array while there is an approximate vertex match.
- // Add all vertices that are valid and whose points match the requested point within tolerance.
- while (vertexindexptr < &VertexIndices [0] + VertexIndices.Count()) {
-
- VerticesStruct *vertexptr;
- vertexptr = &Vertices [*vertexindexptr];
- if (point.X - vertexptr->Point.X < -tolerance) break;
- if (Manhatten_Distance (vertexptr->Point - point) <= tolerance) {
- vertices.Add (vertexptr);
- }
- // Advance to next vertex index.
- vertexindexptr++;
- }
- }
- }
- }
- /***********************************************************************************************
- * LightscapeSolve::Face_Size -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/17/99 IML : Created. *
- *=============================================================================================*/
- LightscapeSolve::FaceSizeEnum LightscapeSolve::Face_Size (const Vector3 *points, unsigned count)
- {
- const float undersizedarea = 0.0016f; // An area << the area of a lightmap lumel (assuming
- // that lumel density is less than 625 lumels/metre).
- float area;
- // Test for degeneracy.
- // NOTE: Assume that the points are ordered (for triangles this is guaranteed).
- for (unsigned n = 0; n < count; n++) {
- if (points [n] == points [(n + 1) % count]) return (FACE_DEGENERATE);
- }
- // Currently, the area calculation requires that the polygon is a triangle.
- ASSERT (count == 3);
-
- // Test for a small area.
- area = 0.5f * Vector3::Cross_Product (points [1] - points [0], points [2] - points [0]).Length();
- if (area < undersizedarea) return (FACE_UNDERSIZED);
- return (FACE_NOT_UNDERSIZED);
- }
- /***********************************************************************************************
- * LightscapeSolve::Longest_Edge -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/17/99 IML : Created. *
- *=============================================================================================*/
- unsigned LightscapeSolve::Longest_Edge (const Vector3 *points, unsigned count, bool *usededges)
- {
- float maxlength = -1.0f;
- float length;
- unsigned edgeindex;
- for (unsigned e = 0; e < count; e++) {
- if (!usededges [e]) {
- length = (points [(e + 1) % count] - points [e]).Length();
- if (length > maxlength) {
- maxlength = length;
- edgeindex = e;
- }
- }
- }
-
- // An edge must have been found.
- ASSERT (maxlength >= 0.0f);
- usededges [edgeindex] = true;
- return (edgeindex);
- }
- /***********************************************************************************************
- * LightscapeSolve::Texture_Name -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/27/99 IML : Created. *
- *=============================================================================================*/
- const TextureNameNode *LightscapeSolve::Texture_Name (unsigned patchindex)
- {
- // If the array element does not exist yet then the name has not been set.
- if ((int) patchindex >= TextureNames.Length()) return (NULL);
- return TextureNames [patchindex];
- }
- /***********************************************************************************************
- * LightscapeSolve::Compare_Material_Texture_Names -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/27/99 IML : Created. *
- *=============================================================================================*/
- int LightscapeSolve::Compare_Material_Texture_Names (const void *materialname0, const void *materialname1)
- {
- return (strcmp (*((const char**) materialname0), *((const char**) materialname1)));
- }
- /***********************************************************************************************
- * LightscapeSolve::Compare_Vertices *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/27/99 IML : Created. *
- *=============================================================================================*/
- int LightscapeSolve::Compare_Vertices (const void *vertexindexptr0, const void *vertexindexptr1)
- {
- float x0, x1;
- ASSERT (_ActiveImporter != NULL);
- x0 = _ActiveImporter->Vertices [*((unsigned*) vertexindexptr0)].Point.X;
- x1 = _ActiveImporter->Vertices [*((unsigned*) vertexindexptr1)].Point.X;
- if (x0 < x1) {
- return (-1);
- } else {
- if (x0 > x1) {
- return (1);
- } else {
- return (0);
- }
- }
- }
- /***********************************************************************************************
- * LightscapeSolve::Compare_Patch_Faces -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/17/99 IML : Created. *
- *=============================================================================================*/
- int LightscapeSolve::Compare_Patch_Faces (const void *patchface0, const void *patchface1)
- {
- unsigned patchindex0 = ((PatchFaceStruct*) patchface0)->PatchIndex;
- unsigned patchindex1 = ((PatchFaceStruct*) patchface1)->PatchIndex;
- if (patchindex0 < patchindex1) {
- return (-1);
- } else {
- if (patchindex0 > patchindex1) {
- return (1);
- } else {
- return (0);
- }
- }
- }
- /***********************************************************************************************
- * LightscapeSolve::Pack -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 09/07/00 IML : Created. *
- *=============================================================================================*/
- void LightscapeSolve::Pack()
- {
- LightmapPacker::Pack (ProceduralTexture);
- }
- /***********************************************************************************************
- * LsInformationFactory::OnGet*Builder -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/16/99 IML : Created. *
- *=============================================================================================*/
- LtTInfoBuilderApi* LsInformationFactory::OnGetInfoBuilder()
- {
- return (new LsInfoBuilder (this));
- }
- LtTParameterBuilderApi* LsInformationFactory::OnGetParameterBuilder()
- {
- return (new LsParameterBuilder (this));
- }
- /***********************************************************************************************
- * LsPreparationFactory::OnGet*Builder -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/27/99 IML : Created. *
- *=============================================================================================*/
- LtTInfoBuilderApi *LsPreparationFactory::OnGetInfoBuilder()
- {
- return (new LsInfoBuilder (this));
- }
- LtTParameterBuilderApi *LsPreparationFactory::OnGetParameterBuilder()
- {
- return (new LsParameterBuilder (this));
- }
- LtTMaterialBuilderApi *LsPreparationFactory::OnGetMaterialBuilder()
- {
- return (new LsMaterialBuilder (this));
- }
- LtTLampBuilderApi *LsPreparationFactory::OnGetLampBuilder()
- {
- return (new LsLampBuilder (this));
- }
- LtTMeshBuilderApi *LsPreparationFactory::OnGetMeshBuilder()
- {
- return (new LsMeshInquirer (this));
- }
- /***********************************************************************************************
- * LsMainFactory::LsMainFactory -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/23/99 IML : Created. *
- *=============================================================================================*/
- LsMainFactory::LsMainFactory()
- : LtTBuilderFactory()
- {
- PatchFaceIndex = 0;
- VertexIndex = 0;
- PatchIndex = 0;
- }
- /***********************************************************************************************
- * LsMainFactory::OnGet*Builder -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/23/99 IML : Created. *
- *=============================================================================================*/
- LtTInfoBuilderApi* LsMainFactory::OnGetInfoBuilder()
- {
- return (new LsInfoBuilder (this));
- }
- LtTParameterBuilderApi* LsMainFactory::OnGetParameterBuilder()
- {
- return (new LsParameterBuilder (this));
- }
- LtTMeshBuilderApi* LsMainFactory::OnGetMeshBuilder()
- {
- return (new LsMeshBuilder (this));
- }
- /***********************************************************************************************
- * LsInfoBuilder::LsInfoBuilder -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/17/99 IML : Created. *
- *=============================================================================================*/
- LsInfoBuilder::LsInfoBuilder (LtTBuilderFactory *factory)
- : LtTBaseInfoBuilder (factory)
- {
- // Do any special initialization here.
- }
- /***********************************************************************************************
- * LsInfoBuilder::Finish -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/17/99 IML : Created. *
- *=============================================================================================*/
- LtTBool LsInfoBuilder::Finish()
- {
- // Read any info values here.
- LightscapeSolve::Importer()->Set_Is_Solution (IsSolution() ? true : false);
- LightscapeSolve::Importer()->Set_Patch_Cluster_Count (GetNumGroups());
- LightscapeSolve::Importer()->Set_Brightness (GetBrightness());
- LightscapeSolve::Importer()->Set_Contrast (GetContrast());
-
- // Return success.
- return (TRUE);
- }
- /***********************************************************************************************
- * LsParameterBuilder::LsParameterBuilder -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/17/99 IML : Created. *
- *=============================================================================================*/
- LsParameterBuilder::LsParameterBuilder (LtTBuilderFactory *factory)
- : LtTBaseParameterBuilder (factory)
- {
- // Do any special initialization here.
- }
- /***********************************************************************************************
- * LsParameterBuilder::Finish -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/17/99 IML : Created. *
- *=============================================================================================*/
- LtTBool LsParameterBuilder::Finish()
- {
- // Read any parameter values here.
- LightscapeSolve::Importer()->Set_Is_Daylight ((GetFlags() & LT_PROCESS_DAYLIGHT) != 0);
- LightscapeSolve::Importer()->Set_Is_Exterior ((GetFlags() & LT_PROCESS_EXTERIOR) != 0);
- // Return success.
- return (TRUE);
- }
- /***********************************************************************************************
- * LsMateriaBuilder::LsMaterialBuilder -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/27/99 IML : Created. *
- *=============================================================================================*/
- LsMaterialBuilder::LsMaterialBuilder (LtTBuilderFactory *factory)
- : LtTBaseMaterialBuilder (factory)
- {
- // Do any special initialization here.
- }
- /***********************************************************************************************
- * LsMateriaBuilder::Finish -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/27/99 IML : Created. *
- *=============================================================================================*/
- LtTBool LsMaterialBuilder::Finish()
- {
- ASSERT (LightscapeSolve::Importer() != NULL);
- LightscapeSolve::Importer()->Add_Material_Texture_Name (GetName(), GetTextureName());
-
- // Return success.
- return (TRUE);
- }
- /***********************************************************************************************
- * LsLampBuilder::LsLampBuilder -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/24/00 IML : Created. *
- *=============================================================================================*/
- LsLampBuilder::LsLampBuilder (LtTBuilderFactory *factory)
- : LtTBaseLampBuilder (factory)
- {
- // Do any special initialization here.
- }
- /***********************************************************************************************
- * LsLampBuilder::Finish -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 3/24/00 IML : Created. *
- *=============================================================================================*/
- LtTBool LsLampBuilder::Finish()
- {
- const char *unknownlighttext =
- "There is a light in the solve with unknown type.";
- const Vector3 oodistancesquaredfactors (0.0f, 0.0f, 1.0f);
- const Vector3 zaxis (0.0f, 0.0f, 1.0f);
- const ColorVector black (0.0f, 0.0f, 0.0f);
- const ColorVector white (1.0f, 1.0f, 1.0f);
- float dir [3][3];
- LightClass *light;
- Vector3 position;
- ColorVector color;
- Matrix3D transform;
- ASSERT (LightscapeSolve::Importer() != NULL);
- // If the light name begins with a '@' skip it - it is not intended for export.
- if (LightscapeSolve::Importer()->Light_Exclusion_String() != NULL) {
- if (strstr (GetName(), LightscapeSolve::Importer()->Light_Exclusion_String())) return (TRUE);
- }
- // Skip skylight - it cannot be meaningfully translated into a LightClass object.
- if ((GetType() == LT_LAMP_DAYLIGHT) && (strcmp (GetName(), "Skylight") == 0)) return (TRUE);
- // If the lamp does not store direct illumination and has not been raytraced then
- // it has not been included in the solve - skip it.
- if ((GetFlags() & LT_LAMP_CAST_NO_DIRECT) && !(GetFlags() & LT_LAMP_RAY_TRACE_DIRECT)) return (TRUE);
- // If this light has non-zero intensity then add the light to the solve database.
- if (GetIntensity() > 0.0f) {
-
- // NOTE 0: Lightscape uses a right-handed coordinate system.
- // NOTE 1: For directional lights (including sunlight), multiplying the direction matrix
- // by (0, 0, 1) will yield the direction of the light rays.
- GetDirection (dir);
- Matrix3 direction (dir [0][0], dir [0][1], dir [0][2],
- dir [1][0], dir [1][1], dir [1][2],
- dir [2][0], dir [2][1], dir [2][2]);
- // Create light of appropriate type.
- switch (GetType()) {
- case LT_LAMP_ISOTROPIC: // Spherical equal intensity distribution.
- light = new LightClass (LightClass::POINT);
- ASSERT (light != NULL);
- break;
-
- case LT_LAMP_DIFFUSE: // Hemispherical distribution with intensity proportional to the cosine to the direction of light.
-
- // Interpret this light as a spotlight with a 180 degree spot angle.
- light = new LightClass (LightClass::SPOT);
- ASSERT (light != NULL);
- light->Set_Spot_Angle (WWMATH_PI);
- light->Set_Spot_Direction (zaxis);
-
- // For efficiency, use unity as exponent.
- light->Set_Spot_Exponent (1.0f);
- break;
-
- case LT_LAMP_SPOTLIGHT: // Spotlight distribution. Intensity at beam angle is one-half maximum intensity. Intensity is truncated to 0 at field angle.
-
- light = new LightClass (LightClass::SPOT);
- ASSERT (light != NULL);
-
- // NOTE: Field angle is defined as angle swept from center of beam to outside.
- light->Set_Spot_Angle (GetFieldAngle() * 2.0f);
- light->Set_Spot_Direction (zaxis);
- // For efficiency, use unity as exponent.
- light->Set_Spot_Exponent (1.0f);
- break;
- case LT_LAMP_GENERAL: // General distribution is determined from table if intensities in given directions.
-
- {
- float angle;
- // Get the widest angle - this is normally, but not always, the field angle.
- angle = MAX (GetBeamAngle(), GetFieldAngle());
- if (angle > WWMATH_PI / 2.0f) {
- // Interpret light as an isometric light.
- light = new LightClass (LightClass::POINT);
- ASSERT (light != NULL);
- } else {
-
- // Interpret light as a spotlight.
- light = new LightClass (LightClass::SPOT);
- ASSERT (light != NULL);
-
- light->Set_Spot_Angle (angle * 2.0f);
- light->Set_Spot_Direction (zaxis);
-
- // For efficiency, use unity as exponent.
- light->Set_Spot_Exponent (1.0f);
- }
- }
- break;
- case LT_LAMP_DAYLIGHT: // Special value used to flag daylight when import an LS file.
- light = new LightClass (LightClass::DIRECTIONAL);
- ASSERT (light != NULL);
- break;
- default:
- ASSERT (FALSE);
- throw (unknownlighttext);
- break;
- }
- // Set transform matrix that defines direction and position of light source.
- position.Set (GetLocation().GetX(), GetLocation().GetY(), GetLocation().GetZ());
- transform.Set (direction, position);
- light->Set_Transform (transform);
- // Set intensity.
- light->Set_Intensity (1.0f);
-
- RadianceMap radiancemap (LightscapeSolve::Importer()->Get_Brightness(), LightscapeSolve::Importer()->Get_Contrast(), LightscapeSolve::Importer()->Is_Daylight(), LightscapeSolve::Importer()->Is_Exterior());
- float i = GetIntensity();
- LtTRGBColor irradiance (i * GetFilterColor().GetR(), i * GetFilterColor().GetG(), i * GetFilterColor().GetB());
-
- // Set colors.
- color.Set (irradiance, radiancemap);
-
- // Clamp to white.
- color.Update_Min (white);
- light->Set_Ambient (black);
- light->Set_Diffuse (color);
- light->Set_Specular (color);
- // Set attenuation model.
- if (GetType() != LT_LAMP_DAYLIGHT) {
- const float oocutoff = 1.0f / 0.025f; // Reciprocal of light intensity at far attenuation.
- // NOTE: Convert Lightscape 1/d^2 attenuation to an equivalent MAX type light.
- light->Set_Flag (LightClass::NEAR_ATTENUATION, false);
- light->Set_Near_Attenuation_Range (0.0f, 0.0f);
- light->Set_Flag (LightClass::FAR_ATTENUATION, true);
- // Calculate attenuation range.
- // The far attenuation is calculated as the distance at which intensity falls to a given
- // ratio (cut-off), assuming an attenuation of c/d^2, where c = monochrome intensity of light source.
- float d = sqrt (oocutoff * color.Length());
- light->Set_Far_Attenuation_Range (d * 0.25f, d);
-
- } else {
-
- light->Set_Flag (LightClass::NEAR_ATTENUATION, false);
- light->Set_Flag (LightClass::FAR_ATTENUATION, false);
- }
- // Miscellaneous attributes.
- light->Enable_Shadows ((GetFlags() & LT_LAMP_CAST_NO_SHADOWS) ? false : true);
- LightscapeSolve::Importer()->Add_Light (light);
-
- // Clean-up.
- light->Release_Ref();
- }
- // Return success.
- return (TRUE);
- }
- /***********************************************************************************************
- * LsMeshInquirer::LsMeshInquirer -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 04/19/00 IML : Created. *
- *=============================================================================================*/
- LsMeshInquirer::LsMeshInquirer (LtTBuilderFactory *factory)
- : LtTBaseMeshBuilder (factory)
- {
- // Assume initially that the solve is NOT an M2T solve.
- LightscapeSolve::Importer()->Set_Is_M2T_Solve (false);
- }
- /***********************************************************************************************
- * LsMeshInquirer::LsMeshInquirer -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 04/19/00 IML : Created. *
- *=============================================================================================*/
- LtTBool LsMeshInquirer::Finish()
- {
- if (GetProperties() & LT_MESH_RAWTEXTURE) {
- LightscapeSolve::Importer()->Set_Is_M2T_Solve (true);
- }
- // Return success.
- return (TRUE);
- }
- /***********************************************************************************************
- * LsMeshBuilder::LsMeshBuilder -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/23/99 IML : Created. *
- *=============================================================================================*/
- LsMeshBuilder::LsMeshBuilder (LtTBuilderFactory *factory)
- : LtTBaseMeshBuilder (factory)
- {
- ASSERT (strcmp (typeid (*factory).name(), "class LsMainFactory") == 0);
- FactoryPtr = (LsMainFactory*) factory;
- Faces = NULL;
- FaceCount = 0;
- AllocatedCount = 0;
- }
- /***********************************************************************************************
- * LsMeshBuilder::~LsMeshBuilder -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/16/99 IML : Created. *
- *=============================================================================================*/
- LsMeshBuilder::~LsMeshBuilder()
- {
- if (Faces != NULL) delete [] Faces;
- }
- /***********************************************************************************************
- * LsMeshBuilder::SetFaces -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/16/99 IML : Created. *
- *=============================================================================================*/
- void LsMeshBuilder::SetFaces (const int facecount, const LtTFace *faces)
- {
- int topcount, f, g;
-
- // Count the number of faces in the top-level hierarchy.
- topcount = 0;
- for (f = 0; f < facecount; f++) {
- topcount++;
- f += faces [f].GetDescendents();
- }
- // If the block allocated for faces is not big enough delete it and allocate a new one.
- if (topcount > AllocatedCount) {
- if (Faces != NULL) delete [] Faces;
- Faces = new LtTFace [topcount];
- ASSERT (Faces != NULL);
- AllocatedCount = topcount;
- }
-
- // Copy the faces in the top-level hierarchy into the block allocated for faces.
- g = 0;
- for (f = 0; f < facecount; f++) {
- Faces [g] = faces [f];
- g++;
- f += faces [f].GetDescendents();
- }
- ASSERT (g == topcount);
- FaceCount = topcount;
- }
- /***********************************************************************************************
- * LsMeshBuilder::GetFaceCount -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/16/99 IML : Created. *
- *=============================================================================================*/
- int LsMeshBuilder::GetFaceCount() const
- {
- return (FaceCount);
- }
- /***********************************************************************************************
- * LsMeshBuilder::GetFaces -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 9/16/99 IML : Created. *
- *=============================================================================================*/
- const LtTFace* LsMeshBuilder::GetFaces() const
- {
- return (Faces);
- }
- /***********************************************************************************************
- * LsMeshBuilder::Finish -- Called by the Lightscape framework after each patch cluster read. *
- * *
- * Called by the Lightscape framework after each patch cluster read from a .ls file. The file *
- * read is initiated by a LtSolutionImport() call. The clustering and the mesh structure is *
- * entirely under the control of Lightscape. Each patch cluster may or may not reference a *
- * texture and may or may not contain a radiosity mesh. If the .ls file has been produced by *
- * Lightscape's 'Mesh to Texture' tool (M2T) with the "Generate Illumination Map" option *
- * enabled then the material definition will (should) reference a lightmap texture. *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/23/99 IML : Created. *
- *=============================================================================================*/
- LtTBool LsMeshBuilder::Finish()
- {
- const char *invalidmappingtext =
- "There is a face in the model with an invalid texture mapping. Please ensure that the\
- Mesh to Texture option called 'Convert each surface to a single texture per surface' was\
- used.";
- const char *notnormalizedtext =
- "There is a vertex in the model with a valid texture mapping but a non-normalized texture\
- coordinate.";
- const char *unmatchedmodeltext =
- "The solve files do not contain the same model information. For any 2 solve files, the first\
- n patches must match, where n is the smallest patch count of the two files.";
- VertexUser usedvertices (*this);
- bool success;
- ASSERT (LightscapeSolve::Importer() != NULL);
-
- // Add the vertices to the Lightscape solve database.
- // If this mesh is an M2T patch...
- if (GetProperties() & LT_MESH_RAWTEXTURE) {
- int vertexindex;
- LtTVector lsv; // Lightscape scratch vertex.
- Vector3 v; // Scratch vertex.
- Vector3 origin, du, dv; // Definition of texture projection.
- Vector2 length; //
- bool normalized;
- LtTUnitVector lsn;
- Vector3 n;
- // Lightscape definition of texture projection.
- LtTTextureProjection lsprojection = GetTextureProjection();
-
- // If the texture mapping is invalid (ie. not orthographic)...
- if ((lsprojection.GetFlags() & LT_PROJECTION_TYPE_MASK) != LT_PROJECTION_ORTHOGRAPHIC) {
- throw (invalidmappingtext);
- }
-
- // Define origin and texture vectors for a planar mapping.
- lsv = lsprojection.GetOrigin();
- origin.Set (lsv.GetX(), lsv.GetY(), lsv.GetZ());
- lsv = lsprojection.GetDu();
- du.Set (lsv.GetX(), lsv.GetY(), lsv.GetZ());
- lsv = lsprojection.GetDv();
- dv.Set (lsv.GetX(), lsv.GetY(), lsv.GetZ());
- // Normalize the texture vectors.
- length.U = du.Length();
- length.V = dv.Length();
- du /= length.U;
- dv /= length.V;
- // Step thru the vertices, calculate UV from the texture projection and add the information
- // to the Lightscape solve database.
- GetPlane (lsn);
- n.Set (lsn.GetX(), lsn.GetY(), lsn.GetZ());
- for (vertexindex = 0; vertexindex < GetVertexCount(); vertexindex++) {
- // Add only if the vertex is referenced by a face.
- if (usedvertices.Is_Used (vertexindex)) {
- LtTPoint lsp = GetVertices() [vertexindex];
-
- Vector3 p (lsp.GetX(), lsp.GetY(), lsp.GetZ());
- Vector2 t;
- v = p - origin;
- t.U = (du * v) / length.U;
- t.V = (dv * v) / length.V;
- // UV's must be normalized (in the range 0..1) in order to reference the lightmap properly.
- normalized = ((t.U >= 0.0f) && (t.U <= 1.0f));
- normalized &= ((t.V >= 0.0f) && (t.V <= 1.0f));
- if (!normalized) throw (notnormalizedtext);
-
- // Assign an index for this vertex which will uniquely identify it in the vertex database.
- usedvertices.Set_Index (vertexindex, FactoryPtr->Vertex_Count());
- // Add the vertex to the database.
- success = LightscapeSolve::Importer()->Add_Vertex (FactoryPtr->Vertex_Count(), p, n, FactoryPtr->Patch_Count(), t);
- if (!success) throw (unmatchedmodeltext);
- // Advance vertex index counter.
- FactoryPtr->Vertex_Increment();
- }
- }
- // Find the texture name that corresponds to the material name and add it for this patch.
- LightscapeSolve::Importer()->Add_Texture_Name (FactoryPtr->Patch_Count(), GetMaterial());
- } else {
- const double filtersharpness = LightscapeSolve::Importer()->Filter_Sharpness();
- ProceduralTexture *blendtexture;
- DynamicVectorClass <FaceVertexStruct> facevertices;
- double *distanceratios;
- int vertexindex;
- int facevertexindex;
- RadianceMap radiancemap (LightscapeSolve::Importer()->Get_Brightness(), LightscapeSolve::Importer()->Get_Contrast(), LightscapeSolve::Importer()->Is_Daylight(), LightscapeSolve::Importer()->Is_Exterior());
- LtTPoint lsp;
- LtTRGBColor irradiance;
- LtTUnitVector lsn;
- Vector3 n;
- blendtexture = LightscapeSolve::Importer()->Procedural_Texture();
- // NOTE: This mesh is not an M2T patch so it must instead contain valid vertex color information.
- // Build an array of face vertices initialized to their respective vertex colors.
- for (vertexindex = 0; vertexindex < GetVertexCount(); vertexindex++) {
- if (usedvertices.Is_Used (vertexindex)) {
- FaceVertexStruct facevertex;
-
- lsp = GetVertices() [vertexindex];
- irradiance = GetIrradiances() [vertexindex];
- facevertex.Point.Set (lsp.GetX(), lsp.GetY(), lsp.GetZ());
- facevertex.Color.Set (irradiance, radiancemap);
-
- // Should the vertex color be blended with a sample from a procedural texture?
- if (blendtexture != NULL) {
- facevertex.Color *= blendtexture->Value (facevertex.Point);
- }
-
- facevertex.Weight = 1.0f;
- facevertices.Add (facevertex);
- }
- }
- // There must be at least one face vertex.
- ASSERT (facevertices.Count() > 0);
- // For every non-face vertex calculate its color contribution to each face vertex.
- distanceratios = new double [facevertices.Count()];
- ASSERT (distanceratios != NULL);
- for (vertexindex = 0; vertexindex < GetVertexCount(); vertexindex++) {
- if (!usedvertices.Is_Used (vertexindex)) {
- Vector3 point;
- ColorVector color;
- double d, s;
- lsp = GetVertices() [vertexindex];
- irradiance = GetIrradiances() [vertexindex];
- point.Set (lsp.GetX(), lsp.GetY(), lsp.GetZ());
- color.Set (irradiance, radiancemap);
- // Should the vertex color be blended with a sample from a procedural texture?
- if (blendtexture != NULL) {
- color *= blendtexture->Value (point);
- }
- d = (point - facevertices [0].Point).Length();
- distanceratios [0] = s = 1.0f;
- for (facevertexindex = 1; facevertexindex < facevertices.Count(); facevertexindex++) {
- distanceratios [facevertexindex] = d / (point - facevertices [facevertexindex].Point).Length();
-
- // Raise the distance ratio to the user specified filter sharpness.
- distanceratios [facevertexindex] = pow (distanceratios [facevertexindex], filtersharpness);
-
- s += distanceratios [facevertexindex];
- }
- for (facevertexindex = 0; facevertexindex < facevertices.Count(); facevertexindex++) {
- float weight;
- weight = distanceratios [facevertexindex] / s;
- facevertices [facevertexindex].Color += color * weight;
- facevertices [facevertexindex].Weight += weight;
- }
- }
- }
- // Add the face vertices to the solve database.
- GetPlane (lsn);
- n.Set (lsn.GetX(), lsn.GetY(), lsn.GetZ());
- facevertexindex = 0;
- for (vertexindex = 0; vertexindex < GetVertexCount(); vertexindex++) {
- if (usedvertices.Is_Used (vertexindex)) {
- ColorVector c = facevertices [facevertexindex].Color;
- c /= facevertices [facevertexindex].Weight;
-
- // Assign an index for this vertex which will uniquely identify it in the vertex database.
- usedvertices.Set_Index (vertexindex, FactoryPtr->Vertex_Count());
-
- // Add the vertex to the database.
- success = LightscapeSolve::Importer()->Add_Vertex (FactoryPtr->Vertex_Count(), facevertices [facevertexindex].Point, n, FactoryPtr->Patch_Count(), c);
- if (!success) {
- delete [] distanceratios;
- throw (unmatchedmodeltext);
- }
- // Advance the vertex index counters.
- FactoryPtr->Vertex_Increment();
- facevertexindex++;
- }
- }
-
- // Clean-up.
- delete [] distanceratios;
- }
- // Add the faces to the Lightscape solve database.
- for (int faceindex = 0; faceindex < GetFaceCount(); faceindex++) {
- const unsigned facevertexindexcount = 4;
- LtTFace face;
- int vertexindex, facevertexcount;
- unsigned facevertexindices [facevertexindexcount];
- ASSERT (faceindex >= 0 && faceindex < GetFaceCount());
- face = GetFaces() [faceindex];
- // If the face is not a triangle then it must be a quadrilateral. It is safe to assume
- // that these are the only polygon types that Lightscape supports.
- facevertexcount = face.IsTriangle() ? 3 : 4;
- for (int v = 0; v < facevertexcount; v++) {
- vertexindex = face.GetVert (v);
- ASSERT (vertexindex >= 0 && vertexindex < GetVertexCount());
- facevertexindices [v] = usedvertices.Get_Index (vertexindex);
- }
-
- success = LightscapeSolve::Importer()->Add_Patch_Face (FactoryPtr->Patch_Face_Count(), FactoryPtr->Patch_Count(), facevertexcount, facevertexindices);
- if (!success) throw (unmatchedmodeltext);
- // Advance patch face counter.
- FactoryPtr->Patch_Face_Increment();
- }
- // Advance the patch index counter.
- FactoryPtr->Patch_Increment();
- // Return success.
- return (TRUE);
- }
- /***********************************************************************************************
- * VertexUser::VertexUser -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/05/00 IML : Created. *
- *=============================================================================================*/
- VertexUser::VertexUser (const LsMeshBuilder &meshbuilder)
- {
- LtTFace face;
- unsigned v, vertexindex, facevertexcount;
- Count = meshbuilder.GetVertexCount();
- UsedVertexIndices = new int [Count];
- ASSERT (UsedVertexIndices != NULL);
- // Initialize. All vertices unused.
- for (v = 0; v < Count; v++) {
- UsedVertexIndices [v] = UNUSED;
- }
- // For each face...
- for (int faceindex = 0; faceindex < meshbuilder.GetFaceCount(); faceindex++) {
- face = meshbuilder.GetFaces() [faceindex];
- // If the face is not a triangle then it must be a quadrilateral. It is safe to assume
- // that these are the only polygon types that Lightscape supports.
- facevertexcount = face.IsTriangle() ? 3 : 4;
- // For each vertex in the face, flag that the vertex is referenced by a face.
- for (v = 0; v < facevertexcount; v++) {
- vertexindex = face.GetVert (v);
- ASSERT (vertexindex >= 0 && vertexindex < Count);
- UsedVertexIndices [vertexindex] = USED;
- }
- }
- }
- /***********************************************************************************************
- * LightscapeMeshSolve::LightscapeMeshSolve -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/30/99 IML : Created. *
- *=============================================================================================*/
- LightscapeMeshSolve::LightscapeMeshSolve (LightscapeSolve &solve, ChunkClass &trianglechunk, ChunkClass &vertexchunk)
- : Statistics (vertexchunk.Get_Size() / sizeof (W3dVectorStruct), trianglechunk.Get_Size() / sizeof (W3dTriStruct))
- {
- const unsigned verticesperface = 3; // No. of vertices in a triangle.
- PackingTriangle *triangles;
- W3dTriStruct *w3dfaces;
- W3dVectorStruct *w3dvertices;
- unsigned f, v;
- // Calculate no. of faces and face-vertices from triangle chunk.
- VertexCount = vertexchunk.Get_Size() / sizeof (W3dVectorStruct);
- FaceCount = trianglechunk.Get_Size() / sizeof (W3dTriStruct);
- FaceVertexCount = FaceCount * verticesperface;
- // Allocate data tables for this mesh.
- VertexColors = new W3dRGBStruct [VertexCount];
- ASSERT (VertexColors != NULL);
- FaceVertexUVs = new Vector2 [FaceVertexCount];
- ASSERT (FaceVertexUVs != NULL);
- FaceRemapLightmapIndices = new unsigned [FaceCount];
- ASSERT (FaceRemapLightmapIndices != NULL);
- LightmapIndices = new unsigned [FaceCount];
- ASSERT (LightmapIndices != NULL);
- triangles = new PackingTriangle [FaceCount];
- ASSERT (triangles != NULL);
- w3dfaces = (W3dTriStruct*) trianglechunk.Get_Data();
- ASSERT (w3dfaces != NULL);
- w3dvertices = (W3dVectorStruct*) vertexchunk.Get_Data();
- ASSERT (w3dvertices != NULL);
- // For each vertex in the vertex chunk...
- for (unsigned vertexindex = 0; vertexindex < VertexCount; vertexindex++) {
- const Vector3 zero (0.0f, 0.0f, 0.0f);
- Vector3 *smoothingnormalptr;
- Vector3 point;
- W3dVectorStruct *w3dvertexptr;
- W3dRGBStruct vertexcolor;
- // Iterate over the faces and calculate a smoothing normal for this vertex based on
- // the faces that reference this vertex.
- smoothingnormalptr = NULL;
- for (f = 0; f < FaceCount; f++) {
- for (v = 0; v < verticesperface; v++) {
- if (w3dfaces [f].Vindex [v] == vertexindex) {
-
- Vector3 facenormal;
- // Do not consider face normals that are zero (face is degenerate).
- facenormal.Set (w3dfaces [f].Normal.X, w3dfaces [f].Normal.Y, w3dfaces [f].Normal.Z);
- if (facenormal != zero) smoothingnormalptr = &facenormal;
- break;
- }
- }
- if (smoothingnormalptr != NULL) break;
- }
-
- w3dvertexptr = w3dvertices + vertexindex;
- point.Set (w3dvertexptr->X, w3dvertexptr->Y, w3dvertexptr->Z);
-
- solve.Find_Vertex (point, smoothingnormalptr, vertexcolor, Statistics);
- VertexColors [vertexindex] = vertexcolor;
- }
- // For each face in the w3d triangle chunk, match it up with a face in the Lightscape solve database.
- for (f = 0; f < FaceCount; f++) {
- Vector3 points [verticesperface];
- Vector3 facenormal;
- Vector2 uvs [verticesperface];
- PackingTriangle triangle;
- // Extract points and face normal from vertex chunk.
- for (v = 0; v < verticesperface; v++) {
- W3dVectorStruct *w3dvertexptr;
- unsigned vindex;
-
- vindex = w3dfaces [f].Vindex [v];
- w3dvertexptr = w3dvertices + vindex;
- points [v].Set (w3dvertexptr->X, w3dvertexptr->Y, w3dvertexptr->Z);
- }
- facenormal.Set (w3dfaces [f].Normal.X, w3dfaces [f].Normal.Y, w3dfaces [f].Normal.Z);
- solve.Find_Triangle (points, facenormal, triangles [f], Statistics);
- }
- if (Statistics.Valid_Lightmap_Solve()) {
-
- unsigned lightmapindex, remaplightmapindex;
- bool found;
- // Submit the triangles for packing.
- for (f = 0; f < FaceCount; f++) {
- solve.Submit_Triangle (triangles [f]);
- }
- // Now pack.
- solve.Pack();
- // Extract the lightmap UV's from the triangles.
- v = 0;
- for (f = 0; f < FaceCount; f++) {
- FaceVertexUVs [v + 0] = triangles [f].PackedUVs [0];
- FaceVertexUVs [v + 1] = triangles [f].PackedUVs [1];
- FaceVertexUVs [v + 2] = triangles [f].PackedUVs [2];
- v += verticesperface;
- }
- // The face-lightmap indices are currently non-zero based, unordered, non-contiguous indices
- // ie. an unknown list of indexes that have been returned from the packing process.
- // The mesh requires face-lightmap indices that are zero-based, ordered, contiguous indices
- // so remap the indices to create face-remaplightmap indices. Also, create a table of 'real'
- // lightmap indices that will be indexed by the face-remaplightmap table.
- remaplightmapindex = 0;
- for (f = 0; f < FaceCount; f++) {
- int g;
- lightmapindex = triangles [f].PackedTextureID;
- // Look backwards thru the face-lightmap table to see if this index has already occured?
- found = false;
- g = ((int) f) - 1;
- while (g >= 0) {
- if (triangles [g].PackedTextureID == lightmapindex) {
- found = true;
- break;
- }
- g--;
- }
- // Was the index found?
- if (found) {
- FaceRemapLightmapIndices [f] = FaceRemapLightmapIndices [g];
- } else {
- FaceRemapLightmapIndices [f] = remaplightmapindex;
- ASSERT (remaplightmapindex < FaceCount);
- LightmapIndices [remaplightmapindex] = lightmapindex;
- remaplightmapindex++;
- }
- }
-
- ASSERT (remaplightmapindex > 0);
- LightmapCount = remaplightmapindex;
- } else {
- LightmapCount = 0;
- }
- // Clean-up.
- delete [] triangles;
- }
- /***********************************************************************************************
- * LightscapeMeshSolve::~LightscapeMeshSolve -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/30/99 IML : Created. *
- *=============================================================================================*/
- LightscapeMeshSolve::~LightscapeMeshSolve()
- {
- // Clean-up.
- delete [] VertexColors;
- delete [] LightmapIndices;
- delete [] FaceRemapLightmapIndices;
- delete [] FaceVertexUVs;
- }
- /***********************************************************************************************
- * LightscapeMeshSolve::Vertex_Color -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 1/06/00 IML : Created. *
- *=============================================================================================*/
- W3dRGBStruct LightscapeMeshSolve::Vertex_Color (unsigned vertexindex) const
- {
- ASSERT (Statistics.Valid_Vertex_Solve());
- ASSERT (vertexindex < VertexCount);
- return (VertexColors [vertexindex]);
- }
- /***********************************************************************************************
- * LightscapeMeshSolve::LightscapeMeshSolve -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/30/99 IML : Created. *
- *=============================================================================================*/
- const char *LightscapeMeshSolve::Lightmap_Pathname (unsigned lightmapindex) const
- {
- ASSERT (Statistics.Valid_Lightmap_Solve());
- ASSERT (lightmapindex < FaceCount);
- return (LightscapeSolve::Lightmap_Pathname (LightmapIndices [lightmapindex]));
- }
- /***********************************************************************************************
- * LightscapeMeshSolve::LightscapeMeshSolve -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/30/99 IML : Created. *
- *=============================================================================================*/
- unsigned LightscapeMeshSolve::Lightmap_Index (unsigned faceindex) const
- {
- ASSERT (Statistics.Valid_Lightmap_Solve());
- ASSERT (faceindex < FaceCount);
- return (FaceRemapLightmapIndices [faceindex]);
- }
- /***********************************************************************************************
- * LightscapeMeshSolve::LightscapeMeshSolve -- *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 7/30/99 IML : Created. *
- *=============================================================================================*/
- W3dTexCoordStruct LightscapeMeshSolve::Lightmap_UV (unsigned facevertexindex) const
- {
- W3dTexCoordStruct w3duv;
-
- ASSERT (Statistics.Valid_Lightmap_Solve());
- ASSERT (facevertexindex < FaceVertexCount);
-
- w3duv.U = FaceVertexUVs [facevertexindex].U;
- w3duv.V = FaceVertexUVs [facevertexindex].V;
- return (w3duv);
- }
|