2
0
mirror of https://github.com/FWGS/xash3d-fwgs synced 2024-11-28 13:02:13 +01:00
xash3d-fwgs/engine/common/imagelib/img_tga.c
Gleb Mazovetskiy 5e0a0765ce Trim all trailing whitespace
The `.editorconfig` file in this repo is configured to trim all trailing
whitespace regardless of whether the line is modified.

Trims all trailing whitespace in the repository to make the codebase easier
to work with in editors that respect `.editorconfig`.

`git blame` becomes less useful on these lines but it already isn't very useful.

Commands:

```
find . -type f -name '*.h' -exec sed --in-place 's/[[:space:]]\+$//' {} \+
find . -type f -name '*.c' -exec sed --in-place 's/[[:space:]]\+$//' {} \+
```
2021-01-04 20:55:10 +03:00

336 lines
8.3 KiB
C

/*
img_tga.c - tga format load & save
Copyright (C) 2007 Uncle Mike
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include "imagelib.h"
#include "xash3d_mathlib.h"
#include "img_tga.h"
/*
=============
Image_LoadTGA
=============
*/
qboolean Image_LoadTGA( const char *name, const byte *buffer, fs_offset_t filesize )
{
int i, columns, rows, row_inc, row, col;
byte *buf_p, *pixbuf, *targa_rgba;
rgba_t palette[256];
byte red = 0, green = 0, blue = 0, alpha = 0;
int readpixelcount, pixelcount;
int reflectivity[3] = { 0, 0, 0 };
qboolean compressed;
tga_t targa_header;
if( filesize < sizeof( tga_t ))
return false;
buf_p = (byte *)buffer;
targa_header.id_length = *buf_p++;
targa_header.colormap_type = *buf_p++;
targa_header.image_type = *buf_p++;
targa_header.colormap_index = buf_p[0] + buf_p[1] * 256; buf_p += 2;
targa_header.colormap_length = buf_p[0] + buf_p[1] * 256; buf_p += 2;
targa_header.colormap_size = *buf_p; buf_p += 1;
targa_header.x_origin = *(short *)buf_p; buf_p += 2;
targa_header.y_origin = *(short *)buf_p; buf_p += 2;
targa_header.width = image.width = *(short *)buf_p; buf_p += 2;
targa_header.height = image.height = *(short *)buf_p; buf_p += 2;
targa_header.pixel_size = *buf_p++;
targa_header.attributes = *buf_p++;
if( targa_header.id_length != 0 ) buf_p += targa_header.id_length; // skip TARGA image comment
// check for tga file
if( !Image_ValidSize( name )) return false;
image.type = PF_RGBA_32; // always exctracted to 32-bit buffer
if( targa_header.image_type == 1 || targa_header.image_type == 9 )
{
// uncompressed colormapped image
if( targa_header.pixel_size != 8 )
{
Con_DPrintf( S_ERROR "Image_LoadTGA: (%s) Only 8 bit images supported for type 1 and 9\n", name );
return false;
}
if( targa_header.colormap_length != 256 )
{
Con_DPrintf( S_ERROR "Image_LoadTGA: (%s) Only 8 bit colormaps are supported for type 1 and 9\n", name );
return false;
}
if( targa_header.colormap_index )
{
Con_DPrintf( S_ERROR "Image_LoadTGA: (%s) colormap_index is not supported for type 1 and 9\n", name );
return false;
}
if( targa_header.colormap_size == 24 )
{
for( i = 0; i < targa_header.colormap_length; i++ )
{
palette[i][2] = *buf_p++;
palette[i][1] = *buf_p++;
palette[i][0] = *buf_p++;
palette[i][3] = 255;
}
}
else if( targa_header.colormap_size == 32 )
{
for( i = 0; i < targa_header.colormap_length; i++ )
{
palette[i][2] = *buf_p++;
palette[i][1] = *buf_p++;
palette[i][0] = *buf_p++;
palette[i][3] = *buf_p++;
}
}
else
{
Con_DPrintf( S_ERROR "Image_LoadTGA: (%s) only 24 and 32 bit colormaps are supported for type 1 and 9\n", name );
return false;
}
}
else if( targa_header.image_type == 2 || targa_header.image_type == 10 )
{
// uncompressed or RLE compressed RGB
if( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 )
{
Con_DPrintf( S_ERROR "Image_LoadTGA: (%s) Only 32 or 24 bit images supported for type 2 and 10\n", name );
return false;
}
}
else if( targa_header.image_type == 3 || targa_header.image_type == 11 )
{
// uncompressed greyscale
if( targa_header.pixel_size != 8 && targa_header.pixel_size != 16 )
{
Con_DPrintf( S_ERROR "Image_LoadTGA: (%s) Only 8 bit images supported for type 3 and 11\n", name );
return false;
}
}
columns = targa_header.width;
rows = targa_header.height;
image.size = image.width * image.height * 4;
targa_rgba = image.rgba = Mem_Malloc( host.imagepool, image.size );
// if bit 5 of attributes isn't set, the image has been stored from bottom to top
if( !Image_CheckFlag( IL_DONTFLIP_TGA ) && targa_header.attributes & 0x20 )
{
pixbuf = targa_rgba;
row_inc = 0;
}
else
{
pixbuf = targa_rgba + ( rows - 1 ) * columns * 4;
row_inc = -columns * 4 * 2;
}
compressed = ( targa_header.image_type == 9 || targa_header.image_type == 10 || targa_header.image_type == 11 );
for( row = col = 0; row < rows; )
{
pixelcount = 0x10000;
readpixelcount = 0x10000;
if( compressed )
{
pixelcount = *buf_p++;
if( pixelcount & 0x80 ) // run-length packet
readpixelcount = 1;
pixelcount = 1 + ( pixelcount & 0x7f );
}
while( pixelcount-- && ( row < rows ) )
{
if( readpixelcount-- > 0 )
{
switch( targa_header.image_type )
{
case 1:
case 9:
// colormapped image
blue = *buf_p++;
if( blue < targa_header.colormap_length )
{
red = palette[blue][0];
green = palette[blue][1];
alpha = palette[blue][3];
blue = palette[blue][2];
if( alpha != 255 ) image.flags |= IMAGE_HAS_ALPHA;
}
break;
case 2:
case 10:
// 24 or 32 bit image
blue = *buf_p++;
green = *buf_p++;
red = *buf_p++;
alpha = 255;
if( targa_header.pixel_size == 32 )
{
alpha = *buf_p++;
if( alpha != 255 )
image.flags |= IMAGE_HAS_ALPHA;
}
break;
case 3:
case 11:
// greyscale image
blue = green = red = *buf_p++;
if( targa_header.pixel_size == 16 )
{
alpha = *buf_p++;
if( alpha != 255 )
image.flags |= IMAGE_HAS_ALPHA;
}
else
alpha = 255;
break;
}
}
if( red != green || green != blue )
image.flags |= IMAGE_HAS_COLOR;
reflectivity[0] += red;
reflectivity[1] += green;
reflectivity[2] += blue;
*pixbuf++ = red;
*pixbuf++ = green;
*pixbuf++ = blue;
*pixbuf++ = alpha;
if( ++col == columns )
{
// run spans across rows
row++;
col = 0;
pixbuf += row_inc;
}
}
}
VectorDivide( reflectivity, ( image.width * image.height ), image.fogParams );
image.depth = 1;
return true;
}
/*
=============
Image_SaveTGA
=============
*/
qboolean Image_SaveTGA( const char *name, rgbdata_t *pix )
{
int y, outsize, pixel_size;
const uint8_t *bufend, *in;
uint8_t *buffer, *out;
tga_t targa_header = {0};
const char comment[] = "Generated by Xash ImageLib";
if( FS_FileExists( name, false ) && !Image_CheckFlag( IL_ALLOW_OVERWRITE ))
return false; // already existed
// bogus parameter check
if( !pix->buffer )
return false;
// get image description
switch( pix->type )
{
case PF_RGB_24:
case PF_BGR_24: pixel_size = 3; break;
case PF_RGBA_32:
case PF_BGRA_32: pixel_size = 4; break;
default:
return false;
}
outsize = pix->width * pix->height * pixel_size;
outsize += sizeof( tga_t );
outsize += sizeof( comment ) - 1;
buffer = (uint8_t *)Mem_Malloc( host.imagepool, outsize );
// prepare header
targa_header.id_length = sizeof( comment ) - 1; // tga comment length
targa_header.image_type = 2; // uncompressed type
targa_header.width = pix->width;
targa_header.height = pix->height;
if( pix->flags & IMAGE_HAS_ALPHA )
{
targa_header.pixel_size = 32;
targa_header.attributes = 8; // 8 bits of alpha
}
else
{
targa_header.pixel_size = 24;
targa_header.attributes = 0;
}
out = buffer;
memcpy( out, &targa_header, sizeof( tga_t ) );
out += sizeof( tga_t );
memcpy( out, comment, sizeof( comment ) - 1 );
out += sizeof( comment ) - 1;
switch( pix->type )
{
case PF_RGB_24:
case PF_RGBA_32:
// swap rgba to bgra and flip upside down
for( y = pix->height - 1; y >= 0; y-- )
{
in = pix->buffer + y * pix->width * pixel_size;
bufend = in + pix->width * pixel_size;
for( ; in < bufend; in += pixel_size )
{
*out++ = in[2];
*out++ = in[1];
*out++ = in[0];
if( pix->flags & IMAGE_HAS_ALPHA )
*out++ = in[3];
}
}
break;
case PF_BGR_24:
case PF_BGRA_32:
// flip upside down
for( y = pix->height - 1; y >= 0; y-- )
{
in = pix->buffer + y * pix->width * pixel_size;
bufend = in + pix->width * pixel_size;
for( ; in < bufend; in += pixel_size )
{
*out++ = in[0];
*out++ = in[1];
*out++ = in[2];
if( pix->flags & IMAGE_HAS_ALPHA )
*out++ = in[3];
}
}
break;
}
FS_WriteFile( name, buffer, outsize );
Mem_Free( buffer );
return true;
}