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