gl_warp.c (12452B)
1 /* 2 Copyright (C) 1997-2001 Id Software, Inc. 3 4 This program is free software; you can redistribute it and/or 5 modify it under the terms of the GNU General Public License 6 as published by the Free Software Foundation; either version 2 7 of the License, or (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 See the GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19 */ 20 // gl_warp.c -- sky and water polygons 21 22 #include "gl_local.h" 23 24 extern model_t *loadmodel; 25 26 char skyname[MAX_QPATH]; 27 float skyrotate; 28 vec3_t skyaxis; 29 image_t *sky_images[6]; 30 31 msurface_t *warpface; 32 33 #define SUBDIVIDE_SIZE 64 34 //#define SUBDIVIDE_SIZE 1024 35 36 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs) 37 { 38 int i, j; 39 float *v; 40 41 mins[0] = mins[1] = mins[2] = 9999; 42 maxs[0] = maxs[1] = maxs[2] = -9999; 43 v = verts; 44 for (i=0 ; i<numverts ; i++) 45 for (j=0 ; j<3 ; j++, v++) 46 { 47 if (*v < mins[j]) 48 mins[j] = *v; 49 if (*v > maxs[j]) 50 maxs[j] = *v; 51 } 52 } 53 54 void SubdividePolygon (int numverts, float *verts) 55 { 56 int i, j, k; 57 vec3_t mins, maxs; 58 float m; 59 float *v; 60 vec3_t front[64], back[64]; 61 int f, b; 62 float dist[64]; 63 float frac; 64 glpoly_t *poly; 65 float s, t; 66 vec3_t total; 67 float total_s, total_t; 68 69 if (numverts > 60) 70 ri.Sys_Error (ERR_DROP, "numverts = %i", numverts); 71 72 BoundPoly (numverts, verts, mins, maxs); 73 74 for (i=0 ; i<3 ; i++) 75 { 76 m = (mins[i] + maxs[i]) * 0.5; 77 m = SUBDIVIDE_SIZE * floor (m/SUBDIVIDE_SIZE + 0.5); 78 if (maxs[i] - m < 8) 79 continue; 80 if (m - mins[i] < 8) 81 continue; 82 83 // cut it 84 v = verts + i; 85 for (j=0 ; j<numverts ; j++, v+= 3) 86 dist[j] = *v - m; 87 88 // wrap cases 89 dist[j] = dist[0]; 90 v-=i; 91 VectorCopy (verts, v); 92 93 f = b = 0; 94 v = verts; 95 for (j=0 ; j<numverts ; j++, v+= 3) 96 { 97 if (dist[j] >= 0) 98 { 99 VectorCopy (v, front[f]); 100 f++; 101 } 102 if (dist[j] <= 0) 103 { 104 VectorCopy (v, back[b]); 105 b++; 106 } 107 if (dist[j] == 0 || dist[j+1] == 0) 108 continue; 109 if ( (dist[j] > 0) != (dist[j+1] > 0) ) 110 { 111 // clip point 112 frac = dist[j] / (dist[j] - dist[j+1]); 113 for (k=0 ; k<3 ; k++) 114 front[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]); 115 f++; 116 b++; 117 } 118 } 119 120 SubdividePolygon (f, front[0]); 121 SubdividePolygon (b, back[0]); 122 return; 123 } 124 125 // add a point in the center to help keep warp valid 126 poly = Hunk_Alloc (sizeof(glpoly_t) + ((numverts-4)+2) * VERTEXSIZE*sizeof(float)); 127 poly->next = warpface->polys; 128 warpface->polys = poly; 129 poly->numverts = numverts+2; 130 VectorClear (total); 131 total_s = 0; 132 total_t = 0; 133 for (i=0 ; i<numverts ; i++, verts+= 3) 134 { 135 VectorCopy (verts, poly->verts[i+1]); 136 s = DotProduct (verts, warpface->texinfo->vecs[0]); 137 t = DotProduct (verts, warpface->texinfo->vecs[1]); 138 139 total_s += s; 140 total_t += t; 141 VectorAdd (total, verts, total); 142 143 poly->verts[i+1][3] = s; 144 poly->verts[i+1][4] = t; 145 } 146 147 VectorScale (total, (1.0/numverts), poly->verts[0]); 148 poly->verts[0][3] = total_s/numverts; 149 poly->verts[0][4] = total_t/numverts; 150 151 // copy first vertex to last 152 memcpy (poly->verts[i+1], poly->verts[1], sizeof(poly->verts[0])); 153 } 154 155 /* 156 ================ 157 GL_SubdivideSurface 158 159 Breaks a polygon up along axial 64 unit 160 boundaries so that turbulent and sky warps 161 can be done reasonably. 162 ================ 163 */ 164 void GL_SubdivideSurface (msurface_t *fa) 165 { 166 vec3_t verts[64]; 167 int numverts; 168 int i; 169 int lindex; 170 float *vec; 171 172 warpface = fa; 173 174 // 175 // convert edges back to a normal polygon 176 // 177 numverts = 0; 178 for (i=0 ; i<fa->numedges ; i++) 179 { 180 lindex = loadmodel->surfedges[fa->firstedge + i]; 181 182 if (lindex > 0) 183 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position; 184 else 185 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position; 186 VectorCopy (vec, verts[numverts]); 187 numverts++; 188 } 189 190 SubdividePolygon (numverts, verts[0]); 191 } 192 193 //========================================================= 194 195 196 197 // speed up sin calculations - Ed 198 float r_turbsin[] = 199 { 200 #include "warpsin.h" 201 }; 202 #define TURBSCALE (256.0 / (2 * M_PI)) 203 204 /* 205 ============= 206 EmitWaterPolys 207 208 Does a water warp on the pre-fragmented glpoly_t chain 209 ============= 210 */ 211 void EmitWaterPolys (msurface_t *fa) 212 { 213 glpoly_t *p, *bp; 214 float *v; 215 int i; 216 float s, t, os, ot; 217 float scroll; 218 float rdt = r_newrefdef.time; 219 220 if (fa->texinfo->flags & SURF_FLOWING) 221 scroll = -64 * ( (r_newrefdef.time*0.5) - (int)(r_newrefdef.time*0.5) ); 222 else 223 scroll = 0; 224 for (bp=fa->polys ; bp ; bp=bp->next) 225 { 226 p = bp; 227 228 qglBegin (GL_TRIANGLE_FAN); 229 for (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE) 230 { 231 os = v[3]; 232 ot = v[4]; 233 234 #if !id386 235 s = os + r_turbsin[(int)((ot*0.125+r_newrefdef.time) * TURBSCALE) & 255]; 236 #else 237 s = os + r_turbsin[Q_ftol( ((ot*0.125+rdt) * TURBSCALE) ) & 255]; 238 #endif 239 s += scroll; 240 s *= (1.0/64); 241 242 #if !id386 243 t = ot + r_turbsin[(int)((os*0.125+rdt) * TURBSCALE) & 255]; 244 #else 245 t = ot + r_turbsin[Q_ftol( ((os*0.125+rdt) * TURBSCALE) ) & 255]; 246 #endif 247 t *= (1.0/64); 248 249 qglTexCoord2f (s, t); 250 qglVertex3fv (v); 251 } 252 qglEnd (); 253 } 254 } 255 256 257 //=================================================================== 258 259 260 vec3_t skyclip[6] = { 261 {1,1,0}, 262 {1,-1,0}, 263 {0,-1,1}, 264 {0,1,1}, 265 {1,0,1}, 266 {-1,0,1} 267 }; 268 int c_sky; 269 270 // 1 = s, 2 = t, 3 = 2048 271 int st_to_vec[6][3] = 272 { 273 {3,-1,2}, 274 {-3,1,2}, 275 276 {1,3,2}, 277 {-1,-3,2}, 278 279 {-2,-1,3}, // 0 degrees yaw, look straight up 280 {2,-1,-3} // look straight down 281 282 // {-1,2,3}, 283 // {1,2,-3} 284 }; 285 286 // s = [0]/[2], t = [1]/[2] 287 int vec_to_st[6][3] = 288 { 289 {-2,3,1}, 290 {2,3,-1}, 291 292 {1,3,2}, 293 {-1,3,-2}, 294 295 {-2,-1,3}, 296 {-2,1,-3} 297 298 // {-1,2,3}, 299 // {1,2,-3} 300 }; 301 302 float skymins[2][6], skymaxs[2][6]; 303 float sky_min, sky_max; 304 305 void DrawSkyPolygon (int nump, vec3_t vecs) 306 { 307 int i,j; 308 vec3_t v, av; 309 float s, t, dv; 310 int axis; 311 float *vp; 312 313 c_sky++; 314 #if 0 315 glBegin (GL_POLYGON); 316 for (i=0 ; i<nump ; i++, vecs+=3) 317 { 318 VectorAdd(vecs, r_origin, v); 319 qglVertex3fv (v); 320 } 321 glEnd(); 322 return; 323 #endif 324 // decide which face it maps to 325 VectorCopy (vec3_origin, v); 326 for (i=0, vp=vecs ; i<nump ; i++, vp+=3) 327 { 328 VectorAdd (vp, v, v); 329 } 330 av[0] = fabs(v[0]); 331 av[1] = fabs(v[1]); 332 av[2] = fabs(v[2]); 333 if (av[0] > av[1] && av[0] > av[2]) 334 { 335 if (v[0] < 0) 336 axis = 1; 337 else 338 axis = 0; 339 } 340 else if (av[1] > av[2] && av[1] > av[0]) 341 { 342 if (v[1] < 0) 343 axis = 3; 344 else 345 axis = 2; 346 } 347 else 348 { 349 if (v[2] < 0) 350 axis = 5; 351 else 352 axis = 4; 353 } 354 355 // project new texture coords 356 for (i=0 ; i<nump ; i++, vecs+=3) 357 { 358 j = vec_to_st[axis][2]; 359 if (j > 0) 360 dv = vecs[j - 1]; 361 else 362 dv = -vecs[-j - 1]; 363 if (dv < 0.001) 364 continue; // don't divide by zero 365 j = vec_to_st[axis][0]; 366 if (j < 0) 367 s = -vecs[-j -1] / dv; 368 else 369 s = vecs[j-1] / dv; 370 j = vec_to_st[axis][1]; 371 if (j < 0) 372 t = -vecs[-j -1] / dv; 373 else 374 t = vecs[j-1] / dv; 375 376 if (s < skymins[0][axis]) 377 skymins[0][axis] = s; 378 if (t < skymins[1][axis]) 379 skymins[1][axis] = t; 380 if (s > skymaxs[0][axis]) 381 skymaxs[0][axis] = s; 382 if (t > skymaxs[1][axis]) 383 skymaxs[1][axis] = t; 384 } 385 } 386 387 #define ON_EPSILON 0.1 // point on plane side epsilon 388 #define MAX_CLIP_VERTS 64 389 void ClipSkyPolygon (int nump, vec3_t vecs, int stage) 390 { 391 float *norm; 392 float *v; 393 qboolean front, back; 394 float d, e; 395 float dists[MAX_CLIP_VERTS]; 396 int sides[MAX_CLIP_VERTS]; 397 vec3_t newv[2][MAX_CLIP_VERTS]; 398 int newc[2]; 399 int i, j; 400 401 if (nump > MAX_CLIP_VERTS-2) 402 ri.Sys_Error (ERR_DROP, "ClipSkyPolygon: MAX_CLIP_VERTS"); 403 if (stage == 6) 404 { // fully clipped, so draw it 405 DrawSkyPolygon (nump, vecs); 406 return; 407 } 408 409 front = back = false; 410 norm = skyclip[stage]; 411 for (i=0, v = vecs ; i<nump ; i++, v+=3) 412 { 413 d = DotProduct (v, norm); 414 if (d > ON_EPSILON) 415 { 416 front = true; 417 sides[i] = SIDE_FRONT; 418 } 419 else if (d < -ON_EPSILON) 420 { 421 back = true; 422 sides[i] = SIDE_BACK; 423 } 424 else 425 sides[i] = SIDE_ON; 426 dists[i] = d; 427 } 428 429 if (!front || !back) 430 { // not clipped 431 ClipSkyPolygon (nump, vecs, stage+1); 432 return; 433 } 434 435 // clip it 436 sides[i] = sides[0]; 437 dists[i] = dists[0]; 438 VectorCopy (vecs, (vecs+(i*3)) ); 439 newc[0] = newc[1] = 0; 440 441 for (i=0, v = vecs ; i<nump ; i++, v+=3) 442 { 443 switch (sides[i]) 444 { 445 case SIDE_FRONT: 446 VectorCopy (v, newv[0][newc[0]]); 447 newc[0]++; 448 break; 449 case SIDE_BACK: 450 VectorCopy (v, newv[1][newc[1]]); 451 newc[1]++; 452 break; 453 case SIDE_ON: 454 VectorCopy (v, newv[0][newc[0]]); 455 newc[0]++; 456 VectorCopy (v, newv[1][newc[1]]); 457 newc[1]++; 458 break; 459 } 460 461 if (sides[i] == SIDE_ON || sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) 462 continue; 463 464 d = dists[i] / (dists[i] - dists[i+1]); 465 for (j=0 ; j<3 ; j++) 466 { 467 e = v[j] + d*(v[j+3] - v[j]); 468 newv[0][newc[0]][j] = e; 469 newv[1][newc[1]][j] = e; 470 } 471 newc[0]++; 472 newc[1]++; 473 } 474 475 // continue 476 ClipSkyPolygon (newc[0], newv[0][0], stage+1); 477 ClipSkyPolygon (newc[1], newv[1][0], stage+1); 478 } 479 480 /* 481 ================= 482 R_AddSkySurface 483 ================= 484 */ 485 void R_AddSkySurface (msurface_t *fa) 486 { 487 int i; 488 vec3_t verts[MAX_CLIP_VERTS]; 489 glpoly_t *p; 490 491 // calculate vertex values for sky box 492 for (p=fa->polys ; p ; p=p->next) 493 { 494 for (i=0 ; i<p->numverts ; i++) 495 { 496 VectorSubtract (p->verts[i], r_origin, verts[i]); 497 } 498 ClipSkyPolygon (p->numverts, verts[0], 0); 499 } 500 } 501 502 503 /* 504 ============== 505 R_ClearSkyBox 506 ============== 507 */ 508 void R_ClearSkyBox (void) 509 { 510 int i; 511 512 for (i=0 ; i<6 ; i++) 513 { 514 skymins[0][i] = skymins[1][i] = 9999; 515 skymaxs[0][i] = skymaxs[1][i] = -9999; 516 } 517 } 518 519 520 void MakeSkyVec (float s, float t, int axis) 521 { 522 vec3_t v, b; 523 int j, k; 524 525 b[0] = s*2300; 526 b[1] = t*2300; 527 b[2] = 2300; 528 529 for (j=0 ; j<3 ; j++) 530 { 531 k = st_to_vec[axis][j]; 532 if (k < 0) 533 v[j] = -b[-k - 1]; 534 else 535 v[j] = b[k - 1]; 536 } 537 538 // avoid bilerp seam 539 s = (s+1)*0.5; 540 t = (t+1)*0.5; 541 542 if (s < sky_min) 543 s = sky_min; 544 else if (s > sky_max) 545 s = sky_max; 546 if (t < sky_min) 547 t = sky_min; 548 else if (t > sky_max) 549 t = sky_max; 550 551 t = 1.0 - t; 552 qglTexCoord2f (s, t); 553 qglVertex3fv (v); 554 } 555 556 /* 557 ============== 558 R_DrawSkyBox 559 ============== 560 */ 561 int skytexorder[6] = {0,2,1,3,4,5}; 562 void R_DrawSkyBox (void) 563 { 564 int i; 565 566 #if 0 567 qglEnable (GL_BLEND); 568 GL_TexEnv( GL_MODULATE ); 569 qglColor4f (1,1,1,0.5); 570 qglDisable (GL_DEPTH_TEST); 571 #endif 572 if (skyrotate) 573 { // check for no sky at all 574 for (i=0 ; i<6 ; i++) 575 if (skymins[0][i] < skymaxs[0][i] 576 && skymins[1][i] < skymaxs[1][i]) 577 break; 578 if (i == 6) 579 return; // nothing visible 580 } 581 582 qglPushMatrix (); 583 qglTranslatef (r_origin[0], r_origin[1], r_origin[2]); 584 qglRotatef (r_newrefdef.time * skyrotate, skyaxis[0], skyaxis[1], skyaxis[2]); 585 586 for (i=0 ; i<6 ; i++) 587 { 588 if (skyrotate) 589 { // hack, forces full sky to draw when rotating 590 skymins[0][i] = -1; 591 skymins[1][i] = -1; 592 skymaxs[0][i] = 1; 593 skymaxs[1][i] = 1; 594 } 595 596 if (skymins[0][i] >= skymaxs[0][i] 597 || skymins[1][i] >= skymaxs[1][i]) 598 continue; 599 600 GL_Bind (sky_images[skytexorder[i]]->texnum); 601 602 qglBegin (GL_QUADS); 603 MakeSkyVec (skymins[0][i], skymins[1][i], i); 604 MakeSkyVec (skymins[0][i], skymaxs[1][i], i); 605 MakeSkyVec (skymaxs[0][i], skymaxs[1][i], i); 606 MakeSkyVec (skymaxs[0][i], skymins[1][i], i); 607 qglEnd (); 608 } 609 qglPopMatrix (); 610 #if 0 611 glDisable (GL_BLEND); 612 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 613 glColor4f (1,1,1,0.5); 614 glEnable (GL_DEPTH_TEST); 615 #endif 616 } 617 618 619 /* 620 ============ 621 R_SetSky 622 ============ 623 */ 624 // 3dstudio environment map names 625 char *suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"}; 626 void R_SetSky (char *name, float rotate, vec3_t axis) 627 { 628 int i; 629 char pathname[MAX_QPATH]; 630 631 strncpy (skyname, name, sizeof(skyname)-1); 632 skyrotate = rotate; 633 VectorCopy (axis, skyaxis); 634 635 for (i=0 ; i<6 ; i++) 636 { 637 // chop down rotating skies for less memory 638 if (gl_skymip->value || skyrotate) 639 gl_picmip->value++; 640 641 if ( qglColorTableEXT && gl_ext_palettedtexture->value ) 642 Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[i]); 643 else 644 Com_sprintf (pathname, sizeof(pathname), "env/%s%s.tga", skyname, suf[i]); 645 646 sky_images[i] = GL_FindImage (pathname, it_sky); 647 if (!sky_images[i]) 648 sky_images[i] = r_notexture; 649 650 if (gl_skymip->value || skyrotate) 651 { // take less memory 652 gl_picmip->value--; 653 sky_min = 1.0/256; 654 sky_max = 255.0/256; 655 } 656 else 657 { 658 sky_min = 1.0/512; 659 sky_max = 511.0/512; 660 } 661 } 662 }