Convert TGA to VTF In-engine

From Valve Developer Community
Jump to: navigation, search
Wikipedia - Letter.png
This article has multiple issues. Please help improve it or discuss these issues on the talk page. (Learn how and when to remove these template messages)
Dead End - Icon.png
This article has no Wikipedia icon links to other VDC articles. Please help improve this article by adding links Wikipedia icon that are relevant to the context within the existing text.
January 2024

This is a helper method that accepts a source TGA path, and spits out a VTF to to specified path based on the TGA. To use it, you will need to include "vtf/vtf.h" in your code to pass through texture flag arguments such as "TEXTUREFLAGS_NOMIP".

It was created to use with a custom load game menu as there doesn't seem any clear way to load TGAs into the interface at present, and all code that does this is part of the closed source GameUI DLL. It was compiled using camomaterialproxy.cpp (reading a TGA) and VBSP's cubemap.cpp (writing VTFs). If you need to extend this, the code in those files is a good place to start.

#include "filesystem.h"
#include "bitmap/tgaloader.h"
#include "vtf/vtf.h"

[...]

// Converts the source TGA to the destination VTF on disk. Returns true on success.
// VTF flags are members of the enum CompiledVtfFlags in vtf.h.
// Pass the optional argument as true to remove the source TGA after a successful conversion.
bool ConvertTGAtoVTF(const char *pSourceTGA, const char *pDestVTF, int pVTFFlags, bool pRemoveSourceTGA = false)
{
	enum ImageFormat indexImageFormat;
	int indexImageSize;
	float gamma;
	int w, h;

	if (!TGALoader::GetInfo(pSourceTGA, &w, &h, &indexImageFormat, &gamma))
	{
		Warning("Unable to find TGA: %s\n", pSourceTGA);
		return false;
	}

	indexImageSize = ImageLoader::GetMemRequired(w, h, 1, indexImageFormat, false);

	unsigned char *pImage = (unsigned char*)new unsigned char[indexImageSize];

	if (!TGALoader::Load( pImage, pSourceTGA, w, h, indexImageFormat, gamma, false ) )
	{
		Warning("Unable to load TGA: %s\n", pSourceTGA);
		return false;
	}

	// Create a new VTF
	IVTFTexture *vtf = CreateVTFTexture();

	// Initialise it with some flags (nomipmap is good for using in the VGUI)
	vtf->Init(w, h, 1, indexImageFormat, pVTFFlags, 1);
	unsigned char* pDest = vtf->ImageData(0, 0, 0);

	// Memcpy it to the VTF
	memcpy(pDest, pImage, indexImageSize);

	// Write
	CUtlBuffer buffer;
	vtf->Serialize(buffer);
	bool vtfWriteSuccess = g_pFullFileSystem->WriteFile(pDestVTF, "MOD", buffer);

	// Clean up
	DestroyVTFTexture(vtf);
	buffer.Clear();

	if (!vtfWriteSuccess)
	{
		Warning("Unable to write VTF: %s\n", pDestVTF);
		return false;
	}

	// Remove the original
	if (pRemoveSourceTGA)
	{
		g_pFullFileSystem->RemoveFile(pSourceTGA, "MOD");
	}

	return true;
}