00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "light.h"
00025 #ifdef _WIN32
00026 #ifdef _TTIMOBUILD
00027 #include "pakstuff.h"
00028 #else
00029 #include "../libs/pakstuff.h"
00030 #endif
00031 #endif
00032
00033
00034 #define EXTRASCALE 2
00035
00036 typedef struct {
00037 float plane[4];
00038 vec3_t origin;
00039 vec3_t vectors[2];
00040 shaderInfo_t *si;
00041 } filter_t;
00042
00043 #define MAX_FILTERS 1024
00044 filter_t filters[MAX_FILTERS];
00045 int numFilters;
00046
00047 extern char source[1024];
00048
00049 qboolean notrace;
00050 qboolean patchshadows;
00051 qboolean dump;
00052 qboolean extra;
00053 qboolean extraWide;
00054 qboolean lightmapBorder;
00055
00056 qboolean noSurfaces;
00057
00058 int samplesize = 16;
00059 int novertexlighting = 0;
00060 int nogridlighting = 0;
00061
00062
00063 float areaScale = 0.25;
00064
00065
00066 float pointScale = 7500;
00067
00068 qboolean exactPointToPolygon = qtrue;
00069
00070 float formFactorValueScale = 3;
00071
00072 float linearScale = 1.0 / 8000;
00073
00074 light_t *lights;
00075 int numPointLights;
00076 int numAreaLights;
00077
00078 FILE *dumpFile;
00079
00080 int c_visible, c_occluded;
00081
00082
00083 int defaultLightSubdivide = 999;
00084
00085 vec3_t ambientColor;
00086
00087 vec3_t surfaceOrigin[ MAX_MAP_DRAW_SURFS ];
00088 int entitySurface[ MAX_MAP_DRAW_SURFS ];
00089
00090
00091
00092
00093
00094
00095
00096 vec3_t sunDirection = { 0.45, 0.3, 0.9 };
00097 vec3_t sunLight = { 100, 100, 50 };
00098
00099
00100
00101 typedef struct {
00102 dbrush_t *b;
00103 vec3_t bounds[2];
00104 } skyBrush_t;
00105
00106 int numSkyBrushes;
00107 skyBrush_t skyBrushes[MAX_MAP_BRUSHES];
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 #define MAX_FACE_POINTS 128
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137 void SubdivideAreaLight( shaderInfo_t *ls, winding_t *w, vec3_t normal,
00138 float areaSubdivide, qboolean backsplash ) {
00139 float area, value, intensity;
00140 light_t *dl, *dl2;
00141 vec3_t mins, maxs;
00142 int axis;
00143 winding_t *front, *back;
00144 vec3_t planeNormal;
00145 float planeDist;
00146
00147 if ( !w ) {
00148 return;
00149 }
00150
00151 WindingBounds( w, mins, maxs );
00152
00153
00154 for ( axis = 0 ; axis < 3 ; axis++ ) {
00155 if ( maxs[axis] - mins[axis] > areaSubdivide ) {
00156 VectorClear( planeNormal );
00157 planeNormal[axis] = 1;
00158 planeDist = ( maxs[axis] + mins[axis] ) * 0.5;
00159 ClipWindingEpsilon ( w, planeNormal, planeDist, ON_EPSILON, &front, &back );
00160 SubdivideAreaLight( ls, front, normal, areaSubdivide, qfalse );
00161 SubdivideAreaLight( ls, back, normal, areaSubdivide, qfalse );
00162 FreeWinding( w );
00163 return;
00164 }
00165 }
00166
00167
00168 area = WindingArea (w);
00169 if ( area <= 0 || area > 20000000 ) {
00170 return;
00171 }
00172
00173 numAreaLights++;
00174 dl = malloc(sizeof(*dl));
00175 memset (dl, 0, sizeof(*dl));
00176 dl->next = lights;
00177 lights = dl;
00178 dl->type = emit_area;
00179
00180 WindingCenter( w, dl->origin );
00181 dl->w = w;
00182 VectorCopy ( normal, dl->normal);
00183 dl->dist = DotProduct( dl->origin, normal );
00184
00185 value = ls->value;
00186 intensity = value * area * areaScale;
00187 VectorAdd( dl->origin, dl->normal, dl->origin );
00188
00189 VectorCopy( ls->color, dl->color );
00190
00191 dl->photons = intensity;
00192
00193
00194 VectorScale( ls->color, value*formFactorValueScale*areaScale, dl->emitColor );
00195
00196 dl->si = ls;
00197
00198 if ( ls->contents & CONTENTS_FOG ) {
00199 dl->twosided = qtrue;
00200 }
00201
00202
00203 if ( backsplash && ls->backsplashFraction > 0 ) {
00204 dl2 = malloc(sizeof(*dl));
00205 memset (dl2, 0, sizeof(*dl2));
00206 dl2->next = lights;
00207 lights = dl2;
00208 dl2->type = emit_point;
00209
00210 VectorMA( dl->origin, ls->backsplashDistance, normal, dl2->origin );
00211
00212 VectorCopy( ls->color, dl2->color );
00213
00214 dl2->photons = dl->photons * ls->backsplashFraction;
00215 dl2->si = ls;
00216 }
00217 }
00218
00219
00220
00221
00222
00223
00224
00225 void CountLightmaps( void ) {
00226 int count;
00227 int i;
00228 dsurface_t *ds;
00229
00230 qprintf ("--- CountLightmaps ---\n");
00231 count = 0;
00232 for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
00233
00234 ds = &drawSurfaces[i];
00235 if ( ds->lightmapNum > count ) {
00236 count = ds->lightmapNum;
00237 }
00238 }
00239
00240 count++;
00241 numLightBytes = count * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3;
00242 if ( numLightBytes > MAX_MAP_LIGHTING ) {
00243 Error("MAX_MAP_LIGHTING exceeded");
00244 }
00245
00246 qprintf( "%5i drawSurfaces\n", numDrawSurfaces );
00247 qprintf( "%5i lightmaps\n", count );
00248 }
00249
00250
00251
00252
00253
00254
00255
00256
00257 void CreateSurfaceLights( void ) {
00258 int i, j, side;
00259 dsurface_t *ds;
00260 shaderInfo_t *ls;
00261 winding_t *w;
00262 cFacet_t *f;
00263 light_t *dl;
00264 vec3_t origin;
00265 drawVert_t *dv;
00266 int c_lightSurfaces;
00267 float lightSubdivide;
00268 vec3_t normal;
00269
00270 qprintf ("--- CreateSurfaceLights ---\n");
00271 c_lightSurfaces = 0;
00272
00273 for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
00274
00275 ds = &drawSurfaces[i];
00276
00277 ls = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
00278 if ( ls->value == 0 ) {
00279 continue;
00280 }
00281
00282
00283 if ( ls->lightSubdivide ) {
00284 lightSubdivide = ls->lightSubdivide;
00285 } else {
00286 lightSubdivide = defaultLightSubdivide;
00287 }
00288
00289 c_lightSurfaces++;
00290
00291
00292
00293 if ( ls->autosprite ) {
00294
00295 if ( surfaceTest[i] ) {
00296
00297 f = surfaceTest[i]->facets;
00298 if ( surfaceTest[i]->numFacets != 1 || f->numBoundaries != 4 ) {
00299 _printf( "WARNING: surface at (%i %i %i) has autosprite shader but isn't a quad\n",
00300 (int)f->points[0], (int)f->points[1], (int)f->points[2] );
00301 }
00302 VectorAdd( f->points[0], f->points[1], origin );
00303 VectorAdd( f->points[2], origin, origin );
00304 VectorAdd( f->points[3], origin, origin );
00305 VectorScale( origin, 0.25, origin );
00306 } else {
00307
00308 dv = &drawVerts[ ds->firstVert ];
00309 if ( ds->numVerts != 4 ) {
00310 _printf( "WARNING: surface at (%i %i %i) has autosprite shader but %i verts\n",
00311 (int)dv->xyz[0], (int)dv->xyz[1], (int)dv->xyz[2] );
00312 continue;
00313 }
00314
00315 VectorAdd( dv[0].xyz, dv[1].xyz, origin );
00316 VectorAdd( dv[2].xyz, origin, origin );
00317 VectorAdd( dv[3].xyz, origin, origin );
00318 VectorScale( origin, 0.25, origin );
00319 }
00320
00321
00322 numPointLights++;
00323 dl = malloc(sizeof(*dl));
00324 memset (dl, 0, sizeof(*dl));
00325 dl->next = lights;
00326 lights = dl;
00327
00328 VectorCopy( origin, dl->origin );
00329 VectorCopy( ls->color, dl->color );
00330 dl->photons = ls->value * pointScale;
00331 dl->type = emit_point;
00332 continue;
00333 }
00334
00335
00336 for ( side = 0 ; side <= ls->twoSided ; side++ ) {
00337
00338 if ( surfaceTest[i] ) {
00339
00340 for ( j = 0 ; j < surfaceTest[i]->numFacets ; j++ ) {
00341 f = surfaceTest[i]->facets + j;
00342 w = AllocWinding( f->numBoundaries );
00343 w->numpoints = f->numBoundaries;
00344 memcpy( w->p, f->points, f->numBoundaries * 12 );
00345
00346 VectorCopy( f->surface, normal );
00347 if ( side ) {
00348 winding_t *t;
00349
00350 t = w;
00351 w = ReverseWinding( t );
00352 FreeWinding( t );
00353 VectorSubtract( vec3_origin, normal, normal );
00354 }
00355 SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
00356 }
00357 } else {
00358
00359
00360 w = AllocWinding( ds->numVerts );
00361 w->numpoints = ds->numVerts;
00362 for ( j = 0 ; j < ds->numVerts ; j++ ) {
00363 VectorCopy( drawVerts[ds->firstVert+j].xyz, w->p[j] );
00364 }
00365 VectorCopy( ds->lightmapVecs[2], normal );
00366 if ( side ) {
00367 winding_t *t;
00368
00369 t = w;
00370 w = ReverseWinding( t );
00371 FreeWinding( t );
00372 VectorSubtract( vec3_origin, normal, normal );
00373 }
00374 SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
00375 }
00376 }
00377 }
00378
00379 _printf( "%5i light emitting surfaces\n", c_lightSurfaces );
00380 }
00381
00382
00383
00384
00385
00386
00387
00388
00389 void FindSkyBrushes( void ) {
00390 int i, j;
00391 dbrush_t *b;
00392 skyBrush_t *sb;
00393 shaderInfo_t *si;
00394 dbrushside_t *s;
00395
00396
00397 for ( i = 0 ; i < numbrushes ; i++ ) {
00398 b = &dbrushes[i];
00399 for ( j = 0 ; j < b->numSides ; j++ ) {
00400 s = &dbrushsides[ b->firstSide + j ];
00401 if ( dshaders[ s->shaderNum ].surfaceFlags & SURF_SKY ) {
00402 sb = &skyBrushes[ numSkyBrushes ];
00403 sb->b = b;
00404 sb->bounds[0][0] = -dplanes[ dbrushsides[ b->firstSide + 0 ].planeNum ].dist - 1;
00405 sb->bounds[1][0] = dplanes[ dbrushsides[ b->firstSide + 1 ].planeNum ].dist + 1;
00406 sb->bounds[0][1] = -dplanes[ dbrushsides[ b->firstSide + 2 ].planeNum ].dist - 1;
00407 sb->bounds[1][1] = dplanes[ dbrushsides[ b->firstSide + 3 ].planeNum ].dist + 1;
00408 sb->bounds[0][2] = -dplanes[ dbrushsides[ b->firstSide + 4 ].planeNum ].dist - 1;
00409 sb->bounds[1][2] = dplanes[ dbrushsides[ b->firstSide + 5 ].planeNum ].dist + 1;
00410 numSkyBrushes++;
00411 break;
00412 }
00413 }
00414 }
00415
00416
00417 VectorNormalize( sunDirection, sunDirection );
00418
00419
00420 for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
00421 si = ShaderInfoForShader( dshaders[ drawSurfaces[i].shaderNum ].shader );
00422 if ( si->surfaceFlags & SURF_SKY ) {
00423 VectorCopy( si->sunLight, sunLight );
00424 VectorCopy( si->sunDirection, sunDirection );
00425 break;
00426 }
00427 }
00428 }
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443 entity_t *FindTargetEntity( const char *target ) {
00444 int i;
00445 const char *n;
00446
00447 for ( i = 0 ; i < num_entities ; i++ ) {
00448 n = ValueForKey (&entities[i], "targetname");
00449 if ( !strcmp (n, target) ) {
00450 return &entities[i];
00451 }
00452 }
00453
00454 return NULL;
00455 }
00456
00457
00458
00459
00460
00461
00462
00463
00464 void CreateEntityLights (void)
00465 {
00466 int i;
00467 light_t *dl;
00468 entity_t *e, *e2;
00469 const char *name;
00470 const char *target;
00471 vec3_t dest;
00472 const char *_color;
00473 float intensity;
00474 int spawnflags;
00475
00476
00477
00478
00479 for ( i = 0 ; i < num_entities ; i++ ) {
00480 e = &entities[i];
00481 name = ValueForKey (e, "classname");
00482 if (strncmp (name, "light", 5))
00483 continue;
00484
00485 numPointLights++;
00486 dl = malloc(sizeof(*dl));
00487 memset (dl, 0, sizeof(*dl));
00488 dl->next = lights;
00489 lights = dl;
00490
00491 spawnflags = FloatForKey (e, "spawnflags");
00492 if ( spawnflags & 1 ) {
00493 dl->linearLight = qtrue;
00494 }
00495
00496 GetVectorForKey (e, "origin", dl->origin);
00497 dl->style = FloatForKey (e, "_style");
00498 if (!dl->style)
00499 dl->style = FloatForKey (e, "style");
00500 if (dl->style < 0)
00501 dl->style = 0;
00502
00503 intensity = FloatForKey (e, "light");
00504 if (!intensity)
00505 intensity = FloatForKey (e, "_light");
00506 if (!intensity)
00507 intensity = 300;
00508 _color = ValueForKey (e, "_color");
00509 if (_color && _color[0])
00510 {
00511 sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);
00512 ColorNormalize (dl->color, dl->color);
00513 }
00514 else
00515 dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
00516
00517 intensity = intensity * pointScale;
00518 dl->photons = intensity;
00519
00520 dl->type = emit_point;
00521
00522
00523 target = ValueForKey (e, "target");
00524
00525 if ( target[0] ) {
00526 float radius;
00527 float dist;
00528
00529 e2 = FindTargetEntity (target);
00530 if (!e2) {
00531 _printf ("WARNING: light at (%i %i %i) has missing target\n",
00532 (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]);
00533 } else {
00534 GetVectorForKey (e2, "origin", dest);
00535 VectorSubtract (dest, dl->origin, dl->normal);
00536 dist = VectorNormalize (dl->normal, dl->normal);
00537 radius = FloatForKey (e, "radius");
00538 if ( !radius ) {
00539 radius = 64;
00540 }
00541 if ( !dist ) {
00542 dist = 64;
00543 }
00544 dl->radiusByDist = (radius + 16) / dist;
00545 dl->type = emit_spotlight;
00546 }
00547 }
00548 }
00549 }
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560 void SetEntityOrigins( void ) {
00561 int i, j;
00562 entity_t *e;
00563 vec3_t origin;
00564 const char *key;
00565 int modelnum;
00566 dmodel_t *dm;
00567
00568 for ( i=0 ; i < num_entities ; i++ ) {
00569 e = &entities[i];
00570 key = ValueForKey (e, "model");
00571 if ( key[0] != '*' ) {
00572 continue;
00573 }
00574 modelnum = atoi( key + 1 );
00575 dm = &dmodels[ modelnum ];
00576
00577
00578 for ( j = 0 ; j < dm->numSurfaces ; j++ ) {
00579 entitySurface[ dm->firstSurface + j ] = qtrue;
00580 }
00581
00582 key = ValueForKey (e, "origin");
00583 if ( !key[0] ) {
00584 continue;
00585 }
00586 GetVectorForKey ( e, "origin", origin );
00587
00588
00589 for ( j = 0 ; j < dm->numSurfaces ; j++ ) {
00590 VectorCopy( origin, surfaceOrigin[ dm->firstSurface + j ] );
00591 }
00592 }
00593 }
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603 #define MAX_POINTS_ON_WINDINGS 64
00604
00605
00606
00607
00608
00609
00610 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w ) {
00611 vec3_t triVector, triNormal;
00612 int i, j;
00613 vec3_t dirs[MAX_POINTS_ON_WINDING];
00614 float total;
00615 float dot, angle, facing;
00616
00617 for ( i = 0 ; i < w->numpoints ; i++ ) {
00618 VectorSubtract( w->p[i], point, dirs[i] );
00619 VectorNormalize( dirs[i], dirs[i] );
00620 }
00621
00622
00623 VectorCopy( dirs[0], dirs[i] );
00624
00625 total = 0;
00626 for ( i = 0 ; i < w->numpoints ; i++ ) {
00627 j = i+1;
00628 dot = DotProduct( dirs[i], dirs[j] );
00629
00630
00631 if ( dot > 1.0 ) {
00632 dot = 1.0;
00633 } else if ( dot < -1.0 ) {
00634 dot = -1.0;
00635 }
00636
00637 angle = acos( dot );
00638 CrossProduct( dirs[i], dirs[j], triVector );
00639 if ( VectorNormalize( triVector, triNormal ) < 0.0001 ) {
00640 continue;
00641 }
00642 facing = DotProduct( normal, triNormal );
00643 total += facing * angle;
00644
00645 if ( total > 6.3 || total < -6.3 ) {
00646 static qboolean printed;
00647
00648 if ( !printed ) {
00649 printed = qtrue;
00650 _printf( "WARNING: bad PointToPolygonFormFactor: %f at %1.1f %1.1f %1.1f from %1.1f %1.1f %1.1f\n", total,
00651 w->p[i][0], w->p[i][1], w->p[i][2], point[0], point[1], point[2]);
00652 }
00653 return 0;
00654 }
00655
00656 }
00657
00658 total /= 2*3.141592657;
00659
00660 return total;
00661 }
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671 void FilterTrace( const vec3_t start, const vec3_t end, vec3_t filter ) {
00672 float d1, d2;
00673 filter_t *f;
00674 int filterNum;
00675 vec3_t point;
00676 float frac;
00677 int i;
00678 float s, t;
00679 int u, v;
00680 int x, y;
00681 byte *pixel;
00682 float radius;
00683 float len;
00684 vec3_t total;
00685
00686 filter[0] = 1.0;
00687 filter[1] = 1.0;
00688 filter[2] = 1.0;
00689
00690 for ( filterNum = 0 ; filterNum < numFilters ; filterNum++ ) {
00691 f = &filters[ filterNum ];
00692
00693
00694 d1 = DotProduct( start, f->plane ) - f->plane[3];
00695 d2 = DotProduct( end, f->plane ) - f->plane[3];
00696
00697 if ( ( d1 < 0 ) == ( d2 < 0 ) ) {
00698 continue;
00699 }
00700
00701
00702 frac = d1 / ( d1 - d2 );
00703
00704 for ( i = 0 ; i < 3 ; i++ ) {
00705 point[i] = start[i] + frac * ( end[i] - start[i] );
00706 }
00707
00708 VectorSubtract( point, f->origin, point );
00709
00710 s = DotProduct( point, f->vectors[0] );
00711 t = 1.0 - DotProduct( point, f->vectors[1] );
00712 if ( s < 0 || s >= 1.0 || t < 0 || t >= 1.0 ) {
00713 continue;
00714 }
00715
00716
00717 radius = 10 * frac;
00718 len = VectorLength( f->vectors[0] );
00719 if ( !len ) {
00720 continue;
00721 }
00722 radius = radius * len * f->si->width;
00723
00724
00725 VectorClear( total );
00726 for ( u = -1 ; u <= 1 ; u++ ) {
00727 for ( v = -1 ; v <=1 ; v++ ) {
00728 x = s * f->si->width + u * radius;
00729 if ( x < 0 ) {
00730 x = 0;
00731 }
00732 if ( x >= f->si->width ) {
00733 x = f->si->width - 1;
00734 }
00735 y = t * f->si->height + v * radius;
00736 if ( y < 0 ) {
00737 y = 0;
00738 }
00739 if ( y >= f->si->height ) {
00740 y = f->si->height - 1;
00741 }
00742
00743 pixel = f->si->pixels + ( y * f->si->width + x ) * 4;
00744 total[0] += pixel[0];
00745 total[1] += pixel[1];
00746 total[2] += pixel[2];
00747 }
00748 }
00749
00750 filter[0] *= total[0]/(255.0*9);
00751 filter[1] *= total[1]/(255.0*9);
00752 filter[2] *= total[2]/(255.0*9);
00753 }
00754
00755 }
00756
00757
00758
00759
00760
00761
00762
00763
00764 int c_sunHit, c_sunMiss;
00765 void SunToPoint( const vec3_t origin, traceWork_t *tw, vec3_t addLight ) {
00766 int i;
00767 trace_t trace;
00768 skyBrush_t *b;
00769 vec3_t end;
00770
00771 if ( !numSkyBrushes ) {
00772 VectorClear( addLight );
00773 return;
00774 }
00775
00776 VectorMA( origin, MAX_WORLD_COORD * 2, sunDirection, end );
00777
00778 TraceLine( origin, end, &trace, qtrue, tw );
00779
00780
00781 for ( i = 0 ; i < numSkyBrushes ; i++) {
00782 b = &skyBrushes[ i ];
00783
00784
00785 if ( trace.hit[0] < b->bounds[0][0]
00786 || trace.hit[0] > b->bounds[1][0]
00787 || trace.hit[1] < b->bounds[0][1]
00788 || trace.hit[1] > b->bounds[1][1]
00789 || trace.hit[2] < b->bounds[0][2]
00790 || trace.hit[2] > b->bounds[1][2] ) {
00791 continue;
00792 }
00793
00794
00795
00796 TraceLine( origin, trace.hit, &trace, qtrue, tw );
00797
00798
00799 if ( numthreads == 1 ) {
00800 c_sunHit++;
00801 }
00802 addLight[0] = trace.filter[0] * sunLight[0];
00803 addLight[1] = trace.filter[1] * sunLight[1];
00804 addLight[2] = trace.filter[2] * sunLight[2];
00805
00806 return;
00807 }
00808
00809 if ( numthreads == 1 ) {
00810 c_sunMiss++;
00811 }
00812
00813 VectorClear( addLight );
00814 }
00815
00816
00817
00818
00819
00820
00821 void SunToPlane( const vec3_t origin, const vec3_t normal, vec3_t color, traceWork_t *tw ) {
00822 float angle;
00823 vec3_t sunColor;
00824
00825 if ( !numSkyBrushes ) {
00826 return;
00827 }
00828
00829 angle = DotProduct( normal, sunDirection );
00830 if ( angle <= 0 ) {
00831 return;
00832 }
00833
00834 SunToPoint( origin, tw, sunColor );
00835 VectorMA( color, angle, sunColor, color );
00836 }
00837
00838
00839
00840
00841
00842
00843 void LightingAtSample( vec3_t origin, vec3_t normal, vec3_t color,
00844 qboolean testOcclusion, qboolean forceSunLight, traceWork_t *tw ) {
00845 light_t *light;
00846 trace_t trace;
00847 float angle;
00848 float add;
00849 float dist;
00850 vec3_t dir;
00851
00852 VectorCopy( ambientColor, color );
00853
00854
00855 for ( light = lights ; light ; light = light->next ) {
00856
00857
00858 if ( DotProduct(light->origin, normal) - DotProduct(normal, origin) < 0 )
00859 continue;
00860
00861 if ( exactPointToPolygon && light->type == emit_area ) {
00862 float factor;
00863 float d;
00864 vec3_t pushedOrigin;
00865
00866
00867 d = DotProduct( origin, light->normal ) - light->dist;
00868 if ( !light->twosided ) {
00869 if ( d < -1 ) {
00870 continue;
00871 }
00872 }
00873
00874
00875
00876 if ( !notrace && testOcclusion ) {
00877 TraceLine( origin, light->origin, &trace, qfalse, tw );
00878
00879
00880 if ( trace.passSolid ) {
00881 continue;
00882 }
00883 } else {
00884 trace.filter[0] = 1.0;
00885 trace.filter[1] = 1.0;
00886 trace.filter[2] = 1.0;
00887 }
00888
00889
00890
00891 if ( d > -8 && d < 8 ) {
00892 VectorMA( origin, (8-d), light->normal, pushedOrigin );
00893 } else {
00894 VectorCopy( origin, pushedOrigin );
00895 }
00896
00897
00898 factor = PointToPolygonFormFactor( pushedOrigin, normal, light->w );
00899 if ( factor <= 0 ) {
00900 if ( light->twosided ) {
00901 factor = -factor;
00902 } else {
00903 continue;
00904 }
00905 }
00906 color[0] += factor * light->emitColor[0] * trace.filter[0];
00907 color[1] += factor * light->emitColor[1] * trace.filter[1];
00908 color[2] += factor * light->emitColor[2] * trace.filter[2];
00909
00910 continue;
00911 }
00912
00913
00914 if ( light->type == emit_point ) {
00915 VectorSubtract( light->origin, origin, dir );
00916 dist = VectorNormalize( dir, dir );
00917
00918 if ( dist < 16 ) {
00919 dist = 16;
00920 }
00921 angle = DotProduct( normal, dir );
00922 if ( light->linearLight ) {
00923 add = angle * light->photons * linearScale - dist;
00924 if ( add < 0 ) {
00925 add = 0;
00926 }
00927 } else {
00928 add = light->photons / ( dist * dist ) * angle;
00929 }
00930 } else if ( light->type == emit_spotlight ) {
00931 float distByNormal;
00932 vec3_t pointAtDist;
00933 float radiusAtDist;
00934 float sampleRadius;
00935 vec3_t distToSample;
00936 float coneScale;
00937
00938 VectorSubtract( light->origin, origin, dir );
00939
00940 distByNormal = -DotProduct( dir, light->normal );
00941 if ( distByNormal < 0 ) {
00942 continue;
00943 }
00944 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
00945 radiusAtDist = light->radiusByDist * distByNormal;
00946
00947 VectorSubtract( origin, pointAtDist, distToSample );
00948 sampleRadius = VectorLength( distToSample );
00949
00950 if ( sampleRadius >= radiusAtDist ) {
00951 continue;
00952 }
00953 if ( sampleRadius <= radiusAtDist - 32 ) {
00954 coneScale = 1.0;
00955 } else {
00956 coneScale = ( radiusAtDist - sampleRadius ) / 32.0;
00957 }
00958
00959 dist = VectorNormalize( dir, dir );
00960
00961 if ( dist < 16 ) {
00962 dist = 16;
00963 }
00964 angle = DotProduct( normal, dir );
00965 add = light->photons / ( dist * dist ) * angle * coneScale;
00966
00967 } else if ( light->type == emit_area ) {
00968 VectorSubtract( light->origin, origin, dir );
00969 dist = VectorNormalize( dir, dir );
00970
00971 if ( dist < 16 ) {
00972 dist = 16;
00973 }
00974 angle = DotProduct( normal, dir );
00975 if ( angle <= 0 ) {
00976 continue;
00977 }
00978 angle *= -DotProduct( light->normal, dir );
00979 if ( angle <= 0 ) {
00980 continue;
00981 }
00982
00983 if ( light->linearLight ) {
00984 add = angle * light->photons * linearScale - dist;
00985 if ( add < 0 ) {
00986 add = 0;
00987 }
00988 } else {
00989 add = light->photons / ( dist * dist ) * angle;
00990 }
00991 }
00992
00993 if ( add <= 1.0 ) {
00994 continue;
00995 }
00996
00997
00998 if ( !notrace && testOcclusion ) {
00999 TraceLine( origin, light->origin, &trace, qfalse, tw );
01000
01001
01002 if ( trace.passSolid ) {
01003 continue;
01004 }
01005 } else {
01006 trace.filter[0] = 1;
01007 trace.filter[1] = 1;
01008 trace.filter[2] = 1;
01009 }
01010
01011
01012 color[0] += add * light->color[0] * trace.filter[0];
01013 color[1] += add * light->color[1] * trace.filter[1];
01014 color[2] += add * light->color[2] * trace.filter[2];
01015 }
01016
01017
01018
01019
01020 if ( testOcclusion || forceSunLight ) {
01021 SunToPlane( origin, normal, color, tw );
01022 }
01023 }
01024
01025
01026
01027
01028
01029
01030
01031
01032 void PrintOccluded( byte occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE],
01033 int width, int height ) {
01034 int i, j;
01035
01036 _printf( "\n" );
01037
01038 for ( i = 0 ; i < height ; i++ ) {
01039 for ( j = 0 ; j < width ; j++ ) {
01040 _printf("%i", (int)occluded[j][i] );
01041 }
01042 _printf( "\n" );
01043 }
01044 }
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055 void VertexLighting( dsurface_t *ds, qboolean testOcclusion, qboolean forceSunLight, float scale, traceWork_t *tw ) {
01056 int i, j;
01057 drawVert_t *dv;
01058 vec3_t sample, normal;
01059 float max;
01060
01061 VectorCopy( ds->lightmapVecs[2], normal );
01062
01063
01064 for ( i = 0 ; i < ds->numVerts ; i++ ) {
01065 dv = &drawVerts[ ds->firstVert + i ];
01066
01067 if ( ds->patchWidth ) {
01068 LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw );
01069 }
01070 else if (ds->surfaceType == MST_TRIANGLE_SOUP) {
01071 LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw );
01072 }
01073 else {
01074 LightingAtSample( dv->xyz, normal, sample, testOcclusion, forceSunLight, tw );
01075 }
01076
01077 if (scale >= 0)
01078 VectorScale(sample, scale, sample);
01079
01080 max = sample[0];
01081 if ( sample[1] > max ) {
01082 max = sample[1];
01083 }
01084 if ( sample[2] > max ) {
01085 max = sample[2];
01086 }
01087 if ( max > 255 ) {
01088 VectorScale( sample, 255/max, sample );
01089 }
01090
01091
01092 for ( j = 0 ; j < 3 ; j++ ) {
01093 if ( sample[j] > 255 ) {
01094 sample[j] = 255;
01095 }
01096 dv->color[j] = sample[j];
01097 }
01098
01099
01100
01101
01102 }
01103 }
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114 mesh_t *LinearSubdivideMesh( mesh_t *in ) {
01115 int i, j;
01116 mesh_t *out;
01117 drawVert_t *v1, *v2, *vout;
01118
01119 out = malloc( sizeof( *out ) );
01120
01121 out->width = in->width * 2;
01122 out->height = in->height;
01123 out->verts = malloc( out->width * out->height * sizeof(*out->verts) );
01124 for ( j = 0 ; j < in->height ; j++ ) {
01125 out->verts[ j * out->width + 0 ] = in->verts[ j * in->width + 0 ];
01126 out->verts[ j * out->width + out->width - 1 ] = in->verts[ j * in->width + in->width - 1 ];
01127 for ( i = 1 ; i < out->width - 1 ; i+= 2 ) {
01128 v1 = in->verts + j * in->width + (i >> 1);
01129 v2 = v1 + 1;
01130 vout = out->verts + j * out->width + i;
01131
01132 vout->xyz[0] = 0.75 * v1->xyz[0] + 0.25 * v2->xyz[0];
01133 vout->xyz[1] = 0.75 * v1->xyz[1] + 0.25 * v2->xyz[1];
01134 vout->xyz[2] = 0.75 * v1->xyz[2] + 0.25 * v2->xyz[2];
01135
01136 vout->normal[0] = 0.75 * v1->normal[0] + 0.25 * v2->normal[0];
01137 vout->normal[1] = 0.75 * v1->normal[1] + 0.25 * v2->normal[1];
01138 vout->normal[2] = 0.75 * v1->normal[2] + 0.25 * v2->normal[2];
01139
01140 VectorNormalize( vout->normal, vout->normal );
01141
01142 vout++;
01143
01144 vout->xyz[0] = 0.25 * v1->xyz[0] + 0.75 * v2->xyz[0];
01145 vout->xyz[1] = 0.25 * v1->xyz[1] + 0.75 * v2->xyz[1];
01146 vout->xyz[2] = 0.25 * v1->xyz[2] + 0.75 * v2->xyz[2];
01147
01148 vout->normal[0] = 0.25 * v1->normal[0] + 0.75 * v2->normal[0];
01149 vout->normal[1] = 0.25 * v1->normal[1] + 0.75 * v2->normal[1];
01150 vout->normal[2] = 0.25 * v1->normal[2] + 0.75 * v2->normal[2];
01151
01152 VectorNormalize( vout->normal, vout->normal );
01153
01154 }
01155 }
01156
01157 FreeMesh( in );
01158
01159 return out;
01160 }
01161
01162
01163
01164
01165
01166
01167 void ColorToBytes( const float *color, byte *colorBytes ) {
01168 float max;
01169 vec3_t sample;
01170
01171 VectorCopy( color, sample );
01172
01173
01174 max = sample[0];
01175 if ( sample[1] > max ) {
01176 max = sample[1];
01177 }
01178 if ( sample[2] > max ) {
01179 max = sample[2];
01180 }
01181 if ( max > 255 ) {
01182 VectorScale( sample, 255/max, sample );
01183 }
01184 colorBytes[ 0 ] = sample[0];
01185 colorBytes[ 1 ] = sample[1];
01186 colorBytes[ 2 ] = sample[2];
01187 }
01188
01189
01190
01191
01192
01193
01194
01195
01196 void TraceLtm( int num ) {
01197 dsurface_t *ds;
01198 int i, j, k;
01199 int x, y;
01200 int position, numPositions;
01201 vec3_t base, origin, normal;
01202 byte occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE];
01203 vec3_t color[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE];
01204 traceWork_t tw;
01205 vec3_t average;
01206 int count;
01207 mesh_t srcMesh, *mesh, *subdivided;
01208 shaderInfo_t *si;
01209 static float nudge[2][9] = {
01210 { 0, -1, 0, 1, -1, 1, -1, 0, 1 },
01211 { 0, -1, -1, -1, 0, 0, 1, 1, 1 }
01212 };
01213 int sampleWidth, sampleHeight, ssize;
01214 vec3_t lightmapOrigin, lightmapVecs[2];
01215 int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_WIDTH];
01216
01217 ds = &drawSurfaces[num];
01218 si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
01219
01220
01221 if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
01222 VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw );
01223 return;
01224 }
01225
01226 if ( ds->lightmapNum == -1 ) {
01227 return;
01228 }
01229
01230 if (!novertexlighting) {
01231
01232 VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw );
01233 }
01234
01235 if ( ds->lightmapNum < 0 ) {
01236 return;
01237 }
01238
01239 si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
01240 ssize = samplesize;
01241 if (si->lightmapSampleSize)
01242 ssize = si->lightmapSampleSize;
01243
01244 if (si->patchShadows)
01245 tw.patchshadows = qtrue;
01246 else
01247 tw.patchshadows = patchshadows;
01248
01249 if ( ds->surfaceType == MST_PATCH ) {
01250 srcMesh.width = ds->patchWidth;
01251 srcMesh.height = ds->patchHeight;
01252 srcMesh.verts = drawVerts + ds->firstVert;
01253 mesh = SubdivideMesh( srcMesh, 8, 999 );
01254 PutMeshOnCurve( *mesh );
01255 MakeMeshNormals( *mesh );
01256
01257 subdivided = RemoveLinearMeshColumnsRows( mesh );
01258 FreeMesh(mesh);
01259
01260 mesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_WIDTH, widthtable, heighttable);
01261 if ( mesh->width != ds->lightmapWidth || mesh->height != ds->lightmapHeight ) {
01262 Error( "Mesh lightmap miscount");
01263 }
01264
01265 if ( extra ) {
01266 mesh_t *mp;
01267
01268
01269 mp = mesh;
01270 mp = LinearSubdivideMesh( mp );
01271 mp = TransposeMesh( mp );
01272 mp = LinearSubdivideMesh( mp );
01273 mp = TransposeMesh( mp );
01274
01275 mesh = mp;
01276 }
01277 } else {
01278 VectorCopy( ds->lightmapVecs[2], normal );
01279
01280 if ( !extra ) {
01281 VectorCopy( ds->lightmapOrigin, lightmapOrigin );
01282 VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] );
01283 VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] );
01284 } else {
01285
01286 VectorCopy( ds->lightmapOrigin, lightmapOrigin );
01287 VectorScale( ds->lightmapVecs[0], 0.5, lightmapVecs[0] );
01288 VectorScale( ds->lightmapVecs[1], 0.5, lightmapVecs[1] );
01289 VectorMA( lightmapOrigin, -0.5, lightmapVecs[0], lightmapOrigin );
01290 VectorMA( lightmapOrigin, -0.5, lightmapVecs[1], lightmapOrigin );
01291 }
01292 }
01293
01294 if ( extra ) {
01295 sampleWidth = ds->lightmapWidth * 2;
01296 sampleHeight = ds->lightmapHeight * 2;
01297 } else {
01298 sampleWidth = ds->lightmapWidth;
01299 sampleHeight = ds->lightmapHeight;
01300 }
01301
01302 memset ( color, 0, sizeof( color ) );
01303
01304
01305 memset ( occluded, 0, sizeof( occluded ) );
01306 for ( i = 0 ; i < sampleWidth ; i++ ) {
01307 for ( j = 0 ; j < sampleHeight ; j++ ) {
01308
01309 if ( ds->patchWidth ) {
01310 numPositions = 9;
01311 VectorCopy( mesh->verts[j*mesh->width+i].normal, normal );
01312
01313
01314 VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base );
01315
01316 MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] );
01317 } else {
01318 numPositions = 9;
01319 for ( k = 0 ; k < 3 ; k++ ) {
01320 base[k] = lightmapOrigin[k] + normal[k]
01321 + i * lightmapVecs[0][k]
01322 + j * lightmapVecs[1][k];
01323 }
01324 }
01325 VectorAdd( base, surfaceOrigin[ num ], base );
01326
01327
01328
01329 for ( position = 0 ; position < numPositions ; position++ ) {
01330
01331 for ( k = 0 ; k < 3 ; k++ ) {
01332 origin[k] = base[k] +
01333 + ( nudge[0][position]/16 ) * lightmapVecs[0][k]
01334 + ( nudge[1][position]/16 ) * lightmapVecs[1][k];
01335 }
01336
01337 if ( notrace ) {
01338 break;
01339 }
01340 if ( !PointInSolid( origin ) ) {
01341 break;
01342 }
01343 }
01344
01345
01346 if ( position == numPositions ) {
01347 occluded[i][j] = qtrue;
01348 if ( numthreads == 1 ) {
01349 c_occluded++;
01350 }
01351 continue;
01352 }
01353
01354 if ( numthreads == 1 ) {
01355 c_visible++;
01356 }
01357 occluded[i][j] = qfalse;
01358 LightingAtSample( origin, normal, color[i][j], qtrue, qfalse, &tw );
01359 }
01360 }
01361
01362 if ( dump ) {
01363 PrintOccluded( occluded, sampleWidth, sampleHeight );
01364 }
01365
01366
01367 for ( i = 0 ; i < sampleWidth ; i++ ) {
01368 for ( j = 0 ; j < sampleHeight ; j++ ) {
01369 if ( !occluded[i][j] ) {
01370 continue;
01371 }
01372
01373 count = 0;
01374 VectorClear( average );
01375 for ( x = -1 ; x <= 1; x++ ) {
01376 for ( y = -1 ; y <= 1 ; y++ ) {
01377 if ( i + x < 0 || i + x >= sampleWidth ) {
01378 continue;
01379 }
01380 if ( j + y < 0 || j + y >= sampleHeight ) {
01381 continue;
01382 }
01383 if ( occluded[i+x][j+y] ) {
01384 continue;
01385 }
01386 count++;
01387 VectorAdd( color[i+x][j+y], average, average );
01388 }
01389 }
01390 if ( count ) {
01391 VectorScale( average, 1.0/count, color[i][j] );
01392 }
01393 }
01394 }
01395
01396
01397 if ( ds->lightmapWidth != sampleWidth ) {
01398 for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
01399 for ( j = 0 ; j < ds->lightmapHeight ; j++ ) {
01400 for ( k = 0 ; k < 3 ; k++ ) {
01401 float value, coverage;
01402
01403 value = color[i*2][j*2][k] + color[i*2][j*2+1][k] +
01404 color[i*2+1][j*2][k] + color[i*2+1][j*2+1][k];
01405 coverage = 4;
01406 if ( extraWide ) {
01407
01408 if ( i > 0 ) {
01409 value += color[i*2-1][j*2][k] + color[i*2-1][j*2+1][k];
01410 value += color[i*2-2][j*2][k] + color[i*2-2][j*2+1][k];
01411 coverage += 4;
01412 }
01413 if ( i < ds->lightmapWidth - 1 ) {
01414 value += color[i*2+2][j*2][k] + color[i*2+2][j*2+1][k];
01415 value += color[i*2+3][j*2][k] + color[i*2+3][j*2+1][k];
01416 coverage += 4;
01417 }
01418 if ( j > 0 ) {
01419 value += color[i*2][j*2-1][k] + color[i*2+1][j*2-1][k];
01420 value += color[i*2][j*2-2][k] + color[i*2+1][j*2-2][k];
01421 coverage += 4;
01422 }
01423 if ( j < ds->lightmapHeight - 1 ) {
01424 value += color[i*2][j*2+2][k] + color[i*2+1][j*2+2][k];
01425 value += color[i*2][j*2+3][k] + color[i*2+1][j*2+3][k];
01426 coverage += 2;
01427 }
01428 }
01429
01430 color[i][j][k] = value / coverage;
01431 }
01432 }
01433 }
01434 }
01435
01436
01437 if ( lightmapBorder ) {
01438 for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
01439 color[i][0][0] = 255;
01440 color[i][0][1] = 0;
01441 color[i][0][2] = 0;
01442
01443 color[i][ds->lightmapHeight-1][0] = 255;
01444 color[i][ds->lightmapHeight-1][1] = 0;
01445 color[i][ds->lightmapHeight-1][2] = 0;
01446 }
01447 for ( i = 0 ; i < ds->lightmapHeight ; i++ ) {
01448 color[0][i][0] = 255;
01449 color[0][i][1] = 0;
01450 color[0][i][2] = 0;
01451
01452 color[ds->lightmapWidth-1][i][0] = 255;
01453 color[ds->lightmapWidth-1][i][1] = 0;
01454 color[ds->lightmapWidth-1][i][2] = 0;
01455 }
01456 }
01457
01458
01459 for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
01460 for ( j = 0 ; j < ds->lightmapHeight ; j++ ) {
01461 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j)
01462 * LIGHTMAP_WIDTH + ds->lightmapX + i;
01463
01464 ColorToBytes( color[i][j], lightBytes + k*3 );
01465 }
01466 }
01467
01468 if (ds->surfaceType == MST_PATCH)
01469 {
01470 FreeMesh(mesh);
01471 }
01472 }
01473
01474
01475
01476
01477 vec3_t gridMins;
01478 vec3_t gridSize = { 64, 64, 128 };
01479 int gridBounds[3];
01480
01481
01482
01483
01484
01485
01486
01487 qboolean LightContributionToPoint( const light_t *light, const vec3_t origin,
01488 vec3_t color, traceWork_t *tw ) {
01489 trace_t trace;
01490 float add;
01491
01492 add = 0;
01493
01494 VectorClear( color );
01495
01496
01497 if ( exactPointToPolygon && light->type == emit_area ) {
01498 float factor;
01499 float d;
01500 vec3_t normal;
01501
01502
01503 d = DotProduct( origin, light->normal ) - light->dist;
01504 if ( !light->twosided ) {
01505 if ( d < 1 ) {
01506 return qfalse;
01507 }
01508 }
01509
01510
01511
01512 TraceLine( origin, light->origin, &trace, qfalse, tw );
01513 if ( trace.passSolid ) {
01514 return qfalse;
01515 }
01516
01517
01518 VectorSubtract( light->origin, origin, normal );
01519 if ( VectorNormalize( normal, normal ) == 0 ) {
01520 return qfalse;
01521 }
01522 factor = PointToPolygonFormFactor( origin, normal, light->w );
01523 if ( factor <= 0 ) {
01524 if ( light->twosided ) {
01525 factor = -factor;
01526 } else {
01527 return qfalse;
01528 }
01529 }
01530 VectorScale( light->emitColor, factor, color );
01531 return qtrue;
01532 }
01533
01534
01535 if ( light->type == emit_point || light->type == emit_spotlight ) {
01536 vec3_t dir;
01537 float dist;
01538
01539 VectorSubtract( light->origin, origin, dir );
01540 dist = VectorLength( dir );
01541
01542 if ( dist < 16 ) {
01543 dist = 16;
01544 }
01545 if ( light->linearLight ) {
01546 add = light->photons * linearScale - dist;
01547 if ( add < 0 ) {
01548 add = 0;
01549 }
01550 } else {
01551 add = light->photons / ( dist * dist );
01552 }
01553 } else {
01554 return qfalse;
01555 }
01556
01557 if ( add <= 1.0 ) {
01558 return qfalse;
01559 }
01560
01561
01562 TraceLine( origin, light->origin, &trace, qfalse, tw );
01563
01564
01565 if ( trace.passSolid ) {
01566 return qfalse;
01567 }
01568
01569
01570 color[0] = add * light->color[0];
01571 color[1] = add * light->color[1];
01572 color[2] = add * light->color[2];
01573
01574 return qtrue;
01575 }
01576
01577 typedef struct {
01578 vec3_t dir;
01579 vec3_t color;
01580 } contribution_t;
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590 #define MAX_CONTRIBUTIONS 1024
01591 void TraceGrid( int num ) {
01592 int x, y, z;
01593 vec3_t origin;
01594 light_t *light;
01595 vec3_t color;
01596 int mod;
01597 vec3_t directedColor;
01598 vec3_t summedDir;
01599 contribution_t contributions[MAX_CONTRIBUTIONS];
01600 int numCon;
01601 int i;
01602 traceWork_t tw;
01603 float addSize;
01604
01605 mod = num;
01606 z = mod / ( gridBounds[0] * gridBounds[1] );
01607 mod -= z * ( gridBounds[0] * gridBounds[1] );
01608
01609 y = mod / gridBounds[0];
01610 mod -= y * gridBounds[0];
01611
01612 x = mod;
01613
01614 origin[0] = gridMins[0] + x * gridSize[0];
01615 origin[1] = gridMins[1] + y * gridSize[1];
01616 origin[2] = gridMins[2] + z * gridSize[2];
01617
01618 if ( PointInSolid( origin ) ) {
01619 vec3_t baseOrigin;
01620 int step;
01621
01622 VectorCopy( origin, baseOrigin );
01623
01624
01625 for ( step = 9 ; step <= 18 ; step += 9 ) {
01626 for ( i = 0 ; i < 8 ; i++ ) {
01627 VectorCopy( baseOrigin, origin );
01628 if ( i & 1 ) {
01629 origin[0] += step;
01630 } else {
01631 origin[0] -= step;
01632 }
01633 if ( i & 2 ) {
01634 origin[1] += step;
01635 } else {
01636 origin[1] -= step;
01637 }
01638 if ( i & 4 ) {
01639 origin[2] += step;
01640 } else {
01641 origin[2] -= step;
01642 }
01643
01644 if ( !PointInSolid( origin ) ) {
01645 break;
01646 }
01647 }
01648 if ( i != 8 ) {
01649 break;
01650 }
01651 }
01652 if ( step > 18 ) {
01653
01654 for ( i = 0 ; i < 8 ; i++ ) {
01655 gridData[ num*8 + i ] = 0;
01656 }
01657 return;
01658 }
01659 }
01660
01661 VectorClear( summedDir );
01662
01663
01664
01665
01666
01667
01668 numCon = 0;
01669 for ( light = lights ; light ; light = light->next ) {
01670 vec3_t add;
01671 vec3_t dir;
01672 float addSize;
01673
01674 if ( !LightContributionToPoint( light, origin, add, &tw ) ) {
01675 continue;
01676 }
01677
01678 VectorSubtract( light->origin, origin, dir );
01679 VectorNormalize( dir, dir );
01680
01681 VectorCopy( add, contributions[numCon].color );
01682 VectorCopy( dir, contributions[numCon].dir );
01683 numCon++;
01684
01685 addSize = VectorLength( add );
01686 VectorMA( summedDir, addSize, dir, summedDir );
01687
01688 if ( numCon == MAX_CONTRIBUTIONS-1 ) {
01689 break;
01690 }
01691 }
01692
01693
01694
01695
01696 SunToPoint( origin, &tw, color );
01697 addSize = VectorLength( color );
01698 if ( addSize > 0 ) {
01699 VectorCopy( color, contributions[numCon].color );
01700 VectorCopy( sunDirection, contributions[numCon].dir );
01701 VectorMA( summedDir, addSize, sunDirection, summedDir );
01702 numCon++;
01703 }
01704
01705
01706
01707
01708 VectorNormalize( summedDir, summedDir );
01709 VectorCopy( ambientColor, color );
01710 VectorClear( directedColor );
01711
01712 for ( i = 0 ; i < numCon ; i++ ) {
01713 float d;
01714
01715 d = DotProduct( contributions[i].dir, summedDir );
01716 if ( d < 0 ) {
01717 d = 0;
01718 }
01719
01720 VectorMA( directedColor, d, contributions[i].color, directedColor );
01721
01722
01723 d = 0.25 * ( 1.0 - d );
01724 VectorMA( color, d, contributions[i].color, color );
01725 }
01726
01727
01728 VectorMA( color, 0.25, directedColor, color );
01729
01730
01731
01732
01733 ColorToBytes( color, gridData + num*8 );
01734 ColorToBytes( directedColor, gridData + num*8 + 3 );
01735
01736 VectorNormalize( summedDir, summedDir );
01737 NormalToLatLong( summedDir, gridData + num*8 + 6);
01738 }
01739
01740
01741
01742
01743
01744
01745
01746 void SetupGrid( void ) {
01747 int i;
01748 vec3_t maxs;
01749
01750 for ( i = 0 ; i < 3 ; i++ ) {
01751 gridMins[i] = gridSize[i] * ceil( dmodels[0].mins[i] / gridSize[i] );
01752 maxs[i] = gridSize[i] * floor( dmodels[0].maxs[i] / gridSize[i] );
01753 gridBounds[i] = (maxs[i] - gridMins[i])/gridSize[i] + 1;
01754 }
01755
01756 numGridPoints = gridBounds[0] * gridBounds[1] * gridBounds[2];
01757 if (numGridPoints * 8 >= MAX_MAP_LIGHTGRID)
01758 Error("MAX_MAP_LIGHTGRID");
01759 qprintf( "%5i gridPoints\n", numGridPoints );
01760 }
01761
01762
01763
01764
01765
01766
01767
01768
01769 void RemoveLightsInSolid(void)
01770 {
01771 light_t *light, *prev;
01772 int numsolid = 0;
01773
01774 prev = NULL;
01775 for ( light = lights ; light ; ) {
01776 if (PointInSolid(light->origin))
01777 {
01778 if (prev) prev->next = light->next;
01779 else lights = light->next;
01780 if (light->w)
01781 FreeWinding(light->w);
01782 free(light);
01783 numsolid++;
01784 if (prev)
01785 light = prev->next;
01786 else
01787 light = lights;
01788 }
01789 else
01790 {
01791 prev = light;
01792 light = light->next;
01793 }
01794 }
01795 _printf (" %7i lights in solid\n", numsolid);
01796 }
01797
01798
01799
01800
01801
01802
01803 void LightWorld (void) {
01804 float f;
01805
01806
01807 SetupGrid();
01808
01809
01810 GetVectorForKey( &entities[0], "_color", ambientColor );
01811 f = FloatForKey( &entities[0], "ambient" );
01812 VectorScale( ambientColor, f, ambientColor );
01813
01814
01815 qprintf ("--- CreateLights ---\n");
01816 CreateEntityLights ();
01817 qprintf ("%i point lights\n", numPointLights);
01818 qprintf ("%i area lights\n", numAreaLights);
01819
01820 if (!nogridlighting) {
01821 qprintf ("--- TraceGrid ---\n");
01822 RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid );
01823 qprintf( "%i x %i x %i = %i grid\n", gridBounds[0], gridBounds[1],
01824 gridBounds[2], numGridPoints);
01825 }
01826
01827 qprintf ("--- TraceLtm ---\n");
01828 RunThreadsOnIndividual( numDrawSurfaces, qtrue, TraceLtm );
01829 qprintf( "%5i visible samples\n", c_visible );
01830 qprintf( "%5i occluded samples\n", c_occluded );
01831 }
01832
01833
01834
01835
01836
01837
01838
01839
01840
01841
01842
01843
01844 #define PLANAR_PATCH_EPSILON 0.1
01845 void CreateFilters( void ) {
01846 int i;
01847 filter_t *f;
01848 dsurface_t *ds;
01849 shaderInfo_t *si;
01850 drawVert_t *v1, *v2, *v3;
01851 vec3_t d1, d2;
01852 int vertNum;
01853
01854 numFilters = 0;
01855
01856 return;
01857
01858 for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
01859 ds = &drawSurfaces[i];
01860 if ( !ds->patchWidth ) {
01861 continue;
01862 }
01863 si = ShaderInfoForShader( dshaders[ ds->shaderNum ].shader );
01864
01865
01866
01867
01868
01869
01870
01871 v1 = &drawVerts[ ds->firstVert ];
01872
01873 if ( ds->patchWidth != 3 || ds->patchHeight != 3 ) {
01874 _printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't a 3 by 3\n",
01875 v1->xyz[0], v1->xyz[1], v1->xyz[2] );
01876 continue;
01877 }
01878
01879 if ( numFilters == MAX_FILTERS ) {
01880 Error( "MAX_FILTERS" );
01881 }
01882 f = &filters[ numFilters ];
01883 numFilters++;
01884
01885 v2 = &drawVerts[ ds->firstVert + 2 ];
01886 v3 = &drawVerts[ ds->firstVert + 6 ];
01887
01888 VectorSubtract( v2->xyz, v1->xyz, d1 );
01889 VectorSubtract( v3->xyz, v1->xyz, d2 );
01890 VectorNormalize( d1, d1 );
01891 VectorNormalize( d2, d2 );
01892 CrossProduct( d1, d2, f->plane );
01893 f->plane[3] = DotProduct( v1->xyz, f->plane );
01894
01895
01896 for ( vertNum = 0 ; vertNum < ds->numVerts ; vertNum++ ) {
01897 float d;
01898
01899 d = DotProduct( drawVerts[ ds->firstVert + vertNum ].xyz, f->plane ) - f->plane[3];
01900 if ( fabs( d ) > PLANAR_PATCH_EPSILON ) {
01901 break;
01902 }
01903 }
01904 if ( vertNum != ds->numVerts ) {
01905 numFilters--;
01906 _printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't flat\n",
01907 v1->xyz[0], v1->xyz[1], v1->xyz[2] );
01908 continue;
01909 }
01910 }
01911
01912 f = &filters[0];
01913 numFilters = 1;
01914
01915 f->plane[0] = 1;
01916 f->plane[1] = 0;
01917 f->plane[2] = 0;
01918 f->plane[3] = 448;
01919
01920 f->origin[0] = 448;
01921 f->origin[1] = 192;
01922 f->origin[2] = 0;
01923
01924 f->vectors[0][0] = 0;
01925 f->vectors[0][1] = -1.0 / 128;
01926 f->vectors[0][2] = 0;
01927
01928 f->vectors[1][0] = 0;
01929 f->vectors[1][1] = 0;
01930 f->vectors[1][2] = 1.0 / 128;
01931
01932 f->si = ShaderInfoForShader( "textures/hell/blocks11ct" );
01933 }
01934
01935
01936
01937
01938
01939
01940 void VertexLightingThread(int num) {
01941 dsurface_t *ds;
01942 traceWork_t tw;
01943 shaderInfo_t *si;
01944
01945 ds = &drawSurfaces[num];
01946
01947
01948 if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
01949 return;
01950 }
01951
01952 if (novertexlighting)
01953 return;
01954
01955 if ( ds->lightmapNum == -1 ) {
01956 return;
01957 }
01958
01959 si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
01960
01961
01962 VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw );
01963 }
01964
01965
01966
01967
01968
01969
01970 void TriSoupLightingThread(int num) {
01971 dsurface_t *ds;
01972 traceWork_t tw;
01973 shaderInfo_t *si;
01974
01975 ds = &drawSurfaces[num];
01976 si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
01977
01978
01979 if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
01980 VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw );
01981 }
01982 }
01983
01984
01985
01986
01987
01988
01989 void GridAndVertexLighting(void) {
01990 SetupGrid();
01991
01992 FindSkyBrushes();
01993 CreateFilters();
01994 InitTrace();
01995 CreateEntityLights ();
01996 CreateSurfaceLights();
01997
01998 if (!nogridlighting) {
01999 _printf ("--- TraceGrid ---\n");
02000 RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid );
02001 }
02002
02003 if (!novertexlighting) {
02004 _printf ("--- Vertex Lighting ---\n");
02005 RunThreadsOnIndividual( numDrawSurfaces, qtrue, VertexLightingThread );
02006 }
02007
02008 _printf("--- Model Lighting ---\n");
02009 RunThreadsOnIndividual( numDrawSurfaces, qtrue, TriSoupLightingThread );
02010 }
02011
02012
02013
02014
02015
02016
02017
02018 int LightMain (int argc, char **argv) {
02019 int i;
02020 double start, end;
02021 const char *value;
02022
02023 _printf ("----- Lighting ----\n");
02024
02025 verbose = qfalse;
02026
02027 for (i=1 ; i<argc ; i++) {
02028 if (!strcmp(argv[i],"-tempname"))
02029 {
02030 i++;
02031 } else if (!strcmp(argv[i],"-v")) {
02032 verbose = qtrue;
02033 } else if (!strcmp(argv[i],"-threads")) {
02034 numthreads = atoi (argv[i+1]);
02035 i++;
02036 } else if (!strcmp(argv[i],"-area")) {
02037 areaScale *= atof(argv[i+1]);
02038 _printf ("area light scaling at %f\n", areaScale);
02039 i++;
02040 } else if (!strcmp(argv[i],"-point")) {
02041 pointScale *= atof(argv[i+1]);
02042 _printf ("point light scaling at %f\n", pointScale);
02043 i++;
02044 } else if (!strcmp(argv[i],"-notrace")) {
02045 notrace = qtrue;
02046 _printf ("No occlusion tracing\n");
02047 } else if (!strcmp(argv[i],"-patchshadows")) {
02048 patchshadows = qtrue;
02049 _printf ("Patch shadow casting enabled\n");
02050 } else if (!strcmp(argv[i],"-extra")) {
02051 extra = qtrue;
02052 _printf ("Extra detail tracing\n");
02053 } else if (!strcmp(argv[i],"-extrawide")) {
02054 extra = qtrue;
02055 extraWide = qtrue;
02056 _printf ("Extra wide detail tracing\n");
02057 } else if (!strcmp(argv[i], "-samplesize")) {
02058 samplesize = atoi(argv[i+1]);
02059 if (samplesize < 1) samplesize = 1;
02060 i++;
02061 _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize);
02062 } else if (!strcmp(argv[i], "-novertex")) {
02063 novertexlighting = qtrue;
02064 _printf("no vertex lighting = true\n");
02065 } else if (!strcmp(argv[i], "-nogrid")) {
02066 nogridlighting = qtrue;
02067 _printf("no grid lighting = true\n");
02068 } else if (!strcmp(argv[i],"-border")) {
02069 lightmapBorder = qtrue;
02070 _printf ("Adding debug border to lightmaps\n");
02071 } else if (!strcmp(argv[i],"-nosurf")) {
02072 noSurfaces = qtrue;
02073 _printf ("Not tracing against surfaces\n" );
02074 } else if (!strcmp(argv[i],"-dump")) {
02075 dump = qtrue;
02076 _printf ("Dumping occlusion maps\n");
02077 } else {
02078 break;
02079 }
02080 }
02081
02082 ThreadSetDefault ();
02083
02084 if (i != argc - 1) {
02085 _printf("usage: q3map -light [-<switch> [-<switch> ...]] <mapname>\n"
02086 "\n"
02087 "Switches:\n"
02088 " v = verbose output\n"
02089 " threads <X> = set number of threads to X\n"
02090 " area <V> = set the area light scale to V\n"
02091 " point <W> = set the point light scale to W\n"
02092 " notrace = don't cast any shadows\n"
02093 " extra = enable super sampling for anti-aliasing\n"
02094 " extrawide = same as extra but smoothen more\n"
02095 " nogrid = don't calculate light grid for dynamic model lighting\n"
02096 " novertex = don't calculate vertex lighting\n"
02097 " samplesize <N> = set the lightmap pixel size to NxN units\n");
02098 exit(0);
02099 }
02100
02101 start = I_FloatTime ();
02102
02103 SetQdirFromPath (argv[i]);
02104
02105 #ifdef _WIN32
02106 InitPakFile(gamedir, NULL);
02107 #endif
02108
02109 strcpy (source, ExpandArg(argv[i]));
02110 StripExtension (source);
02111 DefaultExtension (source, ".bsp");
02112
02113 LoadShaderInfo();
02114
02115 _printf ("reading %s\n", source);
02116
02117 LoadBSPFile (source);
02118
02119 FindSkyBrushes();
02120
02121 ParseEntities();
02122
02123 value = ValueForKey( &entities[0], "gridsize" );
02124 if (strlen(value)) {
02125 sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] );
02126 _printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]);
02127 }
02128
02129 CreateFilters();
02130
02131 InitTrace();
02132
02133 SetEntityOrigins();
02134
02135 CountLightmaps();
02136
02137 CreateSurfaceLights();
02138
02139 LightWorld();
02140
02141 _printf ("writing %s\n", source);
02142 WriteBSPFile (source);
02143
02144 end = I_FloatTime ();
02145 _printf ("%5.0f seconds elapsed\n", end-start);
02146
02147 return 0;
02148 }
02149