496 lines
16 KiB
C
496 lines
16 KiB
C
|
|
/*
|
|
** THIS SOFTWARE IS SUBJECT TO COPYRIGHT PROTECTION AND IS OFFERED ONLY
|
|
** PURSUANT TO THE 3DFX GLIDE GENERAL PUBLIC LICENSE. THERE IS NO RIGHT
|
|
** TO USE THE GLIDE TRADEMARK WITHOUT PRIOR WRITTEN PERMISSION OF 3DFX
|
|
** INTERACTIVE, INC. A COPY OF THIS LICENSE MAY BE OBTAINED FROM THE
|
|
** DISTRIBUTOR OR BY CONTACTING 3DFX INTERACTIVE INC(info@3dfx.com).
|
|
** THIS PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
|
|
** EXPRESSED OR IMPLIED. SEE THE 3DFX GLIDE GENERAL PUBLIC LICENSE FOR A
|
|
** FULL TEXT OF THE NON-WARRANTY PROVISIONS.
|
|
**
|
|
** 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.
|
|
**
|
|
** COPYRIGHT 3DFX INTERACTIVE, INC. 1999, ALL RIGHTS RESERVED
|
|
**
|
|
** $Revision$
|
|
** $Date$
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include "texusint.h"
|
|
|
|
int txVerbose = 0;
|
|
|
|
char *Format_Name[] = {
|
|
"rgb332", // GR_TEXFMT_RGB_332
|
|
"yiq", // GR_TEXFMT_YIQ_422
|
|
"a8", // GR_TEXFMT_ALPHA_8
|
|
"i8", // GR_TEXFMT_INTENSITY_8
|
|
"ai44", // GR_TEXFMT_ALPHA_INTENSITY_44
|
|
"p8", // GR_TEXFMT_P_8
|
|
"rsvd1", // GR_TEXFMT_RSVD1
|
|
"rsvd2", // GR_TEXFMT_RSVD2
|
|
"argb8332", // GR_TEXFMT_ARGB_8332
|
|
"ayiq8422", // GR_TEXFMT_AYIQ_8422
|
|
"rgb565", // GR_TEXFMT_RGB_565
|
|
"argb1555", // GR_TEXFMT_ARGB_1555
|
|
"argb4444", // GR_TEXFMT_ARGB_4444
|
|
"ai88", // GR_TEXFMT_ALPHA_INTENSITY_88
|
|
"ap88", // GR_TEXFMT_AP_88
|
|
"rsvd4", // GR_TEXFMT_RSVD4
|
|
"argb8888", // GR_TEXFMT_ARGB_8888
|
|
};
|
|
|
|
|
|
int
|
|
txLog2(int n)
|
|
{
|
|
switch (n) {
|
|
case 1: return 0;
|
|
case 2: return 1;
|
|
case 4: return 2;
|
|
case 8: return 3;
|
|
case 16: return 4;
|
|
case 32: return 5;
|
|
case 64: return 6;
|
|
case 128: return 7;
|
|
case 256: return 8;
|
|
}
|
|
|
|
txPanic("Bad arg to Log2\n");
|
|
return 0; // to keep compiler quiet.
|
|
}
|
|
|
|
int
|
|
txFloorPow2(int n)
|
|
{
|
|
// Find next smallest integer which is also a power of 2.
|
|
|
|
int i;
|
|
|
|
if ((n & (n -1)) == 0) {
|
|
return n; // already a power of 2.
|
|
}
|
|
|
|
for (i=1; i<= n; i+=i);
|
|
return i>>1;
|
|
}
|
|
|
|
int
|
|
txCeilPow2(int n)
|
|
{
|
|
// Find next smallest integer which is also a power of 2.
|
|
|
|
int i;
|
|
|
|
if ((n & (n -1)) == 0) return n; // already a power of 2.
|
|
|
|
for (i=1; i<= n; i+=i);
|
|
return i;
|
|
}
|
|
|
|
extern TxErrorCallbackFnc_t _txErrorCallback;
|
|
|
|
void
|
|
txPanic(char *message)
|
|
{
|
|
_txErrorCallback( message, FXTRUE );
|
|
}
|
|
|
|
void
|
|
txError(char *message)
|
|
{
|
|
_txErrorCallback( message, FXFALSE );
|
|
}
|
|
|
|
int
|
|
txGCD(int a, int b)
|
|
{
|
|
// Greatest common divisor, used in resampling.
|
|
|
|
if (b > a) { int t; t = a; a = b; b = t;}
|
|
|
|
// a>b here.
|
|
|
|
while (b > 0) {
|
|
int t;
|
|
|
|
t = a % b;
|
|
a = b;
|
|
b = t;
|
|
}
|
|
return a;
|
|
}
|
|
|
|
void
|
|
txYABtoPal256(int *palette, const int* yabTable)
|
|
{
|
|
// Convert YAB table to a 256 color palette
|
|
// Assume yabTable[] has first 16Y's, 12 A's, 12 B's
|
|
|
|
const int *Y = yabTable;
|
|
const int *A = yabTable + 16;
|
|
const int *B = yabTable + 16 + 12;
|
|
int i;
|
|
|
|
for (i=0; i<256; i++) {
|
|
int iy, ia, ib, r, g, b;
|
|
|
|
iy = (i >> 4) & 0xF;
|
|
ia = (i >> 2) & 0x3;
|
|
ib = (i >> 0) & 0x3;
|
|
|
|
r = Y[iy] + A[3*ia + 0] + B[3*ib + 0];
|
|
g = Y[iy] + A[3*ia + 1] + B[3*ib + 1];
|
|
b = Y[iy] + A[3*ia + 2] + B[3*ib + 2];
|
|
|
|
if (r < 0) r = 0; if (r > 255) r = 255;
|
|
if (g < 0) g = 0; if (g > 255) g = 255;
|
|
if (b < 0) b = 0; if (b > 255) b = 255;
|
|
|
|
palette[i] = (r << 16) | (g << 8) | b;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The following table was generated from this piece of code:
|
|
|
|
main()
|
|
{
|
|
int i;
|
|
|
|
printf("static int _explode3[256+256+4] = {\n");
|
|
|
|
for (i=-255; i<256; i++) {
|
|
int k;
|
|
int bits;
|
|
|
|
k = (i < 0) ? -i : i;
|
|
bits = 0;
|
|
|
|
if (k & 0x01) bits += 0x00000001 << 0;
|
|
if (k & 0x02) bits += 0x00000001 << 3;
|
|
if (k & 0x04) bits += 0x00000001 << 6;
|
|
if (k & 0x08) bits += 0x00000001 << 9;
|
|
if (k & 0x10) bits += 0x00000001 << 12;
|
|
if (k & 0x20) bits += 0x00000001 << 15;
|
|
if (k & 0x40) bits += 0x00000001 << 18;
|
|
if (k & 0x80) bits += 0x00000001 << 21;
|
|
|
|
// explode3[i] = bits;
|
|
printf("0x%.06x,", bits);
|
|
if (((i + 255) % 8) == 7) printf("\n");
|
|
}
|
|
printf("\n};\n");
|
|
printf("static int *explode3 = &_explode3[255];\n");
|
|
}
|
|
*/
|
|
|
|
int _explode3[255+256] = {
|
|
0x249249,0x249248,0x249241,0x249240,0x249209,0x249208,0x249201,0x249200,
|
|
0x249049,0x249048,0x249041,0x249040,0x249009,0x249008,0x249001,0x249000,
|
|
0x248249,0x248248,0x248241,0x248240,0x248209,0x248208,0x248201,0x248200,
|
|
0x248049,0x248048,0x248041,0x248040,0x248009,0x248008,0x248001,0x248000,
|
|
0x241249,0x241248,0x241241,0x241240,0x241209,0x241208,0x241201,0x241200,
|
|
0x241049,0x241048,0x241041,0x241040,0x241009,0x241008,0x241001,0x241000,
|
|
0x240249,0x240248,0x240241,0x240240,0x240209,0x240208,0x240201,0x240200,
|
|
0x240049,0x240048,0x240041,0x240040,0x240009,0x240008,0x240001,0x240000,
|
|
0x209249,0x209248,0x209241,0x209240,0x209209,0x209208,0x209201,0x209200,
|
|
0x209049,0x209048,0x209041,0x209040,0x209009,0x209008,0x209001,0x209000,
|
|
0x208249,0x208248,0x208241,0x208240,0x208209,0x208208,0x208201,0x208200,
|
|
0x208049,0x208048,0x208041,0x208040,0x208009,0x208008,0x208001,0x208000,
|
|
0x201249,0x201248,0x201241,0x201240,0x201209,0x201208,0x201201,0x201200,
|
|
0x201049,0x201048,0x201041,0x201040,0x201009,0x201008,0x201001,0x201000,
|
|
0x200249,0x200248,0x200241,0x200240,0x200209,0x200208,0x200201,0x200200,
|
|
0x200049,0x200048,0x200041,0x200040,0x200009,0x200008,0x200001,0x200000,
|
|
0x049249,0x049248,0x049241,0x049240,0x049209,0x049208,0x049201,0x049200,
|
|
0x049049,0x049048,0x049041,0x049040,0x049009,0x049008,0x049001,0x049000,
|
|
0x048249,0x048248,0x048241,0x048240,0x048209,0x048208,0x048201,0x048200,
|
|
0x048049,0x048048,0x048041,0x048040,0x048009,0x048008,0x048001,0x048000,
|
|
0x041249,0x041248,0x041241,0x041240,0x041209,0x041208,0x041201,0x041200,
|
|
0x041049,0x041048,0x041041,0x041040,0x041009,0x041008,0x041001,0x041000,
|
|
0x040249,0x040248,0x040241,0x040240,0x040209,0x040208,0x040201,0x040200,
|
|
0x040049,0x040048,0x040041,0x040040,0x040009,0x040008,0x040001,0x040000,
|
|
0x009249,0x009248,0x009241,0x009240,0x009209,0x009208,0x009201,0x009200,
|
|
0x009049,0x009048,0x009041,0x009040,0x009009,0x009008,0x009001,0x009000,
|
|
0x008249,0x008248,0x008241,0x008240,0x008209,0x008208,0x008201,0x008200,
|
|
0x008049,0x008048,0x008041,0x008040,0x008009,0x008008,0x008001,0x008000,
|
|
0x001249,0x001248,0x001241,0x001240,0x001209,0x001208,0x001201,0x001200,
|
|
0x001049,0x001048,0x001041,0x001040,0x001009,0x001008,0x001001,0x001000,
|
|
0x000249,0x000248,0x000241,0x000240,0x000209,0x000208,0x000201,0x000200,
|
|
0x000049,0x000048,0x000041,0x000040,0x000009,0x000008,0x000001,0x000000,
|
|
0x000001,0x000008,0x000009,0x000040,0x000041,0x000048,0x000049,0x000200,
|
|
0x000201,0x000208,0x000209,0x000240,0x000241,0x000248,0x000249,0x001000,
|
|
0x001001,0x001008,0x001009,0x001040,0x001041,0x001048,0x001049,0x001200,
|
|
0x001201,0x001208,0x001209,0x001240,0x001241,0x001248,0x001249,0x008000,
|
|
0x008001,0x008008,0x008009,0x008040,0x008041,0x008048,0x008049,0x008200,
|
|
0x008201,0x008208,0x008209,0x008240,0x008241,0x008248,0x008249,0x009000,
|
|
0x009001,0x009008,0x009009,0x009040,0x009041,0x009048,0x009049,0x009200,
|
|
0x009201,0x009208,0x009209,0x009240,0x009241,0x009248,0x009249,0x040000,
|
|
0x040001,0x040008,0x040009,0x040040,0x040041,0x040048,0x040049,0x040200,
|
|
0x040201,0x040208,0x040209,0x040240,0x040241,0x040248,0x040249,0x041000,
|
|
0x041001,0x041008,0x041009,0x041040,0x041041,0x041048,0x041049,0x041200,
|
|
0x041201,0x041208,0x041209,0x041240,0x041241,0x041248,0x041249,0x048000,
|
|
0x048001,0x048008,0x048009,0x048040,0x048041,0x048048,0x048049,0x048200,
|
|
0x048201,0x048208,0x048209,0x048240,0x048241,0x048248,0x048249,0x049000,
|
|
0x049001,0x049008,0x049009,0x049040,0x049041,0x049048,0x049049,0x049200,
|
|
0x049201,0x049208,0x049209,0x049240,0x049241,0x049248,0x049249,0x200000,
|
|
0x200001,0x200008,0x200009,0x200040,0x200041,0x200048,0x200049,0x200200,
|
|
0x200201,0x200208,0x200209,0x200240,0x200241,0x200248,0x200249,0x201000,
|
|
0x201001,0x201008,0x201009,0x201040,0x201041,0x201048,0x201049,0x201200,
|
|
0x201201,0x201208,0x201209,0x201240,0x201241,0x201248,0x201249,0x208000,
|
|
0x208001,0x208008,0x208009,0x208040,0x208041,0x208048,0x208049,0x208200,
|
|
0x208201,0x208208,0x208209,0x208240,0x208241,0x208248,0x208249,0x209000,
|
|
0x209001,0x209008,0x209009,0x209040,0x209041,0x209048,0x209049,0x209200,
|
|
0x209201,0x209208,0x209209,0x209240,0x209241,0x209248,0x209249,0x240000,
|
|
0x240001,0x240008,0x240009,0x240040,0x240041,0x240048,0x240049,0x240200,
|
|
0x240201,0x240208,0x240209,0x240240,0x240241,0x240248,0x240249,0x241000,
|
|
0x241001,0x241008,0x241009,0x241040,0x241041,0x241048,0x241049,0x241200,
|
|
0x241201,0x241208,0x241209,0x241240,0x241241,0x241248,0x241249,0x248000,
|
|
0x248001,0x248008,0x248009,0x248040,0x248041,0x248048,0x248049,0x248200,
|
|
0x248201,0x248208,0x248209,0x248240,0x248241,0x248248,0x248249,0x249000,
|
|
0x249001,0x249008,0x249009,0x249040,0x249041,0x249048,0x249049,0x249200,
|
|
0x249201,0x249208,0x249209,0x249240,0x249241,0x249248,0x249249,
|
|
};
|
|
int *explode3 = &_explode3[255];
|
|
|
|
int
|
|
txNearestColor(int ir, int ig, int ib, const FxU32 *pal, int ncolors)
|
|
{
|
|
int i, d;
|
|
int mindist, minpos; // closest distance to input
|
|
|
|
if (&explode3[-255] != &_explode3[0])
|
|
txPanic("Bad explode\n");
|
|
|
|
mindist = DISTANCE((*pal>>16)&0xff, (*pal>>8)&0xff, (*pal)&0xff,
|
|
ir, ig, ib);
|
|
minpos = 0;
|
|
pal ++;
|
|
|
|
/* Find closest color */
|
|
for (i=1; i<ncolors; i++, pal ++) {
|
|
d = DISTANCE((*pal>>16)&0xff, (*pal>>8)&0xff, (*pal)&0xff,
|
|
ir, ig, ib);
|
|
if (d < mindist) { mindist = d; minpos = i; }
|
|
}
|
|
return minpos; // best fit color is returned.
|
|
}
|
|
|
|
#ifdef GLIDE3
|
|
int
|
|
txAspectRatio(int w, int h)
|
|
{
|
|
int ar;
|
|
|
|
ar = (w >= h) ? (((w/h) << 4) | 1) : ((1 << 4) | (h/w));
|
|
switch (ar) {
|
|
case 0x81: return 6;
|
|
case 0x41: return 5;
|
|
case 0x21: return 4;
|
|
case 0x11: return 3;
|
|
case 0x12: return 2;
|
|
case 0x14: return 1;
|
|
case 0x18: return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
#else
|
|
int
|
|
txAspectRatio(int w, int h)
|
|
{
|
|
int ar;
|
|
|
|
ar = (w >= h) ? (((w/h) << 4) | 1) : ((1 << 4) | (h/w));
|
|
switch (ar) {
|
|
case 0x81: return 0;
|
|
case 0x41: return 1;
|
|
case 0x21: return 2;
|
|
case 0x11: return 3;
|
|
case 0x12: return 4;
|
|
case 0x14: return 5;
|
|
case 0x18: return 6;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif /* GLIDE3 */
|
|
|
|
void
|
|
txRectCopy(FxU8 *dst, int dstStride, const FxU8 *src, int srcStride,
|
|
int width, int height)
|
|
{
|
|
// Copy a rectangular region from src to dst, each with different strides.
|
|
|
|
while (height--) {
|
|
int i;
|
|
for (i=0; i<width; i++) {
|
|
dst[i] = src[i];
|
|
}
|
|
dst += dstStride;
|
|
src += srcStride;
|
|
}
|
|
}
|
|
|
|
int
|
|
txMemRequired(TxMip *txMip)
|
|
{
|
|
/* Tell me how much memory is need to hold this mipmap */
|
|
int w, h, memsize, i;
|
|
|
|
w = txMip->width;
|
|
h = txMip->height;
|
|
memsize = 0;
|
|
|
|
for (i=0; i<txMip->depth; i++) {
|
|
memsize += (w * h);
|
|
if (w > 1) w >>= 1;
|
|
if (h > 1) h >>= 1;
|
|
}
|
|
return memsize * GR_TEXFMT_SIZE(txMip->format);
|
|
}
|
|
|
|
FxBool
|
|
txMipAlloc(TxMip *txMip)
|
|
{
|
|
int i, w, h;
|
|
FxU8 *data;
|
|
|
|
txMip->size = txMemRequired(txMip);
|
|
|
|
data = (FxU8 *) txMalloc(txMip->size);
|
|
if (data == NULL) return FXFALSE;
|
|
w = txMip->width;
|
|
h = txMip->height;
|
|
|
|
for (i=0; i<TX_MAX_LEVEL; i++) {
|
|
if (i >= txMip->depth) {
|
|
txMip->data[i] = NULL;
|
|
continue;
|
|
}
|
|
txMip->data[i] = data;
|
|
data += (w * h * GR_TEXFMT_SIZE(txMip->format));
|
|
if (w > 1) w >>= 1;
|
|
if (h > 1) h >>= 1;
|
|
}
|
|
return FXTRUE;
|
|
}
|
|
|
|
FxBool
|
|
txMipSetMipPointers(TxMip *txMip)
|
|
{
|
|
int i, w, h;
|
|
FxU8 *data = txMip->data[0];
|
|
|
|
txMip->size = txMemRequired(txMip);
|
|
|
|
w = txMip->width;
|
|
h = txMip->height;
|
|
|
|
for (i=0; i<TX_MAX_LEVEL; i++) {
|
|
if (i >= txMip->depth) {
|
|
txMip->data[i] = NULL;
|
|
continue;
|
|
}
|
|
txMip->data[i] = data;
|
|
data += (w * h * GR_TEXFMT_SIZE(txMip->format));
|
|
if (w > 1) w >>= 1;
|
|
if (h > 1) h >>= 1;
|
|
}
|
|
return FXTRUE;
|
|
}
|
|
|
|
void
|
|
txBasename(const char *name, char* basename)
|
|
{
|
|
/* Strip the pathname and leave us with filename.ext */
|
|
char *s;
|
|
const char *p, *slash;
|
|
|
|
/* Find the last slash */
|
|
for (p = slash = name; *p; p++) {
|
|
if ((*p == '/') || (*p == '\\')) slash = p + 1;
|
|
}
|
|
|
|
/* Copy everything after the last slash to output */
|
|
strcpy(basename, slash);
|
|
|
|
// Walk to end of string */
|
|
for (s = basename; *s; s++);
|
|
|
|
// Walk backwards; replace any . with 0
|
|
while (--s >= basename) {
|
|
if (*s == '.') {*s = 0; break;}
|
|
}
|
|
}
|
|
|
|
void
|
|
txPathAndBasename(const char *name, char* basename)
|
|
{
|
|
/* Strip the extension and leave us with path,basename */
|
|
char *s;
|
|
|
|
strcpy(basename, name);
|
|
|
|
/* Walk to the end of the string */
|
|
for (s = basename; *s; s++);
|
|
|
|
/* Walk backwards; stop when you hit a slash; replace any . with 0. */
|
|
while (--s >= basename) {
|
|
if ((*s == '/') || (*s == '\\')) break;
|
|
if (*s == '.') {*s = 0; break;}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
txExtension(const char *name, char *extname)
|
|
{
|
|
const char *p, *ext;
|
|
|
|
ext = NULL;
|
|
for (p = name; *p; p++) {
|
|
if (*p == '.') ext = p;
|
|
}
|
|
|
|
if (ext)
|
|
while (*ext) *extname++ = *ext++;
|
|
|
|
*extname = 0;
|
|
}
|
|
|
|
void
|
|
txMipFree( TxMip *mip )
|
|
{
|
|
int i;
|
|
|
|
txFree( mip->data[0] );
|
|
for( i = 0; i < TX_MAX_LEVEL; i++ )
|
|
mip->data[i] = NULL;
|
|
}
|
|
|
|
void *txMalloc( size_t size )
|
|
{
|
|
return malloc( size );
|
|
}
|
|
|
|
void txFree( void *ptr )
|
|
{
|
|
free( ptr );
|
|
}
|
|
|
|
void *txRealloc( void *ptr, size_t size )
|
|
{
|
|
return realloc( ptr, size );
|
|
}
|
|
|