Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

lightv.c (148675B)


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