123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977 |
- /*
- ===========================================================================
- 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"
- /*
- ==============================================================================
- TRIANGLE MESH PROCESSING
- The functions in this file have no vertex / index count limits.
- Truly identical vertexes that match in position, normal, and texcoord can
- be merged away.
- Vertexes that match in position and texcoord, but have distinct normals will
- remain distinct for all purposes. This is usually a poor choice for models,
- as adding a bevel face will not add any more vertexes, and will tend to
- look better.
- Match in position and normal, but differ in texcoords are referenced together
- for calculating tangent vectors for bump mapping.
- Artists should take care to have identical texels in all maps (bump/diffuse/specular)
- in this case
- Vertexes that only match in position are merged for shadow edge finding.
- Degenerate triangles.
- Overlapped triangles, even if normals or texcoords differ, must be removed.
- for the silhoette based stencil shadow algorithm to function properly.
- Is this true???
- Is the overlapped triangle problem just an example of the trippled edge problem?
- Interpenetrating triangles are not currently clipped to surfaces.
- Do they effect the shadows?
- if vertexes are intended to deform apart, make sure that no vertexes
- are on top of each other in the base frame, or the sil edges may be
- calculated incorrectly.
- We might be able to identify this from topology.
- Dangling edges are acceptable, but three way edges are not.
- Are any combinations of two way edges unacceptable, like one facing
- the backside of the other?
- Topology is determined by a collection of triangle indexes.
- The edge list can be built up from this, and stays valid even under
- deformations.
- Somewhat non-intuitively, concave edges cannot be optimized away, or the
- stencil shadow algorithm miscounts.
- Face normals are needed for generating shadow volumes and for calculating
- the silhouette, but they will change with any deformation.
- Vertex normals and vertex tangents will change with each deformation,
- but they may be able to be transformed instead of recalculated.
- bounding volume, both box and sphere will change with deformation.
- silhouette indexes
- shade indexes
- texture indexes
- shade indexes will only be > silhouette indexes if there is facet shading present
- lookups from texture to sil and texture to shade?
- The normal and tangent vector smoothing is simple averaging, no attempt is
- made to better handle the cases where the distribution around the shared vertex
- is highly uneven.
- we may get degenerate triangles even with the uniquing and removal
- if the vertexes have different texcoords.
- ==============================================================================
- */
- // this shouldn't change anything, but previously renderbumped models seem to need it
- #define USE_INVA
- // instead of using the texture T vector, cross the normal and S vector for an orthogonal axis
- #define DERIVE_UNSMOOTHED_BITANGENT
- /*
- =================
- R_TriSurfMemory
- For memory profiling
- =================
- */
- int R_TriSurfMemory( const srfTriangles_t *tri ) {
- int total = 0;
- if ( tri == NULL ) {
- return total;
- }
- if ( tri->preLightShadowVertexes != NULL ) {
- total += tri->numVerts * 2 * sizeof( tri->preLightShadowVertexes[0] );
- }
- if ( tri->staticShadowVertexes != NULL ) {
- total += tri->numVerts * 2 * sizeof( tri->staticShadowVertexes[0] );
- }
- if ( tri->verts != NULL ) {
- if ( tri->ambientSurface == NULL || tri->verts != tri->ambientSurface->verts ) {
- total += tri->numVerts * sizeof( tri->verts[0] );
- }
- }
- if ( tri->indexes != NULL ) {
- if ( tri->ambientSurface == NULL || tri->indexes != tri->ambientSurface->indexes ) {
- total += tri->numIndexes * sizeof( tri->indexes[0] );
- }
- }
- if ( tri->silIndexes != NULL ) {
- total += tri->numIndexes * sizeof( tri->silIndexes[0] );
- }
- if ( tri->silEdges != NULL ) {
- total += tri->numSilEdges * sizeof( tri->silEdges[0] );
- }
- if ( tri->dominantTris != NULL ) {
- total += tri->numVerts * sizeof( tri->dominantTris[0] );
- }
- if ( tri->mirroredVerts != NULL ) {
- total += tri->numMirroredVerts * sizeof( tri->mirroredVerts[0] );
- }
- if ( tri->dupVerts != NULL ) {
- total += tri->numDupVerts * sizeof( tri->dupVerts[0] );
- }
- total += sizeof( *tri );
- return total;
- }
- /*
- ==============
- R_FreeStaticTriSurfVertexCaches
- ==============
- */
- void R_FreeStaticTriSurfVertexCaches( srfTriangles_t * tri ) {
- // we don't support reclaiming static geometry memory
- // without a level change
- tri->ambientCache = 0;
- tri->indexCache = 0;
- tri->shadowCache = 0;
- }
- /*
- ==============
- R_FreeStaticTriSurf
- ==============
- */
- void R_FreeStaticTriSurf( srfTriangles_t *tri ) {
- if ( !tri ) {
- return;
- }
- R_FreeStaticTriSurfVertexCaches( tri );
- if ( !tri->referencedVerts ) {
- if ( tri->verts != NULL ) {
- // R_CreateLightTris points tri->verts at the verts of the ambient surface
- if ( tri->ambientSurface == NULL || tri->verts != tri->ambientSurface->verts ) {
- Mem_Free( tri->verts );
- }
- }
- }
- if ( !tri->referencedIndexes ) {
- if ( tri->indexes != NULL ) {
- // if a surface is completely inside a light volume R_CreateLightTris points tri->indexes at the indexes of the ambient surface
- if ( tri->ambientSurface == NULL || tri->indexes != tri->ambientSurface->indexes ) {
- Mem_Free( tri->indexes );
- }
- }
- if ( tri->silIndexes != NULL ) {
- Mem_Free( tri->silIndexes );
- }
- if ( tri->silEdges != NULL ) {
- Mem_Free( tri->silEdges );
- }
- if ( tri->dominantTris != NULL ) {
- Mem_Free( tri->dominantTris );
- }
- if ( tri->mirroredVerts != NULL ) {
- Mem_Free( tri->mirroredVerts );
- }
- if ( tri->dupVerts != NULL ) {
- Mem_Free( tri->dupVerts );
- }
- }
- if ( tri->preLightShadowVertexes != NULL ) {
- Mem_Free( tri->preLightShadowVertexes );
- }
- if ( tri->staticShadowVertexes != NULL ) {
- Mem_Free( tri->staticShadowVertexes );
- }
- // clear the tri out so we don't retain stale data
- memset( tri, 0, sizeof( srfTriangles_t ) );
- Mem_Free( tri );
- }
- /*
- ==============
- R_FreeStaticTriSurfVerts
- ==============
- */
- void R_FreeStaticTriSurfVerts( srfTriangles_t *tri ) {
- // we don't support reclaiming static geometry memory
- // without a level change
- tri->ambientCache = 0;
- if ( tri->verts != NULL ) {
- // R_CreateLightTris points tri->verts at the verts of the ambient surface
- if ( tri->ambientSurface == NULL || tri->verts != tri->ambientSurface->verts ) {
- Mem_Free( tri->verts );
- }
- }
- }
- /*
- ==============
- R_AllocStaticTriSurf
- ==============
- */
- srfTriangles_t *R_AllocStaticTriSurf() {
- srfTriangles_t *tris = (srfTriangles_t *)Mem_ClearedAlloc( sizeof( srfTriangles_t ), TAG_SRFTRIS );
- return tris;
- }
- /*
- =================
- R_CopyStaticTriSurf
- This only duplicates the indexes and verts, not any of the derived data.
- =================
- */
- srfTriangles_t *R_CopyStaticTriSurf( const srfTriangles_t *tri ) {
- srfTriangles_t *newTri;
- newTri = R_AllocStaticTriSurf();
- R_AllocStaticTriSurfVerts( newTri, tri->numVerts );
- R_AllocStaticTriSurfIndexes( newTri, tri->numIndexes );
- newTri->numVerts = tri->numVerts;
- newTri->numIndexes = tri->numIndexes;
- memcpy( newTri->verts, tri->verts, tri->numVerts * sizeof( newTri->verts[0] ) );
- memcpy( newTri->indexes, tri->indexes, tri->numIndexes * sizeof( newTri->indexes[0] ) );
- return newTri;
- }
- /*
- =================
- R_AllocStaticTriSurfVerts
- =================
- */
- void R_AllocStaticTriSurfVerts( srfTriangles_t *tri, int numVerts ) {
- assert( tri->verts == NULL );
- tri->verts = (idDrawVert *)Mem_Alloc16( numVerts * sizeof( idDrawVert ), TAG_TRI_VERTS );
- }
- /*
- =================
- R_AllocStaticTriSurfIndexes
- =================
- */
- void R_AllocStaticTriSurfIndexes( srfTriangles_t *tri, int numIndexes ) {
- assert( tri->indexes == NULL );
- tri->indexes = (triIndex_t *)Mem_Alloc16( numIndexes * sizeof( triIndex_t ), TAG_TRI_INDEXES );
- }
- /*
- =================
- R_AllocStaticTriSurfSilIndexes
- =================
- */
- void R_AllocStaticTriSurfSilIndexes( srfTriangles_t *tri, int numIndexes ) {
- assert( tri->silIndexes == NULL );
- tri->silIndexes = (triIndex_t *)Mem_Alloc16( numIndexes * sizeof( triIndex_t ), TAG_TRI_SIL_INDEXES );
- }
- /*
- =================
- R_AllocStaticTriSurfDominantTris
- =================
- */
- void R_AllocStaticTriSurfDominantTris( srfTriangles_t *tri, int numVerts ) {
- assert( tri->dominantTris == NULL );
- tri->dominantTris = (dominantTri_t *)Mem_Alloc16( numVerts * sizeof( dominantTri_t ), TAG_TRI_DOMINANT_TRIS );
- }
- /*
- =================
- R_AllocStaticTriSurfMirroredVerts
- =================
- */
- void R_AllocStaticTriSurfMirroredVerts( srfTriangles_t *tri, int numMirroredVerts ) {
- assert( tri->mirroredVerts == NULL );
- tri->mirroredVerts = (int *)Mem_Alloc16( numMirroredVerts * sizeof( *tri->mirroredVerts ), TAG_TRI_MIR_VERT );
- }
- /*
- =================
- R_AllocStaticTriSurfDupVerts
- =================
- */
- void R_AllocStaticTriSurfDupVerts( srfTriangles_t *tri, int numDupVerts ) {
- assert( tri->dupVerts == NULL );
- tri->dupVerts = (int *)Mem_Alloc16( numDupVerts * 2 * sizeof( *tri->dupVerts ), TAG_TRI_DUP_VERT );
- }
- /*
- =================
- R_AllocStaticTriSurfSilEdges
- =================
- */
- void R_AllocStaticTriSurfSilEdges( srfTriangles_t *tri, int numSilEdges ) {
- assert( tri->silEdges == NULL );
- tri->silEdges = (silEdge_t *)Mem_Alloc16( numSilEdges * sizeof( silEdge_t ), TAG_TRI_SIL_EDGE );
- }
- /*
- =================
- R_AllocStaticTriSurfPreLightShadowVerts
- =================
- */
- void R_AllocStaticTriSurfPreLightShadowVerts( srfTriangles_t *tri, int numVerts ) {
- assert( tri->preLightShadowVertexes == NULL );
- tri->preLightShadowVertexes = (idShadowVert *)Mem_Alloc16( numVerts * sizeof( idShadowVert ), TAG_TRI_SHADOW );
- }
- /*
- =================
- R_ResizeStaticTriSurfVerts
- =================
- */
- void R_ResizeStaticTriSurfVerts( srfTriangles_t *tri, int numVerts ) {
- idDrawVert * newVerts = (idDrawVert *)Mem_Alloc16( numVerts * sizeof( idDrawVert ), TAG_TRI_VERTS );
- const int copy = std::min( numVerts, tri->numVerts );
- memcpy( newVerts, tri->verts, copy * sizeof( idDrawVert ) );
- Mem_Free( tri->verts );
- tri->verts = newVerts;
- }
- /*
- =================
- R_ResizeStaticTriSurfIndexes
- =================
- */
- void R_ResizeStaticTriSurfIndexes( srfTriangles_t *tri, int numIndexes ) {
- triIndex_t * newIndexes = (triIndex_t *)Mem_Alloc16( numIndexes * sizeof( triIndex_t ), TAG_TRI_INDEXES );
- const int copy = std::min( numIndexes, tri->numIndexes );
- memcpy( newIndexes, tri->indexes, copy * sizeof( triIndex_t ) );
- Mem_Free( tri->indexes );
- tri->indexes = newIndexes;
- }
- /*
- =================
- R_ReferenceStaticTriSurfVerts
- =================
- */
- void R_ReferenceStaticTriSurfVerts( srfTriangles_t *tri, const srfTriangles_t *reference ) {
- tri->verts = reference->verts;
- }
- /*
- =================
- R_ReferenceStaticTriSurfIndexes
- =================
- */
- void R_ReferenceStaticTriSurfIndexes( srfTriangles_t *tri, const srfTriangles_t *reference ) {
- tri->indexes = reference->indexes;
- }
- /*
- =================
- R_FreeStaticTriSurfSilIndexes
- =================
- */
- void R_FreeStaticTriSurfSilIndexes( srfTriangles_t *tri ) {
- Mem_Free( tri->silIndexes );
- tri->silIndexes = NULL;
- }
- /*
- ===============
- R_RangeCheckIndexes
- Check for syntactically incorrect indexes, like out of range values.
- Does not check for semantics, like degenerate triangles.
- No vertexes is acceptable if no indexes.
- No indexes is acceptable.
- More vertexes than are referenced by indexes are acceptable.
- ===============
- */
- void R_RangeCheckIndexes( const srfTriangles_t *tri ) {
- int i;
- if ( tri->numIndexes < 0 ) {
- common->Error( "R_RangeCheckIndexes: numIndexes < 0" );
- }
- if ( tri->numVerts < 0 ) {
- common->Error( "R_RangeCheckIndexes: numVerts < 0" );
- }
- // must specify an integral number of triangles
- if ( tri->numIndexes % 3 != 0 ) {
- common->Error( "R_RangeCheckIndexes: numIndexes %% 3" );
- }
- for ( i = 0; i < tri->numIndexes; i++ ) {
- if ( tri->indexes[i] >= tri->numVerts ) {
- common->Error( "R_RangeCheckIndexes: index out of range" );
- }
- }
- // this should not be possible unless there are unused verts
- if ( tri->numVerts > tri->numIndexes ) {
- // FIXME: find the causes of these
- // common->Printf( "R_RangeCheckIndexes: tri->numVerts > tri->numIndexes\n" );
- }
- }
- /*
- =================
- R_BoundTriSurf
- =================
- */
- void R_BoundTriSurf( srfTriangles_t *tri ) {
- SIMDProcessor->MinMax( tri->bounds[0], tri->bounds[1], tri->verts, tri->numVerts );
- }
- /*
- =================
- R_CreateSilRemap
- =================
- */
- static int *R_CreateSilRemap( const srfTriangles_t *tri ) {
- int c_removed, c_unique;
- int *remap;
- int i, j, hashKey;
- const idDrawVert *v1, *v2;
- remap = (int *)R_ClearedStaticAlloc( tri->numVerts * sizeof( remap[0] ) );
- if ( !r_useSilRemap.GetBool() ) {
- for ( i = 0; i < tri->numVerts; i++ ) {
- remap[i] = i;
- }
- return remap;
- }
- idHashIndex hash( 1024, tri->numVerts );
- c_removed = 0;
- c_unique = 0;
- for ( i = 0; i < tri->numVerts; i++ ) {
- v1 = &tri->verts[i];
- // see if there is an earlier vert that it can map to
- hashKey = hash.GenerateKey( v1->xyz );
- for ( j = hash.First( hashKey ); j >= 0; j = hash.Next( j ) ) {
- v2 = &tri->verts[j];
- if ( v2->xyz[0] == v1->xyz[0]
- && v2->xyz[1] == v1->xyz[1]
- && v2->xyz[2] == v1->xyz[2] ) {
- c_removed++;
- remap[i] = j;
- break;
- }
- }
- if ( j < 0 ) {
- c_unique++;
- remap[i] = i;
- hash.Add( hashKey, i );
- }
- }
- return remap;
- }
- /*
- =================
- R_CreateSilIndexes
- Uniquing vertexes only on xyz before creating sil edges reduces
- the edge count by about 20% on Q3 models
- =================
- */
- void R_CreateSilIndexes( srfTriangles_t *tri ) {
- int i;
- int *remap;
- if ( tri->silIndexes ) {
- Mem_Free( tri->silIndexes );
- tri->silIndexes = NULL;
- }
- remap = R_CreateSilRemap( tri );
- // remap indexes to the first one
- R_AllocStaticTriSurfSilIndexes( tri, tri->numIndexes );
- assert( tri->silIndexes != NULL );
- for ( i = 0; i < tri->numIndexes; i++ ) {
- tri->silIndexes[i] = remap[tri->indexes[i]];
- }
- R_StaticFree( remap );
- }
- /*
- =====================
- R_CreateDupVerts
- =====================
- */
- void R_CreateDupVerts( srfTriangles_t *tri ) {
- int i;
- idTempArray<int> remap( tri->numVerts );
- // initialize vertex remap in case there are unused verts
- for ( i = 0; i < tri->numVerts; i++ ) {
- remap[i] = i;
- }
- // set the remap based on how the silhouette indexes are remapped
- for ( i = 0; i < tri->numIndexes; i++ ) {
- remap[tri->indexes[i]] = tri->silIndexes[i];
- }
- // create duplicate vertex index based on the vertex remap
- idTempArray<int> tempDupVerts( tri->numVerts * 2 );
- tri->numDupVerts = 0;
- for ( i = 0; i < tri->numVerts; i++ ) {
- if ( remap[i] != i ) {
- tempDupVerts[tri->numDupVerts*2+0] = i;
- tempDupVerts[tri->numDupVerts*2+1] = remap[i];
- tri->numDupVerts++;
- }
- }
- R_AllocStaticTriSurfDupVerts( tri, tri->numDupVerts );
- memcpy( tri->dupVerts, tempDupVerts.Ptr(), tri->numDupVerts * 2 * sizeof( tri->dupVerts[0] ) );
- }
- /*
- ===============
- R_DefineEdge
- ===============
- */
- static int c_duplicatedEdges, c_tripledEdges;
- static const int MAX_SIL_EDGES = 0x7ffff;
- static void R_DefineEdge( const int v1, const int v2, const int planeNum, const int numPlanes,
- idList<silEdge_t> & silEdges, idHashIndex & silEdgeHash ) {
- int i, hashKey;
- // check for degenerate edge
- if ( v1 == v2 ) {
- return;
- }
- hashKey = silEdgeHash.GenerateKey( v1, v2 );
- // search for a matching other side
- for ( i = silEdgeHash.First( hashKey ); i >= 0 && i < MAX_SIL_EDGES; i = silEdgeHash.Next( i ) ) {
- if ( silEdges[i].v1 == v1 && silEdges[i].v2 == v2 ) {
- c_duplicatedEdges++;
- // allow it to still create a new edge
- continue;
- }
- if ( silEdges[i].v2 == v1 && silEdges[i].v1 == v2 ) {
- if ( silEdges[i].p2 != numPlanes ) {
- c_tripledEdges++;
- // allow it to still create a new edge
- continue;
- }
- // this is a matching back side
- silEdges[i].p2 = planeNum;
- return;
- }
- }
- // define the new edge
- silEdgeHash.Add( hashKey, silEdges.Num() );
- silEdge_t silEdge;
- silEdge.p1 = planeNum;
- silEdge.p2 = numPlanes;
- silEdge.v1 = v1;
- silEdge.v2 = v2;
- silEdges.Append( silEdge );
- }
- /*
- =================
- SilEdgeSort
- =================
- */
- static int SilEdgeSort( const void *a, const void *b ) {
- if ( ((silEdge_t *)a)->p1 < ((silEdge_t *)b)->p1 ) {
- return -1;
- }
- if ( ((silEdge_t *)a)->p1 > ((silEdge_t *)b)->p1 ) {
- return 1;
- }
- if ( ((silEdge_t *)a)->p2 < ((silEdge_t *)b)->p2 ) {
- return -1;
- }
- if ( ((silEdge_t *)a)->p2 > ((silEdge_t *)b)->p2 ) {
- return 1;
- }
- return 0;
- }
- /*
- =================
- R_IdentifySilEdges
- If the surface will not deform, coplanar edges (polygon interiors)
- can never create silhouette plains, and can be omited
- =================
- */
- int c_coplanarSilEdges;
- int c_totalSilEdges;
- void R_IdentifySilEdges( srfTriangles_t *tri, bool omitCoplanarEdges ) {
- int i;
- int shared, single;
- omitCoplanarEdges = false; // optimization doesn't work for some reason
- static const int SILEDGE_HASH_SIZE = 1024;
- const int numTris = tri->numIndexes / 3;
- idList<silEdge_t> silEdges( MAX_SIL_EDGES );
- idHashIndex silEdgeHash( SILEDGE_HASH_SIZE, MAX_SIL_EDGES );
- int numPlanes = numTris;
- silEdgeHash.Clear();
- c_duplicatedEdges = 0;
- c_tripledEdges = 0;
- for ( i = 0; i < numTris; i++ ) {
- int i1, i2, i3;
- i1 = tri->silIndexes[ i*3 + 0 ];
- i2 = tri->silIndexes[ i*3 + 1 ];
- i3 = tri->silIndexes[ i*3 + 2 ];
- // create the edges
- R_DefineEdge( i1, i2, i, numPlanes, silEdges, silEdgeHash );
- R_DefineEdge( i2, i3, i, numPlanes, silEdges, silEdgeHash );
- R_DefineEdge( i3, i1, i, numPlanes, silEdges, silEdgeHash );
- }
- if ( c_duplicatedEdges || c_tripledEdges ) {
- common->DWarning( "%i duplicated edge directions, %i tripled edges", c_duplicatedEdges, c_tripledEdges );
- }
- // if we know that the vertexes aren't going
- // to deform, we can remove interior triangulation edges
- // on otherwise planar polygons.
- // I earlier believed that I could also remove concave
- // edges, because they are never silhouettes in the conventional sense,
- // but they are still needed to balance out all the true sil edges
- // for the shadow algorithm to function
- int c_coplanarCulled;
- c_coplanarCulled = 0;
- if ( omitCoplanarEdges ) {
- for ( i = 0; i < silEdges.Num(); i++ ) {
- int i1, i2, i3;
- idPlane plane;
- int base;
- int j;
- float d;
- if ( silEdges[i].p2 == numPlanes ) { // the fake dangling edge
- continue;
- }
- base = silEdges[i].p1 * 3;
- i1 = tri->silIndexes[ base + 0 ];
- i2 = tri->silIndexes[ base + 1 ];
- i3 = tri->silIndexes[ base + 2 ];
- plane.FromPoints( tri->verts[i1].xyz, tri->verts[i2].xyz, tri->verts[i3].xyz );
- // check to see if points of second triangle are not coplanar
- base = silEdges[i].p2 * 3;
- for ( j = 0; j < 3; j++ ) {
- i1 = tri->silIndexes[ base + j ];
- d = plane.Distance( tri->verts[i1].xyz );
- if ( d != 0 ) { // even a small epsilon causes problems
- break;
- }
- }
- if ( j == 3 ) {
- // we can cull this sil edge
- memmove( &silEdges[i], &silEdges[i+1], (silEdges.Num()-i-1) * sizeof( silEdges[i] ) );
- c_coplanarCulled++;
- silEdges.SetNum( silEdges.Num() - 1 );
- i--;
- }
- }
- if ( c_coplanarCulled ) {
- c_coplanarSilEdges += c_coplanarCulled;
- // common->Printf( "%i of %i sil edges coplanar culled\n", c_coplanarCulled,
- // c_coplanarCulled + numSilEdges );
- }
- }
- c_totalSilEdges += silEdges.Num();
- // sort the sil edges based on plane number
- qsort( silEdges.Ptr(), silEdges.Num(), sizeof( silEdges[0] ), SilEdgeSort );
- // count up the distribution.
- // a perfectly built model should only have shared
- // edges, but most models will have some interpenetration
- // and dangling edges
- shared = 0;
- single = 0;
- for ( i = 0; i < silEdges.Num(); i++ ) {
- if ( silEdges[i].p2 == numPlanes ) {
- single++;
- } else {
- shared++;
- }
- }
- if ( !single ) {
- tri->perfectHull = true;
- } else {
- tri->perfectHull = false;
- }
- tri->numSilEdges = silEdges.Num();
- R_AllocStaticTriSurfSilEdges( tri, silEdges.Num() );
- memcpy( tri->silEdges, silEdges.Ptr(), silEdges.Num() * sizeof( tri->silEdges[0] ) );
- }
- /*
- ===============
- R_FaceNegativePolarity
- Returns true if the texture polarity of the face is negative, false if it is positive or zero
- ===============
- */
- static bool R_FaceNegativePolarity( const srfTriangles_t *tri, int firstIndex ) {
- const idDrawVert * a = tri->verts + tri->indexes[firstIndex + 0];
- const idDrawVert * b = tri->verts + tri->indexes[firstIndex + 1];
- const idDrawVert * c = tri->verts + tri->indexes[firstIndex + 2];
- const idVec2 aST = a->GetTexCoord();
- const idVec2 bST = b->GetTexCoord();
- const idVec2 cST = c->GetTexCoord();
- float d0[5];
- d0[3] = bST[0] - aST[0];
- d0[4] = bST[1] - aST[1];
- float d1[5];
- d1[3] = cST[0] - aST[0];
- d1[4] = cST[1] - aST[1];
- const float area = d0[3] * d1[4] - d0[4] * d1[3];
- if ( area >= 0 ) {
- return false;
- }
- return true;
- }
- /*
- ===================
- R_DuplicateMirroredVertexes
- Modifies the surface to bust apart any verts that are shared by both positive and
- negative texture polarities, so tangent space smoothing at the vertex doesn't
- degenerate.
- This will create some identical vertexes (which will eventually get different tangent
- vectors), so never optimize the resulting mesh, or it will get the mirrored edges back.
- Reallocates tri->verts and changes tri->indexes in place
- Silindexes are unchanged by this.
- sets mirroredVerts and mirroredVerts[]
- ===================
- */
- struct tangentVert_t {
- bool polarityUsed[2];
- int negativeRemap;
- };
- static void R_DuplicateMirroredVertexes( srfTriangles_t *tri ) {
- tangentVert_t *vert;
- int i, j;
- int totalVerts;
- int numMirror;
- idTempArray<tangentVert_t> tverts( tri->numVerts );
- tverts.Zero();
- // determine texture polarity of each surface
- // mark each vert with the polarities it uses
- for ( i = 0; i < tri->numIndexes; i+=3 ) {
- int polarity = R_FaceNegativePolarity( tri, i );
- for ( j = 0; j < 3; j++ ) {
- tverts[tri->indexes[i+j]].polarityUsed[ polarity ] = true;
- }
- }
- // now create new vertex indices as needed
- totalVerts = tri->numVerts;
- for ( i = 0; i < tri->numVerts; i++ ) {
- vert = &tverts[i];
- if ( vert->polarityUsed[0] && vert->polarityUsed[1] ) {
- vert->negativeRemap = totalVerts;
- totalVerts++;
- }
- }
- tri->numMirroredVerts = totalVerts - tri->numVerts;
- if ( tri->numMirroredVerts == 0 ) {
- tri->mirroredVerts = NULL;
- return;
- }
- // now create the new list
- R_AllocStaticTriSurfMirroredVerts( tri, tri->numMirroredVerts );
- R_ResizeStaticTriSurfVerts( tri, totalVerts );
- // create the duplicates
- numMirror = 0;
- for ( i = 0; i < tri->numVerts; i++ ) {
- j = tverts[i].negativeRemap;
- if ( j ) {
- tri->verts[j] = tri->verts[i];
- tri->mirroredVerts[numMirror] = i;
- numMirror++;
- }
- }
- tri->numVerts = totalVerts;
- // change the indexes
- for ( i = 0; i < tri->numIndexes; i++ ) {
- if ( tverts[tri->indexes[i]].negativeRemap && R_FaceNegativePolarity( tri, 3 * ( i / 3 ) ) ) {
- tri->indexes[i] = tverts[tri->indexes[i]].negativeRemap;
- }
- }
- }
- /*
- ============
- R_DeriveNormalsAndTangents
- Derives the normal and orthogonal tangent vectors for the triangle vertices.
- For each vertex the normal and tangent vectors are derived from all triangles
- using the vertex which results in smooth tangents across the mesh.
- ============
- */
- void R_DeriveNormalsAndTangents( srfTriangles_t *tri ) {
- idTempArray< idVec3 > vertexNormals( tri->numVerts );
- idTempArray< idVec3 > vertexTangents( tri->numVerts );
- idTempArray< idVec3 > vertexBitangents( tri->numVerts );
- vertexNormals.Zero();
- vertexTangents.Zero();
- vertexBitangents.Zero();
- for ( int i = 0; i < tri->numIndexes; i += 3 ) {
- const int v0 = tri->indexes[i + 0];
- const int v1 = tri->indexes[i + 1];
- const int v2 = tri->indexes[i + 2];
- const idDrawVert * a = tri->verts + v0;
- const idDrawVert * b = tri->verts + v1;
- const idDrawVert * c = tri->verts + v2;
- const idVec2 aST = a->GetTexCoord();
- const idVec2 bST = b->GetTexCoord();
- const idVec2 cST = c->GetTexCoord();
- float d0[5];
- d0[0] = b->xyz[0] - a->xyz[0];
- d0[1] = b->xyz[1] - a->xyz[1];
- d0[2] = b->xyz[2] - a->xyz[2];
- d0[3] = bST[0] - aST[0];
- d0[4] = bST[1] - aST[1];
- float d1[5];
- d1[0] = c->xyz[0] - a->xyz[0];
- d1[1] = c->xyz[1] - a->xyz[1];
- d1[2] = c->xyz[2] - a->xyz[2];
- d1[3] = cST[0] - aST[0];
- d1[4] = cST[1] - aST[1];
- idVec3 normal;
- normal[0] = d1[1] * d0[2] - d1[2] * d0[1];
- normal[1] = d1[2] * d0[0] - d1[0] * d0[2];
- normal[2] = d1[0] * d0[1] - d1[1] * d0[0];
- const float f0 = idMath::InvSqrt( normal.x * normal.x + normal.y * normal.y + normal.z * normal.z );
- normal.x *= f0;
- normal.y *= f0;
- normal.z *= f0;
- // area sign bit
- const float area = d0[3] * d1[4] - d0[4] * d1[3];
- unsigned int signBit = ( *(unsigned int *)&area ) & ( 1 << 31 );
- idVec3 tangent;
- tangent[0] = d0[0] * d1[4] - d0[4] * d1[0];
- tangent[1] = d0[1] * d1[4] - d0[4] * d1[1];
- tangent[2] = d0[2] * d1[4] - d0[4] * d1[2];
- const float f1 = idMath::InvSqrt( tangent.x * tangent.x + tangent.y * tangent.y + tangent.z * tangent.z );
- *(unsigned int *)&f1 ^= signBit;
- tangent.x *= f1;
- tangent.y *= f1;
- tangent.z *= f1;
- idVec3 bitangent;
- bitangent[0] = d0[3] * d1[0] - d0[0] * d1[3];
- bitangent[1] = d0[3] * d1[1] - d0[1] * d1[3];
- bitangent[2] = d0[3] * d1[2] - d0[2] * d1[3];
- const float f2 = idMath::InvSqrt( bitangent.x * bitangent.x + bitangent.y * bitangent.y + bitangent.z * bitangent.z );
- *(unsigned int *)&f2 ^= signBit;
- bitangent.x *= f2;
- bitangent.y *= f2;
- bitangent.z *= f2;
- vertexNormals[v0] += normal;
- vertexTangents[v0] += tangent;
- vertexBitangents[v0] += bitangent;
- vertexNormals[v1] += normal;
- vertexTangents[v1] += tangent;
- vertexBitangents[v1] += bitangent;
- vertexNormals[v2] += normal;
- vertexTangents[v2] += tangent;
- vertexBitangents[v2] += bitangent;
- }
- // add the normal of a duplicated vertex to the normal of the first vertex with the same XYZ
- for ( int i = 0; i < tri->numDupVerts; i++ ) {
- vertexNormals[tri->dupVerts[i*2+0]] += vertexNormals[tri->dupVerts[i*2+1]];
- }
- // copy vertex normals to duplicated vertices
- for ( int i = 0; i < tri->numDupVerts; i++ ) {
- vertexNormals[tri->dupVerts[i*2+1]] = vertexNormals[tri->dupVerts[i*2+0]];
- }
- // Project the summed vectors onto the normal plane and normalize.
- // The tangent vectors will not necessarily be orthogonal to each
- // other, but they will be orthogonal to the surface normal.
- for ( int i = 0; i < tri->numVerts; i++ ) {
- const float normalScale = idMath::InvSqrt( vertexNormals[i].x * vertexNormals[i].x + vertexNormals[i].y * vertexNormals[i].y + vertexNormals[i].z * vertexNormals[i].z );
- vertexNormals[i].x *= normalScale;
- vertexNormals[i].y *= normalScale;
- vertexNormals[i].z *= normalScale;
- vertexTangents[i] -= ( vertexTangents[i] * vertexNormals[i] ) * vertexNormals[i];
- vertexBitangents[i] -= ( vertexBitangents[i] * vertexNormals[i] ) * vertexNormals[i];
- const float tangentScale = idMath::InvSqrt( vertexTangents[i].x * vertexTangents[i].x + vertexTangents[i].y * vertexTangents[i].y + vertexTangents[i].z * vertexTangents[i].z );
- vertexTangents[i].x *= tangentScale;
- vertexTangents[i].y *= tangentScale;
- vertexTangents[i].z *= tangentScale;
- const float bitangentScale = idMath::InvSqrt( vertexBitangents[i].x * vertexBitangents[i].x + vertexBitangents[i].y * vertexBitangents[i].y + vertexBitangents[i].z * vertexBitangents[i].z );
- vertexBitangents[i].x *= bitangentScale;
- vertexBitangents[i].y *= bitangentScale;
- vertexBitangents[i].z *= bitangentScale;
- }
- // compress the normals and tangents
- for ( int i = 0; i < tri->numVerts; i++ ) {
- tri->verts[i].SetNormal( vertexNormals[i] );
- tri->verts[i].SetTangent( vertexTangents[i] );
- tri->verts[i].SetBiTangent( vertexBitangents[i] );
- }
- }
- /*
- ============
- R_DeriveUnsmoothedNormalsAndTangents
- ============
- */
- void R_DeriveUnsmoothedNormalsAndTangents( srfTriangles_t * tri ) {
- for ( int i = 0; i < tri->numVerts; i++ ) {
- float d0, d1, d2, d3, d4;
- float d5, d6, d7, d8, d9;
- float s0, s1, s2;
- float n0, n1, n2;
- float t0, t1, t2;
- float t3, t4, t5;
- const dominantTri_t &dt = tri->dominantTris[i];
- idDrawVert *a = tri->verts + i;
- idDrawVert *b = tri->verts + dt.v2;
- idDrawVert *c = tri->verts + dt.v3;
- const idVec2 aST = a->GetTexCoord();
- const idVec2 bST = b->GetTexCoord();
- const idVec2 cST = c->GetTexCoord();
- d0 = b->xyz[0] - a->xyz[0];
- d1 = b->xyz[1] - a->xyz[1];
- d2 = b->xyz[2] - a->xyz[2];
- d3 = bST[0] - aST[0];
- d4 = bST[1] - aST[1];
- d5 = c->xyz[0] - a->xyz[0];
- d6 = c->xyz[1] - a->xyz[1];
- d7 = c->xyz[2] - a->xyz[2];
- d8 = cST[0] - aST[0];
- d9 = cST[1] - aST[1];
- s0 = dt.normalizationScale[0];
- s1 = dt.normalizationScale[1];
- s2 = dt.normalizationScale[2];
- n0 = s2 * ( d6 * d2 - d7 * d1 );
- n1 = s2 * ( d7 * d0 - d5 * d2 );
- n2 = s2 * ( d5 * d1 - d6 * d0 );
- t0 = s0 * ( d0 * d9 - d4 * d5 );
- t1 = s0 * ( d1 * d9 - d4 * d6 );
- t2 = s0 * ( d2 * d9 - d4 * d7 );
- #ifndef DERIVE_UNSMOOTHED_BITANGENT
- t3 = s1 * ( d3 * d5 - d0 * d8 );
- t4 = s1 * ( d3 * d6 - d1 * d8 );
- t5 = s1 * ( d3 * d7 - d2 * d8 );
- #else
- t3 = s1 * ( n2 * t1 - n1 * t2 );
- t4 = s1 * ( n0 * t2 - n2 * t0 );
- t5 = s1 * ( n1 * t0 - n0 * t1 );
- #endif
- a->SetNormal( n0, n1, n2 );
- a->SetTangent( t0, t1, t2 );
- a->SetBiTangent( t3, t4, t5 );
- }
- }
- /*
- =====================
- R_CreateVertexNormals
- Averages together the contributions of all faces that are
- used by a vertex, creating drawVert->normal
- =====================
- */
- void R_CreateVertexNormals( srfTriangles_t *tri ) {
- if ( tri->silIndexes == NULL ) {
- R_CreateSilIndexes( tri );
- }
- idTempArray< idVec3 > vertexNormals( tri->numVerts );
- vertexNormals.Zero();
- assert( tri->silIndexes != NULL );
- for ( int i = 0; i < tri->numIndexes; i += 3 ) {
- const int i0 = tri->silIndexes[i + 0];
- const int i1 = tri->silIndexes[i + 1];
- const int i2 = tri->silIndexes[i + 2];
- const idDrawVert & v0 = tri->verts[i0];
- const idDrawVert & v1 = tri->verts[i1];
- const idDrawVert & v2 = tri->verts[i2];
- const idPlane plane( v0.xyz, v1.xyz, v2.xyz );
- vertexNormals[i0] += plane.Normal();
- vertexNormals[i1] += plane.Normal();
- vertexNormals[i2] += plane.Normal();
- }
- // replicate from silIndexes to all indexes
- for ( int i = 0; i < tri->numIndexes; i++ ) {
- vertexNormals[tri->indexes[i]] = vertexNormals[tri->silIndexes[i]];
- }
- // normalize
- for ( int i = 0; i < tri->numVerts; i++ ) {
- vertexNormals[i].Normalize();
- }
- // compress the normals
- for ( int i = 0; i < tri->numVerts; i++ ) {
- tri->verts[i].SetNormal( vertexNormals[i] );
- }
- }
- /*
- =================
- R_DeriveTangentsWithoutNormals
- Build texture space tangents for bump mapping
- If a surface is deformed, this must be recalculated
- This assumes that any mirrored vertexes have already been duplicated, so
- any shared vertexes will have the tangent spaces smoothed across.
- Texture wrapping slightly complicates this, but as long as the normals
- are shared, and the tangent vectors are projected onto the normals, the
- separate vertexes should wind up with identical tangent spaces.
- mirroring a normalmap WILL cause a slightly visible seam unless the normals
- are completely flat around the edge's full bilerp support.
- Vertexes which are smooth shaded must have their tangent vectors
- in the same plane, which will allow a seamless
- rendering as long as the normal map is even on both sides of the
- seam.
- A smooth shaded surface may have multiple tangent vectors at a vertex
- due to texture seams or mirroring, but it should only have a single
- normal vector.
- Each triangle has a pair of tangent vectors in it's plane
- Should we consider having vertexes point at shared tangent spaces
- to save space or speed transforms?
- this version only handles bilateral symetry
- =================
- */
- void R_DeriveTangentsWithoutNormals( srfTriangles_t *tri ) {
- idTempArray< idVec3 > triangleTangents( tri->numIndexes / 3 );
- idTempArray< idVec3 > triangleBitangents( tri->numIndexes / 3 );
- //
- // calculate tangent vectors for each face in isolation
- //
- int c_positive = 0;
- int c_negative = 0;
- int c_textureDegenerateFaces = 0;
- for ( int i = 0; i < tri->numIndexes; i += 3 ) {
- idVec3 temp;
- idDrawVert * a = tri->verts + tri->indexes[i + 0];
- idDrawVert * b = tri->verts + tri->indexes[i + 1];
- idDrawVert * c = tri->verts + tri->indexes[i + 2];
- const idVec2 aST = a->GetTexCoord();
- const idVec2 bST = b->GetTexCoord();
- const idVec2 cST = c->GetTexCoord();
- float d0[5];
- d0[0] = b->xyz[0] - a->xyz[0];
- d0[1] = b->xyz[1] - a->xyz[1];
- d0[2] = b->xyz[2] - a->xyz[2];
- d0[3] = bST[0] - aST[0];
- d0[4] = bST[1] - aST[1];
- float d1[5];
- d1[0] = c->xyz[0] - a->xyz[0];
- d1[1] = c->xyz[1] - a->xyz[1];
- d1[2] = c->xyz[2] - a->xyz[2];
- d1[3] = cST[0] - aST[0];
- d1[4] = cST[1] - aST[1];
- const float area = d0[3] * d1[4] - d0[4] * d1[3];
- if ( fabs( area ) < 1e-20f ) {
- triangleTangents[i / 3].Zero();
- triangleBitangents[i / 3].Zero();
- c_textureDegenerateFaces++;
- continue;
- }
- if ( area > 0.0f ) {
- c_positive++;
- } else {
- c_negative++;
- }
- #ifdef USE_INVA
- float inva = ( area < 0.0f ) ? -1.0f : 1.0f; // was = 1.0f / area;
- temp[0] = ( d0[0] * d1[4] - d0[4] * d1[0] ) * inva;
- temp[1] = ( d0[1] * d1[4] - d0[4] * d1[1] ) * inva;
- temp[2] = ( d0[2] * d1[4] - d0[4] * d1[2] ) * inva;
- temp.Normalize();
- triangleTangents[i / 3] = temp;
-
- temp[0] = ( d0[3] * d1[0] - d0[0] * d1[3] ) * inva;
- temp[1] = ( d0[3] * d1[1] - d0[1] * d1[3] ) * inva;
- temp[2] = ( d0[3] * d1[2] - d0[2] * d1[3] ) * inva;
- temp.Normalize();
- triangleBitangents[i / 3] = temp;
- #else
- temp[0] = ( d0[0] * d1[4] - d0[4] * d1[0] );
- temp[1] = ( d0[1] * d1[4] - d0[4] * d1[1] );
- temp[2] = ( d0[2] * d1[4] - d0[4] * d1[2] );
- temp.Normalize();
- triangleTangents[i / 3] = temp;
-
- temp[0] = ( d0[3] * d1[0] - d0[0] * d1[3] );
- temp[1] = ( d0[3] * d1[1] - d0[1] * d1[3] );
- temp[2] = ( d0[3] * d1[2] - d0[2] * d1[3] );
- temp.Normalize();
- triangleBitangents[i / 3] = temp;
- #endif
- }
- idTempArray< idVec3 > vertexTangents( tri->numVerts );
- idTempArray< idVec3 > vertexBitangents( tri->numVerts );
- // clear the tangents
- for ( int i = 0; i < tri->numVerts; ++i ) {
- vertexTangents[i].Zero();
- vertexBitangents[i].Zero();
- }
- // sum up the neighbors
- for ( int i = 0; i < tri->numIndexes; i += 3 ) {
- // for each vertex on this face
- for ( int j = 0; j < 3; j++ ) {
- vertexTangents[tri->indexes[i+j]] += triangleTangents[i / 3];
- vertexBitangents[tri->indexes[i+j]] += triangleBitangents[i / 3];
- }
- }
- // Project the summed vectors onto the normal plane and normalize.
- // The tangent vectors will not necessarily be orthogonal to each
- // other, but they will be orthogonal to the surface normal.
- for ( int i = 0; i < tri->numVerts; i++ ) {
- idVec3 normal = tri->verts[i].GetNormal();
- normal.Normalize();
- vertexTangents[i] -= ( vertexTangents[i] * normal ) * normal;
- vertexTangents[i].Normalize();
- vertexBitangents[i] -= ( vertexBitangents[i] * normal ) * normal;
- vertexBitangents[i].Normalize();
- }
- for ( int i = 0; i < tri->numVerts; i++ ) {
- tri->verts[i].SetTangent( vertexTangents[i] );
- tri->verts[i].SetBiTangent( vertexBitangents[i] );
- }
- tri->tangentsCalculated = true;
- }
- /*
- ===================
- R_BuildDominantTris
- Find the largest triangle that uses each vertex
- ===================
- */
- typedef struct {
- int vertexNum;
- int faceNum;
- } indexSort_t;
- static int IndexSort( const void *a, const void *b ) {
- if ( ((indexSort_t *)a)->vertexNum < ((indexSort_t *)b)->vertexNum ) {
- return -1;
- }
- if ( ((indexSort_t *)a)->vertexNum > ((indexSort_t *)b)->vertexNum ) {
- return 1;
- }
- return 0;
- }
- void R_BuildDominantTris( srfTriangles_t *tri ) {
- int i, j;
- dominantTri_t *dt;
- const int numIndexes = tri->numIndexes;
- indexSort_t *ind = (indexSort_t *)R_StaticAlloc( numIndexes * sizeof( indexSort_t ) );
- if ( ind == NULL ) {
- idLib::Error( "Couldn't allocate index sort array" );
- return;
- }
- for ( i = 0; i < tri->numIndexes; i++ ) {
- ind[i].vertexNum = tri->indexes[i];
- ind[i].faceNum = i / 3;
- }
- qsort( ind, tri->numIndexes, sizeof( *ind ), IndexSort );
- R_AllocStaticTriSurfDominantTris( tri, tri->numVerts );
- dt = tri->dominantTris;
- memset( dt, 0, tri->numVerts * sizeof( dt[0] ) );
- for ( i = 0; i < numIndexes; i += j ) {
- float maxArea = 0;
- #pragma warning( disable: 6385 ) // This is simply to get pass a false defect for /analyze -- if you can figure out a better way, please let Shawn know...
- int vertNum = ind[i].vertexNum;
- #pragma warning( default: 6385 )
- for ( j = 0; i + j < tri->numIndexes && ind[i+j].vertexNum == vertNum; j++ ) {
- float d0[5], d1[5];
- idDrawVert *a, *b, *c;
- idVec3 normal, tangent, bitangent;
- int i1 = tri->indexes[ind[i+j].faceNum * 3 + 0];
- int i2 = tri->indexes[ind[i+j].faceNum * 3 + 1];
- int i3 = tri->indexes[ind[i+j].faceNum * 3 + 2];
-
- a = tri->verts + i1;
- b = tri->verts + i2;
- c = tri->verts + i3;
- const idVec2 aST = a->GetTexCoord();
- const idVec2 bST = b->GetTexCoord();
- const idVec2 cST = c->GetTexCoord();
- d0[0] = b->xyz[0] - a->xyz[0];
- d0[1] = b->xyz[1] - a->xyz[1];
- d0[2] = b->xyz[2] - a->xyz[2];
- d0[3] = bST[0] - aST[0];
- d0[4] = bST[1] - aST[1];
- d1[0] = c->xyz[0] - a->xyz[0];
- d1[1] = c->xyz[1] - a->xyz[1];
- d1[2] = c->xyz[2] - a->xyz[2];
- d1[3] = cST[0] - aST[0];
- d1[4] = cST[1] - aST[1];
- normal[0] = ( d1[1] * d0[2] - d1[2] * d0[1] );
- normal[1] = ( d1[2] * d0[0] - d1[0] * d0[2] );
- normal[2] = ( d1[0] * d0[1] - d1[1] * d0[0] );
- float area = normal.Length();
- // if this is smaller than what we already have, skip it
- if ( area < maxArea ) {
- continue;
- }
- maxArea = area;
- if ( i1 == vertNum ) {
- dt[vertNum].v2 = i2;
- dt[vertNum].v3 = i3;
- } else if ( i2 == vertNum ) {
- dt[vertNum].v2 = i3;
- dt[vertNum].v3 = i1;
- } else {
- dt[vertNum].v2 = i1;
- dt[vertNum].v3 = i2;
- }
- float len = area;
- if ( len < 0.001f ) {
- len = 0.001f;
- }
- dt[vertNum].normalizationScale[2] = 1.0f / len; // normal
- // texture area
- area = d0[3] * d1[4] - d0[4] * d1[3];
- tangent[0] = ( d0[0] * d1[4] - d0[4] * d1[0] );
- tangent[1] = ( d0[1] * d1[4] - d0[4] * d1[1] );
- tangent[2] = ( d0[2] * d1[4] - d0[4] * d1[2] );
- len = tangent.Length();
- if ( len < 0.001f ) {
- len = 0.001f;
- }
- dt[vertNum].normalizationScale[0] = ( area > 0 ? 1 : -1 ) / len; // tangents[0]
-
- bitangent[0] = ( d0[3] * d1[0] - d0[0] * d1[3] );
- bitangent[1] = ( d0[3] * d1[1] - d0[1] * d1[3] );
- bitangent[2] = ( d0[3] * d1[2] - d0[2] * d1[3] );
- len = bitangent.Length();
- if ( len < 0.001f ) {
- len = 0.001f;
- }
- #ifdef DERIVE_UNSMOOTHED_BITANGENT
- dt[vertNum].normalizationScale[1] = ( area > 0 ? 1 : -1 );
- #else
- dt[vertNum].normalizationScale[1] = ( area > 0 ? 1 : -1 ) / len; // tangents[1]
- #endif
- }
- }
- R_StaticFree( ind );
- }
- /*
- ==================
- R_DeriveTangents
- This is called once for static surfaces, and every frame for deforming surfaces
- Builds tangents, normals, and face planes
- ==================
- */
- void R_DeriveTangents( srfTriangles_t *tri ) {
- if ( tri->tangentsCalculated ) {
- return;
- }
- tr.pc.c_tangentIndexes += tri->numIndexes;
- if ( tri->dominantTris != NULL ) {
- R_DeriveUnsmoothedNormalsAndTangents( tri );
- } else {
- R_DeriveNormalsAndTangents( tri );
- }
- tri->tangentsCalculated = true;
- }
- /*
- =================
- R_RemoveDuplicatedTriangles
- silIndexes must have already been calculated
- silIndexes are used instead of indexes, because duplicated
- triangles could have different texture coordinates.
- =================
- */
- void R_RemoveDuplicatedTriangles( srfTriangles_t *tri ) {
- int c_removed;
- int i, j, r;
- int a, b, c;
- c_removed = 0;
- // check for completely duplicated triangles
- // any rotation of the triangle is still the same, but a mirroring
- // is considered different
- for ( i = 0; i < tri->numIndexes; i+=3 ) {
- for ( r = 0; r < 3; r++ ) {
- a = tri->silIndexes[i+r];
- b = tri->silIndexes[i+(r+1)%3];
- c = tri->silIndexes[i+(r+2)%3];
- for ( j = i + 3; j < tri->numIndexes; j+=3 ) {
- if ( tri->silIndexes[j] == a && tri->silIndexes[j+1] == b && tri->silIndexes[j+2] == c ) {
- c_removed++;
- memmove( tri->indexes + j, tri->indexes + j + 3, ( tri->numIndexes - j - 3 ) * sizeof( tri->indexes[0] ) );
- memmove( tri->silIndexes + j, tri->silIndexes + j + 3, ( tri->numIndexes - j - 3 ) * sizeof( tri->silIndexes[0] ) );
- tri->numIndexes -= 3;
- j -= 3;
- }
- }
- }
- }
- if ( c_removed ) {
- common->Printf( "removed %i duplicated triangles\n", c_removed );
- }
- }
- /*
- =================
- R_RemoveDegenerateTriangles
- silIndexes must have already been calculated
- =================
- */
- void R_RemoveDegenerateTriangles( srfTriangles_t *tri ) {
- int c_removed;
- int i;
- int a, b, c;
- assert( tri->silIndexes != NULL );
- // check for completely degenerate triangles
- c_removed = 0;
- for ( i = 0; i < tri->numIndexes; i += 3 ) {
- a = tri->silIndexes[i];
- b = tri->silIndexes[i+1];
- c = tri->silIndexes[i+2];
- if ( a == b || a == c || b == c ) {
- c_removed++;
- memmove( tri->indexes + i, tri->indexes + i + 3, ( tri->numIndexes - i - 3 ) * sizeof( tri->indexes[0] ) );
- memmove( tri->silIndexes + i, tri->silIndexes + i + 3, ( tri->numIndexes - i - 3 ) * sizeof( tri->silIndexes[0] ) );
- tri->numIndexes -= 3;
- i -= 3;
- }
- }
- // this doesn't free the memory used by the unused verts
- if ( c_removed ) {
- common->Printf( "removed %i degenerate triangles\n", c_removed );
- }
- }
- /*
- =================
- R_TestDegenerateTextureSpace
- =================
- */
- void R_TestDegenerateTextureSpace( srfTriangles_t *tri ) {
- int c_degenerate;
- int i;
- // check for triangles with a degenerate texture space
- c_degenerate = 0;
- for ( i = 0; i < tri->numIndexes; i += 3 ) {
- const idDrawVert &a = tri->verts[tri->indexes[i+0]];
- const idDrawVert &b = tri->verts[tri->indexes[i+1]];
- const idDrawVert &c = tri->verts[tri->indexes[i+2]];
- if ( a.st == b.st || b.st == c.st || c.st == a.st ) {
- c_degenerate++;
- }
- }
- if ( c_degenerate ) {
- // common->Printf( "%d triangles with a degenerate texture space\n", c_degenerate );
- }
- }
- /*
- =================
- R_RemoveUnusedVerts
- =================
- */
- void R_RemoveUnusedVerts( srfTriangles_t *tri ) {
- int i;
- int *mark;
- int index;
- int used;
- mark = (int *)R_ClearedStaticAlloc( tri->numVerts * sizeof( *mark ) );
- for ( i = 0; i < tri->numIndexes; i++ ) {
- index = tri->indexes[i];
- if ( index < 0 || index >= tri->numVerts ) {
- common->Error( "R_RemoveUnusedVerts: bad index" );
- }
- mark[ index ] = 1;
- if ( tri->silIndexes ) {
- index = tri->silIndexes[i];
- if ( index < 0 || index >= tri->numVerts ) {
- common->Error( "R_RemoveUnusedVerts: bad index" );
- }
- mark[ index ] = 1;
- }
- }
- used = 0;
- for ( i = 0; i < tri->numVerts; i++ ) {
- if ( !mark[i] ) {
- continue;
- }
- mark[i] = used + 1;
- used++;
- }
- if ( used != tri->numVerts ) {
- for ( i = 0; i < tri->numIndexes; i++ ) {
- tri->indexes[i] = mark[ tri->indexes[i] ] - 1;
- if ( tri->silIndexes ) {
- tri->silIndexes[i] = mark[ tri->silIndexes[i] ] - 1;
- }
- }
- tri->numVerts = used;
- for ( i = 0; i < tri->numVerts; i++ ) {
- index = mark[ i ];
- if ( !index ) {
- continue;
- }
- tri->verts[ index - 1 ] = tri->verts[i];
- }
- // this doesn't realloc the arrays to save the memory used by the unused verts
- }
- R_StaticFree( mark );
- }
- /*
- =================
- R_MergeSurfaceList
- Only deals with vertexes and indexes, not silhouettes, planes, etc.
- Does NOT perform a cleanup triangles, so there may be duplicated verts in the result.
- =================
- */
- srfTriangles_t * R_MergeSurfaceList( const srfTriangles_t **surfaces, int numSurfaces ) {
- srfTriangles_t *newTri;
- const srfTriangles_t *tri;
- int i, j;
- int totalVerts;
- int totalIndexes;
- totalVerts = 0;
- totalIndexes = 0;
- for ( i = 0; i < numSurfaces; i++ ) {
- totalVerts += surfaces[i]->numVerts;
- totalIndexes += surfaces[i]->numIndexes;
- }
- newTri = R_AllocStaticTriSurf();
- newTri->numVerts = totalVerts;
- newTri->numIndexes = totalIndexes;
- R_AllocStaticTriSurfVerts( newTri, newTri->numVerts );
- R_AllocStaticTriSurfIndexes( newTri, newTri->numIndexes );
- totalVerts = 0;
- totalIndexes = 0;
- for ( i = 0; i < numSurfaces; i++ ) {
- tri = surfaces[i];
- memcpy( newTri->verts + totalVerts, tri->verts, tri->numVerts * sizeof( *tri->verts ) );
- for ( j = 0; j < tri->numIndexes; j++ ) {
- newTri->indexes[ totalIndexes + j ] = totalVerts + tri->indexes[j];
- }
- totalVerts += tri->numVerts;
- totalIndexes += tri->numIndexes;
- }
- return newTri;
- }
- /*
- =================
- R_MergeTriangles
- Only deals with vertexes and indexes, not silhouettes, planes, etc.
- Does NOT perform a cleanup triangles, so there may be duplicated verts in the result.
- =================
- */
- srfTriangles_t * R_MergeTriangles( const srfTriangles_t *tri1, const srfTriangles_t *tri2 ) {
- const srfTriangles_t *tris[2];
- tris[0] = tri1;
- tris[1] = tri2;
- return R_MergeSurfaceList( tris, 2 );
- }
- /*
- =================
- R_ReverseTriangles
- Lit two sided surfaces need to have the triangles actually duplicated,
- they can't just turn on two sided lighting, because the normal and tangents
- are wrong on the other sides.
- This should be called before R_CleanupTriangles
- =================
- */
- void R_ReverseTriangles( srfTriangles_t *tri ) {
- int i;
- // flip the normal on each vertex
- // If the surface is going to have generated normals, this won't matter,
- // but if it has explicit normals, this will keep it on the correct side
- for ( i = 0; i < tri->numVerts; i++ ) {
- tri->verts[i].SetNormal( vec3_origin - tri->verts[i].GetNormal() );
- }
- // flip the index order to make them back sided
- for ( i = 0; i < tri->numIndexes; i+= 3 ) {
- triIndex_t temp;
- temp = tri->indexes[ i + 0 ];
- tri->indexes[ i + 0 ] = tri->indexes[ i + 1 ];
- tri->indexes[ i + 1 ] = temp;
- }
- }
- /*
- =================
- R_CleanupTriangles
- FIXME: allow createFlat and createSmooth normals, as well as explicit
- =================
- */
- void R_CleanupTriangles( srfTriangles_t *tri, bool createNormals, bool identifySilEdges, bool useUnsmoothedTangents ) {
- R_RangeCheckIndexes( tri );
- R_CreateSilIndexes( tri );
- // R_RemoveDuplicatedTriangles( tri ); // this may remove valid overlapped transparent triangles
- R_RemoveDegenerateTriangles( tri );
- R_TestDegenerateTextureSpace( tri );
- // R_RemoveUnusedVerts( tri );
- if ( identifySilEdges ) {
- R_IdentifySilEdges( tri, true ); // assume it is non-deformable, and omit coplanar edges
- }
- // bust vertexes that share a mirrored edge into separate vertexes
- R_DuplicateMirroredVertexes( tri );
- R_CreateDupVerts( tri );
- R_BoundTriSurf( tri );
- if ( useUnsmoothedTangents ) {
- R_BuildDominantTris( tri );
- R_DeriveTangents( tri );
- } else if ( !createNormals ) {
- R_DeriveTangentsWithoutNormals( tri );
- } else {
- R_DeriveTangents( tri );
- }
- }
- /*
- ===================================================================================
- DEFORMED SURFACES
- ===================================================================================
- */
- /*
- ===================
- R_BuildDeformInfo
- ===================
- */
- deformInfo_t *R_BuildDeformInfo( int numVerts, const idDrawVert *verts, int numIndexes, const int *indexes,
- bool useUnsmoothedTangents ) {
- srfTriangles_t tri;
- memset( &tri, 0, sizeof( srfTriangles_t ) );
- tri.numVerts = numVerts;
- R_AllocStaticTriSurfVerts( &tri, tri.numVerts );
- SIMDProcessor->Memcpy( tri.verts, verts, tri.numVerts * sizeof( tri.verts[0] ) );
- tri.numIndexes = numIndexes;
- R_AllocStaticTriSurfIndexes( &tri, tri.numIndexes );
- // don't memcpy, so we can change the index type from int to short without changing the interface
- for ( int i = 0; i < tri.numIndexes; i++ ) {
- tri.indexes[i] = indexes[i];
- }
- R_RangeCheckIndexes( &tri );
- R_CreateSilIndexes( &tri );
- R_IdentifySilEdges( &tri, false ); // we cannot remove coplanar edges, because they can deform to silhouettes
- R_DuplicateMirroredVertexes( &tri ); // split mirror points into multiple points
- R_CreateDupVerts( &tri );
- if ( useUnsmoothedTangents ) {
- R_BuildDominantTris( &tri );
- }
- R_DeriveTangents( &tri );
- deformInfo_t * deform = (deformInfo_t *)R_ClearedStaticAlloc( sizeof( *deform ) );
- deform->numSourceVerts = numVerts;
- deform->numOutputVerts = tri.numVerts;
- deform->verts = tri.verts;
- deform->numIndexes = numIndexes;
- deform->indexes = tri.indexes;
- deform->silIndexes = tri.silIndexes;
- deform->numSilEdges = tri.numSilEdges;
- deform->silEdges = tri.silEdges;
- deform->numMirroredVerts = tri.numMirroredVerts;
- deform->mirroredVerts = tri.mirroredVerts;
- deform->numDupVerts = tri.numDupVerts;
- deform->dupVerts = tri.dupVerts;
- if ( tri.dominantTris != NULL ) {
- Mem_Free( tri.dominantTris );
- tri.dominantTris = NULL;
- }
- idShadowVertSkinned * shadowVerts = (idShadowVertSkinned *) Mem_Alloc16( ALIGN( deform->numOutputVerts * 2 * sizeof( idShadowVertSkinned ), 16 ), TAG_MODEL );
- idShadowVertSkinned::CreateShadowCache( shadowVerts, deform->verts, deform->numOutputVerts );
- deform->staticAmbientCache = vertexCache.AllocStaticVertex( deform->verts, ALIGN( deform->numOutputVerts * sizeof( idDrawVert ), VERTEX_CACHE_ALIGN ) );
- deform->staticIndexCache = vertexCache.AllocStaticIndex( deform->indexes, ALIGN( deform->numIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) );
- deform->staticShadowCache = vertexCache.AllocStaticVertex( shadowVerts, ALIGN( deform->numOutputVerts * 2 * sizeof( idShadowVertSkinned ), VERTEX_CACHE_ALIGN ) );
- Mem_Free( shadowVerts );
- return deform;
- }
- /*
- ===================
- R_FreeDeformInfo
- ===================
- */
- void R_FreeDeformInfo( deformInfo_t *deformInfo ) {
- if ( deformInfo->verts != NULL ) {
- Mem_Free( deformInfo->verts );
- }
- if ( deformInfo->indexes != NULL ) {
- Mem_Free( deformInfo->indexes );
- }
- if ( deformInfo->silIndexes != NULL ) {
- Mem_Free( deformInfo->silIndexes );
- }
- if ( deformInfo->silEdges != NULL ) {
- Mem_Free( deformInfo->silEdges );
- }
- if ( deformInfo->mirroredVerts != NULL ) {
- Mem_Free( deformInfo->mirroredVerts );
- }
- if ( deformInfo->dupVerts != NULL ) {
- Mem_Free( deformInfo->dupVerts );
- }
- R_StaticFree( deformInfo );
- }
- /*
- ===================
- R_DeformInfoMemoryUsed
- ===================
- */
- int R_DeformInfoMemoryUsed( deformInfo_t *deformInfo ) {
- int total = 0;
- if ( deformInfo->verts != NULL ) {
- total += deformInfo->numOutputVerts * sizeof( deformInfo->verts[0] );
- }
- if ( deformInfo->indexes != NULL ) {
- total += deformInfo->numIndexes * sizeof( deformInfo->indexes[0] );
- }
- if ( deformInfo->mirroredVerts != NULL ) {
- total += deformInfo->numMirroredVerts * sizeof( deformInfo->mirroredVerts[0] );
- }
- if ( deformInfo->dupVerts != NULL ) {
- total += deformInfo->numDupVerts * sizeof( deformInfo->dupVerts[0] );
- }
- if ( deformInfo->silIndexes != NULL ) {
- total += deformInfo->numIndexes * sizeof( deformInfo->silIndexes[0] );
- }
- if ( deformInfo->silEdges != NULL ) {
- total += deformInfo->numSilEdges * sizeof( deformInfo->silEdges[0] );
- }
- total += sizeof( *deformInfo );
- return total;
- }
- /*
- ===================================================================================
- VERTEX / INDEX CACHING
- ===================================================================================
- */
- /*
- ===================
- R_InitDrawSurfFromTri
- ===================
- */
- void R_InitDrawSurfFromTri( drawSurf_t & ds, srfTriangles_t & tri ) {
- if ( tri.numIndexes == 0 ) {
- ds.numIndexes = 0;
- return;
- }
- // copy verts and indexes to this frame's hardware memory if they aren't already there
- //
- // deformed surfaces will not have any vertices but the ambient cache will have already
- // been created for them.
- if ( ( tri.verts == NULL ) && !tri.referencedIndexes ) {
- // pre-generated shadow models will not have any verts, just shadowVerts
- tri.ambientCache = 0;
- } else if ( !vertexCache.CacheIsCurrent( tri.ambientCache ) ) {
- tri.ambientCache = vertexCache.AllocVertex( tri.verts, ALIGN( tri.numVerts * sizeof( tri.verts[0] ), VERTEX_CACHE_ALIGN ) );
- }
- if ( !vertexCache.CacheIsCurrent( tri.indexCache ) ) {
- tri.indexCache = vertexCache.AllocIndex( tri.indexes, ALIGN( tri.numIndexes * sizeof( tri.indexes[0] ), INDEX_CACHE_ALIGN ) );
- }
- ds.numIndexes = tri.numIndexes;
- ds.ambientCache = tri.ambientCache;
- ds.indexCache = tri.indexCache;
- ds.shadowCache = tri.shadowCache;
- ds.jointCache = 0;
- }
- /*
- ===================
- R_CreateStaticBuffersForTri
- For static surfaces, the indexes, ambient, and shadow buffers can be pre-created at load
- time, rather than being re-created each frame in the frame temporary buffers.
- ===================
- */
- void R_CreateStaticBuffersForTri( srfTriangles_t & tri ) {
- tri.indexCache = 0;
- tri.ambientCache = 0;
- tri.shadowCache = 0;
- // index cache
- if ( tri.indexes != NULL ) {
- tri.indexCache = vertexCache.AllocStaticIndex( tri.indexes, ALIGN( tri.numIndexes * sizeof( tri.indexes[0] ), INDEX_CACHE_ALIGN ) );
- }
- // vertex cache
- if ( tri.verts != NULL ) {
- tri.ambientCache = vertexCache.AllocStaticVertex( tri.verts, ALIGN( tri.numVerts * sizeof( tri.verts[0] ), VERTEX_CACHE_ALIGN ) );
- }
- // shadow cache
- if ( tri.preLightShadowVertexes != NULL ) {
- // this should only be true for the _prelight<NAME> pre-calculated shadow volumes
- assert( tri.verts == NULL ); // pre-light shadow volume surfaces don't have ambient vertices
- const int shadowSize = ALIGN( tri.numVerts * 2 * sizeof( idShadowVert ), VERTEX_CACHE_ALIGN );
- tri.shadowCache = vertexCache.AllocStaticVertex( tri.preLightShadowVertexes, shadowSize );
- } else if ( tri.verts != NULL ) {
- // the shadowVerts for normal models include all the xyz values duplicated
- // for a W of 1 (near cap) and a W of 0 (end cap, projected to infinity)
- const int shadowSize = ALIGN( tri.numVerts * 2 * sizeof( idShadowVert ), VERTEX_CACHE_ALIGN );
- if ( tri.staticShadowVertexes == NULL ) {
- tri.staticShadowVertexes = (idShadowVert *) Mem_Alloc16( shadowSize, TAG_TEMP );
- idShadowVert::CreateShadowCache( tri.staticShadowVertexes, tri.verts, tri.numVerts );
- }
- tri.shadowCache = vertexCache.AllocStaticVertex( tri.staticShadowVertexes, shadowSize );
- #if !defined( KEEP_INTERACTION_CPU_DATA )
- Mem_Free( tri.staticShadowVertexes );
- tri.staticShadowVertexes = NULL;
- #endif
- }
- }
|