Пример #1
0
int main( int argc, char **argv )
{
	SpewOutputFunc( VTF2TGAOutputFunc );
	CommandLine()->CreateCmdLine( argc, argv );
	MathLib_Init( 2.2f, 2.2f, 0.0f, 1.0f, false, false, false, false );
	InitDefaultFileSystem();

	const char *pVTFFileName = CommandLine()->ParmValue( "-i" );
	const char *pTGAFileName = CommandLine()->ParmValue( "-o" );
	bool bGenerateMipLevels = CommandLine()->CheckParm( "-mip" ) != NULL;
	if ( !pVTFFileName )
	{
		Usage();
	}

	if ( !pTGAFileName )
	{
		pTGAFileName = pVTFFileName;
	}

	char pCurrentDirectory[MAX_PATH];
	if ( _getcwd( pCurrentDirectory, sizeof(pCurrentDirectory) ) == NULL )
	{
		fprintf( stderr, "Unable to get the current directory\n" );
		return -1;
	}
	Q_StripTrailingSlash( pCurrentDirectory );

	char pBuf[MAX_PATH];
	if ( !Q_IsAbsolutePath( pTGAFileName ) )
	{
		Q_snprintf( pBuf, sizeof(pBuf), "%s\\%s", pCurrentDirectory, pTGAFileName );
	}
	else
	{
		Q_strncpy( pBuf, pTGAFileName, sizeof(pBuf) );
	}
	Q_FixSlashes( pBuf );

	char pOutFileNameBase[MAX_PATH];
	Q_StripExtension( pBuf, pOutFileNameBase, MAX_PATH );

	char pActualVTFFileName[MAX_PATH];
	Q_strncpy( pActualVTFFileName, pVTFFileName, MAX_PATH );
	if ( !Q_strstr( pActualVTFFileName, ".vtf" ) )
	{
		Q_strcat( pActualVTFFileName, ".vtf", MAX_PATH ); 
	}

	FILE *vtfFp = fopen( pActualVTFFileName, "rb" );
	if( !vtfFp )
	{
		Error( "Can't open %s\n", pActualVTFFileName );
		exit( -1 );
	}

	fseek( vtfFp, 0, SEEK_END );
	int srcVTFLength = ftell( vtfFp );
	fseek( vtfFp, 0, SEEK_SET );

	CUtlBuffer buf;
	buf.EnsureCapacity( srcVTFLength );
	int nBytesRead = fread( buf.Base(), 1, srcVTFLength, vtfFp );
	fclose( vtfFp );
	buf.SeekPut( CUtlBuffer::SEEK_HEAD, nBytesRead );

	IVTFTexture *pTex = CreateVTFTexture();
	if (!pTex->Unserialize( buf ))
	{
		Error( "*** Error reading in .VTF file %s\n", pActualVTFFileName );
		exit(-1);
	}
	
	Msg( "vtf width: %d\n", pTex->Width() );
	Msg( "vtf height: %d\n", pTex->Height() );
	Msg( "vtf numFrames: %d\n", pTex->FrameCount() );

	Msg( "TEXTUREFLAGS_POINTSAMPLE=%s\n", ( pTex->Flags() & TEXTUREFLAGS_POINTSAMPLE ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_TRILINEAR=%s\n", ( pTex->Flags() & TEXTUREFLAGS_TRILINEAR ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_CLAMPS=%s\n", ( pTex->Flags() & TEXTUREFLAGS_CLAMPS ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_CLAMPT=%s\n", ( pTex->Flags() & TEXTUREFLAGS_CLAMPT ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_CLAMPU=%s\n", ( pTex->Flags() & TEXTUREFLAGS_CLAMPU ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_BORDER=%s\n", ( pTex->Flags() & TEXTUREFLAGS_BORDER ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_ANISOTROPIC=%s\n", ( pTex->Flags() & TEXTUREFLAGS_ANISOTROPIC ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_HINT_DXT5=%s\n", ( pTex->Flags() & TEXTUREFLAGS_HINT_DXT5 ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_SRGB=%s\n", ( pTex->Flags() & TEXTUREFLAGS_SRGB ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_NORMAL=%s\n", ( pTex->Flags() & TEXTUREFLAGS_NORMAL ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_NOMIP=%s\n", ( pTex->Flags() & TEXTUREFLAGS_NOMIP ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_NOLOD=%s\n", ( pTex->Flags() & TEXTUREFLAGS_NOLOD ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_ALL_MIPS=%s\n", ( pTex->Flags() & TEXTUREFLAGS_ALL_MIPS ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_PROCEDURAL=%s\n", ( pTex->Flags() & TEXTUREFLAGS_PROCEDURAL ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_ONEBITALPHA=%s\n", ( pTex->Flags() & TEXTUREFLAGS_ONEBITALPHA ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_EIGHTBITALPHA=%s\n", ( pTex->Flags() & TEXTUREFLAGS_EIGHTBITALPHA ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_ENVMAP=%s\n", ( pTex->Flags() & TEXTUREFLAGS_ENVMAP ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_RENDERTARGET=%s\n", ( pTex->Flags() & TEXTUREFLAGS_RENDERTARGET ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_DEPTHRENDERTARGET=%s\n", ( pTex->Flags() & TEXTUREFLAGS_DEPTHRENDERTARGET ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_NODEBUGOVERRIDE=%s\n", ( pTex->Flags() & TEXTUREFLAGS_NODEBUGOVERRIDE ) ? "true" : "false" );
	Msg( "TEXTUREFLAGS_SINGLECOPY=%s\n", ( pTex->Flags() & TEXTUREFLAGS_SINGLECOPY ) ? "true" : "false" );
	
	Vector vecReflectivity = pTex->Reflectivity();
	Msg( "vtf reflectivity: %f %f %f\n", vecReflectivity[0], vecReflectivity[1], vecReflectivity[2] );
	Msg( "transparency: " );
	if( pTex->Flags() & TEXTUREFLAGS_EIGHTBITALPHA )
	{
		Msg( "eightbitalpha\n" );
	}
	else if( pTex->Flags() & TEXTUREFLAGS_ONEBITALPHA )
	{
		Msg( "onebitalpha\n" );
	}
	else
	{
		Msg( "noalpha\n" );
	}
	ImageFormat srcFormat = pTex->Format();
	Msg( "vtf format: %s\n", ImageLoader::GetName( srcFormat ) );
		
	int iTGANameLen = Q_strlen( pOutFileNameBase );

	int iFaceCount = pTex->FaceCount();
	int nFrameCount = pTex->FrameCount();
	bool bIsCubeMap = pTex->IsCubeMap();

	int iLastMipLevel = bGenerateMipLevels ? pTex->MipCount() - 1 : 0;
	for( int iFrame = 0; iFrame < nFrameCount; ++iFrame )
	{
		for ( int iMipLevel = 0; iMipLevel <= iLastMipLevel; ++iMipLevel )
		{
			int iWidth, iHeight, iDepth;
			pTex->ComputeMipLevelDimensions( iMipLevel, &iWidth, &iHeight, &iDepth );

			for (int iCubeFace = 0; iCubeFace < iFaceCount; ++iCubeFace)
			{
				for ( int z = 0; z < iDepth; ++z )
				{
					// Construct output filename
					char *pTempNameBuf = (char *)stackalloc( iTGANameLen + 13 );
					Q_strncpy( pTempNameBuf, pOutFileNameBase, iTGANameLen + 1 );
					char *pExt = Q_strrchr( pTempNameBuf, '.' );
					if ( pExt )
					{
						pExt = 0;
					}

					if ( bIsCubeMap )
					{
						Assert( pTex->Depth() == 1 ); // shouldn't this be 1 instead of 0?
						static const char *pCubeFaceName[7] = { "rt", "lf", "bk", "ft", "up", "dn", "sph" };
						Q_strcat( pTempNameBuf, pCubeFaceName[iCubeFace], iTGANameLen + 13 ); 
					}

					if ( nFrameCount > 1 )
					{
						char pTemp[4];
						Q_snprintf( pTemp, 4, "%03d", iFrame );
						Q_strcat( pTempNameBuf, pTemp, iTGANameLen + 13 ); 
					}

					if ( iLastMipLevel != 0 )
					{
						char pTemp[8];
						Q_snprintf( pTemp, 8, "_mip%d", iMipLevel );
						Q_strcat( pTempNameBuf, pTemp, iTGANameLen + 13 ); 
					}

					if ( pTex->Depth() > 1 )
					{
						char pTemp[6];
						Q_snprintf( pTemp, 6, "_z%03d", z );
						Q_strcat( pTempNameBuf, pTemp, iTGANameLen + 13 ); 
					}

					if( srcFormat == IMAGE_FORMAT_RGBA16161616F )
					{
						Q_strcat( pTempNameBuf, ".pfm", iTGANameLen + 13 ); 
					}
					else
					{
						Q_strcat( pTempNameBuf, ".tga", iTGANameLen + 13 ); 
					}

					unsigned char *pSrcImage = pTex->ImageData( iFrame, iCubeFace, iMipLevel, 0, 0, z );

					ImageFormat dstFormat;
					if( srcFormat == IMAGE_FORMAT_RGBA16161616F )
					{
						dstFormat = IMAGE_FORMAT_RGB323232F;
					}
					else
					{
						if( ImageLoader::IsTransparent( srcFormat ) || (srcFormat == IMAGE_FORMAT_ATI1N ) || (srcFormat == IMAGE_FORMAT_ATI2N ))
						{
							dstFormat = IMAGE_FORMAT_BGRA8888;
						}
						else
						{
							dstFormat = IMAGE_FORMAT_BGR888;
						}
					}
				//	dstFormat = IMAGE_FORMAT_RGBA8888;
				//	dstFormat = IMAGE_FORMAT_RGB888;
				//	dstFormat = IMAGE_FORMAT_BGRA8888;
				//	dstFormat = IMAGE_FORMAT_BGR888;
				//	dstFormat = IMAGE_FORMAT_BGRA5551;
				//	dstFormat = IMAGE_FORMAT_BGR565;
				//	dstFormat = IMAGE_FORMAT_BGRA4444;
				//	printf( "dstFormat: %s\n", ImageLoader::GetName( dstFormat ) );
					unsigned char *pDstImage = new unsigned char[ImageLoader::GetMemRequired( iWidth, iHeight, 1, dstFormat, false )];
					if( !ImageLoader::ConvertImageFormat( pSrcImage, srcFormat, 
						pDstImage, dstFormat, iWidth, iHeight, 0, 0 ) )
					{
						Error( "Error converting from %s to %s\n",
							ImageLoader::GetName( srcFormat ), ImageLoader::GetName( dstFormat ) );
						exit( -1 );
					}

					if( dstFormat != IMAGE_FORMAT_RGB323232F )
					{
						if( ImageLoader::IsTransparent( dstFormat ) && ( dstFormat != IMAGE_FORMAT_RGBA8888 ) )
						{
							unsigned char *tmpImage = pDstImage;
							pDstImage = new unsigned char[ImageLoader::GetMemRequired( iWidth, iHeight, 1, IMAGE_FORMAT_RGBA8888, false )];
							if( !ImageLoader::ConvertImageFormat( tmpImage, dstFormat, pDstImage, IMAGE_FORMAT_RGBA8888,
								iWidth, iHeight, 0, 0 ) )
							{
								Error( "Error converting from %s to %s\n",
									ImageLoader::GetName( dstFormat ), ImageLoader::GetName( IMAGE_FORMAT_RGBA8888 ) );
							}
							dstFormat = IMAGE_FORMAT_RGBA8888;
						}
						else if( !ImageLoader::IsTransparent( dstFormat ) && ( dstFormat != IMAGE_FORMAT_RGB888 ) )
						{
							unsigned char *tmpImage = pDstImage;
							pDstImage = new unsigned char[ImageLoader::GetMemRequired( iWidth, iHeight, 1, IMAGE_FORMAT_RGB888, false )];
							if( !ImageLoader::ConvertImageFormat( tmpImage, dstFormat, pDstImage, IMAGE_FORMAT_RGB888,
								iWidth, iHeight, 0, 0 ) )
							{
								Error( "Error converting from %s to %s\n",
									ImageLoader::GetName( dstFormat ), ImageLoader::GetName( IMAGE_FORMAT_RGB888 ) );
							}
							dstFormat = IMAGE_FORMAT_RGB888;
						}

						CUtlBuffer outBuffer;
						TGAWriter::WriteToBuffer( pDstImage, outBuffer, iWidth, iHeight,
							dstFormat, dstFormat );
						if ( !g_pFullFileSystem->WriteFile( pTempNameBuf, NULL, outBuffer ) )
						{
							fprintf( stderr, "unable to write %s\n", pTempNameBuf );
						}
					}
					else
					{
						PFMWrite( ( float * )pDstImage, pTempNameBuf, iWidth, iHeight );
					}
				}
			}
		}
	}

	// leak leak leak leak leak, leak leak, leak leak (Blue Danube)
	return 0;
}
Пример #2
0
void CreateDefaultCubemaps( bool bHDR )
{
	memset( g_IsCubemapTexData, 0, sizeof(g_IsCubemapTexData) );

	// NOTE: This implementation depends on the fact that all VTF files contain
	// all mipmap levels
	const char *pSkyboxBaseName = FindSkyboxMaterialName();
	char skyboxMaterialName[MAX_PATH];
	Q_snprintf( skyboxMaterialName, MAX_PATH, "skybox/%s", pSkyboxBaseName );

	IVTFTexture *pSrcVTFTextures[6];

	if( !skyboxMaterialName )
	{
		if( s_DefaultCubemapNames.Count() )
		{
			Warning( "This map uses env_cubemap, and you don't have a skybox, so no default env_cubemaps will be generated.\n" );
		}
		return;
	}

	int unionTextureFlags = 0;
	if( !LoadSrcVTFFiles( pSrcVTFTextures, skyboxMaterialName, &unionTextureFlags, bHDR ) )
	{
		Warning( "Can't load skybox file %s to build the default cubemap!\n", skyboxMaterialName );
		return;
	}
	Msg( "Creating default %scubemaps for env_cubemap using skybox materials:\n   %s*.vmt\n"
		" ! Run buildcubemaps in the engine to get the correct cube maps.\n", bHDR ? "HDR " : "LDR ", skyboxMaterialName );
			
	// Figure out the mip differences between the two textures
	int iMipLevelOffset = 0;
	int tmp = pSrcVTFTextures[0]->Width();
	while( tmp > DEFAULT_CUBEMAP_SIZE )
	{
		iMipLevelOffset++;
		tmp >>= 1;
	}

	// Create the destination cubemap
	IVTFTexture *pDstCubemap = CreateVTFTexture();
	pDstCubemap->Init( DEFAULT_CUBEMAP_SIZE, DEFAULT_CUBEMAP_SIZE, 1,
		pSrcVTFTextures[0]->Format(), unionTextureFlags | TEXTUREFLAGS_ENVMAP, 
		pSrcVTFTextures[0]->FrameCount() );

	// First iterate over all frames
	for (int iFrame = 0; iFrame < pDstCubemap->FrameCount(); ++iFrame)
	{
		// Next iterate over all normal cube faces (we know there's 6 cause it's an envmap)
		for (int iFace = 0; iFace < 6; ++iFace )
		{
			// Finally, iterate over all mip levels in the *destination*
			for (int iMip = 0; iMip < pDstCubemap->MipCount(); ++iMip )
			{
				// Copy the bits from the source images into the cube faces
				unsigned char *pSrcBits = pSrcVTFTextures[iFace]->ImageData( iFrame, 0, iMip + iMipLevelOffset );
				unsigned char *pDstBits = pDstCubemap->ImageData( iFrame, iFace, iMip );
				int iSize = pDstCubemap->ComputeMipSize( iMip );
				int iSrcMipSize = pSrcVTFTextures[iFace]->ComputeMipSize( iMip + iMipLevelOffset );

				// !!! FIXME: Set this to black until HDR cubemaps are built properly!
				memset( pDstBits, 0, iSize );
				continue;

				if ( ( pSrcVTFTextures[iFace]->Width() == 4 ) && ( pSrcVTFTextures[iFace]->Height() == 4 ) ) // If texture is 4x4 square
				{
					// Force mip level 2 to get the 1x1 face
					unsigned char *pSrcBits = pSrcVTFTextures[iFace]->ImageData( iFrame, 0, 2 );
					int iSrcMipSize = pSrcVTFTextures[iFace]->ComputeMipSize( 2 );

					// Replicate 1x1 mip level across entire face
					//memset( pDstBits, 0, iSize ); 
					for ( int i = 0; i < ( iSize / iSrcMipSize ); i++ )
					{
						memcpy( pDstBits + ( i * iSrcMipSize ), pSrcBits, iSrcMipSize ); 
					}
				}
				else if ( pSrcVTFTextures[iFace]->Width() == pSrcVTFTextures[iFace]->Height() ) // If texture is square
				{
					if ( iSrcMipSize != iSize )
					{
						Warning( "%s - ERROR! Cannot copy square face for default cubemap! iSrcMipSize(%d) != iSize(%d)\n", skyboxMaterialName, iSrcMipSize, iSize );
						memset( pDstBits, 0, iSize );
					}
					else
					{
						// Just copy the mip level
						memcpy( pDstBits, pSrcBits, iSize ); 
					}
				}
				else if ( pSrcVTFTextures[iFace]->Width() == pSrcVTFTextures[iFace]->Height()*2 ) // If texture is rectangle 2x wide
				{
					int iMipWidth, iMipHeight, iMipDepth;
					pDstCubemap->ComputeMipLevelDimensions( iMip, &iMipWidth, &iMipHeight, &iMipDepth );
					if ( ( iMipHeight > 1 ) && ( iSrcMipSize*2 != iSize ) )
					{
						Warning( "%s - ERROR building default cube map! %d*2 != %d\n", skyboxMaterialName, iSrcMipSize, iSize );
						memset( pDstBits, 0, iSize );
					}
					else
					{
						// Copy row at a time and repeat last row
						memcpy( pDstBits, pSrcBits, iSize/2 ); 
						//memcpy( pDstBits + iSize/2, pSrcBits, iSize/2 );
						int nSrcRowSize = pSrcVTFTextures[iFace]->RowSizeInBytes( iMip + iMipLevelOffset );
						int nDstRowSize = pDstCubemap->RowSizeInBytes( iMip );
						if ( nSrcRowSize != nDstRowSize )
						{
							Warning( "%s - ERROR building default cube map! nSrcRowSize(%d) != nDstRowSize(%d)!\n", skyboxMaterialName, nSrcRowSize, nDstRowSize );
							memset( pDstBits, 0, iSize );
						}
						else
						{
							for ( int i = 0; i < ( iSize/2 / nSrcRowSize ); i++ )
							{
								memcpy( pDstBits + iSize/2 + i*nSrcRowSize, pSrcBits + iSrcMipSize - nSrcRowSize, nSrcRowSize );
							}
						}
					}
				}
				else
				{
					// ERROR! This code only supports square and rectangluar 2x wide
					Warning( "%s - Couldn't create default cubemap because texture res is %dx%d\n", skyboxMaterialName, pSrcVTFTextures[iFace]->Width(), pSrcVTFTextures[iFace]->Height() );
					memset( pDstBits, 0, iSize );
					return;
				}
			}
		}
	}

	ImageFormat originalFormat = pDstCubemap->Format();
	if( !bHDR )
	{
		// Convert the cube to format that we can apply tools to it...
		pDstCubemap->ConvertImageFormat( IMAGE_FORMAT_DEFAULT, false );
	}

	// Fixup the cubemap facing
	pDstCubemap->FixCubemapFaceOrientation();

	// Now that the bits are in place, compute the spheremaps...
	pDstCubemap->GenerateSpheremap();

	if( !bHDR )
	{
		// Convert the cubemap to the final format
		pDstCubemap->ConvertImageFormat( originalFormat, false );
	}

	// Write the puppy out!
	char dstVTFFileName[1024];
	if( bHDR )
	{
		sprintf( dstVTFFileName, "materials/maps/%s/cubemapdefault.hdr.vtf", mapbase );
	}
	else
	{
		sprintf( dstVTFFileName, "materials/maps/%s/cubemapdefault.vtf", mapbase );
	}

	CUtlBuffer outputBuf;
	if (!pDstCubemap->Serialize( outputBuf ))
	{
		Warning( "Error serializing default cubemap %s\n", dstVTFFileName );
		return;
	}

	IZip *pak = GetPakFile();

	// spit out the default one.
	AddBufferToPak( pak, dstVTFFileName, outputBuf.Base(), outputBuf.TellPut(), false );

	// spit out all of the ones that are attached to world geometry.
	int i;
	for( i = 0; i < s_DefaultCubemapNames.Count(); i++ )
	{
		char vtfName[MAX_PATH];
		VTFNameToHDRVTFName( s_DefaultCubemapNames[i], vtfName, MAX_PATH, bHDR );
		if( FileExistsInPak( pak, vtfName ) )
		{
			continue;
		}
		AddBufferToPak( pak, vtfName, outputBuf.Base(),outputBuf.TellPut(), false );
	}

	// Clean up the textures
	for( i = 0; i < 6; i++ )
	{
		DestroyVTFTexture( pSrcVTFTextures[i] );
	}
	DestroyVTFTexture( pDstCubemap );
}