//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //============================================================================= #include "tgaloader.h" #include "tier0/dbg.h" #pragma pack(1) typedef struct _TargaHeader { unsigned char id_length, colormap_type, image_type; unsigned short colormap_index, colormap_length; unsigned char colormap_size; unsigned short x_origin, y_origin, width, height; unsigned char pixel_size, attributes; } TargaHeader; #pragma pack() #define TGA_ATTRIBUTE_HFLIP 16 #define TGA_ATTRIBUTE_VFLIP 32 int fgetLittleShort (unsigned char **p) { byte b1, b2; b1 = *((*p)++); b2 = *((*p)++); return (short)(b1 + b2*256); } int fgetLittleLong (unsigned char **p) { byte b1, b2, b3, b4; b1 = *((*p)++); b2 = *((*p)++); b3 = *((*p)++); b4 = *((*p)++); return b1 + (b2<<8) + (b3<<16) + (b4<<24); } bool GetTGADimensions( int32 iBytes, char *pData, int * width, int *height ) { TargaHeader header; unsigned char *p = (unsigned char *)pData; if (width) *width = 0; if (height) *height = 0; header.id_length = *(p++); header.colormap_type = *(p++); header.image_type = *(p++); header.colormap_index = fgetLittleShort(&p); header.colormap_length = fgetLittleShort(&p); header.colormap_size = *(p++); header.x_origin = fgetLittleShort(&p); header.y_origin = fgetLittleShort(&p); header.width = fgetLittleShort(&p); header.height = fgetLittleShort(&p); header.pixel_size = *(p++); header.attributes = *(p++); if ( header.image_type != 2 && header.image_type != 10 ) { Msg( "LoadTGA: Only type 2 and 10 targa RGB images supported\n" ); return false; } if ( header.colormap_type !=0 || ( header.pixel_size != 32 && header.pixel_size != 24 ) ) { Msg("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); return false; } if (width) *width = header.width; if (height) *height = header.height; return true; } bool LoadTGA( int32 iBytes, char *pData, byte **rawImage, int * rawImageBytes, int * width, int *height ) { TargaHeader header; unsigned char *p = (unsigned char *)pData; if (width) *width = 0; if (height) *height = 0; header.id_length = *(p++); header.colormap_type = *(p++); header.image_type = *(p++); header.colormap_index = fgetLittleShort(&p); header.colormap_length = fgetLittleShort(&p); header.colormap_size = *(p++); header.x_origin = fgetLittleShort(&p); header.y_origin = fgetLittleShort(&p); header.width = fgetLittleShort(&p); header.height = fgetLittleShort(&p); header.pixel_size = *(p++); header.attributes = *(p++); if ( header.image_type != 2 && header.image_type != 10 ) { Msg( "LoadTGA: Only type 2 and 10 targa RGB images supported\n" ); return false; } if ( header.colormap_type !=0 || ( header.pixel_size != 32 && header.pixel_size != 24 ) ) { Msg("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); return false; } int columns = header.width; int rows = header.height; int numPixels = columns * rows; if (width) *width = header.width; if (height) *height = header.height; if (rawImageBytes) *rawImageBytes = header.width * header.height * 4; *rawImage = new byte[ numPixels * 4 ]; byte *pixbuf = *rawImage; if ( header.id_length != 0 ) p += header.id_length; // skip TARGA image comment. if ( header.image_type == 2 ) { // Uncompressed, RGB images for(int row = rows - 1; row >=0; row-- ) { if ( header.attributes & TGA_ATTRIBUTE_VFLIP ) pixbuf = *rawImage + (rows-row-1)*columns*4; else pixbuf = *rawImage + row*columns*4; for(int column=0; column < columns; column++) { unsigned char red,green,blue,alphabyte; switch ( header.pixel_size ) { case 24: blue = *(p++); green = *(p++); red = *(p++); *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = 255; break; case 32: blue = *(p++); green = *(p++); red = *(p++); alphabyte = *(p++); *pixbuf++ = red; *pixbuf++ = green; *pixbuf++ = blue; *pixbuf++ = alphabyte; break; } } } } else if ( header.image_type == 10 ) { // Runlength encoded RGB images unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; for( int row = rows - 1; row >= 0; row--) { if ( header.attributes & TGA_ATTRIBUTE_VFLIP ) pixbuf = *rawImage + (rows-row-1)*columns*4; else pixbuf = *rawImage + row*columns*4; for( int column=0; column < columns; ) { packetHeader=*(p++); packetSize = 1 + (packetHeader & 0x7f); if (packetHeader & 0x80) { // run-length packet switch ( header.pixel_size ) { case 24: blue = *(p++); green = *(p++); red = *(p++); alphabyte = 255; break; case 32: default: blue = *(p++); green = *(p++); red = *(p++); alphabyte = *(p++); break; } for(j=0;j0) row--; else goto breakOut; pixbuf = *rawImage + row*columns*4; } } } else { // non run-length packet for(j=0;j0) row--; else goto breakOut; pixbuf = *rawImage + row*columns*4; } } } } breakOut:; } } return true; } void WriteTGA( const char *pchFileName, void *rgba, int wide, int tall ) { _TargaHeader header; memset( &header, 0x0, sizeof(header) ); header.width = wide; header.height = tall; header.image_type = 2; header.pixel_size = 32; FILE *fp = fopen( pchFileName, "w+" ); fwrite( &header, 1, sizeof(header), fp ); fwrite( rgba, 1, wide*tall*4, fp ); fclose(fp); }