2012-11-26 18:58:24 +00:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
|
|
|
|
Doom 3 BFG Edition GPL Source Code
|
2012-11-28 15:47:07 +00:00
|
|
|
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
2012-11-26 18:58:24 +00:00
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
2012-11-26 18:58:24 +00:00
|
|
|
|
|
|
|
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
|
|
|
|
|
|
|
|
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
|
|
|
|
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma hdrstop
|
|
|
|
#include "../../idlib/precompiled.h"
|
|
|
|
|
|
|
|
#include "../tr_local.h"
|
|
|
|
|
|
|
|
/*
|
|
|
|
====================
|
|
|
|
GL_SelectTexture
|
|
|
|
====================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_SelectTexture( int unit )
|
|
|
|
{
|
|
|
|
if( backEnd.glState.currenttmu == unit )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
|
|
|
if( unit < 0 || unit >= glConfig.maxTextureImageUnits )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
common->Warning( "GL_SelectTexture: unit = %i", unit );
|
|
|
|
return;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
RENDERLOG_PRINTF( "GL_SelectTexture( %i );\n", unit );
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
backEnd.glState.currenttmu = unit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
====================
|
|
|
|
GL_Cull
|
|
|
|
|
|
|
|
This handles the flipping needed when the view being
|
|
|
|
rendered is a mirored view.
|
|
|
|
====================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_Cull( int cullType )
|
|
|
|
{
|
|
|
|
if( backEnd.glState.faceCulling == cullType )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
|
|
|
if( cullType == CT_TWO_SIDED )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglDisable( GL_CULL_FACE );
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( backEnd.glState.faceCulling == CT_TWO_SIDED )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglEnable( GL_CULL_FACE );
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
|
|
|
if( cullType == CT_BACK_SIDED )
|
|
|
|
{
|
|
|
|
if( backEnd.viewDef->isMirror )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglCullFace( GL_FRONT );
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglCullFace( GL_BACK );
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if( backEnd.viewDef->isMirror )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglCullFace( GL_BACK );
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglCullFace( GL_FRONT );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
backEnd.glState.faceCulling = cullType;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
====================
|
|
|
|
GL_Scissor
|
|
|
|
====================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_Scissor( int x /* left*/, int y /* bottom */, int w, int h )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglScissor( x, y, w, h );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
====================
|
|
|
|
GL_Viewport
|
|
|
|
====================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_Viewport( int x /* left */, int y /* bottom */, int w, int h )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglViewport( x, y, w, h );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
====================
|
|
|
|
GL_PolygonOffset
|
|
|
|
====================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_PolygonOffset( float scale, float bias )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
backEnd.glState.polyOfsScale = scale;
|
|
|
|
backEnd.glState.polyOfsBias = bias;
|
2012-11-28 15:47:07 +00:00
|
|
|
if( backEnd.glState.glStateBits & GLS_POLYGON_OFFSET )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglPolygonOffset( scale, bias );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
GL_DepthBoundsTest
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_DepthBoundsTest( const float zmin, const float zmax )
|
|
|
|
{
|
|
|
|
if( !glConfig.depthBoundsTestAvailable || zmin > zmax )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
|
|
|
if( zmin == 0.0f && zmax == 0.0f )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglDisable( GL_DEPTH_BOUNDS_TEST_EXT );
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglEnable( GL_DEPTH_BOUNDS_TEST_EXT );
|
|
|
|
qglDepthBoundsEXT( zmin, zmax );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
GL_StartDepthPass
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_StartDepthPass( const idScreenRect& rect )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
GL_FinishDepthPass
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_FinishDepthPass()
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
GL_GetDepthPassRect
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_GetDepthPassRect( idScreenRect& rect )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
rect.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
====================
|
|
|
|
GL_Color
|
|
|
|
====================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_Color( float* color )
|
|
|
|
{
|
|
|
|
if( color == NULL )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
GL_Color( color[0], color[1], color[2], color[3] );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
====================
|
|
|
|
GL_Color
|
|
|
|
====================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_Color( float r, float g, float b )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
GL_Color( r, g, b, 1.0f );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
====================
|
|
|
|
GL_Color
|
|
|
|
====================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_Color( float r, float g, float b, float a )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
float parm[4];
|
|
|
|
parm[0] = idMath::ClampFloat( 0.0f, 1.0f, r );
|
|
|
|
parm[1] = idMath::ClampFloat( 0.0f, 1.0f, g );
|
|
|
|
parm[2] = idMath::ClampFloat( 0.0f, 1.0f, b );
|
|
|
|
parm[3] = idMath::ClampFloat( 0.0f, 1.0f, a );
|
|
|
|
renderProgManager.SetRenderParm( RENDERPARM_COLOR, parm );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
GL_Clear
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_Clear( bool color, bool depth, bool stencil, byte stencilValue, float r, float g, float b, float a )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
int clearFlags = 0;
|
2012-11-28 15:47:07 +00:00
|
|
|
if( color )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglClearColor( r, g, b, a );
|
|
|
|
clearFlags |= GL_COLOR_BUFFER_BIT;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
if( depth )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
clearFlags |= GL_DEPTH_BUFFER_BIT;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
if( stencil )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglClearStencil( stencilValue );
|
|
|
|
clearFlags |= GL_STENCIL_BUFFER_BIT;
|
|
|
|
}
|
|
|
|
qglClear( clearFlags );
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
GL_SetDefaultState
|
|
|
|
|
|
|
|
This should initialize all GL state that any part of the entire program
|
|
|
|
may touch, including the editor.
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_SetDefaultState()
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
RENDERLOG_PRINTF( "--- GL_SetDefaultState ---\n" );
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
qglClearDepth( 1.0f );
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// make sure our GL state vector is set correctly
|
|
|
|
memset( &backEnd.glState, 0, sizeof( backEnd.glState ) );
|
|
|
|
GL_State( 0, true );
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// These are changed by GL_Cull
|
|
|
|
qglCullFace( GL_FRONT_AND_BACK );
|
|
|
|
qglEnable( GL_CULL_FACE );
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// These are changed by GL_State
|
|
|
|
qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
|
|
|
|
qglBlendFunc( GL_ONE, GL_ZERO );
|
|
|
|
qglDepthMask( GL_TRUE );
|
|
|
|
qglDepthFunc( GL_LESS );
|
|
|
|
qglDisable( GL_STENCIL_TEST );
|
|
|
|
qglDisable( GL_POLYGON_OFFSET_FILL );
|
|
|
|
qglDisable( GL_POLYGON_OFFSET_LINE );
|
|
|
|
qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// These should never be changed
|
|
|
|
qglShadeModel( GL_SMOOTH );
|
|
|
|
qglEnable( GL_DEPTH_TEST );
|
|
|
|
qglEnable( GL_BLEND );
|
|
|
|
qglEnable( GL_SCISSOR_TEST );
|
|
|
|
qglDrawBuffer( GL_BACK );
|
|
|
|
qglReadBuffer( GL_BACK );
|
2012-11-28 15:47:07 +00:00
|
|
|
|
|
|
|
if( r_useScissor.GetBool() )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglScissor( 0, 0, renderSystem->GetWidth(), renderSystem->GetHeight() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
====================
|
|
|
|
GL_State
|
|
|
|
|
|
|
|
This routine is responsible for setting the most commonly changed state
|
|
|
|
====================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
void GL_State( uint64 stateBits, bool forceGlState )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
uint64 diff = stateBits ^ backEnd.glState.glStateBits;
|
|
|
|
|
2012-11-28 15:47:07 +00:00
|
|
|
if( !r_useStateCaching.GetBool() || forceGlState )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
// make sure everything is set all the time, so we
|
|
|
|
// can see if our delta checking is screwing up
|
|
|
|
diff = 0xFFFFFFFFFFFFFFFF;
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else if( diff == 0 )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
//
|
|
|
|
// check depthFunc bits
|
|
|
|
//
|
2012-11-28 15:47:07 +00:00
|
|
|
if( diff & GLS_DEPTHFUNC_BITS )
|
|
|
|
{
|
|
|
|
switch( stateBits & GLS_DEPTHFUNC_BITS )
|
|
|
|
{
|
|
|
|
case GLS_DEPTHFUNC_EQUAL:
|
|
|
|
qglDepthFunc( GL_EQUAL );
|
|
|
|
break;
|
|
|
|
case GLS_DEPTHFUNC_ALWAYS:
|
|
|
|
qglDepthFunc( GL_ALWAYS );
|
|
|
|
break;
|
|
|
|
case GLS_DEPTHFUNC_LESS:
|
|
|
|
qglDepthFunc( GL_LEQUAL );
|
|
|
|
break;
|
|
|
|
case GLS_DEPTHFUNC_GREATER:
|
|
|
|
qglDepthFunc( GL_GEQUAL );
|
|
|
|
break;
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
//
|
|
|
|
// check blend bits
|
|
|
|
//
|
2012-11-28 15:47:07 +00:00
|
|
|
if( diff & ( GLS_SRCBLEND_BITS | GLS_DSTBLEND_BITS ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
GLenum srcFactor = GL_ONE;
|
|
|
|
GLenum dstFactor = GL_ZERO;
|
2012-11-28 15:47:07 +00:00
|
|
|
|
|
|
|
switch( stateBits & GLS_SRCBLEND_BITS )
|
|
|
|
{
|
|
|
|
case GLS_SRCBLEND_ZERO:
|
|
|
|
srcFactor = GL_ZERO;
|
|
|
|
break;
|
|
|
|
case GLS_SRCBLEND_ONE:
|
|
|
|
srcFactor = GL_ONE;
|
|
|
|
break;
|
|
|
|
case GLS_SRCBLEND_DST_COLOR:
|
|
|
|
srcFactor = GL_DST_COLOR;
|
|
|
|
break;
|
|
|
|
case GLS_SRCBLEND_ONE_MINUS_DST_COLOR:
|
|
|
|
srcFactor = GL_ONE_MINUS_DST_COLOR;
|
|
|
|
break;
|
|
|
|
case GLS_SRCBLEND_SRC_ALPHA:
|
|
|
|
srcFactor = GL_SRC_ALPHA;
|
|
|
|
break;
|
|
|
|
case GLS_SRCBLEND_ONE_MINUS_SRC_ALPHA:
|
|
|
|
srcFactor = GL_ONE_MINUS_SRC_ALPHA;
|
|
|
|
break;
|
|
|
|
case GLS_SRCBLEND_DST_ALPHA:
|
|
|
|
srcFactor = GL_DST_ALPHA;
|
|
|
|
break;
|
|
|
|
case GLS_SRCBLEND_ONE_MINUS_DST_ALPHA:
|
|
|
|
srcFactor = GL_ONE_MINUS_DST_ALPHA;
|
|
|
|
break;
|
2012-11-26 18:58:24 +00:00
|
|
|
default:
|
|
|
|
assert( !"GL_State: invalid src blend state bits\n" );
|
|
|
|
break;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
|
|
|
switch( stateBits & GLS_DSTBLEND_BITS )
|
|
|
|
{
|
|
|
|
case GLS_DSTBLEND_ZERO:
|
|
|
|
dstFactor = GL_ZERO;
|
|
|
|
break;
|
|
|
|
case GLS_DSTBLEND_ONE:
|
|
|
|
dstFactor = GL_ONE;
|
|
|
|
break;
|
|
|
|
case GLS_DSTBLEND_SRC_COLOR:
|
|
|
|
dstFactor = GL_SRC_COLOR;
|
|
|
|
break;
|
|
|
|
case GLS_DSTBLEND_ONE_MINUS_SRC_COLOR:
|
|
|
|
dstFactor = GL_ONE_MINUS_SRC_COLOR;
|
|
|
|
break;
|
|
|
|
case GLS_DSTBLEND_SRC_ALPHA:
|
|
|
|
dstFactor = GL_SRC_ALPHA;
|
|
|
|
break;
|
|
|
|
case GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA:
|
|
|
|
dstFactor = GL_ONE_MINUS_SRC_ALPHA;
|
|
|
|
break;
|
|
|
|
case GLS_DSTBLEND_DST_ALPHA:
|
|
|
|
dstFactor = GL_DST_ALPHA;
|
|
|
|
break;
|
|
|
|
case GLS_DSTBLEND_ONE_MINUS_DST_ALPHA:
|
|
|
|
dstFactor = GL_ONE_MINUS_DST_ALPHA;
|
|
|
|
break;
|
2012-11-26 18:58:24 +00:00
|
|
|
default:
|
|
|
|
assert( !"GL_State: invalid dst blend state bits\n" );
|
|
|
|
break;
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
// Only actually update GL's blend func if blending is enabled.
|
2012-11-28 15:47:07 +00:00
|
|
|
if( srcFactor == GL_ONE && dstFactor == GL_ZERO )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglDisable( GL_BLEND );
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglEnable( GL_BLEND );
|
|
|
|
qglBlendFunc( srcFactor, dstFactor );
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
//
|
|
|
|
// check depthmask
|
|
|
|
//
|
2012-11-28 15:47:07 +00:00
|
|
|
if( diff & GLS_DEPTHMASK )
|
|
|
|
{
|
|
|
|
if( stateBits & GLS_DEPTHMASK )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglDepthMask( GL_FALSE );
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglDepthMask( GL_TRUE );
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
//
|
|
|
|
// check colormask
|
|
|
|
//
|
2012-11-28 15:47:07 +00:00
|
|
|
if( diff & ( GLS_REDMASK | GLS_GREENMASK | GLS_BLUEMASK | GLS_ALPHAMASK ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
GLboolean r = ( stateBits & GLS_REDMASK ) ? GL_FALSE : GL_TRUE;
|
|
|
|
GLboolean g = ( stateBits & GLS_GREENMASK ) ? GL_FALSE : GL_TRUE;
|
|
|
|
GLboolean b = ( stateBits & GLS_BLUEMASK ) ? GL_FALSE : GL_TRUE;
|
|
|
|
GLboolean a = ( stateBits & GLS_ALPHAMASK ) ? GL_FALSE : GL_TRUE;
|
|
|
|
qglColorMask( r, g, b, a );
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
//
|
|
|
|
// fill/line mode
|
|
|
|
//
|
2012-11-28 15:47:07 +00:00
|
|
|
if( diff & GLS_POLYMODE_LINE )
|
|
|
|
{
|
|
|
|
if( stateBits & GLS_POLYMODE_LINE )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
//
|
|
|
|
// polygon offset
|
|
|
|
//
|
2012-11-28 15:47:07 +00:00
|
|
|
if( diff & GLS_POLYGON_OFFSET )
|
|
|
|
{
|
|
|
|
if( stateBits & GLS_POLYGON_OFFSET )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglPolygonOffset( backEnd.glState.polyOfsScale, backEnd.glState.polyOfsBias );
|
|
|
|
qglEnable( GL_POLYGON_OFFSET_FILL );
|
|
|
|
qglEnable( GL_POLYGON_OFFSET_LINE );
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglDisable( GL_POLYGON_OFFSET_FILL );
|
|
|
|
qglDisable( GL_POLYGON_OFFSET_LINE );
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
#if !defined( USE_CORE_PROFILE )
|
|
|
|
//
|
|
|
|
// alpha test
|
|
|
|
//
|
2012-11-28 15:47:07 +00:00
|
|
|
if( diff & ( GLS_ALPHATEST_FUNC_BITS | GLS_ALPHATEST_FUNC_REF_BITS ) )
|
|
|
|
{
|
|
|
|
if( ( stateBits & GLS_ALPHATEST_FUNC_BITS ) != 0 )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglEnable( GL_ALPHA_TEST );
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
GLenum func = GL_ALWAYS;
|
2012-11-28 15:47:07 +00:00
|
|
|
switch( stateBits & GLS_ALPHATEST_FUNC_BITS )
|
|
|
|
{
|
|
|
|
case GLS_ALPHATEST_FUNC_LESS:
|
|
|
|
func = GL_LESS;
|
|
|
|
break;
|
|
|
|
case GLS_ALPHATEST_FUNC_EQUAL:
|
|
|
|
func = GL_EQUAL;
|
|
|
|
break;
|
|
|
|
case GLS_ALPHATEST_FUNC_GREATER:
|
|
|
|
func = GL_GEQUAL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert( false );
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
GLclampf ref = ( ( stateBits & GLS_ALPHATEST_FUNC_REF_BITS ) >> GLS_ALPHATEST_FUNC_REF_SHIFT ) / ( float )0xFF;
|
2012-11-26 18:58:24 +00:00
|
|
|
qglAlphaFunc( func, ref );
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglDisable( GL_ALPHA_TEST );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
//
|
|
|
|
// stencil
|
|
|
|
//
|
2012-11-28 15:47:07 +00:00
|
|
|
if( diff & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_OP_BITS ) )
|
|
|
|
{
|
|
|
|
if( ( stateBits & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_OP_BITS ) ) != 0 )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglEnable( GL_STENCIL_TEST );
|
2012-11-28 15:47:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
qglDisable( GL_STENCIL_TEST );
|
|
|
|
}
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
if( diff & ( GLS_STENCIL_FUNC_BITS | GLS_STENCIL_FUNC_REF_BITS | GLS_STENCIL_FUNC_MASK_BITS ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
GLuint ref = GLuint( ( stateBits & GLS_STENCIL_FUNC_REF_BITS ) >> GLS_STENCIL_FUNC_REF_SHIFT );
|
|
|
|
GLuint mask = GLuint( ( stateBits & GLS_STENCIL_FUNC_MASK_BITS ) >> GLS_STENCIL_FUNC_MASK_SHIFT );
|
|
|
|
GLenum func = 0;
|
2012-11-28 15:47:07 +00:00
|
|
|
|
|
|
|
switch( stateBits & GLS_STENCIL_FUNC_BITS )
|
|
|
|
{
|
|
|
|
case GLS_STENCIL_FUNC_NEVER:
|
|
|
|
func = GL_NEVER;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_FUNC_LESS:
|
|
|
|
func = GL_LESS;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_FUNC_EQUAL:
|
|
|
|
func = GL_EQUAL;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_FUNC_LEQUAL:
|
|
|
|
func = GL_LEQUAL;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_FUNC_GREATER:
|
|
|
|
func = GL_GREATER;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_FUNC_NOTEQUAL:
|
|
|
|
func = GL_NOTEQUAL;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_FUNC_GEQUAL:
|
|
|
|
func = GL_GEQUAL;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_FUNC_ALWAYS:
|
|
|
|
func = GL_ALWAYS;
|
|
|
|
break;
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
|
|
|
qglStencilFunc( func, ref, mask );
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
if( diff & ( GLS_STENCIL_OP_FAIL_BITS | GLS_STENCIL_OP_ZFAIL_BITS | GLS_STENCIL_OP_PASS_BITS ) )
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
GLenum sFail = 0;
|
|
|
|
GLenum zFail = 0;
|
|
|
|
GLenum pass = 0;
|
2012-11-28 15:47:07 +00:00
|
|
|
|
|
|
|
switch( stateBits & GLS_STENCIL_OP_FAIL_BITS )
|
|
|
|
{
|
|
|
|
case GLS_STENCIL_OP_FAIL_KEEP:
|
|
|
|
sFail = GL_KEEP;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_FAIL_ZERO:
|
|
|
|
sFail = GL_ZERO;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_FAIL_REPLACE:
|
|
|
|
sFail = GL_REPLACE;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_FAIL_INCR:
|
|
|
|
sFail = GL_INCR;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_FAIL_DECR:
|
|
|
|
sFail = GL_DECR;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_FAIL_INVERT:
|
|
|
|
sFail = GL_INVERT;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_FAIL_INCR_WRAP:
|
|
|
|
sFail = GL_INCR_WRAP;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_FAIL_DECR_WRAP:
|
|
|
|
sFail = GL_DECR_WRAP;
|
|
|
|
break;
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
switch( stateBits & GLS_STENCIL_OP_ZFAIL_BITS )
|
|
|
|
{
|
|
|
|
case GLS_STENCIL_OP_ZFAIL_KEEP:
|
|
|
|
zFail = GL_KEEP;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_ZFAIL_ZERO:
|
|
|
|
zFail = GL_ZERO;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_ZFAIL_REPLACE:
|
|
|
|
zFail = GL_REPLACE;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_ZFAIL_INCR:
|
|
|
|
zFail = GL_INCR;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_ZFAIL_DECR:
|
|
|
|
zFail = GL_DECR;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_ZFAIL_INVERT:
|
|
|
|
zFail = GL_INVERT;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_ZFAIL_INCR_WRAP:
|
|
|
|
zFail = GL_INCR_WRAP;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_ZFAIL_DECR_WRAP:
|
|
|
|
zFail = GL_DECR_WRAP;
|
|
|
|
break;
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
switch( stateBits & GLS_STENCIL_OP_PASS_BITS )
|
|
|
|
{
|
|
|
|
case GLS_STENCIL_OP_PASS_KEEP:
|
|
|
|
pass = GL_KEEP;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_PASS_ZERO:
|
|
|
|
pass = GL_ZERO;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_PASS_REPLACE:
|
|
|
|
pass = GL_REPLACE;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_PASS_INCR:
|
|
|
|
pass = GL_INCR;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_PASS_DECR:
|
|
|
|
pass = GL_DECR;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_PASS_INVERT:
|
|
|
|
pass = GL_INVERT;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_PASS_INCR_WRAP:
|
|
|
|
pass = GL_INCR_WRAP;
|
|
|
|
break;
|
|
|
|
case GLS_STENCIL_OP_PASS_DECR_WRAP:
|
|
|
|
pass = GL_DECR_WRAP;
|
|
|
|
break;
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|
|
|
|
qglStencilOp( sFail, zFail, pass );
|
|
|
|
}
|
2012-11-28 15:47:07 +00:00
|
|
|
|
2012-11-26 18:58:24 +00:00
|
|
|
backEnd.glState.glStateBits = stateBits;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
=================
|
|
|
|
GL_GetCurrentState
|
|
|
|
=================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
uint64 GL_GetCurrentState()
|
|
|
|
{
|
2012-11-26 18:58:24 +00:00
|
|
|
return backEnd.glState.glStateBits;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
========================
|
|
|
|
GL_GetCurrentStateMinusStencil
|
|
|
|
========================
|
|
|
|
*/
|
2012-11-28 15:47:07 +00:00
|
|
|
uint64 GL_GetCurrentStateMinusStencil()
|
|
|
|
{
|
|
|
|
return GL_GetCurrentState() & ~( GLS_STENCIL_OP_BITS | GLS_STENCIL_FUNC_BITS | GLS_STENCIL_FUNC_REF_BITS | GLS_STENCIL_FUNC_MASK_BITS );
|
2012-11-26 18:58:24 +00:00
|
|
|
}
|