int main( int argc, char **argv )
{
	if( argc != 2 )
	{
		Usage();
	}

	memset( g_NumBonesInLOD, 0, sizeof( int ) * MAX_NUM_LODS );
	
	FILE *fp;
	fp = fopen( argv[1], "rb" );
	if( !fp )
	{
		fprintf( stderr, "Can't open: %s\n", argv[1] );
		Usage();
	}
	fseek( fp, 0, SEEK_END );
	int len = ftell( fp );
	rewind( fp );

	studiohdr_t *pStudioHdr = ( studiohdr_t * )malloc( len );
	fread( pStudioHdr, 1, len, fp );
	Studio_ConvertStudioHdrToNewVersion( pStudioHdr );
	if( pStudioHdr->version != STUDIO_VERSION )
	{
		fprintf( stderr, "Wrong version (%d != %d)\n", ( int )pStudioHdr->version, ( int )STUDIO_VERSION );
		Usage();
	}

	int i;
	for( i = 0; i < pStudioHdr->numbones; i++ )
	{
		mstudiobone_t *pBone = pStudioHdr->pBone( i );
		if( pBone->parent == -1 )
		{
			PrintBoneGraphRecursive( pStudioHdr, i, 0 );
		}
	}
	
	fclose( fp );

	for( i = 0; i < MAX_NUM_LODS; i++ )
	{
		printf( "%d bones used in lod %d\n", g_NumBonesInLOD[i], i );
	}

	return 0;
}
Esempio n. 2
0
//-----------------------------------------------------------------------------
// Load studio model vertex data from a file...
//-----------------------------------------------------------------------------
bool LoadStudioModel( char const* pModelName, char const* pEntityType, CUtlBuffer& buf )
{
	if ( !g_pFullFileSystem->ReadFile( pModelName, NULL, buf ) )
		return false;

	// Check that it's valid
	if (strncmp ((const char *) buf.PeekGet(), "IDST", 4) &&
		strncmp ((const char *) buf.PeekGet(), "IDAG", 4))
	{
		return false;
	}

	studiohdr_t* pHdr = (studiohdr_t*)buf.PeekGet();

	Studio_ConvertStudioHdrToNewVersion( pHdr );

	if (pHdr->version != STUDIO_VERSION)
	{
		return false;
	}

	isstaticprop_ret isStaticProp = IsStaticProp(pHdr);
	if ( isStaticProp != RET_VALID )
	{
		if ( isStaticProp == RET_FAIL_NOT_MARKED_STATIC_PROP )
		{
			Warning("Error! To use model \"%s\"\n"
				"      with %s, it must be compiled with $staticprop!\n", pModelName, pEntityType );
		}
		else if ( isStaticProp == RET_FAIL_DYNAMIC )
		{
			Warning("Error! %s using model \"%s\", which must be used on a dynamic entity (i.e. prop_physics). Deleted.\n", pEntityType, pModelName );
		}
		return false;
	}

	// ensure reset
	pHdr->pVertexBase = NULL;
	pHdr->pIndexBase  = NULL;

	return true;
}
Esempio n. 3
0
bool LoadStudioModel( char const* pModelName, CUtlBuffer& buf )
{
	// No luck, gotta build it	
	// Construct the file name...
	if (!LoadFile( pModelName, buf ))
	{
		Warning("Error! Unable to load model \"%s\"\n", pModelName );
		return false;
	}

	// Check that it's valid
	if (strncmp ((const char *) buf.PeekGet(), "IDST", 4) &&
		strncmp ((const char *) buf.PeekGet(), "IDAG", 4))
	{
		Warning("Error! Invalid model file \"%s\"\n", pModelName );
		return false;
	}

	studiohdr_t* pHdr = (studiohdr_t*)buf.PeekGet();

	Studio_ConvertStudioHdrToNewVersion( pHdr );

	if (pHdr->version != STUDIO_VERSION)
	{
		Warning("Error! Invalid model version \"%s\"\n", pModelName );
		return false;
	}

	if (!IsStaticProp(pHdr))
	{
		Warning("Error! To use model \"%s\"\n"
			"      as a static prop, it must be compiled with $staticprop!\n", pModelName );
		return false;
	}

	// ensure reset
	pHdr->pVertexBase = NULL;
	pHdr->pIndexBase  = NULL;

	return true;
}
//----------------------------------------------------------------------
// Get list of files that a model requires.
//----------------------------------------------------------------------
bool GetDependants_MDL( const char *pModelName, CUtlVector< CUtlString > *pList )
{
	if ( !g_bModPathIsValid )
	{
		Msg( "Indeterminate mod path, Cannot perform BSP conversion\n" );
		return false;
	}

	CUtlBuffer sourceBuf;
	if ( !g_pFullFileSystem->ReadFile( pModelName, "GAME", sourceBuf ) )
	{
		Msg( "Error! Couldn't open file '%s'!\n", pModelName ); 
		return false;
	}

	studiohdr_t *pStudioHdr = (studiohdr_t *)sourceBuf.Base();
	Studio_ConvertStudioHdrToNewVersion( pStudioHdr );
	if ( pStudioHdr->version != STUDIO_VERSION )
	{
		Msg( "Error! Bad Model '%s', Expecting Version (%d), got (%d)\n", pModelName, STUDIO_VERSION, pStudioHdr->version ); 
		return false;
	}

	char szOutName[MAX_PATH];
	if ( pStudioHdr->flags & STUDIOHDR_FLAGS_OBSOLETE )
	{
		V_strncpy( szOutName, "materials/sprites/obsolete.vmt", sizeof( szOutName ) );
		V_FixSlashes( szOutName );
		pList->AddToTail( szOutName );
	}
	else if ( pStudioHdr->textureindex != 0 )
	{
		// iterate each texture
		int	i;
		int	j;
		for ( i = 0; i < pStudioHdr->numtextures; i++ )
		{
			// iterate through all directories until a valid material is found
			bool bFound = false;
			for ( j = 0; j < pStudioHdr->numcdtextures; j++ )
			{
				char szPath[MAX_PATH];
				V_ComposeFileName( "materials", pStudioHdr->pCdtexture( j ), szPath, sizeof( szPath ) );

				// should have been fixed in studiomdl
				// some mdls are ending up with double slashes, borking loads
				int len = strlen( szPath );
				if ( len > 2 && szPath[len-2] == '\\' && szPath[len-1] == '\\' )
				{
					szPath[len-1] = '\0';
				}
			
				V_ComposeFileName( szPath, pStudioHdr->pTexture( i )->pszName(), szOutName, sizeof( szOutName ) ); 
				V_SetExtension( szOutName, ".vmt", sizeof( szOutName ) );

				if ( g_pFullFileSystem->FileExists( szOutName, "GAME" ) )
				{
					bFound = true;
					break;
				}
			}

			if ( bFound )
			{
				pList->AddToTail( szOutName );
			}
		}
	}
	
	return true;
}
//-----------------------------------------------------------------------------
// Rebuilds all of a MDL's components.
//-----------------------------------------------------------------------------
static bool GenerateModelFiles( const char *pMdlFilename )
{
	CUtlBuffer	tempBuffer;
	int			fileSize;
	int			paddedSize;
	int			swappedSize;

	// .mdl
	CUtlBuffer mdlBuffer;
	if ( !scriptlib->ReadFileToBuffer( pMdlFilename, mdlBuffer ) )
	{
		return false;
	}
	if ( !Studio_ConvertStudioHdrToNewVersion( (studiohdr_t *)mdlBuffer.Base() ))
	{
		Msg("%s needs to be recompiled\n", pMdlFilename );
	}

	// .vtx
	char szVtxFilename[MAX_PATH];
	V_StripExtension( pMdlFilename, szVtxFilename, sizeof( szVtxFilename ) );
	V_strncat( szVtxFilename, ".dx90.vtx", sizeof( szVtxFilename ) );
	CUtlBuffer vtxBuffer;
	bool bHasVtx = ReadFileToBuffer( szVtxFilename, vtxBuffer, false, true );
	
	// .vvd
	char szVvdFilename[MAX_PATH];
	V_StripExtension( pMdlFilename, szVvdFilename, sizeof( szVvdFilename ) );
	V_strncat( szVvdFilename, ".vvd", sizeof( szVvdFilename ) );
	CUtlBuffer vvdBuffer;
	bool bHasVvd = ReadFileToBuffer( szVvdFilename, vvdBuffer, false, true );

	if ( bHasVtx != bHasVvd )
	{
		// paired resources, either mandates the other
		return false;
	}

	// a .mdl file that has .vtx/.vvd gets re-processed to cull lod data
	if ( bHasVtx && bHasVvd )
	{
		// cull lod if needed
		IMdlStripInfo *pStripInfo = NULL;
		bool bResult = mdllib->StripModelBuffers( mdlBuffer, vvdBuffer, vtxBuffer, &pStripInfo );
		if ( !bResult )
		{
			return false;
		}
		if ( pStripInfo )
		{
			// .vsi
			CUtlBuffer vsiBuffer;
			pStripInfo->Serialize( vsiBuffer );
			pStripInfo->DeleteThis();

			// save strip info for later processing
			char szVsiFilename[MAX_PATH];
			V_StripExtension( pMdlFilename, szVsiFilename, sizeof( szVsiFilename ) );
			V_strncat( szVsiFilename, ".vsi", sizeof( szVsiFilename ) );
			WriteBufferToFile( szVsiFilename, vsiBuffer, false, WRITE_TO_DISK_ALWAYS );
		}
	}

	// .ani processing may further update .mdl buffer
	char szAniFilename[MAX_PATH];
	V_StripExtension( pMdlFilename, szAniFilename, sizeof( szAniFilename ) );
	V_strncat( szAniFilename, ".ani", sizeof( szAniFilename ) );
	CUtlBuffer aniBuffer;
	bool bHasAni = ReadFileToBuffer( szAniFilename, aniBuffer, false, true );
	if ( bHasAni )
	{
		// Some vestigal .ani files exist in the tree, only process valid .ani
		if ( ((studiohdr_t*)mdlBuffer.Base())->numanimblocks != 0 )
		{
			// .ani processing modifies .mdl buffer
			fileSize = aniBuffer.TellPut();
			paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING;
			aniBuffer.EnsureCapacity( paddedSize );
			tempBuffer.EnsureCapacity( paddedSize );
			V_StripExtension( pMdlFilename, szAniFilename, sizeof( szAniFilename ) );
			V_strncat( szAniFilename, ".360.ani", sizeof( szAniFilename ) );
			swappedSize = StudioByteSwap::ByteswapStudioFile( szAniFilename, tempBuffer.Base(), aniBuffer.PeekGet(), fileSize, (studiohdr_t*)mdlBuffer.Base(), CompressFunc );
			if ( swappedSize > 0 )
			{
				// .ani buffer is replaced with swapped data
				aniBuffer.Purge();
				aniBuffer.Put( tempBuffer.Base(), swappedSize );
				WriteBufferToFile( szAniFilename, aniBuffer, false, WRITE_TO_DISK_ALWAYS );
			}
			else
			{
				return false;				
			}
		}
	}

	// .phy
	char szPhyFilename[MAX_PATH];
	V_StripExtension( pMdlFilename, szPhyFilename, sizeof( szPhyFilename ) );
	V_strncat( szPhyFilename, ".phy", sizeof( szPhyFilename ) );
	CUtlBuffer phyBuffer;
	bool bHasPhy = ReadFileToBuffer( szPhyFilename, phyBuffer, false, true );
	if ( bHasPhy )
	{
		fileSize = phyBuffer.TellPut();
		paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING;
		phyBuffer.EnsureCapacity( paddedSize );
		tempBuffer.EnsureCapacity( paddedSize );
		V_StripExtension( pMdlFilename, szPhyFilename, sizeof( szPhyFilename ) );
		V_strncat( szPhyFilename, ".360.phy", sizeof( szPhyFilename ) );
		swappedSize = StudioByteSwap::ByteswapStudioFile( szPhyFilename, tempBuffer.Base(), phyBuffer.PeekGet(), fileSize, (studiohdr_t*)mdlBuffer.Base(), CompressFunc );
		if ( swappedSize > 0 )
		{
			// .phy buffer is replaced with swapped data
			phyBuffer.Purge();
			phyBuffer.Put( tempBuffer.Base(), swappedSize );
			WriteBufferToFile( szPhyFilename, phyBuffer, false, WRITE_TO_DISK_ALWAYS );
		}
		else
		{
			return false;				
		}
	}

	if ( bHasVtx )
	{
		fileSize = vtxBuffer.TellPut();
		paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING;
		vtxBuffer.EnsureCapacity( paddedSize );
		tempBuffer.EnsureCapacity( paddedSize );
		V_StripExtension( pMdlFilename, szVtxFilename, sizeof( szVtxFilename ) );
		V_strncat( szVtxFilename, ".dx90.360.vtx", sizeof( szVtxFilename ) );
		swappedSize = StudioByteSwap::ByteswapStudioFile( szVtxFilename, tempBuffer.Base(), vtxBuffer.PeekGet(), fileSize, (studiohdr_t*)mdlBuffer.Base(), CompressFunc );
		if ( swappedSize > 0 )
		{
			// .vtx buffer is replaced with swapped data
			vtxBuffer.Purge();
			vtxBuffer.Put( tempBuffer.Base(), swappedSize );
			WriteBufferToFile( szVtxFilename, vtxBuffer, false, WRITE_TO_DISK_ALWAYS );
		}
		else
		{
			return false;				
		}
	}

	if ( bHasVvd )
	{
		fileSize = vvdBuffer.TellPut();
		paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING;
		vvdBuffer.EnsureCapacity( paddedSize );
		tempBuffer.EnsureCapacity( paddedSize );
		V_StripExtension( pMdlFilename, szVvdFilename, sizeof( szVvdFilename ) );
		V_strncat( szVvdFilename, ".360.vvd", sizeof( szVvdFilename ) );
		swappedSize = StudioByteSwap::ByteswapStudioFile( szVvdFilename, tempBuffer.Base(), vvdBuffer.PeekGet(), fileSize, (studiohdr_t*)mdlBuffer.Base(), CompressFunc );
		if ( swappedSize > 0 )
		{
			// .vvd buffer is replaced with swapped data
			vvdBuffer.Purge();
			vvdBuffer.Put( tempBuffer.Base(), swappedSize );
			WriteBufferToFile( szVvdFilename, vvdBuffer, false, WRITE_TO_DISK_ALWAYS );
		}
		else
		{
			return false;				
		}
	}

	// swap and write final .mdl
	fileSize = mdlBuffer.TellPut();
	paddedSize = fileSize + BYTESWAP_ALIGNMENT_PADDING;
	mdlBuffer.EnsureCapacity( paddedSize );
	tempBuffer.EnsureCapacity( paddedSize );
	char szMdlFilename[MAX_PATH];
	V_StripExtension( pMdlFilename, szMdlFilename, sizeof( szMdlFilename ) );
	V_strncat( szMdlFilename, ".360.mdl", sizeof( szMdlFilename ) );
	swappedSize = StudioByteSwap::ByteswapStudioFile( szMdlFilename, tempBuffer.Base(), mdlBuffer.PeekGet(), fileSize, NULL, CompressFunc );
	if ( swappedSize > 0 )
	{
		// .mdl buffer is replaced with swapped data
		mdlBuffer.Purge();
		mdlBuffer.Put( tempBuffer.Base(), swappedSize );
		WriteBufferToFile( szMdlFilename, mdlBuffer, false, WRITE_TO_DISK_ALWAYS );
	}
	else
	{
		return false;				
	}

	return true;
}
Esempio n. 6
0
bool ValidateModelFile( char const *modelname, int offset )
{
	studiohdr_t *pHdr;
	FILE *fp;

	pHdr = (studiohdr_t *)buffer;

	fp = fopen( modelname, "rb" );
	if ( !fp )
	{
		vprint( 0, "Unable to open .mdl file %s\n", modelname );
		return false;
	}

	// See if there's a .qc which builds this model
	char shortname[ MAX_PATH ];
	strcpy( shortname, &modelname[ offset ] );

	Q_FixSlashes( shortname );

	fread( buffer, sizeof( buffer ), 1, fp );
	fclose( fp );

	if ( pHdr->id != IDSTUDIOHEADER )
	{
		vprint( 0, "Bogus studiomdl header for %s, expecting 'IDST' four cc code\n", shortname );
		return false;
	}

	bool valid = true;
	bool needsrecompile = false;
	int toobig = 0;

	// previous version is compatible
	if ( pHdr->version < 44 || pHdr->version > STUDIO_VERSION )
	{
		vprint( 0, "Outdated model %s (ver %i != %i)\n", shortname, pHdr->version, STUDIO_VERSION );
		valid = false;
	}

	if (!Studio_ConvertStudioHdrToNewVersion( pHdr ))
	{
		// vprint( 0, "%s needs to be recompiled\n", pHdr->pszName() );
		needsrecompile = true;
	}

	if (checkani)
	{
		// HACK: since the sequence data is written after the animation data, this is rough way to determine how much anim data there really is
		int totalanimsize = pHdr->localseqindex - pHdr->localanimindex - pHdr->numlocalanim * sizeof( mstudioanimdesc_t );
		if (pHdr->pLocalAnimdesc( 0 )->animblock == 0 && totalanimsize > 1024 * 64)
		{
			toobig = totalanimsize;
		}
	}

	int idx = g_Analysis.models.Find( shortname );
	if ( idx ==  g_Analysis.models.InvalidIndex() )
	{
		vprint( 0, "Couldn't find a .qc which builds %s\n", shortname );
		valid = false;
	}
	else
	{
		g_Analysis.models[idx].version = pHdr->version;
		g_Analysis.models[idx].needsrecompile = needsrecompile;
		g_Analysis.models[idx].toobig = toobig;
	}


	return valid;
}