Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

tr_backend.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 #include "tr_local.h"
00023 
00024 backEndData_t   *backEndData[SMP_FRAMES];
00025 backEndState_t  backEnd;
00026 
00027 
00028 static float    s_flipMatrix[16] = {
00029     // convert from our coordinate system (looking down X)
00030     // to OpenGL's coordinate system (looking down -Z)
00031     0, 0, -1, 0,
00032     -1, 0, 0, 0,
00033     0, 1, 0, 0,
00034     0, 0, 0, 1
00035 };
00036 
00037 
00038 /*
00039 ** GL_Bind
00040 */
00041 void GL_Bind( image_t *image ) {
00042     int texnum;
00043 
00044     if ( !image ) {
00045         ri.Printf( PRINT_WARNING, "GL_Bind: NULL image\n" );
00046         texnum = tr.defaultImage->texnum;
00047     } else {
00048         texnum = image->texnum;
00049     }
00050 
00051     if ( r_nobind->integer && tr.dlightImage ) {        // performance evaluation option
00052         texnum = tr.dlightImage->texnum;
00053     }
00054 
00055     if ( glState.currenttextures[glState.currenttmu] != texnum ) {
00056         image->frameUsed = tr.frameCount;
00057         glState.currenttextures[glState.currenttmu] = texnum;
00058         qglBindTexture (GL_TEXTURE_2D, texnum);
00059     }
00060 }
00061 
00062 /*
00063 ** GL_SelectTexture
00064 */
00065 void GL_SelectTexture( int unit )
00066 {
00067     if ( glState.currenttmu == unit )
00068     {
00069         return;
00070     }
00071 
00072     if ( unit == 0 )
00073     {
00074         qglActiveTextureARB( GL_TEXTURE0_ARB );
00075         GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE0_ARB )\n" );
00076         qglClientActiveTextureARB( GL_TEXTURE0_ARB );
00077         GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE0_ARB )\n" );
00078     }
00079     else if ( unit == 1 )
00080     {
00081         qglActiveTextureARB( GL_TEXTURE1_ARB );
00082         GLimp_LogComment( "glActiveTextureARB( GL_TEXTURE1_ARB )\n" );
00083         qglClientActiveTextureARB( GL_TEXTURE1_ARB );
00084         GLimp_LogComment( "glClientActiveTextureARB( GL_TEXTURE1_ARB )\n" );
00085     } else {
00086         ri.Error( ERR_DROP, "GL_SelectTexture: unit = %i", unit );
00087     }
00088 
00089     glState.currenttmu = unit;
00090 }
00091 
00092 
00093 /*
00094 ** GL_BindMultitexture
00095 */
00096 void GL_BindMultitexture( image_t *image0, GLuint env0, image_t *image1, GLuint env1 ) {
00097     int     texnum0, texnum1;
00098 
00099     texnum0 = image0->texnum;
00100     texnum1 = image1->texnum;
00101 
00102     if ( r_nobind->integer && tr.dlightImage ) {        // performance evaluation option
00103         texnum0 = texnum1 = tr.dlightImage->texnum;
00104     }
00105 
00106     if ( glState.currenttextures[1] != texnum1 ) {
00107         GL_SelectTexture( 1 );
00108         image1->frameUsed = tr.frameCount;
00109         glState.currenttextures[1] = texnum1;
00110         qglBindTexture( GL_TEXTURE_2D, texnum1 );
00111     }
00112     if ( glState.currenttextures[0] != texnum0 ) {
00113         GL_SelectTexture( 0 );
00114         image0->frameUsed = tr.frameCount;
00115         glState.currenttextures[0] = texnum0;
00116         qglBindTexture( GL_TEXTURE_2D, texnum0 );
00117     }
00118 }
00119 
00120 
00121 /*
00122 ** GL_Cull
00123 */
00124 void GL_Cull( int cullType ) {
00125     if ( glState.faceCulling == cullType ) {
00126         return;
00127     }
00128 
00129     glState.faceCulling = cullType;
00130 
00131     if ( cullType == CT_TWO_SIDED ) 
00132     {
00133         qglDisable( GL_CULL_FACE );
00134     } 
00135     else 
00136     {
00137         qglEnable( GL_CULL_FACE );
00138 
00139         if ( cullType == CT_BACK_SIDED )
00140         {
00141             if ( backEnd.viewParms.isMirror )
00142             {
00143                 qglCullFace( GL_FRONT );
00144             }
00145             else
00146             {
00147                 qglCullFace( GL_BACK );
00148             }
00149         }
00150         else
00151         {
00152             if ( backEnd.viewParms.isMirror )
00153             {
00154                 qglCullFace( GL_BACK );
00155             }
00156             else
00157             {
00158                 qglCullFace( GL_FRONT );
00159             }
00160         }
00161     }
00162 }
00163 
00164 /*
00165 ** GL_TexEnv
00166 */
00167 void GL_TexEnv( int env )
00168 {
00169     if ( env == glState.texEnv[glState.currenttmu] )
00170     {
00171         return;
00172     }
00173 
00174     glState.texEnv[glState.currenttmu] = env;
00175 
00176 
00177     switch ( env )
00178     {
00179     case GL_MODULATE:
00180         qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
00181         break;
00182     case GL_REPLACE:
00183         qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
00184         break;
00185     case GL_DECAL:
00186         qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
00187         break;
00188     case GL_ADD:
00189         qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD );
00190         break;
00191     default:
00192         ri.Error( ERR_DROP, "GL_TexEnv: invalid env '%d' passed\n", env );
00193         break;
00194     }
00195 }
00196 
00197 /*
00198 ** GL_State
00199 **
00200 ** This routine is responsible for setting the most commonly changed state
00201 ** in Q3.
00202 */
00203 void GL_State( unsigned long stateBits )
00204 {
00205     unsigned long diff = stateBits ^ glState.glStateBits;
00206 
00207     if ( !diff )
00208     {
00209         return;
00210     }
00211 
00212     //
00213     // check depthFunc bits
00214     //
00215     if ( diff & GLS_DEPTHFUNC_EQUAL )
00216     {
00217         if ( stateBits & GLS_DEPTHFUNC_EQUAL )
00218         {
00219             qglDepthFunc( GL_EQUAL );
00220         }
00221         else
00222         {
00223             qglDepthFunc( GL_LEQUAL );
00224         }
00225     }
00226 
00227     //
00228     // check blend bits
00229     //
00230     if ( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )
00231     {
00232         GLenum srcFactor, dstFactor;
00233 
00234         if ( stateBits & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )
00235         {
00236             switch ( stateBits & GLS_SRCBLEND_BITS )
00237             {
00238             case GLS_SRCBLEND_ZERO:
00239                 srcFactor = GL_ZERO;
00240                 break;
00241             case GLS_SRCBLEND_ONE:
00242                 srcFactor = GL_ONE;
00243                 break;
00244             case GLS_SRCBLEND_DST_COLOR:
00245                 srcFactor = GL_DST_COLOR;
00246                 break;
00247             case GLS_SRCBLEND_ONE_MINUS_DST_COLOR:
00248                 srcFactor = GL_ONE_MINUS_DST_COLOR;
00249                 break;
00250             case GLS_SRCBLEND_SRC_ALPHA:
00251                 srcFactor = GL_SRC_ALPHA;
00252                 break;
00253             case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA:
00254                 srcFactor = GL_ONE_MINUS_SRC_ALPHA;
00255                 break;
00256             case GLS_SRCBLEND_DST_ALPHA:
00257                 srcFactor = GL_DST_ALPHA;
00258                 break;
00259             case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA:
00260                 srcFactor = GL_ONE_MINUS_DST_ALPHA;
00261                 break;
00262             case GLS_SRCBLEND_ALPHA_SATURATE:
00263                 srcFactor = GL_SRC_ALPHA_SATURATE;
00264                 break;
00265             default:
00266                 srcFactor = GL_ONE;     // to get warning to shut up
00267                 ri.Error( ERR_DROP, "GL_State: invalid src blend state bits\n" );
00268                 break;
00269             }
00270 
00271             switch ( stateBits & GLS_DSTBLEND_BITS )
00272             {
00273             case GLS_DSTBLEND_ZERO:
00274                 dstFactor = GL_ZERO;
00275                 break;
00276             case GLS_DSTBLEND_ONE:
00277                 dstFactor = GL_ONE;
00278                 break;
00279             case GLS_DSTBLEND_SRC_COLOR:
00280                 dstFactor = GL_SRC_COLOR;
00281                 break;
00282             case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR:
00283                 dstFactor = GL_ONE_MINUS_SRC_COLOR;
00284                 break;
00285             case GLS_DSTBLEND_SRC_ALPHA:
00286                 dstFactor = GL_SRC_ALPHA;
00287                 break;
00288             case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA:
00289                 dstFactor = GL_ONE_MINUS_SRC_ALPHA;
00290                 break;
00291             case GLS_DSTBLEND_DST_ALPHA:
00292                 dstFactor = GL_DST_ALPHA;
00293                 break;
00294             case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA:
00295                 dstFactor = GL_ONE_MINUS_DST_ALPHA;
00296                 break;
00297             default:
00298                 dstFactor = GL_ONE;     // to get warning to shut up
00299                 ri.Error( ERR_DROP, "GL_State: invalid dst blend state bits\n" );
00300                 break;
00301             }
00302 
00303             qglEnable( GL_BLEND );
00304             qglBlendFunc( srcFactor, dstFactor );
00305         }
00306         else
00307         {
00308             qglDisable( GL_BLEND );
00309         }
00310     }
00311 
00312     //
00313     // check depthmask
00314     //
00315     if ( diff & GLS_DEPTHMASK_TRUE )
00316     {
00317         if ( stateBits & GLS_DEPTHMASK_TRUE )
00318         {
00319             qglDepthMask( GL_TRUE );
00320         }
00321         else
00322         {
00323             qglDepthMask( GL_FALSE );
00324         }
00325     }
00326 
00327     //
00328     // fill/line mode
00329     //
00330     if ( diff & GLS_POLYMODE_LINE )
00331     {
00332         if ( stateBits & GLS_POLYMODE_LINE )
00333         {
00334             qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
00335         }
00336         else
00337         {
00338             qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
00339         }
00340     }
00341 
00342     //
00343     // depthtest
00344     //
00345     if ( diff & GLS_DEPTHTEST_DISABLE )
00346     {
00347         if ( stateBits & GLS_DEPTHTEST_DISABLE )
00348         {
00349             qglDisable( GL_DEPTH_TEST );
00350         }
00351         else
00352         {
00353             qglEnable( GL_DEPTH_TEST );
00354         }
00355     }
00356 
00357     //
00358     // alpha test
00359     //
00360     if ( diff & GLS_ATEST_BITS )
00361     {
00362         switch ( stateBits & GLS_ATEST_BITS )
00363         {
00364         case 0:
00365             qglDisable( GL_ALPHA_TEST );
00366             break;
00367         case GLS_ATEST_GT_0:
00368             qglEnable( GL_ALPHA_TEST );
00369             qglAlphaFunc( GL_GREATER, 0.0f );
00370             break;
00371         case GLS_ATEST_LT_80:
00372             qglEnable( GL_ALPHA_TEST );
00373             qglAlphaFunc( GL_LESS, 0.5f );
00374             break;
00375         case GLS_ATEST_GE_80:
00376             qglEnable( GL_ALPHA_TEST );
00377             qglAlphaFunc( GL_GEQUAL, 0.5f );
00378             break;
00379         default:
00380             assert( 0 );
00381             break;
00382         }
00383     }
00384 
00385     glState.glStateBits = stateBits;
00386 }
00387 
00388 
00389 
00390 /*
00391 ================
00392 RB_Hyperspace
00393 
00394 A player has predicted a teleport, but hasn't arrived yet
00395 ================
00396 */
00397 static void RB_Hyperspace( void ) {
00398     float       c;
00399 
00400     if ( !backEnd.isHyperspace ) {
00401         // do initialization shit
00402     }
00403 
00404     c = ( backEnd.refdef.time & 255 ) / 255.0f;
00405     qglClearColor( c, c, c, 1 );
00406     qglClear( GL_COLOR_BUFFER_BIT );
00407 
00408     backEnd.isHyperspace = qtrue;
00409 }
00410 
00411 
00412 static void SetViewportAndScissor( void ) {
00413     qglMatrixMode(GL_PROJECTION);
00414     qglLoadMatrixf( backEnd.viewParms.projectionMatrix );
00415     qglMatrixMode(GL_MODELVIEW);
00416 
00417     // set the window clipping
00418     qglViewport( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, 
00419         backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight );
00420     qglScissor( backEnd.viewParms.viewportX, backEnd.viewParms.viewportY, 
00421         backEnd.viewParms.viewportWidth, backEnd.viewParms.viewportHeight );
00422 }
00423 
00424 /*
00425 =================
00426 RB_BeginDrawingView
00427 
00428 Any mirrored or portaled views have already been drawn, so prepare
00429 to actually render the visible surfaces for this view
00430 =================
00431 */
00432 void RB_BeginDrawingView (void) {
00433     int clearBits = 0;
00434 
00435     // sync with gl if needed
00436     if ( r_finish->integer == 1 && !glState.finishCalled ) {
00437         qglFinish ();
00438         glState.finishCalled = qtrue;
00439     }
00440     if ( r_finish->integer == 0 ) {
00441         glState.finishCalled = qtrue;
00442     }
00443 
00444     // we will need to change the projection matrix before drawing
00445     // 2D images again
00446     backEnd.projection2D = qfalse;
00447 
00448     //
00449     // set the modelview matrix for the viewer
00450     //
00451     SetViewportAndScissor();
00452 
00453     // ensures that depth writes are enabled for the depth clear
00454     GL_State( GLS_DEFAULT );
00455     // clear relevant buffers
00456     clearBits = GL_DEPTH_BUFFER_BIT;
00457 
00458     if ( r_measureOverdraw->integer || r_shadows->integer == 2 )
00459     {
00460         clearBits |= GL_STENCIL_BUFFER_BIT;
00461     }
00462     if ( r_fastsky->integer && !( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) )
00463     {
00464         clearBits |= GL_COLOR_BUFFER_BIT;   // FIXME: only if sky shaders have been used
00465 #ifdef _DEBUG
00466         qglClearColor( 0.8f, 0.7f, 0.4f, 1.0f );    // FIXME: get color of sky
00467 #else
00468         qglClearColor( 0.0f, 0.0f, 0.0f, 1.0f );    // FIXME: get color of sky
00469 #endif
00470     }
00471     qglClear( clearBits );
00472 
00473     if ( ( backEnd.refdef.rdflags & RDF_HYPERSPACE ) )
00474     {
00475         RB_Hyperspace();
00476         return;
00477     }
00478     else
00479     {
00480         backEnd.isHyperspace = qfalse;
00481     }
00482 
00483     glState.faceCulling = -1;       // force face culling to set next time
00484 
00485     // we will only draw a sun if there was sky rendered in this view
00486     backEnd.skyRenderedThisView = qfalse;
00487 
00488     // clip to the plane of the portal
00489     if ( backEnd.viewParms.isPortal ) {
00490         float   plane[4];
00491         double  plane2[4];
00492 
00493         plane[0] = backEnd.viewParms.portalPlane.normal[0];
00494         plane[1] = backEnd.viewParms.portalPlane.normal[1];
00495         plane[2] = backEnd.viewParms.portalPlane.normal[2];
00496         plane[3] = backEnd.viewParms.portalPlane.dist;
00497 
00498         plane2[0] = DotProduct (backEnd.viewParms.or.axis[0], plane);
00499         plane2[1] = DotProduct (backEnd.viewParms.or.axis[1], plane);
00500         plane2[2] = DotProduct (backEnd.viewParms.or.axis[2], plane);
00501         plane2[3] = DotProduct (plane, backEnd.viewParms.or.origin) - plane[3];
00502 
00503         qglLoadMatrixf( s_flipMatrix );
00504         qglClipPlane (GL_CLIP_PLANE0, plane2);
00505         qglEnable (GL_CLIP_PLANE0);
00506     } else {
00507         qglDisable (GL_CLIP_PLANE0);
00508     }
00509 }
00510 
00511 
00512 #define MAC_EVENT_PUMP_MSEC     5
00513 
00514 /*
00515 ==================
00516 RB_RenderDrawSurfList
00517 ==================
00518 */
00519 void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
00520     shader_t        *shader, *oldShader;
00521     int             fogNum, oldFogNum;
00522     int             entityNum, oldEntityNum;
00523     int             dlighted, oldDlighted;
00524     qboolean        depthRange, oldDepthRange;
00525     int             i;
00526     drawSurf_t      *drawSurf;
00527     int             oldSort;
00528     float           originalTime;
00529 #ifdef __MACOS__
00530     int             macEventTime;
00531 
00532     Sys_PumpEvents();       // crutch up the mac's limited buffer queue size
00533 
00534     // we don't want to pump the event loop too often and waste time, so
00535     // we are going to check every shader change
00536     macEventTime = ri.Milliseconds() + MAC_EVENT_PUMP_MSEC;
00537 #endif
00538 
00539     // save original time for entity shader offsets
00540     originalTime = backEnd.refdef.floatTime;
00541 
00542     // clear the z buffer, set the modelview, etc
00543     RB_BeginDrawingView ();
00544 
00545     // draw everything
00546     oldEntityNum = -1;
00547     backEnd.currentEntity = &tr.worldEntity;
00548     oldShader = NULL;
00549     oldFogNum = -1;
00550     oldDepthRange = qfalse;
00551     oldDlighted = qfalse;
00552     oldSort = -1;
00553     depthRange = qfalse;
00554 
00555     backEnd.pc.c_surfaces += numDrawSurfs;
00556 
00557     for (i = 0, drawSurf = drawSurfs ; i < numDrawSurfs ; i++, drawSurf++) {
00558         if ( drawSurf->sort == oldSort ) {
00559             // fast path, same as previous sort
00560             rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
00561             continue;
00562         }
00563         oldSort = drawSurf->sort;
00564         R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );
00565 
00566         //
00567         // change the tess parameters if needed
00568         // a "entityMergable" shader is a shader that can have surfaces from seperate
00569         // entities merged into a single batch, like smoke and blood puff sprites
00570         if (shader != oldShader || fogNum != oldFogNum || dlighted != oldDlighted 
00571             || ( entityNum != oldEntityNum && !shader->entityMergable ) ) {
00572             if (oldShader != NULL) {
00573 #ifdef __MACOS__    // crutch up the mac's limited buffer queue size
00574                 int     t;
00575 
00576                 t = ri.Milliseconds();
00577                 if ( t > macEventTime ) {
00578                     macEventTime = t + MAC_EVENT_PUMP_MSEC;
00579                     Sys_PumpEvents();
00580                 }
00581 #endif
00582                 RB_EndSurface();
00583             }
00584             RB_BeginSurface( shader, fogNum );
00585             oldShader = shader;
00586             oldFogNum = fogNum;
00587             oldDlighted = dlighted;
00588         }
00589 
00590         //
00591         // change the modelview matrix if needed
00592         //
00593         if ( entityNum != oldEntityNum ) {
00594             depthRange = qfalse;
00595 
00596             if ( entityNum != ENTITYNUM_WORLD ) {
00597                 backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
00598                 backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime;
00599                 // we have to reset the shaderTime as well otherwise image animations start
00600                 // from the wrong frame
00601                 tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
00602 
00603                 // set up the transformation matrix
00604                 R_RotateForEntity( backEnd.currentEntity, &backEnd.viewParms, &backEnd.or );
00605 
00606                 // set up the dynamic lighting if needed
00607                 if ( backEnd.currentEntity->needDlights ) {
00608                     R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );
00609                 }
00610 
00611                 if ( backEnd.currentEntity->e.renderfx & RF_DEPTHHACK ) {
00612                     // hack the depth range to prevent view model from poking into walls
00613                     depthRange = qtrue;
00614                 }
00615             } else {
00616                 backEnd.currentEntity = &tr.worldEntity;
00617                 backEnd.refdef.floatTime = originalTime;
00618                 backEnd.or = backEnd.viewParms.world;
00619                 // we have to reset the shaderTime as well otherwise image animations on
00620                 // the world (like water) continue with the wrong frame
00621                 tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
00622                 R_TransformDlights( backEnd.refdef.num_dlights, backEnd.refdef.dlights, &backEnd.or );
00623             }
00624 
00625             qglLoadMatrixf( backEnd.or.modelMatrix );
00626 
00627             //
00628             // change depthrange if needed
00629             //
00630             if ( oldDepthRange != depthRange ) {
00631                 if ( depthRange ) {
00632                     qglDepthRange (0, 0.3);
00633                 } else {
00634                     qglDepthRange (0, 1);
00635                 }
00636                 oldDepthRange = depthRange;
00637             }
00638 
00639             oldEntityNum = entityNum;
00640         }
00641 
00642         // add the triangles for this surface
00643         rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
00644     }
00645 
00646     backEnd.refdef.floatTime = originalTime;
00647 
00648     // draw the contents of the last shader batch
00649     if (oldShader != NULL) {
00650         RB_EndSurface();
00651     }
00652 
00653     // go back to the world modelview matrix
00654     qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
00655     if ( depthRange ) {
00656         qglDepthRange (0, 1);
00657     }
00658 
00659 #if 0
00660     RB_DrawSun();
00661 #endif
00662     // darken down any stencil shadows
00663     RB_ShadowFinish();      
00664 
00665     // add light flares on lights that aren't obscured
00666     RB_RenderFlares();
00667 
00668 #ifdef __MACOS__
00669     Sys_PumpEvents();       // crutch up the mac's limited buffer queue size
00670 #endif
00671 }
00672 
00673 
00674 /*
00675 ============================================================================
00676 
00677 RENDER BACK END THREAD FUNCTIONS
00678 
00679 ============================================================================
00680 */
00681 
00682 /*
00683 ================
00684 RB_SetGL2D
00685 
00686 ================
00687 */
00688 void    RB_SetGL2D (void) {
00689     backEnd.projection2D = qtrue;
00690 
00691     // set 2D virtual screen size
00692     qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
00693     qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight );
00694     qglMatrixMode(GL_PROJECTION);
00695     qglLoadIdentity ();
00696     qglOrtho (0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1);
00697     qglMatrixMode(GL_MODELVIEW);
00698     qglLoadIdentity ();
00699 
00700     GL_State( GLS_DEPTHTEST_DISABLE |
00701               GLS_SRCBLEND_SRC_ALPHA |
00702               GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
00703 
00704     qglDisable( GL_CULL_FACE );
00705     qglDisable( GL_CLIP_PLANE0 );
00706 
00707     // set time for 2D shaders
00708     backEnd.refdef.time = ri.Milliseconds();
00709     backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f;
00710 }
00711 
00712 
00713 /*
00714 =============
00715 RE_StretchRaw
00716 
00717 FIXME: not exactly backend
00718 Stretches a raw 32 bit power of 2 bitmap image over the given screen rectangle.
00719 Used for cinematics.
00720 =============
00721 */
00722 void RE_StretchRaw (int x, int y, int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
00723     int         i, j;
00724     int         start, end;
00725 
00726     if ( !tr.registered ) {
00727         return;
00728     }
00729     R_SyncRenderThread();
00730 
00731     // we definately want to sync every frame for the cinematics
00732     qglFinish();
00733 
00734     start = end = 0;
00735     if ( r_speeds->integer ) {
00736         start = ri.Milliseconds();
00737     }
00738 
00739     // make sure rows and cols are powers of 2
00740     for ( i = 0 ; ( 1 << i ) < cols ; i++ ) {
00741     }
00742     for ( j = 0 ; ( 1 << j ) < rows ; j++ ) {
00743     }
00744     if ( ( 1 << i ) != cols || ( 1 << j ) != rows) {
00745         ri.Error (ERR_DROP, "Draw_StretchRaw: size not a power of 2: %i by %i", cols, rows);
00746     }
00747 
00748     GL_Bind( tr.scratchImage[client] );
00749 
00750     // if the scratchImage isn't in the format we want, specify it as a new texture
00751     if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
00752         tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
00753         tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
00754         qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
00755         qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00756         qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00757         qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
00758         qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); 
00759     } else {
00760         if (dirty) {
00761             // otherwise, just subimage upload it so that drivers can tell we are going to be changing
00762             // it and don't try and do a texture compression
00763             qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
00764         }
00765     }
00766 
00767     if ( r_speeds->integer ) {
00768         end = ri.Milliseconds();
00769         ri.Printf( PRINT_ALL, "qglTexSubImage2D %i, %i: %i msec\n", cols, rows, end - start );
00770     }
00771 
00772     RB_SetGL2D();
00773 
00774     qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );
00775 
00776     qglBegin (GL_QUADS);
00777     qglTexCoord2f ( 0.5f / cols,  0.5f / rows );
00778     qglVertex2f (x, y);
00779     qglTexCoord2f ( ( cols - 0.5f ) / cols ,  0.5f / rows );
00780     qglVertex2f (x+w, y);
00781     qglTexCoord2f ( ( cols - 0.5f ) / cols, ( rows - 0.5f ) / rows );
00782     qglVertex2f (x+w, y+h);
00783     qglTexCoord2f ( 0.5f / cols, ( rows - 0.5f ) / rows );
00784     qglVertex2f (x, y+h);
00785     qglEnd ();
00786 }
00787 
00788 void RE_UploadCinematic (int w, int h, int cols, int rows, const byte *data, int client, qboolean dirty) {
00789 
00790     GL_Bind( tr.scratchImage[client] );
00791 
00792     // if the scratchImage isn't in the format we want, specify it as a new texture
00793     if ( cols != tr.scratchImage[client]->width || rows != tr.scratchImage[client]->height ) {
00794         tr.scratchImage[client]->width = tr.scratchImage[client]->uploadWidth = cols;
00795         tr.scratchImage[client]->height = tr.scratchImage[client]->uploadHeight = rows;
00796         qglTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, cols, rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
00797         qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00798         qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00799         qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
00800         qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); 
00801     } else {
00802         if (dirty) {
00803             // otherwise, just subimage upload it so that drivers can tell we are going to be changing
00804             // it and don't try and do a texture compression
00805             qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_RGBA, GL_UNSIGNED_BYTE, data );
00806         }
00807     }
00808 }
00809 
00810 
00811 /*
00812 =============
00813 RB_SetColor
00814 
00815 =============
00816 */
00817 const void  *RB_SetColor( const void *data ) {
00818     const setColorCommand_t *cmd;
00819 
00820     cmd = (const setColorCommand_t *)data;
00821 
00822     backEnd.color2D[0] = cmd->color[0] * 255;
00823     backEnd.color2D[1] = cmd->color[1] * 255;
00824     backEnd.color2D[2] = cmd->color[2] * 255;
00825     backEnd.color2D[3] = cmd->color[3] * 255;
00826 
00827     return (const void *)(cmd + 1);
00828 }
00829 
00830 /*
00831 =============
00832 RB_StretchPic
00833 =============
00834 */
00835 const void *RB_StretchPic ( const void *data ) {
00836     const stretchPicCommand_t   *cmd;
00837     shader_t *shader;
00838     int     numVerts, numIndexes;
00839 
00840     cmd = (const stretchPicCommand_t *)data;
00841 
00842     if ( !backEnd.projection2D ) {
00843         RB_SetGL2D();
00844     }
00845 
00846     shader = cmd->shader;
00847     if ( shader != tess.shader ) {
00848         if ( tess.numIndexes ) {
00849             RB_EndSurface();
00850         }
00851         backEnd.currentEntity = &backEnd.entity2D;
00852         RB_BeginSurface( shader, 0 );
00853     }
00854 
00855     RB_CHECKOVERFLOW( 4, 6 );
00856     numVerts = tess.numVertexes;
00857     numIndexes = tess.numIndexes;
00858 
00859     tess.numVertexes += 4;
00860     tess.numIndexes += 6;
00861 
00862     tess.indexes[ numIndexes ] = numVerts + 3;
00863     tess.indexes[ numIndexes + 1 ] = numVerts + 0;
00864     tess.indexes[ numIndexes + 2 ] = numVerts + 2;
00865     tess.indexes[ numIndexes + 3 ] = numVerts + 2;
00866     tess.indexes[ numIndexes + 4 ] = numVerts + 0;
00867     tess.indexes[ numIndexes + 5 ] = numVerts + 1;
00868 
00869     *(int *)tess.vertexColors[ numVerts ] =
00870         *(int *)tess.vertexColors[ numVerts + 1 ] =
00871         *(int *)tess.vertexColors[ numVerts + 2 ] =
00872         *(int *)tess.vertexColors[ numVerts + 3 ] = *(int *)backEnd.color2D;
00873 
00874     tess.xyz[ numVerts ][0] = cmd->x;
00875     tess.xyz[ numVerts ][1] = cmd->y;
00876     tess.xyz[ numVerts ][2] = 0;
00877 
00878     tess.texCoords[ numVerts ][0][0] = cmd->s1;
00879     tess.texCoords[ numVerts ][0][1] = cmd->t1;
00880 
00881     tess.xyz[ numVerts + 1 ][0] = cmd->x + cmd->w;
00882     tess.xyz[ numVerts + 1 ][1] = cmd->y;
00883     tess.xyz[ numVerts + 1 ][2] = 0;
00884 
00885     tess.texCoords[ numVerts + 1 ][0][0] = cmd->s2;
00886     tess.texCoords[ numVerts + 1 ][0][1] = cmd->t1;
00887 
00888     tess.xyz[ numVerts + 2 ][0] = cmd->x + cmd->w;
00889     tess.xyz[ numVerts + 2 ][1] = cmd->y + cmd->h;
00890     tess.xyz[ numVerts + 2 ][2] = 0;
00891 
00892     tess.texCoords[ numVerts + 2 ][0][0] = cmd->s2;
00893     tess.texCoords[ numVerts + 2 ][0][1] = cmd->t2;
00894 
00895     tess.xyz[ numVerts + 3 ][0] = cmd->x;
00896     tess.xyz[ numVerts + 3 ][1] = cmd->y + cmd->h;
00897     tess.xyz[ numVerts + 3 ][2] = 0;
00898 
00899     tess.texCoords[ numVerts + 3 ][0][0] = cmd->s1;
00900     tess.texCoords[ numVerts + 3 ][0][1] = cmd->t2;
00901 
00902     return (const void *)(cmd + 1);
00903 }
00904 
00905 
00906 /*
00907 =============
00908 RB_DrawSurfs
00909 
00910 =============
00911 */
00912 const void  *RB_DrawSurfs( const void *data ) {
00913     const drawSurfsCommand_t    *cmd;
00914 
00915     // finish any 2D drawing if needed
00916     if ( tess.numIndexes ) {
00917         RB_EndSurface();
00918     }
00919 
00920     cmd = (const drawSurfsCommand_t *)data;
00921 
00922     backEnd.refdef = cmd->refdef;
00923     backEnd.viewParms = cmd->viewParms;
00924 
00925     RB_RenderDrawSurfList( cmd->drawSurfs, cmd->numDrawSurfs );
00926 
00927     return (const void *)(cmd + 1);
00928 }
00929 
00930 
00931 /*
00932 =============
00933 RB_DrawBuffer
00934 
00935 =============
00936 */
00937 const void  *RB_DrawBuffer( const void *data ) {
00938     const drawBufferCommand_t   *cmd;
00939 
00940     cmd = (const drawBufferCommand_t *)data;
00941 
00942     qglDrawBuffer( cmd->buffer );
00943 
00944     // clear screen for debugging
00945     if ( r_clear->integer ) {
00946         qglClearColor( 1, 0, 0.5, 1 );
00947         qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
00948     }
00949 
00950     return (const void *)(cmd + 1);
00951 }
00952 
00953 /*
00954 ===============
00955 RB_ShowImages
00956 
00957 Draw all the images to the screen, on top of whatever
00958 was there.  This is used to test for texture thrashing.
00959 
00960 Also called by RE_EndRegistration
00961 ===============
00962 */
00963 void RB_ShowImages( void ) {
00964     int     i;
00965     image_t *image;
00966     float   x, y, w, h;
00967     int     start, end;
00968 
00969     if ( !backEnd.projection2D ) {
00970         RB_SetGL2D();
00971     }
00972 
00973     qglClear( GL_COLOR_BUFFER_BIT );
00974 
00975     qglFinish();
00976 
00977     start = ri.Milliseconds();
00978 
00979     for ( i=0 ; i<tr.numImages ; i++ ) {
00980         image = tr.images[i];
00981 
00982         w = glConfig.vidWidth / 20;
00983         h = glConfig.vidHeight / 15;
00984         x = i % 20 * w;
00985         y = i / 20 * h;
00986 
00987         // show in proportional size in mode 2
00988         if ( r_showImages->integer == 2 ) {
00989             w *= image->uploadWidth / 512.0f;
00990             h *= image->uploadHeight / 512.0f;
00991         }
00992 
00993         GL_Bind( image );
00994         qglBegin (GL_QUADS);
00995         qglTexCoord2f( 0, 0 );
00996         qglVertex2f( x, y );
00997         qglTexCoord2f( 1, 0 );
00998         qglVertex2f( x + w, y );
00999         qglTexCoord2f( 1, 1 );
01000         qglVertex2f( x + w, y + h );
01001         qglTexCoord2f( 0, 1 );
01002         qglVertex2f( x, y + h );
01003         qglEnd();
01004     }
01005 
01006     qglFinish();
01007 
01008     end = ri.Milliseconds();
01009     ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start );
01010 
01011 }
01012 
01013 
01014 /*
01015 =============
01016 RB_SwapBuffers
01017 
01018 =============
01019 */
01020 const void  *RB_SwapBuffers( const void *data ) {
01021     const swapBuffersCommand_t  *cmd;
01022 
01023     // finish any 2D drawing if needed
01024     if ( tess.numIndexes ) {
01025         RB_EndSurface();
01026     }
01027 
01028     // texture swapping test
01029     if ( r_showImages->integer ) {
01030         RB_ShowImages();
01031     }
01032 
01033     cmd = (const swapBuffersCommand_t *)data;
01034 
01035     // we measure overdraw by reading back the stencil buffer and
01036     // counting up the number of increments that have happened
01037     if ( r_measureOverdraw->integer ) {
01038         int i;
01039         long sum = 0;
01040         unsigned char *stencilReadback;
01041 
01042         stencilReadback = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight );
01043         qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilReadback );
01044 
01045         for ( i = 0; i < glConfig.vidWidth * glConfig.vidHeight; i++ ) {
01046             sum += stencilReadback[i];
01047         }
01048 
01049         backEnd.pc.c_overDraw += sum;
01050         ri.Hunk_FreeTempMemory( stencilReadback );
01051     }
01052 
01053 
01054     if ( !glState.finishCalled ) {
01055         qglFinish();
01056     }
01057 
01058     GLimp_LogComment( "***************** RB_SwapBuffers *****************\n\n\n" );
01059 
01060     GLimp_EndFrame();
01061 
01062     backEnd.projection2D = qfalse;
01063 
01064     return (const void *)(cmd + 1);
01065 }
01066 
01067 /*
01068 ====================
01069 RB_ExecuteRenderCommands
01070 
01071 This function will be called synchronously if running without
01072 smp extensions, or asynchronously by another thread.
01073 ====================
01074 */
01075 void RB_ExecuteRenderCommands( const void *data ) {
01076     int     t1, t2;
01077 
01078     t1 = ri.Milliseconds ();
01079 
01080     if ( !r_smp->integer || data == backEndData[0]->commands.cmds ) {
01081         backEnd.smpFrame = 0;
01082     } else {
01083         backEnd.smpFrame = 1;
01084     }
01085 
01086     while ( 1 ) {
01087         switch ( *(const int *)data ) {
01088         case RC_SET_COLOR:
01089             data = RB_SetColor( data );
01090             break;
01091         case RC_STRETCH_PIC:
01092             data = RB_StretchPic( data );
01093             break;
01094         case RC_DRAW_SURFS:
01095             data = RB_DrawSurfs( data );
01096             break;
01097         case RC_DRAW_BUFFER:
01098             data = RB_DrawBuffer( data );
01099             break;
01100         case RC_SWAP_BUFFERS:
01101             data = RB_SwapBuffers( data );
01102             break;
01103         case RC_SCREENSHOT:
01104             data = RB_TakeScreenshotCmd( data );
01105             break;
01106 
01107         case RC_END_OF_LIST:
01108         default:
01109             // stop rendering on this thread
01110             t2 = ri.Milliseconds ();
01111             backEnd.pc.msec = t2 - t1;
01112             return;
01113         }
01114     }
01115 
01116 }
01117 
01118 
01119 /*
01120 ================
01121 RB_RenderThread
01122 ================
01123 */
01124 void RB_RenderThread( void ) {
01125     const void  *data;
01126 
01127     // wait for either a rendering command or a quit command
01128     while ( 1 ) {
01129         // sleep until we have work to do
01130         data = GLimp_RendererSleep();
01131 
01132         if ( !data ) {
01133             return; // all done, renderer is shutting down
01134         }
01135 
01136         renderThreadActive = qtrue;
01137 
01138         RB_ExecuteRenderCommands( data );
01139 
01140         renderThreadActive = qfalse;
01141     }
01142 }
01143 

Generated on Thu Aug 25 12:37:50 2005 for Quake III Arena by  doxygen 1.3.9.1