PDGL_API void pdglColor4f(float r, float g, float b, float a) { if(pglColor4f) { pglColor4f(r, g, b, a); return; } pglColor4f=pdglGetProcAddress("glColor4f"); pglColor4f(r, g, b, a); }
/* =============== 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; } }
/* ============= 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 ); }
/* ================= R_Bloom_DownsampleView ================= */ static void R_Bloom_DownsampleView( void ) { pglDisable( GL_BLEND ); pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); if( r_screendownsamplingtexture_size ) { // stepped downsample int midsample_width = ( r_screendownsamplingtexture_size * sampleText_tcw ); int midsample_height = ( r_screendownsamplingtexture_size * sampleText_tch ); // copy the screen and draw resized GL_Bind( GL_TEXTURE0, r_bloomscreentexture ); pglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, curView_x, glState.height - ( curView_y + curView_height ), curView_width, curView_height ); R_Bloom_Quad( 0, glState.height - midsample_height, midsample_width, midsample_height, screenTex_tcw, screenTex_tch ); // now copy into downsampling (mid-sized) texture GL_Bind( GL_TEXTURE0, r_bloomdownsamplingtexture ); pglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, midsample_width, midsample_height ); // now draw again in bloom size pglColor4f( 0.5f, 0.5f, 0.5f, 1.0f ); R_Bloom_Quad( 0, glState.height - sample_height, sample_width, sample_height, sampleText_tcw, sampleText_tch ); // now blend the big screen texture into the bloom generation space (hoping it adds some blur) pglEnable( GL_BLEND ); pglBlendFunc( GL_ONE, GL_ONE ); pglColor4f( 0.5f, 0.5f, 0.5f, 1.0f ); GL_Bind( GL_TEXTURE0, r_bloomscreentexture ); R_Bloom_Quad( 0, glState.height - sample_height, sample_width, sample_height, screenTex_tcw, screenTex_tch ); pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); pglDisable( GL_BLEND ); } else { // downsample simple GL_Bind( GL_TEXTURE0, r_bloomscreentexture ); pglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, curView_x, glState.height - ( curView_y + curView_height ), curView_width, curView_height ); R_Bloom_Quad( 0, glState.height - sample_height, sample_width, sample_height, screenTex_tcw, screenTex_tch ); } }
/* ============= 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 ); }
/* ================= R_Bloom_DrawEffect ================= */ static void R_Bloom_DrawEffect( void ) { GL_Bind( GL_TEXTURE0, r_bloomeffecttexture ); pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); pglColor4f( r_bloom_alpha->value, r_bloom_alpha->value, r_bloom_alpha->value, 1.0f ); pglBlendFunc( GL_ONE, GL_ONE ); pglEnable( GL_BLEND ); pglBegin( GL_QUADS ); pglTexCoord2f( 0, sampleText_tch ); pglVertex2f( curView_x, curView_y ); pglTexCoord2f( 0, 0 ); pglVertex2f( curView_x, curView_y+curView_height ); pglTexCoord2f( sampleText_tcw, 0 ); pglVertex2f( curView_x+curView_width, curView_y+curView_height ); pglTexCoord2f( sampleText_tcw, sampleText_tch ); pglVertex2f( curView_x+curView_width, curView_y ); pglEnd(); pglDisable( GL_BLEND ); }
/* ============= Draw_TileClear This repeats a 64*64 tile graphic to fill the screen around a sized down refresh window. ============= */ void R_DrawTileClear( int x, int y, int w, int h ) { float tw, th; gltexture_t *glt; GL_SetRenderMode( kRenderNormal ); pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); GL_Bind( GL_TEXTURE0, cls.tileImage ); glt = R_GetTexture( cls.tileImage ); tw = glt->srcWidth; th = glt->srcHeight; pglBegin( GL_QUADS ); pglTexCoord2f( x / tw, y / th ); pglVertex2f( x, y ); pglTexCoord2f((x + w) / tw, y / th ); pglVertex2f( x + w, y ); pglTexCoord2f((x + w) / tw, (y + h) / th ); pglVertex2f( x + w, y + h ); pglTexCoord2f( x / tw, (y + h) / th ); pglVertex2f( x, y + h ); pglEnd (); }
/* ============= 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 ); }
/* =============== R_ShowTextures Draw all the images to the screen, on top of whatever was there. This is used to test for texture thrashing. =============== */ void R_ShowTextures( void ) { gltexture_t *image; float x, y, w, h; int i, j, k, base_w, base_h; int total, start, end; rgba_t color = { 192, 192, 192, 255 }; int charHeight, numTries = 0; static qboolean showHelp = true; string shortname; if( !gl_showtextures->integer ) return; if( showHelp ) { CL_CenterPrint( "use '<-' and '->' keys to view all the textures", 0.25f ); showHelp = false; } pglClear( GL_COLOR_BUFFER_BIT ); pglFinish(); base_w = 8; base_h = 6; rebuild_page: total = base_w * base_h; start = total * (gl_showtextures->integer - 1); end = total * gl_showtextures->integer; if( end > MAX_TEXTURES ) end = MAX_TEXTURES; w = glState.width / (float)base_w; h = glState.height / (float)base_h; Con_DrawStringLen( NULL, NULL, &charHeight ); for( i = j = 0; i < MAX_TEXTURES; i++ ) { image = R_GetTexture( i ); if( j == start ) break; // found start if( pglIsTexture( image->texnum )) j++; } if( i == MAX_TEXTURES && gl_showtextures->integer != 1 ) { // bad case, rewind to one and try again Cvar_SetFloat( "r_showtextures", max( 1, gl_showtextures->integer - 1 )); if( ++numTries < 2 ) goto rebuild_page; // to prevent infinite loop } for( k = 0; i < MAX_TEXTURES; i++ ) { if( j == end ) break; // page is full image = R_GetTexture( i ); if( !pglIsTexture( image->texnum )) continue; x = k % base_w * w; y = k / base_w * h; pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); GL_Bind( XASH_TEXTURE0, i ); // NOTE: don't use image->texnum here, because skybox has a 'wrong' indexes if(( image->flags & TF_DEPTHMAP ) && !( image->flags & TF_NOCOMPARE )) pglTexParameteri( image->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE ); pglBegin( GL_QUADS ); pglTexCoord2f( 0, 0 ); pglVertex2f( x, y ); if( image->flags & TF_TEXTURE_RECTANGLE ) pglTexCoord2f( image->width, 0 ); else pglTexCoord2f( 1, 0 ); pglVertex2f( x + w, y ); if( image->flags & TF_TEXTURE_RECTANGLE ) pglTexCoord2f( image->width, image->height ); else pglTexCoord2f( 1, 1 ); pglVertex2f( x + w, y + h ); if( image->flags & TF_TEXTURE_RECTANGLE ) pglTexCoord2f( 0, image->height ); else pglTexCoord2f( 0, 1 ); pglVertex2f( x, y + h ); pglEnd(); if(( image->flags & TF_DEPTHMAP ) && !( image->flags & TF_NOCOMPARE )) pglTexParameteri( image->target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB ); FS_FileBase( image->name, shortname ); if( Q_strlen( shortname ) > 18 ) { // cutoff too long names, it looks ugly shortname[16] = '.'; shortname[17] = '.'; shortname[18] = '\0'; } Con_DrawString( x + 1, y + h - charHeight, shortname, color ); j++, k++; } CL_DrawCenterPrint (); pglFinish(); }
/* ================= R_BloomBlend ================= */ void R_BloomBlend( const ref_params_t *fd ) { if( !r_bloom->value ) return; if( !BLOOM_SIZE ) R_Bloom_InitTextures(); if( screen_texture_width < BLOOM_SIZE || screen_texture_height < BLOOM_SIZE ) return; // set up full screen workspace 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, -10, 100 ); pglMatrixMode( GL_MODELVIEW ); pglLoadIdentity(); pglDisable( GL_DEPTH_TEST ); pglDisable( GL_ALPHA_TEST ); pglDepthMask( GL_FALSE ); pglDisable( GL_BLEND ); GL_Cull( 0 ); pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); pglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); // set up current sizes curView_x = fd->viewport[0]; curView_y = fd->viewport[1]; curView_width = fd->viewport[2]; curView_height = fd->viewport[3]; screenTex_tcw = ( (float)curView_width / (float)screen_texture_width ); screenTex_tch = ( (float)curView_height / (float)screen_texture_height ); if( curView_height > curView_width ) { sampleText_tcw = ( (float)curView_width / (float)curView_height ); sampleText_tch = 1.0f; } else { sampleText_tcw = 1.0f; sampleText_tch = ( (float)curView_height / (float)curView_width ); } sample_width = ( BLOOM_SIZE * sampleText_tcw ); sample_height = ( BLOOM_SIZE * sampleText_tch ); // copy the screen space we'll use to work into the backup texture GL_Bind( GL_TEXTURE0, r_bloombackuptexture ); pglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, r_screenbackuptexture_width * sampleText_tcw, r_screenbackuptexture_height * sampleText_tch ); // create the bloom image R_Bloom_DownsampleView(); R_Bloom_GeneratexDiamonds(); pglDisable( GL_BLEND ); // restore the screen-backup to the screen GL_Bind( GL_TEXTURE0, r_bloombackuptexture ); pglColor4f( 1, 1, 1, 1 ); R_Bloom_Quad( 0, glState.height - (r_screenbackuptexture_height * sampleText_tch), r_screenbackuptexture_width * sampleText_tcw, r_screenbackuptexture_height * sampleText_tch, sampleText_tcw, sampleText_tch ); pglScissor( RI.scissor[0], RI.scissor[1], RI.scissor[2], RI.scissor[3] ); R_Bloom_DrawEffect(); 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 ); pglEnable( GL_DEPTH_TEST ); pglDepthMask( GL_TRUE ); pglDisable( GL_BLEND ); GL_Cull( GL_FRONT ); }
/* ================= R_Bloom_GeneratexDiamonds ================= */ static void R_Bloom_GeneratexDiamonds( void ) { int i, j; float intensity; // set up sample size workspace pglScissor( 0, 0, sample_width, sample_height ); pglViewport( 0, 0, sample_width, sample_height ); pglMatrixMode( GL_PROJECTION ); pglLoadIdentity(); pglOrtho( 0, sample_width, sample_height, 0, -10, 100 ); pglMatrixMode( GL_MODELVIEW ); pglLoadIdentity(); // copy small scene into r_bloomeffecttexture GL_Bind( GL_TEXTURE0, r_bloomeffecttexture ); pglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height ); // start modifying the small scene corner pglColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); pglEnable( GL_BLEND ); // darkening passes if( r_bloom_darken->value ) { pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); pglBlendFunc( GL_DST_COLOR, GL_ZERO ); for( i = 0; i < (int)r_bloom_darken->value; i++ ) R_Bloom_SamplePass( 0, 0 ); pglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height ); } // bluring passes pglBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_COLOR ); if( r_bloom_diamond_size->value > 7.0f || r_bloom_diamond_size->value <= 3.0f ) { if( r_bloom_diamond_size->value != 8.0f ) CVAR_SET_FLOAT( "r_bloom_diamond_size", 8.0f ); for( i = 0; i < r_bloom_diamond_size->value; i++ ) { for( j = 0; j < r_bloom_diamond_size->value; j++ ) { intensity = r_bloom_intensity->value * 0.3f * Diamond8x[i][j]; if( intensity < 0.01f ) continue; pglColor4f( intensity, intensity, intensity, 1.0f ); R_Bloom_SamplePass( i-4, j-4 ); } } } else if( r_bloom_diamond_size->value > 5.0f ) { if( r_bloom_diamond_size->value != 6.0f ) CVAR_SET_FLOAT( "r_bloom_diamond_size", 6.0f ); for( i = 0; i < r_bloom_diamond_size->value; i++ ) { for( j = 0; j < r_bloom_diamond_size->value; j++ ) { intensity = r_bloom_intensity->value * 0.5f * Diamond6x[i][j]; if( intensity < 0.01f ) continue; pglColor4f( intensity, intensity, intensity, 1.0f ); R_Bloom_SamplePass( i-3, j-3 ); } } } else if( r_bloom_diamond_size->value > 3.0f ) { if( r_bloom_diamond_size->value != 4.0f ) CVAR_SET_FLOAT( "r_bloom_diamond_size", 4.0f ); for( i = 0; i < r_bloom_diamond_size->value; i++ ) { for( j = 0; j < r_bloom_diamond_size->value; j++ ) { intensity = r_bloom_intensity->value * 0.8f * Diamond4x[i][j]; if( intensity < 0.01f ) continue; pglColor4f( intensity, intensity, intensity, 1.0f ); R_Bloom_SamplePass( i-2, j-2 ); } } } pglCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, sample_width, sample_height ); // restore full screen workspace 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, -10, 100 ); pglMatrixMode( GL_MODELVIEW ); pglLoadIdentity(); }
void CParticleSystem :: DrawParticle( CParticle *part, Vector &right, Vector &up ) { float fSize = part->m_fSize; // nothing to draw? if( fSize <= 0 ) return; // frustrum visible check if( !ParticleIsVisible( part )) return; Vector point1, point2, point3, point4; Vector origin = part->origin; float fCosSize = CosLookup( part->m_fAngle ) * fSize; float fSinSize = SinLookup( part->m_fAngle ) * fSize; // calculate the four corners of the sprite point1 = origin + up * fSinSize + right * -fCosSize; point2 = origin + up * fCosSize + right * fSinSize; point3 = origin + up * -fSinSize + right * fCosSize; point4 = origin + up * -fCosSize + right * -fSinSize; int iContents = CONTENTS_NONE; model_t *pModel; for( CParticle *pDraw = part; pDraw; pDraw = pDraw->m_pOverlay ) { if( !pDraw->pType->m_hSprite ) continue; if( pDraw->pType->m_iDrawCond ) { if( pDraw->pType->m_iDrawCond == CONTENT_SPOTLIGHT ) { if( !R_CountPlights( )) continue; // fast reject for( int i = 0; i < MAX_PLIGHTS; i++ ) { plight_t *pl = &cl_plights[i]; if( pl->die < GET_CLIENT_TIME() || !pl->radius ) continue; if( !R_CullSphereExt( pl->frustum, part->origin, part->m_fSize + 1, pl->clipflags )) break; // cone intersected with particle } if( i == MAX_PLIGHTS ) continue; // no intersection } else { if( iContents == CONTENTS_NONE ) iContents = POINT_CONTENTS( origin ); if( iContents != pDraw->pType->m_iDrawCond ) continue; } } pModel = (model_t *)gEngfuncs.GetSpritePointer( pDraw->pType->m_hSprite ); // if we've reached the end of the sprite's frames, loop back while (pDraw->frame > pModel->numframes) pDraw->frame -= pModel->numframes; while (pDraw->frame < 0) pDraw->frame += pModel->numframes; if( !TriSpriteTexture( pModel, (int)pDraw->frame )) continue; gEngfuncs.pTriAPI->RenderMode( pDraw->pType->m_iRenderMode ); if( m_iLightingModel >= 1 ) { color24 lightColor; Vector lightingColor; if( m_iLightingModel == 1 ) R_LightForPoint( part->origin, &lightColor, false, true, fSize + 1 ); else R_LightForPoint( part->origin, &lightColor, false, true, 0.0f ); // FIXME: this code is totally wrong. // We need a fake lightmap here like in sprite implementation lightingColor.x = pDraw->m_fRed * lightColor.r * (1.0f / 255.0f); lightingColor.y = pDraw->m_fGreen * lightColor.g * (1.0f / 255.0f); lightingColor.z = pDraw->m_fBlue * lightColor.b * (1.0f / 255.0f); pglColor4f( lightingColor.x, lightingColor.y, lightingColor.z, pDraw->m_fAlpha ); } else pglColor4f( pDraw->m_fRed, pDraw->m_fGreen, pDraw->m_fBlue, pDraw->m_fAlpha ); pglBegin( GL_QUADS ); pglTexCoord2f( 0.0f, 0.0f ); pglVertex3fv( point1 ); pglTexCoord2f( 1.0f, 0.0f ); pglVertex3fv( point2 ); pglTexCoord2f( 1.0f, 1.0f ); pglVertex3fv( point3 ); pglTexCoord2f( 0.0f, 1.0f ); pglVertex3fv( point4 ); pglEnd(); if( m_iLightingModel >=2 && R_CountPlights( )) { for( int i = 0; i < MAX_PLIGHTS; i++ ) { plight_t *pl = &cl_plights[i]; if( pl->die < GET_CLIENT_TIME() || !pl->radius ) continue; if( R_CullSphereExt( pl->frustum, part->origin, part->m_fSize + 1, pl->clipflags )) continue; R_BeginDrawProjection( pl ); pglBegin( GL_QUADS ); pglVertex3fv( point1 ); pglVertex3fv( point2 ); pglVertex3fv( point3 ); pglVertex3fv( point4 ); pglEnd(); R_EndDrawProjection(); } } } }