diff --git a/include/pcx.h b/include/pcx.h new file mode 100644 index 000000000..9a989d65e --- /dev/null +++ b/include/pcx.h @@ -0,0 +1,55 @@ +/* + pcx.h + + pcx image hangling + + 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 + + $Id$ +*/ + +#ifndef __pcx_h +#define __pcx_h + +#include "quakeio.h" + +typedef struct +{ + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin, ymin, xmax, ymax; + unsigned short hres, vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; +} pcx_t; + +void WritePCXfile (char *filename, byte * data, int width, int height, + int rowbytes, byte * palette, qboolean upload, + qboolean flip); +struct tex_s *LoadPCX (QFile *f, int convert); // tex is from Hunk_TempAlloc + +#endif // __pcx_h diff --git a/include/tga.h b/include/tga.h new file mode 100644 index 000000000..3e7f3775d --- /dev/null +++ b/include/tga.h @@ -0,0 +1,74 @@ +/* + tga.h + + targa image hangling + + 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 + + $Id$ +*/ + +#ifndef __tga_h +#define __tga_h + +#include "gcc_attr.h" +#include "qtypes.h" + +#ifndef __GNUC__ +# if defined (__BORLANDC__) || defined (_MSC_VER) +# if (defined(__BORLANDC__) && (__BORLANDC__ < 0x550)) +# pragma option -a1 +# else +# pragma pack(push, tgainclude) +# pragma pack(1) +# endif +# else +# error do some data packing magic here (#pragma pack?) +# endif +#endif + +typedef struct _TargaHeader { + unsigned char id_length __attribute__((packed)); + unsigned char colormap_type __attribute__((packed)); + unsigned char image_type __attribute__((packed)); + unsigned short colormap_index __attribute__((packed)); + unsigned short colormap_length __attribute__((packed)); + unsigned char colormap_size __attribute__((packed)); + unsigned short x_origin __attribute__((packed)); + unsigned short y_origin __attribute__((packed)); + unsigned short width __attribute__((packed)); + unsigned short height __attribute__((packed)); + unsigned char pixel_size __attribute__((packed)); + unsigned char attributes __attribute__((packed)); +} TargaHeader; + +#if defined (__BORLANDC__) || defined (_MSC_VER) +# if (defined(__BORLANDC__) && (__BORLANDC__ < 0x550)) +# pragma option -a4 +# else +# pragma pack(pop, tgainclude) +# endif +#endif + +byte *LoadTGA (QFile *fin); +void WriteTGAfile (const char *tganame, byte *data, int width, int height); + +#endif // __tga_h diff --git a/libs/models/texture/pcx.c b/libs/models/texture/pcx.c new file mode 100644 index 000000000..ecc877e1b --- /dev/null +++ b/libs/models/texture/pcx.c @@ -0,0 +1,216 @@ +/* + pcx.c + + pcx 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 + + $Id$ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "cl_parse.h" +#include "console.h" +#include "host.h" +#include "pcx.h" +#include "qendian.h" +#include "qtypes.h" +#include "quakefs.h" +#include "texture.h" +#include "zone.h" + +/* + LoadPCX +*/ +tex_t * +LoadPCX (QFile *f, int convert) +{ + pcx_t *pcx; + int pcx_mark; + byte *palette; + byte *pix; + byte *dataByte; + int x, y; + int runLength = 1; + int count; + tex_t *tex; + + // + // parse the PCX file + // + pcx_mark = Hunk_LowMark (); + pcx = Hunk_AllocName (com_filesize, "PCX"); + Qread (f, pcx, com_filesize); + + pcx->xmax = LittleShort (pcx->xmax); + pcx->xmin = LittleShort (pcx->xmin); + pcx->ymax = LittleShort (pcx->ymax); + pcx->ymin = LittleShort (pcx->ymin); + pcx->hres = LittleShort (pcx->hres); + pcx->vres = LittleShort (pcx->vres); + pcx->bytes_per_line = LittleShort (pcx->bytes_per_line); + pcx->palette_type = LittleShort (pcx->palette_type); + + if (pcx->manufacturer != 0x0a + || pcx->version != 5 + || pcx->encoding != 1 + || pcx->bits_per_pixel != 8 || pcx->xmax >= 320 || pcx->ymax >= 256) { + Con_Printf ("Bad pcx file\n"); + return 0; + } + + palette = ((byte*)pcx) + com_filesize - 768; + dataByte = (byte*)&pcx[1]; + + count = (pcx->xmax + 1) * (pcx->ymax + 1); + if (convert) + count *= 4; + tex = Hunk_TempAlloc (sizeof (tex_t) + count); + tex->width = pcx->xmax + 1; + tex->height = pcx->ymax + 1; + if (convert) { + tex->palette = 0; + } else { + tex->palette = host_basepal; + } + pix = tex->data; + + for (y = 0; y < tex->height; y++) { + for (x = 0; x < tex->width;) { + runLength = 1; + if (dataByte >= palette) + break; + + if ((*dataByte & 0xC0) == 0xC0) { + runLength = *dataByte++ & 0x3F; + if (dataByte >= palette) + break; + } + + if (convert) { + while (count && runLength > 0) { + pix[0] = palette[*dataByte * 3]; + pix[1] = palette[*dataByte * 3 + 1]; + pix[2] = palette[*dataByte * 3 + 2]; + pix[3] = 255; + pix += 4; + count -= 4; + runLength--; + x++; + } + } else { + while (count && runLength > 0) { + *pix++ = *dataByte; + count--; + runLength--; + x++; + } + } + if (runLength) + break; + dataByte++; + } + if (runLength) + break; + } + Hunk_FreeToLowMark (pcx_mark); + if (count || runLength) { + Con_Printf ("PCX was malformed. You should delete it.\n"); + return 0; + } + return tex; +} + +/* + WritePCXfile +*/ +void +WritePCXfile (char *filename, byte * data, int width, int height, + int rowbytes, byte * palette, qboolean upload, qboolean flip) +{ + int i, j, length; + pcx_t *pcx; + byte *pack; + + if (!(pcx = Hunk_TempAlloc (width * height * 2 + 1000))) { + Con_Printf ("WritePCXfile: not enough memory\n"); + return; + } + + pcx->manufacturer = 0x0a; // PCX id + pcx->version = 5; // 256 color + pcx->encoding = 1; // uncompressed + pcx->bits_per_pixel = 8; // 256 color + pcx->xmin = 0; + pcx->ymin = 0; + pcx->xmax = LittleShort ((short) (width - 1)); + pcx->ymax = LittleShort ((short) (height - 1)); + pcx->hres = LittleShort ((short) width); + pcx->vres = LittleShort ((short) height); + memset (pcx->palette, 0, sizeof (pcx->palette)); + pcx->color_planes = 1; // chunky image + pcx->bytes_per_line = LittleShort ((short) width); + pcx->palette_type = LittleShort (2); // not a grey scale + memset (pcx->filler, 0, sizeof (pcx->filler)); + + // pack the image + pack = (byte*)&pcx[1]; + + if (flip) + data += rowbytes * (height - 1); + + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + if ((*data & 0xc0) != 0xc0) + *pack++ = *data++; + else { + *pack++ = 0xc1; + *pack++ = *data++; + } + } + + data += rowbytes - width; + if (flip) + data -= rowbytes * 2; + } + + // write the palette + *pack++ = 0x0c; // palette ID byte + for (i = 0; i < 768; i++) + *pack++ = *palette++; + + // write output file + length = pack - (byte *) pcx; + + if (upload) + CL_StartUpload ((void *) pcx, length); + else + COM_WriteFile (filename, pcx, length); +} diff --git a/libs/models/texture/tga.c b/libs/models/texture/tga.c new file mode 100644 index 000000000..3115818a6 --- /dev/null +++ b/libs/models/texture/tga.c @@ -0,0 +1,242 @@ +/* + 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 + + $Id$ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "qendian.h" +#include "quakefs.h" +#include "sys.h" +#include "tga.h" + +static int +fgetLittleShort (QFile *f) +{ + byte b1, b2; + + b1 = Qgetc (f); + b2 = Qgetc (f); + + return (short) (b1 + b2 * 256); +} + +/* +static int +fgetLittleLong (QFile *f) +{ + byte b1, b2, b3, b4; + + b1 = Qgetc(f); + b2 = Qgetc(f); + b3 = Qgetc(f); + b4 = Qgetc(f); + + return b1 + (b2<<8) + (b3<<16) + (b4<<24); +} +*/ + + +/* + LoadTGA +*/ +byte * +LoadTGA (QFile *fin) +{ + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + unsigned char red = 0, green = 0, blue = 0, alphabyte = 0; + + TargaHeader targa_header; + byte *targa_rgba; + + targa_header.id_length = Qgetc (fin); + targa_header.colormap_type = Qgetc (fin); + targa_header.image_type = Qgetc (fin); + + targa_header.colormap_index = fgetLittleShort (fin); + targa_header.colormap_length = fgetLittleShort (fin); + targa_header.colormap_size = Qgetc (fin); + targa_header.x_origin = fgetLittleShort (fin); + targa_header.y_origin = fgetLittleShort (fin); + targa_header.width = fgetLittleShort (fin); + targa_header.height = fgetLittleShort (fin); + targa_header.pixel_size = Qgetc (fin); + targa_header.attributes = Qgetc (fin); + + if (targa_header.image_type != 2 && targa_header.image_type != 10) + Sys_Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n"); + + if (targa_header.colormap_type != 0 + || (targa_header.pixel_size != 32 && targa_header.pixel_size != 24)) + Sys_Error + ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + targa_rgba = malloc (numPixels * 4); + + if (targa_header.id_length != 0) + Qseek (fin, targa_header.id_length, SEEK_CUR); // skip TARGA image + // comment + + if (targa_header.image_type == 2) { // Uncompressed, RGB images + for (row = rows - 1; row >= 0; row--) { + pixbuf = targa_rgba + row * columns * 4; + for (column = 0; column < columns; column++) { + switch (targa_header.pixel_size) { + case 24: + + blue = Qgetc (fin); + green = Qgetc (fin); + red = Qgetc (fin); + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = Qgetc (fin); + green = Qgetc (fin); + red = Qgetc (fin); + alphabyte = Qgetc (fin); + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + } + } + } + } else if (targa_header.image_type == 10) { // Runlength encoded RGB + // images + unsigned char packetHeader, packetSize, j; + + for (row = rows - 1; row >= 0; row--) { + pixbuf = targa_rgba + row * columns * 4; + for (column = 0; column < columns;) { + packetHeader = Qgetc (fin); + packetSize = 1 + (packetHeader & 0x7f); + if (packetHeader & 0x80) { // run-length packet + switch (targa_header.pixel_size) { + case 24: + blue = Qgetc (fin); + green = Qgetc (fin); + red = Qgetc (fin); + alphabyte = 255; + break; + case 32: + blue = Qgetc (fin); + green = Qgetc (fin); + red = Qgetc (fin); + alphabyte = Qgetc (fin); + 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 = targa_rgba + row * columns * 4; + } + } + } else { // non run-length packet + for (j = 0; j < packetSize; j++) { + switch (targa_header.pixel_size) { + case 24: + blue = Qgetc (fin); + green = Qgetc (fin); + red = Qgetc (fin); + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = Qgetc (fin); + green = Qgetc (fin); + red = Qgetc (fin); + alphabyte = Qgetc (fin); + *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 = targa_rgba + row * columns * 4; + } + } + } + } + breakOut:; + } + } + + Qclose (fin); + return targa_rgba; +} + +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); +}