home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 58 / pcpp58a.iso / extras / quake 3 source / Q3A_ToolSource.exe / Main / soundv.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-02  |  150.7 KB  |  5,744 lines

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