//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //===========================================================================// #include "studiorendercontext.h" #include "optimize.h" #include "tier0/vprof.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" void CStudioRenderContext::GetTriangles( const DrawModelInfo_t& info, matrix3x4_t *pBoneToWorld, GetTriangles_Output_t &out ) { VPROF( "CStudioRender::GetTriangles"); out.m_MaterialBatches.RemoveAll(); // clear out data. if( !info.m_pStudioHdr || !info.m_pHardwareData || !info.m_pHardwareData->m_NumLODs || !info.m_pHardwareData->m_pLODs ) { return; } int lod = info.m_Lod; int lastlod = info.m_pHardwareData->m_NumLODs - 1; if ( lod == USESHADOWLOD ) { lod = lastlod; } else { lod = clamp( lod, 0, lastlod ); } // clamp to root lod if ( lod < info.m_pHardwareData->m_RootLOD) { lod = info.m_pHardwareData->m_RootLOD; } int nSkin = info.m_Skin; if ( nSkin >= info.m_pStudioHdr->numskinfamilies ) { nSkin = 0; } short *pSkinRef = info.m_pStudioHdr->pSkinref( nSkin * info.m_pStudioHdr->numskinref ); studiomeshdata_t *pStudioMeshes = info.m_pHardwareData->m_pLODs[lod].m_pMeshData; IMaterial **ppMaterials = info.m_pHardwareData->m_pLODs[lod].ppMaterials; // Bone to world must be set before calling this function; it uses it here int boneMask = BONE_USED_BY_VERTEX_AT_LOD(lod); ComputePoseToWorld( out.m_PoseToWorld, info.m_pStudioHdr, boneMask, m_RC.m_ViewOrigin, pBoneToWorld ); int i; for (i=0 ; i < info.m_pStudioHdr->numbodyparts ; i++) { mstudiomodel_t *pModel = NULL; R_StudioSetupModel( i, info.m_Body, &pModel, info.m_pStudioHdr ); // Iterate over all the meshes.... each mesh is a new material int k; for ( k = 0; k < pModel->nummeshes; ++k ) { GetTriangles_MaterialBatch_t &materialBatch = out.m_MaterialBatches[out.m_MaterialBatches.AddToTail()]; mstudiomesh_t *pMesh = pModel->pMesh(k); if ( !pModel->CacheVertexData( info.m_pStudioHdr ) ) { // not available yet continue; } const mstudio_meshvertexdata_t *vertData = pMesh->GetVertexData( info.m_pStudioHdr ); Assert( vertData ); // This can only return NULL on X360 for now // add the verts from this mesh to the materialBatch materialBatch.m_Verts.SetCount( pMesh->numvertices ); for ( int vertID = 0; vertID < pMesh->numvertices; vertID++ ) { GetTriangles_Vertex_t& vert = materialBatch.m_Verts[vertID]; vert.m_Position = *vertData->Position( vertID ); vert.m_Normal = *vertData->Normal( vertID ); vert.m_TexCoord = *vertData->Texcoord( vertID ); if (vertData->HasTangentData()) { vert.m_TangentS = *vertData->TangentS( vertID ); } #if _DEBUG else { // ensure any unintended access faults vert.m_TangentS.Init( VEC_T_NAN, VEC_T_NAN, VEC_T_NAN, VEC_T_NAN ); } #endif vert.m_NumBones = vertData->BoneWeights( vertID )->numbones; int j; for ( j = 0; j < vert.m_NumBones; j++ ) { vert.m_BoneWeight[j] = vertData->BoneWeights( vertID )->weight[j]; vert.m_BoneIndex[j] = vertData->BoneWeights( vertID )->bone[j]; } } IMaterial *pMaterial = ppMaterials[pSkinRef[pMesh->material]]; Assert( pMaterial ); materialBatch.m_pMaterial = pMaterial; studiomeshdata_t *pMeshData = &pStudioMeshes[pMesh->meshid]; if ( pMeshData->m_NumGroup == 0 ) continue; // Clear out indices materialBatch.m_TriListIndices.SetCount( 0 ); // Iterate over all stripgroups int stripGroupID; for ( stripGroupID = 0; stripGroupID < pMeshData->m_NumGroup; stripGroupID++ ) { studiomeshgroup_t *pMeshGroup = &pMeshData->m_pMeshGroup[stripGroupID]; // bool bIsFlexed = ( pMeshGroup->m_Flags & MESHGROUP_IS_FLEXED ) != 0; // bool bIsHWSkinned = ( pMeshGroup->m_Flags & MESHGROUP_IS_HWSKINNED ) != 0; // Iterate over all strips. . . each strip potentially changes bones states. int stripID; for ( stripID = 0; stripID < pMeshGroup->m_NumStrips; stripID++ ) { OptimizedModel::StripHeader_t *pStripData = &pMeshGroup->m_pStripData[stripID]; // int boneID; // for( boneID = 0; boneID < pStripData->numBoneStateChanges; boneID++ ) // { // OptimizedModel::BoneStateChangeHeader_t *pBoneStateChange = pStripData->pBoneStateChange( boneID ); // hardwareBoneToGlobalBone[pBoneStateChange->hardwareID] = pBoneStateChange->newBoneID; // } if ( pStripData->flags & OptimizedModel::STRIP_IS_TRILIST ) { for ( int i = 0; i < pStripData->numIndices; i += 3 ) { int idx = pStripData->indexOffset + i; materialBatch.m_TriListIndices.AddToTail( pMeshGroup->MeshIndex( idx ) ); materialBatch.m_TriListIndices.AddToTail( pMeshGroup->MeshIndex( idx + 1 ) ); materialBatch.m_TriListIndices.AddToTail( pMeshGroup->MeshIndex( idx + 2 ) ); } } else { Assert( pStripData->flags & OptimizedModel::STRIP_IS_TRISTRIP ); for (int i = 0; i < pStripData->numIndices - 2; ++i) { int idx = pStripData->indexOffset + i; bool ccw = (i & 0x1) == 0; materialBatch.m_TriListIndices.AddToTail( pMeshGroup->MeshIndex( idx ) ); materialBatch.m_TriListIndices.AddToTail( pMeshGroup->MeshIndex( idx + 1 + ccw ) ); materialBatch.m_TriListIndices.AddToTail( pMeshGroup->MeshIndex( idx + 2 - ccw ) ); } } } } } } }