425 lines
9.8 KiB
C
425 lines
9.8 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 <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <conio.h>
|
|
#include <glide.h>
|
|
#include <texus.h>
|
|
|
|
/*
|
|
* VIEWPPM
|
|
* This is a simple program to show how to use the Texus library
|
|
* to convert textures from an in memory format to a format
|
|
* that Glide can handle for texture downloads.
|
|
*/
|
|
|
|
typedef struct
|
|
{
|
|
unsigned char b, g, r, a;
|
|
} Color32;
|
|
|
|
/*
|
|
* This structure contains the factors to multiply normalized [0.0, 1.0]
|
|
* texture coordinates by in order to get the texture coordinates that
|
|
* Voodoo Graphics expect.
|
|
*/
|
|
typedef struct
|
|
{
|
|
float sMult;
|
|
float tMult;
|
|
} TexCoordFactors;
|
|
|
|
/*
|
|
* An array which is indexed by GrAspectRatio_t to convert from normalized
|
|
* texture coordinates to Voodoo texture coordinates.
|
|
*/
|
|
TexCoordFactors aspectToTexCoordFactors[7] = {
|
|
{ 255.0f, 255.0f / 8.0f }, /* GR_ASPECT_8x1 */
|
|
{ 255.0f, 255.0f / 4.0f }, /* GR_ASPECT_4x1 */
|
|
{ 255.0f, 255.0f / 2.0f }, /* GR_ASPECT_2x1 */
|
|
{ 255.0f, 255.0f }, /* GR_ASPECT_1x1 */
|
|
{ 255.0f / 2.0f, 255.0f }, /* GR_ASPECT_1x2 */
|
|
{ 255.0f / 4.0f, 255.0f }, /* GR_ASPECT_1x4 */
|
|
{ 255.0f / 8.0f, 255.0f } /* GR_ASPECT_1x8 */
|
|
};
|
|
|
|
/*
|
|
* Do whatever is necessary to get Glide going.
|
|
*/
|
|
void InitGlide( void )
|
|
{
|
|
static GrHwConfiguration hwconfig;
|
|
|
|
grGlideInit();
|
|
|
|
if ( !grSstQueryHardware( &hwconfig ) )
|
|
{
|
|
fprintf( stderr, "grQuery failed!" );
|
|
exit( -1 );
|
|
}
|
|
|
|
grSstSelect( 0 );
|
|
|
|
if ( !grSstWinOpen( 0,
|
|
GR_RESOLUTION_640x480,
|
|
GR_REFRESH_60Hz,
|
|
GR_COLORFORMAT_ABGR,
|
|
GR_ORIGIN_UPPER_LEFT,
|
|
2, 0 ) )
|
|
{
|
|
fprintf( stderr, "grOpen failed!" );
|
|
exit( -1 );
|
|
}
|
|
|
|
grTexCombineFunction( GR_TMU0, GR_TEXTURECOMBINE_DECAL );
|
|
guColorCombineFunction( GR_COLORCOMBINE_DECAL_TEXTURE );
|
|
grCullMode( GR_CULL_NEGATIVE );
|
|
}
|
|
|
|
int ValidateImageDimensions( int width, int height )
|
|
{
|
|
switch( width )
|
|
{
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
case 8:
|
|
case 16:
|
|
case 32:
|
|
case 64:
|
|
case 128:
|
|
case 256:
|
|
break;
|
|
default:
|
|
fprintf( stderr, "Invalid image width: %d\n", width );
|
|
return 0;
|
|
}
|
|
|
|
switch( height )
|
|
{
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
case 8:
|
|
case 16:
|
|
case 32:
|
|
case 64:
|
|
case 128:
|
|
case 256:
|
|
break;
|
|
default:
|
|
fprintf( stderr, "Invalid image height: %d\n", height );
|
|
return 0;
|
|
}
|
|
|
|
if( ( ( width / height ) > 8 ) || ( ( height / width ) > 8 ) )
|
|
{
|
|
fprintf( stderr, "Invalid aspect ratio, must one of:\n" );
|
|
fprintf( stderr, "1:8, 1:4, 1:2, 1:1, 2:1, 4:1, 8:1\n" );
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Get the dimensions of a PPM file.
|
|
* returns 1 if successful, 0 otherwise.
|
|
*/
|
|
int PPMGetDimensions( const char *filename, int *width, int *height )
|
|
{
|
|
FILE *fp;
|
|
char buf[200];
|
|
|
|
/*
|
|
* Open the PPM file.
|
|
*/
|
|
if( !( fp = fopen( filename, "rb" ) ) )
|
|
return 0;
|
|
|
|
/*
|
|
* Read the PPM header.
|
|
*/
|
|
|
|
/* Skip the P6 */
|
|
fgets( buf, 200, fp );
|
|
|
|
/* REad the dimensions */
|
|
fgets( buf, 200, fp );
|
|
sscanf( buf, "%d %d", width, height );
|
|
|
|
fclose( fp );
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* LoadPPM
|
|
* Allocate memory for an image, load a ppm file into it.
|
|
* Not the most efficient loader because it reads directly
|
|
* into a 8888 instead of an 888 without allocating any
|
|
* extra memory.
|
|
*/
|
|
Color32 *PPMLoad( const char *filename )
|
|
{
|
|
Color32 *out;
|
|
char buf[200];
|
|
FILE *fp;
|
|
int width, height;
|
|
long i;
|
|
|
|
/*
|
|
* Open the PPM file.
|
|
*/
|
|
if( !( fp = fopen( filename, "rb" ) ) )
|
|
return NULL;
|
|
|
|
/*
|
|
* Read the PPM header.
|
|
*/
|
|
|
|
/* Skip the P6 */
|
|
fgets( buf, 200, fp );
|
|
|
|
/* REad the dimensions */
|
|
fgets( buf, 200, fp );
|
|
sscanf( buf, "%d %d", &width, &height );
|
|
|
|
/* Skip the maxval line. . . assume that it is 255. */
|
|
fgets( buf, 200, fp );
|
|
|
|
/*
|
|
* Allocate memory for the output image.
|
|
*/
|
|
out = ( Color32 * )malloc( sizeof( Color32 ) * ( long )width * ( long )height );
|
|
|
|
if( !out )
|
|
{
|
|
fclose( fp );
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Read in each texel. . .fill in the alpha with a totally
|
|
* opaque value.
|
|
*/
|
|
for( i = 0; i < ( long )width * ( long )height; i++ )
|
|
{
|
|
fread( &out[i].r, 1, 1, fp );
|
|
fread( &out[i].g, 1, 1, fp );
|
|
fread( &out[i].b, 1, 1, fp );
|
|
out[i].a = 0xff;
|
|
}
|
|
|
|
fclose( fp );
|
|
|
|
return out;
|
|
}
|
|
|
|
|
|
int main( int argc, char **argv )
|
|
{
|
|
Color32 *raw_image;
|
|
size_t tex_mem_required;
|
|
Gu3dfInfo info;
|
|
int ppm_width, ppm_height;
|
|
int target_width, target_height;
|
|
GrMipMapId_t mmid;
|
|
GrVertex vtx[4];
|
|
float smult, tmult;
|
|
|
|
if( argc < 2 )
|
|
{
|
|
fprintf( stderr, "Usage: %s in.ppm [display_width display_height] \n", argv[0] );
|
|
exit( -1 );
|
|
}
|
|
|
|
InitGlide();
|
|
|
|
if( !PPMGetDimensions( argv[1], &ppm_width, &ppm_height ) )
|
|
{
|
|
fprintf( stderr, "Error getting PPM dimensions\n" );
|
|
exit( -1 );
|
|
}
|
|
|
|
/*
|
|
* If there are args to resize the image, then remember them.
|
|
*/
|
|
if( argc == 4 )
|
|
{
|
|
target_width = atoi( argv[2] );
|
|
target_height = atoi( argv[3] );
|
|
}
|
|
else
|
|
{
|
|
target_width = ppm_width;
|
|
target_height = ppm_height;
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
* Validate the geometry of the output image.
|
|
*/
|
|
if( !ValidateImageDimensions( target_width, target_height ) )
|
|
{
|
|
fprintf( stderr, "Invalid image dimensions\n" );
|
|
exit( -1 );
|
|
}
|
|
#endif
|
|
|
|
tex_mem_required = txInit3dfInfo( &info, GR_TEXFMT_P_8,
|
|
&target_width, &target_height,
|
|
-1, TX_AUTORESIZE_GROW );
|
|
|
|
/*
|
|
* Allocate system memory for the texture.
|
|
*/
|
|
info.data = malloc( tex_mem_required );
|
|
if( !info.data )
|
|
{
|
|
fprintf( stderr, "Out of memory allocating system memory textures.\n" );
|
|
exit( -1 );
|
|
}
|
|
|
|
/*
|
|
* Make sure txInit3dfInfo didn't fail.
|
|
*/
|
|
if( tex_mem_required == 0 )
|
|
{
|
|
fprintf( stderr, "Problem with txInit3dfInfo\n" );
|
|
exit( -1 );
|
|
}
|
|
|
|
/*
|
|
* Read the PPM image.
|
|
*/
|
|
if( !( raw_image = PPMLoad( argv[1] ) ) )
|
|
{
|
|
fprintf( stderr, "Not able to load PPM file.\n" );
|
|
exit( -1 );
|
|
}
|
|
|
|
/*
|
|
* Convert to a texture that can be downloaded to the hardware.
|
|
*/
|
|
txConvert( &info, GR_TEXFMT_ARGB_8888,
|
|
ppm_width, ppm_height,
|
|
raw_image, TX_DITHER_NONE, NULL );
|
|
|
|
{
|
|
FILE *fp;
|
|
|
|
fprintf( stderr, "Writing blah.3df\n" );
|
|
if( !( fp = fopen( "blah.3df", "wb" ) ) )
|
|
{
|
|
fprintf( stderr, "Not able to open output file.\n" );
|
|
exit( -1 );
|
|
}
|
|
|
|
txWrite( &info, fp, TX_WRITE_3DF );
|
|
fclose( fp );
|
|
|
|
grTexDownloadTable( GR_TMU0,
|
|
GR_TEXTABLE_PALETTE,
|
|
&info.table.palette.data );
|
|
}
|
|
|
|
/*
|
|
* Call Glide to allocate memory for the converted texture.
|
|
*/
|
|
mmid = guTexAllocateMemory( 0, GR_MIPMAPLEVELMASK_BOTH,
|
|
info.header.width, info.header.height,
|
|
info.header.format,
|
|
GR_MIPMAP_NEAREST,
|
|
info.header.small_lod, info.header.large_lod,
|
|
info.header.aspect_ratio,
|
|
GR_TEXTURECLAMP_WRAP, GR_TEXTURECLAMP_WRAP,
|
|
GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR,
|
|
0.0F,
|
|
FXFALSE );
|
|
|
|
/*
|
|
* Download the texture and set it as the current texture.
|
|
*/
|
|
guTexDownloadMipMap( mmid, info.data, &info.table.nccTable );
|
|
guTexSource( mmid );
|
|
|
|
/*
|
|
* Figure out what the factor is to get from normalized texture
|
|
* coords to something that the hardware can deal with.
|
|
*/
|
|
smult = aspectToTexCoordFactors[info.header.aspect_ratio].sMult;
|
|
tmult = aspectToTexCoordFactors[info.header.aspect_ratio].tMult;
|
|
|
|
/*
|
|
* Set up some verts to draw the texture on a couple of triangles
|
|
* with.
|
|
*/
|
|
vtx[0].x = 0.0f;
|
|
vtx[0].y = 0.0f;
|
|
vtx[0].oow = 1.0f;
|
|
vtx[0].tmuvtx[0].sow = 0.0f;
|
|
vtx[0].tmuvtx[0].tow = 0.0f;
|
|
|
|
vtx[1].x = ( float )target_width - 1.0f;
|
|
vtx[1].y = 0.0f;
|
|
vtx[1].oow = 1.0f;
|
|
vtx[1].tmuvtx[0].sow = 1.0f * smult;
|
|
vtx[1].tmuvtx[0].tow = 0.0f;
|
|
|
|
vtx[2].x = ( float )target_width - 1.0f;
|
|
vtx[2].y = ( float )target_height - 1.0f;
|
|
vtx[2].oow = 1.0f;
|
|
vtx[2].tmuvtx[0].sow = 1.0f * smult;
|
|
vtx[2].tmuvtx[0].tow = 1.0f * tmult;
|
|
|
|
vtx[3].x = 0.0f;
|
|
vtx[3].y = ( float )target_height - 1.0f;
|
|
vtx[3].oow = 1.0f;
|
|
vtx[3].tmuvtx[0].sow = 0.0f;
|
|
vtx[3].tmuvtx[0].tow = 1.0f * tmult;
|
|
|
|
printf( "Hit a key to exit\n" );
|
|
fflush( stdout );
|
|
|
|
while( !kbhit() )
|
|
{
|
|
grDrawTriangle( &vtx[0], &vtx[1], &vtx[2] );
|
|
grDrawTriangle( &vtx[0], &vtx[2], &vtx[3] );
|
|
grBufferSwap( 1 );
|
|
}
|
|
|
|
/*
|
|
* Shutdown Glide (and switch the passthru back to the
|
|
* main display.
|
|
*/
|
|
grGlideShutdown();
|
|
|
|
/*
|
|
* Clean up.
|
|
*/
|
|
free( raw_image );
|
|
free( info.data );
|
|
|
|
return 0;
|
|
}
|