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