Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

tr_sky.c (20535B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 // tr_sky.c
     23 #include "tr_local.h"
     24 
     25 #define SKY_SUBDIVISIONS		8
     26 #define HALF_SKY_SUBDIVISIONS	(SKY_SUBDIVISIONS/2)
     27 
     28 static float s_cloudTexCoords[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
     29 static float s_cloudTexP[6][SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
     30 
     31 /*
     32 ===================================================================================
     33 
     34 POLYGON TO BOX SIDE PROJECTION
     35 
     36 ===================================================================================
     37 */
     38 
     39 static vec3_t sky_clip[6] = 
     40 {
     41 	{1,1,0},
     42 	{1,-1,0},
     43 	{0,-1,1},
     44 	{0,1,1},
     45 	{1,0,1},
     46 	{-1,0,1} 
     47 };
     48 
     49 static float	sky_mins[2][6], sky_maxs[2][6];
     50 static float	sky_min, sky_max;
     51 
     52 /*
     53 ================
     54 AddSkyPolygon
     55 ================
     56 */
     57 static void AddSkyPolygon (int nump, vec3_t vecs) 
     58 {
     59 	int		i,j;
     60 	vec3_t	v, av;
     61 	float	s, t, dv;
     62 	int		axis;
     63 	float	*vp;
     64 	// s = [0]/[2], t = [1]/[2]
     65 	static int	vec_to_st[6][3] =
     66 	{
     67 		{-2,3,1},
     68 		{2,3,-1},
     69 
     70 		{1,3,2},
     71 		{-1,3,-2},
     72 
     73 		{-2,-1,3},
     74 		{-2,1,-3}
     75 
     76 	//	{-1,2,3},
     77 	//	{1,2,-3}
     78 	};
     79 
     80 	// decide which face it maps to
     81 	VectorCopy (vec3_origin, v);
     82 	for (i=0, vp=vecs ; i<nump ; i++, vp+=3)
     83 	{
     84 		VectorAdd (vp, v, v);
     85 	}
     86 	av[0] = fabs(v[0]);
     87 	av[1] = fabs(v[1]);
     88 	av[2] = fabs(v[2]);
     89 	if (av[0] > av[1] && av[0] > av[2])
     90 	{
     91 		if (v[0] < 0)
     92 			axis = 1;
     93 		else
     94 			axis = 0;
     95 	}
     96 	else if (av[1] > av[2] && av[1] > av[0])
     97 	{
     98 		if (v[1] < 0)
     99 			axis = 3;
    100 		else
    101 			axis = 2;
    102 	}
    103 	else
    104 	{
    105 		if (v[2] < 0)
    106 			axis = 5;
    107 		else
    108 			axis = 4;
    109 	}
    110 
    111 	// project new texture coords
    112 	for (i=0 ; i<nump ; i++, vecs+=3)
    113 	{
    114 		j = vec_to_st[axis][2];
    115 		if (j > 0)
    116 			dv = vecs[j - 1];
    117 		else
    118 			dv = -vecs[-j - 1];
    119 		if (dv < 0.001)
    120 			continue;	// don't divide by zero
    121 		j = vec_to_st[axis][0];
    122 		if (j < 0)
    123 			s = -vecs[-j -1] / dv;
    124 		else
    125 			s = vecs[j-1] / dv;
    126 		j = vec_to_st[axis][1];
    127 		if (j < 0)
    128 			t = -vecs[-j -1] / dv;
    129 		else
    130 			t = vecs[j-1] / dv;
    131 
    132 		if (s < sky_mins[0][axis])
    133 			sky_mins[0][axis] = s;
    134 		if (t < sky_mins[1][axis])
    135 			sky_mins[1][axis] = t;
    136 		if (s > sky_maxs[0][axis])
    137 			sky_maxs[0][axis] = s;
    138 		if (t > sky_maxs[1][axis])
    139 			sky_maxs[1][axis] = t;
    140 	}
    141 }
    142 
    143 #define	ON_EPSILON		0.1f			// point on plane side epsilon
    144 #define	MAX_CLIP_VERTS	64
    145 /*
    146 ================
    147 ClipSkyPolygon
    148 ================
    149 */
    150 static void ClipSkyPolygon (int nump, vec3_t vecs, int stage) 
    151 {
    152 	float	*norm;
    153 	float	*v;
    154 	qboolean	front, back;
    155 	float	d, e;
    156 	float	dists[MAX_CLIP_VERTS];
    157 	int		sides[MAX_CLIP_VERTS];
    158 	vec3_t	newv[2][MAX_CLIP_VERTS];
    159 	int		newc[2];
    160 	int		i, j;
    161 
    162 	if (nump > MAX_CLIP_VERTS-2)
    163 		ri.Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS");
    164 	if (stage == 6)
    165 	{	// fully clipped, so draw it
    166 		AddSkyPolygon (nump, vecs);
    167 		return;
    168 	}
    169 
    170 	front = back = qfalse;
    171 	norm = sky_clip[stage];
    172 	for (i=0, v = vecs ; i<nump ; i++, v+=3)
    173 	{
    174 		d = DotProduct (v, norm);
    175 		if (d > ON_EPSILON)
    176 		{
    177 			front = qtrue;
    178 			sides[i] = SIDE_FRONT;
    179 		}
    180 		else if (d < -ON_EPSILON)
    181 		{
    182 			back = qtrue;
    183 			sides[i] = SIDE_BACK;
    184 		}
    185 		else
    186 			sides[i] = SIDE_ON;
    187 		dists[i] = d;
    188 	}
    189 
    190 	if (!front || !back)
    191 	{	// not clipped
    192 		ClipSkyPolygon (nump, vecs, stage+1);
    193 		return;
    194 	}
    195 
    196 	// clip it
    197 	sides[i] = sides[0];
    198 	dists[i] = dists[0];
    199 	VectorCopy (vecs, (vecs+(i*3)) );
    200 	newc[0] = newc[1] = 0;
    201 
    202 	for (i=0, v = vecs ; i<nump ; i++, v+=3)
    203 	{
    204 		switch (sides[i])
    205 		{
    206 		case SIDE_FRONT:
    207 			VectorCopy (v, newv[0][newc[0]]);
    208 			newc[0]++;
    209 			break;
    210 		case SIDE_BACK:
    211 			VectorCopy (v, newv[1][newc[1]]);
    212 			newc[1]++;
    213 			break;
    214 		case SIDE_ON:
    215 			VectorCopy (v, newv[0][newc[0]]);
    216 			newc[0]++;
    217 			VectorCopy (v, newv[1][newc[1]]);
    218 			newc[1]++;
    219 			break;
    220 		}
    221 
    222 		if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
    223 			continue;
    224 
    225 		d = dists[i] / (dists[i] - dists[i+1]);
    226 		for (j=0 ; j<3 ; j++)
    227 		{
    228 			e = v[j] + d*(v[j+3] - v[j]);
    229 			newv[0][newc[0]][j] = e;
    230 			newv[1][newc[1]][j] = e;
    231 		}
    232 		newc[0]++;
    233 		newc[1]++;
    234 	}
    235 
    236 	// continue
    237 	ClipSkyPolygon (newc[0], newv[0][0], stage+1);
    238 	ClipSkyPolygon (newc[1], newv[1][0], stage+1);
    239 }
    240 
    241 /*
    242 ==============
    243 ClearSkyBox
    244 ==============
    245 */
    246 static void ClearSkyBox (void) {
    247 	int		i;
    248 
    249 	for (i=0 ; i<6 ; i++) {
    250 		sky_mins[0][i] = sky_mins[1][i] = 9999;
    251 		sky_maxs[0][i] = sky_maxs[1][i] = -9999;
    252 	}
    253 }
    254 
    255 /*
    256 ================
    257 RB_ClipSkyPolygons
    258 ================
    259 */
    260 void RB_ClipSkyPolygons( shaderCommands_t *input )
    261 {
    262 	vec3_t		p[5];	// need one extra point for clipping
    263 	int			i, j;
    264 
    265 	ClearSkyBox();
    266 
    267 	for ( i = 0; i < input->numIndexes; i += 3 )
    268 	{
    269 		for (j = 0 ; j < 3 ; j++) 
    270 		{
    271 			VectorSubtract( input->xyz[input->indexes[i+j]],
    272 							backEnd.viewParms.or.origin, 
    273 							p[j] );
    274 		}
    275 		ClipSkyPolygon( 3, p[0], 0 );
    276 	}
    277 }
    278 
    279 /*
    280 ===================================================================================
    281 
    282 CLOUD VERTEX GENERATION
    283 
    284 ===================================================================================
    285 */
    286 
    287 /*
    288 ** MakeSkyVec
    289 **
    290 ** Parms: s, t range from -1 to 1
    291 */
    292 static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ )
    293 {
    294 	// 1 = s, 2 = t, 3 = 2048
    295 	static int	st_to_vec[6][3] =
    296 	{
    297 		{3,-1,2},
    298 		{-3,1,2},
    299 
    300 		{1,3,2},
    301 		{-1,-3,2},
    302 
    303 		{-2,-1,3},		// 0 degrees yaw, look straight up
    304 		{2,-1,-3}		// look straight down
    305 	};
    306 
    307 	vec3_t		b;
    308 	int			j, k;
    309 	float	boxSize;
    310 
    311 	boxSize = backEnd.viewParms.zFar / 1.75;		// div sqrt(3)
    312 	b[0] = s*boxSize;
    313 	b[1] = t*boxSize;
    314 	b[2] = boxSize;
    315 
    316 	for (j=0 ; j<3 ; j++)
    317 	{
    318 		k = st_to_vec[axis][j];
    319 		if (k < 0)
    320 		{
    321 			outXYZ[j] = -b[-k - 1];
    322 		}
    323 		else
    324 		{
    325 			outXYZ[j] = b[k - 1];
    326 		}
    327 	}
    328 
    329 	// avoid bilerp seam
    330 	s = (s+1)*0.5;
    331 	t = (t+1)*0.5;
    332 	if (s < sky_min)
    333 	{
    334 		s = sky_min;
    335 	}
    336 	else if (s > sky_max)
    337 	{
    338 		s = sky_max;
    339 	}
    340 
    341 	if (t < sky_min)
    342 	{
    343 		t = sky_min;
    344 	}
    345 	else if (t > sky_max)
    346 	{
    347 		t = sky_max;
    348 	}
    349 
    350 	t = 1.0 - t;
    351 
    352 
    353 	if ( outSt )
    354 	{
    355 		outSt[0] = s;
    356 		outSt[1] = t;
    357 	}
    358 }
    359 
    360 static int	sky_texorder[6] = {0,2,1,3,4,5};
    361 static vec3_t	s_skyPoints[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1];
    362 static float	s_skyTexCoords[SKY_SUBDIVISIONS+1][SKY_SUBDIVISIONS+1][2];
    363 
    364 static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )
    365 {
    366 	int s, t;
    367 
    368 	GL_Bind( image );
    369 
    370 	for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t < maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
    371 	{
    372 		qglBegin( GL_TRIANGLE_STRIP );
    373 
    374 		for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
    375 		{
    376 			qglTexCoord2fv( s_skyTexCoords[t][s] );
    377 			qglVertex3fv( s_skyPoints[t][s] );
    378 
    379 			qglTexCoord2fv( s_skyTexCoords[t+1][s] );
    380 			qglVertex3fv( s_skyPoints[t+1][s] );
    381 		}
    382 
    383 		qglEnd();
    384 	}
    385 }
    386 
    387 static void DrawSkyBox( shader_t *shader )
    388 {
    389 	int		i;
    390 
    391 	sky_min = 0;
    392 	sky_max = 1;
    393 
    394 	Com_Memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) );
    395 
    396 	for (i=0 ; i<6 ; i++)
    397 	{
    398 		int sky_mins_subd[2], sky_maxs_subd[2];
    399 		int s, t;
    400 
    401 		sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
    402 		sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
    403 		sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
    404 		sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
    405 
    406 		if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
    407 			 ( sky_mins[1][i] >= sky_maxs[1][i] ) )
    408 		{
    409 			continue;
    410 		}
    411 
    412 		sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS;
    413 		sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS;
    414 		sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS;
    415 		sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS;
    416 
    417 		if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) 
    418 			sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
    419 		else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) 
    420 			sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
    421 		if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS )
    422 			sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS;
    423 		else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) 
    424 			sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
    425 
    426 		if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) 
    427 			sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
    428 		else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) 
    429 			sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
    430 		if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS ) 
    431 			sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS;
    432 		else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) 
    433 			sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
    434 
    435 		//
    436 		// iterate through the subdivisions
    437 		//
    438 		for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
    439 		{
    440 			for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
    441 			{
    442 				MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, 
    443 							( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, 
    444 							i, 
    445 							s_skyTexCoords[t][s], 
    446 							s_skyPoints[t][s] );
    447 			}
    448 		}
    449 
    450 		DrawSkySide( shader->sky.outerbox[sky_texorder[i]],
    451 			         sky_mins_subd,
    452 					 sky_maxs_subd );
    453 	}
    454 
    455 }
    456 
    457 static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes )
    458 {
    459 	int s, t;
    460 	int vertexStart = tess.numVertexes;
    461 	int tHeight, sWidth;
    462 
    463 	tHeight = maxs[1] - mins[1] + 1;
    464 	sWidth = maxs[0] - mins[0] + 1;
    465 
    466 	for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
    467 	{
    468 		for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
    469 		{
    470 			VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] );
    471 			tess.texCoords[tess.numVertexes][0][0] = s_skyTexCoords[t][s][0];
    472 			tess.texCoords[tess.numVertexes][0][1] = s_skyTexCoords[t][s][1];
    473 
    474 			tess.numVertexes++;
    475 
    476 			if ( tess.numVertexes >= SHADER_MAX_VERTEXES )
    477 			{
    478 				ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()\n" );
    479 			}
    480 		}
    481 	}
    482 
    483 	// only add indexes for one pass, otherwise it would draw multiple times for each pass
    484 	if ( addIndexes ) {
    485 		for ( t = 0; t < tHeight-1; t++ )
    486 		{	
    487 			for ( s = 0; s < sWidth-1; s++ )
    488 			{
    489 				tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth );
    490 				tess.numIndexes++;
    491 				tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
    492 				tess.numIndexes++;
    493 				tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
    494 				tess.numIndexes++;
    495 
    496 				tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
    497 				tess.numIndexes++;
    498 				tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth );
    499 				tess.numIndexes++;
    500 				tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
    501 				tess.numIndexes++;
    502 			}
    503 		}
    504 	}
    505 }
    506 
    507 static void FillCloudBox( const shader_t *shader, int stage )
    508 {
    509 	int i;
    510 
    511 	for ( i =0; i < 6; i++ )
    512 	{
    513 		int sky_mins_subd[2], sky_maxs_subd[2];
    514 		int s, t;
    515 		float MIN_T;
    516 
    517 		if ( 1 ) // FIXME? shader->sky.fullClouds )
    518 		{
    519 			MIN_T = -HALF_SKY_SUBDIVISIONS;
    520 
    521 			// still don't want to draw the bottom, even if fullClouds
    522 			if ( i == 5 )
    523 				continue;
    524 		}
    525 		else
    526 		{
    527 			switch( i )
    528 			{
    529 			case 0:
    530 			case 1:
    531 			case 2:
    532 			case 3:
    533 				MIN_T = -1;
    534 				break;
    535 			case 5:
    536 				// don't draw clouds beneath you
    537 				continue;
    538 			case 4:		// top
    539 			default:
    540 				MIN_T = -HALF_SKY_SUBDIVISIONS;
    541 				break;
    542 			}
    543 		}
    544 
    545 		sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
    546 		sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
    547 		sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
    548 		sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
    549 
    550 		if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
    551 			 ( sky_mins[1][i] >= sky_maxs[1][i] ) )
    552 		{
    553 			continue;
    554 		}
    555 
    556 		sky_mins_subd[0] = myftol( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS );
    557 		sky_mins_subd[1] = myftol( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS );
    558 		sky_maxs_subd[0] = myftol( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS );
    559 		sky_maxs_subd[1] = myftol( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS );
    560 
    561 		if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) 
    562 			sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
    563 		else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) 
    564 			sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
    565 		if ( sky_mins_subd[1] < MIN_T )
    566 			sky_mins_subd[1] = MIN_T;
    567 		else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) 
    568 			sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
    569 
    570 		if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) 
    571 			sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
    572 		else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) 
    573 			sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
    574 		if ( sky_maxs_subd[1] < MIN_T )
    575 			sky_maxs_subd[1] = MIN_T;
    576 		else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) 
    577 			sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
    578 
    579 		//
    580 		// iterate through the subdivisions
    581 		//
    582 		for ( t = sky_mins_subd[1]+HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1]+HALF_SKY_SUBDIVISIONS; t++ )
    583 		{
    584 			for ( s = sky_mins_subd[0]+HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0]+HALF_SKY_SUBDIVISIONS; s++ )
    585 			{
    586 				MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, 
    587 							( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, 
    588 							i, 
    589 							NULL,
    590 							s_skyPoints[t][s] );
    591 
    592 				s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0];
    593 				s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1];
    594 			}
    595 		}
    596 
    597 		// only add indexes for first stage
    598 		FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) );
    599 	}
    600 }
    601 
    602 /*
    603 ** R_BuildCloudData
    604 */
    605 void R_BuildCloudData( shaderCommands_t *input )
    606 {
    607 	int			i;
    608 	shader_t	*shader;
    609 
    610 	shader = input->shader;
    611 
    612 	assert( shader->isSky );
    613 
    614 	sky_min = 1.0 / 256.0f;		// FIXME: not correct?
    615 	sky_max = 255.0 / 256.0f;
    616 
    617 	// set up for drawing
    618 	tess.numIndexes = 0;
    619 	tess.numVertexes = 0;
    620 
    621 	if ( input->shader->sky.cloudHeight )
    622 	{
    623 		for ( i = 0; i < MAX_SHADER_STAGES; i++ )
    624 		{
    625 			if ( !tess.xstages[i] ) {
    626 				break;
    627 			}
    628 			FillCloudBox( input->shader, i );
    629 		}
    630 	}
    631 }
    632 
    633 /*
    634 ** R_InitSkyTexCoords
    635 ** Called when a sky shader is parsed
    636 */
    637 #define SQR( a ) ((a)*(a))
    638 void R_InitSkyTexCoords( float heightCloud )
    639 {
    640 	int i, s, t;
    641 	float radiusWorld = 4096;
    642 	float p;
    643 	float sRad, tRad;
    644 	vec3_t skyVec;
    645 	vec3_t v;
    646 
    647 	// init zfar so MakeSkyVec works even though
    648 	// a world hasn't been bounded
    649 	backEnd.viewParms.zFar = 1024;
    650 
    651 	for ( i = 0; i < 6; i++ )
    652 	{
    653 		for ( t = 0; t <= SKY_SUBDIVISIONS; t++ )
    654 		{
    655 			for ( s = 0; s <= SKY_SUBDIVISIONS; s++ )
    656 			{
    657 				// compute vector from view origin to sky side integral point
    658 				MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, 
    659 							( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS, 
    660 							i, 
    661 							NULL,
    662 							skyVec );
    663 
    664 				// compute parametric value 'p' that intersects with cloud layer
    665 				p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) *
    666 					( -2 * skyVec[2] * radiusWorld + 
    667 					   2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) + 
    668 					             2 * SQR( skyVec[0] ) * radiusWorld * heightCloud +
    669 								 SQR( skyVec[0] ) * SQR( heightCloud ) + 
    670 								 2 * SQR( skyVec[1] ) * radiusWorld * heightCloud +
    671 								 SQR( skyVec[1] ) * SQR( heightCloud ) + 
    672 								 2 * SQR( skyVec[2] ) * radiusWorld * heightCloud +
    673 								 SQR( skyVec[2] ) * SQR( heightCloud ) ) );
    674 
    675 				s_cloudTexP[i][t][s] = p;
    676 
    677 				// compute intersection point based on p
    678 				VectorScale( skyVec, p, v );
    679 				v[2] += radiusWorld;
    680 
    681 				// compute vector from world origin to intersection point 'v'
    682 				VectorNormalize( v );
    683 
    684 				sRad = Q_acos( v[0] );
    685 				tRad = Q_acos( v[1] );
    686 
    687 				s_cloudTexCoords[i][t][s][0] = sRad;
    688 				s_cloudTexCoords[i][t][s][1] = tRad;
    689 			}
    690 		}
    691 	}
    692 }
    693 
    694 //======================================================================================
    695 
    696 /*
    697 ** RB_DrawSun
    698 */
    699 void RB_DrawSun( void ) {
    700 	float		size;
    701 	float		dist;
    702 	vec3_t		origin, vec1, vec2;
    703 	vec3_t		temp;
    704 
    705 	if ( !backEnd.skyRenderedThisView ) {
    706 		return;
    707 	}
    708 	if ( !r_drawSun->integer ) {
    709 		return;
    710 	}
    711 	qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
    712 	qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
    713 
    714 	dist = 	backEnd.viewParms.zFar / 1.75;		// div sqrt(3)
    715 	size = dist * 0.4;
    716 
    717 	VectorScale( tr.sunDirection, dist, origin );
    718 	PerpendicularVector( vec1, tr.sunDirection );
    719 	CrossProduct( tr.sunDirection, vec1, vec2 );
    720 
    721 	VectorScale( vec1, size, vec1 );
    722 	VectorScale( vec2, size, vec2 );
    723 
    724 	// farthest depth range
    725 	qglDepthRange( 1.0, 1.0 );
    726 
    727 	// FIXME: use quad stamp
    728 	RB_BeginSurface( tr.sunShader, tess.fogNum );
    729 		VectorCopy( origin, temp );
    730 		VectorSubtract( temp, vec1, temp );
    731 		VectorSubtract( temp, vec2, temp );
    732 		VectorCopy( temp, tess.xyz[tess.numVertexes] );
    733 		tess.texCoords[tess.numVertexes][0][0] = 0;
    734 		tess.texCoords[tess.numVertexes][0][1] = 0;
    735 		tess.vertexColors[tess.numVertexes][0] = 255;
    736 		tess.vertexColors[tess.numVertexes][1] = 255;
    737 		tess.vertexColors[tess.numVertexes][2] = 255;
    738 		tess.numVertexes++;
    739 
    740 		VectorCopy( origin, temp );
    741 		VectorAdd( temp, vec1, temp );
    742 		VectorSubtract( temp, vec2, temp );
    743 		VectorCopy( temp, tess.xyz[tess.numVertexes] );
    744 		tess.texCoords[tess.numVertexes][0][0] = 0;
    745 		tess.texCoords[tess.numVertexes][0][1] = 1;
    746 		tess.vertexColors[tess.numVertexes][0] = 255;
    747 		tess.vertexColors[tess.numVertexes][1] = 255;
    748 		tess.vertexColors[tess.numVertexes][2] = 255;
    749 		tess.numVertexes++;
    750 
    751 		VectorCopy( origin, temp );
    752 		VectorAdd( temp, vec1, temp );
    753 		VectorAdd( temp, vec2, temp );
    754 		VectorCopy( temp, tess.xyz[tess.numVertexes] );
    755 		tess.texCoords[tess.numVertexes][0][0] = 1;
    756 		tess.texCoords[tess.numVertexes][0][1] = 1;
    757 		tess.vertexColors[tess.numVertexes][0] = 255;
    758 		tess.vertexColors[tess.numVertexes][1] = 255;
    759 		tess.vertexColors[tess.numVertexes][2] = 255;
    760 		tess.numVertexes++;
    761 
    762 		VectorCopy( origin, temp );
    763 		VectorSubtract( temp, vec1, temp );
    764 		VectorAdd( temp, vec2, temp );
    765 		VectorCopy( temp, tess.xyz[tess.numVertexes] );
    766 		tess.texCoords[tess.numVertexes][0][0] = 1;
    767 		tess.texCoords[tess.numVertexes][0][1] = 0;
    768 		tess.vertexColors[tess.numVertexes][0] = 255;
    769 		tess.vertexColors[tess.numVertexes][1] = 255;
    770 		tess.vertexColors[tess.numVertexes][2] = 255;
    771 		tess.numVertexes++;
    772 
    773 		tess.indexes[tess.numIndexes++] = 0;
    774 		tess.indexes[tess.numIndexes++] = 1;
    775 		tess.indexes[tess.numIndexes++] = 2;
    776 		tess.indexes[tess.numIndexes++] = 0;
    777 		tess.indexes[tess.numIndexes++] = 2;
    778 		tess.indexes[tess.numIndexes++] = 3;
    779 
    780 	RB_EndSurface();
    781 
    782 	// back to normal depth range
    783 	qglDepthRange( 0.0, 1.0 );
    784 }
    785 
    786 
    787 
    788 
    789 /*
    790 ================
    791 RB_StageIteratorSky
    792 
    793 All of the visible sky triangles are in tess
    794 
    795 Other things could be stuck in here, like birds in the sky, etc
    796 ================
    797 */
    798 void RB_StageIteratorSky( void ) {
    799 	if ( r_fastsky->integer ) {
    800 		return;
    801 	}
    802 
    803 	// go through all the polygons and project them onto
    804 	// the sky box to see which blocks on each side need
    805 	// to be drawn
    806 	RB_ClipSkyPolygons( &tess );
    807 
    808 	// r_showsky will let all the sky blocks be drawn in
    809 	// front of everything to allow developers to see how
    810 	// much sky is getting sucked in
    811 	if ( r_showsky->integer ) {
    812 		qglDepthRange( 0.0, 0.0 );
    813 	} else {
    814 		qglDepthRange( 1.0, 1.0 );
    815 	}
    816 
    817 	// draw the outer skybox
    818 	if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {
    819 		qglColor3f( tr.identityLight, tr.identityLight, tr.identityLight );
    820 		
    821 		qglPushMatrix ();
    822 		GL_State( 0 );
    823 		qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
    824 
    825 		DrawSkyBox( tess.shader );
    826 
    827 		qglPopMatrix();
    828 	}
    829 
    830 	// generate the vertexes for all the clouds, which will be drawn
    831 	// by the generic shader routine
    832 	R_BuildCloudData( &tess );
    833 
    834 	RB_StageIteratorGeneric();
    835 
    836 	// draw the inner skybox
    837 
    838 
    839 	// back to normal depth range
    840 	qglDepthRange( 0.0, 1.0 );
    841 
    842 	// note that sky was drawn so we will draw a sun later
    843 	backEnd.skyRenderedThisView = qtrue;
    844 }
    845