367 lines
10 KiB
C++
367 lines
10 KiB
C++
//**************************************************************
|
|
//* OpenGLide - Glide to OpenGL Wrapper
|
|
//* http://openglide.sourceforge.net
|
|
//*
|
|
//* 3DF functions
|
|
//*
|
|
//* OpenGLide is OpenSource under LGPL license
|
|
//* Originaly made by Fabio Barros
|
|
//* Modified by Paul for Glidos (http://www.glidos.net)
|
|
//* Mac version and additional features by Jens-Olaf Hemprich
|
|
//**************************************************************
|
|
|
|
#include "OGLTables.h"
|
|
|
|
//*************************************************
|
|
FxU32 GetTexSize( const int Lod, const int aspectRatio, const int format )
|
|
{
|
|
/*
|
|
** If the format is one of these:
|
|
** GR_TEXFMT_RGB_332
|
|
** GR_TEXFMT_YIQ_422
|
|
** GR_TEXFMT_ALPHA_8
|
|
** GR_TEXFMT_INTENSITY_8
|
|
** GR_TEXFMT_ALPHA_INTENSITY_44
|
|
** GR_TEXFMT_P_8
|
|
** Reduces the size by 2
|
|
*/
|
|
return nSquareLod[ format > GR_TEXFMT_RSVD1 ][ aspectRatio ][ Lod ];
|
|
}
|
|
|
|
// prototypes
|
|
int Read3dfHeader( const char *filename, Gu3dfInfo *data );
|
|
|
|
//*************************************************
|
|
FX_ENTRY FxBool FX_CALL
|
|
gu3dfGetInfo( const char *filename, Gu3dfInfo *info )
|
|
{
|
|
#ifdef OGL_PARTDONE
|
|
GlideMsg( "gu3dfGetInfo( %s, --- )\n", filename );
|
|
#endif
|
|
|
|
if ( Read3dfHeader( filename, info ) )
|
|
{
|
|
#ifdef OGL_DEBUG
|
|
GlideMsg( "==========================================\n" );
|
|
GlideMsg( "3df file Header: %s\n", filename );
|
|
GlideMsg( "Texture Format = %d\n", info->header.format );
|
|
GlideMsg( "Aspect = %d\n", info->header.aspect_ratio );
|
|
GlideMsg( "LargeLod = %d\nSmall Lod = %d\n", info->header.large_lod, info->header.small_lod );
|
|
GlideMsg( "Width = %d Height = %d\n", info->header.width, info->header.height );
|
|
GlideMsg( "MemRequired = %d\n", info->mem_required );
|
|
GlideMsg( "==========================================\n" );
|
|
#endif
|
|
return FXTRUE;
|
|
}
|
|
else
|
|
{
|
|
return FXFALSE;
|
|
}
|
|
}
|
|
|
|
|
|
static FxU32 ReadDataLong( FILE *fp )
|
|
{
|
|
FxU32 data;
|
|
FxU8 byte[4];
|
|
|
|
fread( byte, 4, 1, fp );
|
|
data = (((FxU32) byte[ 0 ]) << 24) |
|
|
(((FxU32) byte[ 1 ]) << 16) |
|
|
(((FxU32) byte[ 2 ]) << 8) |
|
|
((FxU32) byte[ 3 ]);
|
|
|
|
return data;
|
|
}
|
|
|
|
static FxU32 ReadDataShort( FILE *fp )
|
|
{
|
|
FxU32 data;
|
|
FxU8 byte[2];
|
|
|
|
fread( byte, 2, 1, fp );
|
|
data = (((FxU32) byte[ 0 ]) << 8) |
|
|
((FxU32) byte[ 1 ]);
|
|
|
|
return data;
|
|
}
|
|
|
|
//*************************************************
|
|
FX_ENTRY FxBool FX_CALL
|
|
gu3dfLoad( const char *filename, Gu3dfInfo *data )
|
|
{
|
|
#ifdef OGL_PARTDONE
|
|
GlideMsg( "gu3dfLoad( %s, --- )\n", filename );
|
|
#endif
|
|
|
|
FILE * file3df;
|
|
int jump = Read3dfHeader( filename, data );
|
|
|
|
#ifdef OGL_DEBUG
|
|
GlideMsg( "Start of Data (Offset) = %d\n", jump );
|
|
GlideMsg( "Total Bytes to be Read = %d\n", data->mem_required );
|
|
#endif
|
|
|
|
file3df = fopen( filename, "rb" );
|
|
|
|
fseek( file3df, jump, SEEK_SET );
|
|
|
|
if ( ( data->header.format == GR_TEXFMT_P_8 ) ||
|
|
( data->header.format == GR_TEXFMT_AP_88 ) )
|
|
{
|
|
for( int i = 0; i < 256; i++ )
|
|
{
|
|
data->table.palette.data[i] = ReadDataLong( file3df );
|
|
}
|
|
#ifdef OGL_DEBUG
|
|
GlideMsg( "Reading Palette\n" );
|
|
#endif
|
|
}
|
|
|
|
if ( ( data->header.format == GR_TEXFMT_YIQ_422 ) ||
|
|
( data->header.format == GR_TEXFMT_AYIQ_8422 ) )
|
|
{
|
|
int i;
|
|
int pi;
|
|
FxU32 pack;
|
|
|
|
GuNccTable *ncc = &(data->table.nccTable);
|
|
|
|
for ( i = 0; i < 16; i++ )
|
|
{
|
|
ncc->yRGB[i] = (FxU8) ReadDataShort( file3df );
|
|
}
|
|
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
/* Masking with 0x1ff is strange but correct apparently */
|
|
ncc->iRGB[i][0] = (FxI16) ( ReadDataShort( file3df ) & 0x1ff );
|
|
ncc->iRGB[i][1] = (FxI16) ( ReadDataShort( file3df ) & 0x1ff );
|
|
ncc->iRGB[i][2] = (FxI16) ( ReadDataShort( file3df ) & 0x1ff );
|
|
}
|
|
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
ncc->qRGB[i][0] = (FxI16) ( ReadDataShort( file3df ) & 0x1ff );
|
|
ncc->qRGB[i][1] = (FxI16) ( ReadDataShort( file3df ) & 0x1ff );
|
|
ncc->qRGB[i][2] = (FxI16) ( ReadDataShort( file3df ) & 0x1ff );
|
|
}
|
|
|
|
pi = 0;
|
|
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
pack = ( ncc->yRGB[i*4 + 0] );
|
|
pack |= ( ncc->yRGB[i*4 + 1] << 8 );
|
|
pack |= ( ncc->yRGB[i*4 + 2] << 16 );
|
|
pack |= ( ncc->yRGB[i*4 + 3] << 24 );
|
|
|
|
ncc->packed_data[pi++] = pack;
|
|
}
|
|
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
pack = ( ncc->iRGB[i][0] << 18 );
|
|
pack |= ( ncc->iRGB[i][1] << 9 );
|
|
pack |= ( ncc->iRGB[i][2] );
|
|
|
|
ncc->packed_data[pi++] = pack;
|
|
}
|
|
|
|
for ( i = 0; i < 4; i++ )
|
|
{
|
|
pack = ( ncc->qRGB[i][0] << 18 );
|
|
pack |= ( ncc->qRGB[i][1] << 9 );
|
|
pack |= ( ncc->qRGB[i][2] );
|
|
|
|
ncc->packed_data[pi++] = pack;
|
|
}
|
|
}
|
|
|
|
switch ( data->header.format )
|
|
{
|
|
case GR_TEXFMT_RGB_565:
|
|
case GR_TEXFMT_ARGB_8332:
|
|
case GR_TEXFMT_ARGB_1555:
|
|
case GR_TEXFMT_AYIQ_8422:
|
|
case GR_TEXFMT_ARGB_4444:
|
|
case GR_TEXFMT_ALPHA_INTENSITY_88:
|
|
case GR_TEXFMT_AP_88:
|
|
{
|
|
FxU16 *d = (FxU16 *) (data->data);
|
|
int i;
|
|
|
|
for ( i = data->mem_required; i > 0; i -= 2 )
|
|
{
|
|
*d++ = (FxU16) ReadDataShort( file3df );
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
fread( data->data, sizeof( FxU8 ), data->mem_required, file3df );
|
|
break;
|
|
}
|
|
|
|
fclose( file3df );
|
|
|
|
return FXTRUE;
|
|
}
|
|
|
|
static const int numFormats = 16;
|
|
static const struct
|
|
{
|
|
const char* name;
|
|
GrTextureFormat_t format;
|
|
}
|
|
formatTable[numFormats] =
|
|
{
|
|
{"argb1555\n",GR_TEXFMT_ARGB_1555},
|
|
{"argb4444\n",GR_TEXFMT_ARGB_4444},
|
|
{"rgb565\n",GR_TEXFMT_RGB_565},
|
|
{"rgb332\n",GR_TEXFMT_RGB_332},
|
|
{"argb8332\n",GR_TEXFMT_ARGB_8332},
|
|
{"p8\n",GR_TEXFMT_P_8},
|
|
{"ap88\n",GR_TEXFMT_AP_88},
|
|
{"ai44\n",GR_TEXFMT_ALPHA_INTENSITY_44},
|
|
{"yiq\n",GR_TEXFMT_YIQ_422},
|
|
{"ayiq8422\n",GR_TEXFMT_AYIQ_8422},
|
|
{"a8\n",GR_TEXFMT_ALPHA_8},
|
|
{"i8\n",GR_TEXFMT_INTENSITY_8},
|
|
{"ai88\n",GR_TEXFMT_ALPHA_INTENSITY_88},
|
|
{"rsvd0\n",GR_TEXFMT_RSVD0},
|
|
{"rsvd1\n",GR_TEXFMT_RSVD1},
|
|
{"rsvd2\n",GR_TEXFMT_RSVD2}
|
|
};
|
|
|
|
GrTextureFormat_t ParseTextureFormat(const char * text)
|
|
{
|
|
for(int i = 0; i < numFormats; i++)
|
|
{
|
|
if (!strcmp(text, formatTable[i].name)) return formatTable[i].format;
|
|
}
|
|
return -1;
|
|
/*
|
|
if (!strcmp( text, "argb1555\n")) return GR_TEXFMT_ARGB_1555;
|
|
else if (!strcmp( text, "argb4444\n")) return GR_TEXFMT_ARGB_4444;
|
|
else if (!strcmp( text, "rgb565\n")) return GR_TEXFMT_RGB_565;
|
|
else if (!strcmp( text, "rgb332\n")) return GR_TEXFMT_RGB_332;
|
|
else if (!strcmp( text, "argb8332\n")) return GR_TEXFMT_ARGB_8332;
|
|
else if (!strcmp( text, "p8\n")) return GR_TEXFMT_P_8;
|
|
else if (!strcmp( text, "ap88\n")) return GR_TEXFMT_AP_88;
|
|
else if (!strcmp( text, "ai44\n")) return GR_TEXFMT_ALPHA_INTENSITY_44;
|
|
else if (!strcmp( text, "yiq\n")) return GR_TEXFMT_YIQ_422;
|
|
else if (!strcmp( text, "ayiq8422\n")) return GR_TEXFMT_AYIQ_8422;
|
|
else if (!strcmp( text, "a8\n")) return GR_TEXFMT_ALPHA_8;
|
|
else if (!strcmp( text, "i8\n")) return GR_TEXFMT_INTENSITY_8;
|
|
else if (!strcmp( text, "ai88\n")) return GR_TEXFMT_ALPHA_INTENSITY_88;
|
|
// @todo: Just guessing the following format names as the docs for the texus tool
|
|
// don't mention them, and they're not supported by the PGTexture class either
|
|
else if (!strcmp( text, "rsvd0\n")) return GR_TEXFMT_RSVD0;
|
|
else if (!strcmp( text, "rsvd1\n")) return GR_TEXFMT_RSVD1;
|
|
else if (!strcmp( text, "rsvd2\n")) return GR_TEXFMT_RSVD2;
|
|
else return -1;
|
|
*/
|
|
}
|
|
|
|
int ParseLod( int Lod )
|
|
{
|
|
switch( Lod )
|
|
{
|
|
case 256: return GR_LOD_256;
|
|
case 128: return GR_LOD_128;
|
|
case 64: return GR_LOD_64;
|
|
case 32: return GR_LOD_32;
|
|
case 16: return GR_LOD_16;
|
|
case 8: return GR_LOD_8;
|
|
case 4: return GR_LOD_4;
|
|
case 2: return GR_LOD_2;
|
|
case 1: return GR_LOD_1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
GrAspectRatio_t ParseAspect( int h, int v )
|
|
{
|
|
switch ( h )
|
|
{
|
|
case 8: return GR_ASPECT_8x1;
|
|
case 4: return GR_ASPECT_4x1;
|
|
case 2: return GR_ASPECT_2x1;
|
|
case 1:
|
|
switch ( v )
|
|
{
|
|
case 8: return GR_ASPECT_1x8;
|
|
case 4: return GR_ASPECT_1x4;
|
|
case 2: return GR_ASPECT_1x2;
|
|
case 1: return GR_ASPECT_1x1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Read3dfHeader( const char *filename, Gu3dfInfo *data )
|
|
{
|
|
FILE * file3df;
|
|
char buffer[255];
|
|
int temp1,
|
|
temp2,
|
|
lod1,
|
|
lod2,
|
|
nWidth,
|
|
nHeight;
|
|
|
|
file3df = fopen( filename, "rb" );
|
|
|
|
if ( file3df == NULL )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
fgets( buffer, 255, file3df );
|
|
fgets( buffer, 255, file3df );
|
|
|
|
data->header.format = ParseTextureFormat( buffer );
|
|
|
|
fgets( buffer, 255, file3df );
|
|
sscanf( buffer, "lod range: %d %d\n", &lod1, &lod2 );
|
|
|
|
data->header.small_lod = ParseLod( lod1 );
|
|
data->header.large_lod = ParseLod( lod2 );
|
|
|
|
fgets( buffer, 255, file3df );
|
|
sscanf( buffer, "aspect ratio: %d %d\n", &temp1, &temp2 );
|
|
|
|
data->header.aspect_ratio = ParseAspect( temp1, temp2 );
|
|
|
|
switch ( data->header.aspect_ratio )
|
|
{
|
|
case GR_ASPECT_8x1: nWidth = lod2; nHeight = lod2 >> 3; break;
|
|
case GR_ASPECT_4x1: nWidth = lod2; nHeight = lod2 >> 2; break;
|
|
case GR_ASPECT_2x1: nWidth = lod2; nHeight = lod2 >> 1; break;
|
|
case GR_ASPECT_1x1: nWidth = lod2; nHeight = lod2; break;
|
|
case GR_ASPECT_1x2: nWidth = lod2 >> 1; nHeight = lod2; break;
|
|
case GR_ASPECT_1x4: nWidth = lod2 >> 2; nHeight = lod2; break;
|
|
case GR_ASPECT_1x8: nWidth = lod2 >> 3; nHeight = lod2; break;
|
|
}
|
|
|
|
data->header.width = nWidth;
|
|
data->header.height = nHeight;
|
|
|
|
{
|
|
GrLOD_t l;
|
|
|
|
data->mem_required = 0;
|
|
|
|
for ( l = data->header.large_lod; l <= data->header.small_lod; l++ )
|
|
data->mem_required += GetTexSize( l, data->header.aspect_ratio, data->header.format );
|
|
}
|
|
|
|
temp1 = ftell( file3df );
|
|
fclose( file3df );
|
|
|
|
return temp1;
|
|
}
|