123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362 |
- /*
- ===========================================================================
- 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.c
- #include "tr_local.h"
- /*
- THIS ENTIRE FILE IS BACK END
- This file deals with applying shaders to surface data in the tess struct.
- */
- /*
- ================
- R_ArrayElementDiscrete
- This is just for OpenGL conformance testing, it should never be the fastest
- ================
- */
- static void APIENTRY R_ArrayElementDiscrete( GLint index ) {
- qglColor4ubv( tess.svars.colors[ index ] );
- if ( glState.currenttmu ) {
- qglMultiTexCoord2fARB( 0, tess.svars.texcoords[ 0 ][ index ][0], tess.svars.texcoords[ 0 ][ index ][1] );
- qglMultiTexCoord2fARB( 1, tess.svars.texcoords[ 1 ][ index ][0], tess.svars.texcoords[ 1 ][ index ][1] );
- } else {
- qglTexCoord2fv( tess.svars.texcoords[ 0 ][ index ] );
- }
- qglVertex3fv( tess.xyz[ index ] );
- }
- /*
- ===================
- R_DrawStripElements
- ===================
- */
- static int c_vertexes; // for seeing how long our average strips are
- static int c_begins;
- static void R_DrawStripElements( int numIndexes, const glIndex_t *indexes, void ( APIENTRY *element )(GLint) ) {
- int i;
- int last[3] = { -1, -1, -1 };
- qboolean even;
- c_begins++;
- if ( numIndexes <= 0 ) {
- return;
- }
- qglBegin( GL_TRIANGLE_STRIP );
- // prime the strip
- element( indexes[0] );
- element( indexes[1] );
- element( indexes[2] );
- c_vertexes += 3;
- last[0] = indexes[0];
- last[1] = indexes[1];
- last[2] = indexes[2];
- even = qfalse;
- for ( i = 3; i < numIndexes; i += 3 )
- {
- // odd numbered triangle in potential strip
- if ( !even )
- {
- // check previous triangle to see if we're continuing a strip
- if ( ( indexes[i+0] == last[2] ) && ( indexes[i+1] == last[1] ) )
- {
- element( indexes[i+2] );
- c_vertexes++;
- assert( indexes[i+2] < tess.numVertexes );
- even = qtrue;
- }
- // otherwise we're done with this strip so finish it and start
- // a new one
- else
- {
- qglEnd();
- qglBegin( GL_TRIANGLE_STRIP );
- c_begins++;
- element( indexes[i+0] );
- element( indexes[i+1] );
- element( indexes[i+2] );
- c_vertexes += 3;
- even = qfalse;
- }
- }
- else
- {
- // check previous triangle to see if we're continuing a strip
- if ( ( last[2] == indexes[i+1] ) && ( last[0] == indexes[i+0] ) )
- {
- element( indexes[i+2] );
- c_vertexes++;
- even = qfalse;
- }
- // otherwise we're done with this strip so finish it and start
- // a new one
- else
- {
- qglEnd();
- qglBegin( GL_TRIANGLE_STRIP );
- c_begins++;
- element( indexes[i+0] );
- element( indexes[i+1] );
- element( indexes[i+2] );
- c_vertexes += 3;
- even = qfalse;
- }
- }
- // cache the last three vertices
- last[0] = indexes[i+0];
- last[1] = indexes[i+1];
- last[2] = indexes[i+2];
- }
- qglEnd();
- }
- /*
- ==================
- R_DrawElements
- Optionally performs our own glDrawElements that looks for strip conditions
- instead of using the single glDrawElements call that may be inefficient
- without compiled vertex arrays.
- ==================
- */
- static void R_DrawElements( int numIndexes, const glIndex_t *indexes ) {
- int primitives;
- primitives = r_primitives->integer;
- // default is to use triangles if compiled vertex arrays are present
- if ( primitives == 0 ) {
- if ( qglLockArraysEXT ) {
- primitives = 2;
- } else {
- primitives = 1;
- }
- }
- if ( primitives == 2 ) {
- qglDrawElements( GL_TRIANGLES,
- numIndexes,
- GL_INDEX_TYPE,
- indexes );
- return;
- }
- if ( primitives == 1 ) {
- R_DrawStripElements( numIndexes, indexes, qglArrayElement );
- return;
- }
-
- if ( primitives == 3 ) {
- R_DrawStripElements( numIndexes, indexes, R_ArrayElementDiscrete );
- return;
- }
- // anything else will cause no drawing
- }
- /*
- =============================================================
- SURFACE SHADERS
- =============================================================
- */
- shaderCommands_t tess;
- static qboolean setArraysOnce;
- /*
- =================
- R_BindAnimatedImage
- =================
- */
- static void R_BindAnimatedImage( textureBundle_t *bundle ) {
- int index;
- if ( bundle->isVideoMap ) {
- ri.CIN_RunCinematic(bundle->videoMapHandle);
- ri.CIN_UploadCinematic(bundle->videoMapHandle);
- return;
- }
- if ( bundle->numImageAnimations <= 1 ) {
- GL_Bind( bundle->image[0] );
- return;
- }
- // it is necessary to do this messy calc to make sure animations line up
- // exactly with waveforms of the same frequency
- index = myftol( tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE );
- index >>= FUNCTABLE_SIZE2;
- if ( index < 0 ) {
- index = 0; // may happen with shader time offsets
- }
- index %= bundle->numImageAnimations;
- GL_Bind( bundle->image[ index ] );
- }
- /*
- ================
- DrawTris
- Draws triangle outlines for debugging
- ================
- */
- static void DrawTris (shaderCommands_t *input) {
- GL_Bind( tr.whiteImage );
- qglColor3f (1,1,1);
- GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
- qglDepthRange( 0, 0 );
- qglDisableClientState (GL_COLOR_ARRAY);
- qglDisableClientState (GL_TEXTURE_COORD_ARRAY);
- qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD
- if (qglLockArraysEXT) {
- qglLockArraysEXT(0, input->numVertexes);
- GLimp_LogComment( "glLockArraysEXT\n" );
- }
- R_DrawElements( input->numIndexes, input->indexes );
- if (qglUnlockArraysEXT) {
- qglUnlockArraysEXT();
- GLimp_LogComment( "glUnlockArraysEXT\n" );
- }
- qglDepthRange( 0, 1 );
- }
- /*
- ================
- DrawNormals
- Draws vertex normals for debugging
- ================
- */
- static void DrawNormals (shaderCommands_t *input) {
- int i;
- vec3_t temp;
- GL_Bind( tr.whiteImage );
- qglColor3f (1,1,1);
- qglDepthRange( 0, 0 ); // never occluded
- GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
- qglBegin (GL_LINES);
- for (i = 0 ; i < input->numVertexes ; i++) {
- qglVertex3fv (input->xyz[i]);
- VectorMA (input->xyz[i], 2, input->normal[i], temp);
- qglVertex3fv (temp);
- }
- qglEnd ();
- qglDepthRange( 0, 1 );
- }
- /*
- ==============
- RB_BeginSurface
- We must set some things up before beginning any tesselation,
- because a surface may be forced to perform a RB_End due
- to overflow.
- ==============
- */
- void RB_BeginSurface( shader_t *shader, int fogNum ) {
- shader_t *state = (shader->remappedShader) ? shader->remappedShader : shader;
- tess.numIndexes = 0;
- tess.numVertexes = 0;
- tess.shader = state;
- tess.fogNum = fogNum;
- tess.dlightBits = 0; // will be OR'd in by surface functions
- tess.xstages = state->stages;
- tess.numPasses = state->numUnfoggedPasses;
- tess.currentStageIteratorFunc = state->optimalStageIteratorFunc;
- tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
- if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) {
- tess.shaderTime = tess.shader->clampTime;
- }
- }
- /*
- ===================
- DrawMultitextured
- output = t0 * t1 or t0 + t1
- t0 = most upstream according to spec
- t1 = most downstream according to spec
- ===================
- */
- static void DrawMultitextured( shaderCommands_t *input, int stage ) {
- shaderStage_t *pStage;
- pStage = tess.xstages[stage];
- GL_State( pStage->stateBits );
- // this is an ugly hack to work around a GeForce driver
- // bug with multitexture and clip planes
- if ( backEnd.viewParms.isPortal ) {
- qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
- }
- //
- // base
- //
- GL_SelectTexture( 0 );
- qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );
- R_BindAnimatedImage( &pStage->bundle[0] );
- //
- // lightmap/secondary pass
- //
- GL_SelectTexture( 1 );
- qglEnable( GL_TEXTURE_2D );
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- if ( r_lightmap->integer ) {
- GL_TexEnv( GL_REPLACE );
- } else {
- GL_TexEnv( tess.shader->multitextureEnv );
- }
- qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[1] );
- R_BindAnimatedImage( &pStage->bundle[1] );
- R_DrawElements( input->numIndexes, input->indexes );
- //
- // disable texturing on TEXTURE1, then select TEXTURE0
- //
- //qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
- qglDisable( GL_TEXTURE_2D );
- GL_SelectTexture( 0 );
- }
- /*
- ===================
- ProjectDlightTexture
- Perform dynamic lighting with another rendering pass
- ===================
- */
- static void ProjectDlightTexture( void ) {
- int i, l;
- #if idppc_altivec
- vec_t origin0, origin1, origin2;
- float texCoords0, texCoords1;
- vector float floatColorVec0, floatColorVec1;
- vector float modulateVec, colorVec, zero;
- vector short colorShort;
- vector signed int colorInt;
- vector unsigned char floatColorVecPerm, modulatePerm, colorChar;
- vector unsigned char vSel = (vector unsigned char)(0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff,
- 0x00, 0x00, 0x00, 0xff);
- #else
- vec3_t origin;
- #endif
- float *texCoords;
- byte *colors;
- byte clipBits[SHADER_MAX_VERTEXES];
- MAC_STATIC float texCoordsArray[SHADER_MAX_VERTEXES][2];
- byte colorArray[SHADER_MAX_VERTEXES][4];
- unsigned hitIndexes[SHADER_MAX_INDEXES];
- int numIndexes;
- float scale;
- float radius;
- vec3_t floatColor;
- float modulate;
- if ( !backEnd.refdef.num_dlights ) {
- return;
- }
- #if idppc_altivec
- // There has to be a better way to do this so that floatColor
- // and/or modulate are already 16-byte aligned.
- floatColorVecPerm = vec_lvsl(0,(float *)floatColor);
- modulatePerm = vec_lvsl(0,(float *)&modulate);
- modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0);
- zero = (vector float)vec_splat_s8(0);
- #endif
- for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
- dlight_t *dl;
- if ( !( tess.dlightBits & ( 1 << l ) ) ) {
- continue; // this surface definately doesn't have any of this light
- }
- texCoords = texCoordsArray[0];
- colors = colorArray[0];
- dl = &backEnd.refdef.dlights[l];
- #if idppc_altivec
- origin0 = dl->transformed[0];
- origin1 = dl->transformed[1];
- origin2 = dl->transformed[2];
- #else
- VectorCopy( dl->transformed, origin );
- #endif
- radius = dl->radius;
- scale = 1.0f / radius;
- floatColor[0] = dl->color[0] * 255.0f;
- floatColor[1] = dl->color[1] * 255.0f;
- floatColor[2] = dl->color[2] * 255.0f;
- #if idppc_altivec
- floatColorVec0 = vec_ld(0, floatColor);
- floatColorVec1 = vec_ld(11, floatColor);
- floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm);
- #endif
- for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
- #if idppc_altivec
- vec_t dist0, dist1, dist2;
- #else
- vec3_t dist;
- #endif
- int clip;
- backEnd.pc.c_dlightVertexes++;
- #if idppc_altivec
- //VectorSubtract( origin, tess.xyz[i], dist );
- dist0 = origin0 - tess.xyz[i][0];
- dist1 = origin1 - tess.xyz[i][1];
- dist2 = origin2 - tess.xyz[i][2];
- texCoords0 = 0.5f + dist0 * scale;
- texCoords1 = 0.5f + dist1 * scale;
- clip = 0;
- if ( texCoords0 < 0.0f ) {
- clip |= 1;
- } else if ( texCoords0 > 1.0f ) {
- clip |= 2;
- }
- if ( texCoords1 < 0.0f ) {
- clip |= 4;
- } else if ( texCoords1 > 1.0f ) {
- clip |= 8;
- }
- texCoords[0] = texCoords0;
- texCoords[1] = texCoords1;
-
- // modulate the strength based on the height and color
- if ( dist2 > radius ) {
- clip |= 16;
- modulate = 0.0f;
- } else if ( dist2 < -radius ) {
- clip |= 32;
- modulate = 0.0f;
- } else {
- dist2 = Q_fabs(dist2);
- if ( dist2 < radius * 0.5f ) {
- modulate = 1.0f;
- } else {
- modulate = 2.0f * (radius - dist2) * scale;
- }
- }
- clipBits[i] = clip;
- modulateVec = vec_ld(0,(float *)&modulate);
- modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm);
- colorVec = vec_madd(floatColorVec0,modulateVec,zero);
- colorInt = vec_cts(colorVec,0); // RGBx
- colorShort = vec_pack(colorInt,colorInt); // RGBxRGBx
- colorChar = vec_packsu(colorShort,colorShort); // RGBxRGBxRGBxRGBx
- colorChar = vec_sel(colorChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255
- vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors); // store color
- #else
- VectorSubtract( origin, tess.xyz[i], dist );
- texCoords[0] = 0.5f + dist[0] * scale;
- texCoords[1] = 0.5f + dist[1] * scale;
- clip = 0;
- if ( texCoords[0] < 0.0f ) {
- clip |= 1;
- } else if ( texCoords[0] > 1.0f ) {
- clip |= 2;
- }
- if ( texCoords[1] < 0.0f ) {
- clip |= 4;
- } else if ( texCoords[1] > 1.0f ) {
- clip |= 8;
- }
- // modulate the strength based on the height and color
- if ( dist[2] > radius ) {
- clip |= 16;
- modulate = 0.0f;
- } else if ( dist[2] < -radius ) {
- clip |= 32;
- modulate = 0.0f;
- } else {
- dist[2] = Q_fabs(dist[2]);
- if ( dist[2] < radius * 0.5f ) {
- modulate = 1.0f;
- } else {
- modulate = 2.0f * (radius - dist[2]) * scale;
- }
- }
- clipBits[i] = clip;
- colors[0] = myftol(floatColor[0] * modulate);
- colors[1] = myftol(floatColor[1] * modulate);
- colors[2] = myftol(floatColor[2] * modulate);
- colors[3] = 255;
- #endif
- }
- // build a list of triangles that need light
- numIndexes = 0;
- for ( i = 0 ; i < tess.numIndexes ; i += 3 ) {
- int a, b, c;
- a = tess.indexes[i];
- b = tess.indexes[i+1];
- c = tess.indexes[i+2];
- if ( clipBits[a] & clipBits[b] & clipBits[c] ) {
- continue; // not lighted
- }
- hitIndexes[numIndexes] = a;
- hitIndexes[numIndexes+1] = b;
- hitIndexes[numIndexes+2] = c;
- numIndexes += 3;
- }
- if ( !numIndexes ) {
- continue;
- }
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );
- qglEnableClientState( GL_COLOR_ARRAY );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );
- GL_Bind( tr.dlightImage );
- // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
- // where they aren't rendered
- if ( dl->additive ) {
- GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
- }
- else {
- GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
- }
- R_DrawElements( numIndexes, hitIndexes );
- backEnd.pc.c_totalIndexes += numIndexes;
- backEnd.pc.c_dlightIndexes += numIndexes;
- }
- }
- /*
- ===================
- RB_FogPass
- Blends a fog texture on top of everything else
- ===================
- */
- static void RB_FogPass( void ) {
- fog_t *fog;
- int i;
- qglEnableClientState( GL_COLOR_ARRAY );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
- qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );
- fog = tr.world->fogs + tess.fogNum;
- for ( i = 0; i < tess.numVertexes; i++ ) {
- * ( int * )&tess.svars.colors[i] = fog->colorInt;
- }
- RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[0] );
- GL_Bind( tr.fogImage );
- if ( tess.shader->fogPass == FP_EQUAL ) {
- GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );
- } else {
- GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
- }
- R_DrawElements( tess.numIndexes, tess.indexes );
- }
- /*
- ===============
- ComputeColors
- ===============
- */
- static void ComputeColors( shaderStage_t *pStage )
- {
- int i;
- //
- // rgbGen
- //
- switch ( pStage->rgbGen )
- {
- case CGEN_IDENTITY:
- Com_Memset( tess.svars.colors, 0xff, tess.numVertexes * 4 );
- break;
- default:
- case CGEN_IDENTITY_LIGHTING:
- Com_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 );
- break;
- case CGEN_LIGHTING_DIFFUSE:
- RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors );
- break;
- case CGEN_EXACT_VERTEX:
- Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) );
- break;
- case CGEN_CONST:
- for ( i = 0; i < tess.numVertexes; i++ ) {
- *(int *)tess.svars.colors[i] = *(int *)pStage->constantColor;
- }
- break;
- case CGEN_VERTEX:
- if ( tr.identityLight == 1 )
- {
- Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) );
- }
- else
- {
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- tess.svars.colors[i][0] = tess.vertexColors[i][0] * tr.identityLight;
- tess.svars.colors[i][1] = tess.vertexColors[i][1] * tr.identityLight;
- tess.svars.colors[i][2] = tess.vertexColors[i][2] * tr.identityLight;
- tess.svars.colors[i][3] = tess.vertexColors[i][3];
- }
- }
- break;
- case CGEN_ONE_MINUS_VERTEX:
- if ( tr.identityLight == 1 )
- {
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- tess.svars.colors[i][0] = 255 - tess.vertexColors[i][0];
- tess.svars.colors[i][1] = 255 - tess.vertexColors[i][1];
- tess.svars.colors[i][2] = 255 - tess.vertexColors[i][2];
- }
- }
- else
- {
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- tess.svars.colors[i][0] = ( 255 - tess.vertexColors[i][0] ) * tr.identityLight;
- tess.svars.colors[i][1] = ( 255 - tess.vertexColors[i][1] ) * tr.identityLight;
- tess.svars.colors[i][2] = ( 255 - tess.vertexColors[i][2] ) * tr.identityLight;
- }
- }
- break;
- case CGEN_FOG:
- {
- fog_t *fog;
- fog = tr.world->fogs + tess.fogNum;
- for ( i = 0; i < tess.numVertexes; i++ ) {
- * ( int * )&tess.svars.colors[i] = fog->colorInt;
- }
- }
- break;
- case CGEN_WAVEFORM:
- RB_CalcWaveColor( &pStage->rgbWave, ( unsigned char * ) tess.svars.colors );
- break;
- case CGEN_ENTITY:
- RB_CalcColorFromEntity( ( unsigned char * ) tess.svars.colors );
- break;
- case CGEN_ONE_MINUS_ENTITY:
- RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors );
- break;
- }
- //
- // alphaGen
- //
- switch ( pStage->alphaGen )
- {
- case AGEN_SKIP:
- break;
- case AGEN_IDENTITY:
- if ( pStage->rgbGen != CGEN_IDENTITY ) {
- if ( ( pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1 ) ||
- pStage->rgbGen != CGEN_VERTEX ) {
- for ( i = 0; i < tess.numVertexes; i++ ) {
- tess.svars.colors[i][3] = 0xff;
- }
- }
- }
- break;
- case AGEN_CONST:
- if ( pStage->rgbGen != CGEN_CONST ) {
- for ( i = 0; i < tess.numVertexes; i++ ) {
- tess.svars.colors[i][3] = pStage->constantColor[3];
- }
- }
- break;
- case AGEN_WAVEFORM:
- RB_CalcWaveAlpha( &pStage->alphaWave, ( unsigned char * ) tess.svars.colors );
- break;
- case AGEN_LIGHTING_SPECULAR:
- RB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors );
- break;
- case AGEN_ENTITY:
- RB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors );
- break;
- case AGEN_ONE_MINUS_ENTITY:
- RB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors );
- break;
- case AGEN_VERTEX:
- if ( pStage->rgbGen != CGEN_VERTEX ) {
- for ( i = 0; i < tess.numVertexes; i++ ) {
- tess.svars.colors[i][3] = tess.vertexColors[i][3];
- }
- }
- break;
- case AGEN_ONE_MINUS_VERTEX:
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- tess.svars.colors[i][3] = 255 - tess.vertexColors[i][3];
- }
- break;
- case AGEN_PORTAL:
- {
- unsigned char alpha;
- for ( i = 0; i < tess.numVertexes; i++ )
- {
- float len;
- vec3_t v;
- VectorSubtract( tess.xyz[i], backEnd.viewParms.or.origin, v );
- len = VectorLength( v );
- len /= tess.shader->portalRange;
- if ( len < 0 )
- {
- alpha = 0;
- }
- else if ( len > 1 )
- {
- alpha = 0xff;
- }
- else
- {
- alpha = len * 0xff;
- }
- tess.svars.colors[i][3] = alpha;
- }
- }
- break;
- }
- //
- // fog adjustment for colors to fade out as fog increases
- //
- if ( tess.fogNum )
- {
- switch ( pStage->adjustColorsForFog )
- {
- case ACFF_MODULATE_RGB:
- RB_CalcModulateColorsByFog( ( unsigned char * ) tess.svars.colors );
- break;
- case ACFF_MODULATE_ALPHA:
- RB_CalcModulateAlphasByFog( ( unsigned char * ) tess.svars.colors );
- break;
- case ACFF_MODULATE_RGBA:
- RB_CalcModulateRGBAsByFog( ( unsigned char * ) tess.svars.colors );
- break;
- case ACFF_NONE:
- break;
- }
- }
- }
- /*
- ===============
- ComputeTexCoords
- ===============
- */
- static void ComputeTexCoords( shaderStage_t *pStage ) {
- int i;
- int b;
- for ( b = 0; b < NUM_TEXTURE_BUNDLES; b++ ) {
- int tm;
- //
- // generate the texture coordinates
- //
- switch ( pStage->bundle[b].tcGen )
- {
- case TCGEN_IDENTITY:
- Com_Memset( tess.svars.texcoords[b], 0, sizeof( float ) * 2 * tess.numVertexes );
- break;
- case TCGEN_TEXTURE:
- for ( i = 0 ; i < tess.numVertexes ; i++ ) {
- tess.svars.texcoords[b][i][0] = tess.texCoords[i][0][0];
- tess.svars.texcoords[b][i][1] = tess.texCoords[i][0][1];
- }
- break;
- case TCGEN_LIGHTMAP:
- for ( i = 0 ; i < tess.numVertexes ; i++ ) {
- tess.svars.texcoords[b][i][0] = tess.texCoords[i][1][0];
- tess.svars.texcoords[b][i][1] = tess.texCoords[i][1][1];
- }
- break;
- case TCGEN_VECTOR:
- for ( i = 0 ; i < tess.numVertexes ; i++ ) {
- tess.svars.texcoords[b][i][0] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[0] );
- tess.svars.texcoords[b][i][1] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[1] );
- }
- break;
- case TCGEN_FOG:
- RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[b] );
- break;
- case TCGEN_ENVIRONMENT_MAPPED:
- RB_CalcEnvironmentTexCoords( ( float * ) tess.svars.texcoords[b] );
- break;
- case TCGEN_BAD:
- return;
- }
- //
- // alter texture coordinates
- //
- for ( tm = 0; tm < pStage->bundle[b].numTexMods ; tm++ ) {
- switch ( pStage->bundle[b].texMods[tm].type )
- {
- case TMOD_NONE:
- tm = TR_MAX_TEXMODS; // break out of for loop
- break;
- case TMOD_TURBULENT:
- RB_CalcTurbulentTexCoords( &pStage->bundle[b].texMods[tm].wave,
- ( float * ) tess.svars.texcoords[b] );
- break;
- case TMOD_ENTITY_TRANSLATE:
- RB_CalcScrollTexCoords( backEnd.currentEntity->e.shaderTexCoord,
- ( float * ) tess.svars.texcoords[b] );
- break;
- case TMOD_SCROLL:
- RB_CalcScrollTexCoords( pStage->bundle[b].texMods[tm].scroll,
- ( float * ) tess.svars.texcoords[b] );
- break;
- case TMOD_SCALE:
- RB_CalcScaleTexCoords( pStage->bundle[b].texMods[tm].scale,
- ( float * ) tess.svars.texcoords[b] );
- break;
-
- case TMOD_STRETCH:
- RB_CalcStretchTexCoords( &pStage->bundle[b].texMods[tm].wave,
- ( float * ) tess.svars.texcoords[b] );
- break;
- case TMOD_TRANSFORM:
- RB_CalcTransformTexCoords( &pStage->bundle[b].texMods[tm],
- ( float * ) tess.svars.texcoords[b] );
- break;
- case TMOD_ROTATE:
- RB_CalcRotateTexCoords( pStage->bundle[b].texMods[tm].rotateSpeed,
- ( float * ) tess.svars.texcoords[b] );
- break;
- default:
- ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'\n", pStage->bundle[b].texMods[tm].type, tess.shader->name );
- break;
- }
- }
- }
- }
- /*
- ** RB_IterateStagesGeneric
- */
- static void RB_IterateStagesGeneric( shaderCommands_t *input )
- {
- int stage;
- for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ )
- {
- shaderStage_t *pStage = tess.xstages[stage];
- if ( !pStage )
- {
- break;
- }
- ComputeColors( pStage );
- ComputeTexCoords( pStage );
- if ( !setArraysOnce )
- {
- qglEnableClientState( GL_COLOR_ARRAY );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors );
- }
- //
- // do multitexture
- //
- if ( pStage->bundle[1].image[0] != 0 )
- {
- DrawMultitextured( input, stage );
- }
- else
- {
- if ( !setArraysOnce )
- {
- qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );
- }
- //
- // set state
- //
- if ( pStage->bundle[0].vertexLightmap && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) && r_lightmap->integer )
- {
- GL_Bind( tr.whiteImage );
- }
- else
- R_BindAnimatedImage( &pStage->bundle[0] );
- GL_State( pStage->stateBits );
- //
- // draw
- //
- R_DrawElements( input->numIndexes, input->indexes );
- }
- // allow skipping out to show just lightmaps during development
- if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap ) )
- {
- break;
- }
- }
- }
- /*
- ** RB_StageIteratorGeneric
- */
- void RB_StageIteratorGeneric( void )
- {
- shaderCommands_t *input;
- input = &tess;
- RB_DeformTessGeometry();
- //
- // log this call
- //
- if ( r_logFile->integer )
- {
- // don't just call LogComment, or we will get
- // a call to va() every frame!
- GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) );
- }
- //
- // set face culling appropriately
- //
- GL_Cull( input->shader->cullType );
- // set polygon offset if necessary
- if ( input->shader->polygonOffset )
- {
- qglEnable( GL_POLYGON_OFFSET_FILL );
- qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value );
- }
- //
- // if there is only a single pass then we can enable color
- // and texture arrays before we compile, otherwise we need
- // to avoid compiling those arrays since they will change
- // during multipass rendering
- //
- if ( tess.numPasses > 1 || input->shader->multitextureEnv )
- {
- setArraysOnce = qfalse;
- qglDisableClientState (GL_COLOR_ARRAY);
- qglDisableClientState (GL_TEXTURE_COORD_ARRAY);
- }
- else
- {
- setArraysOnce = qtrue;
- qglEnableClientState( GL_COLOR_ARRAY);
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
- qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );
- }
- //
- // lock XYZ
- //
- qglVertexPointer (3, GL_FLOAT, 16, input->xyz); // padded for SIMD
- if (qglLockArraysEXT)
- {
- qglLockArraysEXT(0, input->numVertexes);
- GLimp_LogComment( "glLockArraysEXT\n" );
- }
- //
- // enable color and texcoord arrays after the lock if necessary
- //
- if ( !setArraysOnce )
- {
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- qglEnableClientState( GL_COLOR_ARRAY );
- }
- //
- // call shader function
- //
- RB_IterateStagesGeneric( input );
- //
- // now do any dynamic lighting needed
- //
- if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE
- && !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) {
- ProjectDlightTexture();
- }
- //
- // now do fog
- //
- if ( tess.fogNum && tess.shader->fogPass ) {
- RB_FogPass();
- }
- //
- // unlock arrays
- //
- if (qglUnlockArraysEXT)
- {
- qglUnlockArraysEXT();
- GLimp_LogComment( "glUnlockArraysEXT\n" );
- }
- //
- // reset polygon offset
- //
- if ( input->shader->polygonOffset )
- {
- qglDisable( GL_POLYGON_OFFSET_FILL );
- }
- }
- /*
- ** RB_StageIteratorVertexLitTexture
- */
- void RB_StageIteratorVertexLitTexture( void )
- {
- shaderCommands_t *input;
- shader_t *shader;
- input = &tess;
- shader = input->shader;
- //
- // compute colors
- //
- RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors );
- //
- // log this call
- //
- if ( r_logFile->integer )
- {
- // don't just call LogComment, or we will get
- // a call to va() every frame!
- GLimp_LogComment( va("--- RB_StageIteratorVertexLitTexturedUnfogged( %s ) ---\n", tess.shader->name) );
- }
- //
- // set face culling appropriately
- //
- GL_Cull( input->shader->cullType );
- //
- // set arrays and lock
- //
- qglEnableClientState( GL_COLOR_ARRAY);
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
- qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] );
- qglVertexPointer (3, GL_FLOAT, 16, input->xyz);
- if ( qglLockArraysEXT )
- {
- qglLockArraysEXT(0, input->numVertexes);
- GLimp_LogComment( "glLockArraysEXT\n" );
- }
- //
- // call special shade routine
- //
- R_BindAnimatedImage( &tess.xstages[0]->bundle[0] );
- GL_State( tess.xstages[0]->stateBits );
- R_DrawElements( input->numIndexes, input->indexes );
- //
- // now do any dynamic lighting needed
- //
- if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) {
- ProjectDlightTexture();
- }
- //
- // now do fog
- //
- if ( tess.fogNum && tess.shader->fogPass ) {
- RB_FogPass();
- }
- //
- // unlock arrays
- //
- if (qglUnlockArraysEXT)
- {
- qglUnlockArraysEXT();
- GLimp_LogComment( "glUnlockArraysEXT\n" );
- }
- }
- //define REPLACE_MODE
- void RB_StageIteratorLightmappedMultitexture( void ) {
- shaderCommands_t *input;
- input = &tess;
- //
- // log this call
- //
- if ( r_logFile->integer ) {
- // don't just call LogComment, or we will get
- // a call to va() every frame!
- GLimp_LogComment( va("--- RB_StageIteratorLightmappedMultitexture( %s ) ---\n", tess.shader->name) );
- }
- //
- // set face culling appropriately
- //
- GL_Cull( input->shader->cullType );
- //
- // set color, pointers, and lock
- //
- GL_State( GLS_DEFAULT );
- qglVertexPointer( 3, GL_FLOAT, 16, input->xyz );
- #ifdef REPLACE_MODE
- qglDisableClientState( GL_COLOR_ARRAY );
- qglColor3f( 1, 1, 1 );
- qglShadeModel( GL_FLAT );
- #else
- qglEnableClientState( GL_COLOR_ARRAY );
- qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.constantColor255 );
- #endif
- //
- // select base stage
- //
- GL_SelectTexture( 0 );
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- R_BindAnimatedImage( &tess.xstages[0]->bundle[0] );
- qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] );
- //
- // configure second stage
- //
- GL_SelectTexture( 1 );
- qglEnable( GL_TEXTURE_2D );
- if ( r_lightmap->integer ) {
- GL_TexEnv( GL_REPLACE );
- } else {
- GL_TexEnv( GL_MODULATE );
- }
- R_BindAnimatedImage( &tess.xstages[0]->bundle[1] );
- qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
- qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][1] );
- //
- // lock arrays
- //
- if ( qglLockArraysEXT ) {
- qglLockArraysEXT(0, input->numVertexes);
- GLimp_LogComment( "glLockArraysEXT\n" );
- }
- R_DrawElements( input->numIndexes, input->indexes );
- //
- // disable texturing on TEXTURE1, then select TEXTURE0
- //
- qglDisable( GL_TEXTURE_2D );
- qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
- GL_SelectTexture( 0 );
- #ifdef REPLACE_MODE
- GL_TexEnv( GL_MODULATE );
- qglShadeModel( GL_SMOOTH );
- #endif
- //
- // now do any dynamic lighting needed
- //
- if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) {
- ProjectDlightTexture();
- }
- //
- // now do fog
- //
- if ( tess.fogNum && tess.shader->fogPass ) {
- RB_FogPass();
- }
- //
- // unlock arrays
- //
- if ( qglUnlockArraysEXT ) {
- qglUnlockArraysEXT();
- GLimp_LogComment( "glUnlockArraysEXT\n" );
- }
- }
- /*
- ** RB_EndSurface
- */
- void RB_EndSurface( void ) {
- shaderCommands_t *input;
- input = &tess;
- if (input->numIndexes == 0) {
- return;
- }
- if (input->indexes[SHADER_MAX_INDEXES-1] != 0) {
- ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_INDEXES hit");
- }
- if (input->xyz[SHADER_MAX_VERTEXES-1][0] != 0) {
- ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_VERTEXES hit");
- }
- if ( tess.shader == tr.shadowShader ) {
- RB_ShadowTessEnd();
- return;
- }
- // for debugging of sort order issues, stop rendering after a given sort value
- if ( r_debugSort->integer && r_debugSort->integer < tess.shader->sort ) {
- return;
- }
- //
- // update performance counters
- //
- backEnd.pc.c_shaders++;
- backEnd.pc.c_vertexes += tess.numVertexes;
- backEnd.pc.c_indexes += tess.numIndexes;
- backEnd.pc.c_totalIndexes += tess.numIndexes * tess.numPasses;
- //
- // call off to shader specific tess end function
- //
- tess.currentStageIteratorFunc();
- //
- // draw debugging stuff
- //
- if ( r_showtris->integer ) {
- DrawTris (input);
- }
- if ( r_shownormals->integer ) {
- DrawNormals (input);
- }
- // clear shader so we can tell we don't have any unclosed surfaces
- tess.numIndexes = 0;
- GLimp_LogComment( "----------\n" );
- }
|