Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

lightv.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 
00023 
00024 #include "cmdlib.h"
00025 #include "mathlib.h"
00026 #include "bspfile.h"
00027 #include "imagelib.h"
00028 #include "threads.h"
00029 #include "mutex.h"
00030 #include "scriplib.h"
00031 
00032 #include "shaders.h"
00033 #include "mesh.h"
00034 
00035 #ifdef _WIN32
00036 //Improve floating-point consistency.
00037 #pragma optimize( "p", on )
00038 #endif
00039 
00040 #ifdef _WIN32
00041 #include "../libs/pakstuff.h"
00042 #endif
00043 
00044 #define MAX_CLUSTERS        16384
00045 #define MAX_PORTALS         32768
00046 #define MAX_FACETS          65536
00047 #define MAX_LIGHTS          16384
00048 
00049 #define LIGHTMAP_SIZE       128
00050 
00051 #define LIGHTMAP_PIXELSHIFT     0.5
00052 
00053 //#define LIGHTMAP_PATCHSHIFT
00054 
00055 #define PORTALFILE  "PRT1"
00056 
00057 #define ON_EPSILON  0.1
00058 
00059 #define VectorSet(v, x, y, z)       v[0] = x;v[1] = y;v[2] = z;
00060 
00061 typedef struct
00062 {
00063     vec3_t      normal;
00064     float       dist;
00065 } plane_t;
00066 
00067 #define MAX_POINTS_ON_WINDING   64
00068 //NOTE: whenever this is overflowed parts of lightmaps might end up not being lit
00069 #define MAX_POINTS_ON_FIXED_WINDING 48
00070 
00071 typedef struct
00072 {
00073     int     numpoints;
00074     vec3_t  points[MAX_POINTS_ON_FIXED_WINDING];            // variable sized
00075 } winding_t;
00076 
00077 typedef struct
00078 {
00079     plane_t     plane;  // normal pointing into neighbor
00080     int         leaf;   // neighbor
00081     winding_t   *winding;
00082     vec3_t      origin; // for fast clip testing
00083     float       radius;
00084 } lportal_t;
00085 
00086 #define MAX_PORTALS_ON_LEAF     128
00087 typedef struct lleaf_s
00088 {
00089     int         numportals;
00090     lportal_t   *portals[MAX_PORTALS_ON_LEAF];
00091     //
00092     int         numSurfaces;
00093     int         firstSurface;
00094 } lleaf_t;
00095 
00096 typedef struct lFacet_s
00097 {
00098     int     num;
00099     plane_t plane;
00100     vec3_t  points[4];              //
00101     int     numpoints;
00102     float   lightmapCoords[4][2];
00103     plane_t boundaries[4];          // negative is outside the bounds
00104     float   textureMatrix[2][4];    // texture coordinates for translucency
00105     float   lightmapMatrix[2][4];   // lightmap texture coordinates
00106     vec3_t  mins;
00107     int     x, y, width, height;
00108 } lFacet_t;
00109 
00110 typedef struct lsurfaceTest_s
00111 {
00112     vec3_t          mins, maxs;
00113     vec3_t          origin;
00114     float           radius;
00115     qboolean        patch;          // true if this is a patch
00116     qboolean        trisoup;        // true if this is a triangle soup
00117     int             numFacets;
00118     lFacet_t        *facets;
00119     mesh_t          *detailMesh;    // detailed mesh with points for each lmp
00120     shaderInfo_t    *shader;        // for translucency
00121     mutex_t         *mutex;
00122     int             numvolumes;     // number of volumes casted at this surface
00123     //
00124     int             always_tracelight;
00125     int             always_vlight;
00126 } lsurfaceTest_t;
00127 
00128 //volume types
00129 #define VOLUME_NORMAL           0
00130 #define VOLUME_DIRECTED         1
00131 
00132 #define MAX_TRANSLUCENTFACETS   32
00133 
00134 typedef struct lightvolume_s
00135 {
00136     int num;
00137     int cluster;                            //cluster this light volume started in
00138     plane_t endplane;                       //end plane
00139     plane_t farplane;                       //original end plane
00140     vec3_t points[MAX_POINTS_ON_WINDING];   //end winding points
00141     plane_t planes[MAX_POINTS_ON_WINDING];  //volume bounding planes
00142     int numplanes;                          //number of volume bounding planes
00143     int type;                               //light volume type
00144     //list with translucent surfaces the volume went through
00145     int transFacets[MAX_TRANSLUCENTFACETS];
00146     int transSurfaces[MAX_TRANSLUCENTFACETS];
00147     int numtransFacets;
00148     //clusters already tested
00149     byte clusterTested[MAX_CLUSTERS/8];
00150     //facets already tested
00151     byte facetTested[MAX_FACETS/8];
00152     int facetNum;           //number of the facet blocking the light in this volume
00153     int surfaceNum;         //number of the surface blocking the light in this volume
00154 } lightvolume_t;
00155 
00156 //light types
00157 #define LIGHT_POINTRADIAL           1
00158 #define LIGHT_POINTSPOT             2
00159 #define LIGHT_POINTFAKESURFACE      3
00160 #define LIGHT_SURFACEDIRECTED       4
00161 #define LIGHT_SURFACERADIAL         5
00162 #define LIGHT_SURFACESPOT           6
00163 
00164 //light distance attenuation types
00165 #define LDAT_QUADRATIC              0
00166 #define LDAT_LINEAR                 1
00167 #define LDAT_NOSCALE                2
00168 
00169 //light angle attenuation types
00170 #define LAAT_NORMAL                 0
00171 #define LAAT_QUADRATIC              1
00172 #define LAAT_DOUBLEQUADRATIC        2
00173 
00174 typedef struct vlight_s
00175 {
00176     vec3_t origin;              //light origin, for point lights
00177     winding_t w;                //light winding, for area lights
00178     vec4_t plane;               //light winding plane
00179     vec3_t normal;              //direction of the light
00180     int type;                   //light type
00181     vec3_t color;               //light color
00182     qboolean twosided;          //radiates light at both sides of the winding
00183     int style;                  //light style (not used)
00184     int atten_disttype;         //light distance attenuation type
00185     int atten_angletype;        //light angle attenuation type
00186     float atten_distscale;      //distance attenuation scale
00187     float atten_anglescale;     //angle attenuation scale
00188     float radiusByDist;         //radius by distance for spot lights
00189     float photons;              //emitted photons
00190     float intensity;            //intensity
00191     vec3_t emitColor;           //full out-of-gamut value (not used)
00192     struct shaderInfo_s *si;    //shader info
00193     int insolid;                //set when light is in solid
00194 } vlight_t;
00195 
00196 float   lightLinearScale            = 1.0 / 8000;
00197 float   lightPointScale             = 7500;
00198 float   lightAreaScale              = 0.25;
00199 float   lightFormFactorValueScale   = 3;
00200 int     lightDefaultSubdivide       = 999;      // vary by surface size?
00201 vec3_t  lightAmbientColor;
00202 
00203 int         portalclusters, numportals, numfaces;
00204 lleaf_t     *leafs;
00205 lportal_t   *portals;
00206 int         numvlights = 0;
00207 vlight_t    *vlights[MAX_LIGHTS];
00208 int         nostitching = 0;
00209 int         noalphashading = 0;
00210 int         nocolorshading = 0;
00211 int         nobackfaceculling = 0;
00212 int         defaulttracelight = 0;
00213 int         radiosity = 0;
00214 int         radiosity_scale;
00215 
00216 int             clustersurfaces[MAX_MAP_LEAFFACES];
00217 int             numclustersurfaces = 0;
00218 lsurfaceTest_t  *lsurfaceTest[MAX_MAP_DRAW_SURFS];
00219 int             numfacets;
00220 float           lightmappixelarea[MAX_MAP_LIGHTING/3];
00221 float           *lightFloats;//[MAX_MAP_LIGHTING];
00222 
00223 // from polylib.c
00224 winding_t   *AllocWinding (int points);
00225 void        FreeWinding (winding_t *w);
00226 void        WindingCenter (winding_t *w, vec3_t center);
00227 void        WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs);
00228 vec_t       WindingArea (winding_t *w);
00229 winding_t   *BaseWindingForPlane (vec3_t normal, vec_t dist);
00230 void        ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, 
00231                 vec_t epsilon, winding_t **front, winding_t **back);
00232 winding_t   *ReverseWinding (winding_t *w);
00233 
00234 // from light.c
00235 extern char     source[1024];
00236 extern vec3_t   surfaceOrigin[ MAX_MAP_DRAW_SURFS ];
00237 extern int      entitySurface[ MAX_MAP_DRAW_SURFS ];
00238 extern int      samplesize;
00239 extern int      novertexlighting;
00240 extern int      nogridlighting;
00241 extern qboolean patchshadows;
00242 extern vec3_t   gridSize;
00243 
00244 float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w );
00245 void ColorToBytes( const float *color, byte *colorBytes );
00246 void CountLightmaps( void );
00247 void GridAndVertexLighting( void );
00248 void SetEntityOrigins( void );
00249 
00250 
00251 //#define DEBUGNET
00252 
00253 #ifdef DEBUGNET
00254 
00255 #include "l_net.h"
00256 
00257 socket_t *debug_socket;
00258 
00259 /*
00260 =====================
00261 DebugNet_Setup
00262 =====================
00263 */
00264 void DebugNet_Setup(void)
00265 {
00266     address_t address;
00267     int i;
00268 
00269     Net_Setup();
00270     Net_StringToAddress("127.0.0.1:28000", &address);
00271     for (i = 0; i < 10; i++)
00272     {
00273         debug_socket = Net_Connect(&address, 28005 + i);
00274         if (debug_socket)
00275             break;
00276     }
00277 }
00278 
00279 /*
00280 =====================
00281 DebugNet_Shutdown
00282 =====================
00283 */
00284 void DebugNet_Shutdown(void)
00285 {
00286     netmessage_t msg;
00287 
00288     if (debug_socket)
00289     {
00290         NMSG_Clear(&msg);
00291         NMSG_WriteByte(&msg, 1);
00292         Net_Send(debug_socket, &msg);
00293         Net_Disconnect(debug_socket);
00294     }
00295     debug_socket = NULL;
00296     Net_Shutdown();
00297 }
00298 
00299 /*
00300 =====================
00301 DebugNet_RemoveAllPolys
00302 =====================
00303 */
00304 void DebugNet_RemoveAllPolys(void)
00305 {
00306     netmessage_t msg;
00307 
00308     if (!debug_socket)
00309         return;
00310     NMSG_Clear(&msg);
00311     NMSG_WriteByte(&msg, 2);        //remove all debug polys
00312     Net_Send(debug_socket, &msg);
00313 }
00314 
00315 /*
00316 ====================
00317 DebugNet_DrawWinding
00318 =====================
00319 */
00320 void DebugNet_DrawWinding(winding_t *w, int color)
00321 {
00322     netmessage_t msg;
00323     int i;
00324 
00325     if (!debug_socket)
00326         return;
00327     NMSG_Clear(&msg);
00328     NMSG_WriteByte(&msg, 0);                //draw a winding
00329     NMSG_WriteByte(&msg, w->numpoints);     //number of points
00330     NMSG_WriteLong(&msg, color);            //color
00331     for (i = 0; i < w->numpoints; i++)
00332     {
00333         NMSG_WriteFloat(&msg, w->points[i][0]);
00334         NMSG_WriteFloat(&msg, w->points[i][1]);
00335         NMSG_WriteFloat(&msg, w->points[i][2]);
00336     }
00337     Net_Send(debug_socket, &msg);
00338 }
00339 
00340 /*
00341 =====================
00342 DebugNet_DrawLine
00343 =====================
00344 */
00345 void DebugNet_DrawLine(vec3_t p1, vec3_t p2, int color)
00346 {
00347     netmessage_t msg;
00348 
00349     if (!debug_socket)
00350         return;
00351     NMSG_Clear(&msg);
00352     NMSG_WriteByte(&msg, 1);                //draw a line
00353     NMSG_WriteLong(&msg, color);            //color
00354     NMSG_WriteFloat(&msg, p1[0]);
00355     NMSG_WriteFloat(&msg, p1[1]);
00356     NMSG_WriteFloat(&msg, p1[2]);
00357     NMSG_WriteFloat(&msg, p2[0]);
00358     NMSG_WriteFloat(&msg, p2[1]);
00359     NMSG_WriteFloat(&msg, p2[2]);
00360     Net_Send(debug_socket, &msg);
00361 }
00362 
00363 /*
00364 =====================
00365 DebugNet_DrawMesh
00366 =====================
00367 */
00368 void DebugNet_DrawMesh(mesh_t *mesh)
00369 {
00370     int i, j;
00371     float dot;
00372     drawVert_t  *v1, *v2, *v3, *v4;
00373     winding_t winding;
00374     plane_t plane;
00375     vec3_t d1, d2;
00376 
00377     for ( i = 0 ; i < mesh->width - 1 ; i++ ) {
00378         for ( j = 0 ; j < mesh->height - 1 ; j++ ) {
00379 
00380             v1 = mesh->verts + j * mesh->width + i;
00381             v2 = v1 + 1;
00382             v3 = v1 + mesh->width + 1;
00383             v4 = v1 + mesh->width;
00384 
00385             VectorSubtract( v4->xyz, v1->xyz, d1 );
00386             VectorSubtract( v3->xyz, v1->xyz, d2 );
00387             CrossProduct( d2, d1, plane.normal );
00388             if ( VectorNormalize( plane.normal, plane.normal ) != 0 )
00389             {
00390                 plane.dist = DotProduct( v1->xyz, plane.normal );
00391                 dot = DotProduct(plane.normal, v2->xyz) - plane.dist;
00392                 if (fabs(dot) < 0.1)
00393                 {
00394                     VectorCopy(v1->xyz, winding.points[0]);
00395                     VectorCopy(v4->xyz, winding.points[1]);
00396                     VectorCopy(v3->xyz, winding.points[2]);
00397                     VectorCopy(v2->xyz, winding.points[3]);
00398                     winding.numpoints = 4;
00399                     DebugNet_DrawWinding(&winding, 2);
00400                     continue;
00401                 }
00402             }
00403 
00404             winding.numpoints = 3;
00405             VectorCopy(v1->xyz, winding.points[0]);
00406             VectorCopy(v4->xyz, winding.points[1]);
00407             VectorCopy(v3->xyz, winding.points[2]);
00408             DebugNet_DrawWinding(&winding, 2);
00409 
00410             VectorCopy(v1->xyz, winding.points[0]);
00411             VectorCopy(v3->xyz, winding.points[1]);
00412             VectorCopy(v2->xyz, winding.points[2]);
00413             DebugNet_DrawWinding(&winding, 2);
00414         }
00415     }
00416 }
00417 
00418 /*
00419 =====================
00420 VL_DrawLightVolume
00421 =====================
00422 */
00423 int VL_ChopWinding (winding_t *in, plane_t *split, float epsilon);
00424 
00425 void VL_DrawLightVolume(vlight_t *light, lightvolume_t *volume)
00426 {
00427     winding_t w;
00428     int i;
00429     vec3_t p2, invlight;
00430 
00431     memcpy(w.points, volume->points, volume->numplanes * sizeof(vec3_t));
00432     w.numpoints = volume->numplanes;
00433     DebugNet_DrawWinding(&w, 2);
00434 
00435     if (volume->type == VOLUME_DIRECTED)
00436     {
00437         VectorCopy(light->normal, invlight);
00438         VectorInverse(invlight);
00439         for (i = 0; i < volume->numplanes; i++)
00440         {
00441             VectorCopy(volume->points[i], w.points[0]);
00442             VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[1]);
00443             VectorMA(w.points[1], MAX_WORLD_COORD, invlight, w.points[2]);
00444             VectorMA(w.points[0], MAX_WORLD_COORD, invlight, w.points[3]);
00445             w.numpoints = 4;
00446             DebugNet_DrawWinding(&w, 2);
00447             VectorMA(volume->points[i], 8, volume->planes[i].normal, p2);
00448             DebugNet_DrawLine(volume->points[i], p2, 3);
00449         }
00450     }
00451     else
00452     {
00453         //
00454         VectorCopy(light->origin, w.points[0]);
00455         w.numpoints = 3;
00456         for (i = 0; i < volume->numplanes; i++)
00457         {
00458             VectorCopy(volume->points[i], w.points[1]);
00459             VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[2]);
00460             VL_ChopWinding(&w, &volume->endplane, 0);
00461             DebugNet_DrawWinding(&w, 2);
00462             VectorMA(volume->points[i], 8, volume->planes[i].normal, p2);
00463             DebugNet_DrawLine(volume->points[i], p2, 3);
00464         }
00465     }
00466 }
00467 
00468 /*
00469 =============
00470 VL_DrawLightmapPixel
00471 =============
00472 */
00473 void VL_DrawLightmapPixel(int surfaceNum, int x, int y, int color)
00474 {
00475     winding_t w;
00476     dsurface_t *ds;
00477     mesh_t *mesh;
00478 
00479     ds = &drawSurfaces[surfaceNum];
00480 
00481     if (ds->surfaceType == MST_PATCH)
00482     {
00483         mesh = lsurfaceTest[surfaceNum]->detailMesh;
00484         VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]);
00485         VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]);
00486         VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]);
00487         VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]);
00488         w.numpoints = 4;
00489     }
00490     else
00491     {
00492         VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]);
00493         VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]);
00494         VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]);
00495         VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]);
00496         VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]);
00497         VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]);
00498         VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]);
00499         VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]);
00500         w.numpoints = 4;
00501     }
00502     DebugNet_DrawWinding(&w, color);
00503 }
00504 
00505 /*
00506 ============
00507 VL_DrawPortals
00508 ============
00509 */
00510 void VL_DrawPortals(void)
00511 {
00512     int j;
00513     lportal_t *p;
00514 
00515     for (j = 0; j < numportals * 2; j++)
00516     {
00517         p = portals + j;
00518         DebugNet_DrawWinding(p->winding, 1);
00519     }
00520 }
00521 
00522 /*
00523 ============
00524 VL_DrawLeaf
00525 ============
00526 */
00527 void VL_DrawLeaf(int cluster)
00528 {
00529     int i;
00530     lleaf_t *leaf;
00531     lportal_t *p;
00532 
00533     leaf = &leafs[cluster];
00534     for (i = 0; i < leaf->numportals; i++)
00535     {
00536         p = leaf->portals[i];
00537         DebugNet_DrawWinding(p->winding, 1);
00538     }
00539 }
00540 
00541 #endif //DEBUGNET
00542 
00543 /*
00544 =============
00545 VL_SplitWinding
00546 =============
00547 */
00548 int VL_SplitWinding (winding_t *in, winding_t *back, plane_t *split, float epsilon)
00549 {
00550     vec_t   dists[128];
00551     int     sides[128];
00552     int     counts[3];
00553     vec_t   dot;
00554     int     i, j;
00555     vec_t   *p1, *p2;
00556     vec3_t  mid;
00557     winding_t out;
00558     winding_t   *neww;
00559 
00560     counts[0] = counts[1] = counts[2] = 0;
00561 
00562     // determine sides for each point
00563     for (i=0 ; i<in->numpoints ; i++)
00564     {
00565         dot = DotProduct (in->points[i], split->normal);
00566         dot -= split->dist;
00567         dists[i] = dot;
00568         if (dot > epsilon)
00569             sides[i] = SIDE_FRONT;
00570         else if (dot < -epsilon)
00571             sides[i] = SIDE_BACK;
00572         else
00573         {
00574             sides[i] = SIDE_ON;
00575         }
00576         counts[sides[i]]++;
00577     }
00578 
00579     if (!counts[SIDE_BACK])
00580     {
00581         if (!counts[SIDE_FRONT])
00582             return SIDE_ON;
00583         else
00584             return SIDE_FRONT;
00585     }
00586     
00587     if (!counts[SIDE_FRONT])
00588     {
00589         return SIDE_BACK;
00590     }
00591 
00592     sides[i] = sides[0];
00593     dists[i] = dists[0];
00594     
00595     neww = &out;
00596 
00597     neww->numpoints = 0;
00598     back->numpoints = 0;
00599 
00600     for (i=0 ; i<in->numpoints ; i++)
00601     {
00602         p1 = in->points[i];
00603 
00604         if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
00605         {
00606             _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
00607             return SIDE_FRONT;      // can't chop -- fall back to original
00608         }
00609         if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
00610         {
00611             _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
00612             return SIDE_FRONT;
00613         }
00614 
00615         if (sides[i] == SIDE_ON)
00616         {
00617             VectorCopy (p1, neww->points[neww->numpoints]);
00618             neww->numpoints++;
00619             VectorCopy (p1, back->points[back->numpoints]);
00620             back->numpoints++;
00621             continue;
00622         }
00623     
00624         if (sides[i] == SIDE_FRONT)
00625         {
00626             VectorCopy (p1, neww->points[neww->numpoints]);
00627             neww->numpoints++;
00628         }
00629         if (sides[i] == SIDE_BACK)
00630         {
00631             VectorCopy (p1, back->points[back->numpoints]);
00632             back->numpoints++;
00633         }
00634         
00635         if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
00636             continue;
00637             
00638         if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
00639         {
00640             _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
00641             return SIDE_FRONT;      // can't chop -- fall back to original
00642         }
00643 
00644         if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
00645         {
00646             _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
00647             return SIDE_FRONT;      // can't chop -- fall back to original
00648         }
00649 
00650         // generate a split point
00651         p2 = in->points[(i+1)%in->numpoints];
00652         
00653         dot = dists[i] / (dists[i]-dists[i+1]);
00654         for (j=0 ; j<3 ; j++)
00655         {   // avoid round off error when possible
00656             if (split->normal[j] == 1)
00657                 mid[j] = split->dist;
00658             else if (split->normal[j] == -1)
00659                 mid[j] = -split->dist;
00660             else
00661                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
00662         }
00663             
00664         VectorCopy (mid, neww->points[neww->numpoints]);
00665         neww->numpoints++;
00666         VectorCopy (mid, back->points[back->numpoints]);
00667         back->numpoints++;
00668     }
00669     memcpy(in, &out, sizeof(winding_t));
00670     
00671     return SIDE_CROSS;
00672 }
00673 
00674 /*
00675 =====================
00676 VL_LinkSurfaceIntoCluster
00677 =====================
00678 */
00679 void VL_LinkSurfaceIntoCluster(int cluster, int surfaceNum)
00680 {
00681     lleaf_t *leaf;
00682     int i;
00683 
00684     leaf = &leafs[cluster];
00685 
00686     for (i = 0; i < leaf->numSurfaces; i++)
00687     {
00688         if (clustersurfaces[leaf->firstSurface + i] == surfaceNum)
00689             return;
00690     }
00691     for (i = numclustersurfaces; i > leaf->firstSurface + leaf->numSurfaces; i--)
00692         clustersurfaces[i] = clustersurfaces[i-1];
00693     for (i = 0; i < portalclusters; i++)
00694     {
00695         if (i == cluster)
00696             continue;
00697         if (leafs[i].firstSurface >= leaf->firstSurface + leaf->numSurfaces)
00698             leafs[i].firstSurface++;
00699     }
00700     clustersurfaces[leaf->firstSurface + leaf->numSurfaces] = surfaceNum;
00701     leaf->numSurfaces++;
00702     numclustersurfaces++;
00703     if (numclustersurfaces >= MAX_MAP_LEAFFACES)
00704         Error("MAX_MAP_LEAFFACES");
00705 }
00706 
00707 /*
00708 =====================
00709 VL_R_LinkSurface
00710 =====================
00711 */
00712 void VL_R_LinkSurface(int nodenum, int surfaceNum, winding_t *w)
00713 {
00714     int leafnum, cluster, res;
00715     dnode_t *node;
00716     dplane_t *plane;
00717     winding_t back;
00718     plane_t split;
00719 
00720     while(nodenum >= 0)
00721     {
00722         node = &dnodes[nodenum];
00723         plane = &dplanes[node->planeNum];
00724 
00725         VectorCopy(plane->normal, split.normal);
00726         split.dist = plane->dist;
00727         res = VL_SplitWinding (w, &back, &split, 0.1);
00728 
00729         if (res == SIDE_FRONT)
00730         {
00731             nodenum = node->children[0];
00732         }
00733         else if (res == SIDE_BACK)
00734         {
00735             nodenum = node->children[1];
00736         }
00737         else if (res == SIDE_ON)
00738         {
00739             memcpy(&back, w, sizeof(winding_t));
00740             VL_R_LinkSurface(node->children[1], surfaceNum, &back);
00741             nodenum = node->children[0];
00742         }
00743         else
00744         {
00745             VL_R_LinkSurface(node->children[1], surfaceNum, &back);
00746             nodenum = node->children[0];
00747         }
00748     }
00749     leafnum = -nodenum - 1;
00750     cluster = dleafs[leafnum].cluster;
00751     if (cluster != -1)
00752     {
00753         VL_LinkSurfaceIntoCluster(cluster, surfaceNum);
00754     }
00755 }
00756 
00757 /*
00758 =====================
00759 VL_LinkSurfaces
00760 
00761 maybe link each facet seperately instead of the test surfaces?
00762 =====================
00763 */
00764 void VL_LinkSurfaces(void)
00765 {
00766     int i, j;
00767     lsurfaceTest_t *test;
00768     lFacet_t *facet;
00769     winding_t winding;
00770 
00771     for ( i = 0 ; i < numDrawSurfaces ; i++ )
00772     {
00773         test = lsurfaceTest[ i ];
00774         if (!test)
00775             continue;
00776         for (j = 0; j < test->numFacets; j++)
00777         {
00778             facet = &test->facets[j];
00779             memcpy(winding.points, facet->points, facet->numpoints * sizeof(vec3_t));
00780             winding.numpoints = facet->numpoints;
00781             VL_R_LinkSurface(0, i, &winding);
00782         }
00783     }
00784 }
00785 
00786 /*
00787 =====================
00788 VL_TextureMatrixFromPoints
00789 =====================
00790 */
00791 void VL_TextureMatrixFromPoints( lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
00792     int         i, j;
00793     float       t;
00794     float       m[3][4];
00795     float       s;
00796 
00797     // This is an incredibly stupid way of solving a three variable equation
00798     for ( i = 0 ; i < 2 ; i++ ) {
00799 
00800         m[0][0] = a->xyz[0];
00801         m[0][1] = a->xyz[1];
00802         m[0][2] = a->xyz[2];
00803         m[0][3] = a->st[i];
00804 
00805         m[1][0] = b->xyz[0];
00806         m[1][1] = b->xyz[1];
00807         m[1][2] = b->xyz[2];
00808         m[1][3] = b->st[i];
00809 
00810         m[2][0] = c->xyz[0];
00811         m[2][1] = c->xyz[1];
00812         m[2][2] = c->xyz[2];
00813         m[2][3] = c->st[i];
00814 
00815         if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) > fabs(m[2][0]) ) {
00816             for ( j = 0 ; j < 4 ; j ++ ) {
00817                 t = m[0][j];
00818                 m[0][j] = m[1][j];
00819                 m[1][j] = t;
00820             }
00821         } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) > fabs(m[1][0]) ) {
00822             for ( j = 0 ; j < 4 ; j ++ ) {
00823                 t = m[0][j];
00824                 m[0][j] = m[2][j];
00825                 m[2][j] = t;
00826             }
00827         }
00828 
00829         s = 1.0 / m[0][0];
00830         m[0][0] *= s;
00831         m[0][1] *= s;
00832         m[0][2] *= s;
00833         m[0][3] *= s;
00834 
00835         s = m[1][0];
00836         m[1][0] -= m[0][0] * s;
00837         m[1][1] -= m[0][1] * s;
00838         m[1][2] -= m[0][2] * s;
00839         m[1][3] -= m[0][3] * s;
00840 
00841         s = m[2][0];
00842         m[2][0] -= m[0][0] * s;
00843         m[2][1] -= m[0][1] * s;
00844         m[2][2] -= m[0][2] * s;
00845         m[2][3] -= m[0][3] * s;
00846 
00847         if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
00848             for ( j = 0 ; j < 4 ; j ++ ) {
00849                 t = m[1][j];
00850                 m[1][j] = m[2][j];
00851                 m[2][j] = t;
00852             }
00853         }
00854 
00855         s = 1.0 / m[1][1];
00856         m[1][0] *= s;
00857         m[1][1] *= s;
00858         m[1][2] *= s;
00859         m[1][3] *= s;
00860 
00861         s = m[2][1];// / m[1][1];
00862         m[2][0] -= m[1][0] * s;
00863         m[2][1] -= m[1][1] * s;
00864         m[2][2] -= m[1][2] * s;
00865         m[2][3] -= m[1][3] * s;
00866 
00867         s = 1.0 / m[2][2];
00868         m[2][0] *= s;
00869         m[2][1] *= s;
00870         m[2][2] *= s;
00871         m[2][3] *= s;
00872 
00873         f->textureMatrix[i][2] = m[2][3];
00874         f->textureMatrix[i][1] = m[1][3] - f->textureMatrix[i][2] * m[1][2];
00875         f->textureMatrix[i][0] = m[0][3] - f->textureMatrix[i][2] * m[0][2] - f->textureMatrix[i][1] * m[0][1];
00876 
00877         f->textureMatrix[i][3] = 0;
00878 /*
00879         s = fabs( DotProduct( a->xyz, f->textureMatrix[i] ) - a->st[i] );
00880         if ( s > 0.01 ) {
00881             Error( "Bad textureMatrix" );
00882         }
00883         s = fabs( DotProduct( b->xyz, f->textureMatrix[i] ) - b->st[i] );
00884         if ( s > 0.01 ) {
00885             Error( "Bad textureMatrix" );
00886         }
00887         s = fabs( DotProduct( c->xyz, f->textureMatrix[i] ) - c->st[i] );
00888         if ( s > 0.01 ) {
00889             Error( "Bad textureMatrix" );
00890         }
00891 */
00892     }
00893 }
00894 
00895 /*
00896 =====================
00897 VL_LightmapMatrixFromPoints
00898 =====================
00899 */
00900 void VL_LightmapMatrixFromPoints( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
00901     int         i, j;
00902     float       t;
00903     float       m[3][4], al, bl, cl;
00904     float       s;
00905     int         h, w, ssize;
00906     vec3_t      mins, maxs, delta, size, planeNormal;
00907     drawVert_t  *verts;
00908     static int  message;
00909 
00910     // vertex-lit triangle model
00911     if ( dsurf->surfaceType == MST_TRIANGLE_SOUP ) {
00912         return;
00913     }
00914     
00915     if ( dsurf->lightmapNum < 0 ) {
00916         return;     // doesn't need lighting
00917     }
00918 
00919     VectorClear(f->mins);
00920     if (dsurf->surfaceType != MST_PATCH)
00921     {
00922         ssize = samplesize;
00923         if (si->lightmapSampleSize)
00924             ssize = si->lightmapSampleSize;
00925         ClearBounds( mins, maxs );
00926         verts = &drawVerts[dsurf->firstVert];
00927         for ( i = 0 ; i < dsurf->numVerts ; i++ ) {
00928             AddPointToBounds( verts[i].xyz, mins, maxs );
00929         }
00930         // round to the lightmap resolution
00931         for ( i = 0 ; i < 3 ; i++ ) {
00932             mins[i] = ssize * floor( mins[i] / ssize );
00933             maxs[i] = ssize * ceil( maxs[i] / ssize );
00934             f->mins[i] = mins[i];
00935             size[i] = (maxs[i] - mins[i]) / ssize + 1;
00936         }
00937         // the two largest axis will be the lightmap size
00938         VectorClear(f->lightmapMatrix[0]);
00939         f->lightmapMatrix[0][3] = 0;
00940         VectorClear(f->lightmapMatrix[1]);
00941         f->lightmapMatrix[1][3] = 0;
00942 
00943         planeNormal[0] = fabs( dsurf->lightmapVecs[2][0] );
00944         planeNormal[1] = fabs( dsurf->lightmapVecs[2][1] );
00945         planeNormal[2] = fabs( dsurf->lightmapVecs[2][2] );
00946 
00947         if ( planeNormal[0] >= planeNormal[1] && planeNormal[0] >= planeNormal[2] ) {
00948             w = size[1];
00949             h = size[2];
00950             f->lightmapMatrix[0][1] = 1.0 / ssize;
00951             f->lightmapMatrix[1][2] = 1.0 / ssize;
00952         } else if ( planeNormal[1] >= planeNormal[0] && planeNormal[1] >= planeNormal[2] ) {
00953             w = size[0];
00954             h = size[2];
00955             f->lightmapMatrix[0][0] = 1.0 / ssize;
00956             f->lightmapMatrix[1][2] = 1.0 / ssize;
00957         } else {
00958             w = size[0];
00959             h = size[1];
00960             f->lightmapMatrix[0][0] = 1.0 / ssize;
00961             f->lightmapMatrix[1][1] = 1.0 / ssize;
00962         }
00963         if ( w > LIGHTMAP_WIDTH ) {
00964             VectorScale ( f->lightmapMatrix[0], (float)LIGHTMAP_SIZE/w, f->lightmapMatrix[0] );
00965         }
00966         
00967         if ( h > LIGHTMAP_HEIGHT ) {
00968             VectorScale ( f->lightmapMatrix[1], (float)LIGHTMAP_SIZE/h, f->lightmapMatrix[1] );
00969         }
00970         VectorSubtract(a->xyz, f->mins, delta);
00971         s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
00972         if ( fabs(s - a->lightmap[0]) > 0.01 ) {
00973             _printf( "Bad lightmapMatrix" );
00974         }
00975         t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
00976         if ( fabs(t - a->lightmap[1]) > 0.01 ) {
00977             _printf( "Bad lightmapMatrix" );
00978         }
00979         VectorSubtract(b->xyz, f->mins, delta);
00980         s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
00981         if ( fabs(s - b->lightmap[0]) > 0.01 ) {
00982             _printf( "Bad lightmapMatrix" );
00983         }
00984         t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
00985         if ( fabs(t - b->lightmap[1]) > 0.01 ) {
00986             _printf( "Bad lightmapMatrix" );
00987         }
00988         VectorSubtract(c->xyz, f->mins, delta);
00989         s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
00990         if ( fabs(s - c->lightmap[0]) > 0.01 ) {
00991             _printf( "Bad lightmapMatrix" );
00992         }
00993         t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
00994         if ( fabs(t - c->lightmap[1]) > 0.01 ) {
00995             _printf( "Bad lightmapMatrix" );
00996         }
00997         VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins);
00998         return;
00999     }
01000     // This is an incredibly stupid way of solving a three variable equation
01001     for ( i = 0 ; i < 2 ; i++ ) {
01002 
01003         if (i)
01004             al = a->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
01005         else
01006             al = a->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
01007 
01008         m[0][0] = a->xyz[0] - f->mins[0];
01009         m[0][1] = a->xyz[1] - f->mins[1];
01010         m[0][2] = a->xyz[2] - f->mins[2];
01011         m[0][3] = al;
01012 
01013         if (i)
01014             bl = b->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
01015         else
01016             bl = b->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
01017 
01018         m[1][0] = b->xyz[0] - f->mins[0];
01019         m[1][1] = b->xyz[1] - f->mins[1];
01020         m[1][2] = b->xyz[2] - f->mins[2];
01021         m[1][3] = bl;
01022 
01023         if (i)
01024             cl = c->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
01025         else
01026             cl = c->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
01027 
01028         m[2][0] = c->xyz[0] - f->mins[0];
01029         m[2][1] = c->xyz[1] - f->mins[1];
01030         m[2][2] = c->xyz[2] - f->mins[2];
01031         m[2][3] = cl;
01032 
01033         if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) >= fabs(m[2][0]) ) {
01034             for ( j = 0 ; j < 4 ; j ++ ) {
01035                 t = m[0][j];
01036                 m[0][j] = m[1][j];
01037                 m[1][j] = t;
01038             }
01039         } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) >= fabs(m[1][0]) ) {
01040             for ( j = 0 ; j < 4 ; j ++ ) {
01041                 t = m[0][j];
01042                 m[0][j] = m[2][j];
01043                 m[2][j] = t;
01044             }
01045         }
01046 
01047         if (m[0][0])
01048         {
01049             s = 1.0 / m[0][0];
01050             m[0][0] *= s;
01051             m[0][1] *= s;
01052             m[0][2] *= s;
01053             m[0][3] *= s;
01054 
01055             s = m[1][0];
01056             m[1][0] -= m[0][0] * s;
01057             m[1][1] -= m[0][1] * s;
01058             m[1][2] -= m[0][2] * s;
01059             m[1][3] -= m[0][3] * s;
01060 
01061             s = m[2][0];
01062             m[2][0] -= m[0][0] * s;
01063             m[2][1] -= m[0][1] * s;
01064             m[2][2] -= m[0][2] * s;
01065             m[2][3] -= m[0][3] * s;
01066         }
01067 
01068         if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
01069             for ( j = 0 ; j < 4 ; j ++ ) {
01070                 t = m[1][j];
01071                 m[1][j] = m[2][j];
01072                 m[2][j] = t;
01073             }
01074         }
01075 
01076         if (m[1][1])
01077         {
01078             s = 1.0 / m[1][1];
01079             m[1][0] *= s;
01080             m[1][1] *= s;
01081             m[1][2] *= s;
01082             m[1][3] *= s;
01083 
01084             s = m[2][1];
01085             m[2][0] -= m[1][0] * s;
01086             m[2][1] -= m[1][1] * s;
01087             m[2][2] -= m[1][2] * s;
01088             m[2][3] -= m[1][3] * s;
01089         }
01090 
01091         if (m[2][2])
01092         {
01093             s = 1.0 / m[2][2];
01094             m[2][0] *= s;
01095             m[2][1] *= s;
01096             m[2][2] *= s;
01097             m[2][3] *= s;
01098         }
01099 
01100         f->lightmapMatrix[i][2] = m[2][3];
01101         f->lightmapMatrix[i][1] = m[1][3] - f->lightmapMatrix[i][2] * m[1][2];
01102         f->lightmapMatrix[i][0] = m[0][3] - f->lightmapMatrix[i][2] * m[0][2] - f->lightmapMatrix[i][1] * m[0][1];
01103 
01104         f->lightmapMatrix[i][3] = 0;
01105 
01106         VectorSubtract(a->xyz, f->mins, delta);
01107         s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - al );
01108         if ( s > 0.01 ) {
01109             if (!message)
01110                 _printf( "Bad lightmapMatrix\n" );
01111             message = qtrue;
01112         }
01113         VectorSubtract(b->xyz, f->mins, delta);
01114         s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - bl );
01115         if ( s > 0.01 ) {
01116             if (!message)
01117                 _printf( "Bad lightmapMatrix\n" );
01118             message = qtrue;
01119         }
01120         VectorSubtract(c->xyz, f->mins, delta);
01121         s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - cl );
01122         if ( s > 0.01 ) {
01123             if (!message)
01124                 _printf( "Bad lightmapMatrix\n" );
01125             message = qtrue;
01126         }
01127         VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins);
01128     }
01129 }
01130 
01131 /*
01132 =============
01133 Plane_Equal
01134 =============
01135 */
01136 #define NORMAL_EPSILON  0.0001
01137 #define DIST_EPSILON    0.02
01138 
01139 int Plane_Equal(plane_t *a, plane_t *b, int flip)
01140 {
01141     vec3_t normal;
01142     float dist;
01143 
01144     if (flip) {
01145         normal[0] = - b->normal[0];
01146         normal[1] = - b->normal[1];
01147         normal[2] = - b->normal[2];
01148         dist = - b->dist;
01149     }
01150     else {
01151         normal[0] = b->normal[0];
01152         normal[1] = b->normal[1];
01153         normal[2] = b->normal[2];
01154         dist = b->dist;
01155     }
01156     if (
01157        fabs(a->normal[0] - normal[0]) < NORMAL_EPSILON
01158     && fabs(a->normal[1] - normal[1]) < NORMAL_EPSILON
01159     && fabs(a->normal[2] - normal[2]) < NORMAL_EPSILON
01160     && fabs(a->dist - dist) < DIST_EPSILON )
01161         return qtrue;
01162     return qfalse;
01163 }
01164 
01165 /*
01166 =============
01167 VL_PlaneFromPoints
01168 =============
01169 */
01170 qboolean VL_PlaneFromPoints( plane_t *plane, const vec3_t a, const vec3_t b, const vec3_t c ) {
01171     vec3_t  d1, d2;
01172 
01173     VectorSubtract( b, a, d1 );
01174     VectorSubtract( c, a, d2 );
01175     CrossProduct( d2, d1, plane->normal );
01176     if ( VectorNormalize( plane->normal, plane->normal ) == 0 ) {
01177         return qfalse;
01178     }
01179 
01180     plane->dist = DotProduct( a, plane->normal );
01181     return qtrue;
01182 }
01183 
01184 /*
01185 =====================
01186 VL_GenerateBoundaryForPoints
01187 =====================
01188 */
01189 void VL_GenerateBoundaryForPoints( plane_t *boundary, plane_t *plane, vec3_t a, vec3_t b ) {
01190     vec3_t  d1;
01191 
01192     // make a perpendicular vector to the edge and the surface
01193     VectorSubtract( a, b, d1 );
01194     CrossProduct( plane->normal, d1, boundary->normal );
01195     VectorNormalize( boundary->normal, boundary->normal );
01196     boundary->dist = DotProduct( a, boundary->normal );
01197 }
01198 
01199 /*
01200 =====================
01201 VL_GenerateFacetFor3Points
01202 =====================
01203 */
01204 qboolean VL_GenerateFacetFor3Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
01205     //
01206     vec3_t dir;
01207     int i;
01208 
01209     // if we can't generate a valid plane for the points, ignore the facet
01210     if ( !VL_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) {
01211         f->numpoints = 0;
01212         return qfalse;
01213     }
01214 
01215     f->num = numfacets++;
01216 
01217     VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] );
01218     VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] );
01219     VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] );
01220 
01221     f->lightmapCoords[0][0] = a->lightmap[0];
01222     f->lightmapCoords[0][1] = a->lightmap[1];
01223     f->lightmapCoords[1][0] = b->lightmap[0];
01224     f->lightmapCoords[1][1] = b->lightmap[1];
01225     f->lightmapCoords[2][0] = c->lightmap[0];
01226     f->lightmapCoords[2][1] = c->lightmap[1];
01227 
01228     VL_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] );
01229     VL_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] );
01230     VL_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[0] );
01231 
01232     for (i = 0; i < 3; i++)
01233     {
01234         VectorSubtract(f->points[(i+1)%3], f->points[i], dir);
01235         if (VectorLength(dir) < 0.1)
01236             return qfalse;
01237     }
01238 
01239     VL_TextureMatrixFromPoints( f, a, b, c );
01240     VL_LightmapMatrixFromPoints( dsurf, si, f, a, b, c );
01241 
01242     f->numpoints = 3;
01243 
01244     return qtrue;
01245 }
01246 
01247 /*
01248 =====================
01249 VL_GenerateFacetFor4Points
01250 
01251 Attempts to use four points as a planar quad
01252 =====================
01253 */
01254 #define PLANAR_EPSILON  0.1
01255 qboolean VL_GenerateFacetFor4Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c, drawVert_t *d ) {
01256     float   dist;
01257     vec3_t dir;
01258     int i;
01259     plane_t plane;
01260 
01261     // if we can't generate a valid plane for the points, ignore the facet
01262     if ( !VL_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) {
01263         f->numpoints = 0;
01264         return qfalse;
01265     }
01266 
01267     // if the fourth point is also on the plane, we can make a quad facet
01268     dist = DotProduct( d->xyz, f->plane.normal ) - f->plane.dist;
01269     if ( fabs( dist ) > PLANAR_EPSILON ) {
01270         f->numpoints = 0;
01271         return qfalse;
01272     }
01273 
01274     VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] );
01275     VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] );
01276     VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] );
01277     VectorAdd( d->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[3] );
01278 
01279     for (i = 1; i < 4; i++)
01280     {
01281         if ( !VL_PlaneFromPoints( &plane, f->points[i], f->points[(i+1) % 4], f->points[(i+2) % 4]) ) {
01282             f->numpoints = 0;
01283             return qfalse;
01284         }
01285 
01286         if (!Plane_Equal(&f->plane, &plane, qfalse)) {
01287             f->numpoints = 0;
01288             return qfalse;
01289         }
01290     }
01291 
01292     f->lightmapCoords[0][0] = a->lightmap[0];
01293     f->lightmapCoords[0][1] = a->lightmap[1];
01294     f->lightmapCoords[1][0] = b->lightmap[0];
01295     f->lightmapCoords[1][1] = b->lightmap[1];
01296     f->lightmapCoords[2][0] = c->lightmap[0];
01297     f->lightmapCoords[2][1] = c->lightmap[1];
01298     f->lightmapCoords[3][0] = d->lightmap[0];
01299     f->lightmapCoords[3][1] = d->lightmap[1];
01300 
01301     VL_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] );
01302     VL_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] );
01303     VL_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[3] );
01304     VL_GenerateBoundaryForPoints( &f->boundaries[3], &f->plane, f->points[3], f->points[0] );
01305 
01306     for (i = 0; i < 4; i++)
01307     {
01308         VectorSubtract(f->points[(i+1)%4], f->points[i], dir);
01309         if (VectorLength(dir) < 0.1)
01310             return qfalse;
01311     }
01312 
01313     VL_TextureMatrixFromPoints( f, a, b, c );
01314     VL_LightmapMatrixFromPoints( dsurf, si, f, a, b, c );
01315 
01316     f->num = numfacets++;
01317     f->numpoints = 4;
01318 
01319     return qtrue;
01320 }
01321 
01322 /*
01323 ===============
01324 VL_SphereFromBounds
01325 ===============
01326 */
01327 void VL_SphereFromBounds( vec3_t mins, vec3_t maxs, vec3_t origin, float *radius ) {
01328     vec3_t      temp;
01329 
01330     VectorAdd( mins, maxs, origin );
01331     VectorScale( origin, 0.5, origin );
01332     VectorSubtract( maxs, origin, temp );
01333     *radius = VectorLength( temp );
01334 }
01335 
01336 /*
01337 ====================
01338 VL_FacetsForTriangleSurface
01339 ====================
01340 */
01341 void VL_FacetsForTriangleSurface( dsurface_t *dsurf, shaderInfo_t *si, lsurfaceTest_t *test ) {
01342     int         i;
01343     drawVert_t  *v1, *v2, *v3, *v4;
01344     int         count;
01345     int         i1, i2, i3, i4, i5, i6;
01346 
01347     test->patch = qfalse;
01348     if (dsurf->surfaceType == MST_TRIANGLE_SOUP)
01349         test->trisoup = qtrue;
01350     else
01351         test->trisoup = qfalse;
01352     test->numFacets = dsurf->numIndexes / 3;
01353     test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
01354     test->shader = si;
01355 
01356     count = 0;
01357     for ( i = 0 ; i < test->numFacets ; i++ ) {
01358         i1 = drawIndexes[ dsurf->firstIndex + i*3 ];
01359         i2 = drawIndexes[ dsurf->firstIndex + i*3 + 1 ];
01360         i3 = drawIndexes[ dsurf->firstIndex + i*3 + 2 ];
01361 
01362         v1 = &drawVerts[ dsurf->firstVert + i1 ];
01363         v2 = &drawVerts[ dsurf->firstVert + i2 ];
01364         v3 = &drawVerts[ dsurf->firstVert + i3 ];
01365 
01366         // try and make a quad out of two triangles
01367         if ( i != test->numFacets - 1 ) {
01368             i4 = drawIndexes[ dsurf->firstIndex + i*3 + 3 ];
01369             i5 = drawIndexes[ dsurf->firstIndex + i*3 + 4 ];
01370             i6 = drawIndexes[ dsurf->firstIndex + i*3 + 5 ];
01371             if ( i4 == i3 && i5 == i2 ) {
01372                 v4 = &drawVerts[ dsurf->firstVert + i6 ];
01373                 if ( VL_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v2, v4, v3 ) ) {
01374                     count++;
01375                     i++;        // skip next tri
01376                     continue;
01377                 }
01378             }
01379         }
01380 
01381         if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v2, v3 )) {
01382             count++;
01383         }
01384     }       
01385 
01386     // we may have turned some pairs into quads
01387     test->numFacets = count;
01388 }
01389 
01390 /*
01391 ====================
01392 VL_FacetsForPatch
01393 ====================
01394 */
01395 void VL_FacetsForPatch( dsurface_t *dsurf, int surfaceNum, shaderInfo_t *si, lsurfaceTest_t *test ) {
01396     int         i, j, x, y;
01397     drawVert_t  *v1, *v2, *v3, *v4;
01398     int         count, ssize;
01399     mesh_t      mesh;
01400     mesh_t      *subdivided, *detailmesh, *newmesh;
01401     int widthtable[LIGHTMAP_SIZE], heighttable[LIGHTMAP_SIZE];
01402 
01403     mesh.width = dsurf->patchWidth;
01404     mesh.height = dsurf->patchHeight;
01405     mesh.verts = &drawVerts[ dsurf->firstVert ];
01406 
01407     newmesh = SubdivideMesh( mesh, 8, 999 );
01408     PutMeshOnCurve( *newmesh );
01409     MakeMeshNormals( *newmesh );
01410 
01411     subdivided = RemoveLinearMeshColumnsRows( newmesh );
01412     FreeMesh(newmesh);
01413 
01414     //  DebugNet_RemoveAllPolys();
01415     //  DebugNet_DrawMesh(subdivided);
01416 
01417     ssize = samplesize;
01418     if (si->lightmapSampleSize)
01419         ssize = si->lightmapSampleSize;
01420 
01421     if ( dsurf->lightmapNum >= 0 ) {
01422 
01423         detailmesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_SIZE, widthtable, heighttable);
01424         test->detailMesh = detailmesh;
01425 
01426         // DebugNet_RemoveAllPolys();
01427         // DebugNet_DrawMesh(detailmesh);
01428 
01429         if ( detailmesh->width != dsurf->lightmapWidth || detailmesh->height != dsurf->lightmapHeight ) {
01430             Error( "Mesh lightmap miscount");
01431         }
01432     }
01433     else {
01434         test->detailMesh = NULL;
01435         memset(widthtable, 0, sizeof(widthtable));
01436         memset(heighttable, 0, sizeof(heighttable));
01437     }
01438 
01439     test->patch = qtrue;
01440     test->trisoup = qfalse;
01441     test->numFacets = ( subdivided->width - 1 ) * ( subdivided->height - 1 ) * 2;
01442     test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
01443     test->shader = si;
01444 
01445     count = 0;
01446     x = 0;
01447     for ( i = 0 ; i < subdivided->width - 1 ; i++ ) {
01448         y = 0;
01449         for ( j = 0 ; j < subdivided->height - 1 ; j++ ) {
01450 
01451             v1 = subdivided->verts + j * subdivided->width + i;
01452             v2 = v1 + 1;
01453             v3 = v1 + subdivided->width + 1;
01454             v4 = v1 + subdivided->width;
01455 
01456             if ( VL_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v4, v3, v2 ) ) {
01457                 test->facets[count].x = x;
01458                 test->facets[count].y = y;
01459                 test->facets[count].width = widthtable[i];
01460                 test->facets[count].height = heighttable[j];
01461                 count++;
01462             } else {
01463                 if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v4, v3 )) {
01464                     test->facets[count].x = x;
01465                     test->facets[count].y = y;
01466                     test->facets[count].width = widthtable[i];
01467                     test->facets[count].height = heighttable[j];
01468                     count++;
01469                 }
01470                 if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v3, v2 )) {
01471                     test->facets[count].x = x;
01472                     test->facets[count].y = y;
01473                     test->facets[count].width = widthtable[i];
01474                     test->facets[count].height = heighttable[j];
01475                     count++;
01476                 }
01477             }
01478             y += heighttable[j];
01479         }
01480         x += widthtable[i];
01481     }
01482     test->numFacets = count;
01483 
01484     FreeMesh(subdivided);
01485 }
01486 
01487 /*
01488 =====================
01489 VL_InitSurfacesForTesting
01490 =====================
01491 */
01492 void VL_InitSurfacesForTesting( void ) {
01493 
01494     int             i, j, k;
01495     dsurface_t      *dsurf;
01496     lsurfaceTest_t  *test;
01497     shaderInfo_t    *si;
01498     lFacet_t        *facet;
01499 
01500     for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
01501         // don't light the entity surfaces with vlight
01502         if ( entitySurface[i] )
01503             continue;
01504         //
01505         dsurf = &drawSurfaces[ i ];
01506         if ( !dsurf->numIndexes && !dsurf->patchWidth ) {
01507             continue;
01508         }
01509 
01510         si = ShaderInfoForShader( dshaders[ dsurf->shaderNum].shader );
01511         // if the surface is translucent and does not cast an alpha shadow
01512         if ( (si->contents & CONTENTS_TRANSLUCENT) && !(si->surfaceFlags & SURF_ALPHASHADOW) ) {
01513             // if the surface has no lightmap
01514             if ( dsurf->lightmapNum < 0 )
01515                 continue;
01516         }
01517 
01518         test = malloc( sizeof( *test ) );
01519         memset(test, 0, sizeof( *test ));
01520         test->mutex = MutexAlloc();
01521         test->numvolumes = 0;
01522         if (si->forceTraceLight)
01523             test->always_tracelight = qtrue;
01524         else if (si->forceVLight)
01525             test->always_vlight = qtrue;
01526         lsurfaceTest[i] = test;
01527 
01528         if ( dsurf->surfaceType == MST_TRIANGLE_SOUP || dsurf->surfaceType == MST_PLANAR ) {
01529             VL_FacetsForTriangleSurface( dsurf, si, test );
01530         } else if ( dsurf->surfaceType == MST_PATCH ) {
01531             VL_FacetsForPatch( dsurf, i, si, test );
01532         }
01533         if (numfacets >= MAX_FACETS)
01534             Error("numfacets >= MAX_FACETS (%d)", MAX_FACETS);
01535 
01536         ClearBounds( test->mins, test->maxs );
01537         for (j = 0; j < test->numFacets; j++)
01538         {
01539             facet = &test->facets[j];
01540             for ( k = 0 ; k < facet->numpoints; k++) {
01541                 AddPointToBounds( facet->points[k], test->mins, test->maxs );
01542             }
01543         }
01544         VL_SphereFromBounds( test->mins, test->maxs, test->origin, &test->radius );
01545     }
01546     _printf("%6d facets\n", numfacets);
01547     _printf("linking surfaces...\n");
01548     VL_LinkSurfaces();
01549 }
01550 
01551 /*
01552 =============
01553 VL_ChopWinding
01554 =============
01555 */
01556 int VL_ChopWinding (winding_t *in, plane_t *split, float epsilon)
01557 {
01558     vec_t   dists[128];
01559     int     sides[128];
01560     int     counts[3];
01561     vec_t   dot;
01562     int     i, j;
01563     vec_t   *p1, *p2;
01564     vec3_t  mid;
01565     winding_t out;
01566     winding_t   *neww;
01567 
01568     counts[0] = counts[1] = counts[2] = 0;
01569 
01570     // determine sides for each point
01571     for (i=0 ; i<in->numpoints ; i++)
01572     {
01573         dot = DotProduct (in->points[i], split->normal);
01574         dot -= split->dist;
01575         dists[i] = dot;
01576         if (dot > epsilon)
01577             sides[i] = SIDE_FRONT;
01578         else if (dot < -epsilon)
01579             sides[i] = SIDE_BACK;
01580         else
01581         {
01582             sides[i] = SIDE_ON;
01583         }
01584         counts[sides[i]]++;
01585     }
01586 
01587     if (!counts[SIDE_BACK])
01588     {
01589         if (!counts[SIDE_FRONT])
01590             return SIDE_ON;
01591         else
01592             return SIDE_FRONT;
01593     }
01594     
01595     if (!counts[SIDE_FRONT])
01596     {
01597         return SIDE_BACK;
01598     }
01599 
01600     sides[i] = sides[0];
01601     dists[i] = dists[0];
01602     
01603     neww = &out;
01604 
01605     neww->numpoints = 0;
01606 
01607     for (i=0 ; i<in->numpoints ; i++)
01608     {
01609         p1 = in->points[i];
01610 
01611         if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
01612         {
01613             _printf("WARNING: VL_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
01614             return SIDE_FRONT;      // can't chop -- fall back to original
01615         }
01616 
01617         if (sides[i] == SIDE_ON)
01618         {
01619             VectorCopy (p1, neww->points[neww->numpoints]);
01620             neww->numpoints++;
01621             continue;
01622         }
01623     
01624         if (sides[i] == SIDE_FRONT)
01625         {
01626             VectorCopy (p1, neww->points[neww->numpoints]);
01627             neww->numpoints++;
01628         }
01629         
01630         if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
01631             continue;
01632             
01633         if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
01634         {
01635             _printf("WARNING: VL_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
01636             return SIDE_FRONT;      // can't chop -- fall back to original
01637         }
01638 
01639         // generate a split point
01640         p2 = in->points[(i+1)%in->numpoints];
01641         
01642         dot = dists[i] / (dists[i]-dists[i+1]);
01643         for (j=0 ; j<3 ; j++)
01644         {   // avoid round off error when possible
01645             if (split->normal[j] == 1)
01646                 mid[j] = split->dist;
01647             else if (split->normal[j] == -1)
01648                 mid[j] = -split->dist;
01649             else
01650                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
01651         }
01652             
01653         VectorCopy (mid, neww->points[neww->numpoints]);
01654         neww->numpoints++;
01655     }
01656     memcpy(in, &out, sizeof(winding_t));
01657     
01658     return SIDE_CROSS;
01659 }
01660 
01661 /*
01662 =============
01663 VL_ChopWindingWithBrush
01664 
01665   returns all winding fragments outside the brush
01666 =============
01667 */
01668 int VL_ChopWindingWithBrush(winding_t *w, dbrush_t *brush, winding_t *outwindings, int maxout)
01669 {
01670     int i, res, numout;
01671     winding_t front, back;
01672     plane_t plane;
01673 
01674     numout = 0;
01675     memcpy(front.points, w->points, w->numpoints * sizeof(vec3_t));
01676     front.numpoints = w->numpoints;
01677     for (i = 0; i < brush->numSides; i++)
01678     {
01679         VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal);
01680         VectorInverse(plane.normal);
01681         plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist;
01682         res = VL_SplitWinding(&front, &back, &plane, 0.1);
01683         if (res == SIDE_BACK || res == SIDE_ON)
01684         {
01685             memcpy(outwindings[0].points, w->points, w->numpoints * sizeof(vec3_t));
01686             outwindings[0].numpoints = w->numpoints;
01687             return 1;   //did not intersect
01688         }
01689         if (res != SIDE_FRONT)
01690         {
01691             if (numout >= maxout)
01692             {
01693                 _printf("WARNING: VL_ChopWindingWithBrush: more than %d windings\n", maxout);
01694                 return 0;
01695             }
01696             memcpy(outwindings[numout].points, back.points, back.numpoints * sizeof(vec3_t));
01697             outwindings[numout].numpoints = back.numpoints;
01698             numout++;
01699         }
01700     }
01701     return numout;
01702 }
01703 
01704 /*
01705 =============
01706 VL_WindingAreaOutsideBrushes
01707 =============
01708 */
01709 float VL_WindingAreaOutsideBrushes(winding_t *w, int *brushnums, int numbrushes)
01710 {
01711     int i, j, numwindings[2], n;
01712     winding_t windingsbuf[2][64];
01713     dbrush_t *brush;
01714     float area;
01715 
01716     memcpy(windingsbuf[0][0].points, w->points, w->numpoints * sizeof(vec3_t));
01717     windingsbuf[0][0].numpoints = w->numpoints;
01718     numwindings[0] = 1;
01719     for (i = 0; i < numbrushes; i++)
01720     {
01721         brush = &dbrushes[brushnums[i]];
01722         if (!(dshaders[brush->shaderNum].contentFlags & (
01723                     CONTENTS_LAVA
01724                     | CONTENTS_SLIME
01725                     | CONTENTS_WATER
01726                     | CONTENTS_FOG
01727                     | CONTENTS_AREAPORTAL
01728                     | CONTENTS_PLAYERCLIP
01729                     | CONTENTS_MONSTERCLIP
01730                     | CONTENTS_CLUSTERPORTAL
01731                     | CONTENTS_DONOTENTER
01732                     | CONTENTS_BODY
01733                     | CONTENTS_CORPSE
01734                     | CONTENTS_TRANSLUCENT
01735                     | CONTENTS_TRIGGER
01736                     | CONTENTS_NODROP) ) &&
01737             (dshaders[brush->shaderNum].contentFlags & CONTENTS_SOLID) )
01738         {
01739             numwindings[!(i & 1)] = 0;
01740             for (j = 0; j < numwindings[i&1]; j++)
01741             {
01742                 n = VL_ChopWindingWithBrush(&windingsbuf[i&1][j], brush,
01743                                             &windingsbuf[!(i&1)][numwindings[!(i&1)]],
01744                                             64 - numwindings[!(i&1)]);
01745                 numwindings[!(i&1)] += n;
01746             }
01747             if (!numwindings[!(i&1)])
01748                 return 0;
01749         }
01750         else
01751         {
01752             for (j = 0; j < numwindings[i&1]; j++)
01753             {
01754                 windingsbuf[!(i&1)][j] = windingsbuf[i&1][j];
01755             }
01756             numwindings[!(i&1)] = numwindings[i&1];
01757         }
01758     }
01759     area = 0;
01760     for (j = 0; j < numwindings[i&1]; j++)
01761     {
01762         area += WindingArea(&windingsbuf[i&1][j]);
01763     }
01764     return area;
01765 }
01766 
01767 /*
01768 =============
01769 VL_R_WindingAreaOutsideSolid
01770 =============
01771 */
01772 float VL_R_WindingAreaOutsideSolid(winding_t *w, vec3_t normal, int nodenum)
01773 {
01774     int leafnum, res;
01775     float area;
01776     dnode_t *node;
01777     dleaf_t *leaf;
01778     dplane_t *plane;
01779     winding_t back;
01780     plane_t split;
01781 
01782     area = 0;
01783     while(nodenum >= 0)
01784     {
01785         node = &dnodes[nodenum];
01786         plane = &dplanes[node->planeNum];
01787 
01788         VectorCopy(plane->normal, split.normal);
01789         split.dist = plane->dist;
01790         res = VL_SplitWinding (w, &back, &split, 0.1);
01791 
01792         if (res == SIDE_FRONT)
01793         {
01794             nodenum = node->children[0];
01795         }
01796         else if (res == SIDE_BACK)
01797         {
01798             nodenum = node->children[1];
01799         }
01800         else if (res == SIDE_ON)
01801         {
01802             if (DotProduct(normal, plane->normal) > 0)
01803                 nodenum = node->children[0];
01804             else
01805                 nodenum = node->children[1];
01806         }
01807         else
01808         {
01809             area += VL_R_WindingAreaOutsideSolid(&back, normal, node->children[1]);
01810             nodenum = node->children[0];
01811         }
01812     }
01813     leafnum = -nodenum - 1;
01814     leaf = &dleafs[leafnum];
01815     if (leaf->cluster != -1)
01816     {
01817         area += VL_WindingAreaOutsideBrushes(w, &dleafbrushes[leaf->firstLeafBrush], leaf->numLeafBrushes);
01818     }
01819     return area;
01820 }
01821 
01822 /*
01823 =============
01824 VL_WindingAreaOutsideSolid
01825 =============
01826 */
01827 float VL_WindingAreaOutsideSolid(winding_t *w, vec3_t normal)
01828 {
01829     return VL_R_WindingAreaOutsideSolid(w, normal, 0);
01830 }
01831 
01832 /*
01833 =============
01834 VL_ChopWindingWithFacet
01835 =============
01836 */
01837 float VL_ChopWindingWithFacet(winding_t *w, lFacet_t *facet)
01838 {
01839     int i;
01840 
01841     for (i = 0; i < facet->numpoints; i++)
01842     {
01843         if (VL_ChopWinding(w, &facet->boundaries[i], 0) == SIDE_BACK)
01844             return 0;
01845     }
01846     if (nostitching)
01847         return WindingArea(w);
01848     else
01849         return VL_WindingAreaOutsideSolid(w, facet->plane.normal);
01850 }
01851 
01852 /*
01853 =============
01854 VL_CalcVisibleLightmapPixelArea
01855 
01856 nice brute force ;)
01857 =============
01858 */
01859 void VL_CalcVisibleLightmapPixelArea(void)
01860 {
01861     int             i, j, x, y, k;
01862     dsurface_t      *ds;
01863     lsurfaceTest_t  *test;
01864     mesh_t          *mesh;
01865     winding_t w, tmpw;
01866     float area;
01867 
01868     _printf("calculating visible lightmap pixel area...\n");
01869     for ( i = 0 ; i < numDrawSurfaces ; i++ )
01870     {
01871         test = lsurfaceTest[ i ];
01872         if (!test)
01873             continue;
01874         ds = &drawSurfaces[ i ];
01875 
01876         if ( ds->lightmapNum < 0 )
01877             continue;
01878 
01879         for (y = 0; y < ds->lightmapHeight; y++)
01880         {
01881             for (x = 0; x < ds->lightmapWidth; x++)
01882             {
01883                 if (ds->surfaceType == MST_PATCH)
01884                 {
01885                     if (y == ds->lightmapHeight-1)
01886                         continue;
01887                     if (x == ds->lightmapWidth-1)
01888                         continue;
01889                     mesh = lsurfaceTest[i]->detailMesh;
01890                     VectorCopy( mesh->verts[y*mesh->width+x].xyz, w.points[0]);
01891                     VectorCopy( mesh->verts[(y+1)*mesh->width+x].xyz, w.points[1]);
01892                     VectorCopy( mesh->verts[(y+1)*mesh->width+x+1].xyz, w.points[2]);
01893                     VectorCopy( mesh->verts[y*mesh->width+x+1].xyz, w.points[3]);
01894                     w.numpoints = 4;
01895                     if (nostitching)
01896                         area = WindingArea(&w);
01897                     else
01898                         area = VL_WindingAreaOutsideSolid(&w, mesh->verts[y*mesh->width+x].normal);
01899                 }
01900                 else
01901                 {
01902                     VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[0]);
01903                     VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[0]);
01904                     VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[3]);
01905                     VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[3]);
01906                     VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[2]);
01907                     VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[2]);
01908                     VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[1]);
01909                     VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[1]);
01910                     w.numpoints = 4;
01911                     area = 0;
01912                     for (j = 0; j < test->numFacets; j++)
01913                     {
01914                         memcpy(&tmpw, &w, sizeof(winding_t));
01915                         area += VL_ChopWindingWithFacet(&tmpw, &test->facets[j]);
01916                     }
01917                 }
01918                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
01919                         * LIGHTMAP_WIDTH + ds->lightmapX + x;
01920                 lightmappixelarea[k] = area;
01921             }
01922         }
01923     }
01924 }
01925 
01926 /*
01927 =============
01928 VL_FindAdjacentSurface
01929 =============
01930 */
01931 int VL_FindAdjacentSurface(int surfaceNum, int facetNum, vec3_t p1, vec3_t p2, int *sNum, int *fNum, int *point)
01932 {
01933     int i, j, k;
01934     lsurfaceTest_t *test;
01935     lFacet_t *facet;
01936     dsurface_t *ds;
01937     float *fp1, *fp2;
01938     vec3_t dir;
01939     plane_t *facetplane;
01940     //  winding_t w;
01941 
01942     facetplane = &lsurfaceTest[surfaceNum]->facets[facetNum].plane;
01943     //  DebugNet_RemoveAllPolys();
01944     //  memcpy(w.points, lsurfaceTest[surfaceNum]->facets[facetNum].points,
01945     //          lsurfaceTest[surfaceNum]->facets[facetNum].numpoints * sizeof(vec3_t));
01946     //  w.numpoints = lsurfaceTest[surfaceNum]->facets[facetNum].numpoints;
01947     //  DebugNet_DrawWinding(&w, 2);
01948     for ( i = 0 ; i < numDrawSurfaces ; i++ )
01949     {
01950         if (i == surfaceNum)
01951             continue;
01952         test = lsurfaceTest[ i ];
01953         if (!test)
01954             continue;
01955         if (test->trisoup)// || test->patch)
01956             continue;
01957         ds = &drawSurfaces[i];
01958         if ( ds->lightmapNum < 0 )
01959             continue;
01960         //if this surface is not even near the edge
01961         VectorSubtract(p1, test->origin, dir);
01962         if (fabs(dir[0]) > test->radius ||
01963             fabs(dir[1]) > test->radius ||
01964             fabs(dir[1]) > test->radius)
01965         {
01966             VectorSubtract(p2, test->origin, dir);
01967             if (fabs(dir[0]) > test->radius ||
01968                 fabs(dir[1]) > test->radius ||
01969                 fabs(dir[1]) > test->radius)
01970             {
01971                 continue;
01972             }
01973         }
01974         //
01975         for (j = 0; j < test->numFacets; j++)
01976         {
01977             facet = &test->facets[j];
01978             //
01979             //if (!Plane_Equal(&facet->plane, facetplane, qfalse))
01980             if (DotProduct(facet->plane.normal, facetplane->normal) < 0.9)
01981             {
01982                 if (!test->trisoup && !test->patch)
01983                     break;
01984                 continue;
01985             }
01986             //
01987             for (k = 0; k < facet->numpoints; k++)
01988             {
01989                 fp1 = facet->points[k];
01990                 if (fabs(p2[0] - fp1[0]) < 0.1 &&
01991                     fabs(p2[1] - fp1[1]) < 0.1 &&
01992                     fabs(p2[2] - fp1[2]) < 0.1)
01993                 {
01994                     fp2 = facet->points[(k+1) % facet->numpoints];
01995                     if (fabs(p1[0] - fp2[0]) < 0.1 &&
01996                         fabs(p1[1] - fp2[1]) < 0.1 &&
01997                         fabs(p1[2] - fp2[2]) < 0.1)
01998                     {
01999                         //  memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t));
02000                         //  w.numpoints = facet->numpoints;
02001                         //  DebugNet_DrawWinding(&w, 1);
02002                         *sNum = i;
02003                         *fNum = j;
02004                         *point = k;
02005                         return qtrue;
02006                     }
02007                 }
02008                 /*
02009                 else if (fabs(p1[0] - fp1[0]) < 0.1 &&
02010                     fabs(p1[1] - fp1[1]) < 0.1 &&
02011                     fabs(p1[2] - fp1[2]) < 0.1)
02012                 {
02013                     fp2 = facet->points[(k+1) % facet->numpoints];
02014                     if (fabs(p2[0] - fp2[0]) < 0.1 &&
02015                         fabs(p2[1] - fp2[1]) < 0.1 &&
02016                         fabs(p2[2] - fp2[2]) < 0.1)
02017                     {
02018                         //  memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t));
02019                         //  w.numpoints = facet->numpoints;
02020                         //  DebugNet_DrawWinding(&w, 1);
02021                         *sNum = i;
02022                         *fNum = j;
02023                         *point = k;
02024                         return qtrue;
02025                     }
02026                 }
02027                 //*/
02028             }
02029         }
02030     }
02031     return qfalse;
02032 }
02033 
02034 /*
02035 =============
02036 VL_SmoothenLightmapEdges
02037 
02038 this code is used to smoothen lightmaps across surface edges
02039 =============
02040 */
02041 void VL_SmoothenLightmapEdges(void)
02042 {
02043     int i, j, k, coords1[2][2];
02044     float coords2[2][2];
02045     int x1, y1, xinc1, yinc1, k1, k2;
02046     float x2, y2, xinc2, yinc2, length;
02047     int surfaceNum, facetNum, point;
02048     lsurfaceTest_t *test;
02049     lFacet_t *facet1, *facet2;
02050     dsurface_t *ds1, *ds2;
02051     float *p[2], s, t, *color1, *color2;
02052     vec3_t dir, cross;
02053 
02054     for ( i = 0 ; i < numDrawSurfaces ; i++ )
02055     {
02056         test = lsurfaceTest[ i ];
02057         if (!test)
02058             continue;
02059         if (test->trisoup)// || test->patch)
02060             continue;
02061         ds1 = &drawSurfaces[i];
02062         if ( ds1->lightmapNum < 0 )
02063             continue;
02064         for (j = 0; j < test->numFacets; j++)
02065         {
02066             facet1 = &test->facets[j];
02067             //
02068             for (k = 0; k < facet1->numpoints; k++)
02069             {
02070                 p[0] = facet1->points[k];
02071                 p[1] = facet1->points[(k+1)%facet1->numpoints];
02072                 //
02073                 coords1[0][0] = facet1->lightmapCoords[k][0] * LIGHTMAP_SIZE;
02074                 coords1[0][1] = facet1->lightmapCoords[k][1] * LIGHTMAP_SIZE;
02075                 coords1[1][0] = facet1->lightmapCoords[(k+1)%facet1->numpoints][0] * LIGHTMAP_SIZE;
02076                 coords1[1][1] = facet1->lightmapCoords[(k+1)%facet1->numpoints][1] * LIGHTMAP_SIZE;
02077                 if (coords1[0][0] >= LIGHTMAP_SIZE)
02078                     coords1[0][0] = LIGHTMAP_SIZE-1;
02079                 if (coords1[0][1] >= LIGHTMAP_SIZE)
02080                     coords1[0][1] = LIGHTMAP_SIZE-1;
02081                 if (coords1[1][0] >= LIGHTMAP_SIZE)
02082                     coords1[1][0] = LIGHTMAP_SIZE-1;
02083                 if (coords1[1][1] >= LIGHTMAP_SIZE)
02084                     coords1[1][1] = LIGHTMAP_SIZE-1;
02085                 // try one row or column further because on flat faces the lightmap can
02086                 // extend beyond the edge
02087                 VectorSubtract(p[1], p[0], dir);
02088                 VectorNormalize(dir, dir);
02089                 CrossProduct(dir, facet1->plane.normal, cross);
02090                 //
02091                 if (coords1[0][0] - coords1[1][0] == 0)
02092                 {
02093                     s = DotProduct( cross, facet1->lightmapMatrix[0] );
02094                     coords1[0][0] += s < 0 ? 1 : -1;
02095                     coords1[1][0] += s < 0 ? 1 : -1;
02096                     if (coords1[0][0] < ds1->lightmapX || coords1[0][0] >= ds1->lightmapX + ds1->lightmapWidth)
02097                     {
02098                         coords1[0][0] += s < 0 ? -1 : 1;
02099                         coords1[1][0] += s < 0 ? -1 : 1;
02100                     }
02101                     length = fabs(coords1[1][1] - coords1[0][1]);
02102                 }
02103                 else if (coords1[0][1] - coords1[1][1] == 0)
02104                 {
02105                     t = DotProduct( cross, facet1->lightmapMatrix[1] );
02106                     coords1[0][1] += t < 0 ? 1 : -1;
02107                     coords1[1][1] += t < 0 ? 1 : -1;
02108                     if (coords1[0][1] < ds1->lightmapY || coords1[0][1] >= ds1->lightmapY + ds1->lightmapHeight)
02109                     {
02110                         coords1[0][1] += t < 0 ? -1 : 1;
02111                         coords1[1][1] += t < 0 ? -1 : 1;
02112                     }
02113                     length = fabs(coords1[1][0] - coords1[0][0]);
02114                 }
02115                 else
02116                 {
02117                     //the edge is not parallell to one of the lightmap axis
02118                     continue;
02119                 }
02120                 //
02121                 x1 = coords1[0][0];
02122                 y1 = coords1[0][1];
02123                 xinc1 = coords1[1][0] - coords1[0][0];
02124                 if (xinc1 < 0) xinc1 = -1;
02125                 if (xinc1 > 0) xinc1 = 1;
02126                 yinc1 = coords1[1][1] - coords1[0][1];
02127                 if (yinc1 < 0) yinc1 = -1;
02128                 if (yinc1 > 0) yinc1 = 1;
02129                 // the edge should be parallell to one of the lightmap axis
02130                 if (xinc1 != 0 && yinc1 != 0)
02131                     continue;
02132                 //
02133                 if (!VL_FindAdjacentSurface(i, j, p[0], p[1], &surfaceNum, &facetNum, &point))
02134                     continue;
02135                 //
02136                 ds2 = &drawSurfaces[surfaceNum];
02137                 facet2 = &lsurfaceTest[surfaceNum]->facets[facetNum];
02138                 coords2[0][0] = facet2->lightmapCoords[(point+1)%facet2->numpoints][0] * LIGHTMAP_SIZE;
02139                 coords2[0][1] = facet2->lightmapCoords[(point+1)%facet2->numpoints][1] * LIGHTMAP_SIZE;
02140                 coords2[1][0] = facet2->lightmapCoords[point][0] * LIGHTMAP_SIZE;
02141                 coords2[1][1] = facet2->lightmapCoords[point][1] * LIGHTMAP_SIZE;
02142                 if (coords2[0][0] >= LIGHTMAP_SIZE)
02143                     coords2[0][0] = LIGHTMAP_SIZE-1;
02144                 if (coords2[0][1] >= LIGHTMAP_SIZE)
02145                     coords2[0][1] = LIGHTMAP_SIZE-1;
02146                 if (coords2[1][0] >= LIGHTMAP_SIZE)
02147                     coords2[1][0] = LIGHTMAP_SIZE-1;
02148                 if (coords2[1][1] >= LIGHTMAP_SIZE)
02149                     coords2[1][1] = LIGHTMAP_SIZE-1;
02150                 //
02151                 x2 = coords2[0][0];
02152                 y2 = coords2[0][1];
02153                 xinc2 = coords2[1][0] - coords2[0][0];
02154                 if (length)
02155                     xinc2 = xinc2 / length;
02156                 yinc2 = coords2[1][1] - coords2[0][1];
02157                 if (length)
02158                     yinc2 = yinc2 / length;
02159                 // the edge should be parallell to one of the lightmap axis
02160                 if ((int) xinc2 != 0 && (int) yinc2 != 0)
02161                     continue;
02162                 //
02163                 while(1)
02164                 {
02165                     k1 = ( ds1->lightmapNum * LIGHTMAP_HEIGHT + y1) * LIGHTMAP_WIDTH + x1;
02166                     k2 = ( ds2->lightmapNum * LIGHTMAP_HEIGHT + ((int) y2)) * LIGHTMAP_WIDTH + ((int) x2);
02167                     color1 = lightFloats + k1*3;
02168                     color2 = lightFloats + k2*3;
02169                     if (lightmappixelarea[k1] < 0.01)
02170                     {
02171                         color1[0] = color2[0];
02172                         color1[1] = color2[1];
02173                         color1[2] = color2[2];
02174                     }
02175                     else
02176                     {
02177                         color1[0] = (float) color2[0] * 0.7 + (float) color1[0] * 0.3;
02178                         color1[1] = (float) color2[1] * 0.7 + (float) color1[1] * 0.3;
02179                         color1[2] = (float) color2[2] * 0.7 + (float) color1[2] * 0.3;
02180                     }
02181                     //
02182                     if (x1 == coords1[1][0] &&
02183                         y1 == coords1[1][1])
02184                         break;
02185                     x1 += xinc1;
02186                     y1 += yinc1;
02187                     x2 += xinc2;
02188                     y2 += yinc2;
02189                     if (x2 < ds2->lightmapX)
02190                         x2 = ds2->lightmapX;
02191                     if (x2 >= ds2->lightmapX + ds2->lightmapWidth)
02192                         x2 = ds2->lightmapX + ds2->lightmapWidth-1;
02193                     if (y2 < ds2->lightmapY)
02194                         y2 = ds2->lightmapY;
02195                     if (y2 >= ds2->lightmapY + ds2->lightmapHeight)
02196                         y2 = ds2->lightmapY + ds2->lightmapHeight-1;
02197                 }
02198             }
02199         }
02200     }
02201 }
02202 
02203 /*
02204 =============
02205 VL_FixLightmapEdges
02206 =============
02207 */
02208 void VL_FixLightmapEdges(void)
02209 {
02210     int             i, j, x, y, k, foundvalue, height, width, index;
02211     int             pos, top, bottom;
02212     dsurface_t      *ds;
02213     lsurfaceTest_t  *test;
02214     float           color[3];
02215     float           *ptr;
02216     byte filled[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8];
02217     float lightmap_edge_epsilon;
02218 
02219     lightmap_edge_epsilon = 0.1 * samplesize;
02220     for ( i = 0 ; i < numDrawSurfaces ; i++ )
02221     {
02222         test = lsurfaceTest[ i ];
02223         if (!test)
02224             continue;
02225         ds = &drawSurfaces[ i ];
02226 
02227         if ( ds->lightmapNum < 0 )
02228             continue;
02229         if (ds->surfaceType == MST_PATCH)
02230         {
02231             height = ds->lightmapHeight - 1;
02232             width = ds->lightmapWidth - 1;
02233         }
02234         else
02235         {
02236             height = ds->lightmapHeight;
02237             width = ds->lightmapWidth;
02238         }
02239         memset(filled, 0, sizeof(filled));
02240 //      printf("\n");
02241         for (x = 0; x < width; x++)
02242         {
02243             for (y = 0; y < height; y++)
02244             {
02245                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02246                         * LIGHTMAP_WIDTH + ds->lightmapX + x;
02247                 if (lightmappixelarea[k] > lightmap_edge_epsilon)
02248                 {
02249                     index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
02250                     filled[index >> 3] |= 1 << (index & 7);
02251 //                  printf("*");
02252                 }
02253 //              else
02254 //                  printf("_");
02255             }
02256 //          printf("\n");
02257         }
02258         for (y = 0; y < height; y++)
02259         {
02260             pos = -2;
02261             for (x = 0; x < width; x++)
02262             {
02263                 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
02264                 if (pos == -2)
02265                 {
02266                     if (filled[index >> 3] & (1 << (index & 7)))
02267                         pos = -1;
02268                 }
02269                 else if (pos == -1)
02270                 {
02271                     if (!(filled[index >> 3] & (1 << (index & 7))))
02272                         pos = x - 1;
02273                 }
02274                 else
02275                 {
02276                     if (filled[index >> 3] & (1 << (index & 7)))
02277                     {
02278                         bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02279                             * LIGHTMAP_WIDTH + ds->lightmapX + pos;
02280                         top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02281                             * LIGHTMAP_WIDTH + ds->lightmapX + x;
02282                         for (j = 0; j < (x - pos + 1) / 2; j++)
02283                         {
02284                             k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02285                                 * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1;
02286                             index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1;
02287                             filled[index >> 3] |= 1 << (index & 7);
02288                             (lightFloats + k*3)[0] = (lightFloats + top*3)[0];
02289                             (lightFloats + k*3)[1] = (lightFloats + top*3)[1];
02290                             (lightFloats + k*3)[2] = (lightFloats + top*3)[2];
02291                             k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02292                                 * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1;
02293                             index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1;
02294                             filled[index >> 3] |= 1 << (index & 7);
02295                             (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0];
02296                             (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1];
02297                             (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2];
02298                         }
02299                         pos = -1;
02300                     }
02301                 }
02302             }
02303         }
02304         for (x = 0; x < width; x++)
02305         {
02306             pos = -2;
02307             for (y = 0; y < height; y++)
02308             {
02309                 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
02310                 if (pos == -2)
02311                 {
02312                     if (filled[index >> 3] & (1 << (index & 7)))
02313                         pos = -1;
02314                 }
02315                 else if (pos == -1)
02316                 {
02317                     if (!(filled[index >> 3] & (1 << (index & 7))))
02318                         pos = y - 1;
02319                 }
02320                 else
02321                 {
02322                     if (filled[index >> 3] & (1 << (index & 7)))
02323                     {
02324                         bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos)
02325                             * LIGHTMAP_WIDTH + ds->lightmapX + x;
02326                         top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02327                             * LIGHTMAP_WIDTH + ds->lightmapX + x;
02328                         for (j = 0; j < (y - pos + 1) / 2; j++)
02329                         {
02330                             k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos + j + 1)
02331                                 * LIGHTMAP_WIDTH + ds->lightmapX + x;
02332                             index = (ds->lightmapY + pos + j + 1) * LIGHTMAP_WIDTH + ds->lightmapX + x;
02333                             filled[index >> 3] |= 1 << (index & 7);
02334                             (lightFloats + k*3)[0] = (lightFloats + top*3)[0];
02335                             (lightFloats + k*3)[1] = (lightFloats + top*3)[1];
02336                             (lightFloats + k*3)[2] = (lightFloats + top*3)[2];
02337                             k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y - j - 1)
02338                                 * LIGHTMAP_WIDTH + ds->lightmapX + x;
02339                             index = (ds->lightmapY + y - j - 1) * LIGHTMAP_WIDTH + ds->lightmapX + x;
02340                             filled[index >> 3] |= 1 << (index & 7);
02341                             (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0];
02342                             (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1];
02343                             (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2];
02344                         }
02345                         pos = -1;
02346                     }
02347                 }
02348             }
02349         }
02350         for (y = 0; y < height; y++)
02351         {
02352             foundvalue = qfalse;
02353             for (x = 0; x < width; x++)
02354             {
02355                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02356                         * LIGHTMAP_WIDTH + ds->lightmapX + x;
02357                 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
02358                 if (foundvalue)
02359                 {
02360                     if (filled[index >> 3] & (1 << (index & 7)))
02361                     {
02362                         ptr = lightFloats + k*3;
02363                         color[0] = ptr[0];
02364                         color[1] = ptr[1];
02365                         color[2] = ptr[2];
02366                     }
02367                     else
02368                     {
02369                         ptr = lightFloats + k*3;
02370                         ptr[0] = color[0];
02371                         ptr[1] = color[1];
02372                         ptr[2] = color[2];
02373                         filled[index >> 3] |= 1 << (index & 7);
02374                     }
02375                 }
02376                 else
02377                 {
02378                     if (filled[index >> 3] & (1 << (index & 7)))
02379                     {
02380                         ptr = lightFloats + k*3;
02381                         color[0] = ptr[0];
02382                         color[1] = ptr[1];
02383                         color[2] = ptr[2];
02384                         foundvalue = qtrue;
02385                     }
02386                 }
02387             }
02388             foundvalue = qfalse;
02389             for (x = width-1; x >= 0; x--)
02390             {
02391                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02392                         * LIGHTMAP_WIDTH + ds->lightmapX + x;
02393                 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
02394                 if (foundvalue)
02395                 {
02396                     if (filled[index >> 3] & (1 << (index & 7)))
02397                     {
02398                         ptr = lightFloats + k*3;
02399                         color[0] = ptr[0];
02400                         color[1] = ptr[1];
02401                         color[2] = ptr[2];
02402                     }
02403                     else
02404                     {
02405                         ptr = lightFloats + k*3;
02406                         ptr[0] = color[0];
02407                         ptr[1] = color[1];
02408                         ptr[2] = color[2];
02409                         filled[index >> 3] |= 1 << (index & 7);
02410                     }
02411                 }
02412                 else
02413                 {
02414                     if (filled[index >> 3] & (1 << (index & 7)))
02415                     {
02416                         ptr = lightFloats + k*3;
02417                         color[0] = ptr[0];
02418                         color[1] = ptr[1];
02419                         color[2] = ptr[2];
02420                         foundvalue = qtrue;
02421                     }
02422                 }
02423             }
02424         }
02425         for (x = 0; x < width; x++)
02426         {
02427             foundvalue = qfalse;
02428             for (y = 0; y < height; y++)
02429             {
02430                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02431                         * LIGHTMAP_WIDTH + ds->lightmapX + x;
02432                 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
02433                 if (foundvalue)
02434                 {
02435                     if (filled[index >> 3] & (1 << (index & 7)))
02436                     {
02437                         ptr = lightFloats + k*3;
02438                         color[0] = ptr[0];
02439                         color[1] = ptr[1];
02440                         color[2] = ptr[2];
02441                     }
02442                     else
02443                     {
02444                         ptr = lightFloats + k*3;
02445                         ptr[0] = color[0];
02446                         ptr[1] = color[1];
02447                         ptr[2] = color[2];
02448                         filled[index >> 3] |= 1 << (index & 7);
02449                     }
02450                 }
02451                 else
02452                 {
02453                     if (filled[index >> 3] & (1 << (index & 7)))
02454                     {
02455                         ptr = lightFloats + k*3;
02456                         color[0] = ptr[0];
02457                         color[1] = ptr[1];
02458                         color[2] = ptr[2];
02459                         foundvalue = qtrue;
02460                     }
02461                 }
02462             }
02463             foundvalue = qfalse;
02464             for (y = height-1; y >= 0; y--)
02465             {
02466                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02467                         * LIGHTMAP_WIDTH + ds->lightmapX + x;
02468                 index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
02469                 if (foundvalue)
02470                 {
02471                     if (filled[index >> 3] & (1 << (index & 7)))
02472                     {
02473                         ptr = lightFloats + k*3;
02474                         color[0] = ptr[0];
02475                         color[1] = ptr[1];
02476                         color[2] = ptr[2];
02477                     }
02478                     else
02479                     {
02480                         ptr = lightFloats + k*3;
02481                         ptr[0] = color[0];
02482                         ptr[1] = color[1];
02483                         ptr[2] = color[2];
02484                         filled[index >> 3] |= 1 << (index & 7);
02485                     }
02486                 }
02487                 else
02488                 {
02489                     if (filled[index >> 3] & (1 << (index & 7)))
02490                     {
02491                         ptr = lightFloats + k*3;
02492                         color[0] = ptr[0];
02493                         color[1] = ptr[1];
02494                         color[2] = ptr[2];
02495                         foundvalue = qtrue;
02496                     }
02497                 }
02498             }
02499         }
02500         if (ds->surfaceType == MST_PATCH)
02501         {
02502             x = ds->lightmapWidth-1;
02503             for (y = 0; y < ds->lightmapHeight; y++)
02504             {
02505                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02506                         * LIGHTMAP_WIDTH + ds->lightmapX + x;
02507                 ptr = lightFloats + k*3;
02508                 ptr[0] = (lightFloats + (k-1)*3)[0];
02509                 ptr[1] = (lightFloats + (k-1)*3)[1];
02510                 ptr[2] = (lightFloats + (k-1)*3)[2];
02511             }
02512             y = ds->lightmapHeight-1;
02513             for (x = 0; x < ds->lightmapWidth; x++)
02514             {
02515                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02516                         * LIGHTMAP_WIDTH + ds->lightmapX + x;
02517                 ptr = lightFloats + k*3;
02518                 ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0];
02519                 ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1];
02520                 ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2];
02521             }
02522         }
02523         /*
02524         //colored debug edges
02525         if (ds->surfaceType == MST_PATCH)
02526         {
02527             x = ds->lightmapWidth-1;
02528             for (y = 0; y < ds->lightmapHeight; y++)
02529             {
02530                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02531                         * LIGHTMAP_WIDTH + ds->lightmapX + x;
02532                 ptr = lightFloats + k*3;
02533                 ptr[0] = 255;
02534                 ptr[1] = 0;
02535                 ptr[2] = 0;
02536             }
02537             y = ds->lightmapHeight-1;
02538             for (x = 0; x < ds->lightmapWidth; x++)
02539             {
02540                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02541                         * LIGHTMAP_WIDTH + ds->lightmapX + x;
02542                 ptr = lightFloats + k*3;
02543                 ptr[0] = 0;
02544                 ptr[1] = 255;
02545                 ptr[2] = 0;
02546             }
02547         }
02548         //*/
02549     }
02550     //
02551     VL_SmoothenLightmapEdges();
02552 }
02553 
02554 /*
02555 =============
02556 VL_ShiftPatchLightmaps
02557 =============
02558 */
02559 void VL_ShiftPatchLightmaps(void)
02560 {
02561     int             i, j, x, y, k;
02562     drawVert_t      *verts;
02563     dsurface_t      *ds;
02564     lsurfaceTest_t  *test;
02565     float           *ptr;
02566 
02567     for ( i = 0 ; i < numDrawSurfaces ; i++ )
02568     {
02569         test = lsurfaceTest[ i ];
02570         if (!test)
02571             continue;
02572         ds = &drawSurfaces[ i ];
02573 
02574         if ( ds->lightmapNum < 0 )
02575             continue;
02576         if (ds->surfaceType != MST_PATCH)
02577             continue;
02578         for (x = ds->lightmapWidth; x > 0; x--)
02579         {
02580             for (y = 0; y <= ds->lightmapHeight; y++)
02581             {
02582                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02583                         * LIGHTMAP_WIDTH + ds->lightmapX + x;
02584                 ptr = lightFloats + k*3;
02585                 ptr[0] = (lightFloats + (k-1)*3)[0];
02586                 ptr[1] = (lightFloats + (k-1)*3)[1];
02587                 ptr[2] = (lightFloats + (k-1)*3)[2];
02588             }
02589         }
02590         for (y = ds->lightmapHeight; y > 0; y--)
02591         {
02592             for (x = 0; x <= ds->lightmapWidth; x++)
02593             {
02594                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02595                         * LIGHTMAP_WIDTH + ds->lightmapX + x;
02596                 ptr = lightFloats + k*3;
02597                 ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0];
02598                 ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1];
02599                 ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2];
02600             }
02601         }
02602         verts = &drawVerts[ ds->firstVert ];
02603         for ( j = 0 ; j < ds->patchHeight * ds->patchWidth; j++ )
02604         {
02605             verts[j].lightmap[0] += 0.5 / LIGHTMAP_WIDTH;
02606             verts[j].lightmap[1] += 0.5 / LIGHTMAP_HEIGHT;
02607         }
02608         ds->lightmapHeight++;
02609         ds->lightmapWidth++;
02610     }
02611 }
02612 
02613 /*
02614 =============
02615 VL_StoreLightmap
02616 =============
02617 */
02618 void VL_StoreLightmap(void)
02619 {
02620     int             i, x, y, k;
02621     dsurface_t      *ds;
02622     lsurfaceTest_t  *test;
02623     float           *src;
02624     byte            *dst;
02625 
02626     _printf("storing lightmaps...\n");
02627     //fix lightmap edges before storing them
02628     VL_FixLightmapEdges();
02629     //
02630 #ifdef LIGHTMAP_PATCHSHIFT
02631     VL_ShiftPatchLightmaps();
02632 #endif
02633     //
02634     for ( i = 0 ; i < numDrawSurfaces ; i++ )
02635     {
02636         test = lsurfaceTest[ i ];
02637         if (!test)
02638             continue;
02639         ds = &drawSurfaces[ i ];
02640 
02641         if ( ds->lightmapNum < 0 )
02642             continue;
02643 
02644         for (y = 0; y < ds->lightmapHeight; y++)
02645         {
02646             for (x = 0; x < ds->lightmapWidth; x++)
02647             {
02648                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
02649                         * LIGHTMAP_WIDTH + ds->lightmapX + x;
02650                 VectorAdd((lightFloats + k*3), lightAmbientColor, (lightFloats + k*3));
02651                 src = &lightFloats[k*3];
02652                 dst = lightBytes + k*3;
02653                 ColorToBytes(src, dst);
02654             }
02655         }
02656     }
02657 }
02658 
02659 /*
02660 =============
02661 PointInLeafnum
02662 =============
02663 */
02664 int PointInLeafnum(vec3_t point)
02665 {
02666     int     nodenum;
02667     vec_t   dist;
02668     dnode_t *node;
02669     dplane_t    *plane;
02670 
02671     nodenum = 0;
02672     while (nodenum >= 0)
02673     {
02674         node = &dnodes[nodenum];
02675         plane = &dplanes[node->planeNum];
02676         dist = DotProduct (point, plane->normal) - plane->dist;
02677         if (dist > 0)
02678             nodenum = node->children[0];
02679         else
02680             nodenum = node->children[1];
02681     }
02682 
02683     return -nodenum - 1;
02684 }
02685 
02686 /*
02687 =============
02688 VL_PointInLeafnum_r
02689 =============
02690 */
02691 int VL_PointInLeafnum_r(vec3_t point, int nodenum)
02692 {
02693     int leafnum;
02694     vec_t   dist;
02695     dnode_t *node;
02696     dplane_t    *plane;
02697 
02698     while (nodenum >= 0)
02699     {
02700         node = &dnodes[nodenum];
02701         plane = &dplanes[node->planeNum];
02702         dist = DotProduct (point, plane->normal) - plane->dist;
02703         if (dist > 0.1)
02704         {
02705             nodenum = node->children[0];
02706         }
02707         else if (dist < -0.1)
02708         {
02709             nodenum = node->children[1];
02710         }
02711         else
02712         {
02713             leafnum = VL_PointInLeafnum_r(point, node->children[0]);
02714             if (dleafs[leafnum].cluster != -1)
02715                 return leafnum;
02716             nodenum = node->children[1];
02717         }
02718     }
02719 
02720     leafnum = -nodenum - 1;
02721     return leafnum;
02722 }
02723 
02724 /*
02725 =============
02726 VL_PointInLeafnum
02727 =============
02728 */
02729 int VL_PointInLeafnum(vec3_t point)
02730 {
02731     return VL_PointInLeafnum_r(point, 0);
02732 }
02733 
02734 /*
02735 =============
02736 VL_LightLeafnum
02737 =============
02738 */
02739 int VL_LightLeafnum(vec3_t point)
02740 {
02741     /*
02742     int leafnum;
02743     dleaf_t *leaf;
02744     float x, y, z;
02745     vec3_t test;
02746 
02747     leafnum = VL_PointInLeafnum(point);
02748     leaf = &dleafs[leafnum];
02749     if (leaf->cluster != -1)
02750         return leafnum;
02751     for (z = 1; z >= -1; z -= 1)
02752     {
02753         for (x = 1; x >= -1; x -= 1)
02754         {
02755             for (y = 1; y >= -1; y -= 1)
02756             {
02757                 VectorCopy(point, test);
02758                 test[0] += x;
02759                 test[1] += y;
02760                 test[2] += z;
02761                 leafnum = VL_PointInLeafnum(test);
02762                 leaf = &dleafs[leafnum];
02763                 if (leaf->cluster != -1)
02764                 {
02765                     VectorCopy(test, point);
02766                     return leafnum;
02767                 }
02768             }
02769         }
02770     }
02771     return leafnum;
02772     */
02773     return VL_PointInLeafnum(point);
02774 }
02775 
02776 //#define LIGHTPOLYS
02777 
02778 #ifdef LIGHTPOLYS
02779 
02780 winding_t *lightwindings[MAX_MAP_DRAW_SURFS];
02781 int numlightwindings;
02782 
02783 /*
02784 =============
02785 VL_DrawLightWindings
02786 =============
02787 */
02788 void VL_DrawLightWindings(void)
02789 {
02790     int i;
02791     for (i = 0; i < numlightwindings; i++)
02792     {
02793 #ifdef DEBUGNET
02794         DebugNet_DrawWinding(lightwindings[i], 1);
02795 #endif
02796     }
02797 }
02798 
02799 /*
02800 =============
02801 VL_LightSurfaceWithVolume
02802 =============
02803 */
02804 void VL_LightSurfaceWithVolume(int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume)
02805 {
02806     winding_t *w;
02807     lsurfaceTest_t *test;
02808     lFacet_t *facet;
02809     int i;
02810 
02811     test = lsurfaceTest[ surfaceNum ];
02812     facet = &test->facets[ facetNum ];
02813 
02814     //
02815     w = (winding_t *) malloc(sizeof(winding_t));
02816     memcpy(w->points, facet->points, sizeof(vec3_t) * facet->numpoints);
02817     w->numpoints = facet->numpoints;
02818 
02819     for (i = 0; i < volume->numplanes; i++)
02820     {
02821         //if totally on the back
02822         if (VL_ChopWinding(w, &volume->planes[i], 0.01) == SIDE_BACK)
02823             return;
02824     }
02825     lightwindings[numlightwindings] = w;
02826     numlightwindings++;
02827     if (numlightwindings >= MAX_MAP_DRAW_SURFS)
02828         Error("MAX_LIGHTWINDINGS");
02829 }
02830 
02831 #else
02832 
02833 /*
02834 =============
02835 VL_LightSurfaceWithVolume
02836 =============
02837 */
02838 /*
02839 int VL_PointInsideLightVolume(vec3_t point, lightvolume_t *volume)
02840 {
02841     int i;
02842     float d;
02843 
02844     for (i = 0; i < volume->numplanes; i++)
02845     {
02846         d = DotProduct(volume->planes[i].normal, point) - volume->planes[i].dist;
02847         if (d < 0) return qfalse;
02848     }
02849     return qtrue;
02850 }
02851 
02852 void VL_LightSurfaceWithVolume( int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume )
02853 {
02854     dsurface_t  *ds;
02855     int         i, j, k;
02856     int         numPositions;
02857     vec3_t      base, normal, color;
02858     int         sampleWidth, sampleHeight;
02859     vec3_t      lightmapOrigin, lightmapVecs[2], dir;
02860     unsigned char *ptr;
02861     float add, dist, angle;
02862     mesh_t * mesh;
02863 
02864     ds = &drawSurfaces[surfaceNum];
02865 
02866     // vertex-lit triangle model
02867     if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
02868         return;
02869     }
02870     
02871     if ( ds->lightmapNum < 0 ) {
02872         return;     // doesn't need lighting
02873     }
02874 
02875     if ( ds->surfaceType == MST_PATCH ) {
02876         mesh = lsurfaceTest[surfaceNum]->detailMesh;
02877     } else {
02878         VectorCopy( ds->lightmapVecs[2], normal );
02879 
02880         VectorCopy( ds->lightmapOrigin, lightmapOrigin );
02881         VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] );
02882         VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] );
02883     }
02884 
02885     sampleWidth = ds->lightmapWidth;
02886     sampleHeight = ds->lightmapHeight;
02887 
02888     //calculate lightmap
02889     for ( i = 0 ; i < sampleWidth; i++ ) {
02890         for ( j = 0 ; j < sampleHeight; j++ ) {
02891 
02892             if ( ds->patchWidth ) {
02893                 numPositions = 9;
02894                 VectorCopy( mesh->verts[j*mesh->width+i].normal, normal );
02895                 // VectorNormalize( normal, normal );
02896                 // push off of the curve a bit
02897                 VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base );
02898 
02899 //              MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] );
02900             } else {
02901                 numPositions = 9;
02902                 for ( k = 0 ; k < 3 ; k++ ) {
02903                     base[k] = lightmapOrigin[k] + normal[k]
02904                                 + ((float) i) * lightmapVecs[0][k]
02905                                 + ((float) j) * lightmapVecs[1][k];
02906                 }
02907             }
02908             VectorAdd( base, surfaceOrigin[ surfaceNum ], base );
02909 
02910             VectorSubtract(base, light->origin, dir);
02911             dist = VectorNormalize(dir, dir);
02912             if ( dist < 16 ) {
02913                 dist = 16;
02914             }
02915             angle = 1;//DotProduct( normal, dir ); //1;
02916             if (angle > 1)
02917                 angle = 1;
02918             if ( light->atten_disttype == LDAT_LINEAR ) {
02919                 add = angle * light->photons * lightLinearScale - dist;
02920                 if ( add < 0 ) {
02921                     add = 0;
02922                 }
02923             } else {
02924                 add = light->photons / ( dist * dist ) * angle;
02925             }
02926             if (add <= 1.0)
02927                 continue;
02928 
02929             if (VL_PointInsideLightVolume(base, volume))
02930             {
02931                 k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j) 
02932                     * LIGHTMAP_WIDTH + ds->lightmapX + i;
02933                 ptr = lightBytes + k*3;
02934                 color[0] = (float) ptr[0] + add * light->color[0];
02935                 color[1] = (float) ptr[1] + add * light->color[1];
02936                 color[2] = (float) ptr[2] + add * light->color[2];
02937                 ColorToBytes(color, ptr);
02938             }
02939         }
02940     }
02941 }
02942 */
02943 
02944 /*
02945 =============
02946 VL_GetFilter
02947 
02948 FIXME:  don't use a lightmap pixel origin but use the four corner points
02949         to map part of a translucent surface onto the lightmap pixel
02950 =============
02951 */
02952 void VL_GetFilter(vlight_t *light, lightvolume_t *volume, vec3_t lmp, vec3_t filter)
02953 {
02954     lFacet_t *facet;
02955     lsurfaceTest_t *test;
02956     float d, d1, d2, frac, s, t, ns;
02957     int i, j, is, it, b;
02958     int x, y, u, v, numsamples, radius, color[4], largest;
02959     byte *image;
02960     vec3_t point, origin, total;
02961 
02962     VectorSet(filter, 1, 1, 1);
02963 
02964     if (noalphashading)
02965         return;
02966 
02967     if (volume->numtransFacets <= 0)
02968         return;
02969 
02970     if (light->type == LIGHT_SURFACEDIRECTED)
02971     {
02972         // project the light map pixel origin onto the area light source plane
02973         d = DotProduct(lmp, light->normal) - DotProduct(light->normal, light->w.points[0]);
02974         VectorMA(lmp, -d, light->normal, origin);
02975     }
02976     else
02977     {
02978         VectorCopy(light->origin, origin);
02979     }
02980     for (i = 0; i < volume->numtransFacets; i++)
02981     {
02982         test = lsurfaceTest[ volume->transSurfaces[i] ];
02983         facet = &test->facets[ volume->transFacets[i] ];
02984         // if this surface does not cast an alpha shadow
02985         if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) )
02986             continue;
02987         // if there are no texture pixel available
02988         if ( !test->shader->pixels ) {
02989             continue;
02990         }
02991         //
02992         d1 = DotProduct( origin, facet->plane.normal) - facet->plane.dist;
02993         d2 = DotProduct( lmp, facet->plane.normal ) - facet->plane.dist;
02994         // this should never happen because the light volume went through the facet
02995         if ( ( d1 < 0 ) == ( d2 < 0 ) ) {
02996             continue;
02997         }
02998         // calculate the crossing point
02999         frac = d1 / ( d1 - d2 );
03000 
03001         for ( j = 0 ; j < 3 ; j++ ) {
03002             point[j] = origin[j] + frac * ( lmp[j] - origin[j] );
03003         }
03004 
03005         s = DotProduct( point, facet->textureMatrix[0] ) + facet->textureMatrix[0][3];
03006         t = DotProduct( point, facet->textureMatrix[1] ) + facet->textureMatrix[1][3];
03007         if (s < 0)
03008             s = 0;
03009         if (t < 0)
03010             t = 0;
03011 
03012         s = s - floor( s );
03013         t = t - floor( t );
03014 
03015         is = s * test->shader->width;
03016         it = t * test->shader->height;
03017 
03018         //if old style alpha shading
03019         if (nocolorshading) {
03020             image = test->shader->pixels + 4 * ( it * test->shader->width + is );
03021 
03022             // alpha filter
03023             b = image[3];
03024 
03025             // alpha test makes this a binary option
03026             b = b < 128 ? 0 : 255;
03027 
03028             filter[0] = filter[0] * (255-b) / 255;
03029             filter[1] = filter[1] * (255-b) / 255;
03030             filter[2] = filter[2] * (255-b) / 255;
03031         }
03032         else {
03033             VectorClear(total);
03034             numsamples = 0;
03035             radius = 2;
03036             for ( u = -radius; u <= radius; u++ )
03037             {
03038                 x = is + u;
03039                 if ( x < 0 || x >= test->shader->width)
03040                     continue;
03041                 for ( v = -radius; v <= radius; v++ )
03042                 {
03043                     y = it + v;
03044                     if ( y < 0 || y >= test->shader->height)
03045                         continue;
03046 
03047                     image = test->shader->pixels + 4 * ( y * test->shader->width + x );
03048                     color[0] = image[0];
03049                     color[1] = image[1];
03050                     color[2] = image[2];
03051                     largest = 0;
03052                     for (j = 0; j < 3; j++)
03053                         if (image[j] > largest)
03054                             largest = image[j];
03055                     if (largest <= 0 || image[3] == 0) {
03056                         color[0] = 255;
03057                         color[1] = 255;
03058                         color[2] = 255;
03059                         largest = 255;
03060                     }
03061                     total[0] += ((float) color[0]/largest) * (255-image[3]) / 255.0;
03062                     total[1] += ((float) color[1]/largest) * (255-image[3]) / 255.0;
03063                     total[2] += ((float) color[2]/largest) * (255-image[3]) / 255.0;
03064                     numsamples++;
03065                 }
03066             }
03067             ns = numsamples;
03068             //
03069             filter[0] *= total[0] / ns;
03070             filter[1] *= total[1] / ns;
03071             filter[2] *= total[2] / ns;
03072         }
03073     }
03074 }
03075 
03076 /*
03077 =============
03078 VL_LightSurfaceWithVolume
03079 =============
03080 */
03081 void VL_LightSurfaceWithVolume( int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume )
03082 {
03083     int i;
03084     dsurface_t  *ds;
03085     lFacet_t *facet;
03086     lsurfaceTest_t *test;
03087     winding_t w;
03088     vec3_t base, dir, delta, normal, filter, origin;
03089     int min_x[LIGHTMAP_SIZE+2], max_x[LIGHTMAP_SIZE+2];
03090     int min_y, max_y, k, x, y, n;
03091     float *color, distscale;
03092     float d, add, angle, dist, area, insidearea, coords[MAX_POINTS_ON_WINDING+1][2];
03093     mesh_t *mesh;
03094     byte polygonedges[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8];
03095 
03096 
03097     ds = &drawSurfaces[surfaceNum];
03098 
03099     // vertex-lit triangle model
03100     if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
03101         return;
03102     }
03103     
03104     if ( ds->lightmapNum < 0 ) {
03105         return;     // doesn't need lighting
03106     }
03107 
03108     test = lsurfaceTest[ surfaceNum ];
03109     facet = &test->facets[ facetNum ];
03110 
03111     if (defaulttracelight && !test->always_vlight)
03112         return;
03113     if (test->always_tracelight)
03114         return;
03115 
03116     memcpy(w.points, facet->points, sizeof(vec3_t) * facet->numpoints);
03117     w.numpoints = facet->numpoints;
03118 
03119     for (i = 0; i < volume->numplanes; i++)
03120     {
03121         //if totally on the back
03122         if (VL_ChopWinding(&w, &volume->planes[i], 0.01) == SIDE_BACK)
03123             return;
03124     }
03125 
03126     // only one thread at a time may write to the lightmap of this surface
03127     MutexLock(test->mutex);
03128 
03129     test->numvolumes++;
03130 
03131     if (ds->surfaceType == MST_PATCH)
03132     {
03133         // FIXME: reduce size and don't mark all as edge
03134         min_y = ds->lightmapY + facet->y;
03135         max_y = ds->lightmapY + facet->y + facet->height - 1;
03136         for (y = min_y; y <= max_y; y++)
03137         {
03138             min_x[y] = ds->lightmapX + facet->x;
03139             max_x[y] = ds->lightmapX + facet->x + facet->width - 1;
03140             for (x = min_x[y]; x <= max_x[y]; x++)
03141             {
03142                 n = y * LIGHTMAP_SIZE + x;
03143                 polygonedges[n >> 3] |= 1 << (n & 7);
03144             }
03145         }
03146     }
03147     else
03148     {
03149         for (i = 0; i < w.numpoints; i++)
03150         {
03151             float   s, t;
03152 
03153             if (i >= MAX_POINTS_ON_WINDING)
03154                 _printf("coords overflow\n");
03155             if (ds->surfaceType != MST_PATCH)
03156             {
03157                 VectorSubtract(w.points[i], facet->mins, delta);
03158                 s = DotProduct( delta, facet->lightmapMatrix[0] ) + ds->lightmapX + 0.5;
03159                 t = DotProduct( delta, facet->lightmapMatrix[1] ) + ds->lightmapY + 0.5;
03160                 if (s >= LIGHTMAP_SIZE)
03161                     s = LIGHTMAP_SIZE - 0.5;
03162                 if (s < 0)
03163                     s = 0;
03164                 if (t >= LIGHTMAP_SIZE)
03165                     t = LIGHTMAP_SIZE - 0.5;
03166                 if (t < 0)
03167                     t = 0;
03168                 coords[i][0] = s;
03169                 coords[i][1] = t;
03170             }
03171             else
03172             {
03173                 s = DotProduct( w.points[i], facet->lightmapMatrix[0] ) + facet->lightmapMatrix[0][3];
03174                 t = DotProduct( w.points[i], facet->lightmapMatrix[1] ) + facet->lightmapMatrix[1][3];
03175 
03176                 s = s - floor( s );
03177                 t = t - floor( t );
03178 
03179                 coords[i][0] = ds->lightmapX + s * LIGHTMAP_SIZE;// + 0.5;
03180                 coords[i][1] = ds->lightmapY + t * LIGHTMAP_SIZE;// + 0.5;
03181 
03182                 if (coords[i][0] >= LIGHTMAP_SIZE)
03183                     coords[i][0] -= LIGHTMAP_SIZE;
03184                 if (coords[i][1] >= LIGHTMAP_SIZE)
03185                     coords[i][1] -= LIGHTMAP_SIZE;
03186                 if (coords[i][0] < ds->lightmapX)
03187                     coords[i][0] = ds->lightmapX;
03188                 if (coords[i][1] < ds->lightmapY)
03189                     coords[i][1] = ds->lightmapY;
03190             }
03191             x = coords[i][0];
03192             y = coords[i][1];
03193             if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
03194                 _printf("VL_LightSurfaceWithVolume: x outside lightmap\n");
03195             if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
03196                 _printf("VL_LightSurfaceWithVolume: y outside lightmap\n");
03197         }
03198         coords[i][0] = coords[0][0];
03199         coords[i][1] = coords[0][1];
03200 
03201         //
03202         min_y = LIGHTMAP_SIZE;
03203         max_y = 0;
03204         for (i = 0; i < LIGHTMAP_SIZE; i++)
03205         {
03206             min_x[i] = LIGHTMAP_SIZE;
03207             max_x[i] = 0;
03208         }
03209         memset(polygonedges, 0, sizeof(polygonedges));
03210         // scan convert the polygon onto the lightmap
03211         // for each edge it marks *every* lightmap pixel the edge goes through
03212         // so no brasenham and no scan conversion used for texture mapping but
03213         // more something like ray casting
03214         // this is necesary because we need all lightmap pixels totally or partly
03215         // inside the light volume. these lightmap pixels are only lit for the part
03216         // that they are inside the light volume.
03217         for (i = 0; i < w.numpoints; i++)
03218         {
03219             float xf, yf, dx, dy, xstep, ystep, xfrac, yfrac;
03220             int xinc, yinc;
03221 
03222             xf = coords[i][0];
03223             yf = coords[i][1];
03224             dx = coords[i+1][0] - xf;
03225             dy = coords[i+1][1] - yf;
03226             //
03227             x = (int) xf;
03228             y = (int) yf;
03229             //
03230             if (y < min_y)
03231                 min_y = y;
03232             if (y > max_y)
03233                 max_y = y;
03234             //
03235             if (fabs(dx) > fabs(dy))
03236             {
03237                 if (dx > 0)
03238                 {
03239                     // y fraction at integer x below fractional x
03240                     yfrac = yf + (floor(xf) - xf) * dy / dx;
03241                     xinc = 1;
03242                 }
03243                 else if (dx < 0)
03244                 {
03245                     // y fraction at integer x above fractional x
03246                     yfrac = yf + (floor(xf) + 1 - xf) * dy / dx;
03247                     xinc = -1;
03248                 }
03249                 else
03250                 {
03251                     yfrac = yf;
03252                     xinc = 0;
03253                 }
03254                 // step in y direction per 1 unit in x direction
03255                 if (dx)
03256                     ystep = dy / fabs(dx);
03257                 else
03258                     ystep = 0;
03259                 while(1)
03260                 {
03261                     if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
03262                         _printf("VL_LightSurfaceWithVolume: x outside lightmap\n");
03263                     if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
03264                         _printf("VL_LightSurfaceWithVolume: y outside lightmap\n");
03265                     //
03266                     n = y * LIGHTMAP_SIZE + x;
03267                     polygonedges[n >> 3] |= 1 << (n & 7);
03268                     if (x < min_x[y])
03269                         min_x[y] = x;
03270                     if (x > max_x[y])
03271                         max_x[y] = x;
03272                     if (x == (int) coords[i+1][0])
03273                         break;
03274                     yfrac += ystep;
03275                     if (dy > 0)
03276                     {
03277                         if (yfrac > (float) y + 1)
03278                         {
03279                             y += 1;
03280                             //
03281                             n = y * LIGHTMAP_SIZE + x;
03282                             polygonedges[n >> 3] |= 1 << (n & 7);
03283                             if (x < min_x[y])
03284                                 min_x[y] = x;
03285                             if (x > max_x[y])
03286                                 max_x[y] = x;
03287                         }
03288                     }
03289                     else
03290                     {
03291                         if (yfrac < (float) y)
03292                         {
03293                             y -= 1;
03294                             //
03295                             n = y * LIGHTMAP_SIZE + x;
03296                             polygonedges[n >> 3] |= 1 << (n & 7);
03297                             if (x < min_x[y])
03298                                 min_x[y] = x;
03299                             if (x > max_x[y])
03300                                 max_x[y] = x;
03301                         }
03302                     }
03303                     x += xinc;
03304                 }
03305             }
03306             else
03307             {
03308                 if (dy > 0)
03309                 {
03310                     //x fraction at integer y below fractional y
03311                     xfrac = xf + (floor(yf) - yf) * dx / dy;
03312                     yinc = 1;
03313                 }
03314                 else if (dy < 0)
03315                 {
03316                     //x fraction at integer y above fractional y
03317                     xfrac = xf + (floor(yf) + 1 - yf) * dx / dy;
03318                     yinc = -1;
03319                 }
03320                 else
03321                 {
03322                     xfrac = xf;
03323                     yinc = 0;
03324                 }
03325                 // step in x direction per 1 unit in y direction
03326                 if (dy)
03327                     xstep = dx / fabs(dy);
03328                 else
03329                     xstep = 0;
03330                 while(1)
03331                 {
03332                     if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
03333                         _printf("VL_LightSurfaceWithVolume: x outside lightmap\n");
03334                     if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
03335                         _printf("VL_LightSurfaceWithVolume: y outside lightmap\n");
03336                     //
03337                     n = y * LIGHTMAP_SIZE + x;
03338                     polygonedges[n >> 3] |= 1 << (n & 7);
03339                     if (x < min_x[y])
03340                         min_x[y] = x;
03341                     if (x > max_x[y])
03342                         max_x[y] = x;
03343                     if (y == (int) coords[i+1][1])
03344                         break;
03345                     xfrac += xstep;
03346                     if (dx > 0)
03347                     {
03348                         if (xfrac > (float) x + 1)
03349                         {
03350                             x += 1;
03351                             //
03352                             n = y * LIGHTMAP_SIZE + x;
03353                             polygonedges[n >> 3] |= 1 << (n & 7);
03354                             if (x < min_x[y])
03355                                 min_x[y] = x;
03356                             if (x > max_x[y])
03357                                 max_x[y] = x;
03358                         }
03359                     }
03360                     else
03361                     {
03362                         if (xfrac < (float) x)
03363                         {
03364                             x -= 1;
03365                             //
03366                             n = y * LIGHTMAP_SIZE + x;
03367                             polygonedges[n >> 3] |= 1 << (n & 7);
03368                             if (x < min_x[y])
03369                                 min_x[y] = x;
03370                             if (x > max_x[y])
03371                                 max_x[y] = x;
03372                         }
03373                     }
03374                     y += yinc;
03375                 }
03376             }
03377         }
03378     }
03379     // map light onto the lightmap
03380     for (y = min_y; y <= max_y; y++)
03381     {
03382         for (x = min_x[y]; x <= max_x[y]; x++)
03383         {
03384             if (ds->surfaceType == MST_PATCH)
03385             {
03386                 mesh = test->detailMesh;
03387                 VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, base);
03388                 VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].normal, normal);
03389                 //VectorCopy(facet->plane.normal, normal);
03390             }
03391             else
03392             {
03393                 VectorMA(ds->lightmapOrigin, (float) x - ds->lightmapX, ds->lightmapVecs[0], base);
03394                 VectorMA(base, (float) y - ds->lightmapY, ds->lightmapVecs[1], base);
03395                 VectorCopy(facet->plane.normal, normal);
03396             }
03397             if (light->type == LIGHT_POINTSPOT)
03398             {
03399                 float   distByNormal;
03400                 vec3_t  pointAtDist;
03401                 float   radiusAtDist;
03402                 float   sampleRadius;
03403                 vec3_t  distToSample;
03404                 float   coneScale;
03405 
03406                 VectorSubtract( light->origin, base, dir );
03407 
03408                 distByNormal = -DotProduct( dir, light->normal );
03409                 if ( distByNormal < 0 ) {
03410                     continue;
03411                 }
03412                 VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
03413                 radiusAtDist = light->radiusByDist * distByNormal;
03414 
03415                 VectorSubtract( base, pointAtDist, distToSample );
03416                 sampleRadius = VectorLength( distToSample );
03417 
03418                 if ( sampleRadius >= radiusAtDist ) {
03419                     continue;       // outside the cone
03420                 }
03421                 if ( sampleRadius <= radiusAtDist - 32 ) {
03422                     coneScale = 1.0;    // fully inside
03423                 } else {
03424                     coneScale = ( radiusAtDist - sampleRadius ) / 32.0;
03425                 }
03426                 
03427                 dist = VectorNormalize( dir, dir );
03428                 // clamp the distance to prevent super hot spots
03429                 if ( dist < 16 ) {
03430                     dist = 16;
03431                 }
03432                 angle = DotProduct( normal, dir );
03433                 if (angle > 1)
03434                     angle = 1;
03435                 if (angle > 0) {
03436                     if ( light->atten_angletype == LAAT_QUADRATIC ) {
03437                         angle = 1 - angle;
03438                         angle *= angle;
03439                         angle = 1 - angle;
03440                     }
03441                     else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
03442                         angle = 1 - angle;
03443                         angle *= angle * angle;
03444                         angle = 1 - angle;
03445                     }
03446                 }
03447                 if (light->atten_anglescale > 0) {
03448                     angle /= light->atten_anglescale;
03449                     if (angle > 1)
03450                         angle = 1;
03451                 }
03452                 if (light->atten_distscale > 0) {
03453                     distscale = light->atten_distscale;
03454                 }
03455                 else {
03456                     distscale = 1;
03457                 }
03458                 //
03459                 if ( light->atten_disttype == LDAT_NOSCALE ) {
03460                     add = angle * coneScale;
03461                 }
03462                 else if ( light->atten_disttype == LDAT_LINEAR ) {
03463                     add = angle * light->photons * lightLinearScale * coneScale - dist * distscale;
03464                     if ( add < 0 ) {
03465                         add = 0;
03466                     }
03467                 }
03468                 else {
03469                     add = light->photons / ( dist * dist * distscale) * angle * coneScale;
03470                 }
03471                 if (add <= 1.0)
03472                     continue;
03473             }
03474             else if (light->type == LIGHT_POINTFAKESURFACE)
03475             {
03476                 // calculate the contribution
03477                 add = PointToPolygonFormFactor( base, normal, &light->w );
03478                 if ( add <= 0 ) {
03479                     if ( light->twosided ) {
03480                         add = -add;
03481                     } else {
03482                         continue;
03483                     }
03484                 }
03485             }
03486             else if (light->type == LIGHT_SURFACEDIRECTED)
03487             {
03488                 //VectorCopy(light->normal, dir);
03489                 //VectorInverse(dir);
03490                 // project the light map pixel origin onto the area light source plane
03491                 d = DotProduct(base, light->normal) - DotProduct(light->normal, light->w.points[0]);
03492                 VectorMA(base, -d, light->normal, origin);
03493                 VectorSubtract(origin, base, dir);
03494                 dist = VectorNormalize(dir, dir);
03495                 if ( dist < 16 ) {
03496                     dist = 16;
03497                 }
03498                 //
03499                 angle = DotProduct( normal, dir );
03500                 if (angle > 1)
03501                     angle = 1;
03502                 if (angle > 0) {
03503                     if ( light->atten_angletype == LAAT_QUADRATIC ) {
03504                         angle = 1 - angle;
03505                         angle *= angle;
03506                         angle = 1 - angle;
03507                     }
03508                     else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
03509                         angle = 1 - angle;
03510                         angle *= angle * angle;
03511                         angle = 1 - angle;
03512                     }
03513                 }
03514                 if (light->atten_anglescale > 0) {
03515                     angle /= light->atten_anglescale;
03516                     if (angle > 1)
03517                         angle = 1;
03518                 }
03519                 if (light->atten_distscale > 0) {
03520                     distscale = light->atten_distscale;
03521                 }
03522                 else {
03523                     distscale = 1;
03524                 }
03525                 if ( light->atten_disttype == LDAT_NOSCALE ) {
03526                     add = angle;
03527                 }
03528                 else if ( light->atten_disttype == LDAT_LINEAR ) {
03529                     add = angle * light->photons * lightLinearScale - dist * distscale;
03530                     if ( add < 0 ) {
03531                         add = 0;
03532                     }
03533                 } else { //default quadratic
03534                     add = light->photons / ( dist * dist * distscale) * angle;
03535                 }
03536                 if (add <= 0)
03537                     continue;
03538             }
03539             else //normal radial point light
03540             {
03541                 VectorSubtract(light->origin, base, dir);
03542                 dist = VectorNormalize(dir, dir);
03543                 if ( dist < 16 ) {
03544                     dist = 16;
03545                 }
03546                 angle = DotProduct( normal, dir );
03547                 if (angle > 1)
03548                     angle = 1;
03549                 if (angle > 0) {
03550                     if ( light->atten_angletype == LAAT_QUADRATIC ) {
03551                         angle = 1 - angle;
03552                         angle *= angle;
03553                         angle = 1 - angle;
03554                     }
03555                     else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
03556                         angle = 1 - angle;
03557                         angle *= angle * angle;
03558                         angle = 1 - angle;
03559                     }
03560                 }
03561                 if (light->atten_anglescale > 0) {
03562                     angle /= light->atten_anglescale;
03563                     if (angle > 1)
03564                         angle = 1;
03565                 }
03566                 if (light->atten_distscale > 0) {
03567                     distscale = light->atten_distscale;
03568                 }
03569                 else {
03570                     distscale = 1;
03571                 }
03572                 if ( light->atten_disttype == LDAT_NOSCALE ) {
03573                     add = angle;
03574                 }
03575                 else if ( light->atten_disttype == LDAT_LINEAR ) {
03576                     add = angle * light->photons * lightLinearScale - dist * distscale;
03577                     if ( add < 0 ) {
03578                         add = 0;
03579                     }
03580                 } else {
03581                     add = light->photons / ( dist * dist * distscale) * angle;
03582                 }
03583                 if (add <= 1.0)
03584                     continue;
03585             }
03586             //
03587             k = (ds->lightmapNum * LIGHTMAP_HEIGHT + y) * LIGHTMAP_WIDTH + x;
03588             //if on one of the edges
03589             n = y * LIGHTMAP_SIZE + x;
03590             if ((polygonedges[n >> 3] & (1 << (n & 7)) ))
03591             {
03592                 // multiply 'add' by the relative area being lit of the total visible lightmap pixel area
03593                 //
03594                 // first create a winding for the lightmap pixel
03595                 if (ds->surfaceType == MST_PATCH)
03596                 {
03597                     mesh = test->detailMesh;
03598                     if (y-ds->lightmapY >= mesh->height-1)
03599                         _printf("y outside mesh\n");
03600                     if (x-ds->lightmapX >= mesh->width-1)
03601                         _printf("x outside mesh\n");
03602                     VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]);
03603                     VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]);
03604                     VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]);
03605                     VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]);
03606                     w.numpoints = 4;
03607                 }
03608                 else
03609                 {
03610                     VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]);
03611                     VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]);
03612                     VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]);
03613                     VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]);
03614                     VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]);
03615                     VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]);
03616                     VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]);
03617                     VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]);
03618                     w.numpoints = 4;
03619                 }
03620                 //
03621                 // take the visible area of the lightmap pixel into account
03622                 //
03623                 //area = WindingArea(&w);
03624                 area = lightmappixelarea[k];
03625                 if (area <= 0)
03626                     continue;
03627                 // chop the lightmap pixel winding with the light volume
03628                 for (i = 0; i < volume->numplanes; i++)
03629                 {
03630                     //if totally on the back
03631                     if (VL_ChopWinding(&w, &volume->planes[i], 0) == SIDE_BACK)
03632                         break;
03633                 }
03634                 // if the lightmap pixel is partly inside the light volume
03635                 if (i >= volume->numplanes)
03636                 {
03637                     insidearea = WindingArea(&w);
03638                     if (insidearea <= 0)
03639                         i = 0;
03640                     add = add * insidearea / area;
03641                 }
03642                 else
03643                 {
03644                     //DebugNet_DrawWinding(&w, 2);
03645                     continue;   // this shouldn't happen
03646                 }
03647             }
03648             // get the light filter from all the translucent surfaces the light volume went through
03649             VL_GetFilter(light, volume, base, filter);
03650             //
03651             color = &lightFloats[k*3];
03652             color[0] += add * light->color[0] * filter[0];
03653             color[1] += add * light->color[1] * filter[1];
03654             color[2] += add * light->color[2] * filter[2];
03655         }
03656     }
03657 
03658     MutexUnlock(test->mutex);
03659 }
03660 
03661 #endif
03662 
03663 /*
03664 =============
03665 VL_SplitLightVolume
03666 =============
03667 */
03668 int VL_SplitLightVolume(lightvolume_t *volume, lightvolume_t *back, plane_t *split, float epsilon)
03669 {
03670     lightvolume_t f, b;
03671     vec_t   dists[128];
03672     int     sides[128];
03673     int     counts[3];
03674     vec_t   dot;
03675     int     i, j;
03676     vec_t   *p1, *p2;
03677     vec3_t  mid;
03678 
03679     counts[0] = counts[1] = counts[2] = 0;
03680 
03681     // determine sides for each point
03682     for (i = 0; i < volume->numplanes; i++)
03683     {
03684         dot = DotProduct (volume->points[i], split->normal);
03685         dot -= split->dist;
03686         dists[i] = dot;
03687         if (dot > epsilon)
03688             sides[i] = SIDE_FRONT;
03689         else if (dot < -epsilon)
03690             sides[i] = SIDE_BACK;
03691         else
03692         {
03693             sides[i] = SIDE_ON;
03694         }
03695         counts[sides[i]]++;
03696     }
03697 
03698     if (!counts[1])
03699         return 0;       // completely on front side
03700     
03701     if (!counts[0])
03702         return 1;       // completely on back side
03703 
03704     sides[i] = sides[0];
03705     dists[i] = dists[0];
03706     
03707     f.numplanes = 0;
03708     b.numplanes = 0;
03709 
03710     for (i = 0; i < volume->numplanes; i++)
03711     {
03712         p1 = volume->points[i];
03713 
03714         if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
03715         {
03716             _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
03717             return 0;       // can't chop -- fall back to original
03718         }
03719         if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
03720         {
03721             _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
03722             return 0;       // can't chop -- fall back to original
03723         }
03724 
03725         if (sides[i] == SIDE_ON)
03726         {
03727             VectorCopy(p1, f.points[f.numplanes]);
03728             VectorCopy(p1, b.points[b.numplanes]);
03729             if (sides[i+1] == SIDE_BACK)
03730             {
03731                 f.planes[f.numplanes] = *split;
03732                 b.planes[b.numplanes] = volume->planes[i];
03733             }
03734             else if (sides[i+1] == SIDE_FRONT)
03735             {
03736                 f.planes[f.numplanes] = volume->planes[i];
03737                 b.planes[b.numplanes] = *split;
03738                 VectorInverse(b.planes[b.numplanes].normal);
03739                 b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
03740             }
03741             else //this shouldn't happen
03742             {
03743                 f.planes[f.numplanes] = *split;
03744                 b.planes[b.numplanes] = *split;
03745                 VectorInverse(b.planes[b.numplanes].normal);
03746                 b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
03747             }
03748             f.numplanes++;
03749             b.numplanes++;
03750             continue;
03751         }
03752     
03753         if (sides[i] == SIDE_FRONT)
03754         {
03755             VectorCopy (p1, f.points[f.numplanes]);
03756             f.planes[f.numplanes] = volume->planes[i];
03757             f.numplanes++;
03758         }
03759         if (sides[i] == SIDE_BACK)
03760         {
03761             VectorCopy (p1, b.points[b.numplanes]);
03762             b.planes[b.numplanes] = volume->planes[i];
03763             b.numplanes++;
03764         }
03765         
03766         if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
03767             continue;
03768             
03769         if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
03770         {
03771             _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
03772             return 0;       // can't chop -- fall back to original
03773         }
03774         if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
03775         {
03776             _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
03777             return 0;       // can't chop -- fall back to original
03778         }
03779 
03780         // generate a split point
03781         p2 = volume->points[(i+1)%volume->numplanes];
03782         
03783         dot = dists[i] / (dists[i]-dists[i+1]);
03784         for (j=0 ; j<3 ; j++)
03785         {   // avoid round off error when possible
03786             if (split->normal[j] == 1)
03787                 mid[j] = split->dist;
03788             else if (split->normal[j] == -1)
03789                 mid[j] = -split->dist;
03790             else
03791                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
03792         }
03793 
03794         VectorCopy (mid, f.points[f.numplanes]);
03795         VectorCopy(mid, b.points[b.numplanes]);
03796         if (sides[i+1] == SIDE_BACK)
03797         {
03798             f.planes[f.numplanes] = *split;
03799             b.planes[b.numplanes] = volume->planes[i];
03800         }
03801         else
03802         {
03803             f.planes[f.numplanes] = volume->planes[i];
03804             b.planes[b.numplanes] = *split;
03805             VectorInverse(b.planes[b.numplanes].normal);
03806             b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
03807         }
03808         f.numplanes++;
03809         b.numplanes++;
03810     }
03811     memcpy(volume->points, f.points, sizeof(vec3_t) * f.numplanes);
03812     memcpy(volume->planes, f.planes, sizeof(plane_t) * f.numplanes);
03813     volume->numplanes = f.numplanes;
03814     memcpy(back->points, b.points, sizeof(vec3_t) * b.numplanes);
03815     memcpy(back->planes, b.planes, sizeof(plane_t) * b.numplanes);
03816     back->numplanes = b.numplanes;
03817 
03818     return 2;
03819 }
03820 
03821 /*
03822 =============
03823 VL_PlaneForEdgeToWinding
03824 =============
03825 */
03826 void VL_PlaneForEdgeToWinding(vec3_t p1, vec3_t p2, winding_t *w, int windingonfront, plane_t *plane)
03827 {
03828     int i, j;
03829     float length, d;
03830     vec3_t v1, v2;
03831 
03832     VectorSubtract(p2, p1, v1);
03833     for (i = 0; i < w->numpoints; i++)
03834     {
03835         VectorSubtract (w->points[i], p1, v2);
03836 
03837         plane->normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
03838         plane->normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
03839         plane->normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
03840             
03841         // if points don't make a valid plane, skip it
03842         length = plane->normal[0] * plane->normal[0]
03843                     + plane->normal[1] * plane->normal[1]
03844                     + plane->normal[2] * plane->normal[2];
03845             
03846         if (length < ON_EPSILON)
03847             continue;
03848 
03849         length = 1/sqrt(length);
03850             
03851         plane->normal[0] *= length;
03852         plane->normal[1] *= length;
03853         plane->normal[2] *= length;
03854 
03855         plane->dist = DotProduct (w->points[i], plane->normal);
03856         //
03857         for (j = 0; j < w->numpoints; j++)
03858         {
03859             if (j == i)
03860                 continue;
03861             d = DotProduct(w->points[j], plane->normal) - plane->dist;
03862             if (windingonfront)
03863             {
03864                 if (d < -ON_EPSILON)
03865                     break;
03866             }
03867             else
03868             {
03869                 if (d > ON_EPSILON)
03870                     break;
03871             }
03872         }
03873         if (j >= w->numpoints)
03874             return;
03875     }
03876 }
03877 
03878 /*
03879 =============
03880 VL_R_CastLightAtSurface
03881 =============
03882 */
03883 void VL_R_FloodLight(vlight_t *light, lightvolume_t *volume, int cluster, int firstportal);
03884 
03885 void VL_R_CastLightAtSurface(vlight_t *light, lightvolume_t *volume)
03886 {
03887     lsurfaceTest_t *test;
03888     int i, n;
03889 
03890     // light the surface with this volume
03891     VL_LightSurfaceWithVolume(volume->surfaceNum, volume->facetNum, light, volume);
03892     //
03893     test = lsurfaceTest[ volume->surfaceNum ];
03894     // if this is not a translucent surface
03895     if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) && !(test->shader->contents & CONTENTS_TRANSLUCENT))
03896         return;
03897     //
03898     if (volume->numtransFacets >= MAX_TRANSLUCENTFACETS)
03899         Error("a light valume went through more than %d translucent facets", MAX_TRANSLUCENTFACETS);
03900     //add this translucent surface to the list
03901     volume->transSurfaces[volume->numtransFacets] = volume->surfaceNum;
03902     volume->transFacets[volume->numtransFacets] = volume->facetNum;
03903     volume->numtransFacets++;
03904     //clear the tested facets except the translucent ones
03905     memset(volume->facetTested, 0, sizeof(volume->facetTested));
03906     for (i = 0; i < volume->numtransFacets; i++)
03907     {
03908         test = lsurfaceTest[ volume->transSurfaces[i] ];
03909         n = test->facets[volume->transFacets[i]].num;
03910         volume->facetTested[n >> 3] |= 1 << (n & 7);
03911     }
03912     memset(volume->clusterTested, 0, sizeof(volume->clusterTested));
03913     volume->endplane = volume->farplane;
03914     volume->surfaceNum = -1;
03915     volume->facetNum = 0;
03916     VL_R_FloodLight(light, volume, volume->cluster, 0);
03917     if (volume->surfaceNum >= 0)
03918     {
03919         VL_R_CastLightAtSurface(light, volume);
03920     }
03921 }
03922 
03923 /*
03924 =============
03925 VL_R_SplitLightVolume
03926 =============
03927 */
03928 int numvolumes = 0;
03929 
03930 int VL_R_SplitLightVolume(vlight_t *light, lightvolume_t *volume, plane_t *split, int cluster, int firstportal)
03931 {
03932     lightvolume_t back;
03933     int res;
03934 
03935     //
03936     res = VL_SplitLightVolume(volume, &back, split, 0.1);
03937     // if the volume was split
03938     if (res == 2)
03939     {
03940         memcpy(back.clusterTested, volume->clusterTested, sizeof(back.clusterTested));
03941         memcpy(back.facetTested, volume->facetTested, sizeof(back.facetTested));
03942         back.num = numvolumes++;
03943         back.endplane = volume->endplane;
03944         back.surfaceNum = volume->surfaceNum;
03945         back.facetNum = volume->facetNum;
03946         back.type = volume->type;
03947         back.cluster = volume->cluster;
03948         back.farplane = volume->farplane;
03949         if (volume->numtransFacets > 0)
03950         {
03951             memcpy(back.transFacets, volume->transFacets, sizeof(back.transFacets));
03952             memcpy(back.transSurfaces, volume->transSurfaces, sizeof(back.transSurfaces));
03953         }
03954         back.numtransFacets = volume->numtransFacets;
03955         //
03956         // flood the volume at the back of the split plane
03957         VL_R_FloodLight(light, &back, cluster, firstportal);
03958         // if the back volume hit a surface
03959         if (back.surfaceNum >= 0)
03960         {
03961             VL_R_CastLightAtSurface(light, &back);
03962         }
03963     }
03964     return res;
03965 }
03966 
03967 /*
03968 =============
03969 VL_R_FloodLight
03970 =============
03971 */
03972 void VL_R_FloodLight(vlight_t *light, lightvolume_t *volume, int cluster, int firstportal)
03973 {
03974     int i, j, k, res, surfaceNum, backfaceculled, testculled;
03975     float d;
03976     winding_t winding, tmpwinding;
03977     lleaf_t *leaf;
03978     lportal_t *p;
03979     lsurfaceTest_t *test;
03980     lFacet_t *facet;
03981     vec3_t dir1, dir2;
03982     plane_t plane;
03983 
03984     //  DebugNet_RemoveAllPolys();
03985     //  VL_DrawLightVolume(light, volume);
03986 
03987     // if the first portal is not zero then we've checked all occluders in this leaf already
03988     if (firstportal == 0)
03989     {
03990         // check all potential occluders in this leaf
03991         for (i = 0; i < leafs[cluster].numSurfaces; i++)
03992         {
03993             surfaceNum = clustersurfaces[leafs[cluster].firstSurface + i];
03994             //
03995             test = lsurfaceTest[ surfaceNum ];
03996             if ( !test )
03997                 continue;
03998             //
03999             testculled = qfalse;
04000             // use surface as an occluder
04001             for (j = 0; j < test->numFacets; j++)
04002             {
04003                 // use each facet as an occluder
04004                 facet = &test->facets[j];
04005                 //
04006                 //  memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints);
04007                 //  winding.numpoints = facet->numpoints;
04008                 //  DebugNet_DrawWinding(&winding, 5);
04009                 //
04010                 // if the facet was tested already
04011                 if ( volume->facetTested[facet->num >> 3] & (1 << (facet->num & 7)) )
04012                     continue;
04013                 volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
04014                 // backface culling for planar surfaces
04015                 backfaceculled = qfalse;
04016                 if (!test->patch && !test->trisoup)
04017                 {
04018                     if (volume->type == VOLUME_NORMAL)
04019                     {
04020                         // facet backface culling
04021                         d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist;
04022                         if (d < 0)
04023                         {
04024                             // NOTE: this doesn't work too great because of sometimes very bad tesselation
04025                             //      of surfaces that are supposed to be flat
04026                             // FIXME: to work around this problem we should make sure that all facets
04027                             //      created from planar surfaces use the lightmapVecs normal vector
04028                             /*
04029                             if ( !test->shader->twoSided )
04030                             {
04031                                 // skip all other facets of this surface as well because they are in the same plane
04032                                 for (k = 0; k < test->numFacets; k++)
04033                                 {
04034                                     facet = &test->facets[k];
04035                                     volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
04036                                 }
04037                             }*/
04038                             backfaceculled = qtrue;
04039                         }
04040                     }
04041                     else
04042                     {
04043                         // FIXME: if all light source winding points are at the back of the facet
04044                         //          plane then backfaceculled = qtrue
04045                     }
04046                 }
04047                 else // backface culling per facet for patches and triangle soups
04048                 {
04049                     if (volume->type == VOLUME_NORMAL)
04050                     {
04051                         // facet backface culling
04052                         d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist;
04053                         if (d < 0)
04054                             backfaceculled = qtrue;
04055                     }
04056                     else
04057                     {
04058                         // FIXME: if all light source winding points are at the back of the facet
04059                         //          plane then backfaceculled = qtrue
04060                     }
04061                 }
04062                 /* chopping does this already
04063                 // check if this facet is totally or partly in front of the volume end plane
04064                 for (k = 0; k < facet->numpoints; k++)
04065                 {
04066                     d = DotProduct(volume->endplane.normal, facet->points[k]) - volume->endplane.dist;
04067                     if (d > ON_EPSILON)
04068                         break;
04069                 }
04070                 // if this facet is outside the light volume
04071                 if (k >= facet->numpoints)
04072                     continue;
04073                 */
04074                 //
04075                 if (backfaceculled)
04076                 {
04077                     // if the facet is not two sided
04078                     if ( !nobackfaceculling && !test->shader->twoSided )
04079                         continue;
04080                     // flip the winding
04081                     for (k = 0; k < facet->numpoints; k++)
04082                         VectorCopy(facet->points[k], winding.points[facet->numpoints - k - 1]);
04083                     winding.numpoints = facet->numpoints;
04084                 }
04085                 else
04086                 {
04087                     memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints);
04088                     winding.numpoints = facet->numpoints;
04089                 }
04090                 //
04091                 if (!testculled)
04092                 {
04093                     testculled = qtrue;
04094                     // fast check if the surface sphere is totally behind the volume end plane
04095                     d = DotProduct(volume->endplane.normal, test->origin) - volume->endplane.dist;
04096                     if (d < -test->radius)
04097                     {
04098                         for (k = 0; k < test->numFacets; k++)
04099                         {
04100                             facet = &test->facets[k];
04101                             volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
04102                         }
04103                         break;
04104                     }
04105                     for (k = 0; k < volume->numplanes; k++)
04106                     {
04107                         d = DotProduct(volume->planes[k].normal, test->origin) - volume->planes[k].dist;
04108                         if (d < - test->radius)
04109                         {
04110                             for (k = 0; k < test->numFacets; k++)
04111                             {
04112                                 facet = &test->facets[k];
04113                                 volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
04114                             }
04115                             break;
04116                         }
04117                     }
04118                     if (k < volume->numplanes)
04119                         break;
04120                 }
04121                 //NOTE: we have to chop the facet winding with the volume end plane because
04122                 //      the faces in Q3 are not stitched together nicely
04123                 res = VL_ChopWinding(&winding, &volume->endplane, 0.01);
04124                 // if the facet is on or at the back of the volume end plane
04125                 if (res == SIDE_BACK || res == SIDE_ON)
04126                     continue;
04127                 // check if the facet winding is totally or partly inside the light volume
04128                 memcpy(&tmpwinding, &winding, sizeof(winding_t));
04129                 for (k = 0; k < volume->numplanes; k++)
04130                 {
04131                     res = VL_ChopWinding(&tmpwinding, &volume->planes[k], 0.01);
04132                     if (res == SIDE_BACK || res == SIDE_ON)
04133                         break;
04134                 }
04135                 // if no part of the light volume is occluded by this facet
04136                 if (k < volume->numplanes)
04137                     continue;
04138                 //
04139                 for (k = 0; k < winding.numpoints; k++)
04140                 {
04141                     if (volume->type == VOLUME_DIRECTED)
04142                     {
04143                         VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1);
04144                         CrossProduct(light->normal, dir1, plane.normal);
04145                         VectorNormalize(plane.normal, plane.normal);
04146                         plane.dist = DotProduct(plane.normal, winding.points[k]);
04147                     }
04148                     else
04149                     {
04150                         VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1);
04151                         VectorSubtract(light->origin, winding.points[k], dir2);
04152                         CrossProduct(dir1, dir2, plane.normal);
04153                         VectorNormalize(plane.normal, plane.normal);
04154                         plane.dist = DotProduct(plane.normal, winding.points[k]);
04155                     }
04156                     res = VL_R_SplitLightVolume(light, volume, &plane, cluster, 0);
04157                     if (res == 1)
04158                         break; //the facet wasn't really inside the volume
04159                 }
04160                 if (k >= winding.numpoints)
04161                 {
04162                     volume->endplane = facet->plane;
04163                     if (backfaceculled)
04164                     {
04165                         VectorInverse(volume->endplane.normal);
04166                         volume->endplane.dist = -volume->endplane.dist;
04167                     }
04168                     volume->surfaceNum = surfaceNum;
04169                     volume->facetNum = j;
04170                 }
04171             }
04172         }
04173     }
04174     // we've tested all occluders in this cluster
04175     volume->clusterTested[cluster >> 3] |= 1 << (cluster & 7);
04176     // flood light through the portals of the current leaf
04177     leaf = &leafs[cluster];
04178     for (i = firstportal; i < leaf->numportals; i++)
04179     {
04180         p = leaf->portals[i];
04181         //
04182         //  memcpy(&winding, p->winding, sizeof(winding_t));
04183         //  DebugNet_DrawWinding(&winding, 5);
04184         // if already flooded into the cluster this portal leads to
04185         if ( volume->clusterTested[p->leaf >> 3] & (1 << (p->leaf & 7)) )
04186             continue;
04187         //
04188         if (volume->type == VOLUME_NORMAL)
04189         {
04190             // portal backface culling
04191             d = DotProduct(light->origin, p->plane.normal) - p->plane.dist;
04192             if (d > 0) // portal plane normal points into neighbour cluster
04193                 continue;
04194         }
04195         else
04196         {
04197             // FIXME: if all light source winding points are at the back of this portal
04198             //          plane then there's no need to flood through
04199         }
04200         // check if this portal is totally or partly in front of the volume end plane
04201         // fast check with portal sphere
04202         d = DotProduct(volume->endplane.normal, p->origin) - volume->endplane.dist;
04203         if (d < -p->radius)
04204             continue;
04205         for (j = 0; j < p->winding->numpoints; j++)
04206         {
04207             d = DotProduct(volume->endplane.normal, p->winding->points[j]) - volume->endplane.dist;
04208             if (d > -0.01)
04209                 break;
04210         }
04211         // if this portal is totally behind the light volume end plane
04212         if (j >= p->winding->numpoints)
04213             continue;
04214         //distance from point light to portal
04215         d = DotProduct(p->plane.normal, light->origin) - p->plane.dist;
04216         // only check if a point light is Not *on* the portal
04217         if (volume->type != VOLUME_NORMAL || fabs(d) > 0.1)
04218         {
04219             // check if the portal is partly or totally inside the light volume
04220             memcpy(&winding, p->winding, sizeof(winding_t));
04221             for (j = 0; j < volume->numplanes; j++)
04222             {
04223                 res = VL_ChopWinding(&winding, &volume->planes[j], 0.01);
04224                 if (res == SIDE_BACK || res == SIDE_ON)
04225                     break;
04226             }
04227             // if the light volume does not go through this portal at all
04228             if (j < volume->numplanes)
04229                 continue;
04230         }
04231         // chop the light volume with the portal
04232         for (k = 0; k < p->winding->numpoints; k++)
04233         {
04234             if (volume->type == VOLUME_DIRECTED)
04235             {
04236                 VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1);
04237                 CrossProduct(light->normal, dir1, plane.normal);
04238                 VectorNormalize(plane.normal, plane.normal);
04239                 plane.dist = DotProduct(plane.normal, p->winding->points[k]);
04240             }
04241             else
04242             {
04243                 VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1);
04244                 VectorSubtract(light->origin, p->winding->points[k], dir2);
04245                 CrossProduct(dir1, dir2, plane.normal);
04246                 VectorNormalize(plane.normal, plane.normal);
04247                 plane.dist = DotProduct(plane.normal, p->winding->points[k]);
04248             }
04249             res = VL_R_SplitLightVolume(light, volume, &plane, cluster, i+1);
04250             if (res == 1)
04251                 break; //volume didn't really go through the portal
04252         }
04253         // if the light volume went through the portal
04254         if (k >= p->winding->numpoints)
04255         {
04256             // flood through the portal
04257             VL_R_FloodLight(light, volume, p->leaf, 0);
04258         }
04259     }
04260 }
04261 
04262 /*
04263 =============
04264 VL_R_FloodAreaSpotLight
04265 =============
04266 */
04267 void VL_FloodAreaSpotLight(vlight_t *light, winding_t *w, int leafnum)
04268 {
04269 }
04270 
04271 /*
04272 =============
04273 VL_R_SubdivideAreaSpotLight
04274 =============
04275 */
04276 void VL_R_SubdivideAreaSpotLight(vlight_t *light, int nodenum, winding_t *w)
04277 {
04278     int leafnum, res;
04279     dnode_t *node;
04280     dplane_t *plane;
04281     winding_t back;
04282     plane_t split;
04283 
04284     while(nodenum >= 0)
04285     {
04286         node = &dnodes[nodenum];
04287         plane = &dplanes[node->planeNum];
04288 
04289         VectorCopy(plane->normal, split.normal);
04290         split.dist = plane->dist;
04291         res = VL_SplitWinding (w, &back, &split, 0.1);
04292 
04293         if (res == SIDE_FRONT)
04294         {
04295             nodenum = node->children[0];
04296         }
04297         else if (res == SIDE_BACK)
04298         {
04299             nodenum = node->children[1];
04300         }
04301         else if (res == SIDE_ON)
04302         {
04303             memcpy(&back, w, sizeof(winding_t));
04304             VL_R_SubdivideAreaSpotLight(light, node->children[1], &back);
04305             nodenum = node->children[0];
04306         }
04307         else
04308         {
04309             VL_R_SubdivideAreaSpotLight(light, node->children[1], &back);
04310             nodenum = node->children[0];
04311         }
04312     }
04313     leafnum = -nodenum - 1;
04314     if (dleafs[leafnum].cluster != -1)
04315     {
04316         VL_FloodAreaSpotLight(light, w, leafnum);
04317     }
04318 }
04319 
04320 /*
04321 =============
04322 VL_R_FloodRadialAreaLight
04323 =============
04324 */
04325 void VL_FloodRadialAreaLight(vlight_t *light, winding_t *w, int leafnum)
04326 {
04327 }
04328 
04329 /*
04330 =============
04331 VL_R_SubdivideRadialAreaLight
04332 =============
04333 */
04334 void VL_R_SubdivideRadialAreaLight(vlight_t *light, int nodenum, winding_t *w)
04335 {
04336     int leafnum, res;
04337     dnode_t *node;
04338     dplane_t *plane;
04339     winding_t back;
04340     plane_t split;
04341 
04342     while(nodenum >= 0)
04343     {
04344         node = &dnodes[nodenum];
04345         plane = &dplanes[node->planeNum];
04346 
04347         VectorCopy(plane->normal, split.normal);
04348         split.dist = plane->dist;
04349         res = VL_SplitWinding (w, &back, &split, 0.1);
04350 
04351         if (res == SIDE_FRONT)
04352         {
04353             nodenum = node->children[0];
04354         }
04355         else if (res == SIDE_BACK)
04356         {
04357             nodenum = node->children[1];
04358         }
04359         else if (res == SIDE_ON)
04360         {
04361             memcpy(&back, w, sizeof(winding_t));
04362             VL_R_SubdivideRadialAreaLight(light, node->children[1], &back);
04363             nodenum = node->children[0];
04364         }
04365         else
04366         {
04367             VL_R_SubdivideRadialAreaLight(light, node->children[1], &back);
04368             nodenum = node->children[0];
04369         }
04370     }
04371     leafnum = -nodenum - 1;
04372     if (dleafs[leafnum].cluster != -1)
04373     {
04374         VL_FloodRadialAreaLight(light, w, leafnum);
04375     }
04376 }
04377 
04378 /*
04379 =============
04380 VL_R_FloodDirectedLight
04381 =============
04382 */
04383 void VL_FloodDirectedLight(vlight_t *light, winding_t *w, int leafnum)
04384 {
04385     int i;
04386     float dist;
04387     lightvolume_t volume;
04388     vec3_t dir;
04389 
04390     if (light->atten_disttype == LDAT_NOSCALE)
04391     {
04392         // light travels without decrease in intensity over distance
04393         dist = MAX_WORLD_COORD;
04394     }
04395     else
04396     {
04397         if ( light->atten_disttype == LDAT_LINEAR )
04398             dist = light->photons * lightLinearScale;
04399         else
04400             dist = sqrt(light->photons);
04401     }
04402 
04403     memset(&volume, 0, sizeof(lightvolume_t));
04404     for (i = 0; i < w->numpoints; i++)
04405     {
04406         VectorMA(w->points[i], dist, light->normal, volume.points[i]);
04407         VectorSubtract(w->points[(i+1)%w->numpoints], w->points[i], dir);
04408         CrossProduct(light->normal, dir, volume.planes[i].normal);
04409         VectorNormalize(volume.planes[i].normal, volume.planes[i].normal);
04410         volume.planes[i].dist = DotProduct(volume.planes[i].normal, w->points[i]);
04411     }
04412     volume.numplanes = w->numpoints;
04413     VectorCopy(light->normal, volume.endplane.normal);
04414     VectorInverse(volume.endplane.normal);
04415     volume.endplane.dist = DotProduct(volume.endplane.normal, volume.points[0]);
04416     volume.farplane = volume.endplane;
04417     volume.surfaceNum = -1;
04418     volume.type = VOLUME_DIRECTED;
04419     volume.cluster = dleafs[leafnum].cluster;
04420     VL_R_FloodLight(light, &volume, volume.cluster, 0);
04421     if (volume.surfaceNum >= 0)
04422     {
04423         VL_R_CastLightAtSurface(light, &volume);
04424     }
04425 }
04426 
04427 /*
04428 =============
04429 VL_R_SubdivideDirectedAreaLight
04430 =============
04431 */
04432 void VL_R_SubdivideDirectedAreaLight(vlight_t *light, int nodenum, winding_t *w)
04433 {
04434     int leafnum, res;
04435     dnode_t *node;
04436     dplane_t *plane;
04437     winding_t back;
04438     plane_t split;
04439 
04440     while(nodenum >= 0)
04441     {
04442         node = &dnodes[nodenum];
04443         plane = &dplanes[node->planeNum];
04444 
04445         VectorCopy(plane->normal, split.normal);
04446         split.dist = plane->dist;
04447         res = VL_SplitWinding (w, &back, &split, 0.1);
04448 
04449         if (res == SIDE_FRONT)
04450         {
04451             nodenum = node->children[0];
04452         }
04453         else if (res == SIDE_BACK)
04454         {
04455             nodenum = node->children[1];
04456         }
04457         else if (res == SIDE_ON)
04458         {
04459             memcpy(&back, w, sizeof(winding_t));
04460             VL_R_SubdivideDirectedAreaLight(light, node->children[1], &back);
04461             nodenum = node->children[0];
04462         }
04463         else
04464         {
04465             VL_R_SubdivideDirectedAreaLight(light, node->children[1], &back);
04466             nodenum = node->children[0];
04467         }
04468     }
04469     leafnum = -nodenum - 1;
04470     if (dleafs[leafnum].cluster != -1)
04471     {
04472         VL_FloodDirectedLight(light, w, leafnum);
04473     }
04474 }
04475 
04476 /*
04477 =============
04478 VL_FloodLight
04479 =============
04480 */
04481 void VL_FloodLight(vlight_t *light)
04482 {
04483     lightvolume_t volume;
04484     dleaf_t *leaf;
04485     int leafnum, i, j, k, dir[2][4] = {{1, 1, -1, -1}, {1, -1, -1, 1}};
04486     float a, step, dist, radius, windingdist;
04487     vec3_t vec, r, p, temp;
04488     winding_t winding;
04489 
04490     switch(light->type)
04491     {
04492         case LIGHT_POINTRADIAL:
04493         {
04494             // source is a point
04495             // light radiates in all directions
04496             // creates sharp shadows
04497             //
04498             // create 6 volumes shining in the axis directions
04499             // what about: 4 tetrahedrons instead?
04500             //
04501             if ( light->atten_disttype == LDAT_LINEAR )
04502                 dist = light->photons * lightLinearScale;
04503             else
04504                 dist = sqrt(light->photons);
04505             //always put the winding at a large distance to avoid epsilon issues
04506             windingdist = MAX_WORLD_COORD;
04507             if (dist > windingdist)
04508                 windingdist = dist;
04509             //
04510             leafnum = VL_LightLeafnum(light->origin);
04511             leaf = &dleafs[leafnum];
04512             if (leaf->cluster == -1)
04513             {
04514                 light->insolid = qtrue;
04515                 break;
04516             }
04517             // for each axis
04518             for (i = 0; i < 3; i++)
04519             {
04520                 // for both directions on the axis
04521                 for (j = -1; j <= 1; j += 2)
04522                 {
04523                     memset(&volume, 0, sizeof(lightvolume_t));
04524                     volume.numplanes = 0;
04525                     for (k = 0; k < 4; k ++)
04526                     {
04527                         volume.points[volume.numplanes][i] = light->origin[i] + j * windingdist;
04528                         volume.points[volume.numplanes][(i+1)%3] = light->origin[(i+1)%3] + dir[0][k] * windingdist;
04529                         volume.points[volume.numplanes][(i+2)%3] = light->origin[(i+2)%3] + dir[1][k] * windingdist;
04530                         volume.numplanes++;
04531                     }
04532                     if (j >= 0)
04533                     {
04534                         VectorCopy(volume.points[0], temp);
04535                         VectorCopy(volume.points[2], volume.points[0]);
04536                         VectorCopy(temp, volume.points[2]);
04537                     }
04538                     for (k = 0; k < volume.numplanes; k++)
04539                     {
04540                         VL_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]);
04541                     }
04542                     VectorCopy(light->origin, temp);
04543                     temp[i] += (float) j * dist;
04544                     VectorClear(volume.endplane.normal);
04545                     volume.endplane.normal[i] = -j;
04546                     volume.endplane.dist = DotProduct(volume.endplane.normal, temp); //DotProduct(volume.endplane.normal, volume.points[0]);
04547                     volume.farplane = volume.endplane;
04548                     volume.cluster = leaf->cluster;
04549                     volume.surfaceNum = -1;
04550                     volume.type = VOLUME_NORMAL;
04551                     //
04552                     memset(volume.facetTested, 0, sizeof(volume.facetTested));
04553                     memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
04554                     VL_R_FloodLight(light, &volume, leaf->cluster, 0);
04555                     if (volume.surfaceNum >= 0)
04556                     {
04557                         VL_R_CastLightAtSurface(light, &volume);
04558                     }
04559                 }
04560             }
04561             break;
04562         }
04563         case LIGHT_POINTSPOT:
04564         {
04565             // source is a point
04566             // light is targetted
04567             // creates sharp shadows
04568             //
04569             // what about using brushes to shape spot lights? that'd be pretty cool
04570             //
04571             if ( light->atten_disttype == LDAT_LINEAR )
04572                 dist = light->photons * lightLinearScale;
04573             else
04574                 dist = sqrt(light->photons);
04575             dist *= 2;
04576             //
04577             windingdist = 4096;
04578             if (dist > windingdist)
04579                 windingdist = dist;
04580             //take 8 times the cone radius because the spotlight also lights outside the cone
04581             radius = 8 * windingdist * light->radiusByDist;
04582             //
04583             memset(&volume, 0, sizeof(lightvolume_t));
04584             leafnum = VL_LightLeafnum(light->origin);
04585             leaf = &dleafs[leafnum];
04586             if (leaf->cluster == -1)
04587             {
04588                 light->insolid = qtrue;
04589                 break;
04590             }
04591             //
04592             VectorClear(vec);
04593             for (i = 0; i < 3; i++)
04594             {
04595                 if (light->normal[i] > -0.9 && light->normal[i] < 0.9)
04596                 {
04597                     vec[i] = 1;
04598                     break;
04599                 }
04600             }
04601             CrossProduct(light->normal, vec, r);
04602             VectorScale(r, radius, p);
04603             volume.numplanes = 0;
04604             step = 45;
04605             for (a = step / 2; a < 360 + step / 2; a += step)
04606             {
04607                 RotatePointAroundVector(volume.points[volume.numplanes], light->normal, p, a);
04608                 VectorAdd(light->origin, volume.points[volume.numplanes], volume.points[volume.numplanes]);
04609                 VectorMA(volume.points[volume.numplanes], windingdist, light->normal, volume.points[volume.numplanes]);
04610                 volume.numplanes++;
04611             }
04612             for (i = 0; i < volume.numplanes; i++)
04613             {
04614                 VL_PlaneFromPoints(&volume.planes[i], light->origin, volume.points[(i+1)%volume.numplanes], volume.points[i]);
04615             }
04616             VectorMA(light->origin, dist, light->normal, temp);
04617             VectorCopy(light->normal, volume.endplane.normal);
04618             VectorInverse(volume.endplane.normal);
04619             volume.endplane.dist = DotProduct(volume.endplane.normal, temp);//DotProduct(volume.endplane.normal, volume.points[0]);
04620             volume.farplane = volume.endplane;
04621             volume.cluster = leaf->cluster;
04622             volume.surfaceNum = -1;
04623             volume.type = VOLUME_NORMAL;
04624             //
04625             memset(volume.facetTested, 0, sizeof(volume.facetTested));
04626             memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
04627             VL_R_FloodLight(light, &volume, leaf->cluster, 0);
04628             if (volume.surfaceNum >= 0)
04629             {
04630                 VL_R_CastLightAtSurface(light, &volume);
04631             }
04632             break;
04633         }
04634         case LIGHT_POINTFAKESURFACE:
04635         {
04636             float value;
04637             int n, axis;
04638             vec3_t v, vecs[2];
04639 
04640             if ( light->atten_disttype == LDAT_LINEAR )
04641                 dist = light->photons * lightLinearScale;
04642             else
04643                 dist = sqrt(light->photons);
04644             //always put the winding at a large distance to avoid epsilon issues
04645             windingdist = 4096;
04646             if (dist > windingdist)
04647                 windingdist = dist;
04648             //
04649             VectorMA(light->origin, 0.1, light->normal, light->origin);
04650             //
04651             leafnum = VL_LightLeafnum(light->origin);
04652             leaf = &dleafs[leafnum];
04653             if (leaf->cluster == -1)
04654             {
04655                 light->insolid = qtrue;
04656                 break;
04657             }
04658             value = 0;
04659             for (i = 0; i < 3; i++)
04660             {
04661                 if (fabs(light->normal[i]) > value)
04662                 {
04663                     value = fabs(light->normal[i]);
04664                     axis = i;
04665                 }
04666             }
04667             for (i = 0; i < 2; i++)
04668             {
04669                 VectorClear(v);
04670                 v[(axis + 1 + i) % 3] = 1;
04671                 CrossProduct(light->normal, v, vecs[i]);
04672             }
04673             //cast 4 volumes at the front of the surface
04674             for (i = -1; i <= 1; i += 2)
04675             {
04676                 for (j = -1; j <= 1; j += 2)
04677                 {
04678                     for (n = 0; n < 2; n++)
04679                     {
04680                         memset(&volume, 0, sizeof(lightvolume_t));
04681                         volume.numplanes = 3;
04682                         VectorMA(light->origin, i * windingdist, vecs[0], volume.points[(i == j) == n]);
04683                         VectorMA(light->origin, j * windingdist, vecs[1], volume.points[(i != j) == n]);
04684                         VectorMA(light->origin, windingdist, light->normal, volume.points[2]);
04685                         for (k = 0; k < volume.numplanes; k++)
04686                         {
04687                             VL_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]);
04688                         }
04689                         VL_PlaneFromPoints(&volume.endplane, volume.points[0], volume.points[1], volume.points[2]);
04690                         VectorMA(light->origin, dist, light->normal, temp);
04691                         volume.endplane.dist = DotProduct(volume.endplane.normal, temp);
04692                         if (DotProduct(light->origin, volume.endplane.normal) - volume.endplane.dist > 0)
04693                             break;
04694                     }
04695                     volume.farplane = volume.endplane;
04696                     volume.cluster = leaf->cluster;
04697                     volume.surfaceNum = -1;
04698                     volume.type = VOLUME_NORMAL;
04699                     //
04700                     memset(volume.facetTested, 0, sizeof(volume.facetTested));
04701                     memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
04702 
04703                     VL_R_FloodLight(light, &volume, leaf->cluster, 0);
04704                     if (volume.surfaceNum >= 0)
04705                     {
04706                         VL_R_CastLightAtSurface(light, &volume);
04707                     }
04708                 }
04709             }
04710             break;
04711         }
04712         case LIGHT_SURFACEDIRECTED:
04713         {
04714             // source is an area defined by a winding
04715             // the light is unidirectional
04716             // creates sharp shadows
04717             // for instance sun light or laser light
04718             //
04719             memcpy(&winding, &light->w, sizeof(winding_t));
04720             VL_R_SubdivideDirectedAreaLight(light, 0, &winding);
04721             break;
04722         }
04723         case LIGHT_SURFACERADIAL:
04724         {
04725             // source is an area defined by a winding
04726             // the light radiates in all directions at the front of the winding plane
04727             //
04728             memcpy(&winding, &light->w, sizeof(winding_t));
04729             VL_R_SubdivideRadialAreaLight(light, 0, &winding);
04730             break;
04731         }
04732         case LIGHT_SURFACESPOT:
04733         {
04734             // source is an area defined by a winding
04735             // light is targetted but not unidirectional
04736             //
04737             memcpy(&winding, &light->w, sizeof(winding_t));
04738             VL_R_SubdivideAreaSpotLight(light, 0, &winding);
04739             break;
04740         }
04741     }
04742 }
04743 
04744 /*
04745 =============
04746 VL_FloodLightThread
04747 =============
04748 */
04749 void VL_FloodLightThread(int num)
04750 {
04751     VL_FloodLight(vlights[num]);
04752 }
04753 
04754 /*
04755 =============
04756 VL_TestLightLeafs
04757 =============
04758 */
04759 void VL_TestLightLeafs(void)
04760 {
04761     int leafnum, i;
04762     vlight_t *light;
04763     dleaf_t *leaf;
04764 
04765     for (i = 0; i < numvlights; i++)
04766     {
04767         light = vlights[i];
04768         if (light->type != LIGHT_POINTRADIAL &&
04769             light->type != LIGHT_POINTSPOT)
04770             continue;
04771         leafnum = VL_LightLeafnum(light->origin);
04772         leaf = &dleafs[leafnum];
04773         if (leaf->cluster == -1)
04774             if (light->type == LIGHT_POINTRADIAL)
04775                 qprintf("light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]);
04776             else if (light->type == LIGHT_POINTSPOT)
04777                 qprintf("spot light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]);
04778     }
04779 }
04780 
04781 
04782 /*
04783 =============
04784 VL_DoForcedTraceLight
04785 =============
04786 */
04787 // from light.c
04788 void TraceLtm( int num );
04789 
04790 void VL_DoForcedTraceLight(int num)
04791 {
04792     dsurface_t      *ds;
04793     shaderInfo_t    *si;
04794 
04795     ds = &drawSurfaces[num];
04796 
04797     if ( ds->surfaceType == MST_TRIANGLE_SOUP )
04798         return;
04799 
04800     if ( ds->lightmapNum < 0 )
04801         return;
04802 
04803     // always light entity surfaces with the old light algorithm
04804     if ( !entitySurface[num] )
04805     {
04806         si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
04807 
04808         if (defaulttracelight)
04809         {
04810             if (si->forceVLight)
04811                 return;
04812         }
04813         else
04814         {
04815             if (!si->forceTraceLight)
04816                 return;
04817         }
04818     }
04819 
04820     TraceLtm(num);
04821 }
04822 
04823 /*
04824 =============
04825 VL_DoForcedTraceLightSurfaces
04826 =============
04827 */
04828 void VL_DoForcedTraceLightSurfaces(void)
04829 {
04830     _printf( "forced trace light\n" );
04831     RunThreadsOnIndividual( numDrawSurfaces, qtrue, VL_DoForcedTraceLight );
04832 }
04833 
04834 float *oldLightFloats;
04835 
04836 /*
04837 =============
04838 VL_SurfaceRadiosity
04839 =============
04840 */
04841 void VL_SurfaceRadiosity( int num ) {
04842     dsurface_t      *ds;
04843     mesh_t          *mesh;
04844     shaderInfo_t    *si;
04845     lsurfaceTest_t *test;
04846     int x, y, k;
04847     vec3_t base, normal;
04848     float *color, area;
04849     vlight_t vlight;
04850 
04851     ds = &drawSurfaces[num];
04852 
04853     if ( ds->lightmapNum < 0 ) {
04854         return;     // doesn't have a lightmap
04855     }
04856 
04857     // vertex-lit triangle model
04858     if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
04859         return;
04860     }
04861 
04862     si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
04863     test = lsurfaceTest[ num ];
04864 
04865     if (!test) {
04866         return;
04867     }
04868 
04869     for (x = 0; x < ds->lightmapWidth; x++) {
04870         for (y = 0; y < ds->lightmapHeight; y++) {
04871             //
04872             k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y) 
04873                             * LIGHTMAP_WIDTH + ds->lightmapX + x;
04874             area = lightmappixelarea[k];
04875             if (area <= 0)
04876                 continue;
04877             //
04878             if (ds->surfaceType == MST_PATCH)
04879             {
04880                 mesh = test->detailMesh;
04881                 VectorCopy( mesh->verts[y*mesh->width+x].xyz, base);
04882                 VectorCopy( mesh->verts[y*mesh->width+x].normal, normal);
04883             }
04884             else
04885             {
04886                 VectorMA(ds->lightmapOrigin, (float) x, ds->lightmapVecs[0], base);
04887                 VectorMA(base, (float) y, ds->lightmapVecs[1], base);
04888                 VectorCopy(test->facets[0].plane.normal, normal);
04889             }
04890             // create ligth from base
04891             memset(&vlight, 0, sizeof(vlight_t));
04892             color = &oldLightFloats[k*3];
04893             // a few units away from the surface
04894             VectorMA(base, 5, normal, vlight.origin);
04895             ColorNormalize(color, vlight.color);
04896             // ok this is crap
04897             vlight.photons = VectorLength(color) * 0.05 * lightPointScale / (area * radiosity_scale);
04898             // what about using a front facing light only ?
04899             vlight.type = LIGHT_POINTRADIAL;
04900             // flood the light from this lightmap pixel
04901             VL_FloodLight(&vlight);
04902             // only one thread at a time may write to the lightmap of this surface
04903             MutexLock(test->mutex);
04904             // don't light the lightmap pixel itself
04905             lightFloats[k*3] = oldLightFloats[k*3];
04906             lightFloats[k*3+1] = oldLightFloats[k*3+1];
04907             lightFloats[k*3+2] = oldLightFloats[k*3+2];
04908             //
04909             MutexUnlock(test->mutex);
04910         }
04911     }
04912 }
04913 
04914 /*
04915 =============
04916 VL_Radiosity
04917 
04918 this aint working real well but it's fun to play with.
04919 =============
04920 */
04921 void VL_Radiosity(void) {
04922 
04923     oldLightFloats = lightFloats;
04924     lightFloats = (float *) malloc(numLightBytes * sizeof(float));
04925     memcpy(lightFloats, oldLightFloats, numLightBytes * sizeof(float));
04926     _printf("%7i surfaces\n", numDrawSurfaces);
04927     RunThreadsOnIndividual( numDrawSurfaces, qtrue, VL_SurfaceRadiosity );
04928     free(oldLightFloats);
04929 }
04930 
04931 /*
04932 =============
04933 VL_LightWorld
04934 =============
04935 */
04936 void VL_LightWorld(void)
04937 {
04938     int i, numcastedvolumes, numvlightsinsolid;
04939     float f;
04940 
04941     // find the optional world ambient
04942     GetVectorForKey( &entities[0], "_color", lightAmbientColor );
04943     f = FloatForKey( &entities[0], "ambient" );
04944     VectorScale( lightAmbientColor, f, lightAmbientColor );
04945     /*
04946     _printf("\r%6d lights out of %d", 0, numvlights);
04947     for (i = 0; i < numvlights; i++)
04948     {
04949         _printf("\r%6d", i);
04950         VL_FloodLight(vlights[i]);
04951     }
04952     _printf("\r%6d lights out of %d\n", i, numvlights);
04953     */
04954     _printf("%7i lights\n", numvlights);
04955     RunThreadsOnIndividual( numvlights, qtrue, VL_FloodLightThread );
04956 
04957     numcastedvolumes = 0;
04958     for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
04959         if (lsurfaceTest[i])
04960             numcastedvolumes += lsurfaceTest[i]->numvolumes;
04961     }
04962     _printf("%7i light volumes casted\n", numcastedvolumes);
04963     numvlightsinsolid = 0;
04964     for (i = 0; i < numvlights; i++)
04965     {
04966         if (vlights[i]->insolid)
04967             numvlightsinsolid++;
04968     }
04969     _printf("%7i lights in solid\n", numvlightsinsolid);
04970     //
04971     radiosity_scale = 1;
04972     for (i = 0; i < radiosity; i++) {
04973         VL_Radiosity();
04974         radiosity_scale <<= 1;
04975     }
04976     //
04977     VL_StoreLightmap();
04978     // redo surfaces with the old light algorithm when needed
04979     VL_DoForcedTraceLightSurfaces();
04980 }
04981 
04982 /*
04983 =============
04984 VL_CreateEntityLights
04985 =============
04986 */
04987 entity_t *FindTargetEntity( const char *target );
04988 
04989 void VL_CreateEntityLights (void)
04990 {
04991     int     i, c_entityLights;
04992     vlight_t    *dl;
04993     entity_t    *e, *e2;
04994     const char  *name;
04995     const char  *target;
04996     vec3_t  dest;
04997     const char  *_color;
04998     float   intensity;
04999     int     spawnflags;
05000 
05001     //
05002     c_entityLights = 0;
05003     _printf("Creating entity lights...\n");
05004     //
05005     for ( i = 0 ; i < num_entities ; i++ ) {
05006         e = &entities[i];
05007         name = ValueForKey (e, "classname");
05008         if (strncmp (name, "light", 5))
05009             continue;
05010 
05011         dl = malloc(sizeof(*dl));
05012         memset (dl, 0, sizeof(*dl));
05013 
05014         spawnflags = FloatForKey (e, "spawnflags");
05015         if ( spawnflags & 1 ) {
05016             dl->atten_disttype = LDAT_LINEAR;
05017         }
05018         if ( spawnflags & 2 ) {
05019             dl->atten_disttype = LDAT_NOSCALE;
05020         }
05021         if ( spawnflags & 4 ) {
05022             dl->atten_angletype = LAAT_QUADRATIC;
05023         }
05024         if ( spawnflags & 8 ) {
05025             dl->atten_angletype = LAAT_DOUBLEQUADRATIC;
05026         }
05027 
05028         dl->atten_distscale = FloatForKey(e, "atten_distscale");
05029         dl->atten_anglescale = FloatForKey(e, "atten_anglescale");
05030 
05031         GetVectorForKey (e, "origin", dl->origin);
05032         dl->style = FloatForKey (e, "_style");
05033         if (!dl->style)
05034             dl->style = FloatForKey (e, "style");
05035         if (dl->style < 0)
05036             dl->style = 0;
05037 
05038         intensity = FloatForKey (e, "light");
05039         if (!intensity)
05040             intensity = FloatForKey (e, "_light");
05041         if (!intensity)
05042             intensity = 300;
05043         _color = ValueForKey (e, "_color");
05044         if (_color && _color[0])
05045         {
05046             sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);
05047             ColorNormalize (dl->color, dl->color);
05048         }
05049         else
05050             dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
05051 
05052         intensity = intensity * lightPointScale;
05053         dl->photons = intensity;
05054 
05055         dl->type = LIGHT_POINTRADIAL;
05056 
05057         // lights with a target will be spotlights
05058         target = ValueForKey (e, "target");
05059 
05060         if ( target[0] ) {
05061             float   radius;
05062             float   dist;
05063 
05064             e2 = FindTargetEntity (target);
05065             if (!e2) {
05066                 _printf ("WARNING: light at (%i %i %i) has missing target\n",
05067                 (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]);
05068             } else {
05069                 GetVectorForKey (e2, "origin", dest);
05070                 VectorSubtract (dest, dl->origin, dl->normal);
05071                 dist = VectorNormalize (dl->normal, dl->normal);
05072                 radius = FloatForKey (e, "radius");
05073                 if ( !radius ) {
05074                     radius = 64;
05075                 }
05076                 if ( !dist ) {
05077                     dist = 64;
05078                 }
05079                 dl->radiusByDist = (radius + 16) / dist;
05080                 dl->type = LIGHT_POINTSPOT;
05081             }
05082         }
05083         vlights[numvlights++] = dl;
05084         c_entityLights++;
05085     }
05086     _printf("%7i entity lights\n", c_entityLights);
05087 }
05088 
05089 /*
05090 ==================
05091 VL_SubdivideAreaLight
05092 ==================
05093 */
05094 void VL_SubdivideAreaLight( shaderInfo_t *ls, winding_t *w, vec3_t normal, 
05095                         float areaSubdivide, qboolean backsplash ) {
05096     float           area, value, intensity;
05097     vlight_t            *dl, *dl2;
05098     vec3_t          mins, maxs;
05099     int             axis;
05100     winding_t       *front, *back;
05101     vec3_t          planeNormal;
05102     float           planeDist;
05103 
05104     if ( !w ) {
05105         return;
05106     }
05107 
05108     WindingBounds( w, mins, maxs );
05109 
05110     // check for subdivision
05111     for ( axis = 0 ; axis < 3 ; axis++ ) {
05112         if ( maxs[axis] - mins[axis] > areaSubdivide ) {
05113             VectorClear( planeNormal );
05114             planeNormal[axis] = 1;
05115             planeDist = ( maxs[axis] + mins[axis] ) * 0.5;
05116             ClipWindingEpsilon ( w, planeNormal, planeDist, ON_EPSILON, &front, &back );
05117             VL_SubdivideAreaLight( ls, front, normal, areaSubdivide, qfalse );
05118             VL_SubdivideAreaLight( ls, back, normal, areaSubdivide, qfalse );
05119             FreeWinding( w );
05120             return;
05121         }
05122     }
05123 
05124     // create a light from this
05125     area = WindingArea (w);
05126     if ( area <= 0 || area > 20000000 ) {
05127         return;
05128     }
05129 
05130     dl = malloc(sizeof(*dl));
05131     memset (dl, 0, sizeof(*dl));
05132     dl->type = LIGHT_POINTFAKESURFACE;
05133 
05134     WindingCenter( w, dl->origin );
05135     memcpy(dl->w.points, w->points, sizeof(vec3_t) * w->numpoints);
05136     dl->w.numpoints = w->numpoints;
05137     VectorCopy ( normal, dl->normal);
05138     VectorCopy ( normal, dl->plane);
05139     dl->plane[3] = DotProduct( dl->origin, normal );
05140 
05141     value = ls->value;
05142     intensity = value * area * lightAreaScale;
05143     VectorAdd( dl->origin, dl->normal, dl->origin );
05144 
05145     VectorCopy( ls->color, dl->color );
05146 
05147     dl->photons = intensity;
05148 
05149     // emitColor is irrespective of the area
05150     VectorScale( ls->color, value*lightFormFactorValueScale*lightAreaScale, dl->emitColor );
05151     //
05152     VectorCopy(dl->emitColor, dl->color);
05153 
05154     dl->si = ls;
05155 
05156     if ( ls->contents & CONTENTS_FOG ) {
05157         dl->twosided = qtrue;
05158     }
05159 
05160     vlights[numvlights++] = dl;
05161 
05162     // optionally create a point backsplash light
05163     if ( backsplash && ls->backsplashFraction > 0 ) {
05164 
05165         dl2 = malloc(sizeof(*dl));
05166         memset (dl2, 0, sizeof(*dl2));
05167         dl2->type = LIGHT_POINTRADIAL;
05168 
05169         VectorMA( dl->origin, ls->backsplashDistance, normal, dl2->origin );
05170 
05171         VectorCopy( ls->color, dl2->color );
05172 
05173         dl2->photons = dl->photons * ls->backsplashFraction;
05174         dl2->si = ls;
05175 
05176         vlights[numvlights++] = dl2;
05177     }
05178 }
05179 
05180 /*
05181 ==================
05182 VL_CreateFakeSurfaceLights
05183 ==================
05184 */
05185 void VL_CreateFakeSurfaceLights( void ) {
05186     int             i, j, side;
05187     dsurface_t      *ds;
05188     shaderInfo_t    *ls;
05189     winding_t       *w;
05190     lFacet_t        *f;
05191     vlight_t            *dl;
05192     vec3_t          origin;
05193     drawVert_t      *dv;
05194     int             c_surfaceLights;
05195     float           lightSubdivide;
05196     vec3_t          normal;
05197 
05198 
05199     c_surfaceLights = 0;
05200     _printf ("Creating surface lights...\n");
05201 
05202     for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
05203         // see if this surface is light emiting
05204         ds = &drawSurfaces[i];
05205 
05206         ls = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
05207         if ( ls->value == 0 ) {
05208             continue;
05209         }
05210 
05211         // determine how much we need to chop up the surface
05212         if ( ls->lightSubdivide ) {
05213             lightSubdivide = ls->lightSubdivide;
05214         } else {
05215             lightSubdivide = lightDefaultSubdivide;
05216         }
05217 
05218         c_surfaceLights++;
05219 
05220         // an autosprite shader will become
05221         // a point light instead of an area light
05222         if ( ls->autosprite ) {
05223             // autosprite geometry should only have four vertexes
05224             if ( lsurfaceTest[i] ) {
05225                 // curve or misc_model
05226                 f = lsurfaceTest[i]->facets;
05227                 if ( lsurfaceTest[i]->numFacets != 1 || f->numpoints != 4 ) {
05228                     _printf( "WARNING: surface at (%i %i %i) has autosprite shader but isn't a quad\n",
05229                         (int)f->points[0], (int)f->points[1], (int)f->points[2] );
05230                 }
05231                 VectorAdd( f->points[0], f->points[1], origin );
05232                 VectorAdd( f->points[2], origin, origin );
05233                 VectorAdd( f->points[3], origin, origin );
05234                 VectorScale( origin, 0.25, origin );
05235             } else {
05236                 // normal polygon
05237                 dv = &drawVerts[ ds->firstVert ];
05238                 if ( ds->numVerts != 4 ) {
05239                     _printf( "WARNING: surface at (%i %i %i) has autosprite shader but %i verts\n",
05240                         (int)dv->xyz[0], (int)dv->xyz[1], (int)dv->xyz[2] );
05241                     continue;
05242                 }
05243 
05244                 VectorAdd( dv[0].xyz, dv[1].xyz, origin );
05245                 VectorAdd( dv[2].xyz, origin, origin );
05246                 VectorAdd( dv[3].xyz, origin, origin );
05247                 VectorScale( origin, 0.25, origin );
05248             }
05249 
05250             dl = malloc(sizeof(*dl));
05251             memset (dl, 0, sizeof(*dl));
05252             VectorCopy( origin, dl->origin );
05253             VectorCopy( ls->color, dl->color );
05254             dl->photons = ls->value * lightPointScale;
05255             dl->type = LIGHT_POINTRADIAL;
05256             vlights[numvlights++] = dl;
05257             continue;
05258         }
05259 
05260         // possibly create for both sides of the polygon
05261         for ( side = 0 ; side <= ls->twoSided ; side++ ) {
05262             // create area lights
05263             if ( lsurfaceTest[i] ) {
05264                 // curve or misc_model
05265                 for ( j = 0 ; j < lsurfaceTest[i]->numFacets ; j++ ) {
05266                     f = lsurfaceTest[i]->facets + j;
05267                     w = AllocWinding( f->numpoints );
05268                     w->numpoints = f->numpoints;
05269                     memcpy( w->points, f->points, f->numpoints * 12 );
05270 
05271                     VectorCopy( f->plane.normal, normal );
05272                     if ( side ) {
05273                         winding_t   *t;
05274 
05275                         t = w;
05276                         w = ReverseWinding( t );
05277                         FreeWinding( t );
05278                         VectorSubtract( vec3_origin, normal, normal );
05279                     }
05280                     VL_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
05281                 }
05282             } else {
05283                 // normal polygon
05284 
05285                 w = AllocWinding( ds->numVerts );
05286                 w->numpoints = ds->numVerts;
05287                 for ( j = 0 ; j < ds->numVerts ; j++ ) {
05288                     VectorCopy( drawVerts[ds->firstVert+j].xyz, w->points[j] );
05289                 }
05290                 VectorCopy( ds->lightmapVecs[2], normal );
05291                 if ( side ) {
05292                     winding_t   *t;
05293 
05294                     t = w;
05295                     w = ReverseWinding( t );
05296                     FreeWinding( t );
05297                     VectorSubtract( vec3_origin, normal, normal );
05298                 }
05299                 VL_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
05300             }
05301         }
05302     }
05303 
05304     _printf( "%7i light emitting surfaces\n", c_surfaceLights );
05305 }
05306 
05307 
05308 /*
05309 ==================
05310 VL_WindingForBrushSide
05311 ==================
05312 */
05313 winding_t *VL_WindingForBrushSide(dbrush_t *brush, int side, winding_t *w)
05314 {
05315     int i, res;
05316     winding_t *tmpw;
05317     plane_t plane;
05318 
05319     VectorCopy(dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].normal, plane.normal);
05320     VectorInverse(plane.normal);
05321     plane.dist = -dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].dist;
05322     tmpw = BaseWindingForPlane( plane.normal, plane.dist );
05323     memcpy(w->points, tmpw->points, sizeof(vec3_t) * tmpw->numpoints);
05324     w->numpoints = tmpw->numpoints;
05325 
05326     for (i = 0; i < brush->numSides; i++)
05327     {
05328         if (i == side)
05329             continue;
05330         VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal);
05331         VectorInverse(plane.normal);
05332         plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist;
05333         res = VL_ChopWinding(w, &plane, 0.1);
05334         if (res == SIDE_BACK)
05335             return NULL;
05336     }
05337     return w;
05338 }
05339 
05340 /*
05341 ==================
05342 VL_CreateSkyLights
05343 ==================
05344 */
05345 void VL_CreateSkyLights(void)
05346 {
05347     int             i, j, c_skyLights;
05348     dbrush_t        *b;
05349     shaderInfo_t    *si;
05350     dbrushside_t    *s;
05351     vlight_t        *dl;
05352     vec3_t sunColor, sunDir = { 0.45, 0.3, 0.9 };
05353     float d;
05354 
05355     VectorNormalize(sunDir, sunDir);
05356     VectorInverse(sunDir);
05357 
05358     c_skyLights = 0;
05359     _printf("Creating sky lights...\n");
05360     // find the sky shader
05361     for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
05362         si = ShaderInfoForShader( dshaders[ drawSurfaces[i].shaderNum ].shader );
05363         if ( si->surfaceFlags & SURF_SKY ) {
05364             VectorCopy( si->sunLight, sunColor );
05365             VectorCopy( si->sunDirection, sunDir );
05366             VectorInverse(sunDir);
05367             break;
05368         }
05369     }
05370 
05371     // find the brushes
05372     for ( i = 0 ; i < numbrushes ; i++ ) {
05373         b = &dbrushes[i];
05374         for ( j = 0 ; j < b->numSides ; j++ ) {
05375             s = &dbrushsides[ b->firstSide + j ];
05376             if ( dshaders[ s->shaderNum ].surfaceFlags & SURF_SKY ) {
05377                 //if this surface doesn't face in the same direction as the sun
05378                 d = DotProduct(dplanes[ s->planeNum ].normal, sunDir);
05379                 if (d <= 0)
05380                     continue;
05381                 //
05382                 dl = malloc(sizeof(*dl));
05383                 memset (dl, 0, sizeof(*dl));
05384                 VectorCopy(sunColor, dl->color);
05385                 VectorCopy(sunDir, dl->normal);
05386                 VectorCopy(dplanes[ s->planeNum ].normal, dl->plane);
05387                 dl->plane[3] = dplanes[ s->planeNum ].dist;
05388                 dl->type = LIGHT_SURFACEDIRECTED;
05389                 dl->atten_disttype = LDAT_NOSCALE;
05390                 VL_WindingForBrushSide(b, j, &dl->w);
05391 //              DebugNet_DrawWinding(&dl->w, 2);
05392                 //
05393                 vlights[numvlights++] = dl;
05394                 c_skyLights++;
05395             }
05396         }
05397     }
05398     _printf("%7i light emitting sky surfaces\n", c_skyLights);
05399 }
05400 
05401 /*
05402 ==================
05403 VL_SetPortalSphere
05404 ==================
05405 */
05406 void VL_SetPortalSphere (lportal_t *p)
05407 {
05408     int     i;
05409     vec3_t  total, dist;
05410     winding_t   *w;
05411     float   r, bestr;
05412 
05413     w = p->winding;
05414     VectorCopy (vec3_origin, total);
05415     for (i=0 ; i<w->numpoints ; i++)
05416     {
05417         VectorAdd (total, w->points[i], total);
05418     }
05419     
05420     for (i=0 ; i<3 ; i++)
05421         total[i] /= w->numpoints;
05422 
05423     bestr = 0;      
05424     for (i=0 ; i<w->numpoints ; i++)
05425     {
05426         VectorSubtract (w->points[i], total, dist);
05427         r = VectorLength (dist);
05428         if (r > bestr)
05429             bestr = r;
05430     }
05431     VectorCopy (total, p->origin);
05432     p->radius = bestr;
05433 }
05434 
05435 /*
05436 ==================
05437 VL_PlaneFromWinding
05438 ==================
05439 */
05440 void VL_PlaneFromWinding (winding_t *w, plane_t *plane)
05441 {
05442     vec3_t      v1, v2;
05443 
05444     //calc plane
05445     VectorSubtract (w->points[2], w->points[1], v1);
05446     VectorSubtract (w->points[0], w->points[1], v2);
05447     CrossProduct (v2, v1, plane->normal);
05448     VectorNormalize (plane->normal, plane->normal);
05449     plane->dist = DotProduct (w->points[0], plane->normal);
05450 }
05451 
05452 /*
05453 ==================
05454 VL_AllocWinding
05455 ==================
05456 */
05457 winding_t *VL_AllocWinding (int points)
05458 {
05459     winding_t   *w;
05460     int         size;
05461     
05462     if (points > MAX_POINTS_ON_WINDING)
05463         Error ("NewWinding: %i points", points);
05464     
05465     size = (int)((winding_t *)0)->points[points];
05466     w = malloc (size);
05467     memset (w, 0, size);
05468     
05469     return w;
05470 }
05471 
05472 /*
05473 ============
05474 VL_LoadPortals
05475 ============
05476 */
05477 void VL_LoadPortals (char *name)
05478 {
05479     int         i, j, hint;
05480     lportal_t   *p;
05481     lleaf_t     *l;
05482     char        magic[80];
05483     FILE        *f;
05484     int         numpoints;
05485     winding_t   *w;
05486     int         leafnums[2];
05487     plane_t     plane;
05488     //
05489     
05490     if (!strcmp(name,"-"))
05491         f = stdin;
05492     else
05493     {
05494         f = fopen(name, "r");
05495         if (!f)
05496             Error ("LoadPortals: couldn't read %s\n",name);
05497     }
05498 
05499     if (fscanf (f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces) != 4)
05500         Error ("LoadPortals: failed to read header");
05501     if (strcmp(magic, PORTALFILE))
05502         Error ("LoadPortals: not a portal file");
05503 
05504     _printf ("%6i portalclusters\n", portalclusters);
05505     _printf ("%6i numportals\n", numportals);
05506     _printf ("%6i numfaces\n", numfaces);
05507 
05508     if (portalclusters >= MAX_CLUSTERS)
05509         Error ("more than %d clusters in portal file\n", MAX_CLUSTERS);
05510 
05511     // each file portal is split into two memory portals
05512     portals = malloc(2*numportals*sizeof(lportal_t));
05513     memset (portals, 0, 2*numportals*sizeof(lportal_t));
05514     
05515     leafs = malloc(portalclusters*sizeof(lleaf_t));
05516     memset (leafs, 0, portalclusters*sizeof(lleaf_t));
05517 
05518     for (i=0, p=portals ; i<numportals ; i++)
05519     {
05520         if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3)
05521             Error ("LoadPortals: reading portal %i", i);
05522         if (numpoints > MAX_POINTS_ON_WINDING)
05523             Error ("LoadPortals: portal %i has too many points", i);
05524         if ( (unsigned)leafnums[0] > portalclusters
05525         || (unsigned)leafnums[1] > portalclusters)
05526             Error ("LoadPortals: reading portal %i", i);
05527         if (fscanf (f, "%i ", &hint) != 1)
05528             Error ("LoadPortals: reading hint state");
05529         
05530         w = p->winding = VL_AllocWinding (numpoints);
05531         w->numpoints = numpoints;
05532         
05533         for (j=0 ; j<numpoints ; j++)
05534         {
05535             double  v[3];
05536             int     k;
05537 
05538             // scanf into double, then assign to vec_t
05539             // so we don't care what size vec_t is
05540             if (fscanf (f, "(%lf %lf %lf ) "
05541             , &v[0], &v[1], &v[2]) != 3)
05542                 Error ("LoadPortals: reading portal %i", i);
05543             for (k=0 ; k<3 ; k++)
05544                 w->points[j][k] = v[k];
05545         }
05546         fscanf (f, "\n");
05547         
05548         // calc plane
05549         VL_PlaneFromWinding (w, &plane);
05550 
05551         // create forward portal
05552         l = &leafs[leafnums[0]];
05553         if (l->numportals == MAX_PORTALS_ON_LEAF)
05554             Error ("Leaf with too many portals");
05555         l->portals[l->numportals] = p;
05556         l->numportals++;
05557         
05558         p->winding = w;
05559         VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
05560         p->plane.dist = -plane.dist;
05561         p->leaf = leafnums[1];
05562         VL_SetPortalSphere (p);
05563         p++;
05564         
05565         // create backwards portal
05566         l = &leafs[leafnums[1]];
05567         if (l->numportals == MAX_PORTALS_ON_LEAF)
05568             Error ("Leaf with too many portals");
05569         l->portals[l->numportals] = p;
05570         l->numportals++;
05571         
05572         p->winding = VL_AllocWinding(w->numpoints);
05573         p->winding->numpoints = w->numpoints;
05574         for (j=0 ; j<w->numpoints ; j++)
05575         {
05576             VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]);
05577         }
05578 
05579         p->plane = plane;
05580         p->leaf = leafnums[0];
05581         VL_SetPortalSphere (p);
05582         p++;
05583 
05584     }
05585     
05586     fclose (f);
05587 }
05588 
05589 /*
05590 ============
05591 VLightMain
05592 ============
05593 */
05594 int VLightMain (int argc, char **argv) {
05595     int         i;
05596     double      start, end;
05597     const char  *value;
05598 
05599     _printf ("----- VLighting ----\n");
05600 
05601     for (i=1 ; i<argc ; i++) {
05602         if (!strcmp(argv[i],"-v")) {
05603             verbose = qtrue;
05604         } else if (!strcmp(argv[i],"-threads")) {
05605             numthreads = atoi (argv[i+1]);
05606             _printf("num threads = %d\n", numthreads);
05607             i++;
05608         } else if (!strcmp(argv[i],"-area")) {
05609             lightAreaScale *= atof(argv[i+1]);
05610             _printf ("area light scaling at %f\n", lightAreaScale);
05611             i++;
05612         } else if (!strcmp(argv[i],"-point")) {
05613             lightPointScale *= atof(argv[i+1]);
05614             _printf ("point light scaling at %f\n", lightPointScale);
05615             i++;
05616         } else if (!strcmp(argv[i], "-samplesize")) {
05617             samplesize = atoi(argv[i+1]);
05618             if (samplesize < 1) samplesize = 1;
05619             i++;
05620             _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize);
05621         } else if (!strcmp(argv[i], "-novertex")) {
05622             novertexlighting = qtrue;
05623             _printf("no vertex lighting = true\n");
05624         } else if (!strcmp(argv[i], "-nogrid")) {
05625             nogridlighting = qtrue;
05626             _printf("no grid lighting = true\n");
05627         } else if (!strcmp(argv[i], "-nostitching")) {
05628             nostitching = qtrue;
05629             _printf("no stitching = true\n");
05630         } else if (!strcmp(argv[i], "-noalphashading")) {
05631             noalphashading = qtrue;
05632             _printf("no alpha shading = true\n");
05633         } else if (!strcmp(argv[i], "-nocolorshading")) {
05634             nocolorshading = qtrue;
05635             _printf("old style alpha shading = true\n");
05636         } else if (!strcmp(argv[i], "-nobackfaceculling")) {
05637             nobackfaceculling = qtrue;
05638             _printf("no backface culling = true\n");
05639         } else if (!strcmp(argv[i], "-tracelight")) {
05640             defaulttracelight = qtrue;
05641             _printf("default trace light = true\n");
05642         } else if (!strcmp(argv[i], "-radiosity")) {
05643             radiosity = atoi(argv[i+1]);
05644             _printf("radiosity = %d\n", radiosity);
05645             i++;
05646         } else {
05647             break;
05648         }
05649     }
05650 
05651     ThreadSetDefault ();
05652 
05653     if (i != argc - 1) {
05654         _printf("usage: q3map -vlight [-<switch> [-<switch> ...]] <mapname>\n"
05655                 "\n"
05656                 "Switches:\n"
05657                 "   v              = verbose output\n"
05658                 "   threads <X>    = set number of threads to X\n"
05659                 "   area <V>       = set the area light scale to V\n"
05660                 "   point <W>      = set the point light scale to W\n"
05661                 "   novertex       = don't calculate vertex lighting\n"
05662                 "   nogrid         = don't calculate light grid for dynamic model lighting\n"
05663                 "   nostitching    = no polygon stitching before lighting\n"
05664                 "   noalphashading = don't use alpha shading\n"
05665                 "   nocolorshading = don't use color alpha shading\n"
05666                 "   tracelight     = use old light algorithm by default\n"
05667                 "   samplesize <N> = set the lightmap pixel size to NxN units\n");
05668         exit(0);
05669     }
05670 
05671     SetQdirFromPath (argv[i]);  
05672 
05673 #ifdef _WIN32
05674     InitPakFile(gamedir, NULL);
05675 #endif
05676 
05677     strcpy (source, ExpandArg(argv[i]));
05678     StripExtension (source);
05679     DefaultExtension (source, ".bsp");
05680 
05681     LoadShaderInfo();
05682 
05683     _printf ("reading %s\n", source);
05684 
05685     LoadBSPFile (source);
05686     ParseEntities();
05687 
05688     value = ValueForKey( &entities[0], "gridsize" );
05689     if (strlen(value)) {
05690         sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] );
05691         _printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]);
05692     }
05693 
05694     CountLightmaps();
05695 
05696     StripExtension (source);
05697     DefaultExtension (source, ".prt");
05698 
05699     VL_LoadPortals(source);
05700 
05701     // set surfaceOrigin
05702     SetEntityOrigins();
05703 
05704     // grid and vertex lighting
05705     GridAndVertexLighting();
05706 
05707 #ifdef DEBUGNET
05708     DebugNet_Setup();
05709 #endif
05710 
05711     start = clock();
05712 
05713     lightFloats = (float *) malloc(numLightBytes * sizeof(float));
05714     memset(lightFloats, 0, numLightBytes * sizeof(float));
05715 
05716     VL_InitSurfacesForTesting();
05717 
05718     VL_CalcVisibleLightmapPixelArea();
05719 
05720     numvlights = 0;
05721     VL_CreateEntityLights();
05722     VL_CreateFakeSurfaceLights();
05723     VL_CreateSkyLights();
05724 
05725     VL_TestLightLeafs();
05726 
05727     VL_LightWorld();
05728 
05729 #ifndef LIGHTPOLYS
05730     StripExtension (source);
05731     DefaultExtension (source, ".bsp");
05732     _printf ("writing %s\n", source);
05733     WriteBSPFile (source);
05734 #endif
05735 
05736     end = clock();
05737 
05738     _printf ("%5.2f seconds elapsed\n", (end-start) / CLK_TCK);
05739 
05740 #ifdef LIGHTPOLYS
05741     VL_DrawLightWindings();
05742 #endif
05743 
05744 #ifdef DEBUGNET
05745     DebugNet_Shutdown();
05746 #endif
05747     return 0;
05748 }

Generated on Thu Aug 25 12:38:22 2005 for Quake III Arena by  doxygen 1.3.9.1