430 lines
11 KiB
C
430 lines
11 KiB
C
/*
|
|
** Copyright (c) 1995, 3Dfx Interactive, Inc.
|
|
** All Rights Reserved.
|
|
**
|
|
** This is UNPUBLISHED PROPRIETARY SOURCE CODE of 3Dfx Interactive, Inc.;
|
|
** the contents of this file may not be disclosed to third parties, copied or
|
|
** duplicated in any form, in whole or in part, without the prior written
|
|
** permission of 3Dfx Interactive, Inc.
|
|
**
|
|
** RESTRICTED RIGHTS LEGEND:
|
|
** Use, duplication or disclosure by the Government is subject to restrictions
|
|
** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
|
|
** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
|
|
** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
|
|
** rights reserved under the Copyright Laws of the United States.
|
|
**
|
|
** $Revision$
|
|
** $Date$
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include "texusint.h"
|
|
|
|
|
|
typedef struct _tgaHeader{
|
|
FxU8 IDLength;
|
|
FxU8 CMapType;
|
|
FxU8 ImgType;
|
|
FxU8 CMapStartLo;
|
|
FxU8 CMapStartHi;
|
|
FxU8 CMapLengthLo;
|
|
FxU8 CMapLengthHi;
|
|
FxU8 CMapDepth;
|
|
FxU8 XOffSetLo;
|
|
FxU8 XOffSetHi;
|
|
FxU8 YOffSetLo;
|
|
FxU8 YOffSetHi;
|
|
FxU8 WidthLo;
|
|
FxU8 WidthHi;
|
|
FxU8 HeightLo;
|
|
FxU8 HeightHi;
|
|
FxU8 PixelDepth;
|
|
FxU8 ImageDescriptor;
|
|
} TgaHeader;
|
|
|
|
/* Definitions for image types. */
|
|
#define TGA_NULL 0
|
|
#define TGA_CMAP 1
|
|
#define TGA_TRUE 2
|
|
#define TGA_MONO 3
|
|
#define TGA_CMAP_RLE 9
|
|
#define TGA_TRUE_RLE 10
|
|
#define TGA_MONO_RLE 11
|
|
|
|
FxBool
|
|
_txReadTGAHeader( FILE *stream, FxU32 cookie, TxMip *info)
|
|
{
|
|
TgaHeader *tgaHeader = (TgaHeader *) info->pal;
|
|
int i;
|
|
|
|
// Fill up rest of the TGA header.
|
|
if ( fread( &(tgaHeader->ImgType), 1, sizeof(TgaHeader)-2, stream ) !=
|
|
sizeof(TgaHeader)-2) {
|
|
txPanic("Unexpected end of file.");
|
|
return FXFALSE;
|
|
}
|
|
tgaHeader->IDLength = (FxU8) ((cookie >> 8) & 0xFF);
|
|
tgaHeader->CMapType = (FxU8) ((cookie ) & 0xFF);
|
|
|
|
// Optionally, skip the image id fields.
|
|
for (i= (tgaHeader->IDLength) & 0xFF; i; i--) {
|
|
int c;
|
|
|
|
if ((c = getc(stream)) == EOF) {
|
|
txPanic("Unexpected EOF.");
|
|
return FXFALSE;
|
|
}
|
|
}
|
|
|
|
// 3Dfx specific part here.
|
|
info->width = tgaHeader->WidthHi << 8 | tgaHeader->WidthLo;
|
|
info->height = tgaHeader->HeightHi << 8 | tgaHeader->HeightLo;
|
|
info->depth = 1;
|
|
|
|
if ((info->width <= 0) || (info->height <= 0)) {
|
|
txError("TGA Image: width or height is 0.");
|
|
return FXFALSE;
|
|
}
|
|
|
|
switch(tgaHeader->ImgType) {
|
|
case TGA_MONO:
|
|
case TGA_MONO_RLE: // True color image.
|
|
if (tgaHeader->PixelDepth != 8) {
|
|
txError("TGA Image: Mono image is not 8 bits/pixel.");
|
|
return FXFALSE;
|
|
}
|
|
info->format = GR_TEXFMT_I_8;
|
|
break;
|
|
|
|
case TGA_TRUE:
|
|
case TGA_TRUE_RLE:
|
|
switch (tgaHeader->PixelDepth ) {
|
|
case 15:
|
|
case 16:
|
|
info->format = GR_TEXFMT_ARGB_1555; break;
|
|
case 24:
|
|
case 32:
|
|
info->format = GR_TEXFMT_ARGB_8888; break;
|
|
default:
|
|
txError("TGA Image: True color image is not 24/32 bits/pixel.");
|
|
return FXFALSE;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case TGA_CMAP:
|
|
case TGA_CMAP_RLE: // Color mapped image.
|
|
if ( tgaHeader->CMapType != 1 ) {
|
|
txError("TGA Image: Color-mapped TGA image has no palette");
|
|
return FXFALSE;
|
|
}
|
|
if (((tgaHeader->CMapLengthLo + tgaHeader->CMapLengthHi * 256L)
|
|
+(tgaHeader->CMapStartLo + tgaHeader->CMapStartHi * 256L)) > 256){
|
|
txError("TGA Image: Color-mapped image has > 256 colors");
|
|
return FXFALSE;
|
|
}
|
|
info->format = GR_TEXFMT_P_8;
|
|
break;
|
|
|
|
default:
|
|
txError("TGA Image: unsupported format");
|
|
return FXFALSE;
|
|
}
|
|
info->size = info->width*info->height*GR_TEXFMT_SIZE(info->format);
|
|
info->size >>= 3; // convert to bytes
|
|
|
|
return FXTRUE;
|
|
}
|
|
|
|
static FxBool
|
|
_txReadTGAColorMap(FILE *stream, const TgaHeader *tgaHeader, FxU32 *palette)
|
|
{
|
|
int cmapStart;
|
|
int cmapLength;
|
|
int cmapDepth;
|
|
int i;
|
|
|
|
cmapStart = tgaHeader->CMapStartLo;
|
|
cmapStart += tgaHeader->CMapStartHi * 256L;
|
|
|
|
cmapLength = tgaHeader->CMapLengthLo;
|
|
cmapLength += tgaHeader->CMapLengthHi * 256L;
|
|
|
|
cmapDepth = tgaHeader->CMapDepth;
|
|
|
|
if (tgaHeader->CMapType == 0) return FXTRUE; // no colormap.
|
|
|
|
/* Validate some parameters */
|
|
if (cmapStart < 0) {
|
|
txError("TGA Image: Bad Color Map start value.");
|
|
return FXFALSE;
|
|
}
|
|
|
|
cmapDepth = (cmapDepth + 1) >> 3; // to bytes.
|
|
if ((cmapDepth <= 0) || (cmapDepth > 4)) {
|
|
txError("TGA Image: Bad Color Map depth.");
|
|
return FXFALSE;
|
|
}
|
|
|
|
// May have to skip the color map.
|
|
if ((tgaHeader->ImgType != TGA_CMAP) &&
|
|
(tgaHeader->ImgType != TGA_CMAP_RLE)) {
|
|
/* True color, yet there is a palette, this is OK, just skip. */
|
|
|
|
cmapLength *= cmapDepth;
|
|
while (cmapLength--) {
|
|
int c;
|
|
|
|
c = getc(stream);
|
|
if (c == EOF) {
|
|
txError("TGA Image: Unexpected EOF reading Color Map.");
|
|
return FXFALSE;
|
|
}
|
|
}
|
|
return FXTRUE;
|
|
}
|
|
|
|
// This is a real palette that's going to be used.
|
|
|
|
// Verify that it's not too large.
|
|
if ((cmapStart + cmapLength) > 256) {
|
|
txError("TGA Image: Color Map > 256 entries.");
|
|
return FXFALSE;
|
|
}
|
|
|
|
|
|
// printf("cmapdepth = %d, start = %d, length = %d\n", cmapDepth,
|
|
// cmapStart, cmapLength);
|
|
for (i=0; i<256; i++) {
|
|
int r, g, b, a;
|
|
|
|
if ((i < cmapStart) || (i >= (cmapStart + cmapLength))) {
|
|
palette[i] = 0;
|
|
// printf("Skipping palette entry %d\n", i);
|
|
continue;
|
|
}
|
|
|
|
// Read this colormap entry.
|
|
switch (cmapDepth) {
|
|
case 1: // 8 bpp
|
|
r = getc(stream);
|
|
if (r == EOF) {
|
|
txError("TGA Image: Unexpected End of File.");
|
|
return FXFALSE;
|
|
}
|
|
r &= 0xFF;
|
|
palette[i] = (r << 24) | (r << 16) | (r << 8) | (r);
|
|
break;
|
|
|
|
case 2: // 15, 16 bpp.
|
|
|
|
b = getc(stream);
|
|
r = getc(stream);
|
|
if ((r == EOF) || (b == EOF)) {
|
|
txError("TGA Image: Unexpected End of File.");
|
|
return FXFALSE;
|
|
}
|
|
r &= 0xFF;
|
|
b &= 0xFF;
|
|
g = ((r & 0x3) << 6) + ((b & 0xE0) >> 2);
|
|
r = (r & 0x7C) << 1;
|
|
b = (b & 0x1F) << 3;
|
|
|
|
palette[i] = (r << 16) | (g << 8) | (b) | 0xFF000000L;
|
|
break;
|
|
|
|
case 3:
|
|
case 4:
|
|
b = getc(stream);
|
|
g = getc(stream);
|
|
r = getc(stream);
|
|
a = (cmapDepth == 4) ? getc(stream) : 0x0FF;
|
|
|
|
if ((r == EOF) || (g == EOF) || (b == EOF) | (a == EOF)) {
|
|
txError("TGA Image: Unexpected End of File.");
|
|
return FXFALSE;
|
|
}
|
|
palette[i] = (a << 24) | (r << 16) | (g << 8) | b;
|
|
// printf("Setting palette %3d to %.08x\n", i, palette[i]);
|
|
break;
|
|
|
|
default:
|
|
txError("TGA Image: Bad Color Map depth.");
|
|
return FXFALSE;
|
|
}
|
|
}
|
|
return FXTRUE;
|
|
}
|
|
|
|
static int tgaRLE, tgaRLEflag, tgaRLEcount, tgaRLEsav[4];
|
|
|
|
static FxBool
|
|
_txReadTGARLEPixel( FILE *stream, FxU8 *data, int pixsize)
|
|
{
|
|
int c, i;
|
|
|
|
// Run length encoded data Only
|
|
if (tgaRLEcount == 0) {
|
|
// Need to restart the run.
|
|
if ( (tgaRLEcount = c = getc( stream )) == EOF) {
|
|
txError("TGA Image: Unexpected End of File.");
|
|
return FXFALSE;
|
|
}
|
|
tgaRLEflag = tgaRLEcount & 0x80;
|
|
tgaRLEcount = (tgaRLEcount & 0x7F) + 1;
|
|
|
|
if (tgaRLEflag) {
|
|
// Replicated color, read the color to be replicated
|
|
for (i=0; i<pixsize; i++) {
|
|
if ( (c = getc( stream )) == EOF) {
|
|
txError("TGA Image: Unexpected End of File\n");
|
|
return FXFALSE;
|
|
}
|
|
tgaRLEsav[i] = (FxU8) c;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now deliver the data either from input or from saved values.
|
|
tgaRLEcount--;
|
|
if (tgaRLEflag) {
|
|
// deliver from saved data.
|
|
for (i=0; i<pixsize; i++) *data++ = (FxU8) tgaRLEsav[i];
|
|
} else {
|
|
for (i=0; i<pixsize; i++) {
|
|
if ( (c = getc( stream )) == EOF) {
|
|
txError("TGA Image: Unexpected End of File\n");
|
|
return FXFALSE;
|
|
}
|
|
*data++ = (FxU8) c;
|
|
}
|
|
}
|
|
return FXTRUE;
|
|
}
|
|
|
|
static FxBool
|
|
_txReadTGASpan( FILE *stream, FxU8 *data, int w, int pixsize)
|
|
{
|
|
if (tgaRLE == 0) {
|
|
if ( fread( data, 1, w * pixsize, stream) != (FxU32)(w * pixsize)) {
|
|
txError("TGA Image: Unexpected End of File\n");
|
|
return FXFALSE;
|
|
}
|
|
return FXTRUE;
|
|
}
|
|
|
|
// Otherwise, RLE data.
|
|
while (w--) {
|
|
if (!_txReadTGARLEPixel( stream, data, pixsize)) {
|
|
return FXFALSE;
|
|
}
|
|
data += pixsize;
|
|
}
|
|
return FXTRUE;
|
|
}
|
|
|
|
FxBool
|
|
_txReadTGAData( FILE *stream, TxMip *info)
|
|
{
|
|
TgaHeader *tgaHeader = (TgaHeader *) info->pal;
|
|
int i, stride;
|
|
int bpp; // bytesPerPixel
|
|
FxU8* data;
|
|
int BigEndian = 0xff000000;
|
|
|
|
// printf("TxREAD TGA DATA\n");
|
|
tgaRLEcount = 0;
|
|
|
|
bpp = (tgaHeader->PixelDepth + 1) >> 3;
|
|
|
|
switch (tgaHeader->ImgType) {
|
|
case TGA_MONO: tgaRLE = 0; info->format = GR_TEXFMT_I_8; break;
|
|
case TGA_MONO_RLE: tgaRLE = 1; info->format = GR_TEXFMT_I_8; break;
|
|
|
|
case TGA_TRUE: tgaRLE = 0; info->format = (bpp == 2) ?
|
|
GR_TEXFMT_ARGB_1555 : GR_TEXFMT_ARGB_8888; break;
|
|
case TGA_TRUE_RLE: tgaRLE = 1; info->format = (bpp == 2) ?
|
|
GR_TEXFMT_ARGB_1555 : GR_TEXFMT_ARGB_8888; break;
|
|
|
|
case TGA_CMAP: tgaRLE = 0; info->format = GR_TEXFMT_P_8; break;
|
|
case TGA_CMAP_RLE: tgaRLE = 1; info->format = GR_TEXFMT_P_8; break;
|
|
}
|
|
|
|
// printf("bpp = %d, rle = %d\n", bpp, tgaRLE);
|
|
|
|
stride = info->width * bpp;
|
|
data = info->data[0];
|
|
if ((tgaHeader->ImageDescriptor & 0x20) == 0) {
|
|
// Origin is lower left
|
|
data = data + (info->height-1) * stride;
|
|
stride = -stride;
|
|
}
|
|
|
|
/* If there's a colormap, read it now. */
|
|
if (!_txReadTGAColorMap(stream, tgaHeader, (FxU32 *) &(info->pal[0])))
|
|
return FXFALSE;
|
|
// printf("read in color map\n");
|
|
|
|
/* Read in all the data */
|
|
for ( i = 0; i < info->height; i++) {
|
|
if (!_txReadTGASpan( stream, data, info->width, bpp)) {
|
|
txError("TGA Image: Unexpected end of file.");
|
|
return FXFALSE;
|
|
}
|
|
data += stride;
|
|
}
|
|
|
|
/*
|
|
* BPP == 1 -> P8 or I8 formatted data.
|
|
* BPP == 2 -> ARGB1555 formatted data.
|
|
* BPP == 4 -> ARGB8888 formatted data.
|
|
* BPP == 3 should be translated to ARGB8888 from RGB888.
|
|
*/
|
|
// printf("Repacking\n");
|
|
if (bpp == 3) {
|
|
int npixels = info->width * info->height;
|
|
FxU8 *src = ((FxU8 *) info->data[0]) + (npixels - 1) * 3;
|
|
FxU8 *dst = ((FxU8 *) info->data[0]) + (npixels - 1) * 4;
|
|
|
|
while (npixels--) {
|
|
dst[3] = 0xFF;
|
|
dst[2] = src[2];
|
|
dst[1] = src[1];
|
|
dst[0] = src[0];
|
|
dst -= 4;
|
|
src -= 3;
|
|
}
|
|
}
|
|
// printf("Done\n");
|
|
if (*(FxU8 *)&BigEndian) {
|
|
/* Repack 16bpp and 32bpp cases */
|
|
if (bpp == 2) {
|
|
int npixels = info->width * info->height;
|
|
FxU16 *src = (FxU16 *) info->data[0];
|
|
|
|
while (npixels--) {
|
|
*src = (*src << 8) | ((*src >> 8) & 0xff);
|
|
src++;
|
|
}
|
|
}
|
|
if ((bpp == 3) || (bpp == 4)) {
|
|
int npixels = info->width * info->height;
|
|
FxU32 *src = (FxU32 *) info->data[0];
|
|
|
|
while (npixels--) {
|
|
*src = (((*src ) & 0xff) << 24)|
|
|
(((*src >> 8) & 0xff) << 16)|
|
|
(((*src >> 16) & 0xff) << 8)|
|
|
(((*src >> 24) & 0xff) );
|
|
src++;
|
|
}
|
|
}
|
|
}
|
|
return FXTRUE;
|
|
}
|