/* ================ R_DebugPolygon ================ */ void GLRB_DebugPolygon( int color, int numPoints, const float *points ) { int i; GL_Bind( tr.whiteImage); GL_Cull( CT_FRONT_SIDED ); GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); // draw solid shade qglColor3f( color&1, (color>>1)&1, (color>>2)&1 ); qglBegin( GL_POLYGON ); for ( i = 0 ; i < numPoints ; i++ ) { qglVertex3fv( points + i * 3 ); } qglEnd(); // draw wireframe outline GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ); qglDepthRange( 0, 0 ); qglColor3f( 1, 1, 1 ); qglBegin( GL_POLYGON ); for ( i = 0 ; i < numPoints ; i++ ) { qglVertex3fv( points + i * 3 ); } qglEnd(); qglDepthRange( 0, 1 ); }
/* ================ RB_SetGL2D ================ */ void RB_SetGL2D (void) { if ( tess.numIndexes | tess.numVertexes ) Com_Printf(" Going 2d with verts?" ); backEnd.projection2D = qtrue; backEnd.currentModel = 0; // set 2D virtual screen size qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); qglMatrixMode(GL_PROJECTION); qglLoadIdentity (); qglOrtho (0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1); qglMatrixMode(GL_MODELVIEW); qglLoadIdentity (); GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); GL_Cull( CT_TWO_SIDED ); qglDisable( GL_CLIP_PLANE0 ); // set time for 2D shaders // tess.shaderTime = ri.Milliseconds(); }
/* =============== R_Set2DMode =============== */ void R_Set2DMode( qboolean enable ) { if( enable ) { if( glState.in2DMode ) return; // set 2D virtual screen size pglScissor( 0, 0, glState.width, glState.height ); pglViewport( 0, 0, glState.width, glState.height ); pglMatrixMode( GL_PROJECTION ); pglLoadIdentity(); pglOrtho( 0, glState.width, glState.height, 0, -99999, 99999 ); pglMatrixMode( GL_MODELVIEW ); pglLoadIdentity(); GL_Cull( 0 ); pglDepthMask( GL_FALSE ); pglDisable( GL_DEPTH_TEST ); pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); glState.in2DMode = true; RI.currententity = NULL; RI.currentmodel = NULL; } else { pglDepthMask( GL_TRUE ); pglEnable( GL_DEPTH_TEST ); pglMatrixMode( GL_MODELVIEW ); glState.in2DMode = false; } }
/* ================= RB_ShadowFinish Darken everything that is is a shadow volume. We have to delay this until everything has been shadowed, because otherwise shadows from different body parts would overlap and double darken. ================= */ void RB_ShadowFinish( void ) { if ( r_shadows->integer != 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_NOTEQUAL, 0, 255 ); qglDisable (GL_CLIP_PLANE0); GL_Cull( CT_TWO_SIDED ); GL_Bind( tr.whiteImage ); qglLoadIdentity (); qglColor3f( 0.6f, 0.6f, 0.6f ); GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); // qglColor3f( 1, 0, 0 ); // GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); qglBegin( GL_QUADS ); qglVertex3f( -100, 100, -10 ); qglVertex3f( 100, 100, -10 ); qglVertex3f( 100, -100, -10 ); qglVertex3f( -100, -100, -10 ); qglEnd (); qglColor4f(1,1,1,1); qglDisable( GL_STENCIL_TEST ); }
/* ================ RB_SetGL2D ================ */ void RB_SetGL2D( void ) { backEnd.projection2D = qtrue; // set 2D virtual screen size qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); qglOrtho( 0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1 ); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity(); GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); qglDisable( GL_FOG ); //----(SA) added GL_Cull( CT_TWO_SIDED ); qglDisable( GL_CLIP_PLANE0 ); // set time for 2D shaders backEnd.refdef.time = ri.Milliseconds(); backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f; }
/* ============= R_ShadowPassSetupGL ============= */ static void R_ShadowPassSetupGL( const plight_t *pl ) { // matrices already computed RI.worldviewMatrix = pl->modelviewMatrix; RI.projectionMatrix = pl->projectionMatrix; RI.worldviewProjectionMatrix = RI.projectionMatrix.Concat( RI.worldviewMatrix ); GLfloat dest[16]; // tell engine about worldviewprojection matrix so TriWorldToScreen and TriScreenToWorld // will be working properly RI.worldviewProjectionMatrix.CopyToArray( dest ); SET_ENGINE_WORLDVIEW_MATRIX( dest ); pglScissor( RI.scissor[0], RI.scissor[1], RI.scissor[2], RI.scissor[3] ); pglViewport( RI.viewport[0], RI.viewport[1], RI.viewport[2], RI.viewport[3] ); pglMatrixMode( GL_PROJECTION ); GL_LoadMatrix( RI.projectionMatrix ); pglMatrixMode( GL_MODELVIEW ); GL_LoadMatrix( RI.worldviewMatrix ); GL_Cull( GL_FRONT ); pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); pglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); pglEnable( GL_POLYGON_OFFSET_FILL ); pglDisable( GL_TEXTURE_2D ); pglDepthMask( GL_TRUE ); pglPolygonOffset( 8, 30 ); pglEnable( GL_DEPTH_TEST ); pglDisable( GL_ALPHA_TEST ); pglDisable( GL_BLEND ); }
/* ===================== RB_StencilShadowPass Stencil test should already be enabled, and the stencil buffer should have been set to 128 on any surfaces that might receive shadows ===================== */ void RB_StencilShadowPass(const drawSurf_t *drawSurfs) { if (!r_shadows.GetBool()) { return; } if (!drawSurfs) { return; } RB_LogComment("---------- RB_StencilShadowPass ----------\n"); globalImages->BindNull(); qglDisableClientState(GL_TEXTURE_COORD_ARRAY); // for visualizing the shadows if (r_showShadows.GetInteger()) { if (r_showShadows.GetInteger() == 2) { // draw filled in GL_State(GLS_DEPTHMASK | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_LESS); } else { // draw as lines, filling the depth buffer GL_State(GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO | GLS_POLYMODE_LINE | GLS_DEPTHFUNC_ALWAYS); } } else { // don't write to the color buffer, just the stencil buffer GL_State(GLS_DEPTHMASK | GLS_COLORMASK | GLS_ALPHAMASK | GLS_DEPTHFUNC_LESS); } if (r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat()) { qglPolygonOffset(r_shadowPolygonFactor.GetFloat(), -r_shadowPolygonOffset.GetFloat()); qglEnable(GL_POLYGON_OFFSET_FILL); } qglStencilFunc(GL_ALWAYS, 1, 255); if (glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool()) { qglEnable(GL_DEPTH_BOUNDS_TEST_EXT); } RB_RenderDrawSurfChainWithFunction(drawSurfs, RB_T_Shadow); GL_Cull(CT_FRONT_SIDED); if (r_shadowPolygonFactor.GetFloat() || r_shadowPolygonOffset.GetFloat()) { qglDisable(GL_POLYGON_OFFSET_FILL); } if (glConfig.depthBoundsTestAvailable && r_useDepthBoundsTest.GetBool()) { qglDisable(GL_DEPTH_BOUNDS_TEST_EXT); } qglEnableClientState(GL_TEXTURE_COORD_ARRAY); qglStencilFunc(GL_GEQUAL, 128, 255); qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); }
/* ================= RB_ShadowFinish Darken everything that is is a shadow volume. We have to delay this until everything has been shadowed, because otherwise shadows from different body parts would overlap and double darken. ================= */ void RB_ShadowFinish( void ) { if ( r_shadows->integer != 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } #ifdef _DEBUG_STENCIL_SHADOWS return; #endif qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_NOTEQUAL, 0, 255 ); qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); bool planeZeroBack = false; if (qglIsEnabled(GL_CLIP_PLANE0)) { planeZeroBack = true; qglDisable (GL_CLIP_PLANE0); } GL_Cull(CT_TWO_SIDED); //qglDisable (GL_CULL_FACE); GL_Bind( tr.whiteImage ); qglPushMatrix(); qglLoadIdentity (); // qglColor3f( 0.6f, 0.6f, 0.6f ); // GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); // qglColor3f( 1, 0, 0 ); // GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); qglColor4f( 0.0f, 0.0f, 0.0f, 0.5f ); //GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); qglBegin( GL_QUADS ); qglVertex3f( -100, 100, -10 ); qglVertex3f( 100, 100, -10 ); qglVertex3f( 100, -100, -10 ); qglVertex3f( -100, -100, -10 ); qglEnd (); qglColor4f(1,1,1,1); qglDisable( GL_STENCIL_TEST ); if (planeZeroBack) { qglEnable (GL_CLIP_PLANE0); } qglPopMatrix(); }
/* ================= R_BloomScreen ================= */ void R_BloomScreen( void ) { if( !r_bloom->integer ) return; if(r_bloom_sky_only->integer) return; if ( backEnd.doneBloom ) return; if ( !backEnd.doneSurfaces ) return; backEnd.doneBloom = qtrue; if( !bloom.started ) { R_Bloom_InitTextures(); if( !bloom.started ) return; } if ( !backEnd.projection2D ) RB_SetGL2D(); #if 0 // set up full screen workspace GL_TexEnv( GL_MODULATE ); qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity (); qglOrtho( 0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1 ); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity (); GL_Cull( CT_TWO_SIDED ); #endif qglColor4f( 1, 1, 1, 1 ); //Backup the old screen in a texture R_Bloom_BackupScreen(); // create the bloom texture using one of a few methods if(r_bloom_cascade->integer) R_Bloom_Cascaded(); else R_Bloom_WarsowEffect (); // R_Bloom_CreateEffect(); // restore the screen-backup to the screen R_Bloom_RestoreScreen(); // Do the final pass using the bloom texture for the final effect R_Bloom_DrawEffect (); // LEILEI - Lens Bloom Hack // The concept of this is to inverse the coordinates on both X and Y, // then scale outward using the offset value applied, as well as the modulated color // applied to give a rainbow streak effect. Most effective with high bloom darkness // values. if(r_bloom_reflection->integer) R_Bloom_LensEffect (); }
void GLRB_ResetState2D( void ) { qglLoadIdentity(); GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); GL_Cull( CT_TWO_SIDED ); qglDisable( GL_CLIP_PLANE0 ); }
/* ================ RB_StageIteratorSky All of the visible sky triangles are in tess Other things could be stuck in here, like birds in the sky, etc ================ */ void RB_StageIteratorSky( void ) { if ( r_fastsky->integer ) { return; } // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn RB_ClipSkyPolygons( &tess ); // r_showsky will let all the sky blocks be drawn in // front of everything to allow developers to see how // much sky is getting sucked in if ( r_showsky->integer ) { qglDepthRange( 0.0, 0.0 ); } else { qglDepthRange( 1.0, 1.0 ); } // draw the outer skybox if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) { qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); qglPushMatrix (); GL_State( 0 ); GL_Cull( CT_FRONT_SIDED ); qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); DrawSkyBox( tess.shader ); qglPopMatrix(); } // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine R_BuildCloudData( &tess ); RB_StageIteratorGeneric(); // draw the inner skybox // back to normal depth range qglDepthRange( 0.0, 1.0 ); // note that sky was drawn so we will draw a sun later backEnd.skyRenderedThisView = qtrue; }
/* ============= R_SetupGL ============= */ static void R_SetupGL( void ) { if( RI.refdef.waterlevel >= 3 ) { float f; f = sin( cl.time * 0.4f * ( M_PI * 2.7f )); RI.refdef.fov_x += f; RI.refdef.fov_y -= f; } R_SetupModelviewMatrix( &RI.refdef, RI.worldviewMatrix ); R_SetupProjectionMatrix( &RI.refdef, RI.projectionMatrix ); // if( RI.params & RP_MIRRORVIEW ) RI.projectionMatrix[0][0] = -RI.projectionMatrix[0][0]; Matrix4x4_Concat( RI.worldviewProjectionMatrix, RI.projectionMatrix, RI.worldviewMatrix ); pglScissor( RI.scissor[0], RI.scissor[1], RI.scissor[2], RI.scissor[3] ); pglViewport( RI.viewport[0], RI.viewport[1], RI.viewport[2], RI.viewport[3] ); pglMatrixMode( GL_PROJECTION ); GL_LoadMatrix( RI.projectionMatrix ); pglMatrixMode( GL_MODELVIEW ); GL_LoadMatrix( RI.worldviewMatrix ); if( RI.params & RP_CLIPPLANE ) { GLdouble clip[4]; mplane_t *p = &RI.clipPlane; clip[0] = p->normal[0]; clip[1] = p->normal[1]; clip[2] = p->normal[2]; clip[3] = -p->dist; pglClipPlane( GL_CLIP_PLANE0, clip ); pglEnable( GL_CLIP_PLANE0 ); } if( RI.params & RP_FLIPFRONTFACE ) GL_FrontFace( !glState.frontFace ); GL_Cull( GL_FRONT ); pglDisable( GL_BLEND ); pglDisable( GL_ALPHA_TEST ); pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); }
/* ============================ idAutoRender::RenderFrame ============================ */ void idAutoRender::RenderFrame() { // values are 0 to 1 float loadingIconPosX = 0.5f; float loadingIconPosY = 0.6f; float loadingIconScale = 0.025f; float loadingIconSpeed = 0.095f; if( autoRenderIcon == AUTORENDER_HELLICON ) { loadingIconPosX = 0.85f; loadingIconPosY = 0.85f; loadingIconScale = 0.1f; loadingIconSpeed = 0.095f; } else if( autoRenderIcon == AUTORENDER_DIALOGICON ) { loadingIconPosY = 0.73f; } GL_SetDefaultState(); GL_Cull( CT_TWO_SIDED ); const bool stereoRender = false; const int width = renderSystem->GetWidth(); const int height = renderSystem->GetHeight(); const int guardBand = height / 24; if( stereoRender ) { for( int viewNum = 0 ; viewNum < 2; viewNum++ ) { GL_ViewportAndScissor( 0, viewNum * ( height + guardBand ), width, height ); RenderBackground(); RenderLoadingIcon( loadingIconPosX, loadingIconPosY, loadingIconScale, loadingIconSpeed ); } } else { GL_ViewportAndScissor( 0, 0, width, height ); RenderBackground(); RenderLoadingIcon( loadingIconPosX, loadingIconPosY, loadingIconScale, loadingIconSpeed ); } }
/* ================ RB_SetGL2D ================ */ void RB_SetGL2D (void) { mat4_t matrix; int width, height; if (backEnd.projection2D && backEnd.last2DFBO == glState.currentFBO) return; backEnd.projection2D = qtrue; backEnd.last2DFBO = glState.currentFBO; if (glState.currentFBO) { width = glState.currentFBO->width; height = glState.currentFBO->height; } else { width = glConfig.vidWidth; height = glConfig.vidHeight; } // set 2D virtual screen size qglViewport( 0, 0, width, height ); qglScissor( 0, 0, width, height ); Mat4Ortho(0, width, height, 0, 0, 1, matrix); GL_SetProjectionMatrix(matrix); Mat4Identity(matrix); GL_SetModelviewMatrix(matrix); GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); GL_Cull( CT_TWO_SIDED ); qglDisable( GL_CLIP_PLANE0 ); // set time for 2D shaders backEnd.refdef.time = ri.Milliseconds(); backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f; // reset color scaling backEnd.refdef.colorScale = 1.0f; }
/* ============= RB_SetGL2D This is not used by the normal game paths, just by some tools ============= */ void RB_SetGL2D( void ) { // set 2D virtual screen size qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); if ( r_useScissor.GetBool() ) { qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); } qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); qglOrtho( 0, 640, 480, 0, 0, 1 ); // always assume 640x480 virtual coordinates qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity(); GL_State( GLS_DEPTHFUNC_ALWAYS | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); GL_Cull( CT_TWO_SIDED ); qglDisable( GL_DEPTH_TEST ); qglDisable( GL_STENCIL_TEST ); }
/* ================= 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_PostprocessScreen ================= */ void R_PostprocessScreen( void ) { if( !postprocess ) return; if ( backEnd.donepostproc ) return; if ( !backEnd.doneSurfaces ) return; backEnd.donepostproc = qtrue; if( !postproc.started ) { R_Postprocess_InitTextures(); if( !postproc.started ) return; } if ( !backEnd.projection2D ) RB_SetGL2D(); #if 0 // set up full screen workspace GL_TexEnv( GL_MODULATE ); qglScissor( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); qglViewport( 0, 0, glConfig.vidWidth, glConfig.vidHeight ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity (); qglOrtho( 0, glConfig.vidWidth, glConfig.vidHeight, 0, 0, 1 ); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity (); GL_Cull( CT_TWO_SIDED ); #endif qglColor4f( 1, 1, 1, 1 ); //Backup the old screen in a texture R_Postprocess_BackupScreen(); //Redraw texture using GLSL program R_Bloom_RestoreScreen_Postprocessed(); }
void RB_DoShadowTessEnd( vec3_t lightPos ) { #ifndef _XBOX int i; int numTris; vec3_t lightDir; // we can only do this if we have enough space in the vertex buffers if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } #if 1 //controlled method - try to keep shadows in range so they don't show through so much -rww vec3_t worldxyz; vec3_t entLight; float groundDist; VectorCopy( backEnd.currentEntity->lightDir, entLight ); entLight[2] = 0.0f; VectorNormalize(entLight); //Oh well, just cast them straight down no matter what onto the ground plane. //This presets no chance of screwups and still looks better than a stupid //shader blob. VectorSet(lightDir, entLight[0]*0.3f, entLight[1]*0.3f, 1.0f); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { //add or.origin to vert xyz to end up with world oriented coord, then figure //out the ground pos for the vert to project the shadow volume to VectorAdd(tess.xyz[i], backEnd.ori.origin, worldxyz); groundDist = worldxyz[2] - backEnd.currentEntity->e.shadowPlane; groundDist += 16.0f; //fudge factor VectorMA( tess.xyz[i], -groundDist, lightDir, tess.xyz[i+tess.numVertexes] ); } #else if (lightPos) { for ( i = 0 ; i < tess.numVertexes ; i++ ) { tess.xyz[i+tess.numVertexes][0] = tess.xyz[i][0]+(( tess.xyz[i][0]-lightPos[0] )*128.0f); tess.xyz[i+tess.numVertexes][1] = tess.xyz[i][1]+(( tess.xyz[i][1]-lightPos[1] )*128.0f); tess.xyz[i+tess.numVertexes][2] = tess.xyz[i][2]+(( tess.xyz[i][2]-lightPos[2] )*128.0f); } } else { VectorCopy( backEnd.currentEntity->lightDir, lightDir ); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] ); } } #endif // decide which triangles face the light memset( numEdgeDefs, 0, 4 * tess.numVertexes ); numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; vec3_t d1, d2, normal; float *v1, *v2, *v3; float d; i1 = tess.indexes[ i*3 + 0 ]; i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; v1 = tess.xyz[ i1 ]; v2 = tess.xyz[ i2 ]; v3 = tess.xyz[ i3 ]; if (!lightPos) { VectorSubtract( v2, v1, d1 ); VectorSubtract( v3, v1, d2 ); CrossProduct( d1, d2, normal ); d = DotProduct( normal, lightDir ); } else { float planeEq[4]; planeEq[0] = v1[1]*(v2[2]-v3[2]) + v2[1]*(v3[2]-v1[2]) + v3[1]*(v1[2]-v2[2]); planeEq[1] = v1[2]*(v2[0]-v3[0]) + v2[2]*(v3[0]-v1[0]) + v3[2]*(v1[0]-v2[0]); planeEq[2] = v1[0]*(v2[1]-v3[1]) + v2[0]*(v3[1]-v1[1]) + v3[0]*(v1[1]-v2[1]); planeEq[3] = -( v1[0]*( v2[1]*v3[2] - v3[1]*v2[2] ) + v2[0]*(v3[1]*v1[2] - v1[1]*v3[2]) + v3[0]*(v1[1]*v2[2] - v2[1]*v1[2]) ); d = planeEq[0]*lightPos[0]+ planeEq[1]*lightPos[1]+ planeEq[2]*lightPos[2]+ planeEq[3]; } if ( d > 0 ) { facing[ i ] = 1; } else { facing[ i ] = 0; } // create the edges R_AddEdgeDef( i1, i2, facing[ i ] ); R_AddEdgeDef( i2, i3, facing[ i ] ); R_AddEdgeDef( i3, i1, facing[ i ] ); } GL_Bind( tr.whiteImage ); //qglEnable( GL_CULL_FACE ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); #ifndef _DEBUG_STENCIL_SHADOWS qglColor3f( 0.2f, 0.2f, 0.2f ); // don't write to the color buffer qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_ALWAYS, 1, 255 ); #else qglColor3f( 1.0f, 0.0f, 0.0f ); qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //qglDisable(GL_DEPTH_TEST); #endif #ifdef _STENCIL_REVERSE qglDepthFunc(GL_LESS); //now using the Carmack Reverse<tm> -rww if ( backEnd.viewParms.isMirror ) { //qglCullFace( GL_BACK ); GL_Cull(CT_BACK_SIDED); qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP ); R_RenderShadowEdges(); //qglCullFace( GL_FRONT ); GL_Cull(CT_FRONT_SIDED); qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP ); R_RenderShadowEdges(); } else { //qglCullFace( GL_FRONT ); GL_Cull(CT_FRONT_SIDED); qglStencilOp( GL_KEEP, GL_INCR, GL_KEEP ); R_RenderShadowEdges(); //qglCullFace( GL_BACK ); GL_Cull(CT_BACK_SIDED); qglStencilOp( GL_KEEP, GL_DECR, GL_KEEP ); R_RenderShadowEdges(); } qglDepthFunc(GL_LEQUAL); #else // mirrors have the culling order reversed if ( backEnd.viewParms.isMirror ) { qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } else { qglCullFace( GL_BACK ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); qglCullFace( GL_FRONT ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); } #endif // reenable writing to the color buffer qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); #ifdef _DEBUG_STENCIL_SHADOWS qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); #endif #endif // _XBOX }
/* ================ Tess_StageIteratorSky All of the visible sky triangles are in tess Other things could be stuck in here, like birds in the sky, etc ================ */ void Tess_StageIteratorSky( void ) { // 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 ( "--- Tess_StageIteratorSky( %s, %i vertices, %i triangles ) ---\n", tess.surfaceShader->name, tess.numVertexes, tess.numIndexes / 3 ) ); } if ( r_fastsky->integer ) { return; } // trebor: HACK why does this happen with cg_draw2D 0 ? if ( tess.stageIteratorFunc2 == NULL ) { //tess.stageIteratorFunc2 = Tess_StageIteratorGeneric; ri.Error( ERR_FATAL, "tess.stageIteratorFunc == NULL" ); } GL_Cull(CT_TWO_SIDED); if ( tess.stageIteratorFunc2 == &Tess_StageIteratorDepthFill ) { // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn Tess_ClipSkyPolygons(); // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine BuildCloudData(); if ( tess.numVertexes || tess.multiDrawPrimitives ) { tess.stageIteratorFunc2(); } } else { if ( tess.stageIteratorFunc2 == &Tess_StageIteratorGBuffer ) { R_BindFBO( tr.geometricRenderFBO ); } // go through all the polygons and project them onto // the sky box to see which blocks on each side need // to be drawn Tess_ClipSkyPolygons(); // r_showSky will let all the sky blocks be drawn in // front of everything to allow developers to see how // much sky is getting sucked in if ( r_showSky->integer ) { glDepthRange( 0.0, 0.0 ); } else { glDepthRange( 1.0, 1.0 ); } // draw the outer skybox if ( tess.surfaceShader->sky.outerbox && tess.surfaceShader->sky.outerbox != tr.blackCubeImage ) { #if 1 R_BindVBO( tess.vbo ); R_BindIBO( tess.ibo ); gl_skyboxShader->BindProgram(); gl_skyboxShader->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); // in world space gl_skyboxShader->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); gl_skyboxShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); gl_skyboxShader->SetRequiredVertexPointers(); // bind u_ColorMap GL_SelectTexture( 0 ); GL_Bind( tess.surfaceShader->sky.outerbox ); DrawSkyBox( tess.surfaceShader ); #endif } // generate the vertexes for all the clouds, which will be drawn // by the generic shader routine BuildCloudData(); if ( tess.numVertexes || tess.multiDrawPrimitives ) { tess.stageIteratorFunc2(); } // Tr3B: TODO draw the inner skybox? if ( tess.stageIteratorFunc2 == Tess_StageIteratorGBuffer ) { R_BindNullFBO(); } if ( tess.stageIteratorFunc2 != Tess_StageIteratorDepthFill ) { // back to standard depth range glDepthRange( 0.0, 1.0 ); // note that sky was drawn so we will draw a sun later backEnd.skyRenderedThisView = qtrue; } } }
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 GL fog SetIteratorFog(); // // 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, 8, tess.texCoords0 ); // // configure second stage // GL_SelectTexture( 1 ); qglEnable( GL_TEXTURE_2D ); if ( r_lightmap->integer ) { GL_TexEnv( GL_REPLACE ); } else { GL_TexEnv( GL_MODULATE ); } //----(SA) modified for snooper if ( tess.xstages[0]->bundle[1].isLightmap && ( backEnd.refdef.rdflags & RDF_SNOOPERVIEW ) ) { GL_Bind( tr.whiteImage ); } else { R_BindAnimatedImage( &tess.xstages[0]->bundle[1] ); } qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglTexCoordPointer( 2, GL_FLOAT, 8, tess.texCoords1 ); // // 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 ) if ( tess.dlightBits && tess.shader->fogPass && !( tess.shader->surfaceFlags & ( SURF_NODLIGHT | SURF_SKY ) ) ) { if ( r_dynamiclight->integer == 2 ) { DynamicLightPass(); } else { DynamicLightSinglePass(); } } // // now do fog // if ( tess.fogNum && tess.shader->fogPass ) { RB_FogPass(); } // // unlock arrays // if ( qglUnlockArraysEXT ) { qglUnlockArraysEXT(); GLimp_LogComment( "glUnlockArraysEXT\n" ); } }
/* ** 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 { int fadeStart, fadeEnd; if ( !setArraysOnce ) { qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] ); } // // set state // R_BindAnimatedImage( &pStage->bundle[0] ); // Ridah, per stage fogging (detail textures) if ( tess.shader->noFog && pStage->isFogged ) { R_FogOn(); } else if ( tess.shader->noFog && !pStage->isFogged ) { R_FogOff(); // turn it back off } else { // make sure it's on R_FogOn(); } // done. //----(SA) fading model stuff fadeStart = backEnd.currentEntity->e.fadeStartTime; if ( fadeStart ) { fadeEnd = backEnd.currentEntity->e.fadeEndTime; if ( fadeStart > tr.refdef.time ) { // has not started to fade yet GL_State( pStage->stateBits ); } else { int i; unsigned int tempState; float alphaval; if ( fadeEnd < tr.refdef.time ) { // entity faded out completely continue; } alphaval = (float)( fadeEnd - tr.refdef.time ) / (float)( fadeEnd - fadeStart ); tempState = pStage->stateBits; // remove the current blend, and don't write to Z buffer tempState &= ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS | GLS_DEPTHMASK_TRUE ); // set the blend to src_alpha, dst_one_minus_src_alpha tempState |= ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); GL_State( tempState ); GL_Cull( CT_FRONT_SIDED ); // modulate the alpha component of each vertex in the render list for ( i = 0; i < tess.numVertexes; i++ ) { tess.svars.colors[i][0] *= alphaval; tess.svars.colors[i][1] *= alphaval; tess.svars.colors[i][2] *= alphaval; tess.svars.colors[i][3] *= alphaval; } } } //----(SA) end // ydnar: lightmap stages should be GL_ONE GL_ZERO so they can be seen else if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) ) { unsigned int stateBits; stateBits = ( pStage->stateBits & ~( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) ) | ( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); GL_State( stateBits ); } else { 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 ) ) { break; } } }
void RB_ShowImages( void ) { int i; image_t *image; float x, y, w, h; vec4_t quadVerts[ 4 ]; int start, end; GLimp_LogComment( "--- RB_ShowImages ---\n" ); if ( !backEnd.projection2D ) { RB_SetGL2D(); } qglClear( GL_COLOR_BUFFER_BIT ); qglFinish(); GL_BindProgram( &tr.genericSingleShader ); GL_Cull( CT_TWO_SIDED ); // set uniforms GLSL_SetUniform_TCGen_Environment( &tr.genericSingleShader, qfalse ); GLSL_SetUniform_ColorGen( &tr.genericSingleShader, CGEN_VERTEX ); GLSL_SetUniform_AlphaGen( &tr.genericSingleShader, AGEN_VERTEX ); if ( glConfig.vboVertexSkinningAvailable ) { GLSL_SetUniform_VertexSkinning( &tr.genericSingleShader, qfalse ); } GLSL_SetUniform_DeformGen( &tr.genericSingleShader, DGEN_NONE ); GLSL_SetUniform_AlphaTest( &tr.genericSingleShader, 0 ); GLSL_SetUniform_ColorTextureMatrix( &tr.genericSingleShader, matrixIdentity ); GL_SelectTexture( 0 ); start = ri.Milliseconds(); for ( i = 0; i < tr.images.currentElements; i++ ) { image = Com_GrowListElement( &tr.images, i ); /* if(image->bits & (IF_RGBA16F | IF_RGBA32F | IF_LA16F | IF_LA32F)) { // don't render float textures using FFP continue; } */ w = glConfig.vidWidth / 20; h = glConfig.vidHeight / 15; x = i % 20 * w; y = i / 20 * h; // show in proportional size in mode 2 if ( r_showImages->integer == 2 ) { w *= image->uploadWidth / 512.0f; h *= image->uploadHeight / 512.0f; } // bind u_ColorMap GL_Bind( image ); VectorSet4( quadVerts[ 0 ], x, y, 0, 1 ); VectorSet4( quadVerts[ 1 ], x + w, y, 0, 1 ); VectorSet4( quadVerts[ 2 ], x + w, y + h, 0, 1 ); VectorSet4( quadVerts[ 3 ], x, y + h, 0, 1 ); Tess_InstantQuad( quadVerts ); /* qglBegin(GL_QUADS); qglVertexAttrib4fARB(ATTR_INDEX_TEXCOORD0, 0, 0, 0, 1); qglVertexAttrib4fARB(ATTR_INDEX_POSITION, x, y, 0, 1); qglVertexAttrib4fARB(ATTR_INDEX_TEXCOORD0, 1, 0, 0, 1); qglVertexAttrib4fARB(ATTR_INDEX_POSITION, x + w, y, 0, 1); qglVertexAttrib4fARB(ATTR_INDEX_TEXCOORD0, 1, 1, 0, 1); qglVertexAttrib4fARB(ATTR_INDEX_POSITION, x + w, y + h, 0, 1); qglVertexAttrib4fARB(ATTR_INDEX_TEXCOORD0, 0, 1, 0, 1); qglVertexAttrib4fARB(ATTR_INDEX_POSITION, x, y + h, 0, 1); qglEnd(); */ } qglFinish(); end = ri.Milliseconds(); ri.Printf( PRINT_ALL, "%i msec to draw all images\n", end - start ); GL_CheckErrors(); }
/* ================= RB_ShadowTessEnd triangleFromEdge[ v1 ][ v2 ] set triangle from edge( v1, v2, tri ) if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) { } ================= */ void RB_ShadowTessEnd( void ) { int i; int numTris; vec3_t lightDir; GLboolean rgba[4]; if ( glConfig.stencilBits < 4 ) { return; } VectorCopy( backEnd.currentEntity->lightDir, lightDir ); // project vertexes away from light direction for ( i = 0 ; i < tess.numVertexes ; i++ ) { VectorMA( tess.xyz[i], -512, lightDir, shadowXyz[i] ); } // decide which triangles face the light Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes ); numTris = tess.numIndexes / 3; for ( i = 0 ; i < numTris ; i++ ) { int i1, i2, i3; vec3_t d1, d2, normal; float *v1, *v2, *v3; float d; i1 = tess.indexes[ i*3 + 0 ]; i2 = tess.indexes[ i*3 + 1 ]; i3 = tess.indexes[ i*3 + 2 ]; v1 = tess.xyz[ i1 ]; v2 = tess.xyz[ i2 ]; v3 = tess.xyz[ i3 ]; VectorSubtract( v2, v1, d1 ); VectorSubtract( v3, v1, d2 ); CrossProduct( d1, d2, normal ); d = DotProduct( normal, lightDir ); if ( d > 0 ) { facing[ i ] = 1; } else { facing[ i ] = 0; } // create the edges R_AddEdgeDef( i1, i2, facing[ i ] ); R_AddEdgeDef( i2, i3, facing[ i ] ); R_AddEdgeDef( i3, i1, facing[ i ] ); } // draw the silhouette edges GL_Bind( tr.whiteImage ); GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); qglColor3f( 0.2f, 0.2f, 0.2f ); // don't write to the color buffer qglGetBooleanv(GL_COLOR_WRITEMASK, rgba); qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_ALWAYS, 1, 255 ); GL_Cull( CT_BACK_SIDED ); qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); R_RenderShadowEdges(); GL_Cull( CT_FRONT_SIDED ); qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR ); R_RenderShadowEdges(); // reenable writing to the color buffer qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]); }
/* ============= R_SetupGL ============= */ static void R_SetupGL( void ) { if( r_underwater_distortion->value && RI.refdef.waterlevel >= 3 ) { float f; f = sin( cl.time * r_underwater_distortion->value * ( M_PI * 2.7f )); RI.refdef.fov_x += f; RI.refdef.fov_y -= f; } R_SetupModelviewMatrix( &RI.refdef, RI.worldviewMatrix ); R_SetupProjectionMatrix( &RI.refdef, RI.projectionMatrix ); // if( RI.params & RP_MIRRORVIEW ) RI.projectionMatrix[0][0] = -RI.projectionMatrix[0][0]; Matrix4x4_Concat( RI.worldviewProjectionMatrix, RI.projectionMatrix, RI.worldviewMatrix ); if( RP_NORMALPASS( )) { int x, x2, y, y2; // set up viewport (main, playersetup) x = floor( RI.viewport[0] * glState.width / glState.width ); x2 = ceil(( RI.viewport[0] + RI.viewport[2] ) * glState.width / glState.width ); y = floor( glState.height - RI.viewport[1] * glState.height / glState.height ); y2 = ceil( glState.height - ( RI.viewport[1] + RI.viewport[3] ) * glState.height / glState.height ); pglViewport( x, y2, x2 - x, y - y2 ); } else { // envpass, mirrorpass pglViewport( RI.viewport[0], RI.viewport[1], RI.viewport[2], RI.viewport[3] ); } pglMatrixMode( GL_PROJECTION ); GL_LoadMatrix( RI.projectionMatrix ); pglMatrixMode( GL_MODELVIEW ); GL_LoadMatrix( RI.worldviewMatrix ); if( RI.params & RP_CLIPPLANE ) { GLdouble clip[4]; mplane_t *p = &RI.clipPlane; clip[0] = p->normal[0]; clip[1] = p->normal[1]; clip[2] = p->normal[2]; clip[3] = -p->dist; pglClipPlane( GL_CLIP_PLANE0, clip ); pglEnable( GL_CLIP_PLANE0 ); } if( RI.params & RP_FLIPFRONTFACE ) GL_FrontFace( !glState.frontFace ); GL_Cull( GL_FRONT ); pglDisable( GL_BLEND ); pglDisable( GL_ALPHA_TEST ); pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); }
/* ** 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( 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" ); } }
void RB_DistortionFill(void) { float alpha = tr_distortionAlpha; float spost = 0.0f; float spost2 = 0.0f; if ( glConfig.stencilBits < 4 ) { return; } //ok, cap the stupid thing now I guess if (!tr_distortionPrePost) { RB_CaptureScreenImage(); } qglEnable(GL_STENCIL_TEST); qglStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF); qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); qglDisable (GL_CLIP_PLANE0); GL_Cull( CT_TWO_SIDED ); //reset the view matrices and go into ortho mode qglMatrixMode(GL_PROJECTION); qglPushMatrix(); qglLoadIdentity(); qglOrtho(0, glConfig.vidWidth, glConfig.vidHeight, 32, -1, 1); qglMatrixMode(GL_MODELVIEW); qglPushMatrix(); qglLoadIdentity(); if (tr_distortionStretch) { //override spost = tr_distortionStretch; spost2 = tr_distortionStretch; } else { //do slow stretchy effect spost = sin(tr.refdef.time*0.0005f); if (spost < 0.0f) { spost = -spost; } spost *= 0.2f; spost2 = sin(tr.refdef.time*0.0005f); if (spost2 < 0.0f) { spost2 = -spost2; } spost2 *= 0.08f; } if (alpha != 1.0f) { //blend GL_State(GLS_SRCBLEND_SRC_ALPHA|GLS_DSTBLEND_SRC_ALPHA); } else { //be sure to reset the draw state GL_State(0); } #ifdef _XBOX qglBeginEXT(GL_QUADS, 4, 0, 0, 4, 0); #else qglBegin(GL_QUADS); #endif // _XBOX qglColor4f(1.0f, 1.0f, 1.0f, alpha); qglTexCoord2f(0+spost2, 1-spost); qglVertex2f(0, 0); qglTexCoord2f(0+spost2, 0+spost); qglVertex2f(0, glConfig.vidHeight); qglTexCoord2f(1-spost2, 0+spost); qglVertex2f(glConfig.vidWidth, glConfig.vidHeight); qglTexCoord2f(1-spost2, 1-spost); qglVertex2f(glConfig.vidWidth, 0); qglEnd(); if (tr_distortionAlpha == 1.0f && tr_distortionStretch == 0.0f) { //no overrides if (tr_distortionNegate) { //probably the crazy alternate saber trail alpha = 0.8f; GL_State(GLS_SRCBLEND_ZERO|GLS_DSTBLEND_ONE_MINUS_SRC_COLOR); } else { alpha = 0.5f; GL_State(GLS_SRCBLEND_SRC_ALPHA|GLS_DSTBLEND_SRC_ALPHA); } spost = sin(tr.refdef.time*0.0008f); if (spost < 0.0f) { spost = -spost; } spost *= 0.08f; spost2 = sin(tr.refdef.time*0.0008f); if (spost2 < 0.0f) { spost2 = -spost2; } spost2 *= 0.2f; #ifdef _XBOX qglBeginEXT(GL_QUADS, 4, 0, 0, 4, 0); #else qglBegin(GL_QUADS); #endif // _XBOX qglColor4f(1.0f, 1.0f, 1.0f, alpha); qglTexCoord2f(0+spost2, 1-spost); qglVertex2f(0, 0); qglTexCoord2f(0+spost2, 0+spost); qglVertex2f(0, glConfig.vidHeight); qglTexCoord2f(1-spost2, 0+spost); qglVertex2f(glConfig.vidWidth, glConfig.vidHeight); qglTexCoord2f(1-spost2, 1-spost); qglVertex2f(glConfig.vidWidth, 0); qglEnd(); } //pop the view matrices back qglMatrixMode(GL_PROJECTION); qglPopMatrix(); qglMatrixMode(GL_MODELVIEW); qglPopMatrix(); qglDisable( GL_STENCIL_TEST ); }
/* ** RB_StageIteratorGeneric */ void RB_StageIteratorGeneric( void ) { shaderCommands_t *input; shader_t *shader; input = &tess; shader = input->shader; 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( shader->cullType ); // set polygon offset if necessary if ( 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 || 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 ( shader->polygonOffset ) { qglDisable( GL_POLYGON_OFFSET_FILL ); } }
/* ================= RB_ShadowFinish Darken everything that is is a shadow volume. We have to delay this until everything has been shadowed, because otherwise shadows from different body parts would overlap and double darken. ================= */ void RB_ShadowFinish( void ) { if ( r_shadows->integer != 2 ) { return; } if ( glConfig.stencilBits < 4 ) { return; } #ifdef _DEBUG_STENCIL_SHADOWS return; #endif qglEnable( GL_STENCIL_TEST ); qglStencilFunc( GL_NOTEQUAL, 0, 255 ); qglStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); bool planeZeroBack = false; if (qglIsEnabled(GL_CLIP_PLANE0)) { planeZeroBack = true; qglDisable (GL_CLIP_PLANE0); } GL_Cull(CT_TWO_SIDED); //qglDisable (GL_CULL_FACE); GL_Bind( tr.whiteImage ); qglPushMatrix(); qglLoadIdentity (); // qglColor3f( 0.6f, 0.6f, 0.6f ); // GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO ); // qglColor3f( 1, 0, 0 ); // GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO ); qglColor4f( 0.0f, 0.0f, 0.0f, 0.5f ); //GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); #ifdef HAVE_GLES GLfloat vtx[] = { -100, 100, -10, 100, 100, -10, 100, -100, -10, -100, -100, -10 }; GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY); GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY); if (text) qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglDisableClientState( GL_COLOR_ARRAY ); qglVertexPointer ( 3, GL_FLOAT, 0, vtx ); qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 ); if (text) qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); if (glcol) qglEnableClientState( GL_COLOR_ARRAY ); #else qglBegin( GL_QUADS ); qglVertex3f( -100, 100, -10 ); qglVertex3f( 100, 100, -10 ); qglVertex3f( 100, -100, -10 ); qglVertex3f( -100, -100, -10 ); qglEnd (); #endif qglColor4f(1,1,1,1); qglDisable( GL_STENCIL_TEST ); if (planeZeroBack) { qglEnable (GL_CLIP_PLANE0); } qglPopMatrix(); }
void RB_StageIteratorLightmappedMultitexture( void ) { shaderCommands_t *input; shader_t *shader; input = &tess; shader = input->shader; // // 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( 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_STD_DrawShaderPasses Draw non-light dependent passes ===================== */ int RB_STD_DrawShaderPasses( drawSurf_t **drawSurfs, int numDrawSurfs ) { int i; // only obey skipAmbient if we are rendering a view if ( backEnd.viewDef->viewEntitys && r_skipAmbient.GetBool() ) { return numDrawSurfs; } // if we are about to draw the first surface that needs // the rendering in a texture, copy it over if ( drawSurfs[0]->material->GetSort() >= SS_POST_PROCESS ) { if ( r_skipPostProcess.GetBool() ) { return 0; } // only dump if in a 3d view if ( backEnd.viewDef->viewEntitys && tr.backEndRenderer == BE_ARB2 ) { globalImages->currentRenderImage->CopyFramebuffer( backEnd.viewDef->viewport.x1, backEnd.viewDef->viewport.y1, backEnd.viewDef->viewport.x2 - backEnd.viewDef->viewport.x1 + 1, backEnd.viewDef->viewport.y2 - backEnd.viewDef->viewport.y1 + 1, true ); } backEnd.currentRenderCopied = true; } GL_SelectTexture( 1 ); globalImages->BindNull(); GL_SelectTexture( 0 ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); RB_SetProgramEnvironment(); // we don't use RB_RenderDrawSurfListWithFunction() // because we want to defer the matrix load because many // surfaces won't draw any ambient passes backEnd.currentSpace = NULL; for (i = 0 ; i < numDrawSurfs ; i++ ) { if ( drawSurfs[i]->material->SuppressInSubview() ) { continue; } if ( backEnd.viewDef->isXraySubview && drawSurfs[i]->space->entityDef ) { if ( drawSurfs[i]->space->entityDef->parms.xrayIndex != 2 ) { continue; } } // we need to draw the post process shaders after we have drawn the fog lights if ( drawSurfs[i]->material->GetSort() >= SS_POST_PROCESS && !backEnd.currentRenderCopied ) { break; } RB_STD_T_RenderShaderPasses( drawSurfs[i] ); } GL_Cull( CT_FRONT_SIDED ); qglColor3f( 1, 1, 1 ); return i; }