gl_light.c (14896B)
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 // r_light.c 21 22 #include "gl_local.h" 23 24 int r_dlightframecount; 25 26 #define DLIGHT_CUTOFF 64 27 28 /* 29 ============================================================================= 30 31 DYNAMIC LIGHTS BLEND RENDERING 32 33 ============================================================================= 34 */ 35 36 void R_RenderDlight (dlight_t *light) 37 { 38 int i, j; 39 float a; 40 vec3_t v; 41 float rad; 42 43 rad = light->intensity * 0.35; 44 45 VectorSubtract (light->origin, r_origin, v); 46 #if 0 47 // FIXME? 48 if (VectorLength (v) < rad) 49 { // view is inside the dlight 50 V_AddBlend (light->color[0], light->color[1], light->color[2], light->intensity * 0.0003, v_blend); 51 return; 52 } 53 #endif 54 55 qglBegin (GL_TRIANGLE_FAN); 56 qglColor3f (light->color[0]*0.2, light->color[1]*0.2, light->color[2]*0.2); 57 for (i=0 ; i<3 ; i++) 58 v[i] = light->origin[i] - vpn[i]*rad; 59 qglVertex3fv (v); 60 qglColor3f (0,0,0); 61 for (i=16 ; i>=0 ; i--) 62 { 63 a = i/16.0 * M_PI*2; 64 for (j=0 ; j<3 ; j++) 65 v[j] = light->origin[j] + vright[j]*cos(a)*rad 66 + vup[j]*sin(a)*rad; 67 qglVertex3fv (v); 68 } 69 qglEnd (); 70 } 71 72 /* 73 ============= 74 R_RenderDlights 75 ============= 76 */ 77 void R_RenderDlights (void) 78 { 79 int i; 80 dlight_t *l; 81 82 if (!gl_flashblend->value) 83 return; 84 85 r_dlightframecount = r_framecount + 1; // because the count hasn't 86 // advanced yet for this frame 87 qglDepthMask (0); 88 qglDisable (GL_TEXTURE_2D); 89 qglShadeModel (GL_SMOOTH); 90 qglEnable (GL_BLEND); 91 qglBlendFunc (GL_ONE, GL_ONE); 92 93 l = r_newrefdef.dlights; 94 for (i=0 ; i<r_newrefdef.num_dlights ; i++, l++) 95 R_RenderDlight (l); 96 97 qglColor3f (1,1,1); 98 qglDisable (GL_BLEND); 99 qglEnable (GL_TEXTURE_2D); 100 qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 101 qglDepthMask (1); 102 } 103 104 105 /* 106 ============================================================================= 107 108 DYNAMIC LIGHTS 109 110 ============================================================================= 111 */ 112 113 /* 114 ============= 115 R_MarkLights 116 ============= 117 */ 118 void R_MarkLights (dlight_t *light, int bit, mnode_t *node) 119 { 120 cplane_t *splitplane; 121 float dist; 122 msurface_t *surf; 123 int i; 124 125 if (node->contents != -1) 126 return; 127 128 splitplane = node->plane; 129 dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; 130 131 if (dist > light->intensity-DLIGHT_CUTOFF) 132 { 133 R_MarkLights (light, bit, node->children[0]); 134 return; 135 } 136 if (dist < -light->intensity+DLIGHT_CUTOFF) 137 { 138 R_MarkLights (light, bit, node->children[1]); 139 return; 140 } 141 142 // mark the polygons 143 surf = r_worldmodel->surfaces + node->firstsurface; 144 for (i=0 ; i<node->numsurfaces ; i++, surf++) 145 { 146 if (surf->dlightframe != r_dlightframecount) 147 { 148 surf->dlightbits = 0; 149 surf->dlightframe = r_dlightframecount; 150 } 151 surf->dlightbits |= bit; 152 } 153 154 R_MarkLights (light, bit, node->children[0]); 155 R_MarkLights (light, bit, node->children[1]); 156 } 157 158 159 /* 160 ============= 161 R_PushDlights 162 ============= 163 */ 164 void R_PushDlights (void) 165 { 166 int i; 167 dlight_t *l; 168 169 if (gl_flashblend->value) 170 return; 171 172 r_dlightframecount = r_framecount + 1; // because the count hasn't 173 // advanced yet for this frame 174 l = r_newrefdef.dlights; 175 for (i=0 ; i<r_newrefdef.num_dlights ; i++, l++) 176 R_MarkLights ( l, 1<<i, r_worldmodel->nodes ); 177 } 178 179 180 /* 181 ============================================================================= 182 183 LIGHT SAMPLING 184 185 ============================================================================= 186 */ 187 188 vec3_t pointcolor; 189 cplane_t *lightplane; // used as shadow plane 190 vec3_t lightspot; 191 192 int RecursiveLightPoint (mnode_t *node, vec3_t start, vec3_t end) 193 { 194 float front, back, frac; 195 int side; 196 cplane_t *plane; 197 vec3_t mid; 198 msurface_t *surf; 199 int s, t, ds, dt; 200 int i; 201 mtexinfo_t *tex; 202 byte *lightmap; 203 int maps; 204 int r; 205 206 if (node->contents != -1) 207 return -1; // didn't hit anything 208 209 // calculate mid point 210 211 // FIXME: optimize for axial 212 plane = node->plane; 213 front = DotProduct (start, plane->normal) - plane->dist; 214 back = DotProduct (end, plane->normal) - plane->dist; 215 side = front < 0; 216 217 if ( (back < 0) == side) 218 return RecursiveLightPoint (node->children[side], start, end); 219 220 frac = front / (front-back); 221 mid[0] = start[0] + (end[0] - start[0])*frac; 222 mid[1] = start[1] + (end[1] - start[1])*frac; 223 mid[2] = start[2] + (end[2] - start[2])*frac; 224 225 // go down front side 226 r = RecursiveLightPoint (node->children[side], start, mid); 227 if (r >= 0) 228 return r; // hit something 229 230 if ( (back < 0) == side ) 231 return -1; // didn't hit anuthing 232 233 // check for impact on this node 234 VectorCopy (mid, lightspot); 235 lightplane = plane; 236 237 surf = r_worldmodel->surfaces + node->firstsurface; 238 for (i=0 ; i<node->numsurfaces ; i++, surf++) 239 { 240 if (surf->flags&(SURF_DRAWTURB|SURF_DRAWSKY)) 241 continue; // no lightmaps 242 243 tex = surf->texinfo; 244 245 s = DotProduct (mid, tex->vecs[0]) + tex->vecs[0][3]; 246 t = DotProduct (mid, tex->vecs[1]) + tex->vecs[1][3];; 247 248 if (s < surf->texturemins[0] || 249 t < surf->texturemins[1]) 250 continue; 251 252 ds = s - surf->texturemins[0]; 253 dt = t - surf->texturemins[1]; 254 255 if ( ds > surf->extents[0] || dt > surf->extents[1] ) 256 continue; 257 258 if (!surf->samples) 259 return 0; 260 261 ds >>= 4; 262 dt >>= 4; 263 264 lightmap = surf->samples; 265 VectorCopy (vec3_origin, pointcolor); 266 if (lightmap) 267 { 268 vec3_t scale; 269 270 lightmap += 3*(dt * ((surf->extents[0]>>4)+1) + ds); 271 272 for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; 273 maps++) 274 { 275 for (i=0 ; i<3 ; i++) 276 scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i]; 277 278 pointcolor[0] += lightmap[0] * scale[0] * (1.0/255); 279 pointcolor[1] += lightmap[1] * scale[1] * (1.0/255); 280 pointcolor[2] += lightmap[2] * scale[2] * (1.0/255); 281 lightmap += 3*((surf->extents[0]>>4)+1) * 282 ((surf->extents[1]>>4)+1); 283 } 284 } 285 286 return 1; 287 } 288 289 // go down back side 290 return RecursiveLightPoint (node->children[!side], mid, end); 291 } 292 293 /* 294 =============== 295 R_LightPoint 296 =============== 297 */ 298 void R_LightPoint (vec3_t p, vec3_t color) 299 { 300 vec3_t end; 301 float r; 302 int lnum; 303 dlight_t *dl; 304 float light; 305 vec3_t dist; 306 float add; 307 308 if (!r_worldmodel->lightdata) 309 { 310 color[0] = color[1] = color[2] = 1.0; 311 return; 312 } 313 314 end[0] = p[0]; 315 end[1] = p[1]; 316 end[2] = p[2] - 2048; 317 318 r = RecursiveLightPoint (r_worldmodel->nodes, p, end); 319 320 if (r == -1) 321 { 322 VectorCopy (vec3_origin, color); 323 } 324 else 325 { 326 VectorCopy (pointcolor, color); 327 } 328 329 // 330 // add dynamic lights 331 // 332 light = 0; 333 dl = r_newrefdef.dlights; 334 for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++, dl++) 335 { 336 VectorSubtract (currententity->origin, 337 dl->origin, 338 dist); 339 add = dl->intensity - VectorLength(dist); 340 add *= (1.0/256); 341 if (add > 0) 342 { 343 VectorMA (color, add, dl->color, color); 344 } 345 } 346 347 VectorScale (color, gl_modulate->value, color); 348 } 349 350 351 //=================================================================== 352 353 static float s_blocklights[34*34*3]; 354 /* 355 =============== 356 R_AddDynamicLights 357 =============== 358 */ 359 void R_AddDynamicLights (msurface_t *surf) 360 { 361 int lnum; 362 int sd, td; 363 float fdist, frad, fminlight; 364 vec3_t impact, local; 365 int s, t; 366 int i; 367 int smax, tmax; 368 mtexinfo_t *tex; 369 dlight_t *dl; 370 float *pfBL; 371 float fsacc, ftacc; 372 373 smax = (surf->extents[0]>>4)+1; 374 tmax = (surf->extents[1]>>4)+1; 375 tex = surf->texinfo; 376 377 for (lnum=0 ; lnum<r_newrefdef.num_dlights ; lnum++) 378 { 379 if ( !(surf->dlightbits & (1<<lnum) ) ) 380 continue; // not lit by this light 381 382 dl = &r_newrefdef.dlights[lnum]; 383 frad = dl->intensity; 384 fdist = DotProduct (dl->origin, surf->plane->normal) - 385 surf->plane->dist; 386 frad -= fabs(fdist); 387 // rad is now the highest intensity on the plane 388 389 fminlight = DLIGHT_CUTOFF; // FIXME: make configurable? 390 if (frad < fminlight) 391 continue; 392 fminlight = frad - fminlight; 393 394 for (i=0 ; i<3 ; i++) 395 { 396 impact[i] = dl->origin[i] - 397 surf->plane->normal[i]*fdist; 398 } 399 400 local[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3] - surf->texturemins[0]; 401 local[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3] - surf->texturemins[1]; 402 403 pfBL = s_blocklights; 404 for (t = 0, ftacc = 0 ; t<tmax ; t++, ftacc += 16) 405 { 406 td = local[1] - ftacc; 407 if ( td < 0 ) 408 td = -td; 409 410 for ( s=0, fsacc = 0 ; s<smax ; s++, fsacc += 16, pfBL += 3) 411 { 412 sd = Q_ftol( local[0] - fsacc ); 413 414 if ( sd < 0 ) 415 sd = -sd; 416 417 if (sd > td) 418 fdist = sd + (td>>1); 419 else 420 fdist = td + (sd>>1); 421 422 if ( fdist < fminlight ) 423 { 424 pfBL[0] += ( frad - fdist ) * dl->color[0]; 425 pfBL[1] += ( frad - fdist ) * dl->color[1]; 426 pfBL[2] += ( frad - fdist ) * dl->color[2]; 427 } 428 } 429 } 430 } 431 } 432 433 434 /* 435 ** R_SetCacheState 436 */ 437 void R_SetCacheState( msurface_t *surf ) 438 { 439 int maps; 440 441 for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; 442 maps++) 443 { 444 surf->cached_light[maps] = r_newrefdef.lightstyles[surf->styles[maps]].white; 445 } 446 } 447 448 /* 449 =============== 450 R_BuildLightMap 451 452 Combine and scale multiple lightmaps into the floating format in blocklights 453 =============== 454 */ 455 void R_BuildLightMap (msurface_t *surf, byte *dest, int stride) 456 { 457 int smax, tmax; 458 int r, g, b, a, max; 459 int i, j, size; 460 byte *lightmap; 461 float scale[4]; 462 int nummaps; 463 float *bl; 464 lightstyle_t *style; 465 int monolightmap; 466 467 if ( surf->texinfo->flags & (SURF_SKY|SURF_TRANS33|SURF_TRANS66|SURF_WARP) ) 468 ri.Sys_Error (ERR_DROP, "R_BuildLightMap called for non-lit surface"); 469 470 smax = (surf->extents[0]>>4)+1; 471 tmax = (surf->extents[1]>>4)+1; 472 size = smax*tmax; 473 if (size > (sizeof(s_blocklights)>>4) ) 474 ri.Sys_Error (ERR_DROP, "Bad s_blocklights size"); 475 476 // set to full bright if no light data 477 if (!surf->samples) 478 { 479 int maps; 480 481 for (i=0 ; i<size*3 ; i++) 482 s_blocklights[i] = 255; 483 for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; 484 maps++) 485 { 486 style = &r_newrefdef.lightstyles[surf->styles[maps]]; 487 } 488 goto store; 489 } 490 491 // count the # of maps 492 for ( nummaps = 0 ; nummaps < MAXLIGHTMAPS && surf->styles[nummaps] != 255 ; 493 nummaps++) 494 ; 495 496 lightmap = surf->samples; 497 498 // add all the lightmaps 499 if ( nummaps == 1 ) 500 { 501 int maps; 502 503 for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; 504 maps++) 505 { 506 bl = s_blocklights; 507 508 for (i=0 ; i<3 ; i++) 509 scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i]; 510 511 if ( scale[0] == 1.0F && 512 scale[1] == 1.0F && 513 scale[2] == 1.0F ) 514 { 515 for (i=0 ; i<size ; i++, bl+=3) 516 { 517 bl[0] = lightmap[i*3+0]; 518 bl[1] = lightmap[i*3+1]; 519 bl[2] = lightmap[i*3+2]; 520 } 521 } 522 else 523 { 524 for (i=0 ; i<size ; i++, bl+=3) 525 { 526 bl[0] = lightmap[i*3+0] * scale[0]; 527 bl[1] = lightmap[i*3+1] * scale[1]; 528 bl[2] = lightmap[i*3+2] * scale[2]; 529 } 530 } 531 lightmap += size*3; // skip to next lightmap 532 } 533 } 534 else 535 { 536 int maps; 537 538 memset( s_blocklights, 0, sizeof( s_blocklights[0] ) * size * 3 ); 539 540 for (maps = 0 ; maps < MAXLIGHTMAPS && surf->styles[maps] != 255 ; 541 maps++) 542 { 543 bl = s_blocklights; 544 545 for (i=0 ; i<3 ; i++) 546 scale[i] = gl_modulate->value*r_newrefdef.lightstyles[surf->styles[maps]].rgb[i]; 547 548 if ( scale[0] == 1.0F && 549 scale[1] == 1.0F && 550 scale[2] == 1.0F ) 551 { 552 for (i=0 ; i<size ; i++, bl+=3 ) 553 { 554 bl[0] += lightmap[i*3+0]; 555 bl[1] += lightmap[i*3+1]; 556 bl[2] += lightmap[i*3+2]; 557 } 558 } 559 else 560 { 561 for (i=0 ; i<size ; i++, bl+=3) 562 { 563 bl[0] += lightmap[i*3+0] * scale[0]; 564 bl[1] += lightmap[i*3+1] * scale[1]; 565 bl[2] += lightmap[i*3+2] * scale[2]; 566 } 567 } 568 lightmap += size*3; // skip to next lightmap 569 } 570 } 571 572 // add all the dynamic lights 573 if (surf->dlightframe == r_framecount) 574 R_AddDynamicLights (surf); 575 576 // put into texture format 577 store: 578 stride -= (smax<<2); 579 bl = s_blocklights; 580 581 monolightmap = gl_monolightmap->string[0]; 582 583 if ( monolightmap == '0' ) 584 { 585 for (i=0 ; i<tmax ; i++, dest += stride) 586 { 587 for (j=0 ; j<smax ; j++) 588 { 589 590 r = Q_ftol( bl[0] ); 591 g = Q_ftol( bl[1] ); 592 b = Q_ftol( bl[2] ); 593 594 // catch negative lights 595 if (r < 0) 596 r = 0; 597 if (g < 0) 598 g = 0; 599 if (b < 0) 600 b = 0; 601 602 /* 603 ** determine the brightest of the three color components 604 */ 605 if (r > g) 606 max = r; 607 else 608 max = g; 609 if (b > max) 610 max = b; 611 612 /* 613 ** alpha is ONLY used for the mono lightmap case. For this reason 614 ** we set it to the brightest of the color components so that 615 ** things don't get too dim. 616 */ 617 a = max; 618 619 /* 620 ** rescale all the color components if the intensity of the greatest 621 ** channel exceeds 1.0 622 */ 623 if (max > 255) 624 { 625 float t = 255.0F / max; 626 627 r = r*t; 628 g = g*t; 629 b = b*t; 630 a = a*t; 631 } 632 633 dest[0] = r; 634 dest[1] = g; 635 dest[2] = b; 636 dest[3] = a; 637 638 bl += 3; 639 dest += 4; 640 } 641 } 642 } 643 else 644 { 645 for (i=0 ; i<tmax ; i++, dest += stride) 646 { 647 for (j=0 ; j<smax ; j++) 648 { 649 650 r = Q_ftol( bl[0] ); 651 g = Q_ftol( bl[1] ); 652 b = Q_ftol( bl[2] ); 653 654 // catch negative lights 655 if (r < 0) 656 r = 0; 657 if (g < 0) 658 g = 0; 659 if (b < 0) 660 b = 0; 661 662 /* 663 ** determine the brightest of the three color components 664 */ 665 if (r > g) 666 max = r; 667 else 668 max = g; 669 if (b > max) 670 max = b; 671 672 /* 673 ** alpha is ONLY used for the mono lightmap case. For this reason 674 ** we set it to the brightest of the color components so that 675 ** things don't get too dim. 676 */ 677 a = max; 678 679 /* 680 ** rescale all the color components if the intensity of the greatest 681 ** channel exceeds 1.0 682 */ 683 if (max > 255) 684 { 685 float t = 255.0F / max; 686 687 r = r*t; 688 g = g*t; 689 b = b*t; 690 a = a*t; 691 } 692 693 /* 694 ** So if we are doing alpha lightmaps we need to set the R, G, and B 695 ** components to 0 and we need to set alpha to 1-alpha. 696 */ 697 switch ( monolightmap ) 698 { 699 case 'L': 700 case 'I': 701 r = a; 702 g = b = 0; 703 break; 704 case 'C': 705 // try faking colored lighting 706 a = 255 - ((r+g+b)/3); 707 r *= a/255.0; 708 g *= a/255.0; 709 b *= a/255.0; 710 break; 711 case 'A': 712 default: 713 r = g = b = 0; 714 a = 255 - a; 715 break; 716 } 717 718 dest[0] = r; 719 dest[1] = g; 720 dest[2] = b; 721 dest[3] = a; 722 723 bl += 3; 724 dest += 4; 725 } 726 } 727 } 728 } 729