/* Copyright (C) 2003-2006 Andrey Nazarov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "gl_local.h" #include "gl_arbfp.h" glState_t gls; void GL_BindTexture( int texnum ) { #ifdef _DEBUG if( gl_nobind->integer && !gls.tmu ) { texnum = TEXNUM_DEFAULT; } #endif if( gls.texnum[gls.tmu] == texnum ) { return; } qglBindTexture( GL_TEXTURE_2D, texnum ); gls.texnum[gls.tmu] = texnum; c.texSwitches++; } void GL_SelectTMU( int tmu ) { if( gls.tmu == tmu ) { return; } if( tmu < 0 || tmu >= gl_config.numTextureUnits ) { Com_Error( ERR_FATAL, "GL_SelectTMU: bad tmu %d", tmu ); } qglActiveTextureARB( GL_TEXTURE0_ARB + tmu ); qglClientActiveTextureARB( GL_TEXTURE0_ARB + tmu ); gls.tmu = tmu; } void GL_TexEnv( GLenum texenv ) { if( gls.texenv[gls.tmu] == texenv ) { return; } switch( texenv ) { case GL_REPLACE: case GL_MODULATE: case GL_BLEND: case GL_ADD: qglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, texenv ); break; default: Com_Error( ERR_FATAL, "GL_TexEnv: bad texenv" ); break; } gls.texenv[gls.tmu] = texenv; } void GL_CullFace( glCullFace_t cull ) { if( gls.cull == cull ) { return; } switch( cull ) { case GLS_CULL_DISABLE: qglDisable( GL_CULL_FACE ); break; case GLS_CULL_FRONT: qglEnable( GL_CULL_FACE ); qglCullFace( GL_FRONT ); break; case GLS_CULL_BACK: qglEnable( GL_CULL_FACE ); qglCullFace( GL_BACK ); break; default: Com_Error( ERR_FATAL, "GL_CullFace: bad cull" ); break; } gls.cull = cull; } void GL_Bits( glStateBits_t bits ) { glStateBits_t diff = bits ^ gls.bits; if( !diff ) { return; } if( diff & GLS_BLEND_MASK ) { if( bits & GLS_BLEND_MASK ) { qglEnable( GL_BLEND ); if( bits & GLS_BLEND_BLEND ) { qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); } else if( bits & GLS_BLEND_ADD ) { qglBlendFunc( GL_SRC_ALPHA, GL_ONE ); } else if( bits & GLS_BLEND_MODULATE ) { qglBlendFunc( GL_DST_COLOR, GL_ONE ); } } else { qglDisable( GL_BLEND ); } } if( diff & GLS_DEPTHMASK_FALSE ) { if( bits & GLS_DEPTHMASK_FALSE ) { qglDepthMask( GL_FALSE ); } else { qglDepthMask( GL_TRUE ); } } if( diff & GLS_DEPTHTEST_DISABLE ) { if( bits & GLS_DEPTHTEST_DISABLE ) { qglDisable( GL_DEPTH_TEST ); } else { qglEnable( GL_DEPTH_TEST ); } } if( diff & GLS_ALPHATEST_ENABLE ) { if( bits & GLS_ALPHATEST_ENABLE ) { qglEnable( GL_ALPHA_TEST ); } else { qglDisable( GL_ALPHA_TEST ); } } gls.bits = bits; } void GL_Setup2D( void ) { qglViewport( 0, 0, r_config.width, r_config.height ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); qglOrtho( 0, r_config.width, r_config.height, 0, -1, 1 ); draw.scale = 1; draw.colors[0].u32 = U32_WHITE; draw.colors[1].u32 = U32_WHITE; if( draw.flags & DRAW_CLIP_MASK ) { qglDisable( GL_SCISSOR_TEST ); } draw.flags = 0; qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity(); GL_Bits( GLS_DEPTHTEST_DISABLE ); GL_CullFace( GLS_CULL_DISABLE ); } void GL_Setup3D( void ) { GLdouble xmin, xmax, ymin, ymax; int yb = glr.fd.y + glr.fd.height; qglViewport( glr.fd.x, r_config.height - yb, glr.fd.width, glr.fd.height ); qglMatrixMode( GL_PROJECTION ); qglLoadIdentity(); ymax = gl_znear->value * tan( glr.fd.fov_y * M_PI / 360.0 ); ymin = -ymax; xmax = gl_znear->value * tan( glr.fd.fov_x * M_PI / 360.0 ); xmin = -xmax; qglFrustum( xmin, xmax, ymin, ymax, gl_znear->value, gl_zfar->value ); qglMatrixMode( GL_MODELVIEW ); qglLoadIdentity(); qglRotatef( -90, 1, 0, 0 ); /* put z axis up */ qglRotatef( 90, 0, 0, 1 ); /* put y axis west, x axis north */ qglRotatef( -glr.fd.viewangles[ROLL], 1, 0, 0 ); qglRotatef( -glr.fd.viewangles[PITCH], 0, 1, 0 ); qglRotatef( -glr.fd.viewangles[YAW], 0, 0, 1 ); qglTranslatef( -glr.fd.vieworg[0], -glr.fd.vieworg[1], -glr.fd.vieworg[2] ); AngleVectors( glr.fd.viewangles, glr.viewaxis[0], glr.viewaxis[1], glr.viewaxis[2] ); VectorInverse( glr.viewaxis[1] ); GL_Bits( GLS_DEFAULT ); GL_CullFace( GLS_CULL_FRONT ); qglClear( GL_DEPTH_BUFFER_BIT ); } void GL_SetDefaultState( void ) { qglClearColor( 0, 0, 0, 1 ); qglClearDepth( 1 ); qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); qglEnable( GL_DEPTH_TEST ); qglDepthFunc( GL_LEQUAL ); qglDepthRange( 0, 1 ); qglDepthMask( GL_TRUE ); qglDisable( GL_BLEND ); qglDisable( GL_ALPHA_TEST ); qglAlphaFunc( GL_GREATER, 0.666f ); qglHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); qglEnableClientState( GL_VERTEX_ARRAY ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); GL_SelectTMU( 0 ); GL_BindTexture( 0 ); qglEnable( GL_TEXTURE_2D ); GL_Bits( GLS_DEFAULT ); } // for screenshots byte *IMG_ReadPixels( qboolean reverse, int *width, int *height ) { byte *pixels; pixels = FS_AllocTempMem( r_config.width * r_config.height * 3 ); qglReadPixels( 0, 0, r_config.width, r_config.height, reverse ? GL_BGR : GL_RGB, GL_UNSIGNED_BYTE, pixels ); *width = r_config.width; *height = r_config.height; return pixels; } void GL_EnableOutlines( void ) { if( gls.fp_enabled ) { qglDisable( GL_FRAGMENT_PROGRAM_ARB ); } qglDisable( GL_TEXTURE_2D ); qglDisableClientState( GL_TEXTURE_COORD_ARRAY ); qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); qglDepthRange( 0, 0 ); qglColor4f( 1, 1, 1, 1 ); } void GL_DisableOutlines( void ) { qglDepthRange( 0, 1 ); qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); qglEnableClientState( GL_TEXTURE_COORD_ARRAY ); qglEnable( GL_TEXTURE_2D ); if( gls.fp_enabled ) { qglEnable( GL_FRAGMENT_PROGRAM_ARB ); } } void GL_EnableWarp( void ) { vec4_t param; qglEnable( GL_FRAGMENT_PROGRAM_ARB ); qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, gl_static.prognum_warp ); param[0] = glr.fd.time; param[1] = glr.fd.time; param[2] = param[3] = 0; qglProgramLocalParameter4fvARB( GL_FRAGMENT_PROGRAM_ARB, 0, param ); gls.fp_enabled = qtrue; } void GL_DisableWarp( void ) { qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, 0 ); qglDisable( GL_FRAGMENT_PROGRAM_ARB ); gls.fp_enabled = qfalse; } void GL_InitPrograms( void ) { GLuint prog; if( gl_config.ext_supported & QGL_ARB_fragment_program ) { if( gl_fragment_program->integer ) { Com_Printf( "...enabling GL_ARB_fragment_program\n" ); QGL_InitExtensions( QGL_ARB_fragment_program ); gl_config.ext_enabled |= QGL_ARB_fragment_program; } else { Com_Printf( "...ignoring GL_ARB_fragment_program\n" ); } } else if( gl_fragment_program->integer ) { Com_Printf( "GL_ARB_fragment_program not found\n" ); Cvar_Set( "gl_fragment_program", "0" ); } if( !qglProgramStringARB ) { return; } GL_ClearErrors(); qglGenProgramsARB( 1, &prog ); qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, prog ); qglProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, sizeof( gl_prog_warp ) - 1, gl_prog_warp ); if( GL_ShowErrors( "Failed to initialize fragment program" ) ) { qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, 0 ); qglDeleteProgramsARB( 1, &prog ); return; } qglBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, 0 ); gl_static.prognum_warp = prog; } void GL_ShutdownPrograms( void ) { if( !qglDeleteProgramsARB ) { return; } if( gl_static.prognum_warp ) { qglDeleteProgramsARB( 1, &gl_static.prognum_warp ); gl_static.prognum_warp = 0; } QGL_ShutdownExtensions( QGL_ARB_fragment_program ); gl_config.ext_enabled &= ~QGL_ARB_fragment_program; }