1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 // tr_sky.c
30 #include "tr_local.h"
31 
32 #define SKY_SUBDIVISIONS        8
33 #define HALF_SKY_SUBDIVISIONS   ( SKY_SUBDIVISIONS / 2 )
34 
35 static float s_cloudTexCoords[6][SKY_SUBDIVISIONS + 1][SKY_SUBDIVISIONS + 1][2];
36 static float s_cloudTexP[6][SKY_SUBDIVISIONS + 1][SKY_SUBDIVISIONS + 1];
37 
38 /*
39 ===================================================================================
40 
41 POLYGON TO BOX SIDE PROJECTION
42 
43 ===================================================================================
44 */
45 
46 static vec3_t sky_clip[6] =
47 {
48 	{1,1,0},
49 	{1,-1,0},
50 	{0,-1,1},
51 	{0,1,1},
52 	{1,0,1},
53 	{-1,0,1}
54 };
55 
56 static float sky_mins[2][6], sky_maxs[2][6];
57 static float sky_min, sky_max;
58 
59 /*
60 ================
61 AddSkyPolygon
62 ================
63 */
AddSkyPolygon(int nump,vec3_t vecs)64 static void AddSkyPolygon( int nump, vec3_t vecs ) {
65 	int i,j;
66 	vec3_t v, av;
67 	float s, t, dv;
68 	int axis;
69 	float   *vp;
70 	// s = [0]/[2], t = [1]/[2]
71 	static int vec_to_st[6][3] =
72 	{
73 		{-2,3,1},
74 		{2,3,-1},
75 
76 		{1,3,2},
77 		{-1,3,-2},
78 
79 		{-2,-1,3},
80 		{-2,1,-3}
81 
82 		//	{-1,2,3},
83 		//	{1,2,-3}
84 	};
85 
86 	// decide which face it maps to
87 	VectorCopy( vec3_origin, v );
88 	for ( i = 0, vp = vecs ; i < nump ; i++, vp += 3 )
89 	{
90 		VectorAdd( vp, v, v );
91 	}
92 	av[0] = fabs( v[0] );
93 	av[1] = fabs( v[1] );
94 	av[2] = fabs( v[2] );
95 	if ( av[0] > av[1] && av[0] > av[2] ) {
96 		if ( v[0] < 0 ) {
97 			axis = 1;
98 		} else {
99 			axis = 0;
100 		}
101 	} else if ( av[1] > av[2] && av[1] > av[0] )     {
102 		if ( v[1] < 0 ) {
103 			axis = 3;
104 		} else {
105 			axis = 2;
106 		}
107 	} else
108 	{
109 		if ( v[2] < 0 ) {
110 			axis = 5;
111 		} else {
112 			axis = 4;
113 		}
114 	}
115 
116 	// project new texture coords
117 	for ( i = 0 ; i < nump ; i++, vecs += 3 )
118 	{
119 		j = vec_to_st[axis][2];
120 		if ( j > 0 ) {
121 			dv = vecs[j - 1];
122 		} else {
123 			dv = -vecs[-j - 1];
124 		}
125 		if ( dv < 0.001 ) {
126 			continue;   // don't divide by zero
127 		}
128 		j = vec_to_st[axis][0];
129 		if ( j < 0 ) {
130 			s = -vecs[-j - 1] / dv;
131 		} else {
132 			s = vecs[j - 1] / dv;
133 		}
134 		j = vec_to_st[axis][1];
135 		if ( j < 0 ) {
136 			t = -vecs[-j - 1] / dv;
137 		} else {
138 			t = vecs[j - 1] / dv;
139 		}
140 
141 		if ( s < sky_mins[0][axis] ) {
142 			sky_mins[0][axis] = s;
143 		}
144 		if ( t < sky_mins[1][axis] ) {
145 			sky_mins[1][axis] = t;
146 		}
147 		if ( s > sky_maxs[0][axis] ) {
148 			sky_maxs[0][axis] = s;
149 		}
150 		if ( t > sky_maxs[1][axis] ) {
151 			sky_maxs[1][axis] = t;
152 		}
153 	}
154 }
155 
156 #define ON_EPSILON      0.1f            // point on plane side epsilon
157 #define MAX_CLIP_VERTS  64
158 /*
159 ================
160 ClipSkyPolygon
161 ================
162 */
ClipSkyPolygon(int nump,vec3_t vecs,int stage)163 static void ClipSkyPolygon( int nump, vec3_t vecs, int stage ) {
164 	float   *norm;
165 	float   *v;
166 	qboolean front, back;
167 	float d, e;
168 	float dists[MAX_CLIP_VERTS];
169 	int sides[MAX_CLIP_VERTS];
170 	vec3_t newv[2][MAX_CLIP_VERTS];
171 	int newc[2];
172 	int i, j;
173 
174 	if ( nump > MAX_CLIP_VERTS - 2 ) {
175 		ri.Error( ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS" );
176 	}
177 	if ( stage == 6 ) { // fully clipped, so draw it
178 		AddSkyPolygon( nump, vecs );
179 		return;
180 	}
181 
182 	front = back = qfalse;
183 	norm = sky_clip[stage];
184 	for ( i = 0, v = vecs ; i < nump ; i++, v += 3 )
185 	{
186 		d = DotProduct( v, norm );
187 		if ( d > ON_EPSILON ) {
188 			front = qtrue;
189 			sides[i] = SIDE_FRONT;
190 		} else if ( d < -ON_EPSILON )     {
191 			back = qtrue;
192 			sides[i] = SIDE_BACK;
193 		} else {
194 			sides[i] = SIDE_ON;
195 		}
196 		dists[i] = d;
197 	}
198 
199 	if ( !front || !back ) { // not clipped
200 		ClipSkyPolygon( nump, vecs, stage + 1 );
201 		return;
202 	}
203 
204 	// clip it
205 	sides[i] = sides[0];
206 	dists[i] = dists[0];
207 	VectorCopy( vecs, ( vecs + ( i * 3 ) ) );
208 	newc[0] = newc[1] = 0;
209 
210 	for ( i = 0, v = vecs ; i < nump ; i++, v += 3 )
211 	{
212 		switch ( sides[i] )
213 		{
214 		case SIDE_FRONT:
215 			VectorCopy( v, newv[0][newc[0]] );
216 			newc[0]++;
217 			break;
218 		case SIDE_BACK:
219 			VectorCopy( v, newv[1][newc[1]] );
220 			newc[1]++;
221 			break;
222 		case SIDE_ON:
223 			VectorCopy( v, newv[0][newc[0]] );
224 			newc[0]++;
225 			VectorCopy( v, newv[1][newc[1]] );
226 			newc[1]++;
227 			break;
228 		}
229 
230 		if ( sides[i] == SIDE_ON || sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i] ) {
231 			continue;
232 		}
233 
234 		d = dists[i] / ( dists[i] - dists[i + 1] );
235 		for ( j = 0 ; j < 3 ; j++ )
236 		{
237 			e = v[j] + d * ( v[j + 3] - v[j] );
238 			newv[0][newc[0]][j] = e;
239 			newv[1][newc[1]][j] = e;
240 		}
241 		newc[0]++;
242 		newc[1]++;
243 	}
244 
245 	// continue
246 	ClipSkyPolygon( newc[0], newv[0][0], stage + 1 );
247 	ClipSkyPolygon( newc[1], newv[1][0], stage + 1 );
248 }
249 
250 /*
251 ==============
252 ClearSkyBox
253 ==============
254 */
ClearSkyBox(void)255 static void ClearSkyBox( void ) {
256 	int i;
257 
258 	for ( i = 0 ; i < 6 ; i++ ) {
259 		sky_mins[0][i] = sky_mins[1][i] = 9999;
260 		sky_maxs[0][i] = sky_maxs[1][i] = -9999;
261 	}
262 }
263 
264 /*
265 ================
266 RB_ClipSkyPolygons
267 ================
268 */
RB_ClipSkyPolygons(shaderCommands_t * input)269 void RB_ClipSkyPolygons( shaderCommands_t *input ) {
270 	vec3_t p[5];        // need one extra point for clipping
271 	int i, j;
272 
273 	ClearSkyBox();
274 
275 	for ( i = 0; i < input->numIndexes; i += 3 )
276 	{
277 		for ( j = 0 ; j < 3 ; j++ )
278 		{
279 			VectorSubtract( input->xyz[input->indexes[i + j]],
280 							backEnd.viewParms.or.origin,
281 							p[j] );
282 		}
283 		ClipSkyPolygon( 3, p[0], 0 );
284 	}
285 }
286 
287 /*
288 ===================================================================================
289 
290 CLOUD VERTEX GENERATION
291 
292 ===================================================================================
293 */
294 
295 /*
296 ** MakeSkyVec
297 **
298 ** Parms: s, t range from -1 to 1
299 */
MakeSkyVec(float s,float t,int axis,float outSt[2],vec3_t outXYZ)300 static void MakeSkyVec( float s, float t, int axis, float outSt[2], vec3_t outXYZ ) {
301 	// 1 = s, 2 = t, 3 = 2048
302 	static int st_to_vec[6][3] =
303 	{
304 		{3,-1,2},
305 		{-3,1,2},
306 
307 		{1,3,2},
308 		{-1,-3,2},
309 
310 		{-2,-1,3},      // 0 degrees yaw, look straight up
311 		{2,-1,-3}       // look straight down
312 	};
313 
314 	vec3_t b;
315 	int j, k;
316 	float boxSize;
317 
318 // JPW NERVE swiped from Sherman SP fix
319 //	if(glfogNum > FOG_NONE && glfogsettings[FOG_CURRENT].mode == GL_EXP) {
320 	if ( glfogsettings[FOG_SKY].registered ) {     // (SA) trying this...
321 ///		boxSize = backEnd.viewParms.zFar / 1.75;		// div sqrt(3)
322 //		boxSize = glfogsettings[FOG_CURRENT].end / 1.75;
323 		boxSize = glfogsettings[FOG_SKY].end;       // (SA) trying this...
324 // jpw
325 	} else {
326 		boxSize = backEnd.viewParms.zFar / 1.75;        // div sqrt(3)
327 
328 	}
329 // JPW NERVE swiped from Sherman
330 	// make sure the sky is not near clipped
331 	if ( boxSize < r_znear->value * 2.0 ) {
332 		boxSize = r_znear->value * 2.0;
333 	}
334 // jpw
335 	b[0] = s * boxSize;
336 	b[1] = t * boxSize;
337 	b[2] = boxSize;
338 
339 	for ( j = 0 ; j < 3 ; j++ )
340 	{
341 		k = st_to_vec[axis][j];
342 		if ( k < 0 ) {
343 			outXYZ[j] = -b[-k - 1];
344 		} else
345 		{
346 			outXYZ[j] = b[k - 1];
347 		}
348 	}
349 
350 	// avoid bilerp seam
351 	s = ( s + 1 ) * 0.5;
352 	t = ( t + 1 ) * 0.5;
353 	if ( s < sky_min ) {
354 		s = sky_min;
355 	} else if ( s > sky_max )     {
356 		s = sky_max;
357 	}
358 
359 	if ( t < sky_min ) {
360 		t = sky_min;
361 	} else if ( t > sky_max )     {
362 		t = sky_max;
363 	}
364 
365 	t = 1.0 - t;
366 
367 
368 	if ( outSt ) {
369 		outSt[0] = s;
370 		outSt[1] = t;
371 	}
372 }
373 
374 static int sky_texorder[6] = {0,2,1,3,4,5};
375 static vec3_t s_skyPoints[SKY_SUBDIVISIONS + 1][SKY_SUBDIVISIONS + 1];
376 static float s_skyTexCoords[SKY_SUBDIVISIONS + 1][SKY_SUBDIVISIONS + 1][2];
377 
DrawSkySide(struct image_s * image,const int mins[2],const int maxs[2])378 static void DrawSkySide( struct image_s *image, const int mins[2], const int maxs[2] )
379 {
380 	int s, t;
381 	int firstVertex = tess.numVertexes;
382 	//int firstIndex = tess.numIndexes;
383 	vec4_t color;
384 
385 	//tess.numVertexes = 0;
386 	//tess.numIndexes = 0;
387 	tess.firstIndex = tess.numIndexes;
388 
389 	GL_BindToTMU( image, TB_COLORMAP );
390 	GL_Cull( CT_TWO_SIDED );
391 
392 	for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
393 	{
394 		for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
395 		{
396 			tess.xyz[tess.numVertexes][0] = s_skyPoints[t][s][0];
397 			tess.xyz[tess.numVertexes][1] = s_skyPoints[t][s][1];
398 			tess.xyz[tess.numVertexes][2] = s_skyPoints[t][s][2];
399 			tess.xyz[tess.numVertexes][3] = 1.0;
400 
401 			tess.texCoords[tess.numVertexes][0] = s_skyTexCoords[t][s][0];
402 			tess.texCoords[tess.numVertexes][1] = s_skyTexCoords[t][s][1];
403 
404 			tess.numVertexes++;
405 
406 			if(tess.numVertexes >= SHADER_MAX_VERTEXES)
407 			{
408 				ri.Error(ERR_DROP, "SHADER_MAX_VERTEXES hit in DrawSkySideVBO()");
409 			}
410 		}
411 	}
412 
413 	for ( t = 0; t < maxs[1] - mins[1]; t++ )
414 	{
415 		for ( s = 0; s < maxs[0] - mins[0]; s++ )
416 		{
417 			if (tess.numIndexes + 6 >= SHADER_MAX_INDEXES)
418 			{
419 				ri.Error(ERR_DROP, "SHADER_MAX_INDEXES hit in DrawSkySideVBO()");
420 			}
421 
422 			tess.indexes[tess.numIndexes++] =  s +       t      * (maxs[0] - mins[0] + 1) + firstVertex;
423 			tess.indexes[tess.numIndexes++] =  s +      (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
424 			tess.indexes[tess.numIndexes++] = (s + 1) +  t      * (maxs[0] - mins[0] + 1) + firstVertex;
425 
426 			tess.indexes[tess.numIndexes++] = (s + 1) +  t      * (maxs[0] - mins[0] + 1) + firstVertex;
427 			tess.indexes[tess.numIndexes++] =  s +      (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
428 			tess.indexes[tess.numIndexes++] = (s + 1) + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
429 		}
430 	}
431 
432 	// FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function
433 	RB_UpdateTessVao(ATTR_POSITION | ATTR_TEXCOORD);
434 /*
435 	{
436 		shaderProgram_t *sp = &tr.textureColorShader;
437 
438 		GLSL_BindProgram(sp);
439 
440 		GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
441 
442 		color[0] =
443 		color[1] =
444 		color[2] = tr.identityLight;
445 		color[3] = 1.0f;
446 		GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color);
447 	}
448 */
449 	{
450 		shaderProgram_t *sp = &tr.lightallShader[0];
451 		vec4_t vector;
452 
453 		GLSL_BindProgram(sp);
454 
455 		GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
456 
457 		color[0] =
458 		color[1] =
459 		color[2] =
460 		color[3] = 1.0f;
461 		GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, color);
462 
463 		color[0] =
464 		color[1] =
465 		color[2] =
466 		color[3] = 0.0f;
467 		GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, color);
468 
469 		VectorSet4(vector, 1.0, 0.0, 0.0, 1.0);
470 		GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector);
471 
472 		VectorSet4(vector, 0.0, 0.0, 0.0, 0.0);
473 		GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector);
474 
475 		GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
476 	}
477 
478 	R_DrawElements(tess.numIndexes - tess.firstIndex, tess.firstIndex);
479 
480 	//qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(glIndex_t)));
481 
482 	//R_BindNullVBO();
483 	//R_BindNullIBO();
484 
485 	tess.numIndexes = tess.firstIndex;
486 	tess.numVertexes = firstVertex;
487 	tess.firstIndex = 0;
488 }
489 
DrawSkySideInner(struct image_s * image,const int mins[2],const int maxs[2])490 static void DrawSkySideInner( struct image_s *image, const int mins[2], const int maxs[2] )
491 {
492 	int s, t;
493 	int firstVertex = tess.numVertexes;
494 	//int firstIndex = tess.numIndexes;
495 	vec4_t color;
496 
497 	//tess.numVertexes = 0;
498 	//tess.numIndexes = 0;
499 	tess.firstIndex = tess.numIndexes;
500 
501 	GL_BindToTMU( image, TB_COLORMAP );
502 	GL_Cull( CT_TWO_SIDED );
503 
504 	for ( t = mins[1]+HALF_SKY_SUBDIVISIONS; t <= maxs[1]+HALF_SKY_SUBDIVISIONS; t++ )
505 	{
506 		for ( s = mins[0]+HALF_SKY_SUBDIVISIONS; s <= maxs[0]+HALF_SKY_SUBDIVISIONS; s++ )
507 		{
508 			tess.xyz[tess.numVertexes][0] = s_skyPoints[t][s][0];
509 			tess.xyz[tess.numVertexes][1] = s_skyPoints[t][s][1];
510 			tess.xyz[tess.numVertexes][2] = s_skyPoints[t][s][2];
511 			tess.xyz[tess.numVertexes][3] = 1.0;
512 
513 			tess.texCoords[tess.numVertexes][0] = s_skyTexCoords[t][s][0];
514 			tess.texCoords[tess.numVertexes][1] = s_skyTexCoords[t][s][1];
515 
516 			tess.numVertexes++;
517 
518 			if(tess.numVertexes >= SHADER_MAX_VERTEXES)
519 			{
520 				ri.Error(ERR_DROP, "SHADER_MAX_VERTEXES hit in DrawSkySideVBO()\n");
521 			}
522 		}
523 	}
524 
525 	for ( t = 0; t < maxs[1] - mins[1]; t++ )
526 	{
527 		for ( s = 0; s < maxs[0] - mins[0]; s++ )
528 		{
529 			if (tess.numIndexes + 6 >= SHADER_MAX_INDEXES)
530 			{
531 				ri.Error(ERR_DROP, "SHADER_MAX_INDEXES hit in DrawSkySideVBO()\n");
532 			}
533 
534 			tess.indexes[tess.numIndexes++] =  s +       t      * (maxs[0] - mins[0] + 1) + firstVertex;
535 			tess.indexes[tess.numIndexes++] =  s +      (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
536 			tess.indexes[tess.numIndexes++] = (s + 1) +  t      * (maxs[0] - mins[0] + 1) + firstVertex;
537 
538 			tess.indexes[tess.numIndexes++] = (s + 1) +  t      * (maxs[0] - mins[0] + 1) + firstVertex;
539 			tess.indexes[tess.numIndexes++] =  s +      (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
540 			tess.indexes[tess.numIndexes++] = (s + 1) + (t + 1) * (maxs[0] - mins[0] + 1) + firstVertex;
541 		}
542 	}
543 
544 	// FIXME: A lot of this can probably be removed for speed, and refactored into a more convenient function
545 	RB_UpdateTessVao(ATTR_POSITION | ATTR_TEXCOORD);
546 /*
547 	{
548 		shaderProgram_t *sp = &tr.textureColorShader;
549 
550 		GLSL_BindProgram(sp);
551 
552 		GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
553 
554 		color[0] =
555 		color[1] =
556 		color[2] = tr.identityLight;
557 		color[3] = 1.0f;
558 		GLSL_SetUniformVec4(sp, UNIFORM_COLOR, color);
559 	}
560 */
561 	{
562 		shaderProgram_t *sp = &tr.lightallShader[0];
563 		vec4_t vector;
564 
565 		GLSL_BindProgram(sp);
566 
567 		GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection);
568 
569 		color[0] =
570 		color[1] =
571 		color[2] =
572 		color[3] = 1.0f;
573 		GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, color);
574 
575 		color[0] =
576 		color[1] =
577 		color[2] =
578 		color[3] = 0.0f;
579 		GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, color);
580 
581 		VectorSet4(vector, 1.0, 0.0, 0.0, 1.0);
582 		GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, vector);
583 
584 		VectorSet4(vector, 0.0, 0.0, 0.0, 0.0);
585 		GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, vector);
586 
587 		GLSL_SetUniformInt(sp, UNIFORM_ALPHATEST, 0);
588 	}
589 
590 	R_DrawElements(tess.numIndexes - tess.firstIndex, tess.firstIndex);
591 
592 	//qglDrawElements(GL_TRIANGLES, tess.numIndexes - tess.firstIndex, GL_INDEX_TYPE, BUFFER_OFFSET(tess.firstIndex * sizeof(glIndex_t)));
593 
594 	//R_BindNullVBO();
595 	//R_BindNullIBO();
596 
597 	tess.numIndexes = tess.firstIndex;
598 	tess.numVertexes = firstVertex;
599 	tess.firstIndex = 0;
600 }
601 
DrawSkyBox(shader_t * shader)602 static void DrawSkyBox( shader_t *shader ) {
603 	int i;
604 
605 	sky_min = 0;
606 	sky_max = 1;
607 
608 	memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) );
609 
610 	for ( i = 0 ; i < 6 ; i++ )
611 	{
612 		int sky_mins_subd[2], sky_maxs_subd[2];
613 		int s, t;
614 
615 		sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
616 		sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
617 		sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
618 		sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
619 
620 		if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
621 			 ( sky_mins[1][i] >= sky_maxs[1][i] ) ) {
622 			continue;
623 		}
624 
625 		sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS;
626 		sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS;
627 		sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS;
628 		sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS;
629 
630 		if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) {
631 			sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
632 		} else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) {
633 			sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
634 		}
635 		if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS ) {
636 			sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS;
637 		} else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) {
638 			sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
639 		}
640 
641 		if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) {
642 			sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
643 		} else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) {
644 			sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
645 		}
646 		if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS ) {
647 			sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS;
648 		} else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) {
649 			sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
650 		}
651 
652 		//
653 		// iterate through the subdivisions
654 		//
655 		for ( t = sky_mins_subd[1] + HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1] + HALF_SKY_SUBDIVISIONS; t++ )
656 		{
657 			for ( s = sky_mins_subd[0] + HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0] + HALF_SKY_SUBDIVISIONS; s++ )
658 			{
659 				MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
660 							( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
661 							i,
662 							s_skyTexCoords[t][s],
663 							s_skyPoints[t][s] );
664 			}
665 		}
666 
667 		DrawSkySide( shader->sky.outerbox[sky_texorder[i]],
668 					 sky_mins_subd,
669 					 sky_maxs_subd );
670 	}
671 
672 }
673 
674 
DrawSkyBoxInner(shader_t * shader)675 static void DrawSkyBoxInner( shader_t *shader ) {
676 	int i;
677 
678 	memset( s_skyTexCoords, 0, sizeof( s_skyTexCoords ) );
679 
680 	for ( i = 0 ; i < 6 ; i++ )
681 	{
682 		int sky_mins_subd[2], sky_maxs_subd[2];
683 		int s, t;
684 
685 		sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
686 		sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
687 		sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
688 		sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
689 
690 		if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
691 			 ( sky_mins[1][i] >= sky_maxs[1][i] ) ) {
692 			continue;
693 		}
694 
695 		sky_mins_subd[0] = sky_mins[0][i] * HALF_SKY_SUBDIVISIONS;
696 		sky_mins_subd[1] = sky_mins[1][i] * HALF_SKY_SUBDIVISIONS;
697 		sky_maxs_subd[0] = sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS;
698 		sky_maxs_subd[1] = sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS;
699 
700 		if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) {
701 			sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
702 		} else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) {
703 			sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
704 		}
705 		if ( sky_mins_subd[1] < -HALF_SKY_SUBDIVISIONS ) {
706 			sky_mins_subd[1] = -HALF_SKY_SUBDIVISIONS;
707 		} else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) {
708 			sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
709 		}
710 
711 		if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) {
712 			sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
713 		} else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) {
714 			sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
715 		}
716 		if ( sky_maxs_subd[1] < -HALF_SKY_SUBDIVISIONS ) {
717 			sky_maxs_subd[1] = -HALF_SKY_SUBDIVISIONS;
718 		} else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) {
719 			sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
720 		}
721 
722 		//
723 		// iterate through the subdivisions
724 		//
725 		for ( t = sky_mins_subd[1] + HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1] + HALF_SKY_SUBDIVISIONS; t++ )
726 		{
727 			for ( s = sky_mins_subd[0] + HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0] + HALF_SKY_SUBDIVISIONS; s++ )
728 			{
729 				MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
730 							( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
731 							i,
732 							s_skyTexCoords[t][s],
733 							s_skyPoints[t][s] );
734 			}
735 		}
736 
737 		DrawSkySideInner( shader->sky.innerbox[sky_texorder[i]],
738 						  sky_mins_subd,
739 						  sky_maxs_subd );
740 	}
741 
742 }
743 
FillCloudySkySide(const int mins[2],const int maxs[2],qboolean addIndexes)744 static void FillCloudySkySide( const int mins[2], const int maxs[2], qboolean addIndexes ) {
745 	int s, t;
746 	int vertexStart = tess.numVertexes;
747 	int tHeight, sWidth;
748 
749 	tHeight = maxs[1] - mins[1] + 1;
750 	sWidth = maxs[0] - mins[0] + 1;
751 
752 	for ( t = mins[1] + HALF_SKY_SUBDIVISIONS; t <= maxs[1] + HALF_SKY_SUBDIVISIONS; t++ )
753 	{
754 		for ( s = mins[0] + HALF_SKY_SUBDIVISIONS; s <= maxs[0] + HALF_SKY_SUBDIVISIONS; s++ )
755 		{
756 			VectorAdd( s_skyPoints[t][s], backEnd.viewParms.or.origin, tess.xyz[tess.numVertexes] );
757 			tess.texCoords[tess.numVertexes][0] = s_skyTexCoords[t][s][0];
758 			tess.texCoords[tess.numVertexes][1] = s_skyTexCoords[t][s][1];
759 
760 			tess.numVertexes++;
761 
762 			if ( tess.numVertexes >= SHADER_MAX_VERTEXES ) {
763 				ri.Error( ERR_DROP, "SHADER_MAX_VERTEXES hit in FillCloudySkySide()" );
764 			}
765 		}
766 	}
767 
768 	// only add indexes for one pass, otherwise it would draw multiple times for each pass
769 	if ( addIndexes ) {
770 		for ( t = 0; t < tHeight - 1; t++ )
771 		{
772 			for ( s = 0; s < sWidth - 1; s++ )
773 			{
774 				tess.indexes[tess.numIndexes] = vertexStart + s + t * ( sWidth );
775 				tess.numIndexes++;
776 				tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
777 				tess.numIndexes++;
778 				tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
779 				tess.numIndexes++;
780 
781 				tess.indexes[tess.numIndexes] = vertexStart + s + ( t + 1 ) * ( sWidth );
782 				tess.numIndexes++;
783 				tess.indexes[tess.numIndexes] = vertexStart + s + 1 + ( t + 1 ) * ( sWidth );
784 				tess.numIndexes++;
785 				tess.indexes[tess.numIndexes] = vertexStart + s + 1 + t * ( sWidth );
786 				tess.numIndexes++;
787 			}
788 		}
789 	}
790 }
791 
FillCloudBox(const shader_t * shader,int stage)792 static void FillCloudBox( const shader_t *shader, int stage ) {
793 	int i;
794 
795 	for ( i = 0; i < 6; i++ )
796 	{
797 		int sky_mins_subd[2], sky_maxs_subd[2];
798 		int s, t;
799 		float MIN_T;
800 
801 		if ( 1 ) { // FIXME? shader->sky.fullClouds )
802 			MIN_T = -HALF_SKY_SUBDIVISIONS;
803 
804 			// still don't want to draw the bottom, even if fullClouds
805 			if ( i == 5 ) {
806 				continue;
807 			}
808 		} else
809 		{
810 			switch ( i )
811 			{
812 			case 0:
813 			case 1:
814 			case 2:
815 			case 3:
816 				MIN_T = -1;
817 				break;
818 			case 5:
819 				// don't draw clouds beneath you
820 				continue;
821 			case 4:     // top
822 			default:
823 				MIN_T = -HALF_SKY_SUBDIVISIONS;
824 				break;
825 			}
826 		}
827 
828 		sky_mins[0][i] = floor( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
829 		sky_mins[1][i] = floor( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
830 		sky_maxs[0][i] = ceil( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
831 		sky_maxs[1][i] = ceil( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS ) / HALF_SKY_SUBDIVISIONS;
832 
833 		if ( ( sky_mins[0][i] >= sky_maxs[0][i] ) ||
834 			 ( sky_mins[1][i] >= sky_maxs[1][i] ) ) {
835 			continue;
836 		}
837 
838 		sky_mins_subd[0] = ri.ftol( sky_mins[0][i] * HALF_SKY_SUBDIVISIONS );
839 		sky_mins_subd[1] = ri.ftol( sky_mins[1][i] * HALF_SKY_SUBDIVISIONS );
840 		sky_maxs_subd[0] = ri.ftol( sky_maxs[0][i] * HALF_SKY_SUBDIVISIONS );
841 		sky_maxs_subd[1] = ri.ftol( sky_maxs[1][i] * HALF_SKY_SUBDIVISIONS );
842 
843 		if ( sky_mins_subd[0] < -HALF_SKY_SUBDIVISIONS ) {
844 			sky_mins_subd[0] = -HALF_SKY_SUBDIVISIONS;
845 		} else if ( sky_mins_subd[0] > HALF_SKY_SUBDIVISIONS ) {
846 			sky_mins_subd[0] = HALF_SKY_SUBDIVISIONS;
847 		}
848 		if ( sky_mins_subd[1] < MIN_T ) {
849 			sky_mins_subd[1] = MIN_T;
850 		} else if ( sky_mins_subd[1] > HALF_SKY_SUBDIVISIONS ) {
851 			sky_mins_subd[1] = HALF_SKY_SUBDIVISIONS;
852 		}
853 
854 		if ( sky_maxs_subd[0] < -HALF_SKY_SUBDIVISIONS ) {
855 			sky_maxs_subd[0] = -HALF_SKY_SUBDIVISIONS;
856 		} else if ( sky_maxs_subd[0] > HALF_SKY_SUBDIVISIONS ) {
857 			sky_maxs_subd[0] = HALF_SKY_SUBDIVISIONS;
858 		}
859 		if ( sky_maxs_subd[1] < MIN_T ) {
860 			sky_maxs_subd[1] = MIN_T;
861 		} else if ( sky_maxs_subd[1] > HALF_SKY_SUBDIVISIONS ) {
862 			sky_maxs_subd[1] = HALF_SKY_SUBDIVISIONS;
863 		}
864 
865 		//
866 		// iterate through the subdivisions
867 		//
868 		for ( t = sky_mins_subd[1] + HALF_SKY_SUBDIVISIONS; t <= sky_maxs_subd[1] + HALF_SKY_SUBDIVISIONS; t++ )
869 		{
870 			for ( s = sky_mins_subd[0] + HALF_SKY_SUBDIVISIONS; s <= sky_maxs_subd[0] + HALF_SKY_SUBDIVISIONS; s++ )
871 			{
872 				MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
873 							( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
874 							i,
875 							NULL,
876 							s_skyPoints[t][s] );
877 
878 				s_skyTexCoords[t][s][0] = s_cloudTexCoords[i][t][s][0];
879 				s_skyTexCoords[t][s][1] = s_cloudTexCoords[i][t][s][1];
880 			}
881 		}
882 
883 		// only add indexes for first stage
884 		FillCloudySkySide( sky_mins_subd, sky_maxs_subd, ( stage == 0 ) );
885 	}
886 }
887 
888 /*
889 ** R_BuildCloudData
890 */
R_BuildCloudData(shaderCommands_t * input)891 void R_BuildCloudData( shaderCommands_t *input ) {
892 	int i;
893 	shader_t    *shader;
894 
895 	shader = input->shader;
896 
897 	assert( shader->isSky );
898 
899 	sky_min = 1.0 / 256.0f;     // FIXME: not correct?
900 	sky_max = 255.0 / 256.0f;
901 
902 	// set up for drawing
903 	tess.numIndexes = 0;
904 	tess.numVertexes = 0;
905 	tess.firstIndex = 0;
906 
907 	if ( shader->sky.cloudHeight ) {
908 		for ( i = 0; i < MAX_SHADER_STAGES; i++ )
909 		{
910 			if ( !tess.xstages[i] ) {
911 				break;
912 			}
913 			FillCloudBox( shader, i );
914 		}
915 	}
916 }
917 
918 /*
919 ** R_InitSkyTexCoords
920 ** Called when a sky shader is parsed
921 */
922 #define SQR( a ) ( ( a ) * ( a ) )
R_InitSkyTexCoords(float heightCloud)923 void R_InitSkyTexCoords( float heightCloud ) {
924 	int i, s, t;
925 	float radiusWorld = 4096;
926 	float p;
927 	float sRad, tRad;
928 	vec3_t skyVec;
929 	vec3_t v;
930 
931 	// init zfar so MakeSkyVec works even though
932 	// a world hasn't been bounded
933 	backEnd.viewParms.zFar = 1024;
934 
935 	for ( i = 0; i < 6; i++ )
936 	{
937 		for ( t = 0; t <= SKY_SUBDIVISIONS; t++ )
938 		{
939 			for ( s = 0; s <= SKY_SUBDIVISIONS; s++ )
940 			{
941 				// compute vector from view origin to sky side integral point
942 				MakeSkyVec( ( s - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
943 							( t - HALF_SKY_SUBDIVISIONS ) / ( float ) HALF_SKY_SUBDIVISIONS,
944 							i,
945 							NULL,
946 							skyVec );
947 
948 				// compute parametric value 'p' that intersects with cloud layer
949 				p = ( 1.0f / ( 2 * DotProduct( skyVec, skyVec ) ) ) *
950 					( -2 * skyVec[2] * radiusWorld +
951 					  2 * sqrt( SQR( skyVec[2] ) * SQR( radiusWorld ) +
952 								2 * SQR( skyVec[0] ) * radiusWorld * heightCloud +
953 								SQR( skyVec[0] ) * SQR( heightCloud ) +
954 								2 * SQR( skyVec[1] ) * radiusWorld * heightCloud +
955 								SQR( skyVec[1] ) * SQR( heightCloud ) +
956 								2 * SQR( skyVec[2] ) * radiusWorld * heightCloud +
957 								SQR( skyVec[2] ) * SQR( heightCloud ) ) );
958 
959 				s_cloudTexP[i][t][s] = p;
960 
961 				// compute intersection point based on p
962 				VectorScale( skyVec, p, v );
963 				v[2] += radiusWorld;
964 
965 				// compute vector from world origin to intersection point 'v'
966 				VectorNormalize( v );
967 
968 				sRad = Q_acos( v[0] );
969 				tRad = Q_acos( v[1] );
970 
971 				s_cloudTexCoords[i][t][s][0] = sRad;
972 				s_cloudTexCoords[i][t][s][1] = tRad;
973 			}
974 		}
975 	}
976 }
977 
978 //======================================================================================
979 
980 /*
981 ==============
982 RB_DrawSun
983 	(SA) FIXME: sun should render behind clouds, so passing dark areas cover it up
984 ==============
985 */
RB_DrawSun(float scale,shader_t * shader)986 void RB_DrawSun( float scale, shader_t *shader ) {
987 	float size;
988 	float dist;
989 	vec3_t origin, vec1, vec2;
990 	vec3_t    temp;
991 //	vec4_t color;
992 
993 	if ( !shader ) {
994 		return;
995 	}
996 
997 	if ( !backEnd.skyRenderedThisView ) {
998 		return;
999 	}
1000 
1001 	//qglLoadMatrixf( backEnd.viewParms.world.modelMatrix );
1002 	//qglTranslatef (backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2]);
1003 	{
1004 		// FIXME: this could be a lot cleaner
1005 		mat4_t translation, modelview;
1006 
1007 		Mat4Translation( backEnd.viewParms.or.origin, translation );
1008 		Mat4Multiply( backEnd.viewParms.world.modelMatrix, translation, modelview );
1009 		GL_SetModelviewMatrix( modelview );
1010 	}
1011 
1012 	dist =  backEnd.viewParms.zFar / 1.75;      // div sqrt(3)
1013 
1014 	// (SA) shrunk the size of the sun
1015 	size = dist * scale;
1016 
1017 	VectorScale( tr.sunDirection, dist, origin );
1018 	PerpendicularVector( vec1, tr.sunDirection );
1019 	CrossProduct( tr.sunDirection, vec1, vec2 );
1020 
1021 	VectorScale( vec1, size, vec1 );
1022 	VectorScale( vec2, size, vec2 );
1023 
1024 	// farthest depth range
1025 	qglDepthRange( 1.0, 1.0 );
1026 
1027 	RB_BeginSurface( shader, 0, 0 );
1028 
1029 //	color[0] = color[1] = color[2] = color[3] = 1;
1030 
1031 	RB_AddQuadStamp(origin, vec1, vec2, colorWhite);
1032 
1033 	RB_EndSurface();
1034 
1035 
1036 	if ( r_drawSun->integer > 1 ) { // draw flare effect
1037 		// (SA) FYI:	This is cheezy and was only a test so far.
1038 		//				If we decide to use the flare business I will /definatly/ improve all this
1039 
1040 		// get a point a little closer
1041 		dist = dist * 0.7;
1042 		VectorScale( tr.sunDirection, dist, origin );
1043 
1044 		// and make the flare a little smaller
1045 		VectorScale( vec1, 0.5f, vec1 );
1046 		VectorScale( vec2, 0.5f, vec2 );
1047 
1048 		// add the vectors to give an 'off angle' result
1049 		VectorAdd( tr.sunDirection, backEnd.viewParms.or.axis[0], temp );
1050 		VectorNormalize( temp );
1051 
1052 		// amplify the result
1053 		origin[0] += temp[0] * 500.0;
1054 		origin[1] += temp[1] * 500.0;
1055 		origin[2] += temp[2] * 500.0;
1056 
1057 		// (SA) FIXME: todo: flare effect should render last (on top of everything else) and only when sun is in view (sun moving out of camera past degree n should start to cause flare dimming until view angle to sun is off by angle n + x.
1058 
1059 		// draw the flare
1060 		RB_BeginSurface( tr.sunflareShader_old[0], 0, 0 );
1061 		RB_AddQuadStamp( origin, vec1, vec2, colorWhite );
1062 		RB_EndSurface();
1063 	}
1064 
1065 	// back to normal depth range
1066 	qglDepthRange( 0.0, 1.0 );
1067 }
1068 
1069 /*
1070 ================
1071 RB_StageIteratorSky
1072 
1073 All of the visible sky triangles are in tess
1074 
1075 Other things could be stuck in here, like birds in the sky, etc
1076 ================
1077 */
RB_StageIteratorSky(void)1078 void RB_StageIteratorSky( void ) {
1079 	if ( r_fastsky->integer ) {
1080 		return;
1081 	}
1082 
1083 	// when portal sky exists, only render skybox for the portal sky scene
1084 	if ( skyboxportal && !( backEnd.refdef.rdflags & RDF_SKYBOXPORTAL ) ) {
1085 		return;
1086 	}
1087 
1088 	// does the current fog require fastsky?
1089 	if ( backEnd.viewParms.glFog.registered ) {
1090 		if ( !backEnd.viewParms.glFog.drawsky ) {
1091 			return;
1092 		}
1093 	} else if ( glfogNum > FOG_NONE )      {
1094 		if ( !glfogsettings[FOG_CURRENT].drawsky ) {
1095 			return;
1096 		}
1097 	}
1098 
1099 
1100 	backEnd.refdef.rdflags |= RDF_DRAWINGSKY;
1101 
1102 
1103 	// go through all the polygons and project them onto
1104 	// the sky box to see which blocks on each side need
1105 	// to be drawn
1106 	RB_ClipSkyPolygons( &tess );
1107 
1108 	// r_showsky will let all the sky blocks be drawn in
1109 	// front of everything to allow developers to see how
1110 	// much sky is getting sucked in
1111 	if ( r_showsky->integer ) {
1112 		qglDepthRange( 0.0, 0.0 );
1113 	} else {
1114 		qglDepthRange( 1.0, 1.0 );
1115 	}
1116 
1117 	// draw the outer skybox
1118 	if ( tess.shader->sky.outerbox[0] && tess.shader->sky.outerbox[0] != tr.defaultImage ) {
1119 		mat4_t oldmodelview;
1120 
1121 		GL_State( 0 );
1122 		GL_Cull( CT_FRONT_SIDED );
1123 		//qglTranslatef( backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2] );
1124 
1125 		{
1126 			// FIXME: this could be a lot cleaner
1127 			mat4_t trans, product;
1128 
1129 			Mat4Copy( glState.modelview, oldmodelview );
1130 			Mat4Translation( backEnd.viewParms.or.origin, trans );
1131 			Mat4Multiply( glState.modelview, trans, product );
1132 			GL_SetModelviewMatrix( product );
1133 
1134 		}
1135 
1136 		DrawSkyBox( tess.shader );
1137 
1138 		GL_SetModelviewMatrix( oldmodelview );
1139 	}
1140 
1141 	// generate the vertexes for all the clouds, which will be drawn
1142 	// by the generic shader routine
1143 	R_BuildCloudData( &tess );
1144 
1145 	RB_StageIteratorGeneric();
1146 
1147 	// draw the inner skybox
1148 	// Rafael - drawing inner skybox
1149 	if ( tess.shader->sky.innerbox[0] && tess.shader->sky.innerbox[0] != tr.defaultImage ) {
1150 		mat4_t oldmodelview;
1151 
1152 		GL_State( 0 );
1153 		GL_Cull( CT_FRONT_SIDED );
1154 		//qglTranslatef( backEnd.viewParms.or.origin[0], backEnd.viewParms.or.origin[1], backEnd.viewParms.or.origin[2] );
1155 
1156 		{
1157 			// FIXME: this could be a lot cleaner
1158 			mat4_t trans, product;
1159 
1160 			Mat4Copy( glState.modelview, oldmodelview );
1161 			Mat4Translation( backEnd.viewParms.or.origin, trans );
1162 			Mat4Multiply( glState.modelview, trans, product );
1163 			GL_SetModelviewMatrix( product );
1164 
1165 		}
1166 
1167 		DrawSkyBoxInner( tess.shader );
1168 
1169 		GL_SetModelviewMatrix( oldmodelview );
1170 	}
1171 	// Rafael - end
1172 
1173 	// back to normal depth range
1174 	qglDepthRange( 0.0, 1.0 );
1175 
1176 	backEnd.refdef.rdflags &= ~RDF_DRAWINGSKY;
1177 
1178 	// note that sky was drawn so we will draw a sun later
1179 	backEnd.skyRenderedThisView = qtrue;
1180 }
1181 
1182