quakeforge/libs/util/tga.c

250 lines
5.9 KiB
C
Raw Normal View History

2001-05-11 01:01:27 +00:00
/*
tga.c
targa image handling
Copyright (C) 1996-1997 Id Software, Inc.
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 2
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.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static __attribute__ ((unused)) const char rcsid[] =
"$Id$";
2001-05-11 01:01:27 +00:00
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#include "QF/qendian.h"
#include "QF/quakefs.h"
2001-05-11 01:01:27 +00:00
#include "QF/sys.h"
#include "QF/texture.h"
2001-05-11 01:01:27 +00:00
#include "QF/tga.h"
2001-12-21 06:07:30 +00:00
#include "QF/zone.h"
2001-05-11 01:01:27 +00:00
#include "compat.h"
2001-05-11 01:01:27 +00:00
static inline byte *
blit_rgb (byte *buf, int count, byte red, byte green, byte blue)
{
while (count--) {
*buf++ = red;
*buf++ = green;
*buf++ = blue;
*buf++ = 255;
}
return buf;
}
static inline byte *
blit_rgba (byte *buf, int count, byte red, byte green, byte blue, byte alpha)
{
while (count--) {
*buf++ = red;
*buf++ = green;
*buf++ = blue;
*buf++ = alpha;
}
return buf;
}
static inline byte *
2001-12-21 06:07:30 +00:00
read_bgr (byte *buf, int count, byte **data)
{
byte blue = *(*data)++;
byte green = *(*data)++;
byte red = *(*data)++;
return blit_rgb (buf, count, red, green, blue);
}
static inline byte *
2001-12-21 06:07:30 +00:00
read_rgb (byte *buf, int count, byte **data)
{
byte red = *(*data)++;
byte green = *(*data)++;
byte blue = *(*data)++;
return blit_rgb (buf, count, red, green, blue);
}
static inline byte *
2001-12-21 06:07:30 +00:00
read_bgra (byte *buf, int count, byte **data)
{
byte blue = *(*data)++;
byte green = *(*data)++;
byte red = *(*data)++;
byte alpha = *(*data)++;
return blit_rgba (buf, count, red, green, blue, alpha);
}
static inline byte *
2001-12-21 06:07:30 +00:00
read_rgba (byte *buf, int count, byte **data)
{
byte red = *(*data)++;
byte green = *(*data)++;
byte blue = *(*data)++;
byte alpha = *(*data)++;
return blit_rgba (buf, count, red, green, blue, alpha);
}
struct tex_s *
LoadTGA (QFile *fin)
2001-05-11 01:01:27 +00:00
{
2001-12-21 06:07:30 +00:00
byte *dataByte, *pixcol, *pixrow;
2002-08-25 04:47:57 +00:00
int column, row, columns, rows, numPixels, span, targa_mark;
2001-12-21 06:07:30 +00:00
TargaHeader *targa;
tex_t *tex;
targa_mark = Hunk_LowMark ();
targa = Hunk_AllocName (com_filesize, "TGA");
Qread (fin, targa, com_filesize);
targa->colormap_index = LittleShort (targa->colormap_index);
targa->colormap_length = LittleShort (targa->colormap_length);
targa->x_origin = LittleShort (targa->x_origin);
targa->y_origin = LittleShort (targa->y_origin);
targa->width = LittleShort (targa->width);
targa->height = LittleShort (targa->height);
if (targa->image_type != 2 && targa->image_type != 10)
Sys_Error ("LoadTGA: Only type 2 and 10 targa RGB images supported");
2001-05-11 01:01:27 +00:00
2001-12-21 06:07:30 +00:00
if (targa->colormap_type != 0
|| (targa->pixel_size != 32 && targa->pixel_size != 24))
Sys_Error ("Texture_LoadTGA: Only 32 or 24 bit images supported "
"(no colormaps)");
2001-05-11 01:01:27 +00:00
2001-12-21 06:07:30 +00:00
columns = targa->width;
rows = targa->height;
2001-05-11 01:01:27 +00:00
numPixels = columns * rows;
2001-12-21 06:07:30 +00:00
switch (targa->pixel_size) {
case 24:
tex = Hunk_TempAlloc (field_offset (tex_t, data[numPixels * 4]));
2001-12-21 06:07:30 +00:00
tex->format = tex_rgb;
break;
default:
case 32:
2001-12-21 06:07:30 +00:00
tex = Hunk_TempAlloc (field_offset (tex_t, data[numPixels * 4]));
tex->format = tex_rgba;
break;
}
2001-12-21 06:07:30 +00:00
tex->width = columns;
tex->height = rows;
tex->palette = 0;
// skip TARGA image comment
dataByte = (byte *) (targa + 1);
2001-12-21 06:07:30 +00:00
dataByte += targa->id_length;
2001-05-11 01:01:27 +00:00
span = columns * 4; // tex->format
2001-12-21 06:07:30 +00:00
pixrow = tex->data + (rows - 1) * span;
2001-05-11 01:01:27 +00:00
2001-12-21 06:07:30 +00:00
if (targa->image_type == 2) { // Uncompressed image
switch (targa->pixel_size) {
case 24:
for (row = rows - 1; row >= 0; row--, pixrow -= span) {
pixcol = pixrow;
for (column = 0; column < columns; column++)
2001-12-21 06:07:30 +00:00
pixcol = read_bgr (pixcol, 1, &dataByte);
}
break;
case 32:
for (row = rows - 1; row >= 0; row--, pixrow -= span) {
pixcol = pixrow;
for (column = 0; column < columns; column++)
2001-12-21 06:07:30 +00:00
pixcol = read_bgra (pixcol, 1, &dataByte);
2001-05-11 01:01:27 +00:00
}
break;
2001-05-11 01:01:27 +00:00
}
2001-12-21 06:07:30 +00:00
} else if (targa->image_type == 10) { // RLE compressed image
unsigned char packetHeader, packetSize;
2001-05-11 01:01:27 +00:00
byte *(*expand) (byte *buf, int count, byte **data);
2001-12-21 06:07:30 +00:00
if (targa->pixel_size == 24)
expand = read_bgr;
else
expand = read_bgra;
for (row = rows - 1; row >= 0; row--, pixrow -= span) {
pixcol = pixrow;
2001-05-11 01:01:27 +00:00
for (column = 0; column < columns;) {
2001-12-21 06:07:30 +00:00
packetHeader = *dataByte++;
2001-05-11 01:01:27 +00:00
packetSize = 1 + (packetHeader & 0x7f);
while (packetSize > columns - column) {
int count = columns - column;
packetSize -= count;
if (packetHeader & 0x80) { // run-length packet
2001-12-21 06:07:30 +00:00
expand (pixcol, count, &dataByte);
} else { // non run-length packet
while (count--)
2001-12-21 06:07:30 +00:00
expand (pixcol, 1, &dataByte);
2001-05-11 01:01:27 +00:00
}
column = 0;
pixcol = (pixrow -= span);
if (--row < 0)
goto done;
}
column += packetSize;
if (packetHeader & 0x80) { // run-length packet
2001-12-21 06:07:30 +00:00
pixcol = expand (pixcol, packetSize, &dataByte);
} else { // non run-length packet
while (packetSize--)
2001-12-21 06:07:30 +00:00
pixcol = expand (pixcol, 1, &dataByte);
2001-05-11 01:01:27 +00:00
}
}
}
done:;
2001-05-11 01:01:27 +00:00
}
2001-12-21 06:07:30 +00:00
Hunk_FreeToLowMark (targa_mark);
return tex;
2001-05-11 01:01:27 +00:00
}
void
WriteTGAfile (const char *tganame, byte *data, int width, int height)
{
TargaHeader header;
memset (&header, 0, sizeof (header));
header.image_type = 2; // uncompressed type
header.width = LittleShort (width);
header.height = LittleShort (height);
header.pixel_size = 24;
COM_WriteBuffers (tganame, 2, &header, sizeof (header), data,
width * height * 3);
}