diff options
author | zakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2005-08-26 17:39:27 +0000 |
---|---|---|
committer | zakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea> | 2005-08-26 17:39:27 +0000 |
commit | 6bf20c78f5b69d40bcc4931df93d29198435ab67 (patch) | |
tree | e3eda937a05d7db42de725b7013bd0344b987f34 /code/renderer/tr_sky.c | |
parent | 872d4d7f55af706737ffb361bb76ad13e7496770 (diff) | |
download | ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.tar.gz ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.zip |
newlines fixed
git-svn-id: svn://svn.icculus.org/quake3/trunk@6 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'code/renderer/tr_sky.c')
-rwxr-xr-x | code/renderer/tr_sky.c | 1690 |
1 files changed, 845 insertions, 845 deletions
diff --git a/code/renderer/tr_sky.c b/code/renderer/tr_sky.c index 0f8aa24..1f92378 100755 --- a/code/renderer/tr_sky.c +++ b/code/renderer/tr_sky.c @@ -1,845 +1,845 @@ -/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena 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 III Arena 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// tr_sky.c
-#include "tr_local.h"
-
-#define SKY_SUBDIVISIONS 8
-#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2)
-
-static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
-static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
-
-/*
-===================================================================================
-
-POLYGON TO BOX SIDE PROJECTION
-
-===================================================================================
-*/
-
-static vec3_t sky_clip[6] =
-{
- {1,1,0},
- {1,-1,0},
- {0,-1,1},
- {0,1,1},
- {1,0,1},
- {-1,0,1}
-};
-
-static float sky_mins[2][6], sky_maxs[2][6];
-static float sky_min, sky_max;
-
-/*
-================
-AddSkyPolygon
-================
-*/
-static void AddSkyPolygon (int nump, vec3_t vecs)
-{
- int i,j;
- vec3_t v, av;
- float s, t, dv;
- int axis;
- float *vp;
- // s = [0]/[2], t = [1]/[2]
- static int vec_to_st[6][3] =
- {
- {-2,3,1},
- {2,3,-1},
-
- {1,3,2},
- {-1,3,-2},
-
- {-2,-1,3},
- {-2,1,-3}
-
- // {-1,2,3},
- // {1,2,-3}
- };
-
- // decide which face it maps to
- VectorCopy (vec3_origin, v);
- for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
- {
- VectorAdd (vp, v, v);
- }
- av[0] = fabs(v[0]);
- av[1] = fabs(v[1]);
- av[2] = fabs(v[2]);
- if (av[0] > av[1] && av[0] > av[2])
- {
- if (v[0] < 0)
- axis = 1;
- else
- axis = 0;
- }
- else if (av[1] > av[2] && av[1] > av[0])
- {
- if (v[1] < 0)
- axis = 3;
- else
- axis = 2;
- }
- else
- {
- if (v[2] < 0)
- axis = 5;
- else
- axis = 4;
- }
-
- // project new texture coords
- for (i=0 ; i<nump ; i++, vecs+=3)
- {
- j = vec_to_st[axis][2];
- if (j > 0)
- dv = vecs[j - 1];
- else
- dv = -vecs[-j - 1];
- if (dv < 0.001)
- continue; // don't divide by zero
- j = vec_to_st[axis][0];
- if (j < 0)
- s = -vecs[-j -1] / dv;
- else
- s = vecs[j-1] / dv;
- j = vec_to_st[axis][1];
- if (j < 0)
- t = -vecs[-j -1] / dv;
- else
- t = vecs[j-1] / dv;
-
- if (s < sky_mins[0][axis])
- sky_mins[0][axis] = s;
- if (t < sky_mins[1][axis])
- sky_mins[1][axis] = t;
- if (s > sky_maxs[0][axis])
- sky_maxs[0][axis] = s;
- if (t > sky_maxs[1][axis])
- sky_maxs[1][axis] = t;
- }
-}
-
-#define ON_EPSILON 0.1f // point on plane side epsilon
-#define MAX_CLIP_VERTS 64
-/*
-================
-ClipSkyPolygon
-================
-*/
-static void ClipSkyPolygon (int nump, vec3_t vecs, int stage)
-{
- float *norm;
- float *v;
- qboolean front, back;
- float d, e;
- float dists[MAX_CLIP_VERTS];
- int sides[MAX_CLIP_VERTS];
- vec3_t newv[2][MAX_CLIP_VERTS];
- int newc[2];
- int i, j;
-
- if (nump > MAX_CLIP_VERTS-2)
- ri.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS");
- if (stage == 6)
- { // fully clipped, so draw it
- AddSkyPolygon (nump, vecs);
- return;
- }
-
- front = back = qfalse;
- norm = sky_clip[stage];
- for (i=0, v = vecs ; i<nump ; i++, v+=3)
- {
- d = DotProduct (v, norm);
- if (d > ON_EPSILON)
- {
- front = qtrue;
- sides[i] = SIDE_FRONT;
- }
- else if (d < -ON_EPSILON)
- {
- back = qtrue;
- sides[i] = SIDE_BACK;
- }
- else
- sides[i] = SIDE_ON;
- dists[i] = d;
- }
-
- if (!front || !back)
- { // not clipped
- ClipSkyPolygon (nump, vecs, stage+1);
- return;
- }
-
- // clip it
- sides[i] = sides[0];
- dists[i] = dists[0];
- VectorCopy (vecs, (vecs+(i*3)) );
- newc[0] = newc[1] = 0;
-
- for (i=0, v = vecs ; i<nump ; i++, v+=3)
- {
- switch (sides[i])
- {
- case SIDE_FRONT:
- VectorCopy (v, newv[0][newc[0]]);
- newc[0]++;
- break;
- case SIDE_BACK:
- VectorCopy (v, newv[1][newc[1]]);
- newc[1]++;
- break;
- case SIDE_ON:
- VectorCopy (v, newv[0][newc[0]]);
- newc[0]++;
- VectorCopy (v, newv[1][newc[1]]);
- 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 (j=0 ; j<3 ; j++)
- {
- e = v[j] + d*(v[j+3] - v[j]);
- newv[0][newc[0]][j] = e;
- newv[1][newc[1]][j] = e;
- }
- newc[0]++;
- newc[1]++;
- }
-
- // continue
- ClipSkyPolygon (newc[0], newv[0][0], stage+1);
- ClipSkyPolygon (newc[1], newv[1][0], stage+1);
-}
-
-/*
-==============
-ClearSkyBox
-==============
-*/
-static void ClearSkyBox (void) {
- int i;
-
- for (i=0 ; i<6 ; i++) {
- sky_mins[0][i] = sky_mins[1][i] = 9999;
- sky_maxs[0][i] = sky_maxs[1][i] = -9999;
- }
-}
-
-/*
-================
-RB_ClipSkyPolygons
-================
-*/
-void RB_ClipSkyPolygons( shaderCommands_t *input )
-{
- vec3_t p[5]; // need one extra point for clipping
- int i, j;
-
- ClearSkyBox();
-
- for ( i = 0; i < input->numIndexes; i += 3 )
- {
- for (j = 0 ; j < 3 ; j++)
- {
- VectorSubtract( input->xyz[input->indexes[i+j]],
- backEnd.viewParms.or.origin,
- p[j] );
- }
- ClipSkyPolygon( 3, p[0], 0 );
- }
-}
-
-/*
-===================================================================================
-
-CLOUD VERTEX GENERATION
-
-===================================================================================
-*/
-
-/*
-** MakeSkyVec
-**
-** Parms: s, t range from -1 to 1
-*/
-static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ )
-{
- // 1 = s, 2 = t, 3 = 2048
- static 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
- };
-
- vec3_t b;
- int j, k;
- float boxSize;
-
- boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
- b[0] = s*boxSize;
- b[1] = t*boxSize;
- b[2] = boxSize;
-
- for (j=0 ; j<3 ; j++)
- {
- k = st_to_vec[axis][j];
- if (k < 0)
- {
- outXYZ[j] = -b[-k - 1];
- }
- else
- {
- outXYZ[j] = b[k - 1];
- }
- }
-
- // avoid bilerp seam
- s = (s+1)*0.5;
- t = (t+1)*0.5;
- if (s < sky_min)
- {
- s = sky_min;
- }
- else if (s > sky_max)
- {
- s = sky_max;
- }
-
- if (t < sky_min)
- {
- t = sky_min;
- }
- else if (t > sky_max)
- {
- t = sky_max;
- }
-
- t = 1.0 - t;
-
-
- if ( outSt )
- {
- outSt[0] = s;
- outSt[1] = t;
- }
-}
-
-static int sky_texorder[6] = {0,2,1,3,4,5};
-static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
-static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
-
-static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )
-{
- int s, t;
-
- GL_Bind( image );
-
- for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
- {
- qglBegin( GL_TRIANGLE_STRIP );
-
- for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
- {
- qglTexCoord2fv( s_skyTexCoords[t][s] );
- qglVertex3fv( s_skyPoints[t][s] );
-
- qglTexCoord2fv( s_skyTexCoords[t+1][s] );
- qglVertex3fv( s_skyPoints[t+1][s] );
- }
-
- qglEnd();
- }
-}
-
-static void DrawSkyBox( shader_t *shader )
-{
- int i;
-
- sky_min = 0;
- sky_max = 1;
-
- Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) );
-
- for (i=0 ; i<6 ; i++)
- {
- int sky_mins_subd[2], sky_maxs_subd[2];
- int s, t;
-
- sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
-
- if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
- ( sky_mins[1][i] >= sky_maxs[1][i] ) )
- {
- continue;
- }
-
- sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS;
- sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS;
- sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS;
- sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS;
-
- if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
- if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
-
- if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
- if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
-
- //
- // iterate through the subdivisions
- //
- for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
- {
- for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
- {
- MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- i,
- s_skyTexCoords[t][s],
- s_skyPoints[t][s] );
- }
- }
-
- DrawSkySide( shader->sky.outerbox[sky_texorder[i]],
- sky_mins_subd,
- sky_maxs_subd );
- }
-
-}
-
-static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes )
-{
- int s, t;
- int vertexStart = tess.numVertexes;
- int tHeight, sWidth;
-
- tHeight = maxs[1] - mins[1] + 1;
- sWidth = maxs[0] - mins[0] + 1;
-
- for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
- {
- for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
- {
- VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0];
- tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1];
-
- tess.numVertexes++;
-
- if ( tess.numVertexes >= SHADER_MAX_VERTEXES )
- {
- ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()\n" );
- }
- }
- }
-
- // only add indexes for one pass, otherwise it would draw multiple times for each pass
- if ( addIndexes ) {
- for ( t = 0; t < tHeight-1; t++ )
- {
- for ( s = 0; s < sWidth-1; s++ )
- {
- tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth );
- tess.numIndexes++;
- tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
- tess.numIndexes++;
- tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
- tess.numIndexes++;
-
- tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
- tess.numIndexes++;
- tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth );
- tess.numIndexes++;
- tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
- tess.numIndexes++;
- }
- }
- }
-}
-
-static void FillCloudBox( const shader_t *shader, int stage )
-{
- int i;
-
- for ( i =0; i < 6; i++ )
- {
- int sky_mins_subd[2], sky_maxs_subd[2];
- int s, t;
- float MIN_T;
-
- if ( 1 ) // FIXME? shader->sky.fullClouds )
- {
- MIN_T = -HALF_SKY_SUBDIVISIONS;
-
- // still don't want to draw the bottom, even if fullClouds
- if ( i == 5 )
- continue;
- }
- else
- {
- switch( i )
- {
- case 0:
- case 1:
- case 2:
- case 3:
- MIN_T = -1;
- break;
- case 5:
- // don't draw clouds beneath you
- continue;
- case 4: // top
- default:
- MIN_T = -HALF_SKY_SUBDIVISIONS;
- break;
- }
- }
-
- sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
- sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
-
- if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
- ( sky_mins[1][i] >= sky_maxs[1][i] ) )
- {
- continue;
- }
-
- sky_mins_subd[0] = myftol( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS );
- sky_mins_subd[1] = myftol( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS );
- sky_maxs_subd[0] = myftol( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS );
- sky_maxs_subd[1] = myftol( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS );
-
- if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
- if ( sky_mins_subd[1] < MIN_T )
- sky_mins_subd[1] = MIN_T;
- else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS )
- sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
-
- if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
- else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
- if ( sky_maxs_subd[1] < MIN_T )
- sky_maxs_subd[1] = MIN_T;
- else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS )
- sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
-
- //
- // iterate through the subdivisions
- //
- for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
- {
- for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
- {
- MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- i,
- NULL,
- s_skyPoints[t][s] );
-
- s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0];
- s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1];
- }
- }
-
- // only add indexes for first stage
- FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) );
- }
-}
-
-/*
-** R_BuildCloudData
-*/
-void R_BuildCloudData( shaderCommands_t *input )
-{
- int i;
- shader_t *shader;
-
- shader = input->shader;
-
- assert( shader->isSky );
-
- sky_min = 1.0 / 256.0f; // FIXME: not correct?
- sky_max = 255.0 / 256.0f;
-
- // set up for drawing
- tess.numIndexes = 0;
- tess.numVertexes = 0;
-
- if ( input->shader->sky.cloudHeight )
- {
- for ( i = 0; i < MAX_SHADER_STAGES; i++ )
- {
- if ( !tess.xstages[i] ) {
- break;
- }
- FillCloudBox( input->shader, i );
- }
- }
-}
-
-/*
-** R_InitSkyTexCoords
-** Called when a sky shader is parsed
-*/
-#define SQR( a ) ((a)*(a))
-void R_InitSkyTexCoords( float heightCloud )
-{
- int i, s, t;
- float radiusWorld = 4096;
- float p;
- float sRad, tRad;
- vec3_t skyVec;
- vec3_t v;
-
- // init zfar so MakeSkyVec works even though
- // a world hasn't been bounded
- backEnd.viewParms.zFar = 1024;
-
- for ( i = 0; i < 6; i++ )
- {
- for ( t = 0; t <= SKY_SUBDIVISIONS; t++ )
- {
- for ( s = 0; s <= SKY_SUBDIVISIONS; s++ )
- {
- // compute vector from view origin to sky side integral point
- MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
- i,
- NULL,
- skyVec );
-
- // compute parametric value 'p' that intersects with cloud layer
- p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) *
- ( -2 * skyVec[2] * radiusWorld +
- 2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) +
- 2 * SQR( skyVec[0] ) * radiusWorld * heightCloud +
- SQR( skyVec[0] ) * SQR( heightCloud ) +
- 2 * SQR( skyVec[1] ) * radiusWorld * heightCloud +
- SQR( skyVec[1] ) * SQR( heightCloud ) +
- 2 * SQR( skyVec[2] ) * radiusWorld * heightCloud +
- SQR( skyVec[2] ) * SQR( heightCloud ) ) );
-
- s_cloudTexP[i][t][s] = p;
-
- // compute intersection point based on p
- VectorScale( skyVec, p, v );
- v[2] += radiusWorld;
-
- // compute vector from world origin to intersection point 'v'
- VectorNormalize( v );
-
- sRad = Q_acos( v[0] );
- tRad = Q_acos( v[1] );
-
- s_cloudTexCoords[i][t][s][0] = sRad;
- s_cloudTexCoords[i][t][s][1] = tRad;
- }
- }
- }
-}
-
-//======================================================================================
-
-/*
-** RB_DrawSun
-*/
-void RB_DrawSun( void ) {
- float size;
- float dist;
- vec3_t origin, vec1, vec2;
- vec3_t temp;
-
- if ( !backEnd.skyRenderedThisView ) {
- return;
- }
- if ( !r_drawSun->integer ) {
- return;
- }
- qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
- qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
-
- dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3)
- size = dist * 0.4;
-
- VectorScale( tr.sunDirection, dist, origin );
- PerpendicularVector( vec1, tr.sunDirection );
- CrossProduct( tr.sunDirection, vec1, vec2 );
-
- VectorScale( vec1, size, vec1 );
- VectorScale( vec2, size, vec2 );
-
- // farthest depth range
- qglDepthRange( 1.0, 1.0 );
-
- // FIXME: use quad stamp
- RB_BeginSurface( tr.sunShader, tess.fogNum );
- VectorCopy( origin, temp );
- VectorSubtract( temp, vec1, temp );
- VectorSubtract( temp, vec2, temp );
- VectorCopy( temp, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = 255;
- tess.vertexColors[tess.numVertexes][1] = 255;
- tess.vertexColors[tess.numVertexes][2] = 255;
- tess.numVertexes++;
-
- VectorCopy( origin, temp );
- VectorAdd( temp, vec1, temp );
- VectorSubtract( temp, vec2, temp );
- VectorCopy( temp, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 0;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = 255;
- tess.vertexColors[tess.numVertexes][1] = 255;
- tess.vertexColors[tess.numVertexes][2] = 255;
- tess.numVertexes++;
-
- VectorCopy( origin, temp );
- VectorAdd( temp, vec1, temp );
- VectorAdd( temp, vec2, temp );
- VectorCopy( temp, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 1;
- tess.texCoords[tess.numVertexes][0][1] = 1;
- tess.vertexColors[tess.numVertexes][0] = 255;
- tess.vertexColors[tess.numVertexes][1] = 255;
- tess.vertexColors[tess.numVertexes][2] = 255;
- tess.numVertexes++;
-
- VectorCopy( origin, temp );
- VectorSubtract( temp, vec1, temp );
- VectorAdd( temp, vec2, temp );
- VectorCopy( temp, tess.xyz[tess.numVertexes] );
- tess.texCoords[tess.numVertexes][0][0] = 1;
- tess.texCoords[tess.numVertexes][0][1] = 0;
- tess.vertexColors[tess.numVertexes][0] = 255;
- tess.vertexColors[tess.numVertexes][1] = 255;
- tess.vertexColors[tess.numVertexes][2] = 255;
- tess.numVertexes++;
-
- tess.indexes[tess.numIndexes++] = 0;
- tess.indexes[tess.numIndexes++] = 1;
- tess.indexes[tess.numIndexes++] = 2;
- tess.indexes[tess.numIndexes++] = 0;
- tess.indexes[tess.numIndexes++] = 2;
- tess.indexes[tess.numIndexes++] = 3;
-
- RB_EndSurface();
-
- // back to normal depth range
- qglDepthRange( 0.0, 1.0 );
-}
-
-
-
-
-/*
-================
-RB_StageIteratorSky
-
-All of the visible sky triangles are in tess
-
-Other things could be stuck in here, like birds in the sky, etc
-================
-*/
-void RB_StageIteratorSky( void ) {
- if ( r_fastsky->integer ) {
- return;
- }
-
- // go through all the polygons and project them onto
- // the sky box to see which blocks on each side need
- // to be drawn
- RB_ClipSkyPolygons( &tess );
-
- // r_showsky will let all the sky blocks be drawn in
- // front of everything to allow developers to see how
- // much sky is getting sucked in
- if ( r_showsky->integer ) {
- qglDepthRange( 0.0, 0.0 );
- } else {
- qglDepthRange( 1.0, 1.0 );
- }
-
- // draw the outer skybox
- if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {
- qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );
-
- qglPushMatrix ();
- GL_State( 0 );
- qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
-
- DrawSkyBox( tess.shader );
-
- qglPopMatrix();
- }
-
- // generate the vertexes for all the clouds, which will be drawn
- // by the generic shader routine
- R_BuildCloudData( &tess );
-
- RB_StageIteratorGeneric();
-
- // draw the inner skybox
-
-
- // back to normal depth range
- qglDepthRange( 0.0, 1.0 );
-
- // note that sky was drawn so we will draw a sun later
- backEnd.skyRenderedThisView = qtrue;
-}
-
+/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena 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 III Arena 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 Foobar; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +// tr_sky.c +#include "tr_local.h" + +#define SKY_SUBDIVISIONS 8 +#define HALF_SKY_SUBDIVISIONS (SKY_SUBDIVISIONS/2) + +static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; +static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; + +/* +=================================================================================== + +POLYGON TO BOX SIDE PROJECTION + +=================================================================================== +*/ + +static vec3_t sky_clip[6] = +{ + {1,1,0}, + {1,-1,0}, + {0,-1,1}, + {0,1,1}, + {1,0,1}, + {-1,0,1} +}; + +static float sky_mins[2][6], sky_maxs[2][6]; +static float sky_min, sky_max; + +/* +================ +AddSkyPolygon +================ +*/ +static void AddSkyPolygon (int nump, vec3_t vecs) +{ + int i,j; + vec3_t v, av; + float s, t, dv; + int axis; + float *vp; + // s = [0]/[2], t = [1]/[2] + static int vec_to_st[6][3] = + { + {-2,3,1}, + {2,3,-1}, + + {1,3,2}, + {-1,3,-2}, + + {-2,-1,3}, + {-2,1,-3} + + // {-1,2,3}, + // {1,2,-3} + }; + + // decide which face it maps to + VectorCopy (vec3_origin, v); + for (i=0, vp=vecs ; i<nump ; i++, vp+=3) + { + VectorAdd (vp, v, v); + } + av[0] = fabs(v[0]); + av[1] = fabs(v[1]); + av[2] = fabs(v[2]); + if (av[0] > av[1] && av[0] > av[2]) + { + if (v[0] < 0) + axis = 1; + else + axis = 0; + } + else if (av[1] > av[2] && av[1] > av[0]) + { + if (v[1] < 0) + axis = 3; + else + axis = 2; + } + else + { + if (v[2] < 0) + axis = 5; + else + axis = 4; + } + + // project new texture coords + for (i=0 ; i<nump ; i++, vecs+=3) + { + j = vec_to_st[axis][2]; + if (j > 0) + dv = vecs[j - 1]; + else + dv = -vecs[-j - 1]; + if (dv < 0.001) + continue; // don't divide by zero + j = vec_to_st[axis][0]; + if (j < 0) + s = -vecs[-j -1] / dv; + else + s = vecs[j-1] / dv; + j = vec_to_st[axis][1]; + if (j < 0) + t = -vecs[-j -1] / dv; + else + t = vecs[j-1] / dv; + + if (s < sky_mins[0][axis]) + sky_mins[0][axis] = s; + if (t < sky_mins[1][axis]) + sky_mins[1][axis] = t; + if (s > sky_maxs[0][axis]) + sky_maxs[0][axis] = s; + if (t > sky_maxs[1][axis]) + sky_maxs[1][axis] = t; + } +} + +#define ON_EPSILON 0.1f // point on plane side epsilon +#define MAX_CLIP_VERTS 64 +/* +================ +ClipSkyPolygon +================ +*/ +static void ClipSkyPolygon (int nump, vec3_t vecs, int stage) +{ + float *norm; + float *v; + qboolean front, back; + float d, e; + float dists[MAX_CLIP_VERTS]; + int sides[MAX_CLIP_VERTS]; + vec3_t newv[2][MAX_CLIP_VERTS]; + int newc[2]; + int i, j; + + if (nump > MAX_CLIP_VERTS-2) + ri.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); + if (stage == 6) + { // fully clipped, so draw it + AddSkyPolygon (nump, vecs); + return; + } + + front = back = qfalse; + norm = sky_clip[stage]; + for (i=0, v = vecs ; i<nump ; i++, v+=3) + { + d = DotProduct (v, norm); + if (d > ON_EPSILON) + { + front = qtrue; + sides[i] = SIDE_FRONT; + } + else if (d < -ON_EPSILON) + { + back = qtrue; + sides[i] = SIDE_BACK; + } + else + sides[i] = SIDE_ON; + dists[i] = d; + } + + if (!front || !back) + { // not clipped + ClipSkyPolygon (nump, vecs, stage+1); + return; + } + + // clip it + sides[i] = sides[0]; + dists[i] = dists[0]; + VectorCopy (vecs, (vecs+(i*3)) ); + newc[0] = newc[1] = 0; + + for (i=0, v = vecs ; i<nump ; i++, v+=3) + { + switch (sides[i]) + { + case SIDE_FRONT: + VectorCopy (v, newv[0][newc[0]]); + newc[0]++; + break; + case SIDE_BACK: + VectorCopy (v, newv[1][newc[1]]); + newc[1]++; + break; + case SIDE_ON: + VectorCopy (v, newv[0][newc[0]]); + newc[0]++; + VectorCopy (v, newv[1][newc[1]]); + 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 (j=0 ; j<3 ; j++) + { + e = v[j] + d*(v[j+3] - v[j]); + newv[0][newc[0]][j] = e; + newv[1][newc[1]][j] = e; + } + newc[0]++; + newc[1]++; + } + + // continue + ClipSkyPolygon (newc[0], newv[0][0], stage+1); + ClipSkyPolygon (newc[1], newv[1][0], stage+1); +} + +/* +============== +ClearSkyBox +============== +*/ +static void ClearSkyBox (void) { + int i; + + for (i=0 ; i<6 ; i++) { + sky_mins[0][i] = sky_mins[1][i] = 9999; + sky_maxs[0][i] = sky_maxs[1][i] = -9999; + } +} + +/* +================ +RB_ClipSkyPolygons +================ +*/ +void RB_ClipSkyPolygons( shaderCommands_t *input ) +{ + vec3_t p[5]; // need one extra point for clipping + int i, j; + + ClearSkyBox(); + + for ( i = 0; i < input->numIndexes; i += 3 ) + { + for (j = 0 ; j < 3 ; j++) + { + VectorSubtract( input->xyz[input->indexes[i+j]], + backEnd.viewParms.or.origin, + p[j] ); + } + ClipSkyPolygon( 3, p[0], 0 ); + } +} + +/* +=================================================================================== + +CLOUD VERTEX GENERATION + +=================================================================================== +*/ + +/* +** MakeSkyVec +** +** Parms: s, t range from -1 to 1 +*/ +static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ ) +{ + // 1 = s, 2 = t, 3 = 2048 + static 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 + }; + + vec3_t b; + int j, k; + float boxSize; + + boxSize = backEnd.viewParms.zFar / 1.75; // div sqrt(3) + b[0] = s*boxSize; + b[1] = t*boxSize; + b[2] = boxSize; + + for (j=0 ; j<3 ; j++) + { + k = st_to_vec[axis][j]; + if (k < 0) + { + outXYZ[j] = -b[-k - 1]; + } + else + { + outXYZ[j] = b[k - 1]; + } + } + + // avoid bilerp seam + s = (s+1)*0.5; + t = (t+1)*0.5; + if (s < sky_min) + { + s = sky_min; + } + else if (s > sky_max) + { + s = sky_max; + } + + if (t < sky_min) + { + t = sky_min; + } + else if (t > sky_max) + { + t = sky_max; + } + + t = 1.0 - t; + + + if ( outSt ) + { + outSt[0] = s; + outSt[1] = t; + } +} + +static int sky_texorder[6] = {0,2,1,3,4,5}; +static vec3_t s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1]; +static float s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2]; + +static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] ) +{ + int s, t; + + GL_Bind( image ); + + for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) + { + qglBegin( GL_TRIANGLE_STRIP ); + + for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) + { + qglTexCoord2fv( s_skyTexCoords[t][s] ); + qglVertex3fv( s_skyPoints[t][s] ); + + qglTexCoord2fv( s_skyTexCoords[t+1][s] ); + qglVertex3fv( s_skyPoints[t+1][s] ); + } + + qglEnd(); + } +} + +static void DrawSkyBox( shader_t *shader ) +{ + int i; + + sky_min = 0; + sky_max = 1; + + Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) ); + + for (i=0 ; i<6 ; i++) + { + int sky_mins_subd[2], sky_maxs_subd[2]; + int s, t; + + sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + + if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || + ( sky_mins[1][i] >= sky_maxs[1][i] ) ) + { + continue; + } + + sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS; + sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS; + sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS; + sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS; + + if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; + else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; + if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS; + else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; + + if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; + else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; + if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS; + else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; + + // + // iterate through the subdivisions + // + for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) + { + for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) + { + MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + i, + s_skyTexCoords[t][s], + s_skyPoints[t][s] ); + } + } + + DrawSkySide( shader->sky.outerbox[sky_texorder[i]], + sky_mins_subd, + sky_maxs_subd ); + } + +} + +static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes ) +{ + int s, t; + int vertexStart = tess.numVertexes; + int tHeight, sWidth; + + tHeight = maxs[1] - mins[1] + 1; + sWidth = maxs[0] - mins[0] + 1; + + for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ ) + { + for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ ) + { + VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0]; + tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1]; + + tess.numVertexes++; + + if ( tess.numVertexes >= SHADER_MAX_VERTEXES ) + { + ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()\n" ); + } + } + } + + // only add indexes for one pass, otherwise it would draw multiple times for each pass + if ( addIndexes ) { + for ( t = 0; t < tHeight-1; t++ ) + { + for ( s = 0; s < sWidth-1; s++ ) + { + tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth ); + tess.numIndexes++; + tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); + tess.numIndexes++; + tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); + tess.numIndexes++; + + tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth ); + tess.numIndexes++; + tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth ); + tess.numIndexes++; + tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth ); + tess.numIndexes++; + } + } + } +} + +static void FillCloudBox( const shader_t *shader, int stage ) +{ + int i; + + for ( i =0; i < 6; i++ ) + { + int sky_mins_subd[2], sky_maxs_subd[2]; + int s, t; + float MIN_T; + + if ( 1 ) // FIXME? shader->sky.fullClouds ) + { + MIN_T = -HALF_SKY_SUBDIVISIONS; + + // still don't want to draw the bottom, even if fullClouds + if ( i == 5 ) + continue; + } + else + { + switch( i ) + { + case 0: + case 1: + case 2: + case 3: + MIN_T = -1; + break; + case 5: + // don't draw clouds beneath you + continue; + case 4: // top + default: + MIN_T = -HALF_SKY_SUBDIVISIONS; + break; + } + } + + sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS; + + if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) || + ( sky_mins[1][i] >= sky_maxs[1][i] ) ) + { + continue; + } + + sky_mins_subd[0] = myftol( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ); + sky_mins_subd[1] = myftol( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ); + sky_maxs_subd[0] = myftol( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ); + sky_maxs_subd[1] = myftol( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ); + + if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS; + else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS; + if ( sky_mins_subd[1] < MIN_T ) + sky_mins_subd[1] = MIN_T; + else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) + sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS; + + if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS; + else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS; + if ( sky_maxs_subd[1] < MIN_T ) + sky_maxs_subd[1] = MIN_T; + else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) + sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS; + + // + // iterate through the subdivisions + // + for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ ) + { + for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ ) + { + MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + i, + NULL, + s_skyPoints[t][s] ); + + s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0]; + s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1]; + } + } + + // only add indexes for first stage + FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) ); + } +} + +/* +** R_BuildCloudData +*/ +void R_BuildCloudData( shaderCommands_t *input ) +{ + int i; + shader_t *shader; + + shader = input->shader; + + assert( shader->isSky ); + + sky_min = 1.0 / 256.0f; // FIXME: not correct? + sky_max = 255.0 / 256.0f; + + // set up for drawing + tess.numIndexes = 0; + tess.numVertexes = 0; + + if ( input->shader->sky.cloudHeight ) + { + for ( i = 0; i < MAX_SHADER_STAGES; i++ ) + { + if ( !tess.xstages[i] ) { + break; + } + FillCloudBox( input->shader, i ); + } + } +} + +/* +** R_InitSkyTexCoords +** Called when a sky shader is parsed +*/ +#define SQR( a ) ((a)*(a)) +void R_InitSkyTexCoords( float heightCloud ) +{ + int i, s, t; + float radiusWorld = 4096; + float p; + float sRad, tRad; + vec3_t skyVec; + vec3_t v; + + // init zfar so MakeSkyVec works even though + // a world hasn't been bounded + backEnd.viewParms.zFar = 1024; + + for ( i = 0; i < 6; i++ ) + { + for ( t = 0; t <= SKY_SUBDIVISIONS; t++ ) + { + for ( s = 0; s <= SKY_SUBDIVISIONS; s++ ) + { + // compute vector from view origin to sky side integral point + MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + ( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, + i, + NULL, + skyVec ); + + // compute parametric value 'p' that intersects with cloud layer + p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) * + ( -2 * skyVec[2] * radiusWorld + + 2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) + + 2 * SQR( skyVec[0] ) * radiusWorld * heightCloud + + SQR( skyVec[0] ) * SQR( heightCloud ) + + 2 * SQR( skyVec[1] ) * radiusWorld * heightCloud + + SQR( skyVec[1] ) * SQR( heightCloud ) + + 2 * SQR( skyVec[2] ) * radiusWorld * heightCloud + + SQR( skyVec[2] ) * SQR( heightCloud ) ) ); + + s_cloudTexP[i][t][s] = p; + + // compute intersection point based on p + VectorScale( skyVec, p, v ); + v[2] += radiusWorld; + + // compute vector from world origin to intersection point 'v' + VectorNormalize( v ); + + sRad = Q_acos( v[0] ); + tRad = Q_acos( v[1] ); + + s_cloudTexCoords[i][t][s][0] = sRad; + s_cloudTexCoords[i][t][s][1] = tRad; + } + } + } +} + +//====================================================================================== + +/* +** RB_DrawSun +*/ +void RB_DrawSun( void ) { + float size; + float dist; + vec3_t origin, vec1, vec2; + vec3_t temp; + + if ( !backEnd.skyRenderedThisView ) { + return; + } + if ( !r_drawSun->integer ) { + return; + } + qglLoadMatrixf( backEnd.viewParms.world.modelMatrix ); + qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); + + dist = backEnd.viewParms.zFar / 1.75; // div sqrt(3) + size = dist * 0.4; + + VectorScale( tr.sunDirection, dist, origin ); + PerpendicularVector( vec1, tr.sunDirection ); + CrossProduct( tr.sunDirection, vec1, vec2 ); + + VectorScale( vec1, size, vec1 ); + VectorScale( vec2, size, vec2 ); + + // farthest depth range + qglDepthRange( 1.0, 1.0 ); + + // FIXME: use quad stamp + RB_BeginSurface( tr.sunShader, tess.fogNum ); + VectorCopy( origin, temp ); + VectorSubtract( temp, vec1, temp ); + VectorSubtract( temp, vec2, temp ); + VectorCopy( temp, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = 255; + tess.vertexColors[tess.numVertexes][1] = 255; + tess.vertexColors[tess.numVertexes][2] = 255; + tess.numVertexes++; + + VectorCopy( origin, temp ); + VectorAdd( temp, vec1, temp ); + VectorSubtract( temp, vec2, temp ); + VectorCopy( temp, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 0; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = 255; + tess.vertexColors[tess.numVertexes][1] = 255; + tess.vertexColors[tess.numVertexes][2] = 255; + tess.numVertexes++; + + VectorCopy( origin, temp ); + VectorAdd( temp, vec1, temp ); + VectorAdd( temp, vec2, temp ); + VectorCopy( temp, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 1; + tess.vertexColors[tess.numVertexes][0] = 255; + tess.vertexColors[tess.numVertexes][1] = 255; + tess.vertexColors[tess.numVertexes][2] = 255; + tess.numVertexes++; + + VectorCopy( origin, temp ); + VectorSubtract( temp, vec1, temp ); + VectorAdd( temp, vec2, temp ); + VectorCopy( temp, tess.xyz[tess.numVertexes] ); + tess.texCoords[tess.numVertexes][0][0] = 1; + tess.texCoords[tess.numVertexes][0][1] = 0; + tess.vertexColors[tess.numVertexes][0] = 255; + tess.vertexColors[tess.numVertexes][1] = 255; + tess.vertexColors[tess.numVertexes][2] = 255; + tess.numVertexes++; + + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 1; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 0; + tess.indexes[tess.numIndexes++] = 2; + tess.indexes[tess.numIndexes++] = 3; + + RB_EndSurface(); + + // back to normal depth range + qglDepthRange( 0.0, 1.0 ); +} + + + + +/* +================ +RB_StageIteratorSky + +All of the visible sky triangles are in tess + +Other things could be stuck in here, like birds in the sky, etc +================ +*/ +void RB_StageIteratorSky( void ) { + if ( r_fastsky->integer ) { + return; + } + + // go through all the polygons and project them onto + // the sky box to see which blocks on each side need + // to be drawn + RB_ClipSkyPolygons( &tess ); + + // r_showsky will let all the sky blocks be drawn in + // front of everything to allow developers to see how + // much sky is getting sucked in + if ( r_showsky->integer ) { + qglDepthRange( 0.0, 0.0 ); + } else { + qglDepthRange( 1.0, 1.0 ); + } + + // draw the outer skybox + if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) { + qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight ); + + qglPushMatrix (); + GL_State( 0 ); + qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]); + + DrawSkyBox( tess.shader ); + + qglPopMatrix(); + } + + // generate the vertexes for all the clouds, which will be drawn + // by the generic shader routine + R_BuildCloudData( &tess ); + + RB_StageIteratorGeneric(); + + // draw the inner skybox + + + // back to normal depth range + qglDepthRange( 0.0, 1.0 ); + + // note that sky was drawn so we will draw a sun later + backEnd.skyRenderedThisView = qtrue; +} + |