📄 tr_shader.c
字号:
// depthmask
//
else if ( !Q_stricmp( token, "depthwrite" ) )
{
depthMaskBits = GLS_DEPTHMASK_TRUE;
depthMaskExplicit = qtrue;
continue;
}
else
{
ri.Printf( PRINT_WARNING, "WARNING: unknown parameter '%s' in shader '%s'\n", token, shader.name );
return qfalse;
}
}
//
// if cgen isn't explicitly specified, use either identity or identitylighting
//
if ( stage->rgbGen == CGEN_BAD ) {
if ( blendSrcBits == 0 ||
blendSrcBits == GLS_SRCBLEND_ONE ||
blendSrcBits == GLS_SRCBLEND_SRC_ALPHA ) {
stage->rgbGen = CGEN_IDENTITY_LIGHTING;
} else {
stage->rgbGen = CGEN_IDENTITY;
}
}
//
// implicitly assume that a GL_ONE GL_ZERO blend mask disables blending
//
if ( ( blendSrcBits == GLS_SRCBLEND_ONE ) &&
( blendDstBits == GLS_DSTBLEND_ZERO ) )
{
blendDstBits = blendSrcBits = 0;
depthMaskBits = GLS_DEPTHMASK_TRUE;
}
// decide which agens we can skip
if ( stage->alphaGen == CGEN_IDENTITY ) {
if ( stage->rgbGen == CGEN_IDENTITY
|| stage->rgbGen == CGEN_LIGHTING_DIFFUSE ) {
stage->alphaGen = AGEN_SKIP;
}
}
//
// compute state bits
//
stage->stateBits = depthMaskBits |
blendSrcBits | blendDstBits |
atestBits |
depthFuncBits;
return qtrue;
}
/*
===============
ParseDeform
deformVertexes wave <spread> <waveform> <base> <amplitude> <phase> <frequency>
deformVertexes normal <frequency> <amplitude>
deformVertexes move <vector> <waveform> <base> <amplitude> <phase> <frequency>
deformVertexes bulge <bulgeWidth> <bulgeHeight> <bulgeSpeed>
deformVertexes projectionShadow
deformVertexes autoSprite
deformVertexes autoSprite2
deformVertexes text[0-7]
===============
*/
static void ParseDeform( char **text ) {
char *token;
deformStage_t *ds;
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
ri.Printf( PRINT_WARNING, "WARNING: missing deform parm in shader '%s'\n", shader.name );
return;
}
if ( shader.numDeforms == MAX_SHADER_DEFORMS ) {
ri.Printf( PRINT_WARNING, "WARNING: MAX_SHADER_DEFORMS in '%s'\n", shader.name );
return;
}
ds = &shader.deforms[ shader.numDeforms ];
shader.numDeforms++;
if ( !Q_stricmp( token, "projectionShadow" ) ) {
ds->deformation = DEFORM_PROJECTION_SHADOW;
return;
}
if ( !Q_stricmp( token, "autosprite" ) ) {
ds->deformation = DEFORM_AUTOSPRITE;
return;
}
if ( !Q_stricmp( token, "autosprite2" ) ) {
ds->deformation = DEFORM_AUTOSPRITE2;
return;
}
if ( !Q_stricmpn( token, "text", 4 ) ) {
int n;
n = token[4] - '0';
if ( n < 0 || n > 7 ) {
n = 0;
}
ds->deformation = DEFORM_TEXT0 + n;
return;
}
if ( !Q_stricmp( token, "bulge" ) ) {
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
return;
}
ds->bulgeWidth = atof( token );
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
return;
}
ds->bulgeHeight = atof( token );
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes bulge parm in shader '%s'\n", shader.name );
return;
}
ds->bulgeSpeed = atof( token );
ds->deformation = DEFORM_BULGE;
return;
}
if ( !Q_stricmp( token, "wave" ) )
{
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
return;
}
if ( atof( token ) != 0 )
{
ds->deformationSpread = 1.0f / atof( token );
}
else
{
ds->deformationSpread = 100.0f;
ri.Printf( PRINT_WARNING, "WARNING: illegal div value of 0 in deformVertexes command for shader '%s'\n", shader.name );
}
ParseWaveForm( text, &ds->deformationWave );
ds->deformation = DEFORM_WAVE;
return;
}
if ( !Q_stricmp( token, "normal" ) )
{
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
return;
}
ds->deformationWave.amplitude = atof( token );
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 )
{
ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
return;
}
ds->deformationWave.frequency = atof( token );
ds->deformation = DEFORM_NORMALS;
return;
}
if ( !Q_stricmp( token, "move" ) ) {
int i;
for ( i = 0 ; i < 3 ; i++ ) {
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 ) {
ri.Printf( PRINT_WARNING, "WARNING: missing deformVertexes parm in shader '%s'\n", shader.name );
return;
}
ds->moveVector[i] = atof( token );
}
ParseWaveForm( text, &ds->deformationWave );
ds->deformation = DEFORM_MOVE;
return;
}
ri.Printf( PRINT_WARNING, "WARNING: unknown deformVertexes subtype '%s' found in shader '%s'\n", token, shader.name );
}
/*
===============
ParseSkyParms
skyParms <outerbox> <cloudheight> <innerbox>
===============
*/
static void ParseSkyParms( char **text ) {
char *token;
static char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
char pathname[MAX_QPATH];
int i;
// outerbox
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 ) {
ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
return;
}
if ( strcmp( token, "-" ) ) {
for (i=0 ; i<6 ; i++) {
Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga"
, token, suf[i] );
shader.sky.outerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_CLAMP );
if ( !shader.sky.outerbox[i] ) {
shader.sky.outerbox[i] = tr.defaultImage;
}
}
}
// cloudheight
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 ) {
ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
return;
}
shader.sky.cloudHeight = atof( token );
if ( !shader.sky.cloudHeight ) {
shader.sky.cloudHeight = 512;
}
R_InitSkyTexCoords( shader.sky.cloudHeight );
// innerbox
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 ) {
ri.Printf( PRINT_WARNING, "WARNING: 'skyParms' missing parameter in shader '%s'\n", shader.name );
return;
}
if ( strcmp( token, "-" ) ) {
for (i=0 ; i<6 ; i++) {
Com_sprintf( pathname, sizeof(pathname), "%s_%s.tga"
, token, suf[i] );
shader.sky.innerbox[i] = R_FindImageFile( ( char * ) pathname, qtrue, qtrue, GL_REPEAT );
if ( !shader.sky.innerbox[i] ) {
shader.sky.innerbox[i] = tr.defaultImage;
}
}
}
shader.isSky = qtrue;
}
/*
=================
ParseSort
=================
*/
void ParseSort( char **text ) {
char *token;
token = COM_ParseExt( text, qfalse );
if ( token[0] == 0 ) {
ri.Printf( PRINT_WARNING, "WARNING: missing sort parameter in shader '%s'\n", shader.name );
return;
}
if ( !Q_stricmp( token, "portal" ) ) {
shader.sort = SS_PORTAL;
} else if ( !Q_stricmp( token, "sky" ) ) {
shader.sort = SS_ENVIRONMENT;
} else if ( !Q_stricmp( token, "opaque" ) ) {
shader.sort = SS_OPAQUE;
}else if ( !Q_stricmp( token, "decal" ) ) {
shader.sort = SS_DECAL;
} else if ( !Q_stricmp( token, "seeThrough" ) ) {
shader.sort = SS_SEE_THROUGH;
} else if ( !Q_stricmp( token, "banner" ) ) {
shader.sort = SS_BANNER;
} else if ( !Q_stricmp( token, "additive" ) ) {
shader.sort = SS_BLEND1;
} else if ( !Q_stricmp( token, "nearest" ) ) {
shader.sort = SS_NEAREST;
} else if ( !Q_stricmp( token, "underwater" ) ) {
shader.sort = SS_UNDERWATER;
} else {
shader.sort = atof( token );
}
}
// this table is also present in q3map
typedef struct {
char *name;
int clearSolid, surfaceFlags, contents;
} infoParm_t;
infoParm_t infoParms[] = {
// server relevant contents
{"water", 1, 0, CONTENTS_WATER },
{"slime", 1, 0, CONTENTS_SLIME }, // mildly damaging
{"lava", 1, 0, CONTENTS_LAVA }, // very damaging
{"playerclip", 1, 0, CONTENTS_PLAYERCLIP },
{"monsterclip", 1, 0, CONTENTS_MONSTERCLIP },
{"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc)
{"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag
// utility relevant attributes
{"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes
{"trans", 0, 0, CONTENTS_TRANSLUCENT }, // don't eat contained surfaces
{"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp
{"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas
{"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas
{"clusterportal", 1,0, CONTENTS_CLUSTERPORTAL }, // for bots
{"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots
{"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering
{"sky", 0, SURF_SKY, 0 }, // emit light from an environment map
{"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it
{"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis
{"hint", 0, SURF_HINT, 0 }, // use as a primary splitter
// server attributes
{"slick", 0, SURF_SLICK, 0 },
{"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks
{"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode
{"ladder", 0, SURF_LADDER, 0 },
{"nodamage", 0, SURF_NODAMAGE, 0 },
{"metalsteps", 0, SURF_METALSTEPS,0 },
{"flesh", 0, SURF_FLESH, 0 },
{"nosteps", 0, SURF_NOSTEPS, 0 },
// drawsurf attributes
{"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap)
{"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes
{"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap
{"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights
{"dust", 0, SURF_DUST, 0} // leave a dust trail when walking on this surface
};
/*
===============
ParseSurfaceParm
surfaceparm <name>
===============
*/
static void ParseSurfaceParm( char **text ) {
char *token;
int numInfoParms = sizeof(infoParms) / sizeof(infoParms[0]);
int i;
token = COM_ParseExt( text, qfalse );
for ( i = 0 ; i < numInfoParms ; i++ ) {
if ( !Q_stricmp( token, infoParms[i].name ) ) {
shader.surfaceFlags |= infoParms[i].surfaceFlags;
shader.contentFlags |= infoParms[i].contents;
#if 0
if ( infoParms[i].clearSolid ) {
si->contents &= ~CONTENTS_SOLID;
}
#endif
break;
}
}
}
/*
=================
ParseShader
The current text pointer is at the explicit text definition of the
shader. Parse it into the global shader variable. Later functions
will optimize it.
=================
*/
static qboolean ParseShader( char **text )
{
char *token;
int s;
s = 0;
token = COM_ParseExt( text, qtrue );
if ( token[0] != '{' )
{
ri.Printf( PRINT_WARNING, "WARNING: expecting '{', found '%s' instead in shader '%s'\n", token, shader.name );
return qfalse;
}
while ( 1 )
{
token = COM_ParseExt( text, qtrue );
if ( !token[0] )
{
ri.Printf( PRINT_WARNING, "WARNING: no concluding '}' in shader %s\n", shader.name );
return qfalse;
}
// end of shader definition
if ( token[0] == '}' )
{
break;
}
// stage definition
else if ( token[0] == '{' )
{
if ( !ParseStage( &stages[s], text ) )
{
return qfalse;
}
stages[s].active = qtrue;
s++;
continue;
}
// skip stuff that only the QuakeEdRadient needs
else if ( !Q_stricmpn( token, "qer", 3 ) ) {
SkipRestOfLine( text );
continue;
}
// sun parms
else if ( !Q_stricmp( token, "q3map_sun" ) ) {
float a, b;
token = COM_ParseExt( text, qfalse );
tr.sunLight[0] = atof( token );
token = COM_ParseExt( text, qfalse );
tr.sunLight[1] = atof( token );
token = COM_ParseExt( text, qfalse );
tr.sunLight[2] = atof( token );
VectorNormalize( tr.sunLight );
token = COM_ParseExt( text, qfalse );
a = atof( token );
VectorScale( tr.sunLight, a, tr.sunLight);
token = COM_ParseExt( text, qfalse );
a = atof( token );
a = a / 180 * M_PI;
token = COM_ParseExt( text, qfalse );
b = atof( token );
b = b / 180 * M_PI;
tr.sunDirection[0] = cos( a ) * cos( b );
tr.sunDirection[1] = sin( a ) * cos( b );
tr.sunDirection[2] = sin( b );
}
else if ( !Q_stricmp( token, "deformVertexes" ) ) {
ParseDeform( text );
continue;
}
else if ( !Q_stricmp( token, "tesssize" ) ) {
SkipRestOfLine( text );
continue;
}
else if ( !Q_stricmp( token, "clampTime" ) ) {
token = COM_ParseExt( text, qfalse );
if (token[0]) {
shader.clampTime = atof(token);
}
}
// skip stuff that only the q3map needs
else if ( !Q_stricmpn( token, "q3map", 5 ) ) {
SkipRestOfLine( text );
continue;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -