light.c (51041B)
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 // light.c 23 24 #include "light.h" 25 #ifdef _WIN32 26 #ifdef _TTIMOBUILD 27 #include "pakstuff.h" 28 #else 29 #include "../libs/pakstuff.h" 30 #endif 31 #endif 32 33 34 #define EXTRASCALE 2 35 36 typedef struct { 37 float plane[4]; 38 vec3_t origin; 39 vec3_t vectors[2]; 40 shaderInfo_t *si; 41 } filter_t; 42 43 #define MAX_FILTERS 1024 44 filter_t filters[MAX_FILTERS]; 45 int numFilters; 46 47 extern char source[1024]; 48 49 qboolean notrace; 50 qboolean patchshadows; 51 qboolean dump; 52 qboolean extra; 53 qboolean extraWide; 54 qboolean lightmapBorder; 55 56 qboolean noSurfaces; 57 58 int samplesize = 16; //sample size in units 59 int novertexlighting = 0; 60 int nogridlighting = 0; 61 62 // for run time tweaking of all area sources in the level 63 float areaScale = 0.25; 64 65 // for run time tweaking of all point sources in the level 66 float pointScale = 7500; 67 68 qboolean exactPointToPolygon = qtrue; 69 70 float formFactorValueScale = 3; 71 72 float linearScale = 1.0 / 8000; 73 74 light_t *lights; 75 int numPointLights; 76 int numAreaLights; 77 78 FILE *dumpFile; 79 80 int c_visible, c_occluded; 81 82 //int defaultLightSubdivide = 128; // vary by surface size? 83 int defaultLightSubdivide = 999; // vary by surface size? 84 85 vec3_t ambientColor; 86 87 vec3_t surfaceOrigin[ MAX_MAP_DRAW_SURFS ]; 88 int entitySurface[ MAX_MAP_DRAW_SURFS ]; 89 90 // 7,9,11 normalized to avoid being nearly coplanar with common faces 91 //vec3_t sunDirection = { 0.441835, 0.56807, 0.694313 }; 92 //vec3_t sunDirection = { 0.45, 0, 0.9 }; 93 //vec3_t sunDirection = { 0, 0, 1 }; 94 95 // these are usually overrided by shader values 96 vec3_t sunDirection = { 0.45, 0.3, 0.9 }; 97 vec3_t sunLight = { 100, 100, 50 }; 98 99 100 101 typedef struct { 102 dbrush_t *b; 103 vec3_t bounds[2]; 104 } skyBrush_t; 105 106 int numSkyBrushes; 107 skyBrush_t skyBrushes[MAX_MAP_BRUSHES]; 108 109 110 /* 111 112 the corners of a patch mesh will always be exactly at lightmap samples. 113 The dimensions of the lightmap will be equal to the average length of the control 114 mesh in each dimension divided by 2. 115 The lightmap sample points should correspond to the chosen subdivision points. 116 117 */ 118 119 /* 120 =============================================================== 121 122 SURFACE LOADING 123 124 =============================================================== 125 */ 126 127 #define MAX_FACE_POINTS 128 128 129 /* 130 =============== 131 SubdivideAreaLight 132 133 Subdivide area lights that are very large 134 A light that is subdivided will never backsplash, avoiding weird pools of light near edges 135 =============== 136 */ 137 void SubdivideAreaLight( shaderInfo_t *ls, winding_t *w, vec3_t normal, 138 float areaSubdivide, qboolean backsplash ) { 139 float area, value, intensity; 140 light_t *dl, *dl2; 141 vec3_t mins, maxs; 142 int axis; 143 winding_t *front, *back; 144 vec3_t planeNormal; 145 float planeDist; 146 147 if ( !w ) { 148 return; 149 } 150 151 WindingBounds( w, mins, maxs ); 152 153 // check for subdivision 154 for ( axis = 0 ; axis < 3 ; axis++ ) { 155 if ( maxs[axis] - mins[axis] > areaSubdivide ) { 156 VectorClear( planeNormal ); 157 planeNormal[axis] = 1; 158 planeDist = ( maxs[axis] + mins[axis] ) * 0.5; 159 ClipWindingEpsilon ( w, planeNormal, planeDist, ON_EPSILON, &front, &back ); 160 SubdivideAreaLight( ls, front, normal, areaSubdivide, qfalse ); 161 SubdivideAreaLight( ls, back, normal, areaSubdivide, qfalse ); 162 FreeWinding( w ); 163 return; 164 } 165 } 166 167 // create a light from this 168 area = WindingArea (w); 169 if ( area <= 0 || area > 20000000 ) { 170 return; 171 } 172 173 numAreaLights++; 174 dl = malloc(sizeof(*dl)); 175 memset (dl, 0, sizeof(*dl)); 176 dl->next = lights; 177 lights = dl; 178 dl->type = emit_area; 179 180 WindingCenter( w, dl->origin ); 181 dl->w = w; 182 VectorCopy ( normal, dl->normal); 183 dl->dist = DotProduct( dl->origin, normal ); 184 185 value = ls->value; 186 intensity = value * area * areaScale; 187 VectorAdd( dl->origin, dl->normal, dl->origin ); 188 189 VectorCopy( ls->color, dl->color ); 190 191 dl->photons = intensity; 192 193 // emitColor is irrespective of the area 194 VectorScale( ls->color, value*formFactorValueScale*areaScale, dl->emitColor ); 195 196 dl->si = ls; 197 198 if ( ls->contents & CONTENTS_FOG ) { 199 dl->twosided = qtrue; 200 } 201 202 // optionally create a point backsplash light 203 if ( backsplash && ls->backsplashFraction > 0 ) { 204 dl2 = malloc(sizeof(*dl)); 205 memset (dl2, 0, sizeof(*dl2)); 206 dl2->next = lights; 207 lights = dl2; 208 dl2->type = emit_point; 209 210 VectorMA( dl->origin, ls->backsplashDistance, normal, dl2->origin ); 211 212 VectorCopy( ls->color, dl2->color ); 213 214 dl2->photons = dl->photons * ls->backsplashFraction; 215 dl2->si = ls; 216 } 217 } 218 219 220 /* 221 =============== 222 CountLightmaps 223 =============== 224 */ 225 void CountLightmaps( void ) { 226 int count; 227 int i; 228 dsurface_t *ds; 229 230 qprintf ("--- CountLightmaps ---\n"); 231 count = 0; 232 for ( i = 0 ; i < numDrawSurfaces ; i++ ) { 233 // see if this surface is light emiting 234 ds = &drawSurfaces[i]; 235 if ( ds->lightmapNum > count ) { 236 count = ds->lightmapNum; 237 } 238 } 239 240 count++; 241 numLightBytes = count * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3; 242 if ( numLightBytes > MAX_MAP_LIGHTING ) { 243 Error("MAX_MAP_LIGHTING exceeded"); 244 } 245 246 qprintf( "%5i drawSurfaces\n", numDrawSurfaces ); 247 qprintf( "%5i lightmaps\n", count ); 248 } 249 250 /* 251 =============== 252 CreateSurfaceLights 253 254 This creates area lights 255 =============== 256 */ 257 void CreateSurfaceLights( void ) { 258 int i, j, side; 259 dsurface_t *ds; 260 shaderInfo_t *ls; 261 winding_t *w; 262 cFacet_t *f; 263 light_t *dl; 264 vec3_t origin; 265 drawVert_t *dv; 266 int c_lightSurfaces; 267 float lightSubdivide; 268 vec3_t normal; 269 270 qprintf ("--- CreateSurfaceLights ---\n"); 271 c_lightSurfaces = 0; 272 273 for ( i = 0 ; i < numDrawSurfaces ; i++ ) { 274 // see if this surface is light emiting 275 ds = &drawSurfaces[i]; 276 277 ls = ShaderInfoForShader( dshaders[ ds->shaderNum].shader ); 278 if ( ls->value == 0 ) { 279 continue; 280 } 281 282 // determine how much we need to chop up the surface 283 if ( ls->lightSubdivide ) { 284 lightSubdivide = ls->lightSubdivide; 285 } else { 286 lightSubdivide = defaultLightSubdivide; 287 } 288 289 c_lightSurfaces++; 290 291 // an autosprite shader will become 292 // a point light instead of an area light 293 if ( ls->autosprite ) { 294 // autosprite geometry should only have four vertexes 295 if ( surfaceTest[i] ) { 296 // curve or misc_model 297 f = surfaceTest[i]->facets; 298 if ( surfaceTest[i]->numFacets != 1 || f->numBoundaries != 4 ) { 299 _printf( "WARNING: surface at (%i %i %i) has autosprite shader but isn't a quad\n", 300 (int)f->points[0], (int)f->points[1], (int)f->points[2] ); 301 } 302 VectorAdd( f->points[0], f->points[1], origin ); 303 VectorAdd( f->points[2], origin, origin ); 304 VectorAdd( f->points[3], origin, origin ); 305 VectorScale( origin, 0.25, origin ); 306 } else { 307 // normal polygon 308 dv = &drawVerts[ ds->firstVert ]; 309 if ( ds->numVerts != 4 ) { 310 _printf( "WARNING: surface at (%i %i %i) has autosprite shader but %i verts\n", 311 (int)dv->xyz[0], (int)dv->xyz[1], (int)dv->xyz[2] ); 312 continue; 313 } 314 315 VectorAdd( dv[0].xyz, dv[1].xyz, origin ); 316 VectorAdd( dv[2].xyz, origin, origin ); 317 VectorAdd( dv[3].xyz, origin, origin ); 318 VectorScale( origin, 0.25, origin ); 319 } 320 321 322 numPointLights++; 323 dl = malloc(sizeof(*dl)); 324 memset (dl, 0, sizeof(*dl)); 325 dl->next = lights; 326 lights = dl; 327 328 VectorCopy( origin, dl->origin ); 329 VectorCopy( ls->color, dl->color ); 330 dl->photons = ls->value * pointScale; 331 dl->type = emit_point; 332 continue; 333 } 334 335 // possibly create for both sides of the polygon 336 for ( side = 0 ; side <= ls->twoSided ; side++ ) { 337 // create area lights 338 if ( surfaceTest[i] ) { 339 // curve or misc_model 340 for ( j = 0 ; j < surfaceTest[i]->numFacets ; j++ ) { 341 f = surfaceTest[i]->facets + j; 342 w = AllocWinding( f->numBoundaries ); 343 w->numpoints = f->numBoundaries; 344 memcpy( w->p, f->points, f->numBoundaries * 12 ); 345 346 VectorCopy( f->surface, normal ); 347 if ( side ) { 348 winding_t *t; 349 350 t = w; 351 w = ReverseWinding( t ); 352 FreeWinding( t ); 353 VectorSubtract( vec3_origin, normal, normal ); 354 } 355 SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue ); 356 } 357 } else { 358 // normal polygon 359 360 w = AllocWinding( ds->numVerts ); 361 w->numpoints = ds->numVerts; 362 for ( j = 0 ; j < ds->numVerts ; j++ ) { 363 VectorCopy( drawVerts[ds->firstVert+j].xyz, w->p[j] ); 364 } 365 VectorCopy( ds->lightmapVecs[2], normal ); 366 if ( side ) { 367 winding_t *t; 368 369 t = w; 370 w = ReverseWinding( t ); 371 FreeWinding( t ); 372 VectorSubtract( vec3_origin, normal, normal ); 373 } 374 SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue ); 375 } 376 } 377 } 378 379 _printf( "%5i light emitting surfaces\n", c_lightSurfaces ); 380 } 381 382 383 384 /* 385 ================ 386 FindSkyBrushes 387 ================ 388 */ 389 void FindSkyBrushes( void ) { 390 int i, j; 391 dbrush_t *b; 392 skyBrush_t *sb; 393 shaderInfo_t *si; 394 dbrushside_t *s; 395 396 // find the brushes 397 for ( i = 0 ; i < numbrushes ; i++ ) { 398 b = &dbrushes[i]; 399 for ( j = 0 ; j < b->numSides ; j++ ) { 400 s = &dbrushsides[ b->firstSide + j ]; 401 if ( dshaders[ s->shaderNum ].surfaceFlags & SURF_SKY ) { 402 sb = &skyBrushes[ numSkyBrushes ]; 403 sb->b = b; 404 sb->bounds[0][0] = -dplanes[ dbrushsides[ b->firstSide + 0 ].planeNum ].dist - 1; 405 sb->bounds[1][0] = dplanes[ dbrushsides[ b->firstSide + 1 ].planeNum ].dist + 1; 406 sb->bounds[0][1] = -dplanes[ dbrushsides[ b->firstSide + 2 ].planeNum ].dist - 1; 407 sb->bounds[1][1] = dplanes[ dbrushsides[ b->firstSide + 3 ].planeNum ].dist + 1; 408 sb->bounds[0][2] = -dplanes[ dbrushsides[ b->firstSide + 4 ].planeNum ].dist - 1; 409 sb->bounds[1][2] = dplanes[ dbrushsides[ b->firstSide + 5 ].planeNum ].dist + 1; 410 numSkyBrushes++; 411 break; 412 } 413 } 414 } 415 416 // default 417 VectorNormalize( sunDirection, sunDirection ); 418 419 // find the sky shader 420 for ( i = 0 ; i < numDrawSurfaces ; i++ ) { 421 si = ShaderInfoForShader( dshaders[ drawSurfaces[i].shaderNum ].shader ); 422 if ( si->surfaceFlags & SURF_SKY ) { 423 VectorCopy( si->sunLight, sunLight ); 424 VectorCopy( si->sunDirection, sunDirection ); 425 break; 426 } 427 } 428 } 429 430 /* 431 ================================================================= 432 433 LIGHT SETUP 434 435 ================================================================= 436 */ 437 438 /* 439 ================== 440 FindTargetEntity 441 ================== 442 */ 443 entity_t *FindTargetEntity( const char *target ) { 444 int i; 445 const char *n; 446 447 for ( i = 0 ; i < num_entities ; i++ ) { 448 n = ValueForKey (&entities[i], "targetname"); 449 if ( !strcmp (n, target) ) { 450 return &entities[i]; 451 } 452 } 453 454 return NULL; 455 } 456 457 458 459 /* 460 ============= 461 CreateEntityLights 462 ============= 463 */ 464 void CreateEntityLights (void) 465 { 466 int i; 467 light_t *dl; 468 entity_t *e, *e2; 469 const char *name; 470 const char *target; 471 vec3_t dest; 472 const char *_color; 473 float intensity; 474 int spawnflags; 475 476 // 477 // entities 478 // 479 for ( i = 0 ; i < num_entities ; i++ ) { 480 e = &entities[i]; 481 name = ValueForKey (e, "classname"); 482 if (strncmp (name, "light", 5)) 483 continue; 484 485 numPointLights++; 486 dl = malloc(sizeof(*dl)); 487 memset (dl, 0, sizeof(*dl)); 488 dl->next = lights; 489 lights = dl; 490 491 spawnflags = FloatForKey (e, "spawnflags"); 492 if ( spawnflags & 1 ) { 493 dl->linearLight = qtrue; 494 } 495 496 GetVectorForKey (e, "origin", dl->origin); 497 dl->style = FloatForKey (e, "_style"); 498 if (!dl->style) 499 dl->style = FloatForKey (e, "style"); 500 if (dl->style < 0) 501 dl->style = 0; 502 503 intensity = FloatForKey (e, "light"); 504 if (!intensity) 505 intensity = FloatForKey (e, "_light"); 506 if (!intensity) 507 intensity = 300; 508 _color = ValueForKey (e, "_color"); 509 if (_color && _color[0]) 510 { 511 sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]); 512 ColorNormalize (dl->color, dl->color); 513 } 514 else 515 dl->color[0] = dl->color[1] = dl->color[2] = 1.0; 516 517 intensity = intensity * pointScale; 518 dl->photons = intensity; 519 520 dl->type = emit_point; 521 522 // lights with a target will be spotlights 523 target = ValueForKey (e, "target"); 524 525 if ( target[0] ) { 526 float radius; 527 float dist; 528 529 e2 = FindTargetEntity (target); 530 if (!e2) { 531 _printf ("WARNING: light at (%i %i %i) has missing target\n", 532 (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]); 533 } else { 534 GetVectorForKey (e2, "origin", dest); 535 VectorSubtract (dest, dl->origin, dl->normal); 536 dist = VectorNormalize (dl->normal, dl->normal); 537 radius = FloatForKey (e, "radius"); 538 if ( !radius ) { 539 radius = 64; 540 } 541 if ( !dist ) { 542 dist = 64; 543 } 544 dl->radiusByDist = (radius + 16) / dist; 545 dl->type = emit_spotlight; 546 } 547 } 548 } 549 } 550 551 //================================================================= 552 553 /* 554 ================ 555 SetEntityOrigins 556 557 Find the offset values for inline models 558 ================ 559 */ 560 void SetEntityOrigins( void ) { 561 int i, j; 562 entity_t *e; 563 vec3_t origin; 564 const char *key; 565 int modelnum; 566 dmodel_t *dm; 567 568 for ( i=0 ; i < num_entities ; i++ ) { 569 e = &entities[i]; 570 key = ValueForKey (e, "model"); 571 if ( key[0] != '*' ) { 572 continue; 573 } 574 modelnum = atoi( key + 1 ); 575 dm = &dmodels[ modelnum ]; 576 577 // set entity surface to true for all surfaces for this model 578 for ( j = 0 ; j < dm->numSurfaces ; j++ ) { 579 entitySurface[ dm->firstSurface + j ] = qtrue; 580 } 581 582 key = ValueForKey (e, "origin"); 583 if ( !key[0] ) { 584 continue; 585 } 586 GetVectorForKey ( e, "origin", origin ); 587 588 // set origin for all surfaces for this model 589 for ( j = 0 ; j < dm->numSurfaces ; j++ ) { 590 VectorCopy( origin, surfaceOrigin[ dm->firstSurface + j ] ); 591 } 592 } 593 } 594 595 596 /* 597 ================================================================= 598 599 600 ================================================================= 601 */ 602 603 #define MAX_POINTS_ON_WINDINGS 64 604 605 /* 606 ================ 607 PointToPolygonFormFactor 608 ================ 609 */ 610 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w ) { 611 vec3_t triVector, triNormal; 612 int i, j; 613 vec3_t dirs[MAX_POINTS_ON_WINDING]; 614 float total; 615 float dot, angle, facing; 616 617 for ( i = 0 ; i < w->numpoints ; i++ ) { 618 VectorSubtract( w->p[i], point, dirs[i] ); 619 VectorNormalize( dirs[i], dirs[i] ); 620 } 621 622 // duplicate first vertex to avoid mod operation 623 VectorCopy( dirs[0], dirs[i] ); 624 625 total = 0; 626 for ( i = 0 ; i < w->numpoints ; i++ ) { 627 j = i+1; 628 dot = DotProduct( dirs[i], dirs[j] ); 629 630 // roundoff can cause slight creep, which gives an IND from acos 631 if ( dot > 1.0 ) { 632 dot = 1.0; 633 } else if ( dot < -1.0 ) { 634 dot = -1.0; 635 } 636 637 angle = acos( dot ); 638 CrossProduct( dirs[i], dirs[j], triVector ); 639 if ( VectorNormalize( triVector, triNormal ) < 0.0001 ) { 640 continue; 641 } 642 facing = DotProduct( normal, triNormal ); 643 total += facing * angle; 644 645 if ( total > 6.3 || total < -6.3 ) { 646 static qboolean printed; 647 648 if ( !printed ) { 649 printed = qtrue; 650 _printf( "WARNING: bad PointToPolygonFormFactor: %f at %1.1f %1.1f %1.1f from %1.1f %1.1f %1.1f\n", total, 651 w->p[i][0], w->p[i][1], w->p[i][2], point[0], point[1], point[2]); 652 } 653 return 0; 654 } 655 656 } 657 658 total /= 2*3.141592657; // now in the range of 0 to 1 over the entire incoming hemisphere 659 660 return total; 661 } 662 663 664 /* 665 ================ 666 FilterTrace 667 668 Returns 0 to 1.0 filter fractions for the given trace 669 ================ 670 */ 671 void FilterTrace( const vec3_t start, const vec3_t end, vec3_t filter ) { 672 float d1, d2; 673 filter_t *f; 674 int filterNum; 675 vec3_t point; 676 float frac; 677 int i; 678 float s, t; 679 int u, v; 680 int x, y; 681 byte *pixel; 682 float radius; 683 float len; 684 vec3_t total; 685 686 filter[0] = 1.0; 687 filter[1] = 1.0; 688 filter[2] = 1.0; 689 690 for ( filterNum = 0 ; filterNum < numFilters ; filterNum++ ) { 691 f = &filters[ filterNum ]; 692 693 // see if the plane is crossed 694 d1 = DotProduct( start, f->plane ) - f->plane[3]; 695 d2 = DotProduct( end, f->plane ) - f->plane[3]; 696 697 if ( ( d1 < 0 ) == ( d2 < 0 ) ) { 698 continue; 699 } 700 701 // calculate the crossing point 702 frac = d1 / ( d1 - d2 ); 703 704 for ( i = 0 ; i < 3 ; i++ ) { 705 point[i] = start[i] + frac * ( end[i] - start[i] ); 706 } 707 708 VectorSubtract( point, f->origin, point ); 709 710 s = DotProduct( point, f->vectors[0] ); 711 t = 1.0 - DotProduct( point, f->vectors[1] ); 712 if ( s < 0 || s >= 1.0 || t < 0 || t >= 1.0 ) { 713 continue; 714 } 715 716 // decide the filter size 717 radius = 10 * frac; 718 len = VectorLength( f->vectors[0] ); 719 if ( !len ) { 720 continue; 721 } 722 radius = radius * len * f->si->width; 723 724 // look up the filter, taking multiple samples 725 VectorClear( total ); 726 for ( u = -1 ; u <= 1 ; u++ ) { 727 for ( v = -1 ; v <=1 ; v++ ) { 728 x = s * f->si->width + u * radius; 729 if ( x < 0 ) { 730 x = 0; 731 } 732 if ( x >= f->si->width ) { 733 x = f->si->width - 1; 734 } 735 y = t * f->si->height + v * radius; 736 if ( y < 0 ) { 737 y = 0; 738 } 739 if ( y >= f->si->height ) { 740 y = f->si->height - 1; 741 } 742 743 pixel = f->si->pixels + ( y * f->si->width + x ) * 4; 744 total[0] += pixel[0]; 745 total[1] += pixel[1]; 746 total[2] += pixel[2]; 747 } 748 } 749 750 filter[0] *= total[0]/(255.0*9); 751 filter[1] *= total[1]/(255.0*9); 752 filter[2] *= total[2]/(255.0*9); 753 } 754 755 } 756 757 /* 758 ================ 759 SunToPoint 760 761 Returns an amount of light to add at the point 762 ================ 763 */ 764 int c_sunHit, c_sunMiss; 765 void SunToPoint( const vec3_t origin, traceWork_t *tw, vec3_t addLight ) { 766 int i; 767 trace_t trace; 768 skyBrush_t *b; 769 vec3_t end; 770 771 if ( !numSkyBrushes ) { 772 VectorClear( addLight ); 773 return; 774 } 775 776 VectorMA( origin, MAX_WORLD_COORD * 2, sunDirection, end ); 777 778 TraceLine( origin, end, &trace, qtrue, tw ); 779 780 // see if trace.hit is inside a sky brush 781 for ( i = 0 ; i < numSkyBrushes ; i++) { 782 b = &skyBrushes[ i ]; 783 784 // this assumes that sky brushes are axial... 785 if ( trace.hit[0] < b->bounds[0][0] 786 || trace.hit[0] > b->bounds[1][0] 787 || trace.hit[1] < b->bounds[0][1] 788 || trace.hit[1] > b->bounds[1][1] 789 || trace.hit[2] < b->bounds[0][2] 790 || trace.hit[2] > b->bounds[1][2] ) { 791 continue; 792 } 793 794 795 // trace again to get intermediate filters 796 TraceLine( origin, trace.hit, &trace, qtrue, tw ); 797 798 // we hit the sky, so add sunlight 799 if ( numthreads == 1 ) { 800 c_sunHit++; 801 } 802 addLight[0] = trace.filter[0] * sunLight[0]; 803 addLight[1] = trace.filter[1] * sunLight[1]; 804 addLight[2] = trace.filter[2] * sunLight[2]; 805 806 return; 807 } 808 809 if ( numthreads == 1 ) { 810 c_sunMiss++; 811 } 812 813 VectorClear( addLight ); 814 } 815 816 /* 817 ================ 818 SunToPlane 819 ================ 820 */ 821 void SunToPlane( const vec3_t origin, const vec3_t normal, vec3_t color, traceWork_t *tw ) { 822 float angle; 823 vec3_t sunColor; 824 825 if ( !numSkyBrushes ) { 826 return; 827 } 828 829 angle = DotProduct( normal, sunDirection ); 830 if ( angle <= 0 ) { 831 return; // facing away 832 } 833 834 SunToPoint( origin, tw, sunColor ); 835 VectorMA( color, angle, sunColor, color ); 836 } 837 838 /* 839 ================ 840 LightingAtSample 841 ================ 842 */ 843 void LightingAtSample( vec3_t origin, vec3_t normal, vec3_t color, 844 qboolean testOcclusion, qboolean forceSunLight, traceWork_t *tw ) { 845 light_t *light; 846 trace_t trace; 847 float angle; 848 float add; 849 float dist; 850 vec3_t dir; 851 852 VectorCopy( ambientColor, color ); 853 854 // trace to all the lights 855 for ( light = lights ; light ; light = light->next ) { 856 857 //MrE: if the light is behind the surface 858 if ( DotProduct(light->origin, normal) - DotProduct(normal, origin) < 0 ) 859 continue; 860 // testing exact PTPFF 861 if ( exactPointToPolygon && light->type == emit_area ) { 862 float factor; 863 float d; 864 vec3_t pushedOrigin; 865 866 // see if the point is behind the light 867 d = DotProduct( origin, light->normal ) - light->dist; 868 if ( !light->twosided ) { 869 if ( d < -1 ) { 870 continue; // point is behind light 871 } 872 } 873 874 // test occlusion and find light filters 875 // clip the line, tracing from the surface towards the light 876 if ( !notrace && testOcclusion ) { 877 TraceLine( origin, light->origin, &trace, qfalse, tw ); 878 879 // other light rays must not hit anything 880 if ( trace.passSolid ) { 881 continue; 882 } 883 } else { 884 trace.filter[0] = 1.0; 885 trace.filter[1] = 1.0; 886 trace.filter[2] = 1.0; 887 } 888 889 // nudge the point so that it is clearly forward of the light 890 // so that surfaces meeting a light emiter don't get black edges 891 if ( d > -8 && d < 8 ) { 892 VectorMA( origin, (8-d), light->normal, pushedOrigin ); 893 } else { 894 VectorCopy( origin, pushedOrigin ); 895 } 896 897 // calculate the contribution 898 factor = PointToPolygonFormFactor( pushedOrigin, normal, light->w ); 899 if ( factor <= 0 ) { 900 if ( light->twosided ) { 901 factor = -factor; 902 } else { 903 continue; 904 } 905 } 906 color[0] += factor * light->emitColor[0] * trace.filter[0]; 907 color[1] += factor * light->emitColor[1] * trace.filter[1]; 908 color[2] += factor * light->emitColor[2] * trace.filter[2]; 909 910 continue; 911 } 912 913 // calculate the amount of light at this sample 914 if ( light->type == emit_point ) { 915 VectorSubtract( light->origin, origin, dir ); 916 dist = VectorNormalize( dir, dir ); 917 // clamp the distance to prevent super hot spots 918 if ( dist < 16 ) { 919 dist = 16; 920 } 921 angle = DotProduct( normal, dir ); 922 if ( light->linearLight ) { 923 add = angle * light->photons * linearScale - dist; 924 if ( add < 0 ) { 925 add = 0; 926 } 927 } else { 928 add = light->photons / ( dist * dist ) * angle; 929 } 930 } else if ( light->type == emit_spotlight ) { 931 float distByNormal; 932 vec3_t pointAtDist; 933 float radiusAtDist; 934 float sampleRadius; 935 vec3_t distToSample; 936 float coneScale; 937 938 VectorSubtract( light->origin, origin, dir ); 939 940 distByNormal = -DotProduct( dir, light->normal ); 941 if ( distByNormal < 0 ) { 942 continue; 943 } 944 VectorMA( light->origin, distByNormal, light->normal, pointAtDist ); 945 radiusAtDist = light->radiusByDist * distByNormal; 946 947 VectorSubtract( origin, pointAtDist, distToSample ); 948 sampleRadius = VectorLength( distToSample ); 949 950 if ( sampleRadius >= radiusAtDist ) { 951 continue; // outside the cone 952 } 953 if ( sampleRadius <= radiusAtDist - 32 ) { 954 coneScale = 1.0; // fully inside 955 } else { 956 coneScale = ( radiusAtDist - sampleRadius ) / 32.0; 957 } 958 959 dist = VectorNormalize( dir, dir ); 960 // clamp the distance to prevent super hot spots 961 if ( dist < 16 ) { 962 dist = 16; 963 } 964 angle = DotProduct( normal, dir ); 965 add = light->photons / ( dist * dist ) * angle * coneScale; 966 967 } else if ( light->type == emit_area ) { 968 VectorSubtract( light->origin, origin, dir ); 969 dist = VectorNormalize( dir, dir ); 970 // clamp the distance to prevent super hot spots 971 if ( dist < 16 ) { 972 dist = 16; 973 } 974 angle = DotProduct( normal, dir ); 975 if ( angle <= 0 ) { 976 continue; 977 } 978 angle *= -DotProduct( light->normal, dir ); 979 if ( angle <= 0 ) { 980 continue; 981 } 982 983 if ( light->linearLight ) { 984 add = angle * light->photons * linearScale - dist; 985 if ( add < 0 ) { 986 add = 0; 987 } 988 } else { 989 add = light->photons / ( dist * dist ) * angle; 990 } 991 } 992 993 if ( add <= 1.0 ) { 994 continue; 995 } 996 997 // clip the line, tracing from the surface towards the light 998 if ( !notrace && testOcclusion ) { 999 TraceLine( origin, light->origin, &trace, qfalse, tw ); 1000 1001 // other light rays must not hit anything 1002 if ( trace.passSolid ) { 1003 continue; 1004 } 1005 } else { 1006 trace.filter[0] = 1; 1007 trace.filter[1] = 1; 1008 trace.filter[2] = 1; 1009 } 1010 1011 // add the result 1012 color[0] += add * light->color[0] * trace.filter[0]; 1013 color[1] += add * light->color[1] * trace.filter[1]; 1014 color[2] += add * light->color[2] * trace.filter[2]; 1015 } 1016 1017 // 1018 // trace directly to the sun 1019 // 1020 if ( testOcclusion || forceSunLight ) { 1021 SunToPlane( origin, normal, color, tw ); 1022 } 1023 } 1024 1025 /* 1026 ============= 1027 PrintOccluded 1028 1029 For debugging 1030 ============= 1031 */ 1032 void PrintOccluded( byte occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE], 1033 int width, int height ) { 1034 int i, j; 1035 1036 _printf( "\n" ); 1037 1038 for ( i = 0 ; i < height ; i++ ) { 1039 for ( j = 0 ; j < width ; j++ ) { 1040 _printf("%i", (int)occluded[j][i] ); 1041 } 1042 _printf( "\n" ); 1043 } 1044 } 1045 1046 1047 /* 1048 ============= 1049 VertexLighting 1050 1051 Vertex lighting will completely ignore occlusion, because 1052 shadows would not be resolvable anyway. 1053 ============= 1054 */ 1055 void VertexLighting( dsurface_t *ds, qboolean testOcclusion, qboolean forceSunLight, float scale, traceWork_t *tw ) { 1056 int i, j; 1057 drawVert_t *dv; 1058 vec3_t sample, normal; 1059 float max; 1060 1061 VectorCopy( ds->lightmapVecs[2], normal ); 1062 1063 // generate vertex lighting 1064 for ( i = 0 ; i < ds->numVerts ; i++ ) { 1065 dv = &drawVerts[ ds->firstVert + i ]; 1066 1067 if ( ds->patchWidth ) { 1068 LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw ); 1069 } 1070 else if (ds->surfaceType == MST_TRIANGLE_SOUP) { 1071 LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw ); 1072 } 1073 else { 1074 LightingAtSample( dv->xyz, normal, sample, testOcclusion, forceSunLight, tw ); 1075 } 1076 1077 if (scale >= 0) 1078 VectorScale(sample, scale, sample); 1079 // clamp with color normalization 1080 max = sample[0]; 1081 if ( sample[1] > max ) { 1082 max = sample[1]; 1083 } 1084 if ( sample[2] > max ) { 1085 max = sample[2]; 1086 } 1087 if ( max > 255 ) { 1088 VectorScale( sample, 255/max, sample ); 1089 } 1090 1091 // save the sample 1092 for ( j = 0 ; j < 3 ; j++ ) { 1093 if ( sample[j] > 255 ) { 1094 sample[j] = 255; 1095 } 1096 dv->color[j] = sample[j]; 1097 } 1098 1099 // Don't bother writing alpha since it will already be set to 255, 1100 // plus we don't want to write over alpha generated by SetTerrainTextures 1101 //dv->color[3] = 255; 1102 } 1103 } 1104 1105 1106 /* 1107 ================= 1108 LinearSubdivideMesh 1109 1110 For extra lighting, just midpoint one of the axis. 1111 The edges are clamped at the original edges. 1112 ================= 1113 */ 1114 mesh_t *LinearSubdivideMesh( mesh_t *in ) { 1115 int i, j; 1116 mesh_t *out; 1117 drawVert_t *v1, *v2, *vout; 1118 1119 out = malloc( sizeof( *out ) ); 1120 1121 out->width = in->width * 2; 1122 out->height = in->height; 1123 out->verts = malloc( out->width * out->height * sizeof(*out->verts) ); 1124 for ( j = 0 ; j < in->height ; j++ ) { 1125 out->verts[ j * out->width + 0 ] = in->verts[ j * in->width + 0 ]; 1126 out->verts[ j * out->width + out->width - 1 ] = in->verts[ j * in->width + in->width - 1 ]; 1127 for ( i = 1 ; i < out->width - 1 ; i+= 2 ) { 1128 v1 = in->verts + j * in->width + (i >> 1); 1129 v2 = v1 + 1; 1130 vout = out->verts + j * out->width + i; 1131 1132 vout->xyz[0] = 0.75 * v1->xyz[0] + 0.25 * v2->xyz[0]; 1133 vout->xyz[1] = 0.75 * v1->xyz[1] + 0.25 * v2->xyz[1]; 1134 vout->xyz[2] = 0.75 * v1->xyz[2] + 0.25 * v2->xyz[2]; 1135 1136 vout->normal[0] = 0.75 * v1->normal[0] + 0.25 * v2->normal[0]; 1137 vout->normal[1] = 0.75 * v1->normal[1] + 0.25 * v2->normal[1]; 1138 vout->normal[2] = 0.75 * v1->normal[2] + 0.25 * v2->normal[2]; 1139 1140 VectorNormalize( vout->normal, vout->normal ); 1141 1142 vout++; 1143 1144 vout->xyz[0] = 0.25 * v1->xyz[0] + 0.75 * v2->xyz[0]; 1145 vout->xyz[1] = 0.25 * v1->xyz[1] + 0.75 * v2->xyz[1]; 1146 vout->xyz[2] = 0.25 * v1->xyz[2] + 0.75 * v2->xyz[2]; 1147 1148 vout->normal[0] = 0.25 * v1->normal[0] + 0.75 * v2->normal[0]; 1149 vout->normal[1] = 0.25 * v1->normal[1] + 0.75 * v2->normal[1]; 1150 vout->normal[2] = 0.25 * v1->normal[2] + 0.75 * v2->normal[2]; 1151 1152 VectorNormalize( vout->normal, vout->normal ); 1153 1154 } 1155 } 1156 1157 FreeMesh( in ); 1158 1159 return out; 1160 } 1161 1162 /* 1163 ============== 1164 ColorToBytes 1165 ============== 1166 */ 1167 void ColorToBytes( const float *color, byte *colorBytes ) { 1168 float max; 1169 vec3_t sample; 1170 1171 VectorCopy( color, sample ); 1172 1173 // clamp with color normalization 1174 max = sample[0]; 1175 if ( sample[1] > max ) { 1176 max = sample[1]; 1177 } 1178 if ( sample[2] > max ) { 1179 max = sample[2]; 1180 } 1181 if ( max > 255 ) { 1182 VectorScale( sample, 255/max, sample ); 1183 } 1184 colorBytes[ 0 ] = sample[0]; 1185 colorBytes[ 1 ] = sample[1]; 1186 colorBytes[ 2 ] = sample[2]; 1187 } 1188 1189 1190 1191 /* 1192 ============= 1193 TraceLtm 1194 ============= 1195 */ 1196 void TraceLtm( int num ) { 1197 dsurface_t *ds; 1198 int i, j, k; 1199 int x, y; 1200 int position, numPositions; 1201 vec3_t base, origin, normal; 1202 byte occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE]; 1203 vec3_t color[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE]; 1204 traceWork_t tw; 1205 vec3_t average; 1206 int count; 1207 mesh_t srcMesh, *mesh, *subdivided; 1208 shaderInfo_t *si; 1209 static float nudge[2][9] = { 1210 { 0, -1, 0, 1, -1, 1, -1, 0, 1 }, 1211 { 0, -1, -1, -1, 0, 0, 1, 1, 1 } 1212 }; 1213 int sampleWidth, sampleHeight, ssize; 1214 vec3_t lightmapOrigin, lightmapVecs[2]; 1215 int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_WIDTH]; 1216 1217 ds = &drawSurfaces[num]; 1218 si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader ); 1219 1220 // vertex-lit triangle model 1221 if ( ds->surfaceType == MST_TRIANGLE_SOUP ) { 1222 VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw ); 1223 return; 1224 } 1225 1226 if ( ds->lightmapNum == -1 ) { 1227 return; // doesn't need lighting at all 1228 } 1229 1230 if (!novertexlighting) { 1231 // calculate the vertex lighting for gouraud shade mode 1232 VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw ); 1233 } 1234 1235 if ( ds->lightmapNum < 0 ) { 1236 return; // doesn't need lightmap lighting 1237 } 1238 1239 si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader ); 1240 ssize = samplesize; 1241 if (si->lightmapSampleSize) 1242 ssize = si->lightmapSampleSize; 1243 1244 if (si->patchShadows) 1245 tw.patchshadows = qtrue; 1246 else 1247 tw.patchshadows = patchshadows; 1248 1249 if ( ds->surfaceType == MST_PATCH ) { 1250 srcMesh.width = ds->patchWidth; 1251 srcMesh.height = ds->patchHeight; 1252 srcMesh.verts = drawVerts + ds->firstVert; 1253 mesh = SubdivideMesh( srcMesh, 8, 999 ); 1254 PutMeshOnCurve( *mesh ); 1255 MakeMeshNormals( *mesh ); 1256 1257 subdivided = RemoveLinearMeshColumnsRows( mesh ); 1258 FreeMesh(mesh); 1259 1260 mesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_WIDTH, widthtable, heighttable); 1261 if ( mesh->width != ds->lightmapWidth || mesh->height != ds->lightmapHeight ) { 1262 Error( "Mesh lightmap miscount"); 1263 } 1264 1265 if ( extra ) { 1266 mesh_t *mp; 1267 1268 // chop it up for more light samples (leaking memory...) 1269 mp = mesh;//CopyMesh( mesh ); 1270 mp = LinearSubdivideMesh( mp ); 1271 mp = TransposeMesh( mp ); 1272 mp = LinearSubdivideMesh( mp ); 1273 mp = TransposeMesh( mp ); 1274 1275 mesh = mp; 1276 } 1277 } else { 1278 VectorCopy( ds->lightmapVecs[2], normal ); 1279 1280 if ( !extra ) { 1281 VectorCopy( ds->lightmapOrigin, lightmapOrigin ); 1282 VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] ); 1283 VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] ); 1284 } else { 1285 // sample at a closer spacing for antialiasing 1286 VectorCopy( ds->lightmapOrigin, lightmapOrigin ); 1287 VectorScale( ds->lightmapVecs[0], 0.5, lightmapVecs[0] ); 1288 VectorScale( ds->lightmapVecs[1], 0.5, lightmapVecs[1] ); 1289 VectorMA( lightmapOrigin, -0.5, lightmapVecs[0], lightmapOrigin ); 1290 VectorMA( lightmapOrigin, -0.5, lightmapVecs[1], lightmapOrigin ); 1291 } 1292 } 1293 1294 if ( extra ) { 1295 sampleWidth = ds->lightmapWidth * 2; 1296 sampleHeight = ds->lightmapHeight * 2; 1297 } else { 1298 sampleWidth = ds->lightmapWidth; 1299 sampleHeight = ds->lightmapHeight; 1300 } 1301 1302 memset ( color, 0, sizeof( color ) ); 1303 1304 // determine which samples are occluded 1305 memset ( occluded, 0, sizeof( occluded ) ); 1306 for ( i = 0 ; i < sampleWidth ; i++ ) { 1307 for ( j = 0 ; j < sampleHeight ; j++ ) { 1308 1309 if ( ds->patchWidth ) { 1310 numPositions = 9; 1311 VectorCopy( mesh->verts[j*mesh->width+i].normal, normal ); 1312 // VectorNormalize( normal, normal ); 1313 // push off of the curve a bit 1314 VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base ); 1315 1316 MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] ); 1317 } else { 1318 numPositions = 9; 1319 for ( k = 0 ; k < 3 ; k++ ) { 1320 base[k] = lightmapOrigin[k] + normal[k] 1321 + i * lightmapVecs[0][k] 1322 + j * lightmapVecs[1][k]; 1323 } 1324 } 1325 VectorAdd( base, surfaceOrigin[ num ], base ); 1326 1327 // we may need to slightly nudge the sample point 1328 // if directly on a wall 1329 for ( position = 0 ; position < numPositions ; position++ ) { 1330 // calculate lightmap sample position 1331 for ( k = 0 ; k < 3 ; k++ ) { 1332 origin[k] = base[k] + 1333 + ( nudge[0][position]/16 ) * lightmapVecs[0][k] 1334 + ( nudge[1][position]/16 ) * lightmapVecs[1][k]; 1335 } 1336 1337 if ( notrace ) { 1338 break; 1339 } 1340 if ( !PointInSolid( origin ) ) { 1341 break; 1342 } 1343 } 1344 1345 // if none of the nudges worked, this sample is occluded 1346 if ( position == numPositions ) { 1347 occluded[i][j] = qtrue; 1348 if ( numthreads == 1 ) { 1349 c_occluded++; 1350 } 1351 continue; 1352 } 1353 1354 if ( numthreads == 1 ) { 1355 c_visible++; 1356 } 1357 occluded[i][j] = qfalse; 1358 LightingAtSample( origin, normal, color[i][j], qtrue, qfalse, &tw ); 1359 } 1360 } 1361 1362 if ( dump ) { 1363 PrintOccluded( occluded, sampleWidth, sampleHeight ); 1364 } 1365 1366 // calculate average values for occluded samples 1367 for ( i = 0 ; i < sampleWidth ; i++ ) { 1368 for ( j = 0 ; j < sampleHeight ; j++ ) { 1369 if ( !occluded[i][j] ) { 1370 continue; 1371 } 1372 // scan all surrounding samples 1373 count = 0; 1374 VectorClear( average ); 1375 for ( x = -1 ; x <= 1; x++ ) { 1376 for ( y = -1 ; y <= 1 ; y++ ) { 1377 if ( i + x < 0 || i + x >= sampleWidth ) { 1378 continue; 1379 } 1380 if ( j + y < 0 || j + y >= sampleHeight ) { 1381 continue; 1382 } 1383 if ( occluded[i+x][j+y] ) { 1384 continue; 1385 } 1386 count++; 1387 VectorAdd( color[i+x][j+y], average, average ); 1388 } 1389 } 1390 if ( count ) { 1391 VectorScale( average, 1.0/count, color[i][j] ); 1392 } 1393 } 1394 } 1395 1396 // average together the values if we are extra sampling 1397 if ( ds->lightmapWidth != sampleWidth ) { 1398 for ( i = 0 ; i < ds->lightmapWidth ; i++ ) { 1399 for ( j = 0 ; j < ds->lightmapHeight ; j++ ) { 1400 for ( k = 0 ; k < 3 ; k++ ) { 1401 float value, coverage; 1402 1403 value = color[i*2][j*2][k] + color[i*2][j*2+1][k] + 1404 color[i*2+1][j*2][k] + color[i*2+1][j*2+1][k]; 1405 coverage = 4; 1406 if ( extraWide ) { 1407 // wider than box filter 1408 if ( i > 0 ) { 1409 value += color[i*2-1][j*2][k] + color[i*2-1][j*2+1][k]; 1410 value += color[i*2-2][j*2][k] + color[i*2-2][j*2+1][k]; 1411 coverage += 4; 1412 } 1413 if ( i < ds->lightmapWidth - 1 ) { 1414 value += color[i*2+2][j*2][k] + color[i*2+2][j*2+1][k]; 1415 value += color[i*2+3][j*2][k] + color[i*2+3][j*2+1][k]; 1416 coverage += 4; 1417 } 1418 if ( j > 0 ) { 1419 value += color[i*2][j*2-1][k] + color[i*2+1][j*2-1][k]; 1420 value += color[i*2][j*2-2][k] + color[i*2+1][j*2-2][k]; 1421 coverage += 4; 1422 } 1423 if ( j < ds->lightmapHeight - 1 ) { 1424 value += color[i*2][j*2+2][k] + color[i*2+1][j*2+2][k]; 1425 value += color[i*2][j*2+3][k] + color[i*2+1][j*2+3][k]; 1426 coverage += 2; 1427 } 1428 } 1429 1430 color[i][j][k] = value / coverage; 1431 } 1432 } 1433 } 1434 } 1435 1436 // optionally create a debugging border around the lightmap 1437 if ( lightmapBorder ) { 1438 for ( i = 0 ; i < ds->lightmapWidth ; i++ ) { 1439 color[i][0][0] = 255; 1440 color[i][0][1] = 0; 1441 color[i][0][2] = 0; 1442 1443 color[i][ds->lightmapHeight-1][0] = 255; 1444 color[i][ds->lightmapHeight-1][1] = 0; 1445 color[i][ds->lightmapHeight-1][2] = 0; 1446 } 1447 for ( i = 0 ; i < ds->lightmapHeight ; i++ ) { 1448 color[0][i][0] = 255; 1449 color[0][i][1] = 0; 1450 color[0][i][2] = 0; 1451 1452 color[ds->lightmapWidth-1][i][0] = 255; 1453 color[ds->lightmapWidth-1][i][1] = 0; 1454 color[ds->lightmapWidth-1][i][2] = 0; 1455 } 1456 } 1457 1458 // clamp the colors to bytes and store off 1459 for ( i = 0 ; i < ds->lightmapWidth ; i++ ) { 1460 for ( j = 0 ; j < ds->lightmapHeight ; j++ ) { 1461 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j) 1462 * LIGHTMAP_WIDTH + ds->lightmapX + i; 1463 1464 ColorToBytes( color[i][j], lightBytes + k*3 ); 1465 } 1466 } 1467 1468 if (ds->surfaceType == MST_PATCH) 1469 { 1470 FreeMesh(mesh); 1471 } 1472 } 1473 1474 1475 //============================================================================= 1476 1477 vec3_t gridMins; 1478 vec3_t gridSize = { 64, 64, 128 }; 1479 int gridBounds[3]; 1480 1481 1482 /* 1483 ======================== 1484 LightContributionToPoint 1485 ======================== 1486 */ 1487 qboolean LightContributionToPoint( const light_t *light, const vec3_t origin, 1488 vec3_t color, traceWork_t *tw ) { 1489 trace_t trace; 1490 float add; 1491 1492 add = 0; 1493 1494 VectorClear( color ); 1495 1496 // testing exact PTPFF 1497 if ( exactPointToPolygon && light->type == emit_area ) { 1498 float factor; 1499 float d; 1500 vec3_t normal; 1501 1502 // see if the point is behind the light 1503 d = DotProduct( origin, light->normal ) - light->dist; 1504 if ( !light->twosided ) { 1505 if ( d < 1 ) { 1506 return qfalse; // point is behind light 1507 } 1508 } 1509 1510 // test occlusion 1511 // clip the line, tracing from the surface towards the light 1512 TraceLine( origin, light->origin, &trace, qfalse, tw ); 1513 if ( trace.passSolid ) { 1514 return qfalse; 1515 } 1516 1517 // calculate the contribution 1518 VectorSubtract( light->origin, origin, normal ); 1519 if ( VectorNormalize( normal, normal ) == 0 ) { 1520 return qfalse; 1521 } 1522 factor = PointToPolygonFormFactor( origin, normal, light->w ); 1523 if ( factor <= 0 ) { 1524 if ( light->twosided ) { 1525 factor = -factor; 1526 } else { 1527 return qfalse; 1528 } 1529 } 1530 VectorScale( light->emitColor, factor, color ); 1531 return qtrue; 1532 } 1533 1534 // calculate the amount of light at this sample 1535 if ( light->type == emit_point || light->type == emit_spotlight ) { 1536 vec3_t dir; 1537 float dist; 1538 1539 VectorSubtract( light->origin, origin, dir ); 1540 dist = VectorLength( dir ); 1541 // clamp the distance to prevent super hot spots 1542 if ( dist < 16 ) { 1543 dist = 16; 1544 } 1545 if ( light->linearLight ) { 1546 add = light->photons * linearScale - dist; 1547 if ( add < 0 ) { 1548 add = 0; 1549 } 1550 } else { 1551 add = light->photons / ( dist * dist ); 1552 } 1553 } else { 1554 return qfalse; 1555 } 1556 1557 if ( add <= 1.0 ) { 1558 return qfalse; 1559 } 1560 1561 // clip the line, tracing from the surface towards the light 1562 TraceLine( origin, light->origin, &trace, qfalse, tw ); 1563 1564 // other light rays must not hit anything 1565 if ( trace.passSolid ) { 1566 return qfalse; 1567 } 1568 1569 // add the result 1570 color[0] = add * light->color[0]; 1571 color[1] = add * light->color[1]; 1572 color[2] = add * light->color[2]; 1573 1574 return qtrue; 1575 } 1576 1577 typedef struct { 1578 vec3_t dir; 1579 vec3_t color; 1580 } contribution_t; 1581 1582 /* 1583 ============= 1584 TraceGrid 1585 1586 Grid samples are foe quickly determining the lighting 1587 of dynamically placed entities in the world 1588 ============= 1589 */ 1590 #define MAX_CONTRIBUTIONS 1024 1591 void TraceGrid( int num ) { 1592 int x, y, z; 1593 vec3_t origin; 1594 light_t *light; 1595 vec3_t color; 1596 int mod; 1597 vec3_t directedColor; 1598 vec3_t summedDir; 1599 contribution_t contributions[MAX_CONTRIBUTIONS]; 1600 int numCon; 1601 int i; 1602 traceWork_t tw; 1603 float addSize; 1604 1605 mod = num; 1606 z = mod / ( gridBounds[0] * gridBounds[1] ); 1607 mod -= z * ( gridBounds[0] * gridBounds[1] ); 1608 1609 y = mod / gridBounds[0]; 1610 mod -= y * gridBounds[0]; 1611 1612 x = mod; 1613 1614 origin[0] = gridMins[0] + x * gridSize[0]; 1615 origin[1] = gridMins[1] + y * gridSize[1]; 1616 origin[2] = gridMins[2] + z * gridSize[2]; 1617 1618 if ( PointInSolid( origin ) ) { 1619 vec3_t baseOrigin; 1620 int step; 1621 1622 VectorCopy( origin, baseOrigin ); 1623 1624 // try to nudge the origin around to find a valid point 1625 for ( step = 9 ; step <= 18 ; step += 9 ) { 1626 for ( i = 0 ; i < 8 ; i++ ) { 1627 VectorCopy( baseOrigin, origin ); 1628 if ( i & 1 ) { 1629 origin[0] += step; 1630 } else { 1631 origin[0] -= step; 1632 } 1633 if ( i & 2 ) { 1634 origin[1] += step; 1635 } else { 1636 origin[1] -= step; 1637 } 1638 if ( i & 4 ) { 1639 origin[2] += step; 1640 } else { 1641 origin[2] -= step; 1642 } 1643 1644 if ( !PointInSolid( origin ) ) { 1645 break; 1646 } 1647 } 1648 if ( i != 8 ) { 1649 break; 1650 } 1651 } 1652 if ( step > 18 ) { 1653 // can't find a valid point at all 1654 for ( i = 0 ; i < 8 ; i++ ) { 1655 gridData[ num*8 + i ] = 0; 1656 } 1657 return; 1658 } 1659 } 1660 1661 VectorClear( summedDir ); 1662 1663 // trace to all the lights 1664 1665 // find the major light direction, and divide the 1666 // total light between that along the direction and 1667 // the remaining in the ambient 1668 numCon = 0; 1669 for ( light = lights ; light ; light = light->next ) { 1670 vec3_t add; 1671 vec3_t dir; 1672 float addSize; 1673 1674 if ( !LightContributionToPoint( light, origin, add, &tw ) ) { 1675 continue; 1676 } 1677 1678 VectorSubtract( light->origin, origin, dir ); 1679 VectorNormalize( dir, dir ); 1680 1681 VectorCopy( add, contributions[numCon].color ); 1682 VectorCopy( dir, contributions[numCon].dir ); 1683 numCon++; 1684 1685 addSize = VectorLength( add ); 1686 VectorMA( summedDir, addSize, dir, summedDir ); 1687 1688 if ( numCon == MAX_CONTRIBUTIONS-1 ) { 1689 break; 1690 } 1691 } 1692 1693 // 1694 // trace directly to the sun 1695 // 1696 SunToPoint( origin, &tw, color ); 1697 addSize = VectorLength( color ); 1698 if ( addSize > 0 ) { 1699 VectorCopy( color, contributions[numCon].color ); 1700 VectorCopy( sunDirection, contributions[numCon].dir ); 1701 VectorMA( summedDir, addSize, sunDirection, summedDir ); 1702 numCon++; 1703 } 1704 1705 1706 // now that we have identified the primary light direction, 1707 // go back and seperate all the light into directed and ambient 1708 VectorNormalize( summedDir, summedDir ); 1709 VectorCopy( ambientColor, color ); 1710 VectorClear( directedColor ); 1711 1712 for ( i = 0 ; i < numCon ; i++ ) { 1713 float d; 1714 1715 d = DotProduct( contributions[i].dir, summedDir ); 1716 if ( d < 0 ) { 1717 d = 0; 1718 } 1719 1720 VectorMA( directedColor, d, contributions[i].color, directedColor ); 1721 1722 // the ambient light will be at 1/4 the value of directed light 1723 d = 0.25 * ( 1.0 - d ); 1724 VectorMA( color, d, contributions[i].color, color ); 1725 } 1726 1727 // now do some fudging to keep the ambient from being too low 1728 VectorMA( color, 0.25, directedColor, color ); 1729 1730 // 1731 // save the resulting value out 1732 // 1733 ColorToBytes( color, gridData + num*8 ); 1734 ColorToBytes( directedColor, gridData + num*8 + 3 ); 1735 1736 VectorNormalize( summedDir, summedDir ); 1737 NormalToLatLong( summedDir, gridData + num*8 + 6); 1738 } 1739 1740 1741 /* 1742 ============= 1743 SetupGrid 1744 ============= 1745 */ 1746 void SetupGrid( void ) { 1747 int i; 1748 vec3_t maxs; 1749 1750 for ( i = 0 ; i < 3 ; i++ ) { 1751 gridMins[i] = gridSize[i] * ceil( dmodels[0].mins[i] / gridSize[i] ); 1752 maxs[i] = gridSize[i] * floor( dmodels[0].maxs[i] / gridSize[i] ); 1753 gridBounds[i] = (maxs[i] - gridMins[i])/gridSize[i] + 1; 1754 } 1755 1756 numGridPoints = gridBounds[0] * gridBounds[1] * gridBounds[2]; 1757 if (numGridPoints * 8 >= MAX_MAP_LIGHTGRID) 1758 Error("MAX_MAP_LIGHTGRID"); 1759 qprintf( "%5i gridPoints\n", numGridPoints ); 1760 } 1761 1762 //============================================================================= 1763 1764 /* 1765 ============= 1766 RemoveLightsInSolid 1767 ============= 1768 */ 1769 void RemoveLightsInSolid(void) 1770 { 1771 light_t *light, *prev; 1772 int numsolid = 0; 1773 1774 prev = NULL; 1775 for ( light = lights ; light ; ) { 1776 if (PointInSolid(light->origin)) 1777 { 1778 if (prev) prev->next = light->next; 1779 else lights = light->next; 1780 if (light->w) 1781 FreeWinding(light->w); 1782 free(light); 1783 numsolid++; 1784 if (prev) 1785 light = prev->next; 1786 else 1787 light = lights; 1788 } 1789 else 1790 { 1791 prev = light; 1792 light = light->next; 1793 } 1794 } 1795 _printf (" %7i lights in solid\n", numsolid); 1796 } 1797 1798 /* 1799 ============= 1800 LightWorld 1801 ============= 1802 */ 1803 void LightWorld (void) { 1804 float f; 1805 1806 // determine the number of grid points 1807 SetupGrid(); 1808 1809 // find the optional world ambient 1810 GetVectorForKey( &entities[0], "_color", ambientColor ); 1811 f = FloatForKey( &entities[0], "ambient" ); 1812 VectorScale( ambientColor, f, ambientColor ); 1813 1814 // create lights out of patches and lights 1815 qprintf ("--- CreateLights ---\n"); 1816 CreateEntityLights (); 1817 qprintf ("%i point lights\n", numPointLights); 1818 qprintf ("%i area lights\n", numAreaLights); 1819 1820 if (!nogridlighting) { 1821 qprintf ("--- TraceGrid ---\n"); 1822 RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid ); 1823 qprintf( "%i x %i x %i = %i grid\n", gridBounds[0], gridBounds[1], 1824 gridBounds[2], numGridPoints); 1825 } 1826 1827 qprintf ("--- TraceLtm ---\n"); 1828 RunThreadsOnIndividual( numDrawSurfaces, qtrue, TraceLtm ); 1829 qprintf( "%5i visible samples\n", c_visible ); 1830 qprintf( "%5i occluded samples\n", c_occluded ); 1831 } 1832 1833 /* 1834 ======== 1835 CreateFilters 1836 1837 EXPERIMENTAL, UNUSED 1838 1839 Look for transparent light filter surfaces. 1840 1841 This will only work for flat 3*3 patches that exactly hold one copy of the texture. 1842 ======== 1843 */ 1844 #define PLANAR_PATCH_EPSILON 0.1 1845 void CreateFilters( void ) { 1846 int i; 1847 filter_t *f; 1848 dsurface_t *ds; 1849 shaderInfo_t *si; 1850 drawVert_t *v1, *v2, *v3; 1851 vec3_t d1, d2; 1852 int vertNum; 1853 1854 numFilters = 0; 1855 1856 return; 1857 1858 for ( i = 0 ; i < numDrawSurfaces ; i++ ) { 1859 ds = &drawSurfaces[i]; 1860 if ( !ds->patchWidth ) { 1861 continue; 1862 } 1863 si = ShaderInfoForShader( dshaders[ ds->shaderNum ].shader ); 1864 /* 1865 if ( !(si->surfaceFlags & SURF_LIGHTFILTER) ) { 1866 continue; 1867 } 1868 */ 1869 1870 // we have a filter patch 1871 v1 = &drawVerts[ ds->firstVert ]; 1872 1873 if ( ds->patchWidth != 3 || ds->patchHeight != 3 ) { 1874 _printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't a 3 by 3\n", 1875 v1->xyz[0], v1->xyz[1], v1->xyz[2] ); 1876 continue; 1877 } 1878 1879 if ( numFilters == MAX_FILTERS ) { 1880 Error( "MAX_FILTERS" ); 1881 } 1882 f = &filters[ numFilters ]; 1883 numFilters++; 1884 1885 v2 = &drawVerts[ ds->firstVert + 2 ]; 1886 v3 = &drawVerts[ ds->firstVert + 6 ]; 1887 1888 VectorSubtract( v2->xyz, v1->xyz, d1 ); 1889 VectorSubtract( v3->xyz, v1->xyz, d2 ); 1890 VectorNormalize( d1, d1 ); 1891 VectorNormalize( d2, d2 ); 1892 CrossProduct( d1, d2, f->plane ); 1893 f->plane[3] = DotProduct( v1->xyz, f->plane ); 1894 1895 // make sure all the control points are on the plane 1896 for ( vertNum = 0 ; vertNum < ds->numVerts ; vertNum++ ) { 1897 float d; 1898 1899 d = DotProduct( drawVerts[ ds->firstVert + vertNum ].xyz, f->plane ) - f->plane[3]; 1900 if ( fabs( d ) > PLANAR_PATCH_EPSILON ) { 1901 break; 1902 } 1903 } 1904 if ( vertNum != ds->numVerts ) { 1905 numFilters--; 1906 _printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't flat\n", 1907 v1->xyz[0], v1->xyz[1], v1->xyz[2] ); 1908 continue; 1909 } 1910 } 1911 1912 f = &filters[0]; 1913 numFilters = 1; 1914 1915 f->plane[0] = 1; 1916 f->plane[1] = 0; 1917 f->plane[2] = 0; 1918 f->plane[3] = 448; 1919 1920 f->origin[0] = 448; 1921 f->origin[1] = 192; 1922 f->origin[2] = 0; 1923 1924 f->vectors[0][0] = 0; 1925 f->vectors[0][1] = -1.0 / 128; 1926 f->vectors[0][2] = 0; 1927 1928 f->vectors[1][0] = 0; 1929 f->vectors[1][1] = 0; 1930 f->vectors[1][2] = 1.0 / 128; 1931 1932 f->si = ShaderInfoForShader( "textures/hell/blocks11ct" ); 1933 } 1934 1935 /* 1936 ============= 1937 VertexLightingThread 1938 ============= 1939 */ 1940 void VertexLightingThread(int num) { 1941 dsurface_t *ds; 1942 traceWork_t tw; 1943 shaderInfo_t *si; 1944 1945 ds = &drawSurfaces[num]; 1946 1947 // vertex-lit triangle model 1948 if ( ds->surfaceType == MST_TRIANGLE_SOUP ) { 1949 return; 1950 } 1951 1952 if (novertexlighting) 1953 return; 1954 1955 if ( ds->lightmapNum == -1 ) { 1956 return; // doesn't need lighting at all 1957 } 1958 1959 si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader ); 1960 1961 // calculate the vertex lighting for gouraud shade mode 1962 VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw ); 1963 } 1964 1965 /* 1966 ============= 1967 TriSoupLightingThread 1968 ============= 1969 */ 1970 void TriSoupLightingThread(int num) { 1971 dsurface_t *ds; 1972 traceWork_t tw; 1973 shaderInfo_t *si; 1974 1975 ds = &drawSurfaces[num]; 1976 si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader ); 1977 1978 // vertex-lit triangle model 1979 if ( ds->surfaceType == MST_TRIANGLE_SOUP ) { 1980 VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw ); 1981 } 1982 } 1983 1984 /* 1985 ============= 1986 GridAndVertexLighting 1987 ============= 1988 */ 1989 void GridAndVertexLighting(void) { 1990 SetupGrid(); 1991 1992 FindSkyBrushes(); 1993 CreateFilters(); 1994 InitTrace(); 1995 CreateEntityLights (); 1996 CreateSurfaceLights(); 1997 1998 if (!nogridlighting) { 1999 _printf ("--- TraceGrid ---\n"); 2000 RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid ); 2001 } 2002 2003 if (!novertexlighting) { 2004 _printf ("--- Vertex Lighting ---\n"); 2005 RunThreadsOnIndividual( numDrawSurfaces, qtrue, VertexLightingThread ); 2006 } 2007 2008 _printf("--- Model Lighting ---\n"); 2009 RunThreadsOnIndividual( numDrawSurfaces, qtrue, TriSoupLightingThread ); 2010 } 2011 2012 /* 2013 ======== 2014 LightMain 2015 2016 ======== 2017 */ 2018 int LightMain (int argc, char **argv) { 2019 int i; 2020 double start, end; 2021 const char *value; 2022 2023 _printf ("----- Lighting ----\n"); 2024 2025 verbose = qfalse; 2026 2027 for (i=1 ; i<argc ; i++) { 2028 if (!strcmp(argv[i],"-tempname")) 2029 { 2030 i++; 2031 } else if (!strcmp(argv[i],"-v")) { 2032 verbose = qtrue; 2033 } else if (!strcmp(argv[i],"-threads")) { 2034 numthreads = atoi (argv[i+1]); 2035 i++; 2036 } else if (!strcmp(argv[i],"-area")) { 2037 areaScale *= atof(argv[i+1]); 2038 _printf ("area light scaling at %f\n", areaScale); 2039 i++; 2040 } else if (!strcmp(argv[i],"-point")) { 2041 pointScale *= atof(argv[i+1]); 2042 _printf ("point light scaling at %f\n", pointScale); 2043 i++; 2044 } else if (!strcmp(argv[i],"-notrace")) { 2045 notrace = qtrue; 2046 _printf ("No occlusion tracing\n"); 2047 } else if (!strcmp(argv[i],"-patchshadows")) { 2048 patchshadows = qtrue; 2049 _printf ("Patch shadow casting enabled\n"); 2050 } else if (!strcmp(argv[i],"-extra")) { 2051 extra = qtrue; 2052 _printf ("Extra detail tracing\n"); 2053 } else if (!strcmp(argv[i],"-extrawide")) { 2054 extra = qtrue; 2055 extraWide = qtrue; 2056 _printf ("Extra wide detail tracing\n"); 2057 } else if (!strcmp(argv[i], "-samplesize")) { 2058 samplesize = atoi(argv[i+1]); 2059 if (samplesize < 1) samplesize = 1; 2060 i++; 2061 _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize); 2062 } else if (!strcmp(argv[i], "-novertex")) { 2063 novertexlighting = qtrue; 2064 _printf("no vertex lighting = true\n"); 2065 } else if (!strcmp(argv[i], "-nogrid")) { 2066 nogridlighting = qtrue; 2067 _printf("no grid lighting = true\n"); 2068 } else if (!strcmp(argv[i],"-border")) { 2069 lightmapBorder = qtrue; 2070 _printf ("Adding debug border to lightmaps\n"); 2071 } else if (!strcmp(argv[i],"-nosurf")) { 2072 noSurfaces = qtrue; 2073 _printf ("Not tracing against surfaces\n" ); 2074 } else if (!strcmp(argv[i],"-dump")) { 2075 dump = qtrue; 2076 _printf ("Dumping occlusion maps\n"); 2077 } else { 2078 break; 2079 } 2080 } 2081 2082 ThreadSetDefault (); 2083 2084 if (i != argc - 1) { 2085 _printf("usage: q3map -light [-<switch> [-<switch> ...]] <mapname>\n" 2086 "\n" 2087 "Switches:\n" 2088 " v = verbose output\n" 2089 " threads <X> = set number of threads to X\n" 2090 " area <V> = set the area light scale to V\n" 2091 " point <W> = set the point light scale to W\n" 2092 " notrace = don't cast any shadows\n" 2093 " extra = enable super sampling for anti-aliasing\n" 2094 " extrawide = same as extra but smoothen more\n" 2095 " nogrid = don't calculate light grid for dynamic model lighting\n" 2096 " novertex = don't calculate vertex lighting\n" 2097 " samplesize <N> = set the lightmap pixel size to NxN units\n"); 2098 exit(0); 2099 } 2100 2101 start = I_FloatTime (); 2102 2103 SetQdirFromPath (argv[i]); 2104 2105 #ifdef _WIN32 2106 InitPakFile(gamedir, NULL); 2107 #endif 2108 2109 strcpy (source, ExpandArg(argv[i])); 2110 StripExtension (source); 2111 DefaultExtension (source, ".bsp"); 2112 2113 LoadShaderInfo(); 2114 2115 _printf ("reading %s\n", source); 2116 2117 LoadBSPFile (source); 2118 2119 FindSkyBrushes(); 2120 2121 ParseEntities(); 2122 2123 value = ValueForKey( &entities[0], "gridsize" ); 2124 if (strlen(value)) { 2125 sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] ); 2126 _printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]); 2127 } 2128 2129 CreateFilters(); 2130 2131 InitTrace(); 2132 2133 SetEntityOrigins(); 2134 2135 CountLightmaps(); 2136 2137 CreateSurfaceLights(); 2138 2139 LightWorld(); 2140 2141 _printf ("writing %s\n", source); 2142 WriteBSPFile (source); 2143 2144 end = I_FloatTime (); 2145 _printf ("%5.0f seconds elapsed\n", end-start); 2146 2147 return 0; 2148 } 2149