lightv.c (148675B)
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 23 24 #include "cmdlib.h" 25 #include "mathlib.h" 26 #include "bspfile.h" 27 #include "imagelib.h" 28 #include "threads.h" 29 #include "mutex.h" 30 #include "scriplib.h" 31 32 #include "shaders.h" 33 #include "mesh.h" 34 35 #ifdef _WIN32 36 //Improve floating-point consistency. 37 #pragma optimize( "p", on ) 38 #endif 39 40 #ifdef _WIN32 41 #include "../libs/pakstuff.h" 42 #endif 43 44 #define MAX_CLUSTERS 16384 45 #define MAX_PORTALS 32768 46 #define MAX_FACETS 65536 47 #define MAX_LIGHTS 16384 48 49 #define LIGHTMAP_SIZE 128 50 51 #define LIGHTMAP_PIXELSHIFT 0.5 52 53 //#define LIGHTMAP_PATCHSHIFT 54 55 #define PORTALFILE "PRT1" 56 57 #define ON_EPSILON 0.1 58 59 #define VectorSet(v, x, y, z) v[0] = x;v[1] = y;v[2] = z; 60 61 typedef struct 62 { 63 vec3_t normal; 64 float dist; 65 } plane_t; 66 67 #define MAX_POINTS_ON_WINDING 64 68 //NOTE: whenever this is overflowed parts of lightmaps might end up not being lit 69 #define MAX_POINTS_ON_FIXED_WINDING 48 70 71 typedef struct 72 { 73 int numpoints; 74 vec3_t points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized 75 } winding_t; 76 77 typedef struct 78 { 79 plane_t plane; // normal pointing into neighbor 80 int leaf; // neighbor 81 winding_t *winding; 82 vec3_t origin; // for fast clip testing 83 float radius; 84 } lportal_t; 85 86 #define MAX_PORTALS_ON_LEAF 128 87 typedef struct lleaf_s 88 { 89 int numportals; 90 lportal_t *portals[MAX_PORTALS_ON_LEAF]; 91 // 92 int numSurfaces; 93 int firstSurface; 94 } lleaf_t; 95 96 typedef struct lFacet_s 97 { 98 int num; 99 plane_t plane; 100 vec3_t points[4]; // 101 int numpoints; 102 float lightmapCoords[4][2]; 103 plane_t boundaries[4]; // negative is outside the bounds 104 float textureMatrix[2][4]; // texture coordinates for translucency 105 float lightmapMatrix[2][4]; // lightmap texture coordinates 106 vec3_t mins; 107 int x, y, width, height; 108 } lFacet_t; 109 110 typedef struct lsurfaceTest_s 111 { 112 vec3_t mins, maxs; 113 vec3_t origin; 114 float radius; 115 qboolean patch; // true if this is a patch 116 qboolean trisoup; // true if this is a triangle soup 117 int numFacets; 118 lFacet_t *facets; 119 mesh_t *detailMesh; // detailed mesh with points for each lmp 120 shaderInfo_t *shader; // for translucency 121 mutex_t *mutex; 122 int numvolumes; // number of volumes casted at this surface 123 // 124 int always_tracelight; 125 int always_vlight; 126 } lsurfaceTest_t; 127 128 //volume types 129 #define VOLUME_NORMAL 0 130 #define VOLUME_DIRECTED 1 131 132 #define MAX_TRANSLUCENTFACETS 32 133 134 typedef struct lightvolume_s 135 { 136 int num; 137 int cluster; //cluster this light volume started in 138 plane_t endplane; //end plane 139 plane_t farplane; //original end plane 140 vec3_t points[MAX_POINTS_ON_WINDING]; //end winding points 141 plane_t planes[MAX_POINTS_ON_WINDING]; //volume bounding planes 142 int numplanes; //number of volume bounding planes 143 int type; //light volume type 144 //list with translucent surfaces the volume went through 145 int transFacets[MAX_TRANSLUCENTFACETS]; 146 int transSurfaces[MAX_TRANSLUCENTFACETS]; 147 int numtransFacets; 148 //clusters already tested 149 byte clusterTested[MAX_CLUSTERS/8]; 150 //facets already tested 151 byte facetTested[MAX_FACETS/8]; 152 int facetNum; //number of the facet blocking the light in this volume 153 int surfaceNum; //number of the surface blocking the light in this volume 154 } lightvolume_t; 155 156 //light types 157 #define LIGHT_POINTRADIAL 1 158 #define LIGHT_POINTSPOT 2 159 #define LIGHT_POINTFAKESURFACE 3 160 #define LIGHT_SURFACEDIRECTED 4 161 #define LIGHT_SURFACERADIAL 5 162 #define LIGHT_SURFACESPOT 6 163 164 //light distance attenuation types 165 #define LDAT_QUADRATIC 0 166 #define LDAT_LINEAR 1 167 #define LDAT_NOSCALE 2 168 169 //light angle attenuation types 170 #define LAAT_NORMAL 0 171 #define LAAT_QUADRATIC 1 172 #define LAAT_DOUBLEQUADRATIC 2 173 174 typedef struct vlight_s 175 { 176 vec3_t origin; //light origin, for point lights 177 winding_t w; //light winding, for area lights 178 vec4_t plane; //light winding plane 179 vec3_t normal; //direction of the light 180 int type; //light type 181 vec3_t color; //light color 182 qboolean twosided; //radiates light at both sides of the winding 183 int style; //light style (not used) 184 int atten_disttype; //light distance attenuation type 185 int atten_angletype; //light angle attenuation type 186 float atten_distscale; //distance attenuation scale 187 float atten_anglescale; //angle attenuation scale 188 float radiusByDist; //radius by distance for spot lights 189 float photons; //emitted photons 190 float intensity; //intensity 191 vec3_t emitColor; //full out-of-gamut value (not used) 192 struct shaderInfo_s *si; //shader info 193 int insolid; //set when light is in solid 194 } vlight_t; 195 196 float lightLinearScale = 1.0 / 8000; 197 float lightPointScale = 7500; 198 float lightAreaScale = 0.25; 199 float lightFormFactorValueScale = 3; 200 int lightDefaultSubdivide = 999; // vary by surface size? 201 vec3_t lightAmbientColor; 202 203 int portalclusters, numportals, numfaces; 204 lleaf_t *leafs; 205 lportal_t *portals; 206 int numvlights = 0; 207 vlight_t *vlights[MAX_LIGHTS]; 208 int nostitching = 0; 209 int noalphashading = 0; 210 int nocolorshading = 0; 211 int nobackfaceculling = 0; 212 int defaulttracelight = 0; 213 int radiosity = 0; 214 int radiosity_scale; 215 216 int clustersurfaces[MAX_MAP_LEAFFACES]; 217 int numclustersurfaces = 0; 218 lsurfaceTest_t *lsurfaceTest[MAX_MAP_DRAW_SURFS]; 219 int numfacets; 220 float lightmappixelarea[MAX_MAP_LIGHTING/3]; 221 float *lightFloats;//[MAX_MAP_LIGHTING]; 222 223 // from polylib.c 224 winding_t *AllocWinding (int points); 225 void FreeWinding (winding_t *w); 226 void WindingCenter (winding_t *w, vec3_t center); 227 void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs); 228 vec_t WindingArea (winding_t *w); 229 winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist); 230 void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, 231 vec_t epsilon, winding_t **front, winding_t **back); 232 winding_t *ReverseWinding (winding_t *w); 233 234 // from light.c 235 extern char source[1024]; 236 extern vec3_t surfaceOrigin[ MAX_MAP_DRAW_SURFS ]; 237 extern int entitySurface[ MAX_MAP_DRAW_SURFS ]; 238 extern int samplesize; 239 extern int novertexlighting; 240 extern int nogridlighting; 241 extern qboolean patchshadows; 242 extern vec3_t gridSize; 243 244 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w ); 245 void ColorToBytes( const float *color, byte *colorBytes ); 246 void CountLightmaps( void ); 247 void GridAndVertexLighting( void ); 248 void SetEntityOrigins( void ); 249 250 251 //#define DEBUGNET 252 253 #ifdef DEBUGNET 254 255 #include "l_net.h" 256 257 socket_t *debug_socket; 258 259 /* 260 ===================== 261 DebugNet_Setup 262 ===================== 263 */ 264 void DebugNet_Setup(void) 265 { 266 address_t address; 267 int i; 268 269 Net_Setup(); 270 Net_StringToAddress("127.0.0.1:28000", &address); 271 for (i = 0; i < 10; i++) 272 { 273 debug_socket = Net_Connect(&address, 28005 + i); 274 if (debug_socket) 275 break; 276 } 277 } 278 279 /* 280 ===================== 281 DebugNet_Shutdown 282 ===================== 283 */ 284 void DebugNet_Shutdown(void) 285 { 286 netmessage_t msg; 287 288 if (debug_socket) 289 { 290 NMSG_Clear(&msg); 291 NMSG_WriteByte(&msg, 1); 292 Net_Send(debug_socket, &msg); 293 Net_Disconnect(debug_socket); 294 } 295 debug_socket = NULL; 296 Net_Shutdown(); 297 } 298 299 /* 300 ===================== 301 DebugNet_RemoveAllPolys 302 ===================== 303 */ 304 void DebugNet_RemoveAllPolys(void) 305 { 306 netmessage_t msg; 307 308 if (!debug_socket) 309 return; 310 NMSG_Clear(&msg); 311 NMSG_WriteByte(&msg, 2); //remove all debug polys 312 Net_Send(debug_socket, &msg); 313 } 314 315 /* 316 ==================== 317 DebugNet_DrawWinding 318 ===================== 319 */ 320 void DebugNet_DrawWinding(winding_t *w, int color) 321 { 322 netmessage_t msg; 323 int i; 324 325 if (!debug_socket) 326 return; 327 NMSG_Clear(&msg); 328 NMSG_WriteByte(&msg, 0); //draw a winding 329 NMSG_WriteByte(&msg, w->numpoints); //number of points 330 NMSG_WriteLong(&msg, color); //color 331 for (i = 0; i < w->numpoints; i++) 332 { 333 NMSG_WriteFloat(&msg, w->points[i][0]); 334 NMSG_WriteFloat(&msg, w->points[i][1]); 335 NMSG_WriteFloat(&msg, w->points[i][2]); 336 } 337 Net_Send(debug_socket, &msg); 338 } 339 340 /* 341 ===================== 342 DebugNet_DrawLine 343 ===================== 344 */ 345 void DebugNet_DrawLine(vec3_t p1, vec3_t p2, int color) 346 { 347 netmessage_t msg; 348 349 if (!debug_socket) 350 return; 351 NMSG_Clear(&msg); 352 NMSG_WriteByte(&msg, 1); //draw a line 353 NMSG_WriteLong(&msg, color); //color 354 NMSG_WriteFloat(&msg, p1[0]); 355 NMSG_WriteFloat(&msg, p1[1]); 356 NMSG_WriteFloat(&msg, p1[2]); 357 NMSG_WriteFloat(&msg, p2[0]); 358 NMSG_WriteFloat(&msg, p2[1]); 359 NMSG_WriteFloat(&msg, p2[2]); 360 Net_Send(debug_socket, &msg); 361 } 362 363 /* 364 ===================== 365 DebugNet_DrawMesh 366 ===================== 367 */ 368 void DebugNet_DrawMesh(mesh_t *mesh) 369 { 370 int i, j; 371 float dot; 372 drawVert_t *v1, *v2, *v3, *v4; 373 winding_t winding; 374 plane_t plane; 375 vec3_t d1, d2; 376 377 for ( i = 0 ; i < mesh->width - 1 ; i++ ) { 378 for ( j = 0 ; j < mesh->height - 1 ; j++ ) { 379 380 v1 = mesh->verts + j * mesh->width + i; 381 v2 = v1 + 1; 382 v3 = v1 + mesh->width + 1; 383 v4 = v1 + mesh->width; 384 385 VectorSubtract( v4->xyz, v1->xyz, d1 ); 386 VectorSubtract( v3->xyz, v1->xyz, d2 ); 387 CrossProduct( d2, d1, plane.normal ); 388 if ( VectorNormalize( plane.normal, plane.normal ) != 0 ) 389 { 390 plane.dist = DotProduct( v1->xyz, plane.normal ); 391 dot = DotProduct(plane.normal, v2->xyz) - plane.dist; 392 if (fabs(dot) < 0.1) 393 { 394 VectorCopy(v1->xyz, winding.points[0]); 395 VectorCopy(v4->xyz, winding.points[1]); 396 VectorCopy(v3->xyz, winding.points[2]); 397 VectorCopy(v2->xyz, winding.points[3]); 398 winding.numpoints = 4; 399 DebugNet_DrawWinding(&winding, 2); 400 continue; 401 } 402 } 403 404 winding.numpoints = 3; 405 VectorCopy(v1->xyz, winding.points[0]); 406 VectorCopy(v4->xyz, winding.points[1]); 407 VectorCopy(v3->xyz, winding.points[2]); 408 DebugNet_DrawWinding(&winding, 2); 409 410 VectorCopy(v1->xyz, winding.points[0]); 411 VectorCopy(v3->xyz, winding.points[1]); 412 VectorCopy(v2->xyz, winding.points[2]); 413 DebugNet_DrawWinding(&winding, 2); 414 } 415 } 416 } 417 418 /* 419 ===================== 420 VL_DrawLightVolume 421 ===================== 422 */ 423 int VL_ChopWinding (winding_t *in, plane_t *split, float epsilon); 424 425 void VL_DrawLightVolume(vlight_t *light, lightvolume_t *volume) 426 { 427 winding_t w; 428 int i; 429 vec3_t p2, invlight; 430 431 memcpy(w.points, volume->points, volume->numplanes * sizeof(vec3_t)); 432 w.numpoints = volume->numplanes; 433 DebugNet_DrawWinding(&w, 2); 434 435 if (volume->type == VOLUME_DIRECTED) 436 { 437 VectorCopy(light->normal, invlight); 438 VectorInverse(invlight); 439 for (i = 0; i < volume->numplanes; i++) 440 { 441 VectorCopy(volume->points[i], w.points[0]); 442 VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[1]); 443 VectorMA(w.points[1], MAX_WORLD_COORD, invlight, w.points[2]); 444 VectorMA(w.points[0], MAX_WORLD_COORD, invlight, w.points[3]); 445 w.numpoints = 4; 446 DebugNet_DrawWinding(&w, 2); 447 VectorMA(volume->points[i], 8, volume->planes[i].normal, p2); 448 DebugNet_DrawLine(volume->points[i], p2, 3); 449 } 450 } 451 else 452 { 453 // 454 VectorCopy(light->origin, w.points[0]); 455 w.numpoints = 3; 456 for (i = 0; i < volume->numplanes; i++) 457 { 458 VectorCopy(volume->points[i], w.points[1]); 459 VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[2]); 460 VL_ChopWinding(&w, &volume->endplane, 0); 461 DebugNet_DrawWinding(&w, 2); 462 VectorMA(volume->points[i], 8, volume->planes[i].normal, p2); 463 DebugNet_DrawLine(volume->points[i], p2, 3); 464 } 465 } 466 } 467 468 /* 469 ============= 470 VL_DrawLightmapPixel 471 ============= 472 */ 473 void VL_DrawLightmapPixel(int surfaceNum, int x, int y, int color) 474 { 475 winding_t w; 476 dsurface_t *ds; 477 mesh_t *mesh; 478 479 ds = &drawSurfaces[surfaceNum]; 480 481 if (ds->surfaceType == MST_PATCH) 482 { 483 mesh = lsurfaceTest[surfaceNum]->detailMesh; 484 VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]); 485 VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]); 486 VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]); 487 VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]); 488 w.numpoints = 4; 489 } 490 else 491 { 492 VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]); 493 VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]); 494 VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]); 495 VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]); 496 VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]); 497 VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]); 498 VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]); 499 VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]); 500 w.numpoints = 4; 501 } 502 DebugNet_DrawWinding(&w, color); 503 } 504 505 /* 506 ============ 507 VL_DrawPortals 508 ============ 509 */ 510 void VL_DrawPortals(void) 511 { 512 int j; 513 lportal_t *p; 514 515 for (j = 0; j < numportals * 2; j++) 516 { 517 p = portals + j; 518 DebugNet_DrawWinding(p->winding, 1); 519 } 520 } 521 522 /* 523 ============ 524 VL_DrawLeaf 525 ============ 526 */ 527 void VL_DrawLeaf(int cluster) 528 { 529 int i; 530 lleaf_t *leaf; 531 lportal_t *p; 532 533 leaf = &leafs[cluster]; 534 for (i = 0; i < leaf->numportals; i++) 535 { 536 p = leaf->portals[i]; 537 DebugNet_DrawWinding(p->winding, 1); 538 } 539 } 540 541 #endif //DEBUGNET 542 543 /* 544 ============= 545 VL_SplitWinding 546 ============= 547 */ 548 int VL_SplitWinding (winding_t *in, winding_t *back, plane_t *split, float epsilon) 549 { 550 vec_t dists[128]; 551 int sides[128]; 552 int counts[3]; 553 vec_t dot; 554 int i, j; 555 vec_t *p1, *p2; 556 vec3_t mid; 557 winding_t out; 558 winding_t *neww; 559 560 counts[0] = counts[1] = counts[2] = 0; 561 562 // determine sides for each point 563 for (i=0 ; i<in->numpoints ; i++) 564 { 565 dot = DotProduct (in->points[i], split->normal); 566 dot -= split->dist; 567 dists[i] = dot; 568 if (dot > epsilon) 569 sides[i] = SIDE_FRONT; 570 else if (dot < -epsilon) 571 sides[i] = SIDE_BACK; 572 else 573 { 574 sides[i] = SIDE_ON; 575 } 576 counts[sides[i]]++; 577 } 578 579 if (!counts[SIDE_BACK]) 580 { 581 if (!counts[SIDE_FRONT]) 582 return SIDE_ON; 583 else 584 return SIDE_FRONT; 585 } 586 587 if (!counts[SIDE_FRONT]) 588 { 589 return SIDE_BACK; 590 } 591 592 sides[i] = sides[0]; 593 dists[i] = dists[0]; 594 595 neww = &out; 596 597 neww->numpoints = 0; 598 back->numpoints = 0; 599 600 for (i=0 ; i<in->numpoints ; i++) 601 { 602 p1 = in->points[i]; 603 604 if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING) 605 { 606 _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n"); 607 return SIDE_FRONT; // can't chop -- fall back to original 608 } 609 if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING) 610 { 611 _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n"); 612 return SIDE_FRONT; 613 } 614 615 if (sides[i] == SIDE_ON) 616 { 617 VectorCopy (p1, neww->points[neww->numpoints]); 618 neww->numpoints++; 619 VectorCopy (p1, back->points[back->numpoints]); 620 back->numpoints++; 621 continue; 622 } 623 624 if (sides[i] == SIDE_FRONT) 625 { 626 VectorCopy (p1, neww->points[neww->numpoints]); 627 neww->numpoints++; 628 } 629 if (sides[i] == SIDE_BACK) 630 { 631 VectorCopy (p1, back->points[back->numpoints]); 632 back->numpoints++; 633 } 634 635 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) 636 continue; 637 638 if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING) 639 { 640 _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n"); 641 return SIDE_FRONT; // can't chop -- fall back to original 642 } 643 644 if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING) 645 { 646 _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n"); 647 return SIDE_FRONT; // can't chop -- fall back to original 648 } 649 650 // generate a split point 651 p2 = in->points[(i+1)%in->numpoints]; 652 653 dot = dists[i] / (dists[i]-dists[i+1]); 654 for (j=0 ; j<3 ; j++) 655 { // avoid round off error when possible 656 if (split->normal[j] == 1) 657 mid[j] = split->dist; 658 else if (split->normal[j] == -1) 659 mid[j] = -split->dist; 660 else 661 mid[j] = p1[j] + dot*(p2[j]-p1[j]); 662 } 663 664 VectorCopy (mid, neww->points[neww->numpoints]); 665 neww->numpoints++; 666 VectorCopy (mid, back->points[back->numpoints]); 667 back->numpoints++; 668 } 669 memcpy(in, &out, sizeof(winding_t)); 670 671 return SIDE_CROSS; 672 } 673 674 /* 675 ===================== 676 VL_LinkSurfaceIntoCluster 677 ===================== 678 */ 679 void VL_LinkSurfaceIntoCluster(int cluster, int surfaceNum) 680 { 681 lleaf_t *leaf; 682 int i; 683 684 leaf = &leafs[cluster]; 685 686 for (i = 0; i < leaf->numSurfaces; i++) 687 { 688 if (clustersurfaces[leaf->firstSurface + i] == surfaceNum) 689 return; 690 } 691 for (i = numclustersurfaces; i > leaf->firstSurface + leaf->numSurfaces; i--) 692 clustersurfaces[i] = clustersurfaces[i-1]; 693 for (i = 0; i < portalclusters; i++) 694 { 695 if (i == cluster) 696 continue; 697 if (leafs[i].firstSurface >= leaf->firstSurface + leaf->numSurfaces) 698 leafs[i].firstSurface++; 699 } 700 clustersurfaces[leaf->firstSurface + leaf->numSurfaces] = surfaceNum; 701 leaf->numSurfaces++; 702 numclustersurfaces++; 703 if (numclustersurfaces >= MAX_MAP_LEAFFACES) 704 Error("MAX_MAP_LEAFFACES"); 705 } 706 707 /* 708 ===================== 709 VL_R_LinkSurface 710 ===================== 711 */ 712 void VL_R_LinkSurface(int nodenum, int surfaceNum, winding_t *w) 713 { 714 int leafnum, cluster, res; 715 dnode_t *node; 716 dplane_t *plane; 717 winding_t back; 718 plane_t split; 719 720 while(nodenum >= 0) 721 { 722 node = &dnodes[nodenum]; 723 plane = &dplanes[node->planeNum]; 724 725 VectorCopy(plane->normal, split.normal); 726 split.dist = plane->dist; 727 res = VL_SplitWinding (w, &back, &split, 0.1); 728 729 if (res == SIDE_FRONT) 730 { 731 nodenum = node->children[0]; 732 } 733 else if (res == SIDE_BACK) 734 { 735 nodenum = node->children[1]; 736 } 737 else if (res == SIDE_ON) 738 { 739 memcpy(&back, w, sizeof(winding_t)); 740 VL_R_LinkSurface(node->children[1], surfaceNum, &back); 741 nodenum = node->children[0]; 742 } 743 else 744 { 745 VL_R_LinkSurface(node->children[1], surfaceNum, &back); 746 nodenum = node->children[0]; 747 } 748 } 749 leafnum = -nodenum - 1; 750 cluster = dleafs[leafnum].cluster; 751 if (cluster != -1) 752 { 753 VL_LinkSurfaceIntoCluster(cluster, surfaceNum); 754 } 755 } 756 757 /* 758 ===================== 759 VL_LinkSurfaces 760 761 maybe link each facet seperately instead of the test surfaces? 762 ===================== 763 */ 764 void VL_LinkSurfaces(void) 765 { 766 int i, j; 767 lsurfaceTest_t *test; 768 lFacet_t *facet; 769 winding_t winding; 770 771 for ( i = 0 ; i < numDrawSurfaces ; i++ ) 772 { 773 test = lsurfaceTest[ i ]; 774 if (!test) 775 continue; 776 for (j = 0; j < test->numFacets; j++) 777 { 778 facet = &test->facets[j]; 779 memcpy(winding.points, facet->points, facet->numpoints * sizeof(vec3_t)); 780 winding.numpoints = facet->numpoints; 781 VL_R_LinkSurface(0, i, &winding); 782 } 783 } 784 } 785 786 /* 787 ===================== 788 VL_TextureMatrixFromPoints 789 ===================== 790 */ 791 void VL_TextureMatrixFromPoints( lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) { 792 int i, j; 793 float t; 794 float m[3][4]; 795 float s; 796 797 // This is an incredibly stupid way of solving a three variable equation 798 for ( i = 0 ; i < 2 ; i++ ) { 799 800 m[0][0] = a->xyz[0]; 801 m[0][1] = a->xyz[1]; 802 m[0][2] = a->xyz[2]; 803 m[0][3] = a->st[i]; 804 805 m[1][0] = b->xyz[0]; 806 m[1][1] = b->xyz[1]; 807 m[1][2] = b->xyz[2]; 808 m[1][3] = b->st[i]; 809 810 m[2][0] = c->xyz[0]; 811 m[2][1] = c->xyz[1]; 812 m[2][2] = c->xyz[2]; 813 m[2][3] = c->st[i]; 814 815 if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) > fabs(m[2][0]) ) { 816 for ( j = 0 ; j < 4 ; j ++ ) { 817 t = m[0][j]; 818 m[0][j] = m[1][j]; 819 m[1][j] = t; 820 } 821 } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) > fabs(m[1][0]) ) { 822 for ( j = 0 ; j < 4 ; j ++ ) { 823 t = m[0][j]; 824 m[0][j] = m[2][j]; 825 m[2][j] = t; 826 } 827 } 828 829 s = 1.0 / m[0][0]; 830 m[0][0] *= s; 831 m[0][1] *= s; 832 m[0][2] *= s; 833 m[0][3] *= s; 834 835 s = m[1][0]; 836 m[1][0] -= m[0][0] * s; 837 m[1][1] -= m[0][1] * s; 838 m[1][2] -= m[0][2] * s; 839 m[1][3] -= m[0][3] * s; 840 841 s = m[2][0]; 842 m[2][0] -= m[0][0] * s; 843 m[2][1] -= m[0][1] * s; 844 m[2][2] -= m[0][2] * s; 845 m[2][3] -= m[0][3] * s; 846 847 if ( fabs(m[2][1]) > fabs(m[1][1]) ) { 848 for ( j = 0 ; j < 4 ; j ++ ) { 849 t = m[1][j]; 850 m[1][j] = m[2][j]; 851 m[2][j] = t; 852 } 853 } 854 855 s = 1.0 / m[1][1]; 856 m[1][0] *= s; 857 m[1][1] *= s; 858 m[1][2] *= s; 859 m[1][3] *= s; 860 861 s = m[2][1];// / m[1][1]; 862 m[2][0] -= m[1][0] * s; 863 m[2][1] -= m[1][1] * s; 864 m[2][2] -= m[1][2] * s; 865 m[2][3] -= m[1][3] * s; 866 867 s = 1.0 / m[2][2]; 868 m[2][0] *= s; 869 m[2][1] *= s; 870 m[2][2] *= s; 871 m[2][3] *= s; 872 873 f->textureMatrix[i][2] = m[2][3]; 874 f->textureMatrix[i][1] = m[1][3] - f->textureMatrix[i][2] * m[1][2]; 875 f->textureMatrix[i][0] = m[0][3] - f->textureMatrix[i][2] * m[0][2] - f->textureMatrix[i][1] * m[0][1]; 876 877 f->textureMatrix[i][3] = 0; 878 /* 879 s = fabs( DotProduct( a->xyz, f->textureMatrix[i] ) - a->st[i] ); 880 if ( s > 0.01 ) { 881 Error( "Bad textureMatrix" ); 882 } 883 s = fabs( DotProduct( b->xyz, f->textureMatrix[i] ) - b->st[i] ); 884 if ( s > 0.01 ) { 885 Error( "Bad textureMatrix" ); 886 } 887 s = fabs( DotProduct( c->xyz, f->textureMatrix[i] ) - c->st[i] ); 888 if ( s > 0.01 ) { 889 Error( "Bad textureMatrix" ); 890 } 891 */ 892 } 893 } 894 895 /* 896 ===================== 897 VL_LightmapMatrixFromPoints 898 ===================== 899 */ 900 void VL_LightmapMatrixFromPoints( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) { 901 int i, j; 902 float t; 903 float m[3][4], al, bl, cl; 904 float s; 905 int h, w, ssize; 906 vec3_t mins, maxs, delta, size, planeNormal; 907 drawVert_t *verts; 908 static int message; 909 910 // vertex-lit triangle model 911 if ( dsurf->surfaceType == MST_TRIANGLE_SOUP ) { 912 return; 913 } 914 915 if ( dsurf->lightmapNum < 0 ) { 916 return; // doesn't need lighting 917 } 918 919 VectorClear(f->mins); 920 if (dsurf->surfaceType != MST_PATCH) 921 { 922 ssize = samplesize; 923 if (si->lightmapSampleSize) 924 ssize = si->lightmapSampleSize; 925 ClearBounds( mins, maxs ); 926 verts = &drawVerts[dsurf->firstVert]; 927 for ( i = 0 ; i < dsurf->numVerts ; i++ ) { 928 AddPointToBounds( verts[i].xyz, mins, maxs ); 929 } 930 // round to the lightmap resolution 931 for ( i = 0 ; i < 3 ; i++ ) { 932 mins[i] = ssize * floor( mins[i] / ssize ); 933 maxs[i] = ssize * ceil( maxs[i] / ssize ); 934 f->mins[i] = mins[i]; 935 size[i] = (maxs[i] - mins[i]) / ssize + 1; 936 } 937 // the two largest axis will be the lightmap size 938 VectorClear(f->lightmapMatrix[0]); 939 f->lightmapMatrix[0][3] = 0; 940 VectorClear(f->lightmapMatrix[1]); 941 f->lightmapMatrix[1][3] = 0; 942 943 planeNormal[0] = fabs( dsurf->lightmapVecs[2][0] ); 944 planeNormal[1] = fabs( dsurf->lightmapVecs[2][1] ); 945 planeNormal[2] = fabs( dsurf->lightmapVecs[2][2] ); 946 947 if ( planeNormal[0] >= planeNormal[1] && planeNormal[0] >= planeNormal[2] ) { 948 w = size[1]; 949 h = size[2]; 950 f->lightmapMatrix[0][1] = 1.0 / ssize; 951 f->lightmapMatrix[1][2] = 1.0 / ssize; 952 } else if ( planeNormal[1] >= planeNormal[0] && planeNormal[1] >= planeNormal[2] ) { 953 w = size[0]; 954 h = size[2]; 955 f->lightmapMatrix[0][0] = 1.0 / ssize; 956 f->lightmapMatrix[1][2] = 1.0 / ssize; 957 } else { 958 w = size[0]; 959 h = size[1]; 960 f->lightmapMatrix[0][0] = 1.0 / ssize; 961 f->lightmapMatrix[1][1] = 1.0 / ssize; 962 } 963 if ( w > LIGHTMAP_WIDTH ) { 964 VectorScale ( f->lightmapMatrix[0], (float)LIGHTMAP_SIZE/w, f->lightmapMatrix[0] ); 965 } 966 967 if ( h > LIGHTMAP_HEIGHT ) { 968 VectorScale ( f->lightmapMatrix[1], (float)LIGHTMAP_SIZE/h, f->lightmapMatrix[1] ); 969 } 970 VectorSubtract(a->xyz, f->mins, delta); 971 s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE; 972 if ( fabs(s - a->lightmap[0]) > 0.01 ) { 973 _printf( "Bad lightmapMatrix" ); 974 } 975 t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE; 976 if ( fabs(t - a->lightmap[1]) > 0.01 ) { 977 _printf( "Bad lightmapMatrix" ); 978 } 979 VectorSubtract(b->xyz, f->mins, delta); 980 s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE; 981 if ( fabs(s - b->lightmap[0]) > 0.01 ) { 982 _printf( "Bad lightmapMatrix" ); 983 } 984 t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE; 985 if ( fabs(t - b->lightmap[1]) > 0.01 ) { 986 _printf( "Bad lightmapMatrix" ); 987 } 988 VectorSubtract(c->xyz, f->mins, delta); 989 s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE; 990 if ( fabs(s - c->lightmap[0]) > 0.01 ) { 991 _printf( "Bad lightmapMatrix" ); 992 } 993 t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE; 994 if ( fabs(t - c->lightmap[1]) > 0.01 ) { 995 _printf( "Bad lightmapMatrix" ); 996 } 997 VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins); 998 return; 999 } 1000 // This is an incredibly stupid way of solving a three variable equation 1001 for ( i = 0 ; i < 2 ; i++ ) { 1002 1003 if (i) 1004 al = a->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE; 1005 else 1006 al = a->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE; 1007 1008 m[0][0] = a->xyz[0] - f->mins[0]; 1009 m[0][1] = a->xyz[1] - f->mins[1]; 1010 m[0][2] = a->xyz[2] - f->mins[2]; 1011 m[0][3] = al; 1012 1013 if (i) 1014 bl = b->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE; 1015 else 1016 bl = b->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE; 1017 1018 m[1][0] = b->xyz[0] - f->mins[0]; 1019 m[1][1] = b->xyz[1] - f->mins[1]; 1020 m[1][2] = b->xyz[2] - f->mins[2]; 1021 m[1][3] = bl; 1022 1023 if (i) 1024 cl = c->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE; 1025 else 1026 cl = c->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE; 1027 1028 m[2][0] = c->xyz[0] - f->mins[0]; 1029 m[2][1] = c->xyz[1] - f->mins[1]; 1030 m[2][2] = c->xyz[2] - f->mins[2]; 1031 m[2][3] = cl; 1032 1033 if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) >= fabs(m[2][0]) ) { 1034 for ( j = 0 ; j < 4 ; j ++ ) { 1035 t = m[0][j]; 1036 m[0][j] = m[1][j]; 1037 m[1][j] = t; 1038 } 1039 } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) >= fabs(m[1][0]) ) { 1040 for ( j = 0 ; j < 4 ; j ++ ) { 1041 t = m[0][j]; 1042 m[0][j] = m[2][j]; 1043 m[2][j] = t; 1044 } 1045 } 1046 1047 if (m[0][0]) 1048 { 1049 s = 1.0 / m[0][0]; 1050 m[0][0] *= s; 1051 m[0][1] *= s; 1052 m[0][2] *= s; 1053 m[0][3] *= s; 1054 1055 s = m[1][0]; 1056 m[1][0] -= m[0][0] * s; 1057 m[1][1] -= m[0][1] * s; 1058 m[1][2] -= m[0][2] * s; 1059 m[1][3] -= m[0][3] * s; 1060 1061 s = m[2][0]; 1062 m[2][0] -= m[0][0] * s; 1063 m[2][1] -= m[0][1] * s; 1064 m[2][2] -= m[0][2] * s; 1065 m[2][3] -= m[0][3] * s; 1066 } 1067 1068 if ( fabs(m[2][1]) > fabs(m[1][1]) ) { 1069 for ( j = 0 ; j < 4 ; j ++ ) { 1070 t = m[1][j]; 1071 m[1][j] = m[2][j]; 1072 m[2][j] = t; 1073 } 1074 } 1075 1076 if (m[1][1]) 1077 { 1078 s = 1.0 / m[1][1]; 1079 m[1][0] *= s; 1080 m[1][1] *= s; 1081 m[1][2] *= s; 1082 m[1][3] *= s; 1083 1084 s = m[2][1]; 1085 m[2][0] -= m[1][0] * s; 1086 m[2][1] -= m[1][1] * s; 1087 m[2][2] -= m[1][2] * s; 1088 m[2][3] -= m[1][3] * s; 1089 } 1090 1091 if (m[2][2]) 1092 { 1093 s = 1.0 / m[2][2]; 1094 m[2][0] *= s; 1095 m[2][1] *= s; 1096 m[2][2] *= s; 1097 m[2][3] *= s; 1098 } 1099 1100 f->lightmapMatrix[i][2] = m[2][3]; 1101 f->lightmapMatrix[i][1] = m[1][3] - f->lightmapMatrix[i][2] * m[1][2]; 1102 f->lightmapMatrix[i][0] = m[0][3] - f->lightmapMatrix[i][2] * m[0][2] - f->lightmapMatrix[i][1] * m[0][1]; 1103 1104 f->lightmapMatrix[i][3] = 0; 1105 1106 VectorSubtract(a->xyz, f->mins, delta); 1107 s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - al ); 1108 if ( s > 0.01 ) { 1109 if (!message) 1110 _printf( "Bad lightmapMatrix\n" ); 1111 message = qtrue; 1112 } 1113 VectorSubtract(b->xyz, f->mins, delta); 1114 s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - bl ); 1115 if ( s > 0.01 ) { 1116 if (!message) 1117 _printf( "Bad lightmapMatrix\n" ); 1118 message = qtrue; 1119 } 1120 VectorSubtract(c->xyz, f->mins, delta); 1121 s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - cl ); 1122 if ( s > 0.01 ) { 1123 if (!message) 1124 _printf( "Bad lightmapMatrix\n" ); 1125 message = qtrue; 1126 } 1127 VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins); 1128 } 1129 } 1130 1131 /* 1132 ============= 1133 Plane_Equal 1134 ============= 1135 */ 1136 #define NORMAL_EPSILON 0.0001 1137 #define DIST_EPSILON 0.02 1138 1139 int Plane_Equal(plane_t *a, plane_t *b, int flip) 1140 { 1141 vec3_t normal; 1142 float dist; 1143 1144 if (flip) { 1145 normal[0] = - b->normal[0]; 1146 normal[1] = - b->normal[1]; 1147 normal[2] = - b->normal[2]; 1148 dist = - b->dist; 1149 } 1150 else { 1151 normal[0] = b->normal[0]; 1152 normal[1] = b->normal[1]; 1153 normal[2] = b->normal[2]; 1154 dist = b->dist; 1155 } 1156 if ( 1157 fabs(a->normal[0] - normal[0]) < NORMAL_EPSILON 1158 && fabs(a->normal[1] - normal[1]) < NORMAL_EPSILON 1159 && fabs(a->normal[2] - normal[2]) < NORMAL_EPSILON 1160 && fabs(a->dist - dist) < DIST_EPSILON ) 1161 return qtrue; 1162 return qfalse; 1163 } 1164 1165 /* 1166 ============= 1167 VL_PlaneFromPoints 1168 ============= 1169 */ 1170 qboolean VL_PlaneFromPoints( plane_t *plane, const vec3_t a, const vec3_t b, const vec3_t c ) { 1171 vec3_t d1, d2; 1172 1173 VectorSubtract( b, a, d1 ); 1174 VectorSubtract( c, a, d2 ); 1175 CrossProduct( d2, d1, plane->normal ); 1176 if ( VectorNormalize( plane->normal, plane->normal ) == 0 ) { 1177 return qfalse; 1178 } 1179 1180 plane->dist = DotProduct( a, plane->normal ); 1181 return qtrue; 1182 } 1183 1184 /* 1185 ===================== 1186 VL_GenerateBoundaryForPoints 1187 ===================== 1188 */ 1189 void VL_GenerateBoundaryForPoints( plane_t *boundary, plane_t *plane, vec3_t a, vec3_t b ) { 1190 vec3_t d1; 1191 1192 // make a perpendicular vector to the edge and the surface 1193 VectorSubtract( a, b, d1 ); 1194 CrossProduct( plane->normal, d1, boundary->normal ); 1195 VectorNormalize( boundary->normal, boundary->normal ); 1196 boundary->dist = DotProduct( a, boundary->normal ); 1197 } 1198 1199 /* 1200 ===================== 1201 VL_GenerateFacetFor3Points 1202 ===================== 1203 */ 1204 qboolean VL_GenerateFacetFor3Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) { 1205 // 1206 vec3_t dir; 1207 int i; 1208 1209 // if we can't generate a valid plane for the points, ignore the facet 1210 if ( !VL_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) { 1211 f->numpoints = 0; 1212 return qfalse; 1213 } 1214 1215 f->num = numfacets++; 1216 1217 VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] ); 1218 VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] ); 1219 VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] ); 1220 1221 f->lightmapCoords[0][0] = a->lightmap[0]; 1222 f->lightmapCoords[0][1] = a->lightmap[1]; 1223 f->lightmapCoords[1][0] = b->lightmap[0]; 1224 f->lightmapCoords[1][1] = b->lightmap[1]; 1225 f->lightmapCoords[2][0] = c->lightmap[0]; 1226 f->lightmapCoords[2][1] = c->lightmap[1]; 1227 1228 VL_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] ); 1229 VL_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] ); 1230 VL_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[0] ); 1231 1232 for (i = 0; i < 3; i++) 1233 { 1234 VectorSubtract(f->points[(i+1)%3], f->points[i], dir); 1235 if (VectorLength(dir) < 0.1) 1236 return qfalse; 1237 } 1238 1239 VL_TextureMatrixFromPoints( f, a, b, c ); 1240 VL_LightmapMatrixFromPoints( dsurf, si, f, a, b, c ); 1241 1242 f->numpoints = 3; 1243 1244 return qtrue; 1245 } 1246 1247 /* 1248 ===================== 1249 VL_GenerateFacetFor4Points 1250 1251 Attempts to use four points as a planar quad 1252 ===================== 1253 */ 1254 #define PLANAR_EPSILON 0.1 1255 qboolean VL_GenerateFacetFor4Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c, drawVert_t *d ) { 1256 float dist; 1257 vec3_t dir; 1258 int i; 1259 plane_t plane; 1260 1261 // if we can't generate a valid plane for the points, ignore the facet 1262 if ( !VL_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) { 1263 f->numpoints = 0; 1264 return qfalse; 1265 } 1266 1267 // if the fourth point is also on the plane, we can make a quad facet 1268 dist = DotProduct( d->xyz, f->plane.normal ) - f->plane.dist; 1269 if ( fabs( dist ) > PLANAR_EPSILON ) { 1270 f->numpoints = 0; 1271 return qfalse; 1272 } 1273 1274 VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] ); 1275 VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] ); 1276 VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] ); 1277 VectorAdd( d->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[3] ); 1278 1279 for (i = 1; i < 4; i++) 1280 { 1281 if ( !VL_PlaneFromPoints( &plane, f->points[i], f->points[(i+1) % 4], f->points[(i+2) % 4]) ) { 1282 f->numpoints = 0; 1283 return qfalse; 1284 } 1285 1286 if (!Plane_Equal(&f->plane, &plane, qfalse)) { 1287 f->numpoints = 0; 1288 return qfalse; 1289 } 1290 } 1291 1292 f->lightmapCoords[0][0] = a->lightmap[0]; 1293 f->lightmapCoords[0][1] = a->lightmap[1]; 1294 f->lightmapCoords[1][0] = b->lightmap[0]; 1295 f->lightmapCoords[1][1] = b->lightmap[1]; 1296 f->lightmapCoords[2][0] = c->lightmap[0]; 1297 f->lightmapCoords[2][1] = c->lightmap[1]; 1298 f->lightmapCoords[3][0] = d->lightmap[0]; 1299 f->lightmapCoords[3][1] = d->lightmap[1]; 1300 1301 VL_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] ); 1302 VL_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] ); 1303 VL_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[3] ); 1304 VL_GenerateBoundaryForPoints( &f->boundaries[3], &f->plane, f->points[3], f->points[0] ); 1305 1306 for (i = 0; i < 4; i++) 1307 { 1308 VectorSubtract(f->points[(i+1)%4], f->points[i], dir); 1309 if (VectorLength(dir) < 0.1) 1310 return qfalse; 1311 } 1312 1313 VL_TextureMatrixFromPoints( f, a, b, c ); 1314 VL_LightmapMatrixFromPoints( dsurf, si, f, a, b, c ); 1315 1316 f->num = numfacets++; 1317 f->numpoints = 4; 1318 1319 return qtrue; 1320 } 1321 1322 /* 1323 =============== 1324 VL_SphereFromBounds 1325 =============== 1326 */ 1327 void VL_SphereFromBounds( vec3_t mins, vec3_t maxs, vec3_t origin, float *radius ) { 1328 vec3_t temp; 1329 1330 VectorAdd( mins, maxs, origin ); 1331 VectorScale( origin, 0.5, origin ); 1332 VectorSubtract( maxs, origin, temp ); 1333 *radius = VectorLength( temp ); 1334 } 1335 1336 /* 1337 ==================== 1338 VL_FacetsForTriangleSurface 1339 ==================== 1340 */ 1341 void VL_FacetsForTriangleSurface( dsurface_t *dsurf, shaderInfo_t *si, lsurfaceTest_t *test ) { 1342 int i; 1343 drawVert_t *v1, *v2, *v3, *v4; 1344 int count; 1345 int i1, i2, i3, i4, i5, i6; 1346 1347 test->patch = qfalse; 1348 if (dsurf->surfaceType == MST_TRIANGLE_SOUP) 1349 test->trisoup = qtrue; 1350 else 1351 test->trisoup = qfalse; 1352 test->numFacets = dsurf->numIndexes / 3; 1353 test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets ); 1354 test->shader = si; 1355 1356 count = 0; 1357 for ( i = 0 ; i < test->numFacets ; i++ ) { 1358 i1 = drawIndexes[ dsurf->firstIndex + i*3 ]; 1359 i2 = drawIndexes[ dsurf->firstIndex + i*3 + 1 ]; 1360 i3 = drawIndexes[ dsurf->firstIndex + i*3 + 2 ]; 1361 1362 v1 = &drawVerts[ dsurf->firstVert + i1 ]; 1363 v2 = &drawVerts[ dsurf->firstVert + i2 ]; 1364 v3 = &drawVerts[ dsurf->firstVert + i3 ]; 1365 1366 // try and make a quad out of two triangles 1367 if ( i != test->numFacets - 1 ) { 1368 i4 = drawIndexes[ dsurf->firstIndex + i*3 + 3 ]; 1369 i5 = drawIndexes[ dsurf->firstIndex + i*3 + 4 ]; 1370 i6 = drawIndexes[ dsurf->firstIndex + i*3 + 5 ]; 1371 if ( i4 == i3 && i5 == i2 ) { 1372 v4 = &drawVerts[ dsurf->firstVert + i6 ]; 1373 if ( VL_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v2, v4, v3 ) ) { 1374 count++; 1375 i++; // skip next tri 1376 continue; 1377 } 1378 } 1379 } 1380 1381 if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v2, v3 )) { 1382 count++; 1383 } 1384 } 1385 1386 // we may have turned some pairs into quads 1387 test->numFacets = count; 1388 } 1389 1390 /* 1391 ==================== 1392 VL_FacetsForPatch 1393 ==================== 1394 */ 1395 void VL_FacetsForPatch( dsurface_t *dsurf, int surfaceNum, shaderInfo_t *si, lsurfaceTest_t *test ) { 1396 int i, j, x, y; 1397 drawVert_t *v1, *v2, *v3, *v4; 1398 int count, ssize; 1399 mesh_t mesh; 1400 mesh_t *subdivided, *detailmesh, *newmesh; 1401 int widthtable[LIGHTMAP_SIZE], heighttable[LIGHTMAP_SIZE]; 1402 1403 mesh.width = dsurf->patchWidth; 1404 mesh.height = dsurf->patchHeight; 1405 mesh.verts = &drawVerts[ dsurf->firstVert ]; 1406 1407 newmesh = SubdivideMesh( mesh, 8, 999 ); 1408 PutMeshOnCurve( *newmesh ); 1409 MakeMeshNormals( *newmesh ); 1410 1411 subdivided = RemoveLinearMeshColumnsRows( newmesh ); 1412 FreeMesh(newmesh); 1413 1414 // DebugNet_RemoveAllPolys(); 1415 // DebugNet_DrawMesh(subdivided); 1416 1417 ssize = samplesize; 1418 if (si->lightmapSampleSize) 1419 ssize = si->lightmapSampleSize; 1420 1421 if ( dsurf->lightmapNum >= 0 ) { 1422 1423 detailmesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_SIZE, widthtable, heighttable); 1424 test->detailMesh = detailmesh; 1425 1426 // DebugNet_RemoveAllPolys(); 1427 // DebugNet_DrawMesh(detailmesh); 1428 1429 if ( detailmesh->width != dsurf->lightmapWidth || detailmesh->height != dsurf->lightmapHeight ) { 1430 Error( "Mesh lightmap miscount"); 1431 } 1432 } 1433 else { 1434 test->detailMesh = NULL; 1435 memset(widthtable, 0, sizeof(widthtable)); 1436 memset(heighttable, 0, sizeof(heighttable)); 1437 } 1438 1439 test->patch = qtrue; 1440 test->trisoup = qfalse; 1441 test->numFacets = ( subdivided->width - 1 ) * ( subdivided->height - 1 ) * 2; 1442 test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets ); 1443 test->shader = si; 1444 1445 count = 0; 1446 x = 0; 1447 for ( i = 0 ; i < subdivided->width - 1 ; i++ ) { 1448 y = 0; 1449 for ( j = 0 ; j < subdivided->height - 1 ; j++ ) { 1450 1451 v1 = subdivided->verts + j * subdivided->width + i; 1452 v2 = v1 + 1; 1453 v3 = v1 + subdivided->width + 1; 1454 v4 = v1 + subdivided->width; 1455 1456 if ( VL_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v4, v3, v2 ) ) { 1457 test->facets[count].x = x; 1458 test->facets[count].y = y; 1459 test->facets[count].width = widthtable[i]; 1460 test->facets[count].height = heighttable[j]; 1461 count++; 1462 } else { 1463 if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v4, v3 )) { 1464 test->facets[count].x = x; 1465 test->facets[count].y = y; 1466 test->facets[count].width = widthtable[i]; 1467 test->facets[count].height = heighttable[j]; 1468 count++; 1469 } 1470 if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v3, v2 )) { 1471 test->facets[count].x = x; 1472 test->facets[count].y = y; 1473 test->facets[count].width = widthtable[i]; 1474 test->facets[count].height = heighttable[j]; 1475 count++; 1476 } 1477 } 1478 y += heighttable[j]; 1479 } 1480 x += widthtable[i]; 1481 } 1482 test->numFacets = count; 1483 1484 FreeMesh(subdivided); 1485 } 1486 1487 /* 1488 ===================== 1489 VL_InitSurfacesForTesting 1490 ===================== 1491 */ 1492 void VL_InitSurfacesForTesting( void ) { 1493 1494 int i, j, k; 1495 dsurface_t *dsurf; 1496 lsurfaceTest_t *test; 1497 shaderInfo_t *si; 1498 lFacet_t *facet; 1499 1500 for ( i = 0 ; i < numDrawSurfaces ; i++ ) { 1501 // don't light the entity surfaces with vlight 1502 if ( entitySurface[i] ) 1503 continue; 1504 // 1505 dsurf = &drawSurfaces[ i ]; 1506 if ( !dsurf->numIndexes && !dsurf->patchWidth ) { 1507 continue; 1508 } 1509 1510 si = ShaderInfoForShader( dshaders[ dsurf->shaderNum].shader ); 1511 // if the surface is translucent and does not cast an alpha shadow 1512 if ( (si->contents & CONTENTS_TRANSLUCENT) && !(si->surfaceFlags & SURF_ALPHASHADOW) ) { 1513 // if the surface has no lightmap 1514 if ( dsurf->lightmapNum < 0 ) 1515 continue; 1516 } 1517 1518 test = malloc( sizeof( *test ) ); 1519 memset(test, 0, sizeof( *test )); 1520 test->mutex = MutexAlloc(); 1521 test->numvolumes = 0; 1522 if (si->forceTraceLight) 1523 test->always_tracelight = qtrue; 1524 else if (si->forceVLight) 1525 test->always_vlight = qtrue; 1526 lsurfaceTest[i] = test; 1527 1528 if ( dsurf->surfaceType == MST_TRIANGLE_SOUP || dsurf->surfaceType == MST_PLANAR ) { 1529 VL_FacetsForTriangleSurface( dsurf, si, test ); 1530 } else if ( dsurf->surfaceType == MST_PATCH ) { 1531 VL_FacetsForPatch( dsurf, i, si, test ); 1532 } 1533 if (numfacets >= MAX_FACETS) 1534 Error("numfacets >= MAX_FACETS (%d)", MAX_FACETS); 1535 1536 ClearBounds( test->mins, test->maxs ); 1537 for (j = 0; j < test->numFacets; j++) 1538 { 1539 facet = &test->facets[j]; 1540 for ( k = 0 ; k < facet->numpoints; k++) { 1541 AddPointToBounds( facet->points[k], test->mins, test->maxs ); 1542 } 1543 } 1544 VL_SphereFromBounds( test->mins, test->maxs, test->origin, &test->radius ); 1545 } 1546 _printf("%6d facets\n", numfacets); 1547 _printf("linking surfaces...\n"); 1548 VL_LinkSurfaces(); 1549 } 1550 1551 /* 1552 ============= 1553 VL_ChopWinding 1554 ============= 1555 */ 1556 int VL_ChopWinding (winding_t *in, plane_t *split, float epsilon) 1557 { 1558 vec_t dists[128]; 1559 int sides[128]; 1560 int counts[3]; 1561 vec_t dot; 1562 int i, j; 1563 vec_t *p1, *p2; 1564 vec3_t mid; 1565 winding_t out; 1566 winding_t *neww; 1567 1568 counts[0] = counts[1] = counts[2] = 0; 1569 1570 // determine sides for each point 1571 for (i=0 ; i<in->numpoints ; i++) 1572 { 1573 dot = DotProduct (in->points[i], split->normal); 1574 dot -= split->dist; 1575 dists[i] = dot; 1576 if (dot > epsilon) 1577 sides[i] = SIDE_FRONT; 1578 else if (dot < -epsilon) 1579 sides[i] = SIDE_BACK; 1580 else 1581 { 1582 sides[i] = SIDE_ON; 1583 } 1584 counts[sides[i]]++; 1585 } 1586 1587 if (!counts[SIDE_BACK]) 1588 { 1589 if (!counts[SIDE_FRONT]) 1590 return SIDE_ON; 1591 else 1592 return SIDE_FRONT; 1593 } 1594 1595 if (!counts[SIDE_FRONT]) 1596 { 1597 return SIDE_BACK; 1598 } 1599 1600 sides[i] = sides[0]; 1601 dists[i] = dists[0]; 1602 1603 neww = &out; 1604 1605 neww->numpoints = 0; 1606 1607 for (i=0 ; i<in->numpoints ; i++) 1608 { 1609 p1 = in->points[i]; 1610 1611 if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING) 1612 { 1613 _printf("WARNING: VL_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n"); 1614 return SIDE_FRONT; // can't chop -- fall back to original 1615 } 1616 1617 if (sides[i] == SIDE_ON) 1618 { 1619 VectorCopy (p1, neww->points[neww->numpoints]); 1620 neww->numpoints++; 1621 continue; 1622 } 1623 1624 if (sides[i] == SIDE_FRONT) 1625 { 1626 VectorCopy (p1, neww->points[neww->numpoints]); 1627 neww->numpoints++; 1628 } 1629 1630 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) 1631 continue; 1632 1633 if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING) 1634 { 1635 _printf("WARNING: VL_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n"); 1636 return SIDE_FRONT; // can't chop -- fall back to original 1637 } 1638 1639 // generate a split point 1640 p2 = in->points[(i+1)%in->numpoints]; 1641 1642 dot = dists[i] / (dists[i]-dists[i+1]); 1643 for (j=0 ; j<3 ; j++) 1644 { // avoid round off error when possible 1645 if (split->normal[j] == 1) 1646 mid[j] = split->dist; 1647 else if (split->normal[j] == -1) 1648 mid[j] = -split->dist; 1649 else 1650 mid[j] = p1[j] + dot*(p2[j]-p1[j]); 1651 } 1652 1653 VectorCopy (mid, neww->points[neww->numpoints]); 1654 neww->numpoints++; 1655 } 1656 memcpy(in, &out, sizeof(winding_t)); 1657 1658 return SIDE_CROSS; 1659 } 1660 1661 /* 1662 ============= 1663 VL_ChopWindingWithBrush 1664 1665 returns all winding fragments outside the brush 1666 ============= 1667 */ 1668 int VL_ChopWindingWithBrush(winding_t *w, dbrush_t *brush, winding_t *outwindings, int maxout) 1669 { 1670 int i, res, numout; 1671 winding_t front, back; 1672 plane_t plane; 1673 1674 numout = 0; 1675 memcpy(front.points, w->points, w->numpoints * sizeof(vec3_t)); 1676 front.numpoints = w->numpoints; 1677 for (i = 0; i < brush->numSides; i++) 1678 { 1679 VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal); 1680 VectorInverse(plane.normal); 1681 plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist; 1682 res = VL_SplitWinding(&front, &back, &plane, 0.1); 1683 if (res == SIDE_BACK || res == SIDE_ON) 1684 { 1685 memcpy(outwindings[0].points, w->points, w->numpoints * sizeof(vec3_t)); 1686 outwindings[0].numpoints = w->numpoints; 1687 return 1; //did not intersect 1688 } 1689 if (res != SIDE_FRONT) 1690 { 1691 if (numout >= maxout) 1692 { 1693 _printf("WARNING: VL_ChopWindingWithBrush: more than %d windings\n", maxout); 1694 return 0; 1695 } 1696 memcpy(outwindings[numout].points, back.points, back.numpoints * sizeof(vec3_t)); 1697 outwindings[numout].numpoints = back.numpoints; 1698 numout++; 1699 } 1700 } 1701 return numout; 1702 } 1703 1704 /* 1705 ============= 1706 VL_WindingAreaOutsideBrushes 1707 ============= 1708 */ 1709 float VL_WindingAreaOutsideBrushes(winding_t *w, int *brushnums, int numbrushes) 1710 { 1711 int i, j, numwindings[2], n; 1712 winding_t windingsbuf[2][64]; 1713 dbrush_t *brush; 1714 float area; 1715 1716 memcpy(windingsbuf[0][0].points, w->points, w->numpoints * sizeof(vec3_t)); 1717 windingsbuf[0][0].numpoints = w->numpoints; 1718 numwindings[0] = 1; 1719 for (i = 0; i < numbrushes; i++) 1720 { 1721 brush = &dbrushes[brushnums[i]]; 1722 if (!(dshaders[brush->shaderNum].contentFlags & ( 1723 CONTENTS_LAVA 1724 | CONTENTS_SLIME 1725 | CONTENTS_WATER 1726 | CONTENTS_FOG 1727 | CONTENTS_AREAPORTAL 1728 | CONTENTS_PLAYERCLIP 1729 | CONTENTS_MONSTERCLIP 1730 | CONTENTS_CLUSTERPORTAL 1731 | CONTENTS_DONOTENTER 1732 | CONTENTS_BODY 1733 | CONTENTS_CORPSE 1734 | CONTENTS_TRANSLUCENT 1735 | CONTENTS_TRIGGER 1736 | CONTENTS_NODROP) ) && 1737 (dshaders[brush->shaderNum].contentFlags & CONTENTS_SOLID) ) 1738 { 1739 numwindings[!(i & 1)] = 0; 1740 for (j = 0; j < numwindings[i&1]; j++) 1741 { 1742 n = VL_ChopWindingWithBrush(&windingsbuf[i&1][j], brush, 1743 &windingsbuf[!(i&1)][numwindings[!(i&1)]], 1744 64 - numwindings[!(i&1)]); 1745 numwindings[!(i&1)] += n; 1746 } 1747 if (!numwindings[!(i&1)]) 1748 return 0; 1749 } 1750 else 1751 { 1752 for (j = 0; j < numwindings[i&1]; j++) 1753 { 1754 windingsbuf[!(i&1)][j] = windingsbuf[i&1][j]; 1755 } 1756 numwindings[!(i&1)] = numwindings[i&1]; 1757 } 1758 } 1759 area = 0; 1760 for (j = 0; j < numwindings[i&1]; j++) 1761 { 1762 area += WindingArea(&windingsbuf[i&1][j]); 1763 } 1764 return area; 1765 } 1766 1767 /* 1768 ============= 1769 VL_R_WindingAreaOutsideSolid 1770 ============= 1771 */ 1772 float VL_R_WindingAreaOutsideSolid(winding_t *w, vec3_t normal, int nodenum) 1773 { 1774 int leafnum, res; 1775 float area; 1776 dnode_t *node; 1777 dleaf_t *leaf; 1778 dplane_t *plane; 1779 winding_t back; 1780 plane_t split; 1781 1782 area = 0; 1783 while(nodenum >= 0) 1784 { 1785 node = &dnodes[nodenum]; 1786 plane = &dplanes[node->planeNum]; 1787 1788 VectorCopy(plane->normal, split.normal); 1789 split.dist = plane->dist; 1790 res = VL_SplitWinding (w, &back, &split, 0.1); 1791 1792 if (res == SIDE_FRONT) 1793 { 1794 nodenum = node->children[0]; 1795 } 1796 else if (res == SIDE_BACK) 1797 { 1798 nodenum = node->children[1]; 1799 } 1800 else if (res == SIDE_ON) 1801 { 1802 if (DotProduct(normal, plane->normal) > 0) 1803 nodenum = node->children[0]; 1804 else 1805 nodenum = node->children[1]; 1806 } 1807 else 1808 { 1809 area += VL_R_WindingAreaOutsideSolid(&back, normal, node->children[1]); 1810 nodenum = node->children[0]; 1811 } 1812 } 1813 leafnum = -nodenum - 1; 1814 leaf = &dleafs[leafnum]; 1815 if (leaf->cluster != -1) 1816 { 1817 area += VL_WindingAreaOutsideBrushes(w, &dleafbrushes[leaf->firstLeafBrush], leaf->numLeafBrushes); 1818 } 1819 return area; 1820 } 1821 1822 /* 1823 ============= 1824 VL_WindingAreaOutsideSolid 1825 ============= 1826 */ 1827 float VL_WindingAreaOutsideSolid(winding_t *w, vec3_t normal) 1828 { 1829 return VL_R_WindingAreaOutsideSolid(w, normal, 0); 1830 } 1831 1832 /* 1833 ============= 1834 VL_ChopWindingWithFacet 1835 ============= 1836 */ 1837 float VL_ChopWindingWithFacet(winding_t *w, lFacet_t *facet) 1838 { 1839 int i; 1840 1841 for (i = 0; i < facet->numpoints; i++) 1842 { 1843 if (VL_ChopWinding(w, &facet->boundaries[i], 0) == SIDE_BACK) 1844 return 0; 1845 } 1846 if (nostitching) 1847 return WindingArea(w); 1848 else 1849 return VL_WindingAreaOutsideSolid(w, facet->plane.normal); 1850 } 1851 1852 /* 1853 ============= 1854 VL_CalcVisibleLightmapPixelArea 1855 1856 nice brute force ;) 1857 ============= 1858 */ 1859 void VL_CalcVisibleLightmapPixelArea(void) 1860 { 1861 int i, j, x, y, k; 1862 dsurface_t *ds; 1863 lsurfaceTest_t *test; 1864 mesh_t *mesh; 1865 winding_t w, tmpw; 1866 float area; 1867 1868 _printf("calculating visible lightmap pixel area...\n"); 1869 for ( i = 0 ; i < numDrawSurfaces ; i++ ) 1870 { 1871 test = lsurfaceTest[ i ]; 1872 if (!test) 1873 continue; 1874 ds = &drawSurfaces[ i ]; 1875 1876 if ( ds->lightmapNum < 0 ) 1877 continue; 1878 1879 for (y = 0; y < ds->lightmapHeight; y++) 1880 { 1881 for (x = 0; x < ds->lightmapWidth; x++) 1882 { 1883 if (ds->surfaceType == MST_PATCH) 1884 { 1885 if (y == ds->lightmapHeight-1) 1886 continue; 1887 if (x == ds->lightmapWidth-1) 1888 continue; 1889 mesh = lsurfaceTest[i]->detailMesh; 1890 VectorCopy( mesh->verts[y*mesh->width+x].xyz, w.points[0]); 1891 VectorCopy( mesh->verts[(y+1)*mesh->width+x].xyz, w.points[1]); 1892 VectorCopy( mesh->verts[(y+1)*mesh->width+x+1].xyz, w.points[2]); 1893 VectorCopy( mesh->verts[y*mesh->width+x+1].xyz, w.points[3]); 1894 w.numpoints = 4; 1895 if (nostitching) 1896 area = WindingArea(&w); 1897 else 1898 area = VL_WindingAreaOutsideSolid(&w, mesh->verts[y*mesh->width+x].normal); 1899 } 1900 else 1901 { 1902 VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[0]); 1903 VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[0]); 1904 VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[3]); 1905 VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[3]); 1906 VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[2]); 1907 VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[2]); 1908 VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[1]); 1909 VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[1]); 1910 w.numpoints = 4; 1911 area = 0; 1912 for (j = 0; j < test->numFacets; j++) 1913 { 1914 memcpy(&tmpw, &w, sizeof(winding_t)); 1915 area += VL_ChopWindingWithFacet(&tmpw, &test->facets[j]); 1916 } 1917 } 1918 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 1919 * LIGHTMAP_WIDTH + ds->lightmapX + x; 1920 lightmappixelarea[k] = area; 1921 } 1922 } 1923 } 1924 } 1925 1926 /* 1927 ============= 1928 VL_FindAdjacentSurface 1929 ============= 1930 */ 1931 int VL_FindAdjacentSurface(int surfaceNum, int facetNum, vec3_t p1, vec3_t p2, int *sNum, int *fNum, int *point) 1932 { 1933 int i, j, k; 1934 lsurfaceTest_t *test; 1935 lFacet_t *facet; 1936 dsurface_t *ds; 1937 float *fp1, *fp2; 1938 vec3_t dir; 1939 plane_t *facetplane; 1940 // winding_t w; 1941 1942 facetplane = &lsurfaceTest[surfaceNum]->facets[facetNum].plane; 1943 // DebugNet_RemoveAllPolys(); 1944 // memcpy(w.points, lsurfaceTest[surfaceNum]->facets[facetNum].points, 1945 // lsurfaceTest[surfaceNum]->facets[facetNum].numpoints * sizeof(vec3_t)); 1946 // w.numpoints = lsurfaceTest[surfaceNum]->facets[facetNum].numpoints; 1947 // DebugNet_DrawWinding(&w, 2); 1948 for ( i = 0 ; i < numDrawSurfaces ; i++ ) 1949 { 1950 if (i == surfaceNum) 1951 continue; 1952 test = lsurfaceTest[ i ]; 1953 if (!test) 1954 continue; 1955 if (test->trisoup)// || test->patch) 1956 continue; 1957 ds = &drawSurfaces[i]; 1958 if ( ds->lightmapNum < 0 ) 1959 continue; 1960 //if this surface is not even near the edge 1961 VectorSubtract(p1, test->origin, dir); 1962 if (fabs(dir[0]) > test->radius || 1963 fabs(dir[1]) > test->radius || 1964 fabs(dir[1]) > test->radius) 1965 { 1966 VectorSubtract(p2, test->origin, dir); 1967 if (fabs(dir[0]) > test->radius || 1968 fabs(dir[1]) > test->radius || 1969 fabs(dir[1]) > test->radius) 1970 { 1971 continue; 1972 } 1973 } 1974 // 1975 for (j = 0; j < test->numFacets; j++) 1976 { 1977 facet = &test->facets[j]; 1978 // 1979 //if (!Plane_Equal(&facet->plane, facetplane, qfalse)) 1980 if (DotProduct(facet->plane.normal, facetplane->normal) < 0.9) 1981 { 1982 if (!test->trisoup && !test->patch) 1983 break; 1984 continue; 1985 } 1986 // 1987 for (k = 0; k < facet->numpoints; k++) 1988 { 1989 fp1 = facet->points[k]; 1990 if (fabs(p2[0] - fp1[0]) < 0.1 && 1991 fabs(p2[1] - fp1[1]) < 0.1 && 1992 fabs(p2[2] - fp1[2]) < 0.1) 1993 { 1994 fp2 = facet->points[(k+1) % facet->numpoints]; 1995 if (fabs(p1[0] - fp2[0]) < 0.1 && 1996 fabs(p1[1] - fp2[1]) < 0.1 && 1997 fabs(p1[2] - fp2[2]) < 0.1) 1998 { 1999 // memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t)); 2000 // w.numpoints = facet->numpoints; 2001 // DebugNet_DrawWinding(&w, 1); 2002 *sNum = i; 2003 *fNum = j; 2004 *point = k; 2005 return qtrue; 2006 } 2007 } 2008 /* 2009 else if (fabs(p1[0] - fp1[0]) < 0.1 && 2010 fabs(p1[1] - fp1[1]) < 0.1 && 2011 fabs(p1[2] - fp1[2]) < 0.1) 2012 { 2013 fp2 = facet->points[(k+1) % facet->numpoints]; 2014 if (fabs(p2[0] - fp2[0]) < 0.1 && 2015 fabs(p2[1] - fp2[1]) < 0.1 && 2016 fabs(p2[2] - fp2[2]) < 0.1) 2017 { 2018 // memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t)); 2019 // w.numpoints = facet->numpoints; 2020 // DebugNet_DrawWinding(&w, 1); 2021 *sNum = i; 2022 *fNum = j; 2023 *point = k; 2024 return qtrue; 2025 } 2026 } 2027 //*/ 2028 } 2029 } 2030 } 2031 return qfalse; 2032 } 2033 2034 /* 2035 ============= 2036 VL_SmoothenLightmapEdges 2037 2038 this code is used to smoothen lightmaps across surface edges 2039 ============= 2040 */ 2041 void VL_SmoothenLightmapEdges(void) 2042 { 2043 int i, j, k, coords1[2][2]; 2044 float coords2[2][2]; 2045 int x1, y1, xinc1, yinc1, k1, k2; 2046 float x2, y2, xinc2, yinc2, length; 2047 int surfaceNum, facetNum, point; 2048 lsurfaceTest_t *test; 2049 lFacet_t *facet1, *facet2; 2050 dsurface_t *ds1, *ds2; 2051 float *p[2], s, t, *color1, *color2; 2052 vec3_t dir, cross; 2053 2054 for ( i = 0 ; i < numDrawSurfaces ; i++ ) 2055 { 2056 test = lsurfaceTest[ i ]; 2057 if (!test) 2058 continue; 2059 if (test->trisoup)// || test->patch) 2060 continue; 2061 ds1 = &drawSurfaces[i]; 2062 if ( ds1->lightmapNum < 0 ) 2063 continue; 2064 for (j = 0; j < test->numFacets; j++) 2065 { 2066 facet1 = &test->facets[j]; 2067 // 2068 for (k = 0; k < facet1->numpoints; k++) 2069 { 2070 p[0] = facet1->points[k]; 2071 p[1] = facet1->points[(k+1)%facet1->numpoints]; 2072 // 2073 coords1[0][0] = facet1->lightmapCoords[k][0] * LIGHTMAP_SIZE; 2074 coords1[0][1] = facet1->lightmapCoords[k][1] * LIGHTMAP_SIZE; 2075 coords1[1][0] = facet1->lightmapCoords[(k+1)%facet1->numpoints][0] * LIGHTMAP_SIZE; 2076 coords1[1][1] = facet1->lightmapCoords[(k+1)%facet1->numpoints][1] * LIGHTMAP_SIZE; 2077 if (coords1[0][0] >= LIGHTMAP_SIZE) 2078 coords1[0][0] = LIGHTMAP_SIZE-1; 2079 if (coords1[0][1] >= LIGHTMAP_SIZE) 2080 coords1[0][1] = LIGHTMAP_SIZE-1; 2081 if (coords1[1][0] >= LIGHTMAP_SIZE) 2082 coords1[1][0] = LIGHTMAP_SIZE-1; 2083 if (coords1[1][1] >= LIGHTMAP_SIZE) 2084 coords1[1][1] = LIGHTMAP_SIZE-1; 2085 // try one row or column further because on flat faces the lightmap can 2086 // extend beyond the edge 2087 VectorSubtract(p[1], p[0], dir); 2088 VectorNormalize(dir, dir); 2089 CrossProduct(dir, facet1->plane.normal, cross); 2090 // 2091 if (coords1[0][0] - coords1[1][0] == 0) 2092 { 2093 s = DotProduct( cross, facet1->lightmapMatrix[0] ); 2094 coords1[0][0] += s < 0 ? 1 : -1; 2095 coords1[1][0] += s < 0 ? 1 : -1; 2096 if (coords1[0][0] < ds1->lightmapX || coords1[0][0] >= ds1->lightmapX + ds1->lightmapWidth) 2097 { 2098 coords1[0][0] += s < 0 ? -1 : 1; 2099 coords1[1][0] += s < 0 ? -1 : 1; 2100 } 2101 length = fabs(coords1[1][1] - coords1[0][1]); 2102 } 2103 else if (coords1[0][1] - coords1[1][1] == 0) 2104 { 2105 t = DotProduct( cross, facet1->lightmapMatrix[1] ); 2106 coords1[0][1] += t < 0 ? 1 : -1; 2107 coords1[1][1] += t < 0 ? 1 : -1; 2108 if (coords1[0][1] < ds1->lightmapY || coords1[0][1] >= ds1->lightmapY + ds1->lightmapHeight) 2109 { 2110 coords1[0][1] += t < 0 ? -1 : 1; 2111 coords1[1][1] += t < 0 ? -1 : 1; 2112 } 2113 length = fabs(coords1[1][0] - coords1[0][0]); 2114 } 2115 else 2116 { 2117 //the edge is not parallell to one of the lightmap axis 2118 continue; 2119 } 2120 // 2121 x1 = coords1[0][0]; 2122 y1 = coords1[0][1]; 2123 xinc1 = coords1[1][0] - coords1[0][0]; 2124 if (xinc1 < 0) xinc1 = -1; 2125 if (xinc1 > 0) xinc1 = 1; 2126 yinc1 = coords1[1][1] - coords1[0][1]; 2127 if (yinc1 < 0) yinc1 = -1; 2128 if (yinc1 > 0) yinc1 = 1; 2129 // the edge should be parallell to one of the lightmap axis 2130 if (xinc1 != 0 && yinc1 != 0) 2131 continue; 2132 // 2133 if (!VL_FindAdjacentSurface(i, j, p[0], p[1], &surfaceNum, &facetNum, &point)) 2134 continue; 2135 // 2136 ds2 = &drawSurfaces[surfaceNum]; 2137 facet2 = &lsurfaceTest[surfaceNum]->facets[facetNum]; 2138 coords2[0][0] = facet2->lightmapCoords[(point+1)%facet2->numpoints][0] * LIGHTMAP_SIZE; 2139 coords2[0][1] = facet2->lightmapCoords[(point+1)%facet2->numpoints][1] * LIGHTMAP_SIZE; 2140 coords2[1][0] = facet2->lightmapCoords[point][0] * LIGHTMAP_SIZE; 2141 coords2[1][1] = facet2->lightmapCoords[point][1] * LIGHTMAP_SIZE; 2142 if (coords2[0][0] >= LIGHTMAP_SIZE) 2143 coords2[0][0] = LIGHTMAP_SIZE-1; 2144 if (coords2[0][1] >= LIGHTMAP_SIZE) 2145 coords2[0][1] = LIGHTMAP_SIZE-1; 2146 if (coords2[1][0] >= LIGHTMAP_SIZE) 2147 coords2[1][0] = LIGHTMAP_SIZE-1; 2148 if (coords2[1][1] >= LIGHTMAP_SIZE) 2149 coords2[1][1] = LIGHTMAP_SIZE-1; 2150 // 2151 x2 = coords2[0][0]; 2152 y2 = coords2[0][1]; 2153 xinc2 = coords2[1][0] - coords2[0][0]; 2154 if (length) 2155 xinc2 = xinc2 / length; 2156 yinc2 = coords2[1][1] - coords2[0][1]; 2157 if (length) 2158 yinc2 = yinc2 / length; 2159 // the edge should be parallell to one of the lightmap axis 2160 if ((int) xinc2 != 0 && (int) yinc2 != 0) 2161 continue; 2162 // 2163 while(1) 2164 { 2165 k1 = ( ds1->lightmapNum * LIGHTMAP_HEIGHT + y1) * LIGHTMAP_WIDTH + x1; 2166 k2 = ( ds2->lightmapNum * LIGHTMAP_HEIGHT + ((int) y2)) * LIGHTMAP_WIDTH + ((int) x2); 2167 color1 = lightFloats + k1*3; 2168 color2 = lightFloats + k2*3; 2169 if (lightmappixelarea[k1] < 0.01) 2170 { 2171 color1[0] = color2[0]; 2172 color1[1] = color2[1]; 2173 color1[2] = color2[2]; 2174 } 2175 else 2176 { 2177 color1[0] = (float) color2[0] * 0.7 + (float) color1[0] * 0.3; 2178 color1[1] = (float) color2[1] * 0.7 + (float) color1[1] * 0.3; 2179 color1[2] = (float) color2[2] * 0.7 + (float) color1[2] * 0.3; 2180 } 2181 // 2182 if (x1 == coords1[1][0] && 2183 y1 == coords1[1][1]) 2184 break; 2185 x1 += xinc1; 2186 y1 += yinc1; 2187 x2 += xinc2; 2188 y2 += yinc2; 2189 if (x2 < ds2->lightmapX) 2190 x2 = ds2->lightmapX; 2191 if (x2 >= ds2->lightmapX + ds2->lightmapWidth) 2192 x2 = ds2->lightmapX + ds2->lightmapWidth-1; 2193 if (y2 < ds2->lightmapY) 2194 y2 = ds2->lightmapY; 2195 if (y2 >= ds2->lightmapY + ds2->lightmapHeight) 2196 y2 = ds2->lightmapY + ds2->lightmapHeight-1; 2197 } 2198 } 2199 } 2200 } 2201 } 2202 2203 /* 2204 ============= 2205 VL_FixLightmapEdges 2206 ============= 2207 */ 2208 void VL_FixLightmapEdges(void) 2209 { 2210 int i, j, x, y, k, foundvalue, height, width, index; 2211 int pos, top, bottom; 2212 dsurface_t *ds; 2213 lsurfaceTest_t *test; 2214 float color[3]; 2215 float *ptr; 2216 byte filled[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8]; 2217 float lightmap_edge_epsilon; 2218 2219 lightmap_edge_epsilon = 0.1 * samplesize; 2220 for ( i = 0 ; i < numDrawSurfaces ; i++ ) 2221 { 2222 test = lsurfaceTest[ i ]; 2223 if (!test) 2224 continue; 2225 ds = &drawSurfaces[ i ]; 2226 2227 if ( ds->lightmapNum < 0 ) 2228 continue; 2229 if (ds->surfaceType == MST_PATCH) 2230 { 2231 height = ds->lightmapHeight - 1; 2232 width = ds->lightmapWidth - 1; 2233 } 2234 else 2235 { 2236 height = ds->lightmapHeight; 2237 width = ds->lightmapWidth; 2238 } 2239 memset(filled, 0, sizeof(filled)); 2240 // printf("\n"); 2241 for (x = 0; x < width; x++) 2242 { 2243 for (y = 0; y < height; y++) 2244 { 2245 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2246 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2247 if (lightmappixelarea[k] > lightmap_edge_epsilon) 2248 { 2249 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x; 2250 filled[index >> 3] |= 1 << (index & 7); 2251 // printf("*"); 2252 } 2253 // else 2254 // printf("_"); 2255 } 2256 // printf("\n"); 2257 } 2258 for (y = 0; y < height; y++) 2259 { 2260 pos = -2; 2261 for (x = 0; x < width; x++) 2262 { 2263 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x; 2264 if (pos == -2) 2265 { 2266 if (filled[index >> 3] & (1 << (index & 7))) 2267 pos = -1; 2268 } 2269 else if (pos == -1) 2270 { 2271 if (!(filled[index >> 3] & (1 << (index & 7)))) 2272 pos = x - 1; 2273 } 2274 else 2275 { 2276 if (filled[index >> 3] & (1 << (index & 7))) 2277 { 2278 bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2279 * LIGHTMAP_WIDTH + ds->lightmapX + pos; 2280 top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2281 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2282 for (j = 0; j < (x - pos + 1) / 2; j++) 2283 { 2284 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2285 * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1; 2286 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1; 2287 filled[index >> 3] |= 1 << (index & 7); 2288 (lightFloats + k*3)[0] = (lightFloats + top*3)[0]; 2289 (lightFloats + k*3)[1] = (lightFloats + top*3)[1]; 2290 (lightFloats + k*3)[2] = (lightFloats + top*3)[2]; 2291 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2292 * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1; 2293 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1; 2294 filled[index >> 3] |= 1 << (index & 7); 2295 (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0]; 2296 (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1]; 2297 (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2]; 2298 } 2299 pos = -1; 2300 } 2301 } 2302 } 2303 } 2304 for (x = 0; x < width; x++) 2305 { 2306 pos = -2; 2307 for (y = 0; y < height; y++) 2308 { 2309 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x; 2310 if (pos == -2) 2311 { 2312 if (filled[index >> 3] & (1 << (index & 7))) 2313 pos = -1; 2314 } 2315 else if (pos == -1) 2316 { 2317 if (!(filled[index >> 3] & (1 << (index & 7)))) 2318 pos = y - 1; 2319 } 2320 else 2321 { 2322 if (filled[index >> 3] & (1 << (index & 7))) 2323 { 2324 bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos) 2325 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2326 top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2327 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2328 for (j = 0; j < (y - pos + 1) / 2; j++) 2329 { 2330 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos + j + 1) 2331 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2332 index = (ds->lightmapY + pos + j + 1) * LIGHTMAP_WIDTH + ds->lightmapX + x; 2333 filled[index >> 3] |= 1 << (index & 7); 2334 (lightFloats + k*3)[0] = (lightFloats + top*3)[0]; 2335 (lightFloats + k*3)[1] = (lightFloats + top*3)[1]; 2336 (lightFloats + k*3)[2] = (lightFloats + top*3)[2]; 2337 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y - j - 1) 2338 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2339 index = (ds->lightmapY + y - j - 1) * LIGHTMAP_WIDTH + ds->lightmapX + x; 2340 filled[index >> 3] |= 1 << (index & 7); 2341 (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0]; 2342 (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1]; 2343 (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2]; 2344 } 2345 pos = -1; 2346 } 2347 } 2348 } 2349 } 2350 for (y = 0; y < height; y++) 2351 { 2352 foundvalue = qfalse; 2353 for (x = 0; x < width; x++) 2354 { 2355 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2356 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2357 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x; 2358 if (foundvalue) 2359 { 2360 if (filled[index >> 3] & (1 << (index & 7))) 2361 { 2362 ptr = lightFloats + k*3; 2363 color[0] = ptr[0]; 2364 color[1] = ptr[1]; 2365 color[2] = ptr[2]; 2366 } 2367 else 2368 { 2369 ptr = lightFloats + k*3; 2370 ptr[0] = color[0]; 2371 ptr[1] = color[1]; 2372 ptr[2] = color[2]; 2373 filled[index >> 3] |= 1 << (index & 7); 2374 } 2375 } 2376 else 2377 { 2378 if (filled[index >> 3] & (1 << (index & 7))) 2379 { 2380 ptr = lightFloats + k*3; 2381 color[0] = ptr[0]; 2382 color[1] = ptr[1]; 2383 color[2] = ptr[2]; 2384 foundvalue = qtrue; 2385 } 2386 } 2387 } 2388 foundvalue = qfalse; 2389 for (x = width-1; x >= 0; x--) 2390 { 2391 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2392 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2393 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x; 2394 if (foundvalue) 2395 { 2396 if (filled[index >> 3] & (1 << (index & 7))) 2397 { 2398 ptr = lightFloats + k*3; 2399 color[0] = ptr[0]; 2400 color[1] = ptr[1]; 2401 color[2] = ptr[2]; 2402 } 2403 else 2404 { 2405 ptr = lightFloats + k*3; 2406 ptr[0] = color[0]; 2407 ptr[1] = color[1]; 2408 ptr[2] = color[2]; 2409 filled[index >> 3] |= 1 << (index & 7); 2410 } 2411 } 2412 else 2413 { 2414 if (filled[index >> 3] & (1 << (index & 7))) 2415 { 2416 ptr = lightFloats + k*3; 2417 color[0] = ptr[0]; 2418 color[1] = ptr[1]; 2419 color[2] = ptr[2]; 2420 foundvalue = qtrue; 2421 } 2422 } 2423 } 2424 } 2425 for (x = 0; x < width; x++) 2426 { 2427 foundvalue = qfalse; 2428 for (y = 0; y < height; y++) 2429 { 2430 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2431 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2432 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x; 2433 if (foundvalue) 2434 { 2435 if (filled[index >> 3] & (1 << (index & 7))) 2436 { 2437 ptr = lightFloats + k*3; 2438 color[0] = ptr[0]; 2439 color[1] = ptr[1]; 2440 color[2] = ptr[2]; 2441 } 2442 else 2443 { 2444 ptr = lightFloats + k*3; 2445 ptr[0] = color[0]; 2446 ptr[1] = color[1]; 2447 ptr[2] = color[2]; 2448 filled[index >> 3] |= 1 << (index & 7); 2449 } 2450 } 2451 else 2452 { 2453 if (filled[index >> 3] & (1 << (index & 7))) 2454 { 2455 ptr = lightFloats + k*3; 2456 color[0] = ptr[0]; 2457 color[1] = ptr[1]; 2458 color[2] = ptr[2]; 2459 foundvalue = qtrue; 2460 } 2461 } 2462 } 2463 foundvalue = qfalse; 2464 for (y = height-1; y >= 0; y--) 2465 { 2466 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2467 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2468 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x; 2469 if (foundvalue) 2470 { 2471 if (filled[index >> 3] & (1 << (index & 7))) 2472 { 2473 ptr = lightFloats + k*3; 2474 color[0] = ptr[0]; 2475 color[1] = ptr[1]; 2476 color[2] = ptr[2]; 2477 } 2478 else 2479 { 2480 ptr = lightFloats + k*3; 2481 ptr[0] = color[0]; 2482 ptr[1] = color[1]; 2483 ptr[2] = color[2]; 2484 filled[index >> 3] |= 1 << (index & 7); 2485 } 2486 } 2487 else 2488 { 2489 if (filled[index >> 3] & (1 << (index & 7))) 2490 { 2491 ptr = lightFloats + k*3; 2492 color[0] = ptr[0]; 2493 color[1] = ptr[1]; 2494 color[2] = ptr[2]; 2495 foundvalue = qtrue; 2496 } 2497 } 2498 } 2499 } 2500 if (ds->surfaceType == MST_PATCH) 2501 { 2502 x = ds->lightmapWidth-1; 2503 for (y = 0; y < ds->lightmapHeight; y++) 2504 { 2505 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2506 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2507 ptr = lightFloats + k*3; 2508 ptr[0] = (lightFloats + (k-1)*3)[0]; 2509 ptr[1] = (lightFloats + (k-1)*3)[1]; 2510 ptr[2] = (lightFloats + (k-1)*3)[2]; 2511 } 2512 y = ds->lightmapHeight-1; 2513 for (x = 0; x < ds->lightmapWidth; x++) 2514 { 2515 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2516 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2517 ptr = lightFloats + k*3; 2518 ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0]; 2519 ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1]; 2520 ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2]; 2521 } 2522 } 2523 /* 2524 //colored debug edges 2525 if (ds->surfaceType == MST_PATCH) 2526 { 2527 x = ds->lightmapWidth-1; 2528 for (y = 0; y < ds->lightmapHeight; y++) 2529 { 2530 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2531 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2532 ptr = lightFloats + k*3; 2533 ptr[0] = 255; 2534 ptr[1] = 0; 2535 ptr[2] = 0; 2536 } 2537 y = ds->lightmapHeight-1; 2538 for (x = 0; x < ds->lightmapWidth; x++) 2539 { 2540 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2541 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2542 ptr = lightFloats + k*3; 2543 ptr[0] = 0; 2544 ptr[1] = 255; 2545 ptr[2] = 0; 2546 } 2547 } 2548 //*/ 2549 } 2550 // 2551 VL_SmoothenLightmapEdges(); 2552 } 2553 2554 /* 2555 ============= 2556 VL_ShiftPatchLightmaps 2557 ============= 2558 */ 2559 void VL_ShiftPatchLightmaps(void) 2560 { 2561 int i, j, x, y, k; 2562 drawVert_t *verts; 2563 dsurface_t *ds; 2564 lsurfaceTest_t *test; 2565 float *ptr; 2566 2567 for ( i = 0 ; i < numDrawSurfaces ; i++ ) 2568 { 2569 test = lsurfaceTest[ i ]; 2570 if (!test) 2571 continue; 2572 ds = &drawSurfaces[ i ]; 2573 2574 if ( ds->lightmapNum < 0 ) 2575 continue; 2576 if (ds->surfaceType != MST_PATCH) 2577 continue; 2578 for (x = ds->lightmapWidth; x > 0; x--) 2579 { 2580 for (y = 0; y <= ds->lightmapHeight; y++) 2581 { 2582 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2583 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2584 ptr = lightFloats + k*3; 2585 ptr[0] = (lightFloats + (k-1)*3)[0]; 2586 ptr[1] = (lightFloats + (k-1)*3)[1]; 2587 ptr[2] = (lightFloats + (k-1)*3)[2]; 2588 } 2589 } 2590 for (y = ds->lightmapHeight; y > 0; y--) 2591 { 2592 for (x = 0; x <= ds->lightmapWidth; x++) 2593 { 2594 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2595 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2596 ptr = lightFloats + k*3; 2597 ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0]; 2598 ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1]; 2599 ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2]; 2600 } 2601 } 2602 verts = &drawVerts[ ds->firstVert ]; 2603 for ( j = 0 ; j < ds->patchHeight * ds->patchWidth; j++ ) 2604 { 2605 verts[j].lightmap[0] += 0.5 / LIGHTMAP_WIDTH; 2606 verts[j].lightmap[1] += 0.5 / LIGHTMAP_HEIGHT; 2607 } 2608 ds->lightmapHeight++; 2609 ds->lightmapWidth++; 2610 } 2611 } 2612 2613 /* 2614 ============= 2615 VL_StoreLightmap 2616 ============= 2617 */ 2618 void VL_StoreLightmap(void) 2619 { 2620 int i, x, y, k; 2621 dsurface_t *ds; 2622 lsurfaceTest_t *test; 2623 float *src; 2624 byte *dst; 2625 2626 _printf("storing lightmaps...\n"); 2627 //fix lightmap edges before storing them 2628 VL_FixLightmapEdges(); 2629 // 2630 #ifdef LIGHTMAP_PATCHSHIFT 2631 VL_ShiftPatchLightmaps(); 2632 #endif 2633 // 2634 for ( i = 0 ; i < numDrawSurfaces ; i++ ) 2635 { 2636 test = lsurfaceTest[ i ]; 2637 if (!test) 2638 continue; 2639 ds = &drawSurfaces[ i ]; 2640 2641 if ( ds->lightmapNum < 0 ) 2642 continue; 2643 2644 for (y = 0; y < ds->lightmapHeight; y++) 2645 { 2646 for (x = 0; x < ds->lightmapWidth; x++) 2647 { 2648 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 2649 * LIGHTMAP_WIDTH + ds->lightmapX + x; 2650 VectorAdd((lightFloats + k*3), lightAmbientColor, (lightFloats + k*3)); 2651 src = &lightFloats[k*3]; 2652 dst = lightBytes + k*3; 2653 ColorToBytes(src, dst); 2654 } 2655 } 2656 } 2657 } 2658 2659 /* 2660 ============= 2661 PointInLeafnum 2662 ============= 2663 */ 2664 int PointInLeafnum(vec3_t point) 2665 { 2666 int nodenum; 2667 vec_t dist; 2668 dnode_t *node; 2669 dplane_t *plane; 2670 2671 nodenum = 0; 2672 while (nodenum >= 0) 2673 { 2674 node = &dnodes[nodenum]; 2675 plane = &dplanes[node->planeNum]; 2676 dist = DotProduct (point, plane->normal) - plane->dist; 2677 if (dist > 0) 2678 nodenum = node->children[0]; 2679 else 2680 nodenum = node->children[1]; 2681 } 2682 2683 return -nodenum - 1; 2684 } 2685 2686 /* 2687 ============= 2688 VL_PointInLeafnum_r 2689 ============= 2690 */ 2691 int VL_PointInLeafnum_r(vec3_t point, int nodenum) 2692 { 2693 int leafnum; 2694 vec_t dist; 2695 dnode_t *node; 2696 dplane_t *plane; 2697 2698 while (nodenum >= 0) 2699 { 2700 node = &dnodes[nodenum]; 2701 plane = &dplanes[node->planeNum]; 2702 dist = DotProduct (point, plane->normal) - plane->dist; 2703 if (dist > 0.1) 2704 { 2705 nodenum = node->children[0]; 2706 } 2707 else if (dist < -0.1) 2708 { 2709 nodenum = node->children[1]; 2710 } 2711 else 2712 { 2713 leafnum = VL_PointInLeafnum_r(point, node->children[0]); 2714 if (dleafs[leafnum].cluster != -1) 2715 return leafnum; 2716 nodenum = node->children[1]; 2717 } 2718 } 2719 2720 leafnum = -nodenum - 1; 2721 return leafnum; 2722 } 2723 2724 /* 2725 ============= 2726 VL_PointInLeafnum 2727 ============= 2728 */ 2729 int VL_PointInLeafnum(vec3_t point) 2730 { 2731 return VL_PointInLeafnum_r(point, 0); 2732 } 2733 2734 /* 2735 ============= 2736 VL_LightLeafnum 2737 ============= 2738 */ 2739 int VL_LightLeafnum(vec3_t point) 2740 { 2741 /* 2742 int leafnum; 2743 dleaf_t *leaf; 2744 float x, y, z; 2745 vec3_t test; 2746 2747 leafnum = VL_PointInLeafnum(point); 2748 leaf = &dleafs[leafnum]; 2749 if (leaf->cluster != -1) 2750 return leafnum; 2751 for (z = 1; z >= -1; z -= 1) 2752 { 2753 for (x = 1; x >= -1; x -= 1) 2754 { 2755 for (y = 1; y >= -1; y -= 1) 2756 { 2757 VectorCopy(point, test); 2758 test[0] += x; 2759 test[1] += y; 2760 test[2] += z; 2761 leafnum = VL_PointInLeafnum(test); 2762 leaf = &dleafs[leafnum]; 2763 if (leaf->cluster != -1) 2764 { 2765 VectorCopy(test, point); 2766 return leafnum; 2767 } 2768 } 2769 } 2770 } 2771 return leafnum; 2772 */ 2773 return VL_PointInLeafnum(point); 2774 } 2775 2776 //#define LIGHTPOLYS 2777 2778 #ifdef LIGHTPOLYS 2779 2780 winding_t *lightwindings[MAX_MAP_DRAW_SURFS]; 2781 int numlightwindings; 2782 2783 /* 2784 ============= 2785 VL_DrawLightWindings 2786 ============= 2787 */ 2788 void VL_DrawLightWindings(void) 2789 { 2790 int i; 2791 for (i = 0; i < numlightwindings; i++) 2792 { 2793 #ifdef DEBUGNET 2794 DebugNet_DrawWinding(lightwindings[i], 1); 2795 #endif 2796 } 2797 } 2798 2799 /* 2800 ============= 2801 VL_LightSurfaceWithVolume 2802 ============= 2803 */ 2804 void VL_LightSurfaceWithVolume(int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume) 2805 { 2806 winding_t *w; 2807 lsurfaceTest_t *test; 2808 lFacet_t *facet; 2809 int i; 2810 2811 test = lsurfaceTest[ surfaceNum ]; 2812 facet = &test->facets[ facetNum ]; 2813 2814 // 2815 w = (winding_t *) malloc(sizeof(winding_t)); 2816 memcpy(w->points, facet->points, sizeof(vec3_t) * facet->numpoints); 2817 w->numpoints = facet->numpoints; 2818 2819 for (i = 0; i < volume->numplanes; i++) 2820 { 2821 //if totally on the back 2822 if (VL_ChopWinding(w, &volume->planes[i], 0.01) == SIDE_BACK) 2823 return; 2824 } 2825 lightwindings[numlightwindings] = w; 2826 numlightwindings++; 2827 if (numlightwindings >= MAX_MAP_DRAW_SURFS) 2828 Error("MAX_LIGHTWINDINGS"); 2829 } 2830 2831 #else 2832 2833 /* 2834 ============= 2835 VL_LightSurfaceWithVolume 2836 ============= 2837 */ 2838 /* 2839 int VL_PointInsideLightVolume(vec3_t point, lightvolume_t *volume) 2840 { 2841 int i; 2842 float d; 2843 2844 for (i = 0; i < volume->numplanes; i++) 2845 { 2846 d = DotProduct(volume->planes[i].normal, point) - volume->planes[i].dist; 2847 if (d < 0) return qfalse; 2848 } 2849 return qtrue; 2850 } 2851 2852 void VL_LightSurfaceWithVolume( int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume ) 2853 { 2854 dsurface_t *ds; 2855 int i, j, k; 2856 int numPositions; 2857 vec3_t base, normal, color; 2858 int sampleWidth, sampleHeight; 2859 vec3_t lightmapOrigin, lightmapVecs[2], dir; 2860 unsigned char *ptr; 2861 float add, dist, angle; 2862 mesh_t * mesh; 2863 2864 ds = &drawSurfaces[surfaceNum]; 2865 2866 // vertex-lit triangle model 2867 if ( ds->surfaceType == MST_TRIANGLE_SOUP ) { 2868 return; 2869 } 2870 2871 if ( ds->lightmapNum < 0 ) { 2872 return; // doesn't need lighting 2873 } 2874 2875 if ( ds->surfaceType == MST_PATCH ) { 2876 mesh = lsurfaceTest[surfaceNum]->detailMesh; 2877 } else { 2878 VectorCopy( ds->lightmapVecs[2], normal ); 2879 2880 VectorCopy( ds->lightmapOrigin, lightmapOrigin ); 2881 VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] ); 2882 VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] ); 2883 } 2884 2885 sampleWidth = ds->lightmapWidth; 2886 sampleHeight = ds->lightmapHeight; 2887 2888 //calculate lightmap 2889 for ( i = 0 ; i < sampleWidth; i++ ) { 2890 for ( j = 0 ; j < sampleHeight; j++ ) { 2891 2892 if ( ds->patchWidth ) { 2893 numPositions = 9; 2894 VectorCopy( mesh->verts[j*mesh->width+i].normal, normal ); 2895 // VectorNormalize( normal, normal ); 2896 // push off of the curve a bit 2897 VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base ); 2898 2899 // MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] ); 2900 } else { 2901 numPositions = 9; 2902 for ( k = 0 ; k < 3 ; k++ ) { 2903 base[k] = lightmapOrigin[k] + normal[k] 2904 + ((float) i) * lightmapVecs[0][k] 2905 + ((float) j) * lightmapVecs[1][k]; 2906 } 2907 } 2908 VectorAdd( base, surfaceOrigin[ surfaceNum ], base ); 2909 2910 VectorSubtract(base, light->origin, dir); 2911 dist = VectorNormalize(dir, dir); 2912 if ( dist < 16 ) { 2913 dist = 16; 2914 } 2915 angle = 1;//DotProduct( normal, dir ); //1; 2916 if (angle > 1) 2917 angle = 1; 2918 if ( light->atten_disttype == LDAT_LINEAR ) { 2919 add = angle * light->photons * lightLinearScale - dist; 2920 if ( add < 0 ) { 2921 add = 0; 2922 } 2923 } else { 2924 add = light->photons / ( dist * dist ) * angle; 2925 } 2926 if (add <= 1.0) 2927 continue; 2928 2929 if (VL_PointInsideLightVolume(base, volume)) 2930 { 2931 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j) 2932 * LIGHTMAP_WIDTH + ds->lightmapX + i; 2933 ptr = lightBytes + k*3; 2934 color[0] = (float) ptr[0] + add * light->color[0]; 2935 color[1] = (float) ptr[1] + add * light->color[1]; 2936 color[2] = (float) ptr[2] + add * light->color[2]; 2937 ColorToBytes(color, ptr); 2938 } 2939 } 2940 } 2941 } 2942 */ 2943 2944 /* 2945 ============= 2946 VL_GetFilter 2947 2948 FIXME: don't use a lightmap pixel origin but use the four corner points 2949 to map part of a translucent surface onto the lightmap pixel 2950 ============= 2951 */ 2952 void VL_GetFilter(vlight_t *light, lightvolume_t *volume, vec3_t lmp, vec3_t filter) 2953 { 2954 lFacet_t *facet; 2955 lsurfaceTest_t *test; 2956 float d, d1, d2, frac, s, t, ns; 2957 int i, j, is, it, b; 2958 int x, y, u, v, numsamples, radius, color[4], largest; 2959 byte *image; 2960 vec3_t point, origin, total; 2961 2962 VectorSet(filter, 1, 1, 1); 2963 2964 if (noalphashading) 2965 return; 2966 2967 if (volume->numtransFacets <= 0) 2968 return; 2969 2970 if (light->type == LIGHT_SURFACEDIRECTED) 2971 { 2972 // project the light map pixel origin onto the area light source plane 2973 d = DotProduct(lmp, light->normal) - DotProduct(light->normal, light->w.points[0]); 2974 VectorMA(lmp, -d, light->normal, origin); 2975 } 2976 else 2977 { 2978 VectorCopy(light->origin, origin); 2979 } 2980 for (i = 0; i < volume->numtransFacets; i++) 2981 { 2982 test = lsurfaceTest[ volume->transSurfaces[i] ]; 2983 facet = &test->facets[ volume->transFacets[i] ]; 2984 // if this surface does not cast an alpha shadow 2985 if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) ) 2986 continue; 2987 // if there are no texture pixel available 2988 if ( !test->shader->pixels ) { 2989 continue; 2990 } 2991 // 2992 d1 = DotProduct( origin, facet->plane.normal) - facet->plane.dist; 2993 d2 = DotProduct( lmp, facet->plane.normal ) - facet->plane.dist; 2994 // this should never happen because the light volume went through the facet 2995 if ( ( d1 < 0 ) == ( d2 < 0 ) ) { 2996 continue; 2997 } 2998 // calculate the crossing point 2999 frac = d1 / ( d1 - d2 ); 3000 3001 for ( j = 0 ; j < 3 ; j++ ) { 3002 point[j] = origin[j] + frac * ( lmp[j] - origin[j] ); 3003 } 3004 3005 s = DotProduct( point, facet->textureMatrix[0] ) + facet->textureMatrix[0][3]; 3006 t = DotProduct( point, facet->textureMatrix[1] ) + facet->textureMatrix[1][3]; 3007 if (s < 0) 3008 s = 0; 3009 if (t < 0) 3010 t = 0; 3011 3012 s = s - floor( s ); 3013 t = t - floor( t ); 3014 3015 is = s * test->shader->width; 3016 it = t * test->shader->height; 3017 3018 //if old style alpha shading 3019 if (nocolorshading) { 3020 image = test->shader->pixels + 4 * ( it * test->shader->width + is ); 3021 3022 // alpha filter 3023 b = image[3]; 3024 3025 // alpha test makes this a binary option 3026 b = b < 128 ? 0 : 255; 3027 3028 filter[0] = filter[0] * (255-b) / 255; 3029 filter[1] = filter[1] * (255-b) / 255; 3030 filter[2] = filter[2] * (255-b) / 255; 3031 } 3032 else { 3033 VectorClear(total); 3034 numsamples = 0; 3035 radius = 2; 3036 for ( u = -radius; u <= radius; u++ ) 3037 { 3038 x = is + u; 3039 if ( x < 0 || x >= test->shader->width) 3040 continue; 3041 for ( v = -radius; v <= radius; v++ ) 3042 { 3043 y = it + v; 3044 if ( y < 0 || y >= test->shader->height) 3045 continue; 3046 3047 image = test->shader->pixels + 4 * ( y * test->shader->width + x ); 3048 color[0] = image[0]; 3049 color[1] = image[1]; 3050 color[2] = image[2]; 3051 largest = 0; 3052 for (j = 0; j < 3; j++) 3053 if (image[j] > largest) 3054 largest = image[j]; 3055 if (largest <= 0 || image[3] == 0) { 3056 color[0] = 255; 3057 color[1] = 255; 3058 color[2] = 255; 3059 largest = 255; 3060 } 3061 total[0] += ((float) color[0]/largest) * (255-image[3]) / 255.0; 3062 total[1] += ((float) color[1]/largest) * (255-image[3]) / 255.0; 3063 total[2] += ((float) color[2]/largest) * (255-image[3]) / 255.0; 3064 numsamples++; 3065 } 3066 } 3067 ns = numsamples; 3068 // 3069 filter[0] *= total[0] / ns; 3070 filter[1] *= total[1] / ns; 3071 filter[2] *= total[2] / ns; 3072 } 3073 } 3074 } 3075 3076 /* 3077 ============= 3078 VL_LightSurfaceWithVolume 3079 ============= 3080 */ 3081 void VL_LightSurfaceWithVolume( int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume ) 3082 { 3083 int i; 3084 dsurface_t *ds; 3085 lFacet_t *facet; 3086 lsurfaceTest_t *test; 3087 winding_t w; 3088 vec3_t base, dir, delta, normal, filter, origin; 3089 int min_x[LIGHTMAP_SIZE+2], max_x[LIGHTMAP_SIZE+2]; 3090 int min_y, max_y, k, x, y, n; 3091 float *color, distscale; 3092 float d, add, angle, dist, area, insidearea, coords[MAX_POINTS_ON_WINDING+1][2]; 3093 mesh_t *mesh; 3094 byte polygonedges[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8]; 3095 3096 3097 ds = &drawSurfaces[surfaceNum]; 3098 3099 // vertex-lit triangle model 3100 if ( ds->surfaceType == MST_TRIANGLE_SOUP ) { 3101 return; 3102 } 3103 3104 if ( ds->lightmapNum < 0 ) { 3105 return; // doesn't need lighting 3106 } 3107 3108 test = lsurfaceTest[ surfaceNum ]; 3109 facet = &test->facets[ facetNum ]; 3110 3111 if (defaulttracelight && !test->always_vlight) 3112 return; 3113 if (test->always_tracelight) 3114 return; 3115 3116 memcpy(w.points, facet->points, sizeof(vec3_t) * facet->numpoints); 3117 w.numpoints = facet->numpoints; 3118 3119 for (i = 0; i < volume->numplanes; i++) 3120 { 3121 //if totally on the back 3122 if (VL_ChopWinding(&w, &volume->planes[i], 0.01) == SIDE_BACK) 3123 return; 3124 } 3125 3126 // only one thread at a time may write to the lightmap of this surface 3127 MutexLock(test->mutex); 3128 3129 test->numvolumes++; 3130 3131 if (ds->surfaceType == MST_PATCH) 3132 { 3133 // FIXME: reduce size and don't mark all as edge 3134 min_y = ds->lightmapY + facet->y; 3135 max_y = ds->lightmapY + facet->y + facet->height - 1; 3136 for (y = min_y; y <= max_y; y++) 3137 { 3138 min_x[y] = ds->lightmapX + facet->x; 3139 max_x[y] = ds->lightmapX + facet->x + facet->width - 1; 3140 for (x = min_x[y]; x <= max_x[y]; x++) 3141 { 3142 n = y * LIGHTMAP_SIZE + x; 3143 polygonedges[n >> 3] |= 1 << (n & 7); 3144 } 3145 } 3146 } 3147 else 3148 { 3149 for (i = 0; i < w.numpoints; i++) 3150 { 3151 float s, t; 3152 3153 if (i >= MAX_POINTS_ON_WINDING) 3154 _printf("coords overflow\n"); 3155 if (ds->surfaceType != MST_PATCH) 3156 { 3157 VectorSubtract(w.points[i], facet->mins, delta); 3158 s = DotProduct( delta, facet->lightmapMatrix[0] ) + ds->lightmapX + 0.5; 3159 t = DotProduct( delta, facet->lightmapMatrix[1] ) + ds->lightmapY + 0.5; 3160 if (s >= LIGHTMAP_SIZE) 3161 s = LIGHTMAP_SIZE - 0.5; 3162 if (s < 0) 3163 s = 0; 3164 if (t >= LIGHTMAP_SIZE) 3165 t = LIGHTMAP_SIZE - 0.5; 3166 if (t < 0) 3167 t = 0; 3168 coords[i][0] = s; 3169 coords[i][1] = t; 3170 } 3171 else 3172 { 3173 s = DotProduct( w.points[i], facet->lightmapMatrix[0] ) + facet->lightmapMatrix[0][3]; 3174 t = DotProduct( w.points[i], facet->lightmapMatrix[1] ) + facet->lightmapMatrix[1][3]; 3175 3176 s = s - floor( s ); 3177 t = t - floor( t ); 3178 3179 coords[i][0] = ds->lightmapX + s * LIGHTMAP_SIZE;// + 0.5; 3180 coords[i][1] = ds->lightmapY + t * LIGHTMAP_SIZE;// + 0.5; 3181 3182 if (coords[i][0] >= LIGHTMAP_SIZE) 3183 coords[i][0] -= LIGHTMAP_SIZE; 3184 if (coords[i][1] >= LIGHTMAP_SIZE) 3185 coords[i][1] -= LIGHTMAP_SIZE; 3186 if (coords[i][0] < ds->lightmapX) 3187 coords[i][0] = ds->lightmapX; 3188 if (coords[i][1] < ds->lightmapY) 3189 coords[i][1] = ds->lightmapY; 3190 } 3191 x = coords[i][0]; 3192 y = coords[i][1]; 3193 if (x < ds->lightmapX || x >= LIGHTMAP_SIZE) 3194 _printf("VL_LightSurfaceWithVolume: x outside lightmap\n"); 3195 if (y < ds->lightmapY || y >= LIGHTMAP_SIZE) 3196 _printf("VL_LightSurfaceWithVolume: y outside lightmap\n"); 3197 } 3198 coords[i][0] = coords[0][0]; 3199 coords[i][1] = coords[0][1]; 3200 3201 // 3202 min_y = LIGHTMAP_SIZE; 3203 max_y = 0; 3204 for (i = 0; i < LIGHTMAP_SIZE; i++) 3205 { 3206 min_x[i] = LIGHTMAP_SIZE; 3207 max_x[i] = 0; 3208 } 3209 memset(polygonedges, 0, sizeof(polygonedges)); 3210 // scan convert the polygon onto the lightmap 3211 // for each edge it marks *every* lightmap pixel the edge goes through 3212 // so no brasenham and no scan conversion used for texture mapping but 3213 // more something like ray casting 3214 // this is necesary because we need all lightmap pixels totally or partly 3215 // inside the light volume. these lightmap pixels are only lit for the part 3216 // that they are inside the light volume. 3217 for (i = 0; i < w.numpoints; i++) 3218 { 3219 float xf, yf, dx, dy, xstep, ystep, xfrac, yfrac; 3220 int xinc, yinc; 3221 3222 xf = coords[i][0]; 3223 yf = coords[i][1]; 3224 dx = coords[i+1][0] - xf; 3225 dy = coords[i+1][1] - yf; 3226 // 3227 x = (int) xf; 3228 y = (int) yf; 3229 // 3230 if (y < min_y) 3231 min_y = y; 3232 if (y > max_y) 3233 max_y = y; 3234 // 3235 if (fabs(dx) > fabs(dy)) 3236 { 3237 if (dx > 0) 3238 { 3239 // y fraction at integer x below fractional x 3240 yfrac = yf + (floor(xf) - xf) * dy / dx; 3241 xinc = 1; 3242 } 3243 else if (dx < 0) 3244 { 3245 // y fraction at integer x above fractional x 3246 yfrac = yf + (floor(xf) + 1 - xf) * dy / dx; 3247 xinc = -1; 3248 } 3249 else 3250 { 3251 yfrac = yf; 3252 xinc = 0; 3253 } 3254 // step in y direction per 1 unit in x direction 3255 if (dx) 3256 ystep = dy / fabs(dx); 3257 else 3258 ystep = 0; 3259 while(1) 3260 { 3261 if (x < ds->lightmapX || x >= LIGHTMAP_SIZE) 3262 _printf("VL_LightSurfaceWithVolume: x outside lightmap\n"); 3263 if (y < ds->lightmapY || y >= LIGHTMAP_SIZE) 3264 _printf("VL_LightSurfaceWithVolume: y outside lightmap\n"); 3265 // 3266 n = y * LIGHTMAP_SIZE + x; 3267 polygonedges[n >> 3] |= 1 << (n & 7); 3268 if (x < min_x[y]) 3269 min_x[y] = x; 3270 if (x > max_x[y]) 3271 max_x[y] = x; 3272 if (x == (int) coords[i+1][0]) 3273 break; 3274 yfrac += ystep; 3275 if (dy > 0) 3276 { 3277 if (yfrac > (float) y + 1) 3278 { 3279 y += 1; 3280 // 3281 n = y * LIGHTMAP_SIZE + x; 3282 polygonedges[n >> 3] |= 1 << (n & 7); 3283 if (x < min_x[y]) 3284 min_x[y] = x; 3285 if (x > max_x[y]) 3286 max_x[y] = x; 3287 } 3288 } 3289 else 3290 { 3291 if (yfrac < (float) y) 3292 { 3293 y -= 1; 3294 // 3295 n = y * LIGHTMAP_SIZE + x; 3296 polygonedges[n >> 3] |= 1 << (n & 7); 3297 if (x < min_x[y]) 3298 min_x[y] = x; 3299 if (x > max_x[y]) 3300 max_x[y] = x; 3301 } 3302 } 3303 x += xinc; 3304 } 3305 } 3306 else 3307 { 3308 if (dy > 0) 3309 { 3310 //x fraction at integer y below fractional y 3311 xfrac = xf + (floor(yf) - yf) * dx / dy; 3312 yinc = 1; 3313 } 3314 else if (dy < 0) 3315 { 3316 //x fraction at integer y above fractional y 3317 xfrac = xf + (floor(yf) + 1 - yf) * dx / dy; 3318 yinc = -1; 3319 } 3320 else 3321 { 3322 xfrac = xf; 3323 yinc = 0; 3324 } 3325 // step in x direction per 1 unit in y direction 3326 if (dy) 3327 xstep = dx / fabs(dy); 3328 else 3329 xstep = 0; 3330 while(1) 3331 { 3332 if (x < ds->lightmapX || x >= LIGHTMAP_SIZE) 3333 _printf("VL_LightSurfaceWithVolume: x outside lightmap\n"); 3334 if (y < ds->lightmapY || y >= LIGHTMAP_SIZE) 3335 _printf("VL_LightSurfaceWithVolume: y outside lightmap\n"); 3336 // 3337 n = y * LIGHTMAP_SIZE + x; 3338 polygonedges[n >> 3] |= 1 << (n & 7); 3339 if (x < min_x[y]) 3340 min_x[y] = x; 3341 if (x > max_x[y]) 3342 max_x[y] = x; 3343 if (y == (int) coords[i+1][1]) 3344 break; 3345 xfrac += xstep; 3346 if (dx > 0) 3347 { 3348 if (xfrac > (float) x + 1) 3349 { 3350 x += 1; 3351 // 3352 n = y * LIGHTMAP_SIZE + x; 3353 polygonedges[n >> 3] |= 1 << (n & 7); 3354 if (x < min_x[y]) 3355 min_x[y] = x; 3356 if (x > max_x[y]) 3357 max_x[y] = x; 3358 } 3359 } 3360 else 3361 { 3362 if (xfrac < (float) x) 3363 { 3364 x -= 1; 3365 // 3366 n = y * LIGHTMAP_SIZE + x; 3367 polygonedges[n >> 3] |= 1 << (n & 7); 3368 if (x < min_x[y]) 3369 min_x[y] = x; 3370 if (x > max_x[y]) 3371 max_x[y] = x; 3372 } 3373 } 3374 y += yinc; 3375 } 3376 } 3377 } 3378 } 3379 // map light onto the lightmap 3380 for (y = min_y; y <= max_y; y++) 3381 { 3382 for (x = min_x[y]; x <= max_x[y]; x++) 3383 { 3384 if (ds->surfaceType == MST_PATCH) 3385 { 3386 mesh = test->detailMesh; 3387 VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, base); 3388 VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].normal, normal); 3389 //VectorCopy(facet->plane.normal, normal); 3390 } 3391 else 3392 { 3393 VectorMA(ds->lightmapOrigin, (float) x - ds->lightmapX, ds->lightmapVecs[0], base); 3394 VectorMA(base, (float) y - ds->lightmapY, ds->lightmapVecs[1], base); 3395 VectorCopy(facet->plane.normal, normal); 3396 } 3397 if (light->type == LIGHT_POINTSPOT) 3398 { 3399 float distByNormal; 3400 vec3_t pointAtDist; 3401 float radiusAtDist; 3402 float sampleRadius; 3403 vec3_t distToSample; 3404 float coneScale; 3405 3406 VectorSubtract( light->origin, base, dir ); 3407 3408 distByNormal = -DotProduct( dir, light->normal ); 3409 if ( distByNormal < 0 ) { 3410 continue; 3411 } 3412 VectorMA( light->origin, distByNormal, light->normal, pointAtDist ); 3413 radiusAtDist = light->radiusByDist * distByNormal; 3414 3415 VectorSubtract( base, pointAtDist, distToSample ); 3416 sampleRadius = VectorLength( distToSample ); 3417 3418 if ( sampleRadius >= radiusAtDist ) { 3419 continue; // outside the cone 3420 } 3421 if ( sampleRadius <= radiusAtDist - 32 ) { 3422 coneScale = 1.0; // fully inside 3423 } else { 3424 coneScale = ( radiusAtDist - sampleRadius ) / 32.0; 3425 } 3426 3427 dist = VectorNormalize( dir, dir ); 3428 // clamp the distance to prevent super hot spots 3429 if ( dist < 16 ) { 3430 dist = 16; 3431 } 3432 angle = DotProduct( normal, dir ); 3433 if (angle > 1) 3434 angle = 1; 3435 if (angle > 0) { 3436 if ( light->atten_angletype == LAAT_QUADRATIC ) { 3437 angle = 1 - angle; 3438 angle *= angle; 3439 angle = 1 - angle; 3440 } 3441 else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) { 3442 angle = 1 - angle; 3443 angle *= angle * angle; 3444 angle = 1 - angle; 3445 } 3446 } 3447 if (light->atten_anglescale > 0) { 3448 angle /= light->atten_anglescale; 3449 if (angle > 1) 3450 angle = 1; 3451 } 3452 if (light->atten_distscale > 0) { 3453 distscale = light->atten_distscale; 3454 } 3455 else { 3456 distscale = 1; 3457 } 3458 // 3459 if ( light->atten_disttype == LDAT_NOSCALE ) { 3460 add = angle * coneScale; 3461 } 3462 else if ( light->atten_disttype == LDAT_LINEAR ) { 3463 add = angle * light->photons * lightLinearScale * coneScale - dist * distscale; 3464 if ( add < 0 ) { 3465 add = 0; 3466 } 3467 } 3468 else { 3469 add = light->photons / ( dist * dist * distscale) * angle * coneScale; 3470 } 3471 if (add <= 1.0) 3472 continue; 3473 } 3474 else if (light->type == LIGHT_POINTFAKESURFACE) 3475 { 3476 // calculate the contribution 3477 add = PointToPolygonFormFactor( base, normal, &light->w ); 3478 if ( add <= 0 ) { 3479 if ( light->twosided ) { 3480 add = -add; 3481 } else { 3482 continue; 3483 } 3484 } 3485 } 3486 else if (light->type == LIGHT_SURFACEDIRECTED) 3487 { 3488 //VectorCopy(light->normal, dir); 3489 //VectorInverse(dir); 3490 // project the light map pixel origin onto the area light source plane 3491 d = DotProduct(base, light->normal) - DotProduct(light->normal, light->w.points[0]); 3492 VectorMA(base, -d, light->normal, origin); 3493 VectorSubtract(origin, base, dir); 3494 dist = VectorNormalize(dir, dir); 3495 if ( dist < 16 ) { 3496 dist = 16; 3497 } 3498 // 3499 angle = DotProduct( normal, dir ); 3500 if (angle > 1) 3501 angle = 1; 3502 if (angle > 0) { 3503 if ( light->atten_angletype == LAAT_QUADRATIC ) { 3504 angle = 1 - angle; 3505 angle *= angle; 3506 angle = 1 - angle; 3507 } 3508 else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) { 3509 angle = 1 - angle; 3510 angle *= angle * angle; 3511 angle = 1 - angle; 3512 } 3513 } 3514 if (light->atten_anglescale > 0) { 3515 angle /= light->atten_anglescale; 3516 if (angle > 1) 3517 angle = 1; 3518 } 3519 if (light->atten_distscale > 0) { 3520 distscale = light->atten_distscale; 3521 } 3522 else { 3523 distscale = 1; 3524 } 3525 if ( light->atten_disttype == LDAT_NOSCALE ) { 3526 add = angle; 3527 } 3528 else if ( light->atten_disttype == LDAT_LINEAR ) { 3529 add = angle * light->photons * lightLinearScale - dist * distscale; 3530 if ( add < 0 ) { 3531 add = 0; 3532 } 3533 } else { //default quadratic 3534 add = light->photons / ( dist * dist * distscale) * angle; 3535 } 3536 if (add <= 0) 3537 continue; 3538 } 3539 else //normal radial point light 3540 { 3541 VectorSubtract(light->origin, base, dir); 3542 dist = VectorNormalize(dir, dir); 3543 if ( dist < 16 ) { 3544 dist = 16; 3545 } 3546 angle = DotProduct( normal, dir ); 3547 if (angle > 1) 3548 angle = 1; 3549 if (angle > 0) { 3550 if ( light->atten_angletype == LAAT_QUADRATIC ) { 3551 angle = 1 - angle; 3552 angle *= angle; 3553 angle = 1 - angle; 3554 } 3555 else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) { 3556 angle = 1 - angle; 3557 angle *= angle * angle; 3558 angle = 1 - angle; 3559 } 3560 } 3561 if (light->atten_anglescale > 0) { 3562 angle /= light->atten_anglescale; 3563 if (angle > 1) 3564 angle = 1; 3565 } 3566 if (light->atten_distscale > 0) { 3567 distscale = light->atten_distscale; 3568 } 3569 else { 3570 distscale = 1; 3571 } 3572 if ( light->atten_disttype == LDAT_NOSCALE ) { 3573 add = angle; 3574 } 3575 else if ( light->atten_disttype == LDAT_LINEAR ) { 3576 add = angle * light->photons * lightLinearScale - dist * distscale; 3577 if ( add < 0 ) { 3578 add = 0; 3579 } 3580 } else { 3581 add = light->photons / ( dist * dist * distscale) * angle; 3582 } 3583 if (add <= 1.0) 3584 continue; 3585 } 3586 // 3587 k = (ds->lightmapNum * LIGHTMAP_HEIGHT + y) * LIGHTMAP_WIDTH + x; 3588 //if on one of the edges 3589 n = y * LIGHTMAP_SIZE + x; 3590 if ((polygonedges[n >> 3] & (1 << (n & 7)) )) 3591 { 3592 // multiply 'add' by the relative area being lit of the total visible lightmap pixel area 3593 // 3594 // first create a winding for the lightmap pixel 3595 if (ds->surfaceType == MST_PATCH) 3596 { 3597 mesh = test->detailMesh; 3598 if (y-ds->lightmapY >= mesh->height-1) 3599 _printf("y outside mesh\n"); 3600 if (x-ds->lightmapX >= mesh->width-1) 3601 _printf("x outside mesh\n"); 3602 VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]); 3603 VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]); 3604 VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]); 3605 VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]); 3606 w.numpoints = 4; 3607 } 3608 else 3609 { 3610 VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]); 3611 VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]); 3612 VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]); 3613 VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]); 3614 VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]); 3615 VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]); 3616 VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]); 3617 VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]); 3618 w.numpoints = 4; 3619 } 3620 // 3621 // take the visible area of the lightmap pixel into account 3622 // 3623 //area = WindingArea(&w); 3624 area = lightmappixelarea[k]; 3625 if (area <= 0) 3626 continue; 3627 // chop the lightmap pixel winding with the light volume 3628 for (i = 0; i < volume->numplanes; i++) 3629 { 3630 //if totally on the back 3631 if (VL_ChopWinding(&w, &volume->planes[i], 0) == SIDE_BACK) 3632 break; 3633 } 3634 // if the lightmap pixel is partly inside the light volume 3635 if (i >= volume->numplanes) 3636 { 3637 insidearea = WindingArea(&w); 3638 if (insidearea <= 0) 3639 i = 0; 3640 add = add * insidearea / area; 3641 } 3642 else 3643 { 3644 //DebugNet_DrawWinding(&w, 2); 3645 continue; // this shouldn't happen 3646 } 3647 } 3648 // get the light filter from all the translucent surfaces the light volume went through 3649 VL_GetFilter(light, volume, base, filter); 3650 // 3651 color = &lightFloats[k*3]; 3652 color[0] += add * light->color[0] * filter[0]; 3653 color[1] += add * light->color[1] * filter[1]; 3654 color[2] += add * light->color[2] * filter[2]; 3655 } 3656 } 3657 3658 MutexUnlock(test->mutex); 3659 } 3660 3661 #endif 3662 3663 /* 3664 ============= 3665 VL_SplitLightVolume 3666 ============= 3667 */ 3668 int VL_SplitLightVolume(lightvolume_t *volume, lightvolume_t *back, plane_t *split, float epsilon) 3669 { 3670 lightvolume_t f, b; 3671 vec_t dists[128]; 3672 int sides[128]; 3673 int counts[3]; 3674 vec_t dot; 3675 int i, j; 3676 vec_t *p1, *p2; 3677 vec3_t mid; 3678 3679 counts[0] = counts[1] = counts[2] = 0; 3680 3681 // determine sides for each point 3682 for (i = 0; i < volume->numplanes; i++) 3683 { 3684 dot = DotProduct (volume->points[i], split->normal); 3685 dot -= split->dist; 3686 dists[i] = dot; 3687 if (dot > epsilon) 3688 sides[i] = SIDE_FRONT; 3689 else if (dot < -epsilon) 3690 sides[i] = SIDE_BACK; 3691 else 3692 { 3693 sides[i] = SIDE_ON; 3694 } 3695 counts[sides[i]]++; 3696 } 3697 3698 if (!counts[1]) 3699 return 0; // completely on front side 3700 3701 if (!counts[0]) 3702 return 1; // completely on back side 3703 3704 sides[i] = sides[0]; 3705 dists[i] = dists[0]; 3706 3707 f.numplanes = 0; 3708 b.numplanes = 0; 3709 3710 for (i = 0; i < volume->numplanes; i++) 3711 { 3712 p1 = volume->points[i]; 3713 3714 if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING) 3715 { 3716 _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n"); 3717 return 0; // can't chop -- fall back to original 3718 } 3719 if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING) 3720 { 3721 _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n"); 3722 return 0; // can't chop -- fall back to original 3723 } 3724 3725 if (sides[i] == SIDE_ON) 3726 { 3727 VectorCopy(p1, f.points[f.numplanes]); 3728 VectorCopy(p1, b.points[b.numplanes]); 3729 if (sides[i+1] == SIDE_BACK) 3730 { 3731 f.planes[f.numplanes] = *split; 3732 b.planes[b.numplanes] = volume->planes[i]; 3733 } 3734 else if (sides[i+1] == SIDE_FRONT) 3735 { 3736 f.planes[f.numplanes] = volume->planes[i]; 3737 b.planes[b.numplanes] = *split; 3738 VectorInverse(b.planes[b.numplanes].normal); 3739 b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist; 3740 } 3741 else //this shouldn't happen 3742 { 3743 f.planes[f.numplanes] = *split; 3744 b.planes[b.numplanes] = *split; 3745 VectorInverse(b.planes[b.numplanes].normal); 3746 b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist; 3747 } 3748 f.numplanes++; 3749 b.numplanes++; 3750 continue; 3751 } 3752 3753 if (sides[i] == SIDE_FRONT) 3754 { 3755 VectorCopy (p1, f.points[f.numplanes]); 3756 f.planes[f.numplanes] = volume->planes[i]; 3757 f.numplanes++; 3758 } 3759 if (sides[i] == SIDE_BACK) 3760 { 3761 VectorCopy (p1, b.points[b.numplanes]); 3762 b.planes[b.numplanes] = volume->planes[i]; 3763 b.numplanes++; 3764 } 3765 3766 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) 3767 continue; 3768 3769 if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING) 3770 { 3771 _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n"); 3772 return 0; // can't chop -- fall back to original 3773 } 3774 if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING) 3775 { 3776 _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n"); 3777 return 0; // can't chop -- fall back to original 3778 } 3779 3780 // generate a split point 3781 p2 = volume->points[(i+1)%volume->numplanes]; 3782 3783 dot = dists[i] / (dists[i]-dists[i+1]); 3784 for (j=0 ; j<3 ; j++) 3785 { // avoid round off error when possible 3786 if (split->normal[j] == 1) 3787 mid[j] = split->dist; 3788 else if (split->normal[j] == -1) 3789 mid[j] = -split->dist; 3790 else 3791 mid[j] = p1[j] + dot*(p2[j]-p1[j]); 3792 } 3793 3794 VectorCopy (mid, f.points[f.numplanes]); 3795 VectorCopy(mid, b.points[b.numplanes]); 3796 if (sides[i+1] == SIDE_BACK) 3797 { 3798 f.planes[f.numplanes] = *split; 3799 b.planes[b.numplanes] = volume->planes[i]; 3800 } 3801 else 3802 { 3803 f.planes[f.numplanes] = volume->planes[i]; 3804 b.planes[b.numplanes] = *split; 3805 VectorInverse(b.planes[b.numplanes].normal); 3806 b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist; 3807 } 3808 f.numplanes++; 3809 b.numplanes++; 3810 } 3811 memcpy(volume->points, f.points, sizeof(vec3_t) * f.numplanes); 3812 memcpy(volume->planes, f.planes, sizeof(plane_t) * f.numplanes); 3813 volume->numplanes = f.numplanes; 3814 memcpy(back->points, b.points, sizeof(vec3_t) * b.numplanes); 3815 memcpy(back->planes, b.planes, sizeof(plane_t) * b.numplanes); 3816 back->numplanes = b.numplanes; 3817 3818 return 2; 3819 } 3820 3821 /* 3822 ============= 3823 VL_PlaneForEdgeToWinding 3824 ============= 3825 */ 3826 void VL_PlaneForEdgeToWinding(vec3_t p1, vec3_t p2, winding_t *w, int windingonfront, plane_t *plane) 3827 { 3828 int i, j; 3829 float length, d; 3830 vec3_t v1, v2; 3831 3832 VectorSubtract(p2, p1, v1); 3833 for (i = 0; i < w->numpoints; i++) 3834 { 3835 VectorSubtract (w->points[i], p1, v2); 3836 3837 plane->normal[0] = v1[1]*v2[2] - v1[2]*v2[1]; 3838 plane->normal[1] = v1[2]*v2[0] - v1[0]*v2[2]; 3839 plane->normal[2] = v1[0]*v2[1] - v1[1]*v2[0]; 3840 3841 // if points don't make a valid plane, skip it 3842 length = plane->normal[0] * plane->normal[0] 3843 + plane->normal[1] * plane->normal[1] 3844 + plane->normal[2] * plane->normal[2]; 3845 3846 if (length < ON_EPSILON) 3847 continue; 3848 3849 length = 1/sqrt(length); 3850 3851 plane->normal[0] *= length; 3852 plane->normal[1] *= length; 3853 plane->normal[2] *= length; 3854 3855 plane->dist = DotProduct (w->points[i], plane->normal); 3856 // 3857 for (j = 0; j < w->numpoints; j++) 3858 { 3859 if (j == i) 3860 continue; 3861 d = DotProduct(w->points[j], plane->normal) - plane->dist; 3862 if (windingonfront) 3863 { 3864 if (d < -ON_EPSILON) 3865 break; 3866 } 3867 else 3868 { 3869 if (d > ON_EPSILON) 3870 break; 3871 } 3872 } 3873 if (j >= w->numpoints) 3874 return; 3875 } 3876 } 3877 3878 /* 3879 ============= 3880 VL_R_CastLightAtSurface 3881 ============= 3882 */ 3883 void VL_R_FloodLight(vlight_t *light, lightvolume_t *volume, int cluster, int firstportal); 3884 3885 void VL_R_CastLightAtSurface(vlight_t *light, lightvolume_t *volume) 3886 { 3887 lsurfaceTest_t *test; 3888 int i, n; 3889 3890 // light the surface with this volume 3891 VL_LightSurfaceWithVolume(volume->surfaceNum, volume->facetNum, light, volume); 3892 // 3893 test = lsurfaceTest[ volume->surfaceNum ]; 3894 // if this is not a translucent surface 3895 if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) && !(test->shader->contents & CONTENTS_TRANSLUCENT)) 3896 return; 3897 // 3898 if (volume->numtransFacets >= MAX_TRANSLUCENTFACETS) 3899 Error("a light valume went through more than %d translucent facets", MAX_TRANSLUCENTFACETS); 3900 //add this translucent surface to the list 3901 volume->transSurfaces[volume->numtransFacets] = volume->surfaceNum; 3902 volume->transFacets[volume->numtransFacets] = volume->facetNum; 3903 volume->numtransFacets++; 3904 //clear the tested facets except the translucent ones 3905 memset(volume->facetTested, 0, sizeof(volume->facetTested)); 3906 for (i = 0; i < volume->numtransFacets; i++) 3907 { 3908 test = lsurfaceTest[ volume->transSurfaces[i] ]; 3909 n = test->facets[volume->transFacets[i]].num; 3910 volume->facetTested[n >> 3] |= 1 << (n & 7); 3911 } 3912 memset(volume->clusterTested, 0, sizeof(volume->clusterTested)); 3913 volume->endplane = volume->farplane; 3914 volume->surfaceNum = -1; 3915 volume->facetNum = 0; 3916 VL_R_FloodLight(light, volume, volume->cluster, 0); 3917 if (volume->surfaceNum >= 0) 3918 { 3919 VL_R_CastLightAtSurface(light, volume); 3920 } 3921 } 3922 3923 /* 3924 ============= 3925 VL_R_SplitLightVolume 3926 ============= 3927 */ 3928 int numvolumes = 0; 3929 3930 int VL_R_SplitLightVolume(vlight_t *light, lightvolume_t *volume, plane_t *split, int cluster, int firstportal) 3931 { 3932 lightvolume_t back; 3933 int res; 3934 3935 // 3936 res = VL_SplitLightVolume(volume, &back, split, 0.1); 3937 // if the volume was split 3938 if (res == 2) 3939 { 3940 memcpy(back.clusterTested, volume->clusterTested, sizeof(back.clusterTested)); 3941 memcpy(back.facetTested, volume->facetTested, sizeof(back.facetTested)); 3942 back.num = numvolumes++; 3943 back.endplane = volume->endplane; 3944 back.surfaceNum = volume->surfaceNum; 3945 back.facetNum = volume->facetNum; 3946 back.type = volume->type; 3947 back.cluster = volume->cluster; 3948 back.farplane = volume->farplane; 3949 if (volume->numtransFacets > 0) 3950 { 3951 memcpy(back.transFacets, volume->transFacets, sizeof(back.transFacets)); 3952 memcpy(back.transSurfaces, volume->transSurfaces, sizeof(back.transSurfaces)); 3953 } 3954 back.numtransFacets = volume->numtransFacets; 3955 // 3956 // flood the volume at the back of the split plane 3957 VL_R_FloodLight(light, &back, cluster, firstportal); 3958 // if the back volume hit a surface 3959 if (back.surfaceNum >= 0) 3960 { 3961 VL_R_CastLightAtSurface(light, &back); 3962 } 3963 } 3964 return res; 3965 } 3966 3967 /* 3968 ============= 3969 VL_R_FloodLight 3970 ============= 3971 */ 3972 void VL_R_FloodLight(vlight_t *light, lightvolume_t *volume, int cluster, int firstportal) 3973 { 3974 int i, j, k, res, surfaceNum, backfaceculled, testculled; 3975 float d; 3976 winding_t winding, tmpwinding; 3977 lleaf_t *leaf; 3978 lportal_t *p; 3979 lsurfaceTest_t *test; 3980 lFacet_t *facet; 3981 vec3_t dir1, dir2; 3982 plane_t plane; 3983 3984 // DebugNet_RemoveAllPolys(); 3985 // VL_DrawLightVolume(light, volume); 3986 3987 // if the first portal is not zero then we've checked all occluders in this leaf already 3988 if (firstportal == 0) 3989 { 3990 // check all potential occluders in this leaf 3991 for (i = 0; i < leafs[cluster].numSurfaces; i++) 3992 { 3993 surfaceNum = clustersurfaces[leafs[cluster].firstSurface + i]; 3994 // 3995 test = lsurfaceTest[ surfaceNum ]; 3996 if ( !test ) 3997 continue; 3998 // 3999 testculled = qfalse; 4000 // use surface as an occluder 4001 for (j = 0; j < test->numFacets; j++) 4002 { 4003 // use each facet as an occluder 4004 facet = &test->facets[j]; 4005 // 4006 // memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints); 4007 // winding.numpoints = facet->numpoints; 4008 // DebugNet_DrawWinding(&winding, 5); 4009 // 4010 // if the facet was tested already 4011 if ( volume->facetTested[facet->num >> 3] & (1 << (facet->num & 7)) ) 4012 continue; 4013 volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7); 4014 // backface culling for planar surfaces 4015 backfaceculled = qfalse; 4016 if (!test->patch && !test->trisoup) 4017 { 4018 if (volume->type == VOLUME_NORMAL) 4019 { 4020 // facet backface culling 4021 d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist; 4022 if (d < 0) 4023 { 4024 // NOTE: this doesn't work too great because of sometimes very bad tesselation 4025 // of surfaces that are supposed to be flat 4026 // FIXME: to work around this problem we should make sure that all facets 4027 // created from planar surfaces use the lightmapVecs normal vector 4028 /* 4029 if ( !test->shader->twoSided ) 4030 { 4031 // skip all other facets of this surface as well because they are in the same plane 4032 for (k = 0; k < test->numFacets; k++) 4033 { 4034 facet = &test->facets[k]; 4035 volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7); 4036 } 4037 }*/ 4038 backfaceculled = qtrue; 4039 } 4040 } 4041 else 4042 { 4043 // FIXME: if all light source winding points are at the back of the facet 4044 // plane then backfaceculled = qtrue 4045 } 4046 } 4047 else // backface culling per facet for patches and triangle soups 4048 { 4049 if (volume->type == VOLUME_NORMAL) 4050 { 4051 // facet backface culling 4052 d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist; 4053 if (d < 0) 4054 backfaceculled = qtrue; 4055 } 4056 else 4057 { 4058 // FIXME: if all light source winding points are at the back of the facet 4059 // plane then backfaceculled = qtrue 4060 } 4061 } 4062 /* chopping does this already 4063 // check if this facet is totally or partly in front of the volume end plane 4064 for (k = 0; k < facet->numpoints; k++) 4065 { 4066 d = DotProduct(volume->endplane.normal, facet->points[k]) - volume->endplane.dist; 4067 if (d > ON_EPSILON) 4068 break; 4069 } 4070 // if this facet is outside the light volume 4071 if (k >= facet->numpoints) 4072 continue; 4073 */ 4074 // 4075 if (backfaceculled) 4076 { 4077 // if the facet is not two sided 4078 if ( !nobackfaceculling && !test->shader->twoSided ) 4079 continue; 4080 // flip the winding 4081 for (k = 0; k < facet->numpoints; k++) 4082 VectorCopy(facet->points[k], winding.points[facet->numpoints - k - 1]); 4083 winding.numpoints = facet->numpoints; 4084 } 4085 else 4086 { 4087 memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints); 4088 winding.numpoints = facet->numpoints; 4089 } 4090 // 4091 if (!testculled) 4092 { 4093 testculled = qtrue; 4094 // fast check if the surface sphere is totally behind the volume end plane 4095 d = DotProduct(volume->endplane.normal, test->origin) - volume->endplane.dist; 4096 if (d < -test->radius) 4097 { 4098 for (k = 0; k < test->numFacets; k++) 4099 { 4100 facet = &test->facets[k]; 4101 volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7); 4102 } 4103 break; 4104 } 4105 for (k = 0; k < volume->numplanes; k++) 4106 { 4107 d = DotProduct(volume->planes[k].normal, test->origin) - volume->planes[k].dist; 4108 if (d < - test->radius) 4109 { 4110 for (k = 0; k < test->numFacets; k++) 4111 { 4112 facet = &test->facets[k]; 4113 volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7); 4114 } 4115 break; 4116 } 4117 } 4118 if (k < volume->numplanes) 4119 break; 4120 } 4121 //NOTE: we have to chop the facet winding with the volume end plane because 4122 // the faces in Q3 are not stitched together nicely 4123 res = VL_ChopWinding(&winding, &volume->endplane, 0.01); 4124 // if the facet is on or at the back of the volume end plane 4125 if (res == SIDE_BACK || res == SIDE_ON) 4126 continue; 4127 // check if the facet winding is totally or partly inside the light volume 4128 memcpy(&tmpwinding, &winding, sizeof(winding_t)); 4129 for (k = 0; k < volume->numplanes; k++) 4130 { 4131 res = VL_ChopWinding(&tmpwinding, &volume->planes[k], 0.01); 4132 if (res == SIDE_BACK || res == SIDE_ON) 4133 break; 4134 } 4135 // if no part of the light volume is occluded by this facet 4136 if (k < volume->numplanes) 4137 continue; 4138 // 4139 for (k = 0; k < winding.numpoints; k++) 4140 { 4141 if (volume->type == VOLUME_DIRECTED) 4142 { 4143 VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1); 4144 CrossProduct(light->normal, dir1, plane.normal); 4145 VectorNormalize(plane.normal, plane.normal); 4146 plane.dist = DotProduct(plane.normal, winding.points[k]); 4147 } 4148 else 4149 { 4150 VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1); 4151 VectorSubtract(light->origin, winding.points[k], dir2); 4152 CrossProduct(dir1, dir2, plane.normal); 4153 VectorNormalize(plane.normal, plane.normal); 4154 plane.dist = DotProduct(plane.normal, winding.points[k]); 4155 } 4156 res = VL_R_SplitLightVolume(light, volume, &plane, cluster, 0); 4157 if (res == 1) 4158 break; //the facet wasn't really inside the volume 4159 } 4160 if (k >= winding.numpoints) 4161 { 4162 volume->endplane = facet->plane; 4163 if (backfaceculled) 4164 { 4165 VectorInverse(volume->endplane.normal); 4166 volume->endplane.dist = -volume->endplane.dist; 4167 } 4168 volume->surfaceNum = surfaceNum; 4169 volume->facetNum = j; 4170 } 4171 } 4172 } 4173 } 4174 // we've tested all occluders in this cluster 4175 volume->clusterTested[cluster >> 3] |= 1 << (cluster & 7); 4176 // flood light through the portals of the current leaf 4177 leaf = &leafs[cluster]; 4178 for (i = firstportal; i < leaf->numportals; i++) 4179 { 4180 p = leaf->portals[i]; 4181 // 4182 // memcpy(&winding, p->winding, sizeof(winding_t)); 4183 // DebugNet_DrawWinding(&winding, 5); 4184 // if already flooded into the cluster this portal leads to 4185 if ( volume->clusterTested[p->leaf >> 3] & (1 << (p->leaf & 7)) ) 4186 continue; 4187 // 4188 if (volume->type == VOLUME_NORMAL) 4189 { 4190 // portal backface culling 4191 d = DotProduct(light->origin, p->plane.normal) - p->plane.dist; 4192 if (d > 0) // portal plane normal points into neighbour cluster 4193 continue; 4194 } 4195 else 4196 { 4197 // FIXME: if all light source winding points are at the back of this portal 4198 // plane then there's no need to flood through 4199 } 4200 // check if this portal is totally or partly in front of the volume end plane 4201 // fast check with portal sphere 4202 d = DotProduct(volume->endplane.normal, p->origin) - volume->endplane.dist; 4203 if (d < -p->radius) 4204 continue; 4205 for (j = 0; j < p->winding->numpoints; j++) 4206 { 4207 d = DotProduct(volume->endplane.normal, p->winding->points[j]) - volume->endplane.dist; 4208 if (d > -0.01) 4209 break; 4210 } 4211 // if this portal is totally behind the light volume end plane 4212 if (j >= p->winding->numpoints) 4213 continue; 4214 //distance from point light to portal 4215 d = DotProduct(p->plane.normal, light->origin) - p->plane.dist; 4216 // only check if a point light is Not *on* the portal 4217 if (volume->type != VOLUME_NORMAL || fabs(d) > 0.1) 4218 { 4219 // check if the portal is partly or totally inside the light volume 4220 memcpy(&winding, p->winding, sizeof(winding_t)); 4221 for (j = 0; j < volume->numplanes; j++) 4222 { 4223 res = VL_ChopWinding(&winding, &volume->planes[j], 0.01); 4224 if (res == SIDE_BACK || res == SIDE_ON) 4225 break; 4226 } 4227 // if the light volume does not go through this portal at all 4228 if (j < volume->numplanes) 4229 continue; 4230 } 4231 // chop the light volume with the portal 4232 for (k = 0; k < p->winding->numpoints; k++) 4233 { 4234 if (volume->type == VOLUME_DIRECTED) 4235 { 4236 VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1); 4237 CrossProduct(light->normal, dir1, plane.normal); 4238 VectorNormalize(plane.normal, plane.normal); 4239 plane.dist = DotProduct(plane.normal, p->winding->points[k]); 4240 } 4241 else 4242 { 4243 VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1); 4244 VectorSubtract(light->origin, p->winding->points[k], dir2); 4245 CrossProduct(dir1, dir2, plane.normal); 4246 VectorNormalize(plane.normal, plane.normal); 4247 plane.dist = DotProduct(plane.normal, p->winding->points[k]); 4248 } 4249 res = VL_R_SplitLightVolume(light, volume, &plane, cluster, i+1); 4250 if (res == 1) 4251 break; //volume didn't really go through the portal 4252 } 4253 // if the light volume went through the portal 4254 if (k >= p->winding->numpoints) 4255 { 4256 // flood through the portal 4257 VL_R_FloodLight(light, volume, p->leaf, 0); 4258 } 4259 } 4260 } 4261 4262 /* 4263 ============= 4264 VL_R_FloodAreaSpotLight 4265 ============= 4266 */ 4267 void VL_FloodAreaSpotLight(vlight_t *light, winding_t *w, int leafnum) 4268 { 4269 } 4270 4271 /* 4272 ============= 4273 VL_R_SubdivideAreaSpotLight 4274 ============= 4275 */ 4276 void VL_R_SubdivideAreaSpotLight(vlight_t *light, int nodenum, winding_t *w) 4277 { 4278 int leafnum, res; 4279 dnode_t *node; 4280 dplane_t *plane; 4281 winding_t back; 4282 plane_t split; 4283 4284 while(nodenum >= 0) 4285 { 4286 node = &dnodes[nodenum]; 4287 plane = &dplanes[node->planeNum]; 4288 4289 VectorCopy(plane->normal, split.normal); 4290 split.dist = plane->dist; 4291 res = VL_SplitWinding (w, &back, &split, 0.1); 4292 4293 if (res == SIDE_FRONT) 4294 { 4295 nodenum = node->children[0]; 4296 } 4297 else if (res == SIDE_BACK) 4298 { 4299 nodenum = node->children[1]; 4300 } 4301 else if (res == SIDE_ON) 4302 { 4303 memcpy(&back, w, sizeof(winding_t)); 4304 VL_R_SubdivideAreaSpotLight(light, node->children[1], &back); 4305 nodenum = node->children[0]; 4306 } 4307 else 4308 { 4309 VL_R_SubdivideAreaSpotLight(light, node->children[1], &back); 4310 nodenum = node->children[0]; 4311 } 4312 } 4313 leafnum = -nodenum - 1; 4314 if (dleafs[leafnum].cluster != -1) 4315 { 4316 VL_FloodAreaSpotLight(light, w, leafnum); 4317 } 4318 } 4319 4320 /* 4321 ============= 4322 VL_R_FloodRadialAreaLight 4323 ============= 4324 */ 4325 void VL_FloodRadialAreaLight(vlight_t *light, winding_t *w, int leafnum) 4326 { 4327 } 4328 4329 /* 4330 ============= 4331 VL_R_SubdivideRadialAreaLight 4332 ============= 4333 */ 4334 void VL_R_SubdivideRadialAreaLight(vlight_t *light, int nodenum, winding_t *w) 4335 { 4336 int leafnum, res; 4337 dnode_t *node; 4338 dplane_t *plane; 4339 winding_t back; 4340 plane_t split; 4341 4342 while(nodenum >= 0) 4343 { 4344 node = &dnodes[nodenum]; 4345 plane = &dplanes[node->planeNum]; 4346 4347 VectorCopy(plane->normal, split.normal); 4348 split.dist = plane->dist; 4349 res = VL_SplitWinding (w, &back, &split, 0.1); 4350 4351 if (res == SIDE_FRONT) 4352 { 4353 nodenum = node->children[0]; 4354 } 4355 else if (res == SIDE_BACK) 4356 { 4357 nodenum = node->children[1]; 4358 } 4359 else if (res == SIDE_ON) 4360 { 4361 memcpy(&back, w, sizeof(winding_t)); 4362 VL_R_SubdivideRadialAreaLight(light, node->children[1], &back); 4363 nodenum = node->children[0]; 4364 } 4365 else 4366 { 4367 VL_R_SubdivideRadialAreaLight(light, node->children[1], &back); 4368 nodenum = node->children[0]; 4369 } 4370 } 4371 leafnum = -nodenum - 1; 4372 if (dleafs[leafnum].cluster != -1) 4373 { 4374 VL_FloodRadialAreaLight(light, w, leafnum); 4375 } 4376 } 4377 4378 /* 4379 ============= 4380 VL_R_FloodDirectedLight 4381 ============= 4382 */ 4383 void VL_FloodDirectedLight(vlight_t *light, winding_t *w, int leafnum) 4384 { 4385 int i; 4386 float dist; 4387 lightvolume_t volume; 4388 vec3_t dir; 4389 4390 if (light->atten_disttype == LDAT_NOSCALE) 4391 { 4392 // light travels without decrease in intensity over distance 4393 dist = MAX_WORLD_COORD; 4394 } 4395 else 4396 { 4397 if ( light->atten_disttype == LDAT_LINEAR ) 4398 dist = light->photons * lightLinearScale; 4399 else 4400 dist = sqrt(light->photons); 4401 } 4402 4403 memset(&volume, 0, sizeof(lightvolume_t)); 4404 for (i = 0; i < w->numpoints; i++) 4405 { 4406 VectorMA(w->points[i], dist, light->normal, volume.points[i]); 4407 VectorSubtract(w->points[(i+1)%w->numpoints], w->points[i], dir); 4408 CrossProduct(light->normal, dir, volume.planes[i].normal); 4409 VectorNormalize(volume.planes[i].normal, volume.planes[i].normal); 4410 volume.planes[i].dist = DotProduct(volume.planes[i].normal, w->points[i]); 4411 } 4412 volume.numplanes = w->numpoints; 4413 VectorCopy(light->normal, volume.endplane.normal); 4414 VectorInverse(volume.endplane.normal); 4415 volume.endplane.dist = DotProduct(volume.endplane.normal, volume.points[0]); 4416 volume.farplane = volume.endplane; 4417 volume.surfaceNum = -1; 4418 volume.type = VOLUME_DIRECTED; 4419 volume.cluster = dleafs[leafnum].cluster; 4420 VL_R_FloodLight(light, &volume, volume.cluster, 0); 4421 if (volume.surfaceNum >= 0) 4422 { 4423 VL_R_CastLightAtSurface(light, &volume); 4424 } 4425 } 4426 4427 /* 4428 ============= 4429 VL_R_SubdivideDirectedAreaLight 4430 ============= 4431 */ 4432 void VL_R_SubdivideDirectedAreaLight(vlight_t *light, int nodenum, winding_t *w) 4433 { 4434 int leafnum, res; 4435 dnode_t *node; 4436 dplane_t *plane; 4437 winding_t back; 4438 plane_t split; 4439 4440 while(nodenum >= 0) 4441 { 4442 node = &dnodes[nodenum]; 4443 plane = &dplanes[node->planeNum]; 4444 4445 VectorCopy(plane->normal, split.normal); 4446 split.dist = plane->dist; 4447 res = VL_SplitWinding (w, &back, &split, 0.1); 4448 4449 if (res == SIDE_FRONT) 4450 { 4451 nodenum = node->children[0]; 4452 } 4453 else if (res == SIDE_BACK) 4454 { 4455 nodenum = node->children[1]; 4456 } 4457 else if (res == SIDE_ON) 4458 { 4459 memcpy(&back, w, sizeof(winding_t)); 4460 VL_R_SubdivideDirectedAreaLight(light, node->children[1], &back); 4461 nodenum = node->children[0]; 4462 } 4463 else 4464 { 4465 VL_R_SubdivideDirectedAreaLight(light, node->children[1], &back); 4466 nodenum = node->children[0]; 4467 } 4468 } 4469 leafnum = -nodenum - 1; 4470 if (dleafs[leafnum].cluster != -1) 4471 { 4472 VL_FloodDirectedLight(light, w, leafnum); 4473 } 4474 } 4475 4476 /* 4477 ============= 4478 VL_FloodLight 4479 ============= 4480 */ 4481 void VL_FloodLight(vlight_t *light) 4482 { 4483 lightvolume_t volume; 4484 dleaf_t *leaf; 4485 int leafnum, i, j, k, dir[2][4] = {{1, 1, -1, -1}, {1, -1, -1, 1}}; 4486 float a, step, dist, radius, windingdist; 4487 vec3_t vec, r, p, temp; 4488 winding_t winding; 4489 4490 switch(light->type) 4491 { 4492 case LIGHT_POINTRADIAL: 4493 { 4494 // source is a point 4495 // light radiates in all directions 4496 // creates sharp shadows 4497 // 4498 // create 6 volumes shining in the axis directions 4499 // what about: 4 tetrahedrons instead? 4500 // 4501 if ( light->atten_disttype == LDAT_LINEAR ) 4502 dist = light->photons * lightLinearScale; 4503 else 4504 dist = sqrt(light->photons); 4505 //always put the winding at a large distance to avoid epsilon issues 4506 windingdist = MAX_WORLD_COORD; 4507 if (dist > windingdist) 4508 windingdist = dist; 4509 // 4510 leafnum = VL_LightLeafnum(light->origin); 4511 leaf = &dleafs[leafnum]; 4512 if (leaf->cluster == -1) 4513 { 4514 light->insolid = qtrue; 4515 break; 4516 } 4517 // for each axis 4518 for (i = 0; i < 3; i++) 4519 { 4520 // for both directions on the axis 4521 for (j = -1; j <= 1; j += 2) 4522 { 4523 memset(&volume, 0, sizeof(lightvolume_t)); 4524 volume.numplanes = 0; 4525 for (k = 0; k < 4; k ++) 4526 { 4527 volume.points[volume.numplanes][i] = light->origin[i] + j * windingdist; 4528 volume.points[volume.numplanes][(i+1)%3] = light->origin[(i+1)%3] + dir[0][k] * windingdist; 4529 volume.points[volume.numplanes][(i+2)%3] = light->origin[(i+2)%3] + dir[1][k] * windingdist; 4530 volume.numplanes++; 4531 } 4532 if (j >= 0) 4533 { 4534 VectorCopy(volume.points[0], temp); 4535 VectorCopy(volume.points[2], volume.points[0]); 4536 VectorCopy(temp, volume.points[2]); 4537 } 4538 for (k = 0; k < volume.numplanes; k++) 4539 { 4540 VL_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]); 4541 } 4542 VectorCopy(light->origin, temp); 4543 temp[i] += (float) j * dist; 4544 VectorClear(volume.endplane.normal); 4545 volume.endplane.normal[i] = -j; 4546 volume.endplane.dist = DotProduct(volume.endplane.normal, temp); //DotProduct(volume.endplane.normal, volume.points[0]); 4547 volume.farplane = volume.endplane; 4548 volume.cluster = leaf->cluster; 4549 volume.surfaceNum = -1; 4550 volume.type = VOLUME_NORMAL; 4551 // 4552 memset(volume.facetTested, 0, sizeof(volume.facetTested)); 4553 memset(volume.clusterTested, 0, sizeof(volume.clusterTested)); 4554 VL_R_FloodLight(light, &volume, leaf->cluster, 0); 4555 if (volume.surfaceNum >= 0) 4556 { 4557 VL_R_CastLightAtSurface(light, &volume); 4558 } 4559 } 4560 } 4561 break; 4562 } 4563 case LIGHT_POINTSPOT: 4564 { 4565 // source is a point 4566 // light is targetted 4567 // creates sharp shadows 4568 // 4569 // what about using brushes to shape spot lights? that'd be pretty cool 4570 // 4571 if ( light->atten_disttype == LDAT_LINEAR ) 4572 dist = light->photons * lightLinearScale; 4573 else 4574 dist = sqrt(light->photons); 4575 dist *= 2; 4576 // 4577 windingdist = 4096; 4578 if (dist > windingdist) 4579 windingdist = dist; 4580 //take 8 times the cone radius because the spotlight also lights outside the cone 4581 radius = 8 * windingdist * light->radiusByDist; 4582 // 4583 memset(&volume, 0, sizeof(lightvolume_t)); 4584 leafnum = VL_LightLeafnum(light->origin); 4585 leaf = &dleafs[leafnum]; 4586 if (leaf->cluster == -1) 4587 { 4588 light->insolid = qtrue; 4589 break; 4590 } 4591 // 4592 VectorClear(vec); 4593 for (i = 0; i < 3; i++) 4594 { 4595 if (light->normal[i] > -0.9 && light->normal[i] < 0.9) 4596 { 4597 vec[i] = 1; 4598 break; 4599 } 4600 } 4601 CrossProduct(light->normal, vec, r); 4602 VectorScale(r, radius, p); 4603 volume.numplanes = 0; 4604 step = 45; 4605 for (a = step / 2; a < 360 + step / 2; a += step) 4606 { 4607 RotatePointAroundVector(volume.points[volume.numplanes], light->normal, p, a); 4608 VectorAdd(light->origin, volume.points[volume.numplanes], volume.points[volume.numplanes]); 4609 VectorMA(volume.points[volume.numplanes], windingdist, light->normal, volume.points[volume.numplanes]); 4610 volume.numplanes++; 4611 } 4612 for (i = 0; i < volume.numplanes; i++) 4613 { 4614 VL_PlaneFromPoints(&volume.planes[i], light->origin, volume.points[(i+1)%volume.numplanes], volume.points[i]); 4615 } 4616 VectorMA(light->origin, dist, light->normal, temp); 4617 VectorCopy(light->normal, volume.endplane.normal); 4618 VectorInverse(volume.endplane.normal); 4619 volume.endplane.dist = DotProduct(volume.endplane.normal, temp);//DotProduct(volume.endplane.normal, volume.points[0]); 4620 volume.farplane = volume.endplane; 4621 volume.cluster = leaf->cluster; 4622 volume.surfaceNum = -1; 4623 volume.type = VOLUME_NORMAL; 4624 // 4625 memset(volume.facetTested, 0, sizeof(volume.facetTested)); 4626 memset(volume.clusterTested, 0, sizeof(volume.clusterTested)); 4627 VL_R_FloodLight(light, &volume, leaf->cluster, 0); 4628 if (volume.surfaceNum >= 0) 4629 { 4630 VL_R_CastLightAtSurface(light, &volume); 4631 } 4632 break; 4633 } 4634 case LIGHT_POINTFAKESURFACE: 4635 { 4636 float value; 4637 int n, axis; 4638 vec3_t v, vecs[2]; 4639 4640 if ( light->atten_disttype == LDAT_LINEAR ) 4641 dist = light->photons * lightLinearScale; 4642 else 4643 dist = sqrt(light->photons); 4644 //always put the winding at a large distance to avoid epsilon issues 4645 windingdist = 4096; 4646 if (dist > windingdist) 4647 windingdist = dist; 4648 // 4649 VectorMA(light->origin, 0.1, light->normal, light->origin); 4650 // 4651 leafnum = VL_LightLeafnum(light->origin); 4652 leaf = &dleafs[leafnum]; 4653 if (leaf->cluster == -1) 4654 { 4655 light->insolid = qtrue; 4656 break; 4657 } 4658 value = 0; 4659 for (i = 0; i < 3; i++) 4660 { 4661 if (fabs(light->normal[i]) > value) 4662 { 4663 value = fabs(light->normal[i]); 4664 axis = i; 4665 } 4666 } 4667 for (i = 0; i < 2; i++) 4668 { 4669 VectorClear(v); 4670 v[(axis + 1 + i) % 3] = 1; 4671 CrossProduct(light->normal, v, vecs[i]); 4672 } 4673 //cast 4 volumes at the front of the surface 4674 for (i = -1; i <= 1; i += 2) 4675 { 4676 for (j = -1; j <= 1; j += 2) 4677 { 4678 for (n = 0; n < 2; n++) 4679 { 4680 memset(&volume, 0, sizeof(lightvolume_t)); 4681 volume.numplanes = 3; 4682 VectorMA(light->origin, i * windingdist, vecs[0], volume.points[(i == j) == n]); 4683 VectorMA(light->origin, j * windingdist, vecs[1], volume.points[(i != j) == n]); 4684 VectorMA(light->origin, windingdist, light->normal, volume.points[2]); 4685 for (k = 0; k < volume.numplanes; k++) 4686 { 4687 VL_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]); 4688 } 4689 VL_PlaneFromPoints(&volume.endplane, volume.points[0], volume.points[1], volume.points[2]); 4690 VectorMA(light->origin, dist, light->normal, temp); 4691 volume.endplane.dist = DotProduct(volume.endplane.normal, temp); 4692 if (DotProduct(light->origin, volume.endplane.normal) - volume.endplane.dist > 0) 4693 break; 4694 } 4695 volume.farplane = volume.endplane; 4696 volume.cluster = leaf->cluster; 4697 volume.surfaceNum = -1; 4698 volume.type = VOLUME_NORMAL; 4699 // 4700 memset(volume.facetTested, 0, sizeof(volume.facetTested)); 4701 memset(volume.clusterTested, 0, sizeof(volume.clusterTested)); 4702 4703 VL_R_FloodLight(light, &volume, leaf->cluster, 0); 4704 if (volume.surfaceNum >= 0) 4705 { 4706 VL_R_CastLightAtSurface(light, &volume); 4707 } 4708 } 4709 } 4710 break; 4711 } 4712 case LIGHT_SURFACEDIRECTED: 4713 { 4714 // source is an area defined by a winding 4715 // the light is unidirectional 4716 // creates sharp shadows 4717 // for instance sun light or laser light 4718 // 4719 memcpy(&winding, &light->w, sizeof(winding_t)); 4720 VL_R_SubdivideDirectedAreaLight(light, 0, &winding); 4721 break; 4722 } 4723 case LIGHT_SURFACERADIAL: 4724 { 4725 // source is an area defined by a winding 4726 // the light radiates in all directions at the front of the winding plane 4727 // 4728 memcpy(&winding, &light->w, sizeof(winding_t)); 4729 VL_R_SubdivideRadialAreaLight(light, 0, &winding); 4730 break; 4731 } 4732 case LIGHT_SURFACESPOT: 4733 { 4734 // source is an area defined by a winding 4735 // light is targetted but not unidirectional 4736 // 4737 memcpy(&winding, &light->w, sizeof(winding_t)); 4738 VL_R_SubdivideAreaSpotLight(light, 0, &winding); 4739 break; 4740 } 4741 } 4742 } 4743 4744 /* 4745 ============= 4746 VL_FloodLightThread 4747 ============= 4748 */ 4749 void VL_FloodLightThread(int num) 4750 { 4751 VL_FloodLight(vlights[num]); 4752 } 4753 4754 /* 4755 ============= 4756 VL_TestLightLeafs 4757 ============= 4758 */ 4759 void VL_TestLightLeafs(void) 4760 { 4761 int leafnum, i; 4762 vlight_t *light; 4763 dleaf_t *leaf; 4764 4765 for (i = 0; i < numvlights; i++) 4766 { 4767 light = vlights[i]; 4768 if (light->type != LIGHT_POINTRADIAL && 4769 light->type != LIGHT_POINTSPOT) 4770 continue; 4771 leafnum = VL_LightLeafnum(light->origin); 4772 leaf = &dleafs[leafnum]; 4773 if (leaf->cluster == -1) 4774 if (light->type == LIGHT_POINTRADIAL) 4775 qprintf("light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]); 4776 else if (light->type == LIGHT_POINTSPOT) 4777 qprintf("spot light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]); 4778 } 4779 } 4780 4781 4782 /* 4783 ============= 4784 VL_DoForcedTraceLight 4785 ============= 4786 */ 4787 // from light.c 4788 void TraceLtm( int num ); 4789 4790 void VL_DoForcedTraceLight(int num) 4791 { 4792 dsurface_t *ds; 4793 shaderInfo_t *si; 4794 4795 ds = &drawSurfaces[num]; 4796 4797 if ( ds->surfaceType == MST_TRIANGLE_SOUP ) 4798 return; 4799 4800 if ( ds->lightmapNum < 0 ) 4801 return; 4802 4803 // always light entity surfaces with the old light algorithm 4804 if ( !entitySurface[num] ) 4805 { 4806 si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader ); 4807 4808 if (defaulttracelight) 4809 { 4810 if (si->forceVLight) 4811 return; 4812 } 4813 else 4814 { 4815 if (!si->forceTraceLight) 4816 return; 4817 } 4818 } 4819 4820 TraceLtm(num); 4821 } 4822 4823 /* 4824 ============= 4825 VL_DoForcedTraceLightSurfaces 4826 ============= 4827 */ 4828 void VL_DoForcedTraceLightSurfaces(void) 4829 { 4830 _printf( "forced trace light\n" ); 4831 RunThreadsOnIndividual( numDrawSurfaces, qtrue, VL_DoForcedTraceLight ); 4832 } 4833 4834 float *oldLightFloats; 4835 4836 /* 4837 ============= 4838 VL_SurfaceRadiosity 4839 ============= 4840 */ 4841 void VL_SurfaceRadiosity( int num ) { 4842 dsurface_t *ds; 4843 mesh_t *mesh; 4844 shaderInfo_t *si; 4845 lsurfaceTest_t *test; 4846 int x, y, k; 4847 vec3_t base, normal; 4848 float *color, area; 4849 vlight_t vlight; 4850 4851 ds = &drawSurfaces[num]; 4852 4853 if ( ds->lightmapNum < 0 ) { 4854 return; // doesn't have a lightmap 4855 } 4856 4857 // vertex-lit triangle model 4858 if ( ds->surfaceType == MST_TRIANGLE_SOUP ) { 4859 return; 4860 } 4861 4862 si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader ); 4863 test = lsurfaceTest[ num ]; 4864 4865 if (!test) { 4866 return; 4867 } 4868 4869 for (x = 0; x < ds->lightmapWidth; x++) { 4870 for (y = 0; y < ds->lightmapHeight; y++) { 4871 // 4872 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 4873 * LIGHTMAP_WIDTH + ds->lightmapX + x; 4874 area = lightmappixelarea[k]; 4875 if (area <= 0) 4876 continue; 4877 // 4878 if (ds->surfaceType == MST_PATCH) 4879 { 4880 mesh = test->detailMesh; 4881 VectorCopy( mesh->verts[y*mesh->width+x].xyz, base); 4882 VectorCopy( mesh->verts[y*mesh->width+x].normal, normal); 4883 } 4884 else 4885 { 4886 VectorMA(ds->lightmapOrigin, (float) x, ds->lightmapVecs[0], base); 4887 VectorMA(base, (float) y, ds->lightmapVecs[1], base); 4888 VectorCopy(test->facets[0].plane.normal, normal); 4889 } 4890 // create ligth from base 4891 memset(&vlight, 0, sizeof(vlight_t)); 4892 color = &oldLightFloats[k*3]; 4893 // a few units away from the surface 4894 VectorMA(base, 5, normal, vlight.origin); 4895 ColorNormalize(color, vlight.color); 4896 // ok this is crap 4897 vlight.photons = VectorLength(color) * 0.05 * lightPointScale / (area * radiosity_scale); 4898 // what about using a front facing light only ? 4899 vlight.type = LIGHT_POINTRADIAL; 4900 // flood the light from this lightmap pixel 4901 VL_FloodLight(&vlight); 4902 // only one thread at a time may write to the lightmap of this surface 4903 MutexLock(test->mutex); 4904 // don't light the lightmap pixel itself 4905 lightFloats[k*3] = oldLightFloats[k*3]; 4906 lightFloats[k*3+1] = oldLightFloats[k*3+1]; 4907 lightFloats[k*3+2] = oldLightFloats[k*3+2]; 4908 // 4909 MutexUnlock(test->mutex); 4910 } 4911 } 4912 } 4913 4914 /* 4915 ============= 4916 VL_Radiosity 4917 4918 this aint working real well but it's fun to play with. 4919 ============= 4920 */ 4921 void VL_Radiosity(void) { 4922 4923 oldLightFloats = lightFloats; 4924 lightFloats = (float *) malloc(numLightBytes * sizeof(float)); 4925 memcpy(lightFloats, oldLightFloats, numLightBytes * sizeof(float)); 4926 _printf("%7i surfaces\n", numDrawSurfaces); 4927 RunThreadsOnIndividual( numDrawSurfaces, qtrue, VL_SurfaceRadiosity ); 4928 free(oldLightFloats); 4929 } 4930 4931 /* 4932 ============= 4933 VL_LightWorld 4934 ============= 4935 */ 4936 void VL_LightWorld(void) 4937 { 4938 int i, numcastedvolumes, numvlightsinsolid; 4939 float f; 4940 4941 // find the optional world ambient 4942 GetVectorForKey( &entities[0], "_color", lightAmbientColor ); 4943 f = FloatForKey( &entities[0], "ambient" ); 4944 VectorScale( lightAmbientColor, f, lightAmbientColor ); 4945 /* 4946 _printf("\r%6d lights out of %d", 0, numvlights); 4947 for (i = 0; i < numvlights; i++) 4948 { 4949 _printf("\r%6d", i); 4950 VL_FloodLight(vlights[i]); 4951 } 4952 _printf("\r%6d lights out of %d\n", i, numvlights); 4953 */ 4954 _printf("%7i lights\n", numvlights); 4955 RunThreadsOnIndividual( numvlights, qtrue, VL_FloodLightThread ); 4956 4957 numcastedvolumes = 0; 4958 for ( i = 0 ; i < numDrawSurfaces ; i++ ) { 4959 if (lsurfaceTest[i]) 4960 numcastedvolumes += lsurfaceTest[i]->numvolumes; 4961 } 4962 _printf("%7i light volumes casted\n", numcastedvolumes); 4963 numvlightsinsolid = 0; 4964 for (i = 0; i < numvlights; i++) 4965 { 4966 if (vlights[i]->insolid) 4967 numvlightsinsolid++; 4968 } 4969 _printf("%7i lights in solid\n", numvlightsinsolid); 4970 // 4971 radiosity_scale = 1; 4972 for (i = 0; i < radiosity; i++) { 4973 VL_Radiosity(); 4974 radiosity_scale <<= 1; 4975 } 4976 // 4977 VL_StoreLightmap(); 4978 // redo surfaces with the old light algorithm when needed 4979 VL_DoForcedTraceLightSurfaces(); 4980 } 4981 4982 /* 4983 ============= 4984 VL_CreateEntityLights 4985 ============= 4986 */ 4987 entity_t *FindTargetEntity( const char *target ); 4988 4989 void VL_CreateEntityLights (void) 4990 { 4991 int i, c_entityLights; 4992 vlight_t *dl; 4993 entity_t *e, *e2; 4994 const char *name; 4995 const char *target; 4996 vec3_t dest; 4997 const char *_color; 4998 float intensity; 4999 int spawnflags; 5000 5001 // 5002 c_entityLights = 0; 5003 _printf("Creating entity lights...\n"); 5004 // 5005 for ( i = 0 ; i < num_entities ; i++ ) { 5006 e = &entities[i]; 5007 name = ValueForKey (e, "classname"); 5008 if (strncmp (name, "light", 5)) 5009 continue; 5010 5011 dl = malloc(sizeof(*dl)); 5012 memset (dl, 0, sizeof(*dl)); 5013 5014 spawnflags = FloatForKey (e, "spawnflags"); 5015 if ( spawnflags & 1 ) { 5016 dl->atten_disttype = LDAT_LINEAR; 5017 } 5018 if ( spawnflags & 2 ) { 5019 dl->atten_disttype = LDAT_NOSCALE; 5020 } 5021 if ( spawnflags & 4 ) { 5022 dl->atten_angletype = LAAT_QUADRATIC; 5023 } 5024 if ( spawnflags & 8 ) { 5025 dl->atten_angletype = LAAT_DOUBLEQUADRATIC; 5026 } 5027 5028 dl->atten_distscale = FloatForKey(e, "atten_distscale"); 5029 dl->atten_anglescale = FloatForKey(e, "atten_anglescale"); 5030 5031 GetVectorForKey (e, "origin", dl->origin); 5032 dl->style = FloatForKey (e, "_style"); 5033 if (!dl->style) 5034 dl->style = FloatForKey (e, "style"); 5035 if (dl->style < 0) 5036 dl->style = 0; 5037 5038 intensity = FloatForKey (e, "light"); 5039 if (!intensity) 5040 intensity = FloatForKey (e, "_light"); 5041 if (!intensity) 5042 intensity = 300; 5043 _color = ValueForKey (e, "_color"); 5044 if (_color && _color[0]) 5045 { 5046 sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]); 5047 ColorNormalize (dl->color, dl->color); 5048 } 5049 else 5050 dl->color[0] = dl->color[1] = dl->color[2] = 1.0; 5051 5052 intensity = intensity * lightPointScale; 5053 dl->photons = intensity; 5054 5055 dl->type = LIGHT_POINTRADIAL; 5056 5057 // lights with a target will be spotlights 5058 target = ValueForKey (e, "target"); 5059 5060 if ( target[0] ) { 5061 float radius; 5062 float dist; 5063 5064 e2 = FindTargetEntity (target); 5065 if (!e2) { 5066 _printf ("WARNING: light at (%i %i %i) has missing target\n", 5067 (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]); 5068 } else { 5069 GetVectorForKey (e2, "origin", dest); 5070 VectorSubtract (dest, dl->origin, dl->normal); 5071 dist = VectorNormalize (dl->normal, dl->normal); 5072 radius = FloatForKey (e, "radius"); 5073 if ( !radius ) { 5074 radius = 64; 5075 } 5076 if ( !dist ) { 5077 dist = 64; 5078 } 5079 dl->radiusByDist = (radius + 16) / dist; 5080 dl->type = LIGHT_POINTSPOT; 5081 } 5082 } 5083 vlights[numvlights++] = dl; 5084 c_entityLights++; 5085 } 5086 _printf("%7i entity lights\n", c_entityLights); 5087 } 5088 5089 /* 5090 ================== 5091 VL_SubdivideAreaLight 5092 ================== 5093 */ 5094 void VL_SubdivideAreaLight( shaderInfo_t *ls, winding_t *w, vec3_t normal, 5095 float areaSubdivide, qboolean backsplash ) { 5096 float area, value, intensity; 5097 vlight_t *dl, *dl2; 5098 vec3_t mins, maxs; 5099 int axis; 5100 winding_t *front, *back; 5101 vec3_t planeNormal; 5102 float planeDist; 5103 5104 if ( !w ) { 5105 return; 5106 } 5107 5108 WindingBounds( w, mins, maxs ); 5109 5110 // check for subdivision 5111 for ( axis = 0 ; axis < 3 ; axis++ ) { 5112 if ( maxs[axis] - mins[axis] > areaSubdivide ) { 5113 VectorClear( planeNormal ); 5114 planeNormal[axis] = 1; 5115 planeDist = ( maxs[axis] + mins[axis] ) * 0.5; 5116 ClipWindingEpsilon ( w, planeNormal, planeDist, ON_EPSILON, &front, &back ); 5117 VL_SubdivideAreaLight( ls, front, normal, areaSubdivide, qfalse ); 5118 VL_SubdivideAreaLight( ls, back, normal, areaSubdivide, qfalse ); 5119 FreeWinding( w ); 5120 return; 5121 } 5122 } 5123 5124 // create a light from this 5125 area = WindingArea (w); 5126 if ( area <= 0 || area > 20000000 ) { 5127 return; 5128 } 5129 5130 dl = malloc(sizeof(*dl)); 5131 memset (dl, 0, sizeof(*dl)); 5132 dl->type = LIGHT_POINTFAKESURFACE; 5133 5134 WindingCenter( w, dl->origin ); 5135 memcpy(dl->w.points, w->points, sizeof(vec3_t) * w->numpoints); 5136 dl->w.numpoints = w->numpoints; 5137 VectorCopy ( normal, dl->normal); 5138 VectorCopy ( normal, dl->plane); 5139 dl->plane[3] = DotProduct( dl->origin, normal ); 5140 5141 value = ls->value; 5142 intensity = value * area * lightAreaScale; 5143 VectorAdd( dl->origin, dl->normal, dl->origin ); 5144 5145 VectorCopy( ls->color, dl->color ); 5146 5147 dl->photons = intensity; 5148 5149 // emitColor is irrespective of the area 5150 VectorScale( ls->color, value*lightFormFactorValueScale*lightAreaScale, dl->emitColor ); 5151 // 5152 VectorCopy(dl->emitColor, dl->color); 5153 5154 dl->si = ls; 5155 5156 if ( ls->contents & CONTENTS_FOG ) { 5157 dl->twosided = qtrue; 5158 } 5159 5160 vlights[numvlights++] = dl; 5161 5162 // optionally create a point backsplash light 5163 if ( backsplash && ls->backsplashFraction > 0 ) { 5164 5165 dl2 = malloc(sizeof(*dl)); 5166 memset (dl2, 0, sizeof(*dl2)); 5167 dl2->type = LIGHT_POINTRADIAL; 5168 5169 VectorMA( dl->origin, ls->backsplashDistance, normal, dl2->origin ); 5170 5171 VectorCopy( ls->color, dl2->color ); 5172 5173 dl2->photons = dl->photons * ls->backsplashFraction; 5174 dl2->si = ls; 5175 5176 vlights[numvlights++] = dl2; 5177 } 5178 } 5179 5180 /* 5181 ================== 5182 VL_CreateFakeSurfaceLights 5183 ================== 5184 */ 5185 void VL_CreateFakeSurfaceLights( void ) { 5186 int i, j, side; 5187 dsurface_t *ds; 5188 shaderInfo_t *ls; 5189 winding_t *w; 5190 lFacet_t *f; 5191 vlight_t *dl; 5192 vec3_t origin; 5193 drawVert_t *dv; 5194 int c_surfaceLights; 5195 float lightSubdivide; 5196 vec3_t normal; 5197 5198 5199 c_surfaceLights = 0; 5200 _printf ("Creating surface lights...\n"); 5201 5202 for ( i = 0 ; i < numDrawSurfaces ; i++ ) { 5203 // see if this surface is light emiting 5204 ds = &drawSurfaces[i]; 5205 5206 ls = ShaderInfoForShader( dshaders[ ds->shaderNum].shader ); 5207 if ( ls->value == 0 ) { 5208 continue; 5209 } 5210 5211 // determine how much we need to chop up the surface 5212 if ( ls->lightSubdivide ) { 5213 lightSubdivide = ls->lightSubdivide; 5214 } else { 5215 lightSubdivide = lightDefaultSubdivide; 5216 } 5217 5218 c_surfaceLights++; 5219 5220 // an autosprite shader will become 5221 // a point light instead of an area light 5222 if ( ls->autosprite ) { 5223 // autosprite geometry should only have four vertexes 5224 if ( lsurfaceTest[i] ) { 5225 // curve or misc_model 5226 f = lsurfaceTest[i]->facets; 5227 if ( lsurfaceTest[i]->numFacets != 1 || f->numpoints != 4 ) { 5228 _printf( "WARNING: surface at (%i %i %i) has autosprite shader but isn't a quad\n", 5229 (int)f->points[0], (int)f->points[1], (int)f->points[2] ); 5230 } 5231 VectorAdd( f->points[0], f->points[1], origin ); 5232 VectorAdd( f->points[2], origin, origin ); 5233 VectorAdd( f->points[3], origin, origin ); 5234 VectorScale( origin, 0.25, origin ); 5235 } else { 5236 // normal polygon 5237 dv = &drawVerts[ ds->firstVert ]; 5238 if ( ds->numVerts != 4 ) { 5239 _printf( "WARNING: surface at (%i %i %i) has autosprite shader but %i verts\n", 5240 (int)dv->xyz[0], (int)dv->xyz[1], (int)dv->xyz[2] ); 5241 continue; 5242 } 5243 5244 VectorAdd( dv[0].xyz, dv[1].xyz, origin ); 5245 VectorAdd( dv[2].xyz, origin, origin ); 5246 VectorAdd( dv[3].xyz, origin, origin ); 5247 VectorScale( origin, 0.25, origin ); 5248 } 5249 5250 dl = malloc(sizeof(*dl)); 5251 memset (dl, 0, sizeof(*dl)); 5252 VectorCopy( origin, dl->origin ); 5253 VectorCopy( ls->color, dl->color ); 5254 dl->photons = ls->value * lightPointScale; 5255 dl->type = LIGHT_POINTRADIAL; 5256 vlights[numvlights++] = dl; 5257 continue; 5258 } 5259 5260 // possibly create for both sides of the polygon 5261 for ( side = 0 ; side <= ls->twoSided ; side++ ) { 5262 // create area lights 5263 if ( lsurfaceTest[i] ) { 5264 // curve or misc_model 5265 for ( j = 0 ; j < lsurfaceTest[i]->numFacets ; j++ ) { 5266 f = lsurfaceTest[i]->facets + j; 5267 w = AllocWinding( f->numpoints ); 5268 w->numpoints = f->numpoints; 5269 memcpy( w->points, f->points, f->numpoints * 12 ); 5270 5271 VectorCopy( f->plane.normal, normal ); 5272 if ( side ) { 5273 winding_t *t; 5274 5275 t = w; 5276 w = ReverseWinding( t ); 5277 FreeWinding( t ); 5278 VectorSubtract( vec3_origin, normal, normal ); 5279 } 5280 VL_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue ); 5281 } 5282 } else { 5283 // normal polygon 5284 5285 w = AllocWinding( ds->numVerts ); 5286 w->numpoints = ds->numVerts; 5287 for ( j = 0 ; j < ds->numVerts ; j++ ) { 5288 VectorCopy( drawVerts[ds->firstVert+j].xyz, w->points[j] ); 5289 } 5290 VectorCopy( ds->lightmapVecs[2], normal ); 5291 if ( side ) { 5292 winding_t *t; 5293 5294 t = w; 5295 w = ReverseWinding( t ); 5296 FreeWinding( t ); 5297 VectorSubtract( vec3_origin, normal, normal ); 5298 } 5299 VL_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue ); 5300 } 5301 } 5302 } 5303 5304 _printf( "%7i light emitting surfaces\n", c_surfaceLights ); 5305 } 5306 5307 5308 /* 5309 ================== 5310 VL_WindingForBrushSide 5311 ================== 5312 */ 5313 winding_t *VL_WindingForBrushSide(dbrush_t *brush, int side, winding_t *w) 5314 { 5315 int i, res; 5316 winding_t *tmpw; 5317 plane_t plane; 5318 5319 VectorCopy(dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].normal, plane.normal); 5320 VectorInverse(plane.normal); 5321 plane.dist = -dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].dist; 5322 tmpw = BaseWindingForPlane( plane.normal, plane.dist ); 5323 memcpy(w->points, tmpw->points, sizeof(vec3_t) * tmpw->numpoints); 5324 w->numpoints = tmpw->numpoints; 5325 5326 for (i = 0; i < brush->numSides; i++) 5327 { 5328 if (i == side) 5329 continue; 5330 VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal); 5331 VectorInverse(plane.normal); 5332 plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist; 5333 res = VL_ChopWinding(w, &plane, 0.1); 5334 if (res == SIDE_BACK) 5335 return NULL; 5336 } 5337 return w; 5338 } 5339 5340 /* 5341 ================== 5342 VL_CreateSkyLights 5343 ================== 5344 */ 5345 void VL_CreateSkyLights(void) 5346 { 5347 int i, j, c_skyLights; 5348 dbrush_t *b; 5349 shaderInfo_t *si; 5350 dbrushside_t *s; 5351 vlight_t *dl; 5352 vec3_t sunColor, sunDir = { 0.45, 0.3, 0.9 }; 5353 float d; 5354 5355 VectorNormalize(sunDir, sunDir); 5356 VectorInverse(sunDir); 5357 5358 c_skyLights = 0; 5359 _printf("Creating sky lights...\n"); 5360 // find the sky shader 5361 for ( i = 0 ; i < numDrawSurfaces ; i++ ) { 5362 si = ShaderInfoForShader( dshaders[ drawSurfaces[i].shaderNum ].shader ); 5363 if ( si->surfaceFlags & SURF_SKY ) { 5364 VectorCopy( si->sunLight, sunColor ); 5365 VectorCopy( si->sunDirection, sunDir ); 5366 VectorInverse(sunDir); 5367 break; 5368 } 5369 } 5370 5371 // find the brushes 5372 for ( i = 0 ; i < numbrushes ; i++ ) { 5373 b = &dbrushes[i]; 5374 for ( j = 0 ; j < b->numSides ; j++ ) { 5375 s = &dbrushsides[ b->firstSide + j ]; 5376 if ( dshaders[ s->shaderNum ].surfaceFlags & SURF_SKY ) { 5377 //if this surface doesn't face in the same direction as the sun 5378 d = DotProduct(dplanes[ s->planeNum ].normal, sunDir); 5379 if (d <= 0) 5380 continue; 5381 // 5382 dl = malloc(sizeof(*dl)); 5383 memset (dl, 0, sizeof(*dl)); 5384 VectorCopy(sunColor, dl->color); 5385 VectorCopy(sunDir, dl->normal); 5386 VectorCopy(dplanes[ s->planeNum ].normal, dl->plane); 5387 dl->plane[3] = dplanes[ s->planeNum ].dist; 5388 dl->type = LIGHT_SURFACEDIRECTED; 5389 dl->atten_disttype = LDAT_NOSCALE; 5390 VL_WindingForBrushSide(b, j, &dl->w); 5391 // DebugNet_DrawWinding(&dl->w, 2); 5392 // 5393 vlights[numvlights++] = dl; 5394 c_skyLights++; 5395 } 5396 } 5397 } 5398 _printf("%7i light emitting sky surfaces\n", c_skyLights); 5399 } 5400 5401 /* 5402 ================== 5403 VL_SetPortalSphere 5404 ================== 5405 */ 5406 void VL_SetPortalSphere (lportal_t *p) 5407 { 5408 int i; 5409 vec3_t total, dist; 5410 winding_t *w; 5411 float r, bestr; 5412 5413 w = p->winding; 5414 VectorCopy (vec3_origin, total); 5415 for (i=0 ; i<w->numpoints ; i++) 5416 { 5417 VectorAdd (total, w->points[i], total); 5418 } 5419 5420 for (i=0 ; i<3 ; i++) 5421 total[i] /= w->numpoints; 5422 5423 bestr = 0; 5424 for (i=0 ; i<w->numpoints ; i++) 5425 { 5426 VectorSubtract (w->points[i], total, dist); 5427 r = VectorLength (dist); 5428 if (r > bestr) 5429 bestr = r; 5430 } 5431 VectorCopy (total, p->origin); 5432 p->radius = bestr; 5433 } 5434 5435 /* 5436 ================== 5437 VL_PlaneFromWinding 5438 ================== 5439 */ 5440 void VL_PlaneFromWinding (winding_t *w, plane_t *plane) 5441 { 5442 vec3_t v1, v2; 5443 5444 //calc plane 5445 VectorSubtract (w->points[2], w->points[1], v1); 5446 VectorSubtract (w->points[0], w->points[1], v2); 5447 CrossProduct (v2, v1, plane->normal); 5448 VectorNormalize (plane->normal, plane->normal); 5449 plane->dist = DotProduct (w->points[0], plane->normal); 5450 } 5451 5452 /* 5453 ================== 5454 VL_AllocWinding 5455 ================== 5456 */ 5457 winding_t *VL_AllocWinding (int points) 5458 { 5459 winding_t *w; 5460 int size; 5461 5462 if (points > MAX_POINTS_ON_WINDING) 5463 Error ("NewWinding: %i points", points); 5464 5465 size = (int)((winding_t *)0)->points[points]; 5466 w = malloc (size); 5467 memset (w, 0, size); 5468 5469 return w; 5470 } 5471 5472 /* 5473 ============ 5474 VL_LoadPortals 5475 ============ 5476 */ 5477 void VL_LoadPortals (char *name) 5478 { 5479 int i, j, hint; 5480 lportal_t *p; 5481 lleaf_t *l; 5482 char magic[80]; 5483 FILE *f; 5484 int numpoints; 5485 winding_t *w; 5486 int leafnums[2]; 5487 plane_t plane; 5488 // 5489 5490 if (!strcmp(name,"-")) 5491 f = stdin; 5492 else 5493 { 5494 f = fopen(name, "r"); 5495 if (!f) 5496 Error ("LoadPortals: couldn't read %s\n",name); 5497 } 5498 5499 if (fscanf (f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces) != 4) 5500 Error ("LoadPortals: failed to read header"); 5501 if (strcmp(magic, PORTALFILE)) 5502 Error ("LoadPortals: not a portal file"); 5503 5504 _printf ("%6i portalclusters\n", portalclusters); 5505 _printf ("%6i numportals\n", numportals); 5506 _printf ("%6i numfaces\n", numfaces); 5507 5508 if (portalclusters >= MAX_CLUSTERS) 5509 Error ("more than %d clusters in portal file\n", MAX_CLUSTERS); 5510 5511 // each file portal is split into two memory portals 5512 portals = malloc(2*numportals*sizeof(lportal_t)); 5513 memset (portals, 0, 2*numportals*sizeof(lportal_t)); 5514 5515 leafs = malloc(portalclusters*sizeof(lleaf_t)); 5516 memset (leafs, 0, portalclusters*sizeof(lleaf_t)); 5517 5518 for (i=0, p=portals ; i<numportals ; i++) 5519 { 5520 if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3) 5521 Error ("LoadPortals: reading portal %i", i); 5522 if (numpoints > MAX_POINTS_ON_WINDING) 5523 Error ("LoadPortals: portal %i has too many points", i); 5524 if ( (unsigned)leafnums[0] > portalclusters 5525 || (unsigned)leafnums[1] > portalclusters) 5526 Error ("LoadPortals: reading portal %i", i); 5527 if (fscanf (f, "%i ", &hint) != 1) 5528 Error ("LoadPortals: reading hint state"); 5529 5530 w = p->winding = VL_AllocWinding (numpoints); 5531 w->numpoints = numpoints; 5532 5533 for (j=0 ; j<numpoints ; j++) 5534 { 5535 double v[3]; 5536 int k; 5537 5538 // scanf into double, then assign to vec_t 5539 // so we don't care what size vec_t is 5540 if (fscanf (f, "(%lf %lf %lf ) " 5541 , &v[0], &v[1], &v[2]) != 3) 5542 Error ("LoadPortals: reading portal %i", i); 5543 for (k=0 ; k<3 ; k++) 5544 w->points[j][k] = v[k]; 5545 } 5546 fscanf (f, "\n"); 5547 5548 // calc plane 5549 VL_PlaneFromWinding (w, &plane); 5550 5551 // create forward portal 5552 l = &leafs[leafnums[0]]; 5553 if (l->numportals == MAX_PORTALS_ON_LEAF) 5554 Error ("Leaf with too many portals"); 5555 l->portals[l->numportals] = p; 5556 l->numportals++; 5557 5558 p->winding = w; 5559 VectorSubtract (vec3_origin, plane.normal, p->plane.normal); 5560 p->plane.dist = -plane.dist; 5561 p->leaf = leafnums[1]; 5562 VL_SetPortalSphere (p); 5563 p++; 5564 5565 // create backwards portal 5566 l = &leafs[leafnums[1]]; 5567 if (l->numportals == MAX_PORTALS_ON_LEAF) 5568 Error ("Leaf with too many portals"); 5569 l->portals[l->numportals] = p; 5570 l->numportals++; 5571 5572 p->winding = VL_AllocWinding(w->numpoints); 5573 p->winding->numpoints = w->numpoints; 5574 for (j=0 ; j<w->numpoints ; j++) 5575 { 5576 VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]); 5577 } 5578 5579 p->plane = plane; 5580 p->leaf = leafnums[0]; 5581 VL_SetPortalSphere (p); 5582 p++; 5583 5584 } 5585 5586 fclose (f); 5587 } 5588 5589 /* 5590 ============ 5591 VLightMain 5592 ============ 5593 */ 5594 int VLightMain (int argc, char **argv) { 5595 int i; 5596 double start, end; 5597 const char *value; 5598 5599 _printf ("----- VLighting ----\n"); 5600 5601 for (i=1 ; i<argc ; i++) { 5602 if (!strcmp(argv[i],"-v")) { 5603 verbose = qtrue; 5604 } else if (!strcmp(argv[i],"-threads")) { 5605 numthreads = atoi (argv[i+1]); 5606 _printf("num threads = %d\n", numthreads); 5607 i++; 5608 } else if (!strcmp(argv[i],"-area")) { 5609 lightAreaScale *= atof(argv[i+1]); 5610 _printf ("area light scaling at %f\n", lightAreaScale); 5611 i++; 5612 } else if (!strcmp(argv[i],"-point")) { 5613 lightPointScale *= atof(argv[i+1]); 5614 _printf ("point light scaling at %f\n", lightPointScale); 5615 i++; 5616 } else if (!strcmp(argv[i], "-samplesize")) { 5617 samplesize = atoi(argv[i+1]); 5618 if (samplesize < 1) samplesize = 1; 5619 i++; 5620 _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize); 5621 } else if (!strcmp(argv[i], "-novertex")) { 5622 novertexlighting = qtrue; 5623 _printf("no vertex lighting = true\n"); 5624 } else if (!strcmp(argv[i], "-nogrid")) { 5625 nogridlighting = qtrue; 5626 _printf("no grid lighting = true\n"); 5627 } else if (!strcmp(argv[i], "-nostitching")) { 5628 nostitching = qtrue; 5629 _printf("no stitching = true\n"); 5630 } else if (!strcmp(argv[i], "-noalphashading")) { 5631 noalphashading = qtrue; 5632 _printf("no alpha shading = true\n"); 5633 } else if (!strcmp(argv[i], "-nocolorshading")) { 5634 nocolorshading = qtrue; 5635 _printf("old style alpha shading = true\n"); 5636 } else if (!strcmp(argv[i], "-nobackfaceculling")) { 5637 nobackfaceculling = qtrue; 5638 _printf("no backface culling = true\n"); 5639 } else if (!strcmp(argv[i], "-tracelight")) { 5640 defaulttracelight = qtrue; 5641 _printf("default trace light = true\n"); 5642 } else if (!strcmp(argv[i], "-radiosity")) { 5643 radiosity = atoi(argv[i+1]); 5644 _printf("radiosity = %d\n", radiosity); 5645 i++; 5646 } else { 5647 break; 5648 } 5649 } 5650 5651 ThreadSetDefault (); 5652 5653 if (i != argc - 1) { 5654 _printf("usage: q3map -vlight [-<switch> [-<switch> ...]] <mapname>\n" 5655 "\n" 5656 "Switches:\n" 5657 " v = verbose output\n" 5658 " threads <X> = set number of threads to X\n" 5659 " area <V> = set the area light scale to V\n" 5660 " point <W> = set the point light scale to W\n" 5661 " novertex = don't calculate vertex lighting\n" 5662 " nogrid = don't calculate light grid for dynamic model lighting\n" 5663 " nostitching = no polygon stitching before lighting\n" 5664 " noalphashading = don't use alpha shading\n" 5665 " nocolorshading = don't use color alpha shading\n" 5666 " tracelight = use old light algorithm by default\n" 5667 " samplesize <N> = set the lightmap pixel size to NxN units\n"); 5668 exit(0); 5669 } 5670 5671 SetQdirFromPath (argv[i]); 5672 5673 #ifdef _WIN32 5674 InitPakFile(gamedir, NULL); 5675 #endif 5676 5677 strcpy (source, ExpandArg(argv[i])); 5678 StripExtension (source); 5679 DefaultExtension (source, ".bsp"); 5680 5681 LoadShaderInfo(); 5682 5683 _printf ("reading %s\n", source); 5684 5685 LoadBSPFile (source); 5686 ParseEntities(); 5687 5688 value = ValueForKey( &entities[0], "gridsize" ); 5689 if (strlen(value)) { 5690 sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] ); 5691 _printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]); 5692 } 5693 5694 CountLightmaps(); 5695 5696 StripExtension (source); 5697 DefaultExtension (source, ".prt"); 5698 5699 VL_LoadPortals(source); 5700 5701 // set surfaceOrigin 5702 SetEntityOrigins(); 5703 5704 // grid and vertex lighting 5705 GridAndVertexLighting(); 5706 5707 #ifdef DEBUGNET 5708 DebugNet_Setup(); 5709 #endif 5710 5711 start = clock(); 5712 5713 lightFloats = (float *) malloc(numLightBytes * sizeof(float)); 5714 memset(lightFloats, 0, numLightBytes * sizeof(float)); 5715 5716 VL_InitSurfacesForTesting(); 5717 5718 VL_CalcVisibleLightmapPixelArea(); 5719 5720 numvlights = 0; 5721 VL_CreateEntityLights(); 5722 VL_CreateFakeSurfaceLights(); 5723 VL_CreateSkyLights(); 5724 5725 VL_TestLightLeafs(); 5726 5727 VL_LightWorld(); 5728 5729 #ifndef LIGHTPOLYS 5730 StripExtension (source); 5731 DefaultExtension (source, ".bsp"); 5732 _printf ("writing %s\n", source); 5733 WriteBSPFile (source); 5734 #endif 5735 5736 end = clock(); 5737 5738 _printf ("%5.2f seconds elapsed\n", (end-start) / CLK_TCK); 5739 5740 #ifdef LIGHTPOLYS 5741 VL_DrawLightWindings(); 5742 #endif 5743 5744 #ifdef DEBUGNET 5745 DebugNet_Shutdown(); 5746 #endif 5747 return 0; 5748 }