mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 00:41:21 +00:00
85a20a70c2
Removed legacy GL_NV_texture_shader water warp effect. Added r_subdivide_size cvar to control polygon subdivision of warp surfaces. Added preliminary support for warp lightmaps.
626 lines
13 KiB
C
626 lines
13 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1997-2001 Id Software, Inc.
|
|
|
|
This file is part of Quake 2 source code.
|
|
|
|
Quake 2 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 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
Quake 2 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 Quake 2 source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
// r_glstate.c - OpenGL state manager from Q2E
|
|
|
|
#include "r_local.h"
|
|
|
|
|
|
/*
|
|
=================
|
|
GL_Enable
|
|
=================
|
|
*/
|
|
void GL_Enable (GLenum cap)
|
|
{
|
|
switch (cap)
|
|
{
|
|
case GL_CULL_FACE:
|
|
if (glState.cullFace)
|
|
return;
|
|
glState.cullFace = true;
|
|
break;
|
|
case GL_POLYGON_OFFSET_FILL:
|
|
if (glState.polygonOffsetFill)
|
|
return;
|
|
glState.polygonOffsetFill = true;
|
|
break;
|
|
/* case GL_TEXTURE_SHADER_NV:
|
|
if (!glConfig.NV_texshaders || glState.TexShaderNV)
|
|
return;
|
|
glState.TexShaderNV = true;
|
|
break;*/
|
|
case GL_VERTEX_PROGRAM_ARB:
|
|
if (!glConfig.arb_vertex_program || glState.vertexProgram)
|
|
return;
|
|
glState.vertexProgram = true;
|
|
break;
|
|
case GL_FRAGMENT_PROGRAM_ARB:
|
|
if (!glConfig.arb_fragment_program || glState.fragmentProgram)
|
|
return;
|
|
glState.fragmentProgram = true;
|
|
break;
|
|
case GL_ALPHA_TEST:
|
|
if (glState.alphaTest)
|
|
return;
|
|
glState.alphaTest = true;
|
|
break;
|
|
case GL_BLEND:
|
|
if (glState.blend)
|
|
return;
|
|
glState.blend = true;
|
|
break;
|
|
case GL_DEPTH_TEST:
|
|
if (glState.depthTest)
|
|
return;
|
|
glState.depthTest = true;
|
|
break;
|
|
case GL_STENCIL_TEST:
|
|
if (glState.stencilTest)
|
|
return;
|
|
glState.stencilTest = true;
|
|
break;
|
|
case GL_SCISSOR_TEST:
|
|
if (glState.scissorTest)
|
|
return;
|
|
glState.scissorTest = true;
|
|
}
|
|
qglEnable(cap);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
GL_Disable
|
|
=================
|
|
*/
|
|
void GL_Disable (GLenum cap)
|
|
{
|
|
switch (cap)
|
|
{
|
|
case GL_CULL_FACE:
|
|
if (!glState.cullFace)
|
|
return;
|
|
glState.cullFace = false;
|
|
break;
|
|
case GL_POLYGON_OFFSET_FILL:
|
|
if (!glState.polygonOffsetFill)
|
|
return;
|
|
glState.polygonOffsetFill = false;
|
|
break;
|
|
/* case GL_TEXTURE_SHADER_NV:
|
|
if (!glConfig.NV_texshaders || !glState.TexShaderNV)
|
|
return;
|
|
glState.TexShaderNV = false;
|
|
break;*/
|
|
case GL_VERTEX_PROGRAM_ARB:
|
|
if (!glConfig.arb_vertex_program || !glState.vertexProgram)
|
|
return;
|
|
glState.vertexProgram = false;
|
|
break;
|
|
case GL_FRAGMENT_PROGRAM_ARB:
|
|
if (!glConfig.arb_fragment_program || !glState.fragmentProgram)
|
|
return;
|
|
glState.fragmentProgram = false;
|
|
break;
|
|
case GL_ALPHA_TEST:
|
|
if (!glState.alphaTest)
|
|
return;
|
|
glState.alphaTest = false;
|
|
break;
|
|
case GL_BLEND:
|
|
if (!glState.blend)
|
|
return;
|
|
glState.blend = false;
|
|
break;
|
|
case GL_DEPTH_TEST:
|
|
if (!glState.depthTest)
|
|
return;
|
|
glState.depthTest = false;
|
|
break;
|
|
case GL_STENCIL_TEST:
|
|
if (!glState.stencilTest)
|
|
return;
|
|
glState.stencilTest = false;
|
|
break;
|
|
case GL_SCISSOR_TEST:
|
|
if (!glState.scissorTest)
|
|
return;
|
|
glState.scissorTest = false;
|
|
}
|
|
qglDisable(cap);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
GL_Stencil
|
|
setting stencil buffer
|
|
stenciling for shadows & color shells
|
|
=================
|
|
*/
|
|
void GL_Stencil (qboolean enable, qboolean shell)
|
|
{
|
|
if (!glConfig.have_stencil || !r_stencil->integer)
|
|
return;
|
|
|
|
if (enable)
|
|
{
|
|
if (shell || r_shadows->integer == 3) {
|
|
qglPushAttrib(GL_STENCIL_BUFFER_BIT);
|
|
if ( r_shadows->integer == 3)
|
|
qglClearStencil(1);
|
|
qglClear(GL_STENCIL_BUFFER_BIT);
|
|
}
|
|
|
|
GL_Enable(GL_STENCIL_TEST);
|
|
qglStencilFunc(GL_EQUAL, 1, 2);
|
|
qglStencilOp(GL_KEEP,GL_KEEP,GL_INCR);
|
|
}
|
|
else
|
|
{
|
|
GL_Disable(GL_STENCIL_TEST);
|
|
if (shell || r_shadows->integer == 3)
|
|
qglPopAttrib();
|
|
}
|
|
}
|
|
|
|
qboolean GL_HasStencil (void)
|
|
{
|
|
return (glConfig.have_stencil && r_stencil->integer);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
R_ParticleStencil
|
|
uses stencil buffer to redraw
|
|
particles only over trans surfaces
|
|
=================
|
|
*/
|
|
extern cvar_t *r_particle_overdraw;
|
|
void R_ParticleStencil (int passnum)
|
|
{
|
|
if (!glConfig.have_stencil || !r_particle_overdraw->integer)
|
|
return;
|
|
|
|
if (passnum == 1) // write area of trans surfaces to stencil buffer
|
|
{
|
|
qglPushAttrib(GL_STENCIL_BUFFER_BIT); // save stencil buffer
|
|
qglClearStencil(1);
|
|
qglClear(GL_STENCIL_BUFFER_BIT);
|
|
|
|
GL_Enable(GL_STENCIL_TEST);
|
|
qglStencilFunc( GL_ALWAYS, 1, 0xFF);
|
|
qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
|
|
}
|
|
else if (passnum == 2) // turn off writing
|
|
{
|
|
GL_Disable(GL_STENCIL_TEST);
|
|
}
|
|
else if (passnum == 3) // enable drawing only to affected area
|
|
{
|
|
GL_Enable(GL_STENCIL_TEST);
|
|
qglStencilFunc( GL_NOTEQUAL, 1, 0xFF);
|
|
qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
|
}
|
|
else if (passnum == 4) // turn off and restore
|
|
{
|
|
GL_Disable(GL_STENCIL_TEST);
|
|
qglPopAttrib(); // restore stencil buffer
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
GL_Envmap
|
|
setting up envmap
|
|
=================
|
|
*/
|
|
#define GLSTATE_DISABLE_TEXGEN if (glState.texgen) { qglDisable(GL_TEXTURE_GEN_S); qglDisable(GL_TEXTURE_GEN_T); qglDisable(GL_TEXTURE_GEN_R); glState.texgen=false; }
|
|
#define GLSTATE_ENABLE_TEXGEN if (!glState.texgen) { qglEnable(GL_TEXTURE_GEN_S); qglEnable(GL_TEXTURE_GEN_T); qglEnable(GL_TEXTURE_GEN_R); glState.texgen=true; }
|
|
void GL_Envmap (qboolean enable)
|
|
{
|
|
|
|
if (enable)
|
|
{
|
|
qglTexGenf(GL_S, GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
|
|
qglTexGenf(GL_T, GL_TEXTURE_GEN_MODE,GL_SPHERE_MAP);
|
|
GLSTATE_ENABLE_TEXGEN
|
|
}
|
|
else
|
|
{
|
|
GLSTATE_DISABLE_TEXGEN
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
GL_ShadeModel
|
|
=================
|
|
*/
|
|
void GL_ShadeModel (GLenum mode)
|
|
{
|
|
if (glState.shadeModelMode == mode)
|
|
return;
|
|
glState.shadeModelMode = mode;
|
|
qglShadeModel(mode);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
GL_TexEnv
|
|
=================
|
|
*/
|
|
void GL_TexEnv (GLenum mode)
|
|
{
|
|
static int lastmodes[2] = { -1, -1 };
|
|
|
|
if ( mode != lastmodes[glState.currenttmu] )
|
|
{
|
|
qglTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode );
|
|
lastmodes[glState.currenttmu] = mode;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
GL_CullFace
|
|
=================
|
|
*/
|
|
void GL_CullFace (GLenum mode)
|
|
{
|
|
if (glState.cullMode == mode)
|
|
return;
|
|
glState.cullMode = mode;
|
|
qglCullFace(mode);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
GL_PolygonOffset
|
|
=================
|
|
*/
|
|
void GL_PolygonOffset (GLfloat factor, GLfloat units)
|
|
{
|
|
if (glState.offsetFactor == factor && glState.offsetUnits == units)
|
|
return;
|
|
glState.offsetFactor = factor;
|
|
glState.offsetUnits = units;
|
|
qglPolygonOffset(factor, units);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
GL_AlphaFunc
|
|
=================
|
|
*/
|
|
void GL_AlphaFunc (GLenum func, GLclampf ref)
|
|
{
|
|
if (glState.alphaFunc == func && glState.alphaRef == ref)
|
|
return;
|
|
glState.alphaFunc = func;
|
|
glState.alphaRef = ref;
|
|
qglAlphaFunc(func, ref);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
GL_BlendFunc
|
|
=================
|
|
*/
|
|
void GL_BlendFunc (GLenum src, GLenum dst)
|
|
{
|
|
if (glState.blendSrc == src && glState.blendDst == dst)
|
|
return;
|
|
glState.blendSrc = src;
|
|
glState.blendDst = dst;
|
|
qglBlendFunc(src, dst);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
GL_DepthFunc
|
|
=================
|
|
*/
|
|
void GL_DepthFunc (GLenum func)
|
|
{
|
|
if (glState.depthFunc == func)
|
|
return;
|
|
glState.depthFunc = func;
|
|
qglDepthFunc(func);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
GL_DepthMask
|
|
=================
|
|
*/
|
|
void GL_DepthMask (GLboolean mask)
|
|
{
|
|
if (glState.depthMask == mask)
|
|
return;
|
|
glState.depthMask = mask;
|
|
qglDepthMask(mask);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
GL_DepthRange
|
|
=================
|
|
*/
|
|
void GL_DepthRange (GLfloat rMin, GLfloat rMax)
|
|
{
|
|
if (glState.depthMin == rMin && glState.depthMax == rMax)
|
|
return;
|
|
glState.depthMin = rMin;
|
|
glState.depthMax = rMax;
|
|
qglDepthRange (rMin, rMax);
|
|
}
|
|
|
|
|
|
/*
|
|
=============
|
|
GL_LockArrays
|
|
=============
|
|
*/
|
|
void GL_LockArrays (int numVerts)
|
|
{
|
|
if (!glConfig.extCompiledVertArray)
|
|
return;
|
|
if (glState.arraysLocked)
|
|
return;
|
|
|
|
qglLockArraysEXT (0, numVerts);
|
|
glState.arraysLocked = true;
|
|
}
|
|
|
|
|
|
/*
|
|
=============
|
|
GL_UnlockArrays
|
|
=============
|
|
*/
|
|
void GL_UnlockArrays (void)
|
|
{
|
|
if (!glConfig.extCompiledVertArray)
|
|
return;
|
|
if (!glState.arraysLocked)
|
|
return;
|
|
|
|
qglUnlockArraysEXT ();
|
|
glState.arraysLocked = false;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
GL_EnableTexture
|
|
=================
|
|
*/
|
|
void GL_EnableTexture (unsigned tmu)
|
|
{
|
|
if (tmu >= MAX_TEXTURE_UNITS || tmu >= glConfig.max_texunits)
|
|
return;
|
|
|
|
GL_SelectTexture(tmu);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
qglEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
qglTexCoordPointer(2, GL_FLOAT, sizeof(texCoordArray[tmu][0]), texCoordArray[tmu][0]);
|
|
glState.activetmu[tmu] = true;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
GL_DisableTexture
|
|
=================
|
|
*/
|
|
void GL_DisableTexture (unsigned tmu)
|
|
{
|
|
if (tmu >= MAX_TEXTURE_UNITS || tmu >= glConfig.max_texunits)
|
|
return;
|
|
|
|
GL_SelectTexture(tmu);
|
|
qglDisable(GL_TEXTURE_2D);
|
|
qglDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
glState.activetmu[tmu] = false;
|
|
}
|
|
|
|
/*
|
|
=================
|
|
GL_EnableMultitexture
|
|
Only used for world drawing
|
|
=================
|
|
*/
|
|
void GL_EnableMultitexture (qboolean enable)
|
|
{
|
|
if (enable)
|
|
{
|
|
GL_EnableTexture(1);
|
|
GL_TexEnv(GL_REPLACE);
|
|
}
|
|
else
|
|
{
|
|
GL_DisableTexture(1);
|
|
GL_TexEnv(GL_REPLACE);
|
|
}
|
|
GL_SelectTexture(0);
|
|
GL_TexEnv(GL_REPLACE);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
GL_SelectTexture
|
|
=================
|
|
*/
|
|
void GL_SelectTexture (unsigned tmu)
|
|
{
|
|
if (tmu >= MAX_TEXTURE_UNITS || tmu >= glConfig.max_texunits)
|
|
return;
|
|
|
|
if (tmu == glState.currenttmu)
|
|
return;
|
|
|
|
glState.currenttmu = tmu;
|
|
|
|
qglActiveTextureARB(GL_TEXTURE0_ARB+tmu);
|
|
qglClientActiveTextureARB(GL_TEXTURE0_ARB+tmu);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
GL_Bind
|
|
=================
|
|
*/
|
|
void GL_Bind (int texnum)
|
|
{
|
|
extern image_t *r_con_draw_chars;
|
|
|
|
if (r_nobind->integer && r_con_draw_chars) // performance evaluation option
|
|
texnum = r_con_draw_chars->texnum;
|
|
if (glState.currenttextures[glState.currenttmu] == texnum)
|
|
return;
|
|
|
|
glState.currenttextures[glState.currenttmu] = texnum;
|
|
qglBindTexture (GL_TEXTURE_2D, texnum);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
GL_MBind
|
|
=================
|
|
*/
|
|
void GL_MBind (unsigned tmu, int texnum)
|
|
{
|
|
if (tmu >= MAX_TEXTURE_UNITS || tmu >= glConfig.max_texunits)
|
|
return;
|
|
|
|
GL_SelectTexture(tmu);
|
|
|
|
if (glState.currenttextures[tmu] == texnum)
|
|
return;
|
|
|
|
GL_Bind(texnum);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
GL_SetDefaultState
|
|
=================
|
|
*/
|
|
void GL_SetDefaultState (void)
|
|
{
|
|
int i;
|
|
|
|
// Reset the state manager
|
|
glState.texgen = false;
|
|
glState.cullFace = false;
|
|
glState.polygonOffsetFill = false;
|
|
// glState.TexShaderNV = false;
|
|
glState.vertexProgram = false;
|
|
glState.fragmentProgram = false;
|
|
glState.alphaTest = false;
|
|
glState.blend = false;
|
|
glState.stencilTest = false;
|
|
glState.depthTest = false;
|
|
glState.scissorTest = false;
|
|
glState.arraysLocked = false;
|
|
|
|
glState.cullMode = GL_FRONT;
|
|
glState.shadeModelMode = GL_FLAT;
|
|
glState.depthMin = gldepthmin;
|
|
glState.depthMax = gldepthmax;
|
|
glState.offsetFactor = -1;
|
|
glState.offsetUnits = -2;
|
|
glState.alphaFunc = GL_GREATER;
|
|
glState.alphaRef = 0.666;
|
|
glState.blendSrc = GL_SRC_ALPHA;
|
|
glState.blendDst = GL_ONE_MINUS_SRC_ALPHA;
|
|
glState.depthFunc = GL_LEQUAL;
|
|
glState.depthMask = GL_TRUE;
|
|
|
|
// Set default state
|
|
qglDisable(GL_TEXTURE_GEN_S);
|
|
qglDisable(GL_TEXTURE_GEN_T);
|
|
qglDisable(GL_TEXTURE_GEN_R);
|
|
qglEnable(GL_TEXTURE_2D);
|
|
qglDisable(GL_CULL_FACE);
|
|
qglDisable(GL_POLYGON_OFFSET_FILL);
|
|
qglDisable(GL_ALPHA_TEST);
|
|
qglDisable(GL_BLEND);
|
|
qglDisable(GL_STENCIL_TEST);
|
|
qglDisable(GL_DEPTH_TEST);
|
|
qglDisable(GL_SCISSOR_TEST);
|
|
|
|
qglCullFace(GL_FRONT);
|
|
qglShadeModel(GL_FLAT);
|
|
qglPolygonOffset(-1, -2);
|
|
qglAlphaFunc(GL_GREATER, 0.666);
|
|
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
qglDepthFunc(GL_LEQUAL);
|
|
qglDepthMask(GL_TRUE);
|
|
|
|
// qglClearColor (1,0, 0.5, 0.5);
|
|
qglClearColor (r_clearColor[0], r_clearColor[1], r_clearColor[2], r_clearColor[3]);
|
|
qglClearDepth(1.0);
|
|
qglClearStencil(128);
|
|
|
|
qglColor4f (1,1,1,1);
|
|
|
|
qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
|
|
GL_TextureMode (r_texturemode->string);
|
|
|
|
// GL_TextureAlphaMode (r_texturealphamode->string);
|
|
// GL_TextureSolidMode (r_texturesolidmode->string);
|
|
|
|
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
|
|
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
|
|
|
|
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
|
|
|
// Vertex arrays
|
|
qglEnableClientState (GL_TEXTURE_COORD_ARRAY);
|
|
qglEnableClientState (GL_VERTEX_ARRAY);
|
|
qglEnableClientState (GL_COLOR_ARRAY);
|
|
|
|
qglTexCoordPointer (2, GL_FLOAT, sizeof(texCoordArray[0][0]), texCoordArray[0][0]);
|
|
qglVertexPointer (3, GL_FLOAT, sizeof(vertexArray[0]), vertexArray[0]);
|
|
qglColorPointer (4, GL_FLOAT, sizeof(colorArray[0]), colorArray[0]);
|
|
// end vertex arrays
|
|
|
|
glState.activetmu[0] = true;
|
|
for (i=1; i<MAX_TEXTURE_UNITS; i++)
|
|
glState.activetmu[i] = false;
|
|
|
|
GL_TexEnv (GL_REPLACE);
|
|
|
|
GL_UpdateSwapInterval();
|
|
}
|