From 3bf9df6b2785fa6d951086978a3e66f49427166a Mon Sep 17 00:00:00 2001 From: FluorescentCIAAfricanAmerican <0934gj3049fk@protonmail.com> Date: Wed, 22 Apr 2020 12:56:21 -0400 Subject: 1 --- bitmap/tgaloader.cpp | 1001 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1001 insertions(+) create mode 100644 bitmap/tgaloader.cpp (limited to 'bitmap/tgaloader.cpp') 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 +#include "bitmap/tgaloader.h" +#include "tier0/dbg.h" +#include "basetypes.h" +#include +#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 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 &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 &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 + -- cgit v1.2.3