280 lines
6.4 KiB
C++
280 lines
6.4 KiB
C++
//========= 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;j<packetSize;j++)
|
|
{
|
|
*pixbuf++=red;
|
|
*pixbuf++=green;
|
|
*pixbuf++=blue;
|
|
*pixbuf++=alphabyte;
|
|
column++;
|
|
if (column==columns) { // run spans across rows
|
|
column=0;
|
|
if (row>0)
|
|
row--;
|
|
else
|
|
goto breakOut;
|
|
pixbuf = *rawImage + row*columns*4;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ // non run-length packet
|
|
for(j=0;j<packetSize;j++) {
|
|
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;
|
|
}
|
|
column++;
|
|
if (column==columns)
|
|
{ // pixel packet run spans across rows
|
|
column=0;
|
|
if (row>0)
|
|
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);
|
|
|
|
}
|
|
|
|
|