1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432 |
- /*
- ===========================================================================
- 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"
- #ifdef ID_WIN_X86_SSE2_INTRIN
- static const __m128 vector_float_posInfinity = { idMath::INFINITY, idMath::INFINITY, idMath::INFINITY, idMath::INFINITY };
- static const __m128 vector_float_negInfinity = { -idMath::INFINITY, -idMath::INFINITY, -idMath::INFINITY, -idMath::INFINITY };
- #endif
- static const char *MD5_SnapshotName = "_MD5_Snapshot_";
- static const byte MD5B_VERSION = 106;
- static const unsigned int MD5B_MAGIC = ( '5' << 24 ) | ( 'D' << 16 ) | ( 'M' << 8 ) | MD5B_VERSION;
- idCVar r_useGPUSkinning( "r_useGPUSkinning", "1", CVAR_INTEGER, "animate normals and tangents instead of deriving" );
- /***********************************************************************
- idMD5Mesh
- ***********************************************************************/
- static int c_numVerts = 0;
- static int c_numWeights = 0;
- static int c_numWeightJoints = 0;
- struct vertexWeight_t {
- int joint;
- idVec3 offset;
- float jointWeight;
- };
- /*
- ====================
- idMD5Mesh::idMD5Mesh
- ====================
- */
- idMD5Mesh::idMD5Mesh() {
- shader = NULL;
- numVerts = 0;
- numTris = 0;
- meshJoints = NULL;
- numMeshJoints = 0;
- maxJointVertDist = 0.0f;
- deformInfo = NULL;
- surfaceNum = 0;
- }
- /*
- ====================
- idMD5Mesh::~idMD5Mesh
- ====================
- */
- idMD5Mesh::~idMD5Mesh() {
- if ( meshJoints != NULL ) {
- Mem_Free( meshJoints );
- meshJoints = NULL;
- }
- if ( deformInfo != NULL ) {
- R_FreeDeformInfo( deformInfo );
- deformInfo = NULL;
- }
- }
- /*
- ====================
- idMD5Mesh::ParseMesh
- ====================
- */
- void idMD5Mesh::ParseMesh( idLexer &parser, int numJoints, const idJointMat *joints ) {
- idToken token;
- idToken name;
- parser.ExpectTokenString( "{" );
- //
- // parse name
- //
- if ( parser.CheckTokenString( "name" ) ) {
- parser.ReadToken( &name );
- }
- //
- // parse shader
- //
- parser.ExpectTokenString( "shader" );
- parser.ReadToken( &token );
- idStr shaderName = token;
- shader = declManager->FindMaterial( shaderName );
- //
- // parse texture coordinates
- //
- parser.ExpectTokenString( "numverts" );
- int count = parser.ParseInt();
- if ( count < 0 ) {
- parser.Error( "Invalid size: %s", token.c_str() );
- }
- this->numVerts = count;
- idList<idVec2> texCoords;
- idList<int> firstWeightForVertex;
- idList<int> numWeightsForVertex;
- texCoords.SetNum( count );
- firstWeightForVertex.SetNum( count );
- numWeightsForVertex.SetNum( count );
- int numWeights = 0;
- int maxweight = 0;
- for ( int i = 0; i < texCoords.Num(); i++ ) {
- parser.ExpectTokenString( "vert" );
- parser.ParseInt();
- parser.Parse1DMatrix( 2, texCoords[ i ].ToFloatPtr() );
- firstWeightForVertex[ i ] = parser.ParseInt();
- numWeightsForVertex[ i ] = parser.ParseInt();
- if ( !numWeightsForVertex[ i ] ) {
- parser.Error( "Vertex without any joint weights." );
- }
- numWeights += numWeightsForVertex[ i ];
- if ( numWeightsForVertex[ i ] + firstWeightForVertex[ i ] > maxweight ) {
- maxweight = numWeightsForVertex[ i ] + firstWeightForVertex[ i ];
- }
- }
- //
- // parse tris
- //
- parser.ExpectTokenString( "numtris" );
- count = parser.ParseInt();
- if ( count < 0 ) {
- parser.Error( "Invalid size: %d", count );
- }
- idList<int> tris;
- tris.SetNum( count * 3 );
- numTris = count;
- for ( int i = 0; i < count; i++ ) {
- parser.ExpectTokenString( "tri" );
- parser.ParseInt();
- tris[ i * 3 + 0 ] = parser.ParseInt();
- tris[ i * 3 + 1 ] = parser.ParseInt();
- tris[ i * 3 + 2 ] = parser.ParseInt();
- }
- //
- // parse weights
- //
- parser.ExpectTokenString( "numweights" );
- count = parser.ParseInt();
- if ( count < 0 ) {
- parser.Error( "Invalid size: %d", count );
- }
- if ( maxweight > count ) {
- parser.Warning( "Vertices reference out of range weights in model (%d of %d weights).", maxweight, count );
- }
- idList<vertexWeight_t> tempWeights;
- tempWeights.SetNum( count );
- assert( numJoints < 256 ); // so we can pack into bytes
- for ( int i = 0; i < count; i++ ) {
- parser.ExpectTokenString( "weight" );
- parser.ParseInt();
- int jointnum = parser.ParseInt();
- if ( ( jointnum < 0 ) || ( jointnum >= numJoints ) ) {
- parser.Error( "Joint Index out of range(%d): %d", numJoints, jointnum );
- }
- tempWeights[ i ].joint = jointnum;
- tempWeights[ i ].jointWeight = parser.ParseFloat();
- parser.Parse1DMatrix( 3, tempWeights[ i ].offset.ToFloatPtr() );
- }
- // create pre-scaled weights and an index for the vertex/joint lookup
- idVec4 * scaledWeights = (idVec4 *) Mem_Alloc16( numWeights * sizeof( scaledWeights[0] ), TAG_MD5_WEIGHT );
- int * weightIndex = (int *) Mem_Alloc16( numWeights * 2 * sizeof( weightIndex[0] ), TAG_MD5_INDEX );
- memset( weightIndex, 0, numWeights * 2 * sizeof( weightIndex[0] ) );
- count = 0;
- for ( int i = 0; i < texCoords.Num(); i++ ) {
- int num = firstWeightForVertex[i];
- for( int j = 0; j < numWeightsForVertex[i]; j++, num++, count++ ) {
- scaledWeights[count].ToVec3() = tempWeights[num].offset * tempWeights[num].jointWeight;
- scaledWeights[count].w = tempWeights[num].jointWeight;
- weightIndex[count * 2 + 0] = tempWeights[num].joint * sizeof( idJointMat );
- }
- weightIndex[count * 2 - 1] = 1;
- }
- parser.ExpectTokenString( "}" );
- // update counters
- c_numVerts += texCoords.Num();
- c_numWeights += numWeights;
- c_numWeightJoints++;
- for ( int i = 0; i < numWeights; i++ ) {
- c_numWeightJoints += weightIndex[i*2+1];
- }
- //
- // build a base pose that can be used for skinning
- //
- idDrawVert * basePose = (idDrawVert *)Mem_ClearedAlloc( texCoords.Num() * sizeof( *basePose ), TAG_MD5_BASE );
- for( int j = 0, i = 0; i < texCoords.Num(); i++ ) {
- idVec3 v = ( *(idJointMat *) ( (byte *)joints + weightIndex[j*2+0] ) ) * scaledWeights[j];
- while( weightIndex[j*2+1] == 0 ) {
- j++;
- v += ( *(idJointMat *) ( (byte *)joints + weightIndex[j*2+0] ) ) * scaledWeights[j];
- }
- j++;
- basePose[i].Clear();
- basePose[i].xyz = v;
- basePose[i].SetTexCoord( texCoords[i] );
- }
- // build the weights and bone indexes into the verts, so they will be duplicated
- // as necessary at mirror seems
- static int maxWeightsPerVert;
- static float maxResidualWeight;
- const int MAX_VERTEX_WEIGHTS = 4;
- idList< bool > jointIsUsed;
- jointIsUsed.SetNum( numJoints );
- for ( int i = 0; i < jointIsUsed.Num(); i++ ) {
- jointIsUsed[i] = false;
- }
- numMeshJoints = 0;
- maxJointVertDist = 0.0f;
- //-----------------------------------------
- // new-style setup for fixed four weights and normal / tangent deformation
- //
- // Several important models have >25% residual weight in joints after the
- // first four, which is worrisome for using a fixed four joint deformation.
- //-----------------------------------------
- for ( int i = 0; i < texCoords.Num(); i++ ) {
- idDrawVert & dv = basePose[i];
- // some models do have >4 joint weights, so it is necessary to sort and renormalize
- // sort the weights and take the four largest
- int weights[256];
- const int numWeights = numWeightsForVertex[ i ];
- for ( int j = 0; j < numWeights; j++ ) {
- weights[j] = firstWeightForVertex[i] + j;
- }
- // bubble sort
- for ( int j = 0; j < numWeights; j++ ) {
- for ( int k = 0; k < numWeights - 1 - j; k++ ) {
- if ( tempWeights[weights[k]].jointWeight < tempWeights[weights[k+1]].jointWeight ) {
- SwapValues( weights[k], weights[k+1] );
- }
- }
- }
- if ( numWeights > maxWeightsPerVert ) {
- maxWeightsPerVert = numWeights;
- }
- const int usedWeights = Min( MAX_VERTEX_WEIGHTS, numWeights );
- float totalWeight = 0;
- for ( int j = 0; j < numWeights; j++ ) {
- totalWeight += tempWeights[weights[j]].jointWeight;
- }
- assert( totalWeight > 0.999f && totalWeight < 1.001f );
- float usedWeight = 0;
- for ( int j = 0; j < usedWeights; j++ ) {
- usedWeight += tempWeights[weights[j]].jointWeight;
- }
- const float residualWeight = totalWeight - usedWeight;
- if ( residualWeight > maxResidualWeight ) {
- maxResidualWeight = residualWeight;
- }
- byte finalWeights[MAX_VERTEX_WEIGHTS] = { 0 };
- byte finalJointIndecies[MAX_VERTEX_WEIGHTS] = { 0 };
- for ( int j = 0; j < usedWeights; j++ ) {
- const vertexWeight_t & weight = tempWeights[weights[j]];
- const int jointIndex = weight.joint;
- const float fw = weight.jointWeight;
- assert( fw >= 0.0f && fw <= 1.0f );
- const float normalizedWeight = fw / usedWeight;
- finalWeights[j] = idMath::Ftob( normalizedWeight * 255.0f);
- finalJointIndecies[j] = jointIndex;
- }
- // Sort the weights and indices for hardware skinning
- for ( int k = 0; k < 3; ++k ) {
- for ( int l = k + 1; l < 4; ++l ) {
- if ( finalWeights[l] > finalWeights[k] ) {
- SwapValues( finalWeights[k], finalWeights[l] );
- SwapValues( finalJointIndecies[k], finalJointIndecies[l] );
- }
- }
- }
- // Give any left over to the biggest weight
- finalWeights[0] += Max( 255 - finalWeights[0] - finalWeights[1] - finalWeights[2] - finalWeights[3], 0 );
- dv.color[0] = finalJointIndecies[0];
- dv.color[1] = finalJointIndecies[1];
- dv.color[2] = finalJointIndecies[2];
- dv.color[3] = finalJointIndecies[3];
- dv.color2[0] = finalWeights[0];
- dv.color2[1] = finalWeights[1];
- dv.color2[2] = finalWeights[2];
- dv.color2[3] = finalWeights[3];
- for ( int j = usedWeights; j < 4; j++ ) {
- assert( dv.color2[j] == 0 );
- }
- for ( int j = 0; j < usedWeights; j++ ) {
- if ( !jointIsUsed[finalJointIndecies[j]] ) {
- jointIsUsed[finalJointIndecies[j]] = true;
- numMeshJoints++;
- }
- const idJointMat & joint = joints[finalJointIndecies[j]];
- float dist = ( dv.xyz - joint.GetTranslation() ).Length();
- if ( dist > maxJointVertDist ) {
- maxJointVertDist = dist;
- }
- }
- }
- meshJoints = (byte *) Mem_Alloc( numMeshJoints * sizeof( meshJoints[0] ), TAG_MODEL );
- numMeshJoints = 0;
- for ( int i = 0; i < numJoints; i++ ) {
- if ( jointIsUsed[i] ) {
- meshJoints[numMeshJoints++] = i;
- }
- }
- // build the deformInfo and collect a final base pose with the mirror
- // seam verts properly including the bone weights
- deformInfo = R_BuildDeformInfo( texCoords.Num(), basePose, tris.Num(), tris.Ptr(),
- shader->UseUnsmoothedTangents() );
- for ( int i = 0; i < deformInfo->numOutputVerts; i++ ) {
- for ( int j = 0; j < 4; j++ ) {
- if ( deformInfo->verts[i].color[j] >= numJoints ) {
- idLib::FatalError( "Bad joint index" );
- }
- }
- }
- Mem_Free( basePose );
- }
- /*
- ============
- TransformVertsAndTangents
- ============
- */
- void TransformVertsAndTangents( idDrawVert * targetVerts, const int numVerts, const idDrawVert *baseVerts, const idJointMat *joints ) {
- for( int i = 0; i < numVerts; i++ ) {
- const idDrawVert & base = baseVerts[i];
- const idJointMat & j0 = joints[base.color[0]];
- const idJointMat & j1 = joints[base.color[1]];
- const idJointMat & j2 = joints[base.color[2]];
- const idJointMat & j3 = joints[base.color[3]];
- const float w0 = base.color2[0] * ( 1.0f / 255.0f );
- const float w1 = base.color2[1] * ( 1.0f / 255.0f );
- const float w2 = base.color2[2] * ( 1.0f / 255.0f );
- const float w3 = base.color2[3] * ( 1.0f / 255.0f );
- idJointMat accum;
- idJointMat::Mul( accum, j0, w0 );
- idJointMat::Mad( accum, j1, w1 );
- idJointMat::Mad( accum, j2, w2 );
- idJointMat::Mad( accum, j3, w3 );
- targetVerts[i].xyz = accum * idVec4( base.xyz.x, base.xyz.y, base.xyz.z, 1.0f );
- targetVerts[i].SetNormal( accum * base.GetNormal() );
- targetVerts[i].SetTangent( accum * base.GetTangent() );
- targetVerts[i].tangent[3] = base.tangent[3];
- }
- }
- /*
- ====================
- idMD5Mesh::UpdateSurface
- ====================
- */
- void idMD5Mesh::UpdateSurface( const struct renderEntity_s *ent, const idJointMat *entJoints,
- const idJointMat *entJointsInverted, modelSurface_t *surf ) {
- tr.pc.c_deformedSurfaces++;
- tr.pc.c_deformedVerts += deformInfo->numOutputVerts;
- tr.pc.c_deformedIndexes += deformInfo->numIndexes;
- surf->shader = shader;
- if ( surf->geometry != NULL ) {
- // if the number of verts and indexes are the same we can re-use the triangle surface
- if ( surf->geometry->numVerts == deformInfo->numOutputVerts && surf->geometry->numIndexes == deformInfo->numIndexes ) {
- R_FreeStaticTriSurfVertexCaches( surf->geometry );
- } else {
- R_FreeStaticTriSurf( surf->geometry );
- surf->geometry = R_AllocStaticTriSurf();
- }
- } else {
- surf->geometry = R_AllocStaticTriSurf();
- }
- srfTriangles_t * tri = surf->geometry;
- // note that some of the data is referenced, and should not be freed
- tri->referencedIndexes = true;
- tri->numIndexes = deformInfo->numIndexes;
- tri->indexes = deformInfo->indexes;
- tri->silIndexes = deformInfo->silIndexes;
- tri->numMirroredVerts = deformInfo->numMirroredVerts;
- tri->mirroredVerts = deformInfo->mirroredVerts;
- tri->numDupVerts = deformInfo->numDupVerts;
- tri->dupVerts = deformInfo->dupVerts;
- tri->numSilEdges = deformInfo->numSilEdges;
- tri->silEdges = deformInfo->silEdges;
- tri->indexCache = deformInfo->staticIndexCache;
- tri->numVerts = deformInfo->numOutputVerts;
- if ( r_useGPUSkinning.GetBool() ) {
- if ( tri->verts != NULL && tri->verts != deformInfo->verts ) {
- R_FreeStaticTriSurfVerts( tri );
- }
- tri->verts = deformInfo->verts;
- tri->ambientCache = deformInfo->staticAmbientCache;
- tri->shadowCache = deformInfo->staticShadowCache;
- tri->referencedVerts = true;
- } else {
- if ( tri->verts == NULL || tri->verts == deformInfo->verts ) {
- tri->verts = NULL;
- R_AllocStaticTriSurfVerts( tri, deformInfo->numOutputVerts );
- assert( tri->verts != NULL ); // quiet analyze warning
- memcpy( tri->verts, deformInfo->verts, deformInfo->numOutputVerts * sizeof( deformInfo->verts[0] ) ); // copy over the texture coordinates
- }
- TransformVertsAndTangents( tri->verts, deformInfo->numOutputVerts, deformInfo->verts, entJointsInverted );
- tri->referencedVerts = false;
- }
- tri->tangentsCalculated = true;
- CalculateBounds( entJoints, tri->bounds );
- }
- /*
- ====================
- idMD5Mesh::CalculateBounds
- ====================
- */
- void idMD5Mesh::CalculateBounds( const idJointMat * entJoints, idBounds & bounds ) const {
- #ifdef ID_WIN_X86_SSE2_INTRIN
- __m128 minX = vector_float_posInfinity;
- __m128 minY = vector_float_posInfinity;
- __m128 minZ = vector_float_posInfinity;
- __m128 maxX = vector_float_negInfinity;
- __m128 maxY = vector_float_negInfinity;
- __m128 maxZ = vector_float_negInfinity;
- for ( int i = 0; i < numMeshJoints; i++ ) {
- const idJointMat & joint = entJoints[meshJoints[i]];
- __m128 x = _mm_load_ps( joint.ToFloatPtr() + 0 * 4 );
- __m128 y = _mm_load_ps( joint.ToFloatPtr() + 1 * 4 );
- __m128 z = _mm_load_ps( joint.ToFloatPtr() + 2 * 4 );
- minX = _mm_min_ps( minX, x );
- minY = _mm_min_ps( minY, y );
- minZ = _mm_min_ps( minZ, z );
- maxX = _mm_max_ps( maxX, x );
- maxY = _mm_max_ps( maxY, y );
- maxZ = _mm_max_ps( maxZ, z );
- }
- __m128 expand = _mm_splat_ps( _mm_load_ss( & maxJointVertDist ), 0 );
- minX = _mm_sub_ps( minX, expand );
- minY = _mm_sub_ps( minY, expand );
- minZ = _mm_sub_ps( minZ, expand );
- maxX = _mm_add_ps( maxX, expand );
- maxY = _mm_add_ps( maxY, expand );
- maxZ = _mm_add_ps( maxZ, expand );
- _mm_store_ss( bounds.ToFloatPtr() + 0, _mm_splat_ps( minX, 3 ) );
- _mm_store_ss( bounds.ToFloatPtr() + 1, _mm_splat_ps( minY, 3 ) );
- _mm_store_ss( bounds.ToFloatPtr() + 2, _mm_splat_ps( minZ, 3 ) );
- _mm_store_ss( bounds.ToFloatPtr() + 3, _mm_splat_ps( maxX, 3 ) );
- _mm_store_ss( bounds.ToFloatPtr() + 4, _mm_splat_ps( maxY, 3 ) );
- _mm_store_ss( bounds.ToFloatPtr() + 5, _mm_splat_ps( maxZ, 3 ) );
- #else
- bounds.Clear();
- for ( int i = 0; i < numMeshJoints; i++ ) {
- const idJointMat & joint = entJoints[meshJoints[i]];
- bounds.AddPoint( joint.GetTranslation() );
- }
- bounds.ExpandSelf( maxJointVertDist );
- #endif
- }
- /*
- ====================
- idMD5Mesh::NearestJoint
- ====================
- */
- int idMD5Mesh::NearestJoint( int a, int b, int c ) const {
- // duplicated vertices might not have weights
- int vertNum;
- if ( a >= 0 && a < numVerts ) {
- vertNum = a;
- } else if ( b >= 0 && b < numVerts ) {
- vertNum = b;
- } else if ( c >= 0 && c < numVerts ) {
- vertNum = c;
- } else {
- // all vertices are duplicates which shouldn't happen
- return 0;
- }
- const idDrawVert & v = deformInfo->verts[vertNum];
- int bestWeight = 0;
- int bestJoint = 0;
- for ( int i = 0; i < 4; i++ ) {
- if ( v.color2[i] > bestWeight ) {
- bestWeight = v.color2[i];
- bestJoint = v.color[i];
- }
- }
- return bestJoint;
- }
- /***********************************************************************
- idRenderModelMD5
- ***********************************************************************/
- /*
- ====================
- idRenderModelMD5::ParseJoint
- ====================
- */
- void idRenderModelMD5::ParseJoint( idLexer &parser, idMD5Joint *joint, idJointQuat *defaultPose ) {
- //
- // parse name
- //
- idToken token;
- parser.ReadToken( &token );
- joint->name = token;
- //
- // parse parent
- //
- int num = parser.ParseInt();
- if ( num < 0 ) {
- joint->parent = NULL;
- } else {
- if ( num >= joints.Num() - 1 ) {
- parser.Error( "Invalid parent for joint '%s'", joint->name.c_str() );
- }
- joint->parent = &joints[ num ];
- }
- //
- // parse default pose
- //
- parser.Parse1DMatrix( 3, defaultPose->t.ToFloatPtr() );
- parser.Parse1DMatrix( 3, defaultPose->q.ToFloatPtr() );
- defaultPose->q.w = defaultPose->q.CalcW();
- }
- /*
- ====================
- idRenderModelMD5::InitFromFile
- ====================
- */
- void idRenderModelMD5::InitFromFile( const char *fileName ) {
- name = fileName;
- LoadModel();
- }
- /*
- ========================
- idRenderModelMD5::LoadBinaryModel
- ========================
- */
- bool idRenderModelMD5::LoadBinaryModel( idFile * file, const ID_TIME_T sourceTimeStamp ) {
- if ( !idRenderModelStatic::LoadBinaryModel( file, sourceTimeStamp ) ) {
- return false;
- }
- unsigned int magic = 0;
- file->ReadBig( magic );
- if ( magic != MD5B_MAGIC ) {
- return false;
- }
- int tempNum;
- file->ReadBig( tempNum );
- joints.SetNum( tempNum );
- for ( int i = 0; i < joints.Num(); i++ ) {
- file->ReadString( joints[i].name );
- int offset;
- file->ReadBig( offset );
- if ( offset >= 0 ) {
- joints[i].parent = joints.Ptr() + offset;
- } else {
- joints[i].parent = NULL;
- }
- }
- file->ReadBig( tempNum );
- defaultPose.SetNum( tempNum );
- for ( int i = 0; i < defaultPose.Num(); i++ ) {
- file->ReadBig( defaultPose[i].q.x );
- file->ReadBig( defaultPose[i].q.y );
- file->ReadBig( defaultPose[i].q.z );
- file->ReadBig( defaultPose[i].q.w );
- file->ReadVec3( defaultPose[i].t );
- }
- file->ReadBig( tempNum );
- invertedDefaultPose.SetNum( tempNum );
- for ( int i = 0; i < invertedDefaultPose.Num(); i++ ) {
- file->ReadBigArray( invertedDefaultPose[ i ].ToFloatPtr(), JOINTMAT_TYPESIZE );
- }
- SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr(), joints.Num() );
- file->ReadBig( tempNum );
- meshes.SetNum( tempNum );
- for ( int i = 0; i < meshes.Num(); i++ ) {
- idStr materialName;
- file->ReadString( materialName );
- if ( materialName.IsEmpty() ) {
- meshes[i].shader = NULL;
- } else {
- meshes[i].shader = declManager->FindMaterial( materialName );
- }
-
- file->ReadBig( meshes[i].numVerts );
- file->ReadBig( meshes[i].numTris );
- file->ReadBig( meshes[i].numMeshJoints );
- meshes[i].meshJoints = (byte *) Mem_Alloc( meshes[i].numMeshJoints * sizeof( meshes[i].meshJoints[0] ), TAG_MODEL );
- file->ReadBigArray( meshes[i].meshJoints, meshes[i].numMeshJoints );
- file->ReadBig( meshes[i].maxJointVertDist );
- meshes[i].deformInfo = (deformInfo_t *)R_ClearedStaticAlloc( sizeof( deformInfo_t ) );
- deformInfo_t & deform = *meshes[i].deformInfo;
- file->ReadBig( deform.numSourceVerts );
- file->ReadBig( deform.numOutputVerts );
- file->ReadBig( deform.numIndexes );
- file->ReadBig( deform.numMirroredVerts );
- file->ReadBig( deform.numDupVerts );
- file->ReadBig( deform.numSilEdges );
- srfTriangles_t tri;
- memset( &tri, 0, sizeof( srfTriangles_t ) );
-
- if ( deform.numOutputVerts > 0 ) {
- R_AllocStaticTriSurfVerts( &tri, deform.numOutputVerts );
- deform.verts = tri.verts;
- file->ReadBigArray( deform.verts, deform.numOutputVerts );
- }
- if ( deform.numIndexes > 0 ) {
- R_AllocStaticTriSurfIndexes( &tri, deform.numIndexes );
- R_AllocStaticTriSurfSilIndexes( &tri, deform.numIndexes );
- deform.indexes = tri.indexes;
- deform.silIndexes = tri.silIndexes;
- file->ReadBigArray( deform.indexes, deform.numIndexes );
- file->ReadBigArray( deform.silIndexes, deform.numIndexes );
- }
-
- if ( deform.numMirroredVerts > 0 ) {
- R_AllocStaticTriSurfMirroredVerts( &tri, deform.numMirroredVerts );
- deform.mirroredVerts = tri.mirroredVerts;
- file->ReadBigArray( deform.mirroredVerts, deform.numMirroredVerts );
- }
- if ( deform.numDupVerts > 0 ) {
- R_AllocStaticTriSurfDupVerts( &tri, deform.numDupVerts );
- deform.dupVerts = tri.dupVerts;
- file->ReadBigArray( deform.dupVerts, deform.numDupVerts * 2 );
- }
- if ( deform.numSilEdges > 0 ) {
- R_AllocStaticTriSurfSilEdges( &tri, deform.numSilEdges );
- deform.silEdges = tri.silEdges;
- assert( deform.silEdges != NULL );
- for ( int j = 0; j < deform.numSilEdges; j++ ) {
- file->ReadBig( deform.silEdges[j].p1 );
- file->ReadBig( deform.silEdges[j].p2 );
- file->ReadBig( deform.silEdges[j].v1 );
- file->ReadBig( deform.silEdges[j].v2 );
- }
- }
- idShadowVertSkinned * shadowVerts = (idShadowVertSkinned *) Mem_Alloc( 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 );
- file->ReadBig( meshes[i].surfaceNum );
- }
- return true;
- }
- /*
- ========================
- idRenderModelMD5::WriteBinaryModel
- ========================
- */
- void idRenderModelMD5::WriteBinaryModel( idFile * file, ID_TIME_T *_timeStamp ) const {
- idRenderModelStatic::WriteBinaryModel( file );
- if ( file == NULL ) {
- return;
- }
- file->WriteBig( MD5B_MAGIC );
- file->WriteBig( joints.Num() );
- for ( int i = 0; i < joints.Num(); i++ ) {
- file->WriteString( joints[i].name );
- int offset = -1;
- if ( joints[i].parent != NULL ) {
- offset = joints[i].parent - joints.Ptr();
- }
- file->WriteBig( offset );
- }
- file->WriteBig( defaultPose.Num() );
- for ( int i = 0; i < defaultPose.Num(); i++ ) {
- file->WriteBig( defaultPose[i].q.x );
- file->WriteBig( defaultPose[i].q.y );
- file->WriteBig( defaultPose[i].q.z );
- file->WriteBig( defaultPose[i].q.w );
- file->WriteVec3( defaultPose[i].t );
- }
- file->WriteBig( invertedDefaultPose.Num() );
- for ( int i = 0; i < invertedDefaultPose.Num(); i++ ) {
- file->WriteBigArray( invertedDefaultPose[ i ].ToFloatPtr(), JOINTMAT_TYPESIZE );
- }
- file->WriteBig( meshes.Num() );
- for ( int i = 0; i < meshes.Num(); i++ ) {
- if ( meshes[i].shader != NULL && meshes[i].shader->GetName() != NULL ) {
- file->WriteString( meshes[i].shader->GetName() );
- } else {
- file->WriteString( "" );
- }
- file->WriteBig( meshes[i].numVerts );
- file->WriteBig( meshes[i].numTris );
- file->WriteBig( meshes[i].numMeshJoints );
- file->WriteBigArray( meshes[i].meshJoints, meshes[i].numMeshJoints );
- file->WriteBig( meshes[i].maxJointVertDist );
- deformInfo_t & deform = *meshes[i].deformInfo;
- file->WriteBig( deform.numSourceVerts );
- file->WriteBig( deform.numOutputVerts );
- file->WriteBig( deform.numIndexes );
- file->WriteBig( deform.numMirroredVerts );
- file->WriteBig( deform.numDupVerts );
- file->WriteBig( deform.numSilEdges );
- if ( deform.numOutputVerts > 0 ) {
- file->WriteBigArray( deform.verts, deform.numOutputVerts );
- }
- if ( deform.numIndexes > 0 ) {
- file->WriteBigArray( deform.indexes, deform.numIndexes );
- file->WriteBigArray( deform.silIndexes, deform.numIndexes );
- }
- if ( deform.numMirroredVerts > 0 ) {
- file->WriteBigArray( deform.mirroredVerts, deform.numMirroredVerts );
- }
- if ( deform.numDupVerts > 0 ) {
- file->WriteBigArray( deform.dupVerts, deform.numDupVerts * 2 );
- }
- if ( deform.numSilEdges > 0 ) {
- for ( int j = 0; j < deform.numSilEdges; j++ ) {
- file->WriteBig( deform.silEdges[j].p1 );
- file->WriteBig( deform.silEdges[j].p2 );
- file->WriteBig( deform.silEdges[j].v1 );
- file->WriteBig( deform.silEdges[j].v2 );
- }
- }
- file->WriteBig( meshes[i].surfaceNum );
- }
- }
- /*
- ====================
- idRenderModelMD5::LoadModel
- used for initial loads, reloadModel, and reloading the data of purged models
- Upon exit, the model will absolutely be valid, but possibly as a default model
- ====================
- */
- void idRenderModelMD5::LoadModel() {
- int version;
- int num;
- int parentNum;
- idToken token;
- idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS );
- if ( !purged ) {
- PurgeModel();
- }
- purged = false;
- if ( !parser.LoadFile( name ) ) {
- MakeDefaultModel();
- return;
- }
- parser.ExpectTokenString( MD5_VERSION_STRING );
- version = parser.ParseInt();
- if ( version != MD5_VERSION ) {
- parser.Error( "Invalid version %d. Should be version %d\n", version, MD5_VERSION );
- }
- //
- // skip commandline
- //
- parser.ExpectTokenString( "commandline" );
- parser.ReadToken( &token );
- // parse num joints
- parser.ExpectTokenString( "numJoints" );
- num = parser.ParseInt();
- joints.SetGranularity( 1 );
- joints.SetNum( num );
- defaultPose.SetGranularity( 1 );
- defaultPose.SetNum( num );
- // parse num meshes
- parser.ExpectTokenString( "numMeshes" );
- num = parser.ParseInt();
- if ( num < 0 ) {
- parser.Error( "Invalid size: %d", num );
- }
- meshes.SetGranularity( 1 );
- meshes.SetNum( num );
- //
- // parse joints
- //
- parser.ExpectTokenString( "joints" );
- parser.ExpectTokenString( "{" );
- idJointMat *poseMat = ( idJointMat * )_alloca16( joints.Num() * sizeof( poseMat[0] ) );
- for( int i = 0; i < joints.Num(); i++ ) {
- idMD5Joint * joint = &joints[i];
- idJointQuat * pose = &defaultPose[i];
- ParseJoint( parser, joint, pose );
- poseMat[ i ].SetRotation( pose->q.ToMat3() );
- poseMat[ i ].SetTranslation( pose->t );
- if ( joint->parent ) {
- parentNum = joint->parent - joints.Ptr();
- pose->q = ( poseMat[ i ].ToMat3() * poseMat[ parentNum ].ToMat3().Transpose() ).ToQuat();
- pose->t = ( poseMat[ i ].ToVec3() - poseMat[ parentNum ].ToVec3() ) * poseMat[ parentNum ].ToMat3().Transpose();
- }
- }
- parser.ExpectTokenString( "}" );
- //-----------------------------------------
- // create the inverse of the base pose joints to support tech6 style deformation
- // of base pose vertexes, normals, and tangents.
- //
- // vertex * joints * inverseJoints == vertex when joints is the base pose
- // When the joints are in another pose, it gives the animated vertex position
- //-----------------------------------------
- invertedDefaultPose.SetNum( SIMD_ROUND_JOINTS( joints.Num() ) );
- for ( int i = 0; i < joints.Num(); i++ ) {
- invertedDefaultPose[i] = poseMat[i];
- invertedDefaultPose[i].Invert();
- }
- SIMD_INIT_LAST_JOINT( invertedDefaultPose.Ptr(), joints.Num() );
- for ( int i = 0; i < meshes.Num(); i++ ) {
- parser.ExpectTokenString( "mesh" );
- meshes[i].ParseMesh( parser, defaultPose.Num(), poseMat );
- }
- // calculate the bounds of the model
- bounds.Clear();
- for ( int i = 0; i < meshes.Num(); i++ ) {
- idBounds meshBounds;
- meshes[i].CalculateBounds( poseMat, meshBounds );
- bounds.AddBounds( meshBounds );
- }
- // set the timestamp for reloadmodels
- fileSystem->ReadFile( name, NULL, &timeStamp );
- common->UpdateLevelLoadPacifier();
- }
- /*
- ==============
- idRenderModelMD5::Print
- ==============
- */
- void idRenderModelMD5::Print() const {
- common->Printf( "%s\n", name.c_str() );
- common->Printf( "Dynamic model.\n" );
- common->Printf( "Generated smooth normals.\n" );
- common->Printf( " verts tris weights material\n" );
- int totalVerts = 0;
- int totalTris = 0;
- const idMD5Mesh * mesh = meshes.Ptr();
- for ( int i = 0; i < meshes.Num(); i++, mesh++ ) {
- totalVerts += mesh->NumVerts();
- totalTris += mesh->NumTris();
- common->Printf( "%2i: %5i %5i %s\n", i, mesh->NumVerts(), mesh->NumTris(), mesh->shader->GetName() );
- }
- common->Printf( "-----\n" );
- common->Printf( "%4i verts.\n", totalVerts );
- common->Printf( "%4i tris.\n", totalTris );
- common->Printf( "%4i joints.\n", joints.Num() );
- }
- /*
- ==============
- idRenderModelMD5::List
- ==============
- */
- void idRenderModelMD5::List() const {
- int i;
- const idMD5Mesh *mesh;
- int totalTris = 0;
- int totalVerts = 0;
- for( mesh = meshes.Ptr(), i = 0; i < meshes.Num(); i++, mesh++ ) {
- totalTris += mesh->numTris;
- totalVerts += mesh->NumVerts();
- }
- common->Printf( " %4ik %3i %4i %4i %s(MD5)", Memory()/1024, meshes.Num(), totalVerts, totalTris, Name() );
- if ( defaulted ) {
- common->Printf( " (DEFAULTED)" );
- }
- common->Printf( "\n" );
- }
- /*
- ====================
- idRenderModelMD5::Bounds
- This calculates a rough bounds by using the joint radii without
- transforming all the points
- ====================
- */
- idBounds idRenderModelMD5::Bounds( const renderEntity_t *ent ) const {
- if ( ent == NULL ) {
- // this is the bounds for the reference pose
- return bounds;
- }
- return ent->bounds;
- }
- /*
- ====================
- idRenderModelMD5::DrawJoints
- ====================
- */
- void idRenderModelMD5::DrawJoints( const renderEntity_t *ent, const viewDef_t *view ) const {
- int i;
- int num;
- idVec3 pos;
- const idJointMat *joint;
- const idMD5Joint *md5Joint;
- int parentNum;
- num = ent->numJoints;
- joint = ent->joints;
- md5Joint = joints.Ptr();
- for( i = 0; i < num; i++, joint++, md5Joint++ ) {
- pos = ent->origin + joint->ToVec3() * ent->axis;
- if ( md5Joint->parent ) {
- parentNum = md5Joint->parent - joints.Ptr();
- common->RW()->DebugLine( colorWhite, ent->origin + ent->joints[ parentNum ].ToVec3() * ent->axis, pos );
- }
- common->RW()->DebugLine( colorRed, pos, pos + joint->ToMat3()[ 0 ] * 2.0f * ent->axis );
- common->RW()->DebugLine( colorGreen,pos, pos + joint->ToMat3()[ 1 ] * 2.0f * ent->axis );
- common->RW()->DebugLine( colorBlue, pos, pos + joint->ToMat3()[ 2 ] * 2.0f * ent->axis );
- }
- idBounds bounds;
- bounds.FromTransformedBounds( ent->bounds, vec3_zero, ent->axis );
- common->RW()->DebugBounds( colorMagenta, bounds, ent->origin );
- if ( ( r_jointNameScale.GetFloat() != 0.0f ) && ( bounds.Expand( 128.0f ).ContainsPoint( view->renderView.vieworg - ent->origin ) ) ) {
- idVec3 offset( 0, 0, r_jointNameOffset.GetFloat() );
- float scale;
- scale = r_jointNameScale.GetFloat();
- joint = ent->joints;
- num = ent->numJoints;
- for( i = 0; i < num; i++, joint++ ) {
- pos = ent->origin + joint->ToVec3() * ent->axis;
- common->RW()->DrawText( joints[ i ].name, pos + offset, scale, colorWhite, view->renderView.viewaxis, 1 );
- }
- }
- }
- /*
- ====================
- TransformJoints
- ====================
- */
- static void TransformJoints( idJointMat *__restrict outJoints, const int numJoints, const idJointMat *__restrict inJoints1, const idJointMat *__restrict inJoints2 ) {
- float * outFloats = outJoints->ToFloatPtr();
- const float * inFloats1 = inJoints1->ToFloatPtr();
- const float * inFloats2 = inJoints2->ToFloatPtr();
- assert_16_byte_aligned( outFloats );
- assert_16_byte_aligned( inFloats1 );
- assert_16_byte_aligned( inFloats2 );
- #ifdef ID_WIN_X86_SSE2_INTRIN
- const __m128 mask_keep_last = __m128c( _mm_set_epi32( 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000 ) );
- for ( int i = 0; i < numJoints; i += 2, inFloats1 += 2 * 12, inFloats2 += 2 * 12, outFloats += 2 * 12 ) {
- __m128 m1a0 = _mm_load_ps( inFloats1 + 0 * 12 + 0 );
- __m128 m1b0 = _mm_load_ps( inFloats1 + 0 * 12 + 4 );
- __m128 m1c0 = _mm_load_ps( inFloats1 + 0 * 12 + 8 );
- __m128 m1a1 = _mm_load_ps( inFloats1 + 1 * 12 + 0 );
- __m128 m1b1 = _mm_load_ps( inFloats1 + 1 * 12 + 4 );
- __m128 m1c1 = _mm_load_ps( inFloats1 + 1 * 12 + 8 );
- __m128 m2a0 = _mm_load_ps( inFloats2 + 0 * 12 + 0 );
- __m128 m2b0 = _mm_load_ps( inFloats2 + 0 * 12 + 4 );
- __m128 m2c0 = _mm_load_ps( inFloats2 + 0 * 12 + 8 );
- __m128 m2a1 = _mm_load_ps( inFloats2 + 1 * 12 + 0 );
- __m128 m2b1 = _mm_load_ps( inFloats2 + 1 * 12 + 4 );
- __m128 m2c1 = _mm_load_ps( inFloats2 + 1 * 12 + 8 );
- __m128 tj0 = _mm_and_ps( m1a0, mask_keep_last );
- __m128 tk0 = _mm_and_ps( m1b0, mask_keep_last );
- __m128 tl0 = _mm_and_ps( m1c0, mask_keep_last );
- __m128 tj1 = _mm_and_ps( m1a1, mask_keep_last );
- __m128 tk1 = _mm_and_ps( m1b1, mask_keep_last );
- __m128 tl1 = _mm_and_ps( m1c1, mask_keep_last );
- __m128 ta0 = _mm_splat_ps( m1a0, 0 );
- __m128 td0 = _mm_splat_ps( m1b0, 0 );
- __m128 tg0 = _mm_splat_ps( m1c0, 0 );
- __m128 ta1 = _mm_splat_ps( m1a1, 0 );
- __m128 td1 = _mm_splat_ps( m1b1, 0 );
- __m128 tg1 = _mm_splat_ps( m1c1, 0 );
- __m128 ra0 = _mm_add_ps( tj0, _mm_mul_ps( ta0, m2a0 ) );
- __m128 rd0 = _mm_add_ps( tk0, _mm_mul_ps( td0, m2a0 ) );
- __m128 rg0 = _mm_add_ps( tl0, _mm_mul_ps( tg0, m2a0 ) );
- __m128 ra1 = _mm_add_ps( tj1, _mm_mul_ps( ta1, m2a1 ) );
- __m128 rd1 = _mm_add_ps( tk1, _mm_mul_ps( td1, m2a1 ) );
- __m128 rg1 = _mm_add_ps( tl1, _mm_mul_ps( tg1, m2a1 ) );
- __m128 tb0 = _mm_splat_ps( m1a0, 1 );
- __m128 te0 = _mm_splat_ps( m1b0, 1 );
- __m128 th0 = _mm_splat_ps( m1c0, 1 );
- __m128 tb1 = _mm_splat_ps( m1a1, 1 );
- __m128 te1 = _mm_splat_ps( m1b1, 1 );
- __m128 th1 = _mm_splat_ps( m1c1, 1 );
- __m128 rb0 = _mm_add_ps( ra0, _mm_mul_ps( tb0, m2b0 ) );
- __m128 re0 = _mm_add_ps( rd0, _mm_mul_ps( te0, m2b0 ) );
- __m128 rh0 = _mm_add_ps( rg0, _mm_mul_ps( th0, m2b0 ) );
- __m128 rb1 = _mm_add_ps( ra1, _mm_mul_ps( tb1, m2b1 ) );
- __m128 re1 = _mm_add_ps( rd1, _mm_mul_ps( te1, m2b1 ) );
- __m128 rh1 = _mm_add_ps( rg1, _mm_mul_ps( th1, m2b1 ) );
- __m128 tc0 = _mm_splat_ps( m1a0, 2 );
- __m128 tf0 = _mm_splat_ps( m1b0, 2 );
- __m128 ti0 = _mm_splat_ps( m1c0, 2 );
- __m128 tf1 = _mm_splat_ps( m1b1, 2 );
- __m128 ti1 = _mm_splat_ps( m1c1, 2 );
- __m128 tc1 = _mm_splat_ps( m1a1, 2 );
- __m128 rc0 = _mm_add_ps( rb0, _mm_mul_ps( tc0, m2c0 ) );
- __m128 rf0 = _mm_add_ps( re0, _mm_mul_ps( tf0, m2c0 ) );
- __m128 ri0 = _mm_add_ps( rh0, _mm_mul_ps( ti0, m2c0 ) );
- __m128 rc1 = _mm_add_ps( rb1, _mm_mul_ps( tc1, m2c1 ) );
- __m128 rf1 = _mm_add_ps( re1, _mm_mul_ps( tf1, m2c1 ) );
- __m128 ri1 = _mm_add_ps( rh1, _mm_mul_ps( ti1, m2c1 ) );
- _mm_store_ps( outFloats + 0 * 12 + 0, rc0 );
- _mm_store_ps( outFloats + 0 * 12 + 4, rf0 );
- _mm_store_ps( outFloats + 0 * 12 + 8, ri0 );
- _mm_store_ps( outFloats + 1 * 12 + 0, rc1 );
- _mm_store_ps( outFloats + 1 * 12 + 4, rf1 );
- _mm_store_ps( outFloats + 1 * 12 + 8, ri1 );
- }
- #else
- for ( int i = 0; i < numJoints; i++ ) {
- idJointMat::Multiply( outJoints[i], inJoints1[i], inJoints2[i] );
- }
- #endif
- }
- /*
- ====================
- idRenderModelMD5::InstantiateDynamicModel
- ====================
- */
- idRenderModel *idRenderModelMD5::InstantiateDynamicModel( const struct renderEntity_s *ent, const viewDef_t *view, idRenderModel *cachedModel ) {
- if ( cachedModel != NULL && !r_useCachedDynamicModels.GetBool() ) {
- delete cachedModel;
- cachedModel = NULL;
- }
- if ( purged ) {
- common->DWarning( "model %s instantiated while purged", Name() );
- LoadModel();
- }
- if ( !ent->joints ) {
- common->Printf( "idRenderModelMD5::InstantiateDynamicModel: NULL joints on renderEntity for '%s'\n", Name() );
- delete cachedModel;
- return NULL;
- } else if ( ent->numJoints != joints.Num() ) {
- common->Printf( "idRenderModelMD5::InstantiateDynamicModel: renderEntity has different number of joints than model for '%s'\n", Name() );
- delete cachedModel;
- return NULL;
- }
- tr.pc.c_generateMd5++;
- idRenderModelStatic * staticModel;
- if ( cachedModel != NULL ) {
- assert( dynamic_cast<idRenderModelStatic *>(cachedModel) != NULL );
- assert( idStr::Icmp( cachedModel->Name(), MD5_SnapshotName ) == 0 );
- staticModel = static_cast<idRenderModelStatic *>(cachedModel);
- } else {
- staticModel = new (TAG_MODEL) idRenderModelStatic;
- staticModel->InitEmpty( MD5_SnapshotName );
- }
- staticModel->bounds.Clear();
- if ( r_showSkel.GetInteger() ) {
- if ( ( view != NULL ) && ( !r_skipSuppress.GetBool() || !ent->suppressSurfaceInViewID || ( ent->suppressSurfaceInViewID != view->renderView.viewID ) ) ) {
- // only draw the skeleton
- DrawJoints( ent, view );
- }
- if ( r_showSkel.GetInteger() > 1 ) {
- // turn off the model when showing the skeleton
- staticModel->InitEmpty( MD5_SnapshotName );
- return staticModel;
- }
- }
- // update the GPU joints array
- const int numInvertedJoints = SIMD_ROUND_JOINTS( joints.Num() );
- if ( staticModel->jointsInverted == NULL ) {
- staticModel->numInvertedJoints = numInvertedJoints;
- const int alignment = glConfig.uniformBufferOffsetAlignment;
- staticModel->jointsInverted = (idJointMat *)Mem_ClearedAlloc( ALIGN( numInvertedJoints * sizeof( idJointMat ), alignment ), TAG_JOINTMAT );
- staticModel->jointsInvertedBuffer = 0;
- } else {
- assert( staticModel->numInvertedJoints == numInvertedJoints );
- }
- TransformJoints( staticModel->jointsInverted, joints.Num(), ent->joints, invertedDefaultPose.Ptr() );
- // create all the surfaces
- idMD5Mesh * mesh = meshes.Ptr();
- for ( int i = 0; i < meshes.Num(); i++, mesh++ ) {
- // avoid deforming the surface if it will be a nodraw due to a skin remapping
- const idMaterial *shader = mesh->shader;
-
- shader = R_RemapShaderBySkin( shader, ent->customSkin, ent->customShader );
-
- if ( !shader || ( !shader->IsDrawn() && !shader->SurfaceCastsShadow() ) ) {
- staticModel->DeleteSurfaceWithId( i );
- mesh->surfaceNum = -1;
- continue;
- }
- modelSurface_t *surf;
- int surfaceNum = 0;
- if ( staticModel->FindSurfaceWithId( i, surfaceNum ) ) {
- mesh->surfaceNum = surfaceNum;
- surf = &staticModel->surfaces[surfaceNum];
- } else {
- mesh->surfaceNum = staticModel->NumSurfaces();
- surf = &staticModel->surfaces.Alloc();
- surf->geometry = NULL;
- surf->shader = NULL;
- surf->id = i;
- }
- mesh->UpdateSurface( ent, ent->joints, staticModel->jointsInverted, surf );
- assert( surf->geometry != NULL ); // to get around compiler warning
- // the deformation of the tangents can be deferred until each surface is added to the view
- surf->geometry->staticModelWithJoints = staticModel;
-
- staticModel->bounds.AddBounds( surf->geometry->bounds );
- }
- return staticModel;
- }
- /*
- ====================
- idRenderModelMD5::IsDynamicModel
- ====================
- */
- dynamicModel_t idRenderModelMD5::IsDynamicModel() const {
- return DM_CACHED;
- }
- /*
- ====================
- idRenderModelMD5::NumJoints
- ====================
- */
- int idRenderModelMD5::NumJoints() const {
- return joints.Num();
- }
- /*
- ====================
- idRenderModelMD5::GetJoints
- ====================
- */
- const idMD5Joint *idRenderModelMD5::GetJoints() const {
- return joints.Ptr();
- }
- /*
- ====================
- idRenderModelMD5::GetDefaultPose
- ====================
- */
- const idJointQuat *idRenderModelMD5::GetDefaultPose() const {
- return defaultPose.Ptr();
- }
- /*
- ====================
- idRenderModelMD5::GetJointHandle
- ====================
- */
- jointHandle_t idRenderModelMD5::GetJointHandle( const char *name ) const {
- const idMD5Joint *joint = joints.Ptr();
- for ( int i = 0; i < joints.Num(); i++, joint++ ) {
- if ( idStr::Icmp( joint->name.c_str(), name ) == 0 ) {
- return ( jointHandle_t )i;
- }
- }
- return INVALID_JOINT;
- }
- /*
- =====================
- idRenderModelMD5::GetJointName
- =====================
- */
- const char *idRenderModelMD5::GetJointName( jointHandle_t handle ) const {
- if ( ( handle < 0 ) || ( handle >= joints.Num() ) ) {
- return "<invalid joint>";
- }
- return joints[ handle ].name;
- }
- /*
- ====================
- idRenderModelMD5::NearestJoint
- ====================
- */
- int idRenderModelMD5::NearestJoint( int surfaceNum, int a, int b, int c ) const {
- if ( surfaceNum > meshes.Num() ) {
- common->Error( "idRenderModelMD5::NearestJoint: surfaceNum > meshes.Num()" );
- }
- const idMD5Mesh *mesh = meshes.Ptr();
- for ( int i = 0; i < meshes.Num(); i++, mesh++ ) {
- if ( mesh->surfaceNum == surfaceNum ) {
- return mesh->NearestJoint( a, b, c );
- }
- }
- return 0;
- }
- /*
- ====================
- idRenderModelMD5::TouchData
- models that are already loaded at level start time
- will still touch their materials to make sure they
- are kept loaded
- ====================
- */
- void idRenderModelMD5::TouchData() {
- for ( int i = 0; i < meshes.Num(); i++ ) {
- declManager->FindMaterial( meshes[i].shader->GetName() );
- }
- }
- /*
- ===================
- idRenderModelMD5::PurgeModel
- frees all the data, but leaves the class around for dangling references,
- which can regenerate the data with LoadModel()
- ===================
- */
- void idRenderModelMD5::PurgeModel() {
- purged = true;
- joints.Clear();
- defaultPose.Clear();
- meshes.Clear();
- }
- /*
- ===================
- idRenderModelMD5::Memory
- ===================
- */
- int idRenderModelMD5::Memory() const {
- int total = sizeof( *this );
- total += joints.MemoryUsed() + defaultPose.MemoryUsed() + meshes.MemoryUsed();
- // count up strings
- for ( int i = 0; i < joints.Num(); i++ ) {
- total += joints[i].name.DynamicMemoryUsed();
- }
- // count up meshes
- for ( int i = 0; i < meshes.Num(); i++ ) {
- const idMD5Mesh *mesh = &meshes[i];
- total += mesh->numMeshJoints * sizeof( mesh->meshJoints[0] );
- // sum up deform info
- total += sizeof( mesh->deformInfo );
- total += R_DeformInfoMemoryUsed( mesh->deformInfo );
- }
- return total;
- }
|