12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code 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.
- Doom 3 BFG Edition Source Code 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 Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../idlib/precompiled.h"
- #include "tr_local.h"
- #include "Model_local.h"
- #include "Model_ase.h"
- #include "Model_lwo.h"
- #include "Model_ma.h"
- idCVar idRenderModelStatic::r_mergeModelSurfaces( "r_mergeModelSurfaces", "1", CVAR_BOOL|CVAR_RENDERER, "combine model surfaces with the same material" );
- idCVar idRenderModelStatic::r_slopVertex( "r_slopVertex", "0.01", CVAR_RENDERER, "merge xyz coordinates this far apart" );
- idCVar idRenderModelStatic::r_slopTexCoord( "r_slopTexCoord", "0.001", CVAR_RENDERER, "merge texture coordinates this far apart" );
- idCVar idRenderModelStatic::r_slopNormal( "r_slopNormal", "0.02", CVAR_RENDERER, "merge normals that dot less than this" );
- static const byte BRM_VERSION = 108;
- static const unsigned int BRM_MAGIC = ( 'B' << 24 ) | ( 'R' << 16 ) | ( 'M' << 8 ) | BRM_VERSION;
- /*
- ================
- idRenderModelStatic::idRenderModelStatic
- ================
- */
- idRenderModelStatic::idRenderModelStatic() {
- name = "<undefined>";
- bounds.Clear();
- lastModifiedFrame = 0;
- lastArchivedFrame = 0;
- overlaysAdded = 0;
- isStaticWorldModel = false;
- defaulted = false;
- purged = false;
- fastLoad = false;
- reloadable = true;
- levelLoadReferenced = false;
- hasDrawingSurfaces = true;
- hasInteractingSurfaces = true;
- hasShadowCastingSurfaces = true;
- timeStamp = 0;
- numInvertedJoints = 0;
- jointsInverted = NULL;
- jointsInvertedBuffer = 0;
- }
- /*
- ================
- idRenderModelStatic::~idRenderModelStatic
- ================
- */
- idRenderModelStatic::~idRenderModelStatic() {
- PurgeModel();
- }
- /*
- ==============
- idRenderModelStatic::Print
- ==============
- */
- void idRenderModelStatic::Print() const {
- common->Printf( "%s\n", name.c_str() );
- common->Printf( "Static model.\n" );
- common->Printf( "bounds: (%f %f %f) to (%f %f %f)\n",
- bounds[0][0], bounds[0][1], bounds[0][2],
- bounds[1][0], bounds[1][1], bounds[1][2] );
- common->Printf( " verts tris material\n" );
- for ( int i = 0; i < NumSurfaces(); i++ ) {
- const modelSurface_t *surf = Surface( i );
- srfTriangles_t *tri = surf->geometry;
- const idMaterial *material = surf->shader;
-
- if ( !tri ) {
- common->Printf( "%2i: %s, NULL surface geometry\n", i, material->GetName() );
- continue;
- }
- common->Printf( "%2i: %5i %5i %s", i, tri->numVerts, tri->numIndexes / 3, material->GetName() );
- if ( tri->generateNormals ) {
- common->Printf( " (smoothed)\n" );
- } else {
- common->Printf( "\n" );
- }
- }
- }
- /*
- ==============
- idRenderModelStatic::Memory
- ==============
- */
- int idRenderModelStatic::Memory() const {
- int totalBytes = 0;
- totalBytes += sizeof( *this );
- totalBytes += name.DynamicMemoryUsed();
- totalBytes += surfaces.MemoryUsed();
- for ( int j = 0; j < NumSurfaces(); j++ ) {
- const modelSurface_t *surf = Surface( j );
- if ( !surf->geometry ) {
- continue;
- }
- totalBytes += R_TriSurfMemory( surf->geometry );
- }
- return totalBytes;
- }
- /*
- ==============
- idRenderModelStatic::List
- ==============
- */
- void idRenderModelStatic::List() const {
- int totalTris = 0;
- int totalVerts = 0;
- int totalBytes = 0;
- totalBytes = Memory();
- char closed = 'C';
- for ( int j = 0; j < NumSurfaces(); j++ ) {
- const modelSurface_t *surf = Surface( j );
- if ( !surf->geometry ) {
- continue;
- }
- if ( !surf->geometry->perfectHull ) {
- closed = ' ';
- }
- totalTris += surf->geometry->numIndexes / 3;
- totalVerts += surf->geometry->numVerts;
- }
- common->Printf( "%c%4ik %3i %4i %4i %s", closed, totalBytes/1024, NumSurfaces(), totalVerts, totalTris, Name() );
- if ( IsDynamicModel() == DM_CACHED ) {
- common->Printf( " (DM_CACHED)" );
- }
- if ( IsDynamicModel() == DM_CONTINUOUS ) {
- common->Printf( " (DM_CONTINUOUS)" );
- }
- if ( defaulted ) {
- common->Printf( " (DEFAULTED)" );
- }
- if ( bounds[0][0] >= bounds[1][0] ) {
- common->Printf( " (EMPTY BOUNDS)" );
- }
- if ( bounds[1][0] - bounds[0][0] > 100000 ) {
- common->Printf( " (HUGE BOUNDS)" );
- }
- common->Printf( "\n" );
- }
- /*
- ================
- idRenderModelStatic::IsDefaultModel
- ================
- */
- bool idRenderModelStatic::IsDefaultModel() const {
- return defaulted;
- }
- /*
- ================
- AddCubeFace
- ================
- */
- static void AddCubeFace( srfTriangles_t *tri, idVec3 v1, idVec3 v2, idVec3 v3, idVec3 v4 ) {
- tri->verts[tri->numVerts+0].Clear();
- tri->verts[tri->numVerts+0].xyz = v1 * 8;
- tri->verts[tri->numVerts+0].SetTexCoord( 0, 0 );
- tri->verts[tri->numVerts+1].Clear();
- tri->verts[tri->numVerts+1].xyz = v2 * 8;
- tri->verts[tri->numVerts+1].SetTexCoord( 1, 0 );
- tri->verts[tri->numVerts+2].Clear();
- tri->verts[tri->numVerts+2].xyz = v3 * 8;
- tri->verts[tri->numVerts+2].SetTexCoord( 1, 1 );
- tri->verts[tri->numVerts+3].Clear();
- tri->verts[tri->numVerts+3].xyz = v4 * 8;
- tri->verts[tri->numVerts+3].SetTexCoord( 0, 1 );
- tri->indexes[tri->numIndexes+0] = tri->numVerts + 0;
- tri->indexes[tri->numIndexes+1] = tri->numVerts + 1;
- tri->indexes[tri->numIndexes+2] = tri->numVerts + 2;
- tri->indexes[tri->numIndexes+3] = tri->numVerts + 0;
- tri->indexes[tri->numIndexes+4] = tri->numVerts + 2;
- tri->indexes[tri->numIndexes+5] = tri->numVerts + 3;
- tri->numVerts += 4;
- tri->numIndexes += 6;
- }
- /*
- ================
- idRenderModelStatic::MakeDefaultModel
- ================
- */
- void idRenderModelStatic::MakeDefaultModel() {
- defaulted = true;
- // throw out any surfaces we already have
- PurgeModel();
- // create one new surface
- modelSurface_t surf;
- srfTriangles_t *tri = R_AllocStaticTriSurf();
- surf.shader = tr.defaultMaterial;
- surf.geometry = tri;
- R_AllocStaticTriSurfVerts( tri, 24 );
- R_AllocStaticTriSurfIndexes( tri, 36 );
- AddCubeFace( tri, idVec3(-1, 1, 1), idVec3(1, 1, 1), idVec3(1, -1, 1), idVec3(-1, -1, 1) );
- AddCubeFace( tri, idVec3(-1, 1, -1), idVec3(-1, -1, -1), idVec3(1, -1, -1), idVec3(1, 1, -1) );
- AddCubeFace( tri, idVec3(1, -1, 1), idVec3(1, 1, 1), idVec3(1, 1, -1), idVec3(1, -1, -1) );
- AddCubeFace( tri, idVec3(-1, -1, 1), idVec3(-1, -1, -1), idVec3(-1, 1, -1), idVec3(-1, 1, 1) );
- AddCubeFace( tri, idVec3(-1, -1, 1), idVec3(1, -1, 1), idVec3(1, -1, -1), idVec3(-1, -1, -1) );
- AddCubeFace( tri, idVec3(-1, 1, 1), idVec3(-1, 1, -1), idVec3(1, 1, -1), idVec3(1, 1, 1) );
- tri->generateNormals = true;
- AddSurface( surf );
- FinishSurfaces();
- }
- /*
- ================
- idRenderModelStatic::PartialInitFromFile
- ================
- */
- void idRenderModelStatic::PartialInitFromFile( const char *fileName ) {
- fastLoad = true;
- InitFromFile( fileName );
- }
- /*
- ================
- idRenderModelStatic::InitFromFile
- ================
- */
- void idRenderModelStatic::InitFromFile( const char *fileName ) {
- bool loaded;
- idStr extension;
- InitEmpty( fileName );
- // FIXME: load new .proc map format
- name.ExtractFileExtension( extension );
- if ( extension.Icmp( "ase" ) == 0 ) {
- loaded = LoadASE( name );
- reloadable = true;
- } else if ( extension.Icmp( "lwo" ) == 0 ) {
- loaded = LoadLWO( name );
- reloadable = true;
- } else if ( extension.Icmp( "ma" ) == 0 ) {
- loaded = LoadMA( name );
- reloadable = true;
- } else {
- common->Warning( "idRenderModelStatic::InitFromFile: unknown type for model: \'%s\'", name.c_str() );
- loaded = false;
- }
- if ( !loaded ) {
- common->Warning( "Couldn't load model: '%s'", name.c_str() );
- MakeDefaultModel();
- return;
- }
- // it is now available for use
- purged = false;
- // create the bounds for culling and dynamic surface creation
- FinishSurfaces();
- }
- /*
- ========================
- idRenderModelStatic::LoadBinaryModel
- ========================
- */
- bool idRenderModelStatic::LoadBinaryModel( idFile * file, const ID_TIME_T sourceTimeStamp ) {
- if ( file == NULL ) {
- return false;
- }
- unsigned int magic = 0;
- file->ReadBig( magic );
- if ( magic != BRM_MAGIC ) {
- return false;
- }
-
- file->ReadBig( timeStamp );
- if ( !fileSystem->InProductionMode() && sourceTimeStamp != timeStamp ) {
- return false;
- }
- common->UpdateLevelLoadPacifier();
- int numSurfaces;
- file->ReadBig( numSurfaces );
- surfaces.SetNum( numSurfaces );
- for ( int i = 0; i < surfaces.Num(); i++ ) {
- file->ReadBig( surfaces[i].id );
- idStr materialName;
- file->ReadString( materialName );
- if ( materialName.IsEmpty() ) {
- surfaces[i].shader = NULL;
- } else {
- surfaces[i].shader = declManager->FindMaterial( materialName );
- }
- bool isGeometry;
- file->ReadBig( isGeometry );
- surfaces[i].geometry = NULL;
- if ( isGeometry ) {
- bool temp;
- surfaces[i].geometry = R_AllocStaticTriSurf();
-
- // Read the contents of srfTriangles_t
- srfTriangles_t & tri = *surfaces[i].geometry;
- file->ReadVec3( tri.bounds[0] );
- file->ReadVec3( tri.bounds[1] );
- int ambientViewCount = 0; // FIXME: remove
- file->ReadBig( ambientViewCount );
- file->ReadBig( tri.generateNormals );
- file->ReadBig( tri.tangentsCalculated );
- file->ReadBig( tri.perfectHull );
- file->ReadBig( tri.referencedIndexes );
- file->ReadBig( tri.numVerts );
- tri.verts = NULL;
- int numInFile = 0;
- file->ReadBig( numInFile );
- if ( numInFile > 0 ) {
- R_AllocStaticTriSurfVerts( &tri, tri.numVerts );
- assert( tri.verts != NULL );
- for ( int j = 0; j < tri.numVerts; j++ ) {
- file->ReadVec3( tri.verts[j].xyz );
- file->ReadBigArray( tri.verts[j].st, 2 );
- file->ReadBigArray( tri.verts[j].normal, 4 );
- file->ReadBigArray( tri.verts[j].tangent, 4 );
- file->ReadBigArray( tri.verts[j].color, sizeof( tri.verts[j].color ) / sizeof( tri.verts[j].color[0] ) );
- file->ReadBigArray( tri.verts[j].color2, sizeof( tri.verts[j].color2 ) / sizeof( tri.verts[j].color2[0] ) );
- }
- }
- file->ReadBig( numInFile );
- if ( numInFile == 0 ) {
- tri.preLightShadowVertexes = NULL;
- } else {
- R_AllocStaticTriSurfPreLightShadowVerts( &tri, numInFile );
- for ( int j = 0; j < numInFile; j++ ) {
- file->ReadVec4( tri.preLightShadowVertexes[ j ].xyzw );
- }
- }
- file->ReadBig( tri.numIndexes );
- tri.indexes = NULL;
- tri.silIndexes = NULL;
- if ( tri.numIndexes > 0 ) {
- R_AllocStaticTriSurfIndexes( &tri, tri.numIndexes );
- file->ReadBigArray( tri.indexes, tri.numIndexes );
- }
- file->ReadBig( numInFile );
- if ( numInFile > 0 ) {
- R_AllocStaticTriSurfSilIndexes( &tri, tri.numIndexes );
- file->ReadBigArray( tri.silIndexes, tri.numIndexes );
- }
- file->ReadBig( tri.numMirroredVerts );
- tri.mirroredVerts = NULL;
- if ( tri.numMirroredVerts > 0 ) {
- R_AllocStaticTriSurfMirroredVerts( &tri, tri.numMirroredVerts );
- file->ReadBigArray( tri.mirroredVerts, tri.numMirroredVerts );
- }
- file->ReadBig( tri.numDupVerts );
- tri.dupVerts = NULL;
- if ( tri.numDupVerts > 0 ) {
- R_AllocStaticTriSurfDupVerts( &tri, tri.numDupVerts );
- file->ReadBigArray( tri.dupVerts, tri.numDupVerts * 2 );
- }
- file->ReadBig( tri.numSilEdges );
- tri.silEdges = NULL;
- if ( tri.numSilEdges > 0 ) {
- R_AllocStaticTriSurfSilEdges( &tri, tri.numSilEdges );
- assert( tri.silEdges != NULL );
- for ( int j = 0; j < tri.numSilEdges; j++ ) {
- file->ReadBig( tri.silEdges[j].p1 );
- file->ReadBig( tri.silEdges[j].p2 );
- file->ReadBig( tri.silEdges[j].v1 );
- file->ReadBig( tri.silEdges[j].v2 );
- }
- }
- file->ReadBig( temp );
- tri.dominantTris = NULL;
- if ( temp ) {
- R_AllocStaticTriSurfDominantTris( &tri, tri.numVerts );
- assert( tri.dominantTris != NULL );
- for ( int j = 0; j < tri.numVerts; j++ ) {
- file->ReadBig( tri.dominantTris[j].v2 );
- file->ReadBig( tri.dominantTris[j].v3 );
- file->ReadFloat( tri.dominantTris[j].normalizationScale[0] );
- file->ReadFloat( tri.dominantTris[j].normalizationScale[1] );
- file->ReadFloat( tri.dominantTris[j].normalizationScale[2] );
- }
- }
- file->ReadBig( tri.numShadowIndexesNoFrontCaps );
- file->ReadBig( tri.numShadowIndexesNoCaps );
- file->ReadBig( tri.shadowCapPlaneBits );
- tri.ambientSurface = NULL;
- tri.nextDeferredFree = NULL;
- tri.indexCache = 0;
- tri.ambientCache = 0;
- tri.shadowCache = 0;
- }
- }
- file->ReadVec3( bounds[0] );
- file->ReadVec3( bounds[1] );
- file->ReadBig( overlaysAdded );
- file->ReadBig( lastModifiedFrame );
- file->ReadBig( lastArchivedFrame );
- file->ReadString( name );
- file->ReadBig( isStaticWorldModel );
- file->ReadBig( defaulted );
- file->ReadBig( purged );
- file->ReadBig( fastLoad );
- file->ReadBig( reloadable );
- file->ReadBig( levelLoadReferenced ); // should this actually be saved/loaded?
- file->ReadBig( hasDrawingSurfaces );
- file->ReadBig( hasInteractingSurfaces );
- file->ReadBig( hasShadowCastingSurfaces );
- return true;
- }
- /*
- ========================
- idRenderModelStatic::WriteBinaryModel
- ========================
- */
- void idRenderModelStatic::WriteBinaryModel( idFile * file, ID_TIME_T *_timeStamp ) const {
- if ( file == NULL ) {
- common->Printf( "Failed to WriteBinaryModel\n" );
- return;
- }
-
- file->WriteBig( BRM_MAGIC );
- if ( _timeStamp != NULL ) {
- file->WriteBig( *_timeStamp );
- } else {
- file->WriteBig( timeStamp );
- }
- file->WriteBig( surfaces.Num() );
- for ( int i = 0; i < surfaces.Num(); i++ ) {
- file->WriteBig( surfaces[i].id );
- if ( surfaces[i].shader != NULL && surfaces[i].shader->GetName() != NULL ) {
- file->WriteString( surfaces[i].shader->GetName() );
- } else {
- file->WriteString( "" );
- }
- file->WriteBig( surfaces[i].geometry != NULL );
- if ( surfaces[i].geometry != NULL ) {
- srfTriangles_t & tri = *surfaces[i].geometry;
- file->WriteVec3( tri.bounds[0] );
- file->WriteVec3( tri.bounds[1] );
- int ambientViewCount = 0; // FIXME: remove
- file->WriteBig( ambientViewCount );
- file->WriteBig( tri.generateNormals );
- file->WriteBig( tri.tangentsCalculated );
- file->WriteBig( tri.perfectHull );
- file->WriteBig( tri.referencedIndexes );
- // shadow models use numVerts but have no verts
- file->WriteBig( tri.numVerts );
- if ( tri.verts != NULL ) {
- file->WriteBig( tri.numVerts );
- } else {
- file->WriteBig( ( int ) 0 );
- }
- if ( tri.numVerts > 0 && tri.verts != NULL ) {
- for ( int j = 0; j < tri.numVerts; j++ ) {
- file->WriteVec3( tri.verts[j].xyz );
- file->WriteBigArray( tri.verts[j].st, 2 );
- file->WriteBigArray( tri.verts[j].normal, 4 );
- file->WriteBigArray( tri.verts[j].tangent, 4 );
- file->WriteBigArray( tri.verts[j].color, sizeof( tri.verts[j].color ) / sizeof( tri.verts[j].color[0] ) );
- file->WriteBigArray( tri.verts[j].color2, sizeof( tri.verts[j].color2 ) / sizeof( tri.verts[j].color2[0] ) );
- }
- }
- if ( tri.preLightShadowVertexes != NULL ) {
- file->WriteBig( tri.numVerts * 2 );
- for ( int j = 0; j < tri.numVerts * 2; j++ ) {
- file->WriteVec4( tri.preLightShadowVertexes[ j ].xyzw );
- }
- } else {
- file->WriteBig( ( int ) 0 );
- }
- file->WriteBig( tri.numIndexes );
- if ( tri.numIndexes > 0 ) {
- file->WriteBigArray( tri.indexes, tri.numIndexes );
- }
- if ( tri.silIndexes != NULL ) {
- file->WriteBig( tri.numIndexes );
- } else {
- file->WriteBig( ( int ) 0 );
- }
- if ( tri.numIndexes > 0 && tri.silIndexes != NULL ) {
- file->WriteBigArray( tri.silIndexes, tri.numIndexes );
- }
- file->WriteBig( tri.numMirroredVerts );
- if ( tri.numMirroredVerts > 0 ) {
- file->WriteBigArray( tri.mirroredVerts, tri.numMirroredVerts );
- }
- file->WriteBig( tri.numDupVerts );
- if ( tri.numDupVerts > 0 ) {
- file->WriteBigArray( tri.dupVerts, tri.numDupVerts * 2 );
- }
- file->WriteBig( tri.numSilEdges );
- if ( tri.numSilEdges > 0 ) {
- for ( int j = 0; j < tri.numSilEdges; j++ ) {
- file->WriteBig( tri.silEdges[j].p1 );
- file->WriteBig( tri.silEdges[j].p2 );
- file->WriteBig( tri.silEdges[j].v1 );
- file->WriteBig( tri.silEdges[j].v2 );
- }
- }
- file->WriteBig( tri.dominantTris != NULL );
- if ( tri.dominantTris != NULL ) {
- for ( int j = 0; j < tri.numVerts; j++ ) {
- file->WriteBig( tri.dominantTris[j].v2 );
- file->WriteBig( tri.dominantTris[j].v3 );
- file->WriteFloat( tri.dominantTris[j].normalizationScale[0] );
- file->WriteFloat( tri.dominantTris[j].normalizationScale[1] );
- file->WriteFloat( tri.dominantTris[j].normalizationScale[2] );
- }
- }
- file->WriteBig( tri.numShadowIndexesNoFrontCaps );
- file->WriteBig( tri.numShadowIndexesNoCaps );
- file->WriteBig( tri.shadowCapPlaneBits );
- }
- }
- file->WriteVec3( bounds[0] );
- file->WriteVec3( bounds[1] );
- file->WriteBig( overlaysAdded );
- file->WriteBig( lastModifiedFrame );
- file->WriteBig( lastArchivedFrame );
- file->WriteString( name );
- // shadowHull
- file->WriteBig( isStaticWorldModel );
- file->WriteBig( defaulted );
- file->WriteBig( purged );
- file->WriteBig( fastLoad );
- file->WriteBig( reloadable );
- file->WriteBig( levelLoadReferenced );
- file->WriteBig( hasDrawingSurfaces );
- file->WriteBig( hasInteractingSurfaces );
- file->WriteBig( hasShadowCastingSurfaces );
- }
- /*
- ================
- idRenderModelStatic::LoadModel
- ================
- */
- void idRenderModelStatic::LoadModel() {
- PurgeModel();
- InitFromFile( name );
- }
- /*
- ================
- idRenderModelStatic::InitEmpty
- ================
- */
- void idRenderModelStatic::InitEmpty( const char *fileName ) {
- // model names of the form _area* are static parts of the
- // world, and have already been considered for optimized shadows
- // other model names are inline entity models, and need to be
- // shadowed normally
- if ( !idStr::Cmpn( fileName, "_area", 5 ) ) {
- isStaticWorldModel = true;
- } else {
- isStaticWorldModel = false;
- }
- name = fileName;
- reloadable = false; // if it didn't come from a file, we can't reload it
- PurgeModel();
- purged = false;
- bounds.Zero();
- }
- /*
- ================
- idRenderModelStatic::AddSurface
- ================
- */
- void idRenderModelStatic::AddSurface( modelSurface_t surface ) {
- surfaces.Append( surface );
- if ( surface.geometry ) {
- bounds += surface.geometry->bounds;
- }
- }
- /*
- ================
- idRenderModelStatic::Name
- ================
- */
- const char *idRenderModelStatic::Name() const {
- return name;
- }
- /*
- ================
- idRenderModelStatic::Timestamp
- ================
- */
- ID_TIME_T idRenderModelStatic::Timestamp() const {
- return timeStamp;
- }
- /*
- ================
- idRenderModelStatic::NumSurfaces
- ================
- */
- int idRenderModelStatic::NumSurfaces() const {
- return surfaces.Num();
- }
- /*
- ================
- idRenderModelStatic::NumBaseSurfaces
- ================
- */
- int idRenderModelStatic::NumBaseSurfaces() const {
- return surfaces.Num() - overlaysAdded;
- }
- /*
- ================
- idRenderModelStatic::Surface
- ================
- */
- const modelSurface_t *idRenderModelStatic::Surface( int surfaceNum ) const {
- return &surfaces[surfaceNum];
- }
- /*
- ================
- idRenderModelStatic::AllocSurfaceTriangles
- ================
- */
- srfTriangles_t *idRenderModelStatic::AllocSurfaceTriangles( int numVerts, int numIndexes ) const {
- srfTriangles_t *tri = R_AllocStaticTriSurf();
- R_AllocStaticTriSurfVerts( tri, numVerts );
- R_AllocStaticTriSurfIndexes( tri, numIndexes );
- return tri;
- }
- /*
- ================
- idRenderModelStatic::FreeSurfaceTriangles
- ================
- */
- void idRenderModelStatic::FreeSurfaceTriangles( srfTriangles_t *tris ) const {
- R_FreeStaticTriSurf( tris );
- }
- /*
- ================
- idRenderModelStatic::IsStaticWorldModel
- ================
- */
- bool idRenderModelStatic::IsStaticWorldModel() const {
- return isStaticWorldModel;
- }
- /*
- ================
- idRenderModelStatic::IsDynamicModel
- ================
- */
- dynamicModel_t idRenderModelStatic::IsDynamicModel() const {
- // dynamic subclasses will override this
- return DM_STATIC;
- }
- /*
- ================
- idRenderModelStatic::IsReloadable
- ================
- */
- bool idRenderModelStatic::IsReloadable() const {
- return reloadable;
- }
- /*
- ================
- idRenderModelStatic::Bounds
- ================
- */
- idBounds idRenderModelStatic::Bounds( const struct renderEntity_s *mdef ) const {
- return bounds;
- }
- /*
- ================
- idRenderModelStatic::DepthHack
- ================
- */
- float idRenderModelStatic::DepthHack() const {
- return 0.0f;
- }
- /*
- ================
- idRenderModelStatic::InstantiateDynamicModel
- ================
- */
- idRenderModel *idRenderModelStatic::InstantiateDynamicModel( const struct renderEntity_s *ent, const viewDef_t *view, idRenderModel *cachedModel ) {
- if ( cachedModel ) {
- delete cachedModel;
- cachedModel = NULL;
- }
- common->Error( "InstantiateDynamicModel called on static model '%s'", name.c_str() );
- return NULL;
- }
- /*
- ================
- idRenderModelStatic::NumJoints
- ================
- */
- int idRenderModelStatic::NumJoints() const {
- return 0;
- }
- /*
- ================
- idRenderModelStatic::GetJoints
- ================
- */
- const idMD5Joint *idRenderModelStatic::GetJoints() const {
- return NULL;
- }
- /*
- ================
- idRenderModelStatic::GetJointHandle
- ================
- */
- jointHandle_t idRenderModelStatic::GetJointHandle( const char *name ) const {
- return INVALID_JOINT;
- }
- /*
- ================
- idRenderModelStatic::GetJointName
- ================
- */
- const char * idRenderModelStatic::GetJointName( jointHandle_t handle ) const {
- return "";
- }
- /*
- ================
- idRenderModelStatic::GetDefaultPose
- ================
- */
- const idJointQuat *idRenderModelStatic::GetDefaultPose() const {
- return NULL;
- }
- /*
- ================
- idRenderModelStatic::NearestJoint
- ================
- */
- int idRenderModelStatic::NearestJoint( int surfaceNum, int a, int b, int c ) const {
- return INVALID_JOINT;
- }
- //=====================================================================
- /*
- ================
- idRenderModelStatic::FinishSurfaces
- The mergeShadows option allows surfaces with different textures to share
- silhouette edges for shadow calculation, instead of leaving shared edges
- hanging.
- If any of the original shaders have the noSelfShadow flag set, the surfaces
- can't be merged, because they will need to be drawn in different order.
- If there is only one surface, a separate merged surface won't be generated.
- A model with multiple surfaces can't later have a skinned shader change the
- state of the noSelfShadow flag.
- -----------------
- Creates mirrored copies of two sided surfaces with normal maps, which would
- otherwise light funny.
- Extends the bounds of deformed surfaces so they don't cull incorrectly at screen edges.
- ================
- */
- void idRenderModelStatic::FinishSurfaces() {
- int i;
- int totalVerts, totalIndexes;
- hasDrawingSurfaces = false;
- hasInteractingSurfaces = false;
- hasShadowCastingSurfaces = false;
- purged = false;
- // make sure we don't have a huge bounds even if we don't finish everything
- bounds.Zero();
- if ( surfaces.Num() == 0 ) {
- return;
- }
- // renderBump doesn't care about most of this
- if ( fastLoad ) {
- bounds.Zero();
- for ( i = 0; i < surfaces.Num(); i++ ) {
- const modelSurface_t *surf = &surfaces[i];
- R_BoundTriSurf( surf->geometry );
- bounds.AddBounds( surf->geometry->bounds );
- }
- return;
- }
- // cleanup all the final surfaces, but don't create sil edges
- totalVerts = 0;
- totalIndexes = 0;
- // decide if we are going to merge all the surfaces into one shadower
- int numOriginalSurfaces = surfaces.Num();
- // make sure there aren't any NULL shaders or geometry
- for ( i = 0; i < numOriginalSurfaces; i++ ) {
- const modelSurface_t *surf = &surfaces[i];
- if ( surf->geometry == NULL || surf->shader == NULL ) {
- MakeDefaultModel();
- common->Error( "Model %s, surface %i had NULL geometry", name.c_str(), i );
- }
- if ( surf->shader == NULL ) {
- MakeDefaultModel();
- common->Error( "Model %s, surface %i had NULL shader", name.c_str(), i );
- }
- }
- // duplicate and reverse triangles for two sided bump mapped surfaces
- // note that this won't catch surfaces that have their shaders dynamically
- // changed, and won't work with animated models.
- // It is better to create completely separate surfaces, rather than
- // add vertexes and indexes to the existing surface, because the
- // tangent generation wouldn't like the acute shared edges
- for ( i = 0; i < numOriginalSurfaces; i++ ) {
- const modelSurface_t *surf = &surfaces[i];
- if ( surf->shader->ShouldCreateBackSides() ) {
- srfTriangles_t *newTri;
- newTri = R_CopyStaticTriSurf( surf->geometry );
- R_ReverseTriangles( newTri );
- modelSurface_t newSurf;
- newSurf.shader = surf->shader;
- newSurf.geometry = newTri;
- AddSurface( newSurf );
- }
- }
- // clean the surfaces
- for ( i = 0; i < surfaces.Num(); i++ ) {
- const modelSurface_t *surf = &surfaces[i];
- R_CleanupTriangles( surf->geometry, surf->geometry->generateNormals, true, surf->shader->UseUnsmoothedTangents() );
- if ( surf->shader->SurfaceCastsShadow() ) {
- totalVerts += surf->geometry->numVerts;
- totalIndexes += surf->geometry->numIndexes;
- }
- }
- // add up the total surface area for development information
- for ( i = 0; i < surfaces.Num(); i++ ) {
- const modelSurface_t *surf = &surfaces[i];
- srfTriangles_t *tri = surf->geometry;
- for ( int j = 0; j < tri->numIndexes; j += 3 ) {
- float area = idWinding::TriangleArea( tri->verts[tri->indexes[j]].xyz,
- tri->verts[tri->indexes[j+1]].xyz, tri->verts[tri->indexes[j+2]].xyz );
- const_cast<idMaterial *>(surf->shader)->AddToSurfaceArea( area );
- }
- }
- // set flags for whole-model rejection
- for ( i = 0; i < surfaces.Num(); i++ ) {
- const modelSurface_t *surf = &surfaces[i];
- if ( surf->shader->IsDrawn() ) {
- hasDrawingSurfaces = true;
- }
- if ( surf->shader->SurfaceCastsShadow() ) {
- hasShadowCastingSurfaces = true;
- }
- if ( surf->shader->ReceivesLighting() ) {
- hasInteractingSurfaces = true;
- }
- if ( strstr( surf->shader->GetName(), "trigger" ) ) {
- static int breakHere;
- breakHere++;
- }
- }
- // calculate the bounds
- if ( surfaces.Num() == 0 ) {
- bounds.Zero();
- } else {
- bounds.Clear();
- for ( i = 0; i < surfaces.Num(); i++ ) {
- modelSurface_t *surf = &surfaces[i];
- // if the surface has a deformation, increase the bounds
- // the amount here is somewhat arbitrary, designed to handle
- // autosprites and flares, but could be done better with exact
- // deformation information.
- // Note that this doesn't handle deformations that are skinned in
- // at run time...
- if ( surf->shader->Deform() != DFRM_NONE ) {
- srfTriangles_t *tri = surf->geometry;
- idVec3 mid = ( tri->bounds[1] + tri->bounds[0] ) * 0.5f;
- float radius = ( tri->bounds[0] - mid ).Length();
- radius += 20.0f;
- tri->bounds[0][0] = mid[0] - radius;
- tri->bounds[0][1] = mid[1] - radius;
- tri->bounds[0][2] = mid[2] - radius;
- tri->bounds[1][0] = mid[0] + radius;
- tri->bounds[1][1] = mid[1] + radius;
- tri->bounds[1][2] = mid[2] + radius;
- }
- // add to the model bounds
- bounds.AddBounds( surf->geometry->bounds );
- }
- }
- }
- /*
- =================
- idRenderModelStatic::ConvertASEToModelSurfaces
- =================
- */
- typedef struct matchVert_s {
- struct matchVert_s *next;
- int v, tv;
- byte color[4];
- idVec3 normal;
- } matchVert_t;
- bool idRenderModelStatic::ConvertASEToModelSurfaces( const struct aseModel_s *ase ) {
- aseObject_t * object;
- aseMesh_t * mesh;
- aseMaterial_t * material;
- const idMaterial *im1, *im2;
- srfTriangles_t *tri;
- int objectNum;
- int i, j, k;
- int v, tv;
- int * vRemap;
- int * tvRemap;
- matchVert_t * mvTable; // all of the match verts
- matchVert_t ** mvHash; // points inside mvTable for each xyz index
- matchVert_t * lastmv;
- matchVert_t * mv;
- idVec3 normal;
- float uOffset, vOffset, textureSin, textureCos;
- float uTiling, vTiling;
- int * mergeTo;
- byte * color;
- static byte identityColor[4] = { 255, 255, 255, 255 };
- modelSurface_t surf, *modelSurf;
- if ( !ase ) {
- return false;
- }
- if ( ase->objects.Num() < 1 ) {
- return false;
- }
- timeStamp = ase->timeStamp;
- // the modeling programs can save out multiple surfaces with a common
- // material, but we would like to mege them together where possible
- // meaning that this->NumSurfaces() <= ase->objects.currentElements
- mergeTo = (int *)_alloca( ase->objects.Num() * sizeof( *mergeTo ) );
- surf.geometry = NULL;
- if ( ase->materials.Num() == 0 ) {
- // if we don't have any materials, dump everything into a single surface
- surf.shader = tr.defaultMaterial;
- surf.id = 0;
- this->AddSurface( surf );
- for ( i = 0; i < ase->objects.Num(); i++ ) {
- mergeTo[i] = 0;
- }
- } else if ( !r_mergeModelSurfaces.GetBool() ) {
- // don't merge any
- for ( i = 0; i < ase->objects.Num(); i++ ) {
- mergeTo[i] = i;
- object = ase->objects[i];
- material = ase->materials[object->materialRef];
- surf.shader = declManager->FindMaterial( material->name );
- surf.id = this->NumSurfaces();
- this->AddSurface( surf );
- }
- } else {
- // search for material matches
- for ( i = 0; i < ase->objects.Num(); i++ ) {
- object = ase->objects[i];
- material = ase->materials[object->materialRef];
- im1 = declManager->FindMaterial( material->name );
- if ( im1->IsDiscrete() ) {
- // flares, autosprites, etc
- j = this->NumSurfaces();
- } else {
- for ( j = 0; j < this->NumSurfaces(); j++ ) {
- modelSurf = &this->surfaces[j];
- im2 = modelSurf->shader;
- if ( im1 == im2 ) {
- // merge this
- mergeTo[i] = j;
- break;
- }
- }
- }
- if ( j == this->NumSurfaces() ) {
- // didn't merge
- mergeTo[i] = j;
- surf.shader = im1;
- surf.id = this->NumSurfaces();
- this->AddSurface( surf );
- }
- }
- }
- idVectorSubset<idVec3, 3> vertexSubset;
- idVectorSubset<idVec2, 2> texCoordSubset;
- // build the surfaces
- for ( objectNum = 0; objectNum < ase->objects.Num(); objectNum++ ) {
- object = ase->objects[objectNum];
- mesh = &object->mesh;
- material = ase->materials[object->materialRef];
- im1 = declManager->FindMaterial( material->name );
- bool normalsParsed = mesh->normalsParsed;
- // completely ignore any explict normals on surfaces with a renderbump command
- // which will guarantee the best contours and least vertexes.
- const char *rb = im1->GetRenderBump();
- if ( rb != NULL && rb[0] != NULL ) {
- normalsParsed = false;
- }
- // It seems like the tools our artists are using often generate
- // verts and texcoords slightly separated that should be merged
- // note that we really should combine the surfaces with common materials
- // before doing this operation, because we can miss a slop combination
- // if they are in different surfaces
- vRemap = (int *)R_StaticAlloc( mesh->numVertexes * sizeof( vRemap[0] ), TAG_MODEL );
- if ( fastLoad ) {
- // renderbump doesn't care about vertex count
- for ( j = 0; j < mesh->numVertexes; j++ ) {
- vRemap[j] = j;
- }
- } else {
- float vertexEpsilon = r_slopVertex.GetFloat();
- float expand = 2 * 32 * vertexEpsilon;
- idVec3 mins, maxs;
- SIMDProcessor->MinMax( mins, maxs, mesh->vertexes, mesh->numVertexes );
- mins -= idVec3( expand, expand, expand );
- maxs += idVec3( expand, expand, expand );
- vertexSubset.Init( mins, maxs, 32, 1024 );
- for ( j = 0; j < mesh->numVertexes; j++ ) {
- vRemap[j] = vertexSubset.FindVector( mesh->vertexes, j, vertexEpsilon );
- }
- }
- tvRemap = (int *)R_StaticAlloc( mesh->numTVertexes * sizeof( tvRemap[0] ), TAG_MODEL );
- if ( fastLoad ) {
- // renderbump doesn't care about vertex count
- for ( j = 0; j < mesh->numTVertexes; j++ ) {
- tvRemap[j] = j;
- }
- } else {
- float texCoordEpsilon = r_slopTexCoord.GetFloat();
- float expand = 2 * 32 * texCoordEpsilon;
- idVec2 mins, maxs;
- SIMDProcessor->MinMax( mins, maxs, mesh->tvertexes, mesh->numTVertexes );
- mins -= idVec2( expand, expand );
- maxs += idVec2( expand, expand );
- texCoordSubset.Init( mins, maxs, 32, 1024 );
- for ( j = 0; j < mesh->numTVertexes; j++ ) {
- tvRemap[j] = texCoordSubset.FindVector( mesh->tvertexes, j, texCoordEpsilon );
- }
- }
- // we need to find out how many unique vertex / texcoord combinations
- // there are, because ASE tracks them separately but we need them unified
- // the maximum possible number of combined vertexes is the number of indexes
- mvTable = (matchVert_t *)R_ClearedStaticAlloc( mesh->numFaces * 3 * sizeof( mvTable[0] ) );
- // we will have a hash chain based on the xyz values
- mvHash = (matchVert_t **)R_ClearedStaticAlloc( mesh->numVertexes * sizeof( mvHash[0] ) );
- // allocate triangle surface
- tri = R_AllocStaticTriSurf();
- tri->numVerts = 0;
- tri->numIndexes = 0;
- R_AllocStaticTriSurfIndexes( tri, mesh->numFaces * 3 );
- tri->generateNormals = !normalsParsed;
- // init default normal, color and tex coord index
- normal.Zero();
- color = identityColor;
- tv = 0;
- // find all the unique combinations
- float normalEpsilon = 1.0f - r_slopNormal.GetFloat();
- for ( j = 0; j < mesh->numFaces; j++ ) {
- for ( k = 0; k < 3; k++ ) {
- v = mesh->faces[j].vertexNum[k];
- if ( v < 0 || v >= mesh->numVertexes ) {
- common->Error( "ConvertASEToModelSurfaces: bad vertex index in ASE file %s", name.c_str() );
- }
- // collapse the position if it was slightly offset
- v = vRemap[v];
- // we may or may not have texcoords to compare
- if ( mesh->numTVFaces == mesh->numFaces && mesh->numTVertexes != 0 ) {
- tv = mesh->faces[j].tVertexNum[k];
- if ( tv < 0 || tv >= mesh->numTVertexes ) {
- common->Error( "ConvertASEToModelSurfaces: bad tex coord index in ASE file %s", name.c_str() );
- }
- // collapse the tex coord if it was slightly offset
- tv = tvRemap[tv];
- }
- // we may or may not have normals to compare
- if ( normalsParsed ) {
- normal = mesh->faces[j].vertexNormals[k];
- }
- // we may or may not have colors to compare
- if ( mesh->colorsParsed ) {
- color = mesh->faces[j].vertexColors[k];
- }
- // find a matching vert
- for ( lastmv = NULL, mv = mvHash[v]; mv != NULL; lastmv = mv, mv = mv->next ) {
- if ( mv->tv != tv ) {
- continue;
- }
- if ( *(unsigned *)mv->color != *(unsigned *)color ) {
- continue;
- }
- if ( !normalsParsed ) {
- // if we are going to create the normals, just
- // matching texcoords is enough
- break;
- }
- if ( mv->normal * normal > normalEpsilon ) {
- break; // we already have this one
- }
- }
- if ( !mv ) {
- // allocate a new match vert and link to hash chain
- mv = &mvTable[ tri->numVerts ];
- mv->v = v;
- mv->tv = tv;
- mv->normal = normal;
- *(unsigned *)mv->color = *(unsigned *)color;
- mv->next = NULL;
- if ( lastmv ) {
- lastmv->next = mv;
- } else {
- mvHash[v] = mv;
- }
- tri->numVerts++;
- }
- tri->indexes[tri->numIndexes] = mv - mvTable;
- tri->numIndexes++;
- }
- }
- // allocate space for the indexes and copy them
- if ( tri->numIndexes > mesh->numFaces * 3 ) {
- common->FatalError( "ConvertASEToModelSurfaces: index miscount in ASE file %s", name.c_str() );
- }
- if ( tri->numVerts > mesh->numFaces * 3 ) {
- common->FatalError( "ConvertASEToModelSurfaces: vertex miscount in ASE file %s", name.c_str() );
- }
- // an ASE allows the texture coordinates to be scaled, translated, and rotated
- if ( ase->materials.Num() == 0 ) {
- uOffset = vOffset = 0.0f;
- uTiling = vTiling = 1.0f;
- textureSin = 0.0f;
- textureCos = 1.0f;
- } else {
- material = ase->materials[object->materialRef];
- uOffset = -material->uOffset;
- vOffset = material->vOffset;
- uTiling = material->uTiling;
- vTiling = material->vTiling;
- textureSin = idMath::Sin( material->angle );
- textureCos = idMath::Cos( material->angle );
- }
- // now allocate and generate the combined vertexes
- R_AllocStaticTriSurfVerts( tri, tri->numVerts );
- for ( j = 0; j < tri->numVerts; j++ ) {
- mv = &mvTable[j];
- tri->verts[ j ].Clear();
- tri->verts[ j ].xyz = mesh->vertexes[ mv->v ];
- tri->verts[ j ].SetNormal( mv->normal );
- *(unsigned *)tri->verts[j].color = *(unsigned *)mv->color;
- if ( mesh->numTVFaces == mesh->numFaces && mesh->numTVertexes != 0 ) {
- const idVec2 &tv = mesh->tvertexes[ mv->tv ];
- float u = tv.x * uTiling + uOffset;
- float v = tv.y * vTiling + vOffset;
- tri->verts[j].SetTexCoord( u * textureCos + v * textureSin, u * -textureSin + v * textureCos );
- }
- }
- R_StaticFree( mvTable );
- R_StaticFree( mvHash );
- R_StaticFree( tvRemap );
- R_StaticFree( vRemap );
- // see if we need to merge with a previous surface of the same material
- modelSurf = &this->surfaces[mergeTo[ objectNum ]];
- srfTriangles_t *mergeTri = modelSurf->geometry;
- if ( !mergeTri ) {
- modelSurf->geometry = tri;
- } else {
- modelSurf->geometry = R_MergeTriangles( mergeTri, tri );
- R_FreeStaticTriSurf( tri );
- R_FreeStaticTriSurf( mergeTri );
- }
- }
- return true;
- }
- /*
- =================
- idRenderModelStatic::ConvertLWOToModelSurfaces
- =================
- */
- bool idRenderModelStatic::ConvertLWOToModelSurfaces( const struct st_lwObject *lwo ) {
- const idMaterial *im1, *im2;
- srfTriangles_t *tri;
- lwSurface * lwoSurf;
- int numTVertexes;
- int i, j, k;
- int v, tv;
- idVec3 * vList;
- int * vRemap;
- idVec2 * tvList;
- int * tvRemap;
- matchVert_t * mvTable; // all of the match verts
- matchVert_t ** mvHash; // points inside mvTable for each xyz index
- matchVert_t * lastmv;
- matchVert_t * mv;
- idVec3 normal;
- int * mergeTo;
- byte color[4];
- modelSurface_t surf, *modelSurf;
- if ( !lwo ) {
- return false;
- }
- if ( lwo->surf == NULL ) {
- return false;
- }
- timeStamp = lwo->timeStamp;
- // count the number of surfaces
- i = 0;
- for ( lwoSurf = lwo->surf; lwoSurf; lwoSurf = lwoSurf->next ) {
- i++;
- }
- // the modeling programs can save out multiple surfaces with a common
- // material, but we would like to merge them together where possible
- mergeTo = (int *)_alloca( i * sizeof( mergeTo[0] ) );
- memset( &surf, 0, sizeof( surf ) );
- if ( !r_mergeModelSurfaces.GetBool() ) {
- // don't merge any
- for ( lwoSurf = lwo->surf, i = 0; lwoSurf; lwoSurf = lwoSurf->next, i++ ) {
- mergeTo[i] = i;
- surf.shader = declManager->FindMaterial( lwoSurf->name );
- surf.id = this->NumSurfaces();
- this->AddSurface( surf );
- }
- } else {
- // search for material matches
- for ( lwoSurf = lwo->surf, i = 0; lwoSurf; lwoSurf = lwoSurf->next, i++ ) {
- im1 = declManager->FindMaterial( lwoSurf->name );
- if ( im1->IsDiscrete() ) {
- // flares, autosprites, etc
- j = this->NumSurfaces();
- } else {
- for ( j = 0; j < this->NumSurfaces(); j++ ) {
- modelSurf = &this->surfaces[j];
- im2 = modelSurf->shader;
- if ( im1 == im2 ) {
- // merge this
- mergeTo[i] = j;
- break;
- }
- }
- }
- if ( j == this->NumSurfaces() ) {
- // didn't merge
- mergeTo[i] = j;
- surf.shader = im1;
- surf.id = this->NumSurfaces();
- this->AddSurface( surf );
- }
- }
- }
- idVectorSubset<idVec3, 3> vertexSubset;
- idVectorSubset<idVec2, 2> texCoordSubset;
- // we only ever use the first layer
- lwLayer *layer = lwo->layer;
- // vertex positions
- if ( layer->point.count <= 0 ) {
- common->Warning( "ConvertLWOToModelSurfaces: model \'%s\' has bad or missing vertex data", name.c_str() );
- return false;
- }
- vList = (idVec3 *)R_StaticAlloc( layer->point.count * sizeof( vList[0] ), TAG_MODEL );
- for ( j = 0; j < layer->point.count; j++ ) {
- vList[j].x = layer->point.pt[j].pos[0];
- vList[j].y = layer->point.pt[j].pos[2];
- vList[j].z = layer->point.pt[j].pos[1];
- }
- // vertex texture coords
- numTVertexes = 0;
- if ( layer->nvmaps ) {
- for( lwVMap *vm = layer->vmap; vm; vm = vm->next ) {
- if ( vm->type == LWID_('T','X','U','V') ) {
- numTVertexes += vm->nverts;
- }
- }
- }
- if ( numTVertexes ) {
- tvList = (idVec2 *)Mem_Alloc( numTVertexes * sizeof( tvList[0] ), TAG_MODEL );
- int offset = 0;
- for( lwVMap *vm = layer->vmap; vm; vm = vm->next ) {
- if ( vm->type == LWID_('T','X','U','V') ) {
- vm->offset = offset;
- for ( k = 0; k < vm->nverts; k++ ) {
- tvList[k + offset].x = vm->val[k][0];
- tvList[k + offset].y = 1.0f - vm->val[k][1]; // invert the t
- }
- offset += vm->nverts;
- }
- }
- } else {
- common->Warning( "ConvertLWOToModelSurfaces: model \'%s\' has bad or missing uv data", name.c_str() );
- numTVertexes = 1;
- tvList = (idVec2 *)Mem_ClearedAlloc( numTVertexes * sizeof( tvList[0] ), TAG_MODEL );
- }
- // It seems like the tools our artists are using often generate
- // verts and texcoords slightly separated that should be merged
- // note that we really should combine the surfaces with common materials
- // before doing this operation, because we can miss a slop combination
- // if they are in different surfaces
- vRemap = (int *)R_StaticAlloc( layer->point.count * sizeof( vRemap[0] ), TAG_MODEL );
- if ( fastLoad ) {
- // renderbump doesn't care about vertex count
- for ( j = 0; j < layer->point.count; j++ ) {
- vRemap[j] = j;
- }
- } else {
- float vertexEpsilon = r_slopVertex.GetFloat();
- float expand = 2 * 32 * vertexEpsilon;
- idVec3 mins, maxs;
- SIMDProcessor->MinMax( mins, maxs, vList, layer->point.count );
- mins -= idVec3( expand, expand, expand );
- maxs += idVec3( expand, expand, expand );
- vertexSubset.Init( mins, maxs, 32, 1024 );
- for ( j = 0; j < layer->point.count; j++ ) {
- vRemap[j] = vertexSubset.FindVector( vList, j, vertexEpsilon );
- }
- }
- tvRemap = (int *)R_StaticAlloc( numTVertexes * sizeof( tvRemap[0] ), TAG_MODEL );
- if ( fastLoad ) {
- // renderbump doesn't care about vertex count
- for ( j = 0; j < numTVertexes; j++ ) {
- tvRemap[j] = j;
- }
- } else {
- float texCoordEpsilon = r_slopTexCoord.GetFloat();
- float expand = 2 * 32 * texCoordEpsilon;
- idVec2 mins, maxs;
- SIMDProcessor->MinMax( mins, maxs, tvList, numTVertexes );
- mins -= idVec2( expand, expand );
- maxs += idVec2( expand, expand );
- texCoordSubset.Init( mins, maxs, 32, 1024 );
- for ( j = 0; j < numTVertexes; j++ ) {
- tvRemap[j] = texCoordSubset.FindVector( tvList, j, texCoordEpsilon );
- }
- }
- // build the surfaces
- for ( lwoSurf = lwo->surf, i = 0; lwoSurf; lwoSurf = lwoSurf->next, i++ ) {
- im1 = declManager->FindMaterial( lwoSurf->name );
- bool normalsParsed = true;
- // completely ignore any explict normals on surfaces with a renderbump command
- // which will guarantee the best contours and least vertexes.
- const char *rb = im1->GetRenderBump();
- if ( rb && rb[0] ) {
- normalsParsed = false;
- }
- // we need to find out how many unique vertex / texcoord combinations there are
- // the maximum possible number of combined vertexes is the number of indexes
- mvTable = (matchVert_t *)R_ClearedStaticAlloc( layer->polygon.count * 3 * sizeof( mvTable[0] ) );
- // we will have a hash chain based on the xyz values
- mvHash = (matchVert_t **)R_ClearedStaticAlloc( layer->point.count * sizeof( mvHash[0] ) );
- // allocate triangle surface
- tri = R_AllocStaticTriSurf();
- tri->numVerts = 0;
- tri->numIndexes = 0;
- R_AllocStaticTriSurfIndexes( tri, layer->polygon.count * 3 );
- tri->generateNormals = !normalsParsed;
- // find all the unique combinations
- float normalEpsilon;
- if ( fastLoad ) {
- normalEpsilon = 1.0f; // don't merge unless completely exact
- } else {
- normalEpsilon = 1.0f - r_slopNormal.GetFloat();
- }
- for ( j = 0; j < layer->polygon.count; j++ ) {
- lwPolygon *poly = &layer->polygon.pol[j];
- if ( poly->surf != lwoSurf ) {
- continue;
- }
- if ( poly->nverts != 3 ) {
- common->Warning( "ConvertLWOToModelSurfaces: model %s has too many verts for a poly! Make sure you triplet it down", name.c_str() );
- continue;
- }
- for ( k = 0; k < 3; k++ ) {
- v = vRemap[poly->v[k].index];
- normal.x = poly->v[k].norm[0];
- normal.y = poly->v[k].norm[2];
- normal.z = poly->v[k].norm[1];
- // LWO models aren't all that pretty when it comes down to the floating point values they store
- normal.FixDegenerateNormal();
- tv = 0;
- color[0] = lwoSurf->color.rgb[0] * 255;
- color[1] = lwoSurf->color.rgb[1] * 255;
- color[2] = lwoSurf->color.rgb[2] * 255;
- color[3] = 255;
- // first set attributes from the vertex
- lwPoint *pt = &layer->point.pt[poly->v[k].index];
- int nvm;
- for ( nvm = 0; nvm < pt->nvmaps; nvm++ ) {
- lwVMapPt *vm = &pt->vm[nvm];
- if ( vm->vmap->type == LWID_('T','X','U','V') ) {
- tv = tvRemap[vm->index + vm->vmap->offset];
- }
- if ( vm->vmap->type == LWID_('R','G','B','A') ) {
- for ( int chan = 0; chan < 4; chan++ ) {
- color[chan] = 255 * vm->vmap->val[vm->index][chan];
- }
- }
- }
- // then override with polygon attributes
- for ( nvm = 0; nvm < poly->v[k].nvmaps; nvm++ ) {
- lwVMapPt *vm = &poly->v[k].vm[nvm];
- if ( vm->vmap->type == LWID_('T','X','U','V') ) {
- tv = tvRemap[vm->index + vm->vmap->offset];
- }
- if ( vm->vmap->type == LWID_('R','G','B','A') ) {
- for ( int chan = 0; chan < 4; chan++ ) {
- color[chan] = 255 * vm->vmap->val[vm->index][chan];
- }
- }
- }
- // find a matching vert
- for ( lastmv = NULL, mv = mvHash[v]; mv != NULL; lastmv = mv, mv = mv->next ) {
- if ( mv->tv != tv ) {
- continue;
- }
- if ( *(unsigned *)mv->color != *(unsigned *)color ) {
- continue;
- }
- if ( !normalsParsed ) {
- // if we are going to create the normals, just
- // matching texcoords is enough
- break;
- }
- if ( mv->normal * normal > normalEpsilon ) {
- break; // we already have this one
- }
- }
- if ( !mv ) {
- // allocate a new match vert and link to hash chain
- mv = &mvTable[ tri->numVerts ];
- mv->v = v;
- mv->tv = tv;
- mv->normal = normal;
- *(unsigned *)mv->color = *(unsigned *)color;
- mv->next = NULL;
- if ( lastmv ) {
- lastmv->next = mv;
- } else {
- mvHash[v] = mv;
- }
- tri->numVerts++;
- }
- tri->indexes[tri->numIndexes] = mv - mvTable;
- tri->numIndexes++;
- }
- }
- // allocate space for the indexes and copy them
- if ( tri->numIndexes > layer->polygon.count * 3 ) {
- common->FatalError( "ConvertLWOToModelSurfaces: index miscount in LWO file %s", name.c_str() );
- }
- if ( tri->numVerts > layer->polygon.count * 3 ) {
- common->FatalError( "ConvertLWOToModelSurfaces: vertex miscount in LWO file %s", name.c_str() );
- }
- // now allocate and generate the combined vertexes
- R_AllocStaticTriSurfVerts( tri, tri->numVerts );
- for ( j = 0; j < tri->numVerts; j++ ) {
- mv = &mvTable[j];
- tri->verts[ j ].Clear();
- tri->verts[ j ].xyz = vList[ mv->v ];
- tri->verts[ j ].SetTexCoord( tvList[ mv->tv ] );
- tri->verts[ j ].SetNormal( mv->normal );
- *(unsigned *)tri->verts[j].color = *(unsigned *)mv->color;
- }
- R_StaticFree( mvTable );
- R_StaticFree( mvHash );
- // see if we need to merge with a previous surface of the same material
- modelSurf = &this->surfaces[mergeTo[ i ]];
- srfTriangles_t *mergeTri = modelSurf->geometry;
- if ( !mergeTri ) {
- modelSurf->geometry = tri;
- } else {
- modelSurf->geometry = R_MergeTriangles( mergeTri, tri );
- R_FreeStaticTriSurf( tri );
- R_FreeStaticTriSurf( mergeTri );
- }
- }
- R_StaticFree( tvRemap );
- R_StaticFree( vRemap );
- R_StaticFree( tvList );
- R_StaticFree( vList );
- return true;
- }
- /*
- =================
- idRenderModelStatic::ConvertLWOToASE
- =================
- */
- struct aseModel_s *idRenderModelStatic::ConvertLWOToASE( const struct st_lwObject *obj, const char *fileName ) {
- int j, k;
- aseModel_t *ase;
- if ( !obj ) {
- return NULL;
- }
- // NOTE: using new operator because aseModel_t contains idList class objects
- ase = new (TAG_MODEL) aseModel_t;
- ase->timeStamp = obj->timeStamp;
- ase->objects.Resize( obj->nlayers, obj->nlayers );
- int materialRef = 0;
- for ( lwSurface *surf = obj->surf; surf; surf = surf->next ) {
- aseMaterial_t *mat = (aseMaterial_t *)Mem_ClearedAlloc( sizeof( *mat ), TAG_MODEL );
- strcpy( mat->name, surf->name );
- mat->uTiling = mat->vTiling = 1;
- mat->angle = mat->uOffset = mat->vOffset = 0;
- ase->materials.Append( mat );
- lwLayer *layer = obj->layer;
- aseObject_t *object = (aseObject_t *)Mem_ClearedAlloc( sizeof( *object ), TAG_MODEL );
- object->materialRef = materialRef++;
- aseMesh_t *mesh = &object->mesh;
- ase->objects.Append( object );
- mesh->numFaces = layer->polygon.count;
- mesh->numTVFaces = mesh->numFaces;
- mesh->faces = (aseFace_t *)Mem_Alloc( mesh->numFaces * sizeof( mesh->faces[0] ), TAG_MODEL );
- mesh->numVertexes = layer->point.count;
- mesh->vertexes = (idVec3 *)Mem_Alloc( mesh->numVertexes * sizeof( mesh->vertexes[0] ), TAG_MODEL );
- // vertex positions
- if ( layer->point.count <= 0 ) {
- common->Warning( "ConvertLWOToASE: model \'%s\' has bad or missing vertex data", name.c_str() );
- }
- for ( j = 0; j < layer->point.count; j++ ) {
- mesh->vertexes[j].x = layer->point.pt[j].pos[0];
- mesh->vertexes[j].y = layer->point.pt[j].pos[2];
- mesh->vertexes[j].z = layer->point.pt[j].pos[1];
- }
- // vertex texture coords
- mesh->numTVertexes = 0;
- if ( layer->nvmaps ) {
- for( lwVMap *vm = layer->vmap; vm; vm = vm->next ) {
- if ( vm->type == LWID_('T','X','U','V') ) {
- mesh->numTVertexes += vm->nverts;
- }
- }
- }
- if ( mesh->numTVertexes ) {
- mesh->tvertexes = (idVec2 *)Mem_Alloc( mesh->numTVertexes * sizeof( mesh->tvertexes[0] ), TAG_MODEL );
- int offset = 0;
- for( lwVMap *vm = layer->vmap; vm; vm = vm->next ) {
- if ( vm->type == LWID_('T','X','U','V') ) {
- vm->offset = offset;
- for ( k = 0; k < vm->nverts; k++ ) {
- mesh->tvertexes[k + offset].x = vm->val[k][0];
- mesh->tvertexes[k + offset].y = 1.0f - vm->val[k][1]; // invert the t
- }
- offset += vm->nverts;
- }
- }
- } else {
- common->Warning( "ConvertLWOToASE: model \'%s\' has bad or missing uv data", fileName );
- mesh->numTVertexes = 1;
- mesh->tvertexes = (idVec2 *)Mem_ClearedAlloc( mesh->numTVertexes * sizeof( mesh->tvertexes[0] ), TAG_MODEL );
- }
- mesh->normalsParsed = true;
- mesh->colorsParsed = true; // because we are falling back to the surface color
- // triangles
- int faceIndex = 0;
- for ( j = 0; j < layer->polygon.count; j++ ) {
- lwPolygon *poly = &layer->polygon.pol[j];
- if ( poly->surf != surf ) {
- continue;
- }
- if ( poly->nverts != 3 ) {
- common->Warning( "ConvertLWOToASE: model %s has too many verts for a poly! Make sure you triplet it down", fileName );
- continue;
- }
-
- mesh->faces[faceIndex].faceNormal.x = poly->norm[0];
- mesh->faces[faceIndex].faceNormal.y = poly->norm[2];
- mesh->faces[faceIndex].faceNormal.z = poly->norm[1];
- for ( k = 0; k < 3; k++ ) {
- mesh->faces[faceIndex].vertexNum[k] = poly->v[k].index;
- mesh->faces[faceIndex].vertexNormals[k].x = poly->v[k].norm[0];
- mesh->faces[faceIndex].vertexNormals[k].y = poly->v[k].norm[2];
- mesh->faces[faceIndex].vertexNormals[k].z = poly->v[k].norm[1];
- // complete fallbacks
- mesh->faces[faceIndex].tVertexNum[k] = 0;
- mesh->faces[faceIndex].vertexColors[k][0] = surf->color.rgb[0] * 255;
- mesh->faces[faceIndex].vertexColors[k][1] = surf->color.rgb[1] * 255;
- mesh->faces[faceIndex].vertexColors[k][2] = surf->color.rgb[2] * 255;
- mesh->faces[faceIndex].vertexColors[k][3] = 255;
- // first set attributes from the vertex
- lwPoint *pt = &layer->point.pt[poly->v[k].index];
- int nvm;
- for ( nvm = 0; nvm < pt->nvmaps; nvm++ ) {
- lwVMapPt *vm = &pt->vm[nvm];
- if ( vm->vmap->type == LWID_('T','X','U','V') ) {
- mesh->faces[faceIndex].tVertexNum[k] = vm->index + vm->vmap->offset;
- }
- if ( vm->vmap->type == LWID_('R','G','B','A') ) {
- for ( int chan = 0; chan < 4; chan++ ) {
- mesh->faces[faceIndex].vertexColors[k][chan] = 255 * vm->vmap->val[vm->index][chan];
- }
- }
- }
- // then override with polygon attributes
- for ( nvm = 0; nvm < poly->v[k].nvmaps; nvm++ ) {
- lwVMapPt *vm = &poly->v[k].vm[nvm];
- if ( vm->vmap->type == LWID_('T','X','U','V') ) {
- mesh->faces[faceIndex].tVertexNum[k] = vm->index + vm->vmap->offset;
- }
- if ( vm->vmap->type == LWID_('R','G','B','A') ) {
- for ( int chan = 0; chan < 4; chan++ ) {
- mesh->faces[faceIndex].vertexColors[k][chan] = 255 * vm->vmap->val[vm->index][chan];
- }
- }
- }
- }
- faceIndex++;
- }
- mesh->numFaces = faceIndex;
- mesh->numTVFaces = faceIndex;
- aseFace_t *newFaces = ( aseFace_t* )Mem_Alloc( mesh->numFaces * sizeof ( mesh->faces[0] ), TAG_MODEL );
- memcpy( newFaces, mesh->faces, sizeof( mesh->faces[0] ) * mesh->numFaces );
- Mem_Free( mesh->faces );
- mesh->faces = newFaces;
- }
- return ase;
- }
- /*
- =================
- idRenderModelStatic::ConvertMAToModelSurfaces
- =================
- */
- bool idRenderModelStatic::ConvertMAToModelSurfaces (const struct maModel_s *ma ) {
- maObject_t * object;
- maMesh_t * mesh;
- maMaterial_t * material;
-
- const idMaterial *im1, *im2;
- srfTriangles_t *tri;
- int objectNum;
- int i, j, k;
- int v, tv;
- int * vRemap;
- int * tvRemap;
- matchVert_t * mvTable; // all of the match verts
- matchVert_t ** mvHash; // points inside mvTable for each xyz index
- matchVert_t * lastmv;
- matchVert_t * mv;
- idVec3 normal;
- float uOffset, vOffset, textureSin, textureCos;
- float uTiling, vTiling;
- int * mergeTo;
- byte * color;
- static byte identityColor[4] = { 255, 255, 255, 255 };
- modelSurface_t surf, *modelSurf;
- if ( !ma ) {
- return false;
- }
- if ( ma->objects.Num() < 1 ) {
- return false;
- }
- timeStamp = ma->timeStamp;
- // the modeling programs can save out multiple surfaces with a common
- // material, but we would like to mege them together where possible
- // meaning that this->NumSurfaces() <= ma->objects.currentElements
- mergeTo = (int *)_alloca( ma->objects.Num() * sizeof( *mergeTo ) );
- surf.geometry = NULL;
- if ( ma->materials.Num() == 0 ) {
- // if we don't have any materials, dump everything into a single surface
- surf.shader = tr.defaultMaterial;
- surf.id = 0;
- this->AddSurface( surf );
- for ( i = 0; i < ma->objects.Num(); i++ ) {
- mergeTo[i] = 0;
- }
- } else if ( !r_mergeModelSurfaces.GetBool() ) {
- // don't merge any
- for ( i = 0; i < ma->objects.Num(); i++ ) {
- mergeTo[i] = i;
- object = ma->objects[i];
- if(object->materialRef >= 0) {
- material = ma->materials[object->materialRef];
- surf.shader = declManager->FindMaterial( material->name );
- } else {
- surf.shader = tr.defaultMaterial;
- }
- surf.id = this->NumSurfaces();
- this->AddSurface( surf );
- }
- } else {
- // search for material matches
- for ( i = 0; i < ma->objects.Num(); i++ ) {
- object = ma->objects[i];
- if(object->materialRef >= 0) {
- material = ma->materials[object->materialRef];
- im1 = declManager->FindMaterial( material->name );
- } else {
- im1 = tr.defaultMaterial;
- }
- if ( im1->IsDiscrete() ) {
- // flares, autosprites, etc
- j = this->NumSurfaces();
- } else {
- for ( j = 0; j < this->NumSurfaces(); j++ ) {
- modelSurf = &this->surfaces[j];
- im2 = modelSurf->shader;
- if ( im1 == im2 ) {
- // merge this
- mergeTo[i] = j;
- break;
- }
- }
- }
- if ( j == this->NumSurfaces() ) {
- // didn't merge
- mergeTo[i] = j;
- surf.shader = im1;
- surf.id = this->NumSurfaces();
- this->AddSurface( surf );
- }
- }
- }
- idVectorSubset<idVec3, 3> vertexSubset;
- idVectorSubset<idVec2, 2> texCoordSubset;
- // build the surfaces
- for ( objectNum = 0; objectNum < ma->objects.Num(); objectNum++ ) {
- object = ma->objects[objectNum];
- mesh = &object->mesh;
- if(object->materialRef >= 0) {
- material = ma->materials[object->materialRef];
- im1 = declManager->FindMaterial( material->name );
- } else {
- im1 = tr.defaultMaterial;
- }
- bool normalsParsed = mesh->normalsParsed;
-
- // completely ignore any explict normals on surfaces with a renderbump command
- // which will guarantee the best contours and least vertexes.
- const char *rb = im1->GetRenderBump();
- if ( rb != NULL && rb[0] != NULL ) {
- normalsParsed = false;
- }
- // It seems like the tools our artists are using often generate
- // verts and texcoords slightly separated that should be merged
- // note that we really should combine the surfaces with common materials
- // before doing this operation, because we can miss a slop combination
- // if they are in different surfaces
- vRemap = (int *)R_StaticAlloc( mesh->numVertexes * sizeof( vRemap[0] ), TAG_MODEL );
- if ( fastLoad ) {
- // renderbump doesn't care about vertex count
- for ( j = 0; j < mesh->numVertexes; j++ ) {
- vRemap[j] = j;
- }
- } else {
- float vertexEpsilon = r_slopVertex.GetFloat();
- float expand = 2 * 32 * vertexEpsilon;
- idVec3 mins, maxs;
- SIMDProcessor->MinMax( mins, maxs, mesh->vertexes, mesh->numVertexes );
- mins -= idVec3( expand, expand, expand );
- maxs += idVec3( expand, expand, expand );
- vertexSubset.Init( mins, maxs, 32, 1024 );
- for ( j = 0; j < mesh->numVertexes; j++ ) {
- vRemap[j] = vertexSubset.FindVector( mesh->vertexes, j, vertexEpsilon );
- }
- }
- tvRemap = (int *)R_StaticAlloc( mesh->numTVertexes * sizeof( tvRemap[0] ), TAG_MODEL );
- if ( fastLoad ) {
- // renderbump doesn't care about vertex count
- for ( j = 0; j < mesh->numTVertexes; j++ ) {
- tvRemap[j] = j;
- }
- } else {
- float texCoordEpsilon = r_slopTexCoord.GetFloat();
- float expand = 2 * 32 * texCoordEpsilon;
- idVec2 mins, maxs;
- SIMDProcessor->MinMax( mins, maxs, mesh->tvertexes, mesh->numTVertexes );
- mins -= idVec2( expand, expand );
- maxs += idVec2( expand, expand );
- texCoordSubset.Init( mins, maxs, 32, 1024 );
- for ( j = 0; j < mesh->numTVertexes; j++ ) {
- tvRemap[j] = texCoordSubset.FindVector( mesh->tvertexes, j, texCoordEpsilon );
- }
- }
- // we need to find out how many unique vertex / texcoord / color combinations
- // there are, because MA tracks them separately but we need them unified
- // the maximum possible number of combined vertexes is the number of indexes
- mvTable = (matchVert_t *)R_ClearedStaticAlloc( mesh->numFaces * 3 * sizeof( mvTable[0] ) );
- // we will have a hash chain based on the xyz values
- mvHash = (matchVert_t **)R_ClearedStaticAlloc( mesh->numVertexes * sizeof( mvHash[0] ) );
- // allocate triangle surface
- tri = R_AllocStaticTriSurf();
- tri->numVerts = 0;
- tri->numIndexes = 0;
- R_AllocStaticTriSurfIndexes( tri, mesh->numFaces * 3 );
- tri->generateNormals = !normalsParsed;
- // init default normal, color and tex coord index
- normal.Zero();
- color = identityColor;
- tv = 0;
- // find all the unique combinations
- float normalEpsilon = 1.0f - r_slopNormal.GetFloat();
- for ( j = 0; j < mesh->numFaces; j++ ) {
- for ( k = 0; k < 3; k++ ) {
- v = mesh->faces[j].vertexNum[k];
- if ( v < 0 || v >= mesh->numVertexes ) {
- common->Error( "ConvertMAToModelSurfaces: bad vertex index in MA file %s", name.c_str() );
- }
- // collapse the position if it was slightly offset
- v = vRemap[v];
- // we may or may not have texcoords to compare
- if ( mesh->numTVertexes != 0 ) {
- tv = mesh->faces[j].tVertexNum[k];
- if ( tv < 0 || tv >= mesh->numTVertexes ) {
- common->Error( "ConvertMAToModelSurfaces: bad tex coord index in MA file %s", name.c_str() );
- }
- // collapse the tex coord if it was slightly offset
- tv = tvRemap[tv];
- }
- // we may or may not have normals to compare
- if ( normalsParsed ) {
- normal = mesh->faces[j].vertexNormals[k];
- }
- //BSM: Todo: Fix the vertex colors
- // we may or may not have colors to compare
- if ( mesh->faces[j].vertexColors[k] != -1 && mesh->faces[j].vertexColors[k] != -999 ) {
- color = &mesh->colors[mesh->faces[j].vertexColors[k]*4];
- }
- // find a matching vert
- for ( lastmv = NULL, mv = mvHash[v]; mv != NULL; lastmv = mv, mv = mv->next ) {
- if ( mv->tv != tv ) {
- continue;
- }
- if ( *(unsigned *)mv->color != *(unsigned *)color ) {
- continue;
- }
- if ( !normalsParsed ) {
- // if we are going to create the normals, just
- // matching texcoords is enough
- break;
- }
- if ( mv->normal * normal > normalEpsilon ) {
- break; // we already have this one
- }
- }
- if ( !mv ) {
- // allocate a new match vert and link to hash chain
- mv = &mvTable[ tri->numVerts ];
- mv->v = v;
- mv->tv = tv;
- mv->normal = normal;
- *(unsigned *)mv->color = *(unsigned *)color;
- mv->next = NULL;
- if ( lastmv ) {
- lastmv->next = mv;
- } else {
- mvHash[v] = mv;
- }
- tri->numVerts++;
- }
- tri->indexes[tri->numIndexes] = mv - mvTable;
- tri->numIndexes++;
- }
- }
- // allocate space for the indexes and copy them
- if ( tri->numIndexes > mesh->numFaces * 3 ) {
- common->FatalError( "ConvertMAToModelSurfaces: index miscount in MA file %s", name.c_str() );
- }
- if ( tri->numVerts > mesh->numFaces * 3 ) {
- common->FatalError( "ConvertMAToModelSurfaces: vertex miscount in MA file %s", name.c_str() );
- }
- // an MA allows the texture coordinates to be scaled, translated, and rotated
- //BSM: Todo: Does Maya support this and if so how
- //if ( ase->materials.Num() == 0 ) {
- uOffset = vOffset = 0.0f;
- uTiling = vTiling = 1.0f;
- textureSin = 0.0f;
- textureCos = 1.0f;
- //} else {
- // material = ase->materials[object->materialRef];
- // uOffset = -material->uOffset;
- // vOffset = material->vOffset;
- // uTiling = material->uTiling;
- // vTiling = material->vTiling;
- // textureSin = idMath::Sin( material->angle );
- // textureCos = idMath::Cos( material->angle );
- //}
- // now allocate and generate the combined vertexes
- R_AllocStaticTriSurfVerts( tri, tri->numVerts );
- for ( j = 0; j < tri->numVerts; j++ ) {
- mv = &mvTable[j];
- tri->verts[ j ].Clear();
- tri->verts[ j ].xyz = mesh->vertexes[ mv->v ];
- tri->verts[ j ].SetNormal( mv->normal );
- *(unsigned *)tri->verts[j].color = *(unsigned *)mv->color;
- if ( mesh->numTVertexes != 0 ) {
- const idVec2 &tv = mesh->tvertexes[ mv->tv ];
- float u = tv.x * uTiling + uOffset;
- float v = tv.y * vTiling + vOffset;
- tri->verts[j].SetTexCoord( u * textureCos + v * textureSin, u * -textureSin + v * textureCos );
- }
- }
- R_StaticFree( mvTable );
- R_StaticFree( mvHash );
- R_StaticFree( tvRemap );
- R_StaticFree( vRemap );
- // see if we need to merge with a previous surface of the same material
- modelSurf = &this->surfaces[mergeTo[ objectNum ]];
- srfTriangles_t *mergeTri = modelSurf->geometry;
- if ( !mergeTri ) {
- modelSurf->geometry = tri;
- } else {
- modelSurf->geometry = R_MergeTriangles( mergeTri, tri );
- R_FreeStaticTriSurf( tri );
- R_FreeStaticTriSurf( mergeTri );
- }
- }
- return true;
- }
- /*
- =================
- idRenderModelStatic::LoadASE
- =================
- */
- bool idRenderModelStatic::LoadASE( const char *fileName ) {
- aseModel_t *ase;
- ase = ASE_Load( fileName );
- if ( ase == NULL ) {
- return false;
- }
- ConvertASEToModelSurfaces( ase );
- ASE_Free( ase );
- return true;
- }
- /*
- =================
- idRenderModelStatic::LoadLWO
- =================
- */
- bool idRenderModelStatic::LoadLWO( const char *fileName ) {
- unsigned int failID;
- int failPos;
- lwObject *lwo;
- lwo = lwGetObject( fileName, &failID, &failPos );
- if ( lwo == NULL ) {
- return false;
- }
- ConvertLWOToModelSurfaces( lwo );
- lwFreeObject( lwo );
- return true;
- }
- /*
- =================
- idRenderModelStatic::LoadMA
- =================
- */
- bool idRenderModelStatic::LoadMA( const char *fileName ) {
- maModel_t *ma;
- ma = MA_Load( fileName );
- if ( ma == NULL ) {
- return false;
- }
- ConvertMAToModelSurfaces( ma );
- MA_Free( ma );
- return true;
- }
- //=============================================================================
- /*
- ================
- idRenderModelStatic::PurgeModel
- ================
- */
- void idRenderModelStatic::PurgeModel() {
- for ( int i = 0; i < surfaces.Num(); i++ ) {
- modelSurface_t * surf = &surfaces[i];
- if ( surf->geometry ) {
- R_FreeStaticTriSurf( surf->geometry );
- }
- }
- surfaces.Clear();
- if ( jointsInverted != NULL ) {
- Mem_Free( jointsInverted );
- jointsInverted = NULL;
- }
- purged = true;
- }
- /*
- ==============
- idRenderModelStatic::FreeVertexCache
- We are about to restart the vertex cache, so dump everything
- ==============
- */
- void idRenderModelStatic::FreeVertexCache() {
- for ( int j = 0; j < surfaces.Num(); j++ ) {
- srfTriangles_t *tri = surfaces[j].geometry;
- if ( tri == NULL ) {
- continue;
- }
- R_FreeStaticTriSurfVertexCaches( tri );
- }
- }
- /*
- ================
- idRenderModelStatic::ReadFromDemoFile
- ================
- */
- void idRenderModelStatic::ReadFromDemoFile( class idDemoFile *f ) {
- PurgeModel();
- InitEmpty( f->ReadHashString() );
- int i, j, numSurfaces;
- f->ReadInt( numSurfaces );
-
- for ( i = 0; i < numSurfaces; i++ ) {
- modelSurface_t surf;
-
- surf.shader = declManager->FindMaterial( f->ReadHashString() );
-
- srfTriangles_t *tri = R_AllocStaticTriSurf();
-
- f->ReadInt( tri->numIndexes );
- R_AllocStaticTriSurfIndexes( tri, tri->numIndexes );
- for ( j = 0; j < tri->numIndexes; ++j )
- f->ReadInt( (int&)tri->indexes[j] );
-
- f->ReadInt( tri->numVerts );
- R_AllocStaticTriSurfVerts( tri, tri->numVerts );
- idVec3 tNormal, tTangent, tBiTangent;
- for ( j = 0; j < tri->numVerts; ++j ) {
- f->ReadVec3( tri->verts[j].xyz );
- f->ReadBigArray( tri->verts[j].st, 2 );
- f->ReadBigArray( tri->verts[j].normal, 4 );
- f->ReadBigArray( tri->verts[j].tangent, 4 );
- f->ReadUnsignedChar( tri->verts[j].color[0] );
- f->ReadUnsignedChar( tri->verts[j].color[1] );
- f->ReadUnsignedChar( tri->verts[j].color[2] );
- f->ReadUnsignedChar( tri->verts[j].color[3] );
- }
-
- surf.geometry = tri;
-
- this->AddSurface( surf );
- }
- this->FinishSurfaces();
- }
- /*
- ================
- idRenderModelStatic::WriteToDemoFile
- ================
- */
- void idRenderModelStatic::WriteToDemoFile( class idDemoFile *f ) {
- int data[1];
- // note that it has been updated
- lastArchivedFrame = tr.frameCount;
- data[0] = DC_DEFINE_MODEL;
- f->WriteInt( data[0] );
- f->WriteHashString( this->Name() );
- int i, j, iData = surfaces.Num();
- f->WriteInt( iData );
- for ( i = 0; i < surfaces.Num(); i++ ) {
- const modelSurface_t *surf = &surfaces[i];
-
- f->WriteHashString( surf->shader->GetName() );
-
- srfTriangles_t *tri = surf->geometry;
- f->WriteInt( tri->numIndexes );
- for ( j = 0; j < tri->numIndexes; ++j )
- f->WriteInt( (int&)tri->indexes[j] );
- f->WriteInt( tri->numVerts );
- for ( j = 0; j < tri->numVerts; ++j ) {
- f->WriteVec3( tri->verts[j].xyz );
- f->WriteBigArray( tri->verts[j].st, 2 );
- f->WriteBigArray( tri->verts[j].normal, 4 );
- f->WriteBigArray( tri->verts[j].tangent, 4 );
- f->WriteUnsignedChar( tri->verts[j].color[0] );
- f->WriteUnsignedChar( tri->verts[j].color[1] );
- f->WriteUnsignedChar( tri->verts[j].color[2] );
- f->WriteUnsignedChar( tri->verts[j].color[3] );
- }
- }
- }
- /*
- ================
- idRenderModelStatic::IsLoaded
- ================
- */
- bool idRenderModelStatic::IsLoaded() {
- return !purged;
- }
- /*
- ================
- idRenderModelStatic::SetLevelLoadReferenced
- ================
- */
- void idRenderModelStatic::SetLevelLoadReferenced( bool referenced ) {
- levelLoadReferenced = referenced;
- }
- /*
- ================
- idRenderModelStatic::IsLevelLoadReferenced
- ================
- */
- bool idRenderModelStatic::IsLevelLoadReferenced() {
- return levelLoadReferenced;
- }
- /*
- =================
- idRenderModelStatic::TouchData
- =================
- */
- void idRenderModelStatic::TouchData() {
- for ( int i = 0; i < surfaces.Num(); i++ ) {
- const modelSurface_t *surf = &surfaces[i];
- // re-find the material to make sure it gets added to the
- // level keep list
- declManager->FindMaterial( surf->shader->GetName() );
- }
- }
- /*
- =================
- idRenderModelStatic::DeleteSurfaceWithId
- =================
- */
- bool idRenderModelStatic::DeleteSurfaceWithId( int id ) {
- int i;
- for ( i = 0; i < surfaces.Num(); i++ ) {
- if ( surfaces[i].id == id ) {
- R_FreeStaticTriSurf( surfaces[i].geometry );
- surfaces.RemoveIndex( i );
- return true;
- }
- }
- return false;
- }
- /*
- =================
- idRenderModelStatic::DeleteSurfacesWithNegativeId
- =================
- */
- void idRenderModelStatic::DeleteSurfacesWithNegativeId() {
- for ( int i = 0; i < surfaces.Num(); i++ ) {
- if ( surfaces[i].id < 0 ) {
- R_FreeStaticTriSurf( surfaces[i].geometry );
- surfaces.RemoveIndex( i );
- i--;
- }
- }
- }
- /*
- =================
- idRenderModelStatic::FindSurfaceWithId
- =================
- */
- bool idRenderModelStatic::FindSurfaceWithId( int id, int &surfaceNum ) const {
- for ( int i = 0; i < surfaces.Num(); i++ ) {
- if ( surfaces[i].id == id ) {
- surfaceNum = i;
- return true;
- }
- }
- return false;
- }
|