forked from a1batross/Paranoia2_original
373 lines
7.9 KiB
C++
373 lines
7.9 KiB
C++
//
|
|
// written by BUzer for HL: Paranoia modification
|
|
//
|
|
// 2006
|
|
|
|
#include "hud.h"
|
|
#include "cl_util.h"
|
|
#include "gl_local.h"
|
|
#include "gl_shader.h"
|
|
|
|
#define MAX_CLIP_VERTS 128 // skybox clip vertices
|
|
|
|
static const int r_skyTexOrder[6] = { 0, 2, 1, 3, 4, 5 };
|
|
|
|
static const Vector skyclip[6] =
|
|
{
|
|
Vector( 1, 1, 0 ),
|
|
Vector( 1, -1, 0 ),
|
|
Vector( 0, -1, 1 ),
|
|
Vector( 0, 1, 1 ),
|
|
Vector( 1, 0, 1 ),
|
|
Vector( -1, 0, 1 )
|
|
};
|
|
|
|
// 1 = s, 2 = t, 3 = 2048
|
|
static const int st_to_vec[6][3] =
|
|
{
|
|
{ 3, -1, 2 },
|
|
{ -3, 1, 2 },
|
|
{ 1, 3, 2 },
|
|
{ -1, -3, 2 },
|
|
{ -2, -1, 3 }, // 0 degrees yaw, look straight up
|
|
{ 2, -1, -3 } // look straight down
|
|
};
|
|
|
|
// s = [0]/[2], t = [1]/[2]
|
|
static const int vec_to_st[6][3] =
|
|
{
|
|
{ -2, 3, 1 },
|
|
{ 2, 3, -1 },
|
|
{ 1, 3, 2 },
|
|
{ -1, 3, -2 },
|
|
{ -2, -1, 3 },
|
|
{ -2, 1, -3 }
|
|
};
|
|
|
|
static void DrawSkyPolygon( int nump, Vector vecs[] )
|
|
{
|
|
int i, j, axis;
|
|
float s, t, dv;
|
|
Vector v, av;
|
|
|
|
// decide which face it maps to
|
|
v = g_vecZero;
|
|
|
|
for( i = 0; i < nump; i++ )
|
|
v += vecs[i];
|
|
|
|
av[0] = fabs( v[0] );
|
|
av[1] = fabs( v[1] );
|
|
av[2] = fabs( v[2] );
|
|
|
|
if( av[0] > av[1] && av[0] > av[2] )
|
|
axis = (v[0] < 0) ? 1 : 0;
|
|
else if( av[1] > av[2] && av[1] > av[0] )
|
|
axis = (v[1] < 0) ? 3 : 2;
|
|
else axis = (v[2] < 0) ? 5 : 4;
|
|
|
|
// project new texture coords
|
|
for( i = 0; i < nump; i++ )
|
|
{
|
|
j = vec_to_st[axis][2];
|
|
dv = (j > 0) ? (vecs[i])[j-1] : -(vecs[i])[-j-1];
|
|
|
|
j = vec_to_st[axis][0];
|
|
s = (j < 0) ? -vecs[i][-j-1] / dv : (vecs[i])[j-1] / dv;
|
|
|
|
j = vec_to_st[axis][1];
|
|
t = (j < 0) ? -(vecs[i])[-j-1] / dv : (vecs[i])[j-1] / dv;
|
|
|
|
if( s < RI->view.skyMins[0][axis] ) RI->view.skyMins[0][axis] = s;
|
|
if( t < RI->view.skyMins[1][axis] ) RI->view.skyMins[1][axis] = t;
|
|
if( s > RI->view.skyMaxs[0][axis] ) RI->view.skyMaxs[0][axis] = s;
|
|
if( t > RI->view.skyMaxs[1][axis] ) RI->view.skyMaxs[1][axis] = t;
|
|
}
|
|
}
|
|
|
|
/*
|
|
==============
|
|
ClipSkyPolygon
|
|
==============
|
|
*/
|
|
static void ClipSkyPolygon( int nump, Vector vecs[], int stage )
|
|
{
|
|
bool front, back;
|
|
float dists[MAX_CLIP_VERTS + 1];
|
|
int sides[MAX_CLIP_VERTS + 1];
|
|
Vector newv[2][MAX_CLIP_VERTS + 1];
|
|
int newc[2];
|
|
float d, e;
|
|
int i;
|
|
|
|
if( nump > MAX_CLIP_VERTS )
|
|
HOST_ERROR( "ClipSkyPolygon: MAX_CLIP_VERTS\n" );
|
|
loc1:
|
|
if( stage == 6 )
|
|
{
|
|
// fully clipped, so draw it
|
|
DrawSkyPolygon( nump, vecs );
|
|
return;
|
|
}
|
|
|
|
front = back = false;
|
|
const Vector &norm = skyclip[stage];
|
|
|
|
for( i = 0; i < nump; i++ )
|
|
{
|
|
d = DotProduct( vecs[i], norm );
|
|
if( d > ON_EPSILON )
|
|
{
|
|
front = true;
|
|
sides[i] = SIDE_FRONT;
|
|
}
|
|
else if( d < -ON_EPSILON )
|
|
{
|
|
back = true;
|
|
sides[i] = SIDE_BACK;
|
|
}
|
|
else
|
|
{
|
|
sides[i] = SIDE_ON;
|
|
}
|
|
dists[i] = d;
|
|
}
|
|
|
|
if( !front || !back )
|
|
{
|
|
// not clipped
|
|
stage++;
|
|
goto loc1;
|
|
}
|
|
|
|
// clip it
|
|
sides[i] = sides[0];
|
|
dists[i] = dists[0];
|
|
vecs[i] = vecs[0];
|
|
newc[0] = newc[1] = 0;
|
|
|
|
for( i = 0; i < nump; i++ )
|
|
{
|
|
switch( sides[i] )
|
|
{
|
|
case SIDE_FRONT:
|
|
newv[0][newc[0]] = vecs[i];
|
|
newc[0]++;
|
|
break;
|
|
case SIDE_BACK:
|
|
newv[1][newc[1]] = vecs[i];
|
|
newc[1]++;
|
|
break;
|
|
case SIDE_ON:
|
|
newv[0][newc[0]] = vecs[i];
|
|
newc[0]++;
|
|
newv[1][newc[1]] = vecs[i];
|
|
newc[1]++;
|
|
break;
|
|
}
|
|
|
|
if( sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i] )
|
|
continue;
|
|
|
|
d = dists[i] / ( dists[i] - dists[i+1] );
|
|
|
|
for( int j = 0; j < 3; j++ )
|
|
{
|
|
e = (vecs[i])[j] + d * ( (vecs[i+1])[j] - (vecs[i])[j] );
|
|
newv[0][newc[0]][j] = e;
|
|
newv[1][newc[1]][j] = e;
|
|
}
|
|
newc[0]++;
|
|
newc[1]++;
|
|
}
|
|
|
|
// continue
|
|
ClipSkyPolygon( newc[0], newv[0], stage + 1 );
|
|
ClipSkyPolygon( newc[1], newv[1], stage + 1 );
|
|
}
|
|
|
|
static void MakeSkyVec( float s, float t, int axis )
|
|
{
|
|
int j, k, farclip;
|
|
Vector v, b;
|
|
|
|
farclip = RI->view.farClip;
|
|
|
|
b[0] = s * (farclip >> 1);
|
|
b[1] = t * (farclip >> 1);
|
|
b[2] = (farclip >> 1);
|
|
|
|
for( j = 0; j < 3; j++ )
|
|
{
|
|
k = st_to_vec[axis][j];
|
|
v[j] = (k < 0) ? -b[-k-1] : b[k-1];
|
|
v[j] += GetVieworg()[j];
|
|
}
|
|
|
|
// avoid bilerp seam
|
|
s = (s + 1.0f) * 0.5f;
|
|
t = (t + 1.0f) * 0.5f;
|
|
|
|
if( s < ( 1.0f / 512.0f ))
|
|
s = (1.0f / 512.0f);
|
|
else if( s > ( 511.0f / 512.0f ))
|
|
s = (511.0f / 512.0f);
|
|
if( t < ( 1.0f / 512.0f ))
|
|
t = (1.0f / 512.0f);
|
|
else if( t > ( 511.0f / 512.0f ))
|
|
t = (511.0f / 512.0f);
|
|
|
|
t = 1.0f - t;
|
|
|
|
pglTexCoord2f( s, t );
|
|
pglVertex3fv( v );
|
|
}
|
|
|
|
/*
|
|
=================
|
|
R_AddSkyBoxSurface
|
|
=================
|
|
*/
|
|
void R_AddSkyBoxSurface( msurface_t *fa )
|
|
{
|
|
Vector verts[MAX_CLIP_VERTS];
|
|
|
|
// calculate vertex values for sky box
|
|
for( glpoly_t *p = fa->polys; p; p = p->next )
|
|
{
|
|
if( p->numverts >= MAX_CLIP_VERTS )
|
|
HOST_ERROR( "R_AddSkyBoxSurface: numverts >= MAX_CLIP_VERTS\n" );
|
|
|
|
for( int i = 0; i < p->numverts; i++ )
|
|
{
|
|
verts[i][0] = p->verts[i][0] - GetVieworg().x;
|
|
verts[i][1] = p->verts[i][1] - GetVieworg().y;
|
|
verts[i][2] = p->verts[i][2] - GetVieworg().z;
|
|
}
|
|
|
|
ClipSkyPolygon( p->numverts, verts, 0 );
|
|
}
|
|
}
|
|
|
|
static void GL_DrawSkySide( int skyside )
|
|
{
|
|
pglBegin( GL_QUADS );
|
|
MakeSkyVec( RI->view.skyMins[0][skyside], RI->view.skyMins[1][skyside], skyside );
|
|
MakeSkyVec( RI->view.skyMins[0][skyside], RI->view.skyMaxs[1][skyside], skyside );
|
|
MakeSkyVec( RI->view.skyMaxs[0][skyside], RI->view.skyMaxs[1][skyside], skyside );
|
|
MakeSkyVec( RI->view.skyMaxs[0][skyside], RI->view.skyMins[1][skyside], skyside );
|
|
pglEnd();
|
|
}
|
|
|
|
static void GL_DrawSkySide( word hProgram, int skyside )
|
|
{
|
|
if( hProgram <= 0 )
|
|
{
|
|
GL_BindShader( NULL );
|
|
GL_BindTexture( GL_TEXTURE0, tr.skyboxTextures[r_skyTexOrder[skyside]] );
|
|
GL_DrawSkySide( skyside );
|
|
return; // old method
|
|
}
|
|
|
|
if( RI->currentshader != &glsl_programs[hProgram] )
|
|
{
|
|
// force to bind new shader
|
|
GL_BindShader( &glsl_programs[hProgram] );
|
|
}
|
|
|
|
Vector sky_color = (tr.sun_light_enabled) ? tr.sun_diffuse : tr.sky_ambient * (1.0f/128.0f) * tr.diffuseFactor;
|
|
Vector sky_vec = tr.sky_normal.Normalize();
|
|
glsl_program_t *shader = RI->currentshader;
|
|
|
|
ColorNormalize( sky_color, sky_color );
|
|
|
|
// setup specified uniforms (and texture bindings)
|
|
for( int i = 0; i < shader->numUniforms; i++ )
|
|
{
|
|
uniform_t *u = &shader->uniforms[i];
|
|
|
|
switch( u->type )
|
|
{
|
|
case UT_COLORMAP:
|
|
u->SetValue( tr.skyboxTextures[r_skyTexOrder[skyside]] );
|
|
break;
|
|
case UT_LIGHTDIR:
|
|
u->SetValue( sky_vec.x, sky_vec.y, sky_vec.z );
|
|
break;
|
|
case UT_LIGHTDIFFUSE:
|
|
u->SetValue( sky_color.x, sky_color.y, sky_color.z );
|
|
break;
|
|
case UT_VIEWORIGIN:
|
|
u->SetValue( GetVieworg().x, GetVieworg().y, GetVieworg().z );
|
|
break;
|
|
case UT_FOGPARAMS:
|
|
u->SetValue( tr.fogColor[0], tr.fogColor[1], tr.fogColor[2], tr.fogDensity * 0.5f );
|
|
break;
|
|
case UT_ZFAR:
|
|
u->SetValue( RI->view.farClip );
|
|
break;
|
|
default:
|
|
ALERT( at_error, "%s: unhandled uniform %s\n", RI->currentshader->name, u->name );
|
|
break;
|
|
}
|
|
}
|
|
|
|
GL_DrawSkySide( skyside );
|
|
}
|
|
|
|
/*
|
|
==============
|
|
R_DrawSkybox
|
|
==============
|
|
*/
|
|
void R_DrawSkyBox( void )
|
|
{
|
|
bool drawSun = true;
|
|
float fogDenstity = tr.fogDensity;
|
|
word hSkyShader = 0;
|
|
int i;
|
|
|
|
if( !FBitSet( RI->view.flags, RF_SKYVISIBLE ))
|
|
return;
|
|
|
|
GL_DepthRange( 0.9f, 1.0f );
|
|
GL_DepthMask( GL_FALSE );
|
|
GL_Blend( GL_FALSE );
|
|
GL_AlphaTest( GL_FALSE );
|
|
|
|
// clipplane cut the sky if drawing through mirror. Disable it
|
|
GL_ClipPlane( false );
|
|
|
|
int type = tr.sun_light_enabled ? 1 : 0;
|
|
|
|
if( FBitSet( RI->params, RP_SKYVIEW ) || ( FBitSet( RI->params, RP_WATERPASS ) && CVAR_TO_BOOL( cv_specular )))
|
|
drawSun = false;
|
|
|
|
// disable sky fogging while underwater
|
|
if( tr.waterlevel >= 3 || FBitSet( RI->params, RP_SKYVIEW ))
|
|
fogDenstity = 0.0f;
|
|
|
|
// make sure what light_environment is present
|
|
if( tr.sky_normal != g_vecZero && drawSun )
|
|
{
|
|
if( FBitSet( RI->params, RP_DEFERREDSCENE ))
|
|
hSkyShader = tr.defSceneSky;
|
|
else if( FBitSet( RI->params, RP_DEFERREDLIGHT ))
|
|
hSkyShader = tr.defLightSky;
|
|
else hSkyShader = tr.skyboxEnv[type];
|
|
}
|
|
|
|
for( i = 0; i < 6; i++ )
|
|
{
|
|
if( RI->view.skyMins[0][i] >= RI->view.skyMaxs[0][i] || RI->view.skyMins[1][i] >= RI->view.skyMaxs[1][i] )
|
|
continue;
|
|
|
|
GL_DrawSkySide( hSkyShader, i );
|
|
}
|
|
|
|
GL_ClipPlane( true );
|
|
GL_DepthMask( GL_TRUE );
|
|
|
|
// back to normal depth range
|
|
GL_DepthRange( gldepthmin, gldepthmax );
|
|
} |