596 lines
14 KiB
C
596 lines
14 KiB
C
/*
|
|
* Copyright (c) 1993-1995 by Argonaut Technologies Limited. All rights reserved.
|
|
*
|
|
* $Id: loadtga.c 1.5 1995/08/31 16:28:20 sam Exp $
|
|
* $Locker: $
|
|
*
|
|
* Loader for .TGA format
|
|
* support for: 8 bit index palette based (16,24 bit palette)
|
|
* 15,16,24,32 bit true colour
|
|
* 15 & 16 bit are the same except for 1 field in header. (bits)
|
|
* mono (1 bit) bit not supported here
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
#include "brender.h"
|
|
#include "fmt.h"
|
|
#include "fw.h"
|
|
|
|
static char rscid[] = "$Id: loadtga.c 1.5 1995/08/31 16:28:20 sam Exp $";
|
|
|
|
#define RED 2
|
|
#define GRN 1
|
|
#define BLU 0
|
|
#define PAD 3
|
|
|
|
#define YES 1
|
|
#define NO 0
|
|
|
|
static void * ReadLine_Uncomp_8(char *line,void *fh); /* 8 bit indexed, uncompressed */
|
|
static void * ReadLine_Comp_8(char *line,void *fh); /* 8 bit indexed, compressed */
|
|
|
|
static void * ReadLine_Uncomp_16(char *line,void *fh); /* 16 bit, uncompressed */
|
|
static void * ReadLine_Comp_16(char *line,void *fh); /* 16 bit, compressed */
|
|
|
|
static void * ReadLine_Uncomp_24(char *line,void *fh); /* 24 bit, uncompressed */
|
|
static void * ReadLine_Comp_24(char *line,void *fh); /* 24 bit, compressed */
|
|
|
|
static void * ReadLine_Uncomp_32(char *line,void *fh); /* 32 bit, uncompressed */
|
|
static void * ReadLine_Comp_32(char *line,void *fh); /* 32 bit, compressed */
|
|
|
|
static void CopyLine_8(br_pixelmap *pm,char *line,int row);
|
|
static void CopyLine_16(br_pixelmap *pm,char *line,int row);
|
|
static void CopyLine_24(br_pixelmap *pm,char *line,int row);
|
|
static void CopyLine_32(br_pixelmap *pm,char *line,int row);
|
|
|
|
enum {
|
|
BR_TGA_UNCOMPRESSED_PALETTE = 0x01,
|
|
BR_TGA_UNCOMPRESSED_RGB = 0x02,
|
|
BR_TGA_UNCOMPRESSED_MONO = 0x03, /* not supported here */
|
|
BR_TGA_COMPRESSED_PALETTE = 0x09,
|
|
BR_TGA_COMPRESSED_RGB = 0x0a,
|
|
BR_TGA_COMPRESSED_MONO = 0x0b /* not supported here */
|
|
};
|
|
|
|
enum {
|
|
BR_TGA_REVERSED_WIDTH = 0x10, /* right to left */
|
|
BR_TGA_REVERSED_DEPTH = 0x20 /* bottom to top */
|
|
};
|
|
|
|
static struct {
|
|
|
|
char image_type;
|
|
char pixel_bits;
|
|
char supported;
|
|
void * (*read_func)(char *line,void *fh); /* read 1 line of image data from file */
|
|
void (*copy_func)(br_pixelmap *map,char *line,int row); /* copy 1 line of data to pixelmap */
|
|
|
|
} Supported_TGA_types[]={
|
|
|
|
{BR_TGA_UNCOMPRESSED_PALETTE , 8, YES, ReadLine_Uncomp_8, CopyLine_8},
|
|
{BR_TGA_UNCOMPRESSED_RGB , 15, YES, ReadLine_Uncomp_16, CopyLine_16},
|
|
{BR_TGA_UNCOMPRESSED_RGB , 16, YES, ReadLine_Uncomp_16, CopyLine_16},
|
|
{BR_TGA_UNCOMPRESSED_RGB , 24, YES, ReadLine_Uncomp_24, CopyLine_24},
|
|
{BR_TGA_UNCOMPRESSED_RGB , 32, YES, ReadLine_Uncomp_32, CopyLine_32},
|
|
{BR_TGA_UNCOMPRESSED_MONO , 1, NO, NULL, NULL},
|
|
{BR_TGA_COMPRESSED_PALETTE , 8, YES, ReadLine_Comp_8, CopyLine_8},
|
|
{BR_TGA_COMPRESSED_RGB , 15, YES, ReadLine_Comp_16, CopyLine_16},
|
|
{BR_TGA_COMPRESSED_RGB , 16, YES, ReadLine_Comp_16, CopyLine_16},
|
|
{BR_TGA_COMPRESSED_RGB , 24, YES, ReadLine_Comp_24, CopyLine_24},
|
|
{BR_TGA_COMPRESSED_RGB , 32, YES, ReadLine_Comp_32, CopyLine_32},
|
|
{BR_TGA_COMPRESSED_MONO , 1, NO, NULL, NULL},
|
|
};
|
|
|
|
/*
|
|
* TGA header, this format allows for structure packing by compiler
|
|
*/
|
|
#pragma pack(1)
|
|
|
|
static struct {
|
|
char identsize; /* number of bytes between header and whatever next */
|
|
char colourmaptype; /* type of colourmap in file 0=RGB, 1=palette */
|
|
char imagetype; /* type of storage of image */
|
|
unsigned short colourmapstart; /* first colour index used in palette */
|
|
unsigned short colourmaplength; /* number of colours in palette from colourmapstart */
|
|
char colourmapbits; /* size of entry in palette table */
|
|
unsigned short xstart; /* offset between uppr lft of image & uppr lft of screen*/
|
|
unsigned short ystart;
|
|
unsigned short width; /* width in pixels */
|
|
unsigned short depth; /* depth in pixels */
|
|
char bits; /* number of bits of colour: 1,8,16,24,32 */
|
|
char descriptor; /* bit 5 : set, image stored starting with last line */
|
|
/* bit 4 : set, image stored pixels right to left */
|
|
/* bits 0-3: number of bits available for overlays (n/a)*/
|
|
} TGAheader;
|
|
|
|
static unsigned short RGB_16;
|
|
static struct {
|
|
char blue,green,red;
|
|
} RGB_24;
|
|
static struct {
|
|
char blue,green,red,x;
|
|
} RGB_32;
|
|
|
|
#pragma pack()
|
|
|
|
br_pixelmap * BR_PUBLIC_ENTRY BrFmtTGALoad(char *name,br_uint_32 flags)
|
|
{
|
|
void *fh;
|
|
int open_mode = BR_FS_MODE_BINARY,i;
|
|
br_pixelmap *pm;
|
|
|
|
br_uint_8 type;
|
|
br_uint_32 ystart,yend,dy,xstart,xend,dx;
|
|
br_uint_32 bytes_per_line,palette_size;
|
|
|
|
char *mblock,supported;
|
|
|
|
fh = BrFileOpenRead(name,0,NULL,&open_mode);
|
|
|
|
if(fh == NULL)
|
|
BR_ERROR1("Could not open '%s' for reading",name);
|
|
|
|
if(BrFileRead(&TGAheader,1,sizeof(TGAheader),fh) !=sizeof(TGAheader))
|
|
BR_ERROR1("Unable to read header information from '%s'",name);
|
|
|
|
for(i=0,supported=255; i<BR_ASIZE(Supported_TGA_types); i++)
|
|
if((Supported_TGA_types[i].image_type == TGAheader.imagetype) &
|
|
(Supported_TGA_types[i].pixel_bits == TGAheader.bits) &&
|
|
(Supported_TGA_types[i].supported))
|
|
supported=i;
|
|
|
|
if(supported == 255)
|
|
BR_ERROR2("TGA image type %d in file '%s' not supported",TGAheader.imagetype,name);
|
|
|
|
switch(TGAheader.bits)
|
|
{
|
|
case(8):type = BR_PMT_INDEX_8;
|
|
bytes_per_line = TGAheader.width;
|
|
palette_size = TGAheader.colourmaplength;
|
|
break;
|
|
|
|
case(15):type = BR_PMT_RGB_555;
|
|
bytes_per_line = TGAheader.width*2;
|
|
palette_size = 0;
|
|
break;
|
|
|
|
case(16):type = BR_PMT_RGB_565;
|
|
bytes_per_line = TGAheader.width*2;
|
|
palette_size = 0;
|
|
break;
|
|
|
|
case(24):type = BR_PMT_RGB_888;
|
|
bytes_per_line = TGAheader.width*3;
|
|
palette_size = 0;
|
|
break;
|
|
case(32):/*
|
|
* If flags & BR_PMT_RGBA_8888, pixelmap->type = flags
|
|
*/
|
|
|
|
|
|
type = (flags & BR_PMT_RGBA_8888)?BR_PMT_RGBA_8888:BR_PMT_RGBX_888;
|
|
bytes_per_line = TGAheader.width*4;
|
|
palette_size = 0;
|
|
break;
|
|
|
|
default:BR_ERROR2("%d bit TGA file '%s' not supported",TGAheader.bits,name);
|
|
break;
|
|
}
|
|
|
|
if(!(TGAheader.descriptor & BR_TGA_REVERSED_DEPTH))
|
|
{
|
|
ystart = TGAheader.depth-1;
|
|
yend = -1;
|
|
dy = -1;
|
|
}
|
|
else
|
|
{
|
|
ystart = 0;
|
|
yend = TGAheader.depth;
|
|
dy = 1;
|
|
}
|
|
|
|
/*
|
|
* Advance to start of palette/image, allocate pixelmap for image data
|
|
*/
|
|
|
|
BrFileAdvance(TGAheader.identsize,fh);
|
|
pm = BrPixelmapAllocate(type,TGAheader.width,TGAheader.depth,NULL,0);
|
|
|
|
pm->identifier=BrResStrDup(pm,name);
|
|
|
|
/*
|
|
* Get palette,allocate pixelmap for palette data
|
|
*/
|
|
|
|
if(TGAheader.colourmaptype)
|
|
{
|
|
switch(TGAheader.bits)
|
|
{
|
|
/*
|
|
* Allow for nasties that have true colour image with palette
|
|
*/
|
|
|
|
default:BrFileAdvance(TGAheader.colourmaplength * (( TGAheader.colourmapbits ) >> 3),fh);
|
|
break;
|
|
|
|
case(8):pm->map = BrPixelmapAllocate(BR_PMT_RGBX_888,1,256,NULL,0);
|
|
|
|
pm->map->identifier=BrResStrDup(pm->map,name);
|
|
|
|
switch(TGAheader.colourmapbits)
|
|
{
|
|
case(16):for(i=TGAheader.colourmapstart; i<TGAheader.colourmaplength; i++)
|
|
{
|
|
if(i >= 256) break;
|
|
if(BrFileRead(&RGB_16,1,sizeof(RGB_16),fh) != sizeof(RGB_16))
|
|
BR_ERROR1("Unable to read palette from '%s'",name);
|
|
|
|
((char *)(pm->map->pixels))[i*4+RED] = ((RGB_16 ) & 0x1f) << 3;
|
|
((char *)(pm->map->pixels))[i*4+GRN] = ((RGB_16 >> 5 ) & 0x1f) << 3;
|
|
((char *)(pm->map->pixels))[i*4+BLU] = ((RGB_16 >> 10) & 0x1f) << 3;
|
|
((char *)(pm->map->pixels))[i*4+PAD] = 0;
|
|
}
|
|
break;
|
|
|
|
case(24):for(i=TGAheader.colourmapstart; i<TGAheader.colourmaplength; i++)
|
|
{
|
|
if(i >= 256) break;
|
|
if(BrFileRead(&RGB_24,1,sizeof(RGB_24),fh) != sizeof(RGB_24))
|
|
BR_ERROR1("Unable to read palette from '%s'",name);
|
|
|
|
((char *)(pm->map->pixels))[i*4+RED] = RGB_24.red;
|
|
((char *)(pm->map->pixels))[i*4+GRN] = RGB_24.green;
|
|
((char *)(pm->map->pixels))[i*4+BLU] = RGB_24.blue;
|
|
((char *)(pm->map->pixels))[i*4+PAD] = 0;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get image data
|
|
*/
|
|
|
|
mblock = BrMemAllocate(bytes_per_line,BR_MEMORY_SCRATCH);
|
|
|
|
for(i=ystart; i!=yend; i+=dy)
|
|
{
|
|
if(Supported_TGA_types[supported].read_func(mblock,fh) == NULL)
|
|
BR_ERROR1("Unable to read image data from '%s'",name);
|
|
|
|
Supported_TGA_types[supported].copy_func(pm,mblock,i);
|
|
}
|
|
|
|
BrFileClose(fh);
|
|
|
|
return pm;
|
|
}
|
|
|
|
static void *ReadLine_Uncomp_8(char *line,void *fh)
|
|
{
|
|
if(BrFileRead(line,1,TGAheader.width,fh) != TGAheader.width)
|
|
return NULL;
|
|
else
|
|
return line;
|
|
}
|
|
static void * ReadLine_Comp_8(char *line,void *fh)
|
|
{
|
|
unsigned char ch;
|
|
br_uint_32 size,n = 0;
|
|
int i;
|
|
|
|
do
|
|
{
|
|
if(BrFileRead(&ch,1,1,fh) != 1)
|
|
return NULL;
|
|
size = (ch & 0x7f)+1;
|
|
|
|
if(ch & 0x80) /* run of pixels */
|
|
{
|
|
if(BrFileRead(&ch,1,1,fh) != 1)
|
|
return NULL;
|
|
|
|
for(i=0; i<size; i++)
|
|
line[n+i] = ch;
|
|
}
|
|
else /* string */
|
|
{
|
|
for(i=0; i<size; i++)
|
|
{
|
|
if(BrFileRead(&ch,1,1,fh) != 1)
|
|
return NULL;
|
|
|
|
line[n+i] = ch;
|
|
}
|
|
}
|
|
|
|
n += size;
|
|
}
|
|
while (n < TGAheader.width);
|
|
return line;
|
|
}
|
|
|
|
static void * ReadLine_Uncomp_16(char *line,void *fh)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<TGAheader.width;i++)
|
|
{
|
|
if(BrFileRead(&RGB_16,1,sizeof(RGB_16),fh) != sizeof(RGB_16))
|
|
return NULL;
|
|
|
|
line[i*2] = RGB_16 & 0xff;
|
|
line[i*2+1] = (RGB_16 >> 8) &0xff;
|
|
}
|
|
return line;
|
|
}
|
|
static void * ReadLine_Comp_16(char *line,void *fh)
|
|
{
|
|
unsigned char ch;
|
|
br_uint_32 size,n = 0;
|
|
int i;
|
|
|
|
do
|
|
{
|
|
if(BrFileRead(&ch,1,1,fh) != 1)
|
|
return NULL;
|
|
size = (ch & 0x7f)+1;
|
|
|
|
if(ch & 0x80) /* run of pixels */
|
|
{
|
|
if(BrFileRead(&RGB_16,1,sizeof(RGB_16),fh) != sizeof(RGB_16))
|
|
return NULL;
|
|
|
|
for(i=0; i<size; i++)
|
|
{
|
|
line[(n+i)*2] = RGB_16 & 0xff;
|
|
line[(n+i)*2+1] = (RGB_16 >> 8) &0xff;
|
|
}
|
|
}
|
|
else /* string */
|
|
{
|
|
for(i=0; i<size; i++)
|
|
{
|
|
if(BrFileRead(&RGB_16,1,sizeof(RGB_16),fh) != sizeof(RGB_16))
|
|
return NULL;
|
|
|
|
line[(n+i)*2] = RGB_16 & 0xff;
|
|
line[(n+i)*2+1] = (RGB_16 >> 8) &0xff;
|
|
}
|
|
}
|
|
|
|
n += size;
|
|
|
|
}
|
|
while (n < TGAheader.width);
|
|
return line;
|
|
}
|
|
|
|
static void * ReadLine_Uncomp_24(char *line,void *fh)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<TGAheader.width;i++)
|
|
{
|
|
if(BrFileRead(&RGB_24,1,sizeof(RGB_24),fh) != sizeof(RGB_24))
|
|
return NULL;
|
|
|
|
line[i*3] = RGB_24.blue;
|
|
line[i*3+1] = RGB_24.green;
|
|
line[i*3+2] = RGB_24.red;
|
|
}
|
|
return line;
|
|
}
|
|
static void * ReadLine_Comp_24(char *line,void *fh)
|
|
{
|
|
unsigned char ch;
|
|
br_uint_32 size,n = 0;
|
|
int i;
|
|
|
|
do
|
|
{
|
|
if(BrFileRead(&ch,1,1,fh) != 1)
|
|
return NULL;
|
|
size = (ch & 0x7f)+1;
|
|
|
|
if(ch & 0x80) /* run of pixels */
|
|
{
|
|
if(BrFileRead(&RGB_24,1,sizeof(RGB_24),fh) != sizeof(RGB_24))
|
|
return NULL;
|
|
|
|
for(i=0; i<size; i++)
|
|
{
|
|
line[(n+i)*3] = RGB_24.blue;
|
|
line[(n+i)*3+1] = RGB_24.green;
|
|
line[(n+i)*3+2] = RGB_24.red;
|
|
}
|
|
}
|
|
else /* string */
|
|
{
|
|
for(i=0; i<size; i++)
|
|
{
|
|
if(BrFileRead(&RGB_24,1,sizeof(RGB_24),fh) != sizeof(RGB_24))
|
|
return NULL;
|
|
|
|
line[(n+i)*3] = RGB_24.blue;
|
|
line[(n+i)*3+1] = RGB_24.green;
|
|
line[(n+i)*3+2] = RGB_24.red;
|
|
}
|
|
}
|
|
|
|
n += size;
|
|
|
|
}
|
|
while (n < TGAheader.width);
|
|
return line;
|
|
}
|
|
|
|
static void * ReadLine_Uncomp_32(char *line,void *fh)
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i<TGAheader.width;i++)
|
|
{
|
|
if(BrFileRead(&RGB_32,1,sizeof(RGB_32),fh) != sizeof(RGB_32))
|
|
return NULL;
|
|
|
|
line[i*4] = RGB_32.blue;
|
|
line[i*4+1] = RGB_32.green;
|
|
line[i*4+2] = RGB_32.red;
|
|
line[i*4+3] = RGB_32.x;
|
|
}
|
|
return line;
|
|
}
|
|
static void * ReadLine_Comp_32(char *line,void *fh)
|
|
{
|
|
unsigned char ch;
|
|
br_uint_32 size,n = 0;
|
|
int i;
|
|
|
|
do
|
|
{
|
|
if(BrFileRead(&ch,1,1,fh) != 1)
|
|
return NULL;
|
|
size = (ch & 0x7f)+1;
|
|
|
|
if(ch & 0x80) /* run of pixels */
|
|
{
|
|
if(BrFileRead(&RGB_32,1,sizeof(RGB_32),fh) != sizeof(RGB_32))
|
|
return NULL;
|
|
|
|
for(i=0; i<size; i++)
|
|
{
|
|
line[(n+i)*4] = RGB_32.blue;
|
|
line[(n+i)*4+1] = RGB_32.green;
|
|
line[(n+i)*4+2] = RGB_32.red;
|
|
line[(n+i)*4+3] = RGB_32.red;
|
|
}
|
|
}
|
|
else /* string */
|
|
{
|
|
for(i=0; i<size; i++)
|
|
{
|
|
if(BrFileRead(&RGB_32,1,sizeof(RGB_32),fh) != sizeof(RGB_32))
|
|
return NULL;
|
|
|
|
line[(n+i)*4] = RGB_32.blue;
|
|
line[(n+i)*4+1] = RGB_32.green;
|
|
line[(n+i)*4+2] = RGB_32.red;
|
|
line[(n+i)*4+3] = RGB_32.x;
|
|
}
|
|
}
|
|
|
|
n += size;
|
|
|
|
}
|
|
while (n < TGAheader.width);
|
|
return line;
|
|
}
|
|
|
|
static void CopyLine_8(br_pixelmap *pm,char *line,int row)
|
|
{
|
|
br_uint_32 xstart,xend,dx;
|
|
int i,j;
|
|
|
|
if(TGAheader.descriptor & BR_TGA_REVERSED_WIDTH)
|
|
{
|
|
xstart = TGAheader.width-1;
|
|
xend = -1;
|
|
dx = -1;
|
|
}
|
|
else
|
|
{
|
|
xstart = 0;
|
|
xend = TGAheader.width;
|
|
dx = 1;
|
|
}
|
|
|
|
for(i=xstart,j=0; i!=xend; i+=dx,j++)
|
|
((char *)(pm->pixels))[(row*pm->row_bytes)+j]=line[i];
|
|
}
|
|
|
|
static void CopyLine_16(br_pixelmap *pm,char *line,int row)
|
|
{
|
|
br_uint_32 xstart,xend,dx;
|
|
int i,j;
|
|
|
|
if(TGAheader.descriptor & BR_TGA_REVERSED_WIDTH)
|
|
{
|
|
xstart = TGAheader.width-1;
|
|
xend = -1;
|
|
dx = -1;
|
|
}
|
|
else
|
|
{
|
|
xstart = 0;
|
|
xend = TGAheader.width;
|
|
dx = 1;
|
|
}
|
|
|
|
for(i=xstart*2,j=0; i!=xend*2; i+=dx*2,j+=2)
|
|
{
|
|
((char *)(pm->pixels))[(row*pm->row_bytes)+j] = line[i ];
|
|
((char *)(pm->pixels))[(row*pm->row_bytes)+j+1] = line[i + dx];
|
|
}
|
|
|
|
}
|
|
static void CopyLine_24(br_pixelmap *pm,char *line,int row)
|
|
{
|
|
br_uint_32 xstart,xend,dx;
|
|
int i,j;
|
|
|
|
if(TGAheader.descriptor & BR_TGA_REVERSED_WIDTH)
|
|
{
|
|
xstart = TGAheader.width-1;
|
|
xend = -1;
|
|
dx = -1;
|
|
}
|
|
else
|
|
{
|
|
xstart = 0;
|
|
xend = TGAheader.width;
|
|
dx = 1;
|
|
}
|
|
|
|
for(i=xstart*3,j=0; i!=xend*3; i+=dx*3,j+=3)
|
|
{
|
|
((char *)(pm->pixels))[(row*pm->row_bytes)+j] = line[i ];
|
|
((char *)(pm->pixels))[(row*pm->row_bytes)+j+1] = line[i + dx];
|
|
((char *)(pm->pixels))[(row*pm->row_bytes)+j+2] = line[i + dx*2];
|
|
}
|
|
}
|
|
|
|
static void CopyLine_32(br_pixelmap *pm,char *line,int row)
|
|
{
|
|
br_uint_32 xstart,xend,dx;
|
|
int i,j;
|
|
|
|
if(TGAheader.descriptor & BR_TGA_REVERSED_WIDTH)
|
|
{
|
|
xstart = TGAheader.width-1;
|
|
xend = -1;
|
|
dx = -1;
|
|
}
|
|
else
|
|
{
|
|
xstart = 0;
|
|
xend = TGAheader.width;
|
|
dx = 1;
|
|
}
|
|
|
|
for(i=xstart*4,j=0; i!=xend*4; i+=dx*4,j+=4)
|
|
{
|
|
((char *)(pm->pixels))[(row*pm->row_bytes)+j] = line[i];
|
|
((char *)(pm->pixels))[(row*pm->row_bytes)+j+1] = line[i + dx];
|
|
((char *)(pm->pixels))[(row*pm->row_bytes)+j+2] = line[i + dx*2];
|
|
((char *)(pm->pixels))[(row*pm->row_bytes)+j+3] = line[i + dx*3];
|
|
}
|
|
}
|
|
|