123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 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 3 of the License, or
- (at your option) any later version.
- Doom 3 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #include "../idlib/precompiled.h"
- #pragma hdrstop
- #include "tr_local.h"
- /*
- back end scene + lights rendering functions
- */
- /*
- =================
- RB_DrawElementsImmediate
- Draws with immediate mode commands, which is going to be very slow.
- This should never happen if the vertex cache is operating properly.
- =================
- */
- void RB_DrawElementsImmediate( const srfTriangles_t *tri ) {
- backEnd.pc.c_drawElements++;
- backEnd.pc.c_drawIndexes += tri->numIndexes;
- backEnd.pc.c_drawVertexes += tri->numVerts;
- if ( tri->ambientSurface != NULL ) {
- if ( tri->indexes == tri->ambientSurface->indexes ) {
- backEnd.pc.c_drawRefIndexes += tri->numIndexes;
- }
- if ( tri->verts == tri->ambientSurface->verts ) {
- backEnd.pc.c_drawRefVertexes += tri->numVerts;
- }
- }
- qglBegin( GL_TRIANGLES );
- for ( int i = 0 ; i < tri->numIndexes ; i++ ) {
- qglTexCoord2fv( tri->verts[ tri->indexes[i] ].st.ToFloatPtr() );
- qglVertex3fv( tri->verts[ tri->indexes[i] ].xyz.ToFloatPtr() );
- }
- qglEnd();
- }
- /*
- ================
- RB_DrawElementsWithCounters
- ================
- */
- void RB_DrawElementsWithCounters( const srfTriangles_t *tri ) {
- backEnd.pc.c_drawElements++;
- backEnd.pc.c_drawIndexes += tri->numIndexes;
- backEnd.pc.c_drawVertexes += tri->numVerts;
- if ( tri->ambientSurface != NULL ) {
- if ( tri->indexes == tri->ambientSurface->indexes ) {
- backEnd.pc.c_drawRefIndexes += tri->numIndexes;
- }
- if ( tri->verts == tri->ambientSurface->verts ) {
- backEnd.pc.c_drawRefVertexes += tri->numVerts;
- }
- }
- if ( tri->indexCache && r_useIndexBuffers.GetBool() ) {
- qglDrawElements( GL_TRIANGLES,
- r_singleTriangle.GetBool() ? 3 : tri->numIndexes,
- GL_INDEX_TYPE,
- (int *)vertexCache.Position( tri->indexCache ) );
- backEnd.pc.c_vboIndexes += tri->numIndexes;
- } else {
- if ( r_useIndexBuffers.GetBool() ) {
- vertexCache.UnbindIndex();
- }
- qglDrawElements( GL_TRIANGLES,
- r_singleTriangle.GetBool() ? 3 : tri->numIndexes,
- GL_INDEX_TYPE,
- tri->indexes );
- }
- }
- /*
- ================
- RB_DrawShadowElementsWithCounters
- May not use all the indexes in the surface if caps are skipped
- ================
- */
- void RB_DrawShadowElementsWithCounters( const srfTriangles_t *tri, int numIndexes ) {
- backEnd.pc.c_shadowElements++;
- backEnd.pc.c_shadowIndexes += numIndexes;
- backEnd.pc.c_shadowVertexes += tri->numVerts;
- if ( tri->indexCache && r_useIndexBuffers.GetBool() ) {
- qglDrawElements( GL_TRIANGLES,
- r_singleTriangle.GetBool() ? 3 : numIndexes,
- GL_INDEX_TYPE,
- (int *)vertexCache.Position( tri->indexCache ) );
- backEnd.pc.c_vboIndexes += numIndexes;
- } else {
- if ( r_useIndexBuffers.GetBool() ) {
- vertexCache.UnbindIndex();
- }
- qglDrawElements( GL_TRIANGLES,
- r_singleTriangle.GetBool() ? 3 : numIndexes,
- GL_INDEX_TYPE,
- tri->indexes );
- }
- }
- /*
- ===============
- RB_RenderTriangleSurface
- Sets texcoord and vertex pointers
- ===============
- */
- void RB_RenderTriangleSurface( const srfTriangles_t *tri ) {
- if ( !tri->ambientCache ) {
- RB_DrawElementsImmediate( tri );
- return;
- }
- idDrawVert *ac = (idDrawVert *)vertexCache.Position( tri->ambientCache );
- qglVertexPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ac->xyz.ToFloatPtr() );
- qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ), ac->st.ToFloatPtr() );
- RB_DrawElementsWithCounters( tri );
- }
- /*
- ===============
- RB_T_RenderTriangleSurface
- ===============
- */
- void RB_T_RenderTriangleSurface( const drawSurf_t *surf ) {
- RB_RenderTriangleSurface( surf->geo );
- }
- /*
- ===============
- RB_EnterWeaponDepthHack
- ===============
- */
- void RB_EnterWeaponDepthHack() {
- qglDepthRange( 0, 0.5 );
- float matrix[16];
- memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) );
- matrix[14] *= 0.25;
- qglMatrixMode(GL_PROJECTION);
- qglLoadMatrixf( matrix );
- qglMatrixMode(GL_MODELVIEW);
- }
- /*
- ===============
- RB_EnterModelDepthHack
- ===============
- */
- void RB_EnterModelDepthHack( float depth ) {
- qglDepthRange( 0.0f, 1.0f );
- float matrix[16];
- memcpy( matrix, backEnd.viewDef->projectionMatrix, sizeof( matrix ) );
- matrix[14] -= depth;
- qglMatrixMode(GL_PROJECTION);
- qglLoadMatrixf( matrix );
- qglMatrixMode(GL_MODELVIEW);
- }
- /*
- ===============
- RB_LeaveDepthHack
- ===============
- */
- void RB_LeaveDepthHack() {
- qglDepthRange( 0, 1 );
- qglMatrixMode(GL_PROJECTION);
- qglLoadMatrixf( backEnd.viewDef->projectionMatrix );
- qglMatrixMode(GL_MODELVIEW);
- }
- /*
- ====================
- RB_RenderDrawSurfListWithFunction
- The triangle functions can check backEnd.currentSpace != surf->space
- to see if they need to perform any new matrix setup. The modelview
- matrix will already have been loaded, and backEnd.currentSpace will
- be updated after the triangle function completes.
- ====================
- */
- void RB_RenderDrawSurfListWithFunction( drawSurf_t **drawSurfs, int numDrawSurfs,
- void (*triFunc_)( const drawSurf_t *) ) {
- int i;
- const drawSurf_t *drawSurf;
- backEnd.currentSpace = NULL;
- for (i = 0 ; i < numDrawSurfs ; i++ ) {
- drawSurf = drawSurfs[i];
- // change the matrix if needed
- if ( drawSurf->space != backEnd.currentSpace ) {
- qglLoadMatrixf( drawSurf->space->modelViewMatrix );
- }
- if ( drawSurf->space->weaponDepthHack ) {
- RB_EnterWeaponDepthHack();
- }
- if ( drawSurf->space->modelDepthHack != 0.0f ) {
- RB_EnterModelDepthHack( drawSurf->space->modelDepthHack );
- }
- // change the scissor if needed
- if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) {
- backEnd.currentScissor = drawSurf->scissorRect;
- qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
- backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
- backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
- backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
- }
- // render it
- triFunc_( drawSurf );
- if ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) {
- RB_LeaveDepthHack();
- }
- backEnd.currentSpace = drawSurf->space;
- }
- }
- /*
- ======================
- RB_RenderDrawSurfChainWithFunction
- ======================
- */
- void RB_RenderDrawSurfChainWithFunction( const drawSurf_t *drawSurfs,
- void (*triFunc_)( const drawSurf_t *) ) {
- const drawSurf_t *drawSurf;
- backEnd.currentSpace = NULL;
- for ( drawSurf = drawSurfs ; drawSurf ; drawSurf = drawSurf->nextOnLight ) {
- // change the matrix if needed
- if ( drawSurf->space != backEnd.currentSpace ) {
- qglLoadMatrixf( drawSurf->space->modelViewMatrix );
- }
- if ( drawSurf->space->weaponDepthHack ) {
- RB_EnterWeaponDepthHack();
- }
- if ( drawSurf->space->modelDepthHack ) {
- RB_EnterModelDepthHack( drawSurf->space->modelDepthHack );
- }
- // change the scissor if needed
- if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( drawSurf->scissorRect ) ) {
- backEnd.currentScissor = drawSurf->scissorRect;
- qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
- backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
- backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
- backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
- }
- // render it
- triFunc_( drawSurf );
- if ( drawSurf->space->weaponDepthHack || drawSurf->space->modelDepthHack != 0.0f ) {
- RB_LeaveDepthHack();
- }
- backEnd.currentSpace = drawSurf->space;
- }
- }
- /*
- ======================
- RB_GetShaderTextureMatrix
- ======================
- */
- void RB_GetShaderTextureMatrix( const float *shaderRegisters,
- const textureStage_t *texture, float matrix[16] ) {
- matrix[0] = shaderRegisters[ texture->matrix[0][0] ];
- matrix[4] = shaderRegisters[ texture->matrix[0][1] ];
- matrix[8] = 0;
- matrix[12] = shaderRegisters[ texture->matrix[0][2] ];
- // we attempt to keep scrolls from generating incredibly large texture values, but
- // center rotations and center scales can still generate offsets that need to be > 1
- if ( matrix[12] < -40 || matrix[12] > 40 ) {
- matrix[12] -= (int)matrix[12];
- }
- matrix[1] = shaderRegisters[ texture->matrix[1][0] ];
- matrix[5] = shaderRegisters[ texture->matrix[1][1] ];
- matrix[9] = 0;
- matrix[13] = shaderRegisters[ texture->matrix[1][2] ];
- if ( matrix[13] < -40 || matrix[13] > 40 ) {
- matrix[13] -= (int)matrix[13];
- }
- matrix[2] = 0;
- matrix[6] = 0;
- matrix[10] = 1;
- matrix[14] = 0;
- matrix[3] = 0;
- matrix[7] = 0;
- matrix[11] = 0;
- matrix[15] = 1;
- }
- /*
- ======================
- RB_LoadShaderTextureMatrix
- ======================
- */
- void RB_LoadShaderTextureMatrix( const float *shaderRegisters, const textureStage_t *texture ) {
- float matrix[16];
- RB_GetShaderTextureMatrix( shaderRegisters, texture, matrix );
- qglMatrixMode( GL_TEXTURE );
- qglLoadMatrixf( matrix );
- qglMatrixMode( GL_MODELVIEW );
- }
- /*
- ======================
- RB_BindVariableStageImage
- Handles generating a cinematic frame if needed
- ======================
- */
- void RB_BindVariableStageImage( const textureStage_t *texture, const float *shaderRegisters ) {
- if ( texture->cinematic ) {
- cinData_t cin;
- if ( r_skipDynamicTextures.GetBool() ) {
- globalImages->defaultImage->Bind();
- return;
- }
- // offset time by shaderParm[7] (FIXME: make the time offset a parameter of the shader?)
- // We make no attempt to optimize for multiple identical cinematics being in view, or
- // for cinematics going at a lower framerate than the renderer.
- cin = texture->cinematic->ImageForTime( (int)(1000 * ( backEnd.viewDef->floatTime + backEnd.viewDef->renderView.shaderParms[11] ) ) );
- if ( cin.image ) {
- globalImages->cinematicImage->UploadScratch( cin.image, cin.imageWidth, cin.imageHeight );
- } else {
- globalImages->blackImage->Bind();
- }
- } else {
- //FIXME: see why image is invalid
- if (texture->image) {
- texture->image->Bind();
- }
- }
- }
- /*
- ======================
- RB_BindStageTexture
- ======================
- */
- void RB_BindStageTexture( const float *shaderRegisters, const textureStage_t *texture, const drawSurf_t *surf ) {
- // image
- RB_BindVariableStageImage( texture, shaderRegisters );
- // texgens
- if ( texture->texgen == TG_DIFFUSE_CUBE ) {
- qglTexCoordPointer( 3, GL_FLOAT, sizeof( idDrawVert ), ((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->normal.ToFloatPtr() );
- }
- if ( texture->texgen == TG_SKYBOX_CUBE || texture->texgen == TG_WOBBLESKY_CUBE ) {
- qglTexCoordPointer( 3, GL_FLOAT, 0, vertexCache.Position( surf->dynamicTexCoords ) );
- }
- if ( texture->texgen == TG_REFLECT_CUBE ) {
- qglEnable( GL_TEXTURE_GEN_S );
- qglEnable( GL_TEXTURE_GEN_T );
- qglEnable( GL_TEXTURE_GEN_R );
- qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT );
- qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT );
- qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_EXT );
- qglEnableClientState( GL_NORMAL_ARRAY );
- qglNormalPointer( GL_FLOAT, sizeof( idDrawVert ), ((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->normal.ToFloatPtr() );
- qglMatrixMode( GL_TEXTURE );
- float mat[16];
- R_TransposeGLMatrix( backEnd.viewDef->worldSpace.modelViewMatrix, mat );
- qglLoadMatrixf( mat );
- qglMatrixMode( GL_MODELVIEW );
- }
- // matrix
- if ( texture->hasMatrix ) {
- RB_LoadShaderTextureMatrix( shaderRegisters, texture );
- }
- }
- /*
- ======================
- RB_FinishStageTexture
- ======================
- */
- void RB_FinishStageTexture( const textureStage_t *texture, const drawSurf_t *surf ) {
- if ( texture->texgen == TG_DIFFUSE_CUBE || texture->texgen == TG_SKYBOX_CUBE
- || texture->texgen == TG_WOBBLESKY_CUBE ) {
- qglTexCoordPointer( 2, GL_FLOAT, sizeof( idDrawVert ),
- (void *)&(((idDrawVert *)vertexCache.Position( surf->geo->ambientCache ))->st) );
- }
- if ( texture->texgen == TG_REFLECT_CUBE ) {
- qglDisable( GL_TEXTURE_GEN_S );
- qglDisable( GL_TEXTURE_GEN_T );
- qglDisable( GL_TEXTURE_GEN_R );
- qglTexGenf( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
- qglTexGenf( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
- qglTexGenf( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR );
- qglDisableClientState( GL_NORMAL_ARRAY );
- qglMatrixMode( GL_TEXTURE );
- qglLoadIdentity();
- qglMatrixMode( GL_MODELVIEW );
- }
- if ( texture->hasMatrix ) {
- qglMatrixMode( GL_TEXTURE );
- qglLoadIdentity();
- qglMatrixMode( GL_MODELVIEW );
- }
- }
- //=============================================================================================
- /*
- =================
- RB_DetermineLightScale
- Sets:
- backEnd.lightScale
- backEnd.overBright
- Find out how much we are going to need to overscale the lighting, so we
- can down modulate the pre-lighting passes.
- We only look at light calculations, but an argument could be made that
- we should also look at surface evaluations, which would let surfaces
- overbright past 1.0
- =================
- */
- void RB_DetermineLightScale( void ) {
- viewLight_t *vLight;
- const idMaterial *shader;
- float max;
- int i, j, numStages;
- const shaderStage_t *stage;
- // the light scale will be based on the largest color component of any surface
- // that will be drawn.
- // should we consider separating rgb scales?
- // if there are no lights, this will remain at 1.0, so GUI-only
- // rendering will not lose any bits of precision
- max = 1.0;
- for ( vLight = backEnd.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
- // lights with no surfaces or shaderparms may still be present
- // for debug display
- if ( !vLight->localInteractions && !vLight->globalInteractions
- && !vLight->translucentInteractions ) {
- continue;
- }
- shader = vLight->lightShader;
- numStages = shader->GetNumStages();
- for ( i = 0 ; i < numStages ; i++ ) {
- stage = shader->GetStage( i );
- for ( j = 0 ; j < 3 ; j++ ) {
- float v = r_lightScale.GetFloat() * vLight->shaderRegisters[ stage->color.registers[j] ];
- if ( v > max ) {
- max = v;
- }
- }
- }
- }
- backEnd.pc.maxLightValue = max;
- if ( max <= tr.backEndRendererMaxLight ) {
- backEnd.lightScale = r_lightScale.GetFloat();
- backEnd.overBright = 1.0;
- } else {
- backEnd.lightScale = r_lightScale.GetFloat() * tr.backEndRendererMaxLight / max;
- backEnd.overBright = max / tr.backEndRendererMaxLight;
- }
- }
- /*
- =================
- RB_BeginDrawingView
- Any mirrored or portaled views have already been drawn, so prepare
- to actually render the visible surfaces for this view
- =================
- */
- void RB_BeginDrawingView (void) {
- // set the modelview matrix for the viewer
- qglMatrixMode(GL_PROJECTION);
- qglLoadMatrixf( backEnd.viewDef->projectionMatrix );
- qglMatrixMode(GL_MODELVIEW);
- // set the window clipping
- qglViewport( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1,
- tr.viewportOffset[1] + backEnd.viewDef->viewport.y1,
- backEnd.viewDef->viewport.x2 + 1 - backEnd.viewDef->viewport.x1,
- backEnd.viewDef->viewport.y2 + 1 - backEnd.viewDef->viewport.y1 );
- // the scissor may be smaller than the viewport for subviews
- qglScissor( tr.viewportOffset[0] + backEnd.viewDef->viewport.x1 + backEnd.viewDef->scissor.x1,
- tr.viewportOffset[1] + backEnd.viewDef->viewport.y1 + backEnd.viewDef->scissor.y1,
- backEnd.viewDef->scissor.x2 + 1 - backEnd.viewDef->scissor.x1,
- backEnd.viewDef->scissor.y2 + 1 - backEnd.viewDef->scissor.y1 );
- backEnd.currentScissor = backEnd.viewDef->scissor;
- // ensures that depth writes are enabled for the depth clear
- GL_State( GLS_DEFAULT );
- // we don't have to clear the depth / stencil buffer for 2D rendering
- if ( backEnd.viewDef->viewEntitys ) {
- qglStencilMask( 0xff );
- // some cards may have 7 bit stencil buffers, so don't assume this
- // should be 128
- qglClearStencil( 1<<(glConfig.stencilBits-1) );
- qglClear( GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
- qglEnable( GL_DEPTH_TEST );
- } else {
- qglDisable( GL_DEPTH_TEST );
- qglDisable( GL_STENCIL_TEST );
- }
- backEnd.glState.faceCulling = -1; // force face culling to set next time
- GL_Cull( CT_FRONT_SIDED );
- }
- /*
- ==================
- R_SetDrawInteractions
- ==================
- */
- void R_SetDrawInteraction( const shaderStage_t *surfaceStage, const float *surfaceRegs,
- idImage **image, idVec4 matrix[2], float color[4] ) {
- *image = surfaceStage->texture.image;
- if ( surfaceStage->texture.hasMatrix ) {
- matrix[0][0] = surfaceRegs[surfaceStage->texture.matrix[0][0]];
- matrix[0][1] = surfaceRegs[surfaceStage->texture.matrix[0][1]];
- matrix[0][2] = 0;
- matrix[0][3] = surfaceRegs[surfaceStage->texture.matrix[0][2]];
- matrix[1][0] = surfaceRegs[surfaceStage->texture.matrix[1][0]];
- matrix[1][1] = surfaceRegs[surfaceStage->texture.matrix[1][1]];
- matrix[1][2] = 0;
- matrix[1][3] = surfaceRegs[surfaceStage->texture.matrix[1][2]];
- // we attempt to keep scrolls from generating incredibly large texture values, but
- // center rotations and center scales can still generate offsets that need to be > 1
- if ( matrix[0][3] < -40 || matrix[0][3] > 40 ) {
- matrix[0][3] -= (int)matrix[0][3];
- }
- if ( matrix[1][3] < -40 || matrix[1][3] > 40 ) {
- matrix[1][3] -= (int)matrix[1][3];
- }
- } else {
- matrix[0][0] = 1;
- matrix[0][1] = 0;
- matrix[0][2] = 0;
- matrix[0][3] = 0;
- matrix[1][0] = 0;
- matrix[1][1] = 1;
- matrix[1][2] = 0;
- matrix[1][3] = 0;
- }
- if ( color ) {
- for ( int i = 0 ; i < 4 ; i++ ) {
- color[i] = surfaceRegs[surfaceStage->color.registers[i]];
- // clamp here, so card with greater range don't look different.
- // we could perform overbrighting like we do for lights, but
- // it doesn't currently look worth it.
- if ( color[i] < 0 ) {
- color[i] = 0;
- } else if ( color[i] > 1.0 ) {
- color[i] = 1.0;
- }
- }
- }
- }
- /*
- =================
- RB_SubmittInteraction
- =================
- */
- static void RB_SubmittInteraction( drawInteraction_t *din, void (*DrawInteraction)(const drawInteraction_t *) ) {
- if ( !din->bumpImage ) {
- return;
- }
- if ( !din->diffuseImage || r_skipDiffuse.GetBool() ) {
- din->diffuseImage = globalImages->blackImage;
- }
- if ( !din->specularImage || r_skipSpecular.GetBool() || din->ambientLight ) {
- din->specularImage = globalImages->blackImage;
- }
- if ( !din->bumpImage || r_skipBump.GetBool() ) {
- din->bumpImage = globalImages->flatNormalMap;
- }
- // if we wouldn't draw anything, don't call the Draw function
- if (
- ( ( din->diffuseColor[0] > 0 ||
- din->diffuseColor[1] > 0 ||
- din->diffuseColor[2] > 0 ) && din->diffuseImage != globalImages->blackImage )
- || ( ( din->specularColor[0] > 0 ||
- din->specularColor[1] > 0 ||
- din->specularColor[2] > 0 ) && din->specularImage != globalImages->blackImage ) ) {
- DrawInteraction( din );
- }
- }
- /*
- =============
- RB_CreateSingleDrawInteractions
- This can be used by different draw_* backends to decompose a complex light / surface
- interaction into primitive interactions
- =============
- */
- void RB_CreateSingleDrawInteractions( const drawSurf_t *surf, void (*DrawInteraction)(const drawInteraction_t *) ) {
- const idMaterial *surfaceShader = surf->material;
- const float *surfaceRegs = surf->shaderRegisters;
- const viewLight_t *vLight = backEnd.vLight;
- const idMaterial *lightShader = vLight->lightShader;
- const float *lightRegs = vLight->shaderRegisters;
- drawInteraction_t inter;
- if ( r_skipInteractions.GetBool() || !surf->geo || !surf->geo->ambientCache ) {
- return;
- }
- if ( tr.logFile ) {
- RB_LogComment( "---------- RB_CreateSingleDrawInteractions %s on %s ----------\n", lightShader->GetName(), surfaceShader->GetName() );
- }
- // change the matrix and light projection vectors if needed
- if ( surf->space != backEnd.currentSpace ) {
- backEnd.currentSpace = surf->space;
- qglLoadMatrixf( surf->space->modelViewMatrix );
- }
- // change the scissor if needed
- if ( r_useScissor.GetBool() && !backEnd.currentScissor.Equals( surf->scissorRect ) ) {
- backEnd.currentScissor = surf->scissorRect;
- qglScissor( backEnd.viewDef->viewport.x1 + backEnd.currentScissor.x1,
- backEnd.viewDef->viewport.y1 + backEnd.currentScissor.y1,
- backEnd.currentScissor.x2 + 1 - backEnd.currentScissor.x1,
- backEnd.currentScissor.y2 + 1 - backEnd.currentScissor.y1 );
- }
- // hack depth range if needed
- if ( surf->space->weaponDepthHack ) {
- RB_EnterWeaponDepthHack();
- }
- if ( surf->space->modelDepthHack ) {
- RB_EnterModelDepthHack( surf->space->modelDepthHack );
- }
- inter.surf = surf;
- inter.lightFalloffImage = vLight->falloffImage;
- R_GlobalPointToLocal( surf->space->modelMatrix, vLight->globalLightOrigin, inter.localLightOrigin.ToVec3() );
- R_GlobalPointToLocal( surf->space->modelMatrix, backEnd.viewDef->renderView.vieworg, inter.localViewOrigin.ToVec3() );
- inter.localLightOrigin[3] = 0;
- inter.localViewOrigin[3] = 1;
- inter.ambientLight = lightShader->IsAmbientLight();
- // the base projections may be modified by texture matrix on light stages
- idPlane lightProject[4];
- for ( int i = 0 ; i < 4 ; i++ ) {
- R_GlobalPlaneToLocal( surf->space->modelMatrix, backEnd.vLight->lightProject[i], lightProject[i] );
- }
- for ( int lightStageNum = 0 ; lightStageNum < lightShader->GetNumStages() ; lightStageNum++ ) {
- const shaderStage_t *lightStage = lightShader->GetStage( lightStageNum );
- // ignore stages that fail the condition
- if ( !lightRegs[ lightStage->conditionRegister ] ) {
- continue;
- }
- inter.lightImage = lightStage->texture.image;
- memcpy( inter.lightProjection, lightProject, sizeof( inter.lightProjection ) );
- // now multiply the texgen by the light texture matrix
- if ( lightStage->texture.hasMatrix ) {
- RB_GetShaderTextureMatrix( lightRegs, &lightStage->texture, backEnd.lightTextureMatrix );
- RB_BakeTextureMatrixIntoTexgen( reinterpret_cast<class idPlane *>(inter.lightProjection), backEnd.lightTextureMatrix );
- }
- inter.bumpImage = NULL;
- inter.specularImage = NULL;
- inter.diffuseImage = NULL;
- inter.diffuseColor[0] = inter.diffuseColor[1] = inter.diffuseColor[2] = inter.diffuseColor[3] = 0;
- inter.specularColor[0] = inter.specularColor[1] = inter.specularColor[2] = inter.specularColor[3] = 0;
- float lightColor[4];
- // backEnd.lightScale is calculated so that lightColor[] will never exceed
- // tr.backEndRendererMaxLight
- lightColor[0] = backEnd.lightScale * lightRegs[ lightStage->color.registers[0] ];
- lightColor[1] = backEnd.lightScale * lightRegs[ lightStage->color.registers[1] ];
- lightColor[2] = backEnd.lightScale * lightRegs[ lightStage->color.registers[2] ];
- lightColor[3] = lightRegs[ lightStage->color.registers[3] ];
- // go through the individual stages
- for ( int surfaceStageNum = 0 ; surfaceStageNum < surfaceShader->GetNumStages() ; surfaceStageNum++ ) {
- const shaderStage_t *surfaceStage = surfaceShader->GetStage( surfaceStageNum );
- switch( surfaceStage->lighting ) {
- case SL_AMBIENT: {
- // ignore ambient stages while drawing interactions
- break;
- }
- case SL_BUMP: {
- // ignore stage that fails the condition
- if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
- break;
- }
- // draw any previous interaction
- RB_SubmittInteraction( &inter, DrawInteraction );
- inter.diffuseImage = NULL;
- inter.specularImage = NULL;
- R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.bumpImage, inter.bumpMatrix, NULL );
- break;
- }
- case SL_DIFFUSE: {
- // ignore stage that fails the condition
- if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
- break;
- }
- if ( inter.diffuseImage ) {
- RB_SubmittInteraction( &inter, DrawInteraction );
- }
- R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.diffuseImage,
- inter.diffuseMatrix, inter.diffuseColor.ToFloatPtr() );
- inter.diffuseColor[0] *= lightColor[0];
- inter.diffuseColor[1] *= lightColor[1];
- inter.diffuseColor[2] *= lightColor[2];
- inter.diffuseColor[3] *= lightColor[3];
- inter.vertexColor = surfaceStage->vertexColor;
- break;
- }
- case SL_SPECULAR: {
- // ignore stage that fails the condition
- if ( !surfaceRegs[ surfaceStage->conditionRegister ] ) {
- break;
- }
- if ( inter.specularImage ) {
- RB_SubmittInteraction( &inter, DrawInteraction );
- }
- R_SetDrawInteraction( surfaceStage, surfaceRegs, &inter.specularImage,
- inter.specularMatrix, inter.specularColor.ToFloatPtr() );
- inter.specularColor[0] *= lightColor[0];
- inter.specularColor[1] *= lightColor[1];
- inter.specularColor[2] *= lightColor[2];
- inter.specularColor[3] *= lightColor[3];
- inter.vertexColor = surfaceStage->vertexColor;
- break;
- }
- }
- }
- // draw the final interaction
- RB_SubmittInteraction( &inter, DrawInteraction );
- }
- // unhack depth range if needed
- if ( surf->space->weaponDepthHack || surf->space->modelDepthHack != 0.0f ) {
- RB_LeaveDepthHack();
- }
- }
- /*
- =============
- RB_DrawView
- =============
- */
- void RB_DrawView( const void *data ) {
- const drawSurfsCommand_t *cmd;
- cmd = (const drawSurfsCommand_t *)data;
- backEnd.viewDef = cmd->viewDef;
-
- // we will need to do a new copyTexSubImage of the screen
- // when a SS_POST_PROCESS material is used
- backEnd.currentRenderCopied = false;
- // if there aren't any drawsurfs, do nothing
- if ( !backEnd.viewDef->numDrawSurfs ) {
- return;
- }
- // skip render bypasses everything that has models, assuming
- // them to be 3D views, but leaves 2D rendering visible
- if ( r_skipRender.GetBool() && backEnd.viewDef->viewEntitys ) {
- return;
- }
- // skip render context sets the wgl context to NULL,
- // which should factor out the API cost, under the assumption
- // that all gl calls just return if the context isn't valid
- if ( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) {
- GLimp_DeactivateContext();
- }
- backEnd.pc.c_surfaces += backEnd.viewDef->numDrawSurfs;
- RB_ShowOverdraw();
- // render the scene, jumping to the hardware specific interaction renderers
- RB_STD_DrawView();
- // restore the context for 2D drawing if we were stubbing it out
- if ( r_skipRenderContext.GetBool() && backEnd.viewDef->viewEntitys ) {
- GLimp_ActivateContext();
- RB_SetDefaultGLState();
- }
- }
|