void SpewPerfStats( studiohdr_t *pStudioHdr, const char *pFilename, unsigned int flags ) { char fileName[260]; vertexFileHeader_t *pNewVvdHdr; vertexFileHeader_t *pVvdHdr = 0; OptimizedModel::FileHeader_t *pVtxHdr = 0; studiohwdata_t studioHWData; int vvdSize = 0; const char *prefix[] = {".dx80.vtx", ".dx90.vtx", ".sw.vtx"}; s_pSavedSpewFunc = NULL; if( !( flags & SPEWPERFSTATS_SHOWSTUDIORENDERWARNINGS ) ) { s_pSavedSpewFunc = GetSpewOutputFunc(); SpewOutputFunc( NullSpewOutputFunc ); } // no stats on these if (!pStudioHdr->numbodyparts) return; // Need to update the render config to spew perf stats. UpdateStudioRenderConfig(); // persist the vvd data Q_StripExtension( pFilename, fileName, sizeof( fileName ) ); strcat( fileName, ".vvd" ); if (FileExists( fileName )) { vvdSize = LoadFile( fileName, (void**)&pVvdHdr ); } else { MdlError( "Could not open '%s'\n", fileName ); } // validate header if (pVvdHdr->id != MODEL_VERTEX_FILE_ID) { MdlError( "Bad id for '%s' (got %d expected %d)\n", fileName, pVvdHdr->id, MODEL_VERTEX_FILE_ID); } if (pVvdHdr->version != MODEL_VERTEX_FILE_VERSION) { MdlError( "Bad version for '%s' (got %d expected %d)\n", fileName, pVvdHdr->version, MODEL_VERTEX_FILE_VERSION); } if (pVvdHdr->checksum != pStudioHdr->checksum) { MdlError( "Bad checksum for '%s' (got %d expected %d)\n", fileName, pVvdHdr->checksum, pStudioHdr->checksum); } if (pVvdHdr->numFixups) { // need to perform mesh relocation fixups // allocate a new copy pNewVvdHdr = (vertexFileHeader_t *)malloc( vvdSize ); if (!pNewVvdHdr) { MdlError( "Error allocating %d bytes for Vertex File '%s'\n", vvdSize, fileName ); } Studio_LoadVertexes( pVvdHdr, pNewVvdHdr, 0, true ); // discard original free( pVvdHdr ); pVvdHdr = pNewVvdHdr; } // iterate all ???.vtx files for (int j=0; j<sizeof(prefix)/sizeof(prefix[0]); j++) { // make vtx filename Q_StripExtension( pFilename, fileName, sizeof( fileName ) ); strcat( fileName, prefix[j] ); // persist the vtx data if (FileExists(fileName)) { LoadFile( fileName, (void**)&pVtxHdr ); } else { MdlError( "Could not open '%s'\n", fileName ); } // validate header if (pVtxHdr->version != OPTIMIZED_MODEL_FILE_VERSION) { MdlError( "Bad version for '%s' (got %d expected %d)\n", fileName, pVtxHdr->version, OPTIMIZED_MODEL_FILE_VERSION ); } if (pVtxHdr->checkSum != pStudioHdr->checksum) { MdlError( "Bad checksum for '%s' (got %d expected %d)\n", fileName, pVtxHdr->checkSum, pStudioHdr->checksum ); } // studio render will request these through cache interface pStudioHdr->pVertexBase = (void *)pVvdHdr; pStudioHdr->pIndexBase = (void *)pVtxHdr; g_pStudioRender->LoadModel( pStudioHdr, pVtxHdr, &studioHWData ); if( flags & SPEWPERFSTATS_SHOWPERF ) { if( flags & SPEWPERFSTATS_SPREADSHEET ) { printf( "%s,%s,%d,", fileName, prefix[j], studioHWData.m_NumLODs - studioHWData.m_RootLOD ); } else { printf( "\n" ); printf( "Performance Stats: %s\n", fileName ); printf( "------------------\n" ); } } int i; if( flags & SPEWPERFSTATS_SHOWPERF ) { for( i = studioHWData.m_RootLOD; i < studioHWData.m_NumLODs; i++ ) { DrawModelInfo_t drawModelInfo; drawModelInfo.m_Skin = 0; drawModelInfo.m_Body = 0; drawModelInfo.m_HitboxSet = 0; drawModelInfo.m_pClientEntity = 0; drawModelInfo.m_pColorMeshes = 0; drawModelInfo.m_pStudioHdr = pStudioHdr; drawModelInfo.m_pHardwareData = &studioHWData; CUtlBuffer statsOutput( 0, 0, CUtlBuffer::TEXT_BUFFER ); if( !( flags & SPEWPERFSTATS_SPREADSHEET ) ) { printf( "LOD:%d\n", i ); } drawModelInfo.m_Lod = i; DrawModelResults_t results; g_pStudioRender->GetPerfStats( &results, drawModelInfo, &statsOutput ); if( flags & SPEWPERFSTATS_SPREADSHEET ) { printf( "%d,%d,%d,", results.m_ActualTriCount, results.m_NumBatches, results.m_NumMaterials ); } else { printf( " actual tris:%d\n", ( int )results.m_ActualTriCount ); printf( " texture memory bytes: %d (only valid in a rendering app)\n", ( int )results.m_TextureMemoryBytes ); printf( ( char * )statsOutput.Base() ); } } if( flags & SPEWPERFSTATS_SPREADSHEET ) { printf( "\n" ); } } g_pStudioRender->UnloadModel( &studioHWData ); free(pVtxHdr); } if (pVvdHdr) free(pVvdHdr); if( !( flags & SPEWPERFSTATS_SHOWSTUDIORENDERWARNINGS ) ) { SpewOutputFunc( s_pSavedSpewFunc ); } }
void SpewPerfStats( studiohdr_t *pStudioHdr, const char *pFilename ) { char fileName[260]; vertexFileHeader_t *pNewVvdHdr; vertexFileHeader_t *pVvdHdr; OptimizedModel::FileHeader_t *pVtxHdr; DrawModelInfo_t drawModelInfo; studiohwdata_t studioHWData; int vvdSize; const char *prefix[] = {".dx80.vtx", ".dx90.vtx", ".sw.vtx", ".xbox.vtx"}; if (!pStudioHdr->numbodyparts) { // no stats on these return; } // Need to load up StudioRender.dll to spew perf stats. InitStudioRender(); // persist the vvd data Q_StripExtension( pFilename, fileName, sizeof( fileName ) ); strcat( fileName, ".vvd" ); if (FileExists( fileName )) { vvdSize = LoadFile( fileName, (void**)&pVvdHdr ); } else { MdlError( "Could not open '%s'\n", fileName ); } // validate header if (pVvdHdr->id != MODEL_VERTEX_FILE_ID) { MdlError( "Bad id for '%s' (got %d expected %d)\n", fileName, pVvdHdr->id, MODEL_VERTEX_FILE_ID); } if (pVvdHdr->version != MODEL_VERTEX_FILE_VERSION) { MdlError( "Bad version for '%s' (got %d expected %d)\n", fileName, pVvdHdr->version, MODEL_VERTEX_FILE_VERSION); } if (pVvdHdr->checksum != pStudioHdr->checksum) { MdlError( "Bad checksum for '%s' (got %d expected %d)\n", fileName, pVvdHdr->checksum, pStudioHdr->checksum); } if (pVvdHdr->numFixups) { // need to perform mesh relocation fixups // allocate a new copy pNewVvdHdr = (vertexFileHeader_t *)malloc( vvdSize ); if (!pNewVvdHdr) { MdlError( "Error allocating %d bytes for Vertex File '%s'\n", vvdSize, fileName ); } Studio_LoadVertexes( pVvdHdr, pNewVvdHdr, 0, true ); // discard original free( pVvdHdr ); pVvdHdr = pNewVvdHdr; } // iterate all ???.vtx files for (int j=0; j<sizeof(prefix)/sizeof(prefix[0]); j++) { // make vtx filename Q_StripExtension( pFilename, fileName, sizeof( fileName ) ); strcat( fileName, prefix[j] ); printf( "\n" ); printf( "Performance Stats: %s\n", fileName ); printf( "------------------\n" ); // persist the vtx data if (FileExists(fileName)) { LoadFile( fileName, (void**)&pVtxHdr ); } else { MdlError( "Could not open '%s'\n", fileName ); } // validate header if (pVtxHdr->version != OPTIMIZED_MODEL_FILE_VERSION) { MdlError( "Bad version for '%s' (got %d expected %d)\n", fileName, pVtxHdr->version, OPTIMIZED_MODEL_FILE_VERSION ); } if (pVtxHdr->checkSum != pStudioHdr->checksum) { MdlError( "Bad checksum for '%s' (got %d expected %d)\n", fileName, pVtxHdr->checkSum, pStudioHdr->checksum ); } // studio render will request these through cache interface pStudioHdr->pVertexBase = (void *)pVvdHdr; pStudioHdr->pIndexBase = (void *)pVtxHdr; g_pStudioRender->LoadModel( pStudioHdr, pVtxHdr, &studioHWData ); memset( &drawModelInfo, 0, sizeof( DrawModelInfo_t ) ); drawModelInfo.m_pStudioHdr = pStudioHdr; drawModelInfo.m_pHardwareData = &studioHWData; int i; for( i = studioHWData.m_RootLOD; i < studioHWData.m_NumLODs; i++ ) { CUtlBuffer statsOutput( 0, 0, true /* text */ ); printf( "LOD: %d\n", i ); drawModelInfo.m_Lod = i; g_pStudioRender->GetPerfStats( drawModelInfo, &statsOutput ); printf( "\tactual tris: %d\n", ( int )drawModelInfo.m_ActualTriCount ); printf( "\ttexture memory bytes: %d\n", ( int )drawModelInfo.m_TextureMemoryBytes ); printf( ( char * )statsOutput.Base() ); } g_pStudioRender->UnloadModel( &studioHWData ); free(pVtxHdr); } if (pVvdHdr) free(pVvdHdr); }
//-------------------------------------------------------------------------------------------------// // Class: CHL2LoaderPlugIn // // Function: LoadGeometry // // Description: This method gets called by the main application to read in geometry data from // a particular file ('strFileName') into the specified model data container // ('pModelContainer') // //-------------------------------------------------------------------------------------------------// bool CHL2LoaderPlugIn::LoadGeometry( const RM_TCHAR *strFileName, RmMeshModelContainer *pModelContainer ) { //---------------------------------------------------------------------- // Actual loading code goes here //---------------------------------------------------------------------- HRESULT hr; // Store the device pointer IDirect3DDevice9 *pd3dDevice = RmGfxGetD3DDevice(); WCHAR vvdwstr[MAX_PATH]; WCHAR vtxwstr[MAX_PATH]; WCHAR mdlwstr[MAX_PATH]; char vvdstr[MAX_PATH]; char vtxstr[MAX_PATH]; char mdlstr[MAX_PATH]; int vvdFileSize; int vtxFileSize; int mdlFileSize; WCHAR tmpStringName[MAX_PATH]; StringCchCopy( tmpStringName, MAX_PATH, strFileName ); WCHAR* pch = wcsrchr( tmpStringName, L'\.' ); *pch='\0'; StringCchCopy( vvdwstr, MAX_PATH, tmpStringName ); StringCchCopy( vtxwstr, MAX_PATH, tmpStringName ); StringCchCopy( mdlwstr, MAX_PATH, tmpStringName ); StringCchCat( vvdwstr, MAX_PATH, L".vvd" ); StringCchCat( vtxwstr, MAX_PATH, L".dx90.vtx" ); StringCchCat( mdlwstr, MAX_PATH, L".mdl" ); WideCharToMultiByte( CP_ACP, 0, vvdwstr, -1, vvdstr, MAX_PATH, NULL, NULL ); WideCharToMultiByte( CP_ACP, 0, vtxwstr, -1, vtxstr, MAX_PATH, NULL, NULL ); WideCharToMultiByte( CP_ACP, 0, mdlwstr, -1, mdlstr, MAX_PATH, NULL, NULL ); ifstream vvdFile( vvdstr,ios::binary ); ifstream vtxFile( vtxstr,ios::binary ); ifstream mdlFile( mdlstr,ios::binary ); vvdFile.seekg(0,ios::end); vtxFile.seekg(0,ios::end); mdlFile.seekg(0,ios::end); vvdFileSize = vvdFile.tellg(); vtxFileSize = vtxFile.tellg(); mdlFileSize = mdlFile.tellg(); vvdFile.seekg(0,ios::beg); vtxFile.seekg(0,ios::beg); mdlFile.seekg(0,ios::beg); char *m_pVvdMem = new char[vvdFileSize]; char *m_pVtxMem = new char[vtxFileSize]; char *m_pMdlMem = new char[mdlFileSize]; vvdFile.read(m_pVvdMem,vvdFileSize); vtxFile.read(m_pVtxMem,vtxFileSize); mdlFile.read(m_pMdlMem,mdlFileSize); vertexFileHeader_t* m_pVvdFileHeader=(vertexFileHeader_t *)m_pVvdMem; FileHeader_t* m_pVtxFileHeader=(FileHeader_t *)m_pVtxMem; studiohdr_t* m_pMdlFileHeader=(studiohdr_t *)m_pMdlMem; unsigned short m_iLod=0; if (m_pVvdFileHeader->numFixups) { vertexFileHeader_t * pNewVvdHdr; pNewVvdHdr = new vertexFileHeader_t[vvdFileSize]; Studio_LoadVertexes( m_pVvdFileHeader, pNewVvdHdr, 0, true ); free( m_pVvdFileHeader ); m_pVvdFileHeader = pNewVvdHdr; } // check mdl header if (m_pMdlFileHeader->id != IDSTUDIOHEADER) { getRmApp()->OutputText( _T(".mdl File id error") ); return false; } if (m_pMdlFileHeader->version != STUDIO_VERSION) { getRmApp()->OutputText( _T(".mdl File version error") ); return false; } // check vtx header if (m_pVtxFileHeader->version != OPTIMIZED_MODEL_FILE_VERSION) { getRmApp()->OutputText( _T(".vtd File version error") ); return false; } if (m_pVtxFileHeader->checkSum != m_pMdlFileHeader->checksum) { getRmApp()->OutputText( _T(".vtd File checksum error") ); return false; } // check vvd header if (m_pVvdFileHeader->id != MODEL_VERTEX_FILE_ID) { getRmApp()->OutputText( _T(".vvd File id error") ); return false; } if (m_pVvdFileHeader->version != MODEL_VERTEX_FILE_VERSION) { getRmApp()->OutputText( _T(".vvd File version error") ); return false; } if (m_pVvdFileHeader->checksum != m_pMdlFileHeader->checksum) { getRmApp()->OutputText( _T(".vvd File checksum error") ); return false; } m_pMdlFileHeader->pVertexBase = (void *)m_pVvdFileHeader; m_pMdlFileHeader->pIndexBase = (void *)m_pVtxFileHeader; BodyPartHeader_t* pBodyPart = m_pVtxFileHeader->pBodyPart(0); ModelHeader_t* pModel=pBodyPart->pModel(0); ModelLODHeader_t* pLod = pModel->pLOD(m_iLod); mstudiobodyparts_t* pStudioBodyPart = m_pMdlFileHeader->pBodypart(0); mstudiomodel_t* pStudioModel= pStudioBodyPart->pModel(0); int numVerts=0; int numIndices=0; for (int k=0;k<pStudioModel->nummeshes;k++) { MeshHeader_t* pMesh = pLod->pMesh(k); mstudiomesh_t* pStudioMesh = pStudioModel->pMesh( k ); for (int j=0;j<pMesh->numStripGroups;j++) { StripGroupHeader_t* pStripGroup = pMesh->pStripGroup(j); numVerts+=pStripGroup->numVerts; numIndices+=pStripGroup->numIndices; } } RmMeshModel *pRmMesh = new RmMeshModel(); pModelContainer->AddMeshModel(pRmMesh); pRmMesh->GetVertexArray()->SetNumVertices( numVerts, false ); pRmMesh->GetVertexArray()->CreateVertexElementArray( RM_DECLUSAGE_BLENDWEIGHT, 0, RMVSDT_FLOAT3 ); pRmMesh->GetVertexArray()->CreateVertexElementArray( RM_DECLUSAGE_BLENDINDICES, 0, RMVSDT_UBYTE4 ); pRmMesh->GetVertexArray()->CreateVertexElementArray( RM_DECLUSAGE_POSITION, 0, RMVSDT_FLOAT3 ); pRmMesh->GetVertexArray()->CreateVertexElementArray( RM_DECLUSAGE_NORMAL, 0, RMVSDT_FLOAT3 ); pRmMesh->GetVertexArray()->CreateVertexElementArray( RM_DECLUSAGE_TEXCOORD, 0, RMVSDT_FLOAT2 ); pRmMesh->GetVertexArray()->CreateVertexElementArray( RM_DECLUSAGE_TANGENT, 0, RMVSDT_FLOAT4 ); RmVertexElementArray *pBlendWeightElementArray = pRmMesh->GetVertexArray()->GetVertexElementArray( RM_DECLUSAGE_BLENDWEIGHT, 0, RMVSDT_FLOAT3 ); RmVertexElementArray *pBlendIndicesElementArray = pRmMesh->GetVertexArray()->GetVertexElementArray( RM_DECLUSAGE_BLENDINDICES, 0, RMVSDT_UBYTE4 ); RmVertexElementArray *pPositionElementArray = pRmMesh->GetVertexArray()->GetVertexElementArray( RM_DECLUSAGE_POSITION, 0, RMVSDT_FLOAT3 ); RmVertexElementArray *pNormalElementArray = pRmMesh->GetVertexArray()->GetVertexElementArray(RM_DECLUSAGE_NORMAL,0,RMVSDT_FLOAT3); RmVertexElementArray *pTexCoordElementArray = pRmMesh->GetVertexArray()->GetVertexElementArray(RM_DECLUSAGE_TEXCOORD,0,RMVSDT_FLOAT2); RmVertexElementArray *pTangentElementArray = pRmMesh->GetVertexArray()->GetVertexElementArray(RM_DECLUSAGE_TANGENT,0,RMVSDT_FLOAT4); unsigned short indexOffset=0; unsigned short iVertex=0; unsigned short iIndex=0; unsigned short iSubset = 0; for (int k=0;k<pStudioModel->nummeshes;k++) { MeshHeader_t* pMesh = pLod->pMesh(k); mstudiomesh_t* pStudioMesh = pStudioModel->pMesh( k ); for (int j=0;j<pMesh->numStripGroups;j++) { StripGroupHeader_t* pStripGroup = pMesh->pStripGroup(j); for (int i=0;i<pStripGroup->numVerts;i++) { float *pBoneWeight = ( float* ) pBlendWeightElementArray->GetBuffer( iVertex ); float *pBoneIndices = ( float* ) pBlendIndicesElementArray->GetBuffer( iVertex ); float *pPosition = ( float* ) pPositionElementArray->GetBuffer( iVertex ); float *pNormal = ( float* ) pNormalElementArray->GetBuffer( iVertex ); float *pTexCoord = ( float* ) pTexCoordElementArray->GetBuffer( iVertex ); float *pTangent = ( float* ) pTangentElementArray->GetBuffer( iVertex ); float *pVertex = ( float* ) m_pVvdFileHeader->pVertex( pStudioMesh->vertexoffset+pStripGroup->pVertex(i)->origMeshVertID ); pBoneWeight[0]= pVertex[0]; pBoneWeight[1]= pVertex[1]; pBoneWeight[2]= pVertex[2]; pBoneIndices[0]=pVertex[3]; pPosition[0] = pVertex[4]; pPosition[1] = pVertex[5]; pPosition[2] = pVertex[6]; pNormal[0] = pVertex[7]; pNormal[1] = pVertex[8]; pNormal[2] = pVertex[9]; pTexCoord[0] = pVertex[10]; pTexCoord[1] = pVertex[11]; float *pTan = ( float* ) m_pVvdFileHeader->pTangent(pStripGroup->pVertex(i)->origMeshVertID ); pTangent[0] = pTan[0]; pTangent[1] = pTan[1]; pTangent[2] = pTan[2]; pTangent[3] = pTan[3]; iVertex++; } pRmMesh->SetPrimitiveType( RM_PRIMITIVETYPE_TRIANGLELIST ); pRmMesh->SetNumIndices( numIndices ); RM_DWORD *pIndices = pRmMesh->GetIndices(); for (int i=0;i<pStripGroup->numIndices;i+=3) { pIndices[iIndex]=indexOffset + *pStripGroup->pIndex(i); pIndices[iIndex+1]=indexOffset + *pStripGroup->pIndex(i+1); pIndices[iIndex+2]=indexOffset + *pStripGroup->pIndex(i+2); iIndex+=3; } indexOffset=iVertex; } } getRmApp()->OutputText( _T("\nLoad '%s' into RenderMonkey.\n"), vvdwstr ); getRmApp()->OutputText( _T("Load '%s' into RenderMonkey.\n"), vtxwstr ); getRmApp()->OutputText( _T("Load '%s' into RenderMonkey.\n"), mdlwstr ); return true; } // End of LoadGeometry for CHL2LoaderPlugIn