📄 tr_shade_calc.c
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
// tr_shade_calc.c
#include "tr_local.h"
#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ myftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude))
static float *TableForFunc( genFunc_t func )
{
switch ( func )
{
case GF_SIN:
return tr.sinTable;
case GF_TRIANGLE:
return tr.triangleTable;
case GF_SQUARE:
return tr.squareTable;
case GF_SAWTOOTH:
return tr.sawToothTable;
case GF_INVERSE_SAWTOOTH:
return tr.inverseSawToothTable;
case GF_NONE:
default:
break;
}
ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'\n", func, tess.shader->name );
return NULL;
}
/*
** EvalWaveForm
**
** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly
*/
static float EvalWaveForm( const waveForm_t *wf )
{
float *table;
table = TableForFunc( wf->func );
return WAVEVALUE( table, wf->base, wf->amplitude, wf->phase, wf->frequency );
}
static float EvalWaveFormClamped( const waveForm_t *wf )
{
float glow = EvalWaveForm( wf );
if ( glow < 0 )
{
return 0;
}
if ( glow > 1 )
{
return 1;
}
return glow;
}
/*
** RB_CalcStretchTexCoords
*/
void RB_CalcStretchTexCoords( const waveForm_t *wf, float *st )
{
float p;
texModInfo_t tmi;
p = 1.0f / EvalWaveForm( wf );
tmi.matrix[0][0] = p;
tmi.matrix[1][0] = 0;
tmi.translate[0] = 0.5f - 0.5f * p;
tmi.matrix[0][1] = 0;
tmi.matrix[1][1] = p;
tmi.translate[1] = 0.5f - 0.5f * p;
RB_CalcTransformTexCoords( &tmi, st );
}
/*
====================================================================
DEFORMATIONS
====================================================================
*/
/*
========================
RB_CalcDeformVertexes
========================
*/
void RB_CalcDeformVertexes( deformStage_t *ds )
{
int i;
vec3_t offset;
float scale;
float *xyz = ( float * ) tess.xyz;
float *normal = ( float * ) tess.normal;
float *table;
if ( ds->deformationWave.frequency == 0 )
{
scale = EvalWaveForm( &ds->deformationWave );
for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
{
VectorScale( normal, scale, offset );
xyz[0] += offset[0];
xyz[1] += offset[1];
xyz[2] += offset[2];
}
}
else
{
table = TableForFunc( ds->deformationWave.func );
for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
{
float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;
scale = WAVEVALUE( table, ds->deformationWave.base,
ds->deformationWave.amplitude,
ds->deformationWave.phase + off,
ds->deformationWave.frequency );
VectorScale( normal, scale, offset );
xyz[0] += offset[0];
xyz[1] += offset[1];
xyz[2] += offset[2];
}
}
}
/*
=========================
RB_CalcDeformNormals
Wiggle the normals for wavy environment mapping
=========================
*/
void RB_CalcDeformNormals( deformStage_t *ds ) {
int i;
float scale;
float *xyz = ( float * ) tess.xyz;
float *normal = ( float * ) tess.normal;
for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) {
scale = 0.98f;
scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
tess.shaderTime * ds->deformationWave.frequency );
normal[ 0 ] += ds->deformationWave.amplitude * scale;
scale = 0.98f;
scale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
tess.shaderTime * ds->deformationWave.frequency );
normal[ 1 ] += ds->deformationWave.amplitude * scale;
scale = 0.98f;
scale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
tess.shaderTime * ds->deformationWave.frequency );
normal[ 2 ] += ds->deformationWave.amplitude * scale;
VectorNormalizeFast( normal );
}
}
/*
========================
RB_CalcBulgeVertexes
========================
*/
void RB_CalcBulgeVertexes( deformStage_t *ds ) {
int i;
const float *st = ( const float * ) tess.texCoords[0];
float *xyz = ( float * ) tess.xyz;
float *normal = ( float * ) tess.normal;
float now;
now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f;
for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal += 4 ) {
int off;
float scale;
off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now );
scale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight;
xyz[0] += normal[0] * scale;
xyz[1] += normal[1] * scale;
xyz[2] += normal[2] * scale;
}
}
/*
======================
RB_CalcMoveVertexes
A deformation that can move an entire surface along a wave path
======================
*/
void RB_CalcMoveVertexes( deformStage_t *ds ) {
int i;
float *xyz;
float *table;
float scale;
vec3_t offset;
table = TableForFunc( ds->deformationWave.func );
scale = WAVEVALUE( table, ds->deformationWave.base,
ds->deformationWave.amplitude,
ds->deformationWave.phase,
ds->deformationWave.frequency );
VectorScale( ds->moveVector, scale, offset );
xyz = ( float * ) tess.xyz;
for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
VectorAdd( xyz, offset, xyz );
}
}
/*
=============
DeformText
Change a polygon into a bunch of text polygons
=============
*/
void DeformText( const char *text ) {
int i;
vec3_t origin, width, height;
int len;
int ch;
byte color[4];
float bottom, top;
vec3_t mid;
height[0] = 0;
height[1] = 0;
height[2] = -1;
CrossProduct( tess.normal[0], height, width );
// find the midpoint of the box
VectorClear( mid );
bottom = 999999;
top = -999999;
for ( i = 0 ; i < 4 ; i++ ) {
VectorAdd( tess.xyz[i], mid, mid );
if ( tess.xyz[i][2] < bottom ) {
bottom = tess.xyz[i][2];
}
if ( tess.xyz[i][2] > top ) {
top = tess.xyz[i][2];
}
}
VectorScale( mid, 0.25f, origin );
// determine the individual character size
height[0] = 0;
height[1] = 0;
height[2] = ( top - bottom ) * 0.5f;
VectorScale( width, height[2] * -0.75f, width );
// determine the starting position
len = strlen( text );
VectorMA( origin, (len-1), width, origin );
// clear the shader indexes
tess.numIndexes = 0;
tess.numVertexes = 0;
color[0] = color[1] = color[2] = color[3] = 255;
// draw each character
for ( i = 0 ; i < len ; i++ ) {
ch = text[i];
ch &= 255;
if ( ch != ' ' ) {
int row, col;
float frow, fcol, size;
row = ch>>4;
col = ch&15;
frow = row*0.0625f;
fcol = col*0.0625f;
size = 0.0625f;
RB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size );
}
VectorMA( origin, -2, width, origin );
}
}
/*
==================
GlobalVectorToLocal
==================
*/
static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) {
out[0] = DotProduct( in, backEnd.or.axis[0] );
out[1] = DotProduct( in, backEnd.or.axis[1] );
out[2] = DotProduct( in, backEnd.or.axis[2] );
}
/*
=====================
AutospriteDeform
Assuming all the triangles for this shader are independant
quads, rebuild them as forward facing sprites
=====================
*/
static void AutospriteDeform( void ) {
int i;
int oldVerts;
float *xyz;
vec3_t mid, delta;
float radius;
vec3_t left, up;
vec3_t leftDir, upDir;
if ( tess.numVertexes & 3 ) {
ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count", tess.shader->name );
}
if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count", tess.shader->name );
}
oldVerts = tess.numVertexes;
tess.numVertexes = 0;
tess.numIndexes = 0;
if ( backEnd.currentEntity != &tr.worldEntity ) {
GlobalVectorToLocal( backEnd.viewParms.or.axis[1], leftDir );
GlobalVectorToLocal( backEnd.viewParms.or.axis[2], upDir );
} else {
VectorCopy( backEnd.viewParms.or.axis[1], leftDir );
VectorCopy( backEnd.viewParms.or.axis[2], upDir );
}
for ( i = 0 ; i < oldVerts ; i+=4 ) {
// find the midpoint
xyz = tess.xyz[i];
mid[0] = 0.25f * (xyz[0] + xyz[4] + xyz[8] + xyz[12]);
mid[1] = 0.25f * (xyz[1] + xyz[5] + xyz[9] + xyz[13]);
mid[2] = 0.25f * (xyz[2] + xyz[6] + xyz[10] + xyz[14]);
VectorSubtract( xyz, mid, delta );
radius = VectorLength( delta ) * 0.707f; // / sqrt(2)
VectorScale( leftDir, radius, left );
VectorScale( upDir, radius, up );
if ( backEnd.viewParms.isMirror ) {
VectorSubtract( vec3_origin, left, left );
}
// compensate for scale in the axes if necessary
if ( backEnd.currentEntity->e.nonNormalizedAxes ) {
float axisLength;
axisLength = VectorLength( backEnd.currentEntity->e.axis[0] );
if ( !axisLength ) {
axisLength = 0;
} else {
axisLength = 1.0f / axisLength;
}
VectorScale(left, axisLength, left);
VectorScale(up, axisLength, up);
}
RB_AddQuadStamp( mid, left, up, tess.vertexColors[i] );
}
}
/*
=====================
Autosprite2Deform
Autosprite2 will pivot a rectangular quad along the center of its long axis
=====================
*/
int edgeVerts[6][2] = {
{ 0, 1 },
{ 0, 2 },
{ 0, 3 },
{ 1, 2 },
{ 1, 3 },
{ 2, 3 }
};
static void Autosprite2Deform( void ) {
int i, j, k;
int indexes;
float *xyz;
vec3_t forward;
if ( tess.numVertexes & 3 ) {
ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count", tess.shader->name );
}
if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count", tess.shader->name );
}
if ( backEnd.currentEntity != &tr.worldEntity ) {
GlobalVectorToLocal( backEnd.viewParms.or.axis[0], forward );
} else {
VectorCopy( backEnd.viewParms.or.axis[0], forward );
}
// this is a lot of work for two triangles...
// we could precalculate a lot of it is an issue, but it would mess up
// the shader abstraction
for ( i = 0, indexes = 0 ; i < tess.numVertexes ; i+=4, indexes+=6 ) {
float lengths[2];
int nums[2];
vec3_t mid[2];
vec3_t major, minor;
float *v1, *v2;
// find the midpoint
xyz = tess.xyz[i];
// identify the two shortest edges
nums[0] = nums[1] = 0;
lengths[0] = lengths[1] = 999999;
for ( j = 0 ; j < 6 ; j++ ) {
float l;
vec3_t temp;
v1 = xyz + 4 * edgeVerts[j][0];
v2 = xyz + 4 * edgeVerts[j][1];
VectorSubtract( v1, v2, temp );
l = DotProduct( temp, temp );
if ( l < lengths[0] ) {
nums[1] = nums[0];
lengths[1] = lengths[0];
nums[0] = j;
lengths[0] = l;
} else if ( l < lengths[1] ) {
nums[1] = j;
lengths[1] = l;
}
}
for ( j = 0 ; j < 2 ; j++ ) {
v1 = xyz + 4 * edgeVerts[nums[j]][0];
v2 = xyz + 4 * edgeVerts[nums[j]][1];
mid[j][0] = 0.5f * (v1[0] + v2[0]);
mid[j][1] = 0.5f * (v1[1] + v2[1]);
mid[j][2] = 0.5f * (v1[2] + v2[2]);
}
// find the vector of the major axis
VectorSubtract( mid[1], mid[0], major );
// cross this with the view direction to get minor axis
CrossProduct( major, forward, minor );
VectorNormalize( minor );
// re-project the points
for ( j = 0 ; j < 2 ; j++ ) {
float l;
v1 = xyz + 4 * edgeVerts[nums[j]][0];
v2 = xyz + 4 * edgeVerts[nums[j]][1];
l = 0.5 * sqrt( lengths[j] );
// we need to see which direction this edge
// is used to determine direction of projection
for ( k = 0 ; k < 5 ; k++ ) {
if ( tess.indexes[ indexes + k ] == i + edgeVerts[nums[j]][0]
&& tess.indexes[ indexes + k + 1 ] == i + edgeVerts[nums[j]][1] ) {
break;
}
}
if ( k == 5 ) {
VectorMA( mid[j], l, minor, v1 );
VectorMA( mid[j], -l, minor, v2 );
} else {
VectorMA( mid[j], -l, minor, v1 );
VectorMA( mid[j], l, minor, v2 );
}
}
}
}
/*
=====================
RB_DeformTessGeometry
=====================
*/
void RB_DeformTessGeometry( void ) {
int i;
deformStage_t *ds;
for ( i = 0 ; i < tess.shader->numDeforms ; i++ ) {
ds = &tess.shader->deforms[ i ];
switch ( ds->deformation ) {
case DEFORM_NONE:
break;
case DEFORM_NORMALS:
RB_CalcDeformNormals( ds );
break;
case DEFORM_WAVE:
RB_CalcDeformVertexes( ds );
break;
case DEFORM_BULGE:
RB_CalcBulgeVertexes( ds );
break;
case DEFORM_MOVE:
RB_CalcMoveVertexes( ds );
break;
case DEFORM_PROJECTION_SHADOW:
RB_ProjectionShadowDeform();
break;
case DEFORM_AUTOSPRITE:
AutospriteDeform();
break;
case DEFORM_AUTOSPRITE2:
Autosprite2Deform();
break;
case DEFORM_TEXT0:
case DEFORM_TEXT1:
case DEFORM_TEXT2:
case DEFORM_TEXT3:
case DEFORM_TEXT4:
case DEFORM_TEXT5:
case DEFORM_TEXT6:
case DEFORM_TEXT7:
DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] );
break;
}
}
}
/*
====================================================================
COLORS
====================================================================
*/
/*
** RB_CalcColorFromEntity
*/
void RB_CalcColorFromEntity( unsigned char *dstColors )
{
int i;
int *pColors = ( int * ) dstColors;
int c;
if ( !backEnd.currentEntity )
return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -