summaryrefslogtreecommitdiff
path: root/bitmap/tgaloader.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /bitmap/tgaloader.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'bitmap/tgaloader.cpp')
-rw-r--r--bitmap/tgaloader.cpp1001
1 files changed, 1001 insertions, 0 deletions
diff --git a/bitmap/tgaloader.cpp b/bitmap/tgaloader.cpp
new file mode 100644
index 0000000..29b0c31
--- /dev/null
+++ b/bitmap/tgaloader.cpp
@@ -0,0 +1,1001 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include <stdio.h>
+#include "bitmap/tgaloader.h"
+#include "tier0/dbg.h"
+#include "basetypes.h"
+#include <math.h>
+#include "tier1/utlvector.h"
+#include "tier1/utlbuffer.h"
+#include "filesystem.h"
+#include "tier2/tier2.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+namespace TGALoader
+{
+
+//-----------------------------------------------------------------------------
+// Format of the TGA header on disk
+//-----------------------------------------------------------------------------
+
+#pragma pack (1)
+
+struct TGAHeader_t
+{
+ unsigned char id_length;
+ unsigned char colormap_type;
+ unsigned char image_type;
+ unsigned short colormap_index;
+ unsigned short colormap_length;
+ unsigned char colormap_size;
+ unsigned short x_origin;
+ unsigned short y_origin;
+ unsigned short width;
+ unsigned short height;
+ unsigned char pixel_size;
+ unsigned char attributes;
+};
+
+
+//-----------------------------------------------------------------------------
+// read a row into an RGBA8888 array.
+//-----------------------------------------------------------------------------
+
+typedef void (*ReadRowFunc_t)( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDstMemory );
+
+
+//-----------------------------------------------------------------------------
+// output a RGBA8888 row into the destination format.
+//-----------------------------------------------------------------------------
+
+typedef void (*OutputRowFunc_t)( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDstMemory );
+
+
+//-----------------------------------------------------------------------------
+// Important constants
+//-----------------------------------------------------------------------------
+
+#define TGA_MAX_COLORMAP_SIZE ( 256 * 4 )
+#define TGA_MAX_ROW_LENGTH_IN_PIXELS IMAGE_MAX_DIM
+
+
+//-----------------------------------------------------------------------------
+// Globals... blech
+//-----------------------------------------------------------------------------
+static unsigned char g_ColorMap[TGA_MAX_COLORMAP_SIZE];
+
+// run-length state from row to row for RLE images
+static bool g_IsRunLengthPacket;
+static int g_PixelsLeftInPacket;
+
+static unsigned char g_SrcGammaTable[256];
+static unsigned char g_DstGammaTable[256];
+
+typedef CUtlMemory<unsigned char> CTempImage;
+
+
+//-----------------------------------------------------------------------------
+// Reads in a file, sticks it into a UtlVector
+//-----------------------------------------------------------------------------
+
+static bool ReadFile( char const* pFileName, CTempImage& image, int maxbytes = -1 )
+{
+ Assert( pFileName );
+ Assert( g_pFullFileSystem );
+ if( !g_pFullFileSystem )
+ {
+ return false;
+ }
+
+ FileHandle_t fileHandle;
+ fileHandle = g_pFullFileSystem->Open( pFileName, "rb" );
+ if( !fileHandle )
+ return false;
+
+ // How big is the file?
+ long pos;
+ if (maxbytes < 0)
+ {
+ pos = g_pFullFileSystem->Size( fileHandle );
+ }
+ else
+ {
+ pos = maxbytes;
+ }
+
+ // Allocate enough space
+ image.EnsureCapacity( pos );
+
+ // Back to the start of the file
+ g_pFullFileSystem->Seek( fileHandle, 0, FILESYSTEM_SEEK_HEAD );
+
+ // Read the file into the vector memory
+ int len = g_pFullFileSystem->Read( image.Base(), pos, fileHandle );
+
+ // Close the file
+ g_pFullFileSystem->Close( fileHandle );
+
+ // It's an error if we didn't read in enough goodies
+ return len == pos;
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads in the TGA Header
+//-----------------------------------------------------------------------------
+static void ReadHeader( CUtlBuffer& buf, TGAHeader_t& header )
+{
+ buf.Get( &header, sizeof(TGAHeader_t) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Figures out TGA information
+//-----------------------------------------------------------------------------
+bool GetInfo( CUtlBuffer& buf, int *width, int *height,
+ ImageFormat *imageFormat, float *sourceGamma )
+{
+ TGAHeader_t header;
+
+ ReadHeader( buf, header );
+
+ switch( header.image_type )
+ {
+ case 1: // 8 bit uncompressed TGA image
+ case 3: // 8 bit monochrome uncompressed TGA image
+ case 9: // 8 bit compressed TGA image
+ *imageFormat = IMAGE_FORMAT_I8;
+ break;
+ case 2: // 24/32 bit uncompressed TGA image
+ case 10: // 24/32 bit compressed TGA image
+ if( header.pixel_size == 32 )
+ {
+ *imageFormat = IMAGE_FORMAT_ABGR8888;
+ }
+ else if( header.pixel_size == 24 )
+ {
+ *imageFormat = IMAGE_FORMAT_BGR888;
+ }
+ else
+ {
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ break;
+ }
+
+ *width = header.width;
+ *height = header.height;
+ *sourceGamma = ARTWORK_GAMMA;
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the minimum amount you have to load to get information about the TGA file
+//-----------------------------------------------------------------------------
+int TGAHeaderSize()
+{
+ return sizeof( TGAHeader_t );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets info about a TGA file
+//-----------------------------------------------------------------------------
+bool GetInfo( char const* pFileName, int *width, int *height,
+ ImageFormat *imageFormat, float *sourceGamma )
+{
+ // temporary memory
+ CTempImage image;
+
+ // try to read in the file
+ if (!ReadFile( pFileName, image, sizeof(TGAHeader_t) ))
+ return false;
+
+ // Serialization buffer
+ CUtlBuffer buf( image.Base(), image.NumAllocated(), CUtlBuffer::READ_ONLY );
+
+ return GetInfo( buf, width, height, imageFormat, sourceGamma );
+}
+
+
+//-----------------------------------------------------------------------------
+// Various output methods
+//-----------------------------------------------------------------------------
+
+void OutputRowRGBA8888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 4 )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+ pDst[0] = pSrc[0];
+ pDst[1] = pSrc[1];
+ pDst[2] = pSrc[2];
+ pDst[3] = pSrc[3];
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+void OutputRowABGR8888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 4 )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+ pDst[3] = pSrc[0];
+ pDst[2] = pSrc[1];
+ pDst[1] = pSrc[2];
+ pDst[0] = pSrc[3];
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+void OutputRowRGB888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 3 )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+ pDst[0] = pSrc[0];
+ pDst[1] = pSrc[1];
+ pDst[2] = pSrc[2];
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+void OutputRowBGR888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 3 )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+ pDst[2] = pSrc[0];
+ pDst[1] = pSrc[1];
+ pDst[0] = pSrc[2];
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+void OutputRowRGB565( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ Assert( 0 );
+}
+
+void OutputRowI8( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, ++pDst )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+
+ if( ( pSrc[0] == pSrc[1] ) && ( pSrc[1] == pSrc[2] ) )
+ {
+ pDst[0] = pSrc[0];
+ }
+ else
+ {
+ pDst[0] = ( unsigned char )( 0.299f * pSrc[0] + 0.587f * pSrc[1] + 0.114f * pSrc[2] );
+ }
+
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+void OutputRowIA88( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 2 )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+
+ if( ( pSrc[0] == pSrc[1] ) && ( pSrc[1] == pSrc[2] ) )
+ {
+ pDst[0] = pSrc[0];
+ }
+ else
+ {
+ pDst[0] = ( unsigned char )( 0.299f * pSrc[0] + 0.587f * pSrc[1] + 0.114f * pSrc[2] );
+ }
+ pDst[1] = pSrc[3];
+
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+void OutputRowA8( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, ++pDst )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+ pDst[0] = pSrc[3];
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+void OutputRowRGB888BlueScreen( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 3 )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+ pDst[0] = (unsigned char)(( ( int )pSrc[0] * ( int )pSrc[3] ) >> 8);
+ pDst[1] = (unsigned char)(( ( int )pSrc[1] * ( int )pSrc[3] ) >> 8);
+ pDst[2] = (( ( ( ( int )pSrc[2] * ( int )pSrc[3] ) ) >> 8 ) + ( 255 - pSrc[3] ));
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+void OutputRowBGR888BlueScreen( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 3 )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+ pDst[2] = (unsigned char)(( ( int )pSrc[0] * ( int )pSrc[3] ) >> 8);
+ pDst[1] = (unsigned char)(( ( int )pSrc[1] * ( int )pSrc[3] ) >> 8);
+ pDst[0] = (unsigned char)(( ( ( ( int )pSrc[2] * ( int )pSrc[3] ) ) >> 8 ) + ( 255 - pSrc[3] ));
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+void OutputRowARGB8888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 4 )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+ pDst[0] = pSrc[3];
+ pDst[1] = pSrc[0];
+ pDst[2] = pSrc[1];
+ pDst[3] = pSrc[2];
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+void OutputRowBGRA8888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 4 )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+ pDst[0] = pSrc[2];
+ pDst[1] = pSrc[1];
+ pDst[2] = pSrc[0];
+ pDst[3] = pSrc[3];
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+void OutputRowBGRX8888( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 4 )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+ pDst[0] = pSrc[2];
+ pDst[1] = pSrc[1];
+ pDst[2] = pSrc[0];
+ pDst[3] = 255;
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+void OutputRowBGR565( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 2 )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+ unsigned short rgba = (pSrc[2] & 0x1F) | ((pSrc[1] & 0x3F) << 5) |
+ ((pSrc[0] & 0x1F) << 11);
+
+ pDst[0] = rgba & 0xFF;
+ pDst[1] = rgba >> 8;
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+void OutputRowBGRX5551( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 2 )
+ {
+ unsigned char* pSrc = (unsigned char*)buf.PeekGet();
+ unsigned short rgba = (pSrc[2] & 0x1F) | ((pSrc[1] & 0x1F) << 5) |
+ ((pSrc[0] & 0x1F) << 10) | 0x8000;
+
+ pDst[0] = rgba & 0xFF;
+ pDst[1] = rgba >> 8;
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, 4 );
+ }
+}
+
+static OutputRowFunc_t GetOutputRowFunc( ImageFormat imageFormat )
+{
+ switch( imageFormat )
+ {
+ case IMAGE_FORMAT_RGBA8888:
+ return &OutputRowRGBA8888;
+ case IMAGE_FORMAT_ABGR8888:
+ return &OutputRowABGR8888;
+ case IMAGE_FORMAT_RGB888:
+ return &OutputRowRGB888;
+ case IMAGE_FORMAT_BGR888:
+ return &OutputRowBGR888;
+ case IMAGE_FORMAT_RGB565:
+ return &OutputRowRGB565;
+ case IMAGE_FORMAT_I8:
+ return &OutputRowI8;
+ case IMAGE_FORMAT_IA88:
+ return &OutputRowIA88;
+ case IMAGE_FORMAT_A8:
+ return &OutputRowA8;
+ case IMAGE_FORMAT_RGB888_BLUESCREEN:
+ return &OutputRowRGB888BlueScreen;
+ case IMAGE_FORMAT_BGR888_BLUESCREEN:
+ return &OutputRowBGR888BlueScreen;
+ case IMAGE_FORMAT_ARGB8888:
+ return &OutputRowARGB8888;
+ case IMAGE_FORMAT_BGRA8888:
+ return &OutputRowBGRA8888;
+ case IMAGE_FORMAT_BGRX8888:
+ return &OutputRowBGRX8888;
+ case IMAGE_FORMAT_BGR565:
+ return &OutputRowBGR565;
+ case IMAGE_FORMAT_BGRX5551:
+ return &OutputRowBGRX5551;
+#ifdef _X360
+ case IMAGE_FORMAT_LINEAR_RGB888:
+ return &OutputRowRGB888;
+ case IMAGE_FORMAT_LINEAR_BGR888:
+ return &OutputRowBGR888;
+#endif
+ default:
+ return NULL;
+ break;
+ }
+}
+
+#if 0
+static void InitSourceGammaConversionTable( float srcGamma )
+{
+ static float lastSrcGamma = -1;
+ if (lastSrcGamma == srcGamma)
+ return;
+
+ lastSrcGamma = srcGamma;
+ ImageLoader::ConstructGammaTable( g_SrcGammaTable, srcGamma, 1.0f );
+}
+
+static void InitDestGammaConversionTable( float dstGamma )
+{
+ static float lastDstGamma = -1;
+ if (lastDstGamma == dstGamma)
+ return;
+
+ lastDstGamma = dstGamma;
+ ImageLoader::ConstructGammaTable( g_DstGammaTable, 1.0f, dstGamma );
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Reads an 8-bit palettized TGA image
+//-----------------------------------------------------------------------------
+
+void ReadRow8BitUncompressedWithColormap( CUtlBuffer& buf,
+ TGAHeader_t const& header, unsigned char* pDst )
+{
+ int i;
+ unsigned char* colormapEntry;
+
+ switch( header.colormap_size )
+ {
+ case 8:
+ for( i = 0; i < header.width; ++i, pDst += 4 )
+ {
+ int pal = buf.GetUnsignedChar();
+
+ colormapEntry = &g_ColorMap[pal];
+ pDst[0] = colormapEntry[0];
+ pDst[1] = colormapEntry[0];
+ pDst[2] = colormapEntry[0];
+ pDst[3] = 255;
+ }
+ break;
+
+ case 24:
+ for( i = 0; i < header.width; ++i, pDst += 4 )
+ {
+ int pal = buf.GetUnsignedChar();
+
+ colormapEntry = &g_ColorMap[pal * 3];
+ pDst[0] = colormapEntry[2];
+ pDst[1] = colormapEntry[1];
+ pDst[2] = colormapEntry[0];
+ pDst[3] = 255;
+ }
+ break;
+
+ case 32:
+ for( i = 0; i < header.width; ++i, pDst += 4 )
+ {
+ int pal = buf.GetUnsignedChar();
+
+ colormapEntry = &g_ColorMap[pal * 4];
+ pDst[0] = colormapEntry[3];
+ pDst[1] = colormapEntry[2];
+ pDst[2] = colormapEntry[1];
+ pDst[3] = colormapEntry[0];
+ }
+ break;
+
+ default:
+ Assert( 0 );
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads an 8-bit greyscale TGA image
+//-----------------------------------------------------------------------------
+
+void ReadRow8BitUncompressedWithoutColormap( CUtlBuffer& buf,
+ TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 4 )
+ {
+ pDst[0] = pDst[1] = pDst[2] = buf.GetUnsignedChar();
+ pDst[3] = 255;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Reads a 24-bit TGA image
+//-----------------------------------------------------------------------------
+
+void ReadRow24BitUncompressedWithoutColormap( CUtlBuffer& buf,
+ TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 4 )
+ {
+ pDst[2] = buf.GetUnsignedChar();
+ pDst[1] = buf.GetUnsignedChar();
+ pDst[0] = buf.GetUnsignedChar();
+ pDst[3] = 255;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Reads a 32-bit TGA image
+//-----------------------------------------------------------------------------
+
+void ReadRow32BitUncompressedWithoutColormap( CUtlBuffer& buf,
+ TGAHeader_t const& header, unsigned char* pDst )
+{
+ for( int i = 0; i < header.width; ++i, pDst += 4 )
+ {
+ pDst[2] = buf.GetUnsignedChar();
+ pDst[1] = buf.GetUnsignedChar();
+ pDst[0] = buf.GetUnsignedChar();
+ pDst[3] = buf.GetUnsignedChar();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Decompresses a run-length encoded row of bytes
+//-----------------------------------------------------------------------------
+
+static void DecompressRow( CUtlBuffer& buf, TGAHeader_t const& header, unsigned char* pDst )
+{
+ int bytesPerPixel = header.pixel_size >> 3;
+ int pixelsLeftInRow = header.width;
+ int numPixelsToProcess;
+
+#ifdef DBGFLAG_ASSERT
+ unsigned char *pLast = pDst + header.width * bytesPerPixel;
+#endif
+
+ unsigned char repeat[4] = {};
+ do
+ {
+ if( !g_PixelsLeftInPacket )
+ {
+ // start a new packet.
+ unsigned char packetHeader = buf.GetUnsignedChar();
+ g_PixelsLeftInPacket = 1 + ( packetHeader & 0x7f );
+ if( packetHeader & 0x80 )
+ {
+ g_IsRunLengthPacket = true;
+
+ // Read what I'm supposed to repeat
+ for (int i = 0; i < bytesPerPixel; ++i)
+ {
+ repeat[i] = buf.GetUnsignedChar();
+ }
+ }
+ else
+ {
+ g_IsRunLengthPacket = false;
+ }
+ }
+
+ // already in the middle of a packet of data.
+ numPixelsToProcess = g_PixelsLeftInPacket;
+ if( numPixelsToProcess > pixelsLeftInRow )
+ {
+ numPixelsToProcess = pixelsLeftInRow;
+ }
+ if( g_IsRunLengthPacket )
+ {
+ for( int i = numPixelsToProcess; --i >= 0; pDst += bytesPerPixel )
+ {
+ for (int j = 0; j < bytesPerPixel; ++j )
+ {
+ pDst[j] = repeat[j];
+ }
+ }
+ }
+ else
+ {
+ buf.Get( pDst, numPixelsToProcess * bytesPerPixel );
+ pDst += numPixelsToProcess * bytesPerPixel;
+ }
+
+ g_PixelsLeftInPacket -= numPixelsToProcess;
+ pixelsLeftInRow -= numPixelsToProcess;
+
+ } while( pixelsLeftInRow );
+
+ Assert( pDst == pLast );
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads a compressed 8-bit palettized TGA image
+//-----------------------------------------------------------------------------
+void ReadRow8BitCompressedWithColormap( CUtlBuffer& buf,
+ TGAHeader_t const& header, unsigned char* pDst )
+{
+ unsigned char rowI_8[TGA_MAX_ROW_LENGTH_IN_PIXELS];
+
+ DecompressRow( buf, header, rowI_8 );
+
+ CUtlBuffer uncompressedBuf( rowI_8, TGA_MAX_ROW_LENGTH_IN_PIXELS, CUtlBuffer::READ_ONLY );
+ ReadRow8BitUncompressedWithColormap( uncompressedBuf, header, pDst );
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads a compressed 8-bit greyscale TGA image
+//-----------------------------------------------------------------------------
+void ReadRow8BitCompressedWithoutColormap( CUtlBuffer& buf,
+ TGAHeader_t const& header, unsigned char* pDst )
+{
+ unsigned char rowI_8[TGA_MAX_ROW_LENGTH_IN_PIXELS];
+
+ DecompressRow( buf, header, rowI_8 );
+
+ CUtlBuffer uncompressedBuf( rowI_8, TGA_MAX_ROW_LENGTH_IN_PIXELS, CUtlBuffer::READ_ONLY );
+ ReadRow8BitUncompressedWithoutColormap( uncompressedBuf, header, pDst );
+}
+
+//-----------------------------------------------------------------------------
+// Reads a compressed 24-bit TGA image
+//-----------------------------------------------------------------------------
+
+void ReadRow24BitCompressedWithoutColormap( CUtlBuffer& buf,
+ TGAHeader_t const& header, unsigned char* pDst )
+{
+ unsigned char rowBGR_888[TGA_MAX_ROW_LENGTH_IN_PIXELS * 3];
+
+ DecompressRow( buf, header, rowBGR_888 );
+
+ CUtlBuffer uncompressedBuf( rowBGR_888, TGA_MAX_ROW_LENGTH_IN_PIXELS * 3, CUtlBuffer::READ_ONLY );
+ ReadRow24BitUncompressedWithoutColormap( uncompressedBuf, header, pDst );
+}
+
+//-----------------------------------------------------------------------------
+// Reads a compressed 32-bit TGA image
+//-----------------------------------------------------------------------------
+
+void ReadRow32BitCompressedWithoutColormap( CUtlBuffer& buf,
+ TGAHeader_t const& header, unsigned char* pDst )
+{
+ unsigned char rowBGRA_8888[TGA_MAX_ROW_LENGTH_IN_PIXELS << 2];
+
+ DecompressRow( buf, header, rowBGRA_8888 );
+
+ CUtlBuffer uncompressedBuf( rowBGRA_8888, TGA_MAX_ROW_LENGTH_IN_PIXELS << 2, CUtlBuffer::READ_ONLY );
+ ReadRow32BitUncompressedWithoutColormap( uncompressedBuf, header, pDst );
+}
+
+//-----------------------------------------------------------------------------
+// Method used to read the TGA
+//-----------------------------------------------------------------------------
+
+static ReadRowFunc_t GetReadRowFunc( TGAHeader_t const& header )
+{
+ switch( header.image_type )
+ {
+ case 1: // 8 bit uncompressed TGA image
+ case 3: // 8 bit monochrome uncompressed TGA image
+ if( header.colormap_length )
+ {
+ return &ReadRow8BitUncompressedWithColormap;
+ }
+ else
+ {
+ return &ReadRow8BitUncompressedWithoutColormap;
+ }
+ case 9: // 8 bit compressed TGA image
+ if( header.colormap_length )
+ {
+ return &ReadRow8BitCompressedWithColormap;
+ }
+ else
+ {
+ return &ReadRow8BitCompressedWithoutColormap;
+ }
+ case 2: // 24/32 bit uncompressed TGA image
+ switch( header.pixel_size )
+ {
+ case 24:
+ return &ReadRow24BitUncompressedWithoutColormap;
+ break;
+ case 32:
+ return &ReadRow32BitUncompressedWithoutColormap;
+ break;
+ default:
+ //Error( "unsupported tga colordepth: %d", TGAHeader_t.pixel_size" );
+ return 0;
+ break;
+ }
+ case 10: // 24/32 bit compressed TGA image
+ if( header.colormap_length )
+ {
+ // Error( "colormaps not support with 24/32 bit TGAs." );
+ return 0;
+ }
+ else
+ {
+ switch( header.pixel_size )
+ {
+ case 24:
+ return &ReadRow24BitCompressedWithoutColormap;
+ break;
+ case 32:
+ return &ReadRow32BitCompressedWithoutColormap;
+ break;
+ default:
+ //Error( "unsupported tga colordepth: %d", TGAHeader_t.pixel_size" );
+ return NULL;
+ break;
+ }
+ }
+ default:
+ // Error( "unsupported tga pixel format" );
+ return 0;
+ break;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads the color map
+//-----------------------------------------------------------------------------
+
+static bool ReadColormap( CUtlBuffer& buf, TGAHeader_t const& header )
+{
+ int numColormapBytes = header.colormap_length * ( header.colormap_size >> 3 );
+ if( numColormapBytes > TGA_MAX_COLORMAP_SIZE )
+ {
+ // Error( "colormap bigger than TGA_MAX_COLORMAP_SIZE" );
+ return false;
+ }
+
+ // read colormap
+ buf.Get( g_ColorMap, numColormapBytes );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads the source image
+//-----------------------------------------------------------------------------
+static bool ReadSourceImage( CUtlBuffer& buf, TGAHeader_t& header, CTempImage& image )
+{
+ // Figure out our reading and riting
+ ReadRowFunc_t ReadRowFunc = GetReadRowFunc( header );
+ if( !ReadRowFunc )
+ return false;
+
+ // HACK: Fixme: We really shouldn't be using globals here
+ // Init RLE vars
+ g_PixelsLeftInPacket = 0;
+
+ // Only allocate the memory once
+ int memRequired = ImageLoader::GetMemRequired( header.width, header.height, 1,
+ IMAGE_FORMAT_RGBA8888, false );
+ image.EnsureCapacity( memRequired );
+
+ // read each row and process it. Note the image is upside-down from
+ // the way we want it.
+ unsigned char* pDstBits;
+ // flip the image vertically if necessary.
+ if (header.attributes & 0x20)
+ {
+ for( int row = 0; row < header.height; ++row )
+ {
+ pDstBits = image.Base() +
+ row * header.width * ImageLoader::SizeInBytes(IMAGE_FORMAT_RGBA8888);
+ ReadRowFunc( buf, header, pDstBits );
+ }
+ }
+ else
+ {
+ for( int row = header.height; --row >= 0; )
+ {
+ pDstBits = image.Base() +
+ row * header.width * ImageLoader::SizeInBytes(IMAGE_FORMAT_RGBA8888);
+ ReadRowFunc( buf, header, pDstBits );
+ }
+ }
+
+ return true;
+}
+
+#if 0
+//-----------------------------------------------------------------------------
+// Outputs the final image
+//-----------------------------------------------------------------------------
+static bool OutputImage( CTempImage& image, TGAHeader_t& header,
+ ImageFormat imageFormat, unsigned char* pDst )
+{
+ // How do we write?
+ OutputRowFunc_t OutputRowFunc = GetOutputRowFunc( imageFormat );
+ if( !OutputRowFunc )
+ return false;
+
+ CUtlBuffer buf( image.Base(), image.NumAllocated(), CUtlBuffer::READ_ONLY );
+ unsigned char* pDstBits;
+ for( int row = 0; row < header.height; ++row )
+ {
+ pDstBits = pDst +
+ row * header.width * ImageLoader::SizeInBytes(imageFormat);
+ OutputRowFunc( buf, header, pDstBits );
+ }
+
+ return true;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Parses the lovely bits previously read from disk
+//-----------------------------------------------------------------------------
+bool Load( unsigned char *pOutputImage, CUtlBuffer& buf, int width,
+ int height, ImageFormat imageFormat, float targetGamma, bool mipmap )
+{
+ TGAHeader_t header;
+
+ // Read the TGA header
+ ReadHeader( buf, header );
+
+ // skip TARGA image comment
+ if( header.id_length != 0 )
+ {
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, header.id_length );
+ }
+
+ // Read the color map for palettized images
+ if( header.colormap_length != 0 )
+ {
+ if (!ReadColormap( buf, header ))
+ return false;
+ }
+
+ // Stores the RGBA8888 temp version of the image which we'll use to
+ // to do mipmapping...
+ CTempImage tmpImage;
+ if (!ReadSourceImage( buf, header, tmpImage ))
+ return false;
+
+ // Erg... what if header.width * header.height > width * height?
+ // Then don't do anything, this is an error condition...
+ if ((width * height) < (header.width * header.height))
+ return false;
+
+ // Now that we've got the source image, generate the mip-map levels
+ ImageLoader::GenerateMipmapLevels( tmpImage.Base(), pOutputImage,
+ header.width, header.height, 1, imageFormat, ARTWORK_GAMMA, targetGamma,
+ mipmap ? 0 : 1 );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Reads a TGA image from a file
+//-----------------------------------------------------------------------------
+bool Load( unsigned char *pOutputImage, const char *pFileName, int width, int height,
+ ImageFormat imageFormat, float targetGamma, bool mipmap )
+{
+ Assert( pOutputImage && pFileName );
+
+ // memory for the file
+ CTempImage vec;
+
+ // Read that puppy in!
+ if (!ReadFile( pFileName, vec ))
+ return false;
+
+ // Make an unserialization buffer
+ CUtlBuffer buf( vec.Base(), vec.NumAllocated(), CUtlBuffer::READ_ONLY );
+
+ // Do the dirty deed
+ return Load( pOutputImage, buf, width, height, imageFormat, targetGamma, mipmap );
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates a map in linear space
+//-----------------------------------------------------------------------------
+bool LoadRGBA8888( CUtlBuffer& buf, CUtlMemory<unsigned char> &outputData, int &outWidth, int &outHeight )
+{
+ TGAHeader_t header;
+
+ // Read the TGA header
+ ReadHeader( buf, header );
+
+ // skip TARGA image comment
+ if( header.id_length != 0 )
+ {
+ buf.SeekGet( CUtlBuffer::SEEK_CURRENT, header.id_length );
+ }
+
+ // Read the color map for palettized images
+ if( header.colormap_length != 0 )
+ {
+ if (!ReadColormap( buf, header ))
+ return false;
+ }
+
+ // Stores the RGBA8888 temp version of the image which we'll use to
+ // to do mipmapping...
+ int memSize = ImageLoader::GetMemRequired(
+ header.width, header.height, 1, IMAGE_FORMAT_RGBA8888, false );
+
+ outputData.EnsureCapacity( memSize );
+ if (!ReadSourceImage( buf, header, outputData ))
+ return false;
+
+ outWidth = header.width;
+ outHeight = header.height;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Reads a TGA, keeps it in RGBA8888
+//-----------------------------------------------------------------------------
+
+bool LoadRGBA8888( const char *pFileName, CUtlMemory<unsigned char> &outputData, int &outWidth, int &outHeight )
+{
+ Assert( pFileName );
+
+ // memory for the file
+ CTempImage vec;
+
+ // Read that puppy in!
+ if (!ReadFile( pFileName, vec ))
+ return false;
+
+ // Make an unserialization buffer
+ CUtlBuffer buf( vec.Base(), vec.NumAllocated(), CUtlBuffer::READ_ONLY );
+
+ // Do the dirty deed
+ return LoadRGBA8888( buf, outputData, outWidth, outHeight );
+}
+
+} // end namespace TGALoader
+