1005 lines
29 KiB
C
1005 lines
29 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
|
|
**
|
|
** $Header: /cvsroot/macglide/MacGLide/glide2x/sst1/glide/src/gsplash.c,v 1.6 2006/05/18 20:50:17 jens-olaf Exp $
|
|
** $Log: gsplash.c,v $
|
|
** Revision 1.6 2006/05/18 20:50:17 jens-olaf
|
|
** No subtexturing/gapfix in splash anim
|
|
**
|
|
** Revision 1.5 2005/11/05 14:50:49 jens-olaf
|
|
** Fixed endian-issues in grLfbWriteRegion() (fixes the menu backgrunds in Carmageddon 2)
|
|
**
|
|
** Revision 1.4 2005/08/17 20:16:57 jens-olaf
|
|
** Fixed color of "3dfx" texture
|
|
**
|
|
** Revision 1.3 2005/07/14 18:54:34 jens-olaf
|
|
** Fixed clearing the screen after the last frame
|
|
**
|
|
** Revision 1.2 2005/07/11 18:59:44 jens-olaf
|
|
** Fixed buffer swap interval, added clear buffer command at the end of the animation because the last frame was displayed during game load
|
|
**
|
|
** Revision 1.1 2005/07/09 21:28:54 jens-olaf
|
|
** Added splash screen and shameless plug
|
|
**
|
|
** Revision 1.1.1.1 1999/12/07 21:48:52 joseph
|
|
** Initial checkin into SourceForge.
|
|
**
|
|
*
|
|
* 14 12/19/97 8:09a Peter
|
|
* fog table propogation
|
|
*
|
|
* 13 7/07/97 3:05p Dow
|
|
* Moved fouled clears
|
|
*
|
|
* 12 3/18/97 9:07p Dow
|
|
* Got rid of #$#%#$ // comments
|
|
*
|
|
* 11 3/16/97 12:42a Jdt
|
|
* Removed watcom warning
|
|
*
|
|
* 10 3/13/97 10:53p Jdt
|
|
* Rewrote with simple optimizations. Changed prototype for
|
|
* multi-resolution, and running as a better shameless plug.
|
|
*
|
|
* 9 3/13/97 2:52a Jdt
|
|
* Added arguments to splash.
|
|
*
|
|
* 8 3/09/97 10:31a Dow
|
|
* Added GR_DIENTRY for di glide functions
|
|
*
|
|
* 7 3/01/97 6:24p Jdt
|
|
* Made splash force yorigin.
|
|
*
|
|
* 6 1/02/97 1:06p Dow
|
|
* Fixed state bug
|
|
*
|
|
* 3 11/17/96 11:16p Garymct
|
|
* Updated grSplash code to set all of the necessary state itself rather
|
|
* than expecting the caller to do so.
|
|
*/
|
|
|
|
/*
|
|
#include <3dfx.h>
|
|
#define FX_DLL_DEFINITION
|
|
#include <fxdll.h>
|
|
#include <glide.h>
|
|
|
|
#include "fxglide.h"
|
|
*/
|
|
#include "fxinline.h"
|
|
|
|
// OpenGLide specific
|
|
#include "../../../driversrc_defines.h"
|
|
#include "Glide.h"
|
|
|
|
#include <math.h>
|
|
|
|
/*-----------------------------
|
|
Constants
|
|
-----------------------------*/
|
|
#define MAX_NUM_VERTS 2556
|
|
|
|
#define FADEIN_END_PERCENT ( 0.3f )
|
|
#define FADEOUT_BEGIN_PERCENT ( 0.8f )
|
|
|
|
#define SPIN_FRAMES 25
|
|
#define SPIN_START 26
|
|
|
|
#define NO_TABLE ((GrTexTable_t)(~0))
|
|
|
|
/*-----------------------------
|
|
Macros
|
|
-----------------------------*/
|
|
#define SNAP_BIAS ((float)(3<<18))
|
|
#define SNAP_COORD(X) ((X)+SNAP_BIAS)
|
|
|
|
/*-----------------------------
|
|
Types
|
|
-----------------------------*/
|
|
typedef struct {
|
|
float x, y, z; /* object space coordinates */
|
|
float nx, ny, nz; /* object space vertex normal for lighting */
|
|
float s, t; /* pre-glide-ified texture coordinates */
|
|
} Vert;
|
|
|
|
typedef struct {
|
|
int v[3]; /* vertex indices into array of vertes for face */
|
|
int mat_index; /* material index */
|
|
int aa_edge_flags;
|
|
} Face;
|
|
|
|
typedef float Vector[3];
|
|
typedef float Matrix[16];
|
|
|
|
// typedef FxU32 Palette[256];
|
|
typedef struct {
|
|
FxU8 yRGB[16];
|
|
FxI16 iRGB[4][3];
|
|
FxI16 qRGB[4][3];
|
|
FxU32 packed_data[12];
|
|
} NCCTable;
|
|
typedef union {
|
|
// Palette palette;
|
|
FxU32 palette[256];
|
|
NCCTable nccTable;
|
|
} TextureTable;
|
|
|
|
/*-----------------------------
|
|
Globals
|
|
-----------------------------*/
|
|
/* xScale, xOffset, yScale, yOffset */
|
|
static float viewPort[4] = {
|
|
480.0f, 320.0f,
|
|
480.0f, 240.0f
|
|
};
|
|
|
|
typedef struct {
|
|
GrTexInfo info;
|
|
FxU32 addr;
|
|
GrTexTable_t tableType;
|
|
TextureTable tableData;
|
|
} Texture;
|
|
|
|
static int do_phong = 0;
|
|
static int pass;
|
|
static int fog;
|
|
static int useTextures;
|
|
static Vector light = { -0.57735f, -0.57735f, -0.57735f };
|
|
static Vector transformed_verts[MAX_NUM_VERTS];
|
|
static Vector transformed_norms[MAX_NUM_VERTS];
|
|
|
|
#include "splshdat.inc"
|
|
|
|
static Texture textImage;
|
|
static Texture hiliteImage;
|
|
static Texture shadowImage;
|
|
|
|
static FxU32 nextFreeBase;
|
|
|
|
/*-----------------------------
|
|
Privates
|
|
-----------------------------*/
|
|
static void sourceTexture( Texture *texture ) {
|
|
static Texture *lastTexture;
|
|
|
|
if ( texture != lastTexture && useTextures ) {
|
|
grTexSource( GR_TMU0,
|
|
texture->addr,
|
|
GR_MIPMAPLEVELMASK_BOTH,
|
|
&texture->info );
|
|
if ( texture->tableType != NO_TABLE ) {
|
|
grTexDownloadTable( GR_TMU0,
|
|
texture->tableType,
|
|
&texture->tableData );
|
|
}
|
|
lastTexture = texture;
|
|
}
|
|
}
|
|
|
|
static GrTexTable_t texTableType( GrTextureFormat_t format ) {
|
|
GrTexTable_t rv = (GrTexTable_t)NO_TABLE;
|
|
switch( format ) {
|
|
case GR_TEXFMT_YIQ_422:
|
|
case GR_TEXFMT_AYIQ_8422:
|
|
rv = GR_TEXTABLE_NCC0;
|
|
break;
|
|
case GR_TEXFMT_P_8:
|
|
case GR_TEXFMT_AP_88:
|
|
rv = GR_TEXTABLE_PALETTE;
|
|
break;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
static void downloadTexture( Texture *texture, Gu3dfInfo *info ) {
|
|
texture->info.data = info->data;
|
|
texture->info.smallLod = info->header.small_lod;
|
|
texture->info.largeLod = info->header.large_lod;
|
|
texture->info.aspectRatio = info->header.aspect_ratio;
|
|
texture->info.format = info->header.format;
|
|
|
|
texture->addr = nextFreeBase;
|
|
nextFreeBase += grTexTextureMemRequired( GR_MIPMAPLEVELMASK_BOTH,
|
|
&texture->info );
|
|
grTexDownloadMipMap( GR_TMU0,
|
|
texture->addr,
|
|
GR_MIPMAPLEVELMASK_BOTH,
|
|
&texture->info );
|
|
|
|
texture->tableType = texTableType( info->header.format );
|
|
switch( texture->tableType ) {
|
|
case GR_TEXTABLE_NCC0:
|
|
case GR_TEXTABLE_NCC1:
|
|
case GR_TEXTABLE_PALETTE:
|
|
texture->tableData = *(TextureTable*)(&info->table);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
#ifdef OPENGLIDE_HOST_MAC
|
|
void ConvertGu3dfInfoLSB2MSB(Gu3dfInfo* gu3dinfo)
|
|
{
|
|
// Swap endianess fro LSB to MSB:
|
|
// Less optimal than supplying the correct data,
|
|
// but on the other hand it works with the original splash.inc
|
|
if (gu3dinfo->header.width > 0xffff)
|
|
{
|
|
// Convert the first time only...
|
|
swaplong(&gu3dinfo->header.width);
|
|
swaplong(&gu3dinfo->header.height);
|
|
swaplong(&gu3dinfo->header.small_lod);
|
|
swaplong(&gu3dinfo->header.large_lod);
|
|
swaplong(&gu3dinfo->header.aspect_ratio);
|
|
swaplong(&gu3dinfo->header.format);
|
|
// palette tables aren't swapped
|
|
// simply because they're not used
|
|
/*
|
|
for(FxU32 i = 0; i < 256; i++)
|
|
{
|
|
swaplong(&gu3dinfo->table.palette.data[i]);
|
|
}
|
|
*/
|
|
GuNccTable* ncc = &gu3dinfo->table.nccTable;
|
|
for ( int i = 0; i < 4; i++ )
|
|
{
|
|
swapshort(&ncc->iRGB[i][0]);
|
|
swapshort(&ncc->iRGB[i][1]);
|
|
swapshort(&ncc->iRGB[i][2]);
|
|
}
|
|
for ( int i = 0; i < 4; i++ )
|
|
{
|
|
swapshort(&ncc->qRGB[i][0]);
|
|
swapshort(&ncc->qRGB[i][1]);
|
|
swapshort(&ncc->qRGB[i][2]);
|
|
}
|
|
swaplong(&gu3dinfo->mem_required);
|
|
}
|
|
}
|
|
#else
|
|
void ConvertGu3dfInfoLSB2MSB(Gu3dfInfo* gu3dinfo)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
static void createTextures( void ) {
|
|
Gu3dfInfo *info;
|
|
|
|
/*
|
|
* Download the texture for the "3D" part of the model.
|
|
*/
|
|
info = ( Gu3dfInfo * )text_3dfinfo_raw;
|
|
info->data = ( void * )text_3dfinfo_image;
|
|
ConvertGu3dfInfoLSB2MSB(info);
|
|
downloadTexture( &textImage, info );
|
|
|
|
/*
|
|
* Download the texture for the specular highlight.
|
|
*/
|
|
info = ( Gu3dfInfo * )hilite_3dfinfo_raw;
|
|
info->data = ( void * )hilite_3dfinfo_image;
|
|
ConvertGu3dfInfoLSB2MSB(info);
|
|
downloadTexture( &hiliteImage, info );
|
|
|
|
/*
|
|
* Download the texture for the shadow.
|
|
*/
|
|
info = ( Gu3dfInfo * )shadow_3dfinfo_raw;
|
|
info->data = ( void * )shadow_3dfinfo_image;
|
|
ConvertGu3dfInfoLSB2MSB(info);
|
|
downloadTexture( &shadowImage, info );
|
|
return;
|
|
}
|
|
|
|
static void vecMatMult( float *dstVec, float *srcVec, float *matrix ) {
|
|
dstVec[0] =
|
|
srcVec[0] * matrix[0] +
|
|
srcVec[1] * matrix[4] +
|
|
srcVec[2] * matrix[8] +
|
|
matrix[12];
|
|
|
|
dstVec[1] =
|
|
srcVec[0] * matrix[1] +
|
|
srcVec[1] * matrix[5] +
|
|
srcVec[2] * matrix[9] +
|
|
matrix[13];
|
|
|
|
dstVec[2] =
|
|
srcVec[0] * matrix[2] +
|
|
srcVec[1] * matrix[6] +
|
|
srcVec[2] * matrix[10] +
|
|
matrix[14];
|
|
}
|
|
|
|
static void normMatMult( float *dstVec, float *srcVec, float *matrix ) {
|
|
dstVec[0] =
|
|
srcVec[0] * matrix[0] +
|
|
srcVec[1] * matrix[4] +
|
|
srcVec[2] * matrix[8];
|
|
|
|
dstVec[1] =
|
|
srcVec[0] * matrix[1] +
|
|
srcVec[1] * matrix[5] +
|
|
srcVec[2] * matrix[9];
|
|
|
|
dstVec[2] =
|
|
srcVec[0] * matrix[2] +
|
|
srcVec[1] * matrix[6] +
|
|
srcVec[2] * matrix[10];
|
|
}
|
|
|
|
static void xfAndProj( int frame, int obj ) {
|
|
int vertex;
|
|
float *matrix;
|
|
|
|
matrix = &mat[frame][obj][0];
|
|
|
|
for( vertex = 0; vertex < num_verts[obj]; vertex++ ) {
|
|
float *srcVec;
|
|
float *dstVec;
|
|
float oow;
|
|
|
|
/* transform point */
|
|
srcVec = (float*)&(vert[obj][vertex].x);
|
|
dstVec = (float*)transformed_verts[vertex];
|
|
vecMatMult( dstVec, srcVec, matrix );
|
|
|
|
/* project point */
|
|
oow = 1.0f / dstVec[2];
|
|
dstVec[0] = dstVec[0] * oow * viewPort[0] + viewPort[1] + SNAP_BIAS;
|
|
dstVec[1] = dstVec[1] * oow * viewPort[2] + viewPort[3] + SNAP_BIAS;
|
|
|
|
/* transform normal */
|
|
srcVec = (float*)&(vert[obj][vertex].nx);
|
|
dstVec = (float*)transformed_norms[vertex];
|
|
normMatMult( dstVec, srcVec, matrix );
|
|
}
|
|
}
|
|
|
|
static void setupMaterial( int material_index ) {
|
|
switch( material_index ) {
|
|
case 0: /* 3d */
|
|
if( pass == 1 ) {
|
|
sourceTexture( &textImage );
|
|
grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
|
|
GR_COMBINE_FACTOR_LOCAL,
|
|
GR_COMBINE_LOCAL_ITERATED,
|
|
GR_COMBINE_OTHER_TEXTURE,
|
|
FXFALSE );
|
|
do_phong = 1;
|
|
} else if ( pass == 0xbeef ) {
|
|
/* Pantone 320C - 3D Green */
|
|
grConstantColorValue( 0x00989100 );
|
|
grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
|
|
GR_COMBINE_FACTOR_LOCAL,
|
|
GR_COMBINE_LOCAL_CONSTANT,
|
|
GR_COMBINE_OTHER_ITERATED,
|
|
FXFALSE );
|
|
} else {
|
|
sourceTexture( &hiliteImage );
|
|
grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
|
|
GR_COMBINE_FACTOR_ONE,
|
|
GR_COMBINE_LOCAL_NONE,
|
|
GR_COMBINE_OTHER_TEXTURE,
|
|
FXFALSE );
|
|
}
|
|
break;
|
|
case 1: /* fx */
|
|
if ( pass == 0xbeef ) {
|
|
/* Black - fx */
|
|
grConstantColorValue( 0x00 );
|
|
grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
|
|
GR_COMBINE_FACTOR_LOCAL,
|
|
GR_COMBINE_LOCAL_CONSTANT,
|
|
GR_COMBINE_OTHER_ITERATED,
|
|
FXFALSE );
|
|
do_phong = 1;
|
|
} else {
|
|
sourceTexture( &hiliteImage );
|
|
grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
|
|
GR_COMBINE_FACTOR_ONE,
|
|
GR_COMBINE_LOCAL_NONE,
|
|
GR_COMBINE_OTHER_TEXTURE,
|
|
FXFALSE );
|
|
do_phong = 1;
|
|
}
|
|
break;
|
|
case 2:
|
|
case 3:
|
|
case 4:
|
|
grColorCombine( GR_COMBINE_FUNCTION_LOCAL,
|
|
GR_COMBINE_FACTOR_NONE,
|
|
GR_COMBINE_LOCAL_ITERATED,
|
|
GR_COMBINE_OTHER_NONE,
|
|
FXFALSE );
|
|
do_phong = 0;
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void calculateIntensity( int material_index,
|
|
Vector intensity_factor,
|
|
int frame ) {
|
|
switch( material_index ) {
|
|
case 0:
|
|
/* 3d */
|
|
intensity_factor[0] = 1.0f;
|
|
intensity_factor[1] = 1.0f;
|
|
intensity_factor[2] = 1.0f;
|
|
break;
|
|
case 1:
|
|
/* fx */
|
|
intensity_factor[0] = 0.125f;
|
|
intensity_factor[1] = 0.125f;
|
|
intensity_factor[2] = 0.125f;
|
|
break;
|
|
case 2:
|
|
/* cyan */
|
|
intensity_factor[0] = ( 10.0f / 255.0f );
|
|
intensity_factor[1] = ( 75.0f / 255.0f );
|
|
intensity_factor[2] = ( 120.0f / 255.0f );
|
|
break;
|
|
case 3:
|
|
/* white */
|
|
intensity_factor[0] = 1.0f;
|
|
intensity_factor[1] = 1.0f;
|
|
intensity_factor[2] = 1.0f;
|
|
break;
|
|
case 4:
|
|
/* yellow */
|
|
intensity_factor[0] = ( 248.0f / 255.0f );
|
|
intensity_factor[1] = ( 204.0f / 255.0f );
|
|
intensity_factor[2] = 0.0f;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void drawFaces( int frame, int objnum ) {
|
|
int facenum;
|
|
int material_index;
|
|
float intensity_factor[3];
|
|
GrVertex gvert[3];
|
|
static int prev_mat_index = 0xffff;
|
|
int i;
|
|
FxBool aa_a, aa_b, aa_c;
|
|
|
|
for( facenum = 0; facenum < num_faces[objnum]; facenum++ ) {
|
|
material_index = face[objnum][facenum].mat_index;
|
|
if( material_index != prev_mat_index ) {
|
|
setupMaterial( material_index );
|
|
calculateIntensity( material_index,
|
|
intensity_factor, frame );
|
|
prev_mat_index = material_index;
|
|
}
|
|
|
|
if( ( material_index != 0 ) && ( pass == 2 ) )
|
|
continue;
|
|
|
|
aa_a = aa_b = aa_c = FXFALSE;
|
|
if( face[objnum][facenum].aa_edge_flags & 4 )
|
|
aa_a = FXTRUE;
|
|
if( face[objnum][facenum].aa_edge_flags & 2 )
|
|
aa_b = FXTRUE;
|
|
if( face[objnum][facenum].aa_edge_flags & 1 )
|
|
aa_c = FXTRUE;
|
|
|
|
for( i = 0; i < 3; i++ ) {
|
|
float *transformed_vert, *transformed_norm;
|
|
Vert *v;
|
|
int vertnum;
|
|
float factor;
|
|
|
|
vertnum = face[objnum][facenum].v[i];
|
|
transformed_vert = transformed_verts[vertnum];
|
|
transformed_norm = transformed_norms[vertnum];
|
|
v = &vert[objnum][vertnum];
|
|
|
|
gvert[i].x = transformed_vert[0];
|
|
gvert[i].y = transformed_vert[1];
|
|
gvert[i].oow = 1.0f / transformed_vert[2];
|
|
gvert[i].tmuvtx[0].oow = gvert[i].oow;
|
|
gvert[i].tmuvtx[0].sow = v->s * gvert[i].oow;
|
|
gvert[i].tmuvtx[0].tow = v->t * gvert[i].oow;
|
|
|
|
factor =
|
|
( ( light[0] * transformed_norm[0] +
|
|
light[1] * transformed_norm[1] +
|
|
light[2] * transformed_norm[2] ) + 1.0f ) * 127.5f;
|
|
|
|
gvert[i].r = factor * intensity_factor[0];
|
|
gvert[i].g = factor * intensity_factor[1];
|
|
gvert[i].b = factor * intensity_factor[2];
|
|
gvert[i].a = 255.0f;
|
|
}
|
|
|
|
if( pass == 2 ) {
|
|
for( i = 0; i < 3; i++ ) {
|
|
float *transformed_norm;
|
|
|
|
transformed_norm =
|
|
transformed_norms[face[objnum][facenum].v[i]];
|
|
|
|
gvert[i].tmuvtx[0].sow = gvert[i].oow *
|
|
( 128.0f + transformed_norm[0] * 128.0f );
|
|
gvert[i].tmuvtx[0].tow = gvert[i].oow *
|
|
( 128.0f + transformed_norm[1] * 128.0f );
|
|
|
|
gvert[i].r = intensity_factor[0] * 255.0f;
|
|
gvert[i].g = intensity_factor[1] * 255.0f;
|
|
gvert[i].b = intensity_factor[2] * 255.0f;
|
|
}
|
|
|
|
grDrawTriangle( &gvert[0], &gvert[1], &gvert[2] );
|
|
|
|
continue;
|
|
}
|
|
|
|
grAlphaBlendFunction( GR_BLEND_SRC_ALPHA, GR_BLEND_ONE_MINUS_SRC_ALPHA,
|
|
GR_BLEND_ONE, GR_BLEND_ZERO );
|
|
/* Do this if 3D. */
|
|
if( material_index == 0 ) {
|
|
/*
|
|
* Draw the textured 3D without specular.
|
|
*/
|
|
sourceTexture( &textImage );
|
|
#if 0
|
|
grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
|
|
GR_COMBINE_FACTOR_LOCAL,
|
|
GR_COMBINE_LOCAL_ITERATED,
|
|
GR_COMBINE_OTHER_TEXTURE,
|
|
FXFALSE );
|
|
#endif
|
|
grAADrawTriangle( &gvert[0], &gvert[1], &gvert[2],
|
|
aa_a, aa_b, aa_c );
|
|
} else if( material_index != 1 ) {
|
|
/*
|
|
* Just go ahead and draw for things that don't
|
|
* have specular highlights.
|
|
*/
|
|
grAADrawTriangle( &gvert[0], &gvert[1], &gvert[2],
|
|
aa_a, aa_b, aa_c );
|
|
}
|
|
|
|
if( do_phong && ( material_index != 0 ) ) {
|
|
/*
|
|
* figure out texture coords in [0..255.0f] based on the normal
|
|
* the specular highlight.
|
|
*/
|
|
for( i = 0; i < 3; i++ ) {
|
|
float *transformed_norm;
|
|
|
|
transformed_norm =
|
|
transformed_norms[face[objnum][facenum].v[i]];
|
|
|
|
gvert[i].tmuvtx[0].sow = gvert[i].oow *
|
|
( 128.0f + transformed_norm[0] * 128.0f );
|
|
gvert[i].tmuvtx[0].tow = gvert[i].oow *
|
|
( 128.0f + transformed_norm[1] * 128.0f );
|
|
|
|
gvert[i].r = intensity_factor[0] * 255.0f;
|
|
gvert[i].g = intensity_factor[1] * 255.0f;
|
|
gvert[i].b = intensity_factor[2] * 255.0f;
|
|
}
|
|
grAADrawTriangle( &gvert[0], &gvert[1], &gvert[2],
|
|
aa_a, aa_b, aa_c );
|
|
}
|
|
}
|
|
}
|
|
|
|
static void intersectLineWithZPlane( Vector result, Vector p1,
|
|
Vector p2, float z ) {
|
|
float t;
|
|
|
|
t = ( z - p1[2] ) / ( p2[2] - p1[2] );
|
|
result[0] = p1[0] + ( p2[0] - p1[0] ) * t;
|
|
result[1] = p1[1] + ( p2[1] - p1[1] ) * t;
|
|
result[2] = z;
|
|
}
|
|
|
|
static float vectorMag( float *v ) {
|
|
return ( float )sqrt( v[0] * v[0] + v[1] * v[1] + v[2] * v[2] );
|
|
}
|
|
|
|
static void drawShadow( int frame, int shadow_object_index,
|
|
int receiver_object_index, Vector light_position ) {
|
|
float *shadow_object_matrix;
|
|
float *receiver_object_matrix;
|
|
Vector view_verts[4];
|
|
Vector projected_view_verts[4];
|
|
int i;
|
|
|
|
Vector local_verts[4] = {
|
|
{ -280.0f, 0.0f, -160.0f },
|
|
{ -280.0f, 0.0f, 150.0f },
|
|
{ 280.0f, 0.0f, 150.0f },
|
|
{ 280.0f, 0.0f, -160.0f }
|
|
};
|
|
|
|
float texcoords[4][2] = {
|
|
{ 10.5f, 127.5f },
|
|
{ 10.5f, 0.5f },
|
|
{ 255.0f, 0.5f },
|
|
{ 255.0f, 127.5f }
|
|
};
|
|
|
|
GrVertex gvert[4];
|
|
GrVertex projected_gvert[4];
|
|
GrVertex light_gvert;
|
|
|
|
/*
|
|
* The point relative to the back part of the shield that
|
|
* the shadow is going to be projected onto.
|
|
*/
|
|
Vector shadow_light;
|
|
|
|
shadow_light[0] = light_position[0];
|
|
shadow_light[1] = light_position[1];
|
|
shadow_light[2] = light_position[2];
|
|
|
|
shadow_object_matrix = &mat[frame][shadow_object_index][0];
|
|
receiver_object_matrix = &mat[frame][receiver_object_index][0];
|
|
|
|
/*
|
|
* Offset the light by the Z position of
|
|
* the backplane that we are projected
|
|
* onto.
|
|
*/
|
|
shadow_light[2] += receiver_object_matrix[14];
|
|
|
|
for( i = 0; i < 4; i++ ) {
|
|
vecMatMult( view_verts[i], local_verts[i], shadow_object_matrix );
|
|
|
|
/*
|
|
* project . . .
|
|
*/
|
|
gvert[i].oow = 1.0f / view_verts[i][2];
|
|
gvert[i].x =
|
|
view_verts[i][0] * gvert[i].oow * viewPort[0] +
|
|
viewPort[1] + SNAP_BIAS;
|
|
gvert[i].y =
|
|
view_verts[i][1] * gvert[i].oow * viewPort[2] +
|
|
viewPort[3] + SNAP_BIAS;
|
|
|
|
/*
|
|
* Set up texture coordinates.
|
|
*/
|
|
gvert[i].tmuvtx[0].sow = texcoords[i][0] * gvert[i].oow;
|
|
gvert[i].tmuvtx[0].tow = texcoords[i][1] * gvert[i].oow;
|
|
}
|
|
|
|
|
|
/*
|
|
* Intersect each line formed by the light source and a
|
|
* particular corner of the shadow object with the
|
|
* plane which the texture is to be projected onto.
|
|
*/
|
|
for( i = 0; i < 4; i++ ) {
|
|
Vector tmpvect;
|
|
float q;
|
|
|
|
intersectLineWithZPlane( projected_view_verts[i],
|
|
shadow_light,
|
|
view_verts[i],
|
|
receiver_object_matrix[14] - 26.0f );
|
|
projected_gvert[i].oow = 1.0f / projected_view_verts[i][2];
|
|
projected_gvert[i].x =
|
|
projected_view_verts[i][0] * projected_gvert[i].oow * viewPort[0] +
|
|
viewPort[1] + SNAP_BIAS;
|
|
projected_gvert[i].y =
|
|
projected_view_verts[i][1] * projected_gvert[i].oow * viewPort[2] +
|
|
viewPort[3] + SNAP_BIAS;
|
|
|
|
tmpvect[0] = projected_view_verts[i][0] - shadow_light[0];
|
|
tmpvect[1] = projected_view_verts[i][1] - shadow_light[1];
|
|
tmpvect[2] = projected_view_verts[i][2] - shadow_light[2];
|
|
q = vectorMag( tmpvect );
|
|
|
|
/*
|
|
* Set up texture coordinates.
|
|
*/
|
|
projected_gvert[i].tmuvtx[0].oow = projected_gvert[i].oow * q;
|
|
projected_gvert[i].tmuvtx[0].sow =
|
|
texcoords[i][0] * projected_gvert[i].oow;
|
|
projected_gvert[i].tmuvtx[0].tow =
|
|
texcoords[i][1] * projected_gvert[i].oow;
|
|
}
|
|
|
|
light_gvert.oow = 1.0f / shadow_light[2];
|
|
light_gvert.x = shadow_light[0] * light_gvert.oow * viewPort[0] +
|
|
viewPort[1] + SNAP_BIAS;
|
|
light_gvert.y = shadow_light[1] * light_gvert.oow * viewPort[2] +
|
|
viewPort[3] + SNAP_BIAS;
|
|
|
|
/*
|
|
* Draw a segment between the light and the point which hits
|
|
* the surface that the light is being projected onto.
|
|
*/
|
|
grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER,
|
|
GR_COMBINE_FACTOR_ONE,
|
|
GR_COMBINE_LOCAL_NONE,
|
|
GR_COMBINE_OTHER_TEXTURE,
|
|
FXFALSE );
|
|
sourceTexture( &shadowImage );
|
|
|
|
grAlphaBlendFunction( GR_BLEND_DST_COLOR, GR_BLEND_ZERO,
|
|
GR_BLEND_ONE, GR_BLEND_ZERO );
|
|
|
|
|
|
grDrawTriangle( &projected_gvert[0],
|
|
&projected_gvert[1],
|
|
&projected_gvert[2] );
|
|
grDrawTriangle( &projected_gvert[0],
|
|
&projected_gvert[2],
|
|
&projected_gvert[3] );
|
|
grDrawTriangle( &projected_gvert[0],
|
|
&projected_gvert[2],
|
|
&projected_gvert[1] );
|
|
grDrawTriangle( &projected_gvert[0],
|
|
&projected_gvert[3],
|
|
&projected_gvert[2] );
|
|
|
|
grAlphaBlendFunction( GR_BLEND_ONE, GR_BLEND_ZERO,
|
|
GR_BLEND_ONE, GR_BLEND_ZERO );
|
|
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------------------------
|
|
Function: grSplash
|
|
Date: 3/13
|
|
Implementor(s): GaryMcT
|
|
Library: Glide
|
|
Description:
|
|
Render the opening splash screen animation, or render
|
|
a single frame of the splash screen.
|
|
Arguments:
|
|
x, y - upper left hand coord of window
|
|
w, h - width and height of window to render
|
|
_frame - frame number to render ( ~0 to render all frames )
|
|
Return:
|
|
none
|
|
-------------------------------------------------------------------*/
|
|
GR_DIENTRY(grSplash,void,(float x,float y,float w,float h,FxU32 _frame))
|
|
{
|
|
// OpenGLide addition
|
|
#ifdef OGL_DONE
|
|
GlideMsg( "grSplash( %-4.2f, %-4.2f, %-4.2f, %-4.2f, %lu )\n",
|
|
x, y, w, h, _frame );
|
|
#endif
|
|
|
|
GrState oldState;
|
|
int frame;
|
|
Vector lights[] = {
|
|
{ 5.0f, 300.0f, -1500.0f },
|
|
{ 5.0f, 150.0f, -1000.0f },
|
|
{ -30.0f, 150.0f, -1000.0f },
|
|
{ -30.0f, 100.0f, -1000.0f },
|
|
{ 30.0f, 70.0f, -1000.0f },
|
|
};
|
|
GrFog_t fogTable[kInternalFogTableEntryCount];
|
|
int fadeInFrames, fadeOutFrames;
|
|
|
|
GR_BEGIN_NOFIFOCHECK( "grSplash", 85 );
|
|
GDBG_INFO_MORE((gc->myLevel,"(%f,%f,%f,%f,%d)\n",
|
|
x, y, w, h, _frame ));
|
|
|
|
/* Check Screen Dimensions and Check Avail of Depth Buffer */
|
|
// The emulation offers virtually unlimited buffers, so we don't have to check
|
|
/*
|
|
if ( (x > gc->state.screen_width) ||
|
|
((x+w) > gc->state.screen_width) ||
|
|
( y > gc->state.screen_height ) ||
|
|
((y+h) > gc->state.screen_height ) )
|
|
return;
|
|
if ( gc->state.screen_height == 640 ) {
|
|
if ( gc->fbuf_size == 1 ) {
|
|
return;
|
|
}
|
|
} else if ( gc->state.screen_width == 800 ) {
|
|
if ( ( gc->fbuf_size == 1 ) ||
|
|
( gc->fbuf_size == 2 ) ) {
|
|
return;
|
|
}
|
|
}
|
|
*/
|
|
|
|
// subtexturing doesn't work with the splash animation
|
|
// so we're going to turn it off temporarily
|
|
const unsigned long generatesubtextures = InternalConfig.GenerateSubTextures; InternalConfig.GenerateSubTextures = 0;
|
|
// Gapfix decreases the framerate but doesn't improve the rendering quality of the animation
|
|
const OpenGLideGapFixFlags gapfix = InternalConfig.GapFix; InternalConfig.GapFix = OpenGLideGapFixFlag_Disabled;
|
|
|
|
// if ( !(gc->state.fbi_config.fbzMode & SST_YORIGIN)
|
|
if (Glide.State.OriginInformation == GR_ORIGIN_LOWER_LEFT) // @todo: correct?
|
|
{
|
|
y = (( Glide.WindowHeight - 1.0f ) - (h-1.0f) ) - y;
|
|
}
|
|
|
|
viewPort[0] = w * ( 480.0f / 640.0f );
|
|
viewPort[1] = x + ( w / 2.0f );
|
|
viewPort[2] = h;
|
|
viewPort[3] = y + ( h / 2.0f );
|
|
|
|
grGlideGetState(&oldState);
|
|
|
|
grSstOrigin( GR_ORIGIN_LOWER_LEFT );
|
|
|
|
if ( _frame == 0 ) {
|
|
createTextures();
|
|
useTextures = 1;
|
|
} else {
|
|
useTextures = 0;
|
|
}
|
|
|
|
grAlphaTestFunction( GR_CMP_ALWAYS );
|
|
grChromakeyMode( GR_CHROMAKEY_DISABLE );
|
|
grConstantColorValue( 0xffffffff );
|
|
grDepthBufferMode( GR_DEPTHBUFFER_WBUFFER );
|
|
grDepthMask( FXTRUE );
|
|
grAlphaCombine( GR_COMBINE_FUNCTION_LOCAL,
|
|
GR_COMBINE_FACTOR_NONE,
|
|
GR_COMBINE_LOCAL_ITERATED,
|
|
GR_COMBINE_OTHER_NONE,
|
|
FXFALSE );
|
|
grAlphaBlendFunction( GR_BLEND_ONE, GR_BLEND_ZERO,
|
|
GR_BLEND_ONE, GR_BLEND_ZERO );
|
|
if ( useTextures )
|
|
grTexCombine( GR_TMU0,
|
|
GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE,
|
|
GR_COMBINE_FUNCTION_NONE, GR_COMBINE_FACTOR_NONE,
|
|
FXFALSE, FXFALSE );
|
|
else
|
|
grTexCombine( GR_TMU0,
|
|
GR_COMBINE_FUNCTION_ZERO, GR_COMBINE_FACTOR_NONE,
|
|
GR_COMBINE_FUNCTION_NONE, GR_COMBINE_FACTOR_NONE,
|
|
FXTRUE, FXFALSE );
|
|
grTexMipMapMode( GR_TMU0,
|
|
GR_MIPMAP_NEAREST,
|
|
FXFALSE );
|
|
grTexFilterMode( GR_TMU0,
|
|
GR_TEXTUREFILTER_BILINEAR,
|
|
GR_TEXTUREFILTER_BILINEAR );
|
|
grDepthBufferFunction( GR_CMP_LEQUAL );
|
|
grCullMode( GR_CULL_NEGATIVE );
|
|
// grClipWindow( (int)x, (int)y, (int)(x+w), (int)(y+h) );
|
|
grFogColorValue( 0x0 );
|
|
|
|
fadeInFrames = (int)(((float)total_num_frames) * FADEIN_END_PERCENT);
|
|
fadeOutFrames = (int)(((float)total_num_frames) *
|
|
(1.0f - FADEOUT_BEGIN_PERCENT));
|
|
|
|
if ( _frame == 0 ) { /* Render Whole Animation */
|
|
for( frame = 1; frame < total_num_frames; frame++ ) {
|
|
int i;
|
|
|
|
/* Set Fog Value For This Frame */
|
|
if( frame < fadeInFrames ) {
|
|
unsigned char fval =
|
|
((unsigned char)255) -
|
|
((unsigned char)( 255.0f *
|
|
(float)(frame+1) /
|
|
(float)fadeInFrames ));
|
|
for( i = 0; i < kInternalFogTableEntryCount; i++ )
|
|
fogTable[i] = fval;
|
|
grFogMode( GR_FOG_WITH_TABLE );
|
|
grFogTable( fogTable );
|
|
fog = 1;
|
|
} else if( frame > total_num_frames-fadeOutFrames ) {
|
|
unsigned char fval =
|
|
((unsigned char)255) -
|
|
(unsigned char)(255.0f*
|
|
((float)(total_num_frames-frame))/
|
|
((float)fadeOutFrames));
|
|
for( i = 0; i < kInternalFogTableEntryCount; i++ )
|
|
fogTable[i] = fval;
|
|
grFogMode( GR_FOG_WITH_TABLE );
|
|
grFogTable( fogTable );
|
|
fog = 1;
|
|
} else {
|
|
grFogMode( GR_FOG_DISABLE );
|
|
fog = 0;
|
|
}
|
|
grBufferClear( 0x00000000, 0, GR_WDEPTHVALUE_FARTHEST );
|
|
|
|
pass = 1;
|
|
|
|
/*
|
|
* Avoid Z-aliasing between the shield and the 3dfx by
|
|
* not writing Z for the shield.
|
|
*/
|
|
|
|
grDepthMask( FXFALSE );
|
|
/* cyan part of shield */
|
|
xfAndProj( frame, 2 );
|
|
drawFaces( frame, 2 );
|
|
|
|
/* yellow and white part of shield. */
|
|
xfAndProj( frame, 0 );
|
|
drawFaces( frame, 0 );
|
|
|
|
/*
|
|
* Reanable writes to the depth-buffer.
|
|
*/
|
|
grDepthMask( FXTRUE );
|
|
|
|
/*
|
|
* Draw the shadow projected from the 3Dfx logo onto
|
|
* the rest of the powershield.
|
|
*/
|
|
grDepthBufferFunction( GR_CMP_ALWAYS );
|
|
grFogMode( GR_FOG_DISABLE );
|
|
drawShadow( frame, 1, 0, lights[0] );
|
|
if ( fog ) grFogMode( GR_FOG_WITH_TABLE ); /* hack around mp fog */
|
|
grDepthBufferFunction( GR_CMP_LEQUAL );
|
|
|
|
/* 3Dfx logo */
|
|
xfAndProj( frame, 1 );
|
|
drawFaces( frame, 1 );
|
|
grAlphaBlendFunction( GR_BLEND_ONE, GR_BLEND_ONE,
|
|
GR_BLEND_ONE, GR_BLEND_ZERO );
|
|
|
|
pass = 2;
|
|
drawFaces( frame, 1 );
|
|
pass = 1;
|
|
grAlphaBlendFunction( GR_BLEND_ONE, GR_BLEND_ZERO,
|
|
GR_BLEND_ONE, GR_BLEND_ZERO );
|
|
grBufferSwap( 2 );
|
|
}
|
|
} else { /* Render One Frame */
|
|
frame = ((_frame>>1) % SPIN_FRAMES)+SPIN_START;
|
|
|
|
grColorMask( FXFALSE, FXFALSE );
|
|
grBufferClear( 0x00000000, 0, GR_WDEPTHVALUE_FARTHEST );
|
|
grColorMask( FXTRUE, FXFALSE );
|
|
|
|
pass = 0xbeef;
|
|
|
|
/* 3Dfx logo */
|
|
xfAndProj( frame, 1 );
|
|
drawFaces( frame, 1 );
|
|
}
|
|
|
|
|
|
// Added by Jenz: Clear the buffer after the last frame to avoid
|
|
// the last image be displayed while the game is loading
|
|
// (May be a problem of MacGLide since the 3dfx hardware
|
|
if (_frame == 0)
|
|
{
|
|
grColorMask(FXTRUE, FXTRUE);
|
|
grBufferClear(0x00000000, 0, GR_WDEPTHVALUE_FARTHEST);
|
|
grColorMask(FXTRUE, FXFALSE);
|
|
grBufferSwap( 2 );
|
|
|
|
}
|
|
/*
|
|
* Clean up after yourself!
|
|
*/
|
|
grGlideSetState(&oldState);
|
|
|
|
// Reenable temporarily disabled settings
|
|
InternalConfig.GenerateSubTextures = generatesubtextures;
|
|
InternalConfig.GapFix = gapfix;
|
|
}
|
|
|
|
|