aboutsummaryrefslogtreecommitdiffstats
path: root/q3map
diff options
context:
space:
mode:
authorzakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea>2005-08-26 17:39:27 +0000
committerzakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea>2005-08-26 17:39:27 +0000
commit6bf20c78f5b69d40bcc4931df93d29198435ab67 (patch)
treee3eda937a05d7db42de725b7013bd0344b987f34 /q3map
parent872d4d7f55af706737ffb361bb76ad13e7496770 (diff)
downloadioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.tar.gz
ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.zip
newlines fixed
git-svn-id: svn://svn.icculus.org/quake3/trunk@6 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'q3map')
-rwxr-xr-xq3map/brush.c1680
-rwxr-xr-xq3map/brush_primit.c62
-rwxr-xr-xq3map/bsp.c1168
-rwxr-xr-xq3map/facebsp.c716
-rwxr-xr-xq3map/fog.c1066
-rwxr-xr-xq3map/gldraw.c422
-rwxr-xr-xq3map/glfile.c254
-rwxr-xr-xq3map/leakfile.c158
-rwxr-xr-xq3map/light.c4256
-rwxr-xr-xq3map/light.h260
-rwxr-xr-xq3map/light_trace.c1846
-rwxr-xr-xq3map/lightmaps.c748
-rwxr-xr-xq3map/lightv.c11452
-rwxr-xr-xq3map/makefile296
-rwxr-xr-xq3map/map.c2460
-rwxr-xr-xq3map/mesh.c1322
-rwxr-xr-xq3map/mesh.h54
-rwxr-xr-xq3map/misc_model.c902
-rwxr-xr-xq3map/nodraw.c52
-rwxr-xr-xq3map/patch.c530
-rwxr-xr-xq3map/portals.c1644
-rwxr-xr-xq3map/prtfile.c502
-rwxr-xr-xq3map/q3map.sln112
-rwxr-xr-xq3map/q3map.vcproj3212
-rwxr-xr-xq3map/qbsp.h868
-rwxr-xr-xq3map/shaders.c1174
-rwxr-xr-xq3map/shaders.h100
-rwxr-xr-xq3map/soundv.c11442
-rwxr-xr-xq3map/surface.c2274
-rwxr-xr-xq3map/terrain.c2468
-rwxr-xr-xq3map/tjunction.c1060
-rwxr-xr-xq3map/tree.c250
-rwxr-xr-xq3map/vis.c2352
-rwxr-xr-xq3map/vis.h282
-rwxr-xr-xq3map/visflow.c3272
-rwxr-xr-xq3map/writebsp.c794
36 files changed, 30755 insertions, 30755 deletions
diff --git a/q3map/brush.c b/q3map/brush.c
index e373e17..506bd1d 100755
--- a/q3map/brush.c
+++ b/q3map/brush.c
@@ -19,843 +19,843 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-#include "qbsp.h"
-
-
-int c_active_brushes;
-
-int c_nodes;
-
-// if a brush just barely pokes onto the other side,
-// let it slide by without chopping
-#define PLANESIDE_EPSILON 0.001
-//0.1
-
-
-
-
-/*
-================
-CountBrushList
-================
-*/
-int CountBrushList (bspbrush_t *brushes)
-{
- int c;
-
- c = 0;
- for ( ; brushes ; brushes = brushes->next)
- c++;
- return c;
-}
-
-
-/*
-================
-AllocBrush
-================
-*/
-bspbrush_t *AllocBrush (int numsides)
-{
- bspbrush_t *bb;
- int c;
-
- c = (int)&(((bspbrush_t *)0)->sides[numsides]);
- bb = malloc(c);
- memset (bb, 0, c);
- if (numthreads == 1)
- c_active_brushes++;
- return bb;
-}
-
-/*
-================
-FreeBrush
-================
-*/
-void FreeBrush (bspbrush_t *brushes)
-{
- int i;
-
- for (i=0 ; i<brushes->numsides ; i++)
- if (brushes->sides[i].winding)
- FreeWinding(brushes->sides[i].winding);
- free (brushes);
- if (numthreads == 1)
- c_active_brushes--;
-}
-
-
-/*
-================
-FreeBrushList
-================
-*/
-void FreeBrushList (bspbrush_t *brushes)
-{
- bspbrush_t *next;
-
- for ( ; brushes ; brushes = next)
- {
- next = brushes->next;
-
- FreeBrush (brushes);
- }
-}
-
-/*
-==================
-CopyBrush
-
-Duplicates the brush, the sides, and the windings
-==================
-*/
-bspbrush_t *CopyBrush (bspbrush_t *brush)
-{
- bspbrush_t *newbrush;
- int size;
- int i;
-
- size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]);
-
- newbrush = AllocBrush (brush->numsides);
- memcpy (newbrush, brush, size);
-
- for (i=0 ; i<brush->numsides ; i++)
- {
- if (brush->sides[i].winding)
- newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding);
- }
-
- return newbrush;
-}
-
-
-/*
-================
-DrawBrushList
-================
-*/
-void DrawBrushList (bspbrush_t *brush)
-{
- int i;
- side_t *s;
-
- GLS_BeginScene ();
- for ( ; brush ; brush=brush->next)
- {
- for (i=0 ; i<brush->numsides ; i++)
- {
- s = &brush->sides[i];
- if (!s->winding)
- continue;
- GLS_Winding (s->winding, 0);
- }
- }
- GLS_EndScene ();
-}
-
-
-
-/*
-================
-WriteBrushList
-================
-*/
-void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis)
-{
- int i;
- side_t *s;
- FILE *f;
-
- qprintf ("writing %s\n", name);
- f = SafeOpenWrite (name);
-
- for ( ; brush ; brush=brush->next)
- {
- for (i=0 ; i<brush->numsides ; i++)
- {
- s = &brush->sides[i];
- if (!s->winding)
- continue;
- if (onlyvis && !s->visible)
- continue;
- OutputWinding (brush->sides[i].winding, f);
- }
- }
-
- fclose (f);
-}
-
-
-/*
-=============
-PrintBrush
-=============
-*/
-void PrintBrush (bspbrush_t *brush)
-{
- int i;
-
- _printf ("brush: %p\n", brush);
- for (i=0;i<brush->numsides ; i++)
- {
- pw(brush->sides[i].winding);
- _printf ("\n");
- }
-}
-
-/*
-==================
-BoundBrush
-
-Sets the mins/maxs based on the windings
-returns false if the brush doesn't enclose a valid volume
-==================
-*/
-qboolean BoundBrush (bspbrush_t *brush)
-{
- int i, j;
- winding_t *w;
-
- ClearBounds (brush->mins, brush->maxs);
- for (i=0 ; i<brush->numsides ; i++)
- {
- w = brush->sides[i].winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- AddPointToBounds (w->p[j], brush->mins, brush->maxs);
- }
-
- for (i=0 ; i<3 ; i++) {
- if (brush->mins[i] < MIN_WORLD_COORD || brush->maxs[i] > MAX_WORLD_COORD
- || brush->mins[i] >= brush->maxs[i] ) {
- return qfalse;
- }
- }
-
- return qtrue;
-}
-
-/*
-==================
-CreateBrushWindings
-
-makes basewindigs for sides and mins / maxs for the brush
-returns false if the brush doesn't enclose a valid volume
-==================
-*/
-qboolean CreateBrushWindings (bspbrush_t *brush)
-{
- int i, j;
- winding_t *w;
- side_t *side;
- plane_t *plane;
-
- for ( i = 0; i < brush->numsides; i++ )
- {
- side = &brush->sides[i];
- // don't create a winding for a bevel
- if ( side->bevel ) {
- continue;
- }
- plane = &mapplanes[side->planenum];
- w = BaseWindingForPlane (plane->normal, plane->dist);
- for ( j = 0; j < brush->numsides && w; j++ )
- {
- if (i == j)
- continue;
- if ( brush->sides[j].planenum == ( brush->sides[i].planenum ^ 1 ) )
- continue; // back side clipaway
- if (brush->sides[j].bevel)
- continue;
- if (brush->sides[j].backSide)
- continue;
- plane = &mapplanes[brush->sides[j].planenum^1];
- ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
- }
- // free any existing winding
- if ( side->winding ) {
- FreeWinding( side->winding );
- }
- side->winding = w;
- }
-
- return BoundBrush (brush);
-}
-
-/*
-==================
-BrushFromBounds
-
-Creates a new axial brush
-==================
-*/
-bspbrush_t *BrushFromBounds (vec3_t mins, vec3_t maxs)
-{
- bspbrush_t *b;
- int i;
- vec3_t normal;
- vec_t dist;
-
- b = AllocBrush (6);
- b->numsides = 6;
- for (i=0 ; i<3 ; i++)
- {
- VectorClear (normal);
- normal[i] = 1;
- dist = maxs[i];
- b->sides[i].planenum = FindFloatPlane (normal, dist);
-
- normal[i] = -1;
- dist = -mins[i];
- b->sides[3+i].planenum = FindFloatPlane (normal, dist);
- }
-
- CreateBrushWindings (b);
-
- return b;
-}
-
-/*
-==================
-BrushVolume
-
-==================
-*/
-vec_t BrushVolume (bspbrush_t *brush)
-{
- int i;
- winding_t *w;
- vec3_t corner;
- vec_t d, area, volume;
- plane_t *plane;
-
- if (!brush)
- return 0;
-
- // grab the first valid point as the corner
-
- w = NULL;
- for (i=0 ; i<brush->numsides ; i++)
- {
- w = brush->sides[i].winding;
- if (w)
- break;
- }
- if (!w)
- return 0;
- VectorCopy (w->p[0], corner);
-
- // make tetrahedrons to all other faces
-
- volume = 0;
- for ( ; i<brush->numsides ; i++)
- {
- w = brush->sides[i].winding;
- if (!w)
- continue;
- plane = &mapplanes[brush->sides[i].planenum];
- d = -(DotProduct (corner, plane->normal) - plane->dist);
- area = WindingArea (w);
- volume += d*area;
- }
-
- volume /= 3;
- return volume;
-}
-
-
-/*
-==================
-WriteBspBrushMap
-==================
-*/
-void WriteBspBrushMap (char *name, bspbrush_t *list)
-{
- FILE *f;
- side_t *s;
- int i;
- winding_t *w;
-
- _printf ("writing %s\n", name);
- f = fopen (name, "wb");
- if (!f)
- Error ("Can't write %s\b", name);
-
- fprintf (f, "{\n\"classname\" \"worldspawn\"\n");
-
- for ( ; list ; list=list->next )
- {
- fprintf (f, "{\n");
- for (i=0,s=list->sides ; i<list->numsides ; i++,s++)
- {
- w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist);
-
- fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]);
- fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]);
- fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]);
-
- fprintf (f, "notexture 0 0 0 1 1\n" );
- FreeWinding (w);
- }
- fprintf (f, "}\n");
- }
- fprintf (f, "}\n");
-
- fclose (f);
-
-}
-
-
-//=====================================================================================
-
-/*
-====================
-FilterBrushIntoTree_r
-
-====================
-*/
-int FilterBrushIntoTree_r( bspbrush_t *b, node_t *node ) {
- bspbrush_t *front, *back;
- int c;
-
- if ( !b ) {
- return 0;
- }
-
- // add it to the leaf list
- if ( node->planenum == PLANENUM_LEAF ) {
- b->next = node->brushlist;
- node->brushlist = b;
-
- // classify the leaf by the structural brush
- if ( !b->detail ) {
- if ( b->opaque ) {
- node->opaque = qtrue;
- node->areaportal = qfalse;
- } else if ( b->contents & CONTENTS_AREAPORTAL ) {
- if ( !node->opaque ) {
- node->areaportal = qtrue;
- }
- }
- }
-
- return 1;
- }
-
- // split it by the node plane
- SplitBrush ( b, node->planenum, &front, &back );
- FreeBrush( b );
-
- c = 0;
- c += FilterBrushIntoTree_r( front, node->children[0] );
- c += FilterBrushIntoTree_r( back, node->children[1] );
-
- return c;
-}
-
-/*
-=====================
-FilterDetailBrushesIntoTree
-
-Fragment all the detail brushes into the structural leafs
-=====================
-*/
-void FilterDetailBrushesIntoTree( entity_t *e, tree_t *tree ) {
- bspbrush_t *b, *newb;
- int r;
- int c_unique, c_clusters;
- int i;
-
- qprintf( "----- FilterDetailBrushesIntoTree -----\n");
-
- c_unique = 0;
- c_clusters = 0;
- for ( b = e->brushes ; b ; b = b->next ) {
- if ( !b->detail ) {
- continue;
- }
- c_unique++;
- newb = CopyBrush( b );
- r = FilterBrushIntoTree_r( newb, tree->headnode );
- c_clusters += r;
-
- // mark all sides as visible so drawsurfs are created
- if ( r ) {
- for ( i = 0 ; i < b->numsides ; i++ ) {
- if ( b->sides[i].winding ) {
- b->sides[i].visible = qtrue;
- }
- }
- }
- }
-
- qprintf( "%5i detail brushes\n", c_unique );
- qprintf( "%5i cluster references\n", c_clusters );
-}
-
-/*
-=====================
-FilterStructuralBrushesIntoTree
-
-Mark the leafs as opaque and areaportals
-=====================
-*/
-void FilterStructuralBrushesIntoTree( entity_t *e, tree_t *tree ) {
- bspbrush_t *b, *newb;
- int r;
- int c_unique, c_clusters;
- int i;
-
- qprintf( "----- FilterStructuralBrushesIntoTree -----\n");
-
- c_unique = 0;
- c_clusters = 0;
- for ( b = e->brushes ; b ; b = b->next ) {
- if ( b->detail ) {
- continue;
- }
- c_unique++;
- newb = CopyBrush( b );
- r = FilterBrushIntoTree_r( newb, tree->headnode );
- c_clusters += r;
-
- // mark all sides as visible so drawsurfs are created
- if ( r ) {
- for ( i = 0 ; i < b->numsides ; i++ ) {
- if ( b->sides[i].winding ) {
- b->sides[i].visible = qtrue;
- }
- }
- }
- }
-
- qprintf( "%5i structural brushes\n", c_unique );
- qprintf( "%5i cluster references\n", c_clusters );
-}
-
-
-
-/*
-================
-AllocTree
-================
-*/
-tree_t *AllocTree (void)
-{
- tree_t *tree;
-
- tree = malloc(sizeof(*tree));
- memset (tree, 0, sizeof(*tree));
- ClearBounds (tree->mins, tree->maxs);
-
- return tree;
-}
-
-/*
-================
-AllocNode
-================
-*/
-node_t *AllocNode (void)
-{
- node_t *node;
-
- node = malloc(sizeof(*node));
- memset (node, 0, sizeof(*node));
-
- return node;
-}
-
-
-/*
-================
-WindingIsTiny
-
-Returns true if the winding would be crunched out of
-existance by the vertex snapping.
-================
-*/
-#define EDGE_LENGTH 0.2
-qboolean WindingIsTiny (winding_t *w)
-{
-/*
- if (WindingArea (w) < 1)
- return qtrue;
- return qfalse;
-*/
- int i, j;
- vec_t len;
- vec3_t delta;
- int edges;
-
- edges = 0;
- for (i=0 ; i<w->numpoints ; i++)
- {
- j = i == w->numpoints - 1 ? 0 : i+1;
- VectorSubtract (w->p[j], w->p[i], delta);
- len = VectorLength (delta);
- if (len > EDGE_LENGTH)
- {
- if (++edges == 3)
- return qfalse;
- }
- }
- return qtrue;
-}
-
-/*
-================
-WindingIsHuge
-
-Returns true if the winding still has one of the points
-from basewinding for plane
-================
-*/
-qboolean WindingIsHuge (winding_t *w)
-{
- int i, j;
-
- for (i=0 ; i<w->numpoints ; i++)
- {
- for (j=0 ; j<3 ; j++)
- if (w->p[i][j] <= MIN_WORLD_COORD || w->p[i][j] >= MAX_WORLD_COORD)
- return qtrue;
- }
- return qfalse;
-}
-
-//============================================================
-
-/*
-==================
-BrushMostlyOnSide
-
-==================
-*/
-int BrushMostlyOnSide (bspbrush_t *brush, plane_t *plane)
-{
- int i, j;
- winding_t *w;
- vec_t d, max;
- int side;
-
- max = 0;
- side = PSIDE_FRONT;
- for (i=0 ; i<brush->numsides ; i++)
- {
- w = brush->sides[i].winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- {
- d = DotProduct (w->p[j], plane->normal) - plane->dist;
- if (d > max)
- {
- max = d;
- side = PSIDE_FRONT;
- }
- if (-d > max)
- {
- max = -d;
- side = PSIDE_BACK;
- }
- }
- }
- return side;
-}
-
-/*
-================
-SplitBrush
-
-Generates two new brushes, leaving the original
-unchanged
-================
-*/
-void SplitBrush (bspbrush_t *brush, int planenum,
- bspbrush_t **front, bspbrush_t **back)
-{
- bspbrush_t *b[2];
- int i, j;
- winding_t *w, *cw[2], *midwinding;
- plane_t *plane, *plane2;
- side_t *s, *cs;
- float d, d_front, d_back;
-
- *front = *back = NULL;
- plane = &mapplanes[planenum];
-
- // check all points
- d_front = d_back = 0;
- for (i=0 ; i<brush->numsides ; i++)
- {
- w = brush->sides[i].winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- {
- d = DotProduct (w->p[j], plane->normal) - plane->dist;
- if (d > 0 && d > d_front)
- d_front = d;
- if (d < 0 && d < d_back)
- d_back = d;
- }
- }
- if (d_front < 0.1) // PLANESIDE_EPSILON)
- { // only on back
- *back = CopyBrush (brush);
- return;
- }
- if (d_back > -0.1) // PLANESIDE_EPSILON)
- { // only on front
- *front = CopyBrush (brush);
- return;
- }
-
- // create a new winding from the split plane
-
- w = BaseWindingForPlane (plane->normal, plane->dist);
- for (i=0 ; i<brush->numsides && w ; i++)
- {
- if ( brush->sides[i].backSide ) {
- continue; // fake back-sided polygons never split
- }
- plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
- ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON);
- }
-
- if (!w || WindingIsTiny (w) )
- { // the brush isn't really split
- int side;
-
- side = BrushMostlyOnSide (brush, plane);
- if (side == PSIDE_FRONT)
- *front = CopyBrush (brush);
- if (side == PSIDE_BACK)
- *back = CopyBrush (brush);
- return;
- }
-
- if (WindingIsHuge (w))
- {
- qprintf ("WARNING: huge winding\n");
- }
-
- midwinding = w;
-
- // split it for real
-
- for (i=0 ; i<2 ; i++)
- {
- b[i] = AllocBrush (brush->numsides+1);
- memcpy( b[i], brush, sizeof( bspbrush_t ) - sizeof( brush->sides ) );
- b[i]->numsides = 0;
- b[i]->next = NULL;
- b[i]->original = brush->original;
- }
-
- // split all the current windings
-
- for (i=0 ; i<brush->numsides ; i++)
- {
- s = &brush->sides[i];
- w = s->winding;
- if (!w)
- continue;
- ClipWindingEpsilon (w, plane->normal, plane->dist,
- 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
- for (j=0 ; j<2 ; j++)
- {
- if (!cw[j])
- continue;
-/*
- if (WindingIsTiny (cw[j]))
- {
- FreeWinding (cw[j]);
- continue;
- }
-*/
- cs = &b[j]->sides[b[j]->numsides];
- b[j]->numsides++;
- *cs = *s;
- cs->winding = cw[j];
- }
- }
-
-
- // see if we have valid polygons on both sides
-
- for (i=0 ; i<2 ; i++)
- {
- BoundBrush (b[i]);
- for (j=0 ; j<3 ; j++)
- {
- if (b[i]->mins[j] < MIN_WORLD_COORD || b[i]->maxs[j] > MAX_WORLD_COORD)
- {
- qprintf ("bogus brush after clip\n");
- break;
- }
- }
-
- if (b[i]->numsides < 3 || j < 3)
- {
- FreeBrush (b[i]);
- b[i] = NULL;
- }
- }
-
- if ( !(b[0] && b[1]) )
- {
- if (!b[0] && !b[1])
- qprintf ("split removed brush\n");
- else
- qprintf ("split not on both sides\n");
- if (b[0])
- {
- FreeBrush (b[0]);
- *front = CopyBrush (brush);
- }
- if (b[1])
- {
- FreeBrush (b[1]);
- *back = CopyBrush (brush);
- }
- return;
- }
-
- // add the midwinding to both sides
- for (i=0 ; i<2 ; i++)
- {
- cs = &b[i]->sides[b[i]->numsides];
- b[i]->numsides++;
-
- cs->planenum = planenum^i^1;
- cs->shaderInfo = NULL;
- if (i==0)
- cs->winding = CopyWinding (midwinding);
- else
- cs->winding = midwinding;
- }
-
-{
- vec_t v1;
- int i;
-
- for (i=0 ; i<2 ; i++)
- {
- v1 = BrushVolume (b[i]);
- if (v1 < 1.0)
- {
- FreeBrush (b[i]);
- b[i] = NULL;
-// qprintf ("tiny volume after clip\n");
- }
- }
-}
-
- *front = b[0];
- *back = b[1];
-}
+#include "qbsp.h"
+
+
+int c_active_brushes;
+
+int c_nodes;
+
+// if a brush just barely pokes onto the other side,
+// let it slide by without chopping
+#define PLANESIDE_EPSILON 0.001
+//0.1
+
+
+
+
+/*
+================
+CountBrushList
+================
+*/
+int CountBrushList (bspbrush_t *brushes)
+{
+ int c;
+
+ c = 0;
+ for ( ; brushes ; brushes = brushes->next)
+ c++;
+ return c;
+}
+
+
+/*
+================
+AllocBrush
+================
+*/
+bspbrush_t *AllocBrush (int numsides)
+{
+ bspbrush_t *bb;
+ int c;
+
+ c = (int)&(((bspbrush_t *)0)->sides[numsides]);
+ bb = malloc(c);
+ memset (bb, 0, c);
+ if (numthreads == 1)
+ c_active_brushes++;
+ return bb;
+}
+
+/*
+================
+FreeBrush
+================
+*/
+void FreeBrush (bspbrush_t *brushes)
+{
+ int i;
+
+ for (i=0 ; i<brushes->numsides ; i++)
+ if (brushes->sides[i].winding)
+ FreeWinding(brushes->sides[i].winding);
+ free (brushes);
+ if (numthreads == 1)
+ c_active_brushes--;
+}
+
+
+/*
+================
+FreeBrushList
+================
+*/
+void FreeBrushList (bspbrush_t *brushes)
+{
+ bspbrush_t *next;
+
+ for ( ; brushes ; brushes = next)
+ {
+ next = brushes->next;
+
+ FreeBrush (brushes);
+ }
+}
+
+/*
+==================
+CopyBrush
+
+Duplicates the brush, the sides, and the windings
+==================
+*/
+bspbrush_t *CopyBrush (bspbrush_t *brush)
+{
+ bspbrush_t *newbrush;
+ int size;
+ int i;
+
+ size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]);
+
+ newbrush = AllocBrush (brush->numsides);
+ memcpy (newbrush, brush, size);
+
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ if (brush->sides[i].winding)
+ newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding);
+ }
+
+ return newbrush;
+}
+
+
+/*
+================
+DrawBrushList
+================
+*/
+void DrawBrushList (bspbrush_t *brush)
+{
+ int i;
+ side_t *s;
+
+ GLS_BeginScene ();
+ for ( ; brush ; brush=brush->next)
+ {
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ s = &brush->sides[i];
+ if (!s->winding)
+ continue;
+ GLS_Winding (s->winding, 0);
+ }
+ }
+ GLS_EndScene ();
+}
+
+
+
+/*
+================
+WriteBrushList
+================
+*/
+void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis)
+{
+ int i;
+ side_t *s;
+ FILE *f;
+
+ qprintf ("writing %s\n", name);
+ f = SafeOpenWrite (name);
+
+ for ( ; brush ; brush=brush->next)
+ {
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ s = &brush->sides[i];
+ if (!s->winding)
+ continue;
+ if (onlyvis && !s->visible)
+ continue;
+ OutputWinding (brush->sides[i].winding, f);
+ }
+ }
+
+ fclose (f);
+}
+
+
+/*
+=============
+PrintBrush
+=============
+*/
+void PrintBrush (bspbrush_t *brush)
+{
+ int i;
+
+ _printf ("brush: %p\n", brush);
+ for (i=0;i<brush->numsides ; i++)
+ {
+ pw(brush->sides[i].winding);
+ _printf ("\n");
+ }
+}
+
+/*
+==================
+BoundBrush
+
+Sets the mins/maxs based on the windings
+returns false if the brush doesn't enclose a valid volume
+==================
+*/
+qboolean BoundBrush (bspbrush_t *brush)
+{
+ int i, j;
+ winding_t *w;
+
+ ClearBounds (brush->mins, brush->maxs);
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ w = brush->sides[i].winding;
+ if (!w)
+ continue;
+ for (j=0 ; j<w->numpoints ; j++)
+ AddPointToBounds (w->p[j], brush->mins, brush->maxs);
+ }
+
+ for (i=0 ; i<3 ; i++) {
+ if (brush->mins[i] < MIN_WORLD_COORD || brush->maxs[i] > MAX_WORLD_COORD
+ || brush->mins[i] >= brush->maxs[i] ) {
+ return qfalse;
+ }
+ }
+
+ return qtrue;
+}
+
+/*
+==================
+CreateBrushWindings
+
+makes basewindigs for sides and mins / maxs for the brush
+returns false if the brush doesn't enclose a valid volume
+==================
+*/
+qboolean CreateBrushWindings (bspbrush_t *brush)
+{
+ int i, j;
+ winding_t *w;
+ side_t *side;
+ plane_t *plane;
+
+ for ( i = 0; i < brush->numsides; i++ )
+ {
+ side = &brush->sides[i];
+ // don't create a winding for a bevel
+ if ( side->bevel ) {
+ continue;
+ }
+ plane = &mapplanes[side->planenum];
+ w = BaseWindingForPlane (plane->normal, plane->dist);
+ for ( j = 0; j < brush->numsides && w; j++ )
+ {
+ if (i == j)
+ continue;
+ if ( brush->sides[j].planenum == ( brush->sides[i].planenum ^ 1 ) )
+ continue; // back side clipaway
+ if (brush->sides[j].bevel)
+ continue;
+ if (brush->sides[j].backSide)
+ continue;
+ plane = &mapplanes[brush->sides[j].planenum^1];
+ ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
+ }
+ // free any existing winding
+ if ( side->winding ) {
+ FreeWinding( side->winding );
+ }
+ side->winding = w;
+ }
+
+ return BoundBrush (brush);
+}
+
+/*
+==================
+BrushFromBounds
+
+Creates a new axial brush
+==================
+*/
+bspbrush_t *BrushFromBounds (vec3_t mins, vec3_t maxs)
+{
+ bspbrush_t *b;
+ int i;
+ vec3_t normal;
+ vec_t dist;
+
+ b = AllocBrush (6);
+ b->numsides = 6;
+ for (i=0 ; i<3 ; i++)
+ {
+ VectorClear (normal);
+ normal[i] = 1;
+ dist = maxs[i];
+ b->sides[i].planenum = FindFloatPlane (normal, dist);
+
+ normal[i] = -1;
+ dist = -mins[i];
+ b->sides[3+i].planenum = FindFloatPlane (normal, dist);
+ }
+
+ CreateBrushWindings (b);
+
+ return b;
+}
+
+/*
+==================
+BrushVolume
+
+==================
+*/
+vec_t BrushVolume (bspbrush_t *brush)
+{
+ int i;
+ winding_t *w;
+ vec3_t corner;
+ vec_t d, area, volume;
+ plane_t *plane;
+
+ if (!brush)
+ return 0;
+
+ // grab the first valid point as the corner
+
+ w = NULL;
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ w = brush->sides[i].winding;
+ if (w)
+ break;
+ }
+ if (!w)
+ return 0;
+ VectorCopy (w->p[0], corner);
+
+ // make tetrahedrons to all other faces
+
+ volume = 0;
+ for ( ; i<brush->numsides ; i++)
+ {
+ w = brush->sides[i].winding;
+ if (!w)
+ continue;
+ plane = &mapplanes[brush->sides[i].planenum];
+ d = -(DotProduct (corner, plane->normal) - plane->dist);
+ area = WindingArea (w);
+ volume += d*area;
+ }
+
+ volume /= 3;
+ return volume;
+}
+
+
+/*
+==================
+WriteBspBrushMap
+==================
+*/
+void WriteBspBrushMap (char *name, bspbrush_t *list)
+{
+ FILE *f;
+ side_t *s;
+ int i;
+ winding_t *w;
+
+ _printf ("writing %s\n", name);
+ f = fopen (name, "wb");
+ if (!f)
+ Error ("Can't write %s\b", name);
+
+ fprintf (f, "{\n\"classname\" \"worldspawn\"\n");
+
+ for ( ; list ; list=list->next )
+ {
+ fprintf (f, "{\n");
+ for (i=0,s=list->sides ; i<list->numsides ; i++,s++)
+ {
+ w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist);
+
+ fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]);
+ fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]);
+ fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]);
+
+ fprintf (f, "notexture 0 0 0 1 1\n" );
+ FreeWinding (w);
+ }
+ fprintf (f, "}\n");
+ }
+ fprintf (f, "}\n");
+
+ fclose (f);
+
+}
+
+
+//=====================================================================================
+
+/*
+====================
+FilterBrushIntoTree_r
+
+====================
+*/
+int FilterBrushIntoTree_r( bspbrush_t *b, node_t *node ) {
+ bspbrush_t *front, *back;
+ int c;
+
+ if ( !b ) {
+ return 0;
+ }
+
+ // add it to the leaf list
+ if ( node->planenum == PLANENUM_LEAF ) {
+ b->next = node->brushlist;
+ node->brushlist = b;
+
+ // classify the leaf by the structural brush
+ if ( !b->detail ) {
+ if ( b->opaque ) {
+ node->opaque = qtrue;
+ node->areaportal = qfalse;
+ } else if ( b->contents & CONTENTS_AREAPORTAL ) {
+ if ( !node->opaque ) {
+ node->areaportal = qtrue;
+ }
+ }
+ }
+
+ return 1;
+ }
+
+ // split it by the node plane
+ SplitBrush ( b, node->planenum, &front, &back );
+ FreeBrush( b );
+
+ c = 0;
+ c += FilterBrushIntoTree_r( front, node->children[0] );
+ c += FilterBrushIntoTree_r( back, node->children[1] );
+
+ return c;
+}
+
+/*
+=====================
+FilterDetailBrushesIntoTree
+
+Fragment all the detail brushes into the structural leafs
+=====================
+*/
+void FilterDetailBrushesIntoTree( entity_t *e, tree_t *tree ) {
+ bspbrush_t *b, *newb;
+ int r;
+ int c_unique, c_clusters;
+ int i;
+
+ qprintf( "----- FilterDetailBrushesIntoTree -----\n");
+
+ c_unique = 0;
+ c_clusters = 0;
+ for ( b = e->brushes ; b ; b = b->next ) {
+ if ( !b->detail ) {
+ continue;
+ }
+ c_unique++;
+ newb = CopyBrush( b );
+ r = FilterBrushIntoTree_r( newb, tree->headnode );
+ c_clusters += r;
+
+ // mark all sides as visible so drawsurfs are created
+ if ( r ) {
+ for ( i = 0 ; i < b->numsides ; i++ ) {
+ if ( b->sides[i].winding ) {
+ b->sides[i].visible = qtrue;
+ }
+ }
+ }
+ }
+
+ qprintf( "%5i detail brushes\n", c_unique );
+ qprintf( "%5i cluster references\n", c_clusters );
+}
+
+/*
+=====================
+FilterStructuralBrushesIntoTree
+
+Mark the leafs as opaque and areaportals
+=====================
+*/
+void FilterStructuralBrushesIntoTree( entity_t *e, tree_t *tree ) {
+ bspbrush_t *b, *newb;
+ int r;
+ int c_unique, c_clusters;
+ int i;
+
+ qprintf( "----- FilterStructuralBrushesIntoTree -----\n");
+
+ c_unique = 0;
+ c_clusters = 0;
+ for ( b = e->brushes ; b ; b = b->next ) {
+ if ( b->detail ) {
+ continue;
+ }
+ c_unique++;
+ newb = CopyBrush( b );
+ r = FilterBrushIntoTree_r( newb, tree->headnode );
+ c_clusters += r;
+
+ // mark all sides as visible so drawsurfs are created
+ if ( r ) {
+ for ( i = 0 ; i < b->numsides ; i++ ) {
+ if ( b->sides[i].winding ) {
+ b->sides[i].visible = qtrue;
+ }
+ }
+ }
+ }
+
+ qprintf( "%5i structural brushes\n", c_unique );
+ qprintf( "%5i cluster references\n", c_clusters );
+}
+
+
+
+/*
+================
+AllocTree
+================
+*/
+tree_t *AllocTree (void)
+{
+ tree_t *tree;
+
+ tree = malloc(sizeof(*tree));
+ memset (tree, 0, sizeof(*tree));
+ ClearBounds (tree->mins, tree->maxs);
+
+ return tree;
+}
+
+/*
+================
+AllocNode
+================
+*/
+node_t *AllocNode (void)
+{
+ node_t *node;
+
+ node = malloc(sizeof(*node));
+ memset (node, 0, sizeof(*node));
+
+ return node;
+}
+
+
+/*
+================
+WindingIsTiny
+
+Returns true if the winding would be crunched out of
+existance by the vertex snapping.
+================
+*/
+#define EDGE_LENGTH 0.2
+qboolean WindingIsTiny (winding_t *w)
+{
+/*
+ if (WindingArea (w) < 1)
+ return qtrue;
+ return qfalse;
+*/
+ int i, j;
+ vec_t len;
+ vec3_t delta;
+ int edges;
+
+ edges = 0;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ j = i == w->numpoints - 1 ? 0 : i+1;
+ VectorSubtract (w->p[j], w->p[i], delta);
+ len = VectorLength (delta);
+ if (len > EDGE_LENGTH)
+ {
+ if (++edges == 3)
+ return qfalse;
+ }
+ }
+ return qtrue;
+}
+
+/*
+================
+WindingIsHuge
+
+Returns true if the winding still has one of the points
+from basewinding for plane
+================
+*/
+qboolean WindingIsHuge (winding_t *w)
+{
+ int i, j;
+
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ for (j=0 ; j<3 ; j++)
+ if (w->p[i][j] <= MIN_WORLD_COORD || w->p[i][j] >= MAX_WORLD_COORD)
+ return qtrue;
+ }
+ return qfalse;
+}
+
+//============================================================
+
+/*
+==================
+BrushMostlyOnSide
+
+==================
+*/
+int BrushMostlyOnSide (bspbrush_t *brush, plane_t *plane)
+{
+ int i, j;
+ winding_t *w;
+ vec_t d, max;
+ int side;
+
+ max = 0;
+ side = PSIDE_FRONT;
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ w = brush->sides[i].winding;
+ if (!w)
+ continue;
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ d = DotProduct (w->p[j], plane->normal) - plane->dist;
+ if (d > max)
+ {
+ max = d;
+ side = PSIDE_FRONT;
+ }
+ if (-d > max)
+ {
+ max = -d;
+ side = PSIDE_BACK;
+ }
+ }
+ }
+ return side;
+}
+
+/*
+================
+SplitBrush
+
+Generates two new brushes, leaving the original
+unchanged
+================
+*/
+void SplitBrush (bspbrush_t *brush, int planenum,
+ bspbrush_t **front, bspbrush_t **back)
+{
+ bspbrush_t *b[2];
+ int i, j;
+ winding_t *w, *cw[2], *midwinding;
+ plane_t *plane, *plane2;
+ side_t *s, *cs;
+ float d, d_front, d_back;
+
+ *front = *back = NULL;
+ plane = &mapplanes[planenum];
+
+ // check all points
+ d_front = d_back = 0;
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ w = brush->sides[i].winding;
+ if (!w)
+ continue;
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ d = DotProduct (w->p[j], plane->normal) - plane->dist;
+ if (d > 0 && d > d_front)
+ d_front = d;
+ if (d < 0 && d < d_back)
+ d_back = d;
+ }
+ }
+ if (d_front < 0.1) // PLANESIDE_EPSILON)
+ { // only on back
+ *back = CopyBrush (brush);
+ return;
+ }
+ if (d_back > -0.1) // PLANESIDE_EPSILON)
+ { // only on front
+ *front = CopyBrush (brush);
+ return;
+ }
+
+ // create a new winding from the split plane
+
+ w = BaseWindingForPlane (plane->normal, plane->dist);
+ for (i=0 ; i<brush->numsides && w ; i++)
+ {
+ if ( brush->sides[i].backSide ) {
+ continue; // fake back-sided polygons never split
+ }
+ plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
+ ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON);
+ }
+
+ if (!w || WindingIsTiny (w) )
+ { // the brush isn't really split
+ int side;
+
+ side = BrushMostlyOnSide (brush, plane);
+ if (side == PSIDE_FRONT)
+ *front = CopyBrush (brush);
+ if (side == PSIDE_BACK)
+ *back = CopyBrush (brush);
+ return;
+ }
+
+ if (WindingIsHuge (w))
+ {
+ qprintf ("WARNING: huge winding\n");
+ }
+
+ midwinding = w;
+
+ // split it for real
+
+ for (i=0 ; i<2 ; i++)
+ {
+ b[i] = AllocBrush (brush->numsides+1);
+ memcpy( b[i], brush, sizeof( bspbrush_t ) - sizeof( brush->sides ) );
+ b[i]->numsides = 0;
+ b[i]->next = NULL;
+ b[i]->original = brush->original;
+ }
+
+ // split all the current windings
+
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ s = &brush->sides[i];
+ w = s->winding;
+ if (!w)
+ continue;
+ ClipWindingEpsilon (w, plane->normal, plane->dist,
+ 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
+ for (j=0 ; j<2 ; j++)
+ {
+ if (!cw[j])
+ continue;
+/*
+ if (WindingIsTiny (cw[j]))
+ {
+ FreeWinding (cw[j]);
+ continue;
+ }
+*/
+ cs = &b[j]->sides[b[j]->numsides];
+ b[j]->numsides++;
+ *cs = *s;
+ cs->winding = cw[j];
+ }
+ }
+
+
+ // see if we have valid polygons on both sides
+
+ for (i=0 ; i<2 ; i++)
+ {
+ BoundBrush (b[i]);
+ for (j=0 ; j<3 ; j++)
+ {
+ if (b[i]->mins[j] < MIN_WORLD_COORD || b[i]->maxs[j] > MAX_WORLD_COORD)
+ {
+ qprintf ("bogus brush after clip\n");
+ break;
+ }
+ }
+
+ if (b[i]->numsides < 3 || j < 3)
+ {
+ FreeBrush (b[i]);
+ b[i] = NULL;
+ }
+ }
+
+ if ( !(b[0] && b[1]) )
+ {
+ if (!b[0] && !b[1])
+ qprintf ("split removed brush\n");
+ else
+ qprintf ("split not on both sides\n");
+ if (b[0])
+ {
+ FreeBrush (b[0]);
+ *front = CopyBrush (brush);
+ }
+ if (b[1])
+ {
+ FreeBrush (b[1]);
+ *back = CopyBrush (brush);
+ }
+ return;
+ }
+
+ // add the midwinding to both sides
+ for (i=0 ; i<2 ; i++)
+ {
+ cs = &b[i]->sides[b[i]->numsides];
+ b[i]->numsides++;
+
+ cs->planenum = planenum^i^1;
+ cs->shaderInfo = NULL;
+ if (i==0)
+ cs->winding = CopyWinding (midwinding);
+ else
+ cs->winding = midwinding;
+ }
+
+{
+ vec_t v1;
+ int i;
+
+ for (i=0 ; i<2 ; i++)
+ {
+ v1 = BrushVolume (b[i]);
+ if (v1 < 1.0)
+ {
+ FreeBrush (b[i]);
+ b[i] = NULL;
+// qprintf ("tiny volume after clip\n");
+ }
+ }
+}
+
+ *front = b[0];
+ *back = b[1];
+}
diff --git a/q3map/brush_primit.c b/q3map/brush_primit.c
index 5ec44cc..198e90e 100755
--- a/q3map/brush_primit.c
+++ b/q3map/brush_primit.c
@@ -19,34 +19,34 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-#include "qbsp.h"
-
-
-// global flag
-int g_bBrushPrimit;
-
-// NOTE : ComputeAxisBase here and in editor code must always BE THE SAME !
-// WARNING : special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere when x == 0
-// rotation by (0,RotY,RotZ) assigns X to normal
-void ComputeAxisBase(vec3_t normal,vec3_t texX,vec3_t texY)
-{
- vec_t RotY,RotZ;
- // do some cleaning
- if (fabs(normal[0])<1e-6)
- normal[0]=0.0f;
- if (fabs(normal[1])<1e-6)
- normal[1]=0.0f;
- if (fabs(normal[2])<1e-6)
- normal[2]=0.0f;
- // compute the two rotations around Y and Z to rotate X to normal
- RotY=-atan2(normal[2],sqrt(normal[1]*normal[1]+normal[0]*normal[0]));
- RotZ=atan2(normal[1],normal[0]);
- // rotate (0,1,0) and (0,0,1) to compute texX and texY
- texX[0]=-sin(RotZ);
- texX[1]=cos(RotZ);
- texX[2]=0;
- // the texY vector is along -Z ( T texture coorinates axis )
- texY[0]=-sin(RotY)*cos(RotZ);
- texY[1]=-sin(RotY)*sin(RotZ);
- texY[2]=-cos(RotY);
-}
+#include "qbsp.h"
+
+
+// global flag
+int g_bBrushPrimit;
+
+// NOTE : ComputeAxisBase here and in editor code must always BE THE SAME !
+// WARNING : special case behaviour of atan2(y,x) <-> atan(y/x) might not be the same everywhere when x == 0
+// rotation by (0,RotY,RotZ) assigns X to normal
+void ComputeAxisBase(vec3_t normal,vec3_t texX,vec3_t texY)
+{
+ vec_t RotY,RotZ;
+ // do some cleaning
+ if (fabs(normal[0])<1e-6)
+ normal[0]=0.0f;
+ if (fabs(normal[1])<1e-6)
+ normal[1]=0.0f;
+ if (fabs(normal[2])<1e-6)
+ normal[2]=0.0f;
+ // compute the two rotations around Y and Z to rotate X to normal
+ RotY=-atan2(normal[2],sqrt(normal[1]*normal[1]+normal[0]*normal[0]));
+ RotZ=atan2(normal[1],normal[0]);
+ // rotate (0,1,0) and (0,0,1) to compute texX and texY
+ texX[0]=-sin(RotZ);
+ texX[1]=cos(RotZ);
+ texX[2]=0;
+ // the texY vector is along -Z ( T texture coorinates axis )
+ texY[0]=-sin(RotY)*cos(RotZ);
+ texY[1]=-sin(RotY)*sin(RotZ);
+ texY[2]=-cos(RotY);
+}
diff --git a/q3map/bsp.c b/q3map/bsp.c
index 12d66aa..2cf15bd 100755
--- a/q3map/bsp.c
+++ b/q3map/bsp.c
@@ -19,587 +19,587 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-#include "qbsp.h"
-
-#ifdef _WIN32
-#ifdef _TTIMOBUILD
-#include "pakstuff.h"
-#else
-#include "../libs/pakstuff.h"
-#endif
-extern HWND hwndOut;
-#endif
-
-char source[1024];
-char tempsource[1024];
-char name[1024];
-
-vec_t microvolume = 1.0;
-qboolean glview;
-qboolean nodetail;
-qboolean fulldetail;
-qboolean onlyents;
-qboolean onlytextures;
-qboolean nowater;
-qboolean nofill;
-qboolean noopt;
-qboolean leaktest;
-qboolean verboseentities;
-qboolean noCurveBrushes;
-qboolean fakemap;
-qboolean notjunc;
-qboolean nomerge;
-qboolean nofog;
-qboolean nosubdivide;
-qboolean testExpand;
-qboolean showseams;
-
-char outbase[32];
-
-int entity_num;
-
-/*
-============
-ProcessWorldModel
-
-============
-*/
-void ProcessWorldModel( void ) {
- entity_t *e;
- tree_t *tree;
- bspface_t *faces;
- qboolean leaked;
-
- BeginModel();
-
- e = &entities[0];
- e->firstDrawSurf = 0;//numMapDrawSurfs;
-
- // check for patches with adjacent edges that need to LOD together
- PatchMapDrawSurfs( e );
-
- // build an initial bsp tree using all of the sides
- // of all of the structural brushes
- faces = MakeStructuralBspFaceList ( entities[0].brushes );
- tree = FaceBSP( faces );
- MakeTreePortals (tree);
- FilterStructuralBrushesIntoTree( e, tree );
-
- // see if the bsp is completely enclosed
- if ( FloodEntities (tree) ) {
- // rebuild a better bsp tree using only the
- // sides that are visible from the inside
- FillOutside (tree->headnode);
-
- // chop the sides to the convex hull of
- // their visible fragments, giving us the smallest
- // polygons
- ClipSidesIntoTree( e, tree );
-
- faces = MakeVisibleBspFaceList( entities[0].brushes );
- FreeTree (tree);
- tree = FaceBSP( faces );
- MakeTreePortals( tree );
- FilterStructuralBrushesIntoTree( e, tree );
- leaked = qfalse;
- } else {
- _printf ("**********************\n");
- _printf ("******* leaked *******\n");
- _printf ("**********************\n");
- LeakFile (tree);
- if ( leaktest ) {
- _printf ("--- MAP LEAKED, ABORTING LEAKTEST ---\n");
- exit (0);
- }
- leaked = qtrue;
-
- // chop the sides to the convex hull of
- // their visible fragments, giving us the smallest
- // polygons
- ClipSidesIntoTree( e, tree );
- }
-
- // save out information for visibility processing
- NumberClusters( tree );
- if ( !leaked ) {
- WritePortalFile( tree );
- }
- if ( glview ) {
- // dump the portals for debugging
- WriteGLView( tree, source );
- }
- FloodAreas (tree);
-
- // add references to the detail brushes
- FilterDetailBrushesIntoTree( e, tree );
-
- // create drawsurfs for triangle models
- AddTriangleModels( tree );
-
- // drawsurfs that cross fog boundaries will need to
- // be split along the bound
- if ( !nofog ) {
- FogDrawSurfs(); // may fragment drawsurfs
- }
-
- // subdivide each drawsurf as required by shader tesselation
- if ( !nosubdivide ) {
- SubdivideDrawSurfs( e, tree );
- }
-
- // merge together all common shaders on the same plane and remove
- // all colinear points, so extra tjunctions won't be generated
- if ( !nomerge ) {
- MergeSides( e, tree ); // !@# testing
- }
-
- // add in any vertexes required to fix tjunctions
- if ( !notjunc ) {
- FixTJunctions( e );
- }
-
- // allocate lightmaps for faces and patches
- AllocateLightmaps( e );
-
- // add references to the final drawsurfs in the apropriate clusters
- FilterDrawsurfsIntoTree( e, tree );
-
- EndModel( tree->headnode );
-
- FreeTree (tree);
-}
-
-/*
-============
-ProcessSubModel
-
-============
-*/
-void ProcessSubModel( void ) {
- entity_t *e;
- tree_t *tree;
- bspbrush_t *b, *bc;
- node_t *node;
-
- BeginModel ();
-
- e = &entities[entity_num];
- e->firstDrawSurf = numMapDrawSurfs;
-
- PatchMapDrawSurfs( e );
-
- // just put all the brushes in an empty leaf
- // FIXME: patches?
- node = AllocNode();
- node->planenum = PLANENUM_LEAF;
- for ( b = e->brushes ; b ; b = b->next ) {
- bc = CopyBrush( b );
- bc->next = node->brushlist;
- node->brushlist = bc;
- }
-
- tree = AllocTree();
- tree->headnode = node;
-
- ClipSidesIntoTree( e, tree );
-
- // subdivide each drawsurf as required by shader tesselation or fog
- if ( !nosubdivide ) {
- SubdivideDrawSurfs( e, tree );
- }
-
- // merge together all common shaders on the same plane and remove
- // all colinear points, so extra tjunctions won't be generated
- if ( !nomerge ) {
- MergeSides( e, tree ); // !@# testing
- }
-
- // add in any vertexes required to fix tjunctions
- if ( !notjunc ) {
- FixTJunctions( e );
- }
-
- // allocate lightmaps for faces and patches
- AllocateLightmaps( e );
-
- // add references to the final drawsurfs in the apropriate clusters
- FilterDrawsurfsIntoTree( e, tree );
-
- EndModel ( node );
-
- FreeTree( tree );
-}
-
-
-/*
-============
-ProcessModels
-============
-*/
-void ProcessModels (void)
-{
- qboolean oldVerbose;
- entity_t *entity;
-
- oldVerbose = verbose;
-
- BeginBSPFile ();
-
- for ( entity_num=0 ; entity_num< num_entities ; entity_num++ ) {
- entity = &entities[entity_num];
-
- if ( !entity->brushes && !entity->patches ) {
- continue;
- }
-
- qprintf ("############### model %i ###############\n", nummodels);
- if (entity_num == 0)
- ProcessWorldModel ();
- else
- ProcessSubModel ();
-
- if (!verboseentities)
- verbose = qfalse; // don't bother printing submodels
- }
-
- verbose = oldVerbose;
-}
-
-/*
-============
-Bspinfo
-============
-*/
-void Bspinfo( int count, char **fileNames ) {
- int i;
- char source[1024];
- int size;
- FILE *f;
-
- if ( count < 1 ) {
- _printf( "No files to dump info for.\n");
- return;
- }
-
- for ( i = 0 ; i < count ; i++ ) {
- _printf ("---------------------\n");
- strcpy (source, fileNames[ i ] );
- DefaultExtension (source, ".bsp");
- f = fopen (source, "rb");
- if (f)
- {
- size = Q_filelength (f);
- fclose (f);
- }
- else
- size = 0;
- _printf ("%s: %i\n", source, size);
-
- LoadBSPFile (source);
- PrintBSPFileSizes ();
- _printf ("---------------------\n");
- }
-}
-
-
-/*
-============
-OnlyEnts
-============
-*/
-void OnlyEnts( void ) {
- char out[1024];
-
- sprintf (out, "%s.bsp", source);
- LoadBSPFile (out);
- num_entities = 0;
-
- LoadMapFile (name);
- SetModelNumbers ();
- SetLightStyles ();
-
- UnparseEntities ();
-
- WriteBSPFile (out);
-}
-
-
-/*
-============
-OnlyTextures
-============
-*/
-void OnlyTextures( void ) { // FIXME!!!
- char out[1024];
- int i;
-
- Error( "-onlytextures isn't working now..." );
-
- sprintf (out, "%s.bsp", source);
-
- LoadMapFile (name);
-
- LoadBSPFile (out);
-
- // replace all the drawsurface shader names
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- }
-
- WriteBSPFile (out);
-}
-
-
-/*
-============
-main
-============
-*/
-int LightMain( int argc, char **argv );
-int VLightMain (int argc, char **argv);
-int VSoundMain (int argc, char **argv);
-int VisMain( int argc, char **argv );
-
-int main (int argc, char **argv) {
- int i;
- double start, end;
- char path[1024];
-
- _printf ("Q3Map v1.0s (c) 1999 Id Software Inc.\n");
-
- if ( argc < 2 ) {
- Error ("usage: q3map [options] mapfile");
- }
-
- // check for general program options
- if (!strcmp(argv[1], "-info")) {
- Bspinfo( argc - 2, argv + 2 );
- return 0;
- }
- if (!strcmp(argv[1], "-light")) {
- LightMain( argc - 1, argv + 1 );
- return 0;
- }
- if (!strcmp(argv[1], "-vlight")) {
- VLightMain( argc - 1, argv + 1 );
- return 0;
- }
- if (!strcmp(argv[1], "-vsound")) {
- VSoundMain( argc - 1, argv + 1 );
- return 0;
- }
- if (!strcmp(argv[1], "-vis")) {
- VisMain( argc - 1, argv + 1 );
- return 0;
- }
-
- // do a bsp if nothing else was specified
-
- _printf ("---- q3map ----\n");
-
- tempsource[0] = '\0';
-
- for (i=1 ; i<argc ; i++)
- {
- if (!strcmp(argv[i],"-tempname"))
- {
- strcpy(tempsource, argv[++i]);
- }
- else if (!strcmp(argv[i],"-threads"))
- {
- numthreads = atoi (argv[i+1]);
- i++;
- }
- else if (!strcmp(argv[i],"-glview"))
- {
- glview = qtrue;
- }
- else if (!strcmp(argv[i], "-v"))
- {
- _printf ("verbose = true\n");
- verbose = qtrue;
- }
- else if (!strcmp(argv[i], "-draw"))
- {
- _printf ("drawflag = true\n");
- drawflag = qtrue;
- }
- else if (!strcmp(argv[i], "-nowater"))
- {
- _printf ("nowater = true\n");
- nowater = qtrue;
- }
- else if (!strcmp(argv[i], "-noopt"))
- {
- _printf ("noopt = true\n");
- noopt = qtrue;
- }
- else if (!strcmp(argv[i], "-nofill"))
- {
- _printf ("nofill = true\n");
- nofill = qtrue;
- }
- else if (!strcmp(argv[i], "-nodetail"))
- {
- _printf ("nodetail = true\n");
- nodetail = qtrue;
- }
- else if (!strcmp(argv[i], "-fulldetail"))
- {
- _printf ("fulldetail = true\n");
- fulldetail = qtrue;
- }
- else if (!strcmp(argv[i], "-onlyents"))
- {
- _printf ("onlyents = true\n");
- onlyents = qtrue;
- }
- else if (!strcmp(argv[i], "-onlytextures"))
- {
- _printf ("onlytextures = true\n"); // FIXME: make work again!
- onlytextures = qtrue;
- }
- else if (!strcmp(argv[i], "-micro"))
- {
- microvolume = atof(argv[i+1]);
- _printf ("microvolume = %f\n", microvolume);
- i++;
- }
- else if (!strcmp(argv[i], "-nofog"))
- {
- _printf ("nofog = true\n");
- nofog = qtrue;
- }
- else if (!strcmp(argv[i], "-nosubdivide"))
- {
- _printf ("nosubdivide = true\n");
- nosubdivide = qtrue;
- }
- else if (!strcmp(argv[i], "-leaktest"))
- {
- _printf ("leaktest = true\n");
- leaktest = qtrue;
- }
- else if (!strcmp(argv[i], "-verboseentities"))
- {
- _printf ("verboseentities = true\n");
- verboseentities = qtrue;
- }
- else if (!strcmp(argv[i], "-nocurves"))
- {
- noCurveBrushes = qtrue;
- _printf ("no curve brushes\n");
- }
- else if (!strcmp(argv[i], "-notjunc"))
- {
- notjunc = qtrue;
- _printf ("no tjunction fixing\n");
- }
- else if (!strcmp(argv[i], "-expand"))
- {
- testExpand = qtrue;
- _printf ("Writing expanded.map.\n");
- }
- else if (!strcmp(argv[i], "-showseams"))
- {
- showseams = qtrue;
- _printf ("Showing seams on terrain.\n");
- }
- else if (!strcmp (argv[i],"-tmpout"))
- {
- strcpy (outbase, "/tmp");
- }
- else if (!strcmp (argv[i],"-fakemap"))
- {
- fakemap = qtrue;
- _printf( "will generate fakemap.map\n");
- }
- else if (!strcmp(argv[i], "-samplesize"))
- {
- samplesize = atoi(argv[i+1]);
- if (samplesize < 1) samplesize = 1;
- i++;
- _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize);
- }
- else if (argv[i][0] == '-')
- Error ("Unknown option \"%s\"", argv[i]);
- else
- break;
- }
-
- if (i != argc - 1)
- Error ("usage: q3map [options] mapfile");
-
- start = I_FloatTime ();
-
- ThreadSetDefault ();
- //numthreads = 1; // multiple threads aren't helping because of heavy malloc use
- SetQdirFromPath (argv[i]);
-
-#ifdef _WIN32
- InitPakFile(gamedir, NULL);
-#endif
-
- strcpy (source, ExpandArg (argv[i]));
- StripExtension (source);
-
- // delete portal and line files
- sprintf (path, "%s.prt", source);
- remove (path);
- sprintf (path, "%s.lin", source);
- remove (path);
-
- strcpy (name, ExpandArg (argv[i]));
- if ( strcmp(name + strlen(name) - 4, ".reg" ) ) {
- // if we are doing a full map, delete the last saved region map
- sprintf (path, "%s.reg", source);
- remove (path);
-
- DefaultExtension (name, ".map"); // might be .reg
- }
-
- //
- // if onlyents, just grab the entites and resave
- //
- if ( onlyents ) {
- OnlyEnts();
- return 0;
- }
-
- //
- // if onlytextures, just grab the textures and resave
- //
- if ( onlytextures ) {
- OnlyTextures();
- return 0;
- }
-
- //
- // start from scratch
- //
- LoadShaderInfo();
-
- // load original file from temp spot in case it was renamed by the editor on the way in
- if (strlen(tempsource) > 0) {
- LoadMapFile (tempsource);
- } else {
- LoadMapFile (name);
- }
-
- SetModelNumbers ();
- SetLightStyles ();
-
- ProcessModels ();
-
- EndBSPFile();
-
- end = I_FloatTime ();
- _printf ("%5.0f seconds elapsed\n", end-start);
-
- // remove temp name if appropriate
- if (strlen(tempsource) > 0) {
- remove(tempsource);
- }
-
- return 0;
-}
-
+#include "qbsp.h"
+
+#ifdef _WIN32
+#ifdef _TTIMOBUILD
+#include "pakstuff.h"
+#else
+#include "../libs/pakstuff.h"
+#endif
+extern HWND hwndOut;
+#endif
+
+char source[1024];
+char tempsource[1024];
+char name[1024];
+
+vec_t microvolume = 1.0;
+qboolean glview;
+qboolean nodetail;
+qboolean fulldetail;
+qboolean onlyents;
+qboolean onlytextures;
+qboolean nowater;
+qboolean nofill;
+qboolean noopt;
+qboolean leaktest;
+qboolean verboseentities;
+qboolean noCurveBrushes;
+qboolean fakemap;
+qboolean notjunc;
+qboolean nomerge;
+qboolean nofog;
+qboolean nosubdivide;
+qboolean testExpand;
+qboolean showseams;
+
+char outbase[32];
+
+int entity_num;
+
+/*
+============
+ProcessWorldModel
+
+============
+*/
+void ProcessWorldModel( void ) {
+ entity_t *e;
+ tree_t *tree;
+ bspface_t *faces;
+ qboolean leaked;
+
+ BeginModel();
+
+ e = &entities[0];
+ e->firstDrawSurf = 0;//numMapDrawSurfs;
+
+ // check for patches with adjacent edges that need to LOD together
+ PatchMapDrawSurfs( e );
+
+ // build an initial bsp tree using all of the sides
+ // of all of the structural brushes
+ faces = MakeStructuralBspFaceList ( entities[0].brushes );
+ tree = FaceBSP( faces );
+ MakeTreePortals (tree);
+ FilterStructuralBrushesIntoTree( e, tree );
+
+ // see if the bsp is completely enclosed
+ if ( FloodEntities (tree) ) {
+ // rebuild a better bsp tree using only the
+ // sides that are visible from the inside
+ FillOutside (tree->headnode);
+
+ // chop the sides to the convex hull of
+ // their visible fragments, giving us the smallest
+ // polygons
+ ClipSidesIntoTree( e, tree );
+
+ faces = MakeVisibleBspFaceList( entities[0].brushes );
+ FreeTree (tree);
+ tree = FaceBSP( faces );
+ MakeTreePortals( tree );
+ FilterStructuralBrushesIntoTree( e, tree );
+ leaked = qfalse;
+ } else {
+ _printf ("**********************\n");
+ _printf ("******* leaked *******\n");
+ _printf ("**********************\n");
+ LeakFile (tree);
+ if ( leaktest ) {
+ _printf ("--- MAP LEAKED, ABORTING LEAKTEST ---\n");
+ exit (0);
+ }
+ leaked = qtrue;
+
+ // chop the sides to the convex hull of
+ // their visible fragments, giving us the smallest
+ // polygons
+ ClipSidesIntoTree( e, tree );
+ }
+
+ // save out information for visibility processing
+ NumberClusters( tree );
+ if ( !leaked ) {
+ WritePortalFile( tree );
+ }
+ if ( glview ) {
+ // dump the portals for debugging
+ WriteGLView( tree, source );
+ }
+ FloodAreas (tree);
+
+ // add references to the detail brushes
+ FilterDetailBrushesIntoTree( e, tree );
+
+ // create drawsurfs for triangle models
+ AddTriangleModels( tree );
+
+ // drawsurfs that cross fog boundaries will need to
+ // be split along the bound
+ if ( !nofog ) {
+ FogDrawSurfs(); // may fragment drawsurfs
+ }
+
+ // subdivide each drawsurf as required by shader tesselation
+ if ( !nosubdivide ) {
+ SubdivideDrawSurfs( e, tree );
+ }
+
+ // merge together all common shaders on the same plane and remove
+ // all colinear points, so extra tjunctions won't be generated
+ if ( !nomerge ) {
+ MergeSides( e, tree ); // !@# testing
+ }
+
+ // add in any vertexes required to fix tjunctions
+ if ( !notjunc ) {
+ FixTJunctions( e );
+ }
+
+ // allocate lightmaps for faces and patches
+ AllocateLightmaps( e );
+
+ // add references to the final drawsurfs in the apropriate clusters
+ FilterDrawsurfsIntoTree( e, tree );
+
+ EndModel( tree->headnode );
+
+ FreeTree (tree);
+}
+
+/*
+============
+ProcessSubModel
+
+============
+*/
+void ProcessSubModel( void ) {
+ entity_t *e;
+ tree_t *tree;
+ bspbrush_t *b, *bc;
+ node_t *node;
+
+ BeginModel ();
+
+ e = &entities[entity_num];
+ e->firstDrawSurf = numMapDrawSurfs;
+
+ PatchMapDrawSurfs( e );
+
+ // just put all the brushes in an empty leaf
+ // FIXME: patches?
+ node = AllocNode();
+ node->planenum = PLANENUM_LEAF;
+ for ( b = e->brushes ; b ; b = b->next ) {
+ bc = CopyBrush( b );
+ bc->next = node->brushlist;
+ node->brushlist = bc;
+ }
+
+ tree = AllocTree();
+ tree->headnode = node;
+
+ ClipSidesIntoTree( e, tree );
+
+ // subdivide each drawsurf as required by shader tesselation or fog
+ if ( !nosubdivide ) {
+ SubdivideDrawSurfs( e, tree );
+ }
+
+ // merge together all common shaders on the same plane and remove
+ // all colinear points, so extra tjunctions won't be generated
+ if ( !nomerge ) {
+ MergeSides( e, tree ); // !@# testing
+ }
+
+ // add in any vertexes required to fix tjunctions
+ if ( !notjunc ) {
+ FixTJunctions( e );
+ }
+
+ // allocate lightmaps for faces and patches
+ AllocateLightmaps( e );
+
+ // add references to the final drawsurfs in the apropriate clusters
+ FilterDrawsurfsIntoTree( e, tree );
+
+ EndModel ( node );
+
+ FreeTree( tree );
+}
+
+
+/*
+============
+ProcessModels
+============
+*/
+void ProcessModels (void)
+{
+ qboolean oldVerbose;
+ entity_t *entity;
+
+ oldVerbose = verbose;
+
+ BeginBSPFile ();
+
+ for ( entity_num=0 ; entity_num< num_entities ; entity_num++ ) {
+ entity = &entities[entity_num];
+
+ if ( !entity->brushes && !entity->patches ) {
+ continue;
+ }
+
+ qprintf ("############### model %i ###############\n", nummodels);
+ if (entity_num == 0)
+ ProcessWorldModel ();
+ else
+ ProcessSubModel ();
+
+ if (!verboseentities)
+ verbose = qfalse; // don't bother printing submodels
+ }
+
+ verbose = oldVerbose;
+}
+
+/*
+============
+Bspinfo
+============
+*/
+void Bspinfo( int count, char **fileNames ) {
+ int i;
+ char source[1024];
+ int size;
+ FILE *f;
+
+ if ( count < 1 ) {
+ _printf( "No files to dump info for.\n");
+ return;
+ }
+
+ for ( i = 0 ; i < count ; i++ ) {
+ _printf ("---------------------\n");
+ strcpy (source, fileNames[ i ] );
+ DefaultExtension (source, ".bsp");
+ f = fopen (source, "rb");
+ if (f)
+ {
+ size = Q_filelength (f);
+ fclose (f);
+ }
+ else
+ size = 0;
+ _printf ("%s: %i\n", source, size);
+
+ LoadBSPFile (source);
+ PrintBSPFileSizes ();
+ _printf ("---------------------\n");
+ }
+}
+
+
+/*
+============
+OnlyEnts
+============
+*/
+void OnlyEnts( void ) {
+ char out[1024];
+
+ sprintf (out, "%s.bsp", source);
+ LoadBSPFile (out);
+ num_entities = 0;
+
+ LoadMapFile (name);
+ SetModelNumbers ();
+ SetLightStyles ();
+
+ UnparseEntities ();
+
+ WriteBSPFile (out);
+}
+
+
+/*
+============
+OnlyTextures
+============
+*/
+void OnlyTextures( void ) { // FIXME!!!
+ char out[1024];
+ int i;
+
+ Error( "-onlytextures isn't working now..." );
+
+ sprintf (out, "%s.bsp", source);
+
+ LoadMapFile (name);
+
+ LoadBSPFile (out);
+
+ // replace all the drawsurface shader names
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ }
+
+ WriteBSPFile (out);
+}
+
+
+/*
+============
+main
+============
+*/
+int LightMain( int argc, char **argv );
+int VLightMain (int argc, char **argv);
+int VSoundMain (int argc, char **argv);
+int VisMain( int argc, char **argv );
+
+int main (int argc, char **argv) {
+ int i;
+ double start, end;
+ char path[1024];
+
+ _printf ("Q3Map v1.0s (c) 1999 Id Software Inc.\n");
+
+ if ( argc < 2 ) {
+ Error ("usage: q3map [options] mapfile");
+ }
+
+ // check for general program options
+ if (!strcmp(argv[1], "-info")) {
+ Bspinfo( argc - 2, argv + 2 );
+ return 0;
+ }
+ if (!strcmp(argv[1], "-light")) {
+ LightMain( argc - 1, argv + 1 );
+ return 0;
+ }
+ if (!strcmp(argv[1], "-vlight")) {
+ VLightMain( argc - 1, argv + 1 );
+ return 0;
+ }
+ if (!strcmp(argv[1], "-vsound")) {
+ VSoundMain( argc - 1, argv + 1 );
+ return 0;
+ }
+ if (!strcmp(argv[1], "-vis")) {
+ VisMain( argc - 1, argv + 1 );
+ return 0;
+ }
+
+ // do a bsp if nothing else was specified
+
+ _printf ("---- q3map ----\n");
+
+ tempsource[0] = '\0';
+
+ for (i=1 ; i<argc ; i++)
+ {
+ if (!strcmp(argv[i],"-tempname"))
+ {
+ strcpy(tempsource, argv[++i]);
+ }
+ else if (!strcmp(argv[i],"-threads"))
+ {
+ numthreads = atoi (argv[i+1]);
+ i++;
+ }
+ else if (!strcmp(argv[i],"-glview"))
+ {
+ glview = qtrue;
+ }
+ else if (!strcmp(argv[i], "-v"))
+ {
+ _printf ("verbose = true\n");
+ verbose = qtrue;
+ }
+ else if (!strcmp(argv[i], "-draw"))
+ {
+ _printf ("drawflag = true\n");
+ drawflag = qtrue;
+ }
+ else if (!strcmp(argv[i], "-nowater"))
+ {
+ _printf ("nowater = true\n");
+ nowater = qtrue;
+ }
+ else if (!strcmp(argv[i], "-noopt"))
+ {
+ _printf ("noopt = true\n");
+ noopt = qtrue;
+ }
+ else if (!strcmp(argv[i], "-nofill"))
+ {
+ _printf ("nofill = true\n");
+ nofill = qtrue;
+ }
+ else if (!strcmp(argv[i], "-nodetail"))
+ {
+ _printf ("nodetail = true\n");
+ nodetail = qtrue;
+ }
+ else if (!strcmp(argv[i], "-fulldetail"))
+ {
+ _printf ("fulldetail = true\n");
+ fulldetail = qtrue;
+ }
+ else if (!strcmp(argv[i], "-onlyents"))
+ {
+ _printf ("onlyents = true\n");
+ onlyents = qtrue;
+ }
+ else if (!strcmp(argv[i], "-onlytextures"))
+ {
+ _printf ("onlytextures = true\n"); // FIXME: make work again!
+ onlytextures = qtrue;
+ }
+ else if (!strcmp(argv[i], "-micro"))
+ {
+ microvolume = atof(argv[i+1]);
+ _printf ("microvolume = %f\n", microvolume);
+ i++;
+ }
+ else if (!strcmp(argv[i], "-nofog"))
+ {
+ _printf ("nofog = true\n");
+ nofog = qtrue;
+ }
+ else if (!strcmp(argv[i], "-nosubdivide"))
+ {
+ _printf ("nosubdivide = true\n");
+ nosubdivide = qtrue;
+ }
+ else if (!strcmp(argv[i], "-leaktest"))
+ {
+ _printf ("leaktest = true\n");
+ leaktest = qtrue;
+ }
+ else if (!strcmp(argv[i], "-verboseentities"))
+ {
+ _printf ("verboseentities = true\n");
+ verboseentities = qtrue;
+ }
+ else if (!strcmp(argv[i], "-nocurves"))
+ {
+ noCurveBrushes = qtrue;
+ _printf ("no curve brushes\n");
+ }
+ else if (!strcmp(argv[i], "-notjunc"))
+ {
+ notjunc = qtrue;
+ _printf ("no tjunction fixing\n");
+ }
+ else if (!strcmp(argv[i], "-expand"))
+ {
+ testExpand = qtrue;
+ _printf ("Writing expanded.map.\n");
+ }
+ else if (!strcmp(argv[i], "-showseams"))
+ {
+ showseams = qtrue;
+ _printf ("Showing seams on terrain.\n");
+ }
+ else if (!strcmp (argv[i],"-tmpout"))
+ {
+ strcpy (outbase, "/tmp");
+ }
+ else if (!strcmp (argv[i],"-fakemap"))
+ {
+ fakemap = qtrue;
+ _printf( "will generate fakemap.map\n");
+ }
+ else if (!strcmp(argv[i], "-samplesize"))
+ {
+ samplesize = atoi(argv[i+1]);
+ if (samplesize < 1) samplesize = 1;
+ i++;
+ _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize);
+ }
+ else if (argv[i][0] == '-')
+ Error ("Unknown option \"%s\"", argv[i]);
+ else
+ break;
+ }
+
+ if (i != argc - 1)
+ Error ("usage: q3map [options] mapfile");
+
+ start = I_FloatTime ();
+
+ ThreadSetDefault ();
+ //numthreads = 1; // multiple threads aren't helping because of heavy malloc use
+ SetQdirFromPath (argv[i]);
+
+#ifdef _WIN32
+ InitPakFile(gamedir, NULL);
+#endif
+
+ strcpy (source, ExpandArg (argv[i]));
+ StripExtension (source);
+
+ // delete portal and line files
+ sprintf (path, "%s.prt", source);
+ remove (path);
+ sprintf (path, "%s.lin", source);
+ remove (path);
+
+ strcpy (name, ExpandArg (argv[i]));
+ if ( strcmp(name + strlen(name) - 4, ".reg" ) ) {
+ // if we are doing a full map, delete the last saved region map
+ sprintf (path, "%s.reg", source);
+ remove (path);
+
+ DefaultExtension (name, ".map"); // might be .reg
+ }
+
+ //
+ // if onlyents, just grab the entites and resave
+ //
+ if ( onlyents ) {
+ OnlyEnts();
+ return 0;
+ }
+
+ //
+ // if onlytextures, just grab the textures and resave
+ //
+ if ( onlytextures ) {
+ OnlyTextures();
+ return 0;
+ }
+
+ //
+ // start from scratch
+ //
+ LoadShaderInfo();
+
+ // load original file from temp spot in case it was renamed by the editor on the way in
+ if (strlen(tempsource) > 0) {
+ LoadMapFile (tempsource);
+ } else {
+ LoadMapFile (name);
+ }
+
+ SetModelNumbers ();
+ SetLightStyles ();
+
+ ProcessModels ();
+
+ EndBSPFile();
+
+ end = I_FloatTime ();
+ _printf ("%5.0f seconds elapsed\n", end-start);
+
+ // remove temp name if appropriate
+ if (strlen(tempsource) > 0) {
+ remove(tempsource);
+ }
+
+ return 0;
+}
+
diff --git a/q3map/facebsp.c b/q3map/facebsp.c
index d1b00b4..a146a21 100755
--- a/q3map/facebsp.c
+++ b/q3map/facebsp.c
@@ -19,361 +19,361 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include "qbsp.h"
-
-
-int c_faceLeafs;
-
-
-/*
-================
-AllocBspFace
-================
-*/
-bspface_t *AllocBspFace( void ) {
- bspface_t *f;
-
- f = malloc(sizeof(*f));
- memset( f, 0, sizeof(*f) );
-
- return f;
-}
-
-/*
-================
-FreeBspFace
-================
-*/
-void FreeBspFace( bspface_t *f ) {
- if ( f->w ) {
- FreeWinding( f->w );
- }
- free( f );
-}
-
-
-/*
-================
-SelectSplitPlaneNum
-================
-*/
-int hintsplit;
-
-#define BLOCK_SIZE 1024
-int SelectSplitPlaneNum( node_t *node, bspface_t *list ) {
- bspface_t *split;
- bspface_t *check;
- bspface_t *bestSplit;
- int splits, facing, front, back;
- int side;
- plane_t *plane;
- int value, bestValue;
- int i;
- vec3_t normal;
- float dist;
- int planenum;
-
- hintsplit = qfalse;
- // if it is crossing a 1k block boundary, force a split
- for ( i = 0 ; i < 2 ; i++ ) {
- dist = BLOCK_SIZE * ( floor( node->mins[i] / BLOCK_SIZE ) + 1 );
- if ( node->maxs[i] > dist ) {
- VectorClear( normal );
- normal[i] = 1;
- planenum = FindFloatPlane( normal, dist );
- return planenum;
- }
- }
-
- // pick one of the face planes
- bestValue = -99999;
- bestSplit = list;
-
- for ( split = list ; split ; split = split->next ) {
- split->checked = qfalse;
- }
-
- for ( split = list ; split ; split = split->next ) {
- if ( split->checked ) {
- continue;
- }
- plane = &mapplanes[ split->planenum ];
- splits = 0;
- facing = 0;
- front = 0;
- back = 0;
- for ( check = list ; check ; check = check->next ) {
- if ( check->planenum == split->planenum ) {
- facing++;
- check->checked = qtrue; // won't need to test this plane again
- continue;
- }
- side = WindingOnPlaneSide( check->w, plane->normal, plane->dist );
- if ( side == SIDE_CROSS ) {
- splits++;
- } else if ( side == SIDE_FRONT ) {
- front++;
- } else if ( side == SIDE_BACK ) {
- back++;
- }
- }
- value = 5*facing - 5*splits; // - abs(front-back);
- if ( plane->type < 3 ) {
- value+=5; // axial is better
- }
- value += split->priority; // prioritize hints higher
-
- if ( value > bestValue ) {
- bestValue = value;
- bestSplit = split;
- }
- }
-
- if ( bestValue == -99999 ) {
- return -1;
- }
-
- if (bestSplit->hint)
- hintsplit = qtrue;
-
- return bestSplit->planenum;
-}
-
-int CountFaceList( bspface_t *list ) {
- int c;
- c = 0;
- for ( ; list ; list = list->next ) {
- c++;
- }
- return c;
-}
-
-/*
-================
-BuildFaceTree_r
-================
-*/
-void BuildFaceTree_r( node_t *node, bspface_t *list ) {
- bspface_t *split;
- bspface_t *next;
- int side;
- plane_t *plane;
- bspface_t *newFace;
- bspface_t *childLists[2];
- winding_t *frontWinding, *backWinding;
- int i;
- int splitPlaneNum;
-
- i = CountFaceList( list );
-
- splitPlaneNum = SelectSplitPlaneNum( node, list );
- // if we don't have any more faces, this is a node
- if ( splitPlaneNum == -1 ) {
- node->planenum = PLANENUM_LEAF;
- c_faceLeafs++;
- return;
- }
-
- // partition the list
- node->planenum = splitPlaneNum;
- node->hint = hintsplit;
- plane = &mapplanes[ splitPlaneNum ];
- childLists[0] = NULL;
- childLists[1] = NULL;
- for ( split = list ; split ; split = next ) {
- next = split->next;
-
- if ( split->planenum == node->planenum ) {
- FreeBspFace( split );
- continue;
- }
-
- side = WindingOnPlaneSide( split->w, plane->normal, plane->dist );
-
- if ( side == SIDE_CROSS ) {
- ClipWindingEpsilon( split->w, plane->normal, plane->dist, CLIP_EPSILON * 2,
- &frontWinding, &backWinding );
- if ( frontWinding ) {
- newFace = AllocBspFace();
- newFace->w = frontWinding;
- newFace->next = childLists[0];
- newFace->planenum = split->planenum;
- newFace->priority = split->priority;
- newFace->hint = split->hint;
- childLists[0] = newFace;
- }
- if ( backWinding ) {
- newFace = AllocBspFace();
- newFace->w = backWinding;
- newFace->next = childLists[1];
- newFace->planenum = split->planenum;
- newFace->priority = split->priority;
- newFace->hint = split->hint;
- childLists[1] = newFace;
- }
- FreeBspFace( split );
- } else if ( side == SIDE_FRONT ) {
- split->next = childLists[0];
- childLists[0] = split;
- } else if ( side == SIDE_BACK ) {
- split->next = childLists[1];
- childLists[1] = split;
- }
- }
-
-
- // recursively process children
- for ( i = 0 ; i < 2 ; i++ ) {
- node->children[i] = AllocNode();
- node->children[i]->parent = node;
- VectorCopy( node->mins, node->children[i]->mins );
- VectorCopy( node->maxs, node->children[i]->maxs );
- }
-
- for ( i = 0 ; i < 3 ; i++ ) {
- if ( plane->normal[i] == 1 ) {
- node->children[0]->mins[i] = plane->dist;
- node->children[1]->maxs[i] = plane->dist;
- break;
- }
- }
-
- for ( i = 0 ; i < 2 ; i++ ) {
- BuildFaceTree_r ( node->children[i], childLists[i]);
- }
-}
-
-
-/*
-================
-FaceBSP
-
-List will be freed before returning
-================
-*/
-tree_t *FaceBSP( bspface_t *list ) {
- tree_t *tree;
- bspface_t *face;
- int i;
- int count;
-
- qprintf( "--- FaceBSP ---\n" );
-
- tree = AllocTree ();
-
- count = 0;
- for ( face = list ; face ; face = face->next ) {
- count++;
- for ( i = 0 ; i < face->w->numpoints ; i++ ) {
- AddPointToBounds( face->w->p[i], tree->mins, tree->maxs);
- }
- }
- qprintf( "%5i faces\n", count );
-
- tree->headnode = AllocNode();
- VectorCopy( tree->mins, tree->headnode->mins );
- VectorCopy( tree->maxs, tree->headnode->maxs );
- c_faceLeafs = 0;
-
- BuildFaceTree_r ( tree->headnode, list );
-
- qprintf( "%5i leafs\n", c_faceLeafs );
-
- return tree;
-}
-
-
-/*
-=================
-BspFaceForPortal
-=================
-*/
-bspface_t *BspFaceForPortal( portal_t *p ) {
- bspface_t *f;
-
- f = AllocBspFace();
- f->w = CopyWinding( p->winding );
- f->planenum = p->onnode->planenum & ~1;
-
- return f;
-}
-
-
-
-/*
-=================
-MakeStructuralBspFaceList
-=================
-*/
-bspface_t *MakeStructuralBspFaceList( bspbrush_t *list ) {
- bspbrush_t *b;
- int i;
- side_t *s;
- winding_t *w;
- bspface_t *f, *flist;
-
- flist = NULL;
- for ( b = list ; b ; b = b->next ) {
- if ( b->detail ) {
- continue;
- }
- for ( i = 0 ; i < b->numsides ; i++ ) {
- s = &b->sides[i];
- w = s->winding;
- if ( !w ) {
- continue;
- }
- f = AllocBspFace();
- f->w = CopyWinding( w );
- f->planenum = s->planenum & ~1;
- f->next = flist;
- if (s->surfaceFlags & SURF_HINT) {
- //f->priority = HINT_PRIORITY;
- f->hint = qtrue;
- }
- flist = f;
- }
- }
-
- return flist;
-}
-
-/*
-=================
-MakeVisibleBspFaceList
-=================
-*/
-bspface_t *MakeVisibleBspFaceList( bspbrush_t *list ) {
- bspbrush_t *b;
- int i;
- side_t *s;
- winding_t *w;
- bspface_t *f, *flist;
-
- flist = NULL;
- for ( b = list ; b ; b = b->next ) {
- if ( b->detail ) {
- continue;
- }
- for ( i = 0 ; i < b->numsides ; i++ ) {
- s = &b->sides[i];
- w = s->visibleHull;
- if ( !w ) {
- continue;
- }
- f = AllocBspFace();
- f->w = CopyWinding( w );
- f->planenum = s->planenum & ~1;
- f->next = flist;
- if (s->surfaceFlags & SURF_HINT) {
- //f->priority = HINT_PRIORITY;
- f->hint = qtrue;
- }
- flist = f;
- }
- }
-
- return flist;
-}
-
+
+#include "qbsp.h"
+
+
+int c_faceLeafs;
+
+
+/*
+================
+AllocBspFace
+================
+*/
+bspface_t *AllocBspFace( void ) {
+ bspface_t *f;
+
+ f = malloc(sizeof(*f));
+ memset( f, 0, sizeof(*f) );
+
+ return f;
+}
+
+/*
+================
+FreeBspFace
+================
+*/
+void FreeBspFace( bspface_t *f ) {
+ if ( f->w ) {
+ FreeWinding( f->w );
+ }
+ free( f );
+}
+
+
+/*
+================
+SelectSplitPlaneNum
+================
+*/
+int hintsplit;
+
+#define BLOCK_SIZE 1024
+int SelectSplitPlaneNum( node_t *node, bspface_t *list ) {
+ bspface_t *split;
+ bspface_t *check;
+ bspface_t *bestSplit;
+ int splits, facing, front, back;
+ int side;
+ plane_t *plane;
+ int value, bestValue;
+ int i;
+ vec3_t normal;
+ float dist;
+ int planenum;
+
+ hintsplit = qfalse;
+ // if it is crossing a 1k block boundary, force a split
+ for ( i = 0 ; i < 2 ; i++ ) {
+ dist = BLOCK_SIZE * ( floor( node->mins[i] / BLOCK_SIZE ) + 1 );
+ if ( node->maxs[i] > dist ) {
+ VectorClear( normal );
+ normal[i] = 1;
+ planenum = FindFloatPlane( normal, dist );
+ return planenum;
+ }
+ }
+
+ // pick one of the face planes
+ bestValue = -99999;
+ bestSplit = list;
+
+ for ( split = list ; split ; split = split->next ) {
+ split->checked = qfalse;
+ }
+
+ for ( split = list ; split ; split = split->next ) {
+ if ( split->checked ) {
+ continue;
+ }
+ plane = &mapplanes[ split->planenum ];
+ splits = 0;
+ facing = 0;
+ front = 0;
+ back = 0;
+ for ( check = list ; check ; check = check->next ) {
+ if ( check->planenum == split->planenum ) {
+ facing++;
+ check->checked = qtrue; // won't need to test this plane again
+ continue;
+ }
+ side = WindingOnPlaneSide( check->w, plane->normal, plane->dist );
+ if ( side == SIDE_CROSS ) {
+ splits++;
+ } else if ( side == SIDE_FRONT ) {
+ front++;
+ } else if ( side == SIDE_BACK ) {
+ back++;
+ }
+ }
+ value = 5*facing - 5*splits; // - abs(front-back);
+ if ( plane->type < 3 ) {
+ value+=5; // axial is better
+ }
+ value += split->priority; // prioritize hints higher
+
+ if ( value > bestValue ) {
+ bestValue = value;
+ bestSplit = split;
+ }
+ }
+
+ if ( bestValue == -99999 ) {
+ return -1;
+ }
+
+ if (bestSplit->hint)
+ hintsplit = qtrue;
+
+ return bestSplit->planenum;
+}
+
+int CountFaceList( bspface_t *list ) {
+ int c;
+ c = 0;
+ for ( ; list ; list = list->next ) {
+ c++;
+ }
+ return c;
+}
+
+/*
+================
+BuildFaceTree_r
+================
+*/
+void BuildFaceTree_r( node_t *node, bspface_t *list ) {
+ bspface_t *split;
+ bspface_t *next;
+ int side;
+ plane_t *plane;
+ bspface_t *newFace;
+ bspface_t *childLists[2];
+ winding_t *frontWinding, *backWinding;
+ int i;
+ int splitPlaneNum;
+
+ i = CountFaceList( list );
+
+ splitPlaneNum = SelectSplitPlaneNum( node, list );
+ // if we don't have any more faces, this is a node
+ if ( splitPlaneNum == -1 ) {
+ node->planenum = PLANENUM_LEAF;
+ c_faceLeafs++;
+ return;
+ }
+
+ // partition the list
+ node->planenum = splitPlaneNum;
+ node->hint = hintsplit;
+ plane = &mapplanes[ splitPlaneNum ];
+ childLists[0] = NULL;
+ childLists[1] = NULL;
+ for ( split = list ; split ; split = next ) {
+ next = split->next;
+
+ if ( split->planenum == node->planenum ) {
+ FreeBspFace( split );
+ continue;
+ }
+
+ side = WindingOnPlaneSide( split->w, plane->normal, plane->dist );
+
+ if ( side == SIDE_CROSS ) {
+ ClipWindingEpsilon( split->w, plane->normal, plane->dist, CLIP_EPSILON * 2,
+ &frontWinding, &backWinding );
+ if ( frontWinding ) {
+ newFace = AllocBspFace();
+ newFace->w = frontWinding;
+ newFace->next = childLists[0];
+ newFace->planenum = split->planenum;
+ newFace->priority = split->priority;
+ newFace->hint = split->hint;
+ childLists[0] = newFace;
+ }
+ if ( backWinding ) {
+ newFace = AllocBspFace();
+ newFace->w = backWinding;
+ newFace->next = childLists[1];
+ newFace->planenum = split->planenum;
+ newFace->priority = split->priority;
+ newFace->hint = split->hint;
+ childLists[1] = newFace;
+ }
+ FreeBspFace( split );
+ } else if ( side == SIDE_FRONT ) {
+ split->next = childLists[0];
+ childLists[0] = split;
+ } else if ( side == SIDE_BACK ) {
+ split->next = childLists[1];
+ childLists[1] = split;
+ }
+ }
+
+
+ // recursively process children
+ for ( i = 0 ; i < 2 ; i++ ) {
+ node->children[i] = AllocNode();
+ node->children[i]->parent = node;
+ VectorCopy( node->mins, node->children[i]->mins );
+ VectorCopy( node->maxs, node->children[i]->maxs );
+ }
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ if ( plane->normal[i] == 1 ) {
+ node->children[0]->mins[i] = plane->dist;
+ node->children[1]->maxs[i] = plane->dist;
+ break;
+ }
+ }
+
+ for ( i = 0 ; i < 2 ; i++ ) {
+ BuildFaceTree_r ( node->children[i], childLists[i]);
+ }
+}
+
+
+/*
+================
+FaceBSP
+
+List will be freed before returning
+================
+*/
+tree_t *FaceBSP( bspface_t *list ) {
+ tree_t *tree;
+ bspface_t *face;
+ int i;
+ int count;
+
+ qprintf( "--- FaceBSP ---\n" );
+
+ tree = AllocTree ();
+
+ count = 0;
+ for ( face = list ; face ; face = face->next ) {
+ count++;
+ for ( i = 0 ; i < face->w->numpoints ; i++ ) {
+ AddPointToBounds( face->w->p[i], tree->mins, tree->maxs);
+ }
+ }
+ qprintf( "%5i faces\n", count );
+
+ tree->headnode = AllocNode();
+ VectorCopy( tree->mins, tree->headnode->mins );
+ VectorCopy( tree->maxs, tree->headnode->maxs );
+ c_faceLeafs = 0;
+
+ BuildFaceTree_r ( tree->headnode, list );
+
+ qprintf( "%5i leafs\n", c_faceLeafs );
+
+ return tree;
+}
+
+
+/*
+=================
+BspFaceForPortal
+=================
+*/
+bspface_t *BspFaceForPortal( portal_t *p ) {
+ bspface_t *f;
+
+ f = AllocBspFace();
+ f->w = CopyWinding( p->winding );
+ f->planenum = p->onnode->planenum & ~1;
+
+ return f;
+}
+
+
+
+/*
+=================
+MakeStructuralBspFaceList
+=================
+*/
+bspface_t *MakeStructuralBspFaceList( bspbrush_t *list ) {
+ bspbrush_t *b;
+ int i;
+ side_t *s;
+ winding_t *w;
+ bspface_t *f, *flist;
+
+ flist = NULL;
+ for ( b = list ; b ; b = b->next ) {
+ if ( b->detail ) {
+ continue;
+ }
+ for ( i = 0 ; i < b->numsides ; i++ ) {
+ s = &b->sides[i];
+ w = s->winding;
+ if ( !w ) {
+ continue;
+ }
+ f = AllocBspFace();
+ f->w = CopyWinding( w );
+ f->planenum = s->planenum & ~1;
+ f->next = flist;
+ if (s->surfaceFlags & SURF_HINT) {
+ //f->priority = HINT_PRIORITY;
+ f->hint = qtrue;
+ }
+ flist = f;
+ }
+ }
+
+ return flist;
+}
+
+/*
+=================
+MakeVisibleBspFaceList
+=================
+*/
+bspface_t *MakeVisibleBspFaceList( bspbrush_t *list ) {
+ bspbrush_t *b;
+ int i;
+ side_t *s;
+ winding_t *w;
+ bspface_t *f, *flist;
+
+ flist = NULL;
+ for ( b = list ; b ; b = b->next ) {
+ if ( b->detail ) {
+ continue;
+ }
+ for ( i = 0 ; i < b->numsides ; i++ ) {
+ s = &b->sides[i];
+ w = s->visibleHull;
+ if ( !w ) {
+ continue;
+ }
+ f = AllocBspFace();
+ f->w = CopyWinding( w );
+ f->planenum = s->planenum & ~1;
+ f->next = flist;
+ if (s->surfaceFlags & SURF_HINT) {
+ //f->priority = HINT_PRIORITY;
+ f->hint = qtrue;
+ }
+ flist = f;
+ }
+ }
+
+ return flist;
+}
+
diff --git a/q3map/fog.c b/q3map/fog.c
index cf4060a..fa938dd 100755
--- a/q3map/fog.c
+++ b/q3map/fog.c
@@ -19,536 +19,536 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-#include "qbsp.h"
-
-
-int c_fogFragment;
-int c_fogPatchFragments;
-
-/*
-====================
-DrawSurfToMesh
-====================
-*/
-mesh_t *DrawSurfToMesh( mapDrawSurface_t *ds ) {
- mesh_t *m;
-
- m = malloc( sizeof( *m ) );
- m->width = ds->patchWidth;
- m->height = ds->patchHeight;
- m->verts = malloc( sizeof(m->verts[0]) * m->width * m->height );
- memcpy( m->verts, ds->verts, sizeof(m->verts[0]) * m->width * m->height );
-
- return m;
-}
-
-
-/*
-====================
-SplitMeshByPlane
-====================
-*/
-void SplitMeshByPlane( mesh_t *in, vec3_t normal, float dist, mesh_t **front, mesh_t **back ) {
- int w, h, split;
- float d[MAX_PATCH_SIZE][MAX_PATCH_SIZE];
- drawVert_t *dv, *v1, *v2;
- int c_front, c_back, c_on;
- mesh_t *f, *b;
- int i;
- float frac;
- int frontAprox, backAprox;
-
- for ( i = 0 ; i < 2 ; i++ ) {
- dv = in->verts;
- c_front = 0;
- c_back = 0;
- c_on = 0;
- for ( h = 0 ; h < in->height ; h++ ) {
- for ( w = 0 ; w < in->width ; w++, dv++ ) {
- d[h][w] = DotProduct( dv->xyz, normal ) - dist;
- if ( d[h][w] > ON_EPSILON ) {
- c_front++;
- } else if ( d[h][w] < -ON_EPSILON ) {
- c_back++;
- } else {
- c_on++;
- }
- }
- }
-
- *front = NULL;
- *back = NULL;
-
- if ( !c_front ) {
- *back = in;
- return;
- }
- if ( !c_back ) {
- *front = in;
- return;
- }
-
- // find a split point
- split = -1;
- for ( w = 0 ; w < in->width -1 ; w++ ) {
- if ( ( d[0][w] < 0 ) != ( d[0][w+1] < 0 ) ) {
- if ( split == -1 ) {
- split = w;
- break;
- }
- }
- }
-
- if ( split == -1 ) {
- if ( i == 1 ) {
- qprintf( "No crossing points in patch\n");
- *front = in;
- return;
- }
-
- in = TransposeMesh( in );
- InvertMesh( in );
- continue;
- }
-
- // make sure the split point stays the same for all other rows
- for ( h = 1 ; h < in->height ; h++ ) {
- for ( w = 0 ; w < in->width -1 ; w++ ) {
- if ( ( d[h][w] < 0 ) != ( d[h][w+1] < 0 ) ) {
- if ( w != split ) {
- _printf( "multiple crossing points for patch -- can't clip\n");
- *front = in;
- return;
- }
- }
- }
- if ( ( d[h][split] < 0 ) == ( d[h][split+1] < 0 ) ) {
- _printf( "differing crossing points for patch -- can't clip\n");
- *front = in;
- return;
- }
- }
-
- break;
- }
-
-
- // create two new meshes
- f = malloc( sizeof( *f ) );
- f->width = split + 2;
- if ( ! (f->width & 1) ) {
- f->width++;
- frontAprox = 1;
- } else {
- frontAprox = 0;
- }
- if ( f->width > MAX_PATCH_SIZE ) {
- Error( "MAX_PATCH_SIZE after split");
- }
- f->height = in->height;
- f->verts = malloc( sizeof(f->verts[0]) * f->width * f->height );
-
- b = malloc( sizeof( *b ) );
- b->width = in->width - split;
- if ( ! (b->width & 1) ) {
- b->width++;
- backAprox = 1;
- } else {
- backAprox = 0;
- }
- if ( b->width > MAX_PATCH_SIZE ) {
- Error( "MAX_PATCH_SIZE after split");
- }
- b->height = in->height;
- b->verts = malloc( sizeof(b->verts[0]) * b->width * b->height );
-
- if ( d[0][0] > 0 ) {
- *front = f;
- *back = b;
- } else {
- *front = b;
- *back = f;
- }
-
- // distribute the points
- for ( w = 0 ; w < in->width ; w++ ) {
- for ( h = 0 ; h < in->height ; h++ ) {
- if ( w <= split ) {
- f->verts[ h * f->width + w ] = in->verts[ h * in->width + w ];
- } else {
- b->verts[ h * b->width + w - split + backAprox ] = in->verts[ h * in->width + w ];
- }
- }
- }
-
- // clip the crossing line
- for ( h = 0 ; h < in->height ; h++ ) {
- dv = &f->verts[ h * f->width + split + 1 ];
- v1 = &in->verts[ h * in->width + split ];
- v2 = &in->verts[ h * in->width + split + 1 ];
- frac = d[h][split] / ( d[h][split] - d[h][split+1] );
- for ( i = 0 ; i < 10 ; i++ ) {
- dv->xyz[i] = v1->xyz[i] + frac * ( v2->xyz[i] - v1->xyz[i] );
- }
- dv->xyz[10] = 0;//set all 4 colors to 0
- if ( frontAprox ) {
- f->verts[ h * f->width + split + 2 ] = *dv;
- }
- b->verts[ h * b->width ] = *dv;
- if ( backAprox ) {
- b->verts[ h * b->width + 1 ] = *dv;
- }
- }
-
- /*
-PrintMesh( in );
-_printf("\n");
-PrintMesh( f );
-_printf("\n");
-PrintMesh( b );
-_printf("\n");
- */
-
- FreeMesh( in );
-}
-
-
-/*
-====================
-ChopPatchByBrush
-====================
-*/
-qboolean ChopPatchByBrush( mapDrawSurface_t *ds, bspbrush_t *b ) {
- int i, j;
- side_t *s;
- plane_t *plane;
- mesh_t *outside[MAX_BRUSH_SIDES];
- int numOutside;
- mesh_t *m, *front, *back;
- mapDrawSurface_t *newds;
-
- m = DrawSurfToMesh( ds );
- numOutside = 0;
-
- // only split by the top and bottom planes to avoid
- // some messy patch clipping issues
-
- for ( i = 4 ; i <= 5 ; i++ ) {
- s = &b->sides[ i ];
- plane = &mapplanes[ s->planenum ];
-
- SplitMeshByPlane( m, plane->normal, plane->dist, &front, &back );
-
- if ( !back ) {
- // nothing actually contained inside
- for ( j = 0 ; j < numOutside ; j++ ) {
- FreeMesh( outside[j] );
- }
- return qfalse;
- }
- m = back;
-
- if ( front ) {
- if ( numOutside == MAX_BRUSH_SIDES ) {
- Error( "MAX_BRUSH_SIDES" );
- }
- outside[ numOutside ] = front;
- numOutside++;
- }
- }
-
- // all of outside fragments become seperate drawsurfs
- c_fogPatchFragments += numOutside;
- for ( i = 0 ; i < numOutside ; i++ ) {
- newds = DrawSurfaceForMesh( outside[ i ] );
- newds->shaderInfo = ds->shaderInfo;
- FreeMesh( outside[ i ] );
- }
-
- // replace ds with m
- ds->patchWidth = m->width;
- ds->patchHeight = m->height;
- ds->numVerts = m->width * m->height;
- free( ds->verts );
- ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
- memcpy( ds->verts, m->verts, ds->numVerts * sizeof( *ds->verts ) );
-
- FreeMesh( m );
-
- return qtrue;
-}
-
-//===============================================================================
-
-/*
-====================
-WindingFromDrawSurf
-====================
-*/
-winding_t *WindingFromDrawSurf( mapDrawSurface_t *ds ) {
- winding_t *w;
- int i;
-
- w = AllocWinding( ds->numVerts );
- w->numpoints = ds->numVerts;
- for ( i = 0 ; i < ds->numVerts ; i++ ) {
- VectorCopy( ds->verts[i].xyz, w->p[i] );
- }
- return w;
-}
-
-/*
-====================
-ChopFaceByBrush
-
-There may be a fragment contained in the brush
-====================
-*/
-qboolean ChopFaceByBrush( mapDrawSurface_t *ds, bspbrush_t *b ) {
- int i, j;
- side_t *s;
- plane_t *plane;
- winding_t *w;
- winding_t *front, *back;
- winding_t *outside[MAX_BRUSH_SIDES];
- int numOutside;
- mapDrawSurface_t *newds;
- drawVert_t *dv;
- shaderInfo_t *si;
- float mins[2];
-
- // brush primitive :
- // axis base
- vec3_t texX,texY;
- vec_t x,y;
-
- w = WindingFromDrawSurf( ds );
- numOutside = 0;
-
- for ( i = 0 ; i < b->numsides ; i++ ) {
- s = &b->sides[ i ];
- if ( s->backSide ) {
- continue;
- }
- plane = &mapplanes[ s->planenum ];
-
- // handle coplanar outfacing (don't fog)
- if ( ds->side->planenum == s->planenum ) {
- return qfalse;
- }
-
- // handle coplanar infacing (keep inside)
- if ( ( ds->side->planenum ^ 1 ) == s->planenum ) {
- continue;
- }
-
- // general case
- ClipWindingEpsilon( w, plane->normal, plane->dist, ON_EPSILON,
- &front, &back );
- FreeWinding( w );
- if ( !back ) {
- // nothing actually contained inside
- for ( j = 0 ; j < numOutside ; j++ ) {
- FreeWinding( outside[j] );
- }
- return qfalse;
- }
- if ( front ) {
- if ( numOutside == MAX_BRUSH_SIDES ) {
- Error( "MAX_BRUSH_SIDES" );
- }
- outside[ numOutside ] = front;
- numOutside++;
- }
- w = back;
- }
-
- // all of outside fragments become seperate drawsurfs
- // linked to the same side
- c_fogFragment += numOutside;
- s = ds->side;
-
- for ( i = 0 ; i < numOutside ; i++ ) {
- newds = DrawSurfaceForSide( ds->mapBrush, s, outside[i] );
- FreeWinding( outside[i] );
- }
-
-
- // replace ds->verts with the verts for w
- ds->numVerts = w->numpoints;
- free( ds->verts );
-
- ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
- memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
-
- si = s->shaderInfo;
-
- mins[0] = 9999;
- mins[1] = 9999;
-
- // compute s/t coordinates from brush primitive texture matrix
- // compute axis base
- ComputeAxisBase( mapplanes[s->planenum].normal, texX, texY );
-
- for ( j = 0 ; j < w->numpoints ; j++ ) {
- dv = ds->verts + j;
- VectorCopy( w->p[j], dv->xyz );
-
- if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
- {
- // calculate texture s/t
- dv->st[0] = s->vecs[0][3] + DotProduct( s->vecs[0], dv->xyz );
- dv->st[1] = s->vecs[1][3] + DotProduct( s->vecs[1], dv->xyz );
- dv->st[0] /= si->width;
- dv->st[1] /= si->height;
- }
- else
- {
- // calculate texture s/t from brush primitive texture matrix
- x = DotProduct( dv->xyz, texX );
- y = DotProduct( dv->xyz, texY );
- dv->st[0]=s->texMat[0][0]*x+s->texMat[0][1]*y+s->texMat[0][2];
- dv->st[1]=s->texMat[1][0]*x+s->texMat[1][1]*y+s->texMat[1][2];
- }
-
- if ( dv->st[0] < mins[0] ) {
- mins[0] = dv->st[0];
- }
- if ( dv->st[1] < mins[1] ) {
- mins[1] = dv->st[1];
- }
-
- // copy normal
- VectorCopy ( mapplanes[s->planenum].normal, dv->normal );
- }
-
- // adjust the texture coordinates to be as close to 0 as possible
- if ( !si->globalTexture ) {
- mins[0] = floor( mins[0] );
- mins[1] = floor( mins[1] );
- for ( i = 0 ; i < w->numpoints ; i++ ) {
- dv = ds->verts + i;
- dv->st[0] -= mins[0];
- dv->st[1] -= mins[1];
- }
- }
-
- return qtrue;
-}
-
-//===============================================================================
-
-
-/*
-=====================
-FogDrawSurfs
-
-Call after the surface list has been pruned,
-before tjunction fixing
-before lightmap allocation
-=====================
-*/
-void FogDrawSurfs( void ) {
- int i, j, k;
- mapDrawSurface_t *ds;
- bspbrush_t *b;
- vec3_t mins, maxs;
- int c_fogged;
- int numBaseDrawSurfs;
- dfog_t *fog;
-
- qprintf("----- FogDrawsurfs -----\n");
-
- c_fogged = 0;
- c_fogFragment = 0;
-
- // find all fog brushes
- for ( b = entities[0].brushes ; b ; b = b->next ) {
- if ( !(b->contents & CONTENTS_FOG) ) {
- continue;
- }
-
- if ( numFogs == MAX_MAP_FOGS ) {
- Error( "MAX_MAP_FOGS" );
- }
- fog = &dfogs[numFogs];
- numFogs++;
- fog->brushNum = b->outputNumber;
-
- // find a side with a valid shaderInfo
- // non-axial fog columns may have bevel planes that need to be skipped
- for ( i = 0 ; i < b->numsides ; i++ ) {
- if ( b->sides[i].shaderInfo && (b->sides[i].shaderInfo->contents & CONTENTS_FOG) ) {
- strcpy( fog->shader, b->sides[i].shaderInfo->shader );
- break;
- }
- }
- if ( i == b->numsides ) {
- continue; // shouldn't happen
- }
-
- fog->visibleSide = -1;
-
- // clip each surface into this, but don't clip any of
- // the resulting fragments to the same brush
- numBaseDrawSurfs = numMapDrawSurfs;
- for ( i = 0 ; i < numBaseDrawSurfs ; i++ ) {
- ds = &mapDrawSurfs[i];
-
- // bound the drawsurf
- ClearBounds( mins, maxs );
- for ( j = 0 ; j < ds->numVerts ; j++ ) {
- AddPointToBounds( ds->verts[j].xyz, mins, maxs );
- }
-
- // check against the fog brush
- for ( k = 0 ; k < 3 ; k++ ) {
- if ( mins[k] > b->maxs[k] ) {
- break;
- }
- if ( maxs[k] < b->mins[k] ) {
- break;
- }
- }
- if ( k < 3 ) {
- continue; // bboxes don't intersect
- }
-
- if ( ds->mapBrush == b ) {
- int s;
-
- s = ds->side - b->sides;
- if ( s <= 6 ) { // not one of the reversed inside faces
- // this is a visible fog plane
- if ( fog->visibleSide != -1 ) {
- _printf( "WARNING: fog brush %i has multiple visible sides\n", b->brushnum );
- }
- fog->visibleSide = s;
- }
- }
-
- if ( ds->miscModel ) {
- // we could write splitting code for trimodels if we wanted to...
- c_fogged++;
- ds->fogNum = numFogs - 1;
- } else if ( ds->patch ) {
- if ( ChopPatchByBrush( ds, b ) ) {
- c_fogged++;
- ds->fogNum = numFogs - 1;
- }
- } else {
- if ( ChopFaceByBrush( ds, b ) ) {
- c_fogged++;
- ds->fogNum = numFogs - 1;
- }
- }
- }
- }
-
- // split the drawsurfs by the fog brushes
-
- qprintf( "%5i fogs\n", numFogs );
- qprintf( "%5i fog polygon fragments\n", c_fogFragment );
- qprintf( "%5i fog patch fragments\n", c_fogPatchFragments );
- qprintf( "%5i fogged drawsurfs\n", c_fogged );
-}
+#include "qbsp.h"
+
+
+int c_fogFragment;
+int c_fogPatchFragments;
+
+/*
+====================
+DrawSurfToMesh
+====================
+*/
+mesh_t *DrawSurfToMesh( mapDrawSurface_t *ds ) {
+ mesh_t *m;
+
+ m = malloc( sizeof( *m ) );
+ m->width = ds->patchWidth;
+ m->height = ds->patchHeight;
+ m->verts = malloc( sizeof(m->verts[0]) * m->width * m->height );
+ memcpy( m->verts, ds->verts, sizeof(m->verts[0]) * m->width * m->height );
+
+ return m;
+}
+
+
+/*
+====================
+SplitMeshByPlane
+====================
+*/
+void SplitMeshByPlane( mesh_t *in, vec3_t normal, float dist, mesh_t **front, mesh_t **back ) {
+ int w, h, split;
+ float d[MAX_PATCH_SIZE][MAX_PATCH_SIZE];
+ drawVert_t *dv, *v1, *v2;
+ int c_front, c_back, c_on;
+ mesh_t *f, *b;
+ int i;
+ float frac;
+ int frontAprox, backAprox;
+
+ for ( i = 0 ; i < 2 ; i++ ) {
+ dv = in->verts;
+ c_front = 0;
+ c_back = 0;
+ c_on = 0;
+ for ( h = 0 ; h < in->height ; h++ ) {
+ for ( w = 0 ; w < in->width ; w++, dv++ ) {
+ d[h][w] = DotProduct( dv->xyz, normal ) - dist;
+ if ( d[h][w] > ON_EPSILON ) {
+ c_front++;
+ } else if ( d[h][w] < -ON_EPSILON ) {
+ c_back++;
+ } else {
+ c_on++;
+ }
+ }
+ }
+
+ *front = NULL;
+ *back = NULL;
+
+ if ( !c_front ) {
+ *back = in;
+ return;
+ }
+ if ( !c_back ) {
+ *front = in;
+ return;
+ }
+
+ // find a split point
+ split = -1;
+ for ( w = 0 ; w < in->width -1 ; w++ ) {
+ if ( ( d[0][w] < 0 ) != ( d[0][w+1] < 0 ) ) {
+ if ( split == -1 ) {
+ split = w;
+ break;
+ }
+ }
+ }
+
+ if ( split == -1 ) {
+ if ( i == 1 ) {
+ qprintf( "No crossing points in patch\n");
+ *front = in;
+ return;
+ }
+
+ in = TransposeMesh( in );
+ InvertMesh( in );
+ continue;
+ }
+
+ // make sure the split point stays the same for all other rows
+ for ( h = 1 ; h < in->height ; h++ ) {
+ for ( w = 0 ; w < in->width -1 ; w++ ) {
+ if ( ( d[h][w] < 0 ) != ( d[h][w+1] < 0 ) ) {
+ if ( w != split ) {
+ _printf( "multiple crossing points for patch -- can't clip\n");
+ *front = in;
+ return;
+ }
+ }
+ }
+ if ( ( d[h][split] < 0 ) == ( d[h][split+1] < 0 ) ) {
+ _printf( "differing crossing points for patch -- can't clip\n");
+ *front = in;
+ return;
+ }
+ }
+
+ break;
+ }
+
+
+ // create two new meshes
+ f = malloc( sizeof( *f ) );
+ f->width = split + 2;
+ if ( ! (f->width & 1) ) {
+ f->width++;
+ frontAprox = 1;
+ } else {
+ frontAprox = 0;
+ }
+ if ( f->width > MAX_PATCH_SIZE ) {
+ Error( "MAX_PATCH_SIZE after split");
+ }
+ f->height = in->height;
+ f->verts = malloc( sizeof(f->verts[0]) * f->width * f->height );
+
+ b = malloc( sizeof( *b ) );
+ b->width = in->width - split;
+ if ( ! (b->width & 1) ) {
+ b->width++;
+ backAprox = 1;
+ } else {
+ backAprox = 0;
+ }
+ if ( b->width > MAX_PATCH_SIZE ) {
+ Error( "MAX_PATCH_SIZE after split");
+ }
+ b->height = in->height;
+ b->verts = malloc( sizeof(b->verts[0]) * b->width * b->height );
+
+ if ( d[0][0] > 0 ) {
+ *front = f;
+ *back = b;
+ } else {
+ *front = b;
+ *back = f;
+ }
+
+ // distribute the points
+ for ( w = 0 ; w < in->width ; w++ ) {
+ for ( h = 0 ; h < in->height ; h++ ) {
+ if ( w <= split ) {
+ f->verts[ h * f->width + w ] = in->verts[ h * in->width + w ];
+ } else {
+ b->verts[ h * b->width + w - split + backAprox ] = in->verts[ h * in->width + w ];
+ }
+ }
+ }
+
+ // clip the crossing line
+ for ( h = 0 ; h < in->height ; h++ ) {
+ dv = &f->verts[ h * f->width + split + 1 ];
+ v1 = &in->verts[ h * in->width + split ];
+ v2 = &in->verts[ h * in->width + split + 1 ];
+ frac = d[h][split] / ( d[h][split] - d[h][split+1] );
+ for ( i = 0 ; i < 10 ; i++ ) {
+ dv->xyz[i] = v1->xyz[i] + frac * ( v2->xyz[i] - v1->xyz[i] );
+ }
+ dv->xyz[10] = 0;//set all 4 colors to 0
+ if ( frontAprox ) {
+ f->verts[ h * f->width + split + 2 ] = *dv;
+ }
+ b->verts[ h * b->width ] = *dv;
+ if ( backAprox ) {
+ b->verts[ h * b->width + 1 ] = *dv;
+ }
+ }
+
+ /*
+PrintMesh( in );
+_printf("\n");
+PrintMesh( f );
+_printf("\n");
+PrintMesh( b );
+_printf("\n");
+ */
+
+ FreeMesh( in );
+}
+
+
+/*
+====================
+ChopPatchByBrush
+====================
+*/
+qboolean ChopPatchByBrush( mapDrawSurface_t *ds, bspbrush_t *b ) {
+ int i, j;
+ side_t *s;
+ plane_t *plane;
+ mesh_t *outside[MAX_BRUSH_SIDES];
+ int numOutside;
+ mesh_t *m, *front, *back;
+ mapDrawSurface_t *newds;
+
+ m = DrawSurfToMesh( ds );
+ numOutside = 0;
+
+ // only split by the top and bottom planes to avoid
+ // some messy patch clipping issues
+
+ for ( i = 4 ; i <= 5 ; i++ ) {
+ s = &b->sides[ i ];
+ plane = &mapplanes[ s->planenum ];
+
+ SplitMeshByPlane( m, plane->normal, plane->dist, &front, &back );
+
+ if ( !back ) {
+ // nothing actually contained inside
+ for ( j = 0 ; j < numOutside ; j++ ) {
+ FreeMesh( outside[j] );
+ }
+ return qfalse;
+ }
+ m = back;
+
+ if ( front ) {
+ if ( numOutside == MAX_BRUSH_SIDES ) {
+ Error( "MAX_BRUSH_SIDES" );
+ }
+ outside[ numOutside ] = front;
+ numOutside++;
+ }
+ }
+
+ // all of outside fragments become seperate drawsurfs
+ c_fogPatchFragments += numOutside;
+ for ( i = 0 ; i < numOutside ; i++ ) {
+ newds = DrawSurfaceForMesh( outside[ i ] );
+ newds->shaderInfo = ds->shaderInfo;
+ FreeMesh( outside[ i ] );
+ }
+
+ // replace ds with m
+ ds->patchWidth = m->width;
+ ds->patchHeight = m->height;
+ ds->numVerts = m->width * m->height;
+ free( ds->verts );
+ ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
+ memcpy( ds->verts, m->verts, ds->numVerts * sizeof( *ds->verts ) );
+
+ FreeMesh( m );
+
+ return qtrue;
+}
+
+//===============================================================================
+
+/*
+====================
+WindingFromDrawSurf
+====================
+*/
+winding_t *WindingFromDrawSurf( mapDrawSurface_t *ds ) {
+ winding_t *w;
+ int i;
+
+ w = AllocWinding( ds->numVerts );
+ w->numpoints = ds->numVerts;
+ for ( i = 0 ; i < ds->numVerts ; i++ ) {
+ VectorCopy( ds->verts[i].xyz, w->p[i] );
+ }
+ return w;
+}
+
+/*
+====================
+ChopFaceByBrush
+
+There may be a fragment contained in the brush
+====================
+*/
+qboolean ChopFaceByBrush( mapDrawSurface_t *ds, bspbrush_t *b ) {
+ int i, j;
+ side_t *s;
+ plane_t *plane;
+ winding_t *w;
+ winding_t *front, *back;
+ winding_t *outside[MAX_BRUSH_SIDES];
+ int numOutside;
+ mapDrawSurface_t *newds;
+ drawVert_t *dv;
+ shaderInfo_t *si;
+ float mins[2];
+
+ // brush primitive :
+ // axis base
+ vec3_t texX,texY;
+ vec_t x,y;
+
+ w = WindingFromDrawSurf( ds );
+ numOutside = 0;
+
+ for ( i = 0 ; i < b->numsides ; i++ ) {
+ s = &b->sides[ i ];
+ if ( s->backSide ) {
+ continue;
+ }
+ plane = &mapplanes[ s->planenum ];
+
+ // handle coplanar outfacing (don't fog)
+ if ( ds->side->planenum == s->planenum ) {
+ return qfalse;
+ }
+
+ // handle coplanar infacing (keep inside)
+ if ( ( ds->side->planenum ^ 1 ) == s->planenum ) {
+ continue;
+ }
+
+ // general case
+ ClipWindingEpsilon( w, plane->normal, plane->dist, ON_EPSILON,
+ &front, &back );
+ FreeWinding( w );
+ if ( !back ) {
+ // nothing actually contained inside
+ for ( j = 0 ; j < numOutside ; j++ ) {
+ FreeWinding( outside[j] );
+ }
+ return qfalse;
+ }
+ if ( front ) {
+ if ( numOutside == MAX_BRUSH_SIDES ) {
+ Error( "MAX_BRUSH_SIDES" );
+ }
+ outside[ numOutside ] = front;
+ numOutside++;
+ }
+ w = back;
+ }
+
+ // all of outside fragments become seperate drawsurfs
+ // linked to the same side
+ c_fogFragment += numOutside;
+ s = ds->side;
+
+ for ( i = 0 ; i < numOutside ; i++ ) {
+ newds = DrawSurfaceForSide( ds->mapBrush, s, outside[i] );
+ FreeWinding( outside[i] );
+ }
+
+
+ // replace ds->verts with the verts for w
+ ds->numVerts = w->numpoints;
+ free( ds->verts );
+
+ ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
+ memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
+
+ si = s->shaderInfo;
+
+ mins[0] = 9999;
+ mins[1] = 9999;
+
+ // compute s/t coordinates from brush primitive texture matrix
+ // compute axis base
+ ComputeAxisBase( mapplanes[s->planenum].normal, texX, texY );
+
+ for ( j = 0 ; j < w->numpoints ; j++ ) {
+ dv = ds->verts + j;
+ VectorCopy( w->p[j], dv->xyz );
+
+ if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
+ {
+ // calculate texture s/t
+ dv->st[0] = s->vecs[0][3] + DotProduct( s->vecs[0], dv->xyz );
+ dv->st[1] = s->vecs[1][3] + DotProduct( s->vecs[1], dv->xyz );
+ dv->st[0] /= si->width;
+ dv->st[1] /= si->height;
+ }
+ else
+ {
+ // calculate texture s/t from brush primitive texture matrix
+ x = DotProduct( dv->xyz, texX );
+ y = DotProduct( dv->xyz, texY );
+ dv->st[0]=s->texMat[0][0]*x+s->texMat[0][1]*y+s->texMat[0][2];
+ dv->st[1]=s->texMat[1][0]*x+s->texMat[1][1]*y+s->texMat[1][2];
+ }
+
+ if ( dv->st[0] < mins[0] ) {
+ mins[0] = dv->st[0];
+ }
+ if ( dv->st[1] < mins[1] ) {
+ mins[1] = dv->st[1];
+ }
+
+ // copy normal
+ VectorCopy ( mapplanes[s->planenum].normal, dv->normal );
+ }
+
+ // adjust the texture coordinates to be as close to 0 as possible
+ if ( !si->globalTexture ) {
+ mins[0] = floor( mins[0] );
+ mins[1] = floor( mins[1] );
+ for ( i = 0 ; i < w->numpoints ; i++ ) {
+ dv = ds->verts + i;
+ dv->st[0] -= mins[0];
+ dv->st[1] -= mins[1];
+ }
+ }
+
+ return qtrue;
+}
+
+//===============================================================================
+
+
+/*
+=====================
+FogDrawSurfs
+
+Call after the surface list has been pruned,
+before tjunction fixing
+before lightmap allocation
+=====================
+*/
+void FogDrawSurfs( void ) {
+ int i, j, k;
+ mapDrawSurface_t *ds;
+ bspbrush_t *b;
+ vec3_t mins, maxs;
+ int c_fogged;
+ int numBaseDrawSurfs;
+ dfog_t *fog;
+
+ qprintf("----- FogDrawsurfs -----\n");
+
+ c_fogged = 0;
+ c_fogFragment = 0;
+
+ // find all fog brushes
+ for ( b = entities[0].brushes ; b ; b = b->next ) {
+ if ( !(b->contents & CONTENTS_FOG) ) {
+ continue;
+ }
+
+ if ( numFogs == MAX_MAP_FOGS ) {
+ Error( "MAX_MAP_FOGS" );
+ }
+ fog = &dfogs[numFogs];
+ numFogs++;
+ fog->brushNum = b->outputNumber;
+
+ // find a side with a valid shaderInfo
+ // non-axial fog columns may have bevel planes that need to be skipped
+ for ( i = 0 ; i < b->numsides ; i++ ) {
+ if ( b->sides[i].shaderInfo && (b->sides[i].shaderInfo->contents & CONTENTS_FOG) ) {
+ strcpy( fog->shader, b->sides[i].shaderInfo->shader );
+ break;
+ }
+ }
+ if ( i == b->numsides ) {
+ continue; // shouldn't happen
+ }
+
+ fog->visibleSide = -1;
+
+ // clip each surface into this, but don't clip any of
+ // the resulting fragments to the same brush
+ numBaseDrawSurfs = numMapDrawSurfs;
+ for ( i = 0 ; i < numBaseDrawSurfs ; i++ ) {
+ ds = &mapDrawSurfs[i];
+
+ // bound the drawsurf
+ ClearBounds( mins, maxs );
+ for ( j = 0 ; j < ds->numVerts ; j++ ) {
+ AddPointToBounds( ds->verts[j].xyz, mins, maxs );
+ }
+
+ // check against the fog brush
+ for ( k = 0 ; k < 3 ; k++ ) {
+ if ( mins[k] > b->maxs[k] ) {
+ break;
+ }
+ if ( maxs[k] < b->mins[k] ) {
+ break;
+ }
+ }
+ if ( k < 3 ) {
+ continue; // bboxes don't intersect
+ }
+
+ if ( ds->mapBrush == b ) {
+ int s;
+
+ s = ds->side - b->sides;
+ if ( s <= 6 ) { // not one of the reversed inside faces
+ // this is a visible fog plane
+ if ( fog->visibleSide != -1 ) {
+ _printf( "WARNING: fog brush %i has multiple visible sides\n", b->brushnum );
+ }
+ fog->visibleSide = s;
+ }
+ }
+
+ if ( ds->miscModel ) {
+ // we could write splitting code for trimodels if we wanted to...
+ c_fogged++;
+ ds->fogNum = numFogs - 1;
+ } else if ( ds->patch ) {
+ if ( ChopPatchByBrush( ds, b ) ) {
+ c_fogged++;
+ ds->fogNum = numFogs - 1;
+ }
+ } else {
+ if ( ChopFaceByBrush( ds, b ) ) {
+ c_fogged++;
+ ds->fogNum = numFogs - 1;
+ }
+ }
+ }
+ }
+
+ // split the drawsurfs by the fog brushes
+
+ qprintf( "%5i fogs\n", numFogs );
+ qprintf( "%5i fog polygon fragments\n", c_fogFragment );
+ qprintf( "%5i fog patch fragments\n", c_fogPatchFragments );
+ qprintf( "%5i fogged drawsurfs\n", c_fogged );
+}
diff --git a/q3map/gldraw.c b/q3map/gldraw.c
index bf2ceba..80620a4 100755
--- a/q3map/gldraw.c
+++ b/q3map/gldraw.c
@@ -19,214 +19,214 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include <windows.h>
-#include <GL/gl.h>
-#include <GL/glu.h>
-#include <GL/glaux.h>
-
-#include "qbsp.h"
-
-// can't use the glvertex3fv functions, because the vec3_t fields
-// could be either floats or doubles, depending on DOUBLEVEC_T
-
-qboolean drawflag;
-vec3_t draw_mins, draw_maxs;
-
-
-#define WIN_SIZE 512
-
-void InitWindow (void)
-{
- auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
- auxInitPosition (0, 0, WIN_SIZE, WIN_SIZE);
- auxInitWindow ("qcsg");
-}
-
-void Draw_ClearWindow (void)
-{
- static int init;
- int w, h, g;
- vec_t mx, my;
-
- if (!drawflag)
- return;
-
- if (!init)
- {
- init = qtrue;
- InitWindow ();
- }
-
- glClearColor (1,0.8,0.8,0);
- glClear (GL_COLOR_BUFFER_BIT);
-
- w = (draw_maxs[0] - draw_mins[0]);
- h = (draw_maxs[1] - draw_mins[1]);
-
- mx = draw_mins[0] + w/2;
- my = draw_mins[1] + h/2;
-
- g = w > h ? w : h;
-
- glLoadIdentity ();
- gluPerspective (90, 1, 2, 16384);
- gluLookAt (mx, my, draw_maxs[2] + g/2, mx , my, draw_maxs[2], 0, 1, 0);
-
- glColor3f (0,0,0);
-// glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
- glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
- glDisable (GL_DEPTH_TEST);
- glEnable (GL_BLEND);
- glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
-#if 0
- glColor4f (1,0,0,0.5);
- glBegin (GL_POLYGON);
-
- glVertex3f (0, 500, 0);
- glVertex3f (0, 900, 0);
- glVertex3f (0, 900, 100);
- glVertex3f (0, 500, 100);
-
- glEnd ();
-#endif
-
- glFlush ();
-
-}
-
-void Draw_SetRed (void)
-{
- if (!drawflag)
- return;
-
- glColor3f (1,0,0);
-}
-
-void Draw_SetGrey (void)
-{
- if (!drawflag)
- return;
-
- glColor3f (0.5,0.5,0.5);
-}
-
-void Draw_SetBlack (void)
-{
- if (!drawflag)
- return;
-
- glColor3f (0,0,0);
-}
-
-void DrawWinding (winding_t *w)
-{
- int i;
-
- if (!drawflag)
- return;
-
- glColor4f (0,0,0,0.5);
- glBegin (GL_LINE_LOOP);
- for (i=0 ; i<w->numpoints ; i++)
- glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
- glEnd ();
-
- glColor4f (0,1,0,0.3);
- glBegin (GL_POLYGON);
- for (i=0 ; i<w->numpoints ; i++)
- glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
- glEnd ();
-
- glFlush ();
-}
-
-void DrawAuxWinding (winding_t *w)
-{
- int i;
-
- if (!drawflag)
- return;
-
- glColor4f (0,0,0,0.5);
- glBegin (GL_LINE_LOOP);
- for (i=0 ; i<w->numpoints ; i++)
- glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
- glEnd ();
-
- glColor4f (1,0,0,0.3);
- glBegin (GL_POLYGON);
- for (i=0 ; i<w->numpoints ; i++)
- glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
- glEnd ();
-
- glFlush ();
-}
-
-//============================================================
-
-#define GLSERV_PORT 25001
-
-qboolean wins_init;
-int draw_socket;
-
-void GLS_BeginScene (void)
-{
- WSADATA winsockdata;
- WORD wVersionRequested;
- struct sockaddr_in address;
- int r;
-
- if (!wins_init)
- {
- wins_init = qtrue;
-
- wVersionRequested = MAKEWORD(1, 1);
-
- r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
-
- if (r)
- Error ("Winsock initialization failed.");
-
- }
-
- // connect a socket to the server
-
- draw_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (draw_socket == -1)
- Error ("draw_socket failed");
-
- address.sin_family = AF_INET;
- address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- address.sin_port = GLSERV_PORT;
- r = connect (draw_socket, (struct sockaddr *)&address, sizeof(address));
- if (r == -1)
- {
- closesocket (draw_socket);
- draw_socket = 0;
- }
-}
-
-void GLS_Winding (winding_t *w, int code)
-{
- byte buf[1024];
- int i, j;
-
- if (!draw_socket)
- return;
-
- ((int *)buf)[0] = w->numpoints;
- ((int *)buf)[1] = code;
- for (i=0 ; i<w->numpoints ; i++)
- for (j=0 ; j<3 ; j++)
- ((float *)buf)[2+i*3+j] = w->p[i][j];
-
- send (draw_socket, buf, w->numpoints*12+8, 0);
-}
-
-void GLS_EndScene (void)
-{
- closesocket (draw_socket);
- draw_socket = 0;
-}
+
+#include <windows.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <GL/glaux.h>
+
+#include "qbsp.h"
+
+// can't use the glvertex3fv functions, because the vec3_t fields
+// could be either floats or doubles, depending on DOUBLEVEC_T
+
+qboolean drawflag;
+vec3_t draw_mins, draw_maxs;
+
+
+#define WIN_SIZE 512
+
+void InitWindow (void)
+{
+ auxInitDisplayMode (AUX_SINGLE | AUX_RGB);
+ auxInitPosition (0, 0, WIN_SIZE, WIN_SIZE);
+ auxInitWindow ("qcsg");
+}
+
+void Draw_ClearWindow (void)
+{
+ static int init;
+ int w, h, g;
+ vec_t mx, my;
+
+ if (!drawflag)
+ return;
+
+ if (!init)
+ {
+ init = qtrue;
+ InitWindow ();
+ }
+
+ glClearColor (1,0.8,0.8,0);
+ glClear (GL_COLOR_BUFFER_BIT);
+
+ w = (draw_maxs[0] - draw_mins[0]);
+ h = (draw_maxs[1] - draw_mins[1]);
+
+ mx = draw_mins[0] + w/2;
+ my = draw_mins[1] + h/2;
+
+ g = w > h ? w : h;
+
+ glLoadIdentity ();
+ gluPerspective (90, 1, 2, 16384);
+ gluLookAt (mx, my, draw_maxs[2] + g/2, mx , my, draw_maxs[2], 0, 1, 0);
+
+ glColor3f (0,0,0);
+// glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+ glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+ glDisable (GL_DEPTH_TEST);
+ glEnable (GL_BLEND);
+ glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+#if 0
+ glColor4f (1,0,0,0.5);
+ glBegin (GL_POLYGON);
+
+ glVertex3f (0, 500, 0);
+ glVertex3f (0, 900, 0);
+ glVertex3f (0, 900, 100);
+ glVertex3f (0, 500, 100);
+
+ glEnd ();
+#endif
+
+ glFlush ();
+
+}
+
+void Draw_SetRed (void)
+{
+ if (!drawflag)
+ return;
+
+ glColor3f (1,0,0);
+}
+
+void Draw_SetGrey (void)
+{
+ if (!drawflag)
+ return;
+
+ glColor3f (0.5,0.5,0.5);
+}
+
+void Draw_SetBlack (void)
+{
+ if (!drawflag)
+ return;
+
+ glColor3f (0,0,0);
+}
+
+void DrawWinding (winding_t *w)
+{
+ int i;
+
+ if (!drawflag)
+ return;
+
+ glColor4f (0,0,0,0.5);
+ glBegin (GL_LINE_LOOP);
+ for (i=0 ; i<w->numpoints ; i++)
+ glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
+ glEnd ();
+
+ glColor4f (0,1,0,0.3);
+ glBegin (GL_POLYGON);
+ for (i=0 ; i<w->numpoints ; i++)
+ glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
+ glEnd ();
+
+ glFlush ();
+}
+
+void DrawAuxWinding (winding_t *w)
+{
+ int i;
+
+ if (!drawflag)
+ return;
+
+ glColor4f (0,0,0,0.5);
+ glBegin (GL_LINE_LOOP);
+ for (i=0 ; i<w->numpoints ; i++)
+ glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
+ glEnd ();
+
+ glColor4f (1,0,0,0.3);
+ glBegin (GL_POLYGON);
+ for (i=0 ; i<w->numpoints ; i++)
+ glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] );
+ glEnd ();
+
+ glFlush ();
+}
+
+//============================================================
+
+#define GLSERV_PORT 25001
+
+qboolean wins_init;
+int draw_socket;
+
+void GLS_BeginScene (void)
+{
+ WSADATA winsockdata;
+ WORD wVersionRequested;
+ struct sockaddr_in address;
+ int r;
+
+ if (!wins_init)
+ {
+ wins_init = qtrue;
+
+ wVersionRequested = MAKEWORD(1, 1);
+
+ r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
+
+ if (r)
+ Error ("Winsock initialization failed.");
+
+ }
+
+ // connect a socket to the server
+
+ draw_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (draw_socket == -1)
+ Error ("draw_socket failed");
+
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ address.sin_port = GLSERV_PORT;
+ r = connect (draw_socket, (struct sockaddr *)&address, sizeof(address));
+ if (r == -1)
+ {
+ closesocket (draw_socket);
+ draw_socket = 0;
+ }
+}
+
+void GLS_Winding (winding_t *w, int code)
+{
+ byte buf[1024];
+ int i, j;
+
+ if (!draw_socket)
+ return;
+
+ ((int *)buf)[0] = w->numpoints;
+ ((int *)buf)[1] = code;
+ for (i=0 ; i<w->numpoints ; i++)
+ for (j=0 ; j<3 ; j++)
+ ((float *)buf)[2+i*3+j] = w->p[i][j];
+
+ send (draw_socket, buf, w->numpoints*12+8, 0);
+}
+
+void GLS_EndScene (void)
+{
+ closesocket (draw_socket);
+ draw_socket = 0;
+}
diff --git a/q3map/glfile.c b/q3map/glfile.c
index 8bb10c6..b00df75 100755
--- a/q3map/glfile.c
+++ b/q3map/glfile.c
@@ -19,130 +19,130 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include "qbsp.h"
-
-int c_glfaces;
-
-int PortalVisibleSides (portal_t *p)
-{
- int fcon, bcon;
-
- if (!p->onnode)
- return 0; // outside
-
- fcon = p->nodes[0]->opaque;
- bcon = p->nodes[1]->opaque;
-
- // same contents never create a face
- if (fcon == bcon)
- return 0;
-
- if (!fcon)
- return 1;
- if (!bcon)
- return 2;
- return 0;
-}
-
-void OutputWinding (winding_t *w, FILE *glview)
-{
- static int level = 128;
- vec_t light;
- int i;
-
- fprintf (glview, "%i\n", w->numpoints);
- level+=28;
- light = (level&255)/255.0;
- for (i=0 ; i<w->numpoints ; i++)
- {
- fprintf (glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n",
- w->p[i][0],
- w->p[i][1],
- w->p[i][2],
- light,
- light,
- light);
- }
- fprintf (glview, "\n");
-}
-
-/*
-=============
-OutputPortal
-=============
-*/
-void OutputPortal (portal_t *p, FILE *glview)
-{
- winding_t *w;
- int sides;
-
- sides = PortalVisibleSides (p);
- if (!sides)
- return;
-
- c_glfaces++;
-
- w = p->winding;
-
- if (sides == 2) // back side
- w = ReverseWinding (w);
-
- OutputWinding (w, glview);
-
- if (sides == 2)
- FreeWinding(w);
-}
-
-/*
-=============
-WriteGLView_r
-=============
-*/
-void WriteGLView_r (node_t *node, FILE *glview)
-{
- portal_t *p, *nextp;
-
- if (node->planenum != PLANENUM_LEAF)
- {
- WriteGLView_r (node->children[0], glview);
- WriteGLView_r (node->children[1], glview);
- return;
- }
-
- // write all the portals
- for (p=node->portals ; p ; p=nextp)
- {
- if (p->nodes[0] == node)
- {
- OutputPortal (p, glview);
- nextp = p->next[0];
- }
- else
- nextp = p->next[1];
- }
-}
-
-/*
-=============
-WriteGLView
-=============
-*/
-void WriteGLView (tree_t *tree, char *source)
-{
- char name[1024];
- FILE *glview;
-
- c_glfaces = 0;
- sprintf (name, "%s%s.gl",outbase, source);
- _printf ("Writing %s\n", name);
-
- glview = fopen (name, "w");
- if (!glview)
- Error ("Couldn't open %s", name);
- WriteGLView_r (tree->headnode, glview);
- fclose (glview);
-
- _printf ("%5i c_glfaces\n", c_glfaces);
-}
-
+
+#include "qbsp.h"
+
+int c_glfaces;
+
+int PortalVisibleSides (portal_t *p)
+{
+ int fcon, bcon;
+
+ if (!p->onnode)
+ return 0; // outside
+
+ fcon = p->nodes[0]->opaque;
+ bcon = p->nodes[1]->opaque;
+
+ // same contents never create a face
+ if (fcon == bcon)
+ return 0;
+
+ if (!fcon)
+ return 1;
+ if (!bcon)
+ return 2;
+ return 0;
+}
+
+void OutputWinding (winding_t *w, FILE *glview)
+{
+ static int level = 128;
+ vec_t light;
+ int i;
+
+ fprintf (glview, "%i\n", w->numpoints);
+ level+=28;
+ light = (level&255)/255.0;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ fprintf (glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n",
+ w->p[i][0],
+ w->p[i][1],
+ w->p[i][2],
+ light,
+ light,
+ light);
+ }
+ fprintf (glview, "\n");
+}
+
+/*
+=============
+OutputPortal
+=============
+*/
+void OutputPortal (portal_t *p, FILE *glview)
+{
+ winding_t *w;
+ int sides;
+
+ sides = PortalVisibleSides (p);
+ if (!sides)
+ return;
+
+ c_glfaces++;
+
+ w = p->winding;
+
+ if (sides == 2) // back side
+ w = ReverseWinding (w);
+
+ OutputWinding (w, glview);
+
+ if (sides == 2)
+ FreeWinding(w);
+}
+
+/*
+=============
+WriteGLView_r
+=============
+*/
+void WriteGLView_r (node_t *node, FILE *glview)
+{
+ portal_t *p, *nextp;
+
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ WriteGLView_r (node->children[0], glview);
+ WriteGLView_r (node->children[1], glview);
+ return;
+ }
+
+ // write all the portals
+ for (p=node->portals ; p ; p=nextp)
+ {
+ if (p->nodes[0] == node)
+ {
+ OutputPortal (p, glview);
+ nextp = p->next[0];
+ }
+ else
+ nextp = p->next[1];
+ }
+}
+
+/*
+=============
+WriteGLView
+=============
+*/
+void WriteGLView (tree_t *tree, char *source)
+{
+ char name[1024];
+ FILE *glview;
+
+ c_glfaces = 0;
+ sprintf (name, "%s%s.gl",outbase, source);
+ _printf ("Writing %s\n", name);
+
+ glview = fopen (name, "w");
+ if (!glview)
+ Error ("Couldn't open %s", name);
+ WriteGLView_r (tree->headnode, glview);
+ fclose (glview);
+
+ _printf ("%5i c_glfaces\n", c_glfaces);
+}
+
diff --git a/q3map/leakfile.c b/q3map/leakfile.c
index 101e32d..683c22a 100755
--- a/q3map/leakfile.c
+++ b/q3map/leakfile.c
@@ -19,82 +19,82 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include "qbsp.h"
-
-/*
-==============================================================================
-
-LEAF FILE GENERATION
-
-Save out name.line for qe3 to read
-==============================================================================
-*/
-
-
-/*
-=============
-LeakFile
-
-Finds the shortest possible chain of portals
-that leads from the outside leaf to a specifically
-occupied leaf
-=============
-*/
-void LeakFile (tree_t *tree)
-{
- vec3_t mid;
- FILE *linefile;
- char filename[1024];
- node_t *node;
- int count;
-
- if (!tree->outside_node.occupied)
- return;
-
- qprintf ("--- LeakFile ---\n");
-
- //
- // write the points to the file
- //
- sprintf (filename, "%s.lin", source);
- linefile = fopen (filename, "w");
- if (!linefile)
- Error ("Couldn't open %s\n", filename);
-
- count = 0;
- node = &tree->outside_node;
- while (node->occupied > 1)
- {
- int next;
- portal_t *p, *nextportal;
- node_t *nextnode;
- int s;
-
- // find the best portal exit
- next = node->occupied;
- for (p=node->portals ; p ; p = p->next[!s])
- {
- s = (p->nodes[0] == node);
- if (p->nodes[s]->occupied
- && p->nodes[s]->occupied < next)
- {
- nextportal = p;
- nextnode = p->nodes[s];
- next = nextnode->occupied;
- }
- }
- node = nextnode;
- WindingCenter (nextportal->winding, mid);
- fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
- count++;
- }
- // add the occupant center
- GetVectorForKey (node->occupant, "origin", mid);
-
- fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
- qprintf ("%5i point linefile\n", count+1);
-
- fclose (linefile);
-}
-
+
+#include "qbsp.h"
+
+/*
+==============================================================================
+
+LEAF FILE GENERATION
+
+Save out name.line for qe3 to read
+==============================================================================
+*/
+
+
+/*
+=============
+LeakFile
+
+Finds the shortest possible chain of portals
+that leads from the outside leaf to a specifically
+occupied leaf
+=============
+*/
+void LeakFile (tree_t *tree)
+{
+ vec3_t mid;
+ FILE *linefile;
+ char filename[1024];
+ node_t *node;
+ int count;
+
+ if (!tree->outside_node.occupied)
+ return;
+
+ qprintf ("--- LeakFile ---\n");
+
+ //
+ // write the points to the file
+ //
+ sprintf (filename, "%s.lin", source);
+ linefile = fopen (filename, "w");
+ if (!linefile)
+ Error ("Couldn't open %s\n", filename);
+
+ count = 0;
+ node = &tree->outside_node;
+ while (node->occupied > 1)
+ {
+ int next;
+ portal_t *p, *nextportal;
+ node_t *nextnode;
+ int s;
+
+ // find the best portal exit
+ next = node->occupied;
+ for (p=node->portals ; p ; p = p->next[!s])
+ {
+ s = (p->nodes[0] == node);
+ if (p->nodes[s]->occupied
+ && p->nodes[s]->occupied < next)
+ {
+ nextportal = p;
+ nextnode = p->nodes[s];
+ next = nextnode->occupied;
+ }
+ }
+ node = nextnode;
+ WindingCenter (nextportal->winding, mid);
+ fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
+ count++;
+ }
+ // add the occupant center
+ GetVectorForKey (node->occupant, "origin", mid);
+
+ fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]);
+ qprintf ("%5i point linefile\n", count+1);
+
+ fclose (linefile);
+}
+
diff --git a/q3map/light.c b/q3map/light.c
index a3d368b..1563d58 100755
--- a/q3map/light.c
+++ b/q3map/light.c
@@ -19,2131 +19,2131 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-// light.c
-
-#include "light.h"
-#ifdef _WIN32
-#ifdef _TTIMOBUILD
-#include "pakstuff.h"
-#else
-#include "../libs/pakstuff.h"
-#endif
-#endif
-
-
-#define EXTRASCALE 2
-
-typedef struct {
- float plane[4];
- vec3_t origin;
- vec3_t vectors[2];
- shaderInfo_t *si;
-} filter_t;
-
-#define MAX_FILTERS 1024
-filter_t filters[MAX_FILTERS];
-int numFilters;
-
-extern char source[1024];
-
-qboolean notrace;
-qboolean patchshadows;
-qboolean dump;
-qboolean extra;
-qboolean extraWide;
-qboolean lightmapBorder;
-
-qboolean noSurfaces;
-
-int samplesize = 16; //sample size in units
-int novertexlighting = 0;
-int nogridlighting = 0;
-
-// for run time tweaking of all area sources in the level
-float areaScale = 0.25;
-
-// for run time tweaking of all point sources in the level
-float pointScale = 7500;
-
-qboolean exactPointToPolygon = qtrue;
-
-float formFactorValueScale = 3;
-
-float linearScale = 1.0 / 8000;
-
-light_t *lights;
-int numPointLights;
-int numAreaLights;
-
-FILE *dumpFile;
-
-int c_visible, c_occluded;
-
-//int defaultLightSubdivide = 128; // vary by surface size?
-int defaultLightSubdivide = 999; // vary by surface size?
-
-vec3_t ambientColor;
-
-vec3_t surfaceOrigin[ MAX_MAP_DRAW_SURFS ];
-int entitySurface[ MAX_MAP_DRAW_SURFS ];
-
-// 7,9,11 normalized to avoid being nearly coplanar with common faces
-//vec3_t sunDirection = { 0.441835, 0.56807, 0.694313 };
-//vec3_t sunDirection = { 0.45, 0, 0.9 };
-//vec3_t sunDirection = { 0, 0, 1 };
-
-// these are usually overrided by shader values
-vec3_t sunDirection = { 0.45, 0.3, 0.9 };
-vec3_t sunLight = { 100, 100, 50 };
-
-
-
-typedef struct {
- dbrush_t *b;
- vec3_t bounds[2];
-} skyBrush_t;
-
-int numSkyBrushes;
-skyBrush_t skyBrushes[MAX_MAP_BRUSHES];
-
-
-/*
-
-the corners of a patch mesh will always be exactly at lightmap samples.
-The dimensions of the lightmap will be equal to the average length of the control
-mesh in each dimension divided by 2.
-The lightmap sample points should correspond to the chosen subdivision points.
-
-*/
-
-/*
-===============================================================
-
-SURFACE LOADING
-
-===============================================================
-*/
-
-#define MAX_FACE_POINTS 128
-
-/*
-===============
-SubdivideAreaLight
-
-Subdivide area lights that are very large
-A light that is subdivided will never backsplash, avoiding weird pools of light near edges
-===============
-*/
-void SubdivideAreaLight( shaderInfo_t *ls, winding_t *w, vec3_t normal,
- float areaSubdivide, qboolean backsplash ) {
- float area, value, intensity;
- light_t *dl, *dl2;
- vec3_t mins, maxs;
- int axis;
- winding_t *front, *back;
- vec3_t planeNormal;
- float planeDist;
-
- if ( !w ) {
- return;
- }
-
- WindingBounds( w, mins, maxs );
-
- // check for subdivision
- for ( axis = 0 ; axis < 3 ; axis++ ) {
- if ( maxs[axis] - mins[axis] > areaSubdivide ) {
- VectorClear( planeNormal );
- planeNormal[axis] = 1;
- planeDist = ( maxs[axis] + mins[axis] ) * 0.5;
- ClipWindingEpsilon ( w, planeNormal, planeDist, ON_EPSILON, &front, &back );
- SubdivideAreaLight( ls, front, normal, areaSubdivide, qfalse );
- SubdivideAreaLight( ls, back, normal, areaSubdivide, qfalse );
- FreeWinding( w );
- return;
- }
- }
-
- // create a light from this
- area = WindingArea (w);
- if ( area <= 0 || area > 20000000 ) {
- return;
- }
-
- numAreaLights++;
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
- dl->next = lights;
- lights = dl;
- dl->type = emit_area;
-
- WindingCenter( w, dl->origin );
- dl->w = w;
- VectorCopy ( normal, dl->normal);
- dl->dist = DotProduct( dl->origin, normal );
-
- value = ls->value;
- intensity = value * area * areaScale;
- VectorAdd( dl->origin, dl->normal, dl->origin );
-
- VectorCopy( ls->color, dl->color );
-
- dl->photons = intensity;
-
- // emitColor is irrespective of the area
- VectorScale( ls->color, value*formFactorValueScale*areaScale, dl->emitColor );
-
- dl->si = ls;
-
- if ( ls->contents & CONTENTS_FOG ) {
- dl->twosided = qtrue;
- }
-
- // optionally create a point backsplash light
- if ( backsplash && ls->backsplashFraction > 0 ) {
- dl2 = malloc(sizeof(*dl));
- memset (dl2, 0, sizeof(*dl2));
- dl2->next = lights;
- lights = dl2;
- dl2->type = emit_point;
-
- VectorMA( dl->origin, ls->backsplashDistance, normal, dl2->origin );
-
- VectorCopy( ls->color, dl2->color );
-
- dl2->photons = dl->photons * ls->backsplashFraction;
- dl2->si = ls;
- }
-}
-
-
-/*
-===============
-CountLightmaps
-===============
-*/
-void CountLightmaps( void ) {
- int count;
- int i;
- dsurface_t *ds;
-
- qprintf ("--- CountLightmaps ---\n");
- count = 0;
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- // see if this surface is light emiting
- ds = &drawSurfaces[i];
- if ( ds->lightmapNum > count ) {
- count = ds->lightmapNum;
- }
- }
-
- count++;
- numLightBytes = count * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3;
- if ( numLightBytes > MAX_MAP_LIGHTING ) {
- Error("MAX_MAP_LIGHTING exceeded");
- }
-
- qprintf( "%5i drawSurfaces\n", numDrawSurfaces );
- qprintf( "%5i lightmaps\n", count );
-}
-
-/*
-===============
-CreateSurfaceLights
-
-This creates area lights
-===============
-*/
-void CreateSurfaceLights( void ) {
- int i, j, side;
- dsurface_t *ds;
- shaderInfo_t *ls;
- winding_t *w;
- cFacet_t *f;
- light_t *dl;
- vec3_t origin;
- drawVert_t *dv;
- int c_lightSurfaces;
- float lightSubdivide;
- vec3_t normal;
-
- qprintf ("--- CreateSurfaceLights ---\n");
- c_lightSurfaces = 0;
-
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- // see if this surface is light emiting
- ds = &drawSurfaces[i];
-
- ls = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
- if ( ls->value == 0 ) {
- continue;
- }
-
- // determine how much we need to chop up the surface
- if ( ls->lightSubdivide ) {
- lightSubdivide = ls->lightSubdivide;
- } else {
- lightSubdivide = defaultLightSubdivide;
- }
-
- c_lightSurfaces++;
-
- // an autosprite shader will become
- // a point light instead of an area light
- if ( ls->autosprite ) {
- // autosprite geometry should only have four vertexes
- if ( surfaceTest[i] ) {
- // curve or misc_model
- f = surfaceTest[i]->facets;
- if ( surfaceTest[i]->numFacets != 1 || f->numBoundaries != 4 ) {
- _printf( "WARNING: surface at (%i %i %i) has autosprite shader but isn't a quad\n",
- (int)f->points[0], (int)f->points[1], (int)f->points[2] );
- }
- VectorAdd( f->points[0], f->points[1], origin );
- VectorAdd( f->points[2], origin, origin );
- VectorAdd( f->points[3], origin, origin );
- VectorScale( origin, 0.25, origin );
- } else {
- // normal polygon
- dv = &drawVerts[ ds->firstVert ];
- if ( ds->numVerts != 4 ) {
- _printf( "WARNING: surface at (%i %i %i) has autosprite shader but %i verts\n",
- (int)dv->xyz[0], (int)dv->xyz[1], (int)dv->xyz[2] );
- continue;
- }
-
- VectorAdd( dv[0].xyz, dv[1].xyz, origin );
- VectorAdd( dv[2].xyz, origin, origin );
- VectorAdd( dv[3].xyz, origin, origin );
- VectorScale( origin, 0.25, origin );
- }
-
-
- numPointLights++;
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
- dl->next = lights;
- lights = dl;
-
- VectorCopy( origin, dl->origin );
- VectorCopy( ls->color, dl->color );
- dl->photons = ls->value * pointScale;
- dl->type = emit_point;
- continue;
- }
-
- // possibly create for both sides of the polygon
- for ( side = 0 ; side <= ls->twoSided ; side++ ) {
- // create area lights
- if ( surfaceTest[i] ) {
- // curve or misc_model
- for ( j = 0 ; j < surfaceTest[i]->numFacets ; j++ ) {
- f = surfaceTest[i]->facets + j;
- w = AllocWinding( f->numBoundaries );
- w->numpoints = f->numBoundaries;
- memcpy( w->p, f->points, f->numBoundaries * 12 );
-
- VectorCopy( f->surface, normal );
- if ( side ) {
- winding_t *t;
-
- t = w;
- w = ReverseWinding( t );
- FreeWinding( t );
- VectorSubtract( vec3_origin, normal, normal );
- }
- SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
- }
- } else {
- // normal polygon
-
- w = AllocWinding( ds->numVerts );
- w->numpoints = ds->numVerts;
- for ( j = 0 ; j < ds->numVerts ; j++ ) {
- VectorCopy( drawVerts[ds->firstVert+j].xyz, w->p[j] );
- }
- VectorCopy( ds->lightmapVecs[2], normal );
- if ( side ) {
- winding_t *t;
-
- t = w;
- w = ReverseWinding( t );
- FreeWinding( t );
- VectorSubtract( vec3_origin, normal, normal );
- }
- SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
- }
- }
- }
-
- _printf( "%5i light emitting surfaces\n", c_lightSurfaces );
-}
-
-
-
-/*
-================
-FindSkyBrushes
-================
-*/
-void FindSkyBrushes( void ) {
- int i, j;
- dbrush_t *b;
- skyBrush_t *sb;
- shaderInfo_t *si;
- dbrushside_t *s;
-
- // find the brushes
- for ( i = 0 ; i < numbrushes ; i++ ) {
- b = &dbrushes[i];
- for ( j = 0 ; j < b->numSides ; j++ ) {
- s = &dbrushsides[ b->firstSide + j ];
- if ( dshaders[ s->shaderNum ].surfaceFlags & SURF_SKY ) {
- sb = &skyBrushes[ numSkyBrushes ];
- sb->b = b;
- sb->bounds[0][0] = -dplanes[ dbrushsides[ b->firstSide + 0 ].planeNum ].dist - 1;
- sb->bounds[1][0] = dplanes[ dbrushsides[ b->firstSide + 1 ].planeNum ].dist + 1;
- sb->bounds[0][1] = -dplanes[ dbrushsides[ b->firstSide + 2 ].planeNum ].dist - 1;
- sb->bounds[1][1] = dplanes[ dbrushsides[ b->firstSide + 3 ].planeNum ].dist + 1;
- sb->bounds[0][2] = -dplanes[ dbrushsides[ b->firstSide + 4 ].planeNum ].dist - 1;
- sb->bounds[1][2] = dplanes[ dbrushsides[ b->firstSide + 5 ].planeNum ].dist + 1;
- numSkyBrushes++;
- break;
- }
- }
- }
-
- // default
- VectorNormalize( sunDirection, sunDirection );
-
- // find the sky shader
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- si = ShaderInfoForShader( dshaders[ drawSurfaces[i].shaderNum ].shader );
- if ( si->surfaceFlags & SURF_SKY ) {
- VectorCopy( si->sunLight, sunLight );
- VectorCopy( si->sunDirection, sunDirection );
- break;
- }
- }
-}
-
-/*
-=================================================================
-
- LIGHT SETUP
-
-=================================================================
-*/
-
-/*
-==================
-FindTargetEntity
-==================
-*/
-entity_t *FindTargetEntity( const char *target ) {
- int i;
- const char *n;
-
- for ( i = 0 ; i < num_entities ; i++ ) {
- n = ValueForKey (&entities[i], "targetname");
- if ( !strcmp (n, target) ) {
- return &entities[i];
- }
- }
-
- return NULL;
-}
-
-
-
-/*
-=============
-CreateEntityLights
-=============
-*/
-void CreateEntityLights (void)
-{
- int i;
- light_t *dl;
- entity_t *e, *e2;
- const char *name;
- const char *target;
- vec3_t dest;
- const char *_color;
- float intensity;
- int spawnflags;
-
- //
- // entities
- //
- for ( i = 0 ; i < num_entities ; i++ ) {
- e = &entities[i];
- name = ValueForKey (e, "classname");
- if (strncmp (name, "light", 5))
- continue;
-
- numPointLights++;
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
- dl->next = lights;
- lights = dl;
-
- spawnflags = FloatForKey (e, "spawnflags");
- if ( spawnflags & 1 ) {
- dl->linearLight = qtrue;
- }
-
- GetVectorForKey (e, "origin", dl->origin);
- dl->style = FloatForKey (e, "_style");
- if (!dl->style)
- dl->style = FloatForKey (e, "style");
- if (dl->style < 0)
- dl->style = 0;
-
- intensity = FloatForKey (e, "light");
- if (!intensity)
- intensity = FloatForKey (e, "_light");
- if (!intensity)
- intensity = 300;
- _color = ValueForKey (e, "_color");
- if (_color && _color[0])
- {
- sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);
- ColorNormalize (dl->color, dl->color);
- }
- else
- dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
-
- intensity = intensity * pointScale;
- dl->photons = intensity;
-
- dl->type = emit_point;
-
- // lights with a target will be spotlights
- target = ValueForKey (e, "target");
-
- if ( target[0] ) {
- float radius;
- float dist;
-
- e2 = FindTargetEntity (target);
- if (!e2) {
- _printf ("WARNING: light at (%i %i %i) has missing target\n",
- (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]);
- } else {
- GetVectorForKey (e2, "origin", dest);
- VectorSubtract (dest, dl->origin, dl->normal);
- dist = VectorNormalize (dl->normal, dl->normal);
- radius = FloatForKey (e, "radius");
- if ( !radius ) {
- radius = 64;
- }
- if ( !dist ) {
- dist = 64;
- }
- dl->radiusByDist = (radius + 16) / dist;
- dl->type = emit_spotlight;
- }
- }
- }
-}
-
-//=================================================================
-
-/*
-================
-SetEntityOrigins
-
-Find the offset values for inline models
-================
-*/
-void SetEntityOrigins( void ) {
- int i, j;
- entity_t *e;
- vec3_t origin;
- const char *key;
- int modelnum;
- dmodel_t *dm;
-
- for ( i=0 ; i < num_entities ; i++ ) {
- e = &entities[i];
- key = ValueForKey (e, "model");
- if ( key[0] != '*' ) {
- continue;
- }
- modelnum = atoi( key + 1 );
- dm = &dmodels[ modelnum ];
-
- // set entity surface to true for all surfaces for this model
- for ( j = 0 ; j < dm->numSurfaces ; j++ ) {
- entitySurface[ dm->firstSurface + j ] = qtrue;
- }
-
- key = ValueForKey (e, "origin");
- if ( !key[0] ) {
- continue;
- }
- GetVectorForKey ( e, "origin", origin );
-
- // set origin for all surfaces for this model
- for ( j = 0 ; j < dm->numSurfaces ; j++ ) {
- VectorCopy( origin, surfaceOrigin[ dm->firstSurface + j ] );
- }
- }
-}
-
-
-/*
-=================================================================
-
-
-=================================================================
-*/
-
-#define MAX_POINTS_ON_WINDINGS 64
-
-/*
-================
-PointToPolygonFormFactor
-================
-*/
-float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w ) {
- vec3_t triVector, triNormal;
- int i, j;
- vec3_t dirs[MAX_POINTS_ON_WINDING];
- float total;
- float dot, angle, facing;
-
- for ( i = 0 ; i < w->numpoints ; i++ ) {
- VectorSubtract( w->p[i], point, dirs[i] );
- VectorNormalize( dirs[i], dirs[i] );
- }
-
- // duplicate first vertex to avoid mod operation
- VectorCopy( dirs[0], dirs[i] );
-
- total = 0;
- for ( i = 0 ; i < w->numpoints ; i++ ) {
- j = i+1;
- dot = DotProduct( dirs[i], dirs[j] );
-
- // roundoff can cause slight creep, which gives an IND from acos
- if ( dot > 1.0 ) {
- dot = 1.0;
- } else if ( dot < -1.0 ) {
- dot = -1.0;
- }
-
- angle = acos( dot );
- CrossProduct( dirs[i], dirs[j], triVector );
- if ( VectorNormalize( triVector, triNormal ) < 0.0001 ) {
- continue;
- }
- facing = DotProduct( normal, triNormal );
- total += facing * angle;
-
- if ( total > 6.3 || total < -6.3 ) {
- static qboolean printed;
-
- if ( !printed ) {
- printed = qtrue;
- _printf( "WARNING: bad PointToPolygonFormFactor: %f at %1.1f %1.1f %1.1f from %1.1f %1.1f %1.1f\n", total,
- w->p[i][0], w->p[i][1], w->p[i][2], point[0], point[1], point[2]);
- }
- return 0;
- }
-
- }
-
- total /= 2*3.141592657; // now in the range of 0 to 1 over the entire incoming hemisphere
-
- return total;
-}
-
-
-/*
-================
-FilterTrace
-
-Returns 0 to 1.0 filter fractions for the given trace
-================
-*/
-void FilterTrace( const vec3_t start, const vec3_t end, vec3_t filter ) {
- float d1, d2;
- filter_t *f;
- int filterNum;
- vec3_t point;
- float frac;
- int i;
- float s, t;
- int u, v;
- int x, y;
- byte *pixel;
- float radius;
- float len;
- vec3_t total;
-
- filter[0] = 1.0;
- filter[1] = 1.0;
- filter[2] = 1.0;
-
- for ( filterNum = 0 ; filterNum < numFilters ; filterNum++ ) {
- f = &filters[ filterNum ];
-
- // see if the plane is crossed
- d1 = DotProduct( start, f->plane ) - f->plane[3];
- d2 = DotProduct( end, f->plane ) - f->plane[3];
-
- if ( ( d1 < 0 ) == ( d2 < 0 ) ) {
- continue;
- }
-
- // calculate the crossing point
- frac = d1 / ( d1 - d2 );
-
- for ( i = 0 ; i < 3 ; i++ ) {
- point[i] = start[i] + frac * ( end[i] - start[i] );
- }
-
- VectorSubtract( point, f->origin, point );
-
- s = DotProduct( point, f->vectors[0] );
- t = 1.0 - DotProduct( point, f->vectors[1] );
- if ( s < 0 || s >= 1.0 || t < 0 || t >= 1.0 ) {
- continue;
- }
-
- // decide the filter size
- radius = 10 * frac;
- len = VectorLength( f->vectors[0] );
- if ( !len ) {
- continue;
- }
- radius = radius * len * f->si->width;
-
- // look up the filter, taking multiple samples
- VectorClear( total );
- for ( u = -1 ; u <= 1 ; u++ ) {
- for ( v = -1 ; v <=1 ; v++ ) {
- x = s * f->si->width + u * radius;
- if ( x < 0 ) {
- x = 0;
- }
- if ( x >= f->si->width ) {
- x = f->si->width - 1;
- }
- y = t * f->si->height + v * radius;
- if ( y < 0 ) {
- y = 0;
- }
- if ( y >= f->si->height ) {
- y = f->si->height - 1;
- }
-
- pixel = f->si->pixels + ( y * f->si->width + x ) * 4;
- total[0] += pixel[0];
- total[1] += pixel[1];
- total[2] += pixel[2];
- }
- }
-
- filter[0] *= total[0]/(255.0*9);
- filter[1] *= total[1]/(255.0*9);
- filter[2] *= total[2]/(255.0*9);
- }
-
-}
-
-/*
-================
-SunToPoint
-
-Returns an amount of light to add at the point
-================
-*/
-int c_sunHit, c_sunMiss;
-void SunToPoint( const vec3_t origin, traceWork_t *tw, vec3_t addLight ) {
- int i;
- trace_t trace;
- skyBrush_t *b;
- vec3_t end;
-
- if ( !numSkyBrushes ) {
- VectorClear( addLight );
- return;
- }
-
- VectorMA( origin, MAX_WORLD_COORD * 2, sunDirection, end );
-
- TraceLine( origin, end, &trace, qtrue, tw );
-
- // see if trace.hit is inside a sky brush
- for ( i = 0 ; i < numSkyBrushes ; i++) {
- b = &skyBrushes[ i ];
-
- // this assumes that sky brushes are axial...
- if ( trace.hit[0] < b->bounds[0][0]
- || trace.hit[0] > b->bounds[1][0]
- || trace.hit[1] < b->bounds[0][1]
- || trace.hit[1] > b->bounds[1][1]
- || trace.hit[2] < b->bounds[0][2]
- || trace.hit[2] > b->bounds[1][2] ) {
- continue;
- }
-
-
- // trace again to get intermediate filters
- TraceLine( origin, trace.hit, &trace, qtrue, tw );
-
- // we hit the sky, so add sunlight
- if ( numthreads == 1 ) {
- c_sunHit++;
- }
- addLight[0] = trace.filter[0] * sunLight[0];
- addLight[1] = trace.filter[1] * sunLight[1];
- addLight[2] = trace.filter[2] * sunLight[2];
-
- return;
- }
-
- if ( numthreads == 1 ) {
- c_sunMiss++;
- }
-
- VectorClear( addLight );
-}
-
-/*
-================
-SunToPlane
-================
-*/
-void SunToPlane( const vec3_t origin, const vec3_t normal, vec3_t color, traceWork_t *tw ) {
- float angle;
- vec3_t sunColor;
-
- if ( !numSkyBrushes ) {
- return;
- }
-
- angle = DotProduct( normal, sunDirection );
- if ( angle <= 0 ) {
- return; // facing away
- }
-
- SunToPoint( origin, tw, sunColor );
- VectorMA( color, angle, sunColor, color );
-}
-
-/*
-================
-LightingAtSample
-================
-*/
-void LightingAtSample( vec3_t origin, vec3_t normal, vec3_t color,
- qboolean testOcclusion, qboolean forceSunLight, traceWork_t *tw ) {
- light_t *light;
- trace_t trace;
- float angle;
- float add;
- float dist;
- vec3_t dir;
-
- VectorCopy( ambientColor, color );
-
- // trace to all the lights
- for ( light = lights ; light ; light = light->next ) {
-
- //MrE: if the light is behind the surface
- if ( DotProduct(light->origin, normal) - DotProduct(normal, origin) < 0 )
- continue;
- // testing exact PTPFF
- if ( exactPointToPolygon && light->type == emit_area ) {
- float factor;
- float d;
- vec3_t pushedOrigin;
-
- // see if the point is behind the light
- d = DotProduct( origin, light->normal ) - light->dist;
- if ( !light->twosided ) {
- if ( d < -1 ) {
- continue; // point is behind light
- }
- }
-
- // test occlusion and find light filters
- // clip the line, tracing from the surface towards the light
- if ( !notrace && testOcclusion ) {
- TraceLine( origin, light->origin, &trace, qfalse, tw );
-
- // other light rays must not hit anything
- if ( trace.passSolid ) {
- continue;
- }
- } else {
- trace.filter[0] = 1.0;
- trace.filter[1] = 1.0;
- trace.filter[2] = 1.0;
- }
-
- // nudge the point so that it is clearly forward of the light
- // so that surfaces meeting a light emiter don't get black edges
- if ( d > -8 && d < 8 ) {
- VectorMA( origin, (8-d), light->normal, pushedOrigin );
- } else {
- VectorCopy( origin, pushedOrigin );
- }
-
- // calculate the contribution
- factor = PointToPolygonFormFactor( pushedOrigin, normal, light->w );
- if ( factor <= 0 ) {
- if ( light->twosided ) {
- factor = -factor;
- } else {
- continue;
- }
- }
- color[0] += factor * light->emitColor[0] * trace.filter[0];
- color[1] += factor * light->emitColor[1] * trace.filter[1];
- color[2] += factor * light->emitColor[2] * trace.filter[2];
-
- continue;
- }
-
- // calculate the amount of light at this sample
- if ( light->type == emit_point ) {
- VectorSubtract( light->origin, origin, dir );
- dist = VectorNormalize( dir, dir );
- // clamp the distance to prevent super hot spots
- if ( dist < 16 ) {
- dist = 16;
- }
- angle = DotProduct( normal, dir );
- if ( light->linearLight ) {
- add = angle * light->photons * linearScale - dist;
- if ( add < 0 ) {
- add = 0;
- }
- } else {
- add = light->photons / ( dist * dist ) * angle;
- }
- } else if ( light->type == emit_spotlight ) {
- float distByNormal;
- vec3_t pointAtDist;
- float radiusAtDist;
- float sampleRadius;
- vec3_t distToSample;
- float coneScale;
-
- VectorSubtract( light->origin, origin, dir );
-
- distByNormal = -DotProduct( dir, light->normal );
- if ( distByNormal < 0 ) {
- continue;
- }
- VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
- radiusAtDist = light->radiusByDist * distByNormal;
-
- VectorSubtract( origin, pointAtDist, distToSample );
- sampleRadius = VectorLength( distToSample );
-
- if ( sampleRadius >= radiusAtDist ) {
- continue; // outside the cone
- }
- if ( sampleRadius <= radiusAtDist - 32 ) {
- coneScale = 1.0; // fully inside
- } else {
- coneScale = ( radiusAtDist - sampleRadius ) / 32.0;
- }
-
- dist = VectorNormalize( dir, dir );
- // clamp the distance to prevent super hot spots
- if ( dist < 16 ) {
- dist = 16;
- }
- angle = DotProduct( normal, dir );
- add = light->photons / ( dist * dist ) * angle * coneScale;
-
- } else if ( light->type == emit_area ) {
- VectorSubtract( light->origin, origin, dir );
- dist = VectorNormalize( dir, dir );
- // clamp the distance to prevent super hot spots
- if ( dist < 16 ) {
- dist = 16;
- }
- angle = DotProduct( normal, dir );
- if ( angle <= 0 ) {
- continue;
- }
- angle *= -DotProduct( light->normal, dir );
- if ( angle <= 0 ) {
- continue;
- }
-
- if ( light->linearLight ) {
- add = angle * light->photons * linearScale - dist;
- if ( add < 0 ) {
- add = 0;
- }
- } else {
- add = light->photons / ( dist * dist ) * angle;
- }
- }
-
- if ( add <= 1.0 ) {
- continue;
- }
-
- // clip the line, tracing from the surface towards the light
- if ( !notrace && testOcclusion ) {
- TraceLine( origin, light->origin, &trace, qfalse, tw );
-
- // other light rays must not hit anything
- if ( trace.passSolid ) {
- continue;
- }
- } else {
- trace.filter[0] = 1;
- trace.filter[1] = 1;
- trace.filter[2] = 1;
- }
-
- // add the result
- color[0] += add * light->color[0] * trace.filter[0];
- color[1] += add * light->color[1] * trace.filter[1];
- color[2] += add * light->color[2] * trace.filter[2];
- }
-
- //
- // trace directly to the sun
- //
- if ( testOcclusion || forceSunLight ) {
- SunToPlane( origin, normal, color, tw );
- }
-}
-
-/*
-=============
-PrintOccluded
-
-For debugging
-=============
-*/
-void PrintOccluded( byte occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE],
- int width, int height ) {
- int i, j;
-
- _printf( "\n" );
-
- for ( i = 0 ; i < height ; i++ ) {
- for ( j = 0 ; j < width ; j++ ) {
- _printf("%i", (int)occluded[j][i] );
- }
- _printf( "\n" );
- }
-}
-
-
-/*
-=============
-VertexLighting
-
-Vertex lighting will completely ignore occlusion, because
-shadows would not be resolvable anyway.
-=============
-*/
-void VertexLighting( dsurface_t *ds, qboolean testOcclusion, qboolean forceSunLight, float scale, traceWork_t *tw ) {
- int i, j;
- drawVert_t *dv;
- vec3_t sample, normal;
- float max;
-
- VectorCopy( ds->lightmapVecs[2], normal );
-
- // generate vertex lighting
- for ( i = 0 ; i < ds->numVerts ; i++ ) {
- dv = &drawVerts[ ds->firstVert + i ];
-
- if ( ds->patchWidth ) {
- LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw );
- }
- else if (ds->surfaceType == MST_TRIANGLE_SOUP) {
- LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw );
- }
- else {
- LightingAtSample( dv->xyz, normal, sample, testOcclusion, forceSunLight, tw );
- }
-
- if (scale >= 0)
- VectorScale(sample, scale, sample);
- // clamp with color normalization
- max = sample[0];
- if ( sample[1] > max ) {
- max = sample[1];
- }
- if ( sample[2] > max ) {
- max = sample[2];
- }
- if ( max > 255 ) {
- VectorScale( sample, 255/max, sample );
- }
-
- // save the sample
- for ( j = 0 ; j < 3 ; j++ ) {
- if ( sample[j] > 255 ) {
- sample[j] = 255;
- }
- dv->color[j] = sample[j];
- }
-
- // Don't bother writing alpha since it will already be set to 255,
- // plus we don't want to write over alpha generated by SetTerrainTextures
- //dv->color[3] = 255;
- }
-}
-
-
-/*
-=================
-LinearSubdivideMesh
-
-For extra lighting, just midpoint one of the axis.
-The edges are clamped at the original edges.
-=================
-*/
-mesh_t *LinearSubdivideMesh( mesh_t *in ) {
- int i, j;
- mesh_t *out;
- drawVert_t *v1, *v2, *vout;
-
- out = malloc( sizeof( *out ) );
-
- out->width = in->width * 2;
- out->height = in->height;
- out->verts = malloc( out->width * out->height * sizeof(*out->verts) );
- for ( j = 0 ; j < in->height ; j++ ) {
- out->verts[ j * out->width + 0 ] = in->verts[ j * in->width + 0 ];
- out->verts[ j * out->width + out->width - 1 ] = in->verts[ j * in->width + in->width - 1 ];
- for ( i = 1 ; i < out->width - 1 ; i+= 2 ) {
- v1 = in->verts + j * in->width + (i >> 1);
- v2 = v1 + 1;
- vout = out->verts + j * out->width + i;
-
- vout->xyz[0] = 0.75 * v1->xyz[0] + 0.25 * v2->xyz[0];
- vout->xyz[1] = 0.75 * v1->xyz[1] + 0.25 * v2->xyz[1];
- vout->xyz[2] = 0.75 * v1->xyz[2] + 0.25 * v2->xyz[2];
-
- vout->normal[0] = 0.75 * v1->normal[0] + 0.25 * v2->normal[0];
- vout->normal[1] = 0.75 * v1->normal[1] + 0.25 * v2->normal[1];
- vout->normal[2] = 0.75 * v1->normal[2] + 0.25 * v2->normal[2];
-
- VectorNormalize( vout->normal, vout->normal );
-
- vout++;
-
- vout->xyz[0] = 0.25 * v1->xyz[0] + 0.75 * v2->xyz[0];
- vout->xyz[1] = 0.25 * v1->xyz[1] + 0.75 * v2->xyz[1];
- vout->xyz[2] = 0.25 * v1->xyz[2] + 0.75 * v2->xyz[2];
-
- vout->normal[0] = 0.25 * v1->normal[0] + 0.75 * v2->normal[0];
- vout->normal[1] = 0.25 * v1->normal[1] + 0.75 * v2->normal[1];
- vout->normal[2] = 0.25 * v1->normal[2] + 0.75 * v2->normal[2];
-
- VectorNormalize( vout->normal, vout->normal );
-
- }
- }
-
- FreeMesh( in );
-
- return out;
-}
-
-/*
-==============
-ColorToBytes
-==============
-*/
-void ColorToBytes( const float *color, byte *colorBytes ) {
- float max;
- vec3_t sample;
-
- VectorCopy( color, sample );
-
- // clamp with color normalization
- max = sample[0];
- if ( sample[1] > max ) {
- max = sample[1];
- }
- if ( sample[2] > max ) {
- max = sample[2];
- }
- if ( max > 255 ) {
- VectorScale( sample, 255/max, sample );
- }
- colorBytes[ 0 ] = sample[0];
- colorBytes[ 1 ] = sample[1];
- colorBytes[ 2 ] = sample[2];
-}
-
-
-
-/*
-=============
-TraceLtm
-=============
-*/
-void TraceLtm( int num ) {
- dsurface_t *ds;
- int i, j, k;
- int x, y;
- int position, numPositions;
- vec3_t base, origin, normal;
- byte occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE];
- vec3_t color[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE];
- traceWork_t tw;
- vec3_t average;
- int count;
- mesh_t srcMesh, *mesh, *subdivided;
- shaderInfo_t *si;
- static float nudge[2][9] = {
- { 0, -1, 0, 1, -1, 1, -1, 0, 1 },
- { 0, -1, -1, -1, 0, 0, 1, 1, 1 }
- };
- int sampleWidth, sampleHeight, ssize;
- vec3_t lightmapOrigin, lightmapVecs[2];
- int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_WIDTH];
-
- ds = &drawSurfaces[num];
- si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
-
- // vertex-lit triangle model
- if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
- VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw );
- return;
- }
-
- if ( ds->lightmapNum == -1 ) {
- return; // doesn't need lighting at all
- }
-
- if (!novertexlighting) {
- // calculate the vertex lighting for gouraud shade mode
- VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw );
- }
-
- if ( ds->lightmapNum < 0 ) {
- return; // doesn't need lightmap lighting
- }
-
- si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
- ssize = samplesize;
- if (si->lightmapSampleSize)
- ssize = si->lightmapSampleSize;
-
- if (si->patchShadows)
- tw.patchshadows = qtrue;
- else
- tw.patchshadows = patchshadows;
-
- if ( ds->surfaceType == MST_PATCH ) {
- srcMesh.width = ds->patchWidth;
- srcMesh.height = ds->patchHeight;
- srcMesh.verts = drawVerts + ds->firstVert;
- mesh = SubdivideMesh( srcMesh, 8, 999 );
- PutMeshOnCurve( *mesh );
- MakeMeshNormals( *mesh );
-
- subdivided = RemoveLinearMeshColumnsRows( mesh );
- FreeMesh(mesh);
-
- mesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_WIDTH, widthtable, heighttable);
- if ( mesh->width != ds->lightmapWidth || mesh->height != ds->lightmapHeight ) {
- Error( "Mesh lightmap miscount");
- }
-
- if ( extra ) {
- mesh_t *mp;
-
- // chop it up for more light samples (leaking memory...)
- mp = mesh;//CopyMesh( mesh );
- mp = LinearSubdivideMesh( mp );
- mp = TransposeMesh( mp );
- mp = LinearSubdivideMesh( mp );
- mp = TransposeMesh( mp );
-
- mesh = mp;
- }
- } else {
- VectorCopy( ds->lightmapVecs[2], normal );
-
- if ( !extra ) {
- VectorCopy( ds->lightmapOrigin, lightmapOrigin );
- VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] );
- VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] );
- } else {
- // sample at a closer spacing for antialiasing
- VectorCopy( ds->lightmapOrigin, lightmapOrigin );
- VectorScale( ds->lightmapVecs[0], 0.5, lightmapVecs[0] );
- VectorScale( ds->lightmapVecs[1], 0.5, lightmapVecs[1] );
- VectorMA( lightmapOrigin, -0.5, lightmapVecs[0], lightmapOrigin );
- VectorMA( lightmapOrigin, -0.5, lightmapVecs[1], lightmapOrigin );
- }
- }
-
- if ( extra ) {
- sampleWidth = ds->lightmapWidth * 2;
- sampleHeight = ds->lightmapHeight * 2;
- } else {
- sampleWidth = ds->lightmapWidth;
- sampleHeight = ds->lightmapHeight;
- }
-
- memset ( color, 0, sizeof( color ) );
-
- // determine which samples are occluded
- memset ( occluded, 0, sizeof( occluded ) );
- for ( i = 0 ; i < sampleWidth ; i++ ) {
- for ( j = 0 ; j < sampleHeight ; j++ ) {
-
- if ( ds->patchWidth ) {
- numPositions = 9;
- VectorCopy( mesh->verts[j*mesh->width+i].normal, normal );
- // VectorNormalize( normal, normal );
- // push off of the curve a bit
- VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base );
-
- MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] );
- } else {
- numPositions = 9;
- for ( k = 0 ; k < 3 ; k++ ) {
- base[k] = lightmapOrigin[k] + normal[k]
- + i * lightmapVecs[0][k]
- + j * lightmapVecs[1][k];
- }
- }
- VectorAdd( base, surfaceOrigin[ num ], base );
-
- // we may need to slightly nudge the sample point
- // if directly on a wall
- for ( position = 0 ; position < numPositions ; position++ ) {
- // calculate lightmap sample position
- for ( k = 0 ; k < 3 ; k++ ) {
- origin[k] = base[k] +
- + ( nudge[0][position]/16 ) * lightmapVecs[0][k]
- + ( nudge[1][position]/16 ) * lightmapVecs[1][k];
- }
-
- if ( notrace ) {
- break;
- }
- if ( !PointInSolid( origin ) ) {
- break;
- }
- }
-
- // if none of the nudges worked, this sample is occluded
- if ( position == numPositions ) {
- occluded[i][j] = qtrue;
- if ( numthreads == 1 ) {
- c_occluded++;
- }
- continue;
- }
-
- if ( numthreads == 1 ) {
- c_visible++;
- }
- occluded[i][j] = qfalse;
- LightingAtSample( origin, normal, color[i][j], qtrue, qfalse, &tw );
- }
- }
-
- if ( dump ) {
- PrintOccluded( occluded, sampleWidth, sampleHeight );
- }
-
- // calculate average values for occluded samples
- for ( i = 0 ; i < sampleWidth ; i++ ) {
- for ( j = 0 ; j < sampleHeight ; j++ ) {
- if ( !occluded[i][j] ) {
- continue;
- }
- // scan all surrounding samples
- count = 0;
- VectorClear( average );
- for ( x = -1 ; x <= 1; x++ ) {
- for ( y = -1 ; y <= 1 ; y++ ) {
- if ( i + x < 0 || i + x >= sampleWidth ) {
- continue;
- }
- if ( j + y < 0 || j + y >= sampleHeight ) {
- continue;
- }
- if ( occluded[i+x][j+y] ) {
- continue;
- }
- count++;
- VectorAdd( color[i+x][j+y], average, average );
- }
- }
- if ( count ) {
- VectorScale( average, 1.0/count, color[i][j] );
- }
- }
- }
-
- // average together the values if we are extra sampling
- if ( ds->lightmapWidth != sampleWidth ) {
- for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
- for ( j = 0 ; j < ds->lightmapHeight ; j++ ) {
- for ( k = 0 ; k < 3 ; k++ ) {
- float value, coverage;
-
- value = color[i*2][j*2][k] + color[i*2][j*2+1][k] +
- color[i*2+1][j*2][k] + color[i*2+1][j*2+1][k];
- coverage = 4;
- if ( extraWide ) {
- // wider than box filter
- if ( i > 0 ) {
- value += color[i*2-1][j*2][k] + color[i*2-1][j*2+1][k];
- value += color[i*2-2][j*2][k] + color[i*2-2][j*2+1][k];
- coverage += 4;
- }
- if ( i < ds->lightmapWidth - 1 ) {
- value += color[i*2+2][j*2][k] + color[i*2+2][j*2+1][k];
- value += color[i*2+3][j*2][k] + color[i*2+3][j*2+1][k];
- coverage += 4;
- }
- if ( j > 0 ) {
- value += color[i*2][j*2-1][k] + color[i*2+1][j*2-1][k];
- value += color[i*2][j*2-2][k] + color[i*2+1][j*2-2][k];
- coverage += 4;
- }
- if ( j < ds->lightmapHeight - 1 ) {
- value += color[i*2][j*2+2][k] + color[i*2+1][j*2+2][k];
- value += color[i*2][j*2+3][k] + color[i*2+1][j*2+3][k];
- coverage += 2;
- }
- }
-
- color[i][j][k] = value / coverage;
- }
- }
- }
- }
-
- // optionally create a debugging border around the lightmap
- if ( lightmapBorder ) {
- for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
- color[i][0][0] = 255;
- color[i][0][1] = 0;
- color[i][0][2] = 0;
-
- color[i][ds->lightmapHeight-1][0] = 255;
- color[i][ds->lightmapHeight-1][1] = 0;
- color[i][ds->lightmapHeight-1][2] = 0;
- }
- for ( i = 0 ; i < ds->lightmapHeight ; i++ ) {
- color[0][i][0] = 255;
- color[0][i][1] = 0;
- color[0][i][2] = 0;
-
- color[ds->lightmapWidth-1][i][0] = 255;
- color[ds->lightmapWidth-1][i][1] = 0;
- color[ds->lightmapWidth-1][i][2] = 0;
- }
- }
-
- // clamp the colors to bytes and store off
- for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
- for ( j = 0 ; j < ds->lightmapHeight ; j++ ) {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j)
- * LIGHTMAP_WIDTH + ds->lightmapX + i;
-
- ColorToBytes( color[i][j], lightBytes + k*3 );
- }
- }
-
- if (ds->surfaceType == MST_PATCH)
- {
- FreeMesh(mesh);
- }
-}
-
-
-//=============================================================================
-
-vec3_t gridMins;
-vec3_t gridSize = { 64, 64, 128 };
-int gridBounds[3];
-
-
-/*
-========================
-LightContributionToPoint
-========================
-*/
-qboolean LightContributionToPoint( const light_t *light, const vec3_t origin,
- vec3_t color, traceWork_t *tw ) {
- trace_t trace;
- float add;
-
- add = 0;
-
- VectorClear( color );
-
- // testing exact PTPFF
- if ( exactPointToPolygon && light->type == emit_area ) {
- float factor;
- float d;
- vec3_t normal;
-
- // see if the point is behind the light
- d = DotProduct( origin, light->normal ) - light->dist;
- if ( !light->twosided ) {
- if ( d < 1 ) {
- return qfalse; // point is behind light
- }
- }
-
- // test occlusion
- // clip the line, tracing from the surface towards the light
- TraceLine( origin, light->origin, &trace, qfalse, tw );
- if ( trace.passSolid ) {
- return qfalse;
- }
-
- // calculate the contribution
- VectorSubtract( light->origin, origin, normal );
- if ( VectorNormalize( normal, normal ) == 0 ) {
- return qfalse;
- }
- factor = PointToPolygonFormFactor( origin, normal, light->w );
- if ( factor <= 0 ) {
- if ( light->twosided ) {
- factor = -factor;
- } else {
- return qfalse;
- }
- }
- VectorScale( light->emitColor, factor, color );
- return qtrue;
- }
-
- // calculate the amount of light at this sample
- if ( light->type == emit_point || light->type == emit_spotlight ) {
- vec3_t dir;
- float dist;
-
- VectorSubtract( light->origin, origin, dir );
- dist = VectorLength( dir );
- // clamp the distance to prevent super hot spots
- if ( dist < 16 ) {
- dist = 16;
- }
- if ( light->linearLight ) {
- add = light->photons * linearScale - dist;
- if ( add < 0 ) {
- add = 0;
- }
- } else {
- add = light->photons / ( dist * dist );
- }
- } else {
- return qfalse;
- }
-
- if ( add <= 1.0 ) {
- return qfalse;
- }
-
- // clip the line, tracing from the surface towards the light
- TraceLine( origin, light->origin, &trace, qfalse, tw );
-
- // other light rays must not hit anything
- if ( trace.passSolid ) {
- return qfalse;
- }
-
- // add the result
- color[0] = add * light->color[0];
- color[1] = add * light->color[1];
- color[2] = add * light->color[2];
-
- return qtrue;
-}
-
-typedef struct {
- vec3_t dir;
- vec3_t color;
-} contribution_t;
-
-/*
-=============
-TraceGrid
-
-Grid samples are foe quickly determining the lighting
-of dynamically placed entities in the world
-=============
-*/
-#define MAX_CONTRIBUTIONS 1024
-void TraceGrid( int num ) {
- int x, y, z;
- vec3_t origin;
- light_t *light;
- vec3_t color;
- int mod;
- vec3_t directedColor;
- vec3_t summedDir;
- contribution_t contributions[MAX_CONTRIBUTIONS];
- int numCon;
- int i;
- traceWork_t tw;
- float addSize;
-
- mod = num;
- z = mod / ( gridBounds[0] * gridBounds[1] );
- mod -= z * ( gridBounds[0] * gridBounds[1] );
-
- y = mod / gridBounds[0];
- mod -= y * gridBounds[0];
-
- x = mod;
-
- origin[0] = gridMins[0] + x * gridSize[0];
- origin[1] = gridMins[1] + y * gridSize[1];
- origin[2] = gridMins[2] + z * gridSize[2];
-
- if ( PointInSolid( origin ) ) {
- vec3_t baseOrigin;
- int step;
-
- VectorCopy( origin, baseOrigin );
-
- // try to nudge the origin around to find a valid point
- for ( step = 9 ; step <= 18 ; step += 9 ) {
- for ( i = 0 ; i < 8 ; i++ ) {
- VectorCopy( baseOrigin, origin );
- if ( i & 1 ) {
- origin[0] += step;
- } else {
- origin[0] -= step;
- }
- if ( i & 2 ) {
- origin[1] += step;
- } else {
- origin[1] -= step;
- }
- if ( i & 4 ) {
- origin[2] += step;
- } else {
- origin[2] -= step;
- }
-
- if ( !PointInSolid( origin ) ) {
- break;
- }
- }
- if ( i != 8 ) {
- break;
- }
- }
- if ( step > 18 ) {
- // can't find a valid point at all
- for ( i = 0 ; i < 8 ; i++ ) {
- gridData[ num*8 + i ] = 0;
- }
- return;
- }
- }
-
- VectorClear( summedDir );
-
- // trace to all the lights
-
- // find the major light direction, and divide the
- // total light between that along the direction and
- // the remaining in the ambient
- numCon = 0;
- for ( light = lights ; light ; light = light->next ) {
- vec3_t add;
- vec3_t dir;
- float addSize;
-
- if ( !LightContributionToPoint( light, origin, add, &tw ) ) {
- continue;
- }
-
- VectorSubtract( light->origin, origin, dir );
- VectorNormalize( dir, dir );
-
- VectorCopy( add, contributions[numCon].color );
- VectorCopy( dir, contributions[numCon].dir );
- numCon++;
-
- addSize = VectorLength( add );
- VectorMA( summedDir, addSize, dir, summedDir );
-
- if ( numCon == MAX_CONTRIBUTIONS-1 ) {
- break;
- }
- }
-
- //
- // trace directly to the sun
- //
- SunToPoint( origin, &tw, color );
- addSize = VectorLength( color );
- if ( addSize > 0 ) {
- VectorCopy( color, contributions[numCon].color );
- VectorCopy( sunDirection, contributions[numCon].dir );
- VectorMA( summedDir, addSize, sunDirection, summedDir );
- numCon++;
- }
-
-
- // now that we have identified the primary light direction,
- // go back and seperate all the light into directed and ambient
- VectorNormalize( summedDir, summedDir );
- VectorCopy( ambientColor, color );
- VectorClear( directedColor );
-
- for ( i = 0 ; i < numCon ; i++ ) {
- float d;
-
- d = DotProduct( contributions[i].dir, summedDir );
- if ( d < 0 ) {
- d = 0;
- }
-
- VectorMA( directedColor, d, contributions[i].color, directedColor );
-
- // the ambient light will be at 1/4 the value of directed light
- d = 0.25 * ( 1.0 - d );
- VectorMA( color, d, contributions[i].color, color );
- }
-
- // now do some fudging to keep the ambient from being too low
- VectorMA( color, 0.25, directedColor, color );
-
- //
- // save the resulting value out
- //
- ColorToBytes( color, gridData + num*8 );
- ColorToBytes( directedColor, gridData + num*8 + 3 );
-
- VectorNormalize( summedDir, summedDir );
- NormalToLatLong( summedDir, gridData + num*8 + 6);
-}
-
-
-/*
-=============
-SetupGrid
-=============
-*/
-void SetupGrid( void ) {
- int i;
- vec3_t maxs;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- gridMins[i] = gridSize[i] * ceil( dmodels[0].mins[i] / gridSize[i] );
- maxs[i] = gridSize[i] * floor( dmodels[0].maxs[i] / gridSize[i] );
- gridBounds[i] = (maxs[i] - gridMins[i])/gridSize[i] + 1;
- }
-
- numGridPoints = gridBounds[0] * gridBounds[1] * gridBounds[2];
- if (numGridPoints * 8 >= MAX_MAP_LIGHTGRID)
- Error("MAX_MAP_LIGHTGRID");
- qprintf( "%5i gridPoints\n", numGridPoints );
-}
-
-//=============================================================================
-
-/*
-=============
-RemoveLightsInSolid
-=============
-*/
-void RemoveLightsInSolid(void)
-{
- light_t *light, *prev;
- int numsolid = 0;
-
- prev = NULL;
- for ( light = lights ; light ; ) {
- if (PointInSolid(light->origin))
- {
- if (prev) prev->next = light->next;
- else lights = light->next;
- if (light->w)
- FreeWinding(light->w);
- free(light);
- numsolid++;
- if (prev)
- light = prev->next;
- else
- light = lights;
- }
- else
- {
- prev = light;
- light = light->next;
- }
- }
- _printf (" %7i lights in solid\n", numsolid);
-}
-
-/*
-=============
-LightWorld
-=============
-*/
-void LightWorld (void) {
- float f;
-
- // determine the number of grid points
- SetupGrid();
-
- // find the optional world ambient
- GetVectorForKey( &entities[0], "_color", ambientColor );
- f = FloatForKey( &entities[0], "ambient" );
- VectorScale( ambientColor, f, ambientColor );
-
- // create lights out of patches and lights
- qprintf ("--- CreateLights ---\n");
- CreateEntityLights ();
- qprintf ("%i point lights\n", numPointLights);
- qprintf ("%i area lights\n", numAreaLights);
-
- if (!nogridlighting) {
- qprintf ("--- TraceGrid ---\n");
- RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid );
- qprintf( "%i x %i x %i = %i grid\n", gridBounds[0], gridBounds[1],
- gridBounds[2], numGridPoints);
- }
-
- qprintf ("--- TraceLtm ---\n");
- RunThreadsOnIndividual( numDrawSurfaces, qtrue, TraceLtm );
- qprintf( "%5i visible samples\n", c_visible );
- qprintf( "%5i occluded samples\n", c_occluded );
-}
-
-/*
-========
-CreateFilters
-
-EXPERIMENTAL, UNUSED
-
-Look for transparent light filter surfaces.
-
-This will only work for flat 3*3 patches that exactly hold one copy of the texture.
-========
-*/
-#define PLANAR_PATCH_EPSILON 0.1
-void CreateFilters( void ) {
- int i;
- filter_t *f;
- dsurface_t *ds;
- shaderInfo_t *si;
- drawVert_t *v1, *v2, *v3;
- vec3_t d1, d2;
- int vertNum;
-
- numFilters = 0;
-
- return;
-
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- ds = &drawSurfaces[i];
- if ( !ds->patchWidth ) {
- continue;
- }
- si = ShaderInfoForShader( dshaders[ ds->shaderNum ].shader );
-/*
- if ( !(si->surfaceFlags & SURF_LIGHTFILTER) ) {
- continue;
- }
-*/
-
- // we have a filter patch
- v1 = &drawVerts[ ds->firstVert ];
-
- if ( ds->patchWidth != 3 || ds->patchHeight != 3 ) {
- _printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't a 3 by 3\n",
- v1->xyz[0], v1->xyz[1], v1->xyz[2] );
- continue;
- }
-
- if ( numFilters == MAX_FILTERS ) {
- Error( "MAX_FILTERS" );
- }
- f = &filters[ numFilters ];
- numFilters++;
-
- v2 = &drawVerts[ ds->firstVert + 2 ];
- v3 = &drawVerts[ ds->firstVert + 6 ];
-
- VectorSubtract( v2->xyz, v1->xyz, d1 );
- VectorSubtract( v3->xyz, v1->xyz, d2 );
- VectorNormalize( d1, d1 );
- VectorNormalize( d2, d2 );
- CrossProduct( d1, d2, f->plane );
- f->plane[3] = DotProduct( v1->xyz, f->plane );
-
- // make sure all the control points are on the plane
- for ( vertNum = 0 ; vertNum < ds->numVerts ; vertNum++ ) {
- float d;
-
- d = DotProduct( drawVerts[ ds->firstVert + vertNum ].xyz, f->plane ) - f->plane[3];
- if ( fabs( d ) > PLANAR_PATCH_EPSILON ) {
- break;
- }
- }
- if ( vertNum != ds->numVerts ) {
- numFilters--;
- _printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't flat\n",
- v1->xyz[0], v1->xyz[1], v1->xyz[2] );
- continue;
- }
- }
-
- f = &filters[0];
- numFilters = 1;
-
- f->plane[0] = 1;
- f->plane[1] = 0;
- f->plane[2] = 0;
- f->plane[3] = 448;
-
- f->origin[0] = 448;
- f->origin[1] = 192;
- f->origin[2] = 0;
-
- f->vectors[0][0] = 0;
- f->vectors[0][1] = -1.0 / 128;
- f->vectors[0][2] = 0;
-
- f->vectors[1][0] = 0;
- f->vectors[1][1] = 0;
- f->vectors[1][2] = 1.0 / 128;
-
- f->si = ShaderInfoForShader( "textures/hell/blocks11ct" );
-}
-
-/*
-=============
-VertexLightingThread
-=============
-*/
-void VertexLightingThread(int num) {
- dsurface_t *ds;
- traceWork_t tw;
- shaderInfo_t *si;
-
- ds = &drawSurfaces[num];
-
- // vertex-lit triangle model
- if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
- return;
- }
-
- if (novertexlighting)
- return;
-
- if ( ds->lightmapNum == -1 ) {
- return; // doesn't need lighting at all
- }
-
- si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
-
- // calculate the vertex lighting for gouraud shade mode
- VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw );
-}
-
-/*
-=============
-TriSoupLightingThread
-=============
-*/
-void TriSoupLightingThread(int num) {
- dsurface_t *ds;
- traceWork_t tw;
- shaderInfo_t *si;
-
- ds = &drawSurfaces[num];
- si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
-
- // vertex-lit triangle model
- if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
- VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw );
- }
-}
-
-/*
-=============
-GridAndVertexLighting
-=============
-*/
-void GridAndVertexLighting(void) {
- SetupGrid();
-
- FindSkyBrushes();
- CreateFilters();
- InitTrace();
- CreateEntityLights ();
- CreateSurfaceLights();
-
- if (!nogridlighting) {
- _printf ("--- TraceGrid ---\n");
- RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid );
- }
-
- if (!novertexlighting) {
- _printf ("--- Vertex Lighting ---\n");
- RunThreadsOnIndividual( numDrawSurfaces, qtrue, VertexLightingThread );
- }
-
- _printf("--- Model Lighting ---\n");
- RunThreadsOnIndividual( numDrawSurfaces, qtrue, TriSoupLightingThread );
-}
-
-/*
-========
-LightMain
-
-========
-*/
-int LightMain (int argc, char **argv) {
- int i;
- double start, end;
- const char *value;
-
- _printf ("----- Lighting ----\n");
-
- verbose = qfalse;
-
- for (i=1 ; i<argc ; i++) {
- if (!strcmp(argv[i],"-tempname"))
- {
- i++;
- } else if (!strcmp(argv[i],"-v")) {
- verbose = qtrue;
- } else if (!strcmp(argv[i],"-threads")) {
- numthreads = atoi (argv[i+1]);
- i++;
- } else if (!strcmp(argv[i],"-area")) {
- areaScale *= atof(argv[i+1]);
- _printf ("area light scaling at %f\n", areaScale);
- i++;
- } else if (!strcmp(argv[i],"-point")) {
- pointScale *= atof(argv[i+1]);
- _printf ("point light scaling at %f\n", pointScale);
- i++;
- } else if (!strcmp(argv[i],"-notrace")) {
- notrace = qtrue;
- _printf ("No occlusion tracing\n");
- } else if (!strcmp(argv[i],"-patchshadows")) {
- patchshadows = qtrue;
- _printf ("Patch shadow casting enabled\n");
- } else if (!strcmp(argv[i],"-extra")) {
- extra = qtrue;
- _printf ("Extra detail tracing\n");
- } else if (!strcmp(argv[i],"-extrawide")) {
- extra = qtrue;
- extraWide = qtrue;
- _printf ("Extra wide detail tracing\n");
- } else if (!strcmp(argv[i], "-samplesize")) {
- samplesize = atoi(argv[i+1]);
- if (samplesize < 1) samplesize = 1;
- i++;
- _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize);
- } else if (!strcmp(argv[i], "-novertex")) {
- novertexlighting = qtrue;
- _printf("no vertex lighting = true\n");
- } else if (!strcmp(argv[i], "-nogrid")) {
- nogridlighting = qtrue;
- _printf("no grid lighting = true\n");
- } else if (!strcmp(argv[i],"-border")) {
- lightmapBorder = qtrue;
- _printf ("Adding debug border to lightmaps\n");
- } else if (!strcmp(argv[i],"-nosurf")) {
- noSurfaces = qtrue;
- _printf ("Not tracing against surfaces\n" );
- } else if (!strcmp(argv[i],"-dump")) {
- dump = qtrue;
- _printf ("Dumping occlusion maps\n");
- } else {
- break;
- }
- }
-
- ThreadSetDefault ();
-
- if (i != argc - 1) {
- _printf("usage: q3map -light [-<switch> [-<switch> ...]] <mapname>\n"
- "\n"
- "Switches:\n"
- " v = verbose output\n"
- " threads <X> = set number of threads to X\n"
- " area <V> = set the area light scale to V\n"
- " point <W> = set the point light scale to W\n"
- " notrace = don't cast any shadows\n"
- " extra = enable super sampling for anti-aliasing\n"
- " extrawide = same as extra but smoothen more\n"
- " nogrid = don't calculate light grid for dynamic model lighting\n"
- " novertex = don't calculate vertex lighting\n"
- " samplesize <N> = set the lightmap pixel size to NxN units\n");
- exit(0);
- }
-
- start = I_FloatTime ();
-
- SetQdirFromPath (argv[i]);
-
-#ifdef _WIN32
- InitPakFile(gamedir, NULL);
-#endif
-
- strcpy (source, ExpandArg(argv[i]));
- StripExtension (source);
- DefaultExtension (source, ".bsp");
-
- LoadShaderInfo();
-
- _printf ("reading %s\n", source);
-
- LoadBSPFile (source);
-
- FindSkyBrushes();
-
- ParseEntities();
-
- value = ValueForKey( &entities[0], "gridsize" );
- if (strlen(value)) {
- sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] );
- _printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]);
- }
-
- CreateFilters();
-
- InitTrace();
-
- SetEntityOrigins();
-
- CountLightmaps();
-
- CreateSurfaceLights();
-
- LightWorld();
-
- _printf ("writing %s\n", source);
- WriteBSPFile (source);
-
- end = I_FloatTime ();
- _printf ("%5.0f seconds elapsed\n", end-start);
-
- return 0;
-}
-
+// light.c
+
+#include "light.h"
+#ifdef _WIN32
+#ifdef _TTIMOBUILD
+#include "pakstuff.h"
+#else
+#include "../libs/pakstuff.h"
+#endif
+#endif
+
+
+#define EXTRASCALE 2
+
+typedef struct {
+ float plane[4];
+ vec3_t origin;
+ vec3_t vectors[2];
+ shaderInfo_t *si;
+} filter_t;
+
+#define MAX_FILTERS 1024
+filter_t filters[MAX_FILTERS];
+int numFilters;
+
+extern char source[1024];
+
+qboolean notrace;
+qboolean patchshadows;
+qboolean dump;
+qboolean extra;
+qboolean extraWide;
+qboolean lightmapBorder;
+
+qboolean noSurfaces;
+
+int samplesize = 16; //sample size in units
+int novertexlighting = 0;
+int nogridlighting = 0;
+
+// for run time tweaking of all area sources in the level
+float areaScale = 0.25;
+
+// for run time tweaking of all point sources in the level
+float pointScale = 7500;
+
+qboolean exactPointToPolygon = qtrue;
+
+float formFactorValueScale = 3;
+
+float linearScale = 1.0 / 8000;
+
+light_t *lights;
+int numPointLights;
+int numAreaLights;
+
+FILE *dumpFile;
+
+int c_visible, c_occluded;
+
+//int defaultLightSubdivide = 128; // vary by surface size?
+int defaultLightSubdivide = 999; // vary by surface size?
+
+vec3_t ambientColor;
+
+vec3_t surfaceOrigin[ MAX_MAP_DRAW_SURFS ];
+int entitySurface[ MAX_MAP_DRAW_SURFS ];
+
+// 7,9,11 normalized to avoid being nearly coplanar with common faces
+//vec3_t sunDirection = { 0.441835, 0.56807, 0.694313 };
+//vec3_t sunDirection = { 0.45, 0, 0.9 };
+//vec3_t sunDirection = { 0, 0, 1 };
+
+// these are usually overrided by shader values
+vec3_t sunDirection = { 0.45, 0.3, 0.9 };
+vec3_t sunLight = { 100, 100, 50 };
+
+
+
+typedef struct {
+ dbrush_t *b;
+ vec3_t bounds[2];
+} skyBrush_t;
+
+int numSkyBrushes;
+skyBrush_t skyBrushes[MAX_MAP_BRUSHES];
+
+
+/*
+
+the corners of a patch mesh will always be exactly at lightmap samples.
+The dimensions of the lightmap will be equal to the average length of the control
+mesh in each dimension divided by 2.
+The lightmap sample points should correspond to the chosen subdivision points.
+
+*/
+
+/*
+===============================================================
+
+SURFACE LOADING
+
+===============================================================
+*/
+
+#define MAX_FACE_POINTS 128
+
+/*
+===============
+SubdivideAreaLight
+
+Subdivide area lights that are very large
+A light that is subdivided will never backsplash, avoiding weird pools of light near edges
+===============
+*/
+void SubdivideAreaLight( shaderInfo_t *ls, winding_t *w, vec3_t normal,
+ float areaSubdivide, qboolean backsplash ) {
+ float area, value, intensity;
+ light_t *dl, *dl2;
+ vec3_t mins, maxs;
+ int axis;
+ winding_t *front, *back;
+ vec3_t planeNormal;
+ float planeDist;
+
+ if ( !w ) {
+ return;
+ }
+
+ WindingBounds( w, mins, maxs );
+
+ // check for subdivision
+ for ( axis = 0 ; axis < 3 ; axis++ ) {
+ if ( maxs[axis] - mins[axis] > areaSubdivide ) {
+ VectorClear( planeNormal );
+ planeNormal[axis] = 1;
+ planeDist = ( maxs[axis] + mins[axis] ) * 0.5;
+ ClipWindingEpsilon ( w, planeNormal, planeDist, ON_EPSILON, &front, &back );
+ SubdivideAreaLight( ls, front, normal, areaSubdivide, qfalse );
+ SubdivideAreaLight( ls, back, normal, areaSubdivide, qfalse );
+ FreeWinding( w );
+ return;
+ }
+ }
+
+ // create a light from this
+ area = WindingArea (w);
+ if ( area <= 0 || area > 20000000 ) {
+ return;
+ }
+
+ numAreaLights++;
+ dl = malloc(sizeof(*dl));
+ memset (dl, 0, sizeof(*dl));
+ dl->next = lights;
+ lights = dl;
+ dl->type = emit_area;
+
+ WindingCenter( w, dl->origin );
+ dl->w = w;
+ VectorCopy ( normal, dl->normal);
+ dl->dist = DotProduct( dl->origin, normal );
+
+ value = ls->value;
+ intensity = value * area * areaScale;
+ VectorAdd( dl->origin, dl->normal, dl->origin );
+
+ VectorCopy( ls->color, dl->color );
+
+ dl->photons = intensity;
+
+ // emitColor is irrespective of the area
+ VectorScale( ls->color, value*formFactorValueScale*areaScale, dl->emitColor );
+
+ dl->si = ls;
+
+ if ( ls->contents & CONTENTS_FOG ) {
+ dl->twosided = qtrue;
+ }
+
+ // optionally create a point backsplash light
+ if ( backsplash && ls->backsplashFraction > 0 ) {
+ dl2 = malloc(sizeof(*dl));
+ memset (dl2, 0, sizeof(*dl2));
+ dl2->next = lights;
+ lights = dl2;
+ dl2->type = emit_point;
+
+ VectorMA( dl->origin, ls->backsplashDistance, normal, dl2->origin );
+
+ VectorCopy( ls->color, dl2->color );
+
+ dl2->photons = dl->photons * ls->backsplashFraction;
+ dl2->si = ls;
+ }
+}
+
+
+/*
+===============
+CountLightmaps
+===============
+*/
+void CountLightmaps( void ) {
+ int count;
+ int i;
+ dsurface_t *ds;
+
+ qprintf ("--- CountLightmaps ---\n");
+ count = 0;
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ // see if this surface is light emiting
+ ds = &drawSurfaces[i];
+ if ( ds->lightmapNum > count ) {
+ count = ds->lightmapNum;
+ }
+ }
+
+ count++;
+ numLightBytes = count * LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3;
+ if ( numLightBytes > MAX_MAP_LIGHTING ) {
+ Error("MAX_MAP_LIGHTING exceeded");
+ }
+
+ qprintf( "%5i drawSurfaces\n", numDrawSurfaces );
+ qprintf( "%5i lightmaps\n", count );
+}
+
+/*
+===============
+CreateSurfaceLights
+
+This creates area lights
+===============
+*/
+void CreateSurfaceLights( void ) {
+ int i, j, side;
+ dsurface_t *ds;
+ shaderInfo_t *ls;
+ winding_t *w;
+ cFacet_t *f;
+ light_t *dl;
+ vec3_t origin;
+ drawVert_t *dv;
+ int c_lightSurfaces;
+ float lightSubdivide;
+ vec3_t normal;
+
+ qprintf ("--- CreateSurfaceLights ---\n");
+ c_lightSurfaces = 0;
+
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ // see if this surface is light emiting
+ ds = &drawSurfaces[i];
+
+ ls = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
+ if ( ls->value == 0 ) {
+ continue;
+ }
+
+ // determine how much we need to chop up the surface
+ if ( ls->lightSubdivide ) {
+ lightSubdivide = ls->lightSubdivide;
+ } else {
+ lightSubdivide = defaultLightSubdivide;
+ }
+
+ c_lightSurfaces++;
+
+ // an autosprite shader will become
+ // a point light instead of an area light
+ if ( ls->autosprite ) {
+ // autosprite geometry should only have four vertexes
+ if ( surfaceTest[i] ) {
+ // curve or misc_model
+ f = surfaceTest[i]->facets;
+ if ( surfaceTest[i]->numFacets != 1 || f->numBoundaries != 4 ) {
+ _printf( "WARNING: surface at (%i %i %i) has autosprite shader but isn't a quad\n",
+ (int)f->points[0], (int)f->points[1], (int)f->points[2] );
+ }
+ VectorAdd( f->points[0], f->points[1], origin );
+ VectorAdd( f->points[2], origin, origin );
+ VectorAdd( f->points[3], origin, origin );
+ VectorScale( origin, 0.25, origin );
+ } else {
+ // normal polygon
+ dv = &drawVerts[ ds->firstVert ];
+ if ( ds->numVerts != 4 ) {
+ _printf( "WARNING: surface at (%i %i %i) has autosprite shader but %i verts\n",
+ (int)dv->xyz[0], (int)dv->xyz[1], (int)dv->xyz[2] );
+ continue;
+ }
+
+ VectorAdd( dv[0].xyz, dv[1].xyz, origin );
+ VectorAdd( dv[2].xyz, origin, origin );
+ VectorAdd( dv[3].xyz, origin, origin );
+ VectorScale( origin, 0.25, origin );
+ }
+
+
+ numPointLights++;
+ dl = malloc(sizeof(*dl));
+ memset (dl, 0, sizeof(*dl));
+ dl->next = lights;
+ lights = dl;
+
+ VectorCopy( origin, dl->origin );
+ VectorCopy( ls->color, dl->color );
+ dl->photons = ls->value * pointScale;
+ dl->type = emit_point;
+ continue;
+ }
+
+ // possibly create for both sides of the polygon
+ for ( side = 0 ; side <= ls->twoSided ; side++ ) {
+ // create area lights
+ if ( surfaceTest[i] ) {
+ // curve or misc_model
+ for ( j = 0 ; j < surfaceTest[i]->numFacets ; j++ ) {
+ f = surfaceTest[i]->facets + j;
+ w = AllocWinding( f->numBoundaries );
+ w->numpoints = f->numBoundaries;
+ memcpy( w->p, f->points, f->numBoundaries * 12 );
+
+ VectorCopy( f->surface, normal );
+ if ( side ) {
+ winding_t *t;
+
+ t = w;
+ w = ReverseWinding( t );
+ FreeWinding( t );
+ VectorSubtract( vec3_origin, normal, normal );
+ }
+ SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
+ }
+ } else {
+ // normal polygon
+
+ w = AllocWinding( ds->numVerts );
+ w->numpoints = ds->numVerts;
+ for ( j = 0 ; j < ds->numVerts ; j++ ) {
+ VectorCopy( drawVerts[ds->firstVert+j].xyz, w->p[j] );
+ }
+ VectorCopy( ds->lightmapVecs[2], normal );
+ if ( side ) {
+ winding_t *t;
+
+ t = w;
+ w = ReverseWinding( t );
+ FreeWinding( t );
+ VectorSubtract( vec3_origin, normal, normal );
+ }
+ SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
+ }
+ }
+ }
+
+ _printf( "%5i light emitting surfaces\n", c_lightSurfaces );
+}
+
+
+
+/*
+================
+FindSkyBrushes
+================
+*/
+void FindSkyBrushes( void ) {
+ int i, j;
+ dbrush_t *b;
+ skyBrush_t *sb;
+ shaderInfo_t *si;
+ dbrushside_t *s;
+
+ // find the brushes
+ for ( i = 0 ; i < numbrushes ; i++ ) {
+ b = &dbrushes[i];
+ for ( j = 0 ; j < b->numSides ; j++ ) {
+ s = &dbrushsides[ b->firstSide + j ];
+ if ( dshaders[ s->shaderNum ].surfaceFlags & SURF_SKY ) {
+ sb = &skyBrushes[ numSkyBrushes ];
+ sb->b = b;
+ sb->bounds[0][0] = -dplanes[ dbrushsides[ b->firstSide + 0 ].planeNum ].dist - 1;
+ sb->bounds[1][0] = dplanes[ dbrushsides[ b->firstSide + 1 ].planeNum ].dist + 1;
+ sb->bounds[0][1] = -dplanes[ dbrushsides[ b->firstSide + 2 ].planeNum ].dist - 1;
+ sb->bounds[1][1] = dplanes[ dbrushsides[ b->firstSide + 3 ].planeNum ].dist + 1;
+ sb->bounds[0][2] = -dplanes[ dbrushsides[ b->firstSide + 4 ].planeNum ].dist - 1;
+ sb->bounds[1][2] = dplanes[ dbrushsides[ b->firstSide + 5 ].planeNum ].dist + 1;
+ numSkyBrushes++;
+ break;
+ }
+ }
+ }
+
+ // default
+ VectorNormalize( sunDirection, sunDirection );
+
+ // find the sky shader
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ si = ShaderInfoForShader( dshaders[ drawSurfaces[i].shaderNum ].shader );
+ if ( si->surfaceFlags & SURF_SKY ) {
+ VectorCopy( si->sunLight, sunLight );
+ VectorCopy( si->sunDirection, sunDirection );
+ break;
+ }
+ }
+}
+
+/*
+=================================================================
+
+ LIGHT SETUP
+
+=================================================================
+*/
+
+/*
+==================
+FindTargetEntity
+==================
+*/
+entity_t *FindTargetEntity( const char *target ) {
+ int i;
+ const char *n;
+
+ for ( i = 0 ; i < num_entities ; i++ ) {
+ n = ValueForKey (&entities[i], "targetname");
+ if ( !strcmp (n, target) ) {
+ return &entities[i];
+ }
+ }
+
+ return NULL;
+}
+
+
+
+/*
+=============
+CreateEntityLights
+=============
+*/
+void CreateEntityLights (void)
+{
+ int i;
+ light_t *dl;
+ entity_t *e, *e2;
+ const char *name;
+ const char *target;
+ vec3_t dest;
+ const char *_color;
+ float intensity;
+ int spawnflags;
+
+ //
+ // entities
+ //
+ for ( i = 0 ; i < num_entities ; i++ ) {
+ e = &entities[i];
+ name = ValueForKey (e, "classname");
+ if (strncmp (name, "light", 5))
+ continue;
+
+ numPointLights++;
+ dl = malloc(sizeof(*dl));
+ memset (dl, 0, sizeof(*dl));
+ dl->next = lights;
+ lights = dl;
+
+ spawnflags = FloatForKey (e, "spawnflags");
+ if ( spawnflags & 1 ) {
+ dl->linearLight = qtrue;
+ }
+
+ GetVectorForKey (e, "origin", dl->origin);
+ dl->style = FloatForKey (e, "_style");
+ if (!dl->style)
+ dl->style = FloatForKey (e, "style");
+ if (dl->style < 0)
+ dl->style = 0;
+
+ intensity = FloatForKey (e, "light");
+ if (!intensity)
+ intensity = FloatForKey (e, "_light");
+ if (!intensity)
+ intensity = 300;
+ _color = ValueForKey (e, "_color");
+ if (_color && _color[0])
+ {
+ sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);
+ ColorNormalize (dl->color, dl->color);
+ }
+ else
+ dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
+
+ intensity = intensity * pointScale;
+ dl->photons = intensity;
+
+ dl->type = emit_point;
+
+ // lights with a target will be spotlights
+ target = ValueForKey (e, "target");
+
+ if ( target[0] ) {
+ float radius;
+ float dist;
+
+ e2 = FindTargetEntity (target);
+ if (!e2) {
+ _printf ("WARNING: light at (%i %i %i) has missing target\n",
+ (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]);
+ } else {
+ GetVectorForKey (e2, "origin", dest);
+ VectorSubtract (dest, dl->origin, dl->normal);
+ dist = VectorNormalize (dl->normal, dl->normal);
+ radius = FloatForKey (e, "radius");
+ if ( !radius ) {
+ radius = 64;
+ }
+ if ( !dist ) {
+ dist = 64;
+ }
+ dl->radiusByDist = (radius + 16) / dist;
+ dl->type = emit_spotlight;
+ }
+ }
+ }
+}
+
+//=================================================================
+
+/*
+================
+SetEntityOrigins
+
+Find the offset values for inline models
+================
+*/
+void SetEntityOrigins( void ) {
+ int i, j;
+ entity_t *e;
+ vec3_t origin;
+ const char *key;
+ int modelnum;
+ dmodel_t *dm;
+
+ for ( i=0 ; i < num_entities ; i++ ) {
+ e = &entities[i];
+ key = ValueForKey (e, "model");
+ if ( key[0] != '*' ) {
+ continue;
+ }
+ modelnum = atoi( key + 1 );
+ dm = &dmodels[ modelnum ];
+
+ // set entity surface to true for all surfaces for this model
+ for ( j = 0 ; j < dm->numSurfaces ; j++ ) {
+ entitySurface[ dm->firstSurface + j ] = qtrue;
+ }
+
+ key = ValueForKey (e, "origin");
+ if ( !key[0] ) {
+ continue;
+ }
+ GetVectorForKey ( e, "origin", origin );
+
+ // set origin for all surfaces for this model
+ for ( j = 0 ; j < dm->numSurfaces ; j++ ) {
+ VectorCopy( origin, surfaceOrigin[ dm->firstSurface + j ] );
+ }
+ }
+}
+
+
+/*
+=================================================================
+
+
+=================================================================
+*/
+
+#define MAX_POINTS_ON_WINDINGS 64
+
+/*
+================
+PointToPolygonFormFactor
+================
+*/
+float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w ) {
+ vec3_t triVector, triNormal;
+ int i, j;
+ vec3_t dirs[MAX_POINTS_ON_WINDING];
+ float total;
+ float dot, angle, facing;
+
+ for ( i = 0 ; i < w->numpoints ; i++ ) {
+ VectorSubtract( w->p[i], point, dirs[i] );
+ VectorNormalize( dirs[i], dirs[i] );
+ }
+
+ // duplicate first vertex to avoid mod operation
+ VectorCopy( dirs[0], dirs[i] );
+
+ total = 0;
+ for ( i = 0 ; i < w->numpoints ; i++ ) {
+ j = i+1;
+ dot = DotProduct( dirs[i], dirs[j] );
+
+ // roundoff can cause slight creep, which gives an IND from acos
+ if ( dot > 1.0 ) {
+ dot = 1.0;
+ } else if ( dot < -1.0 ) {
+ dot = -1.0;
+ }
+
+ angle = acos( dot );
+ CrossProduct( dirs[i], dirs[j], triVector );
+ if ( VectorNormalize( triVector, triNormal ) < 0.0001 ) {
+ continue;
+ }
+ facing = DotProduct( normal, triNormal );
+ total += facing * angle;
+
+ if ( total > 6.3 || total < -6.3 ) {
+ static qboolean printed;
+
+ if ( !printed ) {
+ printed = qtrue;
+ _printf( "WARNING: bad PointToPolygonFormFactor: %f at %1.1f %1.1f %1.1f from %1.1f %1.1f %1.1f\n", total,
+ w->p[i][0], w->p[i][1], w->p[i][2], point[0], point[1], point[2]);
+ }
+ return 0;
+ }
+
+ }
+
+ total /= 2*3.141592657; // now in the range of 0 to 1 over the entire incoming hemisphere
+
+ return total;
+}
+
+
+/*
+================
+FilterTrace
+
+Returns 0 to 1.0 filter fractions for the given trace
+================
+*/
+void FilterTrace( const vec3_t start, const vec3_t end, vec3_t filter ) {
+ float d1, d2;
+ filter_t *f;
+ int filterNum;
+ vec3_t point;
+ float frac;
+ int i;
+ float s, t;
+ int u, v;
+ int x, y;
+ byte *pixel;
+ float radius;
+ float len;
+ vec3_t total;
+
+ filter[0] = 1.0;
+ filter[1] = 1.0;
+ filter[2] = 1.0;
+
+ for ( filterNum = 0 ; filterNum < numFilters ; filterNum++ ) {
+ f = &filters[ filterNum ];
+
+ // see if the plane is crossed
+ d1 = DotProduct( start, f->plane ) - f->plane[3];
+ d2 = DotProduct( end, f->plane ) - f->plane[3];
+
+ if ( ( d1 < 0 ) == ( d2 < 0 ) ) {
+ continue;
+ }
+
+ // calculate the crossing point
+ frac = d1 / ( d1 - d2 );
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ point[i] = start[i] + frac * ( end[i] - start[i] );
+ }
+
+ VectorSubtract( point, f->origin, point );
+
+ s = DotProduct( point, f->vectors[0] );
+ t = 1.0 - DotProduct( point, f->vectors[1] );
+ if ( s < 0 || s >= 1.0 || t < 0 || t >= 1.0 ) {
+ continue;
+ }
+
+ // decide the filter size
+ radius = 10 * frac;
+ len = VectorLength( f->vectors[0] );
+ if ( !len ) {
+ continue;
+ }
+ radius = radius * len * f->si->width;
+
+ // look up the filter, taking multiple samples
+ VectorClear( total );
+ for ( u = -1 ; u <= 1 ; u++ ) {
+ for ( v = -1 ; v <=1 ; v++ ) {
+ x = s * f->si->width + u * radius;
+ if ( x < 0 ) {
+ x = 0;
+ }
+ if ( x >= f->si->width ) {
+ x = f->si->width - 1;
+ }
+ y = t * f->si->height + v * radius;
+ if ( y < 0 ) {
+ y = 0;
+ }
+ if ( y >= f->si->height ) {
+ y = f->si->height - 1;
+ }
+
+ pixel = f->si->pixels + ( y * f->si->width + x ) * 4;
+ total[0] += pixel[0];
+ total[1] += pixel[1];
+ total[2] += pixel[2];
+ }
+ }
+
+ filter[0] *= total[0]/(255.0*9);
+ filter[1] *= total[1]/(255.0*9);
+ filter[2] *= total[2]/(255.0*9);
+ }
+
+}
+
+/*
+================
+SunToPoint
+
+Returns an amount of light to add at the point
+================
+*/
+int c_sunHit, c_sunMiss;
+void SunToPoint( const vec3_t origin, traceWork_t *tw, vec3_t addLight ) {
+ int i;
+ trace_t trace;
+ skyBrush_t *b;
+ vec3_t end;
+
+ if ( !numSkyBrushes ) {
+ VectorClear( addLight );
+ return;
+ }
+
+ VectorMA( origin, MAX_WORLD_COORD * 2, sunDirection, end );
+
+ TraceLine( origin, end, &trace, qtrue, tw );
+
+ // see if trace.hit is inside a sky brush
+ for ( i = 0 ; i < numSkyBrushes ; i++) {
+ b = &skyBrushes[ i ];
+
+ // this assumes that sky brushes are axial...
+ if ( trace.hit[0] < b->bounds[0][0]
+ || trace.hit[0] > b->bounds[1][0]
+ || trace.hit[1] < b->bounds[0][1]
+ || trace.hit[1] > b->bounds[1][1]
+ || trace.hit[2] < b->bounds[0][2]
+ || trace.hit[2] > b->bounds[1][2] ) {
+ continue;
+ }
+
+
+ // trace again to get intermediate filters
+ TraceLine( origin, trace.hit, &trace, qtrue, tw );
+
+ // we hit the sky, so add sunlight
+ if ( numthreads == 1 ) {
+ c_sunHit++;
+ }
+ addLight[0] = trace.filter[0] * sunLight[0];
+ addLight[1] = trace.filter[1] * sunLight[1];
+ addLight[2] = trace.filter[2] * sunLight[2];
+
+ return;
+ }
+
+ if ( numthreads == 1 ) {
+ c_sunMiss++;
+ }
+
+ VectorClear( addLight );
+}
+
+/*
+================
+SunToPlane
+================
+*/
+void SunToPlane( const vec3_t origin, const vec3_t normal, vec3_t color, traceWork_t *tw ) {
+ float angle;
+ vec3_t sunColor;
+
+ if ( !numSkyBrushes ) {
+ return;
+ }
+
+ angle = DotProduct( normal, sunDirection );
+ if ( angle <= 0 ) {
+ return; // facing away
+ }
+
+ SunToPoint( origin, tw, sunColor );
+ VectorMA( color, angle, sunColor, color );
+}
+
+/*
+================
+LightingAtSample
+================
+*/
+void LightingAtSample( vec3_t origin, vec3_t normal, vec3_t color,
+ qboolean testOcclusion, qboolean forceSunLight, traceWork_t *tw ) {
+ light_t *light;
+ trace_t trace;
+ float angle;
+ float add;
+ float dist;
+ vec3_t dir;
+
+ VectorCopy( ambientColor, color );
+
+ // trace to all the lights
+ for ( light = lights ; light ; light = light->next ) {
+
+ //MrE: if the light is behind the surface
+ if ( DotProduct(light->origin, normal) - DotProduct(normal, origin) < 0 )
+ continue;
+ // testing exact PTPFF
+ if ( exactPointToPolygon && light->type == emit_area ) {
+ float factor;
+ float d;
+ vec3_t pushedOrigin;
+
+ // see if the point is behind the light
+ d = DotProduct( origin, light->normal ) - light->dist;
+ if ( !light->twosided ) {
+ if ( d < -1 ) {
+ continue; // point is behind light
+ }
+ }
+
+ // test occlusion and find light filters
+ // clip the line, tracing from the surface towards the light
+ if ( !notrace && testOcclusion ) {
+ TraceLine( origin, light->origin, &trace, qfalse, tw );
+
+ // other light rays must not hit anything
+ if ( trace.passSolid ) {
+ continue;
+ }
+ } else {
+ trace.filter[0] = 1.0;
+ trace.filter[1] = 1.0;
+ trace.filter[2] = 1.0;
+ }
+
+ // nudge the point so that it is clearly forward of the light
+ // so that surfaces meeting a light emiter don't get black edges
+ if ( d > -8 && d < 8 ) {
+ VectorMA( origin, (8-d), light->normal, pushedOrigin );
+ } else {
+ VectorCopy( origin, pushedOrigin );
+ }
+
+ // calculate the contribution
+ factor = PointToPolygonFormFactor( pushedOrigin, normal, light->w );
+ if ( factor <= 0 ) {
+ if ( light->twosided ) {
+ factor = -factor;
+ } else {
+ continue;
+ }
+ }
+ color[0] += factor * light->emitColor[0] * trace.filter[0];
+ color[1] += factor * light->emitColor[1] * trace.filter[1];
+ color[2] += factor * light->emitColor[2] * trace.filter[2];
+
+ continue;
+ }
+
+ // calculate the amount of light at this sample
+ if ( light->type == emit_point ) {
+ VectorSubtract( light->origin, origin, dir );
+ dist = VectorNormalize( dir, dir );
+ // clamp the distance to prevent super hot spots
+ if ( dist < 16 ) {
+ dist = 16;
+ }
+ angle = DotProduct( normal, dir );
+ if ( light->linearLight ) {
+ add = angle * light->photons * linearScale - dist;
+ if ( add < 0 ) {
+ add = 0;
+ }
+ } else {
+ add = light->photons / ( dist * dist ) * angle;
+ }
+ } else if ( light->type == emit_spotlight ) {
+ float distByNormal;
+ vec3_t pointAtDist;
+ float radiusAtDist;
+ float sampleRadius;
+ vec3_t distToSample;
+ float coneScale;
+
+ VectorSubtract( light->origin, origin, dir );
+
+ distByNormal = -DotProduct( dir, light->normal );
+ if ( distByNormal < 0 ) {
+ continue;
+ }
+ VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
+ radiusAtDist = light->radiusByDist * distByNormal;
+
+ VectorSubtract( origin, pointAtDist, distToSample );
+ sampleRadius = VectorLength( distToSample );
+
+ if ( sampleRadius >= radiusAtDist ) {
+ continue; // outside the cone
+ }
+ if ( sampleRadius <= radiusAtDist - 32 ) {
+ coneScale = 1.0; // fully inside
+ } else {
+ coneScale = ( radiusAtDist - sampleRadius ) / 32.0;
+ }
+
+ dist = VectorNormalize( dir, dir );
+ // clamp the distance to prevent super hot spots
+ if ( dist < 16 ) {
+ dist = 16;
+ }
+ angle = DotProduct( normal, dir );
+ add = light->photons / ( dist * dist ) * angle * coneScale;
+
+ } else if ( light->type == emit_area ) {
+ VectorSubtract( light->origin, origin, dir );
+ dist = VectorNormalize( dir, dir );
+ // clamp the distance to prevent super hot spots
+ if ( dist < 16 ) {
+ dist = 16;
+ }
+ angle = DotProduct( normal, dir );
+ if ( angle <= 0 ) {
+ continue;
+ }
+ angle *= -DotProduct( light->normal, dir );
+ if ( angle <= 0 ) {
+ continue;
+ }
+
+ if ( light->linearLight ) {
+ add = angle * light->photons * linearScale - dist;
+ if ( add < 0 ) {
+ add = 0;
+ }
+ } else {
+ add = light->photons / ( dist * dist ) * angle;
+ }
+ }
+
+ if ( add <= 1.0 ) {
+ continue;
+ }
+
+ // clip the line, tracing from the surface towards the light
+ if ( !notrace && testOcclusion ) {
+ TraceLine( origin, light->origin, &trace, qfalse, tw );
+
+ // other light rays must not hit anything
+ if ( trace.passSolid ) {
+ continue;
+ }
+ } else {
+ trace.filter[0] = 1;
+ trace.filter[1] = 1;
+ trace.filter[2] = 1;
+ }
+
+ // add the result
+ color[0] += add * light->color[0] * trace.filter[0];
+ color[1] += add * light->color[1] * trace.filter[1];
+ color[2] += add * light->color[2] * trace.filter[2];
+ }
+
+ //
+ // trace directly to the sun
+ //
+ if ( testOcclusion || forceSunLight ) {
+ SunToPlane( origin, normal, color, tw );
+ }
+}
+
+/*
+=============
+PrintOccluded
+
+For debugging
+=============
+*/
+void PrintOccluded( byte occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE],
+ int width, int height ) {
+ int i, j;
+
+ _printf( "\n" );
+
+ for ( i = 0 ; i < height ; i++ ) {
+ for ( j = 0 ; j < width ; j++ ) {
+ _printf("%i", (int)occluded[j][i] );
+ }
+ _printf( "\n" );
+ }
+}
+
+
+/*
+=============
+VertexLighting
+
+Vertex lighting will completely ignore occlusion, because
+shadows would not be resolvable anyway.
+=============
+*/
+void VertexLighting( dsurface_t *ds, qboolean testOcclusion, qboolean forceSunLight, float scale, traceWork_t *tw ) {
+ int i, j;
+ drawVert_t *dv;
+ vec3_t sample, normal;
+ float max;
+
+ VectorCopy( ds->lightmapVecs[2], normal );
+
+ // generate vertex lighting
+ for ( i = 0 ; i < ds->numVerts ; i++ ) {
+ dv = &drawVerts[ ds->firstVert + i ];
+
+ if ( ds->patchWidth ) {
+ LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw );
+ }
+ else if (ds->surfaceType == MST_TRIANGLE_SOUP) {
+ LightingAtSample( dv->xyz, dv->normal, sample, testOcclusion, forceSunLight, tw );
+ }
+ else {
+ LightingAtSample( dv->xyz, normal, sample, testOcclusion, forceSunLight, tw );
+ }
+
+ if (scale >= 0)
+ VectorScale(sample, scale, sample);
+ // clamp with color normalization
+ max = sample[0];
+ if ( sample[1] > max ) {
+ max = sample[1];
+ }
+ if ( sample[2] > max ) {
+ max = sample[2];
+ }
+ if ( max > 255 ) {
+ VectorScale( sample, 255/max, sample );
+ }
+
+ // save the sample
+ for ( j = 0 ; j < 3 ; j++ ) {
+ if ( sample[j] > 255 ) {
+ sample[j] = 255;
+ }
+ dv->color[j] = sample[j];
+ }
+
+ // Don't bother writing alpha since it will already be set to 255,
+ // plus we don't want to write over alpha generated by SetTerrainTextures
+ //dv->color[3] = 255;
+ }
+}
+
+
+/*
+=================
+LinearSubdivideMesh
+
+For extra lighting, just midpoint one of the axis.
+The edges are clamped at the original edges.
+=================
+*/
+mesh_t *LinearSubdivideMesh( mesh_t *in ) {
+ int i, j;
+ mesh_t *out;
+ drawVert_t *v1, *v2, *vout;
+
+ out = malloc( sizeof( *out ) );
+
+ out->width = in->width * 2;
+ out->height = in->height;
+ out->verts = malloc( out->width * out->height * sizeof(*out->verts) );
+ for ( j = 0 ; j < in->height ; j++ ) {
+ out->verts[ j * out->width + 0 ] = in->verts[ j * in->width + 0 ];
+ out->verts[ j * out->width + out->width - 1 ] = in->verts[ j * in->width + in->width - 1 ];
+ for ( i = 1 ; i < out->width - 1 ; i+= 2 ) {
+ v1 = in->verts + j * in->width + (i >> 1);
+ v2 = v1 + 1;
+ vout = out->verts + j * out->width + i;
+
+ vout->xyz[0] = 0.75 * v1->xyz[0] + 0.25 * v2->xyz[0];
+ vout->xyz[1] = 0.75 * v1->xyz[1] + 0.25 * v2->xyz[1];
+ vout->xyz[2] = 0.75 * v1->xyz[2] + 0.25 * v2->xyz[2];
+
+ vout->normal[0] = 0.75 * v1->normal[0] + 0.25 * v2->normal[0];
+ vout->normal[1] = 0.75 * v1->normal[1] + 0.25 * v2->normal[1];
+ vout->normal[2] = 0.75 * v1->normal[2] + 0.25 * v2->normal[2];
+
+ VectorNormalize( vout->normal, vout->normal );
+
+ vout++;
+
+ vout->xyz[0] = 0.25 * v1->xyz[0] + 0.75 * v2->xyz[0];
+ vout->xyz[1] = 0.25 * v1->xyz[1] + 0.75 * v2->xyz[1];
+ vout->xyz[2] = 0.25 * v1->xyz[2] + 0.75 * v2->xyz[2];
+
+ vout->normal[0] = 0.25 * v1->normal[0] + 0.75 * v2->normal[0];
+ vout->normal[1] = 0.25 * v1->normal[1] + 0.75 * v2->normal[1];
+ vout->normal[2] = 0.25 * v1->normal[2] + 0.75 * v2->normal[2];
+
+ VectorNormalize( vout->normal, vout->normal );
+
+ }
+ }
+
+ FreeMesh( in );
+
+ return out;
+}
+
+/*
+==============
+ColorToBytes
+==============
+*/
+void ColorToBytes( const float *color, byte *colorBytes ) {
+ float max;
+ vec3_t sample;
+
+ VectorCopy( color, sample );
+
+ // clamp with color normalization
+ max = sample[0];
+ if ( sample[1] > max ) {
+ max = sample[1];
+ }
+ if ( sample[2] > max ) {
+ max = sample[2];
+ }
+ if ( max > 255 ) {
+ VectorScale( sample, 255/max, sample );
+ }
+ colorBytes[ 0 ] = sample[0];
+ colorBytes[ 1 ] = sample[1];
+ colorBytes[ 2 ] = sample[2];
+}
+
+
+
+/*
+=============
+TraceLtm
+=============
+*/
+void TraceLtm( int num ) {
+ dsurface_t *ds;
+ int i, j, k;
+ int x, y;
+ int position, numPositions;
+ vec3_t base, origin, normal;
+ byte occluded[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE];
+ vec3_t color[LIGHTMAP_WIDTH*EXTRASCALE][LIGHTMAP_HEIGHT*EXTRASCALE];
+ traceWork_t tw;
+ vec3_t average;
+ int count;
+ mesh_t srcMesh, *mesh, *subdivided;
+ shaderInfo_t *si;
+ static float nudge[2][9] = {
+ { 0, -1, 0, 1, -1, 1, -1, 0, 1 },
+ { 0, -1, -1, -1, 0, 0, 1, 1, 1 }
+ };
+ int sampleWidth, sampleHeight, ssize;
+ vec3_t lightmapOrigin, lightmapVecs[2];
+ int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_WIDTH];
+
+ ds = &drawSurfaces[num];
+ si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
+
+ // vertex-lit triangle model
+ if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
+ VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw );
+ return;
+ }
+
+ if ( ds->lightmapNum == -1 ) {
+ return; // doesn't need lighting at all
+ }
+
+ if (!novertexlighting) {
+ // calculate the vertex lighting for gouraud shade mode
+ VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw );
+ }
+
+ if ( ds->lightmapNum < 0 ) {
+ return; // doesn't need lightmap lighting
+ }
+
+ si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
+ ssize = samplesize;
+ if (si->lightmapSampleSize)
+ ssize = si->lightmapSampleSize;
+
+ if (si->patchShadows)
+ tw.patchshadows = qtrue;
+ else
+ tw.patchshadows = patchshadows;
+
+ if ( ds->surfaceType == MST_PATCH ) {
+ srcMesh.width = ds->patchWidth;
+ srcMesh.height = ds->patchHeight;
+ srcMesh.verts = drawVerts + ds->firstVert;
+ mesh = SubdivideMesh( srcMesh, 8, 999 );
+ PutMeshOnCurve( *mesh );
+ MakeMeshNormals( *mesh );
+
+ subdivided = RemoveLinearMeshColumnsRows( mesh );
+ FreeMesh(mesh);
+
+ mesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_WIDTH, widthtable, heighttable);
+ if ( mesh->width != ds->lightmapWidth || mesh->height != ds->lightmapHeight ) {
+ Error( "Mesh lightmap miscount");
+ }
+
+ if ( extra ) {
+ mesh_t *mp;
+
+ // chop it up for more light samples (leaking memory...)
+ mp = mesh;//CopyMesh( mesh );
+ mp = LinearSubdivideMesh( mp );
+ mp = TransposeMesh( mp );
+ mp = LinearSubdivideMesh( mp );
+ mp = TransposeMesh( mp );
+
+ mesh = mp;
+ }
+ } else {
+ VectorCopy( ds->lightmapVecs[2], normal );
+
+ if ( !extra ) {
+ VectorCopy( ds->lightmapOrigin, lightmapOrigin );
+ VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] );
+ VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] );
+ } else {
+ // sample at a closer spacing for antialiasing
+ VectorCopy( ds->lightmapOrigin, lightmapOrigin );
+ VectorScale( ds->lightmapVecs[0], 0.5, lightmapVecs[0] );
+ VectorScale( ds->lightmapVecs[1], 0.5, lightmapVecs[1] );
+ VectorMA( lightmapOrigin, -0.5, lightmapVecs[0], lightmapOrigin );
+ VectorMA( lightmapOrigin, -0.5, lightmapVecs[1], lightmapOrigin );
+ }
+ }
+
+ if ( extra ) {
+ sampleWidth = ds->lightmapWidth * 2;
+ sampleHeight = ds->lightmapHeight * 2;
+ } else {
+ sampleWidth = ds->lightmapWidth;
+ sampleHeight = ds->lightmapHeight;
+ }
+
+ memset ( color, 0, sizeof( color ) );
+
+ // determine which samples are occluded
+ memset ( occluded, 0, sizeof( occluded ) );
+ for ( i = 0 ; i < sampleWidth ; i++ ) {
+ for ( j = 0 ; j < sampleHeight ; j++ ) {
+
+ if ( ds->patchWidth ) {
+ numPositions = 9;
+ VectorCopy( mesh->verts[j*mesh->width+i].normal, normal );
+ // VectorNormalize( normal, normal );
+ // push off of the curve a bit
+ VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base );
+
+ MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] );
+ } else {
+ numPositions = 9;
+ for ( k = 0 ; k < 3 ; k++ ) {
+ base[k] = lightmapOrigin[k] + normal[k]
+ + i * lightmapVecs[0][k]
+ + j * lightmapVecs[1][k];
+ }
+ }
+ VectorAdd( base, surfaceOrigin[ num ], base );
+
+ // we may need to slightly nudge the sample point
+ // if directly on a wall
+ for ( position = 0 ; position < numPositions ; position++ ) {
+ // calculate lightmap sample position
+ for ( k = 0 ; k < 3 ; k++ ) {
+ origin[k] = base[k] +
+ + ( nudge[0][position]/16 ) * lightmapVecs[0][k]
+ + ( nudge[1][position]/16 ) * lightmapVecs[1][k];
+ }
+
+ if ( notrace ) {
+ break;
+ }
+ if ( !PointInSolid( origin ) ) {
+ break;
+ }
+ }
+
+ // if none of the nudges worked, this sample is occluded
+ if ( position == numPositions ) {
+ occluded[i][j] = qtrue;
+ if ( numthreads == 1 ) {
+ c_occluded++;
+ }
+ continue;
+ }
+
+ if ( numthreads == 1 ) {
+ c_visible++;
+ }
+ occluded[i][j] = qfalse;
+ LightingAtSample( origin, normal, color[i][j], qtrue, qfalse, &tw );
+ }
+ }
+
+ if ( dump ) {
+ PrintOccluded( occluded, sampleWidth, sampleHeight );
+ }
+
+ // calculate average values for occluded samples
+ for ( i = 0 ; i < sampleWidth ; i++ ) {
+ for ( j = 0 ; j < sampleHeight ; j++ ) {
+ if ( !occluded[i][j] ) {
+ continue;
+ }
+ // scan all surrounding samples
+ count = 0;
+ VectorClear( average );
+ for ( x = -1 ; x <= 1; x++ ) {
+ for ( y = -1 ; y <= 1 ; y++ ) {
+ if ( i + x < 0 || i + x >= sampleWidth ) {
+ continue;
+ }
+ if ( j + y < 0 || j + y >= sampleHeight ) {
+ continue;
+ }
+ if ( occluded[i+x][j+y] ) {
+ continue;
+ }
+ count++;
+ VectorAdd( color[i+x][j+y], average, average );
+ }
+ }
+ if ( count ) {
+ VectorScale( average, 1.0/count, color[i][j] );
+ }
+ }
+ }
+
+ // average together the values if we are extra sampling
+ if ( ds->lightmapWidth != sampleWidth ) {
+ for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
+ for ( j = 0 ; j < ds->lightmapHeight ; j++ ) {
+ for ( k = 0 ; k < 3 ; k++ ) {
+ float value, coverage;
+
+ value = color[i*2][j*2][k] + color[i*2][j*2+1][k] +
+ color[i*2+1][j*2][k] + color[i*2+1][j*2+1][k];
+ coverage = 4;
+ if ( extraWide ) {
+ // wider than box filter
+ if ( i > 0 ) {
+ value += color[i*2-1][j*2][k] + color[i*2-1][j*2+1][k];
+ value += color[i*2-2][j*2][k] + color[i*2-2][j*2+1][k];
+ coverage += 4;
+ }
+ if ( i < ds->lightmapWidth - 1 ) {
+ value += color[i*2+2][j*2][k] + color[i*2+2][j*2+1][k];
+ value += color[i*2+3][j*2][k] + color[i*2+3][j*2+1][k];
+ coverage += 4;
+ }
+ if ( j > 0 ) {
+ value += color[i*2][j*2-1][k] + color[i*2+1][j*2-1][k];
+ value += color[i*2][j*2-2][k] + color[i*2+1][j*2-2][k];
+ coverage += 4;
+ }
+ if ( j < ds->lightmapHeight - 1 ) {
+ value += color[i*2][j*2+2][k] + color[i*2+1][j*2+2][k];
+ value += color[i*2][j*2+3][k] + color[i*2+1][j*2+3][k];
+ coverage += 2;
+ }
+ }
+
+ color[i][j][k] = value / coverage;
+ }
+ }
+ }
+ }
+
+ // optionally create a debugging border around the lightmap
+ if ( lightmapBorder ) {
+ for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
+ color[i][0][0] = 255;
+ color[i][0][1] = 0;
+ color[i][0][2] = 0;
+
+ color[i][ds->lightmapHeight-1][0] = 255;
+ color[i][ds->lightmapHeight-1][1] = 0;
+ color[i][ds->lightmapHeight-1][2] = 0;
+ }
+ for ( i = 0 ; i < ds->lightmapHeight ; i++ ) {
+ color[0][i][0] = 255;
+ color[0][i][1] = 0;
+ color[0][i][2] = 0;
+
+ color[ds->lightmapWidth-1][i][0] = 255;
+ color[ds->lightmapWidth-1][i][1] = 0;
+ color[ds->lightmapWidth-1][i][2] = 0;
+ }
+ }
+
+ // clamp the colors to bytes and store off
+ for ( i = 0 ; i < ds->lightmapWidth ; i++ ) {
+ for ( j = 0 ; j < ds->lightmapHeight ; j++ ) {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j)
+ * LIGHTMAP_WIDTH + ds->lightmapX + i;
+
+ ColorToBytes( color[i][j], lightBytes + k*3 );
+ }
+ }
+
+ if (ds->surfaceType == MST_PATCH)
+ {
+ FreeMesh(mesh);
+ }
+}
+
+
+//=============================================================================
+
+vec3_t gridMins;
+vec3_t gridSize = { 64, 64, 128 };
+int gridBounds[3];
+
+
+/*
+========================
+LightContributionToPoint
+========================
+*/
+qboolean LightContributionToPoint( const light_t *light, const vec3_t origin,
+ vec3_t color, traceWork_t *tw ) {
+ trace_t trace;
+ float add;
+
+ add = 0;
+
+ VectorClear( color );
+
+ // testing exact PTPFF
+ if ( exactPointToPolygon && light->type == emit_area ) {
+ float factor;
+ float d;
+ vec3_t normal;
+
+ // see if the point is behind the light
+ d = DotProduct( origin, light->normal ) - light->dist;
+ if ( !light->twosided ) {
+ if ( d < 1 ) {
+ return qfalse; // point is behind light
+ }
+ }
+
+ // test occlusion
+ // clip the line, tracing from the surface towards the light
+ TraceLine( origin, light->origin, &trace, qfalse, tw );
+ if ( trace.passSolid ) {
+ return qfalse;
+ }
+
+ // calculate the contribution
+ VectorSubtract( light->origin, origin, normal );
+ if ( VectorNormalize( normal, normal ) == 0 ) {
+ return qfalse;
+ }
+ factor = PointToPolygonFormFactor( origin, normal, light->w );
+ if ( factor <= 0 ) {
+ if ( light->twosided ) {
+ factor = -factor;
+ } else {
+ return qfalse;
+ }
+ }
+ VectorScale( light->emitColor, factor, color );
+ return qtrue;
+ }
+
+ // calculate the amount of light at this sample
+ if ( light->type == emit_point || light->type == emit_spotlight ) {
+ vec3_t dir;
+ float dist;
+
+ VectorSubtract( light->origin, origin, dir );
+ dist = VectorLength( dir );
+ // clamp the distance to prevent super hot spots
+ if ( dist < 16 ) {
+ dist = 16;
+ }
+ if ( light->linearLight ) {
+ add = light->photons * linearScale - dist;
+ if ( add < 0 ) {
+ add = 0;
+ }
+ } else {
+ add = light->photons / ( dist * dist );
+ }
+ } else {
+ return qfalse;
+ }
+
+ if ( add <= 1.0 ) {
+ return qfalse;
+ }
+
+ // clip the line, tracing from the surface towards the light
+ TraceLine( origin, light->origin, &trace, qfalse, tw );
+
+ // other light rays must not hit anything
+ if ( trace.passSolid ) {
+ return qfalse;
+ }
+
+ // add the result
+ color[0] = add * light->color[0];
+ color[1] = add * light->color[1];
+ color[2] = add * light->color[2];
+
+ return qtrue;
+}
+
+typedef struct {
+ vec3_t dir;
+ vec3_t color;
+} contribution_t;
+
+/*
+=============
+TraceGrid
+
+Grid samples are foe quickly determining the lighting
+of dynamically placed entities in the world
+=============
+*/
+#define MAX_CONTRIBUTIONS 1024
+void TraceGrid( int num ) {
+ int x, y, z;
+ vec3_t origin;
+ light_t *light;
+ vec3_t color;
+ int mod;
+ vec3_t directedColor;
+ vec3_t summedDir;
+ contribution_t contributions[MAX_CONTRIBUTIONS];
+ int numCon;
+ int i;
+ traceWork_t tw;
+ float addSize;
+
+ mod = num;
+ z = mod / ( gridBounds[0] * gridBounds[1] );
+ mod -= z * ( gridBounds[0] * gridBounds[1] );
+
+ y = mod / gridBounds[0];
+ mod -= y * gridBounds[0];
+
+ x = mod;
+
+ origin[0] = gridMins[0] + x * gridSize[0];
+ origin[1] = gridMins[1] + y * gridSize[1];
+ origin[2] = gridMins[2] + z * gridSize[2];
+
+ if ( PointInSolid( origin ) ) {
+ vec3_t baseOrigin;
+ int step;
+
+ VectorCopy( origin, baseOrigin );
+
+ // try to nudge the origin around to find a valid point
+ for ( step = 9 ; step <= 18 ; step += 9 ) {
+ for ( i = 0 ; i < 8 ; i++ ) {
+ VectorCopy( baseOrigin, origin );
+ if ( i & 1 ) {
+ origin[0] += step;
+ } else {
+ origin[0] -= step;
+ }
+ if ( i & 2 ) {
+ origin[1] += step;
+ } else {
+ origin[1] -= step;
+ }
+ if ( i & 4 ) {
+ origin[2] += step;
+ } else {
+ origin[2] -= step;
+ }
+
+ if ( !PointInSolid( origin ) ) {
+ break;
+ }
+ }
+ if ( i != 8 ) {
+ break;
+ }
+ }
+ if ( step > 18 ) {
+ // can't find a valid point at all
+ for ( i = 0 ; i < 8 ; i++ ) {
+ gridData[ num*8 + i ] = 0;
+ }
+ return;
+ }
+ }
+
+ VectorClear( summedDir );
+
+ // trace to all the lights
+
+ // find the major light direction, and divide the
+ // total light between that along the direction and
+ // the remaining in the ambient
+ numCon = 0;
+ for ( light = lights ; light ; light = light->next ) {
+ vec3_t add;
+ vec3_t dir;
+ float addSize;
+
+ if ( !LightContributionToPoint( light, origin, add, &tw ) ) {
+ continue;
+ }
+
+ VectorSubtract( light->origin, origin, dir );
+ VectorNormalize( dir, dir );
+
+ VectorCopy( add, contributions[numCon].color );
+ VectorCopy( dir, contributions[numCon].dir );
+ numCon++;
+
+ addSize = VectorLength( add );
+ VectorMA( summedDir, addSize, dir, summedDir );
+
+ if ( numCon == MAX_CONTRIBUTIONS-1 ) {
+ break;
+ }
+ }
+
+ //
+ // trace directly to the sun
+ //
+ SunToPoint( origin, &tw, color );
+ addSize = VectorLength( color );
+ if ( addSize > 0 ) {
+ VectorCopy( color, contributions[numCon].color );
+ VectorCopy( sunDirection, contributions[numCon].dir );
+ VectorMA( summedDir, addSize, sunDirection, summedDir );
+ numCon++;
+ }
+
+
+ // now that we have identified the primary light direction,
+ // go back and seperate all the light into directed and ambient
+ VectorNormalize( summedDir, summedDir );
+ VectorCopy( ambientColor, color );
+ VectorClear( directedColor );
+
+ for ( i = 0 ; i < numCon ; i++ ) {
+ float d;
+
+ d = DotProduct( contributions[i].dir, summedDir );
+ if ( d < 0 ) {
+ d = 0;
+ }
+
+ VectorMA( directedColor, d, contributions[i].color, directedColor );
+
+ // the ambient light will be at 1/4 the value of directed light
+ d = 0.25 * ( 1.0 - d );
+ VectorMA( color, d, contributions[i].color, color );
+ }
+
+ // now do some fudging to keep the ambient from being too low
+ VectorMA( color, 0.25, directedColor, color );
+
+ //
+ // save the resulting value out
+ //
+ ColorToBytes( color, gridData + num*8 );
+ ColorToBytes( directedColor, gridData + num*8 + 3 );
+
+ VectorNormalize( summedDir, summedDir );
+ NormalToLatLong( summedDir, gridData + num*8 + 6);
+}
+
+
+/*
+=============
+SetupGrid
+=============
+*/
+void SetupGrid( void ) {
+ int i;
+ vec3_t maxs;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ gridMins[i] = gridSize[i] * ceil( dmodels[0].mins[i] / gridSize[i] );
+ maxs[i] = gridSize[i] * floor( dmodels[0].maxs[i] / gridSize[i] );
+ gridBounds[i] = (maxs[i] - gridMins[i])/gridSize[i] + 1;
+ }
+
+ numGridPoints = gridBounds[0] * gridBounds[1] * gridBounds[2];
+ if (numGridPoints * 8 >= MAX_MAP_LIGHTGRID)
+ Error("MAX_MAP_LIGHTGRID");
+ qprintf( "%5i gridPoints\n", numGridPoints );
+}
+
+//=============================================================================
+
+/*
+=============
+RemoveLightsInSolid
+=============
+*/
+void RemoveLightsInSolid(void)
+{
+ light_t *light, *prev;
+ int numsolid = 0;
+
+ prev = NULL;
+ for ( light = lights ; light ; ) {
+ if (PointInSolid(light->origin))
+ {
+ if (prev) prev->next = light->next;
+ else lights = light->next;
+ if (light->w)
+ FreeWinding(light->w);
+ free(light);
+ numsolid++;
+ if (prev)
+ light = prev->next;
+ else
+ light = lights;
+ }
+ else
+ {
+ prev = light;
+ light = light->next;
+ }
+ }
+ _printf (" %7i lights in solid\n", numsolid);
+}
+
+/*
+=============
+LightWorld
+=============
+*/
+void LightWorld (void) {
+ float f;
+
+ // determine the number of grid points
+ SetupGrid();
+
+ // find the optional world ambient
+ GetVectorForKey( &entities[0], "_color", ambientColor );
+ f = FloatForKey( &entities[0], "ambient" );
+ VectorScale( ambientColor, f, ambientColor );
+
+ // create lights out of patches and lights
+ qprintf ("--- CreateLights ---\n");
+ CreateEntityLights ();
+ qprintf ("%i point lights\n", numPointLights);
+ qprintf ("%i area lights\n", numAreaLights);
+
+ if (!nogridlighting) {
+ qprintf ("--- TraceGrid ---\n");
+ RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid );
+ qprintf( "%i x %i x %i = %i grid\n", gridBounds[0], gridBounds[1],
+ gridBounds[2], numGridPoints);
+ }
+
+ qprintf ("--- TraceLtm ---\n");
+ RunThreadsOnIndividual( numDrawSurfaces, qtrue, TraceLtm );
+ qprintf( "%5i visible samples\n", c_visible );
+ qprintf( "%5i occluded samples\n", c_occluded );
+}
+
+/*
+========
+CreateFilters
+
+EXPERIMENTAL, UNUSED
+
+Look for transparent light filter surfaces.
+
+This will only work for flat 3*3 patches that exactly hold one copy of the texture.
+========
+*/
+#define PLANAR_PATCH_EPSILON 0.1
+void CreateFilters( void ) {
+ int i;
+ filter_t *f;
+ dsurface_t *ds;
+ shaderInfo_t *si;
+ drawVert_t *v1, *v2, *v3;
+ vec3_t d1, d2;
+ int vertNum;
+
+ numFilters = 0;
+
+ return;
+
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ ds = &drawSurfaces[i];
+ if ( !ds->patchWidth ) {
+ continue;
+ }
+ si = ShaderInfoForShader( dshaders[ ds->shaderNum ].shader );
+/*
+ if ( !(si->surfaceFlags & SURF_LIGHTFILTER) ) {
+ continue;
+ }
+*/
+
+ // we have a filter patch
+ v1 = &drawVerts[ ds->firstVert ];
+
+ if ( ds->patchWidth != 3 || ds->patchHeight != 3 ) {
+ _printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't a 3 by 3\n",
+ v1->xyz[0], v1->xyz[1], v1->xyz[2] );
+ continue;
+ }
+
+ if ( numFilters == MAX_FILTERS ) {
+ Error( "MAX_FILTERS" );
+ }
+ f = &filters[ numFilters ];
+ numFilters++;
+
+ v2 = &drawVerts[ ds->firstVert + 2 ];
+ v3 = &drawVerts[ ds->firstVert + 6 ];
+
+ VectorSubtract( v2->xyz, v1->xyz, d1 );
+ VectorSubtract( v3->xyz, v1->xyz, d2 );
+ VectorNormalize( d1, d1 );
+ VectorNormalize( d2, d2 );
+ CrossProduct( d1, d2, f->plane );
+ f->plane[3] = DotProduct( v1->xyz, f->plane );
+
+ // make sure all the control points are on the plane
+ for ( vertNum = 0 ; vertNum < ds->numVerts ; vertNum++ ) {
+ float d;
+
+ d = DotProduct( drawVerts[ ds->firstVert + vertNum ].xyz, f->plane ) - f->plane[3];
+ if ( fabs( d ) > PLANAR_PATCH_EPSILON ) {
+ break;
+ }
+ }
+ if ( vertNum != ds->numVerts ) {
+ numFilters--;
+ _printf("WARNING: patch at %i %i %i has SURF_LIGHTFILTER but isn't flat\n",
+ v1->xyz[0], v1->xyz[1], v1->xyz[2] );
+ continue;
+ }
+ }
+
+ f = &filters[0];
+ numFilters = 1;
+
+ f->plane[0] = 1;
+ f->plane[1] = 0;
+ f->plane[2] = 0;
+ f->plane[3] = 448;
+
+ f->origin[0] = 448;
+ f->origin[1] = 192;
+ f->origin[2] = 0;
+
+ f->vectors[0][0] = 0;
+ f->vectors[0][1] = -1.0 / 128;
+ f->vectors[0][2] = 0;
+
+ f->vectors[1][0] = 0;
+ f->vectors[1][1] = 0;
+ f->vectors[1][2] = 1.0 / 128;
+
+ f->si = ShaderInfoForShader( "textures/hell/blocks11ct" );
+}
+
+/*
+=============
+VertexLightingThread
+=============
+*/
+void VertexLightingThread(int num) {
+ dsurface_t *ds;
+ traceWork_t tw;
+ shaderInfo_t *si;
+
+ ds = &drawSurfaces[num];
+
+ // vertex-lit triangle model
+ if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
+ return;
+ }
+
+ if (novertexlighting)
+ return;
+
+ if ( ds->lightmapNum == -1 ) {
+ return; // doesn't need lighting at all
+ }
+
+ si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
+
+ // calculate the vertex lighting for gouraud shade mode
+ VertexLighting( ds, si->vertexShadows, si->forceSunLight, si->vertexScale, &tw );
+}
+
+/*
+=============
+TriSoupLightingThread
+=============
+*/
+void TriSoupLightingThread(int num) {
+ dsurface_t *ds;
+ traceWork_t tw;
+ shaderInfo_t *si;
+
+ ds = &drawSurfaces[num];
+ si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
+
+ // vertex-lit triangle model
+ if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
+ VertexLighting( ds, !si->noVertexShadows, si->forceSunLight, 1.0, &tw );
+ }
+}
+
+/*
+=============
+GridAndVertexLighting
+=============
+*/
+void GridAndVertexLighting(void) {
+ SetupGrid();
+
+ FindSkyBrushes();
+ CreateFilters();
+ InitTrace();
+ CreateEntityLights ();
+ CreateSurfaceLights();
+
+ if (!nogridlighting) {
+ _printf ("--- TraceGrid ---\n");
+ RunThreadsOnIndividual( numGridPoints, qtrue, TraceGrid );
+ }
+
+ if (!novertexlighting) {
+ _printf ("--- Vertex Lighting ---\n");
+ RunThreadsOnIndividual( numDrawSurfaces, qtrue, VertexLightingThread );
+ }
+
+ _printf("--- Model Lighting ---\n");
+ RunThreadsOnIndividual( numDrawSurfaces, qtrue, TriSoupLightingThread );
+}
+
+/*
+========
+LightMain
+
+========
+*/
+int LightMain (int argc, char **argv) {
+ int i;
+ double start, end;
+ const char *value;
+
+ _printf ("----- Lighting ----\n");
+
+ verbose = qfalse;
+
+ for (i=1 ; i<argc ; i++) {
+ if (!strcmp(argv[i],"-tempname"))
+ {
+ i++;
+ } else if (!strcmp(argv[i],"-v")) {
+ verbose = qtrue;
+ } else if (!strcmp(argv[i],"-threads")) {
+ numthreads = atoi (argv[i+1]);
+ i++;
+ } else if (!strcmp(argv[i],"-area")) {
+ areaScale *= atof(argv[i+1]);
+ _printf ("area light scaling at %f\n", areaScale);
+ i++;
+ } else if (!strcmp(argv[i],"-point")) {
+ pointScale *= atof(argv[i+1]);
+ _printf ("point light scaling at %f\n", pointScale);
+ i++;
+ } else if (!strcmp(argv[i],"-notrace")) {
+ notrace = qtrue;
+ _printf ("No occlusion tracing\n");
+ } else if (!strcmp(argv[i],"-patchshadows")) {
+ patchshadows = qtrue;
+ _printf ("Patch shadow casting enabled\n");
+ } else if (!strcmp(argv[i],"-extra")) {
+ extra = qtrue;
+ _printf ("Extra detail tracing\n");
+ } else if (!strcmp(argv[i],"-extrawide")) {
+ extra = qtrue;
+ extraWide = qtrue;
+ _printf ("Extra wide detail tracing\n");
+ } else if (!strcmp(argv[i], "-samplesize")) {
+ samplesize = atoi(argv[i+1]);
+ if (samplesize < 1) samplesize = 1;
+ i++;
+ _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize);
+ } else if (!strcmp(argv[i], "-novertex")) {
+ novertexlighting = qtrue;
+ _printf("no vertex lighting = true\n");
+ } else if (!strcmp(argv[i], "-nogrid")) {
+ nogridlighting = qtrue;
+ _printf("no grid lighting = true\n");
+ } else if (!strcmp(argv[i],"-border")) {
+ lightmapBorder = qtrue;
+ _printf ("Adding debug border to lightmaps\n");
+ } else if (!strcmp(argv[i],"-nosurf")) {
+ noSurfaces = qtrue;
+ _printf ("Not tracing against surfaces\n" );
+ } else if (!strcmp(argv[i],"-dump")) {
+ dump = qtrue;
+ _printf ("Dumping occlusion maps\n");
+ } else {
+ break;
+ }
+ }
+
+ ThreadSetDefault ();
+
+ if (i != argc - 1) {
+ _printf("usage: q3map -light [-<switch> [-<switch> ...]] <mapname>\n"
+ "\n"
+ "Switches:\n"
+ " v = verbose output\n"
+ " threads <X> = set number of threads to X\n"
+ " area <V> = set the area light scale to V\n"
+ " point <W> = set the point light scale to W\n"
+ " notrace = don't cast any shadows\n"
+ " extra = enable super sampling for anti-aliasing\n"
+ " extrawide = same as extra but smoothen more\n"
+ " nogrid = don't calculate light grid for dynamic model lighting\n"
+ " novertex = don't calculate vertex lighting\n"
+ " samplesize <N> = set the lightmap pixel size to NxN units\n");
+ exit(0);
+ }
+
+ start = I_FloatTime ();
+
+ SetQdirFromPath (argv[i]);
+
+#ifdef _WIN32
+ InitPakFile(gamedir, NULL);
+#endif
+
+ strcpy (source, ExpandArg(argv[i]));
+ StripExtension (source);
+ DefaultExtension (source, ".bsp");
+
+ LoadShaderInfo();
+
+ _printf ("reading %s\n", source);
+
+ LoadBSPFile (source);
+
+ FindSkyBrushes();
+
+ ParseEntities();
+
+ value = ValueForKey( &entities[0], "gridsize" );
+ if (strlen(value)) {
+ sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] );
+ _printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]);
+ }
+
+ CreateFilters();
+
+ InitTrace();
+
+ SetEntityOrigins();
+
+ CountLightmaps();
+
+ CreateSurfaceLights();
+
+ LightWorld();
+
+ _printf ("writing %s\n", source);
+ WriteBSPFile (source);
+
+ end = I_FloatTime ();
+ _printf ("%5.0f seconds elapsed\n", end-start);
+
+ return 0;
+}
+
diff --git a/q3map/light.h b/q3map/light.h
index 5faa24a..ada2763 100755
--- a/q3map/light.h
+++ b/q3map/light.h
@@ -19,133 +19,133 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include "cmdlib.h"
-#include "mathlib.h"
-#include "bspfile.h"
-#include "polylib.h"
-#include "imagelib.h"
-#include "threads.h"
-#include "scriplib.h"
-
-#include "shaders.h"
-#include "mesh.h"
-
-
-
-typedef enum
-{
- emit_point,
- emit_area,
- emit_spotlight,
- emit_sun
-} emittype_t;
-
-#define MAX_LIGHT_EDGES 8
-typedef struct light_s
-{
- struct light_s *next;
- emittype_t type;
- struct shaderInfo_s *si;
-
- vec3_t origin;
- vec3_t normal; // for surfaces, spotlights, and suns
- float dist; // plane location along normal
-
- qboolean linearLight;
- int photons;
- int style;
- vec3_t color;
- float radiusByDist; // for spotlights
-
- qboolean twosided; // fog lights both sides
-
- winding_t *w;
- vec3_t emitColor; // full out-of-gamut value
-} light_t;
-
-
-extern float lightscale;
-extern float ambient;
-extern float maxlight;
-extern float direct_scale;
-extern float entity_scale;
-
-extern qboolean noSurfaces;
-
-//===============================================================
-
-// light_trace.c
-
-// a facet is a subdivided element of a patch aproximation or model
-typedef struct cFacet_s {
- float surface[4];
- int numBoundaries; // either 3 or 4, anything less is degenerate
- float boundaries[4][4]; // positive is outside the bounds
-
- vec3_t points[4]; // needed for area light subdivision
-
- float textureMatrix[2][4]; // compute texture coordinates at point of impact for translucency
-} cFacet_t;
-
-typedef struct {
- vec3_t mins, maxs;
- vec3_t origin;
- float radius;
-
- qboolean patch;
-
- int numFacets;
- cFacet_t *facets;
-
- shaderInfo_t *shader; // for translucency
-} surfaceTest_t;
-
-
-typedef struct {
- vec3_t filter; // starts out 1.0, 1.0, 1.0, may be reduced if
- // transparent surfaces are crossed
-
- vec3_t hit; // the impact point of a completely opaque surface
- float hitFraction; // 0 = at start, 1.0 = at end
- qboolean passSolid;
-} trace_t;
-
-extern surfaceTest_t *surfaceTest[MAX_MAP_DRAW_SURFS];
-
-void InitTrace( void );
-
-// traceWork_t is only a parameter to crutch up poor large local allocations on
-// winNT and macOS. It should be allocated in the worker function, but never
-// looked at.
-typedef struct {
- vec3_t start, end;
- int numOpenLeafs;
- int openLeafNumbers[MAX_MAP_LEAFS];
- trace_t *trace;
- int patchshadows;
-} traceWork_t;
-
-void TraceLine( const vec3_t start, const vec3_t stop, trace_t *trace,
- qboolean testAll, traceWork_t *tw );
-qboolean PointInSolid( vec3_t start );
-
-//===============================================================
-
-//===============================================================
-
-
-typedef struct {
- int textureNum;
- int x, y, width, height;
-
- // for patches
- qboolean patch;
- mesh_t mesh;
-
- // for faces
- vec3_t origin;
- vec3_t vecs[3];
-} lightmap_t;
-
-
+
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "bspfile.h"
+#include "polylib.h"
+#include "imagelib.h"
+#include "threads.h"
+#include "scriplib.h"
+
+#include "shaders.h"
+#include "mesh.h"
+
+
+
+typedef enum
+{
+ emit_point,
+ emit_area,
+ emit_spotlight,
+ emit_sun
+} emittype_t;
+
+#define MAX_LIGHT_EDGES 8
+typedef struct light_s
+{
+ struct light_s *next;
+ emittype_t type;
+ struct shaderInfo_s *si;
+
+ vec3_t origin;
+ vec3_t normal; // for surfaces, spotlights, and suns
+ float dist; // plane location along normal
+
+ qboolean linearLight;
+ int photons;
+ int style;
+ vec3_t color;
+ float radiusByDist; // for spotlights
+
+ qboolean twosided; // fog lights both sides
+
+ winding_t *w;
+ vec3_t emitColor; // full out-of-gamut value
+} light_t;
+
+
+extern float lightscale;
+extern float ambient;
+extern float maxlight;
+extern float direct_scale;
+extern float entity_scale;
+
+extern qboolean noSurfaces;
+
+//===============================================================
+
+// light_trace.c
+
+// a facet is a subdivided element of a patch aproximation or model
+typedef struct cFacet_s {
+ float surface[4];
+ int numBoundaries; // either 3 or 4, anything less is degenerate
+ float boundaries[4][4]; // positive is outside the bounds
+
+ vec3_t points[4]; // needed for area light subdivision
+
+ float textureMatrix[2][4]; // compute texture coordinates at point of impact for translucency
+} cFacet_t;
+
+typedef struct {
+ vec3_t mins, maxs;
+ vec3_t origin;
+ float radius;
+
+ qboolean patch;
+
+ int numFacets;
+ cFacet_t *facets;
+
+ shaderInfo_t *shader; // for translucency
+} surfaceTest_t;
+
+
+typedef struct {
+ vec3_t filter; // starts out 1.0, 1.0, 1.0, may be reduced if
+ // transparent surfaces are crossed
+
+ vec3_t hit; // the impact point of a completely opaque surface
+ float hitFraction; // 0 = at start, 1.0 = at end
+ qboolean passSolid;
+} trace_t;
+
+extern surfaceTest_t *surfaceTest[MAX_MAP_DRAW_SURFS];
+
+void InitTrace( void );
+
+// traceWork_t is only a parameter to crutch up poor large local allocations on
+// winNT and macOS. It should be allocated in the worker function, but never
+// looked at.
+typedef struct {
+ vec3_t start, end;
+ int numOpenLeafs;
+ int openLeafNumbers[MAX_MAP_LEAFS];
+ trace_t *trace;
+ int patchshadows;
+} traceWork_t;
+
+void TraceLine( const vec3_t start, const vec3_t stop, trace_t *trace,
+ qboolean testAll, traceWork_t *tw );
+qboolean PointInSolid( vec3_t start );
+
+//===============================================================
+
+//===============================================================
+
+
+typedef struct {
+ int textureNum;
+ int x, y, width, height;
+
+ // for patches
+ qboolean patch;
+ mesh_t mesh;
+
+ // for faces
+ vec3_t origin;
+ vec3_t vecs[3];
+} lightmap_t;
+
+
diff --git a/q3map/light_trace.c b/q3map/light_trace.c
index f8a51e7..2c78575 100755
--- a/q3map/light_trace.c
+++ b/q3map/light_trace.c
@@ -19,926 +19,926 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-#include "light.h"
-
-
-
-#define CURVE_FACET_ERROR 8
-
-int c_totalTrace;
-int c_cullTrace, c_testTrace;
-int c_testFacets;
-
-surfaceTest_t *surfaceTest[MAX_MAP_DRAW_SURFS];
-
-/*
-=====================
-CM_GenerateBoundaryForPoints
-=====================
-*/
-void CM_GenerateBoundaryForPoints( float boundary[4], float plane[4], vec3_t a, vec3_t b ) {
- vec3_t d1;
-
- // amke a perpendicular vector to the edge and the surface
- VectorSubtract( b, a, d1 );
- CrossProduct( plane, d1, boundary );
- VectorNormalize( boundary, boundary );
- boundary[3] = DotProduct( a, boundary );
-}
-
-/*
-=====================
-TextureMatrixFromPoints
-=====================
-*/
-void TextureMatrixFromPoints( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
- int i, j;
- float t;
- float m[3][4];
- float s;
-
- // This is an incredibly stupid way of solving a three variable equation
- for ( i = 0 ; i < 2 ; i++ ) {
-
- m[0][0] = a->xyz[0];
- m[0][1] = a->xyz[1];
- m[0][2] = a->xyz[2];
- m[0][3] = a->st[i];
-
- m[1][0] = b->xyz[0];
- m[1][1] = b->xyz[1];
- m[1][2] = b->xyz[2];
- m[1][3] = b->st[i];
-
- m[2][0] = c->xyz[0];
- m[2][1] = c->xyz[1];
- m[2][2] = c->xyz[2];
- m[2][3] = c->st[i];
-
- if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) > fabs(m[2][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[1][j];
- m[1][j] = t;
- }
- } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) > fabs(m[1][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[2][j];
- m[2][j] = t;
- }
- }
-
- s = 1.0 / m[0][0];
- m[0][0] *= s;
- m[0][1] *= s;
- m[0][2] *= s;
- m[0][3] *= s;
-
- s = m[1][0];
- m[1][0] -= m[0][0] * s;
- m[1][1] -= m[0][1] * s;
- m[1][2] -= m[0][2] * s;
- m[1][3] -= m[0][3] * s;
-
- s = m[2][0];
- m[2][0] -= m[0][0] * s;
- m[2][1] -= m[0][1] * s;
- m[2][2] -= m[0][2] * s;
- m[2][3] -= m[0][3] * s;
-
- if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[1][j];
- m[1][j] = m[2][j];
- m[2][j] = t;
- }
- }
-
- s = 1.0 / m[1][1];
- m[1][0] *= s;
- m[1][1] *= s;
- m[1][2] *= s;
- m[1][3] *= s;
-
- s = m[2][1];
- m[2][0] -= m[1][0] * s;
- m[2][1] -= m[1][1] * s;
- m[2][2] -= m[1][2] * s;
- m[2][3] -= m[1][3] * s;
-
- s = 1.0 / m[2][2];
- m[2][0] *= s;
- m[2][1] *= s;
- m[2][2] *= s;
- m[2][3] *= s;
-
- f->textureMatrix[i][2] = m[2][3];
- f->textureMatrix[i][1] = m[1][3] - f->textureMatrix[i][2] * m[1][2];
- f->textureMatrix[i][0] = m[0][3] - f->textureMatrix[i][2] * m[0][2] - f->textureMatrix[i][1] * m[0][1];
-
- f->textureMatrix[i][3] = 0;
-/*
- s = fabs( DotProduct( a->xyz, f->textureMatrix[i] ) - a->st[i] );
- if ( s > 0.01 ) {
- Error( "Bad textureMatrix" );
- }
- s = fabs( DotProduct( b->xyz, f->textureMatrix[i] ) - b->st[i] );
- if ( s > 0.01 ) {
- Error( "Bad textureMatrix" );
- }
- s = fabs( DotProduct( c->xyz, f->textureMatrix[i] ) - c->st[i] );
- if ( s > 0.01 ) {
- Error( "Bad textureMatrix" );
- }
-*/
- }
-}
-
-/*
-=====================
-CM_GenerateFacetFor3Points
-=====================
-*/
-qboolean CM_GenerateFacetFor3Points( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
- // if we can't generate a valid plane for the points, ignore the facet
- if ( !PlaneFromPoints( f->surface, a->xyz, b->xyz, c->xyz ) ) {
- f->numBoundaries = 0;
- return qfalse;
- }
-
- // make boundaries
- f->numBoundaries = 3;
-
- CM_GenerateBoundaryForPoints( f->boundaries[0], f->surface, a->xyz, b->xyz );
- CM_GenerateBoundaryForPoints( f->boundaries[1], f->surface, b->xyz, c->xyz );
- CM_GenerateBoundaryForPoints( f->boundaries[2], f->surface, c->xyz, a->xyz );
-
- VectorCopy( a->xyz, f->points[0] );
- VectorCopy( b->xyz, f->points[1] );
- VectorCopy( c->xyz, f->points[2] );
-
- TextureMatrixFromPoints( f, a, b, c );
-
- return qtrue;
-}
-
-/*
-=====================
-CM_GenerateFacetFor4Points
-
-Attempts to use four points as a planar quad
-=====================
-*/
-#define PLANAR_EPSILON 0.1
-qboolean CM_GenerateFacetFor4Points( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c, drawVert_t *d ) {
- float dist;
- int i;
- vec4_t plane;
-
- // if we can't generate a valid plane for the points, ignore the facet
- if ( !PlaneFromPoints( f->surface, a->xyz, b->xyz, c->xyz ) ) {
- f->numBoundaries = 0;
- return qfalse;
- }
-
- // if the fourth point is also on the plane, we can make a quad facet
- dist = DotProduct( d->xyz, f->surface ) - f->surface[3];
- if ( fabs( dist ) > PLANAR_EPSILON ) {
- f->numBoundaries = 0;
- return qfalse;
- }
-
- // make boundaries
- f->numBoundaries = 4;
-
- CM_GenerateBoundaryForPoints( f->boundaries[0], f->surface, a->xyz, b->xyz );
- CM_GenerateBoundaryForPoints( f->boundaries[1], f->surface, b->xyz, c->xyz );
- CM_GenerateBoundaryForPoints( f->boundaries[2], f->surface, c->xyz, d->xyz );
- CM_GenerateBoundaryForPoints( f->boundaries[3], f->surface, d->xyz, a->xyz );
-
- VectorCopy( a->xyz, f->points[0] );
- VectorCopy( b->xyz, f->points[1] );
- VectorCopy( c->xyz, f->points[2] );
- VectorCopy( d->xyz, f->points[3] );
-
- for (i = 1; i < 4; i++)
- {
- if ( !PlaneFromPoints( plane, f->points[i], f->points[(i+1) % 4], f->points[(i+2) % 4]) ) {
- f->numBoundaries = 0;
- return qfalse;
- }
-
- if (DotProduct(f->surface, plane) < 0.9) {
- f->numBoundaries = 0;
- return qfalse;
- }
- }
-
- TextureMatrixFromPoints( f, a, b, c );
-
- return qtrue;
-}
-
-
-
-
-/*
-===============
-SphereFromBounds
-===============
-*/
-void SphereFromBounds( vec3_t mins, vec3_t maxs, vec3_t origin, float *radius ) {
- vec3_t temp;
-
- VectorAdd( mins, maxs, origin );
- VectorScale( origin, 0.5, origin );
- VectorSubtract( maxs, origin, temp );
- *radius = VectorLength( temp );
-}
-
-
-/*
-====================
-FacetsForTriangleSurface
-====================
-*/
-void FacetsForTriangleSurface( dsurface_t *dsurf, shaderInfo_t *si, surfaceTest_t *test ) {
- int i;
- drawVert_t *v1, *v2, *v3, *v4;
- int count;
- int i1, i2, i3, i4, i5, i6;
-
- test->patch = qfalse;
- test->numFacets = dsurf->numIndexes / 3;
- test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
- test->shader = si;
-
- count = 0;
- for ( i = 0 ; i < test->numFacets ; i++ ) {
- i1 = drawIndexes[ dsurf->firstIndex + i*3 ];
- i2 = drawIndexes[ dsurf->firstIndex + i*3 + 1 ];
- i3 = drawIndexes[ dsurf->firstIndex + i*3 + 2 ];
-
- v1 = &drawVerts[ dsurf->firstVert + i1 ];
- v2 = &drawVerts[ dsurf->firstVert + i2 ];
- v3 = &drawVerts[ dsurf->firstVert + i3 ];
-
- // try and make a quad out of two triangles
- if ( i != test->numFacets - 1 ) {
- i4 = drawIndexes[ dsurf->firstIndex + i*3 + 3 ];
- i5 = drawIndexes[ dsurf->firstIndex + i*3 + 4 ];
- i6 = drawIndexes[ dsurf->firstIndex + i*3 + 5 ];
- if ( i4 == i3 && i5 == i2 ) {
- v4 = &drawVerts[ dsurf->firstVert + i6 ];
- if ( CM_GenerateFacetFor4Points( &test->facets[count], v1, v2, v4, v3 ) ) {
- count++;
- i++; // skip next tri
- continue;
- }
- }
- }
-
- if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v2, v3 ))
- count++;
- }
-
- // we may have turned some pairs into quads
- test->numFacets = count;
-}
-
-/*
-====================
-FacetsForPatch
-====================
-*/
-void FacetsForPatch( dsurface_t *dsurf, shaderInfo_t *si, surfaceTest_t *test ) {
- int i, j;
- drawVert_t *v1, *v2, *v3, *v4;
- int count;
- mesh_t srcMesh, *subdivided, *mesh;
-
- srcMesh.width = dsurf->patchWidth;
- srcMesh.height = dsurf->patchHeight;
- srcMesh.verts = &drawVerts[ dsurf->firstVert ];
-
- //subdivided = SubdivideMesh( mesh, CURVE_FACET_ERROR, 9999 );
- mesh = SubdivideMesh( srcMesh, 8, 999 );
- PutMeshOnCurve( *mesh );
- MakeMeshNormals( *mesh );
-
- subdivided = RemoveLinearMeshColumnsRows( mesh );
- FreeMesh(mesh);
-
- test->patch = qtrue;
- test->numFacets = ( subdivided->width - 1 ) * ( subdivided->height - 1 ) * 2;
- test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
- test->shader = si;
-
- count = 0;
- for ( i = 0 ; i < subdivided->width - 1 ; i++ ) {
- for ( j = 0 ; j < subdivided->height - 1 ; j++ ) {
-
- v1 = subdivided->verts + j * subdivided->width + i;
- v2 = v1 + 1;
- v3 = v1 + subdivided->width + 1;
- v4 = v1 + subdivided->width;
-
- if ( CM_GenerateFacetFor4Points( &test->facets[count], v1, v4, v3, v2 ) ) {
- count++;
- } else {
- if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v4, v3 ))
- count++;
- if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v3, v2 ))
- count++;
- }
- }
- }
- test->numFacets = count;
- FreeMesh(subdivided);
-}
-
-
-/*
-=====================
-InitSurfacesForTesting
-
-Builds structures to speed the ray tracing against surfaces
-=====================
-*/
-void InitSurfacesForTesting( void ) {
-
- int i, j;
- dsurface_t *dsurf;
- surfaceTest_t *test;
- drawVert_t *dvert;
- shaderInfo_t *si;
-
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- dsurf = &drawSurfaces[ i ];
- if ( !dsurf->numIndexes && !dsurf->patchWidth ) {
- continue;
- }
-
- // don't make surfaces for transparent objects
- // because we want light to pass through them
- si = ShaderInfoForShader( dshaders[ dsurf->shaderNum].shader );
- if ( (si->contents & CONTENTS_TRANSLUCENT) && !(si->surfaceFlags & SURF_ALPHASHADOW) ) {
- continue;
- }
-
- test = malloc( sizeof( *test ) );
- surfaceTest[i] = test;
- ClearBounds( test->mins, test->maxs );
-
- dvert = &drawVerts[ dsurf->firstVert ];
- for ( j = 0 ; j < dsurf->numVerts ; j++, dvert++ ) {
- AddPointToBounds( dvert->xyz, test->mins, test->maxs );
- }
-
- SphereFromBounds( test->mins, test->maxs, test->origin, &test->radius );
-
- if ( dsurf->surfaceType == MST_TRIANGLE_SOUP || dsurf->surfaceType == MST_PLANAR ) {
- FacetsForTriangleSurface( dsurf, si, test );
- } else if ( dsurf->surfaceType == MST_PATCH ) {
- FacetsForPatch( dsurf, si, test );
- }
- }
-}
-
-
-/*
-=====================
-GenerateBoundaryForPoints
-=====================
-*/
-void GenerateBoundaryForPoints( float boundary[4], float plane[4], vec3_t a, vec3_t b ) {
- vec3_t d1;
-
- // amke a perpendicular vector to the edge and the surface
- VectorSubtract( b, a, d1 );
- CrossProduct( plane, d1, boundary );
- VectorNormalize( boundary, boundary );
- boundary[3] = DotProduct( a, boundary );
-}
-
-
-/*
-=================
-SetFacetFilter
-
-Given a point on a facet, determine the color filter
-for light passing through
-=================
-*/
-void SetFacetFilter( traceWork_t *tr, shaderInfo_t *shader, cFacet_t *facet, vec3_t point ) {
- float s, t;
- int is, it;
- byte *image;
- int b;
-
- // most surfaces are completely opaque
- if ( !(shader->surfaceFlags & SURF_ALPHASHADOW) ) {
- VectorClear( tr->trace->filter );
- return;
- }
-
- s = DotProduct( point, facet->textureMatrix[0] ) + facet->textureMatrix[0][3];
- t = DotProduct( point, facet->textureMatrix[1] ) + facet->textureMatrix[1][3];
-
- if ( !shader->pixels ) {
- // assume completely solid
- VectorClear( point );
- return;
- }
-
- s = s - floor( s );
- t = t - floor( t );
-
- is = s * shader->width;
- it = t * shader->height;
-
- image = shader->pixels + 4 * ( it * shader->width + is );
-
- // alpha filter
- b = image[3];
-
- // alpha test makes this a binary option
- b = b < 128 ? 0 : 255;
-
- tr->trace->filter[0] = tr->trace->filter[0] * (255-b) / 255;
- tr->trace->filter[1] = tr->trace->filter[1] * (255-b) / 255;
- tr->trace->filter[2] = tr->trace->filter[2] * (255-b) / 255;
-}
-
-
-/*
-====================
-TraceAgainstFacet
-
-Shader is needed for translucent surfaces
-====================
-*/
-void TraceAgainstFacet( traceWork_t *tr, shaderInfo_t *shader, cFacet_t *facet ) {
- int j;
- float d1, d2, d, f;
- vec3_t point;
- float dist;
-
- // ignore degenerate facets
- if ( facet->numBoundaries < 3 ) {
- return;
- }
-
- dist = facet->surface[3];
-
- // compare the trace endpoints against the facet plane
- d1 = DotProduct( tr->start, facet->surface ) - dist;
- if ( d1 > -1 && d1 < 1 ) {
- return; // don't self intersect
- }
- d2 = DotProduct( tr->end, facet->surface ) - dist;
- if ( d2 > -1 && d2 < 1 ) {
- return; // don't self intersect
- }
-
- // calculate the intersection fraction
- f = ( d1 - ON_EPSILON ) / ( d1 - d2 );
- if ( f <= 0 ) {
- return;
- }
- if ( f >= tr->trace->hitFraction ) {
- return; // we have hit something earlier
- }
-
- // calculate the intersection point
- for ( j = 0 ; j < 3 ; j++ ) {
- point[j] = tr->start[j] + f * ( tr->end[j] - tr->start[j] );
- }
-
- // check the point against the facet boundaries
- for ( j = 0 ; j < facet->numBoundaries ; j++ ) {
- // adjust the plane distance apropriately for mins/maxs
- dist = facet->boundaries[j][3];
-
- d = DotProduct( point, facet->boundaries[j] );
- if ( d > dist + ON_EPSILON ) {
- break; // outside the bounds
- }
- }
-
- if ( j != facet->numBoundaries ) {
- return; // we are outside the bounds of the facet
- }
-
- // we hit this facet
-
- // if this is a transparent surface, calculate filter value
- if ( shader->surfaceFlags & SURF_ALPHASHADOW ) {
- SetFacetFilter( tr, shader, facet, point );
- } else {
- // completely opaque
- VectorClear( tr->trace->filter );
- tr->trace->hitFraction = f;
- }
-
-// VectorCopy( facet->surface, tr->trace->plane.normal );
-// tr->trace->plane.dist = facet->surface[3];
-}
-
-
-/*
-===============================================================
-
- LINE TRACING
-
-===============================================================
-*/
-
-
-#define TRACE_ON_EPSILON 0.1
-
-typedef struct tnode_s
-{
- int type;
- vec3_t normal;
- float dist;
- int children[2];
- int planeNum;
-} tnode_t;
-
-#define MAX_TNODES (MAX_MAP_NODES*4)
-tnode_t *tnodes, *tnode_p;
-
-/*
-==============
-MakeTnode
-
-Converts the disk node structure into the efficient tracing structure
-==============
-*/
-void MakeTnode (int nodenum)
-{
- tnode_t *t;
- dplane_t *plane;
- int i;
- dnode_t *node;
- int leafNum;
-
- t = tnode_p++;
-
- node = dnodes + nodenum;
- plane = dplanes + node->planeNum;
-
- t->planeNum = node->planeNum;
- t->type = PlaneTypeForNormal( plane->normal );
- VectorCopy (plane->normal, t->normal);
- t->dist = plane->dist;
-
- for (i=0 ; i<2 ; i++)
- {
- if (node->children[i] < 0) {
- leafNum = -node->children[i] - 1;
- if ( dleafs[leafNum].cluster == -1 ) {
- // solid
- t->children[i] = leafNum | ( 1 << 31 ) | ( 1 << 30 );
- } else {
- t->children[i] = leafNum | ( 1 << 31 );
- }
- } else {
- t->children[i] = tnode_p - tnodes;
- MakeTnode (node->children[i]);
- }
- }
-
-}
-
-/*
-=============
-InitTrace
-
-Loads the node structure out of a .bsp file to be used for light occlusion
-=============
-*/
-void InitTrace( void ) {
- // 32 byte align the structs
- tnodes = malloc( (MAX_TNODES+1) * sizeof(tnode_t));
- tnodes = (tnode_t *)(((int)tnodes + 31)&~31);
- tnode_p = tnodes;
-
- MakeTnode (0);
-
- InitSurfacesForTesting();
-}
-
-
-/*
-===================
-PointInSolid
-===================
-*/
-qboolean PointInSolid_r( vec3_t start, int node ) {
- tnode_t *tnode;
- float front;
-
- while ( !(node & (1<<31) ) ) {
- tnode = &tnodes[node];
- switch (tnode->type) {
- case PLANE_X:
- front = start[0] - tnode->dist;
- break;
- case PLANE_Y:
- front = start[1] - tnode->dist;
- break;
- case PLANE_Z:
- front = start[2] - tnode->dist;
- break;
- default:
- front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist;
- break;
- }
-
- if ( front == 0 ) {
- // exactly on node, must check both sides
- return (qboolean) ( PointInSolid_r( start, tnode->children[0] )
- | PointInSolid_r( start, tnode->children[1] ) );
- }
-
- if ( front > 0 ) {
- node = tnode->children[0];
- } else {
- node = tnode->children[1];
- }
- }
-
- if ( node & ( 1 << 30 ) ) {
- return qtrue;
- }
- return qfalse;
-}
-
-/*
-=============
-PointInSolid
-
-=============
-*/
-qboolean PointInSolid( vec3_t start ) {
- return PointInSolid_r( start, 0 );
-}
-
-
-/*
-=============
-TraceLine_r
-
-Returns qtrue if something is hit and tracing can stop
-=============
-*/
-int TraceLine_r( int node, const vec3_t start, const vec3_t stop, traceWork_t *tw ) {
- tnode_t *tnode;
- float front, back;
- vec3_t mid;
- float frac;
- int side;
- int r;
-
- if (node & (1<<31)) {
- if (node & ( 1 << 30 ) ) {
- VectorCopy (start, tw->trace->hit);
- tw->trace->passSolid = qtrue;
- return qtrue;
- } else {
- // save the node off for more exact testing
- if ( tw->numOpenLeafs == MAX_MAP_LEAFS ) {
- return qfalse;
- }
- tw->openLeafNumbers[ tw->numOpenLeafs ] = node & ~(3 << 30);
- tw->numOpenLeafs++;
- return qfalse;
- }
- }
-
- tnode = &tnodes[node];
- switch (tnode->type) {
- case PLANE_X:
- front = start[0] - tnode->dist;
- back = stop[0] - tnode->dist;
- break;
- case PLANE_Y:
- front = start[1] - tnode->dist;
- back = stop[1] - tnode->dist;
- break;
- case PLANE_Z:
- front = start[2] - tnode->dist;
- back = stop[2] - tnode->dist;
- break;
- default:
- front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist;
- back = (stop[0]*tnode->normal[0] + stop[1]*tnode->normal[1] + stop[2]*tnode->normal[2]) - tnode->dist;
- break;
- }
-
- if (front >= -TRACE_ON_EPSILON && back >= -TRACE_ON_EPSILON) {
- return TraceLine_r (tnode->children[0], start, stop, tw);
- }
-
- if (front < TRACE_ON_EPSILON && back < TRACE_ON_EPSILON) {
- return TraceLine_r (tnode->children[1], start, stop, tw);
- }
-
- side = front < 0;
-
- frac = front / (front-back);
-
- mid[0] = start[0] + (stop[0] - start[0])*frac;
- mid[1] = start[1] + (stop[1] - start[1])*frac;
- mid[2] = start[2] + (stop[2] - start[2])*frac;
-
- r = TraceLine_r (tnode->children[side], start, mid, tw);
-
- if (r) {
- return r;
- }
-
-// trace->planeNum = tnode->planeNum;
- return TraceLine_r (tnode->children[!side], mid, stop, tw);
-}
-
-//==========================================================================================
-
-
-/*
-================
-SphereCull
-================
-*/
-qboolean SphereCull( vec3_t start, vec3_t stop, vec3_t origin, float radius ) {
- vec3_t v;
- float d;
- vec3_t dir;
- float len;
- vec3_t on;
-
- VectorSubtract( stop, start, dir );
- len = VectorNormalize( dir, dir );
-
- VectorSubtract( origin, start, v );
- d = DotProduct( v, dir );
- if ( d > len + radius ) {
- return qtrue; // too far ahead
- }
- if ( d < -radius ) {
- return qtrue; // too far behind
- }
- VectorMA( start, d, dir, on );
-
- VectorSubtract( on, origin, v );
-
- len = VectorLength( v );
-
- if ( len > radius ) {
- return qtrue; // too far to the side
- }
-
- return qfalse; // must be traced against
-}
-
-/*
-================
-TraceAgainstSurface
-================
-*/
-void TraceAgainstSurface( traceWork_t *tw, surfaceTest_t *surf ) {
- int i;
-
- // if surfaces are trans
- if ( SphereCull( tw->start, tw->end, surf->origin, surf->radius ) ) {
- if ( numthreads == 1 ) {
- c_cullTrace++;
- }
- return;
- }
-
- if ( numthreads == 1 ) {
- c_testTrace++;
- c_testFacets += surf->numFacets;
- }
-
- /*
- // MrE: backface culling
- if (!surf->patch && surf->numFacets) {
- // if the surface does not cast an alpha shadow
- if ( !(surf->shader->surfaceFlags & SURF_ALPHASHADOW) ) {
- vec3_t vec;
- VectorSubtract(tw->end, tw->start, vec);
- if (DotProduct(vec, surf->facets->surface) > 0)
- return;
- }
- }
- */
-
- // test against each facet
- for ( i = 0 ; i < surf->numFacets ; i++ ) {
- TraceAgainstFacet( tw, surf->shader, surf->facets + i );
- }
-}
-
-/*
-=============
-TraceLine
-
-Follow the trace just through the solid leafs first, and only
-if it passes that, trace against the objects inside the empty leafs
-Returns qtrue if the trace hit any
-
-traceWork_t is only a parameter to crutch up poor large local allocations on
-winNT and macOS. It should be allocated in the worker function, but never
-looked at.
-
-leave testAll false if all you care about is if it hit anything at all.
-if you need to know the exact first point of impact (for a sun trace), set
-testAll to true
-=============
-*/
-extern qboolean patchshadows;
-
-void TraceLine( const vec3_t start, const vec3_t stop, trace_t *trace, qboolean testAll, traceWork_t *tw ) {
- int r;
- int i, j;
- dleaf_t *leaf;
- float oldHitFrac;
- surfaceTest_t *test;
- int surfaceNum;
- byte surfaceTested[MAX_MAP_DRAW_SURFS/8];
- ;
-
- if ( numthreads == 1 ) {
- c_totalTrace++;
- }
-
- // assume all light gets through, unless the ray crosses
- // a translucent surface
- trace->filter[0] = 1.0;
- trace->filter[1] = 1.0;
- trace->filter[2] = 1.0;
-
- VectorCopy( start, tw->start );
- VectorCopy( stop, tw->end );
- tw->trace = trace;
-
- tw->numOpenLeafs = 0;
-
- trace->passSolid = qfalse;
- trace->hitFraction = 1.0;
-
- r = TraceLine_r( 0, start, stop, tw );
-
- // if we hit a solid leaf, stop without testing the leaf
- // surfaces. Note that the plane and endpoint might not
- // be the first solid intersection along the ray.
- if ( r && !testAll ) {
- return;
- }
-
- if ( noSurfaces ) {
- return;
- }
-
- memset( surfaceTested, 0, (numDrawSurfaces+7)/8 );
- oldHitFrac = trace->hitFraction;
-
- for ( i = 0 ; i < tw->numOpenLeafs ; i++ ) {
- leaf = &dleafs[ tw->openLeafNumbers[ i ] ];
- for ( j = 0 ; j < leaf->numLeafSurfaces ; j++ ) {
- surfaceNum = dleafsurfaces[ leaf->firstLeafSurface + j ];
-
- // make sure we don't test the same ray against a surface more than once
- if ( surfaceTested[ surfaceNum>>3 ] & ( 1 << ( surfaceNum & 7) ) ) {
- continue;
- }
- surfaceTested[ surfaceNum>>3 ] |= ( 1 << ( surfaceNum & 7 ) );
-
- test = surfaceTest[ surfaceNum ];
- if ( !test ) {
- continue;
- }
- //
- if ( !tw->patchshadows && test->patch ) {
- continue;
- }
- TraceAgainstSurface( tw, test );
- }
-
- // if the trace is now solid, we can't possibly hit anything closer
- if ( trace->hitFraction < oldHitFrac ) {
- trace->passSolid = qtrue;
- break;
- }
- }
-
- for ( i = 0 ; i < 3 ; i++ ) {
- trace->hit[i] = start[i] + ( stop[i] - start[i] ) * trace->hitFraction;
- }
-}
-
+#include "light.h"
+
+
+
+#define CURVE_FACET_ERROR 8
+
+int c_totalTrace;
+int c_cullTrace, c_testTrace;
+int c_testFacets;
+
+surfaceTest_t *surfaceTest[MAX_MAP_DRAW_SURFS];
+
+/*
+=====================
+CM_GenerateBoundaryForPoints
+=====================
+*/
+void CM_GenerateBoundaryForPoints( float boundary[4], float plane[4], vec3_t a, vec3_t b ) {
+ vec3_t d1;
+
+ // amke a perpendicular vector to the edge and the surface
+ VectorSubtract( b, a, d1 );
+ CrossProduct( plane, d1, boundary );
+ VectorNormalize( boundary, boundary );
+ boundary[3] = DotProduct( a, boundary );
+}
+
+/*
+=====================
+TextureMatrixFromPoints
+=====================
+*/
+void TextureMatrixFromPoints( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
+ int i, j;
+ float t;
+ float m[3][4];
+ float s;
+
+ // This is an incredibly stupid way of solving a three variable equation
+ for ( i = 0 ; i < 2 ; i++ ) {
+
+ m[0][0] = a->xyz[0];
+ m[0][1] = a->xyz[1];
+ m[0][2] = a->xyz[2];
+ m[0][3] = a->st[i];
+
+ m[1][0] = b->xyz[0];
+ m[1][1] = b->xyz[1];
+ m[1][2] = b->xyz[2];
+ m[1][3] = b->st[i];
+
+ m[2][0] = c->xyz[0];
+ m[2][1] = c->xyz[1];
+ m[2][2] = c->xyz[2];
+ m[2][3] = c->st[i];
+
+ if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) > fabs(m[2][0]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[0][j];
+ m[0][j] = m[1][j];
+ m[1][j] = t;
+ }
+ } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) > fabs(m[1][0]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[0][j];
+ m[0][j] = m[2][j];
+ m[2][j] = t;
+ }
+ }
+
+ s = 1.0 / m[0][0];
+ m[0][0] *= s;
+ m[0][1] *= s;
+ m[0][2] *= s;
+ m[0][3] *= s;
+
+ s = m[1][0];
+ m[1][0] -= m[0][0] * s;
+ m[1][1] -= m[0][1] * s;
+ m[1][2] -= m[0][2] * s;
+ m[1][3] -= m[0][3] * s;
+
+ s = m[2][0];
+ m[2][0] -= m[0][0] * s;
+ m[2][1] -= m[0][1] * s;
+ m[2][2] -= m[0][2] * s;
+ m[2][3] -= m[0][3] * s;
+
+ if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[1][j];
+ m[1][j] = m[2][j];
+ m[2][j] = t;
+ }
+ }
+
+ s = 1.0 / m[1][1];
+ m[1][0] *= s;
+ m[1][1] *= s;
+ m[1][2] *= s;
+ m[1][3] *= s;
+
+ s = m[2][1];
+ m[2][0] -= m[1][0] * s;
+ m[2][1] -= m[1][1] * s;
+ m[2][2] -= m[1][2] * s;
+ m[2][3] -= m[1][3] * s;
+
+ s = 1.0 / m[2][2];
+ m[2][0] *= s;
+ m[2][1] *= s;
+ m[2][2] *= s;
+ m[2][3] *= s;
+
+ f->textureMatrix[i][2] = m[2][3];
+ f->textureMatrix[i][1] = m[1][3] - f->textureMatrix[i][2] * m[1][2];
+ f->textureMatrix[i][0] = m[0][3] - f->textureMatrix[i][2] * m[0][2] - f->textureMatrix[i][1] * m[0][1];
+
+ f->textureMatrix[i][3] = 0;
+/*
+ s = fabs( DotProduct( a->xyz, f->textureMatrix[i] ) - a->st[i] );
+ if ( s > 0.01 ) {
+ Error( "Bad textureMatrix" );
+ }
+ s = fabs( DotProduct( b->xyz, f->textureMatrix[i] ) - b->st[i] );
+ if ( s > 0.01 ) {
+ Error( "Bad textureMatrix" );
+ }
+ s = fabs( DotProduct( c->xyz, f->textureMatrix[i] ) - c->st[i] );
+ if ( s > 0.01 ) {
+ Error( "Bad textureMatrix" );
+ }
+*/
+ }
+}
+
+/*
+=====================
+CM_GenerateFacetFor3Points
+=====================
+*/
+qboolean CM_GenerateFacetFor3Points( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
+ // if we can't generate a valid plane for the points, ignore the facet
+ if ( !PlaneFromPoints( f->surface, a->xyz, b->xyz, c->xyz ) ) {
+ f->numBoundaries = 0;
+ return qfalse;
+ }
+
+ // make boundaries
+ f->numBoundaries = 3;
+
+ CM_GenerateBoundaryForPoints( f->boundaries[0], f->surface, a->xyz, b->xyz );
+ CM_GenerateBoundaryForPoints( f->boundaries[1], f->surface, b->xyz, c->xyz );
+ CM_GenerateBoundaryForPoints( f->boundaries[2], f->surface, c->xyz, a->xyz );
+
+ VectorCopy( a->xyz, f->points[0] );
+ VectorCopy( b->xyz, f->points[1] );
+ VectorCopy( c->xyz, f->points[2] );
+
+ TextureMatrixFromPoints( f, a, b, c );
+
+ return qtrue;
+}
+
+/*
+=====================
+CM_GenerateFacetFor4Points
+
+Attempts to use four points as a planar quad
+=====================
+*/
+#define PLANAR_EPSILON 0.1
+qboolean CM_GenerateFacetFor4Points( cFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c, drawVert_t *d ) {
+ float dist;
+ int i;
+ vec4_t plane;
+
+ // if we can't generate a valid plane for the points, ignore the facet
+ if ( !PlaneFromPoints( f->surface, a->xyz, b->xyz, c->xyz ) ) {
+ f->numBoundaries = 0;
+ return qfalse;
+ }
+
+ // if the fourth point is also on the plane, we can make a quad facet
+ dist = DotProduct( d->xyz, f->surface ) - f->surface[3];
+ if ( fabs( dist ) > PLANAR_EPSILON ) {
+ f->numBoundaries = 0;
+ return qfalse;
+ }
+
+ // make boundaries
+ f->numBoundaries = 4;
+
+ CM_GenerateBoundaryForPoints( f->boundaries[0], f->surface, a->xyz, b->xyz );
+ CM_GenerateBoundaryForPoints( f->boundaries[1], f->surface, b->xyz, c->xyz );
+ CM_GenerateBoundaryForPoints( f->boundaries[2], f->surface, c->xyz, d->xyz );
+ CM_GenerateBoundaryForPoints( f->boundaries[3], f->surface, d->xyz, a->xyz );
+
+ VectorCopy( a->xyz, f->points[0] );
+ VectorCopy( b->xyz, f->points[1] );
+ VectorCopy( c->xyz, f->points[2] );
+ VectorCopy( d->xyz, f->points[3] );
+
+ for (i = 1; i < 4; i++)
+ {
+ if ( !PlaneFromPoints( plane, f->points[i], f->points[(i+1) % 4], f->points[(i+2) % 4]) ) {
+ f->numBoundaries = 0;
+ return qfalse;
+ }
+
+ if (DotProduct(f->surface, plane) < 0.9) {
+ f->numBoundaries = 0;
+ return qfalse;
+ }
+ }
+
+ TextureMatrixFromPoints( f, a, b, c );
+
+ return qtrue;
+}
+
+
+
+
+/*
+===============
+SphereFromBounds
+===============
+*/
+void SphereFromBounds( vec3_t mins, vec3_t maxs, vec3_t origin, float *radius ) {
+ vec3_t temp;
+
+ VectorAdd( mins, maxs, origin );
+ VectorScale( origin, 0.5, origin );
+ VectorSubtract( maxs, origin, temp );
+ *radius = VectorLength( temp );
+}
+
+
+/*
+====================
+FacetsForTriangleSurface
+====================
+*/
+void FacetsForTriangleSurface( dsurface_t *dsurf, shaderInfo_t *si, surfaceTest_t *test ) {
+ int i;
+ drawVert_t *v1, *v2, *v3, *v4;
+ int count;
+ int i1, i2, i3, i4, i5, i6;
+
+ test->patch = qfalse;
+ test->numFacets = dsurf->numIndexes / 3;
+ test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
+ test->shader = si;
+
+ count = 0;
+ for ( i = 0 ; i < test->numFacets ; i++ ) {
+ i1 = drawIndexes[ dsurf->firstIndex + i*3 ];
+ i2 = drawIndexes[ dsurf->firstIndex + i*3 + 1 ];
+ i3 = drawIndexes[ dsurf->firstIndex + i*3 + 2 ];
+
+ v1 = &drawVerts[ dsurf->firstVert + i1 ];
+ v2 = &drawVerts[ dsurf->firstVert + i2 ];
+ v3 = &drawVerts[ dsurf->firstVert + i3 ];
+
+ // try and make a quad out of two triangles
+ if ( i != test->numFacets - 1 ) {
+ i4 = drawIndexes[ dsurf->firstIndex + i*3 + 3 ];
+ i5 = drawIndexes[ dsurf->firstIndex + i*3 + 4 ];
+ i6 = drawIndexes[ dsurf->firstIndex + i*3 + 5 ];
+ if ( i4 == i3 && i5 == i2 ) {
+ v4 = &drawVerts[ dsurf->firstVert + i6 ];
+ if ( CM_GenerateFacetFor4Points( &test->facets[count], v1, v2, v4, v3 ) ) {
+ count++;
+ i++; // skip next tri
+ continue;
+ }
+ }
+ }
+
+ if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v2, v3 ))
+ count++;
+ }
+
+ // we may have turned some pairs into quads
+ test->numFacets = count;
+}
+
+/*
+====================
+FacetsForPatch
+====================
+*/
+void FacetsForPatch( dsurface_t *dsurf, shaderInfo_t *si, surfaceTest_t *test ) {
+ int i, j;
+ drawVert_t *v1, *v2, *v3, *v4;
+ int count;
+ mesh_t srcMesh, *subdivided, *mesh;
+
+ srcMesh.width = dsurf->patchWidth;
+ srcMesh.height = dsurf->patchHeight;
+ srcMesh.verts = &drawVerts[ dsurf->firstVert ];
+
+ //subdivided = SubdivideMesh( mesh, CURVE_FACET_ERROR, 9999 );
+ mesh = SubdivideMesh( srcMesh, 8, 999 );
+ PutMeshOnCurve( *mesh );
+ MakeMeshNormals( *mesh );
+
+ subdivided = RemoveLinearMeshColumnsRows( mesh );
+ FreeMesh(mesh);
+
+ test->patch = qtrue;
+ test->numFacets = ( subdivided->width - 1 ) * ( subdivided->height - 1 ) * 2;
+ test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
+ test->shader = si;
+
+ count = 0;
+ for ( i = 0 ; i < subdivided->width - 1 ; i++ ) {
+ for ( j = 0 ; j < subdivided->height - 1 ; j++ ) {
+
+ v1 = subdivided->verts + j * subdivided->width + i;
+ v2 = v1 + 1;
+ v3 = v1 + subdivided->width + 1;
+ v4 = v1 + subdivided->width;
+
+ if ( CM_GenerateFacetFor4Points( &test->facets[count], v1, v4, v3, v2 ) ) {
+ count++;
+ } else {
+ if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v4, v3 ))
+ count++;
+ if (CM_GenerateFacetFor3Points( &test->facets[count], v1, v3, v2 ))
+ count++;
+ }
+ }
+ }
+ test->numFacets = count;
+ FreeMesh(subdivided);
+}
+
+
+/*
+=====================
+InitSurfacesForTesting
+
+Builds structures to speed the ray tracing against surfaces
+=====================
+*/
+void InitSurfacesForTesting( void ) {
+
+ int i, j;
+ dsurface_t *dsurf;
+ surfaceTest_t *test;
+ drawVert_t *dvert;
+ shaderInfo_t *si;
+
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ dsurf = &drawSurfaces[ i ];
+ if ( !dsurf->numIndexes && !dsurf->patchWidth ) {
+ continue;
+ }
+
+ // don't make surfaces for transparent objects
+ // because we want light to pass through them
+ si = ShaderInfoForShader( dshaders[ dsurf->shaderNum].shader );
+ if ( (si->contents & CONTENTS_TRANSLUCENT) && !(si->surfaceFlags & SURF_ALPHASHADOW) ) {
+ continue;
+ }
+
+ test = malloc( sizeof( *test ) );
+ surfaceTest[i] = test;
+ ClearBounds( test->mins, test->maxs );
+
+ dvert = &drawVerts[ dsurf->firstVert ];
+ for ( j = 0 ; j < dsurf->numVerts ; j++, dvert++ ) {
+ AddPointToBounds( dvert->xyz, test->mins, test->maxs );
+ }
+
+ SphereFromBounds( test->mins, test->maxs, test->origin, &test->radius );
+
+ if ( dsurf->surfaceType == MST_TRIANGLE_SOUP || dsurf->surfaceType == MST_PLANAR ) {
+ FacetsForTriangleSurface( dsurf, si, test );
+ } else if ( dsurf->surfaceType == MST_PATCH ) {
+ FacetsForPatch( dsurf, si, test );
+ }
+ }
+}
+
+
+/*
+=====================
+GenerateBoundaryForPoints
+=====================
+*/
+void GenerateBoundaryForPoints( float boundary[4], float plane[4], vec3_t a, vec3_t b ) {
+ vec3_t d1;
+
+ // amke a perpendicular vector to the edge and the surface
+ VectorSubtract( b, a, d1 );
+ CrossProduct( plane, d1, boundary );
+ VectorNormalize( boundary, boundary );
+ boundary[3] = DotProduct( a, boundary );
+}
+
+
+/*
+=================
+SetFacetFilter
+
+Given a point on a facet, determine the color filter
+for light passing through
+=================
+*/
+void SetFacetFilter( traceWork_t *tr, shaderInfo_t *shader, cFacet_t *facet, vec3_t point ) {
+ float s, t;
+ int is, it;
+ byte *image;
+ int b;
+
+ // most surfaces are completely opaque
+ if ( !(shader->surfaceFlags & SURF_ALPHASHADOW) ) {
+ VectorClear( tr->trace->filter );
+ return;
+ }
+
+ s = DotProduct( point, facet->textureMatrix[0] ) + facet->textureMatrix[0][3];
+ t = DotProduct( point, facet->textureMatrix[1] ) + facet->textureMatrix[1][3];
+
+ if ( !shader->pixels ) {
+ // assume completely solid
+ VectorClear( point );
+ return;
+ }
+
+ s = s - floor( s );
+ t = t - floor( t );
+
+ is = s * shader->width;
+ it = t * shader->height;
+
+ image = shader->pixels + 4 * ( it * shader->width + is );
+
+ // alpha filter
+ b = image[3];
+
+ // alpha test makes this a binary option
+ b = b < 128 ? 0 : 255;
+
+ tr->trace->filter[0] = tr->trace->filter[0] * (255-b) / 255;
+ tr->trace->filter[1] = tr->trace->filter[1] * (255-b) / 255;
+ tr->trace->filter[2] = tr->trace->filter[2] * (255-b) / 255;
+}
+
+
+/*
+====================
+TraceAgainstFacet
+
+Shader is needed for translucent surfaces
+====================
+*/
+void TraceAgainstFacet( traceWork_t *tr, shaderInfo_t *shader, cFacet_t *facet ) {
+ int j;
+ float d1, d2, d, f;
+ vec3_t point;
+ float dist;
+
+ // ignore degenerate facets
+ if ( facet->numBoundaries < 3 ) {
+ return;
+ }
+
+ dist = facet->surface[3];
+
+ // compare the trace endpoints against the facet plane
+ d1 = DotProduct( tr->start, facet->surface ) - dist;
+ if ( d1 > -1 && d1 < 1 ) {
+ return; // don't self intersect
+ }
+ d2 = DotProduct( tr->end, facet->surface ) - dist;
+ if ( d2 > -1 && d2 < 1 ) {
+ return; // don't self intersect
+ }
+
+ // calculate the intersection fraction
+ f = ( d1 - ON_EPSILON ) / ( d1 - d2 );
+ if ( f <= 0 ) {
+ return;
+ }
+ if ( f >= tr->trace->hitFraction ) {
+ return; // we have hit something earlier
+ }
+
+ // calculate the intersection point
+ for ( j = 0 ; j < 3 ; j++ ) {
+ point[j] = tr->start[j] + f * ( tr->end[j] - tr->start[j] );
+ }
+
+ // check the point against the facet boundaries
+ for ( j = 0 ; j < facet->numBoundaries ; j++ ) {
+ // adjust the plane distance apropriately for mins/maxs
+ dist = facet->boundaries[j][3];
+
+ d = DotProduct( point, facet->boundaries[j] );
+ if ( d > dist + ON_EPSILON ) {
+ break; // outside the bounds
+ }
+ }
+
+ if ( j != facet->numBoundaries ) {
+ return; // we are outside the bounds of the facet
+ }
+
+ // we hit this facet
+
+ // if this is a transparent surface, calculate filter value
+ if ( shader->surfaceFlags & SURF_ALPHASHADOW ) {
+ SetFacetFilter( tr, shader, facet, point );
+ } else {
+ // completely opaque
+ VectorClear( tr->trace->filter );
+ tr->trace->hitFraction = f;
+ }
+
+// VectorCopy( facet->surface, tr->trace->plane.normal );
+// tr->trace->plane.dist = facet->surface[3];
+}
+
+
+/*
+===============================================================
+
+ LINE TRACING
+
+===============================================================
+*/
+
+
+#define TRACE_ON_EPSILON 0.1
+
+typedef struct tnode_s
+{
+ int type;
+ vec3_t normal;
+ float dist;
+ int children[2];
+ int planeNum;
+} tnode_t;
+
+#define MAX_TNODES (MAX_MAP_NODES*4)
+tnode_t *tnodes, *tnode_p;
+
+/*
+==============
+MakeTnode
+
+Converts the disk node structure into the efficient tracing structure
+==============
+*/
+void MakeTnode (int nodenum)
+{
+ tnode_t *t;
+ dplane_t *plane;
+ int i;
+ dnode_t *node;
+ int leafNum;
+
+ t = tnode_p++;
+
+ node = dnodes + nodenum;
+ plane = dplanes + node->planeNum;
+
+ t->planeNum = node->planeNum;
+ t->type = PlaneTypeForNormal( plane->normal );
+ VectorCopy (plane->normal, t->normal);
+ t->dist = plane->dist;
+
+ for (i=0 ; i<2 ; i++)
+ {
+ if (node->children[i] < 0) {
+ leafNum = -node->children[i] - 1;
+ if ( dleafs[leafNum].cluster == -1 ) {
+ // solid
+ t->children[i] = leafNum | ( 1 << 31 ) | ( 1 << 30 );
+ } else {
+ t->children[i] = leafNum | ( 1 << 31 );
+ }
+ } else {
+ t->children[i] = tnode_p - tnodes;
+ MakeTnode (node->children[i]);
+ }
+ }
+
+}
+
+/*
+=============
+InitTrace
+
+Loads the node structure out of a .bsp file to be used for light occlusion
+=============
+*/
+void InitTrace( void ) {
+ // 32 byte align the structs
+ tnodes = malloc( (MAX_TNODES+1) * sizeof(tnode_t));
+ tnodes = (tnode_t *)(((int)tnodes + 31)&~31);
+ tnode_p = tnodes;
+
+ MakeTnode (0);
+
+ InitSurfacesForTesting();
+}
+
+
+/*
+===================
+PointInSolid
+===================
+*/
+qboolean PointInSolid_r( vec3_t start, int node ) {
+ tnode_t *tnode;
+ float front;
+
+ while ( !(node & (1<<31) ) ) {
+ tnode = &tnodes[node];
+ switch (tnode->type) {
+ case PLANE_X:
+ front = start[0] - tnode->dist;
+ break;
+ case PLANE_Y:
+ front = start[1] - tnode->dist;
+ break;
+ case PLANE_Z:
+ front = start[2] - tnode->dist;
+ break;
+ default:
+ front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist;
+ break;
+ }
+
+ if ( front == 0 ) {
+ // exactly on node, must check both sides
+ return (qboolean) ( PointInSolid_r( start, tnode->children[0] )
+ | PointInSolid_r( start, tnode->children[1] ) );
+ }
+
+ if ( front > 0 ) {
+ node = tnode->children[0];
+ } else {
+ node = tnode->children[1];
+ }
+ }
+
+ if ( node & ( 1 << 30 ) ) {
+ return qtrue;
+ }
+ return qfalse;
+}
+
+/*
+=============
+PointInSolid
+
+=============
+*/
+qboolean PointInSolid( vec3_t start ) {
+ return PointInSolid_r( start, 0 );
+}
+
+
+/*
+=============
+TraceLine_r
+
+Returns qtrue if something is hit and tracing can stop
+=============
+*/
+int TraceLine_r( int node, const vec3_t start, const vec3_t stop, traceWork_t *tw ) {
+ tnode_t *tnode;
+ float front, back;
+ vec3_t mid;
+ float frac;
+ int side;
+ int r;
+
+ if (node & (1<<31)) {
+ if (node & ( 1 << 30 ) ) {
+ VectorCopy (start, tw->trace->hit);
+ tw->trace->passSolid = qtrue;
+ return qtrue;
+ } else {
+ // save the node off for more exact testing
+ if ( tw->numOpenLeafs == MAX_MAP_LEAFS ) {
+ return qfalse;
+ }
+ tw->openLeafNumbers[ tw->numOpenLeafs ] = node & ~(3 << 30);
+ tw->numOpenLeafs++;
+ return qfalse;
+ }
+ }
+
+ tnode = &tnodes[node];
+ switch (tnode->type) {
+ case PLANE_X:
+ front = start[0] - tnode->dist;
+ back = stop[0] - tnode->dist;
+ break;
+ case PLANE_Y:
+ front = start[1] - tnode->dist;
+ back = stop[1] - tnode->dist;
+ break;
+ case PLANE_Z:
+ front = start[2] - tnode->dist;
+ back = stop[2] - tnode->dist;
+ break;
+ default:
+ front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist;
+ back = (stop[0]*tnode->normal[0] + stop[1]*tnode->normal[1] + stop[2]*tnode->normal[2]) - tnode->dist;
+ break;
+ }
+
+ if (front >= -TRACE_ON_EPSILON && back >= -TRACE_ON_EPSILON) {
+ return TraceLine_r (tnode->children[0], start, stop, tw);
+ }
+
+ if (front < TRACE_ON_EPSILON && back < TRACE_ON_EPSILON) {
+ return TraceLine_r (tnode->children[1], start, stop, tw);
+ }
+
+ side = front < 0;
+
+ frac = front / (front-back);
+
+ mid[0] = start[0] + (stop[0] - start[0])*frac;
+ mid[1] = start[1] + (stop[1] - start[1])*frac;
+ mid[2] = start[2] + (stop[2] - start[2])*frac;
+
+ r = TraceLine_r (tnode->children[side], start, mid, tw);
+
+ if (r) {
+ return r;
+ }
+
+// trace->planeNum = tnode->planeNum;
+ return TraceLine_r (tnode->children[!side], mid, stop, tw);
+}
+
+//==========================================================================================
+
+
+/*
+================
+SphereCull
+================
+*/
+qboolean SphereCull( vec3_t start, vec3_t stop, vec3_t origin, float radius ) {
+ vec3_t v;
+ float d;
+ vec3_t dir;
+ float len;
+ vec3_t on;
+
+ VectorSubtract( stop, start, dir );
+ len = VectorNormalize( dir, dir );
+
+ VectorSubtract( origin, start, v );
+ d = DotProduct( v, dir );
+ if ( d > len + radius ) {
+ return qtrue; // too far ahead
+ }
+ if ( d < -radius ) {
+ return qtrue; // too far behind
+ }
+ VectorMA( start, d, dir, on );
+
+ VectorSubtract( on, origin, v );
+
+ len = VectorLength( v );
+
+ if ( len > radius ) {
+ return qtrue; // too far to the side
+ }
+
+ return qfalse; // must be traced against
+}
+
+/*
+================
+TraceAgainstSurface
+================
+*/
+void TraceAgainstSurface( traceWork_t *tw, surfaceTest_t *surf ) {
+ int i;
+
+ // if surfaces are trans
+ if ( SphereCull( tw->start, tw->end, surf->origin, surf->radius ) ) {
+ if ( numthreads == 1 ) {
+ c_cullTrace++;
+ }
+ return;
+ }
+
+ if ( numthreads == 1 ) {
+ c_testTrace++;
+ c_testFacets += surf->numFacets;
+ }
+
+ /*
+ // MrE: backface culling
+ if (!surf->patch && surf->numFacets) {
+ // if the surface does not cast an alpha shadow
+ if ( !(surf->shader->surfaceFlags & SURF_ALPHASHADOW) ) {
+ vec3_t vec;
+ VectorSubtract(tw->end, tw->start, vec);
+ if (DotProduct(vec, surf->facets->surface) > 0)
+ return;
+ }
+ }
+ */
+
+ // test against each facet
+ for ( i = 0 ; i < surf->numFacets ; i++ ) {
+ TraceAgainstFacet( tw, surf->shader, surf->facets + i );
+ }
+}
+
+/*
+=============
+TraceLine
+
+Follow the trace just through the solid leafs first, and only
+if it passes that, trace against the objects inside the empty leafs
+Returns qtrue if the trace hit any
+
+traceWork_t is only a parameter to crutch up poor large local allocations on
+winNT and macOS. It should be allocated in the worker function, but never
+looked at.
+
+leave testAll false if all you care about is if it hit anything at all.
+if you need to know the exact first point of impact (for a sun trace), set
+testAll to true
+=============
+*/
+extern qboolean patchshadows;
+
+void TraceLine( const vec3_t start, const vec3_t stop, trace_t *trace, qboolean testAll, traceWork_t *tw ) {
+ int r;
+ int i, j;
+ dleaf_t *leaf;
+ float oldHitFrac;
+ surfaceTest_t *test;
+ int surfaceNum;
+ byte surfaceTested[MAX_MAP_DRAW_SURFS/8];
+ ;
+
+ if ( numthreads == 1 ) {
+ c_totalTrace++;
+ }
+
+ // assume all light gets through, unless the ray crosses
+ // a translucent surface
+ trace->filter[0] = 1.0;
+ trace->filter[1] = 1.0;
+ trace->filter[2] = 1.0;
+
+ VectorCopy( start, tw->start );
+ VectorCopy( stop, tw->end );
+ tw->trace = trace;
+
+ tw->numOpenLeafs = 0;
+
+ trace->passSolid = qfalse;
+ trace->hitFraction = 1.0;
+
+ r = TraceLine_r( 0, start, stop, tw );
+
+ // if we hit a solid leaf, stop without testing the leaf
+ // surfaces. Note that the plane and endpoint might not
+ // be the first solid intersection along the ray.
+ if ( r && !testAll ) {
+ return;
+ }
+
+ if ( noSurfaces ) {
+ return;
+ }
+
+ memset( surfaceTested, 0, (numDrawSurfaces+7)/8 );
+ oldHitFrac = trace->hitFraction;
+
+ for ( i = 0 ; i < tw->numOpenLeafs ; i++ ) {
+ leaf = &dleafs[ tw->openLeafNumbers[ i ] ];
+ for ( j = 0 ; j < leaf->numLeafSurfaces ; j++ ) {
+ surfaceNum = dleafsurfaces[ leaf->firstLeafSurface + j ];
+
+ // make sure we don't test the same ray against a surface more than once
+ if ( surfaceTested[ surfaceNum>>3 ] & ( 1 << ( surfaceNum & 7) ) ) {
+ continue;
+ }
+ surfaceTested[ surfaceNum>>3 ] |= ( 1 << ( surfaceNum & 7 ) );
+
+ test = surfaceTest[ surfaceNum ];
+ if ( !test ) {
+ continue;
+ }
+ //
+ if ( !tw->patchshadows && test->patch ) {
+ continue;
+ }
+ TraceAgainstSurface( tw, test );
+ }
+
+ // if the trace is now solid, we can't possibly hit anything closer
+ if ( trace->hitFraction < oldHitFrac ) {
+ trace->passSolid = qtrue;
+ break;
+ }
+ }
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ trace->hit[i] = start[i] + ( stop[i] - start[i] ) * trace->hitFraction;
+ }
+}
+
diff --git a/q3map/lightmaps.c b/q3map/lightmaps.c
index 95064e5..ce1fc12 100755
--- a/q3map/lightmaps.c
+++ b/q3map/lightmaps.c
@@ -19,377 +19,377 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-#include "qbsp.h"
-
-
-/*
-
- Lightmap allocation has to be done after all flood filling and
- visible surface determination.
-
-*/
-
-int numSortShaders;
-mapDrawSurface_t *surfsOnShader[MAX_MAP_SHADERS];
-
-
-int allocated[LIGHTMAP_WIDTH];
-
-int numLightmaps = 1;
-int c_exactLightmap;
-
-
-void PrepareNewLightmap( void ) {
- memset( allocated, 0, sizeof( allocated ) );
- numLightmaps++;
-}
-
-/*
-===============
-AllocLMBlock
-
-returns a texture number and the position inside it
-===============
-*/
-qboolean AllocLMBlock (int w, int h, int *x, int *y)
-{
- int i, j;
- int best, best2;
-
- best = LIGHTMAP_HEIGHT;
-
- for ( i=0 ; i <= LIGHTMAP_WIDTH-w ; i++ ) {
- best2 = 0;
-
- for (j=0 ; j<w ; j++) {
- if (allocated[i+j] >= best) {
- break;
- }
- if (allocated[i+j] > best2) {
- best2 = allocated[i+j];
- }
- }
- if (j == w) { // this is a valid spot
- *x = i;
- *y = best = best2;
- }
- }
-
- if (best + h > LIGHTMAP_HEIGHT) {
- return qfalse;
- }
-
- for (i=0 ; i<w ; i++) {
- allocated[*x + i] = best + h;
- }
-
- return qtrue;
-}
-
-
-/*
-===================
-AllocateLightmapForPatch
-===================
-*/
-//#define LIGHTMAP_PATCHSHIFT
-
-void AllocateLightmapForPatch( mapDrawSurface_t *ds ) {
- int i, j, k;
- drawVert_t *verts;
- int w, h;
- int x, y;
- float s, t;
- mesh_t mesh, *subdividedMesh, *tempMesh, *newmesh;
- int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize;
-
- verts = ds->verts;
-
- mesh.width = ds->patchWidth;
- mesh.height = ds->patchHeight;
- mesh.verts = verts;
- newmesh = SubdivideMesh( mesh, 8, 999 );
-
- PutMeshOnCurve( *newmesh );
- tempMesh = RemoveLinearMeshColumnsRows( newmesh );
- FreeMesh(newmesh);
-
- ssize = samplesize;
- if (ds->shaderInfo->lightmapSampleSize)
- ssize = ds->shaderInfo->lightmapSampleSize;
-
-#ifdef LIGHTMAP_PATCHSHIFT
- subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH-1, widthtable, heighttable);
-#else
- subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH, widthtable, heighttable);
-#endif
-
- w = subdividedMesh->width;
- h = subdividedMesh->height;
-
-#ifdef LIGHTMAP_PATCHSHIFT
- w++;
- h++;
-#endif
-
- FreeMesh(subdividedMesh);
-
- // allocate the lightmap
- c_exactLightmap += w * h;
-
- if ( !AllocLMBlock( w, h, &x, &y ) ) {
- PrepareNewLightmap();
- if ( !AllocLMBlock( w, h, &x, &y ) ) {
- Error("Entity %i, brush %i: Lightmap allocation failed",
- ds->mapBrush->entitynum, ds->mapBrush->brushnum );
- }
- }
-
-#ifdef LIGHTMAP_PATCHSHIFT
- w--;
- h--;
-#endif
-
- // set the lightmap texture coordinates in the drawVerts
- ds->lightmapNum = numLightmaps - 1;
- ds->lightmapWidth = w;
- ds->lightmapHeight = h;
- ds->lightmapX = x;
- ds->lightmapY = y;
-
- for ( i = 0 ; i < ds->patchWidth ; i++ ) {
- for ( k = 0 ; k < w ; k++ ) {
- if ( originalWidths[k] >= i ) {
- break;
- }
- }
- if (k >= w)
- k = w-1;
- s = x + k;
- for ( j = 0 ; j < ds->patchHeight ; j++ ) {
- for ( k = 0 ; k < h ; k++ ) {
- if ( originalHeights[k] >= j ) {
- break;
- }
- }
- if (k >= h)
- k = h-1;
- t = y + k;
- verts[i + j * ds->patchWidth].lightmap[0] = ( s + 0.5 ) / LIGHTMAP_WIDTH;
- verts[i + j * ds->patchWidth].lightmap[1] = ( t + 0.5 ) / LIGHTMAP_HEIGHT;
- }
- }
-}
-
-
-/*
-===================
-AllocateLightmapForSurface
-===================
-*/
-//#define LIGHTMAP_BLOCK 16
-void AllocateLightmapForSurface( mapDrawSurface_t *ds ) {
- vec3_t mins, maxs, size, exactSize, delta;
- int i;
- drawVert_t *verts;
- int w, h;
- int x, y, ssize;
- int axis;
- vec3_t vecs[2];
- float s, t;
- vec3_t origin;
- plane_t *plane;
- float d;
- vec3_t planeNormal;
-
- if ( ds->patch ) {
- AllocateLightmapForPatch( ds );
- return;
- }
-
- ssize = samplesize;
- if (ds->shaderInfo->lightmapSampleSize)
- ssize = ds->shaderInfo->lightmapSampleSize;
-
- plane = &mapplanes[ ds->side->planenum ];
-
- // bound the surface
- ClearBounds( mins, maxs );
- verts = ds->verts;
- for ( i = 0 ; i < ds->numVerts ; i++ ) {
- AddPointToBounds( verts[i].xyz, mins, maxs );
- }
-
- // round to the lightmap resolution
- for ( i = 0 ; i < 3 ; i++ ) {
- exactSize[i] = maxs[i] - mins[i];
- mins[i] = ssize * floor( mins[i] / ssize );
- maxs[i] = ssize * ceil( maxs[i] / ssize );
- size[i] = (maxs[i] - mins[i]) / ssize + 1;
- }
-
- // the two largest axis will be the lightmap size
- memset( vecs, 0, sizeof( vecs ) );
-
- planeNormal[0] = fabs( plane->normal[0] );
- planeNormal[1] = fabs( plane->normal[1] );
- planeNormal[2] = fabs( plane->normal[2] );
-
- if ( planeNormal[0] >= planeNormal[1] && planeNormal[0] >= planeNormal[2] ) {
- w = size[1];
- h = size[2];
- axis = 0;
- vecs[0][1] = 1.0 / ssize;
- vecs[1][2] = 1.0 / ssize;
- } else if ( planeNormal[1] >= planeNormal[0] && planeNormal[1] >= planeNormal[2] ) {
- w = size[0];
- h = size[2];
- axis = 1;
- vecs[0][0] = 1.0 / ssize;
- vecs[1][2] = 1.0 / ssize;
- } else {
- w = size[0];
- h = size[1];
- axis = 2;
- vecs[0][0] = 1.0 / ssize;
- vecs[1][1] = 1.0 / ssize;
- }
-
- if ( !plane->normal[axis] ) {
- Error( "Chose a 0 valued axis" );
- }
-
- if ( w > LIGHTMAP_WIDTH ) {
- VectorScale ( vecs[0], (float)LIGHTMAP_WIDTH/w, vecs[0] );
- w = LIGHTMAP_WIDTH;
- }
-
- if ( h > LIGHTMAP_HEIGHT ) {
- VectorScale ( vecs[1], (float)LIGHTMAP_HEIGHT/h, vecs[1] );
- h = LIGHTMAP_HEIGHT;
- }
-
- c_exactLightmap += w * h;
-
- if ( !AllocLMBlock( w, h, &x, &y ) ) {
- PrepareNewLightmap();
- if ( !AllocLMBlock( w, h, &x, &y ) ) {
- Error("Entity %i, brush %i: Lightmap allocation failed",
- ds->mapBrush->entitynum, ds->mapBrush->brushnum );
- }
- }
-
- // set the lightmap texture coordinates in the drawVerts
- ds->lightmapNum = numLightmaps - 1;
- ds->lightmapWidth = w;
- ds->lightmapHeight = h;
- ds->lightmapX = x;
- ds->lightmapY = y;
-
- for ( i = 0 ; i < ds->numVerts ; i++ ) {
- VectorSubtract( verts[i].xyz, mins, delta );
- s = DotProduct( delta, vecs[0] ) + x + 0.5;
- t = DotProduct( delta, vecs[1] ) + y + 0.5;
- verts[i].lightmap[0] = s / LIGHTMAP_WIDTH;
- verts[i].lightmap[1] = t / LIGHTMAP_HEIGHT;
- }
-
- // calculate the world coordinates of the lightmap samples
-
- // project mins onto plane to get origin
- d = DotProduct( mins, plane->normal ) - plane->dist;
- d /= plane->normal[ axis ];
- VectorCopy( mins, origin );
- origin[axis] -= d;
-
- // project stepped lightmap blocks and subtract to get planevecs
- for ( i = 0 ; i < 2 ; i++ ) {
- vec3_t normalized;
- float len;
-
- len = VectorNormalize( vecs[i], normalized );
- VectorScale( normalized, (1.0/len), vecs[i] );
- d = DotProduct( vecs[i], plane->normal );
- d /= plane->normal[ axis ];
- vecs[i][axis] -= d;
- }
-
- VectorCopy( origin, ds->lightmapOrigin );
- VectorCopy( vecs[0], ds->lightmapVecs[0] );
- VectorCopy( vecs[1], ds->lightmapVecs[1] );
- VectorCopy( plane->normal, ds->lightmapVecs[2] );
-}
-
-/*
-===================
-AllocateLightmaps
-===================
-*/
-void AllocateLightmaps( entity_t *e ) {
- int i, j;
- mapDrawSurface_t *ds;
- shaderInfo_t *si;
-
- qprintf ("--- AllocateLightmaps ---\n");
-
-
- // sort all surfaces by shader so common shaders will usually
- // be in the same lightmap
- numSortShaders = 0;
-
- for ( i = e->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
- ds = &mapDrawSurfs[i];
- if ( !ds->numVerts ) {
- continue; // leftover from a surface subdivision
- }
- if ( ds->miscModel ) {
- continue;
- }
- if ( !ds->patch ) {
- VectorCopy( mapplanes[ds->side->planenum].normal, ds->lightmapVecs[2] );
- }
-
- // search for this shader
- for ( j = 0 ; j < numSortShaders ; j++ ) {
- if ( ds->shaderInfo == surfsOnShader[j]->shaderInfo ) {
- ds->nextOnShader = surfsOnShader[j];
- surfsOnShader[j] = ds;
- break;
- }
- }
- if ( j == numSortShaders ) {
- if ( numSortShaders >= MAX_MAP_SHADERS ) {
- Error( "MAX_MAP_SHADERS" );
- }
- surfsOnShader[j] = ds;
- numSortShaders++;
- }
- }
- qprintf( "%5i unique shaders\n", numSortShaders );
-
- // for each shader, allocate lightmaps for each surface
-
-// numLightmaps = 0;
-// PrepareNewLightmap();
-
- for ( i = 0 ; i < numSortShaders ; i++ ) {
- si = surfsOnShader[i]->shaderInfo;
-
- for ( ds = surfsOnShader[i] ; ds ; ds = ds->nextOnShader ) {
- // some surfaces don't need lightmaps allocated for them
- if ( si->surfaceFlags & SURF_NOLIGHTMAP ) {
- ds->lightmapNum = -1;
- } else if ( si->surfaceFlags & SURF_POINTLIGHT ) {
- ds->lightmapNum = -3;
- } else {
- AllocateLightmapForSurface( ds );
- }
- }
- }
-
- qprintf( "%7i exact lightmap texels\n", c_exactLightmap );
- qprintf( "%7i block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH*LIGHTMAP_HEIGHT );
-}
-
-
-
+#include "qbsp.h"
+
+
+/*
+
+ Lightmap allocation has to be done after all flood filling and
+ visible surface determination.
+
+*/
+
+int numSortShaders;
+mapDrawSurface_t *surfsOnShader[MAX_MAP_SHADERS];
+
+
+int allocated[LIGHTMAP_WIDTH];
+
+int numLightmaps = 1;
+int c_exactLightmap;
+
+
+void PrepareNewLightmap( void ) {
+ memset( allocated, 0, sizeof( allocated ) );
+ numLightmaps++;
+}
+
+/*
+===============
+AllocLMBlock
+
+returns a texture number and the position inside it
+===============
+*/
+qboolean AllocLMBlock (int w, int h, int *x, int *y)
+{
+ int i, j;
+ int best, best2;
+
+ best = LIGHTMAP_HEIGHT;
+
+ for ( i=0 ; i <= LIGHTMAP_WIDTH-w ; i++ ) {
+ best2 = 0;
+
+ for (j=0 ; j<w ; j++) {
+ if (allocated[i+j] >= best) {
+ break;
+ }
+ if (allocated[i+j] > best2) {
+ best2 = allocated[i+j];
+ }
+ }
+ if (j == w) { // this is a valid spot
+ *x = i;
+ *y = best = best2;
+ }
+ }
+
+ if (best + h > LIGHTMAP_HEIGHT) {
+ return qfalse;
+ }
+
+ for (i=0 ; i<w ; i++) {
+ allocated[*x + i] = best + h;
+ }
+
+ return qtrue;
+}
+
+
+/*
+===================
+AllocateLightmapForPatch
+===================
+*/
+//#define LIGHTMAP_PATCHSHIFT
+
+void AllocateLightmapForPatch( mapDrawSurface_t *ds ) {
+ int i, j, k;
+ drawVert_t *verts;
+ int w, h;
+ int x, y;
+ float s, t;
+ mesh_t mesh, *subdividedMesh, *tempMesh, *newmesh;
+ int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize;
+
+ verts = ds->verts;
+
+ mesh.width = ds->patchWidth;
+ mesh.height = ds->patchHeight;
+ mesh.verts = verts;
+ newmesh = SubdivideMesh( mesh, 8, 999 );
+
+ PutMeshOnCurve( *newmesh );
+ tempMesh = RemoveLinearMeshColumnsRows( newmesh );
+ FreeMesh(newmesh);
+
+ ssize = samplesize;
+ if (ds->shaderInfo->lightmapSampleSize)
+ ssize = ds->shaderInfo->lightmapSampleSize;
+
+#ifdef LIGHTMAP_PATCHSHIFT
+ subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH-1, widthtable, heighttable);
+#else
+ subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH, widthtable, heighttable);
+#endif
+
+ w = subdividedMesh->width;
+ h = subdividedMesh->height;
+
+#ifdef LIGHTMAP_PATCHSHIFT
+ w++;
+ h++;
+#endif
+
+ FreeMesh(subdividedMesh);
+
+ // allocate the lightmap
+ c_exactLightmap += w * h;
+
+ if ( !AllocLMBlock( w, h, &x, &y ) ) {
+ PrepareNewLightmap();
+ if ( !AllocLMBlock( w, h, &x, &y ) ) {
+ Error("Entity %i, brush %i: Lightmap allocation failed",
+ ds->mapBrush->entitynum, ds->mapBrush->brushnum );
+ }
+ }
+
+#ifdef LIGHTMAP_PATCHSHIFT
+ w--;
+ h--;
+#endif
+
+ // set the lightmap texture coordinates in the drawVerts
+ ds->lightmapNum = numLightmaps - 1;
+ ds->lightmapWidth = w;
+ ds->lightmapHeight = h;
+ ds->lightmapX = x;
+ ds->lightmapY = y;
+
+ for ( i = 0 ; i < ds->patchWidth ; i++ ) {
+ for ( k = 0 ; k < w ; k++ ) {
+ if ( originalWidths[k] >= i ) {
+ break;
+ }
+ }
+ if (k >= w)
+ k = w-1;
+ s = x + k;
+ for ( j = 0 ; j < ds->patchHeight ; j++ ) {
+ for ( k = 0 ; k < h ; k++ ) {
+ if ( originalHeights[k] >= j ) {
+ break;
+ }
+ }
+ if (k >= h)
+ k = h-1;
+ t = y + k;
+ verts[i + j * ds->patchWidth].lightmap[0] = ( s + 0.5 ) / LIGHTMAP_WIDTH;
+ verts[i + j * ds->patchWidth].lightmap[1] = ( t + 0.5 ) / LIGHTMAP_HEIGHT;
+ }
+ }
+}
+
+
+/*
+===================
+AllocateLightmapForSurface
+===================
+*/
+//#define LIGHTMAP_BLOCK 16
+void AllocateLightmapForSurface( mapDrawSurface_t *ds ) {
+ vec3_t mins, maxs, size, exactSize, delta;
+ int i;
+ drawVert_t *verts;
+ int w, h;
+ int x, y, ssize;
+ int axis;
+ vec3_t vecs[2];
+ float s, t;
+ vec3_t origin;
+ plane_t *plane;
+ float d;
+ vec3_t planeNormal;
+
+ if ( ds->patch ) {
+ AllocateLightmapForPatch( ds );
+ return;
+ }
+
+ ssize = samplesize;
+ if (ds->shaderInfo->lightmapSampleSize)
+ ssize = ds->shaderInfo->lightmapSampleSize;
+
+ plane = &mapplanes[ ds->side->planenum ];
+
+ // bound the surface
+ ClearBounds( mins, maxs );
+ verts = ds->verts;
+ for ( i = 0 ; i < ds->numVerts ; i++ ) {
+ AddPointToBounds( verts[i].xyz, mins, maxs );
+ }
+
+ // round to the lightmap resolution
+ for ( i = 0 ; i < 3 ; i++ ) {
+ exactSize[i] = maxs[i] - mins[i];
+ mins[i] = ssize * floor( mins[i] / ssize );
+ maxs[i] = ssize * ceil( maxs[i] / ssize );
+ size[i] = (maxs[i] - mins[i]) / ssize + 1;
+ }
+
+ // the two largest axis will be the lightmap size
+ memset( vecs, 0, sizeof( vecs ) );
+
+ planeNormal[0] = fabs( plane->normal[0] );
+ planeNormal[1] = fabs( plane->normal[1] );
+ planeNormal[2] = fabs( plane->normal[2] );
+
+ if ( planeNormal[0] >= planeNormal[1] && planeNormal[0] >= planeNormal[2] ) {
+ w = size[1];
+ h = size[2];
+ axis = 0;
+ vecs[0][1] = 1.0 / ssize;
+ vecs[1][2] = 1.0 / ssize;
+ } else if ( planeNormal[1] >= planeNormal[0] && planeNormal[1] >= planeNormal[2] ) {
+ w = size[0];
+ h = size[2];
+ axis = 1;
+ vecs[0][0] = 1.0 / ssize;
+ vecs[1][2] = 1.0 / ssize;
+ } else {
+ w = size[0];
+ h = size[1];
+ axis = 2;
+ vecs[0][0] = 1.0 / ssize;
+ vecs[1][1] = 1.0 / ssize;
+ }
+
+ if ( !plane->normal[axis] ) {
+ Error( "Chose a 0 valued axis" );
+ }
+
+ if ( w > LIGHTMAP_WIDTH ) {
+ VectorScale ( vecs[0], (float)LIGHTMAP_WIDTH/w, vecs[0] );
+ w = LIGHTMAP_WIDTH;
+ }
+
+ if ( h > LIGHTMAP_HEIGHT ) {
+ VectorScale ( vecs[1], (float)LIGHTMAP_HEIGHT/h, vecs[1] );
+ h = LIGHTMAP_HEIGHT;
+ }
+
+ c_exactLightmap += w * h;
+
+ if ( !AllocLMBlock( w, h, &x, &y ) ) {
+ PrepareNewLightmap();
+ if ( !AllocLMBlock( w, h, &x, &y ) ) {
+ Error("Entity %i, brush %i: Lightmap allocation failed",
+ ds->mapBrush->entitynum, ds->mapBrush->brushnum );
+ }
+ }
+
+ // set the lightmap texture coordinates in the drawVerts
+ ds->lightmapNum = numLightmaps - 1;
+ ds->lightmapWidth = w;
+ ds->lightmapHeight = h;
+ ds->lightmapX = x;
+ ds->lightmapY = y;
+
+ for ( i = 0 ; i < ds->numVerts ; i++ ) {
+ VectorSubtract( verts[i].xyz, mins, delta );
+ s = DotProduct( delta, vecs[0] ) + x + 0.5;
+ t = DotProduct( delta, vecs[1] ) + y + 0.5;
+ verts[i].lightmap[0] = s / LIGHTMAP_WIDTH;
+ verts[i].lightmap[1] = t / LIGHTMAP_HEIGHT;
+ }
+
+ // calculate the world coordinates of the lightmap samples
+
+ // project mins onto plane to get origin
+ d = DotProduct( mins, plane->normal ) - plane->dist;
+ d /= plane->normal[ axis ];
+ VectorCopy( mins, origin );
+ origin[axis] -= d;
+
+ // project stepped lightmap blocks and subtract to get planevecs
+ for ( i = 0 ; i < 2 ; i++ ) {
+ vec3_t normalized;
+ float len;
+
+ len = VectorNormalize( vecs[i], normalized );
+ VectorScale( normalized, (1.0/len), vecs[i] );
+ d = DotProduct( vecs[i], plane->normal );
+ d /= plane->normal[ axis ];
+ vecs[i][axis] -= d;
+ }
+
+ VectorCopy( origin, ds->lightmapOrigin );
+ VectorCopy( vecs[0], ds->lightmapVecs[0] );
+ VectorCopy( vecs[1], ds->lightmapVecs[1] );
+ VectorCopy( plane->normal, ds->lightmapVecs[2] );
+}
+
+/*
+===================
+AllocateLightmaps
+===================
+*/
+void AllocateLightmaps( entity_t *e ) {
+ int i, j;
+ mapDrawSurface_t *ds;
+ shaderInfo_t *si;
+
+ qprintf ("--- AllocateLightmaps ---\n");
+
+
+ // sort all surfaces by shader so common shaders will usually
+ // be in the same lightmap
+ numSortShaders = 0;
+
+ for ( i = e->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
+ ds = &mapDrawSurfs[i];
+ if ( !ds->numVerts ) {
+ continue; // leftover from a surface subdivision
+ }
+ if ( ds->miscModel ) {
+ continue;
+ }
+ if ( !ds->patch ) {
+ VectorCopy( mapplanes[ds->side->planenum].normal, ds->lightmapVecs[2] );
+ }
+
+ // search for this shader
+ for ( j = 0 ; j < numSortShaders ; j++ ) {
+ if ( ds->shaderInfo == surfsOnShader[j]->shaderInfo ) {
+ ds->nextOnShader = surfsOnShader[j];
+ surfsOnShader[j] = ds;
+ break;
+ }
+ }
+ if ( j == numSortShaders ) {
+ if ( numSortShaders >= MAX_MAP_SHADERS ) {
+ Error( "MAX_MAP_SHADERS" );
+ }
+ surfsOnShader[j] = ds;
+ numSortShaders++;
+ }
+ }
+ qprintf( "%5i unique shaders\n", numSortShaders );
+
+ // for each shader, allocate lightmaps for each surface
+
+// numLightmaps = 0;
+// PrepareNewLightmap();
+
+ for ( i = 0 ; i < numSortShaders ; i++ ) {
+ si = surfsOnShader[i]->shaderInfo;
+
+ for ( ds = surfsOnShader[i] ; ds ; ds = ds->nextOnShader ) {
+ // some surfaces don't need lightmaps allocated for them
+ if ( si->surfaceFlags & SURF_NOLIGHTMAP ) {
+ ds->lightmapNum = -1;
+ } else if ( si->surfaceFlags & SURF_POINTLIGHT ) {
+ ds->lightmapNum = -3;
+ } else {
+ AllocateLightmapForSurface( ds );
+ }
+ }
+ }
+
+ qprintf( "%7i exact lightmap texels\n", c_exactLightmap );
+ qprintf( "%7i block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH*LIGHTMAP_HEIGHT );
+}
+
+
+
diff --git a/q3map/lightv.c b/q3map/lightv.c
index dddecb7..3e9617b 100755
--- a/q3map/lightv.c
+++ b/q3map/lightv.c
@@ -20,5729 +20,5729 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include "cmdlib.h"
-#include "mathlib.h"
-#include "bspfile.h"
-#include "imagelib.h"
-#include "threads.h"
-#include "mutex.h"
-#include "scriplib.h"
-
-#include "shaders.h"
-#include "mesh.h"
-
-#ifdef _WIN32
-//Improve floating-point consistency.
-#pragma optimize( "p", on )
-#endif
-
-#ifdef _WIN32
-#include "../libs/pakstuff.h"
-#endif
-
-#define MAX_CLUSTERS 16384
-#define MAX_PORTALS 32768
-#define MAX_FACETS 65536
-#define MAX_LIGHTS 16384
-
-#define LIGHTMAP_SIZE 128
-
-#define LIGHTMAP_PIXELSHIFT 0.5
-
-//#define LIGHTMAP_PATCHSHIFT
-
-#define PORTALFILE "PRT1"
-
-#define ON_EPSILON 0.1
-
-#define VectorSet(v, x, y, z) v[0] = x;v[1] = y;v[2] = z;
-
-typedef struct
-{
- vec3_t normal;
- float dist;
-} plane_t;
-
-#define MAX_POINTS_ON_WINDING 64
-//NOTE: whenever this is overflowed parts of lightmaps might end up not being lit
-#define MAX_POINTS_ON_FIXED_WINDING 48
-
-typedef struct
-{
- int numpoints;
- vec3_t points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized
-} winding_t;
-
-typedef struct
-{
- plane_t plane; // normal pointing into neighbor
- int leaf; // neighbor
- winding_t *winding;
- vec3_t origin; // for fast clip testing
- float radius;
-} lportal_t;
-
-#define MAX_PORTALS_ON_LEAF 128
-typedef struct lleaf_s
-{
- int numportals;
- lportal_t *portals[MAX_PORTALS_ON_LEAF];
- //
- int numSurfaces;
- int firstSurface;
-} lleaf_t;
-
-typedef struct lFacet_s
-{
- int num;
- plane_t plane;
- vec3_t points[4]; //
- int numpoints;
- float lightmapCoords[4][2];
- plane_t boundaries[4]; // negative is outside the bounds
- float textureMatrix[2][4]; // texture coordinates for translucency
- float lightmapMatrix[2][4]; // lightmap texture coordinates
- vec3_t mins;
- int x, y, width, height;
-} lFacet_t;
-
-typedef struct lsurfaceTest_s
-{
- vec3_t mins, maxs;
- vec3_t origin;
- float radius;
- qboolean patch; // true if this is a patch
- qboolean trisoup; // true if this is a triangle soup
- int numFacets;
- lFacet_t *facets;
- mesh_t *detailMesh; // detailed mesh with points for each lmp
- shaderInfo_t *shader; // for translucency
- mutex_t *mutex;
- int numvolumes; // number of volumes casted at this surface
- //
- int always_tracelight;
- int always_vlight;
-} lsurfaceTest_t;
-
-//volume types
-#define VOLUME_NORMAL 0
-#define VOLUME_DIRECTED 1
-
-#define MAX_TRANSLUCENTFACETS 32
-
-typedef struct lightvolume_s
-{
- int num;
- int cluster; //cluster this light volume started in
- plane_t endplane; //end plane
- plane_t farplane; //original end plane
- vec3_t points[MAX_POINTS_ON_WINDING]; //end winding points
- plane_t planes[MAX_POINTS_ON_WINDING]; //volume bounding planes
- int numplanes; //number of volume bounding planes
- int type; //light volume type
- //list with translucent surfaces the volume went through
- int transFacets[MAX_TRANSLUCENTFACETS];
- int transSurfaces[MAX_TRANSLUCENTFACETS];
- int numtransFacets;
- //clusters already tested
- byte clusterTested[MAX_CLUSTERS/8];
- //facets already tested
- byte facetTested[MAX_FACETS/8];
- int facetNum; //number of the facet blocking the light in this volume
- int surfaceNum; //number of the surface blocking the light in this volume
-} lightvolume_t;
-
-//light types
-#define LIGHT_POINTRADIAL 1
-#define LIGHT_POINTSPOT 2
-#define LIGHT_POINTFAKESURFACE 3
-#define LIGHT_SURFACEDIRECTED 4
-#define LIGHT_SURFACERADIAL 5
-#define LIGHT_SURFACESPOT 6
-
-//light distance attenuation types
-#define LDAT_QUADRATIC 0
-#define LDAT_LINEAR 1
-#define LDAT_NOSCALE 2
-
-//light angle attenuation types
-#define LAAT_NORMAL 0
-#define LAAT_QUADRATIC 1
-#define LAAT_DOUBLEQUADRATIC 2
-
-typedef struct vlight_s
-{
- vec3_t origin; //light origin, for point lights
- winding_t w; //light winding, for area lights
- vec4_t plane; //light winding plane
- vec3_t normal; //direction of the light
- int type; //light type
- vec3_t color; //light color
- qboolean twosided; //radiates light at both sides of the winding
- int style; //light style (not used)
- int atten_disttype; //light distance attenuation type
- int atten_angletype; //light angle attenuation type
- float atten_distscale; //distance attenuation scale
- float atten_anglescale; //angle attenuation scale
- float radiusByDist; //radius by distance for spot lights
- float photons; //emitted photons
- float intensity; //intensity
- vec3_t emitColor; //full out-of-gamut value (not used)
- struct shaderInfo_s *si; //shader info
- int insolid; //set when light is in solid
-} vlight_t;
-
-float lightLinearScale = 1.0 / 8000;
-float lightPointScale = 7500;
-float lightAreaScale = 0.25;
-float lightFormFactorValueScale = 3;
-int lightDefaultSubdivide = 999; // vary by surface size?
-vec3_t lightAmbientColor;
-
-int portalclusters, numportals, numfaces;
-lleaf_t *leafs;
-lportal_t *portals;
-int numvlights = 0;
-vlight_t *vlights[MAX_LIGHTS];
-int nostitching = 0;
-int noalphashading = 0;
-int nocolorshading = 0;
-int nobackfaceculling = 0;
-int defaulttracelight = 0;
-int radiosity = 0;
-int radiosity_scale;
-
-int clustersurfaces[MAX_MAP_LEAFFACES];
-int numclustersurfaces = 0;
-lsurfaceTest_t *lsurfaceTest[MAX_MAP_DRAW_SURFS];
-int numfacets;
-float lightmappixelarea[MAX_MAP_LIGHTING/3];
-float *lightFloats;//[MAX_MAP_LIGHTING];
-
-// from polylib.c
-winding_t *AllocWinding (int points);
-void FreeWinding (winding_t *w);
-void WindingCenter (winding_t *w, vec3_t center);
-void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs);
-vec_t WindingArea (winding_t *w);
-winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist);
-void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
- vec_t epsilon, winding_t **front, winding_t **back);
-winding_t *ReverseWinding (winding_t *w);
-
-// from light.c
-extern char source[1024];
-extern vec3_t surfaceOrigin[ MAX_MAP_DRAW_SURFS ];
-extern int entitySurface[ MAX_MAP_DRAW_SURFS ];
-extern int samplesize;
-extern int novertexlighting;
-extern int nogridlighting;
-extern qboolean patchshadows;
-extern vec3_t gridSize;
-
-float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w );
-void ColorToBytes( const float *color, byte *colorBytes );
-void CountLightmaps( void );
-void GridAndVertexLighting( void );
-void SetEntityOrigins( void );
-
-
-//#define DEBUGNET
-
-#ifdef DEBUGNET
-
-#include "l_net.h"
-
-socket_t *debug_socket;
-
-/*
-=====================
-DebugNet_Setup
-=====================
-*/
-void DebugNet_Setup(void)
-{
- address_t address;
- int i;
-
- Net_Setup();
- Net_StringToAddress("127.0.0.1:28000", &address);
- for (i = 0; i < 10; i++)
- {
- debug_socket = Net_Connect(&address, 28005 + i);
- if (debug_socket)
- break;
- }
-}
-
-/*
-=====================
-DebugNet_Shutdown
-=====================
-*/
-void DebugNet_Shutdown(void)
-{
- netmessage_t msg;
-
- if (debug_socket)
- {
- NMSG_Clear(&msg);
- NMSG_WriteByte(&msg, 1);
- Net_Send(debug_socket, &msg);
- Net_Disconnect(debug_socket);
- }
- debug_socket = NULL;
- Net_Shutdown();
-}
-
-/*
-=====================
-DebugNet_RemoveAllPolys
-=====================
-*/
-void DebugNet_RemoveAllPolys(void)
-{
- netmessage_t msg;
-
- if (!debug_socket)
- return;
- NMSG_Clear(&msg);
- NMSG_WriteByte(&msg, 2); //remove all debug polys
- Net_Send(debug_socket, &msg);
-}
-
-/*
-====================
-DebugNet_DrawWinding
-=====================
-*/
-void DebugNet_DrawWinding(winding_t *w, int color)
-{
- netmessage_t msg;
- int i;
-
- if (!debug_socket)
- return;
- NMSG_Clear(&msg);
- NMSG_WriteByte(&msg, 0); //draw a winding
- NMSG_WriteByte(&msg, w->numpoints); //number of points
- NMSG_WriteLong(&msg, color); //color
- for (i = 0; i < w->numpoints; i++)
- {
- NMSG_WriteFloat(&msg, w->points[i][0]);
- NMSG_WriteFloat(&msg, w->points[i][1]);
- NMSG_WriteFloat(&msg, w->points[i][2]);
- }
- Net_Send(debug_socket, &msg);
-}
-
-/*
-=====================
-DebugNet_DrawLine
-=====================
-*/
-void DebugNet_DrawLine(vec3_t p1, vec3_t p2, int color)
-{
- netmessage_t msg;
-
- if (!debug_socket)
- return;
- NMSG_Clear(&msg);
- NMSG_WriteByte(&msg, 1); //draw a line
- NMSG_WriteLong(&msg, color); //color
- NMSG_WriteFloat(&msg, p1[0]);
- NMSG_WriteFloat(&msg, p1[1]);
- NMSG_WriteFloat(&msg, p1[2]);
- NMSG_WriteFloat(&msg, p2[0]);
- NMSG_WriteFloat(&msg, p2[1]);
- NMSG_WriteFloat(&msg, p2[2]);
- Net_Send(debug_socket, &msg);
-}
-
-/*
-=====================
-DebugNet_DrawMesh
-=====================
-*/
-void DebugNet_DrawMesh(mesh_t *mesh)
-{
- int i, j;
- float dot;
- drawVert_t *v1, *v2, *v3, *v4;
- winding_t winding;
- plane_t plane;
- vec3_t d1, d2;
-
- for ( i = 0 ; i < mesh->width - 1 ; i++ ) {
- for ( j = 0 ; j < mesh->height - 1 ; j++ ) {
-
- v1 = mesh->verts + j * mesh->width + i;
- v2 = v1 + 1;
- v3 = v1 + mesh->width + 1;
- v4 = v1 + mesh->width;
-
- VectorSubtract( v4->xyz, v1->xyz, d1 );
- VectorSubtract( v3->xyz, v1->xyz, d2 );
- CrossProduct( d2, d1, plane.normal );
- if ( VectorNormalize( plane.normal, plane.normal ) != 0 )
- {
- plane.dist = DotProduct( v1->xyz, plane.normal );
- dot = DotProduct(plane.normal, v2->xyz) - plane.dist;
- if (fabs(dot) < 0.1)
- {
- VectorCopy(v1->xyz, winding.points[0]);
- VectorCopy(v4->xyz, winding.points[1]);
- VectorCopy(v3->xyz, winding.points[2]);
- VectorCopy(v2->xyz, winding.points[3]);
- winding.numpoints = 4;
- DebugNet_DrawWinding(&winding, 2);
- continue;
- }
- }
-
- winding.numpoints = 3;
- VectorCopy(v1->xyz, winding.points[0]);
- VectorCopy(v4->xyz, winding.points[1]);
- VectorCopy(v3->xyz, winding.points[2]);
- DebugNet_DrawWinding(&winding, 2);
-
- VectorCopy(v1->xyz, winding.points[0]);
- VectorCopy(v3->xyz, winding.points[1]);
- VectorCopy(v2->xyz, winding.points[2]);
- DebugNet_DrawWinding(&winding, 2);
- }
- }
-}
-
-/*
-=====================
-VL_DrawLightVolume
-=====================
-*/
-int VL_ChopWinding (winding_t *in, plane_t *split, float epsilon);
-
-void VL_DrawLightVolume(vlight_t *light, lightvolume_t *volume)
-{
- winding_t w;
- int i;
- vec3_t p2, invlight;
-
- memcpy(w.points, volume->points, volume->numplanes * sizeof(vec3_t));
- w.numpoints = volume->numplanes;
- DebugNet_DrawWinding(&w, 2);
-
- if (volume->type == VOLUME_DIRECTED)
- {
- VectorCopy(light->normal, invlight);
- VectorInverse(invlight);
- for (i = 0; i < volume->numplanes; i++)
- {
- VectorCopy(volume->points[i], w.points[0]);
- VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[1]);
- VectorMA(w.points[1], MAX_WORLD_COORD, invlight, w.points[2]);
- VectorMA(w.points[0], MAX_WORLD_COORD, invlight, w.points[3]);
- w.numpoints = 4;
- DebugNet_DrawWinding(&w, 2);
- VectorMA(volume->points[i], 8, volume->planes[i].normal, p2);
- DebugNet_DrawLine(volume->points[i], p2, 3);
- }
- }
- else
- {
- //
- VectorCopy(light->origin, w.points[0]);
- w.numpoints = 3;
- for (i = 0; i < volume->numplanes; i++)
- {
- VectorCopy(volume->points[i], w.points[1]);
- VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[2]);
- VL_ChopWinding(&w, &volume->endplane, 0);
- DebugNet_DrawWinding(&w, 2);
- VectorMA(volume->points[i], 8, volume->planes[i].normal, p2);
- DebugNet_DrawLine(volume->points[i], p2, 3);
- }
- }
-}
-
-/*
-=============
-VL_DrawLightmapPixel
-=============
-*/
-void VL_DrawLightmapPixel(int surfaceNum, int x, int y, int color)
-{
- winding_t w;
- dsurface_t *ds;
- mesh_t *mesh;
-
- ds = &drawSurfaces[surfaceNum];
-
- if (ds->surfaceType == MST_PATCH)
- {
- mesh = lsurfaceTest[surfaceNum]->detailMesh;
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]);
- VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]);
- VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]);
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]);
- w.numpoints = 4;
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]);
- VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]);
- VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]);
- VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]);
- VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]);
- w.numpoints = 4;
- }
- DebugNet_DrawWinding(&w, color);
-}
-
-/*
-============
-VL_DrawPortals
-============
-*/
-void VL_DrawPortals(void)
-{
- int j;
- lportal_t *p;
-
- for (j = 0; j < numportals * 2; j++)
- {
- p = portals + j;
- DebugNet_DrawWinding(p->winding, 1);
- }
-}
-
-/*
-============
-VL_DrawLeaf
-============
-*/
-void VL_DrawLeaf(int cluster)
-{
- int i;
- lleaf_t *leaf;
- lportal_t *p;
-
- leaf = &leafs[cluster];
- for (i = 0; i < leaf->numportals; i++)
- {
- p = leaf->portals[i];
- DebugNet_DrawWinding(p->winding, 1);
- }
-}
-
-#endif //DEBUGNET
-
-/*
-=============
-VL_SplitWinding
-=============
-*/
-int VL_SplitWinding (winding_t *in, winding_t *back, plane_t *split, float epsilon)
-{
- vec_t dists[128];
- int sides[128];
- int counts[3];
- vec_t dot;
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- winding_t out;
- winding_t *neww;
-
- counts[0] = counts[1] = counts[2] = 0;
-
- // determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
-
- if (!counts[SIDE_BACK])
- {
- if (!counts[SIDE_FRONT])
- return SIDE_ON;
- else
- return SIDE_FRONT;
- }
-
- if (!counts[SIDE_FRONT])
- {
- return SIDE_BACK;
- }
-
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- neww = &out;
-
- neww->numpoints = 0;
- back->numpoints = 0;
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->points[i];
-
- if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
- if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT;
- }
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- VectorCopy (p1, back->points[back->numpoints]);
- back->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
- if (sides[i] == SIDE_BACK)
- {
- VectorCopy (p1, back->points[back->numpoints]);
- back->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
-
- if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
-
- // generate a split point
- p2 = in->points[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, neww->points[neww->numpoints]);
- neww->numpoints++;
- VectorCopy (mid, back->points[back->numpoints]);
- back->numpoints++;
- }
- memcpy(in, &out, sizeof(winding_t));
-
- return SIDE_CROSS;
-}
-
-/*
-=====================
-VL_LinkSurfaceIntoCluster
-=====================
-*/
-void VL_LinkSurfaceIntoCluster(int cluster, int surfaceNum)
-{
- lleaf_t *leaf;
- int i;
-
- leaf = &leafs[cluster];
-
- for (i = 0; i < leaf->numSurfaces; i++)
- {
- if (clustersurfaces[leaf->firstSurface + i] == surfaceNum)
- return;
- }
- for (i = numclustersurfaces; i > leaf->firstSurface + leaf->numSurfaces; i--)
- clustersurfaces[i] = clustersurfaces[i-1];
- for (i = 0; i < portalclusters; i++)
- {
- if (i == cluster)
- continue;
- if (leafs[i].firstSurface >= leaf->firstSurface + leaf->numSurfaces)
- leafs[i].firstSurface++;
- }
- clustersurfaces[leaf->firstSurface + leaf->numSurfaces] = surfaceNum;
- leaf->numSurfaces++;
- numclustersurfaces++;
- if (numclustersurfaces >= MAX_MAP_LEAFFACES)
- Error("MAX_MAP_LEAFFACES");
-}
-
-/*
-=====================
-VL_R_LinkSurface
-=====================
-*/
-void VL_R_LinkSurface(int nodenum, int surfaceNum, winding_t *w)
-{
- int leafnum, cluster, res;
- dnode_t *node;
- dplane_t *plane;
- winding_t back;
- plane_t split;
-
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
-
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VL_SplitWinding (w, &back, &split, 0.1);
-
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- memcpy(&back, w, sizeof(winding_t));
- VL_R_LinkSurface(node->children[1], surfaceNum, &back);
- nodenum = node->children[0];
- }
- else
- {
- VL_R_LinkSurface(node->children[1], surfaceNum, &back);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- cluster = dleafs[leafnum].cluster;
- if (cluster != -1)
- {
- VL_LinkSurfaceIntoCluster(cluster, surfaceNum);
- }
-}
-
-/*
-=====================
-VL_LinkSurfaces
-
-maybe link each facet seperately instead of the test surfaces?
-=====================
-*/
-void VL_LinkSurfaces(void)
-{
- int i, j;
- lsurfaceTest_t *test;
- lFacet_t *facet;
- winding_t winding;
-
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- for (j = 0; j < test->numFacets; j++)
- {
- facet = &test->facets[j];
- memcpy(winding.points, facet->points, facet->numpoints * sizeof(vec3_t));
- winding.numpoints = facet->numpoints;
- VL_R_LinkSurface(0, i, &winding);
- }
- }
-}
-
-/*
-=====================
-VL_TextureMatrixFromPoints
-=====================
-*/
-void VL_TextureMatrixFromPoints( lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
- int i, j;
- float t;
- float m[3][4];
- float s;
-
- // This is an incredibly stupid way of solving a three variable equation
- for ( i = 0 ; i < 2 ; i++ ) {
-
- m[0][0] = a->xyz[0];
- m[0][1] = a->xyz[1];
- m[0][2] = a->xyz[2];
- m[0][3] = a->st[i];
-
- m[1][0] = b->xyz[0];
- m[1][1] = b->xyz[1];
- m[1][2] = b->xyz[2];
- m[1][3] = b->st[i];
-
- m[2][0] = c->xyz[0];
- m[2][1] = c->xyz[1];
- m[2][2] = c->xyz[2];
- m[2][3] = c->st[i];
-
- if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) > fabs(m[2][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[1][j];
- m[1][j] = t;
- }
- } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) > fabs(m[1][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[2][j];
- m[2][j] = t;
- }
- }
-
- s = 1.0 / m[0][0];
- m[0][0] *= s;
- m[0][1] *= s;
- m[0][2] *= s;
- m[0][3] *= s;
-
- s = m[1][0];
- m[1][0] -= m[0][0] * s;
- m[1][1] -= m[0][1] * s;
- m[1][2] -= m[0][2] * s;
- m[1][3] -= m[0][3] * s;
-
- s = m[2][0];
- m[2][0] -= m[0][0] * s;
- m[2][1] -= m[0][1] * s;
- m[2][2] -= m[0][2] * s;
- m[2][3] -= m[0][3] * s;
-
- if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[1][j];
- m[1][j] = m[2][j];
- m[2][j] = t;
- }
- }
-
- s = 1.0 / m[1][1];
- m[1][0] *= s;
- m[1][1] *= s;
- m[1][2] *= s;
- m[1][3] *= s;
-
- s = m[2][1];// / m[1][1];
- m[2][0] -= m[1][0] * s;
- m[2][1] -= m[1][1] * s;
- m[2][2] -= m[1][2] * s;
- m[2][3] -= m[1][3] * s;
-
- s = 1.0 / m[2][2];
- m[2][0] *= s;
- m[2][1] *= s;
- m[2][2] *= s;
- m[2][3] *= s;
-
- f->textureMatrix[i][2] = m[2][3];
- f->textureMatrix[i][1] = m[1][3] - f->textureMatrix[i][2] * m[1][2];
- f->textureMatrix[i][0] = m[0][3] - f->textureMatrix[i][2] * m[0][2] - f->textureMatrix[i][1] * m[0][1];
-
- f->textureMatrix[i][3] = 0;
-/*
- s = fabs( DotProduct( a->xyz, f->textureMatrix[i] ) - a->st[i] );
- if ( s > 0.01 ) {
- Error( "Bad textureMatrix" );
- }
- s = fabs( DotProduct( b->xyz, f->textureMatrix[i] ) - b->st[i] );
- if ( s > 0.01 ) {
- Error( "Bad textureMatrix" );
- }
- s = fabs( DotProduct( c->xyz, f->textureMatrix[i] ) - c->st[i] );
- if ( s > 0.01 ) {
- Error( "Bad textureMatrix" );
- }
-*/
- }
-}
-
-/*
-=====================
-VL_LightmapMatrixFromPoints
-=====================
-*/
-void VL_LightmapMatrixFromPoints( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
- int i, j;
- float t;
- float m[3][4], al, bl, cl;
- float s;
- int h, w, ssize;
- vec3_t mins, maxs, delta, size, planeNormal;
- drawVert_t *verts;
- static int message;
-
- // vertex-lit triangle model
- if ( dsurf->surfaceType == MST_TRIANGLE_SOUP ) {
- return;
- }
-
- if ( dsurf->lightmapNum < 0 ) {
- return; // doesn't need lighting
- }
-
- VectorClear(f->mins);
- if (dsurf->surfaceType != MST_PATCH)
- {
- ssize = samplesize;
- if (si->lightmapSampleSize)
- ssize = si->lightmapSampleSize;
- ClearBounds( mins, maxs );
- verts = &drawVerts[dsurf->firstVert];
- for ( i = 0 ; i < dsurf->numVerts ; i++ ) {
- AddPointToBounds( verts[i].xyz, mins, maxs );
- }
- // round to the lightmap resolution
- for ( i = 0 ; i < 3 ; i++ ) {
- mins[i] = ssize * floor( mins[i] / ssize );
- maxs[i] = ssize * ceil( maxs[i] / ssize );
- f->mins[i] = mins[i];
- size[i] = (maxs[i] - mins[i]) / ssize + 1;
- }
- // the two largest axis will be the lightmap size
- VectorClear(f->lightmapMatrix[0]);
- f->lightmapMatrix[0][3] = 0;
- VectorClear(f->lightmapMatrix[1]);
- f->lightmapMatrix[1][3] = 0;
-
- planeNormal[0] = fabs( dsurf->lightmapVecs[2][0] );
- planeNormal[1] = fabs( dsurf->lightmapVecs[2][1] );
- planeNormal[2] = fabs( dsurf->lightmapVecs[2][2] );
-
- if ( planeNormal[0] >= planeNormal[1] && planeNormal[0] >= planeNormal[2] ) {
- w = size[1];
- h = size[2];
- f->lightmapMatrix[0][1] = 1.0 / ssize;
- f->lightmapMatrix[1][2] = 1.0 / ssize;
- } else if ( planeNormal[1] >= planeNormal[0] && planeNormal[1] >= planeNormal[2] ) {
- w = size[0];
- h = size[2];
- f->lightmapMatrix[0][0] = 1.0 / ssize;
- f->lightmapMatrix[1][2] = 1.0 / ssize;
- } else {
- w = size[0];
- h = size[1];
- f->lightmapMatrix[0][0] = 1.0 / ssize;
- f->lightmapMatrix[1][1] = 1.0 / ssize;
- }
- if ( w > LIGHTMAP_WIDTH ) {
- VectorScale ( f->lightmapMatrix[0], (float)LIGHTMAP_SIZE/w, f->lightmapMatrix[0] );
- }
-
- if ( h > LIGHTMAP_HEIGHT ) {
- VectorScale ( f->lightmapMatrix[1], (float)LIGHTMAP_SIZE/h, f->lightmapMatrix[1] );
- }
- VectorSubtract(a->xyz, f->mins, delta);
- s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(s - a->lightmap[0]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(t - a->lightmap[1]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- VectorSubtract(b->xyz, f->mins, delta);
- s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(s - b->lightmap[0]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(t - b->lightmap[1]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- VectorSubtract(c->xyz, f->mins, delta);
- s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(s - c->lightmap[0]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(t - c->lightmap[1]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins);
- return;
- }
- // This is an incredibly stupid way of solving a three variable equation
- for ( i = 0 ; i < 2 ; i++ ) {
-
- if (i)
- al = a->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- else
- al = a->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
-
- m[0][0] = a->xyz[0] - f->mins[0];
- m[0][1] = a->xyz[1] - f->mins[1];
- m[0][2] = a->xyz[2] - f->mins[2];
- m[0][3] = al;
-
- if (i)
- bl = b->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- else
- bl = b->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
-
- m[1][0] = b->xyz[0] - f->mins[0];
- m[1][1] = b->xyz[1] - f->mins[1];
- m[1][2] = b->xyz[2] - f->mins[2];
- m[1][3] = bl;
-
- if (i)
- cl = c->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- else
- cl = c->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
-
- m[2][0] = c->xyz[0] - f->mins[0];
- m[2][1] = c->xyz[1] - f->mins[1];
- m[2][2] = c->xyz[2] - f->mins[2];
- m[2][3] = cl;
-
- if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) >= fabs(m[2][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[1][j];
- m[1][j] = t;
- }
- } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) >= fabs(m[1][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[2][j];
- m[2][j] = t;
- }
- }
-
- if (m[0][0])
- {
- s = 1.0 / m[0][0];
- m[0][0] *= s;
- m[0][1] *= s;
- m[0][2] *= s;
- m[0][3] *= s;
-
- s = m[1][0];
- m[1][0] -= m[0][0] * s;
- m[1][1] -= m[0][1] * s;
- m[1][2] -= m[0][2] * s;
- m[1][3] -= m[0][3] * s;
-
- s = m[2][0];
- m[2][0] -= m[0][0] * s;
- m[2][1] -= m[0][1] * s;
- m[2][2] -= m[0][2] * s;
- m[2][3] -= m[0][3] * s;
- }
-
- if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[1][j];
- m[1][j] = m[2][j];
- m[2][j] = t;
- }
- }
-
- if (m[1][1])
- {
- s = 1.0 / m[1][1];
- m[1][0] *= s;
- m[1][1] *= s;
- m[1][2] *= s;
- m[1][3] *= s;
-
- s = m[2][1];
- m[2][0] -= m[1][0] * s;
- m[2][1] -= m[1][1] * s;
- m[2][2] -= m[1][2] * s;
- m[2][3] -= m[1][3] * s;
- }
-
- if (m[2][2])
- {
- s = 1.0 / m[2][2];
- m[2][0] *= s;
- m[2][1] *= s;
- m[2][2] *= s;
- m[2][3] *= s;
- }
-
- f->lightmapMatrix[i][2] = m[2][3];
- f->lightmapMatrix[i][1] = m[1][3] - f->lightmapMatrix[i][2] * m[1][2];
- f->lightmapMatrix[i][0] = m[0][3] - f->lightmapMatrix[i][2] * m[0][2] - f->lightmapMatrix[i][1] * m[0][1];
-
- f->lightmapMatrix[i][3] = 0;
-
- VectorSubtract(a->xyz, f->mins, delta);
- s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - al );
- if ( s > 0.01 ) {
- if (!message)
- _printf( "Bad lightmapMatrix\n" );
- message = qtrue;
- }
- VectorSubtract(b->xyz, f->mins, delta);
- s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - bl );
- if ( s > 0.01 ) {
- if (!message)
- _printf( "Bad lightmapMatrix\n" );
- message = qtrue;
- }
- VectorSubtract(c->xyz, f->mins, delta);
- s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - cl );
- if ( s > 0.01 ) {
- if (!message)
- _printf( "Bad lightmapMatrix\n" );
- message = qtrue;
- }
- VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins);
- }
-}
-
-/*
-=============
-Plane_Equal
-=============
-*/
-#define NORMAL_EPSILON 0.0001
-#define DIST_EPSILON 0.02
-
-int Plane_Equal(plane_t *a, plane_t *b, int flip)
-{
- vec3_t normal;
- float dist;
-
- if (flip) {
- normal[0] = - b->normal[0];
- normal[1] = - b->normal[1];
- normal[2] = - b->normal[2];
- dist = - b->dist;
- }
- else {
- normal[0] = b->normal[0];
- normal[1] = b->normal[1];
- normal[2] = b->normal[2];
- dist = b->dist;
- }
- if (
- fabs(a->normal[0] - normal[0]) < NORMAL_EPSILON
- && fabs(a->normal[1] - normal[1]) < NORMAL_EPSILON
- && fabs(a->normal[2] - normal[2]) < NORMAL_EPSILON
- && fabs(a->dist - dist) < DIST_EPSILON )
- return qtrue;
- return qfalse;
-}
-
-/*
-=============
-VL_PlaneFromPoints
-=============
-*/
-qboolean VL_PlaneFromPoints( plane_t *plane, const vec3_t a, const vec3_t b, const vec3_t c ) {
- vec3_t d1, d2;
-
- VectorSubtract( b, a, d1 );
- VectorSubtract( c, a, d2 );
- CrossProduct( d2, d1, plane->normal );
- if ( VectorNormalize( plane->normal, plane->normal ) == 0 ) {
- return qfalse;
- }
-
- plane->dist = DotProduct( a, plane->normal );
- return qtrue;
-}
-
-/*
-=====================
-VL_GenerateBoundaryForPoints
-=====================
-*/
-void VL_GenerateBoundaryForPoints( plane_t *boundary, plane_t *plane, vec3_t a, vec3_t b ) {
- vec3_t d1;
-
- // make a perpendicular vector to the edge and the surface
- VectorSubtract( a, b, d1 );
- CrossProduct( plane->normal, d1, boundary->normal );
- VectorNormalize( boundary->normal, boundary->normal );
- boundary->dist = DotProduct( a, boundary->normal );
-}
-
-/*
-=====================
-VL_GenerateFacetFor3Points
-=====================
-*/
-qboolean VL_GenerateFacetFor3Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
- //
- vec3_t dir;
- int i;
-
- // if we can't generate a valid plane for the points, ignore the facet
- if ( !VL_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) {
- f->numpoints = 0;
- return qfalse;
- }
-
- f->num = numfacets++;
-
- VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] );
- VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] );
- VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] );
-
- f->lightmapCoords[0][0] = a->lightmap[0];
- f->lightmapCoords[0][1] = a->lightmap[1];
- f->lightmapCoords[1][0] = b->lightmap[0];
- f->lightmapCoords[1][1] = b->lightmap[1];
- f->lightmapCoords[2][0] = c->lightmap[0];
- f->lightmapCoords[2][1] = c->lightmap[1];
-
- VL_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] );
- VL_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] );
- VL_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[0] );
-
- for (i = 0; i < 3; i++)
- {
- VectorSubtract(f->points[(i+1)%3], f->points[i], dir);
- if (VectorLength(dir) < 0.1)
- return qfalse;
- }
-
- VL_TextureMatrixFromPoints( f, a, b, c );
- VL_LightmapMatrixFromPoints( dsurf, si, f, a, b, c );
-
- f->numpoints = 3;
-
- return qtrue;
-}
-
-/*
-=====================
-VL_GenerateFacetFor4Points
-
-Attempts to use four points as a planar quad
-=====================
-*/
-#define PLANAR_EPSILON 0.1
-qboolean VL_GenerateFacetFor4Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c, drawVert_t *d ) {
- float dist;
- vec3_t dir;
- int i;
- plane_t plane;
-
- // if we can't generate a valid plane for the points, ignore the facet
- if ( !VL_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) {
- f->numpoints = 0;
- return qfalse;
- }
-
- // if the fourth point is also on the plane, we can make a quad facet
- dist = DotProduct( d->xyz, f->plane.normal ) - f->plane.dist;
- if ( fabs( dist ) > PLANAR_EPSILON ) {
- f->numpoints = 0;
- return qfalse;
- }
-
- VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] );
- VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] );
- VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] );
- VectorAdd( d->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[3] );
-
- for (i = 1; i < 4; i++)
- {
- if ( !VL_PlaneFromPoints( &plane, f->points[i], f->points[(i+1) % 4], f->points[(i+2) % 4]) ) {
- f->numpoints = 0;
- return qfalse;
- }
-
- if (!Plane_Equal(&f->plane, &plane, qfalse)) {
- f->numpoints = 0;
- return qfalse;
- }
- }
-
- f->lightmapCoords[0][0] = a->lightmap[0];
- f->lightmapCoords[0][1] = a->lightmap[1];
- f->lightmapCoords[1][0] = b->lightmap[0];
- f->lightmapCoords[1][1] = b->lightmap[1];
- f->lightmapCoords[2][0] = c->lightmap[0];
- f->lightmapCoords[2][1] = c->lightmap[1];
- f->lightmapCoords[3][0] = d->lightmap[0];
- f->lightmapCoords[3][1] = d->lightmap[1];
-
- VL_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] );
- VL_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] );
- VL_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[3] );
- VL_GenerateBoundaryForPoints( &f->boundaries[3], &f->plane, f->points[3], f->points[0] );
-
- for (i = 0; i < 4; i++)
- {
- VectorSubtract(f->points[(i+1)%4], f->points[i], dir);
- if (VectorLength(dir) < 0.1)
- return qfalse;
- }
-
- VL_TextureMatrixFromPoints( f, a, b, c );
- VL_LightmapMatrixFromPoints( dsurf, si, f, a, b, c );
-
- f->num = numfacets++;
- f->numpoints = 4;
-
- return qtrue;
-}
-
-/*
-===============
-VL_SphereFromBounds
-===============
-*/
-void VL_SphereFromBounds( vec3_t mins, vec3_t maxs, vec3_t origin, float *radius ) {
- vec3_t temp;
-
- VectorAdd( mins, maxs, origin );
- VectorScale( origin, 0.5, origin );
- VectorSubtract( maxs, origin, temp );
- *radius = VectorLength( temp );
-}
-
-/*
-====================
-VL_FacetsForTriangleSurface
-====================
-*/
-void VL_FacetsForTriangleSurface( dsurface_t *dsurf, shaderInfo_t *si, lsurfaceTest_t *test ) {
- int i;
- drawVert_t *v1, *v2, *v3, *v4;
- int count;
- int i1, i2, i3, i4, i5, i6;
-
- test->patch = qfalse;
- if (dsurf->surfaceType == MST_TRIANGLE_SOUP)
- test->trisoup = qtrue;
- else
- test->trisoup = qfalse;
- test->numFacets = dsurf->numIndexes / 3;
- test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
- test->shader = si;
-
- count = 0;
- for ( i = 0 ; i < test->numFacets ; i++ ) {
- i1 = drawIndexes[ dsurf->firstIndex + i*3 ];
- i2 = drawIndexes[ dsurf->firstIndex + i*3 + 1 ];
- i3 = drawIndexes[ dsurf->firstIndex + i*3 + 2 ];
-
- v1 = &drawVerts[ dsurf->firstVert + i1 ];
- v2 = &drawVerts[ dsurf->firstVert + i2 ];
- v3 = &drawVerts[ dsurf->firstVert + i3 ];
-
- // try and make a quad out of two triangles
- if ( i != test->numFacets - 1 ) {
- i4 = drawIndexes[ dsurf->firstIndex + i*3 + 3 ];
- i5 = drawIndexes[ dsurf->firstIndex + i*3 + 4 ];
- i6 = drawIndexes[ dsurf->firstIndex + i*3 + 5 ];
- if ( i4 == i3 && i5 == i2 ) {
- v4 = &drawVerts[ dsurf->firstVert + i6 ];
- if ( VL_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v2, v4, v3 ) ) {
- count++;
- i++; // skip next tri
- continue;
- }
- }
- }
-
- if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v2, v3 )) {
- count++;
- }
- }
-
- // we may have turned some pairs into quads
- test->numFacets = count;
-}
-
-/*
-====================
-VL_FacetsForPatch
-====================
-*/
-void VL_FacetsForPatch( dsurface_t *dsurf, int surfaceNum, shaderInfo_t *si, lsurfaceTest_t *test ) {
- int i, j, x, y;
- drawVert_t *v1, *v2, *v3, *v4;
- int count, ssize;
- mesh_t mesh;
- mesh_t *subdivided, *detailmesh, *newmesh;
- int widthtable[LIGHTMAP_SIZE], heighttable[LIGHTMAP_SIZE];
-
- mesh.width = dsurf->patchWidth;
- mesh.height = dsurf->patchHeight;
- mesh.verts = &drawVerts[ dsurf->firstVert ];
-
- newmesh = SubdivideMesh( mesh, 8, 999 );
- PutMeshOnCurve( *newmesh );
- MakeMeshNormals( *newmesh );
-
- subdivided = RemoveLinearMeshColumnsRows( newmesh );
- FreeMesh(newmesh);
-
- // DebugNet_RemoveAllPolys();
- // DebugNet_DrawMesh(subdivided);
-
- ssize = samplesize;
- if (si->lightmapSampleSize)
- ssize = si->lightmapSampleSize;
-
- if ( dsurf->lightmapNum >= 0 ) {
-
- detailmesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_SIZE, widthtable, heighttable);
- test->detailMesh = detailmesh;
-
- // DebugNet_RemoveAllPolys();
- // DebugNet_DrawMesh(detailmesh);
-
- if ( detailmesh->width != dsurf->lightmapWidth || detailmesh->height != dsurf->lightmapHeight ) {
- Error( "Mesh lightmap miscount");
- }
- }
- else {
- test->detailMesh = NULL;
- memset(widthtable, 0, sizeof(widthtable));
- memset(heighttable, 0, sizeof(heighttable));
- }
-
- test->patch = qtrue;
- test->trisoup = qfalse;
- test->numFacets = ( subdivided->width - 1 ) * ( subdivided->height - 1 ) * 2;
- test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
- test->shader = si;
-
- count = 0;
- x = 0;
- for ( i = 0 ; i < subdivided->width - 1 ; i++ ) {
- y = 0;
- for ( j = 0 ; j < subdivided->height - 1 ; j++ ) {
-
- v1 = subdivided->verts + j * subdivided->width + i;
- v2 = v1 + 1;
- v3 = v1 + subdivided->width + 1;
- v4 = v1 + subdivided->width;
-
- if ( VL_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v4, v3, v2 ) ) {
- test->facets[count].x = x;
- test->facets[count].y = y;
- test->facets[count].width = widthtable[i];
- test->facets[count].height = heighttable[j];
- count++;
- } else {
- if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v4, v3 )) {
- test->facets[count].x = x;
- test->facets[count].y = y;
- test->facets[count].width = widthtable[i];
- test->facets[count].height = heighttable[j];
- count++;
- }
- if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v3, v2 )) {
- test->facets[count].x = x;
- test->facets[count].y = y;
- test->facets[count].width = widthtable[i];
- test->facets[count].height = heighttable[j];
- count++;
- }
- }
- y += heighttable[j];
- }
- x += widthtable[i];
- }
- test->numFacets = count;
-
- FreeMesh(subdivided);
-}
-
-/*
-=====================
-VL_InitSurfacesForTesting
-=====================
-*/
-void VL_InitSurfacesForTesting( void ) {
-
- int i, j, k;
- dsurface_t *dsurf;
- lsurfaceTest_t *test;
- shaderInfo_t *si;
- lFacet_t *facet;
-
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- // don't light the entity surfaces with vlight
- if ( entitySurface[i] )
- continue;
- //
- dsurf = &drawSurfaces[ i ];
- if ( !dsurf->numIndexes && !dsurf->patchWidth ) {
- continue;
- }
-
- si = ShaderInfoForShader( dshaders[ dsurf->shaderNum].shader );
- // if the surface is translucent and does not cast an alpha shadow
- if ( (si->contents & CONTENTS_TRANSLUCENT) && !(si->surfaceFlags & SURF_ALPHASHADOW) ) {
- // if the surface has no lightmap
- if ( dsurf->lightmapNum < 0 )
- continue;
- }
-
- test = malloc( sizeof( *test ) );
- memset(test, 0, sizeof( *test ));
- test->mutex = MutexAlloc();
- test->numvolumes = 0;
- if (si->forceTraceLight)
- test->always_tracelight = qtrue;
- else if (si->forceVLight)
- test->always_vlight = qtrue;
- lsurfaceTest[i] = test;
-
- if ( dsurf->surfaceType == MST_TRIANGLE_SOUP || dsurf->surfaceType == MST_PLANAR ) {
- VL_FacetsForTriangleSurface( dsurf, si, test );
- } else if ( dsurf->surfaceType == MST_PATCH ) {
- VL_FacetsForPatch( dsurf, i, si, test );
- }
- if (numfacets >= MAX_FACETS)
- Error("numfacets >= MAX_FACETS (%d)", MAX_FACETS);
-
- ClearBounds( test->mins, test->maxs );
- for (j = 0; j < test->numFacets; j++)
- {
- facet = &test->facets[j];
- for ( k = 0 ; k < facet->numpoints; k++) {
- AddPointToBounds( facet->points[k], test->mins, test->maxs );
- }
- }
- VL_SphereFromBounds( test->mins, test->maxs, test->origin, &test->radius );
- }
- _printf("%6d facets\n", numfacets);
- _printf("linking surfaces...\n");
- VL_LinkSurfaces();
-}
-
-/*
-=============
-VL_ChopWinding
-=============
-*/
-int VL_ChopWinding (winding_t *in, plane_t *split, float epsilon)
-{
- vec_t dists[128];
- int sides[128];
- int counts[3];
- vec_t dot;
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- winding_t out;
- winding_t *neww;
-
- counts[0] = counts[1] = counts[2] = 0;
-
- // determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
-
- if (!counts[SIDE_BACK])
- {
- if (!counts[SIDE_FRONT])
- return SIDE_ON;
- else
- return SIDE_FRONT;
- }
-
- if (!counts[SIDE_FRONT])
- {
- return SIDE_BACK;
- }
-
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- neww = &out;
-
- neww->numpoints = 0;
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->points[i];
-
- if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
-
- // generate a split point
- p2 = in->points[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
- memcpy(in, &out, sizeof(winding_t));
-
- return SIDE_CROSS;
-}
-
-/*
-=============
-VL_ChopWindingWithBrush
-
- returns all winding fragments outside the brush
-=============
-*/
-int VL_ChopWindingWithBrush(winding_t *w, dbrush_t *brush, winding_t *outwindings, int maxout)
-{
- int i, res, numout;
- winding_t front, back;
- plane_t plane;
-
- numout = 0;
- memcpy(front.points, w->points, w->numpoints * sizeof(vec3_t));
- front.numpoints = w->numpoints;
- for (i = 0; i < brush->numSides; i++)
- {
- VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal);
- VectorInverse(plane.normal);
- plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist;
- res = VL_SplitWinding(&front, &back, &plane, 0.1);
- if (res == SIDE_BACK || res == SIDE_ON)
- {
- memcpy(outwindings[0].points, w->points, w->numpoints * sizeof(vec3_t));
- outwindings[0].numpoints = w->numpoints;
- return 1; //did not intersect
- }
- if (res != SIDE_FRONT)
- {
- if (numout >= maxout)
- {
- _printf("WARNING: VL_ChopWindingWithBrush: more than %d windings\n", maxout);
- return 0;
- }
- memcpy(outwindings[numout].points, back.points, back.numpoints * sizeof(vec3_t));
- outwindings[numout].numpoints = back.numpoints;
- numout++;
- }
- }
- return numout;
-}
-
-/*
-=============
-VL_WindingAreaOutsideBrushes
-=============
-*/
-float VL_WindingAreaOutsideBrushes(winding_t *w, int *brushnums, int numbrushes)
-{
- int i, j, numwindings[2], n;
- winding_t windingsbuf[2][64];
- dbrush_t *brush;
- float area;
-
- memcpy(windingsbuf[0][0].points, w->points, w->numpoints * sizeof(vec3_t));
- windingsbuf[0][0].numpoints = w->numpoints;
- numwindings[0] = 1;
- for (i = 0; i < numbrushes; i++)
- {
- brush = &dbrushes[brushnums[i]];
- if (!(dshaders[brush->shaderNum].contentFlags & (
- CONTENTS_LAVA
- | CONTENTS_SLIME
- | CONTENTS_WATER
- | CONTENTS_FOG
- | CONTENTS_AREAPORTAL
- | CONTENTS_PLAYERCLIP
- | CONTENTS_MONSTERCLIP
- | CONTENTS_CLUSTERPORTAL
- | CONTENTS_DONOTENTER
- | CONTENTS_BODY
- | CONTENTS_CORPSE
- | CONTENTS_TRANSLUCENT
- | CONTENTS_TRIGGER
- | CONTENTS_NODROP) ) &&
- (dshaders[brush->shaderNum].contentFlags & CONTENTS_SOLID) )
- {
- numwindings[!(i & 1)] = 0;
- for (j = 0; j < numwindings[i&1]; j++)
- {
- n = VL_ChopWindingWithBrush(&windingsbuf[i&1][j], brush,
- &windingsbuf[!(i&1)][numwindings[!(i&1)]],
- 64 - numwindings[!(i&1)]);
- numwindings[!(i&1)] += n;
- }
- if (!numwindings[!(i&1)])
- return 0;
- }
- else
- {
- for (j = 0; j < numwindings[i&1]; j++)
- {
- windingsbuf[!(i&1)][j] = windingsbuf[i&1][j];
- }
- numwindings[!(i&1)] = numwindings[i&1];
- }
- }
- area = 0;
- for (j = 0; j < numwindings[i&1]; j++)
- {
- area += WindingArea(&windingsbuf[i&1][j]);
- }
- return area;
-}
-
-/*
-=============
-VL_R_WindingAreaOutsideSolid
-=============
-*/
-float VL_R_WindingAreaOutsideSolid(winding_t *w, vec3_t normal, int nodenum)
-{
- int leafnum, res;
- float area;
- dnode_t *node;
- dleaf_t *leaf;
- dplane_t *plane;
- winding_t back;
- plane_t split;
-
- area = 0;
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
-
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VL_SplitWinding (w, &back, &split, 0.1);
-
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- if (DotProduct(normal, plane->normal) > 0)
- nodenum = node->children[0];
- else
- nodenum = node->children[1];
- }
- else
- {
- area += VL_R_WindingAreaOutsideSolid(&back, normal, node->children[1]);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- leaf = &dleafs[leafnum];
- if (leaf->cluster != -1)
- {
- area += VL_WindingAreaOutsideBrushes(w, &dleafbrushes[leaf->firstLeafBrush], leaf->numLeafBrushes);
- }
- return area;
-}
-
-/*
-=============
-VL_WindingAreaOutsideSolid
-=============
-*/
-float VL_WindingAreaOutsideSolid(winding_t *w, vec3_t normal)
-{
- return VL_R_WindingAreaOutsideSolid(w, normal, 0);
-}
-
-/*
-=============
-VL_ChopWindingWithFacet
-=============
-*/
-float VL_ChopWindingWithFacet(winding_t *w, lFacet_t *facet)
-{
- int i;
-
- for (i = 0; i < facet->numpoints; i++)
- {
- if (VL_ChopWinding(w, &facet->boundaries[i], 0) == SIDE_BACK)
- return 0;
- }
- if (nostitching)
- return WindingArea(w);
- else
- return VL_WindingAreaOutsideSolid(w, facet->plane.normal);
-}
-
-/*
-=============
-VL_CalcVisibleLightmapPixelArea
-
-nice brute force ;)
-=============
-*/
-void VL_CalcVisibleLightmapPixelArea(void)
-{
- int i, j, x, y, k;
- dsurface_t *ds;
- lsurfaceTest_t *test;
- mesh_t *mesh;
- winding_t w, tmpw;
- float area;
-
- _printf("calculating visible lightmap pixel area...\n");
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- ds = &drawSurfaces[ i ];
-
- if ( ds->lightmapNum < 0 )
- continue;
-
- for (y = 0; y < ds->lightmapHeight; y++)
- {
- for (x = 0; x < ds->lightmapWidth; x++)
- {
- if (ds->surfaceType == MST_PATCH)
- {
- if (y == ds->lightmapHeight-1)
- continue;
- if (x == ds->lightmapWidth-1)
- continue;
- mesh = lsurfaceTest[i]->detailMesh;
- VectorCopy( mesh->verts[y*mesh->width+x].xyz, w.points[0]);
- VectorCopy( mesh->verts[(y+1)*mesh->width+x].xyz, w.points[1]);
- VectorCopy( mesh->verts[(y+1)*mesh->width+x+1].xyz, w.points[2]);
- VectorCopy( mesh->verts[y*mesh->width+x+1].xyz, w.points[3]);
- w.numpoints = 4;
- if (nostitching)
- area = WindingArea(&w);
- else
- area = VL_WindingAreaOutsideSolid(&w, mesh->verts[y*mesh->width+x].normal);
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[0]);
- VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[0]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[3]);
- VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[3]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[2]);
- VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[2]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[1]);
- VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[1]);
- w.numpoints = 4;
- area = 0;
- for (j = 0; j < test->numFacets; j++)
- {
- memcpy(&tmpw, &w, sizeof(winding_t));
- area += VL_ChopWindingWithFacet(&tmpw, &test->facets[j]);
- }
- }
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- lightmappixelarea[k] = area;
- }
- }
- }
-}
-
-/*
-=============
-VL_FindAdjacentSurface
-=============
-*/
-int VL_FindAdjacentSurface(int surfaceNum, int facetNum, vec3_t p1, vec3_t p2, int *sNum, int *fNum, int *point)
-{
- int i, j, k;
- lsurfaceTest_t *test;
- lFacet_t *facet;
- dsurface_t *ds;
- float *fp1, *fp2;
- vec3_t dir;
- plane_t *facetplane;
- // winding_t w;
-
- facetplane = &lsurfaceTest[surfaceNum]->facets[facetNum].plane;
- // DebugNet_RemoveAllPolys();
- // memcpy(w.points, lsurfaceTest[surfaceNum]->facets[facetNum].points,
- // lsurfaceTest[surfaceNum]->facets[facetNum].numpoints * sizeof(vec3_t));
- // w.numpoints = lsurfaceTest[surfaceNum]->facets[facetNum].numpoints;
- // DebugNet_DrawWinding(&w, 2);
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- if (i == surfaceNum)
- continue;
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- if (test->trisoup)// || test->patch)
- continue;
- ds = &drawSurfaces[i];
- if ( ds->lightmapNum < 0 )
- continue;
- //if this surface is not even near the edge
- VectorSubtract(p1, test->origin, dir);
- if (fabs(dir[0]) > test->radius ||
- fabs(dir[1]) > test->radius ||
- fabs(dir[1]) > test->radius)
- {
- VectorSubtract(p2, test->origin, dir);
- if (fabs(dir[0]) > test->radius ||
- fabs(dir[1]) > test->radius ||
- fabs(dir[1]) > test->radius)
- {
- continue;
- }
- }
- //
- for (j = 0; j < test->numFacets; j++)
- {
- facet = &test->facets[j];
- //
- //if (!Plane_Equal(&facet->plane, facetplane, qfalse))
- if (DotProduct(facet->plane.normal, facetplane->normal) < 0.9)
- {
- if (!test->trisoup && !test->patch)
- break;
- continue;
- }
- //
- for (k = 0; k < facet->numpoints; k++)
- {
- fp1 = facet->points[k];
- if (fabs(p2[0] - fp1[0]) < 0.1 &&
- fabs(p2[1] - fp1[1]) < 0.1 &&
- fabs(p2[2] - fp1[2]) < 0.1)
- {
- fp2 = facet->points[(k+1) % facet->numpoints];
- if (fabs(p1[0] - fp2[0]) < 0.1 &&
- fabs(p1[1] - fp2[1]) < 0.1 &&
- fabs(p1[2] - fp2[2]) < 0.1)
- {
- // memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t));
- // w.numpoints = facet->numpoints;
- // DebugNet_DrawWinding(&w, 1);
- *sNum = i;
- *fNum = j;
- *point = k;
- return qtrue;
- }
- }
- /*
- else if (fabs(p1[0] - fp1[0]) < 0.1 &&
- fabs(p1[1] - fp1[1]) < 0.1 &&
- fabs(p1[2] - fp1[2]) < 0.1)
- {
- fp2 = facet->points[(k+1) % facet->numpoints];
- if (fabs(p2[0] - fp2[0]) < 0.1 &&
- fabs(p2[1] - fp2[1]) < 0.1 &&
- fabs(p2[2] - fp2[2]) < 0.1)
- {
- // memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t));
- // w.numpoints = facet->numpoints;
- // DebugNet_DrawWinding(&w, 1);
- *sNum = i;
- *fNum = j;
- *point = k;
- return qtrue;
- }
- }
- //*/
- }
- }
- }
- return qfalse;
-}
-
-/*
-=============
-VL_SmoothenLightmapEdges
-
-this code is used to smoothen lightmaps across surface edges
-=============
-*/
-void VL_SmoothenLightmapEdges(void)
-{
- int i, j, k, coords1[2][2];
- float coords2[2][2];
- int x1, y1, xinc1, yinc1, k1, k2;
- float x2, y2, xinc2, yinc2, length;
- int surfaceNum, facetNum, point;
- lsurfaceTest_t *test;
- lFacet_t *facet1, *facet2;
- dsurface_t *ds1, *ds2;
- float *p[2], s, t, *color1, *color2;
- vec3_t dir, cross;
-
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- if (test->trisoup)// || test->patch)
- continue;
- ds1 = &drawSurfaces[i];
- if ( ds1->lightmapNum < 0 )
- continue;
- for (j = 0; j < test->numFacets; j++)
- {
- facet1 = &test->facets[j];
- //
- for (k = 0; k < facet1->numpoints; k++)
- {
- p[0] = facet1->points[k];
- p[1] = facet1->points[(k+1)%facet1->numpoints];
- //
- coords1[0][0] = facet1->lightmapCoords[k][0] * LIGHTMAP_SIZE;
- coords1[0][1] = facet1->lightmapCoords[k][1] * LIGHTMAP_SIZE;
- coords1[1][0] = facet1->lightmapCoords[(k+1)%facet1->numpoints][0] * LIGHTMAP_SIZE;
- coords1[1][1] = facet1->lightmapCoords[(k+1)%facet1->numpoints][1] * LIGHTMAP_SIZE;
- if (coords1[0][0] >= LIGHTMAP_SIZE)
- coords1[0][0] = LIGHTMAP_SIZE-1;
- if (coords1[0][1] >= LIGHTMAP_SIZE)
- coords1[0][1] = LIGHTMAP_SIZE-1;
- if (coords1[1][0] >= LIGHTMAP_SIZE)
- coords1[1][0] = LIGHTMAP_SIZE-1;
- if (coords1[1][1] >= LIGHTMAP_SIZE)
- coords1[1][1] = LIGHTMAP_SIZE-1;
- // try one row or column further because on flat faces the lightmap can
- // extend beyond the edge
- VectorSubtract(p[1], p[0], dir);
- VectorNormalize(dir, dir);
- CrossProduct(dir, facet1->plane.normal, cross);
- //
- if (coords1[0][0] - coords1[1][0] == 0)
- {
- s = DotProduct( cross, facet1->lightmapMatrix[0] );
- coords1[0][0] += s < 0 ? 1 : -1;
- coords1[1][0] += s < 0 ? 1 : -1;
- if (coords1[0][0] < ds1->lightmapX || coords1[0][0] >= ds1->lightmapX + ds1->lightmapWidth)
- {
- coords1[0][0] += s < 0 ? -1 : 1;
- coords1[1][0] += s < 0 ? -1 : 1;
- }
- length = fabs(coords1[1][1] - coords1[0][1]);
- }
- else if (coords1[0][1] - coords1[1][1] == 0)
- {
- t = DotProduct( cross, facet1->lightmapMatrix[1] );
- coords1[0][1] += t < 0 ? 1 : -1;
- coords1[1][1] += t < 0 ? 1 : -1;
- if (coords1[0][1] < ds1->lightmapY || coords1[0][1] >= ds1->lightmapY + ds1->lightmapHeight)
- {
- coords1[0][1] += t < 0 ? -1 : 1;
- coords1[1][1] += t < 0 ? -1 : 1;
- }
- length = fabs(coords1[1][0] - coords1[0][0]);
- }
- else
- {
- //the edge is not parallell to one of the lightmap axis
- continue;
- }
- //
- x1 = coords1[0][0];
- y1 = coords1[0][1];
- xinc1 = coords1[1][0] - coords1[0][0];
- if (xinc1 < 0) xinc1 = -1;
- if (xinc1 > 0) xinc1 = 1;
- yinc1 = coords1[1][1] - coords1[0][1];
- if (yinc1 < 0) yinc1 = -1;
- if (yinc1 > 0) yinc1 = 1;
- // the edge should be parallell to one of the lightmap axis
- if (xinc1 != 0 && yinc1 != 0)
- continue;
- //
- if (!VL_FindAdjacentSurface(i, j, p[0], p[1], &surfaceNum, &facetNum, &point))
- continue;
- //
- ds2 = &drawSurfaces[surfaceNum];
- facet2 = &lsurfaceTest[surfaceNum]->facets[facetNum];
- coords2[0][0] = facet2->lightmapCoords[(point+1)%facet2->numpoints][0] * LIGHTMAP_SIZE;
- coords2[0][1] = facet2->lightmapCoords[(point+1)%facet2->numpoints][1] * LIGHTMAP_SIZE;
- coords2[1][0] = facet2->lightmapCoords[point][0] * LIGHTMAP_SIZE;
- coords2[1][1] = facet2->lightmapCoords[point][1] * LIGHTMAP_SIZE;
- if (coords2[0][0] >= LIGHTMAP_SIZE)
- coords2[0][0] = LIGHTMAP_SIZE-1;
- if (coords2[0][1] >= LIGHTMAP_SIZE)
- coords2[0][1] = LIGHTMAP_SIZE-1;
- if (coords2[1][0] >= LIGHTMAP_SIZE)
- coords2[1][0] = LIGHTMAP_SIZE-1;
- if (coords2[1][1] >= LIGHTMAP_SIZE)
- coords2[1][1] = LIGHTMAP_SIZE-1;
- //
- x2 = coords2[0][0];
- y2 = coords2[0][1];
- xinc2 = coords2[1][0] - coords2[0][0];
- if (length)
- xinc2 = xinc2 / length;
- yinc2 = coords2[1][1] - coords2[0][1];
- if (length)
- yinc2 = yinc2 / length;
- // the edge should be parallell to one of the lightmap axis
- if ((int) xinc2 != 0 && (int) yinc2 != 0)
- continue;
- //
- while(1)
- {
- k1 = ( ds1->lightmapNum * LIGHTMAP_HEIGHT + y1) * LIGHTMAP_WIDTH + x1;
- k2 = ( ds2->lightmapNum * LIGHTMAP_HEIGHT + ((int) y2)) * LIGHTMAP_WIDTH + ((int) x2);
- color1 = lightFloats + k1*3;
- color2 = lightFloats + k2*3;
- if (lightmappixelarea[k1] < 0.01)
- {
- color1[0] = color2[0];
- color1[1] = color2[1];
- color1[2] = color2[2];
- }
- else
- {
- color1[0] = (float) color2[0] * 0.7 + (float) color1[0] * 0.3;
- color1[1] = (float) color2[1] * 0.7 + (float) color1[1] * 0.3;
- color1[2] = (float) color2[2] * 0.7 + (float) color1[2] * 0.3;
- }
- //
- if (x1 == coords1[1][0] &&
- y1 == coords1[1][1])
- break;
- x1 += xinc1;
- y1 += yinc1;
- x2 += xinc2;
- y2 += yinc2;
- if (x2 < ds2->lightmapX)
- x2 = ds2->lightmapX;
- if (x2 >= ds2->lightmapX + ds2->lightmapWidth)
- x2 = ds2->lightmapX + ds2->lightmapWidth-1;
- if (y2 < ds2->lightmapY)
- y2 = ds2->lightmapY;
- if (y2 >= ds2->lightmapY + ds2->lightmapHeight)
- y2 = ds2->lightmapY + ds2->lightmapHeight-1;
- }
- }
- }
- }
-}
-
-/*
-=============
-VL_FixLightmapEdges
-=============
-*/
-void VL_FixLightmapEdges(void)
-{
- int i, j, x, y, k, foundvalue, height, width, index;
- int pos, top, bottom;
- dsurface_t *ds;
- lsurfaceTest_t *test;
- float color[3];
- float *ptr;
- byte filled[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8];
- float lightmap_edge_epsilon;
-
- lightmap_edge_epsilon = 0.1 * samplesize;
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- ds = &drawSurfaces[ i ];
-
- if ( ds->lightmapNum < 0 )
- continue;
- if (ds->surfaceType == MST_PATCH)
- {
- height = ds->lightmapHeight - 1;
- width = ds->lightmapWidth - 1;
- }
- else
- {
- height = ds->lightmapHeight;
- width = ds->lightmapWidth;
- }
- memset(filled, 0, sizeof(filled));
-// printf("\n");
- for (x = 0; x < width; x++)
- {
- for (y = 0; y < height; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (lightmappixelarea[k] > lightmap_edge_epsilon)
- {
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- filled[index >> 3] |= 1 << (index & 7);
-// printf("*");
- }
-// else
-// printf("_");
- }
-// printf("\n");
- }
- for (y = 0; y < height; y++)
- {
- pos = -2;
- for (x = 0; x < width; x++)
- {
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (pos == -2)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- pos = -1;
- }
- else if (pos == -1)
- {
- if (!(filled[index >> 3] & (1 << (index & 7))))
- pos = x - 1;
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + pos;
- top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- for (j = 0; j < (x - pos + 1) / 2; j++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1;
- filled[index >> 3] |= 1 << (index & 7);
- (lightFloats + k*3)[0] = (lightFloats + top*3)[0];
- (lightFloats + k*3)[1] = (lightFloats + top*3)[1];
- (lightFloats + k*3)[2] = (lightFloats + top*3)[2];
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1;
- filled[index >> 3] |= 1 << (index & 7);
- (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0];
- (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1];
- (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2];
- }
- pos = -1;
- }
- }
- }
- }
- for (x = 0; x < width; x++)
- {
- pos = -2;
- for (y = 0; y < height; y++)
- {
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (pos == -2)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- pos = -1;
- }
- else if (pos == -1)
- {
- if (!(filled[index >> 3] & (1 << (index & 7))))
- pos = y - 1;
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- for (j = 0; j < (y - pos + 1) / 2; j++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos + j + 1)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + pos + j + 1) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- filled[index >> 3] |= 1 << (index & 7);
- (lightFloats + k*3)[0] = (lightFloats + top*3)[0];
- (lightFloats + k*3)[1] = (lightFloats + top*3)[1];
- (lightFloats + k*3)[2] = (lightFloats + top*3)[2];
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y - j - 1)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y - j - 1) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- filled[index >> 3] |= 1 << (index & 7);
- (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0];
- (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1];
- (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2];
- }
- pos = -1;
- }
- }
- }
- }
- for (y = 0; y < height; y++)
- {
- foundvalue = qfalse;
- for (x = 0; x < width; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (foundvalue)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- }
- else
- {
- ptr = lightFloats + k*3;
- ptr[0] = color[0];
- ptr[1] = color[1];
- ptr[2] = color[2];
- filled[index >> 3] |= 1 << (index & 7);
- }
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- foundvalue = qtrue;
- }
- }
- }
- foundvalue = qfalse;
- for (x = width-1; x >= 0; x--)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (foundvalue)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- }
- else
- {
- ptr = lightFloats + k*3;
- ptr[0] = color[0];
- ptr[1] = color[1];
- ptr[2] = color[2];
- filled[index >> 3] |= 1 << (index & 7);
- }
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- foundvalue = qtrue;
- }
- }
- }
- }
- for (x = 0; x < width; x++)
- {
- foundvalue = qfalse;
- for (y = 0; y < height; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (foundvalue)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- }
- else
- {
- ptr = lightFloats + k*3;
- ptr[0] = color[0];
- ptr[1] = color[1];
- ptr[2] = color[2];
- filled[index >> 3] |= 1 << (index & 7);
- }
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- foundvalue = qtrue;
- }
- }
- }
- foundvalue = qfalse;
- for (y = height-1; y >= 0; y--)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (foundvalue)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- }
- else
- {
- ptr = lightFloats + k*3;
- ptr[0] = color[0];
- ptr[1] = color[1];
- ptr[2] = color[2];
- filled[index >> 3] |= 1 << (index & 7);
- }
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- foundvalue = qtrue;
- }
- }
- }
- }
- if (ds->surfaceType == MST_PATCH)
- {
- x = ds->lightmapWidth-1;
- for (y = 0; y < ds->lightmapHeight; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = (lightFloats + (k-1)*3)[0];
- ptr[1] = (lightFloats + (k-1)*3)[1];
- ptr[2] = (lightFloats + (k-1)*3)[2];
- }
- y = ds->lightmapHeight-1;
- for (x = 0; x < ds->lightmapWidth; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0];
- ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1];
- ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2];
- }
- }
- /*
- //colored debug edges
- if (ds->surfaceType == MST_PATCH)
- {
- x = ds->lightmapWidth-1;
- for (y = 0; y < ds->lightmapHeight; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = 255;
- ptr[1] = 0;
- ptr[2] = 0;
- }
- y = ds->lightmapHeight-1;
- for (x = 0; x < ds->lightmapWidth; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = 0;
- ptr[1] = 255;
- ptr[2] = 0;
- }
- }
- //*/
- }
- //
- VL_SmoothenLightmapEdges();
-}
-
-/*
-=============
-VL_ShiftPatchLightmaps
-=============
-*/
-void VL_ShiftPatchLightmaps(void)
-{
- int i, j, x, y, k;
- drawVert_t *verts;
- dsurface_t *ds;
- lsurfaceTest_t *test;
- float *ptr;
-
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- ds = &drawSurfaces[ i ];
-
- if ( ds->lightmapNum < 0 )
- continue;
- if (ds->surfaceType != MST_PATCH)
- continue;
- for (x = ds->lightmapWidth; x > 0; x--)
- {
- for (y = 0; y <= ds->lightmapHeight; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = (lightFloats + (k-1)*3)[0];
- ptr[1] = (lightFloats + (k-1)*3)[1];
- ptr[2] = (lightFloats + (k-1)*3)[2];
- }
- }
- for (y = ds->lightmapHeight; y > 0; y--)
- {
- for (x = 0; x <= ds->lightmapWidth; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0];
- ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1];
- ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2];
- }
- }
- verts = &drawVerts[ ds->firstVert ];
- for ( j = 0 ; j < ds->patchHeight * ds->patchWidth; j++ )
- {
- verts[j].lightmap[0] += 0.5 / LIGHTMAP_WIDTH;
- verts[j].lightmap[1] += 0.5 / LIGHTMAP_HEIGHT;
- }
- ds->lightmapHeight++;
- ds->lightmapWidth++;
- }
-}
-
-/*
-=============
-VL_StoreLightmap
-=============
-*/
-void VL_StoreLightmap(void)
-{
- int i, x, y, k;
- dsurface_t *ds;
- lsurfaceTest_t *test;
- float *src;
- byte *dst;
-
- _printf("storing lightmaps...\n");
- //fix lightmap edges before storing them
- VL_FixLightmapEdges();
- //
-#ifdef LIGHTMAP_PATCHSHIFT
- VL_ShiftPatchLightmaps();
-#endif
- //
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- ds = &drawSurfaces[ i ];
-
- if ( ds->lightmapNum < 0 )
- continue;
-
- for (y = 0; y < ds->lightmapHeight; y++)
- {
- for (x = 0; x < ds->lightmapWidth; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- VectorAdd((lightFloats + k*3), lightAmbientColor, (lightFloats + k*3));
- src = &lightFloats[k*3];
- dst = lightBytes + k*3;
- ColorToBytes(src, dst);
- }
- }
- }
-}
-
-/*
-=============
-PointInLeafnum
-=============
-*/
-int PointInLeafnum(vec3_t point)
-{
- int nodenum;
- vec_t dist;
- dnode_t *node;
- dplane_t *plane;
-
- nodenum = 0;
- while (nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
- dist = DotProduct (point, plane->normal) - plane->dist;
- if (dist > 0)
- nodenum = node->children[0];
- else
- nodenum = node->children[1];
- }
-
- return -nodenum - 1;
-}
-
-/*
-=============
-VL_PointInLeafnum_r
-=============
-*/
-int VL_PointInLeafnum_r(vec3_t point, int nodenum)
-{
- int leafnum;
- vec_t dist;
- dnode_t *node;
- dplane_t *plane;
-
- while (nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
- dist = DotProduct (point, plane->normal) - plane->dist;
- if (dist > 0.1)
- {
- nodenum = node->children[0];
- }
- else if (dist < -0.1)
- {
- nodenum = node->children[1];
- }
- else
- {
- leafnum = VL_PointInLeafnum_r(point, node->children[0]);
- if (dleafs[leafnum].cluster != -1)
- return leafnum;
- nodenum = node->children[1];
- }
- }
-
- leafnum = -nodenum - 1;
- return leafnum;
-}
-
-/*
-=============
-VL_PointInLeafnum
-=============
-*/
-int VL_PointInLeafnum(vec3_t point)
-{
- return VL_PointInLeafnum_r(point, 0);
-}
-
-/*
-=============
-VL_LightLeafnum
-=============
-*/
-int VL_LightLeafnum(vec3_t point)
-{
- /*
- int leafnum;
- dleaf_t *leaf;
- float x, y, z;
- vec3_t test;
-
- leafnum = VL_PointInLeafnum(point);
- leaf = &dleafs[leafnum];
- if (leaf->cluster != -1)
- return leafnum;
- for (z = 1; z >= -1; z -= 1)
- {
- for (x = 1; x >= -1; x -= 1)
- {
- for (y = 1; y >= -1; y -= 1)
- {
- VectorCopy(point, test);
- test[0] += x;
- test[1] += y;
- test[2] += z;
- leafnum = VL_PointInLeafnum(test);
- leaf = &dleafs[leafnum];
- if (leaf->cluster != -1)
- {
- VectorCopy(test, point);
- return leafnum;
- }
- }
- }
- }
- return leafnum;
- */
- return VL_PointInLeafnum(point);
-}
-
-//#define LIGHTPOLYS
-
-#ifdef LIGHTPOLYS
-
-winding_t *lightwindings[MAX_MAP_DRAW_SURFS];
-int numlightwindings;
-
-/*
-=============
-VL_DrawLightWindings
-=============
-*/
-void VL_DrawLightWindings(void)
-{
- int i;
- for (i = 0; i < numlightwindings; i++)
- {
-#ifdef DEBUGNET
- DebugNet_DrawWinding(lightwindings[i], 1);
-#endif
- }
-}
-
-/*
-=============
-VL_LightSurfaceWithVolume
-=============
-*/
-void VL_LightSurfaceWithVolume(int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume)
-{
- winding_t *w;
- lsurfaceTest_t *test;
- lFacet_t *facet;
- int i;
-
- test = lsurfaceTest[ surfaceNum ];
- facet = &test->facets[ facetNum ];
-
- //
- w = (winding_t *) malloc(sizeof(winding_t));
- memcpy(w->points, facet->points, sizeof(vec3_t) * facet->numpoints);
- w->numpoints = facet->numpoints;
-
- for (i = 0; i < volume->numplanes; i++)
- {
- //if totally on the back
- if (VL_ChopWinding(w, &volume->planes[i], 0.01) == SIDE_BACK)
- return;
- }
- lightwindings[numlightwindings] = w;
- numlightwindings++;
- if (numlightwindings >= MAX_MAP_DRAW_SURFS)
- Error("MAX_LIGHTWINDINGS");
-}
-
-#else
-
-/*
-=============
-VL_LightSurfaceWithVolume
-=============
-*/
-/*
-int VL_PointInsideLightVolume(vec3_t point, lightvolume_t *volume)
-{
- int i;
- float d;
-
- for (i = 0; i < volume->numplanes; i++)
- {
- d = DotProduct(volume->planes[i].normal, point) - volume->planes[i].dist;
- if (d < 0) return qfalse;
- }
- return qtrue;
-}
-
-void VL_LightSurfaceWithVolume( int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume )
-{
- dsurface_t *ds;
- int i, j, k;
- int numPositions;
- vec3_t base, normal, color;
- int sampleWidth, sampleHeight;
- vec3_t lightmapOrigin, lightmapVecs[2], dir;
- unsigned char *ptr;
- float add, dist, angle;
- mesh_t * mesh;
-
- ds = &drawSurfaces[surfaceNum];
-
- // vertex-lit triangle model
- if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
- return;
- }
-
- if ( ds->lightmapNum < 0 ) {
- return; // doesn't need lighting
- }
-
- if ( ds->surfaceType == MST_PATCH ) {
- mesh = lsurfaceTest[surfaceNum]->detailMesh;
- } else {
- VectorCopy( ds->lightmapVecs[2], normal );
-
- VectorCopy( ds->lightmapOrigin, lightmapOrigin );
- VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] );
- VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] );
- }
-
- sampleWidth = ds->lightmapWidth;
- sampleHeight = ds->lightmapHeight;
-
- //calculate lightmap
- for ( i = 0 ; i < sampleWidth; i++ ) {
- for ( j = 0 ; j < sampleHeight; j++ ) {
-
- if ( ds->patchWidth ) {
- numPositions = 9;
- VectorCopy( mesh->verts[j*mesh->width+i].normal, normal );
- // VectorNormalize( normal, normal );
- // push off of the curve a bit
- VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base );
-
-// MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] );
- } else {
- numPositions = 9;
- for ( k = 0 ; k < 3 ; k++ ) {
- base[k] = lightmapOrigin[k] + normal[k]
- + ((float) i) * lightmapVecs[0][k]
- + ((float) j) * lightmapVecs[1][k];
- }
- }
- VectorAdd( base, surfaceOrigin[ surfaceNum ], base );
-
- VectorSubtract(base, light->origin, dir);
- dist = VectorNormalize(dir, dir);
- if ( dist < 16 ) {
- dist = 16;
- }
- angle = 1;//DotProduct( normal, dir ); //1;
- if (angle > 1)
- angle = 1;
- if ( light->atten_disttype == LDAT_LINEAR ) {
- add = angle * light->photons * lightLinearScale - dist;
- if ( add < 0 ) {
- add = 0;
- }
- } else {
- add = light->photons / ( dist * dist ) * angle;
- }
- if (add <= 1.0)
- continue;
-
- if (VL_PointInsideLightVolume(base, volume))
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j)
- * LIGHTMAP_WIDTH + ds->lightmapX + i;
- ptr = lightBytes + k*3;
- color[0] = (float) ptr[0] + add * light->color[0];
- color[1] = (float) ptr[1] + add * light->color[1];
- color[2] = (float) ptr[2] + add * light->color[2];
- ColorToBytes(color, ptr);
- }
- }
- }
-}
-*/
-
-/*
-=============
-VL_GetFilter
-
-FIXME: don't use a lightmap pixel origin but use the four corner points
- to map part of a translucent surface onto the lightmap pixel
-=============
-*/
-void VL_GetFilter(vlight_t *light, lightvolume_t *volume, vec3_t lmp, vec3_t filter)
-{
- lFacet_t *facet;
- lsurfaceTest_t *test;
- float d, d1, d2, frac, s, t, ns;
- int i, j, is, it, b;
- int x, y, u, v, numsamples, radius, color[4], largest;
- byte *image;
- vec3_t point, origin, total;
-
- VectorSet(filter, 1, 1, 1);
-
- if (noalphashading)
- return;
-
- if (volume->numtransFacets <= 0)
- return;
-
- if (light->type == LIGHT_SURFACEDIRECTED)
- {
- // project the light map pixel origin onto the area light source plane
- d = DotProduct(lmp, light->normal) - DotProduct(light->normal, light->w.points[0]);
- VectorMA(lmp, -d, light->normal, origin);
- }
- else
- {
- VectorCopy(light->origin, origin);
- }
- for (i = 0; i < volume->numtransFacets; i++)
- {
- test = lsurfaceTest[ volume->transSurfaces[i] ];
- facet = &test->facets[ volume->transFacets[i] ];
- // if this surface does not cast an alpha shadow
- if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) )
- continue;
- // if there are no texture pixel available
- if ( !test->shader->pixels ) {
- continue;
- }
- //
- d1 = DotProduct( origin, facet->plane.normal) - facet->plane.dist;
- d2 = DotProduct( lmp, facet->plane.normal ) - facet->plane.dist;
- // this should never happen because the light volume went through the facet
- if ( ( d1 < 0 ) == ( d2 < 0 ) ) {
- continue;
- }
- // calculate the crossing point
- frac = d1 / ( d1 - d2 );
-
- for ( j = 0 ; j < 3 ; j++ ) {
- point[j] = origin[j] + frac * ( lmp[j] - origin[j] );
- }
-
- s = DotProduct( point, facet->textureMatrix[0] ) + facet->textureMatrix[0][3];
- t = DotProduct( point, facet->textureMatrix[1] ) + facet->textureMatrix[1][3];
- if (s < 0)
- s = 0;
- if (t < 0)
- t = 0;
-
- s = s - floor( s );
- t = t - floor( t );
-
- is = s * test->shader->width;
- it = t * test->shader->height;
-
- //if old style alpha shading
- if (nocolorshading) {
- image = test->shader->pixels + 4 * ( it * test->shader->width + is );
-
- // alpha filter
- b = image[3];
-
- // alpha test makes this a binary option
- b = b < 128 ? 0 : 255;
-
- filter[0] = filter[0] * (255-b) / 255;
- filter[1] = filter[1] * (255-b) / 255;
- filter[2] = filter[2] * (255-b) / 255;
- }
- else {
- VectorClear(total);
- numsamples = 0;
- radius = 2;
- for ( u = -radius; u <= radius; u++ )
- {
- x = is + u;
- if ( x < 0 || x >= test->shader->width)
- continue;
- for ( v = -radius; v <= radius; v++ )
- {
- y = it + v;
- if ( y < 0 || y >= test->shader->height)
- continue;
-
- image = test->shader->pixels + 4 * ( y * test->shader->width + x );
- color[0] = image[0];
- color[1] = image[1];
- color[2] = image[2];
- largest = 0;
- for (j = 0; j < 3; j++)
- if (image[j] > largest)
- largest = image[j];
- if (largest <= 0 || image[3] == 0) {
- color[0] = 255;
- color[1] = 255;
- color[2] = 255;
- largest = 255;
- }
- total[0] += ((float) color[0]/largest) * (255-image[3]) / 255.0;
- total[1] += ((float) color[1]/largest) * (255-image[3]) / 255.0;
- total[2] += ((float) color[2]/largest) * (255-image[3]) / 255.0;
- numsamples++;
- }
- }
- ns = numsamples;
- //
- filter[0] *= total[0] / ns;
- filter[1] *= total[1] / ns;
- filter[2] *= total[2] / ns;
- }
- }
-}
-
-/*
-=============
-VL_LightSurfaceWithVolume
-=============
-*/
-void VL_LightSurfaceWithVolume( int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume )
-{
- int i;
- dsurface_t *ds;
- lFacet_t *facet;
- lsurfaceTest_t *test;
- winding_t w;
- vec3_t base, dir, delta, normal, filter, origin;
- int min_x[LIGHTMAP_SIZE+2], max_x[LIGHTMAP_SIZE+2];
- int min_y, max_y, k, x, y, n;
- float *color, distscale;
- float d, add, angle, dist, area, insidearea, coords[MAX_POINTS_ON_WINDING+1][2];
- mesh_t *mesh;
- byte polygonedges[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8];
-
-
- ds = &drawSurfaces[surfaceNum];
-
- // vertex-lit triangle model
- if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
- return;
- }
-
- if ( ds->lightmapNum < 0 ) {
- return; // doesn't need lighting
- }
-
- test = lsurfaceTest[ surfaceNum ];
- facet = &test->facets[ facetNum ];
-
- if (defaulttracelight && !test->always_vlight)
- return;
- if (test->always_tracelight)
- return;
-
- memcpy(w.points, facet->points, sizeof(vec3_t) * facet->numpoints);
- w.numpoints = facet->numpoints;
-
- for (i = 0; i < volume->numplanes; i++)
- {
- //if totally on the back
- if (VL_ChopWinding(&w, &volume->planes[i], 0.01) == SIDE_BACK)
- return;
- }
-
- // only one thread at a time may write to the lightmap of this surface
- MutexLock(test->mutex);
-
- test->numvolumes++;
-
- if (ds->surfaceType == MST_PATCH)
- {
- // FIXME: reduce size and don't mark all as edge
- min_y = ds->lightmapY + facet->y;
- max_y = ds->lightmapY + facet->y + facet->height - 1;
- for (y = min_y; y <= max_y; y++)
- {
- min_x[y] = ds->lightmapX + facet->x;
- max_x[y] = ds->lightmapX + facet->x + facet->width - 1;
- for (x = min_x[y]; x <= max_x[y]; x++)
- {
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- }
- }
- }
- else
- {
- for (i = 0; i < w.numpoints; i++)
- {
- float s, t;
-
- if (i >= MAX_POINTS_ON_WINDING)
- _printf("coords overflow\n");
- if (ds->surfaceType != MST_PATCH)
- {
- VectorSubtract(w.points[i], facet->mins, delta);
- s = DotProduct( delta, facet->lightmapMatrix[0] ) + ds->lightmapX + 0.5;
- t = DotProduct( delta, facet->lightmapMatrix[1] ) + ds->lightmapY + 0.5;
- if (s >= LIGHTMAP_SIZE)
- s = LIGHTMAP_SIZE - 0.5;
- if (s < 0)
- s = 0;
- if (t >= LIGHTMAP_SIZE)
- t = LIGHTMAP_SIZE - 0.5;
- if (t < 0)
- t = 0;
- coords[i][0] = s;
- coords[i][1] = t;
- }
- else
- {
- s = DotProduct( w.points[i], facet->lightmapMatrix[0] ) + facet->lightmapMatrix[0][3];
- t = DotProduct( w.points[i], facet->lightmapMatrix[1] ) + facet->lightmapMatrix[1][3];
-
- s = s - floor( s );
- t = t - floor( t );
-
- coords[i][0] = ds->lightmapX + s * LIGHTMAP_SIZE;// + 0.5;
- coords[i][1] = ds->lightmapY + t * LIGHTMAP_SIZE;// + 0.5;
-
- if (coords[i][0] >= LIGHTMAP_SIZE)
- coords[i][0] -= LIGHTMAP_SIZE;
- if (coords[i][1] >= LIGHTMAP_SIZE)
- coords[i][1] -= LIGHTMAP_SIZE;
- if (coords[i][0] < ds->lightmapX)
- coords[i][0] = ds->lightmapX;
- if (coords[i][1] < ds->lightmapY)
- coords[i][1] = ds->lightmapY;
- }
- x = coords[i][0];
- y = coords[i][1];
- if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
- _printf("VL_LightSurfaceWithVolume: x outside lightmap\n");
- if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
- _printf("VL_LightSurfaceWithVolume: y outside lightmap\n");
- }
- coords[i][0] = coords[0][0];
- coords[i][1] = coords[0][1];
-
- //
- min_y = LIGHTMAP_SIZE;
- max_y = 0;
- for (i = 0; i < LIGHTMAP_SIZE; i++)
- {
- min_x[i] = LIGHTMAP_SIZE;
- max_x[i] = 0;
- }
- memset(polygonedges, 0, sizeof(polygonedges));
- // scan convert the polygon onto the lightmap
- // for each edge it marks *every* lightmap pixel the edge goes through
- // so no brasenham and no scan conversion used for texture mapping but
- // more something like ray casting
- // this is necesary because we need all lightmap pixels totally or partly
- // inside the light volume. these lightmap pixels are only lit for the part
- // that they are inside the light volume.
- for (i = 0; i < w.numpoints; i++)
- {
- float xf, yf, dx, dy, xstep, ystep, xfrac, yfrac;
- int xinc, yinc;
-
- xf = coords[i][0];
- yf = coords[i][1];
- dx = coords[i+1][0] - xf;
- dy = coords[i+1][1] - yf;
- //
- x = (int) xf;
- y = (int) yf;
- //
- if (y < min_y)
- min_y = y;
- if (y > max_y)
- max_y = y;
- //
- if (fabs(dx) > fabs(dy))
- {
- if (dx > 0)
- {
- // y fraction at integer x below fractional x
- yfrac = yf + (floor(xf) - xf) * dy / dx;
- xinc = 1;
- }
- else if (dx < 0)
- {
- // y fraction at integer x above fractional x
- yfrac = yf + (floor(xf) + 1 - xf) * dy / dx;
- xinc = -1;
- }
- else
- {
- yfrac = yf;
- xinc = 0;
- }
- // step in y direction per 1 unit in x direction
- if (dx)
- ystep = dy / fabs(dx);
- else
- ystep = 0;
- while(1)
- {
- if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
- _printf("VL_LightSurfaceWithVolume: x outside lightmap\n");
- if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
- _printf("VL_LightSurfaceWithVolume: y outside lightmap\n");
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- if (x == (int) coords[i+1][0])
- break;
- yfrac += ystep;
- if (dy > 0)
- {
- if (yfrac > (float) y + 1)
- {
- y += 1;
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- }
- }
- else
- {
- if (yfrac < (float) y)
- {
- y -= 1;
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- }
- }
- x += xinc;
- }
- }
- else
- {
- if (dy > 0)
- {
- //x fraction at integer y below fractional y
- xfrac = xf + (floor(yf) - yf) * dx / dy;
- yinc = 1;
- }
- else if (dy < 0)
- {
- //x fraction at integer y above fractional y
- xfrac = xf + (floor(yf) + 1 - yf) * dx / dy;
- yinc = -1;
- }
- else
- {
- xfrac = xf;
- yinc = 0;
- }
- // step in x direction per 1 unit in y direction
- if (dy)
- xstep = dx / fabs(dy);
- else
- xstep = 0;
- while(1)
- {
- if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
- _printf("VL_LightSurfaceWithVolume: x outside lightmap\n");
- if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
- _printf("VL_LightSurfaceWithVolume: y outside lightmap\n");
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- if (y == (int) coords[i+1][1])
- break;
- xfrac += xstep;
- if (dx > 0)
- {
- if (xfrac > (float) x + 1)
- {
- x += 1;
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- }
- }
- else
- {
- if (xfrac < (float) x)
- {
- x -= 1;
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- }
- }
- y += yinc;
- }
- }
- }
- }
- // map light onto the lightmap
- for (y = min_y; y <= max_y; y++)
- {
- for (x = min_x[y]; x <= max_x[y]; x++)
- {
- if (ds->surfaceType == MST_PATCH)
- {
- mesh = test->detailMesh;
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, base);
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].normal, normal);
- //VectorCopy(facet->plane.normal, normal);
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x - ds->lightmapX, ds->lightmapVecs[0], base);
- VectorMA(base, (float) y - ds->lightmapY, ds->lightmapVecs[1], base);
- VectorCopy(facet->plane.normal, normal);
- }
- if (light->type == LIGHT_POINTSPOT)
- {
- float distByNormal;
- vec3_t pointAtDist;
- float radiusAtDist;
- float sampleRadius;
- vec3_t distToSample;
- float coneScale;
-
- VectorSubtract( light->origin, base, dir );
-
- distByNormal = -DotProduct( dir, light->normal );
- if ( distByNormal < 0 ) {
- continue;
- }
- VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
- radiusAtDist = light->radiusByDist * distByNormal;
-
- VectorSubtract( base, pointAtDist, distToSample );
- sampleRadius = VectorLength( distToSample );
-
- if ( sampleRadius >= radiusAtDist ) {
- continue; // outside the cone
- }
- if ( sampleRadius <= radiusAtDist - 32 ) {
- coneScale = 1.0; // fully inside
- } else {
- coneScale = ( radiusAtDist - sampleRadius ) / 32.0;
- }
-
- dist = VectorNormalize( dir, dir );
- // clamp the distance to prevent super hot spots
- if ( dist < 16 ) {
- dist = 16;
- }
- angle = DotProduct( normal, dir );
- if (angle > 1)
- angle = 1;
- if (angle > 0) {
- if ( light->atten_angletype == LAAT_QUADRATIC ) {
- angle = 1 - angle;
- angle *= angle;
- angle = 1 - angle;
- }
- else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
- angle = 1 - angle;
- angle *= angle * angle;
- angle = 1 - angle;
- }
- }
- if (light->atten_anglescale > 0) {
- angle /= light->atten_anglescale;
- if (angle > 1)
- angle = 1;
- }
- if (light->atten_distscale > 0) {
- distscale = light->atten_distscale;
- }
- else {
- distscale = 1;
- }
- //
- if ( light->atten_disttype == LDAT_NOSCALE ) {
- add = angle * coneScale;
- }
- else if ( light->atten_disttype == LDAT_LINEAR ) {
- add = angle * light->photons * lightLinearScale * coneScale - dist * distscale;
- if ( add < 0 ) {
- add = 0;
- }
- }
- else {
- add = light->photons / ( dist * dist * distscale) * angle * coneScale;
- }
- if (add <= 1.0)
- continue;
- }
- else if (light->type == LIGHT_POINTFAKESURFACE)
- {
- // calculate the contribution
- add = PointToPolygonFormFactor( base, normal, &light->w );
- if ( add <= 0 ) {
- if ( light->twosided ) {
- add = -add;
- } else {
- continue;
- }
- }
- }
- else if (light->type == LIGHT_SURFACEDIRECTED)
- {
- //VectorCopy(light->normal, dir);
- //VectorInverse(dir);
- // project the light map pixel origin onto the area light source plane
- d = DotProduct(base, light->normal) - DotProduct(light->normal, light->w.points[0]);
- VectorMA(base, -d, light->normal, origin);
- VectorSubtract(origin, base, dir);
- dist = VectorNormalize(dir, dir);
- if ( dist < 16 ) {
- dist = 16;
- }
- //
- angle = DotProduct( normal, dir );
- if (angle > 1)
- angle = 1;
- if (angle > 0) {
- if ( light->atten_angletype == LAAT_QUADRATIC ) {
- angle = 1 - angle;
- angle *= angle;
- angle = 1 - angle;
- }
- else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
- angle = 1 - angle;
- angle *= angle * angle;
- angle = 1 - angle;
- }
- }
- if (light->atten_anglescale > 0) {
- angle /= light->atten_anglescale;
- if (angle > 1)
- angle = 1;
- }
- if (light->atten_distscale > 0) {
- distscale = light->atten_distscale;
- }
- else {
- distscale = 1;
- }
- if ( light->atten_disttype == LDAT_NOSCALE ) {
- add = angle;
- }
- else if ( light->atten_disttype == LDAT_LINEAR ) {
- add = angle * light->photons * lightLinearScale - dist * distscale;
- if ( add < 0 ) {
- add = 0;
- }
- } else { //default quadratic
- add = light->photons / ( dist * dist * distscale) * angle;
- }
- if (add <= 0)
- continue;
- }
- else //normal radial point light
- {
- VectorSubtract(light->origin, base, dir);
- dist = VectorNormalize(dir, dir);
- if ( dist < 16 ) {
- dist = 16;
- }
- angle = DotProduct( normal, dir );
- if (angle > 1)
- angle = 1;
- if (angle > 0) {
- if ( light->atten_angletype == LAAT_QUADRATIC ) {
- angle = 1 - angle;
- angle *= angle;
- angle = 1 - angle;
- }
- else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
- angle = 1 - angle;
- angle *= angle * angle;
- angle = 1 - angle;
- }
- }
- if (light->atten_anglescale > 0) {
- angle /= light->atten_anglescale;
- if (angle > 1)
- angle = 1;
- }
- if (light->atten_distscale > 0) {
- distscale = light->atten_distscale;
- }
- else {
- distscale = 1;
- }
- if ( light->atten_disttype == LDAT_NOSCALE ) {
- add = angle;
- }
- else if ( light->atten_disttype == LDAT_LINEAR ) {
- add = angle * light->photons * lightLinearScale - dist * distscale;
- if ( add < 0 ) {
- add = 0;
- }
- } else {
- add = light->photons / ( dist * dist * distscale) * angle;
- }
- if (add <= 1.0)
- continue;
- }
- //
- k = (ds->lightmapNum * LIGHTMAP_HEIGHT + y) * LIGHTMAP_WIDTH + x;
- //if on one of the edges
- n = y * LIGHTMAP_SIZE + x;
- if ((polygonedges[n >> 3] & (1 << (n & 7)) ))
- {
- // multiply 'add' by the relative area being lit of the total visible lightmap pixel area
- //
- // first create a winding for the lightmap pixel
- if (ds->surfaceType == MST_PATCH)
- {
- mesh = test->detailMesh;
- if (y-ds->lightmapY >= mesh->height-1)
- _printf("y outside mesh\n");
- if (x-ds->lightmapX >= mesh->width-1)
- _printf("x outside mesh\n");
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]);
- VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]);
- VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]);
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]);
- w.numpoints = 4;
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]);
- VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]);
- VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]);
- VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]);
- VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]);
- w.numpoints = 4;
- }
- //
- // take the visible area of the lightmap pixel into account
- //
- //area = WindingArea(&w);
- area = lightmappixelarea[k];
- if (area <= 0)
- continue;
- // chop the lightmap pixel winding with the light volume
- for (i = 0; i < volume->numplanes; i++)
- {
- //if totally on the back
- if (VL_ChopWinding(&w, &volume->planes[i], 0) == SIDE_BACK)
- break;
- }
- // if the lightmap pixel is partly inside the light volume
- if (i >= volume->numplanes)
- {
- insidearea = WindingArea(&w);
- if (insidearea <= 0)
- i = 0;
- add = add * insidearea / area;
- }
- else
- {
- //DebugNet_DrawWinding(&w, 2);
- continue; // this shouldn't happen
- }
- }
- // get the light filter from all the translucent surfaces the light volume went through
- VL_GetFilter(light, volume, base, filter);
- //
- color = &lightFloats[k*3];
- color[0] += add * light->color[0] * filter[0];
- color[1] += add * light->color[1] * filter[1];
- color[2] += add * light->color[2] * filter[2];
- }
- }
-
- MutexUnlock(test->mutex);
-}
-
-#endif
-
-/*
-=============
-VL_SplitLightVolume
-=============
-*/
-int VL_SplitLightVolume(lightvolume_t *volume, lightvolume_t *back, plane_t *split, float epsilon)
-{
- lightvolume_t f, b;
- vec_t dists[128];
- int sides[128];
- int counts[3];
- vec_t dot;
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
-
- counts[0] = counts[1] = counts[2] = 0;
-
- // determine sides for each point
- for (i = 0; i < volume->numplanes; i++)
- {
- dot = DotProduct (volume->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
-
- if (!counts[1])
- return 0; // completely on front side
-
- if (!counts[0])
- return 1; // completely on back side
-
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- f.numplanes = 0;
- b.numplanes = 0;
-
- for (i = 0; i < volume->numplanes; i++)
- {
- p1 = volume->points[i];
-
- if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return 0; // can't chop -- fall back to original
- }
- if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return 0; // can't chop -- fall back to original
- }
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy(p1, f.points[f.numplanes]);
- VectorCopy(p1, b.points[b.numplanes]);
- if (sides[i+1] == SIDE_BACK)
- {
- f.planes[f.numplanes] = *split;
- b.planes[b.numplanes] = volume->planes[i];
- }
- else if (sides[i+1] == SIDE_FRONT)
- {
- f.planes[f.numplanes] = volume->planes[i];
- b.planes[b.numplanes] = *split;
- VectorInverse(b.planes[b.numplanes].normal);
- b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
- }
- else //this shouldn't happen
- {
- f.planes[f.numplanes] = *split;
- b.planes[b.numplanes] = *split;
- VectorInverse(b.planes[b.numplanes].normal);
- b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
- }
- f.numplanes++;
- b.numplanes++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, f.points[f.numplanes]);
- f.planes[f.numplanes] = volume->planes[i];
- f.numplanes++;
- }
- if (sides[i] == SIDE_BACK)
- {
- VectorCopy (p1, b.points[b.numplanes]);
- b.planes[b.numplanes] = volume->planes[i];
- b.numplanes++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return 0; // can't chop -- fall back to original
- }
- if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return 0; // can't chop -- fall back to original
- }
-
- // generate a split point
- p2 = volume->points[(i+1)%volume->numplanes];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, f.points[f.numplanes]);
- VectorCopy(mid, b.points[b.numplanes]);
- if (sides[i+1] == SIDE_BACK)
- {
- f.planes[f.numplanes] = *split;
- b.planes[b.numplanes] = volume->planes[i];
- }
- else
- {
- f.planes[f.numplanes] = volume->planes[i];
- b.planes[b.numplanes] = *split;
- VectorInverse(b.planes[b.numplanes].normal);
- b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
- }
- f.numplanes++;
- b.numplanes++;
- }
- memcpy(volume->points, f.points, sizeof(vec3_t) * f.numplanes);
- memcpy(volume->planes, f.planes, sizeof(plane_t) * f.numplanes);
- volume->numplanes = f.numplanes;
- memcpy(back->points, b.points, sizeof(vec3_t) * b.numplanes);
- memcpy(back->planes, b.planes, sizeof(plane_t) * b.numplanes);
- back->numplanes = b.numplanes;
-
- return 2;
-}
-
-/*
-=============
-VL_PlaneForEdgeToWinding
-=============
-*/
-void VL_PlaneForEdgeToWinding(vec3_t p1, vec3_t p2, winding_t *w, int windingonfront, plane_t *plane)
-{
- int i, j;
- float length, d;
- vec3_t v1, v2;
-
- VectorSubtract(p2, p1, v1);
- for (i = 0; i < w->numpoints; i++)
- {
- VectorSubtract (w->points[i], p1, v2);
-
- plane->normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
- plane->normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
- plane->normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
-
- // if points don't make a valid plane, skip it
- length = plane->normal[0] * plane->normal[0]
- + plane->normal[1] * plane->normal[1]
- + plane->normal[2] * plane->normal[2];
-
- if (length < ON_EPSILON)
- continue;
-
- length = 1/sqrt(length);
-
- plane->normal[0] *= length;
- plane->normal[1] *= length;
- plane->normal[2] *= length;
-
- plane->dist = DotProduct (w->points[i], plane->normal);
- //
- for (j = 0; j < w->numpoints; j++)
- {
- if (j == i)
- continue;
- d = DotProduct(w->points[j], plane->normal) - plane->dist;
- if (windingonfront)
- {
- if (d < -ON_EPSILON)
- break;
- }
- else
- {
- if (d > ON_EPSILON)
- break;
- }
- }
- if (j >= w->numpoints)
- return;
- }
-}
-
-/*
-=============
-VL_R_CastLightAtSurface
-=============
-*/
-void VL_R_FloodLight(vlight_t *light, lightvolume_t *volume, int cluster, int firstportal);
-
-void VL_R_CastLightAtSurface(vlight_t *light, lightvolume_t *volume)
-{
- lsurfaceTest_t *test;
- int i, n;
-
- // light the surface with this volume
- VL_LightSurfaceWithVolume(volume->surfaceNum, volume->facetNum, light, volume);
- //
- test = lsurfaceTest[ volume->surfaceNum ];
- // if this is not a translucent surface
- if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) && !(test->shader->contents & CONTENTS_TRANSLUCENT))
- return;
- //
- if (volume->numtransFacets >= MAX_TRANSLUCENTFACETS)
- Error("a light valume went through more than %d translucent facets", MAX_TRANSLUCENTFACETS);
- //add this translucent surface to the list
- volume->transSurfaces[volume->numtransFacets] = volume->surfaceNum;
- volume->transFacets[volume->numtransFacets] = volume->facetNum;
- volume->numtransFacets++;
- //clear the tested facets except the translucent ones
- memset(volume->facetTested, 0, sizeof(volume->facetTested));
- for (i = 0; i < volume->numtransFacets; i++)
- {
- test = lsurfaceTest[ volume->transSurfaces[i] ];
- n = test->facets[volume->transFacets[i]].num;
- volume->facetTested[n >> 3] |= 1 << (n & 7);
- }
- memset(volume->clusterTested, 0, sizeof(volume->clusterTested));
- volume->endplane = volume->farplane;
- volume->surfaceNum = -1;
- volume->facetNum = 0;
- VL_R_FloodLight(light, volume, volume->cluster, 0);
- if (volume->surfaceNum >= 0)
- {
- VL_R_CastLightAtSurface(light, volume);
- }
-}
-
-/*
-=============
-VL_R_SplitLightVolume
-=============
-*/
-int numvolumes = 0;
-
-int VL_R_SplitLightVolume(vlight_t *light, lightvolume_t *volume, plane_t *split, int cluster, int firstportal)
-{
- lightvolume_t back;
- int res;
-
- //
- res = VL_SplitLightVolume(volume, &back, split, 0.1);
- // if the volume was split
- if (res == 2)
- {
- memcpy(back.clusterTested, volume->clusterTested, sizeof(back.clusterTested));
- memcpy(back.facetTested, volume->facetTested, sizeof(back.facetTested));
- back.num = numvolumes++;
- back.endplane = volume->endplane;
- back.surfaceNum = volume->surfaceNum;
- back.facetNum = volume->facetNum;
- back.type = volume->type;
- back.cluster = volume->cluster;
- back.farplane = volume->farplane;
- if (volume->numtransFacets > 0)
- {
- memcpy(back.transFacets, volume->transFacets, sizeof(back.transFacets));
- memcpy(back.transSurfaces, volume->transSurfaces, sizeof(back.transSurfaces));
- }
- back.numtransFacets = volume->numtransFacets;
- //
- // flood the volume at the back of the split plane
- VL_R_FloodLight(light, &back, cluster, firstportal);
- // if the back volume hit a surface
- if (back.surfaceNum >= 0)
- {
- VL_R_CastLightAtSurface(light, &back);
- }
- }
- return res;
-}
-
-/*
-=============
-VL_R_FloodLight
-=============
-*/
-void VL_R_FloodLight(vlight_t *light, lightvolume_t *volume, int cluster, int firstportal)
-{
- int i, j, k, res, surfaceNum, backfaceculled, testculled;
- float d;
- winding_t winding, tmpwinding;
- lleaf_t *leaf;
- lportal_t *p;
- lsurfaceTest_t *test;
- lFacet_t *facet;
- vec3_t dir1, dir2;
- plane_t plane;
-
- // DebugNet_RemoveAllPolys();
- // VL_DrawLightVolume(light, volume);
-
- // if the first portal is not zero then we've checked all occluders in this leaf already
- if (firstportal == 0)
- {
- // check all potential occluders in this leaf
- for (i = 0; i < leafs[cluster].numSurfaces; i++)
- {
- surfaceNum = clustersurfaces[leafs[cluster].firstSurface + i];
- //
- test = lsurfaceTest[ surfaceNum ];
- if ( !test )
- continue;
- //
- testculled = qfalse;
- // use surface as an occluder
- for (j = 0; j < test->numFacets; j++)
- {
- // use each facet as an occluder
- facet = &test->facets[j];
- //
- // memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints);
- // winding.numpoints = facet->numpoints;
- // DebugNet_DrawWinding(&winding, 5);
- //
- // if the facet was tested already
- if ( volume->facetTested[facet->num >> 3] & (1 << (facet->num & 7)) )
- continue;
- volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
- // backface culling for planar surfaces
- backfaceculled = qfalse;
- if (!test->patch && !test->trisoup)
- {
- if (volume->type == VOLUME_NORMAL)
- {
- // facet backface culling
- d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist;
- if (d < 0)
- {
- // NOTE: this doesn't work too great because of sometimes very bad tesselation
- // of surfaces that are supposed to be flat
- // FIXME: to work around this problem we should make sure that all facets
- // created from planar surfaces use the lightmapVecs normal vector
- /*
- if ( !test->shader->twoSided )
- {
- // skip all other facets of this surface as well because they are in the same plane
- for (k = 0; k < test->numFacets; k++)
- {
- facet = &test->facets[k];
- volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
- }
- }*/
- backfaceculled = qtrue;
- }
- }
- else
- {
- // FIXME: if all light source winding points are at the back of the facet
- // plane then backfaceculled = qtrue
- }
- }
- else // backface culling per facet for patches and triangle soups
- {
- if (volume->type == VOLUME_NORMAL)
- {
- // facet backface culling
- d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist;
- if (d < 0)
- backfaceculled = qtrue;
- }
- else
- {
- // FIXME: if all light source winding points are at the back of the facet
- // plane then backfaceculled = qtrue
- }
- }
- /* chopping does this already
- // check if this facet is totally or partly in front of the volume end plane
- for (k = 0; k < facet->numpoints; k++)
- {
- d = DotProduct(volume->endplane.normal, facet->points[k]) - volume->endplane.dist;
- if (d > ON_EPSILON)
- break;
- }
- // if this facet is outside the light volume
- if (k >= facet->numpoints)
- continue;
- */
- //
- if (backfaceculled)
- {
- // if the facet is not two sided
- if ( !nobackfaceculling && !test->shader->twoSided )
- continue;
- // flip the winding
- for (k = 0; k < facet->numpoints; k++)
- VectorCopy(facet->points[k], winding.points[facet->numpoints - k - 1]);
- winding.numpoints = facet->numpoints;
- }
- else
- {
- memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints);
- winding.numpoints = facet->numpoints;
- }
- //
- if (!testculled)
- {
- testculled = qtrue;
- // fast check if the surface sphere is totally behind the volume end plane
- d = DotProduct(volume->endplane.normal, test->origin) - volume->endplane.dist;
- if (d < -test->radius)
- {
- for (k = 0; k < test->numFacets; k++)
- {
- facet = &test->facets[k];
- volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
- }
- break;
- }
- for (k = 0; k < volume->numplanes; k++)
- {
- d = DotProduct(volume->planes[k].normal, test->origin) - volume->planes[k].dist;
- if (d < - test->radius)
- {
- for (k = 0; k < test->numFacets; k++)
- {
- facet = &test->facets[k];
- volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
- }
- break;
- }
- }
- if (k < volume->numplanes)
- break;
- }
- //NOTE: we have to chop the facet winding with the volume end plane because
- // the faces in Q3 are not stitched together nicely
- res = VL_ChopWinding(&winding, &volume->endplane, 0.01);
- // if the facet is on or at the back of the volume end plane
- if (res == SIDE_BACK || res == SIDE_ON)
- continue;
- // check if the facet winding is totally or partly inside the light volume
- memcpy(&tmpwinding, &winding, sizeof(winding_t));
- for (k = 0; k < volume->numplanes; k++)
- {
- res = VL_ChopWinding(&tmpwinding, &volume->planes[k], 0.01);
- if (res == SIDE_BACK || res == SIDE_ON)
- break;
- }
- // if no part of the light volume is occluded by this facet
- if (k < volume->numplanes)
- continue;
- //
- for (k = 0; k < winding.numpoints; k++)
- {
- if (volume->type == VOLUME_DIRECTED)
- {
- VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1);
- CrossProduct(light->normal, dir1, plane.normal);
- VectorNormalize(plane.normal, plane.normal);
- plane.dist = DotProduct(plane.normal, winding.points[k]);
- }
- else
- {
- VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1);
- VectorSubtract(light->origin, winding.points[k], dir2);
- CrossProduct(dir1, dir2, plane.normal);
- VectorNormalize(plane.normal, plane.normal);
- plane.dist = DotProduct(plane.normal, winding.points[k]);
- }
- res = VL_R_SplitLightVolume(light, volume, &plane, cluster, 0);
- if (res == 1)
- break; //the facet wasn't really inside the volume
- }
- if (k >= winding.numpoints)
- {
- volume->endplane = facet->plane;
- if (backfaceculled)
- {
- VectorInverse(volume->endplane.normal);
- volume->endplane.dist = -volume->endplane.dist;
- }
- volume->surfaceNum = surfaceNum;
- volume->facetNum = j;
- }
- }
- }
- }
- // we've tested all occluders in this cluster
- volume->clusterTested[cluster >> 3] |= 1 << (cluster & 7);
- // flood light through the portals of the current leaf
- leaf = &leafs[cluster];
- for (i = firstportal; i < leaf->numportals; i++)
- {
- p = leaf->portals[i];
- //
- // memcpy(&winding, p->winding, sizeof(winding_t));
- // DebugNet_DrawWinding(&winding, 5);
- // if already flooded into the cluster this portal leads to
- if ( volume->clusterTested[p->leaf >> 3] & (1 << (p->leaf & 7)) )
- continue;
- //
- if (volume->type == VOLUME_NORMAL)
- {
- // portal backface culling
- d = DotProduct(light->origin, p->plane.normal) - p->plane.dist;
- if (d > 0) // portal plane normal points into neighbour cluster
- continue;
- }
- else
- {
- // FIXME: if all light source winding points are at the back of this portal
- // plane then there's no need to flood through
- }
- // check if this portal is totally or partly in front of the volume end plane
- // fast check with portal sphere
- d = DotProduct(volume->endplane.normal, p->origin) - volume->endplane.dist;
- if (d < -p->radius)
- continue;
- for (j = 0; j < p->winding->numpoints; j++)
- {
- d = DotProduct(volume->endplane.normal, p->winding->points[j]) - volume->endplane.dist;
- if (d > -0.01)
- break;
- }
- // if this portal is totally behind the light volume end plane
- if (j >= p->winding->numpoints)
- continue;
- //distance from point light to portal
- d = DotProduct(p->plane.normal, light->origin) - p->plane.dist;
- // only check if a point light is Not *on* the portal
- if (volume->type != VOLUME_NORMAL || fabs(d) > 0.1)
- {
- // check if the portal is partly or totally inside the light volume
- memcpy(&winding, p->winding, sizeof(winding_t));
- for (j = 0; j < volume->numplanes; j++)
- {
- res = VL_ChopWinding(&winding, &volume->planes[j], 0.01);
- if (res == SIDE_BACK || res == SIDE_ON)
- break;
- }
- // if the light volume does not go through this portal at all
- if (j < volume->numplanes)
- continue;
- }
- // chop the light volume with the portal
- for (k = 0; k < p->winding->numpoints; k++)
- {
- if (volume->type == VOLUME_DIRECTED)
- {
- VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1);
- CrossProduct(light->normal, dir1, plane.normal);
- VectorNormalize(plane.normal, plane.normal);
- plane.dist = DotProduct(plane.normal, p->winding->points[k]);
- }
- else
- {
- VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1);
- VectorSubtract(light->origin, p->winding->points[k], dir2);
- CrossProduct(dir1, dir2, plane.normal);
- VectorNormalize(plane.normal, plane.normal);
- plane.dist = DotProduct(plane.normal, p->winding->points[k]);
- }
- res = VL_R_SplitLightVolume(light, volume, &plane, cluster, i+1);
- if (res == 1)
- break; //volume didn't really go through the portal
- }
- // if the light volume went through the portal
- if (k >= p->winding->numpoints)
- {
- // flood through the portal
- VL_R_FloodLight(light, volume, p->leaf, 0);
- }
- }
-}
-
-/*
-=============
-VL_R_FloodAreaSpotLight
-=============
-*/
-void VL_FloodAreaSpotLight(vlight_t *light, winding_t *w, int leafnum)
-{
-}
-
-/*
-=============
-VL_R_SubdivideAreaSpotLight
-=============
-*/
-void VL_R_SubdivideAreaSpotLight(vlight_t *light, int nodenum, winding_t *w)
-{
- int leafnum, res;
- dnode_t *node;
- dplane_t *plane;
- winding_t back;
- plane_t split;
-
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
-
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VL_SplitWinding (w, &back, &split, 0.1);
-
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- memcpy(&back, w, sizeof(winding_t));
- VL_R_SubdivideAreaSpotLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- else
- {
- VL_R_SubdivideAreaSpotLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- if (dleafs[leafnum].cluster != -1)
- {
- VL_FloodAreaSpotLight(light, w, leafnum);
- }
-}
-
-/*
-=============
-VL_R_FloodRadialAreaLight
-=============
-*/
-void VL_FloodRadialAreaLight(vlight_t *light, winding_t *w, int leafnum)
-{
-}
-
-/*
-=============
-VL_R_SubdivideRadialAreaLight
-=============
-*/
-void VL_R_SubdivideRadialAreaLight(vlight_t *light, int nodenum, winding_t *w)
-{
- int leafnum, res;
- dnode_t *node;
- dplane_t *plane;
- winding_t back;
- plane_t split;
-
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
-
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VL_SplitWinding (w, &back, &split, 0.1);
-
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- memcpy(&back, w, sizeof(winding_t));
- VL_R_SubdivideRadialAreaLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- else
- {
- VL_R_SubdivideRadialAreaLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- if (dleafs[leafnum].cluster != -1)
- {
- VL_FloodRadialAreaLight(light, w, leafnum);
- }
-}
-
-/*
-=============
-VL_R_FloodDirectedLight
-=============
-*/
-void VL_FloodDirectedLight(vlight_t *light, winding_t *w, int leafnum)
-{
- int i;
- float dist;
- lightvolume_t volume;
- vec3_t dir;
-
- if (light->atten_disttype == LDAT_NOSCALE)
- {
- // light travels without decrease in intensity over distance
- dist = MAX_WORLD_COORD;
- }
- else
- {
- if ( light->atten_disttype == LDAT_LINEAR )
- dist = light->photons * lightLinearScale;
- else
- dist = sqrt(light->photons);
- }
-
- memset(&volume, 0, sizeof(lightvolume_t));
- for (i = 0; i < w->numpoints; i++)
- {
- VectorMA(w->points[i], dist, light->normal, volume.points[i]);
- VectorSubtract(w->points[(i+1)%w->numpoints], w->points[i], dir);
- CrossProduct(light->normal, dir, volume.planes[i].normal);
- VectorNormalize(volume.planes[i].normal, volume.planes[i].normal);
- volume.planes[i].dist = DotProduct(volume.planes[i].normal, w->points[i]);
- }
- volume.numplanes = w->numpoints;
- VectorCopy(light->normal, volume.endplane.normal);
- VectorInverse(volume.endplane.normal);
- volume.endplane.dist = DotProduct(volume.endplane.normal, volume.points[0]);
- volume.farplane = volume.endplane;
- volume.surfaceNum = -1;
- volume.type = VOLUME_DIRECTED;
- volume.cluster = dleafs[leafnum].cluster;
- VL_R_FloodLight(light, &volume, volume.cluster, 0);
- if (volume.surfaceNum >= 0)
- {
- VL_R_CastLightAtSurface(light, &volume);
- }
-}
-
-/*
-=============
-VL_R_SubdivideDirectedAreaLight
-=============
-*/
-void VL_R_SubdivideDirectedAreaLight(vlight_t *light, int nodenum, winding_t *w)
-{
- int leafnum, res;
- dnode_t *node;
- dplane_t *plane;
- winding_t back;
- plane_t split;
-
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
-
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VL_SplitWinding (w, &back, &split, 0.1);
-
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- memcpy(&back, w, sizeof(winding_t));
- VL_R_SubdivideDirectedAreaLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- else
- {
- VL_R_SubdivideDirectedAreaLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- if (dleafs[leafnum].cluster != -1)
- {
- VL_FloodDirectedLight(light, w, leafnum);
- }
-}
-
-/*
-=============
-VL_FloodLight
-=============
-*/
-void VL_FloodLight(vlight_t *light)
-{
- lightvolume_t volume;
- dleaf_t *leaf;
- int leafnum, i, j, k, dir[2][4] = {{1, 1, -1, -1}, {1, -1, -1, 1}};
- float a, step, dist, radius, windingdist;
- vec3_t vec, r, p, temp;
- winding_t winding;
-
- switch(light->type)
- {
- case LIGHT_POINTRADIAL:
- {
- // source is a point
- // light radiates in all directions
- // creates sharp shadows
- //
- // create 6 volumes shining in the axis directions
- // what about: 4 tetrahedrons instead?
- //
- if ( light->atten_disttype == LDAT_LINEAR )
- dist = light->photons * lightLinearScale;
- else
- dist = sqrt(light->photons);
- //always put the winding at a large distance to avoid epsilon issues
- windingdist = MAX_WORLD_COORD;
- if (dist > windingdist)
- windingdist = dist;
- //
- leafnum = VL_LightLeafnum(light->origin);
- leaf = &dleafs[leafnum];
- if (leaf->cluster == -1)
- {
- light->insolid = qtrue;
- break;
- }
- // for each axis
- for (i = 0; i < 3; i++)
- {
- // for both directions on the axis
- for (j = -1; j <= 1; j += 2)
- {
- memset(&volume, 0, sizeof(lightvolume_t));
- volume.numplanes = 0;
- for (k = 0; k < 4; k ++)
- {
- volume.points[volume.numplanes][i] = light->origin[i] + j * windingdist;
- volume.points[volume.numplanes][(i+1)%3] = light->origin[(i+1)%3] + dir[0][k] * windingdist;
- volume.points[volume.numplanes][(i+2)%3] = light->origin[(i+2)%3] + dir[1][k] * windingdist;
- volume.numplanes++;
- }
- if (j >= 0)
- {
- VectorCopy(volume.points[0], temp);
- VectorCopy(volume.points[2], volume.points[0]);
- VectorCopy(temp, volume.points[2]);
- }
- for (k = 0; k < volume.numplanes; k++)
- {
- VL_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]);
- }
- VectorCopy(light->origin, temp);
- temp[i] += (float) j * dist;
- VectorClear(volume.endplane.normal);
- volume.endplane.normal[i] = -j;
- volume.endplane.dist = DotProduct(volume.endplane.normal, temp); //DotProduct(volume.endplane.normal, volume.points[0]);
- volume.farplane = volume.endplane;
- volume.cluster = leaf->cluster;
- volume.surfaceNum = -1;
- volume.type = VOLUME_NORMAL;
- //
- memset(volume.facetTested, 0, sizeof(volume.facetTested));
- memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
- VL_R_FloodLight(light, &volume, leaf->cluster, 0);
- if (volume.surfaceNum >= 0)
- {
- VL_R_CastLightAtSurface(light, &volume);
- }
- }
- }
- break;
- }
- case LIGHT_POINTSPOT:
- {
- // source is a point
- // light is targetted
- // creates sharp shadows
- //
- // what about using brushes to shape spot lights? that'd be pretty cool
- //
- if ( light->atten_disttype == LDAT_LINEAR )
- dist = light->photons * lightLinearScale;
- else
- dist = sqrt(light->photons);
- dist *= 2;
- //
- windingdist = 4096;
- if (dist > windingdist)
- windingdist = dist;
- //take 8 times the cone radius because the spotlight also lights outside the cone
- radius = 8 * windingdist * light->radiusByDist;
- //
- memset(&volume, 0, sizeof(lightvolume_t));
- leafnum = VL_LightLeafnum(light->origin);
- leaf = &dleafs[leafnum];
- if (leaf->cluster == -1)
- {
- light->insolid = qtrue;
- break;
- }
- //
- VectorClear(vec);
- for (i = 0; i < 3; i++)
- {
- if (light->normal[i] > -0.9 && light->normal[i] < 0.9)
- {
- vec[i] = 1;
- break;
- }
- }
- CrossProduct(light->normal, vec, r);
- VectorScale(r, radius, p);
- volume.numplanes = 0;
- step = 45;
- for (a = step / 2; a < 360 + step / 2; a += step)
- {
- RotatePointAroundVector(volume.points[volume.numplanes], light->normal, p, a);
- VectorAdd(light->origin, volume.points[volume.numplanes], volume.points[volume.numplanes]);
- VectorMA(volume.points[volume.numplanes], windingdist, light->normal, volume.points[volume.numplanes]);
- volume.numplanes++;
- }
- for (i = 0; i < volume.numplanes; i++)
- {
- VL_PlaneFromPoints(&volume.planes[i], light->origin, volume.points[(i+1)%volume.numplanes], volume.points[i]);
- }
- VectorMA(light->origin, dist, light->normal, temp);
- VectorCopy(light->normal, volume.endplane.normal);
- VectorInverse(volume.endplane.normal);
- volume.endplane.dist = DotProduct(volume.endplane.normal, temp);//DotProduct(volume.endplane.normal, volume.points[0]);
- volume.farplane = volume.endplane;
- volume.cluster = leaf->cluster;
- volume.surfaceNum = -1;
- volume.type = VOLUME_NORMAL;
- //
- memset(volume.facetTested, 0, sizeof(volume.facetTested));
- memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
- VL_R_FloodLight(light, &volume, leaf->cluster, 0);
- if (volume.surfaceNum >= 0)
- {
- VL_R_CastLightAtSurface(light, &volume);
- }
- break;
- }
- case LIGHT_POINTFAKESURFACE:
- {
- float value;
- int n, axis;
- vec3_t v, vecs[2];
-
- if ( light->atten_disttype == LDAT_LINEAR )
- dist = light->photons * lightLinearScale;
- else
- dist = sqrt(light->photons);
- //always put the winding at a large distance to avoid epsilon issues
- windingdist = 4096;
- if (dist > windingdist)
- windingdist = dist;
- //
- VectorMA(light->origin, 0.1, light->normal, light->origin);
- //
- leafnum = VL_LightLeafnum(light->origin);
- leaf = &dleafs[leafnum];
- if (leaf->cluster == -1)
- {
- light->insolid = qtrue;
- break;
- }
- value = 0;
- for (i = 0; i < 3; i++)
- {
- if (fabs(light->normal[i]) > value)
- {
- value = fabs(light->normal[i]);
- axis = i;
- }
- }
- for (i = 0; i < 2; i++)
- {
- VectorClear(v);
- v[(axis + 1 + i) % 3] = 1;
- CrossProduct(light->normal, v, vecs[i]);
- }
- //cast 4 volumes at the front of the surface
- for (i = -1; i <= 1; i += 2)
- {
- for (j = -1; j <= 1; j += 2)
- {
- for (n = 0; n < 2; n++)
- {
- memset(&volume, 0, sizeof(lightvolume_t));
- volume.numplanes = 3;
- VectorMA(light->origin, i * windingdist, vecs[0], volume.points[(i == j) == n]);
- VectorMA(light->origin, j * windingdist, vecs[1], volume.points[(i != j) == n]);
- VectorMA(light->origin, windingdist, light->normal, volume.points[2]);
- for (k = 0; k < volume.numplanes; k++)
- {
- VL_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]);
- }
- VL_PlaneFromPoints(&volume.endplane, volume.points[0], volume.points[1], volume.points[2]);
- VectorMA(light->origin, dist, light->normal, temp);
- volume.endplane.dist = DotProduct(volume.endplane.normal, temp);
- if (DotProduct(light->origin, volume.endplane.normal) - volume.endplane.dist > 0)
- break;
- }
- volume.farplane = volume.endplane;
- volume.cluster = leaf->cluster;
- volume.surfaceNum = -1;
- volume.type = VOLUME_NORMAL;
- //
- memset(volume.facetTested, 0, sizeof(volume.facetTested));
- memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
-
- VL_R_FloodLight(light, &volume, leaf->cluster, 0);
- if (volume.surfaceNum >= 0)
- {
- VL_R_CastLightAtSurface(light, &volume);
- }
- }
- }
- break;
- }
- case LIGHT_SURFACEDIRECTED:
- {
- // source is an area defined by a winding
- // the light is unidirectional
- // creates sharp shadows
- // for instance sun light or laser light
- //
- memcpy(&winding, &light->w, sizeof(winding_t));
- VL_R_SubdivideDirectedAreaLight(light, 0, &winding);
- break;
- }
- case LIGHT_SURFACERADIAL:
- {
- // source is an area defined by a winding
- // the light radiates in all directions at the front of the winding plane
- //
- memcpy(&winding, &light->w, sizeof(winding_t));
- VL_R_SubdivideRadialAreaLight(light, 0, &winding);
- break;
- }
- case LIGHT_SURFACESPOT:
- {
- // source is an area defined by a winding
- // light is targetted but not unidirectional
- //
- memcpy(&winding, &light->w, sizeof(winding_t));
- VL_R_SubdivideAreaSpotLight(light, 0, &winding);
- break;
- }
- }
-}
-
-/*
-=============
-VL_FloodLightThread
-=============
-*/
-void VL_FloodLightThread(int num)
-{
- VL_FloodLight(vlights[num]);
-}
-
-/*
-=============
-VL_TestLightLeafs
-=============
-*/
-void VL_TestLightLeafs(void)
-{
- int leafnum, i;
- vlight_t *light;
- dleaf_t *leaf;
-
- for (i = 0; i < numvlights; i++)
- {
- light = vlights[i];
- if (light->type != LIGHT_POINTRADIAL &&
- light->type != LIGHT_POINTSPOT)
- continue;
- leafnum = VL_LightLeafnum(light->origin);
- leaf = &dleafs[leafnum];
- if (leaf->cluster == -1)
- if (light->type == LIGHT_POINTRADIAL)
- qprintf("light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]);
- else if (light->type == LIGHT_POINTSPOT)
- qprintf("spot light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]);
- }
-}
-
-
-/*
-=============
-VL_DoForcedTraceLight
-=============
-*/
-// from light.c
-void TraceLtm( int num );
-
-void VL_DoForcedTraceLight(int num)
-{
- dsurface_t *ds;
- shaderInfo_t *si;
-
- ds = &drawSurfaces[num];
-
- if ( ds->surfaceType == MST_TRIANGLE_SOUP )
- return;
-
- if ( ds->lightmapNum < 0 )
- return;
-
- // always light entity surfaces with the old light algorithm
- if ( !entitySurface[num] )
- {
- si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
-
- if (defaulttracelight)
- {
- if (si->forceVLight)
- return;
- }
- else
- {
- if (!si->forceTraceLight)
- return;
- }
- }
-
- TraceLtm(num);
-}
-
-/*
-=============
-VL_DoForcedTraceLightSurfaces
-=============
-*/
-void VL_DoForcedTraceLightSurfaces(void)
-{
- _printf( "forced trace light\n" );
- RunThreadsOnIndividual( numDrawSurfaces, qtrue, VL_DoForcedTraceLight );
-}
-
-float *oldLightFloats;
-
-/*
-=============
-VL_SurfaceRadiosity
-=============
-*/
-void VL_SurfaceRadiosity( int num ) {
- dsurface_t *ds;
- mesh_t *mesh;
- shaderInfo_t *si;
- lsurfaceTest_t *test;
- int x, y, k;
- vec3_t base, normal;
- float *color, area;
- vlight_t vlight;
-
- ds = &drawSurfaces[num];
-
- if ( ds->lightmapNum < 0 ) {
- return; // doesn't have a lightmap
- }
-
- // vertex-lit triangle model
- if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
- return;
- }
-
- si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
- test = lsurfaceTest[ num ];
-
- if (!test) {
- return;
- }
-
- for (x = 0; x < ds->lightmapWidth; x++) {
- for (y = 0; y < ds->lightmapHeight; y++) {
- //
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- area = lightmappixelarea[k];
- if (area <= 0)
- continue;
- //
- if (ds->surfaceType == MST_PATCH)
- {
- mesh = test->detailMesh;
- VectorCopy( mesh->verts[y*mesh->width+x].xyz, base);
- VectorCopy( mesh->verts[y*mesh->width+x].normal, normal);
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x, ds->lightmapVecs[0], base);
- VectorMA(base, (float) y, ds->lightmapVecs[1], base);
- VectorCopy(test->facets[0].plane.normal, normal);
- }
- // create ligth from base
- memset(&vlight, 0, sizeof(vlight_t));
- color = &oldLightFloats[k*3];
- // a few units away from the surface
- VectorMA(base, 5, normal, vlight.origin);
- ColorNormalize(color, vlight.color);
- // ok this is crap
- vlight.photons = VectorLength(color) * 0.05 * lightPointScale / (area * radiosity_scale);
- // what about using a front facing light only ?
- vlight.type = LIGHT_POINTRADIAL;
- // flood the light from this lightmap pixel
- VL_FloodLight(&vlight);
- // only one thread at a time may write to the lightmap of this surface
- MutexLock(test->mutex);
- // don't light the lightmap pixel itself
- lightFloats[k*3] = oldLightFloats[k*3];
- lightFloats[k*3+1] = oldLightFloats[k*3+1];
- lightFloats[k*3+2] = oldLightFloats[k*3+2];
- //
- MutexUnlock(test->mutex);
- }
- }
-}
-
-/*
-=============
-VL_Radiosity
-
-this aint working real well but it's fun to play with.
-=============
-*/
-void VL_Radiosity(void) {
-
- oldLightFloats = lightFloats;
- lightFloats = (float *) malloc(numLightBytes * sizeof(float));
- memcpy(lightFloats, oldLightFloats, numLightBytes * sizeof(float));
- _printf("%7i surfaces\n", numDrawSurfaces);
- RunThreadsOnIndividual( numDrawSurfaces, qtrue, VL_SurfaceRadiosity );
- free(oldLightFloats);
-}
-
-/*
-=============
-VL_LightWorld
-=============
-*/
-void VL_LightWorld(void)
-{
- int i, numcastedvolumes, numvlightsinsolid;
- float f;
-
- // find the optional world ambient
- GetVectorForKey( &entities[0], "_color", lightAmbientColor );
- f = FloatForKey( &entities[0], "ambient" );
- VectorScale( lightAmbientColor, f, lightAmbientColor );
- /*
- _printf("\r%6d lights out of %d", 0, numvlights);
- for (i = 0; i < numvlights; i++)
- {
- _printf("\r%6d", i);
- VL_FloodLight(vlights[i]);
- }
- _printf("\r%6d lights out of %d\n", i, numvlights);
- */
- _printf("%7i lights\n", numvlights);
- RunThreadsOnIndividual( numvlights, qtrue, VL_FloodLightThread );
-
- numcastedvolumes = 0;
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- if (lsurfaceTest[i])
- numcastedvolumes += lsurfaceTest[i]->numvolumes;
- }
- _printf("%7i light volumes casted\n", numcastedvolumes);
- numvlightsinsolid = 0;
- for (i = 0; i < numvlights; i++)
- {
- if (vlights[i]->insolid)
- numvlightsinsolid++;
- }
- _printf("%7i lights in solid\n", numvlightsinsolid);
- //
- radiosity_scale = 1;
- for (i = 0; i < radiosity; i++) {
- VL_Radiosity();
- radiosity_scale <<= 1;
- }
- //
- VL_StoreLightmap();
- // redo surfaces with the old light algorithm when needed
- VL_DoForcedTraceLightSurfaces();
-}
-
-/*
-=============
-VL_CreateEntityLights
-=============
-*/
-entity_t *FindTargetEntity( const char *target );
-
-void VL_CreateEntityLights (void)
-{
- int i, c_entityLights;
- vlight_t *dl;
- entity_t *e, *e2;
- const char *name;
- const char *target;
- vec3_t dest;
- const char *_color;
- float intensity;
- int spawnflags;
-
- //
- c_entityLights = 0;
- _printf("Creating entity lights...\n");
- //
- for ( i = 0 ; i < num_entities ; i++ ) {
- e = &entities[i];
- name = ValueForKey (e, "classname");
- if (strncmp (name, "light", 5))
- continue;
-
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
-
- spawnflags = FloatForKey (e, "spawnflags");
- if ( spawnflags & 1 ) {
- dl->atten_disttype = LDAT_LINEAR;
- }
- if ( spawnflags & 2 ) {
- dl->atten_disttype = LDAT_NOSCALE;
- }
- if ( spawnflags & 4 ) {
- dl->atten_angletype = LAAT_QUADRATIC;
- }
- if ( spawnflags & 8 ) {
- dl->atten_angletype = LAAT_DOUBLEQUADRATIC;
- }
-
- dl->atten_distscale = FloatForKey(e, "atten_distscale");
- dl->atten_anglescale = FloatForKey(e, "atten_anglescale");
-
- GetVectorForKey (e, "origin", dl->origin);
- dl->style = FloatForKey (e, "_style");
- if (!dl->style)
- dl->style = FloatForKey (e, "style");
- if (dl->style < 0)
- dl->style = 0;
-
- intensity = FloatForKey (e, "light");
- if (!intensity)
- intensity = FloatForKey (e, "_light");
- if (!intensity)
- intensity = 300;
- _color = ValueForKey (e, "_color");
- if (_color && _color[0])
- {
- sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);
- ColorNormalize (dl->color, dl->color);
- }
- else
- dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
-
- intensity = intensity * lightPointScale;
- dl->photons = intensity;
-
- dl->type = LIGHT_POINTRADIAL;
-
- // lights with a target will be spotlights
- target = ValueForKey (e, "target");
-
- if ( target[0] ) {
- float radius;
- float dist;
-
- e2 = FindTargetEntity (target);
- if (!e2) {
- _printf ("WARNING: light at (%i %i %i) has missing target\n",
- (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]);
- } else {
- GetVectorForKey (e2, "origin", dest);
- VectorSubtract (dest, dl->origin, dl->normal);
- dist = VectorNormalize (dl->normal, dl->normal);
- radius = FloatForKey (e, "radius");
- if ( !radius ) {
- radius = 64;
- }
- if ( !dist ) {
- dist = 64;
- }
- dl->radiusByDist = (radius + 16) / dist;
- dl->type = LIGHT_POINTSPOT;
- }
- }
- vlights[numvlights++] = dl;
- c_entityLights++;
- }
- _printf("%7i entity lights\n", c_entityLights);
-}
-
-/*
-==================
-VL_SubdivideAreaLight
-==================
-*/
-void VL_SubdivideAreaLight( shaderInfo_t *ls, winding_t *w, vec3_t normal,
- float areaSubdivide, qboolean backsplash ) {
- float area, value, intensity;
- vlight_t *dl, *dl2;
- vec3_t mins, maxs;
- int axis;
- winding_t *front, *back;
- vec3_t planeNormal;
- float planeDist;
-
- if ( !w ) {
- return;
- }
-
- WindingBounds( w, mins, maxs );
-
- // check for subdivision
- for ( axis = 0 ; axis < 3 ; axis++ ) {
- if ( maxs[axis] - mins[axis] > areaSubdivide ) {
- VectorClear( planeNormal );
- planeNormal[axis] = 1;
- planeDist = ( maxs[axis] + mins[axis] ) * 0.5;
- ClipWindingEpsilon ( w, planeNormal, planeDist, ON_EPSILON, &front, &back );
- VL_SubdivideAreaLight( ls, front, normal, areaSubdivide, qfalse );
- VL_SubdivideAreaLight( ls, back, normal, areaSubdivide, qfalse );
- FreeWinding( w );
- return;
- }
- }
-
- // create a light from this
- area = WindingArea (w);
- if ( area <= 0 || area > 20000000 ) {
- return;
- }
-
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
- dl->type = LIGHT_POINTFAKESURFACE;
-
- WindingCenter( w, dl->origin );
- memcpy(dl->w.points, w->points, sizeof(vec3_t) * w->numpoints);
- dl->w.numpoints = w->numpoints;
- VectorCopy ( normal, dl->normal);
- VectorCopy ( normal, dl->plane);
- dl->plane[3] = DotProduct( dl->origin, normal );
-
- value = ls->value;
- intensity = value * area * lightAreaScale;
- VectorAdd( dl->origin, dl->normal, dl->origin );
-
- VectorCopy( ls->color, dl->color );
-
- dl->photons = intensity;
-
- // emitColor is irrespective of the area
- VectorScale( ls->color, value*lightFormFactorValueScale*lightAreaScale, dl->emitColor );
- //
- VectorCopy(dl->emitColor, dl->color);
-
- dl->si = ls;
-
- if ( ls->contents & CONTENTS_FOG ) {
- dl->twosided = qtrue;
- }
-
- vlights[numvlights++] = dl;
-
- // optionally create a point backsplash light
- if ( backsplash && ls->backsplashFraction > 0 ) {
-
- dl2 = malloc(sizeof(*dl));
- memset (dl2, 0, sizeof(*dl2));
- dl2->type = LIGHT_POINTRADIAL;
-
- VectorMA( dl->origin, ls->backsplashDistance, normal, dl2->origin );
-
- VectorCopy( ls->color, dl2->color );
-
- dl2->photons = dl->photons * ls->backsplashFraction;
- dl2->si = ls;
-
- vlights[numvlights++] = dl2;
- }
-}
-
-/*
-==================
-VL_CreateFakeSurfaceLights
-==================
-*/
-void VL_CreateFakeSurfaceLights( void ) {
- int i, j, side;
- dsurface_t *ds;
- shaderInfo_t *ls;
- winding_t *w;
- lFacet_t *f;
- vlight_t *dl;
- vec3_t origin;
- drawVert_t *dv;
- int c_surfaceLights;
- float lightSubdivide;
- vec3_t normal;
-
-
- c_surfaceLights = 0;
- _printf ("Creating surface lights...\n");
-
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- // see if this surface is light emiting
- ds = &drawSurfaces[i];
-
- ls = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
- if ( ls->value == 0 ) {
- continue;
- }
-
- // determine how much we need to chop up the surface
- if ( ls->lightSubdivide ) {
- lightSubdivide = ls->lightSubdivide;
- } else {
- lightSubdivide = lightDefaultSubdivide;
- }
-
- c_surfaceLights++;
-
- // an autosprite shader will become
- // a point light instead of an area light
- if ( ls->autosprite ) {
- // autosprite geometry should only have four vertexes
- if ( lsurfaceTest[i] ) {
- // curve or misc_model
- f = lsurfaceTest[i]->facets;
- if ( lsurfaceTest[i]->numFacets != 1 || f->numpoints != 4 ) {
- _printf( "WARNING: surface at (%i %i %i) has autosprite shader but isn't a quad\n",
- (int)f->points[0], (int)f->points[1], (int)f->points[2] );
- }
- VectorAdd( f->points[0], f->points[1], origin );
- VectorAdd( f->points[2], origin, origin );
- VectorAdd( f->points[3], origin, origin );
- VectorScale( origin, 0.25, origin );
- } else {
- // normal polygon
- dv = &drawVerts[ ds->firstVert ];
- if ( ds->numVerts != 4 ) {
- _printf( "WARNING: surface at (%i %i %i) has autosprite shader but %i verts\n",
- (int)dv->xyz[0], (int)dv->xyz[1], (int)dv->xyz[2] );
- continue;
- }
-
- VectorAdd( dv[0].xyz, dv[1].xyz, origin );
- VectorAdd( dv[2].xyz, origin, origin );
- VectorAdd( dv[3].xyz, origin, origin );
- VectorScale( origin, 0.25, origin );
- }
-
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
- VectorCopy( origin, dl->origin );
- VectorCopy( ls->color, dl->color );
- dl->photons = ls->value * lightPointScale;
- dl->type = LIGHT_POINTRADIAL;
- vlights[numvlights++] = dl;
- continue;
- }
-
- // possibly create for both sides of the polygon
- for ( side = 0 ; side <= ls->twoSided ; side++ ) {
- // create area lights
- if ( lsurfaceTest[i] ) {
- // curve or misc_model
- for ( j = 0 ; j < lsurfaceTest[i]->numFacets ; j++ ) {
- f = lsurfaceTest[i]->facets + j;
- w = AllocWinding( f->numpoints );
- w->numpoints = f->numpoints;
- memcpy( w->points, f->points, f->numpoints * 12 );
-
- VectorCopy( f->plane.normal, normal );
- if ( side ) {
- winding_t *t;
-
- t = w;
- w = ReverseWinding( t );
- FreeWinding( t );
- VectorSubtract( vec3_origin, normal, normal );
- }
- VL_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
- }
- } else {
- // normal polygon
-
- w = AllocWinding( ds->numVerts );
- w->numpoints = ds->numVerts;
- for ( j = 0 ; j < ds->numVerts ; j++ ) {
- VectorCopy( drawVerts[ds->firstVert+j].xyz, w->points[j] );
- }
- VectorCopy( ds->lightmapVecs[2], normal );
- if ( side ) {
- winding_t *t;
-
- t = w;
- w = ReverseWinding( t );
- FreeWinding( t );
- VectorSubtract( vec3_origin, normal, normal );
- }
- VL_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
- }
- }
- }
-
- _printf( "%7i light emitting surfaces\n", c_surfaceLights );
-}
-
-
-/*
-==================
-VL_WindingForBrushSide
-==================
-*/
-winding_t *VL_WindingForBrushSide(dbrush_t *brush, int side, winding_t *w)
-{
- int i, res;
- winding_t *tmpw;
- plane_t plane;
-
- VectorCopy(dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].normal, plane.normal);
- VectorInverse(plane.normal);
- plane.dist = -dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].dist;
- tmpw = BaseWindingForPlane( plane.normal, plane.dist );
- memcpy(w->points, tmpw->points, sizeof(vec3_t) * tmpw->numpoints);
- w->numpoints = tmpw->numpoints;
-
- for (i = 0; i < brush->numSides; i++)
- {
- if (i == side)
- continue;
- VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal);
- VectorInverse(plane.normal);
- plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist;
- res = VL_ChopWinding(w, &plane, 0.1);
- if (res == SIDE_BACK)
- return NULL;
- }
- return w;
-}
-
-/*
-==================
-VL_CreateSkyLights
-==================
-*/
-void VL_CreateSkyLights(void)
-{
- int i, j, c_skyLights;
- dbrush_t *b;
- shaderInfo_t *si;
- dbrushside_t *s;
- vlight_t *dl;
- vec3_t sunColor, sunDir = { 0.45, 0.3, 0.9 };
- float d;
-
- VectorNormalize(sunDir, sunDir);
- VectorInverse(sunDir);
-
- c_skyLights = 0;
- _printf("Creating sky lights...\n");
- // find the sky shader
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- si = ShaderInfoForShader( dshaders[ drawSurfaces[i].shaderNum ].shader );
- if ( si->surfaceFlags & SURF_SKY ) {
- VectorCopy( si->sunLight, sunColor );
- VectorCopy( si->sunDirection, sunDir );
- VectorInverse(sunDir);
- break;
- }
- }
-
- // find the brushes
- for ( i = 0 ; i < numbrushes ; i++ ) {
- b = &dbrushes[i];
- for ( j = 0 ; j < b->numSides ; j++ ) {
- s = &dbrushsides[ b->firstSide + j ];
- if ( dshaders[ s->shaderNum ].surfaceFlags & SURF_SKY ) {
- //if this surface doesn't face in the same direction as the sun
- d = DotProduct(dplanes[ s->planeNum ].normal, sunDir);
- if (d <= 0)
- continue;
- //
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
- VectorCopy(sunColor, dl->color);
- VectorCopy(sunDir, dl->normal);
- VectorCopy(dplanes[ s->planeNum ].normal, dl->plane);
- dl->plane[3] = dplanes[ s->planeNum ].dist;
- dl->type = LIGHT_SURFACEDIRECTED;
- dl->atten_disttype = LDAT_NOSCALE;
- VL_WindingForBrushSide(b, j, &dl->w);
-// DebugNet_DrawWinding(&dl->w, 2);
- //
- vlights[numvlights++] = dl;
- c_skyLights++;
- }
- }
- }
- _printf("%7i light emitting sky surfaces\n", c_skyLights);
-}
-
-/*
-==================
-VL_SetPortalSphere
-==================
-*/
-void VL_SetPortalSphere (lportal_t *p)
-{
- int i;
- vec3_t total, dist;
- winding_t *w;
- float r, bestr;
-
- w = p->winding;
- VectorCopy (vec3_origin, total);
- for (i=0 ; i<w->numpoints ; i++)
- {
- VectorAdd (total, w->points[i], total);
- }
-
- for (i=0 ; i<3 ; i++)
- total[i] /= w->numpoints;
-
- bestr = 0;
- for (i=0 ; i<w->numpoints ; i++)
- {
- VectorSubtract (w->points[i], total, dist);
- r = VectorLength (dist);
- if (r > bestr)
- bestr = r;
- }
- VectorCopy (total, p->origin);
- p->radius = bestr;
-}
-
-/*
-==================
-VL_PlaneFromWinding
-==================
-*/
-void VL_PlaneFromWinding (winding_t *w, plane_t *plane)
-{
- vec3_t v1, v2;
-
- //calc plane
- VectorSubtract (w->points[2], w->points[1], v1);
- VectorSubtract (w->points[0], w->points[1], v2);
- CrossProduct (v2, v1, plane->normal);
- VectorNormalize (plane->normal, plane->normal);
- plane->dist = DotProduct (w->points[0], plane->normal);
-}
-
-/*
-==================
-VL_AllocWinding
-==================
-*/
-winding_t *VL_AllocWinding (int points)
-{
- winding_t *w;
- int size;
-
- if (points > MAX_POINTS_ON_WINDING)
- Error ("NewWinding: %i points", points);
-
- size = (int)((winding_t *)0)->points[points];
- w = malloc (size);
- memset (w, 0, size);
-
- return w;
-}
-
-/*
-============
-VL_LoadPortals
-============
-*/
-void VL_LoadPortals (char *name)
-{
- int i, j, hint;
- lportal_t *p;
- lleaf_t *l;
- char magic[80];
- FILE *f;
- int numpoints;
- winding_t *w;
- int leafnums[2];
- plane_t plane;
- //
-
- if (!strcmp(name,"-"))
- f = stdin;
- else
- {
- f = fopen(name, "r");
- if (!f)
- Error ("LoadPortals: couldn't read %s\n",name);
- }
-
- if (fscanf (f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces) != 4)
- Error ("LoadPortals: failed to read header");
- if (strcmp(magic, PORTALFILE))
- Error ("LoadPortals: not a portal file");
-
- _printf ("%6i portalclusters\n", portalclusters);
- _printf ("%6i numportals\n", numportals);
- _printf ("%6i numfaces\n", numfaces);
-
- if (portalclusters >= MAX_CLUSTERS)
- Error ("more than %d clusters in portal file\n", MAX_CLUSTERS);
-
- // each file portal is split into two memory portals
- portals = malloc(2*numportals*sizeof(lportal_t));
- memset (portals, 0, 2*numportals*sizeof(lportal_t));
-
- leafs = malloc(portalclusters*sizeof(lleaf_t));
- memset (leafs, 0, portalclusters*sizeof(lleaf_t));
-
- for (i=0, p=portals ; i<numportals ; i++)
- {
- if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3)
- Error ("LoadPortals: reading portal %i", i);
- if (numpoints > MAX_POINTS_ON_WINDING)
- Error ("LoadPortals: portal %i has too many points", i);
- if ( (unsigned)leafnums[0] > portalclusters
- || (unsigned)leafnums[1] > portalclusters)
- Error ("LoadPortals: reading portal %i", i);
- if (fscanf (f, "%i ", &hint) != 1)
- Error ("LoadPortals: reading hint state");
-
- w = p->winding = VL_AllocWinding (numpoints);
- w->numpoints = numpoints;
-
- for (j=0 ; j<numpoints ; j++)
- {
- double v[3];
- int k;
-
- // scanf into double, then assign to vec_t
- // so we don't care what size vec_t is
- if (fscanf (f, "(%lf %lf %lf ) "
- , &v[0], &v[1], &v[2]) != 3)
- Error ("LoadPortals: reading portal %i", i);
- for (k=0 ; k<3 ; k++)
- w->points[j][k] = v[k];
- }
- fscanf (f, "\n");
-
- // calc plane
- VL_PlaneFromWinding (w, &plane);
-
- // create forward portal
- l = &leafs[leafnums[0]];
- if (l->numportals == MAX_PORTALS_ON_LEAF)
- Error ("Leaf with too many portals");
- l->portals[l->numportals] = p;
- l->numportals++;
-
- p->winding = w;
- VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
- p->plane.dist = -plane.dist;
- p->leaf = leafnums[1];
- VL_SetPortalSphere (p);
- p++;
-
- // create backwards portal
- l = &leafs[leafnums[1]];
- if (l->numportals == MAX_PORTALS_ON_LEAF)
- Error ("Leaf with too many portals");
- l->portals[l->numportals] = p;
- l->numportals++;
-
- p->winding = VL_AllocWinding(w->numpoints);
- p->winding->numpoints = w->numpoints;
- for (j=0 ; j<w->numpoints ; j++)
- {
- VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]);
- }
-
- p->plane = plane;
- p->leaf = leafnums[0];
- VL_SetPortalSphere (p);
- p++;
-
- }
-
- fclose (f);
-}
-
-/*
-============
-VLightMain
-============
-*/
-int VLightMain (int argc, char **argv) {
- int i;
- double start, end;
- const char *value;
-
- _printf ("----- VLighting ----\n");
-
- for (i=1 ; i<argc ; i++) {
- if (!strcmp(argv[i],"-v")) {
- verbose = qtrue;
- } else if (!strcmp(argv[i],"-threads")) {
- numthreads = atoi (argv[i+1]);
- _printf("num threads = %d\n", numthreads);
- i++;
- } else if (!strcmp(argv[i],"-area")) {
- lightAreaScale *= atof(argv[i+1]);
- _printf ("area light scaling at %f\n", lightAreaScale);
- i++;
- } else if (!strcmp(argv[i],"-point")) {
- lightPointScale *= atof(argv[i+1]);
- _printf ("point light scaling at %f\n", lightPointScale);
- i++;
- } else if (!strcmp(argv[i], "-samplesize")) {
- samplesize = atoi(argv[i+1]);
- if (samplesize < 1) samplesize = 1;
- i++;
- _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize);
- } else if (!strcmp(argv[i], "-novertex")) {
- novertexlighting = qtrue;
- _printf("no vertex lighting = true\n");
- } else if (!strcmp(argv[i], "-nogrid")) {
- nogridlighting = qtrue;
- _printf("no grid lighting = true\n");
- } else if (!strcmp(argv[i], "-nostitching")) {
- nostitching = qtrue;
- _printf("no stitching = true\n");
- } else if (!strcmp(argv[i], "-noalphashading")) {
- noalphashading = qtrue;
- _printf("no alpha shading = true\n");
- } else if (!strcmp(argv[i], "-nocolorshading")) {
- nocolorshading = qtrue;
- _printf("old style alpha shading = true\n");
- } else if (!strcmp(argv[i], "-nobackfaceculling")) {
- nobackfaceculling = qtrue;
- _printf("no backface culling = true\n");
- } else if (!strcmp(argv[i], "-tracelight")) {
- defaulttracelight = qtrue;
- _printf("default trace light = true\n");
- } else if (!strcmp(argv[i], "-radiosity")) {
- radiosity = atoi(argv[i+1]);
- _printf("radiosity = %d\n", radiosity);
- i++;
- } else {
- break;
- }
- }
-
- ThreadSetDefault ();
-
- if (i != argc - 1) {
- _printf("usage: q3map -vlight [-<switch> [-<switch> ...]] <mapname>\n"
- "\n"
- "Switches:\n"
- " v = verbose output\n"
- " threads <X> = set number of threads to X\n"
- " area <V> = set the area light scale to V\n"
- " point <W> = set the point light scale to W\n"
- " novertex = don't calculate vertex lighting\n"
- " nogrid = don't calculate light grid for dynamic model lighting\n"
- " nostitching = no polygon stitching before lighting\n"
- " noalphashading = don't use alpha shading\n"
- " nocolorshading = don't use color alpha shading\n"
- " tracelight = use old light algorithm by default\n"
- " samplesize <N> = set the lightmap pixel size to NxN units\n");
- exit(0);
- }
-
- SetQdirFromPath (argv[i]);
-
-#ifdef _WIN32
- InitPakFile(gamedir, NULL);
-#endif
-
- strcpy (source, ExpandArg(argv[i]));
- StripExtension (source);
- DefaultExtension (source, ".bsp");
-
- LoadShaderInfo();
-
- _printf ("reading %s\n", source);
-
- LoadBSPFile (source);
- ParseEntities();
-
- value = ValueForKey( &entities[0], "gridsize" );
- if (strlen(value)) {
- sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] );
- _printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]);
- }
-
- CountLightmaps();
-
- StripExtension (source);
- DefaultExtension (source, ".prt");
-
- VL_LoadPortals(source);
-
- // set surfaceOrigin
- SetEntityOrigins();
-
- // grid and vertex lighting
- GridAndVertexLighting();
-
-#ifdef DEBUGNET
- DebugNet_Setup();
-#endif
-
- start = clock();
-
- lightFloats = (float *) malloc(numLightBytes * sizeof(float));
- memset(lightFloats, 0, numLightBytes * sizeof(float));
-
- VL_InitSurfacesForTesting();
-
- VL_CalcVisibleLightmapPixelArea();
-
- numvlights = 0;
- VL_CreateEntityLights();
- VL_CreateFakeSurfaceLights();
- VL_CreateSkyLights();
-
- VL_TestLightLeafs();
-
- VL_LightWorld();
-
-#ifndef LIGHTPOLYS
- StripExtension (source);
- DefaultExtension (source, ".bsp");
- _printf ("writing %s\n", source);
- WriteBSPFile (source);
-#endif
-
- end = clock();
-
- _printf ("%5.2f seconds elapsed\n", (end-start) / CLK_TCK);
-
-#ifdef LIGHTPOLYS
- VL_DrawLightWindings();
-#endif
-
-#ifdef DEBUGNET
- DebugNet_Shutdown();
-#endif
- return 0;
-}
+
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "bspfile.h"
+#include "imagelib.h"
+#include "threads.h"
+#include "mutex.h"
+#include "scriplib.h"
+
+#include "shaders.h"
+#include "mesh.h"
+
+#ifdef _WIN32
+//Improve floating-point consistency.
+#pragma optimize( "p", on )
+#endif
+
+#ifdef _WIN32
+#include "../libs/pakstuff.h"
+#endif
+
+#define MAX_CLUSTERS 16384
+#define MAX_PORTALS 32768
+#define MAX_FACETS 65536
+#define MAX_LIGHTS 16384
+
+#define LIGHTMAP_SIZE 128
+
+#define LIGHTMAP_PIXELSHIFT 0.5
+
+//#define LIGHTMAP_PATCHSHIFT
+
+#define PORTALFILE "PRT1"
+
+#define ON_EPSILON 0.1
+
+#define VectorSet(v, x, y, z) v[0] = x;v[1] = y;v[2] = z;
+
+typedef struct
+{
+ vec3_t normal;
+ float dist;
+} plane_t;
+
+#define MAX_POINTS_ON_WINDING 64
+//NOTE: whenever this is overflowed parts of lightmaps might end up not being lit
+#define MAX_POINTS_ON_FIXED_WINDING 48
+
+typedef struct
+{
+ int numpoints;
+ vec3_t points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized
+} winding_t;
+
+typedef struct
+{
+ plane_t plane; // normal pointing into neighbor
+ int leaf; // neighbor
+ winding_t *winding;
+ vec3_t origin; // for fast clip testing
+ float radius;
+} lportal_t;
+
+#define MAX_PORTALS_ON_LEAF 128
+typedef struct lleaf_s
+{
+ int numportals;
+ lportal_t *portals[MAX_PORTALS_ON_LEAF];
+ //
+ int numSurfaces;
+ int firstSurface;
+} lleaf_t;
+
+typedef struct lFacet_s
+{
+ int num;
+ plane_t plane;
+ vec3_t points[4]; //
+ int numpoints;
+ float lightmapCoords[4][2];
+ plane_t boundaries[4]; // negative is outside the bounds
+ float textureMatrix[2][4]; // texture coordinates for translucency
+ float lightmapMatrix[2][4]; // lightmap texture coordinates
+ vec3_t mins;
+ int x, y, width, height;
+} lFacet_t;
+
+typedef struct lsurfaceTest_s
+{
+ vec3_t mins, maxs;
+ vec3_t origin;
+ float radius;
+ qboolean patch; // true if this is a patch
+ qboolean trisoup; // true if this is a triangle soup
+ int numFacets;
+ lFacet_t *facets;
+ mesh_t *detailMesh; // detailed mesh with points for each lmp
+ shaderInfo_t *shader; // for translucency
+ mutex_t *mutex;
+ int numvolumes; // number of volumes casted at this surface
+ //
+ int always_tracelight;
+ int always_vlight;
+} lsurfaceTest_t;
+
+//volume types
+#define VOLUME_NORMAL 0
+#define VOLUME_DIRECTED 1
+
+#define MAX_TRANSLUCENTFACETS 32
+
+typedef struct lightvolume_s
+{
+ int num;
+ int cluster; //cluster this light volume started in
+ plane_t endplane; //end plane
+ plane_t farplane; //original end plane
+ vec3_t points[MAX_POINTS_ON_WINDING]; //end winding points
+ plane_t planes[MAX_POINTS_ON_WINDING]; //volume bounding planes
+ int numplanes; //number of volume bounding planes
+ int type; //light volume type
+ //list with translucent surfaces the volume went through
+ int transFacets[MAX_TRANSLUCENTFACETS];
+ int transSurfaces[MAX_TRANSLUCENTFACETS];
+ int numtransFacets;
+ //clusters already tested
+ byte clusterTested[MAX_CLUSTERS/8];
+ //facets already tested
+ byte facetTested[MAX_FACETS/8];
+ int facetNum; //number of the facet blocking the light in this volume
+ int surfaceNum; //number of the surface blocking the light in this volume
+} lightvolume_t;
+
+//light types
+#define LIGHT_POINTRADIAL 1
+#define LIGHT_POINTSPOT 2
+#define LIGHT_POINTFAKESURFACE 3
+#define LIGHT_SURFACEDIRECTED 4
+#define LIGHT_SURFACERADIAL 5
+#define LIGHT_SURFACESPOT 6
+
+//light distance attenuation types
+#define LDAT_QUADRATIC 0
+#define LDAT_LINEAR 1
+#define LDAT_NOSCALE 2
+
+//light angle attenuation types
+#define LAAT_NORMAL 0
+#define LAAT_QUADRATIC 1
+#define LAAT_DOUBLEQUADRATIC 2
+
+typedef struct vlight_s
+{
+ vec3_t origin; //light origin, for point lights
+ winding_t w; //light winding, for area lights
+ vec4_t plane; //light winding plane
+ vec3_t normal; //direction of the light
+ int type; //light type
+ vec3_t color; //light color
+ qboolean twosided; //radiates light at both sides of the winding
+ int style; //light style (not used)
+ int atten_disttype; //light distance attenuation type
+ int atten_angletype; //light angle attenuation type
+ float atten_distscale; //distance attenuation scale
+ float atten_anglescale; //angle attenuation scale
+ float radiusByDist; //radius by distance for spot lights
+ float photons; //emitted photons
+ float intensity; //intensity
+ vec3_t emitColor; //full out-of-gamut value (not used)
+ struct shaderInfo_s *si; //shader info
+ int insolid; //set when light is in solid
+} vlight_t;
+
+float lightLinearScale = 1.0 / 8000;
+float lightPointScale = 7500;
+float lightAreaScale = 0.25;
+float lightFormFactorValueScale = 3;
+int lightDefaultSubdivide = 999; // vary by surface size?
+vec3_t lightAmbientColor;
+
+int portalclusters, numportals, numfaces;
+lleaf_t *leafs;
+lportal_t *portals;
+int numvlights = 0;
+vlight_t *vlights[MAX_LIGHTS];
+int nostitching = 0;
+int noalphashading = 0;
+int nocolorshading = 0;
+int nobackfaceculling = 0;
+int defaulttracelight = 0;
+int radiosity = 0;
+int radiosity_scale;
+
+int clustersurfaces[MAX_MAP_LEAFFACES];
+int numclustersurfaces = 0;
+lsurfaceTest_t *lsurfaceTest[MAX_MAP_DRAW_SURFS];
+int numfacets;
+float lightmappixelarea[MAX_MAP_LIGHTING/3];
+float *lightFloats;//[MAX_MAP_LIGHTING];
+
+// from polylib.c
+winding_t *AllocWinding (int points);
+void FreeWinding (winding_t *w);
+void WindingCenter (winding_t *w, vec3_t center);
+void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs);
+vec_t WindingArea (winding_t *w);
+winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist);
+void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
+ vec_t epsilon, winding_t **front, winding_t **back);
+winding_t *ReverseWinding (winding_t *w);
+
+// from light.c
+extern char source[1024];
+extern vec3_t surfaceOrigin[ MAX_MAP_DRAW_SURFS ];
+extern int entitySurface[ MAX_MAP_DRAW_SURFS ];
+extern int samplesize;
+extern int novertexlighting;
+extern int nogridlighting;
+extern qboolean patchshadows;
+extern vec3_t gridSize;
+
+float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w );
+void ColorToBytes( const float *color, byte *colorBytes );
+void CountLightmaps( void );
+void GridAndVertexLighting( void );
+void SetEntityOrigins( void );
+
+
+//#define DEBUGNET
+
+#ifdef DEBUGNET
+
+#include "l_net.h"
+
+socket_t *debug_socket;
+
+/*
+=====================
+DebugNet_Setup
+=====================
+*/
+void DebugNet_Setup(void)
+{
+ address_t address;
+ int i;
+
+ Net_Setup();
+ Net_StringToAddress("127.0.0.1:28000", &address);
+ for (i = 0; i < 10; i++)
+ {
+ debug_socket = Net_Connect(&address, 28005 + i);
+ if (debug_socket)
+ break;
+ }
+}
+
+/*
+=====================
+DebugNet_Shutdown
+=====================
+*/
+void DebugNet_Shutdown(void)
+{
+ netmessage_t msg;
+
+ if (debug_socket)
+ {
+ NMSG_Clear(&msg);
+ NMSG_WriteByte(&msg, 1);
+ Net_Send(debug_socket, &msg);
+ Net_Disconnect(debug_socket);
+ }
+ debug_socket = NULL;
+ Net_Shutdown();
+}
+
+/*
+=====================
+DebugNet_RemoveAllPolys
+=====================
+*/
+void DebugNet_RemoveAllPolys(void)
+{
+ netmessage_t msg;
+
+ if (!debug_socket)
+ return;
+ NMSG_Clear(&msg);
+ NMSG_WriteByte(&msg, 2); //remove all debug polys
+ Net_Send(debug_socket, &msg);
+}
+
+/*
+====================
+DebugNet_DrawWinding
+=====================
+*/
+void DebugNet_DrawWinding(winding_t *w, int color)
+{
+ netmessage_t msg;
+ int i;
+
+ if (!debug_socket)
+ return;
+ NMSG_Clear(&msg);
+ NMSG_WriteByte(&msg, 0); //draw a winding
+ NMSG_WriteByte(&msg, w->numpoints); //number of points
+ NMSG_WriteLong(&msg, color); //color
+ for (i = 0; i < w->numpoints; i++)
+ {
+ NMSG_WriteFloat(&msg, w->points[i][0]);
+ NMSG_WriteFloat(&msg, w->points[i][1]);
+ NMSG_WriteFloat(&msg, w->points[i][2]);
+ }
+ Net_Send(debug_socket, &msg);
+}
+
+/*
+=====================
+DebugNet_DrawLine
+=====================
+*/
+void DebugNet_DrawLine(vec3_t p1, vec3_t p2, int color)
+{
+ netmessage_t msg;
+
+ if (!debug_socket)
+ return;
+ NMSG_Clear(&msg);
+ NMSG_WriteByte(&msg, 1); //draw a line
+ NMSG_WriteLong(&msg, color); //color
+ NMSG_WriteFloat(&msg, p1[0]);
+ NMSG_WriteFloat(&msg, p1[1]);
+ NMSG_WriteFloat(&msg, p1[2]);
+ NMSG_WriteFloat(&msg, p2[0]);
+ NMSG_WriteFloat(&msg, p2[1]);
+ NMSG_WriteFloat(&msg, p2[2]);
+ Net_Send(debug_socket, &msg);
+}
+
+/*
+=====================
+DebugNet_DrawMesh
+=====================
+*/
+void DebugNet_DrawMesh(mesh_t *mesh)
+{
+ int i, j;
+ float dot;
+ drawVert_t *v1, *v2, *v3, *v4;
+ winding_t winding;
+ plane_t plane;
+ vec3_t d1, d2;
+
+ for ( i = 0 ; i < mesh->width - 1 ; i++ ) {
+ for ( j = 0 ; j < mesh->height - 1 ; j++ ) {
+
+ v1 = mesh->verts + j * mesh->width + i;
+ v2 = v1 + 1;
+ v3 = v1 + mesh->width + 1;
+ v4 = v1 + mesh->width;
+
+ VectorSubtract( v4->xyz, v1->xyz, d1 );
+ VectorSubtract( v3->xyz, v1->xyz, d2 );
+ CrossProduct( d2, d1, plane.normal );
+ if ( VectorNormalize( plane.normal, plane.normal ) != 0 )
+ {
+ plane.dist = DotProduct( v1->xyz, plane.normal );
+ dot = DotProduct(plane.normal, v2->xyz) - plane.dist;
+ if (fabs(dot) < 0.1)
+ {
+ VectorCopy(v1->xyz, winding.points[0]);
+ VectorCopy(v4->xyz, winding.points[1]);
+ VectorCopy(v3->xyz, winding.points[2]);
+ VectorCopy(v2->xyz, winding.points[3]);
+ winding.numpoints = 4;
+ DebugNet_DrawWinding(&winding, 2);
+ continue;
+ }
+ }
+
+ winding.numpoints = 3;
+ VectorCopy(v1->xyz, winding.points[0]);
+ VectorCopy(v4->xyz, winding.points[1]);
+ VectorCopy(v3->xyz, winding.points[2]);
+ DebugNet_DrawWinding(&winding, 2);
+
+ VectorCopy(v1->xyz, winding.points[0]);
+ VectorCopy(v3->xyz, winding.points[1]);
+ VectorCopy(v2->xyz, winding.points[2]);
+ DebugNet_DrawWinding(&winding, 2);
+ }
+ }
+}
+
+/*
+=====================
+VL_DrawLightVolume
+=====================
+*/
+int VL_ChopWinding (winding_t *in, plane_t *split, float epsilon);
+
+void VL_DrawLightVolume(vlight_t *light, lightvolume_t *volume)
+{
+ winding_t w;
+ int i;
+ vec3_t p2, invlight;
+
+ memcpy(w.points, volume->points, volume->numplanes * sizeof(vec3_t));
+ w.numpoints = volume->numplanes;
+ DebugNet_DrawWinding(&w, 2);
+
+ if (volume->type == VOLUME_DIRECTED)
+ {
+ VectorCopy(light->normal, invlight);
+ VectorInverse(invlight);
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ VectorCopy(volume->points[i], w.points[0]);
+ VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[1]);
+ VectorMA(w.points[1], MAX_WORLD_COORD, invlight, w.points[2]);
+ VectorMA(w.points[0], MAX_WORLD_COORD, invlight, w.points[3]);
+ w.numpoints = 4;
+ DebugNet_DrawWinding(&w, 2);
+ VectorMA(volume->points[i], 8, volume->planes[i].normal, p2);
+ DebugNet_DrawLine(volume->points[i], p2, 3);
+ }
+ }
+ else
+ {
+ //
+ VectorCopy(light->origin, w.points[0]);
+ w.numpoints = 3;
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ VectorCopy(volume->points[i], w.points[1]);
+ VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[2]);
+ VL_ChopWinding(&w, &volume->endplane, 0);
+ DebugNet_DrawWinding(&w, 2);
+ VectorMA(volume->points[i], 8, volume->planes[i].normal, p2);
+ DebugNet_DrawLine(volume->points[i], p2, 3);
+ }
+ }
+}
+
+/*
+=============
+VL_DrawLightmapPixel
+=============
+*/
+void VL_DrawLightmapPixel(int surfaceNum, int x, int y, int color)
+{
+ winding_t w;
+ dsurface_t *ds;
+ mesh_t *mesh;
+
+ ds = &drawSurfaces[surfaceNum];
+
+ if (ds->surfaceType == MST_PATCH)
+ {
+ mesh = lsurfaceTest[surfaceNum]->detailMesh;
+ VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]);
+ VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]);
+ VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]);
+ VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]);
+ w.numpoints = 4;
+ }
+ else
+ {
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]);
+ VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]);
+ VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]);
+ VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]);
+ VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]);
+ w.numpoints = 4;
+ }
+ DebugNet_DrawWinding(&w, color);
+}
+
+/*
+============
+VL_DrawPortals
+============
+*/
+void VL_DrawPortals(void)
+{
+ int j;
+ lportal_t *p;
+
+ for (j = 0; j < numportals * 2; j++)
+ {
+ p = portals + j;
+ DebugNet_DrawWinding(p->winding, 1);
+ }
+}
+
+/*
+============
+VL_DrawLeaf
+============
+*/
+void VL_DrawLeaf(int cluster)
+{
+ int i;
+ lleaf_t *leaf;
+ lportal_t *p;
+
+ leaf = &leafs[cluster];
+ for (i = 0; i < leaf->numportals; i++)
+ {
+ p = leaf->portals[i];
+ DebugNet_DrawWinding(p->winding, 1);
+ }
+}
+
+#endif //DEBUGNET
+
+/*
+=============
+VL_SplitWinding
+=============
+*/
+int VL_SplitWinding (winding_t *in, winding_t *back, plane_t *split, float epsilon)
+{
+ vec_t dists[128];
+ int sides[128];
+ int counts[3];
+ vec_t dot;
+ int i, j;
+ vec_t *p1, *p2;
+ vec3_t mid;
+ winding_t out;
+ winding_t *neww;
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+ // determine sides for each point
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ dot = DotProduct (in->points[i], split->normal);
+ dot -= split->dist;
+ dists[i] = dot;
+ if (dot > epsilon)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -epsilon)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+
+ if (!counts[SIDE_BACK])
+ {
+ if (!counts[SIDE_FRONT])
+ return SIDE_ON;
+ else
+ return SIDE_FRONT;
+ }
+
+ if (!counts[SIDE_FRONT])
+ {
+ return SIDE_BACK;
+ }
+
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ neww = &out;
+
+ neww->numpoints = 0;
+ back->numpoints = 0;
+
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ p1 = in->points[i];
+
+ if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return SIDE_FRONT; // can't chop -- fall back to original
+ }
+ if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return SIDE_FRONT;
+ }
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy (p1, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ VectorCopy (p1, back->points[back->numpoints]);
+ back->numpoints++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ }
+ if (sides[i] == SIDE_BACK)
+ {
+ VectorCopy (p1, back->points[back->numpoints]);
+ back->numpoints++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return SIDE_FRONT; // can't chop -- fall back to original
+ }
+
+ if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VL_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return SIDE_FRONT; // can't chop -- fall back to original
+ }
+
+ // generate a split point
+ p2 = in->points[(i+1)%in->numpoints];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (split->normal[j] == 1)
+ mid[j] = split->dist;
+ else if (split->normal[j] == -1)
+ mid[j] = -split->dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ VectorCopy (mid, back->points[back->numpoints]);
+ back->numpoints++;
+ }
+ memcpy(in, &out, sizeof(winding_t));
+
+ return SIDE_CROSS;
+}
+
+/*
+=====================
+VL_LinkSurfaceIntoCluster
+=====================
+*/
+void VL_LinkSurfaceIntoCluster(int cluster, int surfaceNum)
+{
+ lleaf_t *leaf;
+ int i;
+
+ leaf = &leafs[cluster];
+
+ for (i = 0; i < leaf->numSurfaces; i++)
+ {
+ if (clustersurfaces[leaf->firstSurface + i] == surfaceNum)
+ return;
+ }
+ for (i = numclustersurfaces; i > leaf->firstSurface + leaf->numSurfaces; i--)
+ clustersurfaces[i] = clustersurfaces[i-1];
+ for (i = 0; i < portalclusters; i++)
+ {
+ if (i == cluster)
+ continue;
+ if (leafs[i].firstSurface >= leaf->firstSurface + leaf->numSurfaces)
+ leafs[i].firstSurface++;
+ }
+ clustersurfaces[leaf->firstSurface + leaf->numSurfaces] = surfaceNum;
+ leaf->numSurfaces++;
+ numclustersurfaces++;
+ if (numclustersurfaces >= MAX_MAP_LEAFFACES)
+ Error("MAX_MAP_LEAFFACES");
+}
+
+/*
+=====================
+VL_R_LinkSurface
+=====================
+*/
+void VL_R_LinkSurface(int nodenum, int surfaceNum, winding_t *w)
+{
+ int leafnum, cluster, res;
+ dnode_t *node;
+ dplane_t *plane;
+ winding_t back;
+ plane_t split;
+
+ while(nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+
+ VectorCopy(plane->normal, split.normal);
+ split.dist = plane->dist;
+ res = VL_SplitWinding (w, &back, &split, 0.1);
+
+ if (res == SIDE_FRONT)
+ {
+ nodenum = node->children[0];
+ }
+ else if (res == SIDE_BACK)
+ {
+ nodenum = node->children[1];
+ }
+ else if (res == SIDE_ON)
+ {
+ memcpy(&back, w, sizeof(winding_t));
+ VL_R_LinkSurface(node->children[1], surfaceNum, &back);
+ nodenum = node->children[0];
+ }
+ else
+ {
+ VL_R_LinkSurface(node->children[1], surfaceNum, &back);
+ nodenum = node->children[0];
+ }
+ }
+ leafnum = -nodenum - 1;
+ cluster = dleafs[leafnum].cluster;
+ if (cluster != -1)
+ {
+ VL_LinkSurfaceIntoCluster(cluster, surfaceNum);
+ }
+}
+
+/*
+=====================
+VL_LinkSurfaces
+
+maybe link each facet seperately instead of the test surfaces?
+=====================
+*/
+void VL_LinkSurfaces(void)
+{
+ int i, j;
+ lsurfaceTest_t *test;
+ lFacet_t *facet;
+ winding_t winding;
+
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ for (j = 0; j < test->numFacets; j++)
+ {
+ facet = &test->facets[j];
+ memcpy(winding.points, facet->points, facet->numpoints * sizeof(vec3_t));
+ winding.numpoints = facet->numpoints;
+ VL_R_LinkSurface(0, i, &winding);
+ }
+ }
+}
+
+/*
+=====================
+VL_TextureMatrixFromPoints
+=====================
+*/
+void VL_TextureMatrixFromPoints( lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
+ int i, j;
+ float t;
+ float m[3][4];
+ float s;
+
+ // This is an incredibly stupid way of solving a three variable equation
+ for ( i = 0 ; i < 2 ; i++ ) {
+
+ m[0][0] = a->xyz[0];
+ m[0][1] = a->xyz[1];
+ m[0][2] = a->xyz[2];
+ m[0][3] = a->st[i];
+
+ m[1][0] = b->xyz[0];
+ m[1][1] = b->xyz[1];
+ m[1][2] = b->xyz[2];
+ m[1][3] = b->st[i];
+
+ m[2][0] = c->xyz[0];
+ m[2][1] = c->xyz[1];
+ m[2][2] = c->xyz[2];
+ m[2][3] = c->st[i];
+
+ if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) > fabs(m[2][0]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[0][j];
+ m[0][j] = m[1][j];
+ m[1][j] = t;
+ }
+ } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) > fabs(m[1][0]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[0][j];
+ m[0][j] = m[2][j];
+ m[2][j] = t;
+ }
+ }
+
+ s = 1.0 / m[0][0];
+ m[0][0] *= s;
+ m[0][1] *= s;
+ m[0][2] *= s;
+ m[0][3] *= s;
+
+ s = m[1][0];
+ m[1][0] -= m[0][0] * s;
+ m[1][1] -= m[0][1] * s;
+ m[1][2] -= m[0][2] * s;
+ m[1][3] -= m[0][3] * s;
+
+ s = m[2][0];
+ m[2][0] -= m[0][0] * s;
+ m[2][1] -= m[0][1] * s;
+ m[2][2] -= m[0][2] * s;
+ m[2][3] -= m[0][3] * s;
+
+ if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[1][j];
+ m[1][j] = m[2][j];
+ m[2][j] = t;
+ }
+ }
+
+ s = 1.0 / m[1][1];
+ m[1][0] *= s;
+ m[1][1] *= s;
+ m[1][2] *= s;
+ m[1][3] *= s;
+
+ s = m[2][1];// / m[1][1];
+ m[2][0] -= m[1][0] * s;
+ m[2][1] -= m[1][1] * s;
+ m[2][2] -= m[1][2] * s;
+ m[2][3] -= m[1][3] * s;
+
+ s = 1.0 / m[2][2];
+ m[2][0] *= s;
+ m[2][1] *= s;
+ m[2][2] *= s;
+ m[2][3] *= s;
+
+ f->textureMatrix[i][2] = m[2][3];
+ f->textureMatrix[i][1] = m[1][3] - f->textureMatrix[i][2] * m[1][2];
+ f->textureMatrix[i][0] = m[0][3] - f->textureMatrix[i][2] * m[0][2] - f->textureMatrix[i][1] * m[0][1];
+
+ f->textureMatrix[i][3] = 0;
+/*
+ s = fabs( DotProduct( a->xyz, f->textureMatrix[i] ) - a->st[i] );
+ if ( s > 0.01 ) {
+ Error( "Bad textureMatrix" );
+ }
+ s = fabs( DotProduct( b->xyz, f->textureMatrix[i] ) - b->st[i] );
+ if ( s > 0.01 ) {
+ Error( "Bad textureMatrix" );
+ }
+ s = fabs( DotProduct( c->xyz, f->textureMatrix[i] ) - c->st[i] );
+ if ( s > 0.01 ) {
+ Error( "Bad textureMatrix" );
+ }
+*/
+ }
+}
+
+/*
+=====================
+VL_LightmapMatrixFromPoints
+=====================
+*/
+void VL_LightmapMatrixFromPoints( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
+ int i, j;
+ float t;
+ float m[3][4], al, bl, cl;
+ float s;
+ int h, w, ssize;
+ vec3_t mins, maxs, delta, size, planeNormal;
+ drawVert_t *verts;
+ static int message;
+
+ // vertex-lit triangle model
+ if ( dsurf->surfaceType == MST_TRIANGLE_SOUP ) {
+ return;
+ }
+
+ if ( dsurf->lightmapNum < 0 ) {
+ return; // doesn't need lighting
+ }
+
+ VectorClear(f->mins);
+ if (dsurf->surfaceType != MST_PATCH)
+ {
+ ssize = samplesize;
+ if (si->lightmapSampleSize)
+ ssize = si->lightmapSampleSize;
+ ClearBounds( mins, maxs );
+ verts = &drawVerts[dsurf->firstVert];
+ for ( i = 0 ; i < dsurf->numVerts ; i++ ) {
+ AddPointToBounds( verts[i].xyz, mins, maxs );
+ }
+ // round to the lightmap resolution
+ for ( i = 0 ; i < 3 ; i++ ) {
+ mins[i] = ssize * floor( mins[i] / ssize );
+ maxs[i] = ssize * ceil( maxs[i] / ssize );
+ f->mins[i] = mins[i];
+ size[i] = (maxs[i] - mins[i]) / ssize + 1;
+ }
+ // the two largest axis will be the lightmap size
+ VectorClear(f->lightmapMatrix[0]);
+ f->lightmapMatrix[0][3] = 0;
+ VectorClear(f->lightmapMatrix[1]);
+ f->lightmapMatrix[1][3] = 0;
+
+ planeNormal[0] = fabs( dsurf->lightmapVecs[2][0] );
+ planeNormal[1] = fabs( dsurf->lightmapVecs[2][1] );
+ planeNormal[2] = fabs( dsurf->lightmapVecs[2][2] );
+
+ if ( planeNormal[0] >= planeNormal[1] && planeNormal[0] >= planeNormal[2] ) {
+ w = size[1];
+ h = size[2];
+ f->lightmapMatrix[0][1] = 1.0 / ssize;
+ f->lightmapMatrix[1][2] = 1.0 / ssize;
+ } else if ( planeNormal[1] >= planeNormal[0] && planeNormal[1] >= planeNormal[2] ) {
+ w = size[0];
+ h = size[2];
+ f->lightmapMatrix[0][0] = 1.0 / ssize;
+ f->lightmapMatrix[1][2] = 1.0 / ssize;
+ } else {
+ w = size[0];
+ h = size[1];
+ f->lightmapMatrix[0][0] = 1.0 / ssize;
+ f->lightmapMatrix[1][1] = 1.0 / ssize;
+ }
+ if ( w > LIGHTMAP_WIDTH ) {
+ VectorScale ( f->lightmapMatrix[0], (float)LIGHTMAP_SIZE/w, f->lightmapMatrix[0] );
+ }
+
+ if ( h > LIGHTMAP_HEIGHT ) {
+ VectorScale ( f->lightmapMatrix[1], (float)LIGHTMAP_SIZE/h, f->lightmapMatrix[1] );
+ }
+ VectorSubtract(a->xyz, f->mins, delta);
+ s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
+ if ( fabs(s - a->lightmap[0]) > 0.01 ) {
+ _printf( "Bad lightmapMatrix" );
+ }
+ t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
+ if ( fabs(t - a->lightmap[1]) > 0.01 ) {
+ _printf( "Bad lightmapMatrix" );
+ }
+ VectorSubtract(b->xyz, f->mins, delta);
+ s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
+ if ( fabs(s - b->lightmap[0]) > 0.01 ) {
+ _printf( "Bad lightmapMatrix" );
+ }
+ t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
+ if ( fabs(t - b->lightmap[1]) > 0.01 ) {
+ _printf( "Bad lightmapMatrix" );
+ }
+ VectorSubtract(c->xyz, f->mins, delta);
+ s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
+ if ( fabs(s - c->lightmap[0]) > 0.01 ) {
+ _printf( "Bad lightmapMatrix" );
+ }
+ t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
+ if ( fabs(t - c->lightmap[1]) > 0.01 ) {
+ _printf( "Bad lightmapMatrix" );
+ }
+ VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins);
+ return;
+ }
+ // This is an incredibly stupid way of solving a three variable equation
+ for ( i = 0 ; i < 2 ; i++ ) {
+
+ if (i)
+ al = a->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
+ else
+ al = a->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
+
+ m[0][0] = a->xyz[0] - f->mins[0];
+ m[0][1] = a->xyz[1] - f->mins[1];
+ m[0][2] = a->xyz[2] - f->mins[2];
+ m[0][3] = al;
+
+ if (i)
+ bl = b->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
+ else
+ bl = b->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
+
+ m[1][0] = b->xyz[0] - f->mins[0];
+ m[1][1] = b->xyz[1] - f->mins[1];
+ m[1][2] = b->xyz[2] - f->mins[2];
+ m[1][3] = bl;
+
+ if (i)
+ cl = c->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
+ else
+ cl = c->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
+
+ m[2][0] = c->xyz[0] - f->mins[0];
+ m[2][1] = c->xyz[1] - f->mins[1];
+ m[2][2] = c->xyz[2] - f->mins[2];
+ m[2][3] = cl;
+
+ if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) >= fabs(m[2][0]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[0][j];
+ m[0][j] = m[1][j];
+ m[1][j] = t;
+ }
+ } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) >= fabs(m[1][0]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[0][j];
+ m[0][j] = m[2][j];
+ m[2][j] = t;
+ }
+ }
+
+ if (m[0][0])
+ {
+ s = 1.0 / m[0][0];
+ m[0][0] *= s;
+ m[0][1] *= s;
+ m[0][2] *= s;
+ m[0][3] *= s;
+
+ s = m[1][0];
+ m[1][0] -= m[0][0] * s;
+ m[1][1] -= m[0][1] * s;
+ m[1][2] -= m[0][2] * s;
+ m[1][3] -= m[0][3] * s;
+
+ s = m[2][0];
+ m[2][0] -= m[0][0] * s;
+ m[2][1] -= m[0][1] * s;
+ m[2][2] -= m[0][2] * s;
+ m[2][3] -= m[0][3] * s;
+ }
+
+ if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[1][j];
+ m[1][j] = m[2][j];
+ m[2][j] = t;
+ }
+ }
+
+ if (m[1][1])
+ {
+ s = 1.0 / m[1][1];
+ m[1][0] *= s;
+ m[1][1] *= s;
+ m[1][2] *= s;
+ m[1][3] *= s;
+
+ s = m[2][1];
+ m[2][0] -= m[1][0] * s;
+ m[2][1] -= m[1][1] * s;
+ m[2][2] -= m[1][2] * s;
+ m[2][3] -= m[1][3] * s;
+ }
+
+ if (m[2][2])
+ {
+ s = 1.0 / m[2][2];
+ m[2][0] *= s;
+ m[2][1] *= s;
+ m[2][2] *= s;
+ m[2][3] *= s;
+ }
+
+ f->lightmapMatrix[i][2] = m[2][3];
+ f->lightmapMatrix[i][1] = m[1][3] - f->lightmapMatrix[i][2] * m[1][2];
+ f->lightmapMatrix[i][0] = m[0][3] - f->lightmapMatrix[i][2] * m[0][2] - f->lightmapMatrix[i][1] * m[0][1];
+
+ f->lightmapMatrix[i][3] = 0;
+
+ VectorSubtract(a->xyz, f->mins, delta);
+ s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - al );
+ if ( s > 0.01 ) {
+ if (!message)
+ _printf( "Bad lightmapMatrix\n" );
+ message = qtrue;
+ }
+ VectorSubtract(b->xyz, f->mins, delta);
+ s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - bl );
+ if ( s > 0.01 ) {
+ if (!message)
+ _printf( "Bad lightmapMatrix\n" );
+ message = qtrue;
+ }
+ VectorSubtract(c->xyz, f->mins, delta);
+ s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - cl );
+ if ( s > 0.01 ) {
+ if (!message)
+ _printf( "Bad lightmapMatrix\n" );
+ message = qtrue;
+ }
+ VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins);
+ }
+}
+
+/*
+=============
+Plane_Equal
+=============
+*/
+#define NORMAL_EPSILON 0.0001
+#define DIST_EPSILON 0.02
+
+int Plane_Equal(plane_t *a, plane_t *b, int flip)
+{
+ vec3_t normal;
+ float dist;
+
+ if (flip) {
+ normal[0] = - b->normal[0];
+ normal[1] = - b->normal[1];
+ normal[2] = - b->normal[2];
+ dist = - b->dist;
+ }
+ else {
+ normal[0] = b->normal[0];
+ normal[1] = b->normal[1];
+ normal[2] = b->normal[2];
+ dist = b->dist;
+ }
+ if (
+ fabs(a->normal[0] - normal[0]) < NORMAL_EPSILON
+ && fabs(a->normal[1] - normal[1]) < NORMAL_EPSILON
+ && fabs(a->normal[2] - normal[2]) < NORMAL_EPSILON
+ && fabs(a->dist - dist) < DIST_EPSILON )
+ return qtrue;
+ return qfalse;
+}
+
+/*
+=============
+VL_PlaneFromPoints
+=============
+*/
+qboolean VL_PlaneFromPoints( plane_t *plane, const vec3_t a, const vec3_t b, const vec3_t c ) {
+ vec3_t d1, d2;
+
+ VectorSubtract( b, a, d1 );
+ VectorSubtract( c, a, d2 );
+ CrossProduct( d2, d1, plane->normal );
+ if ( VectorNormalize( plane->normal, plane->normal ) == 0 ) {
+ return qfalse;
+ }
+
+ plane->dist = DotProduct( a, plane->normal );
+ return qtrue;
+}
+
+/*
+=====================
+VL_GenerateBoundaryForPoints
+=====================
+*/
+void VL_GenerateBoundaryForPoints( plane_t *boundary, plane_t *plane, vec3_t a, vec3_t b ) {
+ vec3_t d1;
+
+ // make a perpendicular vector to the edge and the surface
+ VectorSubtract( a, b, d1 );
+ CrossProduct( plane->normal, d1, boundary->normal );
+ VectorNormalize( boundary->normal, boundary->normal );
+ boundary->dist = DotProduct( a, boundary->normal );
+}
+
+/*
+=====================
+VL_GenerateFacetFor3Points
+=====================
+*/
+qboolean VL_GenerateFacetFor3Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
+ //
+ vec3_t dir;
+ int i;
+
+ // if we can't generate a valid plane for the points, ignore the facet
+ if ( !VL_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) {
+ f->numpoints = 0;
+ return qfalse;
+ }
+
+ f->num = numfacets++;
+
+ VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] );
+ VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] );
+ VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] );
+
+ f->lightmapCoords[0][0] = a->lightmap[0];
+ f->lightmapCoords[0][1] = a->lightmap[1];
+ f->lightmapCoords[1][0] = b->lightmap[0];
+ f->lightmapCoords[1][1] = b->lightmap[1];
+ f->lightmapCoords[2][0] = c->lightmap[0];
+ f->lightmapCoords[2][1] = c->lightmap[1];
+
+ VL_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] );
+ VL_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] );
+ VL_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[0] );
+
+ for (i = 0; i < 3; i++)
+ {
+ VectorSubtract(f->points[(i+1)%3], f->points[i], dir);
+ if (VectorLength(dir) < 0.1)
+ return qfalse;
+ }
+
+ VL_TextureMatrixFromPoints( f, a, b, c );
+ VL_LightmapMatrixFromPoints( dsurf, si, f, a, b, c );
+
+ f->numpoints = 3;
+
+ return qtrue;
+}
+
+/*
+=====================
+VL_GenerateFacetFor4Points
+
+Attempts to use four points as a planar quad
+=====================
+*/
+#define PLANAR_EPSILON 0.1
+qboolean VL_GenerateFacetFor4Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c, drawVert_t *d ) {
+ float dist;
+ vec3_t dir;
+ int i;
+ plane_t plane;
+
+ // if we can't generate a valid plane for the points, ignore the facet
+ if ( !VL_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) {
+ f->numpoints = 0;
+ return qfalse;
+ }
+
+ // if the fourth point is also on the plane, we can make a quad facet
+ dist = DotProduct( d->xyz, f->plane.normal ) - f->plane.dist;
+ if ( fabs( dist ) > PLANAR_EPSILON ) {
+ f->numpoints = 0;
+ return qfalse;
+ }
+
+ VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] );
+ VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] );
+ VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] );
+ VectorAdd( d->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[3] );
+
+ for (i = 1; i < 4; i++)
+ {
+ if ( !VL_PlaneFromPoints( &plane, f->points[i], f->points[(i+1) % 4], f->points[(i+2) % 4]) ) {
+ f->numpoints = 0;
+ return qfalse;
+ }
+
+ if (!Plane_Equal(&f->plane, &plane, qfalse)) {
+ f->numpoints = 0;
+ return qfalse;
+ }
+ }
+
+ f->lightmapCoords[0][0] = a->lightmap[0];
+ f->lightmapCoords[0][1] = a->lightmap[1];
+ f->lightmapCoords[1][0] = b->lightmap[0];
+ f->lightmapCoords[1][1] = b->lightmap[1];
+ f->lightmapCoords[2][0] = c->lightmap[0];
+ f->lightmapCoords[2][1] = c->lightmap[1];
+ f->lightmapCoords[3][0] = d->lightmap[0];
+ f->lightmapCoords[3][1] = d->lightmap[1];
+
+ VL_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] );
+ VL_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] );
+ VL_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[3] );
+ VL_GenerateBoundaryForPoints( &f->boundaries[3], &f->plane, f->points[3], f->points[0] );
+
+ for (i = 0; i < 4; i++)
+ {
+ VectorSubtract(f->points[(i+1)%4], f->points[i], dir);
+ if (VectorLength(dir) < 0.1)
+ return qfalse;
+ }
+
+ VL_TextureMatrixFromPoints( f, a, b, c );
+ VL_LightmapMatrixFromPoints( dsurf, si, f, a, b, c );
+
+ f->num = numfacets++;
+ f->numpoints = 4;
+
+ return qtrue;
+}
+
+/*
+===============
+VL_SphereFromBounds
+===============
+*/
+void VL_SphereFromBounds( vec3_t mins, vec3_t maxs, vec3_t origin, float *radius ) {
+ vec3_t temp;
+
+ VectorAdd( mins, maxs, origin );
+ VectorScale( origin, 0.5, origin );
+ VectorSubtract( maxs, origin, temp );
+ *radius = VectorLength( temp );
+}
+
+/*
+====================
+VL_FacetsForTriangleSurface
+====================
+*/
+void VL_FacetsForTriangleSurface( dsurface_t *dsurf, shaderInfo_t *si, lsurfaceTest_t *test ) {
+ int i;
+ drawVert_t *v1, *v2, *v3, *v4;
+ int count;
+ int i1, i2, i3, i4, i5, i6;
+
+ test->patch = qfalse;
+ if (dsurf->surfaceType == MST_TRIANGLE_SOUP)
+ test->trisoup = qtrue;
+ else
+ test->trisoup = qfalse;
+ test->numFacets = dsurf->numIndexes / 3;
+ test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
+ test->shader = si;
+
+ count = 0;
+ for ( i = 0 ; i < test->numFacets ; i++ ) {
+ i1 = drawIndexes[ dsurf->firstIndex + i*3 ];
+ i2 = drawIndexes[ dsurf->firstIndex + i*3 + 1 ];
+ i3 = drawIndexes[ dsurf->firstIndex + i*3 + 2 ];
+
+ v1 = &drawVerts[ dsurf->firstVert + i1 ];
+ v2 = &drawVerts[ dsurf->firstVert + i2 ];
+ v3 = &drawVerts[ dsurf->firstVert + i3 ];
+
+ // try and make a quad out of two triangles
+ if ( i != test->numFacets - 1 ) {
+ i4 = drawIndexes[ dsurf->firstIndex + i*3 + 3 ];
+ i5 = drawIndexes[ dsurf->firstIndex + i*3 + 4 ];
+ i6 = drawIndexes[ dsurf->firstIndex + i*3 + 5 ];
+ if ( i4 == i3 && i5 == i2 ) {
+ v4 = &drawVerts[ dsurf->firstVert + i6 ];
+ if ( VL_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v2, v4, v3 ) ) {
+ count++;
+ i++; // skip next tri
+ continue;
+ }
+ }
+ }
+
+ if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v2, v3 )) {
+ count++;
+ }
+ }
+
+ // we may have turned some pairs into quads
+ test->numFacets = count;
+}
+
+/*
+====================
+VL_FacetsForPatch
+====================
+*/
+void VL_FacetsForPatch( dsurface_t *dsurf, int surfaceNum, shaderInfo_t *si, lsurfaceTest_t *test ) {
+ int i, j, x, y;
+ drawVert_t *v1, *v2, *v3, *v4;
+ int count, ssize;
+ mesh_t mesh;
+ mesh_t *subdivided, *detailmesh, *newmesh;
+ int widthtable[LIGHTMAP_SIZE], heighttable[LIGHTMAP_SIZE];
+
+ mesh.width = dsurf->patchWidth;
+ mesh.height = dsurf->patchHeight;
+ mesh.verts = &drawVerts[ dsurf->firstVert ];
+
+ newmesh = SubdivideMesh( mesh, 8, 999 );
+ PutMeshOnCurve( *newmesh );
+ MakeMeshNormals( *newmesh );
+
+ subdivided = RemoveLinearMeshColumnsRows( newmesh );
+ FreeMesh(newmesh);
+
+ // DebugNet_RemoveAllPolys();
+ // DebugNet_DrawMesh(subdivided);
+
+ ssize = samplesize;
+ if (si->lightmapSampleSize)
+ ssize = si->lightmapSampleSize;
+
+ if ( dsurf->lightmapNum >= 0 ) {
+
+ detailmesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_SIZE, widthtable, heighttable);
+ test->detailMesh = detailmesh;
+
+ // DebugNet_RemoveAllPolys();
+ // DebugNet_DrawMesh(detailmesh);
+
+ if ( detailmesh->width != dsurf->lightmapWidth || detailmesh->height != dsurf->lightmapHeight ) {
+ Error( "Mesh lightmap miscount");
+ }
+ }
+ else {
+ test->detailMesh = NULL;
+ memset(widthtable, 0, sizeof(widthtable));
+ memset(heighttable, 0, sizeof(heighttable));
+ }
+
+ test->patch = qtrue;
+ test->trisoup = qfalse;
+ test->numFacets = ( subdivided->width - 1 ) * ( subdivided->height - 1 ) * 2;
+ test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
+ test->shader = si;
+
+ count = 0;
+ x = 0;
+ for ( i = 0 ; i < subdivided->width - 1 ; i++ ) {
+ y = 0;
+ for ( j = 0 ; j < subdivided->height - 1 ; j++ ) {
+
+ v1 = subdivided->verts + j * subdivided->width + i;
+ v2 = v1 + 1;
+ v3 = v1 + subdivided->width + 1;
+ v4 = v1 + subdivided->width;
+
+ if ( VL_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v4, v3, v2 ) ) {
+ test->facets[count].x = x;
+ test->facets[count].y = y;
+ test->facets[count].width = widthtable[i];
+ test->facets[count].height = heighttable[j];
+ count++;
+ } else {
+ if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v4, v3 )) {
+ test->facets[count].x = x;
+ test->facets[count].y = y;
+ test->facets[count].width = widthtable[i];
+ test->facets[count].height = heighttable[j];
+ count++;
+ }
+ if (VL_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v3, v2 )) {
+ test->facets[count].x = x;
+ test->facets[count].y = y;
+ test->facets[count].width = widthtable[i];
+ test->facets[count].height = heighttable[j];
+ count++;
+ }
+ }
+ y += heighttable[j];
+ }
+ x += widthtable[i];
+ }
+ test->numFacets = count;
+
+ FreeMesh(subdivided);
+}
+
+/*
+=====================
+VL_InitSurfacesForTesting
+=====================
+*/
+void VL_InitSurfacesForTesting( void ) {
+
+ int i, j, k;
+ dsurface_t *dsurf;
+ lsurfaceTest_t *test;
+ shaderInfo_t *si;
+ lFacet_t *facet;
+
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ // don't light the entity surfaces with vlight
+ if ( entitySurface[i] )
+ continue;
+ //
+ dsurf = &drawSurfaces[ i ];
+ if ( !dsurf->numIndexes && !dsurf->patchWidth ) {
+ continue;
+ }
+
+ si = ShaderInfoForShader( dshaders[ dsurf->shaderNum].shader );
+ // if the surface is translucent and does not cast an alpha shadow
+ if ( (si->contents & CONTENTS_TRANSLUCENT) && !(si->surfaceFlags & SURF_ALPHASHADOW) ) {
+ // if the surface has no lightmap
+ if ( dsurf->lightmapNum < 0 )
+ continue;
+ }
+
+ test = malloc( sizeof( *test ) );
+ memset(test, 0, sizeof( *test ));
+ test->mutex = MutexAlloc();
+ test->numvolumes = 0;
+ if (si->forceTraceLight)
+ test->always_tracelight = qtrue;
+ else if (si->forceVLight)
+ test->always_vlight = qtrue;
+ lsurfaceTest[i] = test;
+
+ if ( dsurf->surfaceType == MST_TRIANGLE_SOUP || dsurf->surfaceType == MST_PLANAR ) {
+ VL_FacetsForTriangleSurface( dsurf, si, test );
+ } else if ( dsurf->surfaceType == MST_PATCH ) {
+ VL_FacetsForPatch( dsurf, i, si, test );
+ }
+ if (numfacets >= MAX_FACETS)
+ Error("numfacets >= MAX_FACETS (%d)", MAX_FACETS);
+
+ ClearBounds( test->mins, test->maxs );
+ for (j = 0; j < test->numFacets; j++)
+ {
+ facet = &test->facets[j];
+ for ( k = 0 ; k < facet->numpoints; k++) {
+ AddPointToBounds( facet->points[k], test->mins, test->maxs );
+ }
+ }
+ VL_SphereFromBounds( test->mins, test->maxs, test->origin, &test->radius );
+ }
+ _printf("%6d facets\n", numfacets);
+ _printf("linking surfaces...\n");
+ VL_LinkSurfaces();
+}
+
+/*
+=============
+VL_ChopWinding
+=============
+*/
+int VL_ChopWinding (winding_t *in, plane_t *split, float epsilon)
+{
+ vec_t dists[128];
+ int sides[128];
+ int counts[3];
+ vec_t dot;
+ int i, j;
+ vec_t *p1, *p2;
+ vec3_t mid;
+ winding_t out;
+ winding_t *neww;
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+ // determine sides for each point
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ dot = DotProduct (in->points[i], split->normal);
+ dot -= split->dist;
+ dists[i] = dot;
+ if (dot > epsilon)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -epsilon)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+
+ if (!counts[SIDE_BACK])
+ {
+ if (!counts[SIDE_FRONT])
+ return SIDE_ON;
+ else
+ return SIDE_FRONT;
+ }
+
+ if (!counts[SIDE_FRONT])
+ {
+ return SIDE_BACK;
+ }
+
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ neww = &out;
+
+ neww->numpoints = 0;
+
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ p1 = in->points[i];
+
+ if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VL_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return SIDE_FRONT; // can't chop -- fall back to original
+ }
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy (p1, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VL_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return SIDE_FRONT; // can't chop -- fall back to original
+ }
+
+ // generate a split point
+ p2 = in->points[(i+1)%in->numpoints];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (split->normal[j] == 1)
+ mid[j] = split->dist;
+ else if (split->normal[j] == -1)
+ mid[j] = -split->dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ }
+ memcpy(in, &out, sizeof(winding_t));
+
+ return SIDE_CROSS;
+}
+
+/*
+=============
+VL_ChopWindingWithBrush
+
+ returns all winding fragments outside the brush
+=============
+*/
+int VL_ChopWindingWithBrush(winding_t *w, dbrush_t *brush, winding_t *outwindings, int maxout)
+{
+ int i, res, numout;
+ winding_t front, back;
+ plane_t plane;
+
+ numout = 0;
+ memcpy(front.points, w->points, w->numpoints * sizeof(vec3_t));
+ front.numpoints = w->numpoints;
+ for (i = 0; i < brush->numSides; i++)
+ {
+ VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal);
+ VectorInverse(plane.normal);
+ plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist;
+ res = VL_SplitWinding(&front, &back, &plane, 0.1);
+ if (res == SIDE_BACK || res == SIDE_ON)
+ {
+ memcpy(outwindings[0].points, w->points, w->numpoints * sizeof(vec3_t));
+ outwindings[0].numpoints = w->numpoints;
+ return 1; //did not intersect
+ }
+ if (res != SIDE_FRONT)
+ {
+ if (numout >= maxout)
+ {
+ _printf("WARNING: VL_ChopWindingWithBrush: more than %d windings\n", maxout);
+ return 0;
+ }
+ memcpy(outwindings[numout].points, back.points, back.numpoints * sizeof(vec3_t));
+ outwindings[numout].numpoints = back.numpoints;
+ numout++;
+ }
+ }
+ return numout;
+}
+
+/*
+=============
+VL_WindingAreaOutsideBrushes
+=============
+*/
+float VL_WindingAreaOutsideBrushes(winding_t *w, int *brushnums, int numbrushes)
+{
+ int i, j, numwindings[2], n;
+ winding_t windingsbuf[2][64];
+ dbrush_t *brush;
+ float area;
+
+ memcpy(windingsbuf[0][0].points, w->points, w->numpoints * sizeof(vec3_t));
+ windingsbuf[0][0].numpoints = w->numpoints;
+ numwindings[0] = 1;
+ for (i = 0; i < numbrushes; i++)
+ {
+ brush = &dbrushes[brushnums[i]];
+ if (!(dshaders[brush->shaderNum].contentFlags & (
+ CONTENTS_LAVA
+ | CONTENTS_SLIME
+ | CONTENTS_WATER
+ | CONTENTS_FOG
+ | CONTENTS_AREAPORTAL
+ | CONTENTS_PLAYERCLIP
+ | CONTENTS_MONSTERCLIP
+ | CONTENTS_CLUSTERPORTAL
+ | CONTENTS_DONOTENTER
+ | CONTENTS_BODY
+ | CONTENTS_CORPSE
+ | CONTENTS_TRANSLUCENT
+ | CONTENTS_TRIGGER
+ | CONTENTS_NODROP) ) &&
+ (dshaders[brush->shaderNum].contentFlags & CONTENTS_SOLID) )
+ {
+ numwindings[!(i & 1)] = 0;
+ for (j = 0; j < numwindings[i&1]; j++)
+ {
+ n = VL_ChopWindingWithBrush(&windingsbuf[i&1][j], brush,
+ &windingsbuf[!(i&1)][numwindings[!(i&1)]],
+ 64 - numwindings[!(i&1)]);
+ numwindings[!(i&1)] += n;
+ }
+ if (!numwindings[!(i&1)])
+ return 0;
+ }
+ else
+ {
+ for (j = 0; j < numwindings[i&1]; j++)
+ {
+ windingsbuf[!(i&1)][j] = windingsbuf[i&1][j];
+ }
+ numwindings[!(i&1)] = numwindings[i&1];
+ }
+ }
+ area = 0;
+ for (j = 0; j < numwindings[i&1]; j++)
+ {
+ area += WindingArea(&windingsbuf[i&1][j]);
+ }
+ return area;
+}
+
+/*
+=============
+VL_R_WindingAreaOutsideSolid
+=============
+*/
+float VL_R_WindingAreaOutsideSolid(winding_t *w, vec3_t normal, int nodenum)
+{
+ int leafnum, res;
+ float area;
+ dnode_t *node;
+ dleaf_t *leaf;
+ dplane_t *plane;
+ winding_t back;
+ plane_t split;
+
+ area = 0;
+ while(nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+
+ VectorCopy(plane->normal, split.normal);
+ split.dist = plane->dist;
+ res = VL_SplitWinding (w, &back, &split, 0.1);
+
+ if (res == SIDE_FRONT)
+ {
+ nodenum = node->children[0];
+ }
+ else if (res == SIDE_BACK)
+ {
+ nodenum = node->children[1];
+ }
+ else if (res == SIDE_ON)
+ {
+ if (DotProduct(normal, plane->normal) > 0)
+ nodenum = node->children[0];
+ else
+ nodenum = node->children[1];
+ }
+ else
+ {
+ area += VL_R_WindingAreaOutsideSolid(&back, normal, node->children[1]);
+ nodenum = node->children[0];
+ }
+ }
+ leafnum = -nodenum - 1;
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster != -1)
+ {
+ area += VL_WindingAreaOutsideBrushes(w, &dleafbrushes[leaf->firstLeafBrush], leaf->numLeafBrushes);
+ }
+ return area;
+}
+
+/*
+=============
+VL_WindingAreaOutsideSolid
+=============
+*/
+float VL_WindingAreaOutsideSolid(winding_t *w, vec3_t normal)
+{
+ return VL_R_WindingAreaOutsideSolid(w, normal, 0);
+}
+
+/*
+=============
+VL_ChopWindingWithFacet
+=============
+*/
+float VL_ChopWindingWithFacet(winding_t *w, lFacet_t *facet)
+{
+ int i;
+
+ for (i = 0; i < facet->numpoints; i++)
+ {
+ if (VL_ChopWinding(w, &facet->boundaries[i], 0) == SIDE_BACK)
+ return 0;
+ }
+ if (nostitching)
+ return WindingArea(w);
+ else
+ return VL_WindingAreaOutsideSolid(w, facet->plane.normal);
+}
+
+/*
+=============
+VL_CalcVisibleLightmapPixelArea
+
+nice brute force ;)
+=============
+*/
+void VL_CalcVisibleLightmapPixelArea(void)
+{
+ int i, j, x, y, k;
+ dsurface_t *ds;
+ lsurfaceTest_t *test;
+ mesh_t *mesh;
+ winding_t w, tmpw;
+ float area;
+
+ _printf("calculating visible lightmap pixel area...\n");
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ ds = &drawSurfaces[ i ];
+
+ if ( ds->lightmapNum < 0 )
+ continue;
+
+ for (y = 0; y < ds->lightmapHeight; y++)
+ {
+ for (x = 0; x < ds->lightmapWidth; x++)
+ {
+ if (ds->surfaceType == MST_PATCH)
+ {
+ if (y == ds->lightmapHeight-1)
+ continue;
+ if (x == ds->lightmapWidth-1)
+ continue;
+ mesh = lsurfaceTest[i]->detailMesh;
+ VectorCopy( mesh->verts[y*mesh->width+x].xyz, w.points[0]);
+ VectorCopy( mesh->verts[(y+1)*mesh->width+x].xyz, w.points[1]);
+ VectorCopy( mesh->verts[(y+1)*mesh->width+x+1].xyz, w.points[2]);
+ VectorCopy( mesh->verts[y*mesh->width+x+1].xyz, w.points[3]);
+ w.numpoints = 4;
+ if (nostitching)
+ area = WindingArea(&w);
+ else
+ area = VL_WindingAreaOutsideSolid(&w, mesh->verts[y*mesh->width+x].normal);
+ }
+ else
+ {
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[0]);
+ VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[0]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[3]);
+ VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[3]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[2]);
+ VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[2]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[1]);
+ VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[1]);
+ w.numpoints = 4;
+ area = 0;
+ for (j = 0; j < test->numFacets; j++)
+ {
+ memcpy(&tmpw, &w, sizeof(winding_t));
+ area += VL_ChopWindingWithFacet(&tmpw, &test->facets[j]);
+ }
+ }
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ lightmappixelarea[k] = area;
+ }
+ }
+ }
+}
+
+/*
+=============
+VL_FindAdjacentSurface
+=============
+*/
+int VL_FindAdjacentSurface(int surfaceNum, int facetNum, vec3_t p1, vec3_t p2, int *sNum, int *fNum, int *point)
+{
+ int i, j, k;
+ lsurfaceTest_t *test;
+ lFacet_t *facet;
+ dsurface_t *ds;
+ float *fp1, *fp2;
+ vec3_t dir;
+ plane_t *facetplane;
+ // winding_t w;
+
+ facetplane = &lsurfaceTest[surfaceNum]->facets[facetNum].plane;
+ // DebugNet_RemoveAllPolys();
+ // memcpy(w.points, lsurfaceTest[surfaceNum]->facets[facetNum].points,
+ // lsurfaceTest[surfaceNum]->facets[facetNum].numpoints * sizeof(vec3_t));
+ // w.numpoints = lsurfaceTest[surfaceNum]->facets[facetNum].numpoints;
+ // DebugNet_DrawWinding(&w, 2);
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ if (i == surfaceNum)
+ continue;
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ if (test->trisoup)// || test->patch)
+ continue;
+ ds = &drawSurfaces[i];
+ if ( ds->lightmapNum < 0 )
+ continue;
+ //if this surface is not even near the edge
+ VectorSubtract(p1, test->origin, dir);
+ if (fabs(dir[0]) > test->radius ||
+ fabs(dir[1]) > test->radius ||
+ fabs(dir[1]) > test->radius)
+ {
+ VectorSubtract(p2, test->origin, dir);
+ if (fabs(dir[0]) > test->radius ||
+ fabs(dir[1]) > test->radius ||
+ fabs(dir[1]) > test->radius)
+ {
+ continue;
+ }
+ }
+ //
+ for (j = 0; j < test->numFacets; j++)
+ {
+ facet = &test->facets[j];
+ //
+ //if (!Plane_Equal(&facet->plane, facetplane, qfalse))
+ if (DotProduct(facet->plane.normal, facetplane->normal) < 0.9)
+ {
+ if (!test->trisoup && !test->patch)
+ break;
+ continue;
+ }
+ //
+ for (k = 0; k < facet->numpoints; k++)
+ {
+ fp1 = facet->points[k];
+ if (fabs(p2[0] - fp1[0]) < 0.1 &&
+ fabs(p2[1] - fp1[1]) < 0.1 &&
+ fabs(p2[2] - fp1[2]) < 0.1)
+ {
+ fp2 = facet->points[(k+1) % facet->numpoints];
+ if (fabs(p1[0] - fp2[0]) < 0.1 &&
+ fabs(p1[1] - fp2[1]) < 0.1 &&
+ fabs(p1[2] - fp2[2]) < 0.1)
+ {
+ // memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t));
+ // w.numpoints = facet->numpoints;
+ // DebugNet_DrawWinding(&w, 1);
+ *sNum = i;
+ *fNum = j;
+ *point = k;
+ return qtrue;
+ }
+ }
+ /*
+ else if (fabs(p1[0] - fp1[0]) < 0.1 &&
+ fabs(p1[1] - fp1[1]) < 0.1 &&
+ fabs(p1[2] - fp1[2]) < 0.1)
+ {
+ fp2 = facet->points[(k+1) % facet->numpoints];
+ if (fabs(p2[0] - fp2[0]) < 0.1 &&
+ fabs(p2[1] - fp2[1]) < 0.1 &&
+ fabs(p2[2] - fp2[2]) < 0.1)
+ {
+ // memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t));
+ // w.numpoints = facet->numpoints;
+ // DebugNet_DrawWinding(&w, 1);
+ *sNum = i;
+ *fNum = j;
+ *point = k;
+ return qtrue;
+ }
+ }
+ //*/
+ }
+ }
+ }
+ return qfalse;
+}
+
+/*
+=============
+VL_SmoothenLightmapEdges
+
+this code is used to smoothen lightmaps across surface edges
+=============
+*/
+void VL_SmoothenLightmapEdges(void)
+{
+ int i, j, k, coords1[2][2];
+ float coords2[2][2];
+ int x1, y1, xinc1, yinc1, k1, k2;
+ float x2, y2, xinc2, yinc2, length;
+ int surfaceNum, facetNum, point;
+ lsurfaceTest_t *test;
+ lFacet_t *facet1, *facet2;
+ dsurface_t *ds1, *ds2;
+ float *p[2], s, t, *color1, *color2;
+ vec3_t dir, cross;
+
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ if (test->trisoup)// || test->patch)
+ continue;
+ ds1 = &drawSurfaces[i];
+ if ( ds1->lightmapNum < 0 )
+ continue;
+ for (j = 0; j < test->numFacets; j++)
+ {
+ facet1 = &test->facets[j];
+ //
+ for (k = 0; k < facet1->numpoints; k++)
+ {
+ p[0] = facet1->points[k];
+ p[1] = facet1->points[(k+1)%facet1->numpoints];
+ //
+ coords1[0][0] = facet1->lightmapCoords[k][0] * LIGHTMAP_SIZE;
+ coords1[0][1] = facet1->lightmapCoords[k][1] * LIGHTMAP_SIZE;
+ coords1[1][0] = facet1->lightmapCoords[(k+1)%facet1->numpoints][0] * LIGHTMAP_SIZE;
+ coords1[1][1] = facet1->lightmapCoords[(k+1)%facet1->numpoints][1] * LIGHTMAP_SIZE;
+ if (coords1[0][0] >= LIGHTMAP_SIZE)
+ coords1[0][0] = LIGHTMAP_SIZE-1;
+ if (coords1[0][1] >= LIGHTMAP_SIZE)
+ coords1[0][1] = LIGHTMAP_SIZE-1;
+ if (coords1[1][0] >= LIGHTMAP_SIZE)
+ coords1[1][0] = LIGHTMAP_SIZE-1;
+ if (coords1[1][1] >= LIGHTMAP_SIZE)
+ coords1[1][1] = LIGHTMAP_SIZE-1;
+ // try one row or column further because on flat faces the lightmap can
+ // extend beyond the edge
+ VectorSubtract(p[1], p[0], dir);
+ VectorNormalize(dir, dir);
+ CrossProduct(dir, facet1->plane.normal, cross);
+ //
+ if (coords1[0][0] - coords1[1][0] == 0)
+ {
+ s = DotProduct( cross, facet1->lightmapMatrix[0] );
+ coords1[0][0] += s < 0 ? 1 : -1;
+ coords1[1][0] += s < 0 ? 1 : -1;
+ if (coords1[0][0] < ds1->lightmapX || coords1[0][0] >= ds1->lightmapX + ds1->lightmapWidth)
+ {
+ coords1[0][0] += s < 0 ? -1 : 1;
+ coords1[1][0] += s < 0 ? -1 : 1;
+ }
+ length = fabs(coords1[1][1] - coords1[0][1]);
+ }
+ else if (coords1[0][1] - coords1[1][1] == 0)
+ {
+ t = DotProduct( cross, facet1->lightmapMatrix[1] );
+ coords1[0][1] += t < 0 ? 1 : -1;
+ coords1[1][1] += t < 0 ? 1 : -1;
+ if (coords1[0][1] < ds1->lightmapY || coords1[0][1] >= ds1->lightmapY + ds1->lightmapHeight)
+ {
+ coords1[0][1] += t < 0 ? -1 : 1;
+ coords1[1][1] += t < 0 ? -1 : 1;
+ }
+ length = fabs(coords1[1][0] - coords1[0][0]);
+ }
+ else
+ {
+ //the edge is not parallell to one of the lightmap axis
+ continue;
+ }
+ //
+ x1 = coords1[0][0];
+ y1 = coords1[0][1];
+ xinc1 = coords1[1][0] - coords1[0][0];
+ if (xinc1 < 0) xinc1 = -1;
+ if (xinc1 > 0) xinc1 = 1;
+ yinc1 = coords1[1][1] - coords1[0][1];
+ if (yinc1 < 0) yinc1 = -1;
+ if (yinc1 > 0) yinc1 = 1;
+ // the edge should be parallell to one of the lightmap axis
+ if (xinc1 != 0 && yinc1 != 0)
+ continue;
+ //
+ if (!VL_FindAdjacentSurface(i, j, p[0], p[1], &surfaceNum, &facetNum, &point))
+ continue;
+ //
+ ds2 = &drawSurfaces[surfaceNum];
+ facet2 = &lsurfaceTest[surfaceNum]->facets[facetNum];
+ coords2[0][0] = facet2->lightmapCoords[(point+1)%facet2->numpoints][0] * LIGHTMAP_SIZE;
+ coords2[0][1] = facet2->lightmapCoords[(point+1)%facet2->numpoints][1] * LIGHTMAP_SIZE;
+ coords2[1][0] = facet2->lightmapCoords[point][0] * LIGHTMAP_SIZE;
+ coords2[1][1] = facet2->lightmapCoords[point][1] * LIGHTMAP_SIZE;
+ if (coords2[0][0] >= LIGHTMAP_SIZE)
+ coords2[0][0] = LIGHTMAP_SIZE-1;
+ if (coords2[0][1] >= LIGHTMAP_SIZE)
+ coords2[0][1] = LIGHTMAP_SIZE-1;
+ if (coords2[1][0] >= LIGHTMAP_SIZE)
+ coords2[1][0] = LIGHTMAP_SIZE-1;
+ if (coords2[1][1] >= LIGHTMAP_SIZE)
+ coords2[1][1] = LIGHTMAP_SIZE-1;
+ //
+ x2 = coords2[0][0];
+ y2 = coords2[0][1];
+ xinc2 = coords2[1][0] - coords2[0][0];
+ if (length)
+ xinc2 = xinc2 / length;
+ yinc2 = coords2[1][1] - coords2[0][1];
+ if (length)
+ yinc2 = yinc2 / length;
+ // the edge should be parallell to one of the lightmap axis
+ if ((int) xinc2 != 0 && (int) yinc2 != 0)
+ continue;
+ //
+ while(1)
+ {
+ k1 = ( ds1->lightmapNum * LIGHTMAP_HEIGHT + y1) * LIGHTMAP_WIDTH + x1;
+ k2 = ( ds2->lightmapNum * LIGHTMAP_HEIGHT + ((int) y2)) * LIGHTMAP_WIDTH + ((int) x2);
+ color1 = lightFloats + k1*3;
+ color2 = lightFloats + k2*3;
+ if (lightmappixelarea[k1] < 0.01)
+ {
+ color1[0] = color2[0];
+ color1[1] = color2[1];
+ color1[2] = color2[2];
+ }
+ else
+ {
+ color1[0] = (float) color2[0] * 0.7 + (float) color1[0] * 0.3;
+ color1[1] = (float) color2[1] * 0.7 + (float) color1[1] * 0.3;
+ color1[2] = (float) color2[2] * 0.7 + (float) color1[2] * 0.3;
+ }
+ //
+ if (x1 == coords1[1][0] &&
+ y1 == coords1[1][1])
+ break;
+ x1 += xinc1;
+ y1 += yinc1;
+ x2 += xinc2;
+ y2 += yinc2;
+ if (x2 < ds2->lightmapX)
+ x2 = ds2->lightmapX;
+ if (x2 >= ds2->lightmapX + ds2->lightmapWidth)
+ x2 = ds2->lightmapX + ds2->lightmapWidth-1;
+ if (y2 < ds2->lightmapY)
+ y2 = ds2->lightmapY;
+ if (y2 >= ds2->lightmapY + ds2->lightmapHeight)
+ y2 = ds2->lightmapY + ds2->lightmapHeight-1;
+ }
+ }
+ }
+ }
+}
+
+/*
+=============
+VL_FixLightmapEdges
+=============
+*/
+void VL_FixLightmapEdges(void)
+{
+ int i, j, x, y, k, foundvalue, height, width, index;
+ int pos, top, bottom;
+ dsurface_t *ds;
+ lsurfaceTest_t *test;
+ float color[3];
+ float *ptr;
+ byte filled[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8];
+ float lightmap_edge_epsilon;
+
+ lightmap_edge_epsilon = 0.1 * samplesize;
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ ds = &drawSurfaces[ i ];
+
+ if ( ds->lightmapNum < 0 )
+ continue;
+ if (ds->surfaceType == MST_PATCH)
+ {
+ height = ds->lightmapHeight - 1;
+ width = ds->lightmapWidth - 1;
+ }
+ else
+ {
+ height = ds->lightmapHeight;
+ width = ds->lightmapWidth;
+ }
+ memset(filled, 0, sizeof(filled));
+// printf("\n");
+ for (x = 0; x < width; x++)
+ {
+ for (y = 0; y < height; y++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (lightmappixelarea[k] > lightmap_edge_epsilon)
+ {
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ filled[index >> 3] |= 1 << (index & 7);
+// printf("*");
+ }
+// else
+// printf("_");
+ }
+// printf("\n");
+ }
+ for (y = 0; y < height; y++)
+ {
+ pos = -2;
+ for (x = 0; x < width; x++)
+ {
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (pos == -2)
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ pos = -1;
+ }
+ else if (pos == -1)
+ {
+ if (!(filled[index >> 3] & (1 << (index & 7))))
+ pos = x - 1;
+ }
+ else
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + pos;
+ top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ for (j = 0; j < (x - pos + 1) / 2; j++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1;
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1;
+ filled[index >> 3] |= 1 << (index & 7);
+ (lightFloats + k*3)[0] = (lightFloats + top*3)[0];
+ (lightFloats + k*3)[1] = (lightFloats + top*3)[1];
+ (lightFloats + k*3)[2] = (lightFloats + top*3)[2];
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1;
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1;
+ filled[index >> 3] |= 1 << (index & 7);
+ (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0];
+ (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1];
+ (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2];
+ }
+ pos = -1;
+ }
+ }
+ }
+ }
+ for (x = 0; x < width; x++)
+ {
+ pos = -2;
+ for (y = 0; y < height; y++)
+ {
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (pos == -2)
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ pos = -1;
+ }
+ else if (pos == -1)
+ {
+ if (!(filled[index >> 3] & (1 << (index & 7))))
+ pos = y - 1;
+ }
+ else
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ for (j = 0; j < (y - pos + 1) / 2; j++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos + j + 1)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ index = (ds->lightmapY + pos + j + 1) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ filled[index >> 3] |= 1 << (index & 7);
+ (lightFloats + k*3)[0] = (lightFloats + top*3)[0];
+ (lightFloats + k*3)[1] = (lightFloats + top*3)[1];
+ (lightFloats + k*3)[2] = (lightFloats + top*3)[2];
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y - j - 1)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ index = (ds->lightmapY + y - j - 1) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ filled[index >> 3] |= 1 << (index & 7);
+ (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0];
+ (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1];
+ (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2];
+ }
+ pos = -1;
+ }
+ }
+ }
+ }
+ for (y = 0; y < height; y++)
+ {
+ foundvalue = qfalse;
+ for (x = 0; x < width; x++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (foundvalue)
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ }
+ else
+ {
+ ptr = lightFloats + k*3;
+ ptr[0] = color[0];
+ ptr[1] = color[1];
+ ptr[2] = color[2];
+ filled[index >> 3] |= 1 << (index & 7);
+ }
+ }
+ else
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ foundvalue = qtrue;
+ }
+ }
+ }
+ foundvalue = qfalse;
+ for (x = width-1; x >= 0; x--)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (foundvalue)
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ }
+ else
+ {
+ ptr = lightFloats + k*3;
+ ptr[0] = color[0];
+ ptr[1] = color[1];
+ ptr[2] = color[2];
+ filled[index >> 3] |= 1 << (index & 7);
+ }
+ }
+ else
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ foundvalue = qtrue;
+ }
+ }
+ }
+ }
+ for (x = 0; x < width; x++)
+ {
+ foundvalue = qfalse;
+ for (y = 0; y < height; y++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (foundvalue)
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ }
+ else
+ {
+ ptr = lightFloats + k*3;
+ ptr[0] = color[0];
+ ptr[1] = color[1];
+ ptr[2] = color[2];
+ filled[index >> 3] |= 1 << (index & 7);
+ }
+ }
+ else
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ foundvalue = qtrue;
+ }
+ }
+ }
+ foundvalue = qfalse;
+ for (y = height-1; y >= 0; y--)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (foundvalue)
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ }
+ else
+ {
+ ptr = lightFloats + k*3;
+ ptr[0] = color[0];
+ ptr[1] = color[1];
+ ptr[2] = color[2];
+ filled[index >> 3] |= 1 << (index & 7);
+ }
+ }
+ else
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ foundvalue = qtrue;
+ }
+ }
+ }
+ }
+ if (ds->surfaceType == MST_PATCH)
+ {
+ x = ds->lightmapWidth-1;
+ for (y = 0; y < ds->lightmapHeight; y++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ ptr = lightFloats + k*3;
+ ptr[0] = (lightFloats + (k-1)*3)[0];
+ ptr[1] = (lightFloats + (k-1)*3)[1];
+ ptr[2] = (lightFloats + (k-1)*3)[2];
+ }
+ y = ds->lightmapHeight-1;
+ for (x = 0; x < ds->lightmapWidth; x++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ ptr = lightFloats + k*3;
+ ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0];
+ ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1];
+ ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2];
+ }
+ }
+ /*
+ //colored debug edges
+ if (ds->surfaceType == MST_PATCH)
+ {
+ x = ds->lightmapWidth-1;
+ for (y = 0; y < ds->lightmapHeight; y++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ ptr = lightFloats + k*3;
+ ptr[0] = 255;
+ ptr[1] = 0;
+ ptr[2] = 0;
+ }
+ y = ds->lightmapHeight-1;
+ for (x = 0; x < ds->lightmapWidth; x++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ ptr = lightFloats + k*3;
+ ptr[0] = 0;
+ ptr[1] = 255;
+ ptr[2] = 0;
+ }
+ }
+ //*/
+ }
+ //
+ VL_SmoothenLightmapEdges();
+}
+
+/*
+=============
+VL_ShiftPatchLightmaps
+=============
+*/
+void VL_ShiftPatchLightmaps(void)
+{
+ int i, j, x, y, k;
+ drawVert_t *verts;
+ dsurface_t *ds;
+ lsurfaceTest_t *test;
+ float *ptr;
+
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ ds = &drawSurfaces[ i ];
+
+ if ( ds->lightmapNum < 0 )
+ continue;
+ if (ds->surfaceType != MST_PATCH)
+ continue;
+ for (x = ds->lightmapWidth; x > 0; x--)
+ {
+ for (y = 0; y <= ds->lightmapHeight; y++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ ptr = lightFloats + k*3;
+ ptr[0] = (lightFloats + (k-1)*3)[0];
+ ptr[1] = (lightFloats + (k-1)*3)[1];
+ ptr[2] = (lightFloats + (k-1)*3)[2];
+ }
+ }
+ for (y = ds->lightmapHeight; y > 0; y--)
+ {
+ for (x = 0; x <= ds->lightmapWidth; x++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ ptr = lightFloats + k*3;
+ ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0];
+ ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1];
+ ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2];
+ }
+ }
+ verts = &drawVerts[ ds->firstVert ];
+ for ( j = 0 ; j < ds->patchHeight * ds->patchWidth; j++ )
+ {
+ verts[j].lightmap[0] += 0.5 / LIGHTMAP_WIDTH;
+ verts[j].lightmap[1] += 0.5 / LIGHTMAP_HEIGHT;
+ }
+ ds->lightmapHeight++;
+ ds->lightmapWidth++;
+ }
+}
+
+/*
+=============
+VL_StoreLightmap
+=============
+*/
+void VL_StoreLightmap(void)
+{
+ int i, x, y, k;
+ dsurface_t *ds;
+ lsurfaceTest_t *test;
+ float *src;
+ byte *dst;
+
+ _printf("storing lightmaps...\n");
+ //fix lightmap edges before storing them
+ VL_FixLightmapEdges();
+ //
+#ifdef LIGHTMAP_PATCHSHIFT
+ VL_ShiftPatchLightmaps();
+#endif
+ //
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ ds = &drawSurfaces[ i ];
+
+ if ( ds->lightmapNum < 0 )
+ continue;
+
+ for (y = 0; y < ds->lightmapHeight; y++)
+ {
+ for (x = 0; x < ds->lightmapWidth; x++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ VectorAdd((lightFloats + k*3), lightAmbientColor, (lightFloats + k*3));
+ src = &lightFloats[k*3];
+ dst = lightBytes + k*3;
+ ColorToBytes(src, dst);
+ }
+ }
+ }
+}
+
+/*
+=============
+PointInLeafnum
+=============
+*/
+int PointInLeafnum(vec3_t point)
+{
+ int nodenum;
+ vec_t dist;
+ dnode_t *node;
+ dplane_t *plane;
+
+ nodenum = 0;
+ while (nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+ dist = DotProduct (point, plane->normal) - plane->dist;
+ if (dist > 0)
+ nodenum = node->children[0];
+ else
+ nodenum = node->children[1];
+ }
+
+ return -nodenum - 1;
+}
+
+/*
+=============
+VL_PointInLeafnum_r
+=============
+*/
+int VL_PointInLeafnum_r(vec3_t point, int nodenum)
+{
+ int leafnum;
+ vec_t dist;
+ dnode_t *node;
+ dplane_t *plane;
+
+ while (nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+ dist = DotProduct (point, plane->normal) - plane->dist;
+ if (dist > 0.1)
+ {
+ nodenum = node->children[0];
+ }
+ else if (dist < -0.1)
+ {
+ nodenum = node->children[1];
+ }
+ else
+ {
+ leafnum = VL_PointInLeafnum_r(point, node->children[0]);
+ if (dleafs[leafnum].cluster != -1)
+ return leafnum;
+ nodenum = node->children[1];
+ }
+ }
+
+ leafnum = -nodenum - 1;
+ return leafnum;
+}
+
+/*
+=============
+VL_PointInLeafnum
+=============
+*/
+int VL_PointInLeafnum(vec3_t point)
+{
+ return VL_PointInLeafnum_r(point, 0);
+}
+
+/*
+=============
+VL_LightLeafnum
+=============
+*/
+int VL_LightLeafnum(vec3_t point)
+{
+ /*
+ int leafnum;
+ dleaf_t *leaf;
+ float x, y, z;
+ vec3_t test;
+
+ leafnum = VL_PointInLeafnum(point);
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster != -1)
+ return leafnum;
+ for (z = 1; z >= -1; z -= 1)
+ {
+ for (x = 1; x >= -1; x -= 1)
+ {
+ for (y = 1; y >= -1; y -= 1)
+ {
+ VectorCopy(point, test);
+ test[0] += x;
+ test[1] += y;
+ test[2] += z;
+ leafnum = VL_PointInLeafnum(test);
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster != -1)
+ {
+ VectorCopy(test, point);
+ return leafnum;
+ }
+ }
+ }
+ }
+ return leafnum;
+ */
+ return VL_PointInLeafnum(point);
+}
+
+//#define LIGHTPOLYS
+
+#ifdef LIGHTPOLYS
+
+winding_t *lightwindings[MAX_MAP_DRAW_SURFS];
+int numlightwindings;
+
+/*
+=============
+VL_DrawLightWindings
+=============
+*/
+void VL_DrawLightWindings(void)
+{
+ int i;
+ for (i = 0; i < numlightwindings; i++)
+ {
+#ifdef DEBUGNET
+ DebugNet_DrawWinding(lightwindings[i], 1);
+#endif
+ }
+}
+
+/*
+=============
+VL_LightSurfaceWithVolume
+=============
+*/
+void VL_LightSurfaceWithVolume(int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume)
+{
+ winding_t *w;
+ lsurfaceTest_t *test;
+ lFacet_t *facet;
+ int i;
+
+ test = lsurfaceTest[ surfaceNum ];
+ facet = &test->facets[ facetNum ];
+
+ //
+ w = (winding_t *) malloc(sizeof(winding_t));
+ memcpy(w->points, facet->points, sizeof(vec3_t) * facet->numpoints);
+ w->numpoints = facet->numpoints;
+
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ //if totally on the back
+ if (VL_ChopWinding(w, &volume->planes[i], 0.01) == SIDE_BACK)
+ return;
+ }
+ lightwindings[numlightwindings] = w;
+ numlightwindings++;
+ if (numlightwindings >= MAX_MAP_DRAW_SURFS)
+ Error("MAX_LIGHTWINDINGS");
+}
+
+#else
+
+/*
+=============
+VL_LightSurfaceWithVolume
+=============
+*/
+/*
+int VL_PointInsideLightVolume(vec3_t point, lightvolume_t *volume)
+{
+ int i;
+ float d;
+
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ d = DotProduct(volume->planes[i].normal, point) - volume->planes[i].dist;
+ if (d < 0) return qfalse;
+ }
+ return qtrue;
+}
+
+void VL_LightSurfaceWithVolume( int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume )
+{
+ dsurface_t *ds;
+ int i, j, k;
+ int numPositions;
+ vec3_t base, normal, color;
+ int sampleWidth, sampleHeight;
+ vec3_t lightmapOrigin, lightmapVecs[2], dir;
+ unsigned char *ptr;
+ float add, dist, angle;
+ mesh_t * mesh;
+
+ ds = &drawSurfaces[surfaceNum];
+
+ // vertex-lit triangle model
+ if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
+ return;
+ }
+
+ if ( ds->lightmapNum < 0 ) {
+ return; // doesn't need lighting
+ }
+
+ if ( ds->surfaceType == MST_PATCH ) {
+ mesh = lsurfaceTest[surfaceNum]->detailMesh;
+ } else {
+ VectorCopy( ds->lightmapVecs[2], normal );
+
+ VectorCopy( ds->lightmapOrigin, lightmapOrigin );
+ VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] );
+ VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] );
+ }
+
+ sampleWidth = ds->lightmapWidth;
+ sampleHeight = ds->lightmapHeight;
+
+ //calculate lightmap
+ for ( i = 0 ; i < sampleWidth; i++ ) {
+ for ( j = 0 ; j < sampleHeight; j++ ) {
+
+ if ( ds->patchWidth ) {
+ numPositions = 9;
+ VectorCopy( mesh->verts[j*mesh->width+i].normal, normal );
+ // VectorNormalize( normal, normal );
+ // push off of the curve a bit
+ VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base );
+
+// MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] );
+ } else {
+ numPositions = 9;
+ for ( k = 0 ; k < 3 ; k++ ) {
+ base[k] = lightmapOrigin[k] + normal[k]
+ + ((float) i) * lightmapVecs[0][k]
+ + ((float) j) * lightmapVecs[1][k];
+ }
+ }
+ VectorAdd( base, surfaceOrigin[ surfaceNum ], base );
+
+ VectorSubtract(base, light->origin, dir);
+ dist = VectorNormalize(dir, dir);
+ if ( dist < 16 ) {
+ dist = 16;
+ }
+ angle = 1;//DotProduct( normal, dir ); //1;
+ if (angle > 1)
+ angle = 1;
+ if ( light->atten_disttype == LDAT_LINEAR ) {
+ add = angle * light->photons * lightLinearScale - dist;
+ if ( add < 0 ) {
+ add = 0;
+ }
+ } else {
+ add = light->photons / ( dist * dist ) * angle;
+ }
+ if (add <= 1.0)
+ continue;
+
+ if (VL_PointInsideLightVolume(base, volume))
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j)
+ * LIGHTMAP_WIDTH + ds->lightmapX + i;
+ ptr = lightBytes + k*3;
+ color[0] = (float) ptr[0] + add * light->color[0];
+ color[1] = (float) ptr[1] + add * light->color[1];
+ color[2] = (float) ptr[2] + add * light->color[2];
+ ColorToBytes(color, ptr);
+ }
+ }
+ }
+}
+*/
+
+/*
+=============
+VL_GetFilter
+
+FIXME: don't use a lightmap pixel origin but use the four corner points
+ to map part of a translucent surface onto the lightmap pixel
+=============
+*/
+void VL_GetFilter(vlight_t *light, lightvolume_t *volume, vec3_t lmp, vec3_t filter)
+{
+ lFacet_t *facet;
+ lsurfaceTest_t *test;
+ float d, d1, d2, frac, s, t, ns;
+ int i, j, is, it, b;
+ int x, y, u, v, numsamples, radius, color[4], largest;
+ byte *image;
+ vec3_t point, origin, total;
+
+ VectorSet(filter, 1, 1, 1);
+
+ if (noalphashading)
+ return;
+
+ if (volume->numtransFacets <= 0)
+ return;
+
+ if (light->type == LIGHT_SURFACEDIRECTED)
+ {
+ // project the light map pixel origin onto the area light source plane
+ d = DotProduct(lmp, light->normal) - DotProduct(light->normal, light->w.points[0]);
+ VectorMA(lmp, -d, light->normal, origin);
+ }
+ else
+ {
+ VectorCopy(light->origin, origin);
+ }
+ for (i = 0; i < volume->numtransFacets; i++)
+ {
+ test = lsurfaceTest[ volume->transSurfaces[i] ];
+ facet = &test->facets[ volume->transFacets[i] ];
+ // if this surface does not cast an alpha shadow
+ if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) )
+ continue;
+ // if there are no texture pixel available
+ if ( !test->shader->pixels ) {
+ continue;
+ }
+ //
+ d1 = DotProduct( origin, facet->plane.normal) - facet->plane.dist;
+ d2 = DotProduct( lmp, facet->plane.normal ) - facet->plane.dist;
+ // this should never happen because the light volume went through the facet
+ if ( ( d1 < 0 ) == ( d2 < 0 ) ) {
+ continue;
+ }
+ // calculate the crossing point
+ frac = d1 / ( d1 - d2 );
+
+ for ( j = 0 ; j < 3 ; j++ ) {
+ point[j] = origin[j] + frac * ( lmp[j] - origin[j] );
+ }
+
+ s = DotProduct( point, facet->textureMatrix[0] ) + facet->textureMatrix[0][3];
+ t = DotProduct( point, facet->textureMatrix[1] ) + facet->textureMatrix[1][3];
+ if (s < 0)
+ s = 0;
+ if (t < 0)
+ t = 0;
+
+ s = s - floor( s );
+ t = t - floor( t );
+
+ is = s * test->shader->width;
+ it = t * test->shader->height;
+
+ //if old style alpha shading
+ if (nocolorshading) {
+ image = test->shader->pixels + 4 * ( it * test->shader->width + is );
+
+ // alpha filter
+ b = image[3];
+
+ // alpha test makes this a binary option
+ b = b < 128 ? 0 : 255;
+
+ filter[0] = filter[0] * (255-b) / 255;
+ filter[1] = filter[1] * (255-b) / 255;
+ filter[2] = filter[2] * (255-b) / 255;
+ }
+ else {
+ VectorClear(total);
+ numsamples = 0;
+ radius = 2;
+ for ( u = -radius; u <= radius; u++ )
+ {
+ x = is + u;
+ if ( x < 0 || x >= test->shader->width)
+ continue;
+ for ( v = -radius; v <= radius; v++ )
+ {
+ y = it + v;
+ if ( y < 0 || y >= test->shader->height)
+ continue;
+
+ image = test->shader->pixels + 4 * ( y * test->shader->width + x );
+ color[0] = image[0];
+ color[1] = image[1];
+ color[2] = image[2];
+ largest = 0;
+ for (j = 0; j < 3; j++)
+ if (image[j] > largest)
+ largest = image[j];
+ if (largest <= 0 || image[3] == 0) {
+ color[0] = 255;
+ color[1] = 255;
+ color[2] = 255;
+ largest = 255;
+ }
+ total[0] += ((float) color[0]/largest) * (255-image[3]) / 255.0;
+ total[1] += ((float) color[1]/largest) * (255-image[3]) / 255.0;
+ total[2] += ((float) color[2]/largest) * (255-image[3]) / 255.0;
+ numsamples++;
+ }
+ }
+ ns = numsamples;
+ //
+ filter[0] *= total[0] / ns;
+ filter[1] *= total[1] / ns;
+ filter[2] *= total[2] / ns;
+ }
+ }
+}
+
+/*
+=============
+VL_LightSurfaceWithVolume
+=============
+*/
+void VL_LightSurfaceWithVolume( int surfaceNum, int facetNum, vlight_t *light, lightvolume_t *volume )
+{
+ int i;
+ dsurface_t *ds;
+ lFacet_t *facet;
+ lsurfaceTest_t *test;
+ winding_t w;
+ vec3_t base, dir, delta, normal, filter, origin;
+ int min_x[LIGHTMAP_SIZE+2], max_x[LIGHTMAP_SIZE+2];
+ int min_y, max_y, k, x, y, n;
+ float *color, distscale;
+ float d, add, angle, dist, area, insidearea, coords[MAX_POINTS_ON_WINDING+1][2];
+ mesh_t *mesh;
+ byte polygonedges[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8];
+
+
+ ds = &drawSurfaces[surfaceNum];
+
+ // vertex-lit triangle model
+ if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
+ return;
+ }
+
+ if ( ds->lightmapNum < 0 ) {
+ return; // doesn't need lighting
+ }
+
+ test = lsurfaceTest[ surfaceNum ];
+ facet = &test->facets[ facetNum ];
+
+ if (defaulttracelight && !test->always_vlight)
+ return;
+ if (test->always_tracelight)
+ return;
+
+ memcpy(w.points, facet->points, sizeof(vec3_t) * facet->numpoints);
+ w.numpoints = facet->numpoints;
+
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ //if totally on the back
+ if (VL_ChopWinding(&w, &volume->planes[i], 0.01) == SIDE_BACK)
+ return;
+ }
+
+ // only one thread at a time may write to the lightmap of this surface
+ MutexLock(test->mutex);
+
+ test->numvolumes++;
+
+ if (ds->surfaceType == MST_PATCH)
+ {
+ // FIXME: reduce size and don't mark all as edge
+ min_y = ds->lightmapY + facet->y;
+ max_y = ds->lightmapY + facet->y + facet->height - 1;
+ for (y = min_y; y <= max_y; y++)
+ {
+ min_x[y] = ds->lightmapX + facet->x;
+ max_x[y] = ds->lightmapX + facet->x + facet->width - 1;
+ for (x = min_x[y]; x <= max_x[y]; x++)
+ {
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < w.numpoints; i++)
+ {
+ float s, t;
+
+ if (i >= MAX_POINTS_ON_WINDING)
+ _printf("coords overflow\n");
+ if (ds->surfaceType != MST_PATCH)
+ {
+ VectorSubtract(w.points[i], facet->mins, delta);
+ s = DotProduct( delta, facet->lightmapMatrix[0] ) + ds->lightmapX + 0.5;
+ t = DotProduct( delta, facet->lightmapMatrix[1] ) + ds->lightmapY + 0.5;
+ if (s >= LIGHTMAP_SIZE)
+ s = LIGHTMAP_SIZE - 0.5;
+ if (s < 0)
+ s = 0;
+ if (t >= LIGHTMAP_SIZE)
+ t = LIGHTMAP_SIZE - 0.5;
+ if (t < 0)
+ t = 0;
+ coords[i][0] = s;
+ coords[i][1] = t;
+ }
+ else
+ {
+ s = DotProduct( w.points[i], facet->lightmapMatrix[0] ) + facet->lightmapMatrix[0][3];
+ t = DotProduct( w.points[i], facet->lightmapMatrix[1] ) + facet->lightmapMatrix[1][3];
+
+ s = s - floor( s );
+ t = t - floor( t );
+
+ coords[i][0] = ds->lightmapX + s * LIGHTMAP_SIZE;// + 0.5;
+ coords[i][1] = ds->lightmapY + t * LIGHTMAP_SIZE;// + 0.5;
+
+ if (coords[i][0] >= LIGHTMAP_SIZE)
+ coords[i][0] -= LIGHTMAP_SIZE;
+ if (coords[i][1] >= LIGHTMAP_SIZE)
+ coords[i][1] -= LIGHTMAP_SIZE;
+ if (coords[i][0] < ds->lightmapX)
+ coords[i][0] = ds->lightmapX;
+ if (coords[i][1] < ds->lightmapY)
+ coords[i][1] = ds->lightmapY;
+ }
+ x = coords[i][0];
+ y = coords[i][1];
+ if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
+ _printf("VL_LightSurfaceWithVolume: x outside lightmap\n");
+ if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
+ _printf("VL_LightSurfaceWithVolume: y outside lightmap\n");
+ }
+ coords[i][0] = coords[0][0];
+ coords[i][1] = coords[0][1];
+
+ //
+ min_y = LIGHTMAP_SIZE;
+ max_y = 0;
+ for (i = 0; i < LIGHTMAP_SIZE; i++)
+ {
+ min_x[i] = LIGHTMAP_SIZE;
+ max_x[i] = 0;
+ }
+ memset(polygonedges, 0, sizeof(polygonedges));
+ // scan convert the polygon onto the lightmap
+ // for each edge it marks *every* lightmap pixel the edge goes through
+ // so no brasenham and no scan conversion used for texture mapping but
+ // more something like ray casting
+ // this is necesary because we need all lightmap pixels totally or partly
+ // inside the light volume. these lightmap pixels are only lit for the part
+ // that they are inside the light volume.
+ for (i = 0; i < w.numpoints; i++)
+ {
+ float xf, yf, dx, dy, xstep, ystep, xfrac, yfrac;
+ int xinc, yinc;
+
+ xf = coords[i][0];
+ yf = coords[i][1];
+ dx = coords[i+1][0] - xf;
+ dy = coords[i+1][1] - yf;
+ //
+ x = (int) xf;
+ y = (int) yf;
+ //
+ if (y < min_y)
+ min_y = y;
+ if (y > max_y)
+ max_y = y;
+ //
+ if (fabs(dx) > fabs(dy))
+ {
+ if (dx > 0)
+ {
+ // y fraction at integer x below fractional x
+ yfrac = yf + (floor(xf) - xf) * dy / dx;
+ xinc = 1;
+ }
+ else if (dx < 0)
+ {
+ // y fraction at integer x above fractional x
+ yfrac = yf + (floor(xf) + 1 - xf) * dy / dx;
+ xinc = -1;
+ }
+ else
+ {
+ yfrac = yf;
+ xinc = 0;
+ }
+ // step in y direction per 1 unit in x direction
+ if (dx)
+ ystep = dy / fabs(dx);
+ else
+ ystep = 0;
+ while(1)
+ {
+ if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
+ _printf("VL_LightSurfaceWithVolume: x outside lightmap\n");
+ if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
+ _printf("VL_LightSurfaceWithVolume: y outside lightmap\n");
+ //
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ if (x < min_x[y])
+ min_x[y] = x;
+ if (x > max_x[y])
+ max_x[y] = x;
+ if (x == (int) coords[i+1][0])
+ break;
+ yfrac += ystep;
+ if (dy > 0)
+ {
+ if (yfrac > (float) y + 1)
+ {
+ y += 1;
+ //
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ if (x < min_x[y])
+ min_x[y] = x;
+ if (x > max_x[y])
+ max_x[y] = x;
+ }
+ }
+ else
+ {
+ if (yfrac < (float) y)
+ {
+ y -= 1;
+ //
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ if (x < min_x[y])
+ min_x[y] = x;
+ if (x > max_x[y])
+ max_x[y] = x;
+ }
+ }
+ x += xinc;
+ }
+ }
+ else
+ {
+ if (dy > 0)
+ {
+ //x fraction at integer y below fractional y
+ xfrac = xf + (floor(yf) - yf) * dx / dy;
+ yinc = 1;
+ }
+ else if (dy < 0)
+ {
+ //x fraction at integer y above fractional y
+ xfrac = xf + (floor(yf) + 1 - yf) * dx / dy;
+ yinc = -1;
+ }
+ else
+ {
+ xfrac = xf;
+ yinc = 0;
+ }
+ // step in x direction per 1 unit in y direction
+ if (dy)
+ xstep = dx / fabs(dy);
+ else
+ xstep = 0;
+ while(1)
+ {
+ if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
+ _printf("VL_LightSurfaceWithVolume: x outside lightmap\n");
+ if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
+ _printf("VL_LightSurfaceWithVolume: y outside lightmap\n");
+ //
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ if (x < min_x[y])
+ min_x[y] = x;
+ if (x > max_x[y])
+ max_x[y] = x;
+ if (y == (int) coords[i+1][1])
+ break;
+ xfrac += xstep;
+ if (dx > 0)
+ {
+ if (xfrac > (float) x + 1)
+ {
+ x += 1;
+ //
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ if (x < min_x[y])
+ min_x[y] = x;
+ if (x > max_x[y])
+ max_x[y] = x;
+ }
+ }
+ else
+ {
+ if (xfrac < (float) x)
+ {
+ x -= 1;
+ //
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ if (x < min_x[y])
+ min_x[y] = x;
+ if (x > max_x[y])
+ max_x[y] = x;
+ }
+ }
+ y += yinc;
+ }
+ }
+ }
+ }
+ // map light onto the lightmap
+ for (y = min_y; y <= max_y; y++)
+ {
+ for (x = min_x[y]; x <= max_x[y]; x++)
+ {
+ if (ds->surfaceType == MST_PATCH)
+ {
+ mesh = test->detailMesh;
+ VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, base);
+ VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].normal, normal);
+ //VectorCopy(facet->plane.normal, normal);
+ }
+ else
+ {
+ VectorMA(ds->lightmapOrigin, (float) x - ds->lightmapX, ds->lightmapVecs[0], base);
+ VectorMA(base, (float) y - ds->lightmapY, ds->lightmapVecs[1], base);
+ VectorCopy(facet->plane.normal, normal);
+ }
+ if (light->type == LIGHT_POINTSPOT)
+ {
+ float distByNormal;
+ vec3_t pointAtDist;
+ float radiusAtDist;
+ float sampleRadius;
+ vec3_t distToSample;
+ float coneScale;
+
+ VectorSubtract( light->origin, base, dir );
+
+ distByNormal = -DotProduct( dir, light->normal );
+ if ( distByNormal < 0 ) {
+ continue;
+ }
+ VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
+ radiusAtDist = light->radiusByDist * distByNormal;
+
+ VectorSubtract( base, pointAtDist, distToSample );
+ sampleRadius = VectorLength( distToSample );
+
+ if ( sampleRadius >= radiusAtDist ) {
+ continue; // outside the cone
+ }
+ if ( sampleRadius <= radiusAtDist - 32 ) {
+ coneScale = 1.0; // fully inside
+ } else {
+ coneScale = ( radiusAtDist - sampleRadius ) / 32.0;
+ }
+
+ dist = VectorNormalize( dir, dir );
+ // clamp the distance to prevent super hot spots
+ if ( dist < 16 ) {
+ dist = 16;
+ }
+ angle = DotProduct( normal, dir );
+ if (angle > 1)
+ angle = 1;
+ if (angle > 0) {
+ if ( light->atten_angletype == LAAT_QUADRATIC ) {
+ angle = 1 - angle;
+ angle *= angle;
+ angle = 1 - angle;
+ }
+ else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
+ angle = 1 - angle;
+ angle *= angle * angle;
+ angle = 1 - angle;
+ }
+ }
+ if (light->atten_anglescale > 0) {
+ angle /= light->atten_anglescale;
+ if (angle > 1)
+ angle = 1;
+ }
+ if (light->atten_distscale > 0) {
+ distscale = light->atten_distscale;
+ }
+ else {
+ distscale = 1;
+ }
+ //
+ if ( light->atten_disttype == LDAT_NOSCALE ) {
+ add = angle * coneScale;
+ }
+ else if ( light->atten_disttype == LDAT_LINEAR ) {
+ add = angle * light->photons * lightLinearScale * coneScale - dist * distscale;
+ if ( add < 0 ) {
+ add = 0;
+ }
+ }
+ else {
+ add = light->photons / ( dist * dist * distscale) * angle * coneScale;
+ }
+ if (add <= 1.0)
+ continue;
+ }
+ else if (light->type == LIGHT_POINTFAKESURFACE)
+ {
+ // calculate the contribution
+ add = PointToPolygonFormFactor( base, normal, &light->w );
+ if ( add <= 0 ) {
+ if ( light->twosided ) {
+ add = -add;
+ } else {
+ continue;
+ }
+ }
+ }
+ else if (light->type == LIGHT_SURFACEDIRECTED)
+ {
+ //VectorCopy(light->normal, dir);
+ //VectorInverse(dir);
+ // project the light map pixel origin onto the area light source plane
+ d = DotProduct(base, light->normal) - DotProduct(light->normal, light->w.points[0]);
+ VectorMA(base, -d, light->normal, origin);
+ VectorSubtract(origin, base, dir);
+ dist = VectorNormalize(dir, dir);
+ if ( dist < 16 ) {
+ dist = 16;
+ }
+ //
+ angle = DotProduct( normal, dir );
+ if (angle > 1)
+ angle = 1;
+ if (angle > 0) {
+ if ( light->atten_angletype == LAAT_QUADRATIC ) {
+ angle = 1 - angle;
+ angle *= angle;
+ angle = 1 - angle;
+ }
+ else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
+ angle = 1 - angle;
+ angle *= angle * angle;
+ angle = 1 - angle;
+ }
+ }
+ if (light->atten_anglescale > 0) {
+ angle /= light->atten_anglescale;
+ if (angle > 1)
+ angle = 1;
+ }
+ if (light->atten_distscale > 0) {
+ distscale = light->atten_distscale;
+ }
+ else {
+ distscale = 1;
+ }
+ if ( light->atten_disttype == LDAT_NOSCALE ) {
+ add = angle;
+ }
+ else if ( light->atten_disttype == LDAT_LINEAR ) {
+ add = angle * light->photons * lightLinearScale - dist * distscale;
+ if ( add < 0 ) {
+ add = 0;
+ }
+ } else { //default quadratic
+ add = light->photons / ( dist * dist * distscale) * angle;
+ }
+ if (add <= 0)
+ continue;
+ }
+ else //normal radial point light
+ {
+ VectorSubtract(light->origin, base, dir);
+ dist = VectorNormalize(dir, dir);
+ if ( dist < 16 ) {
+ dist = 16;
+ }
+ angle = DotProduct( normal, dir );
+ if (angle > 1)
+ angle = 1;
+ if (angle > 0) {
+ if ( light->atten_angletype == LAAT_QUADRATIC ) {
+ angle = 1 - angle;
+ angle *= angle;
+ angle = 1 - angle;
+ }
+ else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
+ angle = 1 - angle;
+ angle *= angle * angle;
+ angle = 1 - angle;
+ }
+ }
+ if (light->atten_anglescale > 0) {
+ angle /= light->atten_anglescale;
+ if (angle > 1)
+ angle = 1;
+ }
+ if (light->atten_distscale > 0) {
+ distscale = light->atten_distscale;
+ }
+ else {
+ distscale = 1;
+ }
+ if ( light->atten_disttype == LDAT_NOSCALE ) {
+ add = angle;
+ }
+ else if ( light->atten_disttype == LDAT_LINEAR ) {
+ add = angle * light->photons * lightLinearScale - dist * distscale;
+ if ( add < 0 ) {
+ add = 0;
+ }
+ } else {
+ add = light->photons / ( dist * dist * distscale) * angle;
+ }
+ if (add <= 1.0)
+ continue;
+ }
+ //
+ k = (ds->lightmapNum * LIGHTMAP_HEIGHT + y) * LIGHTMAP_WIDTH + x;
+ //if on one of the edges
+ n = y * LIGHTMAP_SIZE + x;
+ if ((polygonedges[n >> 3] & (1 << (n & 7)) ))
+ {
+ // multiply 'add' by the relative area being lit of the total visible lightmap pixel area
+ //
+ // first create a winding for the lightmap pixel
+ if (ds->surfaceType == MST_PATCH)
+ {
+ mesh = test->detailMesh;
+ if (y-ds->lightmapY >= mesh->height-1)
+ _printf("y outside mesh\n");
+ if (x-ds->lightmapX >= mesh->width-1)
+ _printf("x outside mesh\n");
+ VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]);
+ VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]);
+ VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]);
+ VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]);
+ w.numpoints = 4;
+ }
+ else
+ {
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]);
+ VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]);
+ VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]);
+ VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]);
+ VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]);
+ w.numpoints = 4;
+ }
+ //
+ // take the visible area of the lightmap pixel into account
+ //
+ //area = WindingArea(&w);
+ area = lightmappixelarea[k];
+ if (area <= 0)
+ continue;
+ // chop the lightmap pixel winding with the light volume
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ //if totally on the back
+ if (VL_ChopWinding(&w, &volume->planes[i], 0) == SIDE_BACK)
+ break;
+ }
+ // if the lightmap pixel is partly inside the light volume
+ if (i >= volume->numplanes)
+ {
+ insidearea = WindingArea(&w);
+ if (insidearea <= 0)
+ i = 0;
+ add = add * insidearea / area;
+ }
+ else
+ {
+ //DebugNet_DrawWinding(&w, 2);
+ continue; // this shouldn't happen
+ }
+ }
+ // get the light filter from all the translucent surfaces the light volume went through
+ VL_GetFilter(light, volume, base, filter);
+ //
+ color = &lightFloats[k*3];
+ color[0] += add * light->color[0] * filter[0];
+ color[1] += add * light->color[1] * filter[1];
+ color[2] += add * light->color[2] * filter[2];
+ }
+ }
+
+ MutexUnlock(test->mutex);
+}
+
+#endif
+
+/*
+=============
+VL_SplitLightVolume
+=============
+*/
+int VL_SplitLightVolume(lightvolume_t *volume, lightvolume_t *back, plane_t *split, float epsilon)
+{
+ lightvolume_t f, b;
+ vec_t dists[128];
+ int sides[128];
+ int counts[3];
+ vec_t dot;
+ int i, j;
+ vec_t *p1, *p2;
+ vec3_t mid;
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+ // determine sides for each point
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ dot = DotProduct (volume->points[i], split->normal);
+ dot -= split->dist;
+ dists[i] = dot;
+ if (dot > epsilon)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -epsilon)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+
+ if (!counts[1])
+ return 0; // completely on front side
+
+ if (!counts[0])
+ return 1; // completely on back side
+
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ f.numplanes = 0;
+ b.numplanes = 0;
+
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ p1 = volume->points[i];
+
+ if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return 0; // can't chop -- fall back to original
+ }
+ if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return 0; // can't chop -- fall back to original
+ }
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy(p1, f.points[f.numplanes]);
+ VectorCopy(p1, b.points[b.numplanes]);
+ if (sides[i+1] == SIDE_BACK)
+ {
+ f.planes[f.numplanes] = *split;
+ b.planes[b.numplanes] = volume->planes[i];
+ }
+ else if (sides[i+1] == SIDE_FRONT)
+ {
+ f.planes[f.numplanes] = volume->planes[i];
+ b.planes[b.numplanes] = *split;
+ VectorInverse(b.planes[b.numplanes].normal);
+ b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
+ }
+ else //this shouldn't happen
+ {
+ f.planes[f.numplanes] = *split;
+ b.planes[b.numplanes] = *split;
+ VectorInverse(b.planes[b.numplanes].normal);
+ b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
+ }
+ f.numplanes++;
+ b.numplanes++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, f.points[f.numplanes]);
+ f.planes[f.numplanes] = volume->planes[i];
+ f.numplanes++;
+ }
+ if (sides[i] == SIDE_BACK)
+ {
+ VectorCopy (p1, b.points[b.numplanes]);
+ b.planes[b.numplanes] = volume->planes[i];
+ b.numplanes++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return 0; // can't chop -- fall back to original
+ }
+ if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VL_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return 0; // can't chop -- fall back to original
+ }
+
+ // generate a split point
+ p2 = volume->points[(i+1)%volume->numplanes];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (split->normal[j] == 1)
+ mid[j] = split->dist;
+ else if (split->normal[j] == -1)
+ mid[j] = -split->dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, f.points[f.numplanes]);
+ VectorCopy(mid, b.points[b.numplanes]);
+ if (sides[i+1] == SIDE_BACK)
+ {
+ f.planes[f.numplanes] = *split;
+ b.planes[b.numplanes] = volume->planes[i];
+ }
+ else
+ {
+ f.planes[f.numplanes] = volume->planes[i];
+ b.planes[b.numplanes] = *split;
+ VectorInverse(b.planes[b.numplanes].normal);
+ b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
+ }
+ f.numplanes++;
+ b.numplanes++;
+ }
+ memcpy(volume->points, f.points, sizeof(vec3_t) * f.numplanes);
+ memcpy(volume->planes, f.planes, sizeof(plane_t) * f.numplanes);
+ volume->numplanes = f.numplanes;
+ memcpy(back->points, b.points, sizeof(vec3_t) * b.numplanes);
+ memcpy(back->planes, b.planes, sizeof(plane_t) * b.numplanes);
+ back->numplanes = b.numplanes;
+
+ return 2;
+}
+
+/*
+=============
+VL_PlaneForEdgeToWinding
+=============
+*/
+void VL_PlaneForEdgeToWinding(vec3_t p1, vec3_t p2, winding_t *w, int windingonfront, plane_t *plane)
+{
+ int i, j;
+ float length, d;
+ vec3_t v1, v2;
+
+ VectorSubtract(p2, p1, v1);
+ for (i = 0; i < w->numpoints; i++)
+ {
+ VectorSubtract (w->points[i], p1, v2);
+
+ plane->normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
+ plane->normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
+ plane->normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
+
+ // if points don't make a valid plane, skip it
+ length = plane->normal[0] * plane->normal[0]
+ + plane->normal[1] * plane->normal[1]
+ + plane->normal[2] * plane->normal[2];
+
+ if (length < ON_EPSILON)
+ continue;
+
+ length = 1/sqrt(length);
+
+ plane->normal[0] *= length;
+ plane->normal[1] *= length;
+ plane->normal[2] *= length;
+
+ plane->dist = DotProduct (w->points[i], plane->normal);
+ //
+ for (j = 0; j < w->numpoints; j++)
+ {
+ if (j == i)
+ continue;
+ d = DotProduct(w->points[j], plane->normal) - plane->dist;
+ if (windingonfront)
+ {
+ if (d < -ON_EPSILON)
+ break;
+ }
+ else
+ {
+ if (d > ON_EPSILON)
+ break;
+ }
+ }
+ if (j >= w->numpoints)
+ return;
+ }
+}
+
+/*
+=============
+VL_R_CastLightAtSurface
+=============
+*/
+void VL_R_FloodLight(vlight_t *light, lightvolume_t *volume, int cluster, int firstportal);
+
+void VL_R_CastLightAtSurface(vlight_t *light, lightvolume_t *volume)
+{
+ lsurfaceTest_t *test;
+ int i, n;
+
+ // light the surface with this volume
+ VL_LightSurfaceWithVolume(volume->surfaceNum, volume->facetNum, light, volume);
+ //
+ test = lsurfaceTest[ volume->surfaceNum ];
+ // if this is not a translucent surface
+ if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) && !(test->shader->contents & CONTENTS_TRANSLUCENT))
+ return;
+ //
+ if (volume->numtransFacets >= MAX_TRANSLUCENTFACETS)
+ Error("a light valume went through more than %d translucent facets", MAX_TRANSLUCENTFACETS);
+ //add this translucent surface to the list
+ volume->transSurfaces[volume->numtransFacets] = volume->surfaceNum;
+ volume->transFacets[volume->numtransFacets] = volume->facetNum;
+ volume->numtransFacets++;
+ //clear the tested facets except the translucent ones
+ memset(volume->facetTested, 0, sizeof(volume->facetTested));
+ for (i = 0; i < volume->numtransFacets; i++)
+ {
+ test = lsurfaceTest[ volume->transSurfaces[i] ];
+ n = test->facets[volume->transFacets[i]].num;
+ volume->facetTested[n >> 3] |= 1 << (n & 7);
+ }
+ memset(volume->clusterTested, 0, sizeof(volume->clusterTested));
+ volume->endplane = volume->farplane;
+ volume->surfaceNum = -1;
+ volume->facetNum = 0;
+ VL_R_FloodLight(light, volume, volume->cluster, 0);
+ if (volume->surfaceNum >= 0)
+ {
+ VL_R_CastLightAtSurface(light, volume);
+ }
+}
+
+/*
+=============
+VL_R_SplitLightVolume
+=============
+*/
+int numvolumes = 0;
+
+int VL_R_SplitLightVolume(vlight_t *light, lightvolume_t *volume, plane_t *split, int cluster, int firstportal)
+{
+ lightvolume_t back;
+ int res;
+
+ //
+ res = VL_SplitLightVolume(volume, &back, split, 0.1);
+ // if the volume was split
+ if (res == 2)
+ {
+ memcpy(back.clusterTested, volume->clusterTested, sizeof(back.clusterTested));
+ memcpy(back.facetTested, volume->facetTested, sizeof(back.facetTested));
+ back.num = numvolumes++;
+ back.endplane = volume->endplane;
+ back.surfaceNum = volume->surfaceNum;
+ back.facetNum = volume->facetNum;
+ back.type = volume->type;
+ back.cluster = volume->cluster;
+ back.farplane = volume->farplane;
+ if (volume->numtransFacets > 0)
+ {
+ memcpy(back.transFacets, volume->transFacets, sizeof(back.transFacets));
+ memcpy(back.transSurfaces, volume->transSurfaces, sizeof(back.transSurfaces));
+ }
+ back.numtransFacets = volume->numtransFacets;
+ //
+ // flood the volume at the back of the split plane
+ VL_R_FloodLight(light, &back, cluster, firstportal);
+ // if the back volume hit a surface
+ if (back.surfaceNum >= 0)
+ {
+ VL_R_CastLightAtSurface(light, &back);
+ }
+ }
+ return res;
+}
+
+/*
+=============
+VL_R_FloodLight
+=============
+*/
+void VL_R_FloodLight(vlight_t *light, lightvolume_t *volume, int cluster, int firstportal)
+{
+ int i, j, k, res, surfaceNum, backfaceculled, testculled;
+ float d;
+ winding_t winding, tmpwinding;
+ lleaf_t *leaf;
+ lportal_t *p;
+ lsurfaceTest_t *test;
+ lFacet_t *facet;
+ vec3_t dir1, dir2;
+ plane_t plane;
+
+ // DebugNet_RemoveAllPolys();
+ // VL_DrawLightVolume(light, volume);
+
+ // if the first portal is not zero then we've checked all occluders in this leaf already
+ if (firstportal == 0)
+ {
+ // check all potential occluders in this leaf
+ for (i = 0; i < leafs[cluster].numSurfaces; i++)
+ {
+ surfaceNum = clustersurfaces[leafs[cluster].firstSurface + i];
+ //
+ test = lsurfaceTest[ surfaceNum ];
+ if ( !test )
+ continue;
+ //
+ testculled = qfalse;
+ // use surface as an occluder
+ for (j = 0; j < test->numFacets; j++)
+ {
+ // use each facet as an occluder
+ facet = &test->facets[j];
+ //
+ // memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints);
+ // winding.numpoints = facet->numpoints;
+ // DebugNet_DrawWinding(&winding, 5);
+ //
+ // if the facet was tested already
+ if ( volume->facetTested[facet->num >> 3] & (1 << (facet->num & 7)) )
+ continue;
+ volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
+ // backface culling for planar surfaces
+ backfaceculled = qfalse;
+ if (!test->patch && !test->trisoup)
+ {
+ if (volume->type == VOLUME_NORMAL)
+ {
+ // facet backface culling
+ d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist;
+ if (d < 0)
+ {
+ // NOTE: this doesn't work too great because of sometimes very bad tesselation
+ // of surfaces that are supposed to be flat
+ // FIXME: to work around this problem we should make sure that all facets
+ // created from planar surfaces use the lightmapVecs normal vector
+ /*
+ if ( !test->shader->twoSided )
+ {
+ // skip all other facets of this surface as well because they are in the same plane
+ for (k = 0; k < test->numFacets; k++)
+ {
+ facet = &test->facets[k];
+ volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
+ }
+ }*/
+ backfaceculled = qtrue;
+ }
+ }
+ else
+ {
+ // FIXME: if all light source winding points are at the back of the facet
+ // plane then backfaceculled = qtrue
+ }
+ }
+ else // backface culling per facet for patches and triangle soups
+ {
+ if (volume->type == VOLUME_NORMAL)
+ {
+ // facet backface culling
+ d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist;
+ if (d < 0)
+ backfaceculled = qtrue;
+ }
+ else
+ {
+ // FIXME: if all light source winding points are at the back of the facet
+ // plane then backfaceculled = qtrue
+ }
+ }
+ /* chopping does this already
+ // check if this facet is totally or partly in front of the volume end plane
+ for (k = 0; k < facet->numpoints; k++)
+ {
+ d = DotProduct(volume->endplane.normal, facet->points[k]) - volume->endplane.dist;
+ if (d > ON_EPSILON)
+ break;
+ }
+ // if this facet is outside the light volume
+ if (k >= facet->numpoints)
+ continue;
+ */
+ //
+ if (backfaceculled)
+ {
+ // if the facet is not two sided
+ if ( !nobackfaceculling && !test->shader->twoSided )
+ continue;
+ // flip the winding
+ for (k = 0; k < facet->numpoints; k++)
+ VectorCopy(facet->points[k], winding.points[facet->numpoints - k - 1]);
+ winding.numpoints = facet->numpoints;
+ }
+ else
+ {
+ memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints);
+ winding.numpoints = facet->numpoints;
+ }
+ //
+ if (!testculled)
+ {
+ testculled = qtrue;
+ // fast check if the surface sphere is totally behind the volume end plane
+ d = DotProduct(volume->endplane.normal, test->origin) - volume->endplane.dist;
+ if (d < -test->radius)
+ {
+ for (k = 0; k < test->numFacets; k++)
+ {
+ facet = &test->facets[k];
+ volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
+ }
+ break;
+ }
+ for (k = 0; k < volume->numplanes; k++)
+ {
+ d = DotProduct(volume->planes[k].normal, test->origin) - volume->planes[k].dist;
+ if (d < - test->radius)
+ {
+ for (k = 0; k < test->numFacets; k++)
+ {
+ facet = &test->facets[k];
+ volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
+ }
+ break;
+ }
+ }
+ if (k < volume->numplanes)
+ break;
+ }
+ //NOTE: we have to chop the facet winding with the volume end plane because
+ // the faces in Q3 are not stitched together nicely
+ res = VL_ChopWinding(&winding, &volume->endplane, 0.01);
+ // if the facet is on or at the back of the volume end plane
+ if (res == SIDE_BACK || res == SIDE_ON)
+ continue;
+ // check if the facet winding is totally or partly inside the light volume
+ memcpy(&tmpwinding, &winding, sizeof(winding_t));
+ for (k = 0; k < volume->numplanes; k++)
+ {
+ res = VL_ChopWinding(&tmpwinding, &volume->planes[k], 0.01);
+ if (res == SIDE_BACK || res == SIDE_ON)
+ break;
+ }
+ // if no part of the light volume is occluded by this facet
+ if (k < volume->numplanes)
+ continue;
+ //
+ for (k = 0; k < winding.numpoints; k++)
+ {
+ if (volume->type == VOLUME_DIRECTED)
+ {
+ VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1);
+ CrossProduct(light->normal, dir1, plane.normal);
+ VectorNormalize(plane.normal, plane.normal);
+ plane.dist = DotProduct(plane.normal, winding.points[k]);
+ }
+ else
+ {
+ VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1);
+ VectorSubtract(light->origin, winding.points[k], dir2);
+ CrossProduct(dir1, dir2, plane.normal);
+ VectorNormalize(plane.normal, plane.normal);
+ plane.dist = DotProduct(plane.normal, winding.points[k]);
+ }
+ res = VL_R_SplitLightVolume(light, volume, &plane, cluster, 0);
+ if (res == 1)
+ break; //the facet wasn't really inside the volume
+ }
+ if (k >= winding.numpoints)
+ {
+ volume->endplane = facet->plane;
+ if (backfaceculled)
+ {
+ VectorInverse(volume->endplane.normal);
+ volume->endplane.dist = -volume->endplane.dist;
+ }
+ volume->surfaceNum = surfaceNum;
+ volume->facetNum = j;
+ }
+ }
+ }
+ }
+ // we've tested all occluders in this cluster
+ volume->clusterTested[cluster >> 3] |= 1 << (cluster & 7);
+ // flood light through the portals of the current leaf
+ leaf = &leafs[cluster];
+ for (i = firstportal; i < leaf->numportals; i++)
+ {
+ p = leaf->portals[i];
+ //
+ // memcpy(&winding, p->winding, sizeof(winding_t));
+ // DebugNet_DrawWinding(&winding, 5);
+ // if already flooded into the cluster this portal leads to
+ if ( volume->clusterTested[p->leaf >> 3] & (1 << (p->leaf & 7)) )
+ continue;
+ //
+ if (volume->type == VOLUME_NORMAL)
+ {
+ // portal backface culling
+ d = DotProduct(light->origin, p->plane.normal) - p->plane.dist;
+ if (d > 0) // portal plane normal points into neighbour cluster
+ continue;
+ }
+ else
+ {
+ // FIXME: if all light source winding points are at the back of this portal
+ // plane then there's no need to flood through
+ }
+ // check if this portal is totally or partly in front of the volume end plane
+ // fast check with portal sphere
+ d = DotProduct(volume->endplane.normal, p->origin) - volume->endplane.dist;
+ if (d < -p->radius)
+ continue;
+ for (j = 0; j < p->winding->numpoints; j++)
+ {
+ d = DotProduct(volume->endplane.normal, p->winding->points[j]) - volume->endplane.dist;
+ if (d > -0.01)
+ break;
+ }
+ // if this portal is totally behind the light volume end plane
+ if (j >= p->winding->numpoints)
+ continue;
+ //distance from point light to portal
+ d = DotProduct(p->plane.normal, light->origin) - p->plane.dist;
+ // only check if a point light is Not *on* the portal
+ if (volume->type != VOLUME_NORMAL || fabs(d) > 0.1)
+ {
+ // check if the portal is partly or totally inside the light volume
+ memcpy(&winding, p->winding, sizeof(winding_t));
+ for (j = 0; j < volume->numplanes; j++)
+ {
+ res = VL_ChopWinding(&winding, &volume->planes[j], 0.01);
+ if (res == SIDE_BACK || res == SIDE_ON)
+ break;
+ }
+ // if the light volume does not go through this portal at all
+ if (j < volume->numplanes)
+ continue;
+ }
+ // chop the light volume with the portal
+ for (k = 0; k < p->winding->numpoints; k++)
+ {
+ if (volume->type == VOLUME_DIRECTED)
+ {
+ VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1);
+ CrossProduct(light->normal, dir1, plane.normal);
+ VectorNormalize(plane.normal, plane.normal);
+ plane.dist = DotProduct(plane.normal, p->winding->points[k]);
+ }
+ else
+ {
+ VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1);
+ VectorSubtract(light->origin, p->winding->points[k], dir2);
+ CrossProduct(dir1, dir2, plane.normal);
+ VectorNormalize(plane.normal, plane.normal);
+ plane.dist = DotProduct(plane.normal, p->winding->points[k]);
+ }
+ res = VL_R_SplitLightVolume(light, volume, &plane, cluster, i+1);
+ if (res == 1)
+ break; //volume didn't really go through the portal
+ }
+ // if the light volume went through the portal
+ if (k >= p->winding->numpoints)
+ {
+ // flood through the portal
+ VL_R_FloodLight(light, volume, p->leaf, 0);
+ }
+ }
+}
+
+/*
+=============
+VL_R_FloodAreaSpotLight
+=============
+*/
+void VL_FloodAreaSpotLight(vlight_t *light, winding_t *w, int leafnum)
+{
+}
+
+/*
+=============
+VL_R_SubdivideAreaSpotLight
+=============
+*/
+void VL_R_SubdivideAreaSpotLight(vlight_t *light, int nodenum, winding_t *w)
+{
+ int leafnum, res;
+ dnode_t *node;
+ dplane_t *plane;
+ winding_t back;
+ plane_t split;
+
+ while(nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+
+ VectorCopy(plane->normal, split.normal);
+ split.dist = plane->dist;
+ res = VL_SplitWinding (w, &back, &split, 0.1);
+
+ if (res == SIDE_FRONT)
+ {
+ nodenum = node->children[0];
+ }
+ else if (res == SIDE_BACK)
+ {
+ nodenum = node->children[1];
+ }
+ else if (res == SIDE_ON)
+ {
+ memcpy(&back, w, sizeof(winding_t));
+ VL_R_SubdivideAreaSpotLight(light, node->children[1], &back);
+ nodenum = node->children[0];
+ }
+ else
+ {
+ VL_R_SubdivideAreaSpotLight(light, node->children[1], &back);
+ nodenum = node->children[0];
+ }
+ }
+ leafnum = -nodenum - 1;
+ if (dleafs[leafnum].cluster != -1)
+ {
+ VL_FloodAreaSpotLight(light, w, leafnum);
+ }
+}
+
+/*
+=============
+VL_R_FloodRadialAreaLight
+=============
+*/
+void VL_FloodRadialAreaLight(vlight_t *light, winding_t *w, int leafnum)
+{
+}
+
+/*
+=============
+VL_R_SubdivideRadialAreaLight
+=============
+*/
+void VL_R_SubdivideRadialAreaLight(vlight_t *light, int nodenum, winding_t *w)
+{
+ int leafnum, res;
+ dnode_t *node;
+ dplane_t *plane;
+ winding_t back;
+ plane_t split;
+
+ while(nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+
+ VectorCopy(plane->normal, split.normal);
+ split.dist = plane->dist;
+ res = VL_SplitWinding (w, &back, &split, 0.1);
+
+ if (res == SIDE_FRONT)
+ {
+ nodenum = node->children[0];
+ }
+ else if (res == SIDE_BACK)
+ {
+ nodenum = node->children[1];
+ }
+ else if (res == SIDE_ON)
+ {
+ memcpy(&back, w, sizeof(winding_t));
+ VL_R_SubdivideRadialAreaLight(light, node->children[1], &back);
+ nodenum = node->children[0];
+ }
+ else
+ {
+ VL_R_SubdivideRadialAreaLight(light, node->children[1], &back);
+ nodenum = node->children[0];
+ }
+ }
+ leafnum = -nodenum - 1;
+ if (dleafs[leafnum].cluster != -1)
+ {
+ VL_FloodRadialAreaLight(light, w, leafnum);
+ }
+}
+
+/*
+=============
+VL_R_FloodDirectedLight
+=============
+*/
+void VL_FloodDirectedLight(vlight_t *light, winding_t *w, int leafnum)
+{
+ int i;
+ float dist;
+ lightvolume_t volume;
+ vec3_t dir;
+
+ if (light->atten_disttype == LDAT_NOSCALE)
+ {
+ // light travels without decrease in intensity over distance
+ dist = MAX_WORLD_COORD;
+ }
+ else
+ {
+ if ( light->atten_disttype == LDAT_LINEAR )
+ dist = light->photons * lightLinearScale;
+ else
+ dist = sqrt(light->photons);
+ }
+
+ memset(&volume, 0, sizeof(lightvolume_t));
+ for (i = 0; i < w->numpoints; i++)
+ {
+ VectorMA(w->points[i], dist, light->normal, volume.points[i]);
+ VectorSubtract(w->points[(i+1)%w->numpoints], w->points[i], dir);
+ CrossProduct(light->normal, dir, volume.planes[i].normal);
+ VectorNormalize(volume.planes[i].normal, volume.planes[i].normal);
+ volume.planes[i].dist = DotProduct(volume.planes[i].normal, w->points[i]);
+ }
+ volume.numplanes = w->numpoints;
+ VectorCopy(light->normal, volume.endplane.normal);
+ VectorInverse(volume.endplane.normal);
+ volume.endplane.dist = DotProduct(volume.endplane.normal, volume.points[0]);
+ volume.farplane = volume.endplane;
+ volume.surfaceNum = -1;
+ volume.type = VOLUME_DIRECTED;
+ volume.cluster = dleafs[leafnum].cluster;
+ VL_R_FloodLight(light, &volume, volume.cluster, 0);
+ if (volume.surfaceNum >= 0)
+ {
+ VL_R_CastLightAtSurface(light, &volume);
+ }
+}
+
+/*
+=============
+VL_R_SubdivideDirectedAreaLight
+=============
+*/
+void VL_R_SubdivideDirectedAreaLight(vlight_t *light, int nodenum, winding_t *w)
+{
+ int leafnum, res;
+ dnode_t *node;
+ dplane_t *plane;
+ winding_t back;
+ plane_t split;
+
+ while(nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+
+ VectorCopy(plane->normal, split.normal);
+ split.dist = plane->dist;
+ res = VL_SplitWinding (w, &back, &split, 0.1);
+
+ if (res == SIDE_FRONT)
+ {
+ nodenum = node->children[0];
+ }
+ else if (res == SIDE_BACK)
+ {
+ nodenum = node->children[1];
+ }
+ else if (res == SIDE_ON)
+ {
+ memcpy(&back, w, sizeof(winding_t));
+ VL_R_SubdivideDirectedAreaLight(light, node->children[1], &back);
+ nodenum = node->children[0];
+ }
+ else
+ {
+ VL_R_SubdivideDirectedAreaLight(light, node->children[1], &back);
+ nodenum = node->children[0];
+ }
+ }
+ leafnum = -nodenum - 1;
+ if (dleafs[leafnum].cluster != -1)
+ {
+ VL_FloodDirectedLight(light, w, leafnum);
+ }
+}
+
+/*
+=============
+VL_FloodLight
+=============
+*/
+void VL_FloodLight(vlight_t *light)
+{
+ lightvolume_t volume;
+ dleaf_t *leaf;
+ int leafnum, i, j, k, dir[2][4] = {{1, 1, -1, -1}, {1, -1, -1, 1}};
+ float a, step, dist, radius, windingdist;
+ vec3_t vec, r, p, temp;
+ winding_t winding;
+
+ switch(light->type)
+ {
+ case LIGHT_POINTRADIAL:
+ {
+ // source is a point
+ // light radiates in all directions
+ // creates sharp shadows
+ //
+ // create 6 volumes shining in the axis directions
+ // what about: 4 tetrahedrons instead?
+ //
+ if ( light->atten_disttype == LDAT_LINEAR )
+ dist = light->photons * lightLinearScale;
+ else
+ dist = sqrt(light->photons);
+ //always put the winding at a large distance to avoid epsilon issues
+ windingdist = MAX_WORLD_COORD;
+ if (dist > windingdist)
+ windingdist = dist;
+ //
+ leafnum = VL_LightLeafnum(light->origin);
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster == -1)
+ {
+ light->insolid = qtrue;
+ break;
+ }
+ // for each axis
+ for (i = 0; i < 3; i++)
+ {
+ // for both directions on the axis
+ for (j = -1; j <= 1; j += 2)
+ {
+ memset(&volume, 0, sizeof(lightvolume_t));
+ volume.numplanes = 0;
+ for (k = 0; k < 4; k ++)
+ {
+ volume.points[volume.numplanes][i] = light->origin[i] + j * windingdist;
+ volume.points[volume.numplanes][(i+1)%3] = light->origin[(i+1)%3] + dir[0][k] * windingdist;
+ volume.points[volume.numplanes][(i+2)%3] = light->origin[(i+2)%3] + dir[1][k] * windingdist;
+ volume.numplanes++;
+ }
+ if (j >= 0)
+ {
+ VectorCopy(volume.points[0], temp);
+ VectorCopy(volume.points[2], volume.points[0]);
+ VectorCopy(temp, volume.points[2]);
+ }
+ for (k = 0; k < volume.numplanes; k++)
+ {
+ VL_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]);
+ }
+ VectorCopy(light->origin, temp);
+ temp[i] += (float) j * dist;
+ VectorClear(volume.endplane.normal);
+ volume.endplane.normal[i] = -j;
+ volume.endplane.dist = DotProduct(volume.endplane.normal, temp); //DotProduct(volume.endplane.normal, volume.points[0]);
+ volume.farplane = volume.endplane;
+ volume.cluster = leaf->cluster;
+ volume.surfaceNum = -1;
+ volume.type = VOLUME_NORMAL;
+ //
+ memset(volume.facetTested, 0, sizeof(volume.facetTested));
+ memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
+ VL_R_FloodLight(light, &volume, leaf->cluster, 0);
+ if (volume.surfaceNum >= 0)
+ {
+ VL_R_CastLightAtSurface(light, &volume);
+ }
+ }
+ }
+ break;
+ }
+ case LIGHT_POINTSPOT:
+ {
+ // source is a point
+ // light is targetted
+ // creates sharp shadows
+ //
+ // what about using brushes to shape spot lights? that'd be pretty cool
+ //
+ if ( light->atten_disttype == LDAT_LINEAR )
+ dist = light->photons * lightLinearScale;
+ else
+ dist = sqrt(light->photons);
+ dist *= 2;
+ //
+ windingdist = 4096;
+ if (dist > windingdist)
+ windingdist = dist;
+ //take 8 times the cone radius because the spotlight also lights outside the cone
+ radius = 8 * windingdist * light->radiusByDist;
+ //
+ memset(&volume, 0, sizeof(lightvolume_t));
+ leafnum = VL_LightLeafnum(light->origin);
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster == -1)
+ {
+ light->insolid = qtrue;
+ break;
+ }
+ //
+ VectorClear(vec);
+ for (i = 0; i < 3; i++)
+ {
+ if (light->normal[i] > -0.9 && light->normal[i] < 0.9)
+ {
+ vec[i] = 1;
+ break;
+ }
+ }
+ CrossProduct(light->normal, vec, r);
+ VectorScale(r, radius, p);
+ volume.numplanes = 0;
+ step = 45;
+ for (a = step / 2; a < 360 + step / 2; a += step)
+ {
+ RotatePointAroundVector(volume.points[volume.numplanes], light->normal, p, a);
+ VectorAdd(light->origin, volume.points[volume.numplanes], volume.points[volume.numplanes]);
+ VectorMA(volume.points[volume.numplanes], windingdist, light->normal, volume.points[volume.numplanes]);
+ volume.numplanes++;
+ }
+ for (i = 0; i < volume.numplanes; i++)
+ {
+ VL_PlaneFromPoints(&volume.planes[i], light->origin, volume.points[(i+1)%volume.numplanes], volume.points[i]);
+ }
+ VectorMA(light->origin, dist, light->normal, temp);
+ VectorCopy(light->normal, volume.endplane.normal);
+ VectorInverse(volume.endplane.normal);
+ volume.endplane.dist = DotProduct(volume.endplane.normal, temp);//DotProduct(volume.endplane.normal, volume.points[0]);
+ volume.farplane = volume.endplane;
+ volume.cluster = leaf->cluster;
+ volume.surfaceNum = -1;
+ volume.type = VOLUME_NORMAL;
+ //
+ memset(volume.facetTested, 0, sizeof(volume.facetTested));
+ memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
+ VL_R_FloodLight(light, &volume, leaf->cluster, 0);
+ if (volume.surfaceNum >= 0)
+ {
+ VL_R_CastLightAtSurface(light, &volume);
+ }
+ break;
+ }
+ case LIGHT_POINTFAKESURFACE:
+ {
+ float value;
+ int n, axis;
+ vec3_t v, vecs[2];
+
+ if ( light->atten_disttype == LDAT_LINEAR )
+ dist = light->photons * lightLinearScale;
+ else
+ dist = sqrt(light->photons);
+ //always put the winding at a large distance to avoid epsilon issues
+ windingdist = 4096;
+ if (dist > windingdist)
+ windingdist = dist;
+ //
+ VectorMA(light->origin, 0.1, light->normal, light->origin);
+ //
+ leafnum = VL_LightLeafnum(light->origin);
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster == -1)
+ {
+ light->insolid = qtrue;
+ break;
+ }
+ value = 0;
+ for (i = 0; i < 3; i++)
+ {
+ if (fabs(light->normal[i]) > value)
+ {
+ value = fabs(light->normal[i]);
+ axis = i;
+ }
+ }
+ for (i = 0; i < 2; i++)
+ {
+ VectorClear(v);
+ v[(axis + 1 + i) % 3] = 1;
+ CrossProduct(light->normal, v, vecs[i]);
+ }
+ //cast 4 volumes at the front of the surface
+ for (i = -1; i <= 1; i += 2)
+ {
+ for (j = -1; j <= 1; j += 2)
+ {
+ for (n = 0; n < 2; n++)
+ {
+ memset(&volume, 0, sizeof(lightvolume_t));
+ volume.numplanes = 3;
+ VectorMA(light->origin, i * windingdist, vecs[0], volume.points[(i == j) == n]);
+ VectorMA(light->origin, j * windingdist, vecs[1], volume.points[(i != j) == n]);
+ VectorMA(light->origin, windingdist, light->normal, volume.points[2]);
+ for (k = 0; k < volume.numplanes; k++)
+ {
+ VL_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]);
+ }
+ VL_PlaneFromPoints(&volume.endplane, volume.points[0], volume.points[1], volume.points[2]);
+ VectorMA(light->origin, dist, light->normal, temp);
+ volume.endplane.dist = DotProduct(volume.endplane.normal, temp);
+ if (DotProduct(light->origin, volume.endplane.normal) - volume.endplane.dist > 0)
+ break;
+ }
+ volume.farplane = volume.endplane;
+ volume.cluster = leaf->cluster;
+ volume.surfaceNum = -1;
+ volume.type = VOLUME_NORMAL;
+ //
+ memset(volume.facetTested, 0, sizeof(volume.facetTested));
+ memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
+
+ VL_R_FloodLight(light, &volume, leaf->cluster, 0);
+ if (volume.surfaceNum >= 0)
+ {
+ VL_R_CastLightAtSurface(light, &volume);
+ }
+ }
+ }
+ break;
+ }
+ case LIGHT_SURFACEDIRECTED:
+ {
+ // source is an area defined by a winding
+ // the light is unidirectional
+ // creates sharp shadows
+ // for instance sun light or laser light
+ //
+ memcpy(&winding, &light->w, sizeof(winding_t));
+ VL_R_SubdivideDirectedAreaLight(light, 0, &winding);
+ break;
+ }
+ case LIGHT_SURFACERADIAL:
+ {
+ // source is an area defined by a winding
+ // the light radiates in all directions at the front of the winding plane
+ //
+ memcpy(&winding, &light->w, sizeof(winding_t));
+ VL_R_SubdivideRadialAreaLight(light, 0, &winding);
+ break;
+ }
+ case LIGHT_SURFACESPOT:
+ {
+ // source is an area defined by a winding
+ // light is targetted but not unidirectional
+ //
+ memcpy(&winding, &light->w, sizeof(winding_t));
+ VL_R_SubdivideAreaSpotLight(light, 0, &winding);
+ break;
+ }
+ }
+}
+
+/*
+=============
+VL_FloodLightThread
+=============
+*/
+void VL_FloodLightThread(int num)
+{
+ VL_FloodLight(vlights[num]);
+}
+
+/*
+=============
+VL_TestLightLeafs
+=============
+*/
+void VL_TestLightLeafs(void)
+{
+ int leafnum, i;
+ vlight_t *light;
+ dleaf_t *leaf;
+
+ for (i = 0; i < numvlights; i++)
+ {
+ light = vlights[i];
+ if (light->type != LIGHT_POINTRADIAL &&
+ light->type != LIGHT_POINTSPOT)
+ continue;
+ leafnum = VL_LightLeafnum(light->origin);
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster == -1)
+ if (light->type == LIGHT_POINTRADIAL)
+ qprintf("light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]);
+ else if (light->type == LIGHT_POINTSPOT)
+ qprintf("spot light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]);
+ }
+}
+
+
+/*
+=============
+VL_DoForcedTraceLight
+=============
+*/
+// from light.c
+void TraceLtm( int num );
+
+void VL_DoForcedTraceLight(int num)
+{
+ dsurface_t *ds;
+ shaderInfo_t *si;
+
+ ds = &drawSurfaces[num];
+
+ if ( ds->surfaceType == MST_TRIANGLE_SOUP )
+ return;
+
+ if ( ds->lightmapNum < 0 )
+ return;
+
+ // always light entity surfaces with the old light algorithm
+ if ( !entitySurface[num] )
+ {
+ si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
+
+ if (defaulttracelight)
+ {
+ if (si->forceVLight)
+ return;
+ }
+ else
+ {
+ if (!si->forceTraceLight)
+ return;
+ }
+ }
+
+ TraceLtm(num);
+}
+
+/*
+=============
+VL_DoForcedTraceLightSurfaces
+=============
+*/
+void VL_DoForcedTraceLightSurfaces(void)
+{
+ _printf( "forced trace light\n" );
+ RunThreadsOnIndividual( numDrawSurfaces, qtrue, VL_DoForcedTraceLight );
+}
+
+float *oldLightFloats;
+
+/*
+=============
+VL_SurfaceRadiosity
+=============
+*/
+void VL_SurfaceRadiosity( int num ) {
+ dsurface_t *ds;
+ mesh_t *mesh;
+ shaderInfo_t *si;
+ lsurfaceTest_t *test;
+ int x, y, k;
+ vec3_t base, normal;
+ float *color, area;
+ vlight_t vlight;
+
+ ds = &drawSurfaces[num];
+
+ if ( ds->lightmapNum < 0 ) {
+ return; // doesn't have a lightmap
+ }
+
+ // vertex-lit triangle model
+ if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
+ return;
+ }
+
+ si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
+ test = lsurfaceTest[ num ];
+
+ if (!test) {
+ return;
+ }
+
+ for (x = 0; x < ds->lightmapWidth; x++) {
+ for (y = 0; y < ds->lightmapHeight; y++) {
+ //
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ area = lightmappixelarea[k];
+ if (area <= 0)
+ continue;
+ //
+ if (ds->surfaceType == MST_PATCH)
+ {
+ mesh = test->detailMesh;
+ VectorCopy( mesh->verts[y*mesh->width+x].xyz, base);
+ VectorCopy( mesh->verts[y*mesh->width+x].normal, normal);
+ }
+ else
+ {
+ VectorMA(ds->lightmapOrigin, (float) x, ds->lightmapVecs[0], base);
+ VectorMA(base, (float) y, ds->lightmapVecs[1], base);
+ VectorCopy(test->facets[0].plane.normal, normal);
+ }
+ // create ligth from base
+ memset(&vlight, 0, sizeof(vlight_t));
+ color = &oldLightFloats[k*3];
+ // a few units away from the surface
+ VectorMA(base, 5, normal, vlight.origin);
+ ColorNormalize(color, vlight.color);
+ // ok this is crap
+ vlight.photons = VectorLength(color) * 0.05 * lightPointScale / (area * radiosity_scale);
+ // what about using a front facing light only ?
+ vlight.type = LIGHT_POINTRADIAL;
+ // flood the light from this lightmap pixel
+ VL_FloodLight(&vlight);
+ // only one thread at a time may write to the lightmap of this surface
+ MutexLock(test->mutex);
+ // don't light the lightmap pixel itself
+ lightFloats[k*3] = oldLightFloats[k*3];
+ lightFloats[k*3+1] = oldLightFloats[k*3+1];
+ lightFloats[k*3+2] = oldLightFloats[k*3+2];
+ //
+ MutexUnlock(test->mutex);
+ }
+ }
+}
+
+/*
+=============
+VL_Radiosity
+
+this aint working real well but it's fun to play with.
+=============
+*/
+void VL_Radiosity(void) {
+
+ oldLightFloats = lightFloats;
+ lightFloats = (float *) malloc(numLightBytes * sizeof(float));
+ memcpy(lightFloats, oldLightFloats, numLightBytes * sizeof(float));
+ _printf("%7i surfaces\n", numDrawSurfaces);
+ RunThreadsOnIndividual( numDrawSurfaces, qtrue, VL_SurfaceRadiosity );
+ free(oldLightFloats);
+}
+
+/*
+=============
+VL_LightWorld
+=============
+*/
+void VL_LightWorld(void)
+{
+ int i, numcastedvolumes, numvlightsinsolid;
+ float f;
+
+ // find the optional world ambient
+ GetVectorForKey( &entities[0], "_color", lightAmbientColor );
+ f = FloatForKey( &entities[0], "ambient" );
+ VectorScale( lightAmbientColor, f, lightAmbientColor );
+ /*
+ _printf("\r%6d lights out of %d", 0, numvlights);
+ for (i = 0; i < numvlights; i++)
+ {
+ _printf("\r%6d", i);
+ VL_FloodLight(vlights[i]);
+ }
+ _printf("\r%6d lights out of %d\n", i, numvlights);
+ */
+ _printf("%7i lights\n", numvlights);
+ RunThreadsOnIndividual( numvlights, qtrue, VL_FloodLightThread );
+
+ numcastedvolumes = 0;
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ if (lsurfaceTest[i])
+ numcastedvolumes += lsurfaceTest[i]->numvolumes;
+ }
+ _printf("%7i light volumes casted\n", numcastedvolumes);
+ numvlightsinsolid = 0;
+ for (i = 0; i < numvlights; i++)
+ {
+ if (vlights[i]->insolid)
+ numvlightsinsolid++;
+ }
+ _printf("%7i lights in solid\n", numvlightsinsolid);
+ //
+ radiosity_scale = 1;
+ for (i = 0; i < radiosity; i++) {
+ VL_Radiosity();
+ radiosity_scale <<= 1;
+ }
+ //
+ VL_StoreLightmap();
+ // redo surfaces with the old light algorithm when needed
+ VL_DoForcedTraceLightSurfaces();
+}
+
+/*
+=============
+VL_CreateEntityLights
+=============
+*/
+entity_t *FindTargetEntity( const char *target );
+
+void VL_CreateEntityLights (void)
+{
+ int i, c_entityLights;
+ vlight_t *dl;
+ entity_t *e, *e2;
+ const char *name;
+ const char *target;
+ vec3_t dest;
+ const char *_color;
+ float intensity;
+ int spawnflags;
+
+ //
+ c_entityLights = 0;
+ _printf("Creating entity lights...\n");
+ //
+ for ( i = 0 ; i < num_entities ; i++ ) {
+ e = &entities[i];
+ name = ValueForKey (e, "classname");
+ if (strncmp (name, "light", 5))
+ continue;
+
+ dl = malloc(sizeof(*dl));
+ memset (dl, 0, sizeof(*dl));
+
+ spawnflags = FloatForKey (e, "spawnflags");
+ if ( spawnflags & 1 ) {
+ dl->atten_disttype = LDAT_LINEAR;
+ }
+ if ( spawnflags & 2 ) {
+ dl->atten_disttype = LDAT_NOSCALE;
+ }
+ if ( spawnflags & 4 ) {
+ dl->atten_angletype = LAAT_QUADRATIC;
+ }
+ if ( spawnflags & 8 ) {
+ dl->atten_angletype = LAAT_DOUBLEQUADRATIC;
+ }
+
+ dl->atten_distscale = FloatForKey(e, "atten_distscale");
+ dl->atten_anglescale = FloatForKey(e, "atten_anglescale");
+
+ GetVectorForKey (e, "origin", dl->origin);
+ dl->style = FloatForKey (e, "_style");
+ if (!dl->style)
+ dl->style = FloatForKey (e, "style");
+ if (dl->style < 0)
+ dl->style = 0;
+
+ intensity = FloatForKey (e, "light");
+ if (!intensity)
+ intensity = FloatForKey (e, "_light");
+ if (!intensity)
+ intensity = 300;
+ _color = ValueForKey (e, "_color");
+ if (_color && _color[0])
+ {
+ sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);
+ ColorNormalize (dl->color, dl->color);
+ }
+ else
+ dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
+
+ intensity = intensity * lightPointScale;
+ dl->photons = intensity;
+
+ dl->type = LIGHT_POINTRADIAL;
+
+ // lights with a target will be spotlights
+ target = ValueForKey (e, "target");
+
+ if ( target[0] ) {
+ float radius;
+ float dist;
+
+ e2 = FindTargetEntity (target);
+ if (!e2) {
+ _printf ("WARNING: light at (%i %i %i) has missing target\n",
+ (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]);
+ } else {
+ GetVectorForKey (e2, "origin", dest);
+ VectorSubtract (dest, dl->origin, dl->normal);
+ dist = VectorNormalize (dl->normal, dl->normal);
+ radius = FloatForKey (e, "radius");
+ if ( !radius ) {
+ radius = 64;
+ }
+ if ( !dist ) {
+ dist = 64;
+ }
+ dl->radiusByDist = (radius + 16) / dist;
+ dl->type = LIGHT_POINTSPOT;
+ }
+ }
+ vlights[numvlights++] = dl;
+ c_entityLights++;
+ }
+ _printf("%7i entity lights\n", c_entityLights);
+}
+
+/*
+==================
+VL_SubdivideAreaLight
+==================
+*/
+void VL_SubdivideAreaLight( shaderInfo_t *ls, winding_t *w, vec3_t normal,
+ float areaSubdivide, qboolean backsplash ) {
+ float area, value, intensity;
+ vlight_t *dl, *dl2;
+ vec3_t mins, maxs;
+ int axis;
+ winding_t *front, *back;
+ vec3_t planeNormal;
+ float planeDist;
+
+ if ( !w ) {
+ return;
+ }
+
+ WindingBounds( w, mins, maxs );
+
+ // check for subdivision
+ for ( axis = 0 ; axis < 3 ; axis++ ) {
+ if ( maxs[axis] - mins[axis] > areaSubdivide ) {
+ VectorClear( planeNormal );
+ planeNormal[axis] = 1;
+ planeDist = ( maxs[axis] + mins[axis] ) * 0.5;
+ ClipWindingEpsilon ( w, planeNormal, planeDist, ON_EPSILON, &front, &back );
+ VL_SubdivideAreaLight( ls, front, normal, areaSubdivide, qfalse );
+ VL_SubdivideAreaLight( ls, back, normal, areaSubdivide, qfalse );
+ FreeWinding( w );
+ return;
+ }
+ }
+
+ // create a light from this
+ area = WindingArea (w);
+ if ( area <= 0 || area > 20000000 ) {
+ return;
+ }
+
+ dl = malloc(sizeof(*dl));
+ memset (dl, 0, sizeof(*dl));
+ dl->type = LIGHT_POINTFAKESURFACE;
+
+ WindingCenter( w, dl->origin );
+ memcpy(dl->w.points, w->points, sizeof(vec3_t) * w->numpoints);
+ dl->w.numpoints = w->numpoints;
+ VectorCopy ( normal, dl->normal);
+ VectorCopy ( normal, dl->plane);
+ dl->plane[3] = DotProduct( dl->origin, normal );
+
+ value = ls->value;
+ intensity = value * area * lightAreaScale;
+ VectorAdd( dl->origin, dl->normal, dl->origin );
+
+ VectorCopy( ls->color, dl->color );
+
+ dl->photons = intensity;
+
+ // emitColor is irrespective of the area
+ VectorScale( ls->color, value*lightFormFactorValueScale*lightAreaScale, dl->emitColor );
+ //
+ VectorCopy(dl->emitColor, dl->color);
+
+ dl->si = ls;
+
+ if ( ls->contents & CONTENTS_FOG ) {
+ dl->twosided = qtrue;
+ }
+
+ vlights[numvlights++] = dl;
+
+ // optionally create a point backsplash light
+ if ( backsplash && ls->backsplashFraction > 0 ) {
+
+ dl2 = malloc(sizeof(*dl));
+ memset (dl2, 0, sizeof(*dl2));
+ dl2->type = LIGHT_POINTRADIAL;
+
+ VectorMA( dl->origin, ls->backsplashDistance, normal, dl2->origin );
+
+ VectorCopy( ls->color, dl2->color );
+
+ dl2->photons = dl->photons * ls->backsplashFraction;
+ dl2->si = ls;
+
+ vlights[numvlights++] = dl2;
+ }
+}
+
+/*
+==================
+VL_CreateFakeSurfaceLights
+==================
+*/
+void VL_CreateFakeSurfaceLights( void ) {
+ int i, j, side;
+ dsurface_t *ds;
+ shaderInfo_t *ls;
+ winding_t *w;
+ lFacet_t *f;
+ vlight_t *dl;
+ vec3_t origin;
+ drawVert_t *dv;
+ int c_surfaceLights;
+ float lightSubdivide;
+ vec3_t normal;
+
+
+ c_surfaceLights = 0;
+ _printf ("Creating surface lights...\n");
+
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ // see if this surface is light emiting
+ ds = &drawSurfaces[i];
+
+ ls = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
+ if ( ls->value == 0 ) {
+ continue;
+ }
+
+ // determine how much we need to chop up the surface
+ if ( ls->lightSubdivide ) {
+ lightSubdivide = ls->lightSubdivide;
+ } else {
+ lightSubdivide = lightDefaultSubdivide;
+ }
+
+ c_surfaceLights++;
+
+ // an autosprite shader will become
+ // a point light instead of an area light
+ if ( ls->autosprite ) {
+ // autosprite geometry should only have four vertexes
+ if ( lsurfaceTest[i] ) {
+ // curve or misc_model
+ f = lsurfaceTest[i]->facets;
+ if ( lsurfaceTest[i]->numFacets != 1 || f->numpoints != 4 ) {
+ _printf( "WARNING: surface at (%i %i %i) has autosprite shader but isn't a quad\n",
+ (int)f->points[0], (int)f->points[1], (int)f->points[2] );
+ }
+ VectorAdd( f->points[0], f->points[1], origin );
+ VectorAdd( f->points[2], origin, origin );
+ VectorAdd( f->points[3], origin, origin );
+ VectorScale( origin, 0.25, origin );
+ } else {
+ // normal polygon
+ dv = &drawVerts[ ds->firstVert ];
+ if ( ds->numVerts != 4 ) {
+ _printf( "WARNING: surface at (%i %i %i) has autosprite shader but %i verts\n",
+ (int)dv->xyz[0], (int)dv->xyz[1], (int)dv->xyz[2] );
+ continue;
+ }
+
+ VectorAdd( dv[0].xyz, dv[1].xyz, origin );
+ VectorAdd( dv[2].xyz, origin, origin );
+ VectorAdd( dv[3].xyz, origin, origin );
+ VectorScale( origin, 0.25, origin );
+ }
+
+ dl = malloc(sizeof(*dl));
+ memset (dl, 0, sizeof(*dl));
+ VectorCopy( origin, dl->origin );
+ VectorCopy( ls->color, dl->color );
+ dl->photons = ls->value * lightPointScale;
+ dl->type = LIGHT_POINTRADIAL;
+ vlights[numvlights++] = dl;
+ continue;
+ }
+
+ // possibly create for both sides of the polygon
+ for ( side = 0 ; side <= ls->twoSided ; side++ ) {
+ // create area lights
+ if ( lsurfaceTest[i] ) {
+ // curve or misc_model
+ for ( j = 0 ; j < lsurfaceTest[i]->numFacets ; j++ ) {
+ f = lsurfaceTest[i]->facets + j;
+ w = AllocWinding( f->numpoints );
+ w->numpoints = f->numpoints;
+ memcpy( w->points, f->points, f->numpoints * 12 );
+
+ VectorCopy( f->plane.normal, normal );
+ if ( side ) {
+ winding_t *t;
+
+ t = w;
+ w = ReverseWinding( t );
+ FreeWinding( t );
+ VectorSubtract( vec3_origin, normal, normal );
+ }
+ VL_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
+ }
+ } else {
+ // normal polygon
+
+ w = AllocWinding( ds->numVerts );
+ w->numpoints = ds->numVerts;
+ for ( j = 0 ; j < ds->numVerts ; j++ ) {
+ VectorCopy( drawVerts[ds->firstVert+j].xyz, w->points[j] );
+ }
+ VectorCopy( ds->lightmapVecs[2], normal );
+ if ( side ) {
+ winding_t *t;
+
+ t = w;
+ w = ReverseWinding( t );
+ FreeWinding( t );
+ VectorSubtract( vec3_origin, normal, normal );
+ }
+ VL_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
+ }
+ }
+ }
+
+ _printf( "%7i light emitting surfaces\n", c_surfaceLights );
+}
+
+
+/*
+==================
+VL_WindingForBrushSide
+==================
+*/
+winding_t *VL_WindingForBrushSide(dbrush_t *brush, int side, winding_t *w)
+{
+ int i, res;
+ winding_t *tmpw;
+ plane_t plane;
+
+ VectorCopy(dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].normal, plane.normal);
+ VectorInverse(plane.normal);
+ plane.dist = -dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].dist;
+ tmpw = BaseWindingForPlane( plane.normal, plane.dist );
+ memcpy(w->points, tmpw->points, sizeof(vec3_t) * tmpw->numpoints);
+ w->numpoints = tmpw->numpoints;
+
+ for (i = 0; i < brush->numSides; i++)
+ {
+ if (i == side)
+ continue;
+ VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal);
+ VectorInverse(plane.normal);
+ plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist;
+ res = VL_ChopWinding(w, &plane, 0.1);
+ if (res == SIDE_BACK)
+ return NULL;
+ }
+ return w;
+}
+
+/*
+==================
+VL_CreateSkyLights
+==================
+*/
+void VL_CreateSkyLights(void)
+{
+ int i, j, c_skyLights;
+ dbrush_t *b;
+ shaderInfo_t *si;
+ dbrushside_t *s;
+ vlight_t *dl;
+ vec3_t sunColor, sunDir = { 0.45, 0.3, 0.9 };
+ float d;
+
+ VectorNormalize(sunDir, sunDir);
+ VectorInverse(sunDir);
+
+ c_skyLights = 0;
+ _printf("Creating sky lights...\n");
+ // find the sky shader
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ si = ShaderInfoForShader( dshaders[ drawSurfaces[i].shaderNum ].shader );
+ if ( si->surfaceFlags & SURF_SKY ) {
+ VectorCopy( si->sunLight, sunColor );
+ VectorCopy( si->sunDirection, sunDir );
+ VectorInverse(sunDir);
+ break;
+ }
+ }
+
+ // find the brushes
+ for ( i = 0 ; i < numbrushes ; i++ ) {
+ b = &dbrushes[i];
+ for ( j = 0 ; j < b->numSides ; j++ ) {
+ s = &dbrushsides[ b->firstSide + j ];
+ if ( dshaders[ s->shaderNum ].surfaceFlags & SURF_SKY ) {
+ //if this surface doesn't face in the same direction as the sun
+ d = DotProduct(dplanes[ s->planeNum ].normal, sunDir);
+ if (d <= 0)
+ continue;
+ //
+ dl = malloc(sizeof(*dl));
+ memset (dl, 0, sizeof(*dl));
+ VectorCopy(sunColor, dl->color);
+ VectorCopy(sunDir, dl->normal);
+ VectorCopy(dplanes[ s->planeNum ].normal, dl->plane);
+ dl->plane[3] = dplanes[ s->planeNum ].dist;
+ dl->type = LIGHT_SURFACEDIRECTED;
+ dl->atten_disttype = LDAT_NOSCALE;
+ VL_WindingForBrushSide(b, j, &dl->w);
+// DebugNet_DrawWinding(&dl->w, 2);
+ //
+ vlights[numvlights++] = dl;
+ c_skyLights++;
+ }
+ }
+ }
+ _printf("%7i light emitting sky surfaces\n", c_skyLights);
+}
+
+/*
+==================
+VL_SetPortalSphere
+==================
+*/
+void VL_SetPortalSphere (lportal_t *p)
+{
+ int i;
+ vec3_t total, dist;
+ winding_t *w;
+ float r, bestr;
+
+ w = p->winding;
+ VectorCopy (vec3_origin, total);
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ VectorAdd (total, w->points[i], total);
+ }
+
+ for (i=0 ; i<3 ; i++)
+ total[i] /= w->numpoints;
+
+ bestr = 0;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ VectorSubtract (w->points[i], total, dist);
+ r = VectorLength (dist);
+ if (r > bestr)
+ bestr = r;
+ }
+ VectorCopy (total, p->origin);
+ p->radius = bestr;
+}
+
+/*
+==================
+VL_PlaneFromWinding
+==================
+*/
+void VL_PlaneFromWinding (winding_t *w, plane_t *plane)
+{
+ vec3_t v1, v2;
+
+ //calc plane
+ VectorSubtract (w->points[2], w->points[1], v1);
+ VectorSubtract (w->points[0], w->points[1], v2);
+ CrossProduct (v2, v1, plane->normal);
+ VectorNormalize (plane->normal, plane->normal);
+ plane->dist = DotProduct (w->points[0], plane->normal);
+}
+
+/*
+==================
+VL_AllocWinding
+==================
+*/
+winding_t *VL_AllocWinding (int points)
+{
+ winding_t *w;
+ int size;
+
+ if (points > MAX_POINTS_ON_WINDING)
+ Error ("NewWinding: %i points", points);
+
+ size = (int)((winding_t *)0)->points[points];
+ w = malloc (size);
+ memset (w, 0, size);
+
+ return w;
+}
+
+/*
+============
+VL_LoadPortals
+============
+*/
+void VL_LoadPortals (char *name)
+{
+ int i, j, hint;
+ lportal_t *p;
+ lleaf_t *l;
+ char magic[80];
+ FILE *f;
+ int numpoints;
+ winding_t *w;
+ int leafnums[2];
+ plane_t plane;
+ //
+
+ if (!strcmp(name,"-"))
+ f = stdin;
+ else
+ {
+ f = fopen(name, "r");
+ if (!f)
+ Error ("LoadPortals: couldn't read %s\n",name);
+ }
+
+ if (fscanf (f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces) != 4)
+ Error ("LoadPortals: failed to read header");
+ if (strcmp(magic, PORTALFILE))
+ Error ("LoadPortals: not a portal file");
+
+ _printf ("%6i portalclusters\n", portalclusters);
+ _printf ("%6i numportals\n", numportals);
+ _printf ("%6i numfaces\n", numfaces);
+
+ if (portalclusters >= MAX_CLUSTERS)
+ Error ("more than %d clusters in portal file\n", MAX_CLUSTERS);
+
+ // each file portal is split into two memory portals
+ portals = malloc(2*numportals*sizeof(lportal_t));
+ memset (portals, 0, 2*numportals*sizeof(lportal_t));
+
+ leafs = malloc(portalclusters*sizeof(lleaf_t));
+ memset (leafs, 0, portalclusters*sizeof(lleaf_t));
+
+ for (i=0, p=portals ; i<numportals ; i++)
+ {
+ if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3)
+ Error ("LoadPortals: reading portal %i", i);
+ if (numpoints > MAX_POINTS_ON_WINDING)
+ Error ("LoadPortals: portal %i has too many points", i);
+ if ( (unsigned)leafnums[0] > portalclusters
+ || (unsigned)leafnums[1] > portalclusters)
+ Error ("LoadPortals: reading portal %i", i);
+ if (fscanf (f, "%i ", &hint) != 1)
+ Error ("LoadPortals: reading hint state");
+
+ w = p->winding = VL_AllocWinding (numpoints);
+ w->numpoints = numpoints;
+
+ for (j=0 ; j<numpoints ; j++)
+ {
+ double v[3];
+ int k;
+
+ // scanf into double, then assign to vec_t
+ // so we don't care what size vec_t is
+ if (fscanf (f, "(%lf %lf %lf ) "
+ , &v[0], &v[1], &v[2]) != 3)
+ Error ("LoadPortals: reading portal %i", i);
+ for (k=0 ; k<3 ; k++)
+ w->points[j][k] = v[k];
+ }
+ fscanf (f, "\n");
+
+ // calc plane
+ VL_PlaneFromWinding (w, &plane);
+
+ // create forward portal
+ l = &leafs[leafnums[0]];
+ if (l->numportals == MAX_PORTALS_ON_LEAF)
+ Error ("Leaf with too many portals");
+ l->portals[l->numportals] = p;
+ l->numportals++;
+
+ p->winding = w;
+ VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
+ p->plane.dist = -plane.dist;
+ p->leaf = leafnums[1];
+ VL_SetPortalSphere (p);
+ p++;
+
+ // create backwards portal
+ l = &leafs[leafnums[1]];
+ if (l->numportals == MAX_PORTALS_ON_LEAF)
+ Error ("Leaf with too many portals");
+ l->portals[l->numportals] = p;
+ l->numportals++;
+
+ p->winding = VL_AllocWinding(w->numpoints);
+ p->winding->numpoints = w->numpoints;
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]);
+ }
+
+ p->plane = plane;
+ p->leaf = leafnums[0];
+ VL_SetPortalSphere (p);
+ p++;
+
+ }
+
+ fclose (f);
+}
+
+/*
+============
+VLightMain
+============
+*/
+int VLightMain (int argc, char **argv) {
+ int i;
+ double start, end;
+ const char *value;
+
+ _printf ("----- VLighting ----\n");
+
+ for (i=1 ; i<argc ; i++) {
+ if (!strcmp(argv[i],"-v")) {
+ verbose = qtrue;
+ } else if (!strcmp(argv[i],"-threads")) {
+ numthreads = atoi (argv[i+1]);
+ _printf("num threads = %d\n", numthreads);
+ i++;
+ } else if (!strcmp(argv[i],"-area")) {
+ lightAreaScale *= atof(argv[i+1]);
+ _printf ("area light scaling at %f\n", lightAreaScale);
+ i++;
+ } else if (!strcmp(argv[i],"-point")) {
+ lightPointScale *= atof(argv[i+1]);
+ _printf ("point light scaling at %f\n", lightPointScale);
+ i++;
+ } else if (!strcmp(argv[i], "-samplesize")) {
+ samplesize = atoi(argv[i+1]);
+ if (samplesize < 1) samplesize = 1;
+ i++;
+ _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize);
+ } else if (!strcmp(argv[i], "-novertex")) {
+ novertexlighting = qtrue;
+ _printf("no vertex lighting = true\n");
+ } else if (!strcmp(argv[i], "-nogrid")) {
+ nogridlighting = qtrue;
+ _printf("no grid lighting = true\n");
+ } else if (!strcmp(argv[i], "-nostitching")) {
+ nostitching = qtrue;
+ _printf("no stitching = true\n");
+ } else if (!strcmp(argv[i], "-noalphashading")) {
+ noalphashading = qtrue;
+ _printf("no alpha shading = true\n");
+ } else if (!strcmp(argv[i], "-nocolorshading")) {
+ nocolorshading = qtrue;
+ _printf("old style alpha shading = true\n");
+ } else if (!strcmp(argv[i], "-nobackfaceculling")) {
+ nobackfaceculling = qtrue;
+ _printf("no backface culling = true\n");
+ } else if (!strcmp(argv[i], "-tracelight")) {
+ defaulttracelight = qtrue;
+ _printf("default trace light = true\n");
+ } else if (!strcmp(argv[i], "-radiosity")) {
+ radiosity = atoi(argv[i+1]);
+ _printf("radiosity = %d\n", radiosity);
+ i++;
+ } else {
+ break;
+ }
+ }
+
+ ThreadSetDefault ();
+
+ if (i != argc - 1) {
+ _printf("usage: q3map -vlight [-<switch> [-<switch> ...]] <mapname>\n"
+ "\n"
+ "Switches:\n"
+ " v = verbose output\n"
+ " threads <X> = set number of threads to X\n"
+ " area <V> = set the area light scale to V\n"
+ " point <W> = set the point light scale to W\n"
+ " novertex = don't calculate vertex lighting\n"
+ " nogrid = don't calculate light grid for dynamic model lighting\n"
+ " nostitching = no polygon stitching before lighting\n"
+ " noalphashading = don't use alpha shading\n"
+ " nocolorshading = don't use color alpha shading\n"
+ " tracelight = use old light algorithm by default\n"
+ " samplesize <N> = set the lightmap pixel size to NxN units\n");
+ exit(0);
+ }
+
+ SetQdirFromPath (argv[i]);
+
+#ifdef _WIN32
+ InitPakFile(gamedir, NULL);
+#endif
+
+ strcpy (source, ExpandArg(argv[i]));
+ StripExtension (source);
+ DefaultExtension (source, ".bsp");
+
+ LoadShaderInfo();
+
+ _printf ("reading %s\n", source);
+
+ LoadBSPFile (source);
+ ParseEntities();
+
+ value = ValueForKey( &entities[0], "gridsize" );
+ if (strlen(value)) {
+ sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] );
+ _printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]);
+ }
+
+ CountLightmaps();
+
+ StripExtension (source);
+ DefaultExtension (source, ".prt");
+
+ VL_LoadPortals(source);
+
+ // set surfaceOrigin
+ SetEntityOrigins();
+
+ // grid and vertex lighting
+ GridAndVertexLighting();
+
+#ifdef DEBUGNET
+ DebugNet_Setup();
+#endif
+
+ start = clock();
+
+ lightFloats = (float *) malloc(numLightBytes * sizeof(float));
+ memset(lightFloats, 0, numLightBytes * sizeof(float));
+
+ VL_InitSurfacesForTesting();
+
+ VL_CalcVisibleLightmapPixelArea();
+
+ numvlights = 0;
+ VL_CreateEntityLights();
+ VL_CreateFakeSurfaceLights();
+ VL_CreateSkyLights();
+
+ VL_TestLightLeafs();
+
+ VL_LightWorld();
+
+#ifndef LIGHTPOLYS
+ StripExtension (source);
+ DefaultExtension (source, ".bsp");
+ _printf ("writing %s\n", source);
+ WriteBSPFile (source);
+#endif
+
+ end = clock();
+
+ _printf ("%5.2f seconds elapsed\n", (end-start) / CLK_TCK);
+
+#ifdef LIGHTPOLYS
+ VL_DrawLightWindings();
+#endif
+
+#ifdef DEBUGNET
+ DebugNet_Shutdown();
+#endif
+ return 0;
+}
diff --git a/q3map/makefile b/q3map/makefile
index 15c6a0b..ff8d6c1 100755
--- a/q3map/makefile
+++ b/q3map/makefile
@@ -1,148 +1,148 @@
-
-CFLAGS = -c
-LDFLAGS =
-ODIR = /q3/q3map
-
-EXEBASE = q3map
-EXE = $(ODIR)/$(EXEBASE)
-all: $(EXE)
-
-_irix:
- make "CFLAGS = -c -Ofast=ip27 -OPT:IEEE_arithmetic=3 -I../common -Xcpluscomm " "LDFLAGS = -Ofast=ip27 -OPT:IEEE_arithmetic=3 -g"
-
-_irixdebug:
- make "CFLAGS = -c -O2 -g -I../common -Xcpluscomm" "LDFLAGS = -g"
-
-_irixinst:
- make "_irix"
- make "install"
-
-clean:
- rm -f $(ODIR)/*.o $(EXE)
-
-install:
- cp $(EXE) /quake3_bin
- chmod 0777 /quake3_bin/$(EXEBASE)
-
-installtest:
- cp $(EXE) /quake3_bin/$(EXEBASE)_test
- chmod 0777 /quake3_bin/$(EXEBASE)_test
-
-
-FILES = $(ODIR)/fog.o $(ODIR)/brush.o $(ODIR)/tjunction.o $(ODIR)/vis.o $(ODIR)/visflow.o \
-$(ODIR)/light.o $(ODIR)/lightmaps.o $(ODIR)/bspfile.o \
-$(ODIR)/cmdlib.o $(ODIR)/patch.o $(ODIR)/mesh.o $(ODIR)/nodraw.o $(ODIR)/glfile.o \
-$(ODIR)/leakfile.o $(ODIR)/map.o $(ODIR)/mathlib.o $(ODIR)/polylib.o $(ODIR)/aselib.o \
-$(ODIR)/imagelib.o $(ODIR)/portals.o $(ODIR)/prtfile.o $(ODIR)/bsp.o $(ODIR)/surface.o \
-$(ODIR)/scriplib.o $(ODIR)/shaders.o $(ODIR)/threads.o $(ODIR)/tree.o \
-$(ODIR)/writebsp.o $(ODIR)/facebsp.o $(ODIR)/misc_model.o $(ODIR)/light_trace.o
-
-$(EXE) : $(FILES)
- cc -o $(EXE) $(LDFLAGS) $(FILES) -lm
-
-$(ODIR)/surface.o : surface.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/fog.o : fog.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/brush.o : brush.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/tjunction.o : tjunction.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/lightmaps.o : lightmaps.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/brushbsp.o : brushbsp.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/facebsp.o : facebsp.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/patch.o : patch.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/mesh.o : mesh.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/misc_model.o : misc_model.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/nodraw.o : nodraw.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/glfile.o : glfile.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/leakfile.o : leakfile.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/map.o : map.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/portals.o : portals.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/prtfile.o : prtfile.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/bsp.o : bsp.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/tree.o : tree.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/shaders.o : shaders.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/writebsp.o : writebsp.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/csg.o : csg.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-
-
-$(ODIR)/vis.o : vis.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/visflow.o : visflow.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-
-
-$(ODIR)/light.o : light.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/light_trace.o : light_trace.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-
-$(ODIR)/cmdlib.o : ../common/cmdlib.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/mathlib.o : ../common/mathlib.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/polylib.o : ../common/polylib.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/aselib.o : ../common/aselib.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/imagelib.o : ../common/imagelib.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/scriplib.o : ../common/scriplib.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/threads.o : ../common/threads.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-$(ODIR)/bspfile.o : ../common/bspfile.c
- cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
- cc $(CFLAGS) -o $@ /tmp/temp.i
-
-
+
+CFLAGS = -c
+LDFLAGS =
+ODIR = /q3/q3map
+
+EXEBASE = q3map
+EXE = $(ODIR)/$(EXEBASE)
+all: $(EXE)
+
+_irix:
+ make "CFLAGS = -c -Ofast=ip27 -OPT:IEEE_arithmetic=3 -I../common -Xcpluscomm " "LDFLAGS = -Ofast=ip27 -OPT:IEEE_arithmetic=3 -g"
+
+_irixdebug:
+ make "CFLAGS = -c -O2 -g -I../common -Xcpluscomm" "LDFLAGS = -g"
+
+_irixinst:
+ make "_irix"
+ make "install"
+
+clean:
+ rm -f $(ODIR)/*.o $(EXE)
+
+install:
+ cp $(EXE) /quake3_bin
+ chmod 0777 /quake3_bin/$(EXEBASE)
+
+installtest:
+ cp $(EXE) /quake3_bin/$(EXEBASE)_test
+ chmod 0777 /quake3_bin/$(EXEBASE)_test
+
+
+FILES = $(ODIR)/fog.o $(ODIR)/brush.o $(ODIR)/tjunction.o $(ODIR)/vis.o $(ODIR)/visflow.o \
+$(ODIR)/light.o $(ODIR)/lightmaps.o $(ODIR)/bspfile.o \
+$(ODIR)/cmdlib.o $(ODIR)/patch.o $(ODIR)/mesh.o $(ODIR)/nodraw.o $(ODIR)/glfile.o \
+$(ODIR)/leakfile.o $(ODIR)/map.o $(ODIR)/mathlib.o $(ODIR)/polylib.o $(ODIR)/aselib.o \
+$(ODIR)/imagelib.o $(ODIR)/portals.o $(ODIR)/prtfile.o $(ODIR)/bsp.o $(ODIR)/surface.o \
+$(ODIR)/scriplib.o $(ODIR)/shaders.o $(ODIR)/threads.o $(ODIR)/tree.o \
+$(ODIR)/writebsp.o $(ODIR)/facebsp.o $(ODIR)/misc_model.o $(ODIR)/light_trace.o
+
+$(EXE) : $(FILES)
+ cc -o $(EXE) $(LDFLAGS) $(FILES) -lm
+
+$(ODIR)/surface.o : surface.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/fog.o : fog.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/brush.o : brush.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/tjunction.o : tjunction.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/lightmaps.o : lightmaps.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/brushbsp.o : brushbsp.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/facebsp.o : facebsp.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/patch.o : patch.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/mesh.o : mesh.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/misc_model.o : misc_model.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/nodraw.o : nodraw.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/glfile.o : glfile.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/leakfile.o : leakfile.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/map.o : map.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/portals.o : portals.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/prtfile.o : prtfile.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/bsp.o : bsp.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/tree.o : tree.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/shaders.o : shaders.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/writebsp.o : writebsp.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/csg.o : csg.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+
+
+$(ODIR)/vis.o : vis.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/visflow.o : visflow.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+
+
+$(ODIR)/light.o : light.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/light_trace.o : light_trace.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+
+$(ODIR)/cmdlib.o : ../common/cmdlib.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/mathlib.o : ../common/mathlib.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/polylib.o : ../common/polylib.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/aselib.o : ../common/aselib.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/imagelib.o : ../common/imagelib.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/scriplib.o : ../common/scriplib.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/threads.o : ../common/threads.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+$(ODIR)/bspfile.o : ../common/bspfile.c
+ cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
+ cc $(CFLAGS) -o $@ /tmp/temp.i
+
+
diff --git a/q3map/map.c b/q3map/map.c
index e275e34..3de6ede 100755
--- a/q3map/map.c
+++ b/q3map/map.c
@@ -19,1233 +19,1233 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-// map.c
-
-#include "qbsp.h"
-
-
-int entitySourceBrushes; // to track editor brush numbers
-
-int numMapPatches;
-
-// undefine to make plane finding use linear sort
-#define USE_HASHING
-#define PLANE_HASHES 1024
-plane_t *planehash[PLANE_HASHES];
-
-plane_t mapplanes[MAX_MAP_PLANES];
-int nummapplanes;
-
-// as brushes and patches are read in, the shaders are stored out in order
-// here, so -onlytextures can just copy them out over the existing shaders
-// in the drawSurfaces
-char mapIndexedShaders[MAX_MAP_BRUSHSIDES][MAX_QPATH];
-int numMapIndexedShaders;
-
-vec3_t map_mins, map_maxs;
-
-entity_t *mapent;
-
-
-
-int c_boxbevels;
-int c_edgebevels;
-
-int c_areaportals;
-int c_detail;
-int c_structural;
-
-// brushes are parsed into a temporary array of sides,
-// which will have the bevels added and duplicates
-// removed before the final brush is allocated
-bspbrush_t *buildBrush;
-
-
-void TestExpandBrushes (void);
-void SetTerrainTextures( void );
-void ParseTerrain( void );
-
-
-/*
-=============================================================================
-
-PLANE FINDING
-
-=============================================================================
-*/
-
-
-/*
-================
-PlaneEqual
-================
-*/
-#define NORMAL_EPSILON 0.00001
-#define DIST_EPSILON 0.01
-qboolean PlaneEqual (plane_t *p, vec3_t normal, vec_t dist)
-{
-#if 1
- if (
- fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
- && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
- && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
- && fabs(p->dist - dist) < DIST_EPSILON )
- return qtrue;
-#else
- if (p->normal[0] == normal[0]
- && p->normal[1] == normal[1]
- && p->normal[2] == normal[2]
- && p->dist == dist)
- return qtrue;
-#endif
- return qfalse;
-}
-
-/*
-================
-AddPlaneToHash
-================
-*/
-void AddPlaneToHash (plane_t *p)
-{
- int hash;
-
- hash = (int)fabs(p->dist) / 8;
- hash &= (PLANE_HASHES-1);
-
- p->hash_chain = planehash[hash];
- planehash[hash] = p;
-}
-
-/*
-================
-CreateNewFloatPlane
-================
-*/
-int CreateNewFloatPlane (vec3_t normal, vec_t dist)
-{
- plane_t *p, temp;
-
- if (VectorLength(normal) < 0.5)
- {
- _printf( "FloatPlane: bad normal\n");
- return -1;
- }
-
- // create a new plane
- if (nummapplanes+2 > MAX_MAP_PLANES)
- Error ("MAX_MAP_PLANES");
-
- p = &mapplanes[nummapplanes];
- VectorCopy (normal, p->normal);
- p->dist = dist;
- p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
-
- VectorSubtract (vec3_origin, normal, (p+1)->normal);
- (p+1)->dist = -dist;
-
- nummapplanes += 2;
-
- // allways put axial planes facing positive first
- if (p->type < 3)
- {
- if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
- {
- // flip order
- temp = *p;
- *p = *(p+1);
- *(p+1) = temp;
-
- AddPlaneToHash (p);
- AddPlaneToHash (p+1);
- return nummapplanes - 1;
- }
- }
-
- AddPlaneToHash (p);
- AddPlaneToHash (p+1);
- return nummapplanes - 2;
-}
-
-/*
-==============
-SnapVector
-==============
-*/
-void SnapVector (vec3_t normal)
-{
- int i;
-
- for (i=0 ; i<3 ; i++)
- {
- if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
- {
- VectorClear (normal);
- normal[i] = 1;
- break;
- }
- if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
- {
- VectorClear (normal);
- normal[i] = -1;
- break;
- }
- }
-}
-
-/*
-==============
-SnapPlane
-==============
-*/
-void SnapPlane (vec3_t normal, vec_t *dist)
-{
- SnapVector (normal);
-
- if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
- *dist = Q_rint(*dist);
-}
-
-/*
-=============
-FindFloatPlane
-
-=============
-*/
-#ifndef USE_HASHING
-int FindFloatPlane (vec3_t normal, vec_t dist)
-{
- int i;
- plane_t *p;
-
- SnapPlane (normal, &dist);
- for (i=0, p=mapplanes ; i<nummapplanes ; i++, p++)
- {
- if (PlaneEqual (p, normal, dist))
- return i;
- }
-
- return CreateNewFloatPlane (normal, dist);
-}
-#else
-int FindFloatPlane (vec3_t normal, vec_t dist)
-{
- int i;
- plane_t *p;
- int hash, h;
-
- SnapPlane (normal, &dist);
- hash = (int)fabs(dist) / 8;
- hash &= (PLANE_HASHES-1);
-
- // search the border bins as well
- for (i=-1 ; i<=1 ; i++)
- {
- h = (hash+i)&(PLANE_HASHES-1);
- for (p = planehash[h] ; p ; p=p->hash_chain)
- {
- if (PlaneEqual (p, normal, dist))
- return p-mapplanes;
- }
- }
-
- return CreateNewFloatPlane (normal, dist);
-}
-#endif
-
-/*
-================
-MapPlaneFromPoints
-================
-*/
-int MapPlaneFromPoints (vec3_t p0, vec3_t p1, vec3_t p2) {
- vec3_t t1, t2, normal;
- vec_t dist;
-
- VectorSubtract (p0, p1, t1);
- VectorSubtract (p2, p1, t2);
- CrossProduct (t1, t2, normal);
- VectorNormalize (normal, normal);
-
- dist = DotProduct (p0, normal);
-
- return FindFloatPlane (normal, dist);
-}
-
-
-//====================================================================
-
-/*
-===========
-SetBrushContents
-
-The contents on all sides of a brush should be the same
-Sets contentsShader, contents, opaque, and detail
-===========
-*/
-void SetBrushContents( bspbrush_t *b ) {
- int contents, c2;
- side_t *s;
- int i;
- qboolean mixed;
- int allFlags;
-
- s = &b->sides[0];
- contents = s->contents;
- b->contentShader = s->shaderInfo;
- mixed = qfalse;
-
- allFlags = 0;
-
- for ( i=1 ; i<b->numsides ; i++, s++ ) {
- s = &b->sides[i];
-
- if ( !s->shaderInfo ) {
- continue;
- }
-
- c2 = s->contents;
- if (c2 != contents) {
- mixed = qtrue;
- }
-
- allFlags |= s->surfaceFlags;
- }
-
- if ( mixed ) {
- qprintf ("Entity %i, Brush %i: mixed face contents\n"
- , b->entitynum, b->brushnum);
- }
-
- if ( ( contents & CONTENTS_DETAIL ) && ( contents & CONTENTS_STRUCTURAL ) ) {
- _printf ("Entity %i, Brush %i: mixed CONTENTS_DETAIL and CONTENTS_STRUCTURAL\n"
- , num_entities-1, entitySourceBrushes );
- contents &= ~CONTENTS_DETAIL;
- }
-
- // the fulldetail flag will cause detail brushes to be
- // treated like normal brushes
- if ( fulldetail ) {
- contents &= ~CONTENTS_DETAIL;
- }
-
- // all translucent brushes that aren't specirically made structural will
- // be detail
- if ( ( contents & CONTENTS_TRANSLUCENT ) && !( contents & CONTENTS_STRUCTURAL ) ) {
- contents |= CONTENTS_DETAIL;
- }
-
- if ( contents & CONTENTS_DETAIL ) {
- c_detail++;
- b->detail = qtrue;
- } else {
- c_structural++;
- b->detail = qfalse;
- }
-
- if ( contents & CONTENTS_TRANSLUCENT ) {
- b->opaque = qfalse;
- } else {
- b->opaque = qtrue;
- }
-
- if ( contents & CONTENTS_AREAPORTAL ) {
- c_areaportals++;
- }
-
- b->contents = contents;
-}
-
-
-//============================================================================
-
-/*
-=================
-AddBrushBevels
-
-Adds any additional planes necessary to allow the brush being
-built to be expanded against axial bounding boxes
-=================
-*/
-void AddBrushBevels( void ) {
- int axis, dir;
- int i, order;
- side_t sidetemp;
- side_t *s;
- vec3_t normal;
- float dist;
-
- //
- // add the axial planes
- //
- order = 0;
- for (axis=0 ; axis <3 ; axis++)
- {
- for (dir=-1 ; dir <= 1 ; dir+=2, order++)
- {
- // see if the plane is allready present
- for ( i=0, s=buildBrush->sides ; i < buildBrush->numsides ; i++,s++ ) {
- if (mapplanes[s->planenum].normal[axis] == dir)
- break;
- }
-
- if (i == buildBrush->numsides )
- { // add a new side
- if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
- Error( "MAX_BUILD_SIDES" );
- }
- memset( s, 0, sizeof( *s ) );
- buildBrush->numsides++;
- VectorClear (normal);
- normal[axis] = dir;
- if (dir == 1)
- dist = buildBrush->maxs[axis];
- else
- dist = -buildBrush->mins[axis];
- s->planenum = FindFloatPlane (normal, dist);
- s->contents = buildBrush->sides[0].contents;
- s->bevel = qtrue;
- c_boxbevels++;
- }
-
- // if the plane is not in it canonical order, swap it
- if (i != order)
- {
- sidetemp = buildBrush->sides[order];
- buildBrush->sides[order] = buildBrush->sides[i];
- buildBrush->sides[i] = sidetemp;
- }
- }
- }
-
- //
- // add the edge bevels
- //
- if ( buildBrush->numsides == 6 ) {
- return; // pure axial
- } else {
- int j, k, l;
- float d;
- winding_t *w, *w2;
- side_t *s2;
- vec3_t vec, vec2;
-
- // test the non-axial plane edges
- // this code tends to cause some problems...
- for (i=6 ; i<buildBrush->numsides ; i++)
- {
- s = buildBrush->sides + i;
- w = s->winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- {
- k = (j+1)%w->numpoints;
- VectorSubtract (w->p[j], w->p[k], vec);
- if (VectorNormalize (vec, vec) < 0.5)
- continue;
- SnapVector (vec);
- for (k=0 ; k<3 ; k++)
- if ( vec[k] == -1 || vec[k] == 1)
- break; // axial
- if (k != 3)
- continue; // only test non-axial edges
-
- // try the six possible slanted axials from this edge
- for (axis=0 ; axis <3 ; axis++)
- {
- for (dir=-1 ; dir <= 1 ; dir+=2)
- {
- // construct a plane
- VectorClear (vec2);
- vec2[axis] = dir;
- CrossProduct (vec, vec2, normal);
- if (VectorNormalize (normal, normal) < 0.5)
- continue;
- dist = DotProduct (w->p[j], normal);
-
- // if all the points on all the sides are
- // behind this plane, it is a proper edge bevel
- for (k=0 ; k < buildBrush->numsides ; k++)
- {
- // if this plane has allready been used, skip it
- if (PlaneEqual (&mapplanes[buildBrush->sides[k].planenum]
- , normal, dist) )
- break;
-
- w2 = buildBrush->sides[k].winding;
- if (!w2)
- continue;
- for (l=0 ; l<w2->numpoints ; l++)
- {
- d = DotProduct (w2->p[l], normal) - dist;
- if (d > 0.1)
- break; // point in front
- }
- if (l != w2->numpoints)
- break;
- }
-
- if (k != buildBrush->numsides)
- continue; // wasn't part of the outer hull
- // add this plane
- if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
- Error( "MAX_BUILD_SIDES" );
- }
-
- s2 = &buildBrush->sides[buildBrush->numsides];
- buildBrush->numsides++;
- memset( s2, 0, sizeof( *s2 ) );
-
- s2->planenum = FindFloatPlane (normal, dist);
- s2->contents = buildBrush->sides[0].contents;
- s2->bevel = qtrue;
- c_edgebevels++;
- }
- }
- }
- }
- }
-}
-
-/*
-===============
-AddBackSides
-
-fog volumes need to have inside faces created
-===============
-*/
-void AddBackSides( void ) {
-/*
- bspbrush_t *b;
- int i, originalSides;
- side_t *s;
- side_t *newSide;
-
- b = buildBrush;
- originalSides = b->numsides;
- for ( i = 0 ; i < originalSides ; i++ ) {
- s = &b->sides[i];
- if ( !s->shaderInfo ) {
- continue;
- }
- if ( !(s->shaderInfo->contents & CONTENTS_FOG) ) {
- continue;
- }
-
- // duplicate the up-facing side
- if ( mapplanes[ s->planenum ].normal[2] == 1 ) {
- newSide = &b->sides[ b->numsides ];
- b->numsides++;
-
- *newSide = *s;
- newSide->backSide = qtrue;
- newSide->planenum = s->planenum ^ 1; // opposite side
- }
- }
-*/
-}
-
-/*
-===============
-FinishBrush
-
-Produces a final brush based on the buildBrush->sides array
-and links it to the current entity
-===============
-*/
-bspbrush_t *FinishBrush( void ) {
- bspbrush_t *b;
-
- // liquids may need to have extra sides created for back sides
- AddBackSides();
-
- // create windings for sides and bounds for brush
- if ( !CreateBrushWindings( buildBrush ) ) {
- // don't keep this brush
- return NULL;
- }
-
- // brushes that will not be visible at all are forced to be detail
- if ( buildBrush->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- {
- buildBrush->detail = qtrue;
- c_detail++;
- }
-
- //
- // origin brushes are removed, but they set
- // the rotation origin for the rest of the brushes
- // in the entity. After the entire entity is parsed,
- // the planenums and texinfos will be adjusted for
- // the origin brush
- //
- if ( buildBrush->contents & CONTENTS_ORIGIN )
- {
- char string[32];
- vec3_t origin;
-
- if (num_entities == 1) {
- _printf ("Entity %i, Brush %i: origin brushes not allowed in world\n"
- , num_entities - 1, entitySourceBrushes);
- return NULL;
- }
-
- VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
- VectorScale (origin, 0.5, origin);
-
- sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
- SetKeyValue (&entities[num_entities - 1], "origin", string);
-
- VectorCopy (origin, entities[num_entities - 1].origin);
-
- // don't keep this brush
- return NULL;
- }
-
- if ( buildBrush->contents & CONTENTS_AREAPORTAL ) {
- if (num_entities != 1) {
- _printf ("Entity %i, Brush %i: areaportals only allowed in world\n"
- , num_entities - 1, entitySourceBrushes);
- return NULL;
- }
- }
-
- AddBrushBevels ();
-
- // keep it
- b = CopyBrush( buildBrush );
-
- b->entitynum = num_entities-1;
- b->brushnum = entitySourceBrushes;
-
- b->original = b;
-
- b->next = mapent->brushes;
- mapent->brushes = b;
-
- return b;
-}
-
-//======================================================================
-
-
-/*
-==================
-textureAxisFromPlane
-==================
-*/
-vec3_t baseaxis[18] =
-{
-{0,0,1}, {1,0,0}, {0,-1,0}, // floor
-{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
-{1,0,0}, {0,1,0}, {0,0,-1}, // west wall
-{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
-{0,1,0}, {1,0,0}, {0,0,-1}, // south wall
-{0,-1,0}, {1,0,0}, {0,0,-1} // north wall
-};
-
-void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
-{
- int bestaxis;
- vec_t dot,best;
- int i;
-
- best = 0;
- bestaxis = 0;
-
- for (i=0 ; i<6 ; i++)
- {
- dot = DotProduct (pln->normal, baseaxis[i*3]);
- if (dot > best)
- {
- best = dot;
- bestaxis = i;
- }
- }
-
- VectorCopy (baseaxis[bestaxis*3+1], xv);
- VectorCopy (baseaxis[bestaxis*3+2], yv);
-}
-
-
-
-/*
-=================
-QuakeTextureVecs
-
-Creates world-to-texture mapping vecs for crappy quake plane arrangements
-=================
-*/
-void QuakeTextureVecs( plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2],
- vec_t mappingVecs[2][4] ) {
-
- vec3_t vecs[2];
- int sv, tv;
- vec_t ang, sinv, cosv;
- vec_t ns, nt;
- int i, j;
-
- TextureAxisFromPlane(plane, vecs[0], vecs[1]);
-
- if (!scale[0])
- scale[0] = 1;
- if (!scale[1])
- scale[1] = 1;
-
- // rotate axis
- if (rotate == 0)
- { sinv = 0 ; cosv = 1; }
- else if (rotate == 90)
- { sinv = 1 ; cosv = 0; }
- else if (rotate == 180)
- { sinv = 0 ; cosv = -1; }
- else if (rotate == 270)
- { sinv = -1 ; cosv = 0; }
- else
- {
- ang = rotate / 180 * Q_PI;
- sinv = sin(ang);
- cosv = cos(ang);
- }
-
- if (vecs[0][0])
- sv = 0;
- else if (vecs[0][1])
- sv = 1;
- else
- sv = 2;
-
- if (vecs[1][0])
- tv = 0;
- else if (vecs[1][1])
- tv = 1;
- else
- tv = 2;
-
- for (i=0 ; i<2 ; i++) {
- ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
- nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
- vecs[i][sv] = ns;
- vecs[i][tv] = nt;
- }
-
- for (i=0 ; i<2 ; i++)
- for (j=0 ; j<3 ; j++)
- mappingVecs[i][j] = vecs[i][j] / scale[i];
-
- mappingVecs[0][3] = shift[0];
- mappingVecs[1][3] = shift[1];
-}
-
-//======================================================================
-
-/*
-=================
-ParseRawBrush
-
-Just parses the sides into buildBrush->sides[], nothing else.
-no validation, back plane removal, etc.
-
-Timo - 08/26/99
-added brush epairs parsing ( ignoring actually )
-Timo - 08/04/99
-added exclusive brush primitive parsing
-Timo - 08/08/99
-support for old brush format back in
-NOTE : it would be "cleaner" to have seperate functions to parse between old and new brushes
-=================
-*/
-void ParseRawBrush( ) {
- side_t *side;
- vec3_t planepts[3];
- int planenum;
- shaderInfo_t *si;
- // old brushes
- vec_t shift[2];
- vec_t rotate;
- vec_t scale[2];
- char name[MAX_QPATH];
- char shader[MAX_QPATH];
- int flags;
-
- buildBrush->numsides = 0;
- buildBrush->detail = qfalse;
-
- if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
- MatchToken( "{" );
-
- do
- {
- if (!GetToken (qtrue))
- break;
- if (!strcmp (token, "}") )
- break;
- //Timo : brush primitive : here we may have to jump over brush epairs ( only used in editor )
- if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
- {
- do
- {
- if (strcmp (token, "(") )
- GetToken( qfalse );
- else
- break;
- GetToken( qtrue );
- } while (1);
- }
- UnGetToken();
-
- if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
- Error( "MAX_BUILD_SIDES" );
- }
-
- side = &buildBrush->sides[ buildBrush->numsides ];
- memset( side, 0, sizeof( *side ) );
- buildBrush->numsides++;
-
- // read the three point plane definition
- Parse1DMatrix( 3, planepts[0] );
- Parse1DMatrix( 3, planepts[1] );
- Parse1DMatrix( 3, planepts[2] );
-
- if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
- // read the texture matrix
- Parse2DMatrix( 2, 3, (float *)side->texMat );
-
- // read the texturedef
- GetToken (qfalse);
- strcpy (name, token);
-
- // save the shader name for retexturing
- if ( numMapIndexedShaders == MAX_MAP_BRUSHSIDES ) {
- Error( "MAX_MAP_BRUSHSIDES" );
- }
- strcpy( mapIndexedShaders[numMapIndexedShaders], name );
- numMapIndexedShaders++;
-
- if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
- {
- GetToken (qfalse);
- shift[0] = atoi(token);
- GetToken (qfalse);
- shift[1] = atoi(token);
- GetToken (qfalse);
- rotate = atoi(token);
- GetToken (qfalse);
- scale[0] = atof(token);
- GetToken (qfalse);
- scale[1] = atof(token);
- }
-
- // find default flags and values
- sprintf( shader, "textures/%s", name );
- si = ShaderInfoForShader( shader );
- side->shaderInfo = si;
- side->surfaceFlags = si->surfaceFlags;
- side->value = si->value;
- side->contents = si->contents;
-
- // allow override of default flags and values
- // in Q3, the only thing you can override is DETAIL
- if (TokenAvailable())
- {
- GetToken (qfalse);
-// side->contents = atoi(token);
- flags = atoi(token);
- if ( flags & CONTENTS_DETAIL ) {
- side->contents |= CONTENTS_DETAIL;
- }
-
- GetToken (qfalse);
-// td.flags = atoi(token);
-
- GetToken (qfalse);
-// td.value = atoi(token);
- }
-
-
- // find the plane number
- planenum = MapPlaneFromPoints (planepts[0], planepts[1], planepts[2]);
- side->planenum = planenum;
-
- if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
- // get the texture mapping for this texturedef / plane combination
- QuakeTextureVecs( &mapplanes[planenum], shift, rotate, scale, side->vecs );
-
- } while (1);
-
- if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
- {
- UnGetToken();
- MatchToken( "}" );
- MatchToken( "}" );
- }
-}
-
-/*
-=================
-RemoveDuplicateBrushPlanes
-
-Returns false if the brush has a mirrored set of planes,
-meaning it encloses no volume.
-Also removes planes without any normal
-=================
-*/
-qboolean RemoveDuplicateBrushPlanes( bspbrush_t * b ) {
- int i, j, k;
- side_t *sides;
-
- sides = b->sides;
-
- for ( i = 1 ; i < b->numsides ; i++ ) {
-
- // check for a degenerate plane
- if ( sides[i].planenum == -1) {
- _printf ("Entity %i, Brush %i: degenerate plane\n"
- , b->entitynum, b->brushnum);
- // remove it
- for ( k = i + 1 ; k < b->numsides ; k++ ) {
- sides[k-1] = sides[k];
- }
- b->numsides--;
- i--;
- continue;
- }
-
- // check for duplication and mirroring
- for ( j = 0 ; j < i ; j++ ) {
- if ( sides[i].planenum == sides[j].planenum ) {
- _printf ("Entity %i, Brush %i: duplicate plane\n"
- , b->entitynum, b->brushnum);
- // remove the second duplicate
- for ( k = i + 1 ; k < b->numsides ; k++ ) {
- sides[k-1] = sides[k];
- }
- b->numsides--;
- i--;
- break;
- }
-
- if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
- // mirror plane, brush is invalid
- _printf ("Entity %i, Brush %i: mirrored plane\n"
- , b->entitynum, b->brushnum);
- return qfalse;
- }
- }
- }
- return qtrue;
-}
-
-
-/*
-=================
-ParseBrush
-
- qboolean parameter to true -> parse new brush primitive format ( else use old format )
-=================
-*/
-void ParseBrush (void) {
- bspbrush_t *b;
-
- ParseRawBrush();
-
- buildBrush->portalareas[0] = -1;
- buildBrush->portalareas[1] = -1;
- buildBrush->entitynum = num_entities-1;
- buildBrush->brushnum = entitySourceBrushes;
-
- // if there are mirrored planes, the entire brush is invalid
- if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
- return;
- }
-
- // get the content for the entire brush
- SetBrushContents( buildBrush );
-
- // allow detail brushes to be removed
- if (nodetail && (buildBrush->contents & CONTENTS_DETAIL) ) {
- FreeBrush( buildBrush );
- return;
- }
-
- // allow water brushes to be removed
- if (nowater && (buildBrush->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) ) {
- FreeBrush( buildBrush );
- return;
- }
-
- b = FinishBrush( );
- if ( !b ) {
- return;
- }
-}
-
-
-/*
-================
-MoveBrushesToWorld
-
-Takes all of the brushes from the current entity and
-adds them to the world's brush list.
-
-Used by func_group
-================
-*/
-void MoveBrushesToWorld (entity_t *mapent) {
- bspbrush_t *b, *next;
- parseMesh_t *pm;
-
- // move brushes
- for ( b = mapent->brushes ; b ; b = next ) {
- next = b->next;
-
- b->next = entities[0].brushes;
- entities[0].brushes = b;
- }
- mapent->brushes = NULL;
-
- // move patches
- if ( mapent->patches ) {
-
- for ( pm = mapent->patches ; pm->next ; pm = pm->next ) {
- }
-
- pm->next = entities[0].patches;
- entities[0].patches = mapent->patches;
-
- mapent->patches = NULL;
- }
-}
-
-
-/*
-================
-AdjustBrushesForOrigin
-================
-*/
-void AdjustBrushesForOrigin( entity_t *ent ) {
- bspbrush_t *b;
- int i;
- side_t *s;
- vec_t newdist;
- parseMesh_t *p;
-
- for ( b = ent->brushes ; b ; b = b->next ) {
- for (i=0 ; i<b->numsides ; i++) {
- s = &b->sides[i];
- newdist = mapplanes[s->planenum].dist -
- DotProduct (mapplanes[s->planenum].normal, ent->origin);
- s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
- }
- CreateBrushWindings(b);
- }
-
- for ( p = ent->patches ; p ; p = p->next ) {
- for ( i = 0 ; i < p->mesh.width*p->mesh.height ; i++ ) {
- VectorSubtract( p->mesh.verts[i].xyz, ent->origin, p->mesh.verts[i].xyz );
- }
- }
-
-}
-
-/*
-================
-ParseMapEntity
-================
-*/
-qboolean ParseMapEntity (void) {
- epair_t *e;
-
- if (!GetToken (qtrue))
- return qfalse;
-
- if (strcmp (token, "{") )
- {
- Error ("ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...", token, scriptline, entities[num_entities].origin[0], entities[num_entities].origin[1], entities[num_entities].origin[2]);
- }
-
- if (num_entities == MAX_MAP_ENTITIES)
- Error ("num_entities == MAX_MAP_ENTITIES");
-
- entitySourceBrushes = 0;
-
- mapent = &entities[num_entities];
- num_entities++;
- memset (mapent, 0, sizeof(*mapent));
-
- do
- {
- if (!GetToken (qtrue))
- Error ("ParseEntity: EOF without closing brace");
- if (!strcmp (token, "}") )
- break;
-
- if (!strcmp (token, "{") ) {
- // parse a brush or patch
- if (!GetToken (qtrue))
- break;
- if ( !strcmp( token, "patchDef2" ) ) {
- numMapPatches++;
- ParsePatch();
- } else if ( !strcmp( token, "terrainDef" ) ) {
- ParseTerrain();
- } else if ( !strcmp( token, "brushDef" ) ) {
- if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
- Error("old brush format not allowed in new brush format map");
- g_bBrushPrimit=BPRIMIT_NEWBRUSHES;
- // parse brush primitive
- ParseBrush();
- }
- else
- {
- if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
- Error("new brush format not allowed in old brush format map");
- g_bBrushPrimit=BPRIMIT_OLDBRUSHES;
- // parse old brush format
- UnGetToken();
- ParseBrush();
- }
- entitySourceBrushes++;
- }
- else
- {
- // parse a key / value pair
- e = ParseEpair ();
- e->next = mapent->epairs;
- mapent->epairs = e;
- }
- } while (1);
-
- GetVectorForKey (mapent, "origin", mapent->origin);
-
- //
- // if there was an origin brush, offset all of the planes and texinfo
- // for all the brushes in the entity
- if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) {
- AdjustBrushesForOrigin( mapent );
- }
-
- // group_info entities are just for editor grouping
- // ignored
- // FIXME: leak!
- if (!strcmp("group_info", ValueForKey (mapent, "classname")))
- {
- num_entities--;
- return qtrue;
- }
-
- // group entities are just for editor convenience
- // toss all brushes into the world entity
- if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
- {
- if ( !strcmp ("1", ValueForKey (mapent, "terrain"))) {
- SetTerrainTextures();
- }
- MoveBrushesToWorld (mapent);
- num_entities--;
- return qtrue;
- }
-
- return qtrue;
-}
-
-//===================================================================
-
-
-/*
-================
-LoadMapFile
-================
-*/
-void LoadMapFile (char *filename) {
- bspbrush_t *b;
-
- qprintf ("--- LoadMapFile ---\n");
- _printf ("Loading map file %s\n", filename);
-
- LoadScriptFile (filename);
-
- num_entities = 0;
- numMapDrawSurfs = 0;
- c_detail = 0;
-
- g_bBrushPrimit = BPRIMIT_UNDEFINED;
-
- // allocate a very large temporary brush for building
- // the brushes as they are loaded
- buildBrush = AllocBrush( MAX_BUILD_SIDES );
-
- while (ParseMapEntity ())
- {
- }
-
- ClearBounds (map_mins, map_maxs);
- for ( b = entities[0].brushes ; b ; b=b->next ) {
- AddPointToBounds( b->mins, map_mins, map_maxs );
- AddPointToBounds( b->maxs, map_mins, map_maxs );
- }
-
- qprintf ("%5i total world brushes\n", CountBrushList( entities[0].brushes ) );
- qprintf ("%5i detail brushes\n", c_detail );
- qprintf ("%5i patches\n", numMapPatches);
- qprintf ("%5i boxbevels\n", c_boxbevels);
- qprintf ("%5i edgebevels\n", c_edgebevels);
- qprintf ("%5i entities\n", num_entities);
- qprintf ("%5i planes\n", nummapplanes);
- qprintf ("%5i areaportals\n", c_areaportals);
- qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
- map_maxs[0],map_maxs[1],map_maxs[2]);
-
- if ( fakemap ) {
- WriteBspBrushMap ("fakemap.map", entities[0].brushes );
- }
-
- if ( testExpand ) {
- TestExpandBrushes ();
- }
-}
-
-
-//====================================================================
-
-
-/*
-================
-TestExpandBrushes
-
-Expands all the brush planes and saves a new map out to
-allow visual inspection of the clipping bevels
-================
-*/
-void TestExpandBrushes( void ) {
- side_t *s;
- int i, j;
- bspbrush_t *brush, *list, *copy;
- vec_t dist;
- plane_t *plane;
-
- list = NULL;
-
- for ( brush = entities[0].brushes ; brush ; brush = brush->next ) {
- copy = CopyBrush( brush );
- copy->next = list;
- list = copy;
-
- // expand all the planes
- for ( i=0 ; i<brush->numsides ; i++ ) {
- s = brush->sides + i;
- plane = &mapplanes[s->planenum];
- dist = plane->dist;
- for (j=0 ; j<3 ; j++) {
- dist += fabs( 16 * plane->normal[j] );
- }
- s->planenum = FindFloatPlane( plane->normal, dist );
- }
-
- }
-
- WriteBspBrushMap ( "expanded.map", entities[0].brushes );
-
- Error ("can't proceed after expanding brushes");
-}
+// map.c
+
+#include "qbsp.h"
+
+
+int entitySourceBrushes; // to track editor brush numbers
+
+int numMapPatches;
+
+// undefine to make plane finding use linear sort
+#define USE_HASHING
+#define PLANE_HASHES 1024
+plane_t *planehash[PLANE_HASHES];
+
+plane_t mapplanes[MAX_MAP_PLANES];
+int nummapplanes;
+
+// as brushes and patches are read in, the shaders are stored out in order
+// here, so -onlytextures can just copy them out over the existing shaders
+// in the drawSurfaces
+char mapIndexedShaders[MAX_MAP_BRUSHSIDES][MAX_QPATH];
+int numMapIndexedShaders;
+
+vec3_t map_mins, map_maxs;
+
+entity_t *mapent;
+
+
+
+int c_boxbevels;
+int c_edgebevels;
+
+int c_areaportals;
+int c_detail;
+int c_structural;
+
+// brushes are parsed into a temporary array of sides,
+// which will have the bevels added and duplicates
+// removed before the final brush is allocated
+bspbrush_t *buildBrush;
+
+
+void TestExpandBrushes (void);
+void SetTerrainTextures( void );
+void ParseTerrain( void );
+
+
+/*
+=============================================================================
+
+PLANE FINDING
+
+=============================================================================
+*/
+
+
+/*
+================
+PlaneEqual
+================
+*/
+#define NORMAL_EPSILON 0.00001
+#define DIST_EPSILON 0.01
+qboolean PlaneEqual (plane_t *p, vec3_t normal, vec_t dist)
+{
+#if 1
+ if (
+ fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
+ && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
+ && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
+ && fabs(p->dist - dist) < DIST_EPSILON )
+ return qtrue;
+#else
+ if (p->normal[0] == normal[0]
+ && p->normal[1] == normal[1]
+ && p->normal[2] == normal[2]
+ && p->dist == dist)
+ return qtrue;
+#endif
+ return qfalse;
+}
+
+/*
+================
+AddPlaneToHash
+================
+*/
+void AddPlaneToHash (plane_t *p)
+{
+ int hash;
+
+ hash = (int)fabs(p->dist) / 8;
+ hash &= (PLANE_HASHES-1);
+
+ p->hash_chain = planehash[hash];
+ planehash[hash] = p;
+}
+
+/*
+================
+CreateNewFloatPlane
+================
+*/
+int CreateNewFloatPlane (vec3_t normal, vec_t dist)
+{
+ plane_t *p, temp;
+
+ if (VectorLength(normal) < 0.5)
+ {
+ _printf( "FloatPlane: bad normal\n");
+ return -1;
+ }
+
+ // create a new plane
+ if (nummapplanes+2 > MAX_MAP_PLANES)
+ Error ("MAX_MAP_PLANES");
+
+ p = &mapplanes[nummapplanes];
+ VectorCopy (normal, p->normal);
+ p->dist = dist;
+ p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
+
+ VectorSubtract (vec3_origin, normal, (p+1)->normal);
+ (p+1)->dist = -dist;
+
+ nummapplanes += 2;
+
+ // allways put axial planes facing positive first
+ if (p->type < 3)
+ {
+ if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
+ {
+ // flip order
+ temp = *p;
+ *p = *(p+1);
+ *(p+1) = temp;
+
+ AddPlaneToHash (p);
+ AddPlaneToHash (p+1);
+ return nummapplanes - 1;
+ }
+ }
+
+ AddPlaneToHash (p);
+ AddPlaneToHash (p+1);
+ return nummapplanes - 2;
+}
+
+/*
+==============
+SnapVector
+==============
+*/
+void SnapVector (vec3_t normal)
+{
+ int i;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
+ {
+ VectorClear (normal);
+ normal[i] = 1;
+ break;
+ }
+ if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
+ {
+ VectorClear (normal);
+ normal[i] = -1;
+ break;
+ }
+ }
+}
+
+/*
+==============
+SnapPlane
+==============
+*/
+void SnapPlane (vec3_t normal, vec_t *dist)
+{
+ SnapVector (normal);
+
+ if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
+ *dist = Q_rint(*dist);
+}
+
+/*
+=============
+FindFloatPlane
+
+=============
+*/
+#ifndef USE_HASHING
+int FindFloatPlane (vec3_t normal, vec_t dist)
+{
+ int i;
+ plane_t *p;
+
+ SnapPlane (normal, &dist);
+ for (i=0, p=mapplanes ; i<nummapplanes ; i++, p++)
+ {
+ if (PlaneEqual (p, normal, dist))
+ return i;
+ }
+
+ return CreateNewFloatPlane (normal, dist);
+}
+#else
+int FindFloatPlane (vec3_t normal, vec_t dist)
+{
+ int i;
+ plane_t *p;
+ int hash, h;
+
+ SnapPlane (normal, &dist);
+ hash = (int)fabs(dist) / 8;
+ hash &= (PLANE_HASHES-1);
+
+ // search the border bins as well
+ for (i=-1 ; i<=1 ; i++)
+ {
+ h = (hash+i)&(PLANE_HASHES-1);
+ for (p = planehash[h] ; p ; p=p->hash_chain)
+ {
+ if (PlaneEqual (p, normal, dist))
+ return p-mapplanes;
+ }
+ }
+
+ return CreateNewFloatPlane (normal, dist);
+}
+#endif
+
+/*
+================
+MapPlaneFromPoints
+================
+*/
+int MapPlaneFromPoints (vec3_t p0, vec3_t p1, vec3_t p2) {
+ vec3_t t1, t2, normal;
+ vec_t dist;
+
+ VectorSubtract (p0, p1, t1);
+ VectorSubtract (p2, p1, t2);
+ CrossProduct (t1, t2, normal);
+ VectorNormalize (normal, normal);
+
+ dist = DotProduct (p0, normal);
+
+ return FindFloatPlane (normal, dist);
+}
+
+
+//====================================================================
+
+/*
+===========
+SetBrushContents
+
+The contents on all sides of a brush should be the same
+Sets contentsShader, contents, opaque, and detail
+===========
+*/
+void SetBrushContents( bspbrush_t *b ) {
+ int contents, c2;
+ side_t *s;
+ int i;
+ qboolean mixed;
+ int allFlags;
+
+ s = &b->sides[0];
+ contents = s->contents;
+ b->contentShader = s->shaderInfo;
+ mixed = qfalse;
+
+ allFlags = 0;
+
+ for ( i=1 ; i<b->numsides ; i++, s++ ) {
+ s = &b->sides[i];
+
+ if ( !s->shaderInfo ) {
+ continue;
+ }
+
+ c2 = s->contents;
+ if (c2 != contents) {
+ mixed = qtrue;
+ }
+
+ allFlags |= s->surfaceFlags;
+ }
+
+ if ( mixed ) {
+ qprintf ("Entity %i, Brush %i: mixed face contents\n"
+ , b->entitynum, b->brushnum);
+ }
+
+ if ( ( contents & CONTENTS_DETAIL ) && ( contents & CONTENTS_STRUCTURAL ) ) {
+ _printf ("Entity %i, Brush %i: mixed CONTENTS_DETAIL and CONTENTS_STRUCTURAL\n"
+ , num_entities-1, entitySourceBrushes );
+ contents &= ~CONTENTS_DETAIL;
+ }
+
+ // the fulldetail flag will cause detail brushes to be
+ // treated like normal brushes
+ if ( fulldetail ) {
+ contents &= ~CONTENTS_DETAIL;
+ }
+
+ // all translucent brushes that aren't specirically made structural will
+ // be detail
+ if ( ( contents & CONTENTS_TRANSLUCENT ) && !( contents & CONTENTS_STRUCTURAL ) ) {
+ contents |= CONTENTS_DETAIL;
+ }
+
+ if ( contents & CONTENTS_DETAIL ) {
+ c_detail++;
+ b->detail = qtrue;
+ } else {
+ c_structural++;
+ b->detail = qfalse;
+ }
+
+ if ( contents & CONTENTS_TRANSLUCENT ) {
+ b->opaque = qfalse;
+ } else {
+ b->opaque = qtrue;
+ }
+
+ if ( contents & CONTENTS_AREAPORTAL ) {
+ c_areaportals++;
+ }
+
+ b->contents = contents;
+}
+
+
+//============================================================================
+
+/*
+=================
+AddBrushBevels
+
+Adds any additional planes necessary to allow the brush being
+built to be expanded against axial bounding boxes
+=================
+*/
+void AddBrushBevels( void ) {
+ int axis, dir;
+ int i, order;
+ side_t sidetemp;
+ side_t *s;
+ vec3_t normal;
+ float dist;
+
+ //
+ // add the axial planes
+ //
+ order = 0;
+ for (axis=0 ; axis <3 ; axis++)
+ {
+ for (dir=-1 ; dir <= 1 ; dir+=2, order++)
+ {
+ // see if the plane is allready present
+ for ( i=0, s=buildBrush->sides ; i < buildBrush->numsides ; i++,s++ ) {
+ if (mapplanes[s->planenum].normal[axis] == dir)
+ break;
+ }
+
+ if (i == buildBrush->numsides )
+ { // add a new side
+ if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
+ Error( "MAX_BUILD_SIDES" );
+ }
+ memset( s, 0, sizeof( *s ) );
+ buildBrush->numsides++;
+ VectorClear (normal);
+ normal[axis] = dir;
+ if (dir == 1)
+ dist = buildBrush->maxs[axis];
+ else
+ dist = -buildBrush->mins[axis];
+ s->planenum = FindFloatPlane (normal, dist);
+ s->contents = buildBrush->sides[0].contents;
+ s->bevel = qtrue;
+ c_boxbevels++;
+ }
+
+ // if the plane is not in it canonical order, swap it
+ if (i != order)
+ {
+ sidetemp = buildBrush->sides[order];
+ buildBrush->sides[order] = buildBrush->sides[i];
+ buildBrush->sides[i] = sidetemp;
+ }
+ }
+ }
+
+ //
+ // add the edge bevels
+ //
+ if ( buildBrush->numsides == 6 ) {
+ return; // pure axial
+ } else {
+ int j, k, l;
+ float d;
+ winding_t *w, *w2;
+ side_t *s2;
+ vec3_t vec, vec2;
+
+ // test the non-axial plane edges
+ // this code tends to cause some problems...
+ for (i=6 ; i<buildBrush->numsides ; i++)
+ {
+ s = buildBrush->sides + i;
+ w = s->winding;
+ if (!w)
+ continue;
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ k = (j+1)%w->numpoints;
+ VectorSubtract (w->p[j], w->p[k], vec);
+ if (VectorNormalize (vec, vec) < 0.5)
+ continue;
+ SnapVector (vec);
+ for (k=0 ; k<3 ; k++)
+ if ( vec[k] == -1 || vec[k] == 1)
+ break; // axial
+ if (k != 3)
+ continue; // only test non-axial edges
+
+ // try the six possible slanted axials from this edge
+ for (axis=0 ; axis <3 ; axis++)
+ {
+ for (dir=-1 ; dir <= 1 ; dir+=2)
+ {
+ // construct a plane
+ VectorClear (vec2);
+ vec2[axis] = dir;
+ CrossProduct (vec, vec2, normal);
+ if (VectorNormalize (normal, normal) < 0.5)
+ continue;
+ dist = DotProduct (w->p[j], normal);
+
+ // if all the points on all the sides are
+ // behind this plane, it is a proper edge bevel
+ for (k=0 ; k < buildBrush->numsides ; k++)
+ {
+ // if this plane has allready been used, skip it
+ if (PlaneEqual (&mapplanes[buildBrush->sides[k].planenum]
+ , normal, dist) )
+ break;
+
+ w2 = buildBrush->sides[k].winding;
+ if (!w2)
+ continue;
+ for (l=0 ; l<w2->numpoints ; l++)
+ {
+ d = DotProduct (w2->p[l], normal) - dist;
+ if (d > 0.1)
+ break; // point in front
+ }
+ if (l != w2->numpoints)
+ break;
+ }
+
+ if (k != buildBrush->numsides)
+ continue; // wasn't part of the outer hull
+ // add this plane
+ if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
+ Error( "MAX_BUILD_SIDES" );
+ }
+
+ s2 = &buildBrush->sides[buildBrush->numsides];
+ buildBrush->numsides++;
+ memset( s2, 0, sizeof( *s2 ) );
+
+ s2->planenum = FindFloatPlane (normal, dist);
+ s2->contents = buildBrush->sides[0].contents;
+ s2->bevel = qtrue;
+ c_edgebevels++;
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+===============
+AddBackSides
+
+fog volumes need to have inside faces created
+===============
+*/
+void AddBackSides( void ) {
+/*
+ bspbrush_t *b;
+ int i, originalSides;
+ side_t *s;
+ side_t *newSide;
+
+ b = buildBrush;
+ originalSides = b->numsides;
+ for ( i = 0 ; i < originalSides ; i++ ) {
+ s = &b->sides[i];
+ if ( !s->shaderInfo ) {
+ continue;
+ }
+ if ( !(s->shaderInfo->contents & CONTENTS_FOG) ) {
+ continue;
+ }
+
+ // duplicate the up-facing side
+ if ( mapplanes[ s->planenum ].normal[2] == 1 ) {
+ newSide = &b->sides[ b->numsides ];
+ b->numsides++;
+
+ *newSide = *s;
+ newSide->backSide = qtrue;
+ newSide->planenum = s->planenum ^ 1; // opposite side
+ }
+ }
+*/
+}
+
+/*
+===============
+FinishBrush
+
+Produces a final brush based on the buildBrush->sides array
+and links it to the current entity
+===============
+*/
+bspbrush_t *FinishBrush( void ) {
+ bspbrush_t *b;
+
+ // liquids may need to have extra sides created for back sides
+ AddBackSides();
+
+ // create windings for sides and bounds for brush
+ if ( !CreateBrushWindings( buildBrush ) ) {
+ // don't keep this brush
+ return NULL;
+ }
+
+ // brushes that will not be visible at all are forced to be detail
+ if ( buildBrush->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ {
+ buildBrush->detail = qtrue;
+ c_detail++;
+ }
+
+ //
+ // origin brushes are removed, but they set
+ // the rotation origin for the rest of the brushes
+ // in the entity. After the entire entity is parsed,
+ // the planenums and texinfos will be adjusted for
+ // the origin brush
+ //
+ if ( buildBrush->contents & CONTENTS_ORIGIN )
+ {
+ char string[32];
+ vec3_t origin;
+
+ if (num_entities == 1) {
+ _printf ("Entity %i, Brush %i: origin brushes not allowed in world\n"
+ , num_entities - 1, entitySourceBrushes);
+ return NULL;
+ }
+
+ VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
+ VectorScale (origin, 0.5, origin);
+
+ sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
+ SetKeyValue (&entities[num_entities - 1], "origin", string);
+
+ VectorCopy (origin, entities[num_entities - 1].origin);
+
+ // don't keep this brush
+ return NULL;
+ }
+
+ if ( buildBrush->contents & CONTENTS_AREAPORTAL ) {
+ if (num_entities != 1) {
+ _printf ("Entity %i, Brush %i: areaportals only allowed in world\n"
+ , num_entities - 1, entitySourceBrushes);
+ return NULL;
+ }
+ }
+
+ AddBrushBevels ();
+
+ // keep it
+ b = CopyBrush( buildBrush );
+
+ b->entitynum = num_entities-1;
+ b->brushnum = entitySourceBrushes;
+
+ b->original = b;
+
+ b->next = mapent->brushes;
+ mapent->brushes = b;
+
+ return b;
+}
+
+//======================================================================
+
+
+/*
+==================
+textureAxisFromPlane
+==================
+*/
+vec3_t baseaxis[18] =
+{
+{0,0,1}, {1,0,0}, {0,-1,0}, // floor
+{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
+{1,0,0}, {0,1,0}, {0,0,-1}, // west wall
+{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
+{0,1,0}, {1,0,0}, {0,0,-1}, // south wall
+{0,-1,0}, {1,0,0}, {0,0,-1} // north wall
+};
+
+void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
+{
+ int bestaxis;
+ vec_t dot,best;
+ int i;
+
+ best = 0;
+ bestaxis = 0;
+
+ for (i=0 ; i<6 ; i++)
+ {
+ dot = DotProduct (pln->normal, baseaxis[i*3]);
+ if (dot > best)
+ {
+ best = dot;
+ bestaxis = i;
+ }
+ }
+
+ VectorCopy (baseaxis[bestaxis*3+1], xv);
+ VectorCopy (baseaxis[bestaxis*3+2], yv);
+}
+
+
+
+/*
+=================
+QuakeTextureVecs
+
+Creates world-to-texture mapping vecs for crappy quake plane arrangements
+=================
+*/
+void QuakeTextureVecs( plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2],
+ vec_t mappingVecs[2][4] ) {
+
+ vec3_t vecs[2];
+ int sv, tv;
+ vec_t ang, sinv, cosv;
+ vec_t ns, nt;
+ int i, j;
+
+ TextureAxisFromPlane(plane, vecs[0], vecs[1]);
+
+ if (!scale[0])
+ scale[0] = 1;
+ if (!scale[1])
+ scale[1] = 1;
+
+ // rotate axis
+ if (rotate == 0)
+ { sinv = 0 ; cosv = 1; }
+ else if (rotate == 90)
+ { sinv = 1 ; cosv = 0; }
+ else if (rotate == 180)
+ { sinv = 0 ; cosv = -1; }
+ else if (rotate == 270)
+ { sinv = -1 ; cosv = 0; }
+ else
+ {
+ ang = rotate / 180 * Q_PI;
+ sinv = sin(ang);
+ cosv = cos(ang);
+ }
+
+ if (vecs[0][0])
+ sv = 0;
+ else if (vecs[0][1])
+ sv = 1;
+ else
+ sv = 2;
+
+ if (vecs[1][0])
+ tv = 0;
+ else if (vecs[1][1])
+ tv = 1;
+ else
+ tv = 2;
+
+ for (i=0 ; i<2 ; i++) {
+ ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
+ nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
+ vecs[i][sv] = ns;
+ vecs[i][tv] = nt;
+ }
+
+ for (i=0 ; i<2 ; i++)
+ for (j=0 ; j<3 ; j++)
+ mappingVecs[i][j] = vecs[i][j] / scale[i];
+
+ mappingVecs[0][3] = shift[0];
+ mappingVecs[1][3] = shift[1];
+}
+
+//======================================================================
+
+/*
+=================
+ParseRawBrush
+
+Just parses the sides into buildBrush->sides[], nothing else.
+no validation, back plane removal, etc.
+
+Timo - 08/26/99
+added brush epairs parsing ( ignoring actually )
+Timo - 08/04/99
+added exclusive brush primitive parsing
+Timo - 08/08/99
+support for old brush format back in
+NOTE : it would be "cleaner" to have seperate functions to parse between old and new brushes
+=================
+*/
+void ParseRawBrush( ) {
+ side_t *side;
+ vec3_t planepts[3];
+ int planenum;
+ shaderInfo_t *si;
+ // old brushes
+ vec_t shift[2];
+ vec_t rotate;
+ vec_t scale[2];
+ char name[MAX_QPATH];
+ char shader[MAX_QPATH];
+ int flags;
+
+ buildBrush->numsides = 0;
+ buildBrush->detail = qfalse;
+
+ if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
+ MatchToken( "{" );
+
+ do
+ {
+ if (!GetToken (qtrue))
+ break;
+ if (!strcmp (token, "}") )
+ break;
+ //Timo : brush primitive : here we may have to jump over brush epairs ( only used in editor )
+ if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
+ {
+ do
+ {
+ if (strcmp (token, "(") )
+ GetToken( qfalse );
+ else
+ break;
+ GetToken( qtrue );
+ } while (1);
+ }
+ UnGetToken();
+
+ if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
+ Error( "MAX_BUILD_SIDES" );
+ }
+
+ side = &buildBrush->sides[ buildBrush->numsides ];
+ memset( side, 0, sizeof( *side ) );
+ buildBrush->numsides++;
+
+ // read the three point plane definition
+ Parse1DMatrix( 3, planepts[0] );
+ Parse1DMatrix( 3, planepts[1] );
+ Parse1DMatrix( 3, planepts[2] );
+
+ if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
+ // read the texture matrix
+ Parse2DMatrix( 2, 3, (float *)side->texMat );
+
+ // read the texturedef
+ GetToken (qfalse);
+ strcpy (name, token);
+
+ // save the shader name for retexturing
+ if ( numMapIndexedShaders == MAX_MAP_BRUSHSIDES ) {
+ Error( "MAX_MAP_BRUSHSIDES" );
+ }
+ strcpy( mapIndexedShaders[numMapIndexedShaders], name );
+ numMapIndexedShaders++;
+
+ if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
+ {
+ GetToken (qfalse);
+ shift[0] = atoi(token);
+ GetToken (qfalse);
+ shift[1] = atoi(token);
+ GetToken (qfalse);
+ rotate = atoi(token);
+ GetToken (qfalse);
+ scale[0] = atof(token);
+ GetToken (qfalse);
+ scale[1] = atof(token);
+ }
+
+ // find default flags and values
+ sprintf( shader, "textures/%s", name );
+ si = ShaderInfoForShader( shader );
+ side->shaderInfo = si;
+ side->surfaceFlags = si->surfaceFlags;
+ side->value = si->value;
+ side->contents = si->contents;
+
+ // allow override of default flags and values
+ // in Q3, the only thing you can override is DETAIL
+ if (TokenAvailable())
+ {
+ GetToken (qfalse);
+// side->contents = atoi(token);
+ flags = atoi(token);
+ if ( flags & CONTENTS_DETAIL ) {
+ side->contents |= CONTENTS_DETAIL;
+ }
+
+ GetToken (qfalse);
+// td.flags = atoi(token);
+
+ GetToken (qfalse);
+// td.value = atoi(token);
+ }
+
+
+ // find the plane number
+ planenum = MapPlaneFromPoints (planepts[0], planepts[1], planepts[2]);
+ side->planenum = planenum;
+
+ if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
+ // get the texture mapping for this texturedef / plane combination
+ QuakeTextureVecs( &mapplanes[planenum], shift, rotate, scale, side->vecs );
+
+ } while (1);
+
+ if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
+ {
+ UnGetToken();
+ MatchToken( "}" );
+ MatchToken( "}" );
+ }
+}
+
+/*
+=================
+RemoveDuplicateBrushPlanes
+
+Returns false if the brush has a mirrored set of planes,
+meaning it encloses no volume.
+Also removes planes without any normal
+=================
+*/
+qboolean RemoveDuplicateBrushPlanes( bspbrush_t * b ) {
+ int i, j, k;
+ side_t *sides;
+
+ sides = b->sides;
+
+ for ( i = 1 ; i < b->numsides ; i++ ) {
+
+ // check for a degenerate plane
+ if ( sides[i].planenum == -1) {
+ _printf ("Entity %i, Brush %i: degenerate plane\n"
+ , b->entitynum, b->brushnum);
+ // remove it
+ for ( k = i + 1 ; k < b->numsides ; k++ ) {
+ sides[k-1] = sides[k];
+ }
+ b->numsides--;
+ i--;
+ continue;
+ }
+
+ // check for duplication and mirroring
+ for ( j = 0 ; j < i ; j++ ) {
+ if ( sides[i].planenum == sides[j].planenum ) {
+ _printf ("Entity %i, Brush %i: duplicate plane\n"
+ , b->entitynum, b->brushnum);
+ // remove the second duplicate
+ for ( k = i + 1 ; k < b->numsides ; k++ ) {
+ sides[k-1] = sides[k];
+ }
+ b->numsides--;
+ i--;
+ break;
+ }
+
+ if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
+ // mirror plane, brush is invalid
+ _printf ("Entity %i, Brush %i: mirrored plane\n"
+ , b->entitynum, b->brushnum);
+ return qfalse;
+ }
+ }
+ }
+ return qtrue;
+}
+
+
+/*
+=================
+ParseBrush
+
+ qboolean parameter to true -> parse new brush primitive format ( else use old format )
+=================
+*/
+void ParseBrush (void) {
+ bspbrush_t *b;
+
+ ParseRawBrush();
+
+ buildBrush->portalareas[0] = -1;
+ buildBrush->portalareas[1] = -1;
+ buildBrush->entitynum = num_entities-1;
+ buildBrush->brushnum = entitySourceBrushes;
+
+ // if there are mirrored planes, the entire brush is invalid
+ if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
+ return;
+ }
+
+ // get the content for the entire brush
+ SetBrushContents( buildBrush );
+
+ // allow detail brushes to be removed
+ if (nodetail && (buildBrush->contents & CONTENTS_DETAIL) ) {
+ FreeBrush( buildBrush );
+ return;
+ }
+
+ // allow water brushes to be removed
+ if (nowater && (buildBrush->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) ) {
+ FreeBrush( buildBrush );
+ return;
+ }
+
+ b = FinishBrush( );
+ if ( !b ) {
+ return;
+ }
+}
+
+
+/*
+================
+MoveBrushesToWorld
+
+Takes all of the brushes from the current entity and
+adds them to the world's brush list.
+
+Used by func_group
+================
+*/
+void MoveBrushesToWorld (entity_t *mapent) {
+ bspbrush_t *b, *next;
+ parseMesh_t *pm;
+
+ // move brushes
+ for ( b = mapent->brushes ; b ; b = next ) {
+ next = b->next;
+
+ b->next = entities[0].brushes;
+ entities[0].brushes = b;
+ }
+ mapent->brushes = NULL;
+
+ // move patches
+ if ( mapent->patches ) {
+
+ for ( pm = mapent->patches ; pm->next ; pm = pm->next ) {
+ }
+
+ pm->next = entities[0].patches;
+ entities[0].patches = mapent->patches;
+
+ mapent->patches = NULL;
+ }
+}
+
+
+/*
+================
+AdjustBrushesForOrigin
+================
+*/
+void AdjustBrushesForOrigin( entity_t *ent ) {
+ bspbrush_t *b;
+ int i;
+ side_t *s;
+ vec_t newdist;
+ parseMesh_t *p;
+
+ for ( b = ent->brushes ; b ; b = b->next ) {
+ for (i=0 ; i<b->numsides ; i++) {
+ s = &b->sides[i];
+ newdist = mapplanes[s->planenum].dist -
+ DotProduct (mapplanes[s->planenum].normal, ent->origin);
+ s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
+ }
+ CreateBrushWindings(b);
+ }
+
+ for ( p = ent->patches ; p ; p = p->next ) {
+ for ( i = 0 ; i < p->mesh.width*p->mesh.height ; i++ ) {
+ VectorSubtract( p->mesh.verts[i].xyz, ent->origin, p->mesh.verts[i].xyz );
+ }
+ }
+
+}
+
+/*
+================
+ParseMapEntity
+================
+*/
+qboolean ParseMapEntity (void) {
+ epair_t *e;
+
+ if (!GetToken (qtrue))
+ return qfalse;
+
+ if (strcmp (token, "{") )
+ {
+ Error ("ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...", token, scriptline, entities[num_entities].origin[0], entities[num_entities].origin[1], entities[num_entities].origin[2]);
+ }
+
+ if (num_entities == MAX_MAP_ENTITIES)
+ Error ("num_entities == MAX_MAP_ENTITIES");
+
+ entitySourceBrushes = 0;
+
+ mapent = &entities[num_entities];
+ num_entities++;
+ memset (mapent, 0, sizeof(*mapent));
+
+ do
+ {
+ if (!GetToken (qtrue))
+ Error ("ParseEntity: EOF without closing brace");
+ if (!strcmp (token, "}") )
+ break;
+
+ if (!strcmp (token, "{") ) {
+ // parse a brush or patch
+ if (!GetToken (qtrue))
+ break;
+ if ( !strcmp( token, "patchDef2" ) ) {
+ numMapPatches++;
+ ParsePatch();
+ } else if ( !strcmp( token, "terrainDef" ) ) {
+ ParseTerrain();
+ } else if ( !strcmp( token, "brushDef" ) ) {
+ if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
+ Error("old brush format not allowed in new brush format map");
+ g_bBrushPrimit=BPRIMIT_NEWBRUSHES;
+ // parse brush primitive
+ ParseBrush();
+ }
+ else
+ {
+ if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
+ Error("new brush format not allowed in old brush format map");
+ g_bBrushPrimit=BPRIMIT_OLDBRUSHES;
+ // parse old brush format
+ UnGetToken();
+ ParseBrush();
+ }
+ entitySourceBrushes++;
+ }
+ else
+ {
+ // parse a key / value pair
+ e = ParseEpair ();
+ e->next = mapent->epairs;
+ mapent->epairs = e;
+ }
+ } while (1);
+
+ GetVectorForKey (mapent, "origin", mapent->origin);
+
+ //
+ // if there was an origin brush, offset all of the planes and texinfo
+ // for all the brushes in the entity
+ if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) {
+ AdjustBrushesForOrigin( mapent );
+ }
+
+ // group_info entities are just for editor grouping
+ // ignored
+ // FIXME: leak!
+ if (!strcmp("group_info", ValueForKey (mapent, "classname")))
+ {
+ num_entities--;
+ return qtrue;
+ }
+
+ // group entities are just for editor convenience
+ // toss all brushes into the world entity
+ if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
+ {
+ if ( !strcmp ("1", ValueForKey (mapent, "terrain"))) {
+ SetTerrainTextures();
+ }
+ MoveBrushesToWorld (mapent);
+ num_entities--;
+ return qtrue;
+ }
+
+ return qtrue;
+}
+
+//===================================================================
+
+
+/*
+================
+LoadMapFile
+================
+*/
+void LoadMapFile (char *filename) {
+ bspbrush_t *b;
+
+ qprintf ("--- LoadMapFile ---\n");
+ _printf ("Loading map file %s\n", filename);
+
+ LoadScriptFile (filename);
+
+ num_entities = 0;
+ numMapDrawSurfs = 0;
+ c_detail = 0;
+
+ g_bBrushPrimit = BPRIMIT_UNDEFINED;
+
+ // allocate a very large temporary brush for building
+ // the brushes as they are loaded
+ buildBrush = AllocBrush( MAX_BUILD_SIDES );
+
+ while (ParseMapEntity ())
+ {
+ }
+
+ ClearBounds (map_mins, map_maxs);
+ for ( b = entities[0].brushes ; b ; b=b->next ) {
+ AddPointToBounds( b->mins, map_mins, map_maxs );
+ AddPointToBounds( b->maxs, map_mins, map_maxs );
+ }
+
+ qprintf ("%5i total world brushes\n", CountBrushList( entities[0].brushes ) );
+ qprintf ("%5i detail brushes\n", c_detail );
+ qprintf ("%5i patches\n", numMapPatches);
+ qprintf ("%5i boxbevels\n", c_boxbevels);
+ qprintf ("%5i edgebevels\n", c_edgebevels);
+ qprintf ("%5i entities\n", num_entities);
+ qprintf ("%5i planes\n", nummapplanes);
+ qprintf ("%5i areaportals\n", c_areaportals);
+ qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
+ map_maxs[0],map_maxs[1],map_maxs[2]);
+
+ if ( fakemap ) {
+ WriteBspBrushMap ("fakemap.map", entities[0].brushes );
+ }
+
+ if ( testExpand ) {
+ TestExpandBrushes ();
+ }
+}
+
+
+//====================================================================
+
+
+/*
+================
+TestExpandBrushes
+
+Expands all the brush planes and saves a new map out to
+allow visual inspection of the clipping bevels
+================
+*/
+void TestExpandBrushes( void ) {
+ side_t *s;
+ int i, j;
+ bspbrush_t *brush, *list, *copy;
+ vec_t dist;
+ plane_t *plane;
+
+ list = NULL;
+
+ for ( brush = entities[0].brushes ; brush ; brush = brush->next ) {
+ copy = CopyBrush( brush );
+ copy->next = list;
+ list = copy;
+
+ // expand all the planes
+ for ( i=0 ; i<brush->numsides ; i++ ) {
+ s = brush->sides + i;
+ plane = &mapplanes[s->planenum];
+ dist = plane->dist;
+ for (j=0 ; j<3 ; j++) {
+ dist += fabs( 16 * plane->normal[j] );
+ }
+ s->planenum = FindFloatPlane( plane->normal, dist );
+ }
+
+ }
+
+ WriteBspBrushMap ( "expanded.map", entities[0].brushes );
+
+ Error ("can't proceed after expanding brushes");
+}
diff --git a/q3map/mesh.c b/q3map/mesh.c
index c49c76b..e2b3010 100755
--- a/q3map/mesh.c
+++ b/q3map/mesh.c
@@ -19,664 +19,664 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include "qbsp.h"
-
-
-/*
-===============================================================
-
-MESH SUBDIVISION
-
-===============================================================
-*/
-
-
-int originalWidths[MAX_EXPANDED_AXIS];
-int originalHeights[MAX_EXPANDED_AXIS];
-
-int neighbors[8][2] = {
- {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
-};
-
-/*
-============
-LerpDrawVert
-============
-*/
-void LerpDrawVert( drawVert_t *a, drawVert_t *b, drawVert_t *out ) {
- out->xyz[0] = 0.5 * (a->xyz[0] + b->xyz[0]);
- out->xyz[1] = 0.5 * (a->xyz[1] + b->xyz[1]);
- out->xyz[2] = 0.5 * (a->xyz[2] + b->xyz[2]);
-
- out->st[0] = 0.5 * (a->st[0] + b->st[0]);
- out->st[1] = 0.5 * (a->st[1] + b->st[1]);
-
- out->lightmap[0] = 0.5 * (a->lightmap[0] + b->lightmap[0]);
- out->lightmap[1] = 0.5 * (a->lightmap[1] + b->lightmap[1]);
-
- out->color[0] = (a->color[0] + b->color[0]) >> 1;
- out->color[1] = (a->color[1] + b->color[1]) >> 1;
- out->color[2] = (a->color[2] + b->color[2]) >> 1;
- out->color[3] = (a->color[3] + b->color[3]) >> 1;
-}
-
-
-void FreeMesh( mesh_t *m ) {
- free( m->verts );
- free( m );
-}
-
-void PrintMesh( mesh_t *m ) {
- int i, j;
-
- for ( i = 0 ; i < m->height ; i++ ) {
- for ( j = 0 ; j < m->width ; j++ ) {
- _printf("(%5.2f %5.2f %5.2f) "
- , m->verts[i*m->width+j].xyz[0]
- , m->verts[i*m->width+j].xyz[1]
- , m->verts[i*m->width+j].xyz[2] );
- }
- _printf("\n");
- }
-}
-
-
-mesh_t *CopyMesh( mesh_t *mesh ) {
- mesh_t *out;
- int size;
-
- out = malloc( sizeof( *out ) );
- out->width = mesh->width;
- out->height = mesh->height;
-
- size = out->width * out->height * sizeof( *out->verts );
- out->verts = malloc( size );
- memcpy( out->verts, mesh->verts, size );
-
- return out;
-}
-
-
-/*
-=================
-TransposeMesh
-
-Returns a transposed copy of the mesh, freeing the original
-=================
-*/
-mesh_t *TransposeMesh( mesh_t *in ) {
- int w, h;
- mesh_t *out;
-
- out = malloc( sizeof( *out ) );
- out->width = in->height;
- out->height = in->width;
- out->verts = malloc( out->width * out->height * sizeof( drawVert_t ) );
-
- for ( h = 0 ; h < in->height ; h++ ) {
- for ( w = 0 ; w < in->width ; w++ ) {
- out->verts[ w * in->height + h ] = in->verts[ h * in->width + w ];
- }
- }
-
- FreeMesh( in );
-
- return out;
-}
-
-void InvertMesh( mesh_t *in ) {
- int w, h;
- drawVert_t temp;
-
- for ( h = 0 ; h < in->height ; h++ ) {
- for ( w = 0 ; w < in->width / 2 ; w++ ) {
- temp = in->verts[ h * in->width + w ];
- in->verts[ h * in->width + w ] = in->verts[ h * in->width + in->width - 1 - w ];
- in->verts[ h * in->width + in->width - 1 - w ] = temp;
- }
- }
-}
-
-/*
-=================
-MakeMeshNormals
-
-=================
-*/
-void MakeMeshNormals( mesh_t in ) {
- int i, j, k, dist;
- vec3_t normal;
- vec3_t sum;
- int count;
- vec3_t base;
- vec3_t delta;
- int x, y;
- drawVert_t *dv;
- vec3_t around[8], temp;
- qboolean good[8];
- qboolean wrapWidth, wrapHeight;
- float len;
-
- wrapWidth = qfalse;
- for ( i = 0 ; i < in.height ; i++ ) {
- VectorSubtract( in.verts[i*in.width].xyz,
- in.verts[i*in.width+in.width-1].xyz, delta );
- len = VectorLength( delta );
- if ( len > 1.0 ) {
- break;
- }
- }
- if ( i == in.height ) {
- wrapWidth = qtrue;
- }
-
- wrapHeight = qfalse;
- for ( i = 0 ; i < in.width ; i++ ) {
- VectorSubtract( in.verts[i].xyz,
- in.verts[i + (in.height-1)*in.width].xyz, delta );
- len = VectorLength( delta );
- if ( len > 1.0 ) {
- break;
- }
- }
- if ( i == in.width) {
- wrapHeight = qtrue;
- }
-
-
- for ( i = 0 ; i < in.width ; i++ ) {
- for ( j = 0 ; j < in.height ; j++ ) {
- count = 0;
- dv = &in.verts[j*in.width+i];
- VectorCopy( dv->xyz, base );
- for ( k = 0 ; k < 8 ; k++ ) {
- VectorClear( around[k] );
- good[k] = qfalse;
-
- for ( dist = 1 ; dist <= 3 ; dist++ ) {
- x = i + neighbors[k][0] * dist;
- y = j + neighbors[k][1] * dist;
- if ( wrapWidth ) {
- if ( x < 0 ) {
- x = in.width - 1 + x;
- } else if ( x >= in.width ) {
- x = 1 + x - in.width;
- }
- }
- if ( wrapHeight ) {
- if ( y < 0 ) {
- y = in.height - 1 + y;
- } else if ( y >= in.height ) {
- y = 1 + y - in.height;
- }
- }
-
- if ( x < 0 || x >= in.width || y < 0 || y >= in.height ) {
- break; // edge of patch
- }
- VectorSubtract( in.verts[y*in.width+x].xyz, base, temp );
- if ( VectorNormalize( temp, temp ) == 0 ) {
- continue; // degenerate edge, get more dist
- } else {
- good[k] = qtrue;
- VectorCopy( temp, around[k] );
- break; // good edge
- }
- }
- }
-
- VectorClear( sum );
- for ( k = 0 ; k < 8 ; k++ ) {
- if ( !good[k] || !good[(k+1)&7] ) {
- continue; // didn't get two points
- }
- CrossProduct( around[(k+1)&7], around[k], normal );
- if ( VectorNormalize( normal, normal ) == 0 ) {
- continue;
- }
- VectorAdd( normal, sum, sum );
- count++;
- }
- if ( count == 0 ) {
-//_printf("bad normal\n");
- count = 1;
- }
- VectorNormalize( sum, dv->normal );
- }
- }
-}
-
-/*
-=================
-PutMeshOnCurve
-
-Drops the aproximating points onto the curve
-=================
-*/
-void PutMeshOnCurve( mesh_t in ) {
- int i, j, l;
- float prev, next;
-
- // put all the aproximating points on the curve
- for ( i = 0 ; i < in.width ; i++ ) {
- for ( j = 1 ; j < in.height ; j += 2 ) {
- for ( l = 0 ; l < 3 ; l++ ) {
- prev = ( in.verts[j*in.width+i].xyz[l] + in.verts[(j+1)*in.width+i].xyz[l] ) * 0.5;
- next = ( in.verts[j*in.width+i].xyz[l] + in.verts[(j-1)*in.width+i].xyz[l] ) * 0.5;
- in.verts[j*in.width+i].xyz[l] = ( prev + next ) * 0.5;
- }
- }
- }
-
- for ( j = 0 ; j < in.height ; j++ ) {
- for ( i = 1 ; i < in.width ; i += 2 ) {
- for ( l = 0 ; l < 3 ; l++ ) {
- prev = ( in.verts[j*in.width+i].xyz[l] + in.verts[j*in.width+i+1].xyz[l] ) * 0.5;
- next = ( in.verts[j*in.width+i].xyz[l] + in.verts[j*in.width+i-1].xyz[l] ) * 0.5;
- in.verts[j*in.width+i].xyz[l] = ( prev + next ) * 0.5;
- }
- }
- }
-}
-
-
-/*
-=================
-SubdivideMesh
-
-=================
-*/
-mesh_t *SubdivideMesh( mesh_t in, float maxError, float minLength ) {
- int i, j, k, l;
- drawVert_t prev, next, mid;
- vec3_t prevxyz, nextxyz, midxyz;
- vec3_t delta;
- float len;
- mesh_t out;
- drawVert_t expand[MAX_EXPANDED_AXIS][MAX_EXPANDED_AXIS];
-
- out.width = in.width;
- out.height = in.height;
-
- for ( i = 0 ; i < in.width ; i++ ) {
- for ( j = 0 ; j < in.height ; j++ ) {
- expand[j][i] = in.verts[j*in.width+i];
- }
- }
-
- for ( i = 0 ; i < in.height ; i++ ) {
- originalHeights[i] = i;
- }
- for ( i = 0 ; i < in.width ; i++ ) {
- originalWidths[i] = i;
- }
-
- // horizontal subdivisions
- for ( j = 0 ; j + 2 < out.width ; j += 2 ) {
- // check subdivided midpoints against control points
- for ( i = 0 ; i < out.height ; i++ ) {
- for ( l = 0 ; l < 3 ; l++ ) {
- prevxyz[l] = expand[i][j+1].xyz[l] - expand[i][j].xyz[l];
- nextxyz[l] = expand[i][j+2].xyz[l] - expand[i][j+1].xyz[l];
- midxyz[l] = (expand[i][j].xyz[l] + expand[i][j+1].xyz[l] * 2
- + expand[i][j+2].xyz[l] ) * 0.25;
- }
-
- // if the span length is too long, force a subdivision
- if ( VectorLength( prevxyz ) > minLength
- || VectorLength( nextxyz ) > minLength ) {
- break;
- }
-
- // see if this midpoint is off far enough to subdivide
- VectorSubtract( expand[i][j+1].xyz, midxyz, delta );
- len = VectorLength( delta );
- if ( len > maxError ) {
- break;
- }
- }
-
- if ( out.width + 2 >= MAX_EXPANDED_AXIS ) {
- break; // can't subdivide any more
- }
-
- if ( i == out.height ) {
- continue; // didn't need subdivision
- }
-
- // insert two columns and replace the peak
- out.width += 2;
-
- for ( k = out.width - 1 ; k > j + 3 ; k-- ) {
- originalWidths[k] = originalWidths[k-2];
- }
- originalWidths[j+3] = originalWidths[j+1];
- originalWidths[j+2] = originalWidths[j+1];
- originalWidths[j+1] = originalWidths[j];
-
- for ( i = 0 ; i < out.height ; i++ ) {
- LerpDrawVert( &expand[i][j], &expand[i][j+1], &prev );
- LerpDrawVert( &expand[i][j+1], &expand[i][j+2], &next );
- LerpDrawVert( &prev, &next, &mid );
-
- for ( k = out.width - 1 ; k > j + 3 ; k-- ) {
- expand[i][k] = expand[i][k-2];
- }
- expand[i][j + 1] = prev;
- expand[i][j + 2] = mid;
- expand[i][j + 3] = next;
- }
-
- // back up and recheck this set again, it may need more subdivision
- j -= 2;
-
- }
-
- // vertical subdivisions
- for ( j = 0 ; j + 2 < out.height ; j += 2 ) {
- // check subdivided midpoints against control points
- for ( i = 0 ; i < out.width ; i++ ) {
- for ( l = 0 ; l < 3 ; l++ ) {
- prevxyz[l] = expand[j+1][i].xyz[l] - expand[j][i].xyz[l];
- nextxyz[l] = expand[j+2][i].xyz[l] - expand[j+1][i].xyz[l];
- midxyz[l] = (expand[j][i].xyz[l] + expand[j+1][i].xyz[l] * 2
- + expand[j+2][i].xyz[l] ) * 0.25;
- }
-
- // if the span length is too long, force a subdivision
- if ( VectorLength( prevxyz ) > minLength
- || VectorLength( nextxyz ) > minLength ) {
- break;
- }
- // see if this midpoint is off far enough to subdivide
- VectorSubtract( expand[j+1][i].xyz, midxyz, delta );
- len = VectorLength( delta );
- if ( len > maxError ) {
- break;
- }
- }
-
- if ( out.height + 2 >= MAX_EXPANDED_AXIS ) {
- break; // can't subdivide any more
- }
-
- if ( i == out.width ) {
- continue; // didn't need subdivision
- }
-
- // insert two columns and replace the peak
- out.height += 2;
-
- for ( k = out.height - 1 ; k > j + 3 ; k-- ) {
- originalHeights[k] = originalHeights[k-2];
- }
- originalHeights[j+3] = originalHeights[j+1];
- originalHeights[j+2] = originalHeights[j+1];
- originalHeights[j+1] = originalHeights[j];
-
- for ( i = 0 ; i < out.width ; i++ ) {
- LerpDrawVert( &expand[j][i], &expand[j+1][i], &prev );
- LerpDrawVert( &expand[j+1][i], &expand[j+2][i], &next );
- LerpDrawVert( &prev, &next, &mid );
-
- for ( k = out.height - 1 ; k > j + 3 ; k-- ) {
- expand[k][i] = expand[k-2][i];
- }
- expand[j+1][i] = prev;
- expand[j+2][i] = mid;
- expand[j+3][i] = next;
- }
-
- // back up and recheck this set again, it may need more subdivision
- j -= 2;
-
- }
-
- // collapse the verts
-
- out.verts = &expand[0][0];
- for ( i = 1 ; i < out.height ; i++ ) {
- memmove( &out.verts[i*out.width], expand[i], out.width * sizeof(drawVert_t) );
- }
-
- return CopyMesh(&out);
-}
-
-/*
-================
-ProjectPointOntoVector
-================
-*/
-void ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj )
-{
- vec3_t pVec, vec;
-
- VectorSubtract( point, vStart, pVec );
- VectorSubtract( vEnd, vStart, vec );
- VectorNormalize( vec, vec );
- // project onto the directional vector for this segment
- VectorMA( vStart, DotProduct( pVec, vec ), vec, vProj );
-}
-
-/*
-================
-RemoveLinearMeshColumsRows
-================
-*/
-mesh_t *RemoveLinearMeshColumnsRows( mesh_t *in ) {
- int i, j, k;
- float len, maxLength;
- vec3_t proj, dir;
- mesh_t out;
- drawVert_t expand[MAX_EXPANDED_AXIS][MAX_EXPANDED_AXIS];
-
- out.width = in->width;
- out.height = in->height;
-
- for ( i = 0 ; i < in->width ; i++ ) {
- for ( j = 0 ; j < in->height ; j++ ) {
- expand[j][i] = in->verts[j*in->width+i];
- }
- }
-
- for ( j = 1 ; j < out.width - 1; j++ ) {
- maxLength = 0;
- for ( i = 0 ; i < out.height ; i++ ) {
- ProjectPointOntoVector(expand[i][j].xyz, expand[i][j-1].xyz, expand[i][j+1].xyz, proj);
- VectorSubtract(expand[i][j].xyz, proj, dir);
- len = VectorLength(dir);
- if (len > maxLength) {
- maxLength = len;
- }
- }
- if (maxLength < 0.1)
- {
- out.width--;
- for ( i = 0 ; i < out.height ; i++ ) {
- for (k = j; k < out.width; k++) {
- expand[i][k] = expand[i][k+1];
- }
- }
- for (k = j; k < out.width; k++) {
- originalWidths[k] = originalWidths[k+1];
- }
- j--;
- }
- }
- for ( j = 1 ; j < out.height - 1; j++ ) {
- maxLength = 0;
- for ( i = 0 ; i < out.width ; i++ ) {
- ProjectPointOntoVector(expand[j][i].xyz, expand[j-1][i].xyz, expand[j+1][i].xyz, proj);
- VectorSubtract(expand[j][i].xyz, proj, dir);
- len = VectorLength(dir);
- if (len > maxLength) {
- maxLength = len;
- }
- }
- if (maxLength < 0.1)
- {
- out.height--;
- for ( i = 0 ; i < out.width ; i++ ) {
- for (k = j; k < out.height; k++) {
- expand[k][i] = expand[k+1][i];
- }
- }
- for (k = j; k < out.height; k++) {
- originalHeights[k] = originalHeights[k+1];
- }
- j--;
- }
- }
- // collapse the verts
- out.verts = &expand[0][0];
- for ( i = 1 ; i < out.height ; i++ ) {
- memmove( &out.verts[i*out.width], expand[i], out.width * sizeof(drawVert_t) );
- }
-
- return CopyMesh(&out);
-}
-
-/*
-============
-LerpDrawVertAmount
-============
-*/
-void LerpDrawVertAmount( drawVert_t *a, drawVert_t *b, float amount, drawVert_t *out ) {
- out->xyz[0] = a->xyz[0] + amount * (b->xyz[0] - a->xyz[0]);
- out->xyz[1] = a->xyz[1] + amount * (b->xyz[1] - a->xyz[1]);
- out->xyz[2] = a->xyz[2] + amount * (b->xyz[2] - a->xyz[2]);
-
- out->st[0] = a->st[0] + amount * (b->st[0] - a->st[0]);
- out->st[1] = a->st[1] + amount * (b->st[1] - a->st[1]);
-
- out->lightmap[0] = a->lightmap[0] + amount * (b->lightmap[0] - a->lightmap[0]);
- out->lightmap[1] = a->lightmap[1] + amount * (b->lightmap[1] - a->lightmap[1]);
-
- out->color[0] = a->color[0] + amount * (b->color[0] - a->color[0]);
- out->color[1] = a->color[1] + amount * (b->color[1] - a->color[1]);
- out->color[2] = a->color[2] + amount * (b->color[2] - a->color[2]);
- out->color[3] = a->color[3] + amount * (b->color[3] - a->color[3]);
-
- out->normal[0] = a->normal[0] + amount * (b->normal[0] - a->normal[0]);
- out->normal[1] = a->normal[1] + amount * (b->normal[1] - a->normal[1]);
- out->normal[2] = a->normal[2] + amount * (b->normal[2] - a->normal[2]);
- VectorNormalize(out->normal, out->normal);
-}
-
-/*
-=================
-SubdivideMeshQuads
-=================
-*/
-mesh_t *SubdivideMeshQuads( mesh_t *in, float minLength, int maxsize, int widthtable[], int heighttable[]) {
- int i, j, k, w, h, maxsubdivisions, subdivisions;
- vec3_t dir;
- float length, maxLength, amount;
- mesh_t out;
- drawVert_t expand[MAX_EXPANDED_AXIS][MAX_EXPANDED_AXIS];
-
- out.width = in->width;
- out.height = in->height;
-
- for ( i = 0 ; i < in->width ; i++ ) {
- for ( j = 0 ; j < in->height ; j++ ) {
- expand[j][i] = in->verts[j*in->width+i];
- }
- }
-
- if (maxsize > MAX_EXPANDED_AXIS)
- Error("SubdivideMeshQuads: maxsize > MAX_EXPANDED_AXIS");
-
- // horizontal subdivisions
-
- maxsubdivisions = (maxsize - in->width) / (in->width - 1);
-
- for ( w = 0, j = 0 ; w < in->width - 1; w++, j += subdivisions + 1) {
- maxLength = 0;
- for ( i = 0 ; i < out.height ; i++ ) {
- VectorSubtract(expand[i][j+1].xyz, expand[i][j].xyz, dir);
- length = VectorLength( dir );
- if (length > maxLength) {
- maxLength = length;
- }
- }
-
- subdivisions = (int) (maxLength / minLength);
- if (subdivisions > maxsubdivisions)
- subdivisions = maxsubdivisions;
-
- widthtable[w] = subdivisions + 1;
- if (subdivisions <= 0)
- continue;
-
- out.width += subdivisions;
-
- for ( k = out.width - 1; k >= j + subdivisions; k-- ) {
- originalWidths[k] = originalWidths[k-subdivisions];
- }
- for (k = 1; k <= subdivisions; k++) {
- originalWidths[j+k] = originalWidths[j];
- }
-
- for ( i = 0 ; i < out.height ; i++ ) {
- for ( k = out.width - 1 ; k > j + subdivisions; k-- ) {
- expand[i][k] = expand[i][k-subdivisions];
- }
- for (k = 1; k <= subdivisions; k++)
- {
- amount = (float) k / (subdivisions + 1);
- LerpDrawVertAmount(&expand[i][j], &expand[i][j+subdivisions+1], amount, &expand[i][j+k]);
- }
- }
- }
-
- maxsubdivisions = (maxsize - in->height) / (in->height - 1);
-
- for ( h = 0, j = 0 ; h < in->height - 1; h++, j += subdivisions + 1) {
- maxLength = 0;
- for ( i = 0 ; i < out.width ; i++ ) {
- VectorSubtract(expand[j+1][i].xyz, expand[j][i].xyz, dir);
- length = VectorLength( dir );
- if (length > maxLength) {
- maxLength = length;
- }
- }
-
- subdivisions = (int) (maxLength / minLength);
- if (subdivisions > maxsubdivisions)
- subdivisions = maxsubdivisions;
-
- heighttable[h] = subdivisions + 1;
- if (subdivisions <= 0)
- continue;
-
- out.height += subdivisions;
-
- for ( k = out.height - 1; k >= j + subdivisions; k-- ) {
- originalHeights[k] = originalHeights[k-subdivisions];
- }
- for (k = 1; k <= subdivisions; k++) {
- originalHeights[j+k] = originalHeights[j];
- }
-
- for ( i = 0 ; i < out.width ; i++ ) {
- for ( k = out.height - 1 ; k > j + subdivisions; k-- ) {
- expand[k][i] = expand[k-subdivisions][i];
- }
- for (k = 1; k <= subdivisions; k++)
- {
- amount = (float) k / (subdivisions + 1);
- LerpDrawVertAmount(&expand[j][i], &expand[j+subdivisions+1][i], amount, &expand[j+k][i]);
- }
- }
- }
-
- // collapse the verts
- out.verts = &expand[0][0];
- for ( i = 1 ; i < out.height ; i++ ) {
- memmove( &out.verts[i*out.width], expand[i], out.width * sizeof(drawVert_t) );
- }
-
- return CopyMesh(&out);
-}
+
+#include "qbsp.h"
+
+
+/*
+===============================================================
+
+MESH SUBDIVISION
+
+===============================================================
+*/
+
+
+int originalWidths[MAX_EXPANDED_AXIS];
+int originalHeights[MAX_EXPANDED_AXIS];
+
+int neighbors[8][2] = {
+ {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
+};
+
+/*
+============
+LerpDrawVert
+============
+*/
+void LerpDrawVert( drawVert_t *a, drawVert_t *b, drawVert_t *out ) {
+ out->xyz[0] = 0.5 * (a->xyz[0] + b->xyz[0]);
+ out->xyz[1] = 0.5 * (a->xyz[1] + b->xyz[1]);
+ out->xyz[2] = 0.5 * (a->xyz[2] + b->xyz[2]);
+
+ out->st[0] = 0.5 * (a->st[0] + b->st[0]);
+ out->st[1] = 0.5 * (a->st[1] + b->st[1]);
+
+ out->lightmap[0] = 0.5 * (a->lightmap[0] + b->lightmap[0]);
+ out->lightmap[1] = 0.5 * (a->lightmap[1] + b->lightmap[1]);
+
+ out->color[0] = (a->color[0] + b->color[0]) >> 1;
+ out->color[1] = (a->color[1] + b->color[1]) >> 1;
+ out->color[2] = (a->color[2] + b->color[2]) >> 1;
+ out->color[3] = (a->color[3] + b->color[3]) >> 1;
+}
+
+
+void FreeMesh( mesh_t *m ) {
+ free( m->verts );
+ free( m );
+}
+
+void PrintMesh( mesh_t *m ) {
+ int i, j;
+
+ for ( i = 0 ; i < m->height ; i++ ) {
+ for ( j = 0 ; j < m->width ; j++ ) {
+ _printf("(%5.2f %5.2f %5.2f) "
+ , m->verts[i*m->width+j].xyz[0]
+ , m->verts[i*m->width+j].xyz[1]
+ , m->verts[i*m->width+j].xyz[2] );
+ }
+ _printf("\n");
+ }
+}
+
+
+mesh_t *CopyMesh( mesh_t *mesh ) {
+ mesh_t *out;
+ int size;
+
+ out = malloc( sizeof( *out ) );
+ out->width = mesh->width;
+ out->height = mesh->height;
+
+ size = out->width * out->height * sizeof( *out->verts );
+ out->verts = malloc( size );
+ memcpy( out->verts, mesh->verts, size );
+
+ return out;
+}
+
+
+/*
+=================
+TransposeMesh
+
+Returns a transposed copy of the mesh, freeing the original
+=================
+*/
+mesh_t *TransposeMesh( mesh_t *in ) {
+ int w, h;
+ mesh_t *out;
+
+ out = malloc( sizeof( *out ) );
+ out->width = in->height;
+ out->height = in->width;
+ out->verts = malloc( out->width * out->height * sizeof( drawVert_t ) );
+
+ for ( h = 0 ; h < in->height ; h++ ) {
+ for ( w = 0 ; w < in->width ; w++ ) {
+ out->verts[ w * in->height + h ] = in->verts[ h * in->width + w ];
+ }
+ }
+
+ FreeMesh( in );
+
+ return out;
+}
+
+void InvertMesh( mesh_t *in ) {
+ int w, h;
+ drawVert_t temp;
+
+ for ( h = 0 ; h < in->height ; h++ ) {
+ for ( w = 0 ; w < in->width / 2 ; w++ ) {
+ temp = in->verts[ h * in->width + w ];
+ in->verts[ h * in->width + w ] = in->verts[ h * in->width + in->width - 1 - w ];
+ in->verts[ h * in->width + in->width - 1 - w ] = temp;
+ }
+ }
+}
+
+/*
+=================
+MakeMeshNormals
+
+=================
+*/
+void MakeMeshNormals( mesh_t in ) {
+ int i, j, k, dist;
+ vec3_t normal;
+ vec3_t sum;
+ int count;
+ vec3_t base;
+ vec3_t delta;
+ int x, y;
+ drawVert_t *dv;
+ vec3_t around[8], temp;
+ qboolean good[8];
+ qboolean wrapWidth, wrapHeight;
+ float len;
+
+ wrapWidth = qfalse;
+ for ( i = 0 ; i < in.height ; i++ ) {
+ VectorSubtract( in.verts[i*in.width].xyz,
+ in.verts[i*in.width+in.width-1].xyz, delta );
+ len = VectorLength( delta );
+ if ( len > 1.0 ) {
+ break;
+ }
+ }
+ if ( i == in.height ) {
+ wrapWidth = qtrue;
+ }
+
+ wrapHeight = qfalse;
+ for ( i = 0 ; i < in.width ; i++ ) {
+ VectorSubtract( in.verts[i].xyz,
+ in.verts[i + (in.height-1)*in.width].xyz, delta );
+ len = VectorLength( delta );
+ if ( len > 1.0 ) {
+ break;
+ }
+ }
+ if ( i == in.width) {
+ wrapHeight = qtrue;
+ }
+
+
+ for ( i = 0 ; i < in.width ; i++ ) {
+ for ( j = 0 ; j < in.height ; j++ ) {
+ count = 0;
+ dv = &in.verts[j*in.width+i];
+ VectorCopy( dv->xyz, base );
+ for ( k = 0 ; k < 8 ; k++ ) {
+ VectorClear( around[k] );
+ good[k] = qfalse;
+
+ for ( dist = 1 ; dist <= 3 ; dist++ ) {
+ x = i + neighbors[k][0] * dist;
+ y = j + neighbors[k][1] * dist;
+ if ( wrapWidth ) {
+ if ( x < 0 ) {
+ x = in.width - 1 + x;
+ } else if ( x >= in.width ) {
+ x = 1 + x - in.width;
+ }
+ }
+ if ( wrapHeight ) {
+ if ( y < 0 ) {
+ y = in.height - 1 + y;
+ } else if ( y >= in.height ) {
+ y = 1 + y - in.height;
+ }
+ }
+
+ if ( x < 0 || x >= in.width || y < 0 || y >= in.height ) {
+ break; // edge of patch
+ }
+ VectorSubtract( in.verts[y*in.width+x].xyz, base, temp );
+ if ( VectorNormalize( temp, temp ) == 0 ) {
+ continue; // degenerate edge, get more dist
+ } else {
+ good[k] = qtrue;
+ VectorCopy( temp, around[k] );
+ break; // good edge
+ }
+ }
+ }
+
+ VectorClear( sum );
+ for ( k = 0 ; k < 8 ; k++ ) {
+ if ( !good[k] || !good[(k+1)&7] ) {
+ continue; // didn't get two points
+ }
+ CrossProduct( around[(k+1)&7], around[k], normal );
+ if ( VectorNormalize( normal, normal ) == 0 ) {
+ continue;
+ }
+ VectorAdd( normal, sum, sum );
+ count++;
+ }
+ if ( count == 0 ) {
+//_printf("bad normal\n");
+ count = 1;
+ }
+ VectorNormalize( sum, dv->normal );
+ }
+ }
+}
+
+/*
+=================
+PutMeshOnCurve
+
+Drops the aproximating points onto the curve
+=================
+*/
+void PutMeshOnCurve( mesh_t in ) {
+ int i, j, l;
+ float prev, next;
+
+ // put all the aproximating points on the curve
+ for ( i = 0 ; i < in.width ; i++ ) {
+ for ( j = 1 ; j < in.height ; j += 2 ) {
+ for ( l = 0 ; l < 3 ; l++ ) {
+ prev = ( in.verts[j*in.width+i].xyz[l] + in.verts[(j+1)*in.width+i].xyz[l] ) * 0.5;
+ next = ( in.verts[j*in.width+i].xyz[l] + in.verts[(j-1)*in.width+i].xyz[l] ) * 0.5;
+ in.verts[j*in.width+i].xyz[l] = ( prev + next ) * 0.5;
+ }
+ }
+ }
+
+ for ( j = 0 ; j < in.height ; j++ ) {
+ for ( i = 1 ; i < in.width ; i += 2 ) {
+ for ( l = 0 ; l < 3 ; l++ ) {
+ prev = ( in.verts[j*in.width+i].xyz[l] + in.verts[j*in.width+i+1].xyz[l] ) * 0.5;
+ next = ( in.verts[j*in.width+i].xyz[l] + in.verts[j*in.width+i-1].xyz[l] ) * 0.5;
+ in.verts[j*in.width+i].xyz[l] = ( prev + next ) * 0.5;
+ }
+ }
+ }
+}
+
+
+/*
+=================
+SubdivideMesh
+
+=================
+*/
+mesh_t *SubdivideMesh( mesh_t in, float maxError, float minLength ) {
+ int i, j, k, l;
+ drawVert_t prev, next, mid;
+ vec3_t prevxyz, nextxyz, midxyz;
+ vec3_t delta;
+ float len;
+ mesh_t out;
+ drawVert_t expand[MAX_EXPANDED_AXIS][MAX_EXPANDED_AXIS];
+
+ out.width = in.width;
+ out.height = in.height;
+
+ for ( i = 0 ; i < in.width ; i++ ) {
+ for ( j = 0 ; j < in.height ; j++ ) {
+ expand[j][i] = in.verts[j*in.width+i];
+ }
+ }
+
+ for ( i = 0 ; i < in.height ; i++ ) {
+ originalHeights[i] = i;
+ }
+ for ( i = 0 ; i < in.width ; i++ ) {
+ originalWidths[i] = i;
+ }
+
+ // horizontal subdivisions
+ for ( j = 0 ; j + 2 < out.width ; j += 2 ) {
+ // check subdivided midpoints against control points
+ for ( i = 0 ; i < out.height ; i++ ) {
+ for ( l = 0 ; l < 3 ; l++ ) {
+ prevxyz[l] = expand[i][j+1].xyz[l] - expand[i][j].xyz[l];
+ nextxyz[l] = expand[i][j+2].xyz[l] - expand[i][j+1].xyz[l];
+ midxyz[l] = (expand[i][j].xyz[l] + expand[i][j+1].xyz[l] * 2
+ + expand[i][j+2].xyz[l] ) * 0.25;
+ }
+
+ // if the span length is too long, force a subdivision
+ if ( VectorLength( prevxyz ) > minLength
+ || VectorLength( nextxyz ) > minLength ) {
+ break;
+ }
+
+ // see if this midpoint is off far enough to subdivide
+ VectorSubtract( expand[i][j+1].xyz, midxyz, delta );
+ len = VectorLength( delta );
+ if ( len > maxError ) {
+ break;
+ }
+ }
+
+ if ( out.width + 2 >= MAX_EXPANDED_AXIS ) {
+ break; // can't subdivide any more
+ }
+
+ if ( i == out.height ) {
+ continue; // didn't need subdivision
+ }
+
+ // insert two columns and replace the peak
+ out.width += 2;
+
+ for ( k = out.width - 1 ; k > j + 3 ; k-- ) {
+ originalWidths[k] = originalWidths[k-2];
+ }
+ originalWidths[j+3] = originalWidths[j+1];
+ originalWidths[j+2] = originalWidths[j+1];
+ originalWidths[j+1] = originalWidths[j];
+
+ for ( i = 0 ; i < out.height ; i++ ) {
+ LerpDrawVert( &expand[i][j], &expand[i][j+1], &prev );
+ LerpDrawVert( &expand[i][j+1], &expand[i][j+2], &next );
+ LerpDrawVert( &prev, &next, &mid );
+
+ for ( k = out.width - 1 ; k > j + 3 ; k-- ) {
+ expand[i][k] = expand[i][k-2];
+ }
+ expand[i][j + 1] = prev;
+ expand[i][j + 2] = mid;
+ expand[i][j + 3] = next;
+ }
+
+ // back up and recheck this set again, it may need more subdivision
+ j -= 2;
+
+ }
+
+ // vertical subdivisions
+ for ( j = 0 ; j + 2 < out.height ; j += 2 ) {
+ // check subdivided midpoints against control points
+ for ( i = 0 ; i < out.width ; i++ ) {
+ for ( l = 0 ; l < 3 ; l++ ) {
+ prevxyz[l] = expand[j+1][i].xyz[l] - expand[j][i].xyz[l];
+ nextxyz[l] = expand[j+2][i].xyz[l] - expand[j+1][i].xyz[l];
+ midxyz[l] = (expand[j][i].xyz[l] + expand[j+1][i].xyz[l] * 2
+ + expand[j+2][i].xyz[l] ) * 0.25;
+ }
+
+ // if the span length is too long, force a subdivision
+ if ( VectorLength( prevxyz ) > minLength
+ || VectorLength( nextxyz ) > minLength ) {
+ break;
+ }
+ // see if this midpoint is off far enough to subdivide
+ VectorSubtract( expand[j+1][i].xyz, midxyz, delta );
+ len = VectorLength( delta );
+ if ( len > maxError ) {
+ break;
+ }
+ }
+
+ if ( out.height + 2 >= MAX_EXPANDED_AXIS ) {
+ break; // can't subdivide any more
+ }
+
+ if ( i == out.width ) {
+ continue; // didn't need subdivision
+ }
+
+ // insert two columns and replace the peak
+ out.height += 2;
+
+ for ( k = out.height - 1 ; k > j + 3 ; k-- ) {
+ originalHeights[k] = originalHeights[k-2];
+ }
+ originalHeights[j+3] = originalHeights[j+1];
+ originalHeights[j+2] = originalHeights[j+1];
+ originalHeights[j+1] = originalHeights[j];
+
+ for ( i = 0 ; i < out.width ; i++ ) {
+ LerpDrawVert( &expand[j][i], &expand[j+1][i], &prev );
+ LerpDrawVert( &expand[j+1][i], &expand[j+2][i], &next );
+ LerpDrawVert( &prev, &next, &mid );
+
+ for ( k = out.height - 1 ; k > j + 3 ; k-- ) {
+ expand[k][i] = expand[k-2][i];
+ }
+ expand[j+1][i] = prev;
+ expand[j+2][i] = mid;
+ expand[j+3][i] = next;
+ }
+
+ // back up and recheck this set again, it may need more subdivision
+ j -= 2;
+
+ }
+
+ // collapse the verts
+
+ out.verts = &expand[0][0];
+ for ( i = 1 ; i < out.height ; i++ ) {
+ memmove( &out.verts[i*out.width], expand[i], out.width * sizeof(drawVert_t) );
+ }
+
+ return CopyMesh(&out);
+}
+
+/*
+================
+ProjectPointOntoVector
+================
+*/
+void ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj )
+{
+ vec3_t pVec, vec;
+
+ VectorSubtract( point, vStart, pVec );
+ VectorSubtract( vEnd, vStart, vec );
+ VectorNormalize( vec, vec );
+ // project onto the directional vector for this segment
+ VectorMA( vStart, DotProduct( pVec, vec ), vec, vProj );
+}
+
+/*
+================
+RemoveLinearMeshColumsRows
+================
+*/
+mesh_t *RemoveLinearMeshColumnsRows( mesh_t *in ) {
+ int i, j, k;
+ float len, maxLength;
+ vec3_t proj, dir;
+ mesh_t out;
+ drawVert_t expand[MAX_EXPANDED_AXIS][MAX_EXPANDED_AXIS];
+
+ out.width = in->width;
+ out.height = in->height;
+
+ for ( i = 0 ; i < in->width ; i++ ) {
+ for ( j = 0 ; j < in->height ; j++ ) {
+ expand[j][i] = in->verts[j*in->width+i];
+ }
+ }
+
+ for ( j = 1 ; j < out.width - 1; j++ ) {
+ maxLength = 0;
+ for ( i = 0 ; i < out.height ; i++ ) {
+ ProjectPointOntoVector(expand[i][j].xyz, expand[i][j-1].xyz, expand[i][j+1].xyz, proj);
+ VectorSubtract(expand[i][j].xyz, proj, dir);
+ len = VectorLength(dir);
+ if (len > maxLength) {
+ maxLength = len;
+ }
+ }
+ if (maxLength < 0.1)
+ {
+ out.width--;
+ for ( i = 0 ; i < out.height ; i++ ) {
+ for (k = j; k < out.width; k++) {
+ expand[i][k] = expand[i][k+1];
+ }
+ }
+ for (k = j; k < out.width; k++) {
+ originalWidths[k] = originalWidths[k+1];
+ }
+ j--;
+ }
+ }
+ for ( j = 1 ; j < out.height - 1; j++ ) {
+ maxLength = 0;
+ for ( i = 0 ; i < out.width ; i++ ) {
+ ProjectPointOntoVector(expand[j][i].xyz, expand[j-1][i].xyz, expand[j+1][i].xyz, proj);
+ VectorSubtract(expand[j][i].xyz, proj, dir);
+ len = VectorLength(dir);
+ if (len > maxLength) {
+ maxLength = len;
+ }
+ }
+ if (maxLength < 0.1)
+ {
+ out.height--;
+ for ( i = 0 ; i < out.width ; i++ ) {
+ for (k = j; k < out.height; k++) {
+ expand[k][i] = expand[k+1][i];
+ }
+ }
+ for (k = j; k < out.height; k++) {
+ originalHeights[k] = originalHeights[k+1];
+ }
+ j--;
+ }
+ }
+ // collapse the verts
+ out.verts = &expand[0][0];
+ for ( i = 1 ; i < out.height ; i++ ) {
+ memmove( &out.verts[i*out.width], expand[i], out.width * sizeof(drawVert_t) );
+ }
+
+ return CopyMesh(&out);
+}
+
+/*
+============
+LerpDrawVertAmount
+============
+*/
+void LerpDrawVertAmount( drawVert_t *a, drawVert_t *b, float amount, drawVert_t *out ) {
+ out->xyz[0] = a->xyz[0] + amount * (b->xyz[0] - a->xyz[0]);
+ out->xyz[1] = a->xyz[1] + amount * (b->xyz[1] - a->xyz[1]);
+ out->xyz[2] = a->xyz[2] + amount * (b->xyz[2] - a->xyz[2]);
+
+ out->st[0] = a->st[0] + amount * (b->st[0] - a->st[0]);
+ out->st[1] = a->st[1] + amount * (b->st[1] - a->st[1]);
+
+ out->lightmap[0] = a->lightmap[0] + amount * (b->lightmap[0] - a->lightmap[0]);
+ out->lightmap[1] = a->lightmap[1] + amount * (b->lightmap[1] - a->lightmap[1]);
+
+ out->color[0] = a->color[0] + amount * (b->color[0] - a->color[0]);
+ out->color[1] = a->color[1] + amount * (b->color[1] - a->color[1]);
+ out->color[2] = a->color[2] + amount * (b->color[2] - a->color[2]);
+ out->color[3] = a->color[3] + amount * (b->color[3] - a->color[3]);
+
+ out->normal[0] = a->normal[0] + amount * (b->normal[0] - a->normal[0]);
+ out->normal[1] = a->normal[1] + amount * (b->normal[1] - a->normal[1]);
+ out->normal[2] = a->normal[2] + amount * (b->normal[2] - a->normal[2]);
+ VectorNormalize(out->normal, out->normal);
+}
+
+/*
+=================
+SubdivideMeshQuads
+=================
+*/
+mesh_t *SubdivideMeshQuads( mesh_t *in, float minLength, int maxsize, int widthtable[], int heighttable[]) {
+ int i, j, k, w, h, maxsubdivisions, subdivisions;
+ vec3_t dir;
+ float length, maxLength, amount;
+ mesh_t out;
+ drawVert_t expand[MAX_EXPANDED_AXIS][MAX_EXPANDED_AXIS];
+
+ out.width = in->width;
+ out.height = in->height;
+
+ for ( i = 0 ; i < in->width ; i++ ) {
+ for ( j = 0 ; j < in->height ; j++ ) {
+ expand[j][i] = in->verts[j*in->width+i];
+ }
+ }
+
+ if (maxsize > MAX_EXPANDED_AXIS)
+ Error("SubdivideMeshQuads: maxsize > MAX_EXPANDED_AXIS");
+
+ // horizontal subdivisions
+
+ maxsubdivisions = (maxsize - in->width) / (in->width - 1);
+
+ for ( w = 0, j = 0 ; w < in->width - 1; w++, j += subdivisions + 1) {
+ maxLength = 0;
+ for ( i = 0 ; i < out.height ; i++ ) {
+ VectorSubtract(expand[i][j+1].xyz, expand[i][j].xyz, dir);
+ length = VectorLength( dir );
+ if (length > maxLength) {
+ maxLength = length;
+ }
+ }
+
+ subdivisions = (int) (maxLength / minLength);
+ if (subdivisions > maxsubdivisions)
+ subdivisions = maxsubdivisions;
+
+ widthtable[w] = subdivisions + 1;
+ if (subdivisions <= 0)
+ continue;
+
+ out.width += subdivisions;
+
+ for ( k = out.width - 1; k >= j + subdivisions; k-- ) {
+ originalWidths[k] = originalWidths[k-subdivisions];
+ }
+ for (k = 1; k <= subdivisions; k++) {
+ originalWidths[j+k] = originalWidths[j];
+ }
+
+ for ( i = 0 ; i < out.height ; i++ ) {
+ for ( k = out.width - 1 ; k > j + subdivisions; k-- ) {
+ expand[i][k] = expand[i][k-subdivisions];
+ }
+ for (k = 1; k <= subdivisions; k++)
+ {
+ amount = (float) k / (subdivisions + 1);
+ LerpDrawVertAmount(&expand[i][j], &expand[i][j+subdivisions+1], amount, &expand[i][j+k]);
+ }
+ }
+ }
+
+ maxsubdivisions = (maxsize - in->height) / (in->height - 1);
+
+ for ( h = 0, j = 0 ; h < in->height - 1; h++, j += subdivisions + 1) {
+ maxLength = 0;
+ for ( i = 0 ; i < out.width ; i++ ) {
+ VectorSubtract(expand[j+1][i].xyz, expand[j][i].xyz, dir);
+ length = VectorLength( dir );
+ if (length > maxLength) {
+ maxLength = length;
+ }
+ }
+
+ subdivisions = (int) (maxLength / minLength);
+ if (subdivisions > maxsubdivisions)
+ subdivisions = maxsubdivisions;
+
+ heighttable[h] = subdivisions + 1;
+ if (subdivisions <= 0)
+ continue;
+
+ out.height += subdivisions;
+
+ for ( k = out.height - 1; k >= j + subdivisions; k-- ) {
+ originalHeights[k] = originalHeights[k-subdivisions];
+ }
+ for (k = 1; k <= subdivisions; k++) {
+ originalHeights[j+k] = originalHeights[j];
+ }
+
+ for ( i = 0 ; i < out.width ; i++ ) {
+ for ( k = out.height - 1 ; k > j + subdivisions; k-- ) {
+ expand[k][i] = expand[k-subdivisions][i];
+ }
+ for (k = 1; k <= subdivisions; k++)
+ {
+ amount = (float) k / (subdivisions + 1);
+ LerpDrawVertAmount(&expand[j][i], &expand[j+subdivisions+1][i], amount, &expand[j+k][i]);
+ }
+ }
+ }
+
+ // collapse the verts
+ out.verts = &expand[0][0];
+ for ( i = 1 ; i < out.height ; i++ ) {
+ memmove( &out.verts[i*out.width], expand[i], out.width * sizeof(drawVert_t) );
+ }
+
+ return CopyMesh(&out);
+}
diff --git a/q3map/mesh.h b/q3map/mesh.h
index 06f5684..ee338d4 100755
--- a/q3map/mesh.h
+++ b/q3map/mesh.h
@@ -19,30 +19,30 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-// mesh.h
-
-
-typedef struct {
- int width, height;
- drawVert_t *verts;
-} mesh_t;
-
-#define MAX_EXPANDED_AXIS 128
-
-extern int originalWidths[MAX_EXPANDED_AXIS];
-extern int originalHeights[MAX_EXPANDED_AXIS];
-
-void FreeMesh( mesh_t *m );
-mesh_t *CopyMesh( mesh_t *mesh );
-void PrintMesh( mesh_t *m );
-mesh_t *TransposeMesh( mesh_t *in );
-void InvertMesh( mesh_t *m );
-mesh_t *SubdivideMesh( mesh_t in, float maxError, float minLength );
-mesh_t *SubdivideMeshQuads( mesh_t *in, float minLength, int maxsize, int widthtable[], int heighttable[]);
-mesh_t *RemoveLinearMeshColumnsRows( mesh_t *in );
-void MakeMeshNormals( mesh_t in );
-void PutMeshOnCurve( mesh_t in );
-
-
-void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up);
+
+// mesh.h
+
+
+typedef struct {
+ int width, height;
+ drawVert_t *verts;
+} mesh_t;
+
+#define MAX_EXPANDED_AXIS 128
+
+extern int originalWidths[MAX_EXPANDED_AXIS];
+extern int originalHeights[MAX_EXPANDED_AXIS];
+
+void FreeMesh( mesh_t *m );
+mesh_t *CopyMesh( mesh_t *mesh );
+void PrintMesh( mesh_t *m );
+mesh_t *TransposeMesh( mesh_t *in );
+void InvertMesh( mesh_t *m );
+mesh_t *SubdivideMesh( mesh_t in, float maxError, float minLength );
+mesh_t *SubdivideMeshQuads( mesh_t *in, float minLength, int maxsize, int widthtable[], int heighttable[]);
+mesh_t *RemoveLinearMeshColumnsRows( mesh_t *in );
+void MakeMeshNormals( mesh_t in );
+void PutMeshOnCurve( mesh_t in );
+
+
+void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up);
diff --git a/q3map/misc_model.c b/q3map/misc_model.c
index c83e7e7..cd003d6 100755
--- a/q3map/misc_model.c
+++ b/q3map/misc_model.c
@@ -19,454 +19,454 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include "qbsp.h"
-#include "aselib.h"
-#ifdef _WIN32
-#ifdef _TTIMOBUILD
-#include "pakstuff.h"
-#else
-#include "../libs/pakstuff.h"
-#endif
-#endif
-
-
-typedef struct {
- char modelName[1024];
- md3Header_t *header;
-} loadedModel_t;
-
-int c_triangleModels;
-int c_triangleSurfaces;
-int c_triangleVertexes;
-int c_triangleIndexes;
-
-
-#define MAX_LOADED_MODELS 1024
-loadedModel_t loadedModels[MAX_LOADED_MODELS];
-int numLoadedModels;
-
-/*
-=================
-R_LoadMD3
-=================
-*/
-#define LL(x) x=LittleLong(x)
-md3Header_t *R_LoadMD3( const char *mod_name ) {
- int i, j;
- md3Header_t *md3;
- md3Frame_t *frame;
- md3Surface_t *surf;
- md3Triangle_t *tri;
- md3St_t *st;
- md3XyzNormal_t *xyz;
- int version;
- char filename[1024];
- int len;
-
- sprintf( filename, "%s%s", gamedir, mod_name );
- len = TryLoadFile( filename, (void **)&md3 );
-#ifdef _WIN32
- if ( len <= 0 ) {
- len = PakLoadAnyFile(filename, (void **)&md3);
- }
-#endif
- if ( len <= 0 ) {
- return NULL;
- }
-
- version = LittleLong (md3->version);
- if (version != MD3_VERSION) {
- _printf( "R_LoadMD3: %s has wrong version (%i should be %i)\n",
- mod_name, version, MD3_VERSION);
- return NULL;
- }
-
- LL(md3->ident);
- LL(md3->version);
- LL(md3->numFrames);
- LL(md3->numTags);
- LL(md3->numSurfaces);
- LL(md3->numSkins);
- LL(md3->ofsFrames);
- LL(md3->ofsTags);
- LL(md3->ofsSurfaces);
- LL(md3->ofsEnd);
-
- if ( md3->numFrames < 1 ) {
- _printf( "R_LoadMD3: %s has no frames\n", mod_name );
- return NULL;
- }
-
- // we don't need to swap tags in the renderer, they aren't used
-
- // swap all the frames
- frame = (md3Frame_t *) ( (byte *)md3 + md3->ofsFrames );
- for ( i = 0 ; i < md3->numFrames ; i++, frame++) {
- frame->radius = LittleFloat( frame->radius );
- for ( j = 0 ; j < 3 ; j++ ) {
- frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
- frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
- frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
- }
- }
-
- // swap all the surfaces
- surf = (md3Surface_t *) ( (byte *)md3 + md3->ofsSurfaces );
- for ( i = 0 ; i < md3->numSurfaces ; i++) {
-
- LL(surf->ident);
- LL(surf->flags);
- LL(surf->numFrames);
- LL(surf->numShaders);
- LL(surf->numTriangles);
- LL(surf->ofsTriangles);
- LL(surf->numVerts);
- LL(surf->ofsShaders);
- LL(surf->ofsSt);
- LL(surf->ofsXyzNormals);
- LL(surf->ofsEnd);
-
- if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
- Error ("R_LoadMD3: %s has more than %i verts on a surface (%i)",
- mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
- }
- if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
- Error ("R_LoadMD3: %s has more than %i triangles on a surface (%i)",
- mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
- }
-
- // swap all the triangles
- tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
- for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
- LL(tri->indexes[0]);
- LL(tri->indexes[1]);
- LL(tri->indexes[2]);
- }
-
- // swap all the ST
- st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
- for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
- st->st[0] = LittleFloat( st->st[0] );
- st->st[1] = LittleFloat( st->st[1] );
- }
-
- // swap all the XyzNormals
- xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
- for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ )
- {
- xyz->xyz[0] = LittleShort( xyz->xyz[0] );
- xyz->xyz[1] = LittleShort( xyz->xyz[1] );
- xyz->xyz[2] = LittleShort( xyz->xyz[2] );
-
- xyz->normal = LittleShort( xyz->normal );
- }
-
-
- // find the next surface
- surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
- }
-
- return md3;
-}
-
-
-/*
-================
-LoadModel
-================
-*/
-md3Header_t *LoadModel( const char *modelName ) {
- int i;
- loadedModel_t *lm;
-
- // see if we already have it loaded
- for ( i = 0, lm = loadedModels ; i < numLoadedModels ; i++, lm++ ) {
- if ( !strcmp( modelName, lm->modelName ) ) {
- return lm->header;
- }
- }
-
- // load it
- if ( numLoadedModels == MAX_LOADED_MODELS ) {
- Error( "MAX_LOADED_MODELS" );
- }
- numLoadedModels++;
-
- strcpy( lm->modelName, modelName );
-
- lm->header = R_LoadMD3( modelName );
-
- return lm->header;
-}
-
-/*
-============
-InsertMD3Model
-
-Convert a model entity to raw geometry surfaces and insert it in the tree
-============
-*/
-void InsertMD3Model( const char *modelName, vec3_t origin, float angle, tree_t *tree ) {
- int i, j;
- md3Header_t *md3;
- md3Surface_t *surf;
- md3Shader_t *shader;
- md3Triangle_t *tri;
- md3St_t *st;
- md3XyzNormal_t *xyz;
- drawVert_t *outv;
- float lat, lng;
- float angleCos, angleSin;
- mapDrawSurface_t *out;
- vec3_t temp;
-
- angle = angle / 180 * Q_PI;
- angleCos = cos( angle );
- angleSin = sin( angle );
-
- // load the model
- md3 = LoadModel( modelName );
- if ( !md3 ) {
- return;
- }
-
- // each md3 surface will become a new bsp surface
-
- c_triangleModels++;
- c_triangleSurfaces += md3->numSurfaces;
-
- // expand, translate, and rotate the vertexes
- // swap all the surfaces
- surf = (md3Surface_t *) ( (byte *)md3 + md3->ofsSurfaces );
- for ( i = 0 ; i < md3->numSurfaces ; i++) {
- // allocate a surface
- out = AllocDrawSurf();
- out->miscModel = qtrue;
-
- shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
-
- out->shaderInfo = ShaderInfoForShader( shader->name );
-
- out->numVerts = surf->numVerts;
- out->verts = malloc( out->numVerts * sizeof( out->verts[0] ) );
-
- out->numIndexes = surf->numTriangles * 3;
- out->indexes = malloc( out->numIndexes * sizeof( out->indexes[0] ) );
-
- out->lightmapNum = -1;
- out->fogNum = -1;
-
- // emit the indexes
- c_triangleIndexes += surf->numTriangles * 3;
- tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
- for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
- out->indexes[j*3+0] = tri->indexes[0];
- out->indexes[j*3+1] = tri->indexes[1];
- out->indexes[j*3+2] = tri->indexes[2];
- }
-
- // emit the vertexes
- st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
- xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
-
- c_triangleVertexes += surf->numVerts;
- for ( j = 0 ; j < surf->numVerts ; j++, st++, xyz++ ) {
- outv = &out->verts[ j ];
-
- outv->st[0] = st->st[0];
- outv->st[1] = st->st[1];
-
- outv->lightmap[0] = 0;
- outv->lightmap[1] = 0;
-
- // the colors will be set by the lighting pass
- outv->color[0] = 255;
- outv->color[1] = 255;
- outv->color[2] = 255;
- outv->color[3] = 255;
-
- outv->xyz[0] = origin[0] + MD3_XYZ_SCALE * ( xyz->xyz[0] * angleCos - xyz->xyz[1] * angleSin );
- outv->xyz[1] = origin[1] + MD3_XYZ_SCALE * ( xyz->xyz[0] * angleSin + xyz->xyz[1] * angleCos );
- outv->xyz[2] = origin[2] + MD3_XYZ_SCALE * ( xyz->xyz[2] );
-
- // decode the lat/lng normal to a 3 float normal
- lat = ( xyz->normal >> 8 ) & 0xff;
- lng = ( xyz->normal & 0xff );
- lat *= Q_PI/128;
- lng *= Q_PI/128;
-
- temp[0] = cos(lat) * sin(lng);
- temp[1] = sin(lat) * sin(lng);
- temp[2] = cos(lng);
-
- // rotate the normal
- outv->normal[0] = temp[0] * angleCos - temp[1] * angleSin;
- outv->normal[1] = temp[0] * angleSin + temp[1] * angleCos;
- outv->normal[2] = temp[2];
- }
-
- // find the next surface
- surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
- }
-
-}
-
-//==============================================================================
-
-
-/*
-============
-InsertASEModel
-
-Convert a model entity to raw geometry surfaces and insert it in the tree
-============
-*/
-void InsertASEModel( const char *modelName, vec3_t origin, float angle, tree_t *tree ) {
- int i, j;
- drawVert_t *outv;
- float angleCos, angleSin;
- mapDrawSurface_t *out;
- int numSurfaces;
- const char *name;
- polyset_t *pset;
- int numFrames;
- char filename[1024];
-
- sprintf( filename, "%s%s", gamedir, modelName );
-
- angle = angle / 180 * Q_PI;
- angleCos = cos( angle );
- angleSin = sin( angle );
-
- // load the model
- ASE_Load( filename, qfalse, qfalse );
-
- // each ase surface will become a new bsp surface
- numSurfaces = ASE_GetNumSurfaces();
-
- c_triangleModels++;
- c_triangleSurfaces += numSurfaces;
-
- // expand, translate, and rotate the vertexes
- // swap all the surfaces
- for ( i = 0 ; i < numSurfaces ; i++) {
- name = ASE_GetSurfaceName( i );
-
- pset = ASE_GetSurfaceAnimation( i, &numFrames, -1, -1, -1 );
- if ( !name || !pset ) {
- continue;
- }
-
- // allocate a surface
- out = AllocDrawSurf();
- out->miscModel = qtrue;
-
- out->shaderInfo = ShaderInfoForShader( pset->materialname );
-
- out->numVerts = 3 * pset->numtriangles;
- out->verts = malloc( out->numVerts * sizeof( out->verts[0] ) );
-
- out->numIndexes = 3 * pset->numtriangles;
- out->indexes = malloc( out->numIndexes * sizeof( out->indexes[0] ) );
-
- out->lightmapNum = -1;
- out->fogNum = -1;
-
- // emit the indexes
- c_triangleIndexes += out->numIndexes;
- for ( j = 0 ; j < out->numIndexes ; j++ ) {
- out->indexes[j] = j;
- }
-
- // emit the vertexes
- c_triangleVertexes += out->numVerts;
- for ( j = 0 ; j < out->numVerts ; j++ ) {
- int index;
- triangle_t *tri;
-
- index = j % 3;
- tri = &pset->triangles[ j / 3 ];
-
- outv = &out->verts[ j ];
-
- outv->st[0] = tri->texcoords[index][0];
- outv->st[1] = tri->texcoords[index][1];
-
- outv->lightmap[0] = 0;
- outv->lightmap[1] = 0;
-
- // the colors will be set by the lighting pass
- outv->color[0] = 255;
- outv->color[1] = 255;
- outv->color[2] = 255;
- outv->color[3] = 255;
-
- outv->xyz[0] = origin[0] + tri->verts[index][0];
- outv->xyz[1] = origin[1] + tri->verts[index][1];
- outv->xyz[2] = origin[2] + tri->verts[index][2];
-
- // rotate the normal
- outv->normal[0] = tri->normals[index][0];
- outv->normal[1] = tri->normals[index][1];
- outv->normal[2] = tri->normals[index][2];
- }
- }
-
-}
-
-
-//==============================================================================
-
-
-
-/*
-=====================
-AddTriangleModels
-=====================
-*/
-void AddTriangleModels( tree_t *tree ) {
- int entity_num;
- entity_t *entity;
-
- qprintf("----- AddTriangleModels -----\n");
-
- for ( entity_num=1 ; entity_num< num_entities ; entity_num++ ) {
- entity = &entities[entity_num];
-
- // convert misc_models into raw geometry
- if ( !Q_stricmp( "misc_model", ValueForKey( entity, "classname" ) ) ) {
- const char *model;
- vec3_t origin;
- float angle;
-
- // get the angle for rotation FIXME: support full matrix positioning
- angle = FloatForKey( entity, "angle" );
-
- GetVectorForKey( entity, "origin", origin );
-
- model = ValueForKey( entity, "model" );
- if ( !model[0] ) {
- _printf("WARNING: misc_model at %i %i %i without a model key\n", (int)origin[0],
- (int)origin[1], (int)origin[2] );
- continue;
- }
- if ( strstr( model, ".md3" ) || strstr( model, ".MD3" ) ) {
- InsertMD3Model( model, origin, angle, tree );
- continue;
- }
- if ( strstr( model, ".ase" ) || strstr( model, ".ASE" ) ) {
- InsertASEModel( model, origin, angle, tree );
- continue;
- }
- _printf( "Unknown misc_model type: %s\n", model );
- continue;
- }
- }
-
- qprintf( "%5i triangle models\n", c_triangleModels );
- qprintf( "%5i triangle surfaces\n", c_triangleSurfaces );
- qprintf( "%5i triangle vertexes\n", c_triangleVertexes );
- qprintf( "%5i triangle indexes\n", c_triangleIndexes );
-}
-
+
+#include "qbsp.h"
+#include "aselib.h"
+#ifdef _WIN32
+#ifdef _TTIMOBUILD
+#include "pakstuff.h"
+#else
+#include "../libs/pakstuff.h"
+#endif
+#endif
+
+
+typedef struct {
+ char modelName[1024];
+ md3Header_t *header;
+} loadedModel_t;
+
+int c_triangleModels;
+int c_triangleSurfaces;
+int c_triangleVertexes;
+int c_triangleIndexes;
+
+
+#define MAX_LOADED_MODELS 1024
+loadedModel_t loadedModels[MAX_LOADED_MODELS];
+int numLoadedModels;
+
+/*
+=================
+R_LoadMD3
+=================
+*/
+#define LL(x) x=LittleLong(x)
+md3Header_t *R_LoadMD3( const char *mod_name ) {
+ int i, j;
+ md3Header_t *md3;
+ md3Frame_t *frame;
+ md3Surface_t *surf;
+ md3Triangle_t *tri;
+ md3St_t *st;
+ md3XyzNormal_t *xyz;
+ int version;
+ char filename[1024];
+ int len;
+
+ sprintf( filename, "%s%s", gamedir, mod_name );
+ len = TryLoadFile( filename, (void **)&md3 );
+#ifdef _WIN32
+ if ( len <= 0 ) {
+ len = PakLoadAnyFile(filename, (void **)&md3);
+ }
+#endif
+ if ( len <= 0 ) {
+ return NULL;
+ }
+
+ version = LittleLong (md3->version);
+ if (version != MD3_VERSION) {
+ _printf( "R_LoadMD3: %s has wrong version (%i should be %i)\n",
+ mod_name, version, MD3_VERSION);
+ return NULL;
+ }
+
+ LL(md3->ident);
+ LL(md3->version);
+ LL(md3->numFrames);
+ LL(md3->numTags);
+ LL(md3->numSurfaces);
+ LL(md3->numSkins);
+ LL(md3->ofsFrames);
+ LL(md3->ofsTags);
+ LL(md3->ofsSurfaces);
+ LL(md3->ofsEnd);
+
+ if ( md3->numFrames < 1 ) {
+ _printf( "R_LoadMD3: %s has no frames\n", mod_name );
+ return NULL;
+ }
+
+ // we don't need to swap tags in the renderer, they aren't used
+
+ // swap all the frames
+ frame = (md3Frame_t *) ( (byte *)md3 + md3->ofsFrames );
+ for ( i = 0 ; i < md3->numFrames ; i++, frame++) {
+ frame->radius = LittleFloat( frame->radius );
+ for ( j = 0 ; j < 3 ; j++ ) {
+ frame->bounds[0][j] = LittleFloat( frame->bounds[0][j] );
+ frame->bounds[1][j] = LittleFloat( frame->bounds[1][j] );
+ frame->localOrigin[j] = LittleFloat( frame->localOrigin[j] );
+ }
+ }
+
+ // swap all the surfaces
+ surf = (md3Surface_t *) ( (byte *)md3 + md3->ofsSurfaces );
+ for ( i = 0 ; i < md3->numSurfaces ; i++) {
+
+ LL(surf->ident);
+ LL(surf->flags);
+ LL(surf->numFrames);
+ LL(surf->numShaders);
+ LL(surf->numTriangles);
+ LL(surf->ofsTriangles);
+ LL(surf->numVerts);
+ LL(surf->ofsShaders);
+ LL(surf->ofsSt);
+ LL(surf->ofsXyzNormals);
+ LL(surf->ofsEnd);
+
+ if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
+ Error ("R_LoadMD3: %s has more than %i verts on a surface (%i)",
+ mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
+ }
+ if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
+ Error ("R_LoadMD3: %s has more than %i triangles on a surface (%i)",
+ mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
+ }
+
+ // swap all the triangles
+ tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
+ for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
+ LL(tri->indexes[0]);
+ LL(tri->indexes[1]);
+ LL(tri->indexes[2]);
+ }
+
+ // swap all the ST
+ st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
+ for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
+ st->st[0] = LittleFloat( st->st[0] );
+ st->st[1] = LittleFloat( st->st[1] );
+ }
+
+ // swap all the XyzNormals
+ xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
+ for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ )
+ {
+ xyz->xyz[0] = LittleShort( xyz->xyz[0] );
+ xyz->xyz[1] = LittleShort( xyz->xyz[1] );
+ xyz->xyz[2] = LittleShort( xyz->xyz[2] );
+
+ xyz->normal = LittleShort( xyz->normal );
+ }
+
+
+ // find the next surface
+ surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
+ }
+
+ return md3;
+}
+
+
+/*
+================
+LoadModel
+================
+*/
+md3Header_t *LoadModel( const char *modelName ) {
+ int i;
+ loadedModel_t *lm;
+
+ // see if we already have it loaded
+ for ( i = 0, lm = loadedModels ; i < numLoadedModels ; i++, lm++ ) {
+ if ( !strcmp( modelName, lm->modelName ) ) {
+ return lm->header;
+ }
+ }
+
+ // load it
+ if ( numLoadedModels == MAX_LOADED_MODELS ) {
+ Error( "MAX_LOADED_MODELS" );
+ }
+ numLoadedModels++;
+
+ strcpy( lm->modelName, modelName );
+
+ lm->header = R_LoadMD3( modelName );
+
+ return lm->header;
+}
+
+/*
+============
+InsertMD3Model
+
+Convert a model entity to raw geometry surfaces and insert it in the tree
+============
+*/
+void InsertMD3Model( const char *modelName, vec3_t origin, float angle, tree_t *tree ) {
+ int i, j;
+ md3Header_t *md3;
+ md3Surface_t *surf;
+ md3Shader_t *shader;
+ md3Triangle_t *tri;
+ md3St_t *st;
+ md3XyzNormal_t *xyz;
+ drawVert_t *outv;
+ float lat, lng;
+ float angleCos, angleSin;
+ mapDrawSurface_t *out;
+ vec3_t temp;
+
+ angle = angle / 180 * Q_PI;
+ angleCos = cos( angle );
+ angleSin = sin( angle );
+
+ // load the model
+ md3 = LoadModel( modelName );
+ if ( !md3 ) {
+ return;
+ }
+
+ // each md3 surface will become a new bsp surface
+
+ c_triangleModels++;
+ c_triangleSurfaces += md3->numSurfaces;
+
+ // expand, translate, and rotate the vertexes
+ // swap all the surfaces
+ surf = (md3Surface_t *) ( (byte *)md3 + md3->ofsSurfaces );
+ for ( i = 0 ; i < md3->numSurfaces ; i++) {
+ // allocate a surface
+ out = AllocDrawSurf();
+ out->miscModel = qtrue;
+
+ shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
+
+ out->shaderInfo = ShaderInfoForShader( shader->name );
+
+ out->numVerts = surf->numVerts;
+ out->verts = malloc( out->numVerts * sizeof( out->verts[0] ) );
+
+ out->numIndexes = surf->numTriangles * 3;
+ out->indexes = malloc( out->numIndexes * sizeof( out->indexes[0] ) );
+
+ out->lightmapNum = -1;
+ out->fogNum = -1;
+
+ // emit the indexes
+ c_triangleIndexes += surf->numTriangles * 3;
+ tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
+ for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
+ out->indexes[j*3+0] = tri->indexes[0];
+ out->indexes[j*3+1] = tri->indexes[1];
+ out->indexes[j*3+2] = tri->indexes[2];
+ }
+
+ // emit the vertexes
+ st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
+ xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
+
+ c_triangleVertexes += surf->numVerts;
+ for ( j = 0 ; j < surf->numVerts ; j++, st++, xyz++ ) {
+ outv = &out->verts[ j ];
+
+ outv->st[0] = st->st[0];
+ outv->st[1] = st->st[1];
+
+ outv->lightmap[0] = 0;
+ outv->lightmap[1] = 0;
+
+ // the colors will be set by the lighting pass
+ outv->color[0] = 255;
+ outv->color[1] = 255;
+ outv->color[2] = 255;
+ outv->color[3] = 255;
+
+ outv->xyz[0] = origin[0] + MD3_XYZ_SCALE * ( xyz->xyz[0] * angleCos - xyz->xyz[1] * angleSin );
+ outv->xyz[1] = origin[1] + MD3_XYZ_SCALE * ( xyz->xyz[0] * angleSin + xyz->xyz[1] * angleCos );
+ outv->xyz[2] = origin[2] + MD3_XYZ_SCALE * ( xyz->xyz[2] );
+
+ // decode the lat/lng normal to a 3 float normal
+ lat = ( xyz->normal >> 8 ) & 0xff;
+ lng = ( xyz->normal & 0xff );
+ lat *= Q_PI/128;
+ lng *= Q_PI/128;
+
+ temp[0] = cos(lat) * sin(lng);
+ temp[1] = sin(lat) * sin(lng);
+ temp[2] = cos(lng);
+
+ // rotate the normal
+ outv->normal[0] = temp[0] * angleCos - temp[1] * angleSin;
+ outv->normal[1] = temp[0] * angleSin + temp[1] * angleCos;
+ outv->normal[2] = temp[2];
+ }
+
+ // find the next surface
+ surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
+ }
+
+}
+
+//==============================================================================
+
+
+/*
+============
+InsertASEModel
+
+Convert a model entity to raw geometry surfaces and insert it in the tree
+============
+*/
+void InsertASEModel( const char *modelName, vec3_t origin, float angle, tree_t *tree ) {
+ int i, j;
+ drawVert_t *outv;
+ float angleCos, angleSin;
+ mapDrawSurface_t *out;
+ int numSurfaces;
+ const char *name;
+ polyset_t *pset;
+ int numFrames;
+ char filename[1024];
+
+ sprintf( filename, "%s%s", gamedir, modelName );
+
+ angle = angle / 180 * Q_PI;
+ angleCos = cos( angle );
+ angleSin = sin( angle );
+
+ // load the model
+ ASE_Load( filename, qfalse, qfalse );
+
+ // each ase surface will become a new bsp surface
+ numSurfaces = ASE_GetNumSurfaces();
+
+ c_triangleModels++;
+ c_triangleSurfaces += numSurfaces;
+
+ // expand, translate, and rotate the vertexes
+ // swap all the surfaces
+ for ( i = 0 ; i < numSurfaces ; i++) {
+ name = ASE_GetSurfaceName( i );
+
+ pset = ASE_GetSurfaceAnimation( i, &numFrames, -1, -1, -1 );
+ if ( !name || !pset ) {
+ continue;
+ }
+
+ // allocate a surface
+ out = AllocDrawSurf();
+ out->miscModel = qtrue;
+
+ out->shaderInfo = ShaderInfoForShader( pset->materialname );
+
+ out->numVerts = 3 * pset->numtriangles;
+ out->verts = malloc( out->numVerts * sizeof( out->verts[0] ) );
+
+ out->numIndexes = 3 * pset->numtriangles;
+ out->indexes = malloc( out->numIndexes * sizeof( out->indexes[0] ) );
+
+ out->lightmapNum = -1;
+ out->fogNum = -1;
+
+ // emit the indexes
+ c_triangleIndexes += out->numIndexes;
+ for ( j = 0 ; j < out->numIndexes ; j++ ) {
+ out->indexes[j] = j;
+ }
+
+ // emit the vertexes
+ c_triangleVertexes += out->numVerts;
+ for ( j = 0 ; j < out->numVerts ; j++ ) {
+ int index;
+ triangle_t *tri;
+
+ index = j % 3;
+ tri = &pset->triangles[ j / 3 ];
+
+ outv = &out->verts[ j ];
+
+ outv->st[0] = tri->texcoords[index][0];
+ outv->st[1] = tri->texcoords[index][1];
+
+ outv->lightmap[0] = 0;
+ outv->lightmap[1] = 0;
+
+ // the colors will be set by the lighting pass
+ outv->color[0] = 255;
+ outv->color[1] = 255;
+ outv->color[2] = 255;
+ outv->color[3] = 255;
+
+ outv->xyz[0] = origin[0] + tri->verts[index][0];
+ outv->xyz[1] = origin[1] + tri->verts[index][1];
+ outv->xyz[2] = origin[2] + tri->verts[index][2];
+
+ // rotate the normal
+ outv->normal[0] = tri->normals[index][0];
+ outv->normal[1] = tri->normals[index][1];
+ outv->normal[2] = tri->normals[index][2];
+ }
+ }
+
+}
+
+
+//==============================================================================
+
+
+
+/*
+=====================
+AddTriangleModels
+=====================
+*/
+void AddTriangleModels( tree_t *tree ) {
+ int entity_num;
+ entity_t *entity;
+
+ qprintf("----- AddTriangleModels -----\n");
+
+ for ( entity_num=1 ; entity_num< num_entities ; entity_num++ ) {
+ entity = &entities[entity_num];
+
+ // convert misc_models into raw geometry
+ if ( !Q_stricmp( "misc_model", ValueForKey( entity, "classname" ) ) ) {
+ const char *model;
+ vec3_t origin;
+ float angle;
+
+ // get the angle for rotation FIXME: support full matrix positioning
+ angle = FloatForKey( entity, "angle" );
+
+ GetVectorForKey( entity, "origin", origin );
+
+ model = ValueForKey( entity, "model" );
+ if ( !model[0] ) {
+ _printf("WARNING: misc_model at %i %i %i without a model key\n", (int)origin[0],
+ (int)origin[1], (int)origin[2] );
+ continue;
+ }
+ if ( strstr( model, ".md3" ) || strstr( model, ".MD3" ) ) {
+ InsertMD3Model( model, origin, angle, tree );
+ continue;
+ }
+ if ( strstr( model, ".ase" ) || strstr( model, ".ASE" ) ) {
+ InsertASEModel( model, origin, angle, tree );
+ continue;
+ }
+ _printf( "Unknown misc_model type: %s\n", model );
+ continue;
+ }
+ }
+
+ qprintf( "%5i triangle models\n", c_triangleModels );
+ qprintf( "%5i triangle surfaces\n", c_triangleSurfaces );
+ qprintf( "%5i triangle vertexes\n", c_triangleVertexes );
+ qprintf( "%5i triangle indexes\n", c_triangleIndexes );
+}
+
diff --git a/q3map/nodraw.c b/q3map/nodraw.c
index 9931f27..7503a48 100755
--- a/q3map/nodraw.c
+++ b/q3map/nodraw.c
@@ -19,29 +19,29 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include "qbsp.h"
-
-vec3_t draw_mins, draw_maxs;
-qboolean drawflag;
-
-void Draw_ClearWindow (void)
-{
-}
-
-//============================================================
-
-#define GLSERV_PORT 25001
-
-
-void GLS_BeginScene (void)
-{
-}
-
-void GLS_Winding (winding_t *w, int code)
-{
-}
-
-void GLS_EndScene (void)
-{
-}
+
+#include "qbsp.h"
+
+vec3_t draw_mins, draw_maxs;
+qboolean drawflag;
+
+void Draw_ClearWindow (void)
+{
+}
+
+//============================================================
+
+#define GLSERV_PORT 25001
+
+
+void GLS_BeginScene (void)
+{
+}
+
+void GLS_Winding (winding_t *w, int code)
+{
+}
+
+void GLS_EndScene (void)
+{
+}
diff --git a/q3map/patch.c b/q3map/patch.c
index 5dbd354..df461d6 100755
--- a/q3map/patch.c
+++ b/q3map/patch.c
@@ -19,268 +19,268 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-#include "qbsp.h"
-
-
-void PrintCtrl( vec3_t ctrl[9] ) {
- int i, j;
-
- for ( i = 0 ; i < 3 ; i++ ) {
- for ( j = 0 ; j < 3 ; j++ ) {
- _printf("(%5.2f %5.2f %5.2f) ", ctrl[i*3+j][0], ctrl[i*3+j][1], ctrl[i*3+j][2] );
- }
- _printf("\n");
- }
-}
-
-/*
-================
-DrawSurfaceForMesh
-================
-*/
-mapDrawSurface_t *DrawSurfaceForMesh( mesh_t *m ) {
- mapDrawSurface_t *ds;
- int i, j;
- mesh_t *copy;
-
- // to make valid normals for patches with degenerate edges,
- // we need to make a copy of the mesh and put the aproximating
- // points onto the curve
- copy = CopyMesh( m );
- PutMeshOnCurve( *copy );
- MakeMeshNormals( *copy );
- for ( j = 0 ; j < m->width ; j++ ) {
- for ( i = 0 ; i < m->height ; i++ ) {
- VectorCopy( copy->verts[i*m->width+j].normal, m->verts[i*m->width+j].normal );
- }
- }
- FreeMesh( copy );
-
- ds = AllocDrawSurf();
- ds->mapBrush = NULL;
- ds->side = NULL;
-
- ds->patch = qtrue;
- ds->patchWidth = m->width;
- ds->patchHeight = m->height;
- ds->numVerts = ds->patchWidth * ds->patchHeight;
- ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
- memcpy( ds->verts, m->verts, ds->numVerts * sizeof( *ds->verts ) );
-
- ds->lightmapNum = -1;
- ds->fogNum = -1;
-
- return ds;
-}
-
-/*
-=================
-ParsePatch
-
-Creates a mapDrawSurface_t from the patch text
-=================
-*/
-void ParsePatch( void ) {
- vec_t info[5];
- int i, j;
- parseMesh_t *pm;
- char texture[MAX_QPATH];
- char shader[MAX_QPATH];
- mesh_t m;
- drawVert_t *verts;
- epair_t *ep;
-
- MatchToken( "{" );
-
- // get texture
- GetToken (qtrue);
- strcpy( texture, token );
-
- // save the shader name for retexturing
- if ( numMapIndexedShaders == MAX_MAP_BRUSHSIDES ) {
- Error( "MAX_MAP_BRUSHSIDES" );
- }
- strcpy( mapIndexedShaders[numMapIndexedShaders], texture );
- numMapIndexedShaders++;
-
-
- Parse1DMatrix( 5, info );
- m.width = info[0];
- m.height = info[1];
- m.verts = verts = malloc( m.width * m.height * sizeof( m.verts[0] ) );
-
- if ( m.width < 0 || m.width > MAX_PATCH_SIZE
- || m.height < 0 || m.height > MAX_PATCH_SIZE ) {
- Error("ParsePatch: bad size");
- }
-
- MatchToken( "(" );
- for ( j = 0 ; j < m.width ; j++ ) {
- MatchToken( "(" );
- for ( i = 0 ; i < m.height ; i++ ) {
- Parse1DMatrix( 5, verts[i*m.width+j].xyz );
- }
- MatchToken( ")" );
- }
- MatchToken( ")" );
-
- // if brush primitives format, we may have some epairs to ignore here
- GetToken(qtrue);
- if (g_bBrushPrimit!=BPRIMIT_OLDBRUSHES && strcmp(token,"}"))
- {
- // NOTE: we leak that!
- ep = ParseEpair();
- }
- else
- UnGetToken();
-
- MatchToken( "}" );
- MatchToken( "}" );
-
- if ( noCurveBrushes ) {
- return;
- }
-
- // find default flags and values
- pm = malloc( sizeof( *pm ) );
- memset( pm, 0, sizeof( *pm ) );
-
- sprintf( shader, "textures/%s", texture );
- pm->shaderInfo = ShaderInfoForShader( shader );
- pm->mesh = m;
-
- // link to the entity
- pm->next = mapent->patches;
- mapent->patches = pm;
-}
-
-
-void GrowGroup_r( int patchNum, int patchCount, const byte *bordering, byte *group ) {
- int i;
- const byte *row;
-
- if ( group[patchNum] ) {
- return;
- }
- group[patchNum] = 1;
- row = bordering + patchNum * patchCount;
- for ( i = 0 ; i < patchCount ; i++ ) {
- if ( row[i] ) {
- GrowGroup_r( i, patchCount, bordering, group );
- }
- }
-}
-
-
-/*
-=====================
-PatchMapDrawSurfs
-
-Any patches that share an edge need to choose their
-level of detail as a unit, otherwise the edges would
-pull apart.
-=====================
-*/
-void PatchMapDrawSurfs( entity_t *e ) {
- parseMesh_t *pm;
- parseMesh_t *check, *scan;
- mapDrawSurface_t *ds;
- int patchCount, groupCount;
- int i, j, k, l, c1, c2;
- drawVert_t *v1, *v2;
- vec3_t bounds[2];
- byte *bordering;
- parseMesh_t *meshes[MAX_MAP_DRAW_SURFS];
- qboolean grouped[MAX_MAP_DRAW_SURFS];
- byte group[MAX_MAP_DRAW_SURFS];
-
- qprintf( "----- PatchMapDrawSurfs -----\n" );
-
- patchCount = 0;
- for ( pm = e->patches ; pm ; pm = pm->next ) {
- meshes[patchCount] = pm;
- patchCount++;
- }
-
- if ( !patchCount ) {
- return;
- }
- bordering = malloc( patchCount * patchCount );
- memset( bordering, 0, patchCount * patchCount );
-
- // build the bordering matrix
- for ( k = 0 ; k < patchCount ; k++ ) {
- bordering[k*patchCount+k] = 1;
-
- for ( l = k+1 ; l < patchCount ; l++ ) {
- check = meshes[k];
- scan = meshes[l];
- c1 = scan->mesh.width * scan->mesh.height;
- v1 = scan->mesh.verts;
-
- for ( i = 0 ; i < c1 ; i++, v1++ ) {
- c2 = check->mesh.width * check->mesh.height;
- v2 = check->mesh.verts;
- for ( j = 0 ; j < c2 ; j++, v2++ ) {
- if ( fabs( v1->xyz[0] - v2->xyz[0] ) < 1.0
- && fabs( v1->xyz[1] - v2->xyz[1] ) < 1.0
- && fabs( v1->xyz[2] - v2->xyz[2] ) < 1.0 ) {
- break;
- }
- }
- if ( j != c2 ) {
- break;
- }
- }
- if ( i != c1 ) {
- // we have a connection
- bordering[k*patchCount+l] =
- bordering[l*patchCount+k] = 1;
- } else {
- // no connection
- bordering[k*patchCount+l] =
- bordering[l*patchCount+k] = 0;
- }
-
- }
- }
-
- // build groups
- memset( grouped, 0, sizeof(grouped) );
- groupCount = 0;
- for ( i = 0 ; i < patchCount ; i++ ) {
- if ( !grouped[i] ) {
- groupCount++;
- }
-
- // recursively find all patches that belong in the same group
- memset( group, 0, patchCount );
- GrowGroup_r( i, patchCount, bordering, group );
-
- // bound them
- ClearBounds( bounds[0], bounds[1] );
- for ( j = 0 ; j < patchCount ; j++ ) {
- if ( group[j] ) {
- grouped[j] = qtrue;
- scan = meshes[j];
- c1 = scan->mesh.width * scan->mesh.height;
- v1 = scan->mesh.verts;
- for ( k = 0 ; k < c1 ; k++, v1++ ) {
- AddPointToBounds( v1->xyz, bounds[0], bounds[1] );
- }
- }
- }
-
- // create drawsurf
- scan = meshes[i];
- scan->grouped = qtrue;
- ds = DrawSurfaceForMesh( &scan->mesh );
- ds->shaderInfo = scan->shaderInfo;
- VectorCopy( bounds[0], ds->lightmapVecs[0] );
- VectorCopy( bounds[1], ds->lightmapVecs[1] );
- }
-
- qprintf( "%5i patches\n", patchCount );
- qprintf( "%5i patch LOD groups\n", groupCount );
-}
-
+#include "qbsp.h"
+
+
+void PrintCtrl( vec3_t ctrl[9] ) {
+ int i, j;
+
+ for ( i = 0 ; i < 3 ; i++ ) {
+ for ( j = 0 ; j < 3 ; j++ ) {
+ _printf("(%5.2f %5.2f %5.2f) ", ctrl[i*3+j][0], ctrl[i*3+j][1], ctrl[i*3+j][2] );
+ }
+ _printf("\n");
+ }
+}
+
+/*
+================
+DrawSurfaceForMesh
+================
+*/
+mapDrawSurface_t *DrawSurfaceForMesh( mesh_t *m ) {
+ mapDrawSurface_t *ds;
+ int i, j;
+ mesh_t *copy;
+
+ // to make valid normals for patches with degenerate edges,
+ // we need to make a copy of the mesh and put the aproximating
+ // points onto the curve
+ copy = CopyMesh( m );
+ PutMeshOnCurve( *copy );
+ MakeMeshNormals( *copy );
+ for ( j = 0 ; j < m->width ; j++ ) {
+ for ( i = 0 ; i < m->height ; i++ ) {
+ VectorCopy( copy->verts[i*m->width+j].normal, m->verts[i*m->width+j].normal );
+ }
+ }
+ FreeMesh( copy );
+
+ ds = AllocDrawSurf();
+ ds->mapBrush = NULL;
+ ds->side = NULL;
+
+ ds->patch = qtrue;
+ ds->patchWidth = m->width;
+ ds->patchHeight = m->height;
+ ds->numVerts = ds->patchWidth * ds->patchHeight;
+ ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
+ memcpy( ds->verts, m->verts, ds->numVerts * sizeof( *ds->verts ) );
+
+ ds->lightmapNum = -1;
+ ds->fogNum = -1;
+
+ return ds;
+}
+
+/*
+=================
+ParsePatch
+
+Creates a mapDrawSurface_t from the patch text
+=================
+*/
+void ParsePatch( void ) {
+ vec_t info[5];
+ int i, j;
+ parseMesh_t *pm;
+ char texture[MAX_QPATH];
+ char shader[MAX_QPATH];
+ mesh_t m;
+ drawVert_t *verts;
+ epair_t *ep;
+
+ MatchToken( "{" );
+
+ // get texture
+ GetToken (qtrue);
+ strcpy( texture, token );
+
+ // save the shader name for retexturing
+ if ( numMapIndexedShaders == MAX_MAP_BRUSHSIDES ) {
+ Error( "MAX_MAP_BRUSHSIDES" );
+ }
+ strcpy( mapIndexedShaders[numMapIndexedShaders], texture );
+ numMapIndexedShaders++;
+
+
+ Parse1DMatrix( 5, info );
+ m.width = info[0];
+ m.height = info[1];
+ m.verts = verts = malloc( m.width * m.height * sizeof( m.verts[0] ) );
+
+ if ( m.width < 0 || m.width > MAX_PATCH_SIZE
+ || m.height < 0 || m.height > MAX_PATCH_SIZE ) {
+ Error("ParsePatch: bad size");
+ }
+
+ MatchToken( "(" );
+ for ( j = 0 ; j < m.width ; j++ ) {
+ MatchToken( "(" );
+ for ( i = 0 ; i < m.height ; i++ ) {
+ Parse1DMatrix( 5, verts[i*m.width+j].xyz );
+ }
+ MatchToken( ")" );
+ }
+ MatchToken( ")" );
+
+ // if brush primitives format, we may have some epairs to ignore here
+ GetToken(qtrue);
+ if (g_bBrushPrimit!=BPRIMIT_OLDBRUSHES && strcmp(token,"}"))
+ {
+ // NOTE: we leak that!
+ ep = ParseEpair();
+ }
+ else
+ UnGetToken();
+
+ MatchToken( "}" );
+ MatchToken( "}" );
+
+ if ( noCurveBrushes ) {
+ return;
+ }
+
+ // find default flags and values
+ pm = malloc( sizeof( *pm ) );
+ memset( pm, 0, sizeof( *pm ) );
+
+ sprintf( shader, "textures/%s", texture );
+ pm->shaderInfo = ShaderInfoForShader( shader );
+ pm->mesh = m;
+
+ // link to the entity
+ pm->next = mapent->patches;
+ mapent->patches = pm;
+}
+
+
+void GrowGroup_r( int patchNum, int patchCount, const byte *bordering, byte *group ) {
+ int i;
+ const byte *row;
+
+ if ( group[patchNum] ) {
+ return;
+ }
+ group[patchNum] = 1;
+ row = bordering + patchNum * patchCount;
+ for ( i = 0 ; i < patchCount ; i++ ) {
+ if ( row[i] ) {
+ GrowGroup_r( i, patchCount, bordering, group );
+ }
+ }
+}
+
+
+/*
+=====================
+PatchMapDrawSurfs
+
+Any patches that share an edge need to choose their
+level of detail as a unit, otherwise the edges would
+pull apart.
+=====================
+*/
+void PatchMapDrawSurfs( entity_t *e ) {
+ parseMesh_t *pm;
+ parseMesh_t *check, *scan;
+ mapDrawSurface_t *ds;
+ int patchCount, groupCount;
+ int i, j, k, l, c1, c2;
+ drawVert_t *v1, *v2;
+ vec3_t bounds[2];
+ byte *bordering;
+ parseMesh_t *meshes[MAX_MAP_DRAW_SURFS];
+ qboolean grouped[MAX_MAP_DRAW_SURFS];
+ byte group[MAX_MAP_DRAW_SURFS];
+
+ qprintf( "----- PatchMapDrawSurfs -----\n" );
+
+ patchCount = 0;
+ for ( pm = e->patches ; pm ; pm = pm->next ) {
+ meshes[patchCount] = pm;
+ patchCount++;
+ }
+
+ if ( !patchCount ) {
+ return;
+ }
+ bordering = malloc( patchCount * patchCount );
+ memset( bordering, 0, patchCount * patchCount );
+
+ // build the bordering matrix
+ for ( k = 0 ; k < patchCount ; k++ ) {
+ bordering[k*patchCount+k] = 1;
+
+ for ( l = k+1 ; l < patchCount ; l++ ) {
+ check = meshes[k];
+ scan = meshes[l];
+ c1 = scan->mesh.width * scan->mesh.height;
+ v1 = scan->mesh.verts;
+
+ for ( i = 0 ; i < c1 ; i++, v1++ ) {
+ c2 = check->mesh.width * check->mesh.height;
+ v2 = check->mesh.verts;
+ for ( j = 0 ; j < c2 ; j++, v2++ ) {
+ if ( fabs( v1->xyz[0] - v2->xyz[0] ) < 1.0
+ && fabs( v1->xyz[1] - v2->xyz[1] ) < 1.0
+ && fabs( v1->xyz[2] - v2->xyz[2] ) < 1.0 ) {
+ break;
+ }
+ }
+ if ( j != c2 ) {
+ break;
+ }
+ }
+ if ( i != c1 ) {
+ // we have a connection
+ bordering[k*patchCount+l] =
+ bordering[l*patchCount+k] = 1;
+ } else {
+ // no connection
+ bordering[k*patchCount+l] =
+ bordering[l*patchCount+k] = 0;
+ }
+
+ }
+ }
+
+ // build groups
+ memset( grouped, 0, sizeof(grouped) );
+ groupCount = 0;
+ for ( i = 0 ; i < patchCount ; i++ ) {
+ if ( !grouped[i] ) {
+ groupCount++;
+ }
+
+ // recursively find all patches that belong in the same group
+ memset( group, 0, patchCount );
+ GrowGroup_r( i, patchCount, bordering, group );
+
+ // bound them
+ ClearBounds( bounds[0], bounds[1] );
+ for ( j = 0 ; j < patchCount ; j++ ) {
+ if ( group[j] ) {
+ grouped[j] = qtrue;
+ scan = meshes[j];
+ c1 = scan->mesh.width * scan->mesh.height;
+ v1 = scan->mesh.verts;
+ for ( k = 0 ; k < c1 ; k++, v1++ ) {
+ AddPointToBounds( v1->xyz, bounds[0], bounds[1] );
+ }
+ }
+ }
+
+ // create drawsurf
+ scan = meshes[i];
+ scan->grouped = qtrue;
+ ds = DrawSurfaceForMesh( &scan->mesh );
+ ds->shaderInfo = scan->shaderInfo;
+ VectorCopy( bounds[0], ds->lightmapVecs[0] );
+ VectorCopy( bounds[1], ds->lightmapVecs[1] );
+ }
+
+ qprintf( "%5i patches\n", patchCount );
+ qprintf( "%5i patch LOD groups\n", groupCount );
+}
+
diff --git a/q3map/portals.c b/q3map/portals.c
index dee708f..059760f 100755
--- a/q3map/portals.c
+++ b/q3map/portals.c
@@ -19,825 +19,825 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include "qbsp.h"
-
-
-int c_active_portals;
-int c_peak_portals;
-int c_boundary;
-int c_boundary_sides;
-
-/*
-===========
-AllocPortal
-===========
-*/
-portal_t *AllocPortal (void)
-{
- portal_t *p;
-
- if (numthreads == 1)
- c_active_portals++;
- if (c_active_portals > c_peak_portals)
- c_peak_portals = c_active_portals;
-
- p = malloc (sizeof(portal_t));
- memset (p, 0, sizeof(portal_t));
-
- return p;
-}
-
-void FreePortal (portal_t *p)
-{
- if (p->winding)
- FreeWinding (p->winding);
- if (numthreads == 1)
- c_active_portals--;
- free (p);
-}
-
-//==============================================================
-
-/*
-=============
-Portal_Passable
-
-Returns true if the portal has non-opaque leafs on both sides
-=============
-*/
-qboolean Portal_Passable(portal_t *p) {
- if (!p->onnode) {
- return qfalse; // to global outsideleaf
- }
-
- if (p->nodes[0]->planenum != PLANENUM_LEAF
- || p->nodes[1]->planenum != PLANENUM_LEAF) {
- Error ("Portal_EntityFlood: not a leaf");
- }
-
- if ( !p->nodes[0]->opaque && !p->nodes[1]->opaque ) {
- return qtrue;
- }
-
- return qfalse;
-}
-
-
-//=============================================================================
-
-int c_tinyportals;
-
-/*
-=============
-AddPortalToNodes
-=============
-*/
-void AddPortalToNodes (portal_t *p, node_t *front, node_t *back)
-{
- if (p->nodes[0] || p->nodes[1])
- Error ("AddPortalToNode: allready included");
-
- p->nodes[0] = front;
- p->next[0] = front->portals;
- front->portals = p;
-
- p->nodes[1] = back;
- p->next[1] = back->portals;
- back->portals = p;
-}
-
-
-/*
-=============
-RemovePortalFromNode
-=============
-*/
-void RemovePortalFromNode (portal_t *portal, node_t *l)
-{
- portal_t **pp, *t;
-
-// remove reference to the current portal
- pp = &l->portals;
- while (1)
- {
- t = *pp;
- if (!t)
- Error ("RemovePortalFromNode: portal not in leaf");
-
- if ( t == portal )
- break;
-
- if (t->nodes[0] == l)
- pp = &t->next[0];
- else if (t->nodes[1] == l)
- pp = &t->next[1];
- else
- Error ("RemovePortalFromNode: portal not bounding leaf");
- }
-
- if (portal->nodes[0] == l)
- {
- *pp = portal->next[0];
- portal->nodes[0] = NULL;
- }
- else if (portal->nodes[1] == l)
- {
- *pp = portal->next[1];
- portal->nodes[1] = NULL;
- }
-}
-
-//============================================================================
-
-void PrintPortal (portal_t *p)
-{
- int i;
- winding_t *w;
-
- w = p->winding;
- for (i=0 ; i<w->numpoints ; i++)
- _printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0]
- , w->p[i][1], w->p[i][2]);
-}
-
-/*
-================
-MakeHeadnodePortals
-
-The created portals will face the global outside_node
-================
-*/
-#define SIDESPACE 8
-void MakeHeadnodePortals (tree_t *tree)
-{
- vec3_t bounds[2];
- int i, j, n;
- portal_t *p, *portals[6];
- plane_t bplanes[6], *pl;
- node_t *node;
-
- node = tree->headnode;
-
-// pad with some space so there will never be null volume leafs
- for (i=0 ; i<3 ; i++)
- {
- bounds[0][i] = tree->mins[i] - SIDESPACE;
- bounds[1][i] = tree->maxs[i] + SIDESPACE;
- if ( bounds[0][i] >= bounds[1][i] ) {
- Error( "Backwards tree volume" );
- }
- }
-
- tree->outside_node.planenum = PLANENUM_LEAF;
- tree->outside_node.brushlist = NULL;
- tree->outside_node.portals = NULL;
- tree->outside_node.opaque = qfalse;
-
- for (i=0 ; i<3 ; i++)
- for (j=0 ; j<2 ; j++)
- {
- n = j*3 + i;
-
- p = AllocPortal ();
- portals[n] = p;
-
- pl = &bplanes[n];
- memset (pl, 0, sizeof(*pl));
- if (j)
- {
- pl->normal[i] = -1;
- pl->dist = -bounds[j][i];
- }
- else
- {
- pl->normal[i] = 1;
- pl->dist = bounds[j][i];
- }
- p->plane = *pl;
- p->winding = BaseWindingForPlane (pl->normal, pl->dist);
- AddPortalToNodes (p, node, &tree->outside_node);
- }
-
-// clip the basewindings by all the other planes
- for (i=0 ; i<6 ; i++)
- {
- for (j=0 ; j<6 ; j++)
- {
- if (j == i)
- continue;
- ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON);
- }
- }
-}
-
-//===================================================
-
-
-/*
-================
-BaseWindingForNode
-================
-*/
-#define BASE_WINDING_EPSILON 0.001
-#define SPLIT_WINDING_EPSILON 0.001
-
-winding_t *BaseWindingForNode (node_t *node)
-{
- winding_t *w;
- node_t *n;
- plane_t *plane;
- vec3_t normal;
- vec_t dist;
-
- w = BaseWindingForPlane (mapplanes[node->planenum].normal
- , mapplanes[node->planenum].dist);
-
- // clip by all the parents
- for (n=node->parent ; n && w ; )
- {
- plane = &mapplanes[n->planenum];
-
- if (n->children[0] == node)
- { // take front
- ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON);
- }
- else
- { // take back
- VectorSubtract (vec3_origin, plane->normal, normal);
- dist = -plane->dist;
- ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON);
- }
- node = n;
- n = n->parent;
- }
-
- return w;
-}
-
-//============================================================
-
-/*
-==================
-MakeNodePortal
-
-create the new portal by taking the full plane winding for the cutting plane
-and clipping it by all of parents of this node
-==================
-*/
-void MakeNodePortal (node_t *node)
-{
- portal_t *new_portal, *p;
- winding_t *w;
- vec3_t normal;
- float dist;
- int side;
-
- w = BaseWindingForNode (node);
-
- // clip the portal by all the other portals in the node
- for (p = node->portals ; p && w; p = p->next[side])
- {
- if (p->nodes[0] == node)
- {
- side = 0;
- VectorCopy (p->plane.normal, normal);
- dist = p->plane.dist;
- }
- else if (p->nodes[1] == node)
- {
- side = 1;
- VectorSubtract (vec3_origin, p->plane.normal, normal);
- dist = -p->plane.dist;
- }
- else
- Error ("CutNodePortals_r: mislinked portal");
-
- ChopWindingInPlace (&w, normal, dist, CLIP_EPSILON);
- }
-
- if (!w)
- {
- return;
- }
-
- if (WindingIsTiny (w))
- {
- c_tinyportals++;
- FreeWinding (w);
- return;
- }
-
- new_portal = AllocPortal ();
- new_portal->plane = mapplanes[node->planenum];
- new_portal->onnode = node;
- new_portal->winding = w;
- new_portal->hint = node->hint;
- AddPortalToNodes (new_portal, node->children[0], node->children[1]);
-}
-
-
-/*
-==============
-SplitNodePortals
-
-Move or split the portals that bound node so that the node's
-children have portals instead of node.
-==============
-*/
-void SplitNodePortals (node_t *node)
-{
- portal_t *p, *next_portal, *new_portal;
- node_t *f, *b, *other_node;
- int side;
- plane_t *plane;
- winding_t *frontwinding, *backwinding;
-
- plane = &mapplanes[node->planenum];
- f = node->children[0];
- b = node->children[1];
-
- for (p = node->portals ; p ; p = next_portal)
- {
- if (p->nodes[0] == node)
- side = 0;
- else if (p->nodes[1] == node)
- side = 1;
- else
- Error ("SplitNodePortals: mislinked portal");
- next_portal = p->next[side];
-
- other_node = p->nodes[!side];
- RemovePortalFromNode (p, p->nodes[0]);
- RemovePortalFromNode (p, p->nodes[1]);
-
-//
-// cut the portal into two portals, one on each side of the cut plane
-//
- ClipWindingEpsilon (p->winding, plane->normal, plane->dist,
- SPLIT_WINDING_EPSILON, &frontwinding, &backwinding);
-
- if (frontwinding && WindingIsTiny(frontwinding))
- {
- if (!f->tinyportals)
- VectorCopy(frontwinding->p[0], f->referencepoint);
- f->tinyportals++;
- if (!other_node->tinyportals)
- VectorCopy(frontwinding->p[0], other_node->referencepoint);
- other_node->tinyportals++;
-
- FreeWinding (frontwinding);
- frontwinding = NULL;
- c_tinyportals++;
- }
-
- if (backwinding && WindingIsTiny(backwinding))
- {
- if (!b->tinyportals)
- VectorCopy(backwinding->p[0], b->referencepoint);
- b->tinyportals++;
- if (!other_node->tinyportals)
- VectorCopy(backwinding->p[0], other_node->referencepoint);
- other_node->tinyportals++;
-
- FreeWinding (backwinding);
- backwinding = NULL;
- c_tinyportals++;
- }
-
- if (!frontwinding && !backwinding)
- { // tiny windings on both sides
- continue;
- }
-
- if (!frontwinding)
- {
- FreeWinding (backwinding);
- if (side == 0)
- AddPortalToNodes (p, b, other_node);
- else
- AddPortalToNodes (p, other_node, b);
- continue;
- }
- if (!backwinding)
- {
- FreeWinding (frontwinding);
- if (side == 0)
- AddPortalToNodes (p, f, other_node);
- else
- AddPortalToNodes (p, other_node, f);
- continue;
- }
-
- // the winding is split
- new_portal = AllocPortal ();
- *new_portal = *p;
- new_portal->winding = backwinding;
- FreeWinding (p->winding);
- p->winding = frontwinding;
-
- if (side == 0)
- {
- AddPortalToNodes (p, f, other_node);
- AddPortalToNodes (new_portal, b, other_node);
- }
- else
- {
- AddPortalToNodes (p, other_node, f);
- AddPortalToNodes (new_portal, other_node, b);
- }
- }
-
- node->portals = NULL;
-}
-
-
-/*
-================
-CalcNodeBounds
-================
-*/
-void CalcNodeBounds (node_t *node)
-{
- portal_t *p;
- int s;
- int i;
-
- // calc mins/maxs for both leafs and nodes
- ClearBounds (node->mins, node->maxs);
- for (p = node->portals ; p ; p = p->next[s])
- {
- s = (p->nodes[1] == node);
- for (i=0 ; i<p->winding->numpoints ; i++)
- AddPointToBounds (p->winding->p[i], node->mins, node->maxs);
- }
-}
-
-/*
-==================
-MakeTreePortals_r
-==================
-*/
-void MakeTreePortals_r (node_t *node)
-{
- int i;
-
- CalcNodeBounds (node);
- if (node->mins[0] >= node->maxs[0])
- {
- _printf ("WARNING: node without a volume\n");
- _printf("node has %d tiny portals\n", node->tinyportals);
- _printf("node reference point %1.2f %1.2f %1.2f\n", node->referencepoint[0],
- node->referencepoint[1],
- node->referencepoint[2]);
- }
-
- for (i=0 ; i<3 ; i++)
- {
- if (node->mins[i] < MIN_WORLD_COORD || node->maxs[i] > MAX_WORLD_COORD)
- {
- _printf ("WARNING: node with unbounded volume\n");
- break;
- }
- }
- if (node->planenum == PLANENUM_LEAF)
- return;
-
- MakeNodePortal (node);
- SplitNodePortals (node);
-
- MakeTreePortals_r (node->children[0]);
- MakeTreePortals_r (node->children[1]);
-}
-
-/*
-==================
-MakeTreePortals
-==================
-*/
-void MakeTreePortals (tree_t *tree)
-{
- qprintf( "----- MakeTreePortals -----\n");
- MakeHeadnodePortals (tree);
- MakeTreePortals_r (tree->headnode);
- qprintf("%6d tiny portals\n", c_tinyportals);
-}
-
-/*
-=========================================================
-
-FLOOD ENTITIES
-
-=========================================================
-*/
-
-int c_floodedleafs;
-
-/*
-=============
-FloodPortals_r
-=============
-*/
-void FloodPortals_r (node_t *node, int dist) {
- portal_t *p;
- int s;
-
- if ( node->occupied ) {
- return;
- }
-
- if ( node->opaque ) {
- return;
- }
-
- c_floodedleafs++;
- node->occupied = dist;
-
- for (p=node->portals ; p ; p = p->next[s]) {
- s = (p->nodes[1] == node);
- FloodPortals_r (p->nodes[!s], dist+1);
- }
-}
-
-/*
-=============
-PlaceOccupant
-=============
-*/
-qboolean PlaceOccupant (node_t *headnode, vec3_t origin, entity_t *occupant)
-{
- node_t *node;
- vec_t d;
- plane_t *plane;
-
- // find the leaf to start in
- node = headnode;
- while (node->planenum != PLANENUM_LEAF)
- {
- plane = &mapplanes[node->planenum];
- d = DotProduct (origin, plane->normal) - plane->dist;
- if (d >= 0)
- node = node->children[0];
- else
- node = node->children[1];
- }
-
- if ( node->opaque )
- return qfalse;
- node->occupant = occupant;
-
- FloodPortals_r (node, 1);
-
- return qtrue;
-}
-
-/*
-=============
-FloodEntities
-
-Marks all nodes that can be reached by entites
-=============
-*/
-qboolean FloodEntities( tree_t *tree ) {
- int i;
- vec3_t origin;
- const char *cl;
- qboolean inside;
- node_t *headnode;
-
- headnode = tree->headnode;
- qprintf ("--- FloodEntities ---\n");
- inside = qfalse;
- tree->outside_node.occupied = 0;
-
- c_floodedleafs = 0;
- for (i=1 ; i<num_entities ; i++)
- {
- GetVectorForKey (&entities[i], "origin", origin);
- if (VectorCompare(origin, vec3_origin))
- continue;
-
- cl = ValueForKey (&entities[i], "classname");
-
- origin[2] += 1; // so objects on floor are ok
-
- if (PlaceOccupant (headnode, origin, &entities[i]))
- inside = qtrue;
- }
-
- qprintf("%5i flooded leafs\n", c_floodedleafs );
-
- if (!inside)
- {
- qprintf ("no entities in open -- no filling\n");
- }
- else if (tree->outside_node.occupied)
- {
- qprintf ("entity reached from outside -- no filling\n");
- }
-
- return (qboolean)(inside && !tree->outside_node.occupied);
-}
-
-/*
-=========================================================
-
-FLOOD AREAS
-
-=========================================================
-*/
-
-int c_areas;
-
-/*
-=============
-FloodAreas_r
-=============
-*/
-void FloodAreas_r (node_t *node)
-{
- portal_t *p;
- int s;
- bspbrush_t *b;
-
- if ( node->areaportal ) {
- //
- if ( node->area == -1 ) {
- node->area = c_areas;
- }
- // this node is part of an area portal brush
- b = node->brushlist->original;
-
- // if the current area has allready touched this
- // portal, we are done
- if (b->portalareas[0] == c_areas || b->portalareas[1] == c_areas)
- return;
-
- // note the current area as bounding the portal
- if (b->portalareas[1] != -1)
- {
- _printf ("WARNING: areaportal brush %i touches > 2 areas\n", b->brushnum );
- return;
- }
- if (b->portalareas[0] != -1) {
- b->portalareas[1] = c_areas;
- } else {
- b->portalareas[0] = c_areas;
- }
-
- return;
- }
-
- if (node->area != -1) {
- return; // allready got it
- }
- if ( node->cluster == -1 ) {
- return;
- }
-
- node->area = c_areas;
-
- for (p=node->portals ; p ; p = p->next[s])
- {
- s = (p->nodes[1] == node);
-
- if ( !Portal_Passable(p) )
- continue;
-
- FloodAreas_r (p->nodes[!s]);
- }
-}
-
-
-/*
-=============
-FindAreas_r
-
-Just decend the tree, and for each node that hasn't had an
-area set, flood fill out from there
-=============
-*/
-void FindAreas_r (node_t *node)
-{
- if (node->planenum != PLANENUM_LEAF)
- {
- FindAreas_r (node->children[0]);
- FindAreas_r (node->children[1]);
- return;
- }
-
- if (node->opaque)
- return;
-
- if (node->areaportal)
- return;
-
- if (node->area != -1)
- return; // allready got it
-
- FloodAreas_r (node);
- c_areas++;
-}
-
-/*
-=============
-CheckAreas_r
-=============
-*/
-void CheckAreas_r (node_t *node)
-{
- bspbrush_t *b;
-
- if (node->planenum != PLANENUM_LEAF)
- {
- CheckAreas_r (node->children[0]);
- CheckAreas_r (node->children[1]);
- return;
- }
-
- if (node->opaque)
- return;
-
- if (node->cluster != -1)
- if (node->area == -1)
- _printf("WARNING: cluster %d has area set to -1\n", node->cluster);
- if (node->areaportal)
- {
- b = node->brushlist->original;
-
- // check if the areaportal touches two areas
- if (b->portalareas[0] == -1 || b->portalareas[1] == -1)
- _printf ("WARNING: areaportal brush %i doesn't touch two areas\n", b->brushnum);
- }
-}
-
-/*
-=============
-FloodAreas
-
-Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL
-=============
-*/
-void FloodAreas (tree_t *tree)
-{
- qprintf ("--- FloodAreas ---\n");
- FindAreas_r( tree->headnode );
-
- // check for areaportal brushes that don't touch two areas
- CheckAreas_r( tree->headnode );
-
- qprintf ("%5i areas\n", c_areas);
-}
-
-//======================================================
-
-int c_outside;
-int c_inside;
-int c_solid;
-
-void FillOutside_r (node_t *node)
-{
- if (node->planenum != PLANENUM_LEAF)
- {
- FillOutside_r (node->children[0]);
- FillOutside_r (node->children[1]);
- return;
- }
-
- // anything not reachable by an entity
- // can be filled away
- if (!node->occupied) {
- if ( !node->opaque ) {
- c_outside++;
- node->opaque = qtrue;
- } else {
- c_solid++;
- }
- } else {
- c_inside++;
- }
-
-}
-
-/*
-=============
-FillOutside
-
-Fill all nodes that can't be reached by entities
-=============
-*/
-void FillOutside (node_t *headnode)
-{
- c_outside = 0;
- c_inside = 0;
- c_solid = 0;
- qprintf ("--- FillOutside ---\n");
- FillOutside_r (headnode);
- qprintf ("%5i solid leafs\n", c_solid);
- qprintf ("%5i leafs filled\n", c_outside);
- qprintf ("%5i inside leafs\n", c_inside);
-}
-
-
-//==============================================================
-
+
+#include "qbsp.h"
+
+
+int c_active_portals;
+int c_peak_portals;
+int c_boundary;
+int c_boundary_sides;
+
+/*
+===========
+AllocPortal
+===========
+*/
+portal_t *AllocPortal (void)
+{
+ portal_t *p;
+
+ if (numthreads == 1)
+ c_active_portals++;
+ if (c_active_portals > c_peak_portals)
+ c_peak_portals = c_active_portals;
+
+ p = malloc (sizeof(portal_t));
+ memset (p, 0, sizeof(portal_t));
+
+ return p;
+}
+
+void FreePortal (portal_t *p)
+{
+ if (p->winding)
+ FreeWinding (p->winding);
+ if (numthreads == 1)
+ c_active_portals--;
+ free (p);
+}
+
+//==============================================================
+
+/*
+=============
+Portal_Passable
+
+Returns true if the portal has non-opaque leafs on both sides
+=============
+*/
+qboolean Portal_Passable(portal_t *p) {
+ if (!p->onnode) {
+ return qfalse; // to global outsideleaf
+ }
+
+ if (p->nodes[0]->planenum != PLANENUM_LEAF
+ || p->nodes[1]->planenum != PLANENUM_LEAF) {
+ Error ("Portal_EntityFlood: not a leaf");
+ }
+
+ if ( !p->nodes[0]->opaque && !p->nodes[1]->opaque ) {
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+
+//=============================================================================
+
+int c_tinyportals;
+
+/*
+=============
+AddPortalToNodes
+=============
+*/
+void AddPortalToNodes (portal_t *p, node_t *front, node_t *back)
+{
+ if (p->nodes[0] || p->nodes[1])
+ Error ("AddPortalToNode: allready included");
+
+ p->nodes[0] = front;
+ p->next[0] = front->portals;
+ front->portals = p;
+
+ p->nodes[1] = back;
+ p->next[1] = back->portals;
+ back->portals = p;
+}
+
+
+/*
+=============
+RemovePortalFromNode
+=============
+*/
+void RemovePortalFromNode (portal_t *portal, node_t *l)
+{
+ portal_t **pp, *t;
+
+// remove reference to the current portal
+ pp = &l->portals;
+ while (1)
+ {
+ t = *pp;
+ if (!t)
+ Error ("RemovePortalFromNode: portal not in leaf");
+
+ if ( t == portal )
+ break;
+
+ if (t->nodes[0] == l)
+ pp = &t->next[0];
+ else if (t->nodes[1] == l)
+ pp = &t->next[1];
+ else
+ Error ("RemovePortalFromNode: portal not bounding leaf");
+ }
+
+ if (portal->nodes[0] == l)
+ {
+ *pp = portal->next[0];
+ portal->nodes[0] = NULL;
+ }
+ else if (portal->nodes[1] == l)
+ {
+ *pp = portal->next[1];
+ portal->nodes[1] = NULL;
+ }
+}
+
+//============================================================================
+
+void PrintPortal (portal_t *p)
+{
+ int i;
+ winding_t *w;
+
+ w = p->winding;
+ for (i=0 ; i<w->numpoints ; i++)
+ _printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0]
+ , w->p[i][1], w->p[i][2]);
+}
+
+/*
+================
+MakeHeadnodePortals
+
+The created portals will face the global outside_node
+================
+*/
+#define SIDESPACE 8
+void MakeHeadnodePortals (tree_t *tree)
+{
+ vec3_t bounds[2];
+ int i, j, n;
+ portal_t *p, *portals[6];
+ plane_t bplanes[6], *pl;
+ node_t *node;
+
+ node = tree->headnode;
+
+// pad with some space so there will never be null volume leafs
+ for (i=0 ; i<3 ; i++)
+ {
+ bounds[0][i] = tree->mins[i] - SIDESPACE;
+ bounds[1][i] = tree->maxs[i] + SIDESPACE;
+ if ( bounds[0][i] >= bounds[1][i] ) {
+ Error( "Backwards tree volume" );
+ }
+ }
+
+ tree->outside_node.planenum = PLANENUM_LEAF;
+ tree->outside_node.brushlist = NULL;
+ tree->outside_node.portals = NULL;
+ tree->outside_node.opaque = qfalse;
+
+ for (i=0 ; i<3 ; i++)
+ for (j=0 ; j<2 ; j++)
+ {
+ n = j*3 + i;
+
+ p = AllocPortal ();
+ portals[n] = p;
+
+ pl = &bplanes[n];
+ memset (pl, 0, sizeof(*pl));
+ if (j)
+ {
+ pl->normal[i] = -1;
+ pl->dist = -bounds[j][i];
+ }
+ else
+ {
+ pl->normal[i] = 1;
+ pl->dist = bounds[j][i];
+ }
+ p->plane = *pl;
+ p->winding = BaseWindingForPlane (pl->normal, pl->dist);
+ AddPortalToNodes (p, node, &tree->outside_node);
+ }
+
+// clip the basewindings by all the other planes
+ for (i=0 ; i<6 ; i++)
+ {
+ for (j=0 ; j<6 ; j++)
+ {
+ if (j == i)
+ continue;
+ ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON);
+ }
+ }
+}
+
+//===================================================
+
+
+/*
+================
+BaseWindingForNode
+================
+*/
+#define BASE_WINDING_EPSILON 0.001
+#define SPLIT_WINDING_EPSILON 0.001
+
+winding_t *BaseWindingForNode (node_t *node)
+{
+ winding_t *w;
+ node_t *n;
+ plane_t *plane;
+ vec3_t normal;
+ vec_t dist;
+
+ w = BaseWindingForPlane (mapplanes[node->planenum].normal
+ , mapplanes[node->planenum].dist);
+
+ // clip by all the parents
+ for (n=node->parent ; n && w ; )
+ {
+ plane = &mapplanes[n->planenum];
+
+ if (n->children[0] == node)
+ { // take front
+ ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON);
+ }
+ else
+ { // take back
+ VectorSubtract (vec3_origin, plane->normal, normal);
+ dist = -plane->dist;
+ ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON);
+ }
+ node = n;
+ n = n->parent;
+ }
+
+ return w;
+}
+
+//============================================================
+
+/*
+==================
+MakeNodePortal
+
+create the new portal by taking the full plane winding for the cutting plane
+and clipping it by all of parents of this node
+==================
+*/
+void MakeNodePortal (node_t *node)
+{
+ portal_t *new_portal, *p;
+ winding_t *w;
+ vec3_t normal;
+ float dist;
+ int side;
+
+ w = BaseWindingForNode (node);
+
+ // clip the portal by all the other portals in the node
+ for (p = node->portals ; p && w; p = p->next[side])
+ {
+ if (p->nodes[0] == node)
+ {
+ side = 0;
+ VectorCopy (p->plane.normal, normal);
+ dist = p->plane.dist;
+ }
+ else if (p->nodes[1] == node)
+ {
+ side = 1;
+ VectorSubtract (vec3_origin, p->plane.normal, normal);
+ dist = -p->plane.dist;
+ }
+ else
+ Error ("CutNodePortals_r: mislinked portal");
+
+ ChopWindingInPlace (&w, normal, dist, CLIP_EPSILON);
+ }
+
+ if (!w)
+ {
+ return;
+ }
+
+ if (WindingIsTiny (w))
+ {
+ c_tinyportals++;
+ FreeWinding (w);
+ return;
+ }
+
+ new_portal = AllocPortal ();
+ new_portal->plane = mapplanes[node->planenum];
+ new_portal->onnode = node;
+ new_portal->winding = w;
+ new_portal->hint = node->hint;
+ AddPortalToNodes (new_portal, node->children[0], node->children[1]);
+}
+
+
+/*
+==============
+SplitNodePortals
+
+Move or split the portals that bound node so that the node's
+children have portals instead of node.
+==============
+*/
+void SplitNodePortals (node_t *node)
+{
+ portal_t *p, *next_portal, *new_portal;
+ node_t *f, *b, *other_node;
+ int side;
+ plane_t *plane;
+ winding_t *frontwinding, *backwinding;
+
+ plane = &mapplanes[node->planenum];
+ f = node->children[0];
+ b = node->children[1];
+
+ for (p = node->portals ; p ; p = next_portal)
+ {
+ if (p->nodes[0] == node)
+ side = 0;
+ else if (p->nodes[1] == node)
+ side = 1;
+ else
+ Error ("SplitNodePortals: mislinked portal");
+ next_portal = p->next[side];
+
+ other_node = p->nodes[!side];
+ RemovePortalFromNode (p, p->nodes[0]);
+ RemovePortalFromNode (p, p->nodes[1]);
+
+//
+// cut the portal into two portals, one on each side of the cut plane
+//
+ ClipWindingEpsilon (p->winding, plane->normal, plane->dist,
+ SPLIT_WINDING_EPSILON, &frontwinding, &backwinding);
+
+ if (frontwinding && WindingIsTiny(frontwinding))
+ {
+ if (!f->tinyportals)
+ VectorCopy(frontwinding->p[0], f->referencepoint);
+ f->tinyportals++;
+ if (!other_node->tinyportals)
+ VectorCopy(frontwinding->p[0], other_node->referencepoint);
+ other_node->tinyportals++;
+
+ FreeWinding (frontwinding);
+ frontwinding = NULL;
+ c_tinyportals++;
+ }
+
+ if (backwinding && WindingIsTiny(backwinding))
+ {
+ if (!b->tinyportals)
+ VectorCopy(backwinding->p[0], b->referencepoint);
+ b->tinyportals++;
+ if (!other_node->tinyportals)
+ VectorCopy(backwinding->p[0], other_node->referencepoint);
+ other_node->tinyportals++;
+
+ FreeWinding (backwinding);
+ backwinding = NULL;
+ c_tinyportals++;
+ }
+
+ if (!frontwinding && !backwinding)
+ { // tiny windings on both sides
+ continue;
+ }
+
+ if (!frontwinding)
+ {
+ FreeWinding (backwinding);
+ if (side == 0)
+ AddPortalToNodes (p, b, other_node);
+ else
+ AddPortalToNodes (p, other_node, b);
+ continue;
+ }
+ if (!backwinding)
+ {
+ FreeWinding (frontwinding);
+ if (side == 0)
+ AddPortalToNodes (p, f, other_node);
+ else
+ AddPortalToNodes (p, other_node, f);
+ continue;
+ }
+
+ // the winding is split
+ new_portal = AllocPortal ();
+ *new_portal = *p;
+ new_portal->winding = backwinding;
+ FreeWinding (p->winding);
+ p->winding = frontwinding;
+
+ if (side == 0)
+ {
+ AddPortalToNodes (p, f, other_node);
+ AddPortalToNodes (new_portal, b, other_node);
+ }
+ else
+ {
+ AddPortalToNodes (p, other_node, f);
+ AddPortalToNodes (new_portal, other_node, b);
+ }
+ }
+
+ node->portals = NULL;
+}
+
+
+/*
+================
+CalcNodeBounds
+================
+*/
+void CalcNodeBounds (node_t *node)
+{
+ portal_t *p;
+ int s;
+ int i;
+
+ // calc mins/maxs for both leafs and nodes
+ ClearBounds (node->mins, node->maxs);
+ for (p = node->portals ; p ; p = p->next[s])
+ {
+ s = (p->nodes[1] == node);
+ for (i=0 ; i<p->winding->numpoints ; i++)
+ AddPointToBounds (p->winding->p[i], node->mins, node->maxs);
+ }
+}
+
+/*
+==================
+MakeTreePortals_r
+==================
+*/
+void MakeTreePortals_r (node_t *node)
+{
+ int i;
+
+ CalcNodeBounds (node);
+ if (node->mins[0] >= node->maxs[0])
+ {
+ _printf ("WARNING: node without a volume\n");
+ _printf("node has %d tiny portals\n", node->tinyportals);
+ _printf("node reference point %1.2f %1.2f %1.2f\n", node->referencepoint[0],
+ node->referencepoint[1],
+ node->referencepoint[2]);
+ }
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if (node->mins[i] < MIN_WORLD_COORD || node->maxs[i] > MAX_WORLD_COORD)
+ {
+ _printf ("WARNING: node with unbounded volume\n");
+ break;
+ }
+ }
+ if (node->planenum == PLANENUM_LEAF)
+ return;
+
+ MakeNodePortal (node);
+ SplitNodePortals (node);
+
+ MakeTreePortals_r (node->children[0]);
+ MakeTreePortals_r (node->children[1]);
+}
+
+/*
+==================
+MakeTreePortals
+==================
+*/
+void MakeTreePortals (tree_t *tree)
+{
+ qprintf( "----- MakeTreePortals -----\n");
+ MakeHeadnodePortals (tree);
+ MakeTreePortals_r (tree->headnode);
+ qprintf("%6d tiny portals\n", c_tinyportals);
+}
+
+/*
+=========================================================
+
+FLOOD ENTITIES
+
+=========================================================
+*/
+
+int c_floodedleafs;
+
+/*
+=============
+FloodPortals_r
+=============
+*/
+void FloodPortals_r (node_t *node, int dist) {
+ portal_t *p;
+ int s;
+
+ if ( node->occupied ) {
+ return;
+ }
+
+ if ( node->opaque ) {
+ return;
+ }
+
+ c_floodedleafs++;
+ node->occupied = dist;
+
+ for (p=node->portals ; p ; p = p->next[s]) {
+ s = (p->nodes[1] == node);
+ FloodPortals_r (p->nodes[!s], dist+1);
+ }
+}
+
+/*
+=============
+PlaceOccupant
+=============
+*/
+qboolean PlaceOccupant (node_t *headnode, vec3_t origin, entity_t *occupant)
+{
+ node_t *node;
+ vec_t d;
+ plane_t *plane;
+
+ // find the leaf to start in
+ node = headnode;
+ while (node->planenum != PLANENUM_LEAF)
+ {
+ plane = &mapplanes[node->planenum];
+ d = DotProduct (origin, plane->normal) - plane->dist;
+ if (d >= 0)
+ node = node->children[0];
+ else
+ node = node->children[1];
+ }
+
+ if ( node->opaque )
+ return qfalse;
+ node->occupant = occupant;
+
+ FloodPortals_r (node, 1);
+
+ return qtrue;
+}
+
+/*
+=============
+FloodEntities
+
+Marks all nodes that can be reached by entites
+=============
+*/
+qboolean FloodEntities( tree_t *tree ) {
+ int i;
+ vec3_t origin;
+ const char *cl;
+ qboolean inside;
+ node_t *headnode;
+
+ headnode = tree->headnode;
+ qprintf ("--- FloodEntities ---\n");
+ inside = qfalse;
+ tree->outside_node.occupied = 0;
+
+ c_floodedleafs = 0;
+ for (i=1 ; i<num_entities ; i++)
+ {
+ GetVectorForKey (&entities[i], "origin", origin);
+ if (VectorCompare(origin, vec3_origin))
+ continue;
+
+ cl = ValueForKey (&entities[i], "classname");
+
+ origin[2] += 1; // so objects on floor are ok
+
+ if (PlaceOccupant (headnode, origin, &entities[i]))
+ inside = qtrue;
+ }
+
+ qprintf("%5i flooded leafs\n", c_floodedleafs );
+
+ if (!inside)
+ {
+ qprintf ("no entities in open -- no filling\n");
+ }
+ else if (tree->outside_node.occupied)
+ {
+ qprintf ("entity reached from outside -- no filling\n");
+ }
+
+ return (qboolean)(inside && !tree->outside_node.occupied);
+}
+
+/*
+=========================================================
+
+FLOOD AREAS
+
+=========================================================
+*/
+
+int c_areas;
+
+/*
+=============
+FloodAreas_r
+=============
+*/
+void FloodAreas_r (node_t *node)
+{
+ portal_t *p;
+ int s;
+ bspbrush_t *b;
+
+ if ( node->areaportal ) {
+ //
+ if ( node->area == -1 ) {
+ node->area = c_areas;
+ }
+ // this node is part of an area portal brush
+ b = node->brushlist->original;
+
+ // if the current area has allready touched this
+ // portal, we are done
+ if (b->portalareas[0] == c_areas || b->portalareas[1] == c_areas)
+ return;
+
+ // note the current area as bounding the portal
+ if (b->portalareas[1] != -1)
+ {
+ _printf ("WARNING: areaportal brush %i touches > 2 areas\n", b->brushnum );
+ return;
+ }
+ if (b->portalareas[0] != -1) {
+ b->portalareas[1] = c_areas;
+ } else {
+ b->portalareas[0] = c_areas;
+ }
+
+ return;
+ }
+
+ if (node->area != -1) {
+ return; // allready got it
+ }
+ if ( node->cluster == -1 ) {
+ return;
+ }
+
+ node->area = c_areas;
+
+ for (p=node->portals ; p ; p = p->next[s])
+ {
+ s = (p->nodes[1] == node);
+
+ if ( !Portal_Passable(p) )
+ continue;
+
+ FloodAreas_r (p->nodes[!s]);
+ }
+}
+
+
+/*
+=============
+FindAreas_r
+
+Just decend the tree, and for each node that hasn't had an
+area set, flood fill out from there
+=============
+*/
+void FindAreas_r (node_t *node)
+{
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ FindAreas_r (node->children[0]);
+ FindAreas_r (node->children[1]);
+ return;
+ }
+
+ if (node->opaque)
+ return;
+
+ if (node->areaportal)
+ return;
+
+ if (node->area != -1)
+ return; // allready got it
+
+ FloodAreas_r (node);
+ c_areas++;
+}
+
+/*
+=============
+CheckAreas_r
+=============
+*/
+void CheckAreas_r (node_t *node)
+{
+ bspbrush_t *b;
+
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ CheckAreas_r (node->children[0]);
+ CheckAreas_r (node->children[1]);
+ return;
+ }
+
+ if (node->opaque)
+ return;
+
+ if (node->cluster != -1)
+ if (node->area == -1)
+ _printf("WARNING: cluster %d has area set to -1\n", node->cluster);
+ if (node->areaportal)
+ {
+ b = node->brushlist->original;
+
+ // check if the areaportal touches two areas
+ if (b->portalareas[0] == -1 || b->portalareas[1] == -1)
+ _printf ("WARNING: areaportal brush %i doesn't touch two areas\n", b->brushnum);
+ }
+}
+
+/*
+=============
+FloodAreas
+
+Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL
+=============
+*/
+void FloodAreas (tree_t *tree)
+{
+ qprintf ("--- FloodAreas ---\n");
+ FindAreas_r( tree->headnode );
+
+ // check for areaportal brushes that don't touch two areas
+ CheckAreas_r( tree->headnode );
+
+ qprintf ("%5i areas\n", c_areas);
+}
+
+//======================================================
+
+int c_outside;
+int c_inside;
+int c_solid;
+
+void FillOutside_r (node_t *node)
+{
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ FillOutside_r (node->children[0]);
+ FillOutside_r (node->children[1]);
+ return;
+ }
+
+ // anything not reachable by an entity
+ // can be filled away
+ if (!node->occupied) {
+ if ( !node->opaque ) {
+ c_outside++;
+ node->opaque = qtrue;
+ } else {
+ c_solid++;
+ }
+ } else {
+ c_inside++;
+ }
+
+}
+
+/*
+=============
+FillOutside
+
+Fill all nodes that can't be reached by entities
+=============
+*/
+void FillOutside (node_t *headnode)
+{
+ c_outside = 0;
+ c_inside = 0;
+ c_solid = 0;
+ qprintf ("--- FillOutside ---\n");
+ FillOutside_r (headnode);
+ qprintf ("%5i solid leafs\n", c_solid);
+ qprintf ("%5i leafs filled\n", c_outside);
+ qprintf ("%5i inside leafs\n", c_inside);
+}
+
+
+//==============================================================
+
diff --git a/q3map/prtfile.c b/q3map/prtfile.c
index 902ae05..6a7bb15 100755
--- a/q3map/prtfile.c
+++ b/q3map/prtfile.c
@@ -19,254 +19,254 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include "qbsp.h"
-
-/*
-==============================================================================
-
-PORTAL FILE GENERATION
-
-Save out name.prt for qvis to read
-==============================================================================
-*/
-
-
-#define PORTALFILE "PRT1"
-
-FILE *pf;
-int num_visclusters; // clusters the player can be in
-int num_visportals;
-int num_solidfaces;
-
-void WriteFloat (FILE *f, vec_t v)
-{
- if ( fabs(v - Q_rint(v)) < 0.001 )
- fprintf (f,"%i ",(int)Q_rint(v));
- else
- fprintf (f,"%f ",v);
-}
-
-/*
-=================
-WritePortalFile_r
-=================
-*/
-void WritePortalFile_r (node_t *node)
-{
- int i, s;
- portal_t *p;
- winding_t *w;
- vec3_t normal;
- vec_t dist;
-
- // decision node
- if (node->planenum != PLANENUM_LEAF) {
- WritePortalFile_r (node->children[0]);
- WritePortalFile_r (node->children[1]);
- return;
- }
-
- if (node->opaque) {
- return;
- }
-
- for (p = node->portals ; p ; p=p->next[s])
- {
- w = p->winding;
- s = (p->nodes[1] == node);
- if (w && p->nodes[0] == node)
- {
- if (!Portal_Passable(p))
- continue;
- // write out to the file
-
- // sometimes planes get turned around when they are very near
- // the changeover point between different axis. interpret the
- // plane the same way vis will, and flip the side orders if needed
- // FIXME: is this still relevent?
- WindingPlane (w, normal, &dist);
- if ( DotProduct (p->plane.normal, normal) < 0.99 )
- { // backwards...
- fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster);
- }
- else
- fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster);
- if (p->hint)
- fprintf (pf, "1 ");
- else
- fprintf (pf, "0 ");
- for (i=0 ; i<w->numpoints ; i++)
- {
- fprintf (pf,"(");
- WriteFloat (pf, w->p[i][0]);
- WriteFloat (pf, w->p[i][1]);
- WriteFloat (pf, w->p[i][2]);
- fprintf (pf,") ");
- }
- fprintf (pf,"\n");
- }
- }
-
-}
-
-/*
-=================
-WriteFaceFile_r
-=================
-*/
-void WriteFaceFile_r (node_t *node)
-{
- int i, s;
- portal_t *p;
- winding_t *w;
-
- // decision node
- if (node->planenum != PLANENUM_LEAF) {
- WriteFaceFile_r (node->children[0]);
- WriteFaceFile_r (node->children[1]);
- return;
- }
-
- if (node->opaque) {
- return;
- }
-
- for (p = node->portals ; p ; p=p->next[s])
- {
- w = p->winding;
- s = (p->nodes[1] == node);
- if (w)
- {
- if (Portal_Passable(p))
- continue;
- // write out to the file
-
- if (p->nodes[0] == node)
- {
- fprintf (pf,"%i %i ",w->numpoints, p->nodes[0]->cluster);
- for (i=0 ; i<w->numpoints ; i++)
- {
- fprintf (pf,"(");
- WriteFloat (pf, w->p[i][0]);
- WriteFloat (pf, w->p[i][1]);
- WriteFloat (pf, w->p[i][2]);
- fprintf (pf,") ");
- }
- fprintf (pf,"\n");
- }
- else
- {
- fprintf (pf,"%i %i ",w->numpoints, p->nodes[1]->cluster);
- for (i = w->numpoints-1; i >= 0; i--)
- {
- fprintf (pf,"(");
- WriteFloat (pf, w->p[i][0]);
- WriteFloat (pf, w->p[i][1]);
- WriteFloat (pf, w->p[i][2]);
- fprintf (pf,") ");
- }
- fprintf (pf,"\n");
- }
- }
- }
-}
-
-/*
-================
-NumberLeafs_r
-================
-*/
-void NumberLeafs_r (node_t *node)
-{
- portal_t *p;
-
- if ( node->planenum != PLANENUM_LEAF ) {
- // decision node
- node->cluster = -99;
- NumberLeafs_r (node->children[0]);
- NumberLeafs_r (node->children[1]);
- return;
- }
-
- node->area = -1;
-
- if ( node->opaque ) {
- // solid block, viewpoint never inside
- node->cluster = -1;
- return;
- }
-
- node->cluster = num_visclusters;
- num_visclusters++;
-
- // count the portals
- for (p = node->portals ; p ; )
- {
- if (p->nodes[0] == node) // only write out from first leaf
- {
- if (Portal_Passable(p))
- num_visportals++;
- else
- num_solidfaces++;
- p = p->next[0];
- }
- else
- {
- if (!Portal_Passable(p))
- num_solidfaces++;
- p = p->next[1];
- }
- }
-}
-
-
-/*
-================
-NumberClusters
-================
-*/
-void NumberClusters(tree_t *tree) {
- num_visclusters = 0;
- num_visportals = 0;
- num_solidfaces = 0;
-
- qprintf ("--- NumberClusters ---\n");
-
- // set the cluster field in every leaf and count the total number of portals
- NumberLeafs_r (tree->headnode);
-
- qprintf ("%5i visclusters\n", num_visclusters);
- qprintf ("%5i visportals\n", num_visportals);
- qprintf ("%5i solidfaces\n", num_solidfaces);
-}
-
-/*
-================
-WritePortalFile
-================
-*/
-void WritePortalFile (tree_t *tree)
-{
- char filename[1024];
-
- qprintf ("--- WritePortalFile ---\n");
-
- // write the file
- sprintf (filename, "%s.prt", source);
- _printf ("writing %s\n", filename);
- pf = fopen (filename, "w");
- if (!pf)
- Error ("Error opening %s", filename);
-
- fprintf (pf, "%s\n", PORTALFILE);
- fprintf (pf, "%i\n", num_visclusters);
- fprintf (pf, "%i\n", num_visportals);
- fprintf (pf, "%i\n", num_solidfaces);
-
- WritePortalFile_r(tree->headnode);
- WriteFaceFile_r(tree->headnode);
-
- fclose (pf);
-}
-
+
+#include "qbsp.h"
+
+/*
+==============================================================================
+
+PORTAL FILE GENERATION
+
+Save out name.prt for qvis to read
+==============================================================================
+*/
+
+
+#define PORTALFILE "PRT1"
+
+FILE *pf;
+int num_visclusters; // clusters the player can be in
+int num_visportals;
+int num_solidfaces;
+
+void WriteFloat (FILE *f, vec_t v)
+{
+ if ( fabs(v - Q_rint(v)) < 0.001 )
+ fprintf (f,"%i ",(int)Q_rint(v));
+ else
+ fprintf (f,"%f ",v);
+}
+
+/*
+=================
+WritePortalFile_r
+=================
+*/
+void WritePortalFile_r (node_t *node)
+{
+ int i, s;
+ portal_t *p;
+ winding_t *w;
+ vec3_t normal;
+ vec_t dist;
+
+ // decision node
+ if (node->planenum != PLANENUM_LEAF) {
+ WritePortalFile_r (node->children[0]);
+ WritePortalFile_r (node->children[1]);
+ return;
+ }
+
+ if (node->opaque) {
+ return;
+ }
+
+ for (p = node->portals ; p ; p=p->next[s])
+ {
+ w = p->winding;
+ s = (p->nodes[1] == node);
+ if (w && p->nodes[0] == node)
+ {
+ if (!Portal_Passable(p))
+ continue;
+ // write out to the file
+
+ // sometimes planes get turned around when they are very near
+ // the changeover point between different axis. interpret the
+ // plane the same way vis will, and flip the side orders if needed
+ // FIXME: is this still relevent?
+ WindingPlane (w, normal, &dist);
+ if ( DotProduct (p->plane.normal, normal) < 0.99 )
+ { // backwards...
+ fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster);
+ }
+ else
+ fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster);
+ if (p->hint)
+ fprintf (pf, "1 ");
+ else
+ fprintf (pf, "0 ");
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ fprintf (pf,"(");
+ WriteFloat (pf, w->p[i][0]);
+ WriteFloat (pf, w->p[i][1]);
+ WriteFloat (pf, w->p[i][2]);
+ fprintf (pf,") ");
+ }
+ fprintf (pf,"\n");
+ }
+ }
+
+}
+
+/*
+=================
+WriteFaceFile_r
+=================
+*/
+void WriteFaceFile_r (node_t *node)
+{
+ int i, s;
+ portal_t *p;
+ winding_t *w;
+
+ // decision node
+ if (node->planenum != PLANENUM_LEAF) {
+ WriteFaceFile_r (node->children[0]);
+ WriteFaceFile_r (node->children[1]);
+ return;
+ }
+
+ if (node->opaque) {
+ return;
+ }
+
+ for (p = node->portals ; p ; p=p->next[s])
+ {
+ w = p->winding;
+ s = (p->nodes[1] == node);
+ if (w)
+ {
+ if (Portal_Passable(p))
+ continue;
+ // write out to the file
+
+ if (p->nodes[0] == node)
+ {
+ fprintf (pf,"%i %i ",w->numpoints, p->nodes[0]->cluster);
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ fprintf (pf,"(");
+ WriteFloat (pf, w->p[i][0]);
+ WriteFloat (pf, w->p[i][1]);
+ WriteFloat (pf, w->p[i][2]);
+ fprintf (pf,") ");
+ }
+ fprintf (pf,"\n");
+ }
+ else
+ {
+ fprintf (pf,"%i %i ",w->numpoints, p->nodes[1]->cluster);
+ for (i = w->numpoints-1; i >= 0; i--)
+ {
+ fprintf (pf,"(");
+ WriteFloat (pf, w->p[i][0]);
+ WriteFloat (pf, w->p[i][1]);
+ WriteFloat (pf, w->p[i][2]);
+ fprintf (pf,") ");
+ }
+ fprintf (pf,"\n");
+ }
+ }
+ }
+}
+
+/*
+================
+NumberLeafs_r
+================
+*/
+void NumberLeafs_r (node_t *node)
+{
+ portal_t *p;
+
+ if ( node->planenum != PLANENUM_LEAF ) {
+ // decision node
+ node->cluster = -99;
+ NumberLeafs_r (node->children[0]);
+ NumberLeafs_r (node->children[1]);
+ return;
+ }
+
+ node->area = -1;
+
+ if ( node->opaque ) {
+ // solid block, viewpoint never inside
+ node->cluster = -1;
+ return;
+ }
+
+ node->cluster = num_visclusters;
+ num_visclusters++;
+
+ // count the portals
+ for (p = node->portals ; p ; )
+ {
+ if (p->nodes[0] == node) // only write out from first leaf
+ {
+ if (Portal_Passable(p))
+ num_visportals++;
+ else
+ num_solidfaces++;
+ p = p->next[0];
+ }
+ else
+ {
+ if (!Portal_Passable(p))
+ num_solidfaces++;
+ p = p->next[1];
+ }
+ }
+}
+
+
+/*
+================
+NumberClusters
+================
+*/
+void NumberClusters(tree_t *tree) {
+ num_visclusters = 0;
+ num_visportals = 0;
+ num_solidfaces = 0;
+
+ qprintf ("--- NumberClusters ---\n");
+
+ // set the cluster field in every leaf and count the total number of portals
+ NumberLeafs_r (tree->headnode);
+
+ qprintf ("%5i visclusters\n", num_visclusters);
+ qprintf ("%5i visportals\n", num_visportals);
+ qprintf ("%5i solidfaces\n", num_solidfaces);
+}
+
+/*
+================
+WritePortalFile
+================
+*/
+void WritePortalFile (tree_t *tree)
+{
+ char filename[1024];
+
+ qprintf ("--- WritePortalFile ---\n");
+
+ // write the file
+ sprintf (filename, "%s.prt", source);
+ _printf ("writing %s\n", filename);
+ pf = fopen (filename, "w");
+ if (!pf)
+ Error ("Error opening %s", filename);
+
+ fprintf (pf, "%s\n", PORTALFILE);
+ fprintf (pf, "%i\n", num_visclusters);
+ fprintf (pf, "%i\n", num_visportals);
+ fprintf (pf, "%i\n", num_solidfaces);
+
+ WritePortalFile_r(tree->headnode);
+ WriteFaceFile_r(tree->headnode);
+
+ fclose (pf);
+}
+
diff --git a/q3map/q3map.sln b/q3map/q3map.sln
index 6e4bb3c..e0b2699 100755
--- a/q3map/q3map.sln
+++ b/q3map/q3map.sln
@@ -1,56 +1,56 @@
-Microsoft Visual Studio Solution File, Format Version 8.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpeg6", "..\libs\jpeg6\jpeg6.vcproj", "{A862AD26-94DD-4618-A814-F6AACA0B2FE3}"
- ProjectSection(ProjectDependencies) = postProject
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pak", "..\libs\pak\pak.vcproj", "{F2ACC9D7-D628-4624-864F-87FE58787625}"
- ProjectSection(ProjectDependencies) = postProject
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "q3map", "q3map.vcproj", "{F1162C55-66E7-4486-B1F3-071CFAA78332}"
- ProjectSection(ProjectDependencies) = postProject
- {F2ACC9D7-D628-4624-864F-87FE58787625} = {F2ACC9D7-D628-4624-864F-87FE58787625}
- {A862AD26-94DD-4618-A814-F6AACA0B2FE3} = {A862AD26-94DD-4618-A814-F6AACA0B2FE3}
- EndProjectSection
-EndProject
-Global
- GlobalSection(SourceCodeControl) = preSolution
- SccNumberOfProjects = 3
- SccProjectUniqueName0 = ..\\libs\\jpeg6\\jpeg6.vcproj
- SccProjectName0 = \u0022$/source/q3radiant\u0022,\u0020FEFAAAAA
- SccLocalPath0 = ..\\q3radiant
- SccProvider0 = MSSCCI:Perforce\u0020SCM
- SccProjectFilePathRelativizedFromConnection0 = ..\\libs\\jpeg6\\
- SccProjectUniqueName1 = ..\\libs\\pak\\pak.vcproj
- SccProjectName1 = \u0022$/source/q3radiant\u0022,\u0020FEFAAAAA
- SccLocalPath1 = ..\\q3radiant
- SccProvider1 = MSSCCI:Perforce\u0020SCM
- SccProjectFilePathRelativizedFromConnection1 = ..\\libs\\pak\\
- SccProjectUniqueName2 = q3map.vcproj
- SccProjectName2 = \u0022$/source/q3map\u0022,\u0020PADAAAAA
- SccLocalPath2 = .
- SccProvider2 = MSSCCI:Perforce\u0020SCM
- EndGlobalSection
- GlobalSection(SolutionConfiguration) = preSolution
- Debug = Debug
- Release = Release
- EndGlobalSection
- GlobalSection(ProjectConfiguration) = postSolution
- {A862AD26-94DD-4618-A814-F6AACA0B2FE3}.Debug.ActiveCfg = Debug|Win32
- {A862AD26-94DD-4618-A814-F6AACA0B2FE3}.Debug.Build.0 = Debug|Win32
- {A862AD26-94DD-4618-A814-F6AACA0B2FE3}.Release.ActiveCfg = Release|Win32
- {A862AD26-94DD-4618-A814-F6AACA0B2FE3}.Release.Build.0 = Release|Win32
- {F2ACC9D7-D628-4624-864F-87FE58787625}.Debug.ActiveCfg = Debug|Win32
- {F2ACC9D7-D628-4624-864F-87FE58787625}.Debug.Build.0 = Debug|Win32
- {F2ACC9D7-D628-4624-864F-87FE58787625}.Release.ActiveCfg = Release|Win32
- {F2ACC9D7-D628-4624-864F-87FE58787625}.Release.Build.0 = Release|Win32
- {F1162C55-66E7-4486-B1F3-071CFAA78332}.Debug.ActiveCfg = Debug|Win32
- {F1162C55-66E7-4486-B1F3-071CFAA78332}.Debug.Build.0 = Debug|Win32
- {F1162C55-66E7-4486-B1F3-071CFAA78332}.Release.ActiveCfg = Release|Win32
- {F1162C55-66E7-4486-B1F3-071CFAA78332}.Release.Build.0 = Release|Win32
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- EndGlobalSection
- GlobalSection(ExtensibilityAddIns) = postSolution
- EndGlobalSection
-EndGlobal
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jpeg6", "..\libs\jpeg6\jpeg6.vcproj", "{A862AD26-94DD-4618-A814-F6AACA0B2FE3}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pak", "..\libs\pak\pak.vcproj", "{F2ACC9D7-D628-4624-864F-87FE58787625}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "q3map", "q3map.vcproj", "{F1162C55-66E7-4486-B1F3-071CFAA78332}"
+ ProjectSection(ProjectDependencies) = postProject
+ {F2ACC9D7-D628-4624-864F-87FE58787625} = {F2ACC9D7-D628-4624-864F-87FE58787625}
+ {A862AD26-94DD-4618-A814-F6AACA0B2FE3} = {A862AD26-94DD-4618-A814-F6AACA0B2FE3}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SourceCodeControl) = preSolution
+ SccNumberOfProjects = 3
+ SccProjectUniqueName0 = ..\\libs\\jpeg6\\jpeg6.vcproj
+ SccProjectName0 = \u0022$/source/q3radiant\u0022,\u0020FEFAAAAA
+ SccLocalPath0 = ..\\q3radiant
+ SccProvider0 = MSSCCI:Perforce\u0020SCM
+ SccProjectFilePathRelativizedFromConnection0 = ..\\libs\\jpeg6\\
+ SccProjectUniqueName1 = ..\\libs\\pak\\pak.vcproj
+ SccProjectName1 = \u0022$/source/q3radiant\u0022,\u0020FEFAAAAA
+ SccLocalPath1 = ..\\q3radiant
+ SccProvider1 = MSSCCI:Perforce\u0020SCM
+ SccProjectFilePathRelativizedFromConnection1 = ..\\libs\\pak\\
+ SccProjectUniqueName2 = q3map.vcproj
+ SccProjectName2 = \u0022$/source/q3map\u0022,\u0020PADAAAAA
+ SccLocalPath2 = .
+ SccProvider2 = MSSCCI:Perforce\u0020SCM
+ EndGlobalSection
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {A862AD26-94DD-4618-A814-F6AACA0B2FE3}.Debug.ActiveCfg = Debug|Win32
+ {A862AD26-94DD-4618-A814-F6AACA0B2FE3}.Debug.Build.0 = Debug|Win32
+ {A862AD26-94DD-4618-A814-F6AACA0B2FE3}.Release.ActiveCfg = Release|Win32
+ {A862AD26-94DD-4618-A814-F6AACA0B2FE3}.Release.Build.0 = Release|Win32
+ {F2ACC9D7-D628-4624-864F-87FE58787625}.Debug.ActiveCfg = Debug|Win32
+ {F2ACC9D7-D628-4624-864F-87FE58787625}.Debug.Build.0 = Debug|Win32
+ {F2ACC9D7-D628-4624-864F-87FE58787625}.Release.ActiveCfg = Release|Win32
+ {F2ACC9D7-D628-4624-864F-87FE58787625}.Release.Build.0 = Release|Win32
+ {F1162C55-66E7-4486-B1F3-071CFAA78332}.Debug.ActiveCfg = Debug|Win32
+ {F1162C55-66E7-4486-B1F3-071CFAA78332}.Debug.Build.0 = Debug|Win32
+ {F1162C55-66E7-4486-B1F3-071CFAA78332}.Release.ActiveCfg = Release|Win32
+ {F1162C55-66E7-4486-B1F3-071CFAA78332}.Release.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
diff --git a/q3map/q3map.vcproj b/q3map/q3map.vcproj
index 64ad4f8..6fa6606 100755
--- a/q3map/q3map.vcproj
+++ b/q3map/q3map.vcproj
@@ -1,1606 +1,1606 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="7.10"
- Name="q3map"
- SccProjectName="&quot;$/source/q3map&quot;, PADAAAAA"
- SccLocalPath=".">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory=".\Debug"
- IntermediateDirectory=".\Debug"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="../common,c:\quake3\common,c:\quake3\libs"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
- RuntimeLibrary="1"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\Debug/q3map.pch"
- AssemblerListingLocation=".\Debug/"
- ObjectFile=".\Debug/"
- ProgramDataBaseFileName=".\Debug/"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="TRUE"
- DebugInformationFormat="4"
- CompileAs="0"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="glaux.lib glu32.lib wsock32.lib opengl32.lib odbc32.lib odbccp32.lib ..\libs\pakd.lib ..\libs\jpeg6d.lib"
- OutputFile=".\Debug/q3map.exe"
- LinkIncremental="2"
- SuppressStartupBanner="TRUE"
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile=".\Debug/q3map.pdb"
- SubSystem="1"
- StackReserveSize="4194304"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"
- TypeLibraryName=".\Debug/q3map.tlb"
- HeaderFileName=""/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory=".\Release"
- IntermediateDirectory=".\Release"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- AdditionalIncludeDirectories="../common,c:\quake3\common,c:\quake3\libs"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
- StringPooling="TRUE"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="TRUE"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\Release/q3map.pch"
- AssemblerListingLocation=".\Release/"
- ObjectFile=".\Release/"
- ProgramDataBaseFileName=".\Release/"
- WarningLevel="3"
- SuppressStartupBanner="TRUE"
- DebugInformationFormat="3"
- CompileAs="0"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="glaux.lib glu32.lib wsock32.lib opengl32.lib odbc32.lib odbccp32.lib ..\libs\pak.lib ..\libs\jpeg6.lib"
- OutputFile=".\Release/q3map.exe"
- LinkIncremental="1"
- SuppressStartupBanner="TRUE"
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile=".\Release/q3map.pdb"
- SubSystem="1"
- StackReserveSize="4194304"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"
- TypeLibraryName=".\Release/q3map.tlb"
- HeaderFileName=""/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="DebugTTimo|Win32"
- OutputDirectory=".\q3map___Win32_DebugTTimo"
- IntermediateDirectory=".\q3map___Win32_DebugTTimo"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories="../common,../../Libs,c:\quake3\common,c:\quake3\libs"
- PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_TTIMOBUILD"
- RuntimeLibrary="1"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\q3map___Win32_DebugTTimo/q3map.pch"
- AssemblerListingLocation=".\q3map___Win32_DebugTTimo/"
- ObjectFile=".\q3map___Win32_DebugTTimo/"
- ProgramDataBaseFileName=".\q3map___Win32_DebugTTimo/"
- BrowseInformation="1"
- WarningLevel="3"
- SuppressStartupBanner="TRUE"
- DebugInformationFormat="4"
- CompileAs="0"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="glaux.lib glu32.lib wsock32.lib opengl32.lib odbc32.lib odbccp32.lib pakd.lib jpeg6d.lib"
- OutputFile=".\q3map___Win32_DebugTTimo/q3map.exe"
- LinkIncremental="2"
- SuppressStartupBanner="TRUE"
- AdditionalLibraryDirectories="../../Libs"
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile=".\q3map___Win32_DebugTTimo/q3map.pdb"
- SubSystem="1"
- StackReserveSize="4194304"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"
- TypeLibraryName=".\q3map___Win32_DebugTTimo/q3map.tlb"
- HeaderFileName=""/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="_DEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="ReleaseTTimo|Win32"
- OutputDirectory=".\q3map___Win32_ReleaseTTimo"
- IntermediateDirectory=".\q3map___Win32_ReleaseTTimo"
- ConfigurationType="1"
- UseOfMFC="0"
- ATLMinimizesCRunTimeLibraryUsage="FALSE"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- InlineFunctionExpansion="1"
- AdditionalIncludeDirectories="../common,../../Libs,c:\quake3\common,c:\quake3\libs"
- PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_TTIMOBUILD"
- StringPooling="TRUE"
- RuntimeLibrary="0"
- EnableFunctionLevelLinking="TRUE"
- UsePrecompiledHeader="2"
- PrecompiledHeaderFile=".\q3map___Win32_ReleaseTTimo/q3map.pch"
- AssemblerListingLocation=".\q3map___Win32_ReleaseTTimo/"
- ObjectFile=".\q3map___Win32_ReleaseTTimo/"
- ProgramDataBaseFileName=".\q3map___Win32_ReleaseTTimo/"
- WarningLevel="3"
- SuppressStartupBanner="TRUE"
- DebugInformationFormat="3"
- CompileAs="0"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="glaux.lib glu32.lib wsock32.lib opengl32.lib odbc32.lib odbccp32.lib pak.lib jpeg6.lib"
- OutputFile=".\q3map___Win32_ReleaseTTimo/q3map.exe"
- LinkIncremental="1"
- SuppressStartupBanner="TRUE"
- AdditionalLibraryDirectories="../../Libs"
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile=".\q3map___Win32_ReleaseTTimo/q3map.pdb"
- SubSystem="1"
- StackReserveSize="4194304"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"
- TypeLibraryName=".\q3map___Win32_ReleaseTTimo/q3map.tlb"
- HeaderFileName=""/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"
- PreprocessorDefinitions="NDEBUG"
- Culture="1033"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <File
- RelativePath="..\common\aselib.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="brush.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="brush_primit.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="bsp.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\common\bspfile.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\common\cmdlib.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="facebsp.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="fog.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="gldraw.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="glfile.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\common\imagelib.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="leakfile.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="light.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="light_trace.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="lightmaps.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="lightv.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="map.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\common\mathlib.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="mesh.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="misc_model.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\common\mutex.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="patch.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\common\polylib.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="portals.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="prtfile.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\common\scriplib.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="shaders.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="soundv.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="surface.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="terrain.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="..\common\threads.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tjunction.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="tree.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="vis.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="visflow.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- <File
- RelativePath="writebsp.c">
- <FileConfiguration
- Name="Debug|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="Release|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- <FileConfiguration
- Name="DebugTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""
- BrowseInformation="1"/>
- </FileConfiguration>
- <FileConfiguration
- Name="ReleaseTTimo|Win32">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="2"
- AdditionalIncludeDirectories=""
- PreprocessorDefinitions=""/>
- </FileConfiguration>
- </File>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="q3map"
+ SccProjectName="&quot;$/source/q3map&quot;, PADAAAAA"
+ SccLocalPath=".">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../common,c:\quake3\common,c:\quake3\libs"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Debug/q3map.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="glaux.lib glu32.lib wsock32.lib opengl32.lib odbc32.lib odbccp32.lib ..\libs\pakd.lib ..\libs\jpeg6d.lib"
+ OutputFile=".\Debug/q3map.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\Debug/q3map.pdb"
+ SubSystem="1"
+ StackReserveSize="4194304"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\Debug/q3map.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="../common,c:\quake3\common,c:\quake3\libs"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Release/q3map.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="glaux.lib glu32.lib wsock32.lib opengl32.lib odbc32.lib odbccp32.lib ..\libs\pak.lib ..\libs\jpeg6.lib"
+ OutputFile=".\Release/q3map.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\Release/q3map.pdb"
+ SubSystem="1"
+ StackReserveSize="4194304"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\Release/q3map.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="DebugTTimo|Win32"
+ OutputDirectory=".\q3map___Win32_DebugTTimo"
+ IntermediateDirectory=".\q3map___Win32_DebugTTimo"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../common,../../Libs,c:\quake3\common,c:\quake3\libs"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_TTIMOBUILD"
+ RuntimeLibrary="1"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\q3map___Win32_DebugTTimo/q3map.pch"
+ AssemblerListingLocation=".\q3map___Win32_DebugTTimo/"
+ ObjectFile=".\q3map___Win32_DebugTTimo/"
+ ProgramDataBaseFileName=".\q3map___Win32_DebugTTimo/"
+ BrowseInformation="1"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="glaux.lib glu32.lib wsock32.lib opengl32.lib odbc32.lib odbccp32.lib pakd.lib jpeg6d.lib"
+ OutputFile=".\q3map___Win32_DebugTTimo/q3map.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="TRUE"
+ AdditionalLibraryDirectories="../../Libs"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\q3map___Win32_DebugTTimo/q3map.pdb"
+ SubSystem="1"
+ StackReserveSize="4194304"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\q3map___Win32_DebugTTimo/q3map.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="ReleaseTTimo|Win32"
+ OutputDirectory=".\q3map___Win32_ReleaseTTimo"
+ IntermediateDirectory=".\q3map___Win32_ReleaseTTimo"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="../common,../../Libs,c:\quake3\common,c:\quake3\libs"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_TTIMOBUILD"
+ StringPooling="TRUE"
+ RuntimeLibrary="0"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\q3map___Win32_ReleaseTTimo/q3map.pch"
+ AssemblerListingLocation=".\q3map___Win32_ReleaseTTimo/"
+ ObjectFile=".\q3map___Win32_ReleaseTTimo/"
+ ProgramDataBaseFileName=".\q3map___Win32_ReleaseTTimo/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="glaux.lib glu32.lib wsock32.lib opengl32.lib odbc32.lib odbccp32.lib pak.lib jpeg6.lib"
+ OutputFile=".\q3map___Win32_ReleaseTTimo/q3map.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ AdditionalLibraryDirectories="../../Libs"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\q3map___Win32_ReleaseTTimo/q3map.pdb"
+ SubSystem="1"
+ StackReserveSize="4194304"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\q3map___Win32_ReleaseTTimo/q3map.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath="..\common\aselib.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="brush.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="brush_primit.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="bsp.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\common\bspfile.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\common\cmdlib.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="facebsp.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="fog.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="gldraw.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="glfile.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\common\imagelib.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="leakfile.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="light.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="light_trace.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="lightmaps.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="lightv.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="map.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\common\mathlib.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="mesh.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="misc_model.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\common\mutex.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="patch.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\common\polylib.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="portals.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="prtfile.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\common\scriplib.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="shaders.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="soundv.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="surface.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="terrain.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\common\threads.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="tjunction.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="tree.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="vis.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="visflow.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="writebsp.c">
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="DebugTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="ReleaseTTimo|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/q3map/qbsp.h b/q3map/qbsp.h
index 0890713..7c7cfba 100755
--- a/q3map/qbsp.h
+++ b/q3map/qbsp.h
@@ -19,437 +19,437 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include "cmdlib.h"
-#include "mathlib.h"
-#include "scriplib.h"
-#include "polylib.h"
-#include "imagelib.h"
-#include "threads.h"
-#include "bspfile.h"
-#include "shaders.h"
-#include "mesh.h"
-
-
-#define MAX_PATCH_SIZE 32
-
-#define CLIP_EPSILON 0.1
-#define PLANENUM_LEAF -1
-
-#define HINT_PRIORITY 1000
-
-typedef struct parseMesh_s {
- struct parseMesh_s *next;
- mesh_t mesh;
- shaderInfo_t *shaderInfo;
-
- qboolean grouped; // used during shared edge grouping
- struct parseMesh_s *groupChain;
-} parseMesh_t;
-
-typedef struct bspface_s {
- struct bspface_s *next;
- int planenum;
- int priority; // added to value calculation
- qboolean checked;
- qboolean hint;
- winding_t *w;
-} bspface_t;
-
-typedef struct plane_s {
- vec3_t normal;
- vec_t dist;
- int type;
- struct plane_s *hash_chain;
-} plane_t;
-
-typedef struct side_s {
- int planenum;
-
- float texMat[2][3]; // brush primitive texture matrix
- // for old brush coordinates mode
- float vecs[2][4]; // texture coordinate mapping
-
- winding_t *winding;
- winding_t *visibleHull; // convex hull of all visible fragments
-
- struct shaderInfo_s *shaderInfo;
-
- int contents; // from shaderInfo
- int surfaceFlags; // from shaderInfo
- int value; // from shaderInfo
-
- qboolean visible; // choose visble planes first
- qboolean bevel; // don't ever use for bsp splitting, and don't bother
- // making windings for it
- qboolean backSide; // generated side for a q3map_backShader
-} side_t;
-
-
-#define MAX_BRUSH_SIDES 1024
-
-typedef struct bspbrush_s {
- struct bspbrush_s *next;
-
- int entitynum; // editor numbering
- int brushnum; // editor numbering
-
- struct shaderInfo_s *contentShader;
-
- int contents;
- qboolean detail;
- qboolean opaque;
- int outputNumber; // set when the brush is written to the file list
-
- int portalareas[2];
-
- struct bspbrush_s *original; // chopped up brushes will reference the originals
-
- vec3_t mins, maxs;
- int numsides;
- side_t sides[6]; // variably sized
-} bspbrush_t;
-
-
-
-typedef struct drawsurf_s {
- shaderInfo_t *shaderInfo;
-
- bspbrush_t *mapBrush; // not valid for patches
- side_t *side; // not valid for patches
-
- struct drawsurf_s *nextOnShader; // when sorting by shader for lightmaps
-
- int fogNum; // set by FogDrawSurfs
-
- int lightmapNum; // -1 = no lightmap
- int lightmapX, lightmapY;
- int lightmapWidth, lightmapHeight;
-
- int numVerts;
- drawVert_t *verts;
-
- int numIndexes;
- int *indexes;
-
- // for faces only
- int planeNum;
-
- vec3_t lightmapOrigin; // also used for flares
- vec3_t lightmapVecs[3]; // also used for flares
-
- // for patches only
- qboolean patch;
- int patchWidth;
- int patchHeight;
-
- // for misc_models only
- qboolean miscModel;
-
- qboolean flareSurface;
-} mapDrawSurface_t;
-
-typedef struct drawSurfRef_s {
- struct drawSurfRef_s *nextRef;
- int outputNumber;
-} drawSurfRef_t;
-
-typedef struct node_s {
- // both leafs and nodes
- int planenum; // -1 = leaf node
- struct node_s *parent;
- vec3_t mins, maxs; // valid after portalization
- bspbrush_t *volume; // one for each leaf/node
-
- // nodes only
- side_t *side; // the side that created the node
- struct node_s *children[2];
- qboolean hint;
- int tinyportals;
- vec3_t referencepoint;
-
- // leafs only
- qboolean opaque; // view can never be inside
- qboolean areaportal;
- int cluster; // for portalfile writing
- int area; // for areaportals
- bspbrush_t *brushlist; // fragments of all brushes in this leaf
- drawSurfRef_t *drawSurfReferences; // references to patches pushed down
-
- int occupied; // 1 or greater can reach entity
- entity_t *occupant; // for leak file testing
-
- struct portal_s *portals; // also on nodes during construction
-} node_t;
-
-typedef struct portal_s {
- plane_t plane;
- node_t *onnode; // NULL = outside box
- node_t *nodes[2]; // [0] = front side of plane
- struct portal_s *next[2];
- winding_t *winding;
-
- qboolean sidefound; // false if ->side hasn't been checked
- qboolean hint;
- side_t *side; // NULL = non-visible
-} portal_t;
-
-typedef struct {
- node_t *headnode;
- node_t outside_node;
- vec3_t mins, maxs;
-} tree_t;
-
-extern int entity_num;
-
-
-extern qboolean noprune;
-extern qboolean nodetail;
-extern qboolean fulldetail;
-extern qboolean nowater;
-extern qboolean noCurveBrushes;
-extern qboolean fakemap;
-extern qboolean coplanar;
-extern qboolean nofog;
-extern qboolean testExpand;
-extern qboolean showseams;
-
-extern vec_t microvolume;
-
-extern char outbase[32];
-extern char source[1024];
-
-extern int samplesize; //sample size in units
-extern int novertexlighting;
-extern int nogridlighting;
-
-//=============================================================================
-
-// brush.c
-
-int CountBrushList (bspbrush_t *brushes);
-bspbrush_t *AllocBrush (int numsides);
-void FreeBrush (bspbrush_t *brushes);
-void FreeBrushList (bspbrush_t *brushes);
-bspbrush_t *CopyBrush (bspbrush_t *brush);
-void DrawBrushList (bspbrush_t *brush);
-void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis);
-void PrintBrush (bspbrush_t *brush);
-qboolean BoundBrush (bspbrush_t *brush);
-qboolean CreateBrushWindings (bspbrush_t *brush);
-bspbrush_t *BrushFromBounds (vec3_t mins, vec3_t maxs);
-vec_t BrushVolume (bspbrush_t *brush);
-void WriteBspBrushMap (char *name, bspbrush_t *list);
-
-void FilterDetailBrushesIntoTree( entity_t *e, tree_t *tree );
-void FilterStructuralBrushesIntoTree( entity_t *e, tree_t *tree );
-
-//=============================================================================
-
-// map.c
-
-extern int entitySourceBrushes;
-
-// mapplanes[ num^1 ] will always be the mirror or mapplanes[ num ]
-// nummapplanes will always be even
-extern plane_t mapplanes[MAX_MAP_PLANES];
-extern int nummapplanes;
-
-extern vec3_t map_mins, map_maxs;
-
-extern char mapIndexedShaders[MAX_MAP_BRUSHSIDES][MAX_QPATH];
-extern int numMapIndexedShaders;
-
-extern entity_t *mapent;
-
-#define MAX_BUILD_SIDES 300
-extern bspbrush_t *buildBrush;
-
-
-void LoadMapFile (char *filename);
-int FindFloatPlane (vec3_t normal, vec_t dist);
-int PlaneTypeForNormal (vec3_t normal);
-bspbrush_t *FinishBrush( void );
-mapDrawSurface_t *AllocDrawSurf( void );
-mapDrawSurface_t *DrawSurfaceForSide( bspbrush_t *b, side_t *s, winding_t *w );
-
-//=============================================================================
-
-//=============================================================================
-
-// draw.c
-
-extern vec3_t draw_mins, draw_maxs;
-extern qboolean drawflag;
-
-void Draw_ClearWindow (void);
-void DrawWinding (winding_t *w);
-
-void GLS_BeginScene (void);
-void GLS_Winding (winding_t *w, int code);
-void GLS_EndScene (void);
-
-//=============================================================================
-
-// csg
-
-bspbrush_t *MakeBspBrushList ( bspbrush_t *brushes, vec3_t clipmins, vec3_t clipmaxs);
-
-//=============================================================================
-
-// brushbsp
-
-#define PSIDE_FRONT 1
-#define PSIDE_BACK 2
-#define PSIDE_BOTH (PSIDE_FRONT|PSIDE_BACK)
-#define PSIDE_FACING 4
-
-int BoxOnPlaneSide (vec3_t mins, vec3_t maxs, plane_t *plane);
-qboolean WindingIsTiny (winding_t *w);
-
-void SplitBrush (bspbrush_t *brush, int planenum,
- bspbrush_t **front, bspbrush_t **back);
-
-tree_t *AllocTree (void);
-node_t *AllocNode (void);
-
-tree_t *BrushBSP (bspbrush_t *brushlist, vec3_t mins, vec3_t maxs);
-
-//=============================================================================
-
-// portals.c
-
-void MakeHeadnodePortals (tree_t *tree);
-void MakeNodePortal (node_t *node);
-void SplitNodePortals (node_t *node);
-
-qboolean Portal_Passable(portal_t *p);
-
-qboolean FloodEntities (tree_t *tree);
-void FillOutside (node_t *headnode);
-void FloodAreas (tree_t *tree);
-bspface_t *VisibleFaces(entity_t *e, tree_t *tree);
-void FreePortal (portal_t *p);
-
-void MakeTreePortals (tree_t *tree);
-
-//=============================================================================
-
-// glfile.c
-
-void OutputWinding( winding_t *w, FILE *glview );
-void WriteGLView( tree_t *tree, char *source );
-
-//=============================================================================
-
-// leakfile.c
-
-void LeakFile( tree_t *tree );
-
-//=============================================================================
-
-// prtfile.c
-
-void NumberClusters( tree_t *tree );
-void WritePortalFile( tree_t *tree );
-
-//=============================================================================
-
-// writebsp.c
-
-void SetModelNumbers (void);
-void SetLightStyles (void);
-
-int EmitShader( const char *shader );
-
-void BeginBSPFile (void);
-void EndBSPFile (void);
-
-void BeginModel (void);
-void EndModel( node_t *headnode );
-
-
-//=============================================================================
-
-// tree.c
-
-void FreeTree (tree_t *tree);
-void FreeTree_r (node_t *node);
-void PrintTree_r (node_t *node, int depth);
-void FreeTreePortals_r (node_t *node);
-
-//=============================================================================
-
-// patch.c
-
-extern int numMapPatches;
-
-mapDrawSurface_t *DrawSurfaceForMesh( mesh_t *m );
-void ParsePatch( void );
-mesh_t *SubdivideMesh( mesh_t in, float maxError, float minLength );
-void PatchMapDrawSurfs( entity_t *e );
-
-//=============================================================================
-
-// lightmap.c
-
-void AllocateLightmaps( entity_t *e );
-
-//=============================================================================
-
-// tjunction.c
-
-void FixTJunctions( entity_t *e );
-
-
-//=============================================================================
-
-// fog.c
-
-void FogDrawSurfs( void );
-winding_t *WindingFromDrawSurf( mapDrawSurface_t *ds );
-
-//=============================================================================
-
-// facebsp.c
-
-bspface_t *BspFaceForPortal( portal_t *p );
-bspface_t *MakeStructuralBspFaceList( bspbrush_t *list );
-bspface_t *MakeVisibleBspFaceList( bspbrush_t *list );
-tree_t *FaceBSP( bspface_t *list );
-
-//=============================================================================
-
-// misc_model.c
-
-extern int c_triangleModels;
-extern int c_triangleSurfaces;
-extern int c_triangleVertexes;
-extern int c_triangleIndexes;
-
-void AddTriangleModels( tree_t *tree );
-
-//=============================================================================
-
-// surface.c
-
-extern mapDrawSurface_t mapDrawSurfs[MAX_MAP_DRAW_SURFS];
-extern int numMapDrawSurfs;
-
-mapDrawSurface_t *AllocDrawSurf( void );
-void MergeSides( entity_t *e, tree_t *tree );
-void SubdivideDrawSurfs( entity_t *e, tree_t *tree );
-void MakeDrawSurfaces( bspbrush_t *b );
-void ClipSidesIntoTree( entity_t *e, tree_t *tree );
-void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree );
-
-//==============================================================================
-
-// brush_primit.c
-
-#define BPRIMIT_UNDEFINED 0
-#define BPRIMIT_OLDBRUSHES 1
-#define BPRIMIT_NEWBRUSHES 2
-extern int g_bBrushPrimit;
-
-void ComputeAxisBase( vec3_t normal, vec3_t texX, vec3_t texY);
+
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "scriplib.h"
+#include "polylib.h"
+#include "imagelib.h"
+#include "threads.h"
+#include "bspfile.h"
+#include "shaders.h"
+#include "mesh.h"
+
+
+#define MAX_PATCH_SIZE 32
+
+#define CLIP_EPSILON 0.1
+#define PLANENUM_LEAF -1
+
+#define HINT_PRIORITY 1000
+
+typedef struct parseMesh_s {
+ struct parseMesh_s *next;
+ mesh_t mesh;
+ shaderInfo_t *shaderInfo;
+
+ qboolean grouped; // used during shared edge grouping
+ struct parseMesh_s *groupChain;
+} parseMesh_t;
+
+typedef struct bspface_s {
+ struct bspface_s *next;
+ int planenum;
+ int priority; // added to value calculation
+ qboolean checked;
+ qboolean hint;
+ winding_t *w;
+} bspface_t;
+
+typedef struct plane_s {
+ vec3_t normal;
+ vec_t dist;
+ int type;
+ struct plane_s *hash_chain;
+} plane_t;
+
+typedef struct side_s {
+ int planenum;
+
+ float texMat[2][3]; // brush primitive texture matrix
+ // for old brush coordinates mode
+ float vecs[2][4]; // texture coordinate mapping
+
+ winding_t *winding;
+ winding_t *visibleHull; // convex hull of all visible fragments
+
+ struct shaderInfo_s *shaderInfo;
+
+ int contents; // from shaderInfo
+ int surfaceFlags; // from shaderInfo
+ int value; // from shaderInfo
+
+ qboolean visible; // choose visble planes first
+ qboolean bevel; // don't ever use for bsp splitting, and don't bother
+ // making windings for it
+ qboolean backSide; // generated side for a q3map_backShader
+} side_t;
+
+
+#define MAX_BRUSH_SIDES 1024
+
+typedef struct bspbrush_s {
+ struct bspbrush_s *next;
+
+ int entitynum; // editor numbering
+ int brushnum; // editor numbering
+
+ struct shaderInfo_s *contentShader;
+
+ int contents;
+ qboolean detail;
+ qboolean opaque;
+ int outputNumber; // set when the brush is written to the file list
+
+ int portalareas[2];
+
+ struct bspbrush_s *original; // chopped up brushes will reference the originals
+
+ vec3_t mins, maxs;
+ int numsides;
+ side_t sides[6]; // variably sized
+} bspbrush_t;
+
+
+
+typedef struct drawsurf_s {
+ shaderInfo_t *shaderInfo;
+
+ bspbrush_t *mapBrush; // not valid for patches
+ side_t *side; // not valid for patches
+
+ struct drawsurf_s *nextOnShader; // when sorting by shader for lightmaps
+
+ int fogNum; // set by FogDrawSurfs
+
+ int lightmapNum; // -1 = no lightmap
+ int lightmapX, lightmapY;
+ int lightmapWidth, lightmapHeight;
+
+ int numVerts;
+ drawVert_t *verts;
+
+ int numIndexes;
+ int *indexes;
+
+ // for faces only
+ int planeNum;
+
+ vec3_t lightmapOrigin; // also used for flares
+ vec3_t lightmapVecs[3]; // also used for flares
+
+ // for patches only
+ qboolean patch;
+ int patchWidth;
+ int patchHeight;
+
+ // for misc_models only
+ qboolean miscModel;
+
+ qboolean flareSurface;
+} mapDrawSurface_t;
+
+typedef struct drawSurfRef_s {
+ struct drawSurfRef_s *nextRef;
+ int outputNumber;
+} drawSurfRef_t;
+
+typedef struct node_s {
+ // both leafs and nodes
+ int planenum; // -1 = leaf node
+ struct node_s *parent;
+ vec3_t mins, maxs; // valid after portalization
+ bspbrush_t *volume; // one for each leaf/node
+
+ // nodes only
+ side_t *side; // the side that created the node
+ struct node_s *children[2];
+ qboolean hint;
+ int tinyportals;
+ vec3_t referencepoint;
+
+ // leafs only
+ qboolean opaque; // view can never be inside
+ qboolean areaportal;
+ int cluster; // for portalfile writing
+ int area; // for areaportals
+ bspbrush_t *brushlist; // fragments of all brushes in this leaf
+ drawSurfRef_t *drawSurfReferences; // references to patches pushed down
+
+ int occupied; // 1 or greater can reach entity
+ entity_t *occupant; // for leak file testing
+
+ struct portal_s *portals; // also on nodes during construction
+} node_t;
+
+typedef struct portal_s {
+ plane_t plane;
+ node_t *onnode; // NULL = outside box
+ node_t *nodes[2]; // [0] = front side of plane
+ struct portal_s *next[2];
+ winding_t *winding;
+
+ qboolean sidefound; // false if ->side hasn't been checked
+ qboolean hint;
+ side_t *side; // NULL = non-visible
+} portal_t;
+
+typedef struct {
+ node_t *headnode;
+ node_t outside_node;
+ vec3_t mins, maxs;
+} tree_t;
+
+extern int entity_num;
+
+
+extern qboolean noprune;
+extern qboolean nodetail;
+extern qboolean fulldetail;
+extern qboolean nowater;
+extern qboolean noCurveBrushes;
+extern qboolean fakemap;
+extern qboolean coplanar;
+extern qboolean nofog;
+extern qboolean testExpand;
+extern qboolean showseams;
+
+extern vec_t microvolume;
+
+extern char outbase[32];
+extern char source[1024];
+
+extern int samplesize; //sample size in units
+extern int novertexlighting;
+extern int nogridlighting;
+
+//=============================================================================
+
+// brush.c
+
+int CountBrushList (bspbrush_t *brushes);
+bspbrush_t *AllocBrush (int numsides);
+void FreeBrush (bspbrush_t *brushes);
+void FreeBrushList (bspbrush_t *brushes);
+bspbrush_t *CopyBrush (bspbrush_t *brush);
+void DrawBrushList (bspbrush_t *brush);
+void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis);
+void PrintBrush (bspbrush_t *brush);
+qboolean BoundBrush (bspbrush_t *brush);
+qboolean CreateBrushWindings (bspbrush_t *brush);
+bspbrush_t *BrushFromBounds (vec3_t mins, vec3_t maxs);
+vec_t BrushVolume (bspbrush_t *brush);
+void WriteBspBrushMap (char *name, bspbrush_t *list);
+
+void FilterDetailBrushesIntoTree( entity_t *e, tree_t *tree );
+void FilterStructuralBrushesIntoTree( entity_t *e, tree_t *tree );
+
+//=============================================================================
+
+// map.c
+
+extern int entitySourceBrushes;
+
+// mapplanes[ num^1 ] will always be the mirror or mapplanes[ num ]
+// nummapplanes will always be even
+extern plane_t mapplanes[MAX_MAP_PLANES];
+extern int nummapplanes;
+
+extern vec3_t map_mins, map_maxs;
+
+extern char mapIndexedShaders[MAX_MAP_BRUSHSIDES][MAX_QPATH];
+extern int numMapIndexedShaders;
+
+extern entity_t *mapent;
+
+#define MAX_BUILD_SIDES 300
+extern bspbrush_t *buildBrush;
+
+
+void LoadMapFile (char *filename);
+int FindFloatPlane (vec3_t normal, vec_t dist);
+int PlaneTypeForNormal (vec3_t normal);
+bspbrush_t *FinishBrush( void );
+mapDrawSurface_t *AllocDrawSurf( void );
+mapDrawSurface_t *DrawSurfaceForSide( bspbrush_t *b, side_t *s, winding_t *w );
+
+//=============================================================================
+
+//=============================================================================
+
+// draw.c
+
+extern vec3_t draw_mins, draw_maxs;
+extern qboolean drawflag;
+
+void Draw_ClearWindow (void);
+void DrawWinding (winding_t *w);
+
+void GLS_BeginScene (void);
+void GLS_Winding (winding_t *w, int code);
+void GLS_EndScene (void);
+
+//=============================================================================
+
+// csg
+
+bspbrush_t *MakeBspBrushList ( bspbrush_t *brushes, vec3_t clipmins, vec3_t clipmaxs);
+
+//=============================================================================
+
+// brushbsp
+
+#define PSIDE_FRONT 1
+#define PSIDE_BACK 2
+#define PSIDE_BOTH (PSIDE_FRONT|PSIDE_BACK)
+#define PSIDE_FACING 4
+
+int BoxOnPlaneSide (vec3_t mins, vec3_t maxs, plane_t *plane);
+qboolean WindingIsTiny (winding_t *w);
+
+void SplitBrush (bspbrush_t *brush, int planenum,
+ bspbrush_t **front, bspbrush_t **back);
+
+tree_t *AllocTree (void);
+node_t *AllocNode (void);
+
+tree_t *BrushBSP (bspbrush_t *brushlist, vec3_t mins, vec3_t maxs);
+
+//=============================================================================
+
+// portals.c
+
+void MakeHeadnodePortals (tree_t *tree);
+void MakeNodePortal (node_t *node);
+void SplitNodePortals (node_t *node);
+
+qboolean Portal_Passable(portal_t *p);
+
+qboolean FloodEntities (tree_t *tree);
+void FillOutside (node_t *headnode);
+void FloodAreas (tree_t *tree);
+bspface_t *VisibleFaces(entity_t *e, tree_t *tree);
+void FreePortal (portal_t *p);
+
+void MakeTreePortals (tree_t *tree);
+
+//=============================================================================
+
+// glfile.c
+
+void OutputWinding( winding_t *w, FILE *glview );
+void WriteGLView( tree_t *tree, char *source );
+
+//=============================================================================
+
+// leakfile.c
+
+void LeakFile( tree_t *tree );
+
+//=============================================================================
+
+// prtfile.c
+
+void NumberClusters( tree_t *tree );
+void WritePortalFile( tree_t *tree );
+
+//=============================================================================
+
+// writebsp.c
+
+void SetModelNumbers (void);
+void SetLightStyles (void);
+
+int EmitShader( const char *shader );
+
+void BeginBSPFile (void);
+void EndBSPFile (void);
+
+void BeginModel (void);
+void EndModel( node_t *headnode );
+
+
+//=============================================================================
+
+// tree.c
+
+void FreeTree (tree_t *tree);
+void FreeTree_r (node_t *node);
+void PrintTree_r (node_t *node, int depth);
+void FreeTreePortals_r (node_t *node);
+
+//=============================================================================
+
+// patch.c
+
+extern int numMapPatches;
+
+mapDrawSurface_t *DrawSurfaceForMesh( mesh_t *m );
+void ParsePatch( void );
+mesh_t *SubdivideMesh( mesh_t in, float maxError, float minLength );
+void PatchMapDrawSurfs( entity_t *e );
+
+//=============================================================================
+
+// lightmap.c
+
+void AllocateLightmaps( entity_t *e );
+
+//=============================================================================
+
+// tjunction.c
+
+void FixTJunctions( entity_t *e );
+
+
+//=============================================================================
+
+// fog.c
+
+void FogDrawSurfs( void );
+winding_t *WindingFromDrawSurf( mapDrawSurface_t *ds );
+
+//=============================================================================
+
+// facebsp.c
+
+bspface_t *BspFaceForPortal( portal_t *p );
+bspface_t *MakeStructuralBspFaceList( bspbrush_t *list );
+bspface_t *MakeVisibleBspFaceList( bspbrush_t *list );
+tree_t *FaceBSP( bspface_t *list );
+
+//=============================================================================
+
+// misc_model.c
+
+extern int c_triangleModels;
+extern int c_triangleSurfaces;
+extern int c_triangleVertexes;
+extern int c_triangleIndexes;
+
+void AddTriangleModels( tree_t *tree );
+
+//=============================================================================
+
+// surface.c
+
+extern mapDrawSurface_t mapDrawSurfs[MAX_MAP_DRAW_SURFS];
+extern int numMapDrawSurfs;
+
+mapDrawSurface_t *AllocDrawSurf( void );
+void MergeSides( entity_t *e, tree_t *tree );
+void SubdivideDrawSurfs( entity_t *e, tree_t *tree );
+void MakeDrawSurfaces( bspbrush_t *b );
+void ClipSidesIntoTree( entity_t *e, tree_t *tree );
+void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree );
+
+//==============================================================================
+
+// brush_primit.c
+
+#define BPRIMIT_UNDEFINED 0
+#define BPRIMIT_OLDBRUSHES 1
+#define BPRIMIT_NEWBRUSHES 2
+extern int g_bBrushPrimit;
+
+void ComputeAxisBase( vec3_t normal, vec3_t texX, vec3_t texY);
diff --git a/q3map/shaders.c b/q3map/shaders.c
index 1efc513..4adfcf0 100755
--- a/q3map/shaders.c
+++ b/q3map/shaders.c
@@ -19,590 +19,590 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include <string.h>
-#include <math.h>
-#include "cmdlib.h"
-#include "mathlib.h"
-#include "imagelib.h"
-#include "scriplib.h"
-
-#ifdef _TTIMOBUILD
-#include "../common/qfiles.h"
-#include "../common/surfaceflags.h"
-#else
-#include "../code/qcommon/qfiles.h"
-#include "../code/game/surfaceflags.h"
-#endif
-
-#include "shaders.h"
-#ifdef _WIN32
-
-#ifdef _TTIMOBUILD
-#include "pakstuff.h"
-#include "jpeglib.h"
-#else
-#include "../libs/pakstuff.h"
-#include "../libs/jpeglib.h"
-#endif
-
-#endif
-
-
-// 5% backsplash by default
-#define DEFAULT_BACKSPLASH_FRACTION 0.05
-#define DEFAULT_BACKSPLASH_DISTANCE 24
-
-
-#define MAX_SURFACE_INFO 4096
-
-shaderInfo_t defaultInfo;
-shaderInfo_t shaderInfo[MAX_SURFACE_INFO];
-int numShaderInfo;
-
-
-typedef struct {
- char *name;
- int clearSolid, surfaceFlags, contents;
-} infoParm_t;
-
-infoParm_t infoParms[] = {
- // server relevant contents
- {"water", 1, 0, CONTENTS_WATER },
- {"slime", 1, 0, CONTENTS_SLIME }, // mildly damaging
- {"lava", 1, 0, CONTENTS_LAVA }, // very damaging
- {"playerclip", 1, 0, CONTENTS_PLAYERCLIP },
- {"monsterclip", 1, 0, CONTENTS_MONSTERCLIP },
- {"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc)
- {"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag
-
- // utility relevant attributes
- {"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes
- {"trans", 0, 0, CONTENTS_TRANSLUCENT }, // don't eat contained surfaces
- {"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp
- {"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas
- {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas
- {"clusterportal",1, 0, CONTENTS_CLUSTERPORTAL },// for bots
- {"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots
- {"botclip", 1, 0, CONTENTS_BOTCLIP }, // for bots
- {"nobotclip", 0, 0, CONTENTS_NOBOTCLIP }, // don't use for bot clipping
-
- {"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering
- {"sky", 0, SURF_SKY, 0 }, // emit light from an environment map
- {"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it
- {"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis
- {"hint", 0, SURF_HINT, 0 }, // use as a primary splitter
-
- // server attributes
- {"slick", 0, SURF_SLICK, 0 },
- {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks
- {"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode
- {"ladder", 0, SURF_LADDER, 0 },
- {"nodamage", 0, SURF_NODAMAGE, 0 },
- {"metalsteps", 0, SURF_METALSTEPS,0 },
- {"flesh", 0, SURF_FLESH, 0 },
- {"nosteps", 0, SURF_NOSTEPS, 0 },
-
- // drawsurf attributes
- {"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap)
- {"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes
- {"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap
- {"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights
- {"dust", 0, SURF_DUST, 0} // leave dust trail when walking on this surface
-};
-
-
-/*
-===============
-LoadShaderImage
-===============
-*/
-
-byte* LoadImageFile(char *filename, qboolean *bTGA)
-{
- byte *buffer = NULL;
- int nLen = 0;
- *bTGA = qtrue;
- if (FileExists(filename))
- {
- LoadFileBlock(filename, &buffer);
- }
-#ifdef _WIN32
- else
- {
- PakLoadAnyFile(filename, &buffer);
- }
-#endif
- if ( buffer == NULL)
- {
- nLen = strlen(filename);
- filename[nLen-3] = 'j';
- filename[nLen-2] = 'p';
- filename[nLen-1] = 'g';
- if (FileExists(filename))
- {
- LoadFileBlock(filename, &buffer);
- }
-#ifdef _WIN32
- else
- {
- PakLoadAnyFile(filename, &buffer);
- }
-#endif
- if ( buffer )
- {
- *bTGA = qfalse;
- }
- }
- return buffer;
-}
-
-/*
-===============
-LoadShaderImage
-===============
-*/
-static void LoadShaderImage( shaderInfo_t *si ) {
- char filename[1024];
- int i, count;
- float color[4];
- byte *buffer;
- qboolean bTGA = qtrue;
-
- // look for the lightimage if it is specified
- if ( si->lightimage[0] ) {
- sprintf( filename, "%s%s", gamedir, si->lightimage );
- DefaultExtension( filename, ".tga" );
- buffer = LoadImageFile(filename, &bTGA);
- if ( buffer != NULL) {
- goto loadTga;
- }
- }
-
- // look for the editorimage if it is specified
- if ( si->editorimage[0] ) {
- sprintf( filename, "%s%s", gamedir, si->editorimage );
- DefaultExtension( filename, ".tga" );
- buffer = LoadImageFile(filename, &bTGA);
- if ( buffer != NULL) {
- goto loadTga;
- }
- }
-
- // just try the shader name with a .tga
- // on unix, we have case sensitivity problems...
- sprintf( filename, "%s%s.tga", gamedir, si->shader );
- buffer = LoadImageFile(filename, &bTGA);
- if ( buffer != NULL) {
- goto loadTga;
- }
-
- sprintf( filename, "%s%s.TGA", gamedir, si->shader );
- buffer = LoadImageFile(filename, &bTGA);
- if ( buffer != NULL) {
- goto loadTga;
- }
-
- // couldn't load anything
- _printf("WARNING: Couldn't find image for shader %s\n", si->shader );
-
- si->color[0] = 1;
- si->color[1] = 1;
- si->color[2] = 1;
- si->width = 64;
- si->height = 64;
- si->pixels = malloc( si->width * si->height * 4 );
- memset ( si->pixels, 255, si->width * si->height * 4 );
- return;
-
- // load the image to get dimensions and color
-loadTga:
- if ( bTGA) {
- LoadTGABuffer( buffer, &si->pixels, &si->width, &si->height );
- }
- else {
-#ifdef _WIN32
- LoadJPGBuff(buffer, &si->pixels, &si->width, &si->height );
-#endif
- }
-
- free(buffer);
-
- count = si->width * si->height;
-
- VectorClear( color );
- color[ 3 ] = 0;
- for ( i = 0 ; i < count ; i++ ) {
- color[0] += si->pixels[ i * 4 + 0 ];
- color[1] += si->pixels[ i * 4 + 1 ];
- color[2] += si->pixels[ i * 4 + 2 ];
- color[3] += si->pixels[ i * 4 + 3 ];
- }
- ColorNormalize( color, si->color );
- VectorScale( color, 1.0/count, si->averageColor );
-}
-
-/*
-===============
-AllocShaderInfo
-===============
-*/
-static shaderInfo_t *AllocShaderInfo( void ) {
- shaderInfo_t *si;
-
- if ( numShaderInfo == MAX_SURFACE_INFO ) {
- Error( "MAX_SURFACE_INFO" );
- }
- si = &shaderInfo[ numShaderInfo ];
- numShaderInfo++;
-
- // set defaults
-
- si->contents = CONTENTS_SOLID;
-
- si->backsplashFraction = DEFAULT_BACKSPLASH_FRACTION;
- si->backsplashDistance = DEFAULT_BACKSPLASH_DISTANCE;
-
- si->lightmapSampleSize = 0;
- si->forceTraceLight = qfalse;
- si->forceVLight = qfalse;
- si->patchShadows = qfalse;
- si->vertexShadows = qfalse;
- si->noVertexShadows = qfalse;
- si->forceSunLight = qfalse;
- si->vertexScale = 1.0;
- si->notjunc = qfalse;
-
- return si;
-}
-
-/*
-===============
-ShaderInfoForShader
-===============
-*/
-shaderInfo_t *ShaderInfoForShader( const char *shaderName ) {
- int i;
- shaderInfo_t *si;
- char shader[MAX_QPATH];
-
- // strip off extension
- strcpy( shader, shaderName );
- StripExtension( shader );
-
- // search for it
- for ( i = 0 ; i < numShaderInfo ; i++ ) {
- si = &shaderInfo[ i ];
- if ( !Q_stricmp( shader, si->shader ) ) {
- if ( !si->width ) {
- LoadShaderImage( si );
- }
- return si;
- }
- }
-
- si = AllocShaderInfo();
- strcpy( si->shader, shader );
-
- LoadShaderImage( si );
-
- return si;
-}
-
-/*
-===============
-ParseShaderFile
-===============
-*/
-static void ParseShaderFile( const char *filename ) {
- int i;
- int numInfoParms = sizeof(infoParms) / sizeof(infoParms[0]);
- shaderInfo_t *si;
-
-// qprintf( "shaderFile: %s\n", filename );
- LoadScriptFile( filename );
- while ( 1 ) {
- if ( !GetToken( qtrue ) ) {
- break;
- }
-
- si = AllocShaderInfo();
- strcpy( si->shader, token );
- MatchToken( "{" );
- while ( 1 ) {
- if ( !GetToken( qtrue ) ) {
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
-
- // skip internal braced sections
- if ( !strcmp( token, "{" ) ) {
- si->hasPasses = qtrue;
- while ( 1 ) {
- if ( !GetToken( qtrue ) ) {
- break;
- }
- if ( !strcmp( token, "}" ) ) {
- break;
- }
- }
- continue;
- }
-
- if ( !Q_stricmp( token, "surfaceparm" ) ) {
- GetToken( qfalse );
- for ( i = 0 ; i < numInfoParms ; i++ ) {
- if ( !Q_stricmp( token, infoParms[i].name ) ) {
- si->surfaceFlags |= infoParms[i].surfaceFlags;
- si->contents |= infoParms[i].contents;
- if ( infoParms[i].clearSolid ) {
- si->contents &= ~CONTENTS_SOLID;
- }
- break;
- }
- }
- if ( i == numInfoParms ) {
- // we will silently ignore all tokens beginning with qer,
- // which are QuakeEdRadient parameters
- if ( Q_strncasecmp( token, "qer", 3 ) ) {
- _printf( "Unknown surfaceparm: \"%s\"\n", token );
- }
- }
- continue;
- }
-
-
- // qer_editorimage <image>
- if ( !Q_stricmp( token, "qer_editorimage" ) ) {
- GetToken( qfalse );
- strcpy( si->editorimage, token );
- DefaultExtension( si->editorimage, ".tga" );
- continue;
- }
-
- // q3map_lightimage <image>
- if ( !Q_stricmp( token, "q3map_lightimage" ) ) {
- GetToken( qfalse );
- strcpy( si->lightimage, token );
- DefaultExtension( si->lightimage, ".tga" );
- continue;
- }
-
- // q3map_surfacelight <value>
- if ( !Q_stricmp( token, "q3map_surfacelight" ) ) {
- GetToken( qfalse );
- si->value = atoi( token );
- continue;
- }
-
- // q3map_lightsubdivide <value>
- if ( !Q_stricmp( token, "q3map_lightsubdivide" ) ) {
- GetToken( qfalse );
- si->lightSubdivide = atoi( token );
- continue;
- }
-
- // q3map_lightmapsamplesize <value>
- if ( !Q_stricmp( token, "q3map_lightmapsamplesize" ) ) {
- GetToken( qfalse );
- si->lightmapSampleSize = atoi( token );
- continue;
- }
-
- // q3map_tracelight
- if ( !Q_stricmp( token, "q3map_tracelight" ) ) {
- si->forceTraceLight = qtrue;
- continue;
- }
-
- // q3map_vlight
- if ( !Q_stricmp( token, "q3map_vlight" ) ) {
- si->forceVLight = qtrue;
- continue;
- }
-
- // q3map_patchshadows
- if ( !Q_stricmp( token, "q3map_patchshadows" ) ) {
- si->patchShadows = qtrue;
- continue;
- }
-
- // q3map_vertexshadows
- if ( !Q_stricmp( token, "q3map_vertexshadows" ) ) {
- si->vertexShadows = qtrue;
- continue;
- }
-
- // q3map_novertexshadows
- if ( !Q_stricmp( token, "q3map_novertexshadows" ) ) {
- si->noVertexShadows = qtrue;
- continue;
- }
-
- // q3map_forcesunlight
- if ( !Q_stricmp( token, "q3map_forcesunlight" ) ) {
- si->forceSunLight = qtrue;
- continue;
- }
-
- // q3map_vertexscale
- if ( !Q_stricmp( token, "q3map_vertexscale" ) ) {
- GetToken( qfalse );
- si->vertexScale = atof(token);
- continue;
- }
-
- // q3map_notjunc
- if ( !Q_stricmp( token, "q3map_notjunc" ) ) {
- si->notjunc = qtrue;
- continue;
- }
-
- // q3map_globaltexture
- if ( !Q_stricmp( token, "q3map_globaltexture" ) ) {
- si->globalTexture = qtrue;
- continue;
- }
-
- // q3map_backsplash <percent> <distance>
- if ( !Q_stricmp( token, "q3map_backsplash" ) ) {
- GetToken( qfalse );
- si->backsplashFraction = atof( token ) * 0.01;
- GetToken( qfalse );
- si->backsplashDistance = atof( token );
- continue;
- }
-
- // q3map_backshader <shader>
- if ( !Q_stricmp( token, "q3map_backshader" ) ) {
- GetToken( qfalse );
- strcpy( si->backShader, token );
- continue;
- }
-
- // q3map_flare <shader>
- if ( !Q_stricmp( token, "q3map_flare" ) ) {
- GetToken( qfalse );
- strcpy( si->flareShader, token );
- continue;
- }
-
- // light <value>
- // old style flare specification
- if ( !Q_stricmp( token, "light" ) ) {
- GetToken( qfalse );
- strcpy( si->flareShader, "flareshader" );
- continue;
- }
-
- // q3map_sun <red> <green> <blue> <intensity> <degrees> <elivation>
- // color will be normalized, so it doesn't matter what range you use
- // intensity falls off with angle but not distance 100 is a fairly bright sun
- // degree of 0 = from the east, 90 = north, etc. altitude of 0 = sunrise/set, 90 = noon
- if ( !Q_stricmp( token, "q3map_sun" ) ) {
- float a, b;
-
- GetToken( qfalse );
- si->sunLight[0] = atof( token );
- GetToken( qfalse );
- si->sunLight[1] = atof( token );
- GetToken( qfalse );
- si->sunLight[2] = atof( token );
-
- VectorNormalize( si->sunLight, si->sunLight);
-
- GetToken( qfalse );
- a = atof( token );
- VectorScale( si->sunLight, a, si->sunLight);
-
- GetToken( qfalse );
- a = atof( token );
- a = a / 180 * Q_PI;
-
- GetToken( qfalse );
- b = atof( token );
- b = b / 180 * Q_PI;
-
- si->sunDirection[0] = cos( a ) * cos( b );
- si->sunDirection[1] = sin( a ) * cos( b );
- si->sunDirection[2] = sin( b );
-
- si->surfaceFlags |= SURF_SKY;
- continue;
- }
-
- // tesssize is used to force liquid surfaces to subdivide
- if ( !Q_stricmp( token, "tesssize" ) ) {
- GetToken( qfalse );
- si->subdivisions = atof( token );
- continue;
- }
-
- // cull none will set twoSided
- if ( !Q_stricmp( token, "cull" ) ) {
- GetToken( qfalse );
- if ( !Q_stricmp( token, "none" ) ) {
- si->twoSided = qtrue;
- }
- continue;
- }
-
-
- // deformVertexes autosprite[2]
- // we catch this so autosprited surfaces become point
- // lights instead of area lights
- if ( !Q_stricmp( token, "deformVertexes" ) ) {
- GetToken( qfalse );
- if ( !Q_strncasecmp( token, "autosprite", 10 ) ) {
- si->autosprite = qtrue;
- si->contents = CONTENTS_DETAIL;
- }
- continue;
- }
-
-
- // ignore all other tokens on the line
-
- while ( TokenAvailable() ) {
- GetToken( qfalse );
- }
- }
- }
-}
-
-/*
-===============
-LoadShaderInfo
-===============
-*/
-#define MAX_SHADER_FILES 64
-void LoadShaderInfo( void ) {
- char filename[1024];
- int i;
- char *shaderFiles[MAX_SHADER_FILES];
- int numShaderFiles;
-
- sprintf( filename, "%sscripts/shaderlist.txt", gamedir );
- LoadScriptFile( filename );
-
- numShaderFiles = 0;
- while ( 1 ) {
- if ( !GetToken( qtrue ) ) {
- break;
- }
- shaderFiles[numShaderFiles] = malloc(MAX_OS_PATH);
- strcpy( shaderFiles[ numShaderFiles ], token );
- numShaderFiles++;
- }
-
- for ( i = 0 ; i < numShaderFiles ; i++ ) {
- sprintf( filename, "%sscripts/%s.shader", gamedir, shaderFiles[i] );
- ParseShaderFile( filename );
- free(shaderFiles[i]);
- }
-
- qprintf( "%5i shaderInfo\n", numShaderInfo);
-}
-
+
+#include <string.h>
+#include <math.h>
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "imagelib.h"
+#include "scriplib.h"
+
+#ifdef _TTIMOBUILD
+#include "../common/qfiles.h"
+#include "../common/surfaceflags.h"
+#else
+#include "../code/qcommon/qfiles.h"
+#include "../code/game/surfaceflags.h"
+#endif
+
+#include "shaders.h"
+#ifdef _WIN32
+
+#ifdef _TTIMOBUILD
+#include "pakstuff.h"
+#include "jpeglib.h"
+#else
+#include "../libs/pakstuff.h"
+#include "../libs/jpeglib.h"
+#endif
+
+#endif
+
+
+// 5% backsplash by default
+#define DEFAULT_BACKSPLASH_FRACTION 0.05
+#define DEFAULT_BACKSPLASH_DISTANCE 24
+
+
+#define MAX_SURFACE_INFO 4096
+
+shaderInfo_t defaultInfo;
+shaderInfo_t shaderInfo[MAX_SURFACE_INFO];
+int numShaderInfo;
+
+
+typedef struct {
+ char *name;
+ int clearSolid, surfaceFlags, contents;
+} infoParm_t;
+
+infoParm_t infoParms[] = {
+ // server relevant contents
+ {"water", 1, 0, CONTENTS_WATER },
+ {"slime", 1, 0, CONTENTS_SLIME }, // mildly damaging
+ {"lava", 1, 0, CONTENTS_LAVA }, // very damaging
+ {"playerclip", 1, 0, CONTENTS_PLAYERCLIP },
+ {"monsterclip", 1, 0, CONTENTS_MONSTERCLIP },
+ {"nodrop", 1, 0, CONTENTS_NODROP }, // don't drop items or leave bodies (death fog, lava, etc)
+ {"nonsolid", 1, SURF_NONSOLID, 0}, // clears the solid flag
+
+ // utility relevant attributes
+ {"origin", 1, 0, CONTENTS_ORIGIN }, // center of rotating brushes
+ {"trans", 0, 0, CONTENTS_TRANSLUCENT }, // don't eat contained surfaces
+ {"detail", 0, 0, CONTENTS_DETAIL }, // don't include in structural bsp
+ {"structural", 0, 0, CONTENTS_STRUCTURAL }, // force into structural bsp even if trnas
+ {"areaportal", 1, 0, CONTENTS_AREAPORTAL }, // divides areas
+ {"clusterportal",1, 0, CONTENTS_CLUSTERPORTAL },// for bots
+ {"donotenter", 1, 0, CONTENTS_DONOTENTER }, // for bots
+ {"botclip", 1, 0, CONTENTS_BOTCLIP }, // for bots
+ {"nobotclip", 0, 0, CONTENTS_NOBOTCLIP }, // don't use for bot clipping
+
+ {"fog", 1, 0, CONTENTS_FOG}, // carves surfaces entering
+ {"sky", 0, SURF_SKY, 0 }, // emit light from an environment map
+ {"lightfilter", 0, SURF_LIGHTFILTER, 0 }, // filter light going through it
+ {"alphashadow", 0, SURF_ALPHASHADOW, 0 }, // test light on a per-pixel basis
+ {"hint", 0, SURF_HINT, 0 }, // use as a primary splitter
+
+ // server attributes
+ {"slick", 0, SURF_SLICK, 0 },
+ {"noimpact", 0, SURF_NOIMPACT, 0 }, // don't make impact explosions or marks
+ {"nomarks", 0, SURF_NOMARKS, 0 }, // don't make impact marks, but still explode
+ {"ladder", 0, SURF_LADDER, 0 },
+ {"nodamage", 0, SURF_NODAMAGE, 0 },
+ {"metalsteps", 0, SURF_METALSTEPS,0 },
+ {"flesh", 0, SURF_FLESH, 0 },
+ {"nosteps", 0, SURF_NOSTEPS, 0 },
+
+ // drawsurf attributes
+ {"nodraw", 0, SURF_NODRAW, 0 }, // don't generate a drawsurface (or a lightmap)
+ {"pointlight", 0, SURF_POINTLIGHT, 0 }, // sample lighting at vertexes
+ {"nolightmap", 0, SURF_NOLIGHTMAP,0 }, // don't generate a lightmap
+ {"nodlight", 0, SURF_NODLIGHT, 0 }, // don't ever add dynamic lights
+ {"dust", 0, SURF_DUST, 0} // leave dust trail when walking on this surface
+};
+
+
+/*
+===============
+LoadShaderImage
+===============
+*/
+
+byte* LoadImageFile(char *filename, qboolean *bTGA)
+{
+ byte *buffer = NULL;
+ int nLen = 0;
+ *bTGA = qtrue;
+ if (FileExists(filename))
+ {
+ LoadFileBlock(filename, &buffer);
+ }
+#ifdef _WIN32
+ else
+ {
+ PakLoadAnyFile(filename, &buffer);
+ }
+#endif
+ if ( buffer == NULL)
+ {
+ nLen = strlen(filename);
+ filename[nLen-3] = 'j';
+ filename[nLen-2] = 'p';
+ filename[nLen-1] = 'g';
+ if (FileExists(filename))
+ {
+ LoadFileBlock(filename, &buffer);
+ }
+#ifdef _WIN32
+ else
+ {
+ PakLoadAnyFile(filename, &buffer);
+ }
+#endif
+ if ( buffer )
+ {
+ *bTGA = qfalse;
+ }
+ }
+ return buffer;
+}
+
+/*
+===============
+LoadShaderImage
+===============
+*/
+static void LoadShaderImage( shaderInfo_t *si ) {
+ char filename[1024];
+ int i, count;
+ float color[4];
+ byte *buffer;
+ qboolean bTGA = qtrue;
+
+ // look for the lightimage if it is specified
+ if ( si->lightimage[0] ) {
+ sprintf( filename, "%s%s", gamedir, si->lightimage );
+ DefaultExtension( filename, ".tga" );
+ buffer = LoadImageFile(filename, &bTGA);
+ if ( buffer != NULL) {
+ goto loadTga;
+ }
+ }
+
+ // look for the editorimage if it is specified
+ if ( si->editorimage[0] ) {
+ sprintf( filename, "%s%s", gamedir, si->editorimage );
+ DefaultExtension( filename, ".tga" );
+ buffer = LoadImageFile(filename, &bTGA);
+ if ( buffer != NULL) {
+ goto loadTga;
+ }
+ }
+
+ // just try the shader name with a .tga
+ // on unix, we have case sensitivity problems...
+ sprintf( filename, "%s%s.tga", gamedir, si->shader );
+ buffer = LoadImageFile(filename, &bTGA);
+ if ( buffer != NULL) {
+ goto loadTga;
+ }
+
+ sprintf( filename, "%s%s.TGA", gamedir, si->shader );
+ buffer = LoadImageFile(filename, &bTGA);
+ if ( buffer != NULL) {
+ goto loadTga;
+ }
+
+ // couldn't load anything
+ _printf("WARNING: Couldn't find image for shader %s\n", si->shader );
+
+ si->color[0] = 1;
+ si->color[1] = 1;
+ si->color[2] = 1;
+ si->width = 64;
+ si->height = 64;
+ si->pixels = malloc( si->width * si->height * 4 );
+ memset ( si->pixels, 255, si->width * si->height * 4 );
+ return;
+
+ // load the image to get dimensions and color
+loadTga:
+ if ( bTGA) {
+ LoadTGABuffer( buffer, &si->pixels, &si->width, &si->height );
+ }
+ else {
+#ifdef _WIN32
+ LoadJPGBuff(buffer, &si->pixels, &si->width, &si->height );
+#endif
+ }
+
+ free(buffer);
+
+ count = si->width * si->height;
+
+ VectorClear( color );
+ color[ 3 ] = 0;
+ for ( i = 0 ; i < count ; i++ ) {
+ color[0] += si->pixels[ i * 4 + 0 ];
+ color[1] += si->pixels[ i * 4 + 1 ];
+ color[2] += si->pixels[ i * 4 + 2 ];
+ color[3] += si->pixels[ i * 4 + 3 ];
+ }
+ ColorNormalize( color, si->color );
+ VectorScale( color, 1.0/count, si->averageColor );
+}
+
+/*
+===============
+AllocShaderInfo
+===============
+*/
+static shaderInfo_t *AllocShaderInfo( void ) {
+ shaderInfo_t *si;
+
+ if ( numShaderInfo == MAX_SURFACE_INFO ) {
+ Error( "MAX_SURFACE_INFO" );
+ }
+ si = &shaderInfo[ numShaderInfo ];
+ numShaderInfo++;
+
+ // set defaults
+
+ si->contents = CONTENTS_SOLID;
+
+ si->backsplashFraction = DEFAULT_BACKSPLASH_FRACTION;
+ si->backsplashDistance = DEFAULT_BACKSPLASH_DISTANCE;
+
+ si->lightmapSampleSize = 0;
+ si->forceTraceLight = qfalse;
+ si->forceVLight = qfalse;
+ si->patchShadows = qfalse;
+ si->vertexShadows = qfalse;
+ si->noVertexShadows = qfalse;
+ si->forceSunLight = qfalse;
+ si->vertexScale = 1.0;
+ si->notjunc = qfalse;
+
+ return si;
+}
+
+/*
+===============
+ShaderInfoForShader
+===============
+*/
+shaderInfo_t *ShaderInfoForShader( const char *shaderName ) {
+ int i;
+ shaderInfo_t *si;
+ char shader[MAX_QPATH];
+
+ // strip off extension
+ strcpy( shader, shaderName );
+ StripExtension( shader );
+
+ // search for it
+ for ( i = 0 ; i < numShaderInfo ; i++ ) {
+ si = &shaderInfo[ i ];
+ if ( !Q_stricmp( shader, si->shader ) ) {
+ if ( !si->width ) {
+ LoadShaderImage( si );
+ }
+ return si;
+ }
+ }
+
+ si = AllocShaderInfo();
+ strcpy( si->shader, shader );
+
+ LoadShaderImage( si );
+
+ return si;
+}
+
+/*
+===============
+ParseShaderFile
+===============
+*/
+static void ParseShaderFile( const char *filename ) {
+ int i;
+ int numInfoParms = sizeof(infoParms) / sizeof(infoParms[0]);
+ shaderInfo_t *si;
+
+// qprintf( "shaderFile: %s\n", filename );
+ LoadScriptFile( filename );
+ while ( 1 ) {
+ if ( !GetToken( qtrue ) ) {
+ break;
+ }
+
+ si = AllocShaderInfo();
+ strcpy( si->shader, token );
+ MatchToken( "{" );
+ while ( 1 ) {
+ if ( !GetToken( qtrue ) ) {
+ break;
+ }
+ if ( !strcmp( token, "}" ) ) {
+ break;
+ }
+
+ // skip internal braced sections
+ if ( !strcmp( token, "{" ) ) {
+ si->hasPasses = qtrue;
+ while ( 1 ) {
+ if ( !GetToken( qtrue ) ) {
+ break;
+ }
+ if ( !strcmp( token, "}" ) ) {
+ break;
+ }
+ }
+ continue;
+ }
+
+ if ( !Q_stricmp( token, "surfaceparm" ) ) {
+ GetToken( qfalse );
+ for ( i = 0 ; i < numInfoParms ; i++ ) {
+ if ( !Q_stricmp( token, infoParms[i].name ) ) {
+ si->surfaceFlags |= infoParms[i].surfaceFlags;
+ si->contents |= infoParms[i].contents;
+ if ( infoParms[i].clearSolid ) {
+ si->contents &= ~CONTENTS_SOLID;
+ }
+ break;
+ }
+ }
+ if ( i == numInfoParms ) {
+ // we will silently ignore all tokens beginning with qer,
+ // which are QuakeEdRadient parameters
+ if ( Q_strncasecmp( token, "qer", 3 ) ) {
+ _printf( "Unknown surfaceparm: \"%s\"\n", token );
+ }
+ }
+ continue;
+ }
+
+
+ // qer_editorimage <image>
+ if ( !Q_stricmp( token, "qer_editorimage" ) ) {
+ GetToken( qfalse );
+ strcpy( si->editorimage, token );
+ DefaultExtension( si->editorimage, ".tga" );
+ continue;
+ }
+
+ // q3map_lightimage <image>
+ if ( !Q_stricmp( token, "q3map_lightimage" ) ) {
+ GetToken( qfalse );
+ strcpy( si->lightimage, token );
+ DefaultExtension( si->lightimage, ".tga" );
+ continue;
+ }
+
+ // q3map_surfacelight <value>
+ if ( !Q_stricmp( token, "q3map_surfacelight" ) ) {
+ GetToken( qfalse );
+ si->value = atoi( token );
+ continue;
+ }
+
+ // q3map_lightsubdivide <value>
+ if ( !Q_stricmp( token, "q3map_lightsubdivide" ) ) {
+ GetToken( qfalse );
+ si->lightSubdivide = atoi( token );
+ continue;
+ }
+
+ // q3map_lightmapsamplesize <value>
+ if ( !Q_stricmp( token, "q3map_lightmapsamplesize" ) ) {
+ GetToken( qfalse );
+ si->lightmapSampleSize = atoi( token );
+ continue;
+ }
+
+ // q3map_tracelight
+ if ( !Q_stricmp( token, "q3map_tracelight" ) ) {
+ si->forceTraceLight = qtrue;
+ continue;
+ }
+
+ // q3map_vlight
+ if ( !Q_stricmp( token, "q3map_vlight" ) ) {
+ si->forceVLight = qtrue;
+ continue;
+ }
+
+ // q3map_patchshadows
+ if ( !Q_stricmp( token, "q3map_patchshadows" ) ) {
+ si->patchShadows = qtrue;
+ continue;
+ }
+
+ // q3map_vertexshadows
+ if ( !Q_stricmp( token, "q3map_vertexshadows" ) ) {
+ si->vertexShadows = qtrue;
+ continue;
+ }
+
+ // q3map_novertexshadows
+ if ( !Q_stricmp( token, "q3map_novertexshadows" ) ) {
+ si->noVertexShadows = qtrue;
+ continue;
+ }
+
+ // q3map_forcesunlight
+ if ( !Q_stricmp( token, "q3map_forcesunlight" ) ) {
+ si->forceSunLight = qtrue;
+ continue;
+ }
+
+ // q3map_vertexscale
+ if ( !Q_stricmp( token, "q3map_vertexscale" ) ) {
+ GetToken( qfalse );
+ si->vertexScale = atof(token);
+ continue;
+ }
+
+ // q3map_notjunc
+ if ( !Q_stricmp( token, "q3map_notjunc" ) ) {
+ si->notjunc = qtrue;
+ continue;
+ }
+
+ // q3map_globaltexture
+ if ( !Q_stricmp( token, "q3map_globaltexture" ) ) {
+ si->globalTexture = qtrue;
+ continue;
+ }
+
+ // q3map_backsplash <percent> <distance>
+ if ( !Q_stricmp( token, "q3map_backsplash" ) ) {
+ GetToken( qfalse );
+ si->backsplashFraction = atof( token ) * 0.01;
+ GetToken( qfalse );
+ si->backsplashDistance = atof( token );
+ continue;
+ }
+
+ // q3map_backshader <shader>
+ if ( !Q_stricmp( token, "q3map_backshader" ) ) {
+ GetToken( qfalse );
+ strcpy( si->backShader, token );
+ continue;
+ }
+
+ // q3map_flare <shader>
+ if ( !Q_stricmp( token, "q3map_flare" ) ) {
+ GetToken( qfalse );
+ strcpy( si->flareShader, token );
+ continue;
+ }
+
+ // light <value>
+ // old style flare specification
+ if ( !Q_stricmp( token, "light" ) ) {
+ GetToken( qfalse );
+ strcpy( si->flareShader, "flareshader" );
+ continue;
+ }
+
+ // q3map_sun <red> <green> <blue> <intensity> <degrees> <elivation>
+ // color will be normalized, so it doesn't matter what range you use
+ // intensity falls off with angle but not distance 100 is a fairly bright sun
+ // degree of 0 = from the east, 90 = north, etc. altitude of 0 = sunrise/set, 90 = noon
+ if ( !Q_stricmp( token, "q3map_sun" ) ) {
+ float a, b;
+
+ GetToken( qfalse );
+ si->sunLight[0] = atof( token );
+ GetToken( qfalse );
+ si->sunLight[1] = atof( token );
+ GetToken( qfalse );
+ si->sunLight[2] = atof( token );
+
+ VectorNormalize( si->sunLight, si->sunLight);
+
+ GetToken( qfalse );
+ a = atof( token );
+ VectorScale( si->sunLight, a, si->sunLight);
+
+ GetToken( qfalse );
+ a = atof( token );
+ a = a / 180 * Q_PI;
+
+ GetToken( qfalse );
+ b = atof( token );
+ b = b / 180 * Q_PI;
+
+ si->sunDirection[0] = cos( a ) * cos( b );
+ si->sunDirection[1] = sin( a ) * cos( b );
+ si->sunDirection[2] = sin( b );
+
+ si->surfaceFlags |= SURF_SKY;
+ continue;
+ }
+
+ // tesssize is used to force liquid surfaces to subdivide
+ if ( !Q_stricmp( token, "tesssize" ) ) {
+ GetToken( qfalse );
+ si->subdivisions = atof( token );
+ continue;
+ }
+
+ // cull none will set twoSided
+ if ( !Q_stricmp( token, "cull" ) ) {
+ GetToken( qfalse );
+ if ( !Q_stricmp( token, "none" ) ) {
+ si->twoSided = qtrue;
+ }
+ continue;
+ }
+
+
+ // deformVertexes autosprite[2]
+ // we catch this so autosprited surfaces become point
+ // lights instead of area lights
+ if ( !Q_stricmp( token, "deformVertexes" ) ) {
+ GetToken( qfalse );
+ if ( !Q_strncasecmp( token, "autosprite", 10 ) ) {
+ si->autosprite = qtrue;
+ si->contents = CONTENTS_DETAIL;
+ }
+ continue;
+ }
+
+
+ // ignore all other tokens on the line
+
+ while ( TokenAvailable() ) {
+ GetToken( qfalse );
+ }
+ }
+ }
+}
+
+/*
+===============
+LoadShaderInfo
+===============
+*/
+#define MAX_SHADER_FILES 64
+void LoadShaderInfo( void ) {
+ char filename[1024];
+ int i;
+ char *shaderFiles[MAX_SHADER_FILES];
+ int numShaderFiles;
+
+ sprintf( filename, "%sscripts/shaderlist.txt", gamedir );
+ LoadScriptFile( filename );
+
+ numShaderFiles = 0;
+ while ( 1 ) {
+ if ( !GetToken( qtrue ) ) {
+ break;
+ }
+ shaderFiles[numShaderFiles] = malloc(MAX_OS_PATH);
+ strcpy( shaderFiles[ numShaderFiles ], token );
+ numShaderFiles++;
+ }
+
+ for ( i = 0 ; i < numShaderFiles ; i++ ) {
+ sprintf( filename, "%sscripts/%s.shader", gamedir, shaderFiles[i] );
+ ParseShaderFile( filename );
+ free(shaderFiles[i]);
+ }
+
+ qprintf( "%5i shaderInfo\n", numShaderInfo);
+}
+
diff --git a/q3map/shaders.h b/q3map/shaders.h
index fc187c6..27918bb 100755
--- a/q3map/shaders.h
+++ b/q3map/shaders.h
@@ -19,53 +19,53 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-
-typedef struct shaderInfo_s {
- char shader[MAX_QPATH];
- int surfaceFlags;
- int contents;
- int value;
-
- char backShader[MAX_QPATH]; // for surfaces that generate different front and back passes
- char flareShader[MAX_QPATH]; // for light flares
-
- float subdivisions; // from a "tesssize xxx"
- float backsplashFraction; // floating point value, usually 0.05
- float backsplashDistance; // default 16
- float lightSubdivide; // default 120
- int lightmapSampleSize; // lightmap sample size
-
- qboolean hasPasses; // false if the shader doesn't define any rendering passes
-
- qboolean globalTexture; // don't normalize texture repeats
-
- qboolean twoSided; // cull none
- qboolean autosprite; // autosprite shaders will become point lights
- // instead of area lights
- qboolean lightFilter; // light rays that cross surfaces of this type
- // should test against the filter image
- qboolean forceTraceLight; // always use -light for this surface
- qboolean forceVLight; // always use -vlight for this surface
- qboolean patchShadows; // have patches casting shadows when using -light for this surface
- qboolean vertexShadows; // shadows will be casted at this surface even when vertex lit
- qboolean noVertexShadows; // no shadows will be casted at this surface in vertex lighting
- qboolean forceSunLight; // force sun light at this surface even tho we might not calculate shadows in vertex lighting
- qboolean notjunc; // don't use this surface for tjunction fixing
- float vertexScale; // vertex light scale
-
- char editorimage[MAX_QPATH]; // use this image to generate texture coordinates
- char lightimage[MAX_QPATH]; // use this image to generate color / averageColor
- vec3_t color; // colorNormalized
- vec3_t averageColor;
-
- int width, height;
- byte *pixels;
-
- vec3_t sunLight;
- vec3_t sunDirection;
-} shaderInfo_t;
-
-void LoadShaderInfo( void );
-shaderInfo_t *ShaderInfoForShader( const char *shader );
-
+
+
+typedef struct shaderInfo_s {
+ char shader[MAX_QPATH];
+ int surfaceFlags;
+ int contents;
+ int value;
+
+ char backShader[MAX_QPATH]; // for surfaces that generate different front and back passes
+ char flareShader[MAX_QPATH]; // for light flares
+
+ float subdivisions; // from a "tesssize xxx"
+ float backsplashFraction; // floating point value, usually 0.05
+ float backsplashDistance; // default 16
+ float lightSubdivide; // default 120
+ int lightmapSampleSize; // lightmap sample size
+
+ qboolean hasPasses; // false if the shader doesn't define any rendering passes
+
+ qboolean globalTexture; // don't normalize texture repeats
+
+ qboolean twoSided; // cull none
+ qboolean autosprite; // autosprite shaders will become point lights
+ // instead of area lights
+ qboolean lightFilter; // light rays that cross surfaces of this type
+ // should test against the filter image
+ qboolean forceTraceLight; // always use -light for this surface
+ qboolean forceVLight; // always use -vlight for this surface
+ qboolean patchShadows; // have patches casting shadows when using -light for this surface
+ qboolean vertexShadows; // shadows will be casted at this surface even when vertex lit
+ qboolean noVertexShadows; // no shadows will be casted at this surface in vertex lighting
+ qboolean forceSunLight; // force sun light at this surface even tho we might not calculate shadows in vertex lighting
+ qboolean notjunc; // don't use this surface for tjunction fixing
+ float vertexScale; // vertex light scale
+
+ char editorimage[MAX_QPATH]; // use this image to generate texture coordinates
+ char lightimage[MAX_QPATH]; // use this image to generate color / averageColor
+ vec3_t color; // colorNormalized
+ vec3_t averageColor;
+
+ int width, height;
+ byte *pixels;
+
+ vec3_t sunLight;
+ vec3_t sunDirection;
+} shaderInfo_t;
+
+void LoadShaderInfo( void );
+shaderInfo_t *ShaderInfoForShader( const char *shader );
+
diff --git a/q3map/soundv.c b/q3map/soundv.c
index 1883c52..e7a57b6 100755
--- a/q3map/soundv.c
+++ b/q3map/soundv.c
@@ -19,5724 +19,5724 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-/*****************************************************************************
- * name: soundv.c
- *****************************************************************************/
-
-#include "cmdlib.h"
-#include "mathlib.h"
-#include "bspfile.h"
-#include "imagelib.h"
-#include "threads.h"
-#include "mutex.h"
-#include "scriplib.h"
-
-#include "shaders.h"
-#include "mesh.h"
-
-#ifdef _WIN32
-//Improve floating-point consistency.
-#pragma optimize( "p", on )
-#endif
-
-#ifdef _WIN32
-#include "../libs/pakstuff.h"
-#endif
-
-#define MAX_CLUSTERS 16384
-#define MAX_PORTALS 32768
-#define MAX_FACETS 65536
-#define MAX_LIGHTS 16384
-
-#define LIGHTMAP_SIZE 128
-
-#define LIGHTMAP_PIXELSHIFT 0.5
-
-//#define LIGHTMAP_PATCHSHIFT
-
-#define PORTALFILE "PRT1"
-
-#define ON_EPSILON 0.1
-
-#define VectorSet(v, x, y, z) v[0] = x;v[1] = y;v[2] = z;
-
-typedef struct
-{
- vec3_t normal;
- float dist;
-} plane_t;
-
-#define MAX_POINTS_ON_WINDING 64
-//NOTE: whenever this is overflowed parts of lightmaps might end up not being lit
-#define MAX_POINTS_ON_FIXED_WINDING 48
-
-typedef struct
-{
- int numpoints;
- vec3_t points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized
-} winding_t;
-
-typedef struct
-{
- plane_t plane; // normal pointing into neighbor
- int leaf; // neighbor
- winding_t *winding;
- vec3_t origin; // for fast clip testing
- float radius;
-} lportal_t;
-
-#define MAX_PORTALS_ON_LEAF 128
-typedef struct lleaf_s
-{
- int numportals;
- lportal_t *portals[MAX_PORTALS_ON_LEAF];
- //
- int numSurfaces;
- int firstSurface;
-} lleaf_t;
-
-typedef struct lFacet_s
-{
- int num;
- plane_t plane;
- vec3_t points[4]; //
- int numpoints;
- float lightmapCoords[4][2];
- plane_t boundaries[4]; // negative is outside the bounds
- float textureMatrix[2][4]; // texture coordinates for translucency
- float lightmapMatrix[2][4]; // lightmap texture coordinates
- vec3_t mins;
- int x, y, width, height;
-} lFacet_t;
-
-typedef struct lsurfaceTest_s
-{
- vec3_t mins, maxs;
- vec3_t origin;
- float radius;
- qboolean patch; // true if this is a patch
- qboolean trisoup; // true if this is a triangle soup
- int numFacets;
- lFacet_t *facets;
- mesh_t *detailMesh; // detailed mesh with points for each lmp
- shaderInfo_t *shader; // for translucency
- mutex_t *mutex;
- int numvolumes; // number of volumes casted at this surface
- //
- int always_tracelight;
- int always_vsound;
-} lsurfaceTest_t;
-
-//volume types
-#define VOLUME_NORMAL 0
-#define VOLUME_DIRECTED 1
-
-#define MAX_TRANSLUCENTFACETS 32
-
-typedef struct lightvolume_s
-{
- int num;
- int cluster; //cluster this light volume started in
- plane_t endplane; //end plane
- plane_t farplane; //original end plane
- vec3_t points[MAX_POINTS_ON_WINDING]; //end winding points
- plane_t planes[MAX_POINTS_ON_WINDING]; //volume bounding planes
- int numplanes; //number of volume bounding planes
- int type; //light volume type
- //list with translucent surfaces the volume went through
- int transFacets[MAX_TRANSLUCENTFACETS];
- int transSurfaces[MAX_TRANSLUCENTFACETS];
- int numtransFacets;
- //clusters already tested
- byte clusterTested[MAX_CLUSTERS/8];
- //facets already tested
- byte facetTested[MAX_FACETS/8];
- int facetNum; //number of the facet blocking the light in this volume
- int surfaceNum; //number of the surface blocking the light in this volume
-} lightvolume_t;
-
-//light types
-#define LIGHT_POINTRADIAL 1
-#define LIGHT_POINTSPOT 2
-#define LIGHT_POINTFAKESURFACE 3
-#define LIGHT_SURFACEDIRECTED 4
-#define LIGHT_SURFACERADIAL 5
-#define LIGHT_SURFACESPOT 6
-
-//light distance attenuation types
-#define LDAT_QUADRATIC 0
-#define LDAT_LINEAR 1
-#define LDAT_NOSCALE 2
-
-//light angle attenuation types
-#define LAAT_NORMAL 0
-#define LAAT_QUADRATIC 1
-#define LAAT_DOUBLEQUADRATIC 2
-
-typedef struct vsound_s
-{
- vec3_t origin; //light origin, for point lights
- winding_t w; //light winding, for area lights
- vec4_t plane; //light winding plane
- vec3_t normal; //direction of the light
- int type; //light type
- vec3_t color; //light color
- qboolean twosided; //radiates light at both sides of the winding
- int style; //light style (not used)
- int atten_disttype; //light distance attenuation type
- int atten_angletype; //light angle attenuation type
- float atten_distscale; //distance attenuation scale
- float atten_anglescale; //angle attenuation scale
- float radiusByDist; //radius by distance for spot lights
- float photons; //emitted photons
- float intensity; //intensity
- vec3_t emitColor; //full out-of-gamut value (not used)
- struct shaderInfo_s *si; //shader info
- int insolid; //set when light is in solid
-} vsound_t;
-
-static float lightLinearScale = 1.0 / 8000;
-static float lightPointScale = 7500;
-static float lightAreaScale = 0.25;
-static float lightFormFactorValueScale = 3;
-static int lightDefaultSubdivide = 999; // vary by surface size?
-static vec3_t lightAmbientColor;
-
-static int portalclusters, numportals, numfaces;
-static lleaf_t *leafs;
-static lportal_t *portals;
-static int numvsounds = 0;
-static vsound_t *vsounds[MAX_LIGHTS];
-static int nostitching = 0;
-static int noalphashading = 0;
-static int nocolorshading = 0;
-static int nobackfaceculling = 0;
-static int defaulttracelight = 0;
-static int radiosity = 0;
-static int radiosity_scale;
-
-static int clustersurfaces[MAX_MAP_LEAFFACES];
-static int numclustersurfaces = 0;
-static lsurfaceTest_t *lsurfaceTest[MAX_MAP_DRAW_SURFS];
-static int numfacets;
-static float lightmappixelarea[MAX_MAP_LIGHTING/3];
-static float *lightFloats;//[MAX_MAP_LIGHTING];
-
-// from polylib.c
-winding_t *AllocWinding (int points);
-void FreeWinding (winding_t *w);
-void WindingCenter (winding_t *w, vec3_t center);
-void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs);
-vec_t WindingArea (winding_t *w);
-winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist);
-void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
- vec_t epsilon, winding_t **front, winding_t **back);
-winding_t *ReverseWinding (winding_t *w);
-
-// from light.c
-extern char source[1024];
-extern vec3_t surfaceOrigin[ MAX_MAP_DRAW_SURFS ];
-extern int entitySurface[ MAX_MAP_DRAW_SURFS ];
-extern int samplesize;
-extern qboolean patchshadows;
-extern vec3_t gridSize;
-
-float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w );
-void ColorToBytes( const float *color, byte *colorBytes );
-void CountLightmaps( void );
-void GridAndVertexLighting( void );
-void SetEntityOrigins( void );
-
-
-//#define DEBUGNET
-
-#ifdef DEBUGNET
-
-#include "l_net.h"
-
-socket_t *debug_socket;
-
-/*
-=====================
-DebugNet_Setup
-=====================
-*/
-void DebugNet_Setup(void)
-{
- address_t address;
- int i;
-
- Net_Setup();
- Net_StringToAddress("127.0.0.1:28000", &address);
- for (i = 0; i < 10; i++)
- {
- debug_socket = Net_Connect(&address, 28005 + i);
- if (debug_socket)
- break;
- }
-}
-
-/*
-=====================
-DebugNet_Shutdown
-=====================
-*/
-void DebugNet_Shutdown(void)
-{
- netmessage_t msg;
-
- if (debug_socket)
- {
- NMSG_Clear(&msg);
- NMSG_WriteByte(&msg, 1);
- Net_Send(debug_socket, &msg);
- Net_Disconnect(debug_socket);
- }
- debug_socket = NULL;
- Net_Shutdown();
-}
-
-/*
-=====================
-DebugNet_RemoveAllPolys
-=====================
-*/
-void DebugNet_RemoveAllPolys(void)
-{
- netmessage_t msg;
-
- if (!debug_socket)
- return;
- NMSG_Clear(&msg);
- NMSG_WriteByte(&msg, 2); //remove all debug polys
- Net_Send(debug_socket, &msg);
-}
-
-/*
-====================
-DebugNet_DrawWinding
-=====================
-*/
-void DebugNet_DrawWinding(winding_t *w, int color)
-{
- netmessage_t msg;
- int i;
-
- if (!debug_socket)
- return;
- NMSG_Clear(&msg);
- NMSG_WriteByte(&msg, 0); //draw a winding
- NMSG_WriteByte(&msg, w->numpoints); //number of points
- NMSG_WriteLong(&msg, color); //color
- for (i = 0; i < w->numpoints; i++)
- {
- NMSG_WriteFloat(&msg, w->points[i][0]);
- NMSG_WriteFloat(&msg, w->points[i][1]);
- NMSG_WriteFloat(&msg, w->points[i][2]);
- }
- Net_Send(debug_socket, &msg);
-}
-
-/*
-=====================
-DebugNet_DrawLine
-=====================
-*/
-void DebugNet_DrawLine(vec3_t p1, vec3_t p2, int color)
-{
- netmessage_t msg;
-
- if (!debug_socket)
- return;
- NMSG_Clear(&msg);
- NMSG_WriteByte(&msg, 1); //draw a line
- NMSG_WriteLong(&msg, color); //color
- NMSG_WriteFloat(&msg, p1[0]);
- NMSG_WriteFloat(&msg, p1[1]);
- NMSG_WriteFloat(&msg, p1[2]);
- NMSG_WriteFloat(&msg, p2[0]);
- NMSG_WriteFloat(&msg, p2[1]);
- NMSG_WriteFloat(&msg, p2[2]);
- Net_Send(debug_socket, &msg);
-}
-
-/*
-=====================
-DebugNet_DrawMesh
-=====================
-*/
-void DebugNet_DrawMesh(mesh_t *mesh)
-{
- int i, j;
- float dot;
- drawVert_t *v1, *v2, *v3, *v4;
- winding_t winding;
- plane_t plane;
- vec3_t d1, d2;
-
- for ( i = 0 ; i < mesh->width - 1 ; i++ ) {
- for ( j = 0 ; j < mesh->height - 1 ; j++ ) {
-
- v1 = mesh->verts + j * mesh->width + i;
- v2 = v1 + 1;
- v3 = v1 + mesh->width + 1;
- v4 = v1 + mesh->width;
-
- VectorSubtract( v4->xyz, v1->xyz, d1 );
- VectorSubtract( v3->xyz, v1->xyz, d2 );
- CrossProduct( d2, d1, plane.normal );
- if ( VectorNormalize( plane.normal, plane.normal ) != 0 )
- {
- plane.dist = DotProduct( v1->xyz, plane.normal );
- dot = DotProduct(plane.normal, v2->xyz) - plane.dist;
- if (fabs(dot) < 0.1)
- {
- VectorCopy(v1->xyz, winding.points[0]);
- VectorCopy(v4->xyz, winding.points[1]);
- VectorCopy(v3->xyz, winding.points[2]);
- VectorCopy(v2->xyz, winding.points[3]);
- winding.numpoints = 4;
- DebugNet_DrawWinding(&winding, 2);
- continue;
- }
- }
-
- winding.numpoints = 3;
- VectorCopy(v1->xyz, winding.points[0]);
- VectorCopy(v4->xyz, winding.points[1]);
- VectorCopy(v3->xyz, winding.points[2]);
- DebugNet_DrawWinding(&winding, 2);
-
- VectorCopy(v1->xyz, winding.points[0]);
- VectorCopy(v3->xyz, winding.points[1]);
- VectorCopy(v2->xyz, winding.points[2]);
- DebugNet_DrawWinding(&winding, 2);
- }
- }
-}
-
-/*
-=====================
-VS_DrawLightVolume
-=====================
-*/
-int VS_ChopWinding (winding_t *in, plane_t *split, float epsilon);
-
-void VS_DrawLightVolume(vsound_t *light, lightvolume_t *volume)
-{
- winding_t w;
- int i;
- vec3_t p2, invsound;
-
- memcpy(w.points, volume->points, volume->numplanes * sizeof(vec3_t));
- w.numpoints = volume->numplanes;
- DebugNet_DrawWinding(&w, 2);
-
- if (volume->type == VOLUME_DIRECTED)
- {
- VectorCopy(light->normal, invsound);
- VectorInverse(invsound);
- for (i = 0; i < volume->numplanes; i++)
- {
- VectorCopy(volume->points[i], w.points[0]);
- VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[1]);
- VectorMA(w.points[1], MAX_WORLD_COORD, invsound, w.points[2]);
- VectorMA(w.points[0], MAX_WORLD_COORD, invsound, w.points[3]);
- w.numpoints = 4;
- DebugNet_DrawWinding(&w, 2);
- VectorMA(volume->points[i], 8, volume->planes[i].normal, p2);
- DebugNet_DrawLine(volume->points[i], p2, 3);
- }
- }
- else
- {
- //
- VectorCopy(light->origin, w.points[0]);
- w.numpoints = 3;
- for (i = 0; i < volume->numplanes; i++)
- {
- VectorCopy(volume->points[i], w.points[1]);
- VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[2]);
- VS_ChopWinding(&w, &volume->endplane, 0);
- DebugNet_DrawWinding(&w, 2);
- VectorMA(volume->points[i], 8, volume->planes[i].normal, p2);
- DebugNet_DrawLine(volume->points[i], p2, 3);
- }
- }
-}
-
-/*
-=============
-VS_DrawLightmapPixel
-=============
-*/
-void VS_DrawLightmapPixel(int surfaceNum, int x, int y, int color)
-{
- winding_t w;
- dsurface_t *ds;
- mesh_t *mesh;
-
- ds = &drawSurfaces[surfaceNum];
-
- if (ds->surfaceType == MST_PATCH)
- {
- mesh = lsurfaceTest[surfaceNum]->detailMesh;
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]);
- VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]);
- VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]);
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]);
- w.numpoints = 4;
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]);
- VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]);
- VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]);
- VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]);
- VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]);
- w.numpoints = 4;
- }
- DebugNet_DrawWinding(&w, color);
-}
-
-/*
-============
-VS_DrawPortals
-============
-*/
-void VS_DrawPortals(void)
-{
- int j;
- lportal_t *p;
-
- for (j = 0; j < numportals * 2; j++)
- {
- p = portals + j;
- DebugNet_DrawWinding(p->winding, 1);
- }
-}
-
-/*
-============
-VS_DrawLeaf
-============
-*/
-void VS_DrawLeaf(int cluster)
-{
- int i;
- lleaf_t *leaf;
- lportal_t *p;
-
- leaf = &leafs[cluster];
- for (i = 0; i < leaf->numportals; i++)
- {
- p = leaf->portals[i];
- DebugNet_DrawWinding(p->winding, 1);
- }
-}
-
-#endif //DEBUGNET
-
-/*
-=============
-VS_SplitWinding
-=============
-*/
-int VS_SplitWinding (winding_t *in, winding_t *back, plane_t *split, float epsilon)
-{
- vec_t dists[128];
- int sides[128];
- int counts[3];
- vec_t dot;
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- winding_t out;
- winding_t *neww;
-
- counts[0] = counts[1] = counts[2] = 0;
-
- // determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
-
- if (!counts[SIDE_BACK])
- {
- if (!counts[SIDE_FRONT])
- return SIDE_ON;
- else
- return SIDE_FRONT;
- }
-
- if (!counts[SIDE_FRONT])
- {
- return SIDE_BACK;
- }
-
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- neww = &out;
-
- neww->numpoints = 0;
- back->numpoints = 0;
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->points[i];
-
- if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VS_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
- if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VS_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT;
- }
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- VectorCopy (p1, back->points[back->numpoints]);
- back->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
- if (sides[i] == SIDE_BACK)
- {
- VectorCopy (p1, back->points[back->numpoints]);
- back->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VS_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
-
- if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VS_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
-
- // generate a split point
- p2 = in->points[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, neww->points[neww->numpoints]);
- neww->numpoints++;
- VectorCopy (mid, back->points[back->numpoints]);
- back->numpoints++;
- }
- memcpy(in, &out, sizeof(winding_t));
-
- return SIDE_CROSS;
-}
-
-/*
-=====================
-VS_LinkSurfaceIntoCluster
-=====================
-*/
-void VS_LinkSurfaceIntoCluster(int cluster, int surfaceNum)
-{
- lleaf_t *leaf;
- int i;
-
- leaf = &leafs[cluster];
-
- for (i = 0; i < leaf->numSurfaces; i++)
- {
- if (clustersurfaces[leaf->firstSurface + i] == surfaceNum)
- return;
- }
- for (i = numclustersurfaces; i > leaf->firstSurface + leaf->numSurfaces; i--)
- clustersurfaces[i] = clustersurfaces[i-1];
- for (i = 0; i < portalclusters; i++)
- {
- if (i == cluster)
- continue;
- if (leafs[i].firstSurface >= leaf->firstSurface + leaf->numSurfaces)
- leafs[i].firstSurface++;
- }
- clustersurfaces[leaf->firstSurface + leaf->numSurfaces] = surfaceNum;
- leaf->numSurfaces++;
- numclustersurfaces++;
- if (numclustersurfaces >= MAX_MAP_LEAFFACES)
- Error("MAX_MAP_LEAFFACES");
-}
-
-/*
-=====================
-VS_R_LinkSurface
-=====================
-*/
-void VS_R_LinkSurface(int nodenum, int surfaceNum, winding_t *w)
-{
- int leafnum, cluster, res;
- dnode_t *node;
- dplane_t *plane;
- winding_t back;
- plane_t split;
-
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
-
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VS_SplitWinding (w, &back, &split, 0.1);
-
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- memcpy(&back, w, sizeof(winding_t));
- VS_R_LinkSurface(node->children[1], surfaceNum, &back);
- nodenum = node->children[0];
- }
- else
- {
- VS_R_LinkSurface(node->children[1], surfaceNum, &back);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- cluster = dleafs[leafnum].cluster;
- if (cluster != -1)
- {
- VS_LinkSurfaceIntoCluster(cluster, surfaceNum);
- }
-}
-
-/*
-=====================
-VS_LinkSurfaces
-
-maybe link each facet seperately instead of the test surfaces?
-=====================
-*/
-void VS_LinkSurfaces(void)
-{
- int i, j;
- lsurfaceTest_t *test;
- lFacet_t *facet;
- winding_t winding;
-
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- for (j = 0; j < test->numFacets; j++)
- {
- facet = &test->facets[j];
- memcpy(winding.points, facet->points, facet->numpoints * sizeof(vec3_t));
- winding.numpoints = facet->numpoints;
- VS_R_LinkSurface(0, i, &winding);
- }
- }
-}
-
-/*
-=====================
-VS_TextureMatrixFromPoints
-=====================
-*/
-void VS_TextureMatrixFromPoints( lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
- int i, j;
- float t;
- float m[3][4];
- float s;
-
- // This is an incredibly stupid way of solving a three variable equation
- for ( i = 0 ; i < 2 ; i++ ) {
-
- m[0][0] = a->xyz[0];
- m[0][1] = a->xyz[1];
- m[0][2] = a->xyz[2];
- m[0][3] = a->st[i];
-
- m[1][0] = b->xyz[0];
- m[1][1] = b->xyz[1];
- m[1][2] = b->xyz[2];
- m[1][3] = b->st[i];
-
- m[2][0] = c->xyz[0];
- m[2][1] = c->xyz[1];
- m[2][2] = c->xyz[2];
- m[2][3] = c->st[i];
-
- if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) > fabs(m[2][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[1][j];
- m[1][j] = t;
- }
- } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) > fabs(m[1][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[2][j];
- m[2][j] = t;
- }
- }
-
- s = 1.0 / m[0][0];
- m[0][0] *= s;
- m[0][1] *= s;
- m[0][2] *= s;
- m[0][3] *= s;
-
- s = m[1][0];
- m[1][0] -= m[0][0] * s;
- m[1][1] -= m[0][1] * s;
- m[1][2] -= m[0][2] * s;
- m[1][3] -= m[0][3] * s;
-
- s = m[2][0];
- m[2][0] -= m[0][0] * s;
- m[2][1] -= m[0][1] * s;
- m[2][2] -= m[0][2] * s;
- m[2][3] -= m[0][3] * s;
-
- if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[1][j];
- m[1][j] = m[2][j];
- m[2][j] = t;
- }
- }
-
- s = 1.0 / m[1][1];
- m[1][0] *= s;
- m[1][1] *= s;
- m[1][2] *= s;
- m[1][3] *= s;
-
- s = m[2][1];// / m[1][1];
- m[2][0] -= m[1][0] * s;
- m[2][1] -= m[1][1] * s;
- m[2][2] -= m[1][2] * s;
- m[2][3] -= m[1][3] * s;
-
- s = 1.0 / m[2][2];
- m[2][0] *= s;
- m[2][1] *= s;
- m[2][2] *= s;
- m[2][3] *= s;
-
- f->textureMatrix[i][2] = m[2][3];
- f->textureMatrix[i][1] = m[1][3] - f->textureMatrix[i][2] * m[1][2];
- f->textureMatrix[i][0] = m[0][3] - f->textureMatrix[i][2] * m[0][2] - f->textureMatrix[i][1] * m[0][1];
-
- f->textureMatrix[i][3] = 0;
-/*
- s = fabs( DotProduct( a->xyz, f->textureMatrix[i] ) - a->st[i] );
- if ( s > 0.01 ) {
- Error( "Bad textureMatrix" );
- }
- s = fabs( DotProduct( b->xyz, f->textureMatrix[i] ) - b->st[i] );
- if ( s > 0.01 ) {
- Error( "Bad textureMatrix" );
- }
- s = fabs( DotProduct( c->xyz, f->textureMatrix[i] ) - c->st[i] );
- if ( s > 0.01 ) {
- Error( "Bad textureMatrix" );
- }
-*/
- }
-}
-
-/*
-=====================
-VS_LightmapMatrixFromPoints
-=====================
-*/
-void VS_LightmapMatrixFromPoints( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
- int i, j;
- float t;
- float m[3][4], al, bl, cl;
- float s;
- int h, w, ssize;
- vec3_t mins, maxs, delta, size, planeNormal;
- drawVert_t *verts;
- static int message;
-
- // vertex-lit triangle model
- if ( dsurf->surfaceType == MST_TRIANGLE_SOUP ) {
- return;
- }
-
- if ( dsurf->lightmapNum < 0 ) {
- return; // doesn't need lighting
- }
-
- VectorClear(f->mins);
- if (dsurf->surfaceType != MST_PATCH)
- {
- ssize = samplesize;
- if (si->lightmapSampleSize)
- ssize = si->lightmapSampleSize;
- ClearBounds( mins, maxs );
- verts = &drawVerts[dsurf->firstVert];
- for ( i = 0 ; i < dsurf->numVerts ; i++ ) {
- AddPointToBounds( verts[i].xyz, mins, maxs );
- }
- // round to the lightmap resolution
- for ( i = 0 ; i < 3 ; i++ ) {
- mins[i] = ssize * floor( mins[i] / ssize );
- maxs[i] = ssize * ceil( maxs[i] / ssize );
- f->mins[i] = mins[i];
- size[i] = (maxs[i] - mins[i]) / ssize + 1;
- }
- // the two largest axis will be the lightmap size
- VectorClear(f->lightmapMatrix[0]);
- f->lightmapMatrix[0][3] = 0;
- VectorClear(f->lightmapMatrix[1]);
- f->lightmapMatrix[1][3] = 0;
-
- planeNormal[0] = fabs( dsurf->lightmapVecs[2][0] );
- planeNormal[1] = fabs( dsurf->lightmapVecs[2][1] );
- planeNormal[2] = fabs( dsurf->lightmapVecs[2][2] );
-
- if ( planeNormal[0] >= planeNormal[1] && planeNormal[0] >= planeNormal[2] ) {
- w = size[1];
- h = size[2];
- f->lightmapMatrix[0][1] = 1.0 / ssize;
- f->lightmapMatrix[1][2] = 1.0 / ssize;
- } else if ( planeNormal[1] >= planeNormal[0] && planeNormal[1] >= planeNormal[2] ) {
- w = size[0];
- h = size[2];
- f->lightmapMatrix[0][0] = 1.0 / ssize;
- f->lightmapMatrix[1][2] = 1.0 / ssize;
- } else {
- w = size[0];
- h = size[1];
- f->lightmapMatrix[0][0] = 1.0 / ssize;
- f->lightmapMatrix[1][1] = 1.0 / ssize;
- }
- if ( w > LIGHTMAP_WIDTH ) {
- VectorScale ( f->lightmapMatrix[0], (float)LIGHTMAP_SIZE/w, f->lightmapMatrix[0] );
- }
-
- if ( h > LIGHTMAP_HEIGHT ) {
- VectorScale ( f->lightmapMatrix[1], (float)LIGHTMAP_SIZE/h, f->lightmapMatrix[1] );
- }
- VectorSubtract(a->xyz, f->mins, delta);
- s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(s - a->lightmap[0]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(t - a->lightmap[1]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- VectorSubtract(b->xyz, f->mins, delta);
- s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(s - b->lightmap[0]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(t - b->lightmap[1]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- VectorSubtract(c->xyz, f->mins, delta);
- s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(s - c->lightmap[0]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- if ( fabs(t - c->lightmap[1]) > 0.01 ) {
- _printf( "Bad lightmapMatrix" );
- }
- VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins);
- return;
- }
- // This is an incredibly stupid way of solving a three variable equation
- for ( i = 0 ; i < 2 ; i++ ) {
-
- if (i)
- al = a->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- else
- al = a->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
-
- m[0][0] = a->xyz[0] - f->mins[0];
- m[0][1] = a->xyz[1] - f->mins[1];
- m[0][2] = a->xyz[2] - f->mins[2];
- m[0][3] = al;
-
- if (i)
- bl = b->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- else
- bl = b->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
-
- m[1][0] = b->xyz[0] - f->mins[0];
- m[1][1] = b->xyz[1] - f->mins[1];
- m[1][2] = b->xyz[2] - f->mins[2];
- m[1][3] = bl;
-
- if (i)
- cl = c->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
- else
- cl = c->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
-
- m[2][0] = c->xyz[0] - f->mins[0];
- m[2][1] = c->xyz[1] - f->mins[1];
- m[2][2] = c->xyz[2] - f->mins[2];
- m[2][3] = cl;
-
- if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) >= fabs(m[2][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[1][j];
- m[1][j] = t;
- }
- } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) >= fabs(m[1][0]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[0][j];
- m[0][j] = m[2][j];
- m[2][j] = t;
- }
- }
-
- if (m[0][0])
- {
- s = 1.0 / m[0][0];
- m[0][0] *= s;
- m[0][1] *= s;
- m[0][2] *= s;
- m[0][3] *= s;
-
- s = m[1][0];
- m[1][0] -= m[0][0] * s;
- m[1][1] -= m[0][1] * s;
- m[1][2] -= m[0][2] * s;
- m[1][3] -= m[0][3] * s;
-
- s = m[2][0];
- m[2][0] -= m[0][0] * s;
- m[2][1] -= m[0][1] * s;
- m[2][2] -= m[0][2] * s;
- m[2][3] -= m[0][3] * s;
- }
-
- if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
- for ( j = 0 ; j < 4 ; j ++ ) {
- t = m[1][j];
- m[1][j] = m[2][j];
- m[2][j] = t;
- }
- }
-
- if (m[1][1])
- {
- s = 1.0 / m[1][1];
- m[1][0] *= s;
- m[1][1] *= s;
- m[1][2] *= s;
- m[1][3] *= s;
-
- s = m[2][1];
- m[2][0] -= m[1][0] * s;
- m[2][1] -= m[1][1] * s;
- m[2][2] -= m[1][2] * s;
- m[2][3] -= m[1][3] * s;
- }
-
- if (m[2][2])
- {
- s = 1.0 / m[2][2];
- m[2][0] *= s;
- m[2][1] *= s;
- m[2][2] *= s;
- m[2][3] *= s;
- }
-
- f->lightmapMatrix[i][2] = m[2][3];
- f->lightmapMatrix[i][1] = m[1][3] - f->lightmapMatrix[i][2] * m[1][2];
- f->lightmapMatrix[i][0] = m[0][3] - f->lightmapMatrix[i][2] * m[0][2] - f->lightmapMatrix[i][1] * m[0][1];
-
- f->lightmapMatrix[i][3] = 0;
-
- VectorSubtract(a->xyz, f->mins, delta);
- s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - al );
- if ( s > 0.01 ) {
- if (!message)
- _printf( "Bad lightmapMatrix\n" );
- message = qtrue;
- }
- VectorSubtract(b->xyz, f->mins, delta);
- s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - bl );
- if ( s > 0.01 ) {
- if (!message)
- _printf( "Bad lightmapMatrix\n" );
- message = qtrue;
- }
- VectorSubtract(c->xyz, f->mins, delta);
- s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - cl );
- if ( s > 0.01 ) {
- if (!message)
- _printf( "Bad lightmapMatrix\n" );
- message = qtrue;
- }
- VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins);
- }
-}
-
-/*
-=============
-Plane_Equal
-=============
-*/
-#define NORMAL_EPSILON 0.0001
-#define DIST_EPSILON 0.02
-
-static int Plane_Equal(plane_t *a, plane_t *b, int flip)
-{
- vec3_t normal;
- float dist;
-
- if (flip) {
- normal[0] = - b->normal[0];
- normal[1] = - b->normal[1];
- normal[2] = - b->normal[2];
- dist = - b->dist;
- }
- else {
- normal[0] = b->normal[0];
- normal[1] = b->normal[1];
- normal[2] = b->normal[2];
- dist = b->dist;
- }
- if (
- fabs(a->normal[0] - normal[0]) < NORMAL_EPSILON
- && fabs(a->normal[1] - normal[1]) < NORMAL_EPSILON
- && fabs(a->normal[2] - normal[2]) < NORMAL_EPSILON
- && fabs(a->dist - dist) < DIST_EPSILON )
- return qtrue;
- return qfalse;
-}
-
-/*
-=============
-VS_PlaneFromPoints
-=============
-*/
-qboolean VS_PlaneFromPoints( plane_t *plane, const vec3_t a, const vec3_t b, const vec3_t c ) {
- vec3_t d1, d2;
-
- VectorSubtract( b, a, d1 );
- VectorSubtract( c, a, d2 );
- CrossProduct( d2, d1, plane->normal );
- if ( VectorNormalize( plane->normal, plane->normal ) == 0 ) {
- return qfalse;
- }
-
- plane->dist = DotProduct( a, plane->normal );
- return qtrue;
-}
-
-/*
-=====================
-VS_GenerateBoundaryForPoints
-=====================
-*/
-void VS_GenerateBoundaryForPoints( plane_t *boundary, plane_t *plane, vec3_t a, vec3_t b ) {
- vec3_t d1;
-
- // make a perpendicular vector to the edge and the surface
- VectorSubtract( a, b, d1 );
- CrossProduct( plane->normal, d1, boundary->normal );
- VectorNormalize( boundary->normal, boundary->normal );
- boundary->dist = DotProduct( a, boundary->normal );
-}
-
-/*
-=====================
-VS_GenerateFacetFor3Points
-=====================
-*/
-qboolean VS_GenerateFacetFor3Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
- //
- vec3_t dir;
- int i;
-
- // if we can't generate a valid plane for the points, ignore the facet
- if ( !VS_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) {
- f->numpoints = 0;
- return qfalse;
- }
-
- f->num = numfacets++;
-
- VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] );
- VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] );
- VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] );
-
- f->lightmapCoords[0][0] = a->lightmap[0];
- f->lightmapCoords[0][1] = a->lightmap[1];
- f->lightmapCoords[1][0] = b->lightmap[0];
- f->lightmapCoords[1][1] = b->lightmap[1];
- f->lightmapCoords[2][0] = c->lightmap[0];
- f->lightmapCoords[2][1] = c->lightmap[1];
-
- VS_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] );
- VS_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] );
- VS_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[0] );
-
- for (i = 0; i < 3; i++)
- {
- VectorSubtract(f->points[(i+1)%3], f->points[i], dir);
- if (VectorLength(dir) < 0.1)
- return qfalse;
- }
-
- VS_TextureMatrixFromPoints( f, a, b, c );
- VS_LightmapMatrixFromPoints( dsurf, si, f, a, b, c );
-
- f->numpoints = 3;
-
- return qtrue;
-}
-
-/*
-=====================
-VS_GenerateFacetFor4Points
-
-Attempts to use four points as a planar quad
-=====================
-*/
-#define PLANAR_EPSILON 0.1
-qboolean VS_GenerateFacetFor4Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c, drawVert_t *d ) {
- float dist;
- vec3_t dir;
- int i;
- plane_t plane;
-
- // if we can't generate a valid plane for the points, ignore the facet
- if ( !VS_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) {
- f->numpoints = 0;
- return qfalse;
- }
-
- // if the fourth point is also on the plane, we can make a quad facet
- dist = DotProduct( d->xyz, f->plane.normal ) - f->plane.dist;
- if ( fabs( dist ) > PLANAR_EPSILON ) {
- f->numpoints = 0;
- return qfalse;
- }
-
- VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] );
- VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] );
- VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] );
- VectorAdd( d->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[3] );
-
- for (i = 1; i < 4; i++)
- {
- if ( !VS_PlaneFromPoints( &plane, f->points[i], f->points[(i+1) % 4], f->points[(i+2) % 4]) ) {
- f->numpoints = 0;
- return qfalse;
- }
-
- if (!Plane_Equal(&f->plane, &plane, qfalse)) {
- f->numpoints = 0;
- return qfalse;
- }
- }
-
- f->lightmapCoords[0][0] = a->lightmap[0];
- f->lightmapCoords[0][1] = a->lightmap[1];
- f->lightmapCoords[1][0] = b->lightmap[0];
- f->lightmapCoords[1][1] = b->lightmap[1];
- f->lightmapCoords[2][0] = c->lightmap[0];
- f->lightmapCoords[2][1] = c->lightmap[1];
- f->lightmapCoords[3][0] = d->lightmap[0];
- f->lightmapCoords[3][1] = d->lightmap[1];
-
- VS_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] );
- VS_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] );
- VS_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[3] );
- VS_GenerateBoundaryForPoints( &f->boundaries[3], &f->plane, f->points[3], f->points[0] );
-
- for (i = 0; i < 4; i++)
- {
- VectorSubtract(f->points[(i+1)%4], f->points[i], dir);
- if (VectorLength(dir) < 0.1)
- return qfalse;
- }
-
- VS_TextureMatrixFromPoints( f, a, b, c );
- VS_LightmapMatrixFromPoints( dsurf, si, f, a, b, c );
-
- f->num = numfacets++;
- f->numpoints = 4;
-
- return qtrue;
-}
-
-/*
-===============
-VS_SphereFromBounds
-===============
-*/
-void VS_SphereFromBounds( vec3_t mins, vec3_t maxs, vec3_t origin, float *radius ) {
- vec3_t temp;
-
- VectorAdd( mins, maxs, origin );
- VectorScale( origin, 0.5, origin );
- VectorSubtract( maxs, origin, temp );
- *radius = VectorLength( temp );
-}
-
-/*
-====================
-VS_FacetsForTriangleSurface
-====================
-*/
-void VS_FacetsForTriangleSurface( dsurface_t *dsurf, shaderInfo_t *si, lsurfaceTest_t *test ) {
- int i;
- drawVert_t *v1, *v2, *v3, *v4;
- int count;
- int i1, i2, i3, i4, i5, i6;
-
- test->patch = qfalse;
- if (dsurf->surfaceType == MST_TRIANGLE_SOUP)
- test->trisoup = qtrue;
- else
- test->trisoup = qfalse;
- test->numFacets = dsurf->numIndexes / 3;
- test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
- test->shader = si;
-
- count = 0;
- for ( i = 0 ; i < test->numFacets ; i++ ) {
- i1 = drawIndexes[ dsurf->firstIndex + i*3 ];
- i2 = drawIndexes[ dsurf->firstIndex + i*3 + 1 ];
- i3 = drawIndexes[ dsurf->firstIndex + i*3 + 2 ];
-
- v1 = &drawVerts[ dsurf->firstVert + i1 ];
- v2 = &drawVerts[ dsurf->firstVert + i2 ];
- v3 = &drawVerts[ dsurf->firstVert + i3 ];
-
- // try and make a quad out of two triangles
- if ( i != test->numFacets - 1 ) {
- i4 = drawIndexes[ dsurf->firstIndex + i*3 + 3 ];
- i5 = drawIndexes[ dsurf->firstIndex + i*3 + 4 ];
- i6 = drawIndexes[ dsurf->firstIndex + i*3 + 5 ];
- if ( i4 == i3 && i5 == i2 ) {
- v4 = &drawVerts[ dsurf->firstVert + i6 ];
- if ( VS_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v2, v4, v3 ) ) {
- count++;
- i++; // skip next tri
- continue;
- }
- }
- }
-
- if (VS_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v2, v3 )) {
- count++;
- }
- }
-
- // we may have turned some pairs into quads
- test->numFacets = count;
-}
-
-/*
-====================
-VS_FacetsForPatch
-====================
-*/
-void VS_FacetsForPatch( dsurface_t *dsurf, int surfaceNum, shaderInfo_t *si, lsurfaceTest_t *test ) {
- int i, j, x, y;
- drawVert_t *v1, *v2, *v3, *v4;
- int count, ssize;
- mesh_t mesh;
- mesh_t *subdivided, *detailmesh, *newmesh;
- int widthtable[LIGHTMAP_SIZE], heighttable[LIGHTMAP_SIZE];
-
- mesh.width = dsurf->patchWidth;
- mesh.height = dsurf->patchHeight;
- mesh.verts = &drawVerts[ dsurf->firstVert ];
-
- newmesh = SubdivideMesh( mesh, 8, 999 );
- PutMeshOnCurve( *newmesh );
- MakeMeshNormals( *newmesh );
-
- subdivided = RemoveLinearMeshColumnsRows( newmesh );
- FreeMesh(newmesh);
-
- // DebugNet_RemoveAllPolys();
- // DebugNet_DrawMesh(subdivided);
-
- ssize = samplesize;
- if (si->lightmapSampleSize)
- ssize = si->lightmapSampleSize;
-
- if ( dsurf->lightmapNum >= 0 ) {
-
- detailmesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_SIZE, widthtable, heighttable);
- test->detailMesh = detailmesh;
-
- // DebugNet_RemoveAllPolys();
- // DebugNet_DrawMesh(detailmesh);
-
- if ( detailmesh->width != dsurf->lightmapWidth || detailmesh->height != dsurf->lightmapHeight ) {
- Error( "Mesh lightmap miscount");
- }
- }
- else {
- test->detailMesh = NULL;
- memset(widthtable, 0, sizeof(widthtable));
- memset(heighttable, 0, sizeof(heighttable));
- }
-
- test->patch = qtrue;
- test->trisoup = qfalse;
- test->numFacets = ( subdivided->width - 1 ) * ( subdivided->height - 1 ) * 2;
- test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
- test->shader = si;
-
- count = 0;
- x = 0;
- for ( i = 0 ; i < subdivided->width - 1 ; i++ ) {
- y = 0;
- for ( j = 0 ; j < subdivided->height - 1 ; j++ ) {
-
- v1 = subdivided->verts + j * subdivided->width + i;
- v2 = v1 + 1;
- v3 = v1 + subdivided->width + 1;
- v4 = v1 + subdivided->width;
-
- if ( VS_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v4, v3, v2 ) ) {
- test->facets[count].x = x;
- test->facets[count].y = y;
- test->facets[count].width = widthtable[i];
- test->facets[count].height = heighttable[j];
- count++;
- } else {
- if (VS_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v4, v3 )) {
- test->facets[count].x = x;
- test->facets[count].y = y;
- test->facets[count].width = widthtable[i];
- test->facets[count].height = heighttable[j];
- count++;
- }
- if (VS_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v3, v2 )) {
- test->facets[count].x = x;
- test->facets[count].y = y;
- test->facets[count].width = widthtable[i];
- test->facets[count].height = heighttable[j];
- count++;
- }
- }
- y += heighttable[j];
- }
- x += widthtable[i];
- }
- test->numFacets = count;
-
- FreeMesh(subdivided);
-}
-
-/*
-=====================
-VS_InitSurfacesForTesting
-=====================
-*/
-void VS_InitSurfacesForTesting( void ) {
-
- int i, j, k;
- dsurface_t *dsurf;
- lsurfaceTest_t *test;
- shaderInfo_t *si;
- lFacet_t *facet;
-
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- // don't light the entity surfaces with vsound
- if ( entitySurface[i] )
- continue;
- //
- dsurf = &drawSurfaces[ i ];
- if ( !dsurf->numIndexes && !dsurf->patchWidth ) {
- continue;
- }
-
- si = ShaderInfoForShader( dshaders[ dsurf->shaderNum].shader );
- // if the surface is translucent and does not cast an alpha shadow
- if ( (si->contents & CONTENTS_TRANSLUCENT) && !(si->surfaceFlags & SURF_ALPHASHADOW) ) {
- // if the surface has no lightmap
- if ( dsurf->lightmapNum < 0 )
- continue;
- }
-
- test = malloc( sizeof( *test ) );
- memset(test, 0, sizeof( *test ));
- test->mutex = MutexAlloc();
- test->numvolumes = 0;
- if (si->forceTraceLight)
- test->always_tracelight = qtrue;
- else if (si->forceVLight)
- test->always_vsound = qtrue;
- lsurfaceTest[i] = test;
-
- if ( dsurf->surfaceType == MST_TRIANGLE_SOUP || dsurf->surfaceType == MST_PLANAR ) {
- VS_FacetsForTriangleSurface( dsurf, si, test );
- } else if ( dsurf->surfaceType == MST_PATCH ) {
- VS_FacetsForPatch( dsurf, i, si, test );
- }
- if (numfacets >= MAX_FACETS)
- Error("numfacets >= MAX_FACETS (%d)", MAX_FACETS);
-
- ClearBounds( test->mins, test->maxs );
- for (j = 0; j < test->numFacets; j++)
- {
- facet = &test->facets[j];
- for ( k = 0 ; k < facet->numpoints; k++) {
- AddPointToBounds( facet->points[k], test->mins, test->maxs );
- }
- }
- VS_SphereFromBounds( test->mins, test->maxs, test->origin, &test->radius );
- }
- _printf("%6d facets\n", numfacets);
- _printf("linking surfaces...\n");
- VS_LinkSurfaces();
-}
-
-/*
-=============
-VS_ChopWinding
-=============
-*/
-int VS_ChopWinding (winding_t *in, plane_t *split, float epsilon)
-{
- vec_t dists[128];
- int sides[128];
- int counts[3];
- vec_t dot;
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- winding_t out;
- winding_t *neww;
-
- counts[0] = counts[1] = counts[2] = 0;
-
- // determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
-
- if (!counts[SIDE_BACK])
- {
- if (!counts[SIDE_FRONT])
- return SIDE_ON;
- else
- return SIDE_FRONT;
- }
-
- if (!counts[SIDE_FRONT])
- {
- return SIDE_BACK;
- }
-
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- neww = &out;
-
- neww->numpoints = 0;
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->points[i];
-
- if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VS_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VS_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return SIDE_FRONT; // can't chop -- fall back to original
- }
-
- // generate a split point
- p2 = in->points[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
- memcpy(in, &out, sizeof(winding_t));
-
- return SIDE_CROSS;
-}
-
-/*
-=============
-VS_ChopWindingWithBrush
-
- returns all winding fragments outside the brush
-=============
-*/
-int VS_ChopWindingWithBrush(winding_t *w, dbrush_t *brush, winding_t *outwindings, int maxout)
-{
- int i, res, numout;
- winding_t front, back;
- plane_t plane;
-
- numout = 0;
- memcpy(front.points, w->points, w->numpoints * sizeof(vec3_t));
- front.numpoints = w->numpoints;
- for (i = 0; i < brush->numSides; i++)
- {
- VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal);
- VectorInverse(plane.normal);
- plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist;
- res = VS_SplitWinding(&front, &back, &plane, 0.1);
- if (res == SIDE_BACK || res == SIDE_ON)
- {
- memcpy(outwindings[0].points, w->points, w->numpoints * sizeof(vec3_t));
- outwindings[0].numpoints = w->numpoints;
- return 1; //did not intersect
- }
- if (res != SIDE_FRONT)
- {
- if (numout >= maxout)
- {
- _printf("WARNING: VS_ChopWindingWithBrush: more than %d windings\n", maxout);
- return 0;
- }
- memcpy(outwindings[numout].points, back.points, back.numpoints * sizeof(vec3_t));
- outwindings[numout].numpoints = back.numpoints;
- numout++;
- }
- }
- return numout;
-}
-
-/*
-=============
-VS_WindingAreaOutsideBrushes
-=============
-*/
-float VS_WindingAreaOutsideBrushes(winding_t *w, int *brushnums, int numbrushes)
-{
- int i, j, numwindings[2], n;
- winding_t windingsbuf[2][64];
- dbrush_t *brush;
- float area;
-
- memcpy(windingsbuf[0][0].points, w->points, w->numpoints * sizeof(vec3_t));
- windingsbuf[0][0].numpoints = w->numpoints;
- numwindings[0] = 1;
- for (i = 0; i < numbrushes; i++)
- {
- brush = &dbrushes[brushnums[i]];
- if (!(dshaders[brush->shaderNum].contentFlags & (
- CONTENTS_LAVA
- | CONTENTS_SLIME
- | CONTENTS_WATER
- | CONTENTS_FOG
- | CONTENTS_AREAPORTAL
- | CONTENTS_PLAYERCLIP
- | CONTENTS_MONSTERCLIP
- | CONTENTS_CLUSTERPORTAL
- | CONTENTS_DONOTENTER
- | CONTENTS_BODY
- | CONTENTS_CORPSE
- | CONTENTS_TRANSLUCENT
- | CONTENTS_TRIGGER
- | CONTENTS_NODROP) ) &&
- (dshaders[brush->shaderNum].contentFlags & CONTENTS_SOLID) )
- {
- numwindings[!(i & 1)] = 0;
- for (j = 0; j < numwindings[i&1]; j++)
- {
- n = VS_ChopWindingWithBrush(&windingsbuf[i&1][j], brush,
- &windingsbuf[!(i&1)][numwindings[!(i&1)]],
- 64 - numwindings[!(i&1)]);
- numwindings[!(i&1)] += n;
- }
- if (!numwindings[!(i&1)])
- return 0;
- }
- else
- {
- for (j = 0; j < numwindings[i&1]; j++)
- {
- windingsbuf[!(i&1)][j] = windingsbuf[i&1][j];
- }
- numwindings[!(i&1)] = numwindings[i&1];
- }
- }
- area = 0;
- for (j = 0; j < numwindings[i&1]; j++)
- {
- area += WindingArea(&windingsbuf[i&1][j]);
- }
- return area;
-}
-
-/*
-=============
-VS_R_WindingAreaOutsideSolid
-=============
-*/
-float VS_R_WindingAreaOutsideSolid(winding_t *w, vec3_t normal, int nodenum)
-{
- int leafnum, res;
- float area;
- dnode_t *node;
- dleaf_t *leaf;
- dplane_t *plane;
- winding_t back;
- plane_t split;
-
- area = 0;
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
-
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VS_SplitWinding (w, &back, &split, 0.1);
-
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- if (DotProduct(normal, plane->normal) > 0)
- nodenum = node->children[0];
- else
- nodenum = node->children[1];
- }
- else
- {
- area += VS_R_WindingAreaOutsideSolid(&back, normal, node->children[1]);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- leaf = &dleafs[leafnum];
- if (leaf->cluster != -1)
- {
- area += VS_WindingAreaOutsideBrushes(w, &dleafbrushes[leaf->firstLeafBrush], leaf->numLeafBrushes);
- }
- return area;
-}
-
-/*
-=============
-VS_WindingAreaOutsideSolid
-=============
-*/
-float VS_WindingAreaOutsideSolid(winding_t *w, vec3_t normal)
-{
- return VS_R_WindingAreaOutsideSolid(w, normal, 0);
-}
-
-/*
-=============
-VS_ChopWindingWithFacet
-=============
-*/
-float VS_ChopWindingWithFacet(winding_t *w, lFacet_t *facet)
-{
- int i;
-
- for (i = 0; i < facet->numpoints; i++)
- {
- if (VS_ChopWinding(w, &facet->boundaries[i], 0) == SIDE_BACK)
- return 0;
- }
- if (nostitching)
- return WindingArea(w);
- else
- return VS_WindingAreaOutsideSolid(w, facet->plane.normal);
-}
-
-/*
-=============
-VS_CalcVisibleLightmapPixelArea
-
-nice brute force ;)
-=============
-*/
-void VS_CalcVisibleLightmapPixelArea(void)
-{
- int i, j, x, y, k;
- dsurface_t *ds;
- lsurfaceTest_t *test;
- mesh_t *mesh;
- winding_t w, tmpw;
- float area;
-
- _printf("calculating visible lightmap pixel area...\n");
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- ds = &drawSurfaces[ i ];
-
- if ( ds->lightmapNum < 0 )
- continue;
-
- for (y = 0; y < ds->lightmapHeight; y++)
- {
- for (x = 0; x < ds->lightmapWidth; x++)
- {
- if (ds->surfaceType == MST_PATCH)
- {
- if (y == ds->lightmapHeight-1)
- continue;
- if (x == ds->lightmapWidth-1)
- continue;
- mesh = lsurfaceTest[i]->detailMesh;
- VectorCopy( mesh->verts[y*mesh->width+x].xyz, w.points[0]);
- VectorCopy( mesh->verts[(y+1)*mesh->width+x].xyz, w.points[1]);
- VectorCopy( mesh->verts[(y+1)*mesh->width+x+1].xyz, w.points[2]);
- VectorCopy( mesh->verts[y*mesh->width+x+1].xyz, w.points[3]);
- w.numpoints = 4;
- if (nostitching)
- area = WindingArea(&w);
- else
- area = VS_WindingAreaOutsideSolid(&w, mesh->verts[y*mesh->width+x].normal);
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[0]);
- VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[0]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[3]);
- VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[3]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[2]);
- VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[2]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[1]);
- VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[1]);
- w.numpoints = 4;
- area = 0;
- for (j = 0; j < test->numFacets; j++)
- {
- memcpy(&tmpw, &w, sizeof(winding_t));
- area += VS_ChopWindingWithFacet(&tmpw, &test->facets[j]);
- }
- }
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- lightmappixelarea[k] = area;
- }
- }
- }
-}
-
-/*
-=============
-VS_FindAdjacentSurface
-=============
-*/
-int VS_FindAdjacentSurface(int surfaceNum, int facetNum, vec3_t p1, vec3_t p2, int *sNum, int *fNum, int *point)
-{
- int i, j, k;
- lsurfaceTest_t *test;
- lFacet_t *facet;
- dsurface_t *ds;
- float *fp1, *fp2;
- vec3_t dir;
- plane_t *facetplane;
- // winding_t w;
-
- facetplane = &lsurfaceTest[surfaceNum]->facets[facetNum].plane;
- // DebugNet_RemoveAllPolys();
- // memcpy(w.points, lsurfaceTest[surfaceNum]->facets[facetNum].points,
- // lsurfaceTest[surfaceNum]->facets[facetNum].numpoints * sizeof(vec3_t));
- // w.numpoints = lsurfaceTest[surfaceNum]->facets[facetNum].numpoints;
- // DebugNet_DrawWinding(&w, 2);
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- if (i == surfaceNum)
- continue;
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- if (test->trisoup)// || test->patch)
- continue;
- ds = &drawSurfaces[i];
- if ( ds->lightmapNum < 0 )
- continue;
- //if this surface is not even near the edge
- VectorSubtract(p1, test->origin, dir);
- if (fabs(dir[0]) > test->radius ||
- fabs(dir[1]) > test->radius ||
- fabs(dir[1]) > test->radius)
- {
- VectorSubtract(p2, test->origin, dir);
- if (fabs(dir[0]) > test->radius ||
- fabs(dir[1]) > test->radius ||
- fabs(dir[1]) > test->radius)
- {
- continue;
- }
- }
- //
- for (j = 0; j < test->numFacets; j++)
- {
- facet = &test->facets[j];
- //
- //if (!Plane_Equal(&facet->plane, facetplane, qfalse))
- if (DotProduct(facet->plane.normal, facetplane->normal) < 0.9)
- {
- if (!test->trisoup && !test->patch)
- break;
- continue;
- }
- //
- for (k = 0; k < facet->numpoints; k++)
- {
- fp1 = facet->points[k];
- if (fabs(p2[0] - fp1[0]) < 0.1 &&
- fabs(p2[1] - fp1[1]) < 0.1 &&
- fabs(p2[2] - fp1[2]) < 0.1)
- {
- fp2 = facet->points[(k+1) % facet->numpoints];
- if (fabs(p1[0] - fp2[0]) < 0.1 &&
- fabs(p1[1] - fp2[1]) < 0.1 &&
- fabs(p1[2] - fp2[2]) < 0.1)
- {
- // memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t));
- // w.numpoints = facet->numpoints;
- // DebugNet_DrawWinding(&w, 1);
- *sNum = i;
- *fNum = j;
- *point = k;
- return qtrue;
- }
- }
- /*
- else if (fabs(p1[0] - fp1[0]) < 0.1 &&
- fabs(p1[1] - fp1[1]) < 0.1 &&
- fabs(p1[2] - fp1[2]) < 0.1)
- {
- fp2 = facet->points[(k+1) % facet->numpoints];
- if (fabs(p2[0] - fp2[0]) < 0.1 &&
- fabs(p2[1] - fp2[1]) < 0.1 &&
- fabs(p2[2] - fp2[2]) < 0.1)
- {
- // memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t));
- // w.numpoints = facet->numpoints;
- // DebugNet_DrawWinding(&w, 1);
- *sNum = i;
- *fNum = j;
- *point = k;
- return qtrue;
- }
- }
- //*/
- }
- }
- }
- return qfalse;
-}
-
-/*
-=============
-VS_SmoothenLightmapEdges
-
-this code is used to smoothen lightmaps across surface edges
-=============
-*/
-void VS_SmoothenLightmapEdges(void)
-{
- int i, j, k, coords1[2][2];
- float coords2[2][2];
- int x1, y1, xinc1, yinc1, k1, k2;
- float x2, y2, xinc2, yinc2, length;
- int surfaceNum, facetNum, point;
- lsurfaceTest_t *test;
- lFacet_t *facet1, *facet2;
- dsurface_t *ds1, *ds2;
- float *p[2], s, t, *color1, *color2;
- vec3_t dir, cross;
-
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- if (test->trisoup)// || test->patch)
- continue;
- ds1 = &drawSurfaces[i];
- if ( ds1->lightmapNum < 0 )
- continue;
- for (j = 0; j < test->numFacets; j++)
- {
- facet1 = &test->facets[j];
- //
- for (k = 0; k < facet1->numpoints; k++)
- {
- p[0] = facet1->points[k];
- p[1] = facet1->points[(k+1)%facet1->numpoints];
- //
- coords1[0][0] = facet1->lightmapCoords[k][0] * LIGHTMAP_SIZE;
- coords1[0][1] = facet1->lightmapCoords[k][1] * LIGHTMAP_SIZE;
- coords1[1][0] = facet1->lightmapCoords[(k+1)%facet1->numpoints][0] * LIGHTMAP_SIZE;
- coords1[1][1] = facet1->lightmapCoords[(k+1)%facet1->numpoints][1] * LIGHTMAP_SIZE;
- if (coords1[0][0] >= LIGHTMAP_SIZE)
- coords1[0][0] = LIGHTMAP_SIZE-1;
- if (coords1[0][1] >= LIGHTMAP_SIZE)
- coords1[0][1] = LIGHTMAP_SIZE-1;
- if (coords1[1][0] >= LIGHTMAP_SIZE)
- coords1[1][0] = LIGHTMAP_SIZE-1;
- if (coords1[1][1] >= LIGHTMAP_SIZE)
- coords1[1][1] = LIGHTMAP_SIZE-1;
- // try one row or column further because on flat faces the lightmap can
- // extend beyond the edge
- VectorSubtract(p[1], p[0], dir);
- VectorNormalize(dir, dir);
- CrossProduct(dir, facet1->plane.normal, cross);
- //
- if (coords1[0][0] - coords1[1][0] == 0)
- {
- s = DotProduct( cross, facet1->lightmapMatrix[0] );
- coords1[0][0] += s < 0 ? 1 : -1;
- coords1[1][0] += s < 0 ? 1 : -1;
- if (coords1[0][0] < ds1->lightmapX || coords1[0][0] >= ds1->lightmapX + ds1->lightmapWidth)
- {
- coords1[0][0] += s < 0 ? -1 : 1;
- coords1[1][0] += s < 0 ? -1 : 1;
- }
- length = fabs(coords1[1][1] - coords1[0][1]);
- }
- else if (coords1[0][1] - coords1[1][1] == 0)
- {
- t = DotProduct( cross, facet1->lightmapMatrix[1] );
- coords1[0][1] += t < 0 ? 1 : -1;
- coords1[1][1] += t < 0 ? 1 : -1;
- if (coords1[0][1] < ds1->lightmapY || coords1[0][1] >= ds1->lightmapY + ds1->lightmapHeight)
- {
- coords1[0][1] += t < 0 ? -1 : 1;
- coords1[1][1] += t < 0 ? -1 : 1;
- }
- length = fabs(coords1[1][0] - coords1[0][0]);
- }
- else
- {
- //the edge is not parallell to one of the lightmap axis
- continue;
- }
- //
- x1 = coords1[0][0];
- y1 = coords1[0][1];
- xinc1 = coords1[1][0] - coords1[0][0];
- if (xinc1 < 0) xinc1 = -1;
- if (xinc1 > 0) xinc1 = 1;
- yinc1 = coords1[1][1] - coords1[0][1];
- if (yinc1 < 0) yinc1 = -1;
- if (yinc1 > 0) yinc1 = 1;
- // the edge should be parallell to one of the lightmap axis
- if (xinc1 != 0 && yinc1 != 0)
- continue;
- //
- if (!VS_FindAdjacentSurface(i, j, p[0], p[1], &surfaceNum, &facetNum, &point))
- continue;
- //
- ds2 = &drawSurfaces[surfaceNum];
- facet2 = &lsurfaceTest[surfaceNum]->facets[facetNum];
- coords2[0][0] = facet2->lightmapCoords[(point+1)%facet2->numpoints][0] * LIGHTMAP_SIZE;
- coords2[0][1] = facet2->lightmapCoords[(point+1)%facet2->numpoints][1] * LIGHTMAP_SIZE;
- coords2[1][0] = facet2->lightmapCoords[point][0] * LIGHTMAP_SIZE;
- coords2[1][1] = facet2->lightmapCoords[point][1] * LIGHTMAP_SIZE;
- if (coords2[0][0] >= LIGHTMAP_SIZE)
- coords2[0][0] = LIGHTMAP_SIZE-1;
- if (coords2[0][1] >= LIGHTMAP_SIZE)
- coords2[0][1] = LIGHTMAP_SIZE-1;
- if (coords2[1][0] >= LIGHTMAP_SIZE)
- coords2[1][0] = LIGHTMAP_SIZE-1;
- if (coords2[1][1] >= LIGHTMAP_SIZE)
- coords2[1][1] = LIGHTMAP_SIZE-1;
- //
- x2 = coords2[0][0];
- y2 = coords2[0][1];
- xinc2 = coords2[1][0] - coords2[0][0];
- if (length)
- xinc2 = xinc2 / length;
- yinc2 = coords2[1][1] - coords2[0][1];
- if (length)
- yinc2 = yinc2 / length;
- // the edge should be parallell to one of the lightmap axis
- if ((int) xinc2 != 0 && (int) yinc2 != 0)
- continue;
- //
- while(1)
- {
- k1 = ( ds1->lightmapNum * LIGHTMAP_HEIGHT + y1) * LIGHTMAP_WIDTH + x1;
- k2 = ( ds2->lightmapNum * LIGHTMAP_HEIGHT + ((int) y2)) * LIGHTMAP_WIDTH + ((int) x2);
- color1 = lightFloats + k1*3;
- color2 = lightFloats + k2*3;
- if (lightmappixelarea[k1] < 0.01)
- {
- color1[0] = color2[0];
- color1[1] = color2[1];
- color1[2] = color2[2];
- }
- else
- {
- color1[0] = (float) color2[0] * 0.7 + (float) color1[0] * 0.3;
- color1[1] = (float) color2[1] * 0.7 + (float) color1[1] * 0.3;
- color1[2] = (float) color2[2] * 0.7 + (float) color1[2] * 0.3;
- }
- //
- if (x1 == coords1[1][0] &&
- y1 == coords1[1][1])
- break;
- x1 += xinc1;
- y1 += yinc1;
- x2 += xinc2;
- y2 += yinc2;
- if (x2 < ds2->lightmapX)
- x2 = ds2->lightmapX;
- if (x2 >= ds2->lightmapX + ds2->lightmapWidth)
- x2 = ds2->lightmapX + ds2->lightmapWidth-1;
- if (y2 < ds2->lightmapY)
- y2 = ds2->lightmapY;
- if (y2 >= ds2->lightmapY + ds2->lightmapHeight)
- y2 = ds2->lightmapY + ds2->lightmapHeight-1;
- }
- }
- }
- }
-}
-
-/*
-=============
-VS_FixLightmapEdges
-=============
-*/
-void VS_FixLightmapEdges(void)
-{
- int i, j, x, y, k, foundvalue, height, width, index;
- int pos, top, bottom;
- dsurface_t *ds;
- lsurfaceTest_t *test;
- float color[3];
- float *ptr;
- byte filled[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8];
- float lightmap_edge_epsilon;
-
- lightmap_edge_epsilon = 0.1 * samplesize;
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- ds = &drawSurfaces[ i ];
-
- if ( ds->lightmapNum < 0 )
- continue;
- if (ds->surfaceType == MST_PATCH)
- {
- height = ds->lightmapHeight - 1;
- width = ds->lightmapWidth - 1;
- }
- else
- {
- height = ds->lightmapHeight;
- width = ds->lightmapWidth;
- }
- memset(filled, 0, sizeof(filled));
-// printf("\n");
- for (x = 0; x < width; x++)
- {
- for (y = 0; y < height; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (lightmappixelarea[k] > lightmap_edge_epsilon)
- {
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- filled[index >> 3] |= 1 << (index & 7);
-// printf("*");
- }
-// else
-// printf("_");
- }
-// printf("\n");
- }
- for (y = 0; y < height; y++)
- {
- pos = -2;
- for (x = 0; x < width; x++)
- {
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (pos == -2)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- pos = -1;
- }
- else if (pos == -1)
- {
- if (!(filled[index >> 3] & (1 << (index & 7))))
- pos = x - 1;
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + pos;
- top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- for (j = 0; j < (x - pos + 1) / 2; j++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1;
- filled[index >> 3] |= 1 << (index & 7);
- (lightFloats + k*3)[0] = (lightFloats + top*3)[0];
- (lightFloats + k*3)[1] = (lightFloats + top*3)[1];
- (lightFloats + k*3)[2] = (lightFloats + top*3)[2];
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1;
- filled[index >> 3] |= 1 << (index & 7);
- (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0];
- (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1];
- (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2];
- }
- pos = -1;
- }
- }
- }
- }
- for (x = 0; x < width; x++)
- {
- pos = -2;
- for (y = 0; y < height; y++)
- {
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (pos == -2)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- pos = -1;
- }
- else if (pos == -1)
- {
- if (!(filled[index >> 3] & (1 << (index & 7))))
- pos = y - 1;
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- for (j = 0; j < (y - pos + 1) / 2; j++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos + j + 1)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + pos + j + 1) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- filled[index >> 3] |= 1 << (index & 7);
- (lightFloats + k*3)[0] = (lightFloats + top*3)[0];
- (lightFloats + k*3)[1] = (lightFloats + top*3)[1];
- (lightFloats + k*3)[2] = (lightFloats + top*3)[2];
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y - j - 1)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y - j - 1) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- filled[index >> 3] |= 1 << (index & 7);
- (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0];
- (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1];
- (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2];
- }
- pos = -1;
- }
- }
- }
- }
- for (y = 0; y < height; y++)
- {
- foundvalue = qfalse;
- for (x = 0; x < width; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (foundvalue)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- }
- else
- {
- ptr = lightFloats + k*3;
- ptr[0] = color[0];
- ptr[1] = color[1];
- ptr[2] = color[2];
- filled[index >> 3] |= 1 << (index & 7);
- }
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- foundvalue = qtrue;
- }
- }
- }
- foundvalue = qfalse;
- for (x = width-1; x >= 0; x--)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (foundvalue)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- }
- else
- {
- ptr = lightFloats + k*3;
- ptr[0] = color[0];
- ptr[1] = color[1];
- ptr[2] = color[2];
- filled[index >> 3] |= 1 << (index & 7);
- }
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- foundvalue = qtrue;
- }
- }
- }
- }
- for (x = 0; x < width; x++)
- {
- foundvalue = qfalse;
- for (y = 0; y < height; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (foundvalue)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- }
- else
- {
- ptr = lightFloats + k*3;
- ptr[0] = color[0];
- ptr[1] = color[1];
- ptr[2] = color[2];
- filled[index >> 3] |= 1 << (index & 7);
- }
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- foundvalue = qtrue;
- }
- }
- }
- foundvalue = qfalse;
- for (y = height-1; y >= 0; y--)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
- if (foundvalue)
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- }
- else
- {
- ptr = lightFloats + k*3;
- ptr[0] = color[0];
- ptr[1] = color[1];
- ptr[2] = color[2];
- filled[index >> 3] |= 1 << (index & 7);
- }
- }
- else
- {
- if (filled[index >> 3] & (1 << (index & 7)))
- {
- ptr = lightFloats + k*3;
- color[0] = ptr[0];
- color[1] = ptr[1];
- color[2] = ptr[2];
- foundvalue = qtrue;
- }
- }
- }
- }
- if (ds->surfaceType == MST_PATCH)
- {
- x = ds->lightmapWidth-1;
- for (y = 0; y < ds->lightmapHeight; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = (lightFloats + (k-1)*3)[0];
- ptr[1] = (lightFloats + (k-1)*3)[1];
- ptr[2] = (lightFloats + (k-1)*3)[2];
- }
- y = ds->lightmapHeight-1;
- for (x = 0; x < ds->lightmapWidth; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0];
- ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1];
- ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2];
- }
- }
- /*
- //colored debug edges
- if (ds->surfaceType == MST_PATCH)
- {
- x = ds->lightmapWidth-1;
- for (y = 0; y < ds->lightmapHeight; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = 255;
- ptr[1] = 0;
- ptr[2] = 0;
- }
- y = ds->lightmapHeight-1;
- for (x = 0; x < ds->lightmapWidth; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = 0;
- ptr[1] = 255;
- ptr[2] = 0;
- }
- }
- //*/
- }
- //
- VS_SmoothenLightmapEdges();
-}
-
-/*
-=============
-VS_ShiftPatchLightmaps
-=============
-*/
-void VS_ShiftPatchLightmaps(void)
-{
- int i, j, x, y, k;
- drawVert_t *verts;
- dsurface_t *ds;
- lsurfaceTest_t *test;
- float *ptr;
-
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- ds = &drawSurfaces[ i ];
-
- if ( ds->lightmapNum < 0 )
- continue;
- if (ds->surfaceType != MST_PATCH)
- continue;
- for (x = ds->lightmapWidth; x > 0; x--)
- {
- for (y = 0; y <= ds->lightmapHeight; y++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = (lightFloats + (k-1)*3)[0];
- ptr[1] = (lightFloats + (k-1)*3)[1];
- ptr[2] = (lightFloats + (k-1)*3)[2];
- }
- }
- for (y = ds->lightmapHeight; y > 0; y--)
- {
- for (x = 0; x <= ds->lightmapWidth; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- ptr = lightFloats + k*3;
- ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0];
- ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1];
- ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2];
- }
- }
- verts = &drawVerts[ ds->firstVert ];
- for ( j = 0 ; j < ds->patchHeight * ds->patchWidth; j++ )
- {
- verts[j].lightmap[0] += 0.5 / LIGHTMAP_WIDTH;
- verts[j].lightmap[1] += 0.5 / LIGHTMAP_HEIGHT;
- }
- ds->lightmapHeight++;
- ds->lightmapWidth++;
- }
-}
-
-/*
-=============
-VS_StoreLightmap
-=============
-*/
-void VS_StoreLightmap(void)
-{
- int i, x, y, k;
- dsurface_t *ds;
- lsurfaceTest_t *test;
- float *src;
- byte *dst;
-
- _printf("storing lightmaps...\n");
- //fix lightmap edges before storing them
- VS_FixLightmapEdges();
- //
-#ifdef LIGHTMAP_PATCHSHIFT
- VS_ShiftPatchLightmaps();
-#endif
- //
- for ( i = 0 ; i < numDrawSurfaces ; i++ )
- {
- test = lsurfaceTest[ i ];
- if (!test)
- continue;
- ds = &drawSurfaces[ i ];
-
- if ( ds->lightmapNum < 0 )
- continue;
-
- for (y = 0; y < ds->lightmapHeight; y++)
- {
- for (x = 0; x < ds->lightmapWidth; x++)
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- VectorAdd((lightFloats + k*3), lightAmbientColor, (lightFloats + k*3));
- src = &lightFloats[k*3];
- dst = lightBytes + k*3;
- ColorToBytes(src, dst);
- }
- }
- }
-}
-
-/*
-=============
-PointInLeafnum
-=============
-*/
-static int PointInLeafnum(vec3_t point)
-{
- int nodenum;
- vec_t dist;
- dnode_t *node;
- dplane_t *plane;
-
- nodenum = 0;
- while (nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
- dist = DotProduct (point, plane->normal) - plane->dist;
- if (dist > 0)
- nodenum = node->children[0];
- else
- nodenum = node->children[1];
- }
-
- return -nodenum - 1;
-}
-
-/*
-=============
-VS_PointInLeafnum_r
-=============
-*/
-int VS_PointInLeafnum_r(vec3_t point, int nodenum)
-{
- int leafnum;
- vec_t dist;
- dnode_t *node;
- dplane_t *plane;
-
- while (nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
- dist = DotProduct (point, plane->normal) - plane->dist;
- if (dist > 0.1)
- {
- nodenum = node->children[0];
- }
- else if (dist < -0.1)
- {
- nodenum = node->children[1];
- }
- else
- {
- leafnum = VS_PointInLeafnum_r(point, node->children[0]);
- if (dleafs[leafnum].cluster != -1)
- return leafnum;
- nodenum = node->children[1];
- }
- }
-
- leafnum = -nodenum - 1;
- return leafnum;
-}
-
-/*
-=============
-VS_PointInLeafnum
-=============
-*/
-int VS_PointInLeafnum(vec3_t point)
-{
- return VS_PointInLeafnum_r(point, 0);
-}
-
-/*
-=============
-VS_LightLeafnum
-=============
-*/
-int VS_LightLeafnum(vec3_t point)
-{
- /*
- int leafnum;
- dleaf_t *leaf;
- float x, y, z;
- vec3_t test;
-
- leafnum = VS_PointInLeafnum(point);
- leaf = &dleafs[leafnum];
- if (leaf->cluster != -1)
- return leafnum;
- for (z = 1; z >= -1; z -= 1)
- {
- for (x = 1; x >= -1; x -= 1)
- {
- for (y = 1; y >= -1; y -= 1)
- {
- VectorCopy(point, test);
- test[0] += x;
- test[1] += y;
- test[2] += z;
- leafnum = VS_PointInLeafnum(test);
- leaf = &dleafs[leafnum];
- if (leaf->cluster != -1)
- {
- VectorCopy(test, point);
- return leafnum;
- }
- }
- }
- }
- return leafnum;
- */
- return VS_PointInLeafnum(point);
-}
-
-//#define LIGHTPOLYS
-
-#ifdef LIGHTPOLYS
-
-winding_t *lightwindings[MAX_MAP_DRAW_SURFS];
-int numlightwindings;
-
-/*
-=============
-VS_DrawLightWindings
-=============
-*/
-void VS_DrawLightWindings(void)
-{
- int i;
- for (i = 0; i < numlightwindings; i++)
- {
-#ifdef DEBUGNET
- DebugNet_DrawWinding(lightwindings[i], 1);
-#endif
- }
-}
-
-/*
-=============
-VS_LightSurfaceWithVolume
-=============
-*/
-void VS_LightSurfaceWithVolume(int surfaceNum, int facetNum, vsound_t *light, lightvolume_t *volume)
-{
- winding_t *w;
- lsurfaceTest_t *test;
- lFacet_t *facet;
- int i;
-
- test = lsurfaceTest[ surfaceNum ];
- facet = &test->facets[ facetNum ];
-
- //
- w = (winding_t *) malloc(sizeof(winding_t));
- memcpy(w->points, facet->points, sizeof(vec3_t) * facet->numpoints);
- w->numpoints = facet->numpoints;
-
- for (i = 0; i < volume->numplanes; i++)
- {
- //if totally on the back
- if (VS_ChopWinding(w, &volume->planes[i], 0.01) == SIDE_BACK)
- return;
- }
- lightwindings[numlightwindings] = w;
- numlightwindings++;
- if (numlightwindings >= MAX_MAP_DRAW_SURFS)
- Error("MAX_LIGHTWINDINGS");
-}
-
-#else
-
-/*
-=============
-VS_LightSurfaceWithVolume
-=============
-*/
-/*
-int VS_PointInsideLightVolume(vec3_t point, lightvolume_t *volume)
-{
- int i;
- float d;
-
- for (i = 0; i < volume->numplanes; i++)
- {
- d = DotProduct(volume->planes[i].normal, point) - volume->planes[i].dist;
- if (d < 0) return qfalse;
- }
- return qtrue;
-}
-
-void VS_LightSurfaceWithVolume( int surfaceNum, int facetNum, vsound_t *light, lightvolume_t *volume )
-{
- dsurface_t *ds;
- int i, j, k;
- int numPositions;
- vec3_t base, normal, color;
- int sampleWidth, sampleHeight;
- vec3_t lightmapOrigin, lightmapVecs[2], dir;
- unsigned char *ptr;
- float add, dist, angle;
- mesh_t * mesh;
-
- ds = &drawSurfaces[surfaceNum];
-
- // vertex-lit triangle model
- if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
- return;
- }
-
- if ( ds->lightmapNum < 0 ) {
- return; // doesn't need lighting
- }
-
- if ( ds->surfaceType == MST_PATCH ) {
- mesh = lsurfaceTest[surfaceNum]->detailMesh;
- } else {
- VectorCopy( ds->lightmapVecs[2], normal );
-
- VectorCopy( ds->lightmapOrigin, lightmapOrigin );
- VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] );
- VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] );
- }
-
- sampleWidth = ds->lightmapWidth;
- sampleHeight = ds->lightmapHeight;
-
- //calculate lightmap
- for ( i = 0 ; i < sampleWidth; i++ ) {
- for ( j = 0 ; j < sampleHeight; j++ ) {
-
- if ( ds->patchWidth ) {
- numPositions = 9;
- VectorCopy( mesh->verts[j*mesh->width+i].normal, normal );
- // VectorNormalize( normal, normal );
- // push off of the curve a bit
- VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base );
-
-// MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] );
- } else {
- numPositions = 9;
- for ( k = 0 ; k < 3 ; k++ ) {
- base[k] = lightmapOrigin[k] + normal[k]
- + ((float) i) * lightmapVecs[0][k]
- + ((float) j) * lightmapVecs[1][k];
- }
- }
- VectorAdd( base, surfaceOrigin[ surfaceNum ], base );
-
- VectorSubtract(base, light->origin, dir);
- dist = VectorNormalize(dir, dir);
- if ( dist < 16 ) {
- dist = 16;
- }
- angle = 1;//DotProduct( normal, dir ); //1;
- if (angle > 1)
- angle = 1;
- if ( light->atten_disttype == LDAT_LINEAR ) {
- add = angle * light->photons * lightLinearScale - dist;
- if ( add < 0 ) {
- add = 0;
- }
- } else {
- add = light->photons / ( dist * dist ) * angle;
- }
- if (add <= 1.0)
- continue;
-
- if (VS_PointInsideLightVolume(base, volume))
- {
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j)
- * LIGHTMAP_WIDTH + ds->lightmapX + i;
- ptr = lightBytes + k*3;
- color[0] = (float) ptr[0] + add * light->color[0];
- color[1] = (float) ptr[1] + add * light->color[1];
- color[2] = (float) ptr[2] + add * light->color[2];
- ColorToBytes(color, ptr);
- }
- }
- }
-}
-*/
-
-/*
-=============
-VS_GetFilter
-
-FIXME: don't use a lightmap pixel origin but use the four corner points
- to map part of a translucent surface onto the lightmap pixel
-=============
-*/
-void VS_GetFilter(vsound_t *light, lightvolume_t *volume, vec3_t lmp, vec3_t filter)
-{
- lFacet_t *facet;
- lsurfaceTest_t *test;
- float d, d1, d2, frac, s, t, ns;
- int i, j, is, it, b;
- int x, y, u, v, numsamples, radius, color[4], largest;
- byte *image;
- vec3_t point, origin, total;
-
- VectorSet(filter, 1, 1, 1);
-
- if (noalphashading)
- return;
-
- if (volume->numtransFacets <= 0)
- return;
-
- if (light->type == LIGHT_SURFACEDIRECTED)
- {
- // project the light map pixel origin onto the area light source plane
- d = DotProduct(lmp, light->normal) - DotProduct(light->normal, light->w.points[0]);
- VectorMA(lmp, -d, light->normal, origin);
- }
- else
- {
- VectorCopy(light->origin, origin);
- }
- for (i = 0; i < volume->numtransFacets; i++)
- {
- test = lsurfaceTest[ volume->transSurfaces[i] ];
- facet = &test->facets[ volume->transFacets[i] ];
- // if this surface does not cast an alpha shadow
- if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) )
- continue;
- // if there are no texture pixel available
- if ( !test->shader->pixels ) {
- continue;
- }
- //
- d1 = DotProduct( origin, facet->plane.normal) - facet->plane.dist;
- d2 = DotProduct( lmp, facet->plane.normal ) - facet->plane.dist;
- // this should never happen because the light volume went through the facet
- if ( ( d1 < 0 ) == ( d2 < 0 ) ) {
- continue;
- }
- // calculate the crossing point
- frac = d1 / ( d1 - d2 );
-
- for ( j = 0 ; j < 3 ; j++ ) {
- point[j] = origin[j] + frac * ( lmp[j] - origin[j] );
- }
-
- s = DotProduct( point, facet->textureMatrix[0] ) + facet->textureMatrix[0][3];
- t = DotProduct( point, facet->textureMatrix[1] ) + facet->textureMatrix[1][3];
- if (s < 0)
- s = 0;
- if (t < 0)
- t = 0;
-
- s = s - floor( s );
- t = t - floor( t );
-
- is = s * test->shader->width;
- it = t * test->shader->height;
-
- //if old style alpha shading
- if (nocolorshading) {
- image = test->shader->pixels + 4 * ( it * test->shader->width + is );
-
- // alpha filter
- b = image[3];
-
- // alpha test makes this a binary option
- b = b < 128 ? 0 : 255;
-
- filter[0] = filter[0] * (255-b) / 255;
- filter[1] = filter[1] * (255-b) / 255;
- filter[2] = filter[2] * (255-b) / 255;
- }
- else {
- VectorClear(total);
- numsamples = 0;
- radius = 2;
- for ( u = -radius; u <= radius; u++ )
- {
- x = is + u;
- if ( x < 0 || x >= test->shader->width)
- continue;
- for ( v = -radius; v <= radius; v++ )
- {
- y = it + v;
- if ( y < 0 || y >= test->shader->height)
- continue;
-
- image = test->shader->pixels + 4 * ( y * test->shader->width + x );
- color[0] = image[0];
- color[1] = image[1];
- color[2] = image[2];
- largest = 0;
- for (j = 0; j < 3; j++)
- if (image[j] > largest)
- largest = image[j];
- if (largest <= 0 || image[3] == 0) {
- color[0] = 255;
- color[1] = 255;
- color[2] = 255;
- largest = 255;
- }
- total[0] += ((float) color[0]/largest) * (255-image[3]) / 255.0;
- total[1] += ((float) color[1]/largest) * (255-image[3]) / 255.0;
- total[2] += ((float) color[2]/largest) * (255-image[3]) / 255.0;
- numsamples++;
- }
- }
- ns = numsamples;
- //
- filter[0] *= total[0] / ns;
- filter[1] *= total[1] / ns;
- filter[2] *= total[2] / ns;
- }
- }
-}
-
-/*
-=============
-VS_LightSurfaceWithVolume
-=============
-*/
-void VS_LightSurfaceWithVolume( int surfaceNum, int facetNum, vsound_t *light, lightvolume_t *volume )
-{
- int i;
- dsurface_t *ds;
- lFacet_t *facet;
- lsurfaceTest_t *test;
- winding_t w;
- vec3_t base, dir, delta, normal, filter, origin;
- int min_x[LIGHTMAP_SIZE+2], max_x[LIGHTMAP_SIZE+2];
- int min_y, max_y, k, x, y, n;
- float *color, distscale;
- float d, add, angle, dist, area, insidearea, coords[MAX_POINTS_ON_WINDING+1][2];
- mesh_t *mesh;
- byte polygonedges[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8];
-
-
- ds = &drawSurfaces[surfaceNum];
-
- // vertex-lit triangle model
- if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
- return;
- }
-
- if ( ds->lightmapNum < 0 ) {
- return; // doesn't need lighting
- }
-
- test = lsurfaceTest[ surfaceNum ];
- facet = &test->facets[ facetNum ];
-
- if (defaulttracelight && !test->always_vsound)
- return;
- if (test->always_tracelight)
- return;
-
- memcpy(w.points, facet->points, sizeof(vec3_t) * facet->numpoints);
- w.numpoints = facet->numpoints;
-
- for (i = 0; i < volume->numplanes; i++)
- {
- //if totally on the back
- if (VS_ChopWinding(&w, &volume->planes[i], 0.01) == SIDE_BACK)
- return;
- }
-
- // only one thread at a time may write to the lightmap of this surface
- MutexLock(test->mutex);
-
- test->numvolumes++;
-
- if (ds->surfaceType == MST_PATCH)
- {
- // FIXME: reduce size and don't mark all as edge
- min_y = ds->lightmapY + facet->y;
- max_y = ds->lightmapY + facet->y + facet->height - 1;
- for (y = min_y; y <= max_y; y++)
- {
- min_x[y] = ds->lightmapX + facet->x;
- max_x[y] = ds->lightmapX + facet->x + facet->width - 1;
- for (x = min_x[y]; x <= max_x[y]; x++)
- {
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- }
- }
- }
- else
- {
- for (i = 0; i < w.numpoints; i++)
- {
- float s, t;
-
- if (i >= MAX_POINTS_ON_WINDING)
- _printf("coords overflow\n");
- if (ds->surfaceType != MST_PATCH)
- {
- VectorSubtract(w.points[i], facet->mins, delta);
- s = DotProduct( delta, facet->lightmapMatrix[0] ) + ds->lightmapX + 0.5;
- t = DotProduct( delta, facet->lightmapMatrix[1] ) + ds->lightmapY + 0.5;
- if (s >= LIGHTMAP_SIZE)
- s = LIGHTMAP_SIZE - 0.5;
- if (s < 0)
- s = 0;
- if (t >= LIGHTMAP_SIZE)
- t = LIGHTMAP_SIZE - 0.5;
- if (t < 0)
- t = 0;
- coords[i][0] = s;
- coords[i][1] = t;
- }
- else
- {
- s = DotProduct( w.points[i], facet->lightmapMatrix[0] ) + facet->lightmapMatrix[0][3];
- t = DotProduct( w.points[i], facet->lightmapMatrix[1] ) + facet->lightmapMatrix[1][3];
-
- s = s - floor( s );
- t = t - floor( t );
-
- coords[i][0] = ds->lightmapX + s * LIGHTMAP_SIZE;// + 0.5;
- coords[i][1] = ds->lightmapY + t * LIGHTMAP_SIZE;// + 0.5;
-
- if (coords[i][0] >= LIGHTMAP_SIZE)
- coords[i][0] -= LIGHTMAP_SIZE;
- if (coords[i][1] >= LIGHTMAP_SIZE)
- coords[i][1] -= LIGHTMAP_SIZE;
- if (coords[i][0] < ds->lightmapX)
- coords[i][0] = ds->lightmapX;
- if (coords[i][1] < ds->lightmapY)
- coords[i][1] = ds->lightmapY;
- }
- x = coords[i][0];
- y = coords[i][1];
- if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
- _printf("VS_LightSurfaceWithVolume: x outside lightmap\n");
- if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
- _printf("VS_LightSurfaceWithVolume: y outside lightmap\n");
- }
- coords[i][0] = coords[0][0];
- coords[i][1] = coords[0][1];
-
- //
- min_y = LIGHTMAP_SIZE;
- max_y = 0;
- for (i = 0; i < LIGHTMAP_SIZE; i++)
- {
- min_x[i] = LIGHTMAP_SIZE;
- max_x[i] = 0;
- }
- memset(polygonedges, 0, sizeof(polygonedges));
- // scan convert the polygon onto the lightmap
- // for each edge it marks *every* lightmap pixel the edge goes through
- // so no brasenham and no scan conversion used for texture mapping but
- // more something like ray casting
- // this is necesary because we need all lightmap pixels totally or partly
- // inside the light volume. these lightmap pixels are only lit for the part
- // that they are inside the light volume.
- for (i = 0; i < w.numpoints; i++)
- {
- float xf, yf, dx, dy, xstep, ystep, xfrac, yfrac;
- int xinc, yinc;
-
- xf = coords[i][0];
- yf = coords[i][1];
- dx = coords[i+1][0] - xf;
- dy = coords[i+1][1] - yf;
- //
- x = (int) xf;
- y = (int) yf;
- //
- if (y < min_y)
- min_y = y;
- if (y > max_y)
- max_y = y;
- //
- if (fabs(dx) > fabs(dy))
- {
- if (dx > 0)
- {
- // y fraction at integer x below fractional x
- yfrac = yf + (floor(xf) - xf) * dy / dx;
- xinc = 1;
- }
- else if (dx < 0)
- {
- // y fraction at integer x above fractional x
- yfrac = yf + (floor(xf) + 1 - xf) * dy / dx;
- xinc = -1;
- }
- else
- {
- yfrac = yf;
- xinc = 0;
- }
- // step in y direction per 1 unit in x direction
- if (dx)
- ystep = dy / fabs(dx);
- else
- ystep = 0;
- while(1)
- {
- if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
- _printf("VS_LightSurfaceWithVolume: x outside lightmap\n");
- if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
- _printf("VS_LightSurfaceWithVolume: y outside lightmap\n");
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- if (x == (int) coords[i+1][0])
- break;
- yfrac += ystep;
- if (dy > 0)
- {
- if (yfrac > (float) y + 1)
- {
- y += 1;
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- }
- }
- else
- {
- if (yfrac < (float) y)
- {
- y -= 1;
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- }
- }
- x += xinc;
- }
- }
- else
- {
- if (dy > 0)
- {
- //x fraction at integer y below fractional y
- xfrac = xf + (floor(yf) - yf) * dx / dy;
- yinc = 1;
- }
- else if (dy < 0)
- {
- //x fraction at integer y above fractional y
- xfrac = xf + (floor(yf) + 1 - yf) * dx / dy;
- yinc = -1;
- }
- else
- {
- xfrac = xf;
- yinc = 0;
- }
- // step in x direction per 1 unit in y direction
- if (dy)
- xstep = dx / fabs(dy);
- else
- xstep = 0;
- while(1)
- {
- if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
- _printf("VS_LightSurfaceWithVolume: x outside lightmap\n");
- if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
- _printf("VS_LightSurfaceWithVolume: y outside lightmap\n");
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- if (y == (int) coords[i+1][1])
- break;
- xfrac += xstep;
- if (dx > 0)
- {
- if (xfrac > (float) x + 1)
- {
- x += 1;
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- }
- }
- else
- {
- if (xfrac < (float) x)
- {
- x -= 1;
- //
- n = y * LIGHTMAP_SIZE + x;
- polygonedges[n >> 3] |= 1 << (n & 7);
- if (x < min_x[y])
- min_x[y] = x;
- if (x > max_x[y])
- max_x[y] = x;
- }
- }
- y += yinc;
- }
- }
- }
- }
- // map light onto the lightmap
- for (y = min_y; y <= max_y; y++)
- {
- for (x = min_x[y]; x <= max_x[y]; x++)
- {
- if (ds->surfaceType == MST_PATCH)
- {
- mesh = test->detailMesh;
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, base);
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].normal, normal);
- //VectorCopy(facet->plane.normal, normal);
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x - ds->lightmapX, ds->lightmapVecs[0], base);
- VectorMA(base, (float) y - ds->lightmapY, ds->lightmapVecs[1], base);
- VectorCopy(facet->plane.normal, normal);
- }
- if (light->type == LIGHT_POINTSPOT)
- {
- float distByNormal;
- vec3_t pointAtDist;
- float radiusAtDist;
- float sampleRadius;
- vec3_t distToSample;
- float coneScale;
-
- VectorSubtract( light->origin, base, dir );
-
- distByNormal = -DotProduct( dir, light->normal );
- if ( distByNormal < 0 ) {
- continue;
- }
- VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
- radiusAtDist = light->radiusByDist * distByNormal;
-
- VectorSubtract( base, pointAtDist, distToSample );
- sampleRadius = VectorLength( distToSample );
-
- if ( sampleRadius >= radiusAtDist ) {
- continue; // outside the cone
- }
- if ( sampleRadius <= radiusAtDist - 32 ) {
- coneScale = 1.0; // fully inside
- } else {
- coneScale = ( radiusAtDist - sampleRadius ) / 32.0;
- }
-
- dist = VectorNormalize( dir, dir );
- // clamp the distance to prevent super hot spots
- if ( dist < 16 ) {
- dist = 16;
- }
- angle = DotProduct( normal, dir );
- if (angle > 1)
- angle = 1;
- if (angle > 0) {
- if ( light->atten_angletype == LAAT_QUADRATIC ) {
- angle = 1 - angle;
- angle *= angle;
- angle = 1 - angle;
- }
- else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
- angle = 1 - angle;
- angle *= angle * angle;
- angle = 1 - angle;
- }
- }
- if (light->atten_anglescale > 0) {
- angle /= light->atten_anglescale;
- if (angle > 1)
- angle = 1;
- }
- if (light->atten_distscale > 0) {
- distscale = light->atten_distscale;
- }
- else {
- distscale = 1;
- }
- //
- if ( light->atten_disttype == LDAT_NOSCALE ) {
- add = angle * coneScale;
- }
- else if ( light->atten_disttype == LDAT_LINEAR ) {
- add = angle * light->photons * lightLinearScale * coneScale - dist * distscale;
- if ( add < 0 ) {
- add = 0;
- }
- }
- else {
- add = light->photons / ( dist * dist * distscale) * angle * coneScale;
- }
- if (add <= 1.0)
- continue;
- }
- else if (light->type == LIGHT_POINTFAKESURFACE)
- {
- // calculate the contribution
- add = PointToPolygonFormFactor( base, normal, &light->w );
- if ( add <= 0 ) {
- if ( light->twosided ) {
- add = -add;
- } else {
- continue;
- }
- }
- }
- else if (light->type == LIGHT_SURFACEDIRECTED)
- {
- //VectorCopy(light->normal, dir);
- //VectorInverse(dir);
- // project the light map pixel origin onto the area light source plane
- d = DotProduct(base, light->normal) - DotProduct(light->normal, light->w.points[0]);
- VectorMA(base, -d, light->normal, origin);
- VectorSubtract(origin, base, dir);
- dist = VectorNormalize(dir, dir);
- if ( dist < 16 ) {
- dist = 16;
- }
- //
- angle = DotProduct( normal, dir );
- if (angle > 1)
- angle = 1;
- if (angle > 0) {
- if ( light->atten_angletype == LAAT_QUADRATIC ) {
- angle = 1 - angle;
- angle *= angle;
- angle = 1 - angle;
- }
- else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
- angle = 1 - angle;
- angle *= angle * angle;
- angle = 1 - angle;
- }
- }
- if (light->atten_anglescale > 0) {
- angle /= light->atten_anglescale;
- if (angle > 1)
- angle = 1;
- }
- if (light->atten_distscale > 0) {
- distscale = light->atten_distscale;
- }
- else {
- distscale = 1;
- }
- if ( light->atten_disttype == LDAT_NOSCALE ) {
- add = angle;
- }
- else if ( light->atten_disttype == LDAT_LINEAR ) {
- add = angle * light->photons * lightLinearScale - dist * distscale;
- if ( add < 0 ) {
- add = 0;
- }
- } else { //default quadratic
- add = light->photons / ( dist * dist * distscale) * angle;
- }
- if (add <= 0)
- continue;
- }
- else //normal radial point light
- {
- VectorSubtract(light->origin, base, dir);
- dist = VectorNormalize(dir, dir);
- if ( dist < 16 ) {
- dist = 16;
- }
- angle = DotProduct( normal, dir );
- if (angle > 1)
- angle = 1;
- if (angle > 0) {
- if ( light->atten_angletype == LAAT_QUADRATIC ) {
- angle = 1 - angle;
- angle *= angle;
- angle = 1 - angle;
- }
- else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
- angle = 1 - angle;
- angle *= angle * angle;
- angle = 1 - angle;
- }
- }
- if (light->atten_anglescale > 0) {
- angle /= light->atten_anglescale;
- if (angle > 1)
- angle = 1;
- }
- if (light->atten_distscale > 0) {
- distscale = light->atten_distscale;
- }
- else {
- distscale = 1;
- }
- if ( light->atten_disttype == LDAT_NOSCALE ) {
- add = angle;
- }
- else if ( light->atten_disttype == LDAT_LINEAR ) {
- add = angle * light->photons * lightLinearScale - dist * distscale;
- if ( add < 0 ) {
- add = 0;
- }
- } else {
- add = light->photons / ( dist * dist * distscale) * angle;
- }
- if (add <= 1.0)
- continue;
- }
- //
- k = (ds->lightmapNum * LIGHTMAP_HEIGHT + y) * LIGHTMAP_WIDTH + x;
- //if on one of the edges
- n = y * LIGHTMAP_SIZE + x;
- if ((polygonedges[n >> 3] & (1 << (n & 7)) ))
- {
- // multiply 'add' by the relative area being lit of the total visible lightmap pixel area
- //
- // first create a winding for the lightmap pixel
- if (ds->surfaceType == MST_PATCH)
- {
- mesh = test->detailMesh;
- if (y-ds->lightmapY >= mesh->height-1)
- _printf("y outside mesh\n");
- if (x-ds->lightmapX >= mesh->width-1)
- _printf("x outside mesh\n");
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]);
- VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]);
- VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]);
- VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]);
- w.numpoints = 4;
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]);
- VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]);
- VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]);
- VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]);
- VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]);
- VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]);
- w.numpoints = 4;
- }
- //
- // take the visible area of the lightmap pixel into account
- //
- //area = WindingArea(&w);
- area = lightmappixelarea[k];
- if (area <= 0)
- continue;
- // chop the lightmap pixel winding with the light volume
- for (i = 0; i < volume->numplanes; i++)
- {
- //if totally on the back
- if (VS_ChopWinding(&w, &volume->planes[i], 0) == SIDE_BACK)
- break;
- }
- // if the lightmap pixel is partly inside the light volume
- if (i >= volume->numplanes)
- {
- insidearea = WindingArea(&w);
- if (insidearea <= 0)
- i = 0;
- add = add * insidearea / area;
- }
- else
- {
- //DebugNet_DrawWinding(&w, 2);
- continue; // this shouldn't happen
- }
- }
- // get the light filter from all the translucent surfaces the light volume went through
- VS_GetFilter(light, volume, base, filter);
- //
- color = &lightFloats[k*3];
- color[0] += add * light->color[0] * filter[0];
- color[1] += add * light->color[1] * filter[1];
- color[2] += add * light->color[2] * filter[2];
- }
- }
-
- MutexUnlock(test->mutex);
-}
-
-#endif
-
-/*
-=============
-VS_SplitLightVolume
-=============
-*/
-int VS_SplitLightVolume(lightvolume_t *volume, lightvolume_t *back, plane_t *split, float epsilon)
-{
- lightvolume_t f, b;
- vec_t dists[128];
- int sides[128];
- int counts[3];
- vec_t dot;
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
-
- counts[0] = counts[1] = counts[2] = 0;
-
- // determine sides for each point
- for (i = 0; i < volume->numplanes; i++)
- {
- dot = DotProduct (volume->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > epsilon)
- sides[i] = SIDE_FRONT;
- else if (dot < -epsilon)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
-
- if (!counts[1])
- return 0; // completely on front side
-
- if (!counts[0])
- return 1; // completely on back side
-
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- f.numplanes = 0;
- b.numplanes = 0;
-
- for (i = 0; i < volume->numplanes; i++)
- {
- p1 = volume->points[i];
-
- if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VS_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return 0; // can't chop -- fall back to original
- }
- if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VS_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return 0; // can't chop -- fall back to original
- }
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy(p1, f.points[f.numplanes]);
- VectorCopy(p1, b.points[b.numplanes]);
- if (sides[i+1] == SIDE_BACK)
- {
- f.planes[f.numplanes] = *split;
- b.planes[b.numplanes] = volume->planes[i];
- }
- else if (sides[i+1] == SIDE_FRONT)
- {
- f.planes[f.numplanes] = volume->planes[i];
- b.planes[b.numplanes] = *split;
- VectorInverse(b.planes[b.numplanes].normal);
- b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
- }
- else //this shouldn't happen
- {
- f.planes[f.numplanes] = *split;
- b.planes[b.numplanes] = *split;
- VectorInverse(b.planes[b.numplanes].normal);
- b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
- }
- f.numplanes++;
- b.numplanes++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, f.points[f.numplanes]);
- f.planes[f.numplanes] = volume->planes[i];
- f.numplanes++;
- }
- if (sides[i] == SIDE_BACK)
- {
- VectorCopy (p1, b.points[b.numplanes]);
- b.planes[b.numplanes] = volume->planes[i];
- b.numplanes++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VS_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return 0; // can't chop -- fall back to original
- }
- if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
- {
- _printf("WARNING: VS_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
- return 0; // can't chop -- fall back to original
- }
-
- // generate a split point
- p2 = volume->points[(i+1)%volume->numplanes];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, f.points[f.numplanes]);
- VectorCopy(mid, b.points[b.numplanes]);
- if (sides[i+1] == SIDE_BACK)
- {
- f.planes[f.numplanes] = *split;
- b.planes[b.numplanes] = volume->planes[i];
- }
- else
- {
- f.planes[f.numplanes] = volume->planes[i];
- b.planes[b.numplanes] = *split;
- VectorInverse(b.planes[b.numplanes].normal);
- b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
- }
- f.numplanes++;
- b.numplanes++;
- }
- memcpy(volume->points, f.points, sizeof(vec3_t) * f.numplanes);
- memcpy(volume->planes, f.planes, sizeof(plane_t) * f.numplanes);
- volume->numplanes = f.numplanes;
- memcpy(back->points, b.points, sizeof(vec3_t) * b.numplanes);
- memcpy(back->planes, b.planes, sizeof(plane_t) * b.numplanes);
- back->numplanes = b.numplanes;
-
- return 2;
-}
-
-/*
-=============
-VS_PlaneForEdgeToWinding
-=============
-*/
-void VS_PlaneForEdgeToWinding(vec3_t p1, vec3_t p2, winding_t *w, int windingonfront, plane_t *plane)
-{
- int i, j;
- float length, d;
- vec3_t v1, v2;
-
- VectorSubtract(p2, p1, v1);
- for (i = 0; i < w->numpoints; i++)
- {
- VectorSubtract (w->points[i], p1, v2);
-
- plane->normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
- plane->normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
- plane->normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
-
- // if points don't make a valid plane, skip it
- length = plane->normal[0] * plane->normal[0]
- + plane->normal[1] * plane->normal[1]
- + plane->normal[2] * plane->normal[2];
-
- if (length < ON_EPSILON)
- continue;
-
- length = 1/sqrt(length);
-
- plane->normal[0] *= length;
- plane->normal[1] *= length;
- plane->normal[2] *= length;
-
- plane->dist = DotProduct (w->points[i], plane->normal);
- //
- for (j = 0; j < w->numpoints; j++)
- {
- if (j == i)
- continue;
- d = DotProduct(w->points[j], plane->normal) - plane->dist;
- if (windingonfront)
- {
- if (d < -ON_EPSILON)
- break;
- }
- else
- {
- if (d > ON_EPSILON)
- break;
- }
- }
- if (j >= w->numpoints)
- return;
- }
-}
-
-/*
-=============
-VS_R_CastLightAtSurface
-=============
-*/
-void VS_R_FloodLight(vsound_t *light, lightvolume_t *volume, int cluster, int firstportal);
-
-void VS_R_CastLightAtSurface(vsound_t *light, lightvolume_t *volume)
-{
- lsurfaceTest_t *test;
- int i, n;
-
- // light the surface with this volume
- VS_LightSurfaceWithVolume(volume->surfaceNum, volume->facetNum, light, volume);
- //
- test = lsurfaceTest[ volume->surfaceNum ];
- // if this is not a translucent surface
- if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) && !(test->shader->contents & CONTENTS_TRANSLUCENT))
- return;
- //
- if (volume->numtransFacets >= MAX_TRANSLUCENTFACETS)
- Error("a light valume went through more than %d translucent facets", MAX_TRANSLUCENTFACETS);
- //add this translucent surface to the list
- volume->transSurfaces[volume->numtransFacets] = volume->surfaceNum;
- volume->transFacets[volume->numtransFacets] = volume->facetNum;
- volume->numtransFacets++;
- //clear the tested facets except the translucent ones
- memset(volume->facetTested, 0, sizeof(volume->facetTested));
- for (i = 0; i < volume->numtransFacets; i++)
- {
- test = lsurfaceTest[ volume->transSurfaces[i] ];
- n = test->facets[volume->transFacets[i]].num;
- volume->facetTested[n >> 3] |= 1 << (n & 7);
- }
- memset(volume->clusterTested, 0, sizeof(volume->clusterTested));
- volume->endplane = volume->farplane;
- volume->surfaceNum = -1;
- volume->facetNum = 0;
- VS_R_FloodLight(light, volume, volume->cluster, 0);
- if (volume->surfaceNum >= 0)
- {
- VS_R_CastLightAtSurface(light, volume);
- }
-}
-
-/*
-=============
-VS_R_SplitLightVolume
-=============
-*/
-static int numvolumes = 0;
-
-int VS_R_SplitLightVolume(vsound_t *light, lightvolume_t *volume, plane_t *split, int cluster, int firstportal)
-{
- lightvolume_t back;
- int res;
-
- //
- res = VS_SplitLightVolume(volume, &back, split, 0.1);
- // if the volume was split
- if (res == 2)
- {
- memcpy(back.clusterTested, volume->clusterTested, sizeof(back.clusterTested));
- memcpy(back.facetTested, volume->facetTested, sizeof(back.facetTested));
- back.num = numvolumes++;
- back.endplane = volume->endplane;
- back.surfaceNum = volume->surfaceNum;
- back.facetNum = volume->facetNum;
- back.type = volume->type;
- back.cluster = volume->cluster;
- back.farplane = volume->farplane;
- if (volume->numtransFacets > 0)
- {
- memcpy(back.transFacets, volume->transFacets, sizeof(back.transFacets));
- memcpy(back.transSurfaces, volume->transSurfaces, sizeof(back.transSurfaces));
- }
- back.numtransFacets = volume->numtransFacets;
- //
- // flood the volume at the back of the split plane
- VS_R_FloodLight(light, &back, cluster, firstportal);
- // if the back volume hit a surface
- if (back.surfaceNum >= 0)
- {
- VS_R_CastLightAtSurface(light, &back);
- }
- }
- return res;
-}
-
-/*
-=============
-VS_R_FloodLight
-=============
-*/
-void VS_R_FloodLight(vsound_t *light, lightvolume_t *volume, int cluster, int firstportal)
-{
- int i, j, k, res, surfaceNum, backfaceculled, testculled;
- float d;
- winding_t winding, tmpwinding;
- lleaf_t *leaf;
- lportal_t *p;
- lsurfaceTest_t *test;
- lFacet_t *facet;
- vec3_t dir1, dir2;
- plane_t plane;
-
- // DebugNet_RemoveAllPolys();
- // VS_DrawLightVolume(light, volume);
-
- // if the first portal is not zero then we've checked all occluders in this leaf already
- if (firstportal == 0)
- {
- // check all potential occluders in this leaf
- for (i = 0; i < leafs[cluster].numSurfaces; i++)
- {
- surfaceNum = clustersurfaces[leafs[cluster].firstSurface + i];
- //
- test = lsurfaceTest[ surfaceNum ];
- if ( !test )
- continue;
- //
- testculled = qfalse;
- // use surface as an occluder
- for (j = 0; j < test->numFacets; j++)
- {
- // use each facet as an occluder
- facet = &test->facets[j];
- //
- // memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints);
- // winding.numpoints = facet->numpoints;
- // DebugNet_DrawWinding(&winding, 5);
- //
- // if the facet was tested already
- if ( volume->facetTested[facet->num >> 3] & (1 << (facet->num & 7)) )
- continue;
- volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
- // backface culling for planar surfaces
- backfaceculled = qfalse;
- if (!test->patch && !test->trisoup)
- {
- if (volume->type == VOLUME_NORMAL)
- {
- // facet backface culling
- d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist;
- if (d < 0)
- {
- // NOTE: this doesn't work too great because of sometimes very bad tesselation
- // of surfaces that are supposed to be flat
- // FIXME: to work around this problem we should make sure that all facets
- // created from planar surfaces use the lightmapVecs normal vector
- /*
- if ( !test->shader->twoSided )
- {
- // skip all other facets of this surface as well because they are in the same plane
- for (k = 0; k < test->numFacets; k++)
- {
- facet = &test->facets[k];
- volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
- }
- }*/
- backfaceculled = qtrue;
- }
- }
- else
- {
- // FIXME: if all light source winding points are at the back of the facet
- // plane then backfaceculled = qtrue
- }
- }
- else // backface culling per facet for patches and triangle soups
- {
- if (volume->type == VOLUME_NORMAL)
- {
- // facet backface culling
- d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist;
- if (d < 0)
- backfaceculled = qtrue;
- }
- else
- {
- // FIXME: if all light source winding points are at the back of the facet
- // plane then backfaceculled = qtrue
- }
- }
- /* chopping does this already
- // check if this facet is totally or partly in front of the volume end plane
- for (k = 0; k < facet->numpoints; k++)
- {
- d = DotProduct(volume->endplane.normal, facet->points[k]) - volume->endplane.dist;
- if (d > ON_EPSILON)
- break;
- }
- // if this facet is outside the light volume
- if (k >= facet->numpoints)
- continue;
- */
- //
- if (backfaceculled)
- {
- // if the facet is not two sided
- if ( !nobackfaceculling && !test->shader->twoSided )
- continue;
- // flip the winding
- for (k = 0; k < facet->numpoints; k++)
- VectorCopy(facet->points[k], winding.points[facet->numpoints - k - 1]);
- winding.numpoints = facet->numpoints;
- }
- else
- {
- memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints);
- winding.numpoints = facet->numpoints;
- }
- //
- if (!testculled)
- {
- testculled = qtrue;
- // fast check if the surface sphere is totally behind the volume end plane
- d = DotProduct(volume->endplane.normal, test->origin) - volume->endplane.dist;
- if (d < -test->radius)
- {
- for (k = 0; k < test->numFacets; k++)
- {
- facet = &test->facets[k];
- volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
- }
- break;
- }
- for (k = 0; k < volume->numplanes; k++)
- {
- d = DotProduct(volume->planes[k].normal, test->origin) - volume->planes[k].dist;
- if (d < - test->radius)
- {
- for (k = 0; k < test->numFacets; k++)
- {
- facet = &test->facets[k];
- volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
- }
- break;
- }
- }
- if (k < volume->numplanes)
- break;
- }
- //NOTE: we have to chop the facet winding with the volume end plane because
- // the faces in Q3 are not stitched together nicely
- res = VS_ChopWinding(&winding, &volume->endplane, 0.01);
- // if the facet is on or at the back of the volume end plane
- if (res == SIDE_BACK || res == SIDE_ON)
- continue;
- // check if the facet winding is totally or partly inside the light volume
- memcpy(&tmpwinding, &winding, sizeof(winding_t));
- for (k = 0; k < volume->numplanes; k++)
- {
- res = VS_ChopWinding(&tmpwinding, &volume->planes[k], 0.01);
- if (res == SIDE_BACK || res == SIDE_ON)
- break;
- }
- // if no part of the light volume is occluded by this facet
- if (k < volume->numplanes)
- continue;
- //
- for (k = 0; k < winding.numpoints; k++)
- {
- if (volume->type == VOLUME_DIRECTED)
- {
- VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1);
- CrossProduct(light->normal, dir1, plane.normal);
- VectorNormalize(plane.normal, plane.normal);
- plane.dist = DotProduct(plane.normal, winding.points[k]);
- }
- else
- {
- VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1);
- VectorSubtract(light->origin, winding.points[k], dir2);
- CrossProduct(dir1, dir2, plane.normal);
- VectorNormalize(plane.normal, plane.normal);
- plane.dist = DotProduct(plane.normal, winding.points[k]);
- }
- res = VS_R_SplitLightVolume(light, volume, &plane, cluster, 0);
- if (res == 1)
- break; //the facet wasn't really inside the volume
- }
- if (k >= winding.numpoints)
- {
- volume->endplane = facet->plane;
- if (backfaceculled)
- {
- VectorInverse(volume->endplane.normal);
- volume->endplane.dist = -volume->endplane.dist;
- }
- volume->surfaceNum = surfaceNum;
- volume->facetNum = j;
- }
- }
- }
- }
- // we've tested all occluders in this cluster
- volume->clusterTested[cluster >> 3] |= 1 << (cluster & 7);
- // flood light through the portals of the current leaf
- leaf = &leafs[cluster];
- for (i = firstportal; i < leaf->numportals; i++)
- {
- p = leaf->portals[i];
- //
- // memcpy(&winding, p->winding, sizeof(winding_t));
- // DebugNet_DrawWinding(&winding, 5);
- // if already flooded into the cluster this portal leads to
- if ( volume->clusterTested[p->leaf >> 3] & (1 << (p->leaf & 7)) )
- continue;
- //
- if (volume->type == VOLUME_NORMAL)
- {
- // portal backface culling
- d = DotProduct(light->origin, p->plane.normal) - p->plane.dist;
- if (d > 0) // portal plane normal points into neighbour cluster
- continue;
- }
- else
- {
- // FIXME: if all light source winding points are at the back of this portal
- // plane then there's no need to flood through
- }
- // check if this portal is totally or partly in front of the volume end plane
- // fast check with portal sphere
- d = DotProduct(volume->endplane.normal, p->origin) - volume->endplane.dist;
- if (d < -p->radius)
- continue;
- for (j = 0; j < p->winding->numpoints; j++)
- {
- d = DotProduct(volume->endplane.normal, p->winding->points[j]) - volume->endplane.dist;
- if (d > -0.01)
- break;
- }
- // if this portal is totally behind the light volume end plane
- if (j >= p->winding->numpoints)
- continue;
- //distance from point light to portal
- d = DotProduct(p->plane.normal, light->origin) - p->plane.dist;
- // only check if a point light is Not *on* the portal
- if (volume->type != VOLUME_NORMAL || fabs(d) > 0.1)
- {
- // check if the portal is partly or totally inside the light volume
- memcpy(&winding, p->winding, sizeof(winding_t));
- for (j = 0; j < volume->numplanes; j++)
- {
- res = VS_ChopWinding(&winding, &volume->planes[j], 0.01);
- if (res == SIDE_BACK || res == SIDE_ON)
- break;
- }
- // if the light volume does not go through this portal at all
- if (j < volume->numplanes)
- continue;
- }
- // chop the light volume with the portal
- for (k = 0; k < p->winding->numpoints; k++)
- {
- if (volume->type == VOLUME_DIRECTED)
- {
- VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1);
- CrossProduct(light->normal, dir1, plane.normal);
- VectorNormalize(plane.normal, plane.normal);
- plane.dist = DotProduct(plane.normal, p->winding->points[k]);
- }
- else
- {
- VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1);
- VectorSubtract(light->origin, p->winding->points[k], dir2);
- CrossProduct(dir1, dir2, plane.normal);
- VectorNormalize(plane.normal, plane.normal);
- plane.dist = DotProduct(plane.normal, p->winding->points[k]);
- }
- res = VS_R_SplitLightVolume(light, volume, &plane, cluster, i+1);
- if (res == 1)
- break; //volume didn't really go through the portal
- }
- // if the light volume went through the portal
- if (k >= p->winding->numpoints)
- {
- // flood through the portal
- VS_R_FloodLight(light, volume, p->leaf, 0);
- }
- }
-}
-
-/*
-=============
-VS_R_FloodAreaSpotLight
-=============
-*/
-void VS_FloodAreaSpotLight(vsound_t *light, winding_t *w, int leafnum)
-{
-}
-
-/*
-=============
-VS_R_SubdivideAreaSpotLight
-=============
-*/
-void VS_R_SubdivideAreaSpotLight(vsound_t *light, int nodenum, winding_t *w)
-{
- int leafnum, res;
- dnode_t *node;
- dplane_t *plane;
- winding_t back;
- plane_t split;
-
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
-
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VS_SplitWinding (w, &back, &split, 0.1);
-
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- memcpy(&back, w, sizeof(winding_t));
- VS_R_SubdivideAreaSpotLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- else
- {
- VS_R_SubdivideAreaSpotLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- if (dleafs[leafnum].cluster != -1)
- {
- VS_FloodAreaSpotLight(light, w, leafnum);
- }
-}
-
-/*
-=============
-VS_R_FloodRadialAreaLight
-=============
-*/
-void VS_FloodRadialAreaLight(vsound_t *light, winding_t *w, int leafnum)
-{
-}
-
-/*
-=============
-VS_R_SubdivideRadialAreaLight
-=============
-*/
-void VS_R_SubdivideRadialAreaLight(vsound_t *light, int nodenum, winding_t *w)
-{
- int leafnum, res;
- dnode_t *node;
- dplane_t *plane;
- winding_t back;
- plane_t split;
-
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
-
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VS_SplitWinding (w, &back, &split, 0.1);
-
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- memcpy(&back, w, sizeof(winding_t));
- VS_R_SubdivideRadialAreaLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- else
- {
- VS_R_SubdivideRadialAreaLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- if (dleafs[leafnum].cluster != -1)
- {
- VS_FloodRadialAreaLight(light, w, leafnum);
- }
-}
-
-/*
-=============
-VS_R_FloodDirectedLight
-=============
-*/
-void VS_FloodDirectedLight(vsound_t *light, winding_t *w, int leafnum)
-{
- int i;
- float dist;
- lightvolume_t volume;
- vec3_t dir;
-
- if (light->atten_disttype == LDAT_NOSCALE)
- {
- // light travels without decrease in intensity over distance
- dist = MAX_WORLD_COORD;
- }
- else
- {
- if ( light->atten_disttype == LDAT_LINEAR )
- dist = light->photons * lightLinearScale;
- else
- dist = sqrt(light->photons);
- }
-
- memset(&volume, 0, sizeof(lightvolume_t));
- for (i = 0; i < w->numpoints; i++)
- {
- VectorMA(w->points[i], dist, light->normal, volume.points[i]);
- VectorSubtract(w->points[(i+1)%w->numpoints], w->points[i], dir);
- CrossProduct(light->normal, dir, volume.planes[i].normal);
- VectorNormalize(volume.planes[i].normal, volume.planes[i].normal);
- volume.planes[i].dist = DotProduct(volume.planes[i].normal, w->points[i]);
- }
- volume.numplanes = w->numpoints;
- VectorCopy(light->normal, volume.endplane.normal);
- VectorInverse(volume.endplane.normal);
- volume.endplane.dist = DotProduct(volume.endplane.normal, volume.points[0]);
- volume.farplane = volume.endplane;
- volume.surfaceNum = -1;
- volume.type = VOLUME_DIRECTED;
- volume.cluster = dleafs[leafnum].cluster;
- VS_R_FloodLight(light, &volume, volume.cluster, 0);
- if (volume.surfaceNum >= 0)
- {
- VS_R_CastLightAtSurface(light, &volume);
- }
-}
-
-/*
-=============
-VS_R_SubdivideDirectedAreaLight
-=============
-*/
-void VS_R_SubdivideDirectedAreaLight(vsound_t *light, int nodenum, winding_t *w)
-{
- int leafnum, res;
- dnode_t *node;
- dplane_t *plane;
- winding_t back;
- plane_t split;
-
- while(nodenum >= 0)
- {
- node = &dnodes[nodenum];
- plane = &dplanes[node->planeNum];
-
- VectorCopy(plane->normal, split.normal);
- split.dist = plane->dist;
- res = VS_SplitWinding (w, &back, &split, 0.1);
-
- if (res == SIDE_FRONT)
- {
- nodenum = node->children[0];
- }
- else if (res == SIDE_BACK)
- {
- nodenum = node->children[1];
- }
- else if (res == SIDE_ON)
- {
- memcpy(&back, w, sizeof(winding_t));
- VS_R_SubdivideDirectedAreaLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- else
- {
- VS_R_SubdivideDirectedAreaLight(light, node->children[1], &back);
- nodenum = node->children[0];
- }
- }
- leafnum = -nodenum - 1;
- if (dleafs[leafnum].cluster != -1)
- {
- VS_FloodDirectedLight(light, w, leafnum);
- }
-}
-
-/*
-=============
-VS_FloodLight
-=============
-*/
-void VS_FloodLight(vsound_t *light)
-{
- lightvolume_t volume;
- dleaf_t *leaf;
- int leafnum, i, j, k, dir[2][4] = {{1, 1, -1, -1}, {1, -1, -1, 1}};
- float a, step, dist, radius, windingdist;
- vec3_t vec, r, p, temp;
- winding_t winding;
-
- switch(light->type)
- {
- case LIGHT_POINTRADIAL:
- {
- // source is a point
- // light radiates in all directions
- // creates sharp shadows
- //
- // create 6 volumes shining in the axis directions
- // what about: 4 tetrahedrons instead?
- //
- if ( light->atten_disttype == LDAT_LINEAR )
- dist = light->photons * lightLinearScale;
- else
- dist = sqrt(light->photons);
- //always put the winding at a large distance to avoid epsilon issues
- windingdist = MAX_WORLD_COORD;
- if (dist > windingdist)
- windingdist = dist;
- //
- leafnum = VS_LightLeafnum(light->origin);
- leaf = &dleafs[leafnum];
- if (leaf->cluster == -1)
- {
- light->insolid = qtrue;
- break;
- }
- // for each axis
- for (i = 0; i < 3; i++)
- {
- // for both directions on the axis
- for (j = -1; j <= 1; j += 2)
- {
- memset(&volume, 0, sizeof(lightvolume_t));
- volume.numplanes = 0;
- for (k = 0; k < 4; k ++)
- {
- volume.points[volume.numplanes][i] = light->origin[i] + j * windingdist;
- volume.points[volume.numplanes][(i+1)%3] = light->origin[(i+1)%3] + dir[0][k] * windingdist;
- volume.points[volume.numplanes][(i+2)%3] = light->origin[(i+2)%3] + dir[1][k] * windingdist;
- volume.numplanes++;
- }
- if (j >= 0)
- {
- VectorCopy(volume.points[0], temp);
- VectorCopy(volume.points[2], volume.points[0]);
- VectorCopy(temp, volume.points[2]);
- }
- for (k = 0; k < volume.numplanes; k++)
- {
- VS_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]);
- }
- VectorCopy(light->origin, temp);
- temp[i] += (float) j * dist;
- VectorClear(volume.endplane.normal);
- volume.endplane.normal[i] = -j;
- volume.endplane.dist = DotProduct(volume.endplane.normal, temp); //DotProduct(volume.endplane.normal, volume.points[0]);
- volume.farplane = volume.endplane;
- volume.cluster = leaf->cluster;
- volume.surfaceNum = -1;
- volume.type = VOLUME_NORMAL;
- //
- memset(volume.facetTested, 0, sizeof(volume.facetTested));
- memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
- VS_R_FloodLight(light, &volume, leaf->cluster, 0);
- if (volume.surfaceNum >= 0)
- {
- VS_R_CastLightAtSurface(light, &volume);
- }
- }
- }
- break;
- }
- case LIGHT_POINTSPOT:
- {
- // source is a point
- // light is targetted
- // creates sharp shadows
- //
- // what about using brushes to shape spot lights? that'd be pretty cool
- //
- if ( light->atten_disttype == LDAT_LINEAR )
- dist = light->photons * lightLinearScale;
- else
- dist = sqrt(light->photons);
- dist *= 2;
- //
- windingdist = 4096;
- if (dist > windingdist)
- windingdist = dist;
- //take 8 times the cone radius because the spotlight also lights outside the cone
- radius = 8 * windingdist * light->radiusByDist;
- //
- memset(&volume, 0, sizeof(lightvolume_t));
- leafnum = VS_LightLeafnum(light->origin);
- leaf = &dleafs[leafnum];
- if (leaf->cluster == -1)
- {
- light->insolid = qtrue;
- break;
- }
- //
- VectorClear(vec);
- for (i = 0; i < 3; i++)
- {
- if (light->normal[i] > -0.9 && light->normal[i] < 0.9)
- {
- vec[i] = 1;
- break;
- }
- }
- CrossProduct(light->normal, vec, r);
- VectorScale(r, radius, p);
- volume.numplanes = 0;
- step = 45;
- for (a = step / 2; a < 360 + step / 2; a += step)
- {
- RotatePointAroundVector(volume.points[volume.numplanes], light->normal, p, a);
- VectorAdd(light->origin, volume.points[volume.numplanes], volume.points[volume.numplanes]);
- VectorMA(volume.points[volume.numplanes], windingdist, light->normal, volume.points[volume.numplanes]);
- volume.numplanes++;
- }
- for (i = 0; i < volume.numplanes; i++)
- {
- VS_PlaneFromPoints(&volume.planes[i], light->origin, volume.points[(i+1)%volume.numplanes], volume.points[i]);
- }
- VectorMA(light->origin, dist, light->normal, temp);
- VectorCopy(light->normal, volume.endplane.normal);
- VectorInverse(volume.endplane.normal);
- volume.endplane.dist = DotProduct(volume.endplane.normal, temp);//DotProduct(volume.endplane.normal, volume.points[0]);
- volume.farplane = volume.endplane;
- volume.cluster = leaf->cluster;
- volume.surfaceNum = -1;
- volume.type = VOLUME_NORMAL;
- //
- memset(volume.facetTested, 0, sizeof(volume.facetTested));
- memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
- VS_R_FloodLight(light, &volume, leaf->cluster, 0);
- if (volume.surfaceNum >= 0)
- {
- VS_R_CastLightAtSurface(light, &volume);
- }
- break;
- }
- case LIGHT_POINTFAKESURFACE:
- {
- float value;
- int n, axis;
- vec3_t v, vecs[2];
-
- if ( light->atten_disttype == LDAT_LINEAR )
- dist = light->photons * lightLinearScale;
- else
- dist = sqrt(light->photons);
- //always put the winding at a large distance to avoid epsilon issues
- windingdist = 4096;
- if (dist > windingdist)
- windingdist = dist;
- //
- VectorMA(light->origin, 0.1, light->normal, light->origin);
- //
- leafnum = VS_LightLeafnum(light->origin);
- leaf = &dleafs[leafnum];
- if (leaf->cluster == -1)
- {
- light->insolid = qtrue;
- break;
- }
- value = 0;
- for (i = 0; i < 3; i++)
- {
- if (fabs(light->normal[i]) > value)
- {
- value = fabs(light->normal[i]);
- axis = i;
- }
- }
- for (i = 0; i < 2; i++)
- {
- VectorClear(v);
- v[(axis + 1 + i) % 3] = 1;
- CrossProduct(light->normal, v, vecs[i]);
- }
- //cast 4 volumes at the front of the surface
- for (i = -1; i <= 1; i += 2)
- {
- for (j = -1; j <= 1; j += 2)
- {
- for (n = 0; n < 2; n++)
- {
- memset(&volume, 0, sizeof(lightvolume_t));
- volume.numplanes = 3;
- VectorMA(light->origin, i * windingdist, vecs[0], volume.points[(i == j) == n]);
- VectorMA(light->origin, j * windingdist, vecs[1], volume.points[(i != j) == n]);
- VectorMA(light->origin, windingdist, light->normal, volume.points[2]);
- for (k = 0; k < volume.numplanes; k++)
- {
- VS_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]);
- }
- VS_PlaneFromPoints(&volume.endplane, volume.points[0], volume.points[1], volume.points[2]);
- VectorMA(light->origin, dist, light->normal, temp);
- volume.endplane.dist = DotProduct(volume.endplane.normal, temp);
- if (DotProduct(light->origin, volume.endplane.normal) - volume.endplane.dist > 0)
- break;
- }
- volume.farplane = volume.endplane;
- volume.cluster = leaf->cluster;
- volume.surfaceNum = -1;
- volume.type = VOLUME_NORMAL;
- //
- memset(volume.facetTested, 0, sizeof(volume.facetTested));
- memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
-
- VS_R_FloodLight(light, &volume, leaf->cluster, 0);
- if (volume.surfaceNum >= 0)
- {
- VS_R_CastLightAtSurface(light, &volume);
- }
- }
- }
- break;
- }
- case LIGHT_SURFACEDIRECTED:
- {
- // source is an area defined by a winding
- // the light is unidirectional
- // creates sharp shadows
- // for instance sun light or laser light
- //
- memcpy(&winding, &light->w, sizeof(winding_t));
- VS_R_SubdivideDirectedAreaLight(light, 0, &winding);
- break;
- }
- case LIGHT_SURFACERADIAL:
- {
- // source is an area defined by a winding
- // the light radiates in all directions at the front of the winding plane
- //
- memcpy(&winding, &light->w, sizeof(winding_t));
- VS_R_SubdivideRadialAreaLight(light, 0, &winding);
- break;
- }
- case LIGHT_SURFACESPOT:
- {
- // source is an area defined by a winding
- // light is targetted but not unidirectional
- //
- memcpy(&winding, &light->w, sizeof(winding_t));
- VS_R_SubdivideAreaSpotLight(light, 0, &winding);
- break;
- }
- }
-}
-
-/*
-=============
-VS_FloodLightThread
-=============
-*/
-void VS_FloodLightThread(int num)
-{
- VS_FloodLight(vsounds[num]);
-}
-
-/*
-=============
-VS_TestLightLeafs
-=============
-*/
-void VS_TestLightLeafs(void)
-{
- int leafnum, i;
- vsound_t *light;
- dleaf_t *leaf;
-
- for (i = 0; i < numvsounds; i++)
- {
- light = vsounds[i];
- if (light->type != LIGHT_POINTRADIAL &&
- light->type != LIGHT_POINTSPOT)
- continue;
- leafnum = VS_LightLeafnum(light->origin);
- leaf = &dleafs[leafnum];
- if (leaf->cluster == -1)
- if (light->type == LIGHT_POINTRADIAL)
- qprintf("light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]);
- else if (light->type == LIGHT_POINTSPOT)
- qprintf("spot light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]);
- }
-}
-
-
-/*
-=============
-VS_DoForcedTraceLight
-=============
-*/
-// from light.c
-void TraceLtm( int num );
-
-void VS_DoForcedTraceLight(int num)
-{
- dsurface_t *ds;
- shaderInfo_t *si;
-
- ds = &drawSurfaces[num];
-
- if ( ds->surfaceType == MST_TRIANGLE_SOUP )
- return;
-
- if ( ds->lightmapNum < 0 )
- return;
-
- // always light entity surfaces with the old light algorithm
- if ( !entitySurface[num] )
- {
- si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
-
- if (defaulttracelight)
- {
- if (si->forceVLight)
- return;
- }
- else
- {
- if (!si->forceTraceLight)
- return;
- }
- }
-
- TraceLtm(num);
-}
-
-/*
-=============
-VS_DoForcedTraceLightSurfaces
-=============
-*/
-void VS_DoForcedTraceLightSurfaces(void)
-{
- _printf( "forced trace light\n" );
- RunThreadsOnIndividual( numDrawSurfaces, qtrue, VS_DoForcedTraceLight );
-}
-
-float *oldLightFloats;
-
-/*
-=============
-VS_SurfaceRadiosity
-=============
-*/
-void VS_SurfaceRadiosity( int num ) {
- dsurface_t *ds;
- mesh_t *mesh;
- shaderInfo_t *si;
- lsurfaceTest_t *test;
- int x, y, k;
- vec3_t base, normal;
- float *color, area;
- vsound_t vsound;
-
- ds = &drawSurfaces[num];
-
- if ( ds->lightmapNum < 0 ) {
- return; // doesn't have a lightmap
- }
-
- // vertex-lit triangle model
- if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
- return;
- }
-
- si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
- test = lsurfaceTest[ num ];
-
- if (!test) {
- return;
- }
-
- for (x = 0; x < ds->lightmapWidth; x++) {
- for (y = 0; y < ds->lightmapHeight; y++) {
- //
- k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
- * LIGHTMAP_WIDTH + ds->lightmapX + x;
- area = lightmappixelarea[k];
- if (area <= 0)
- continue;
- //
- if (ds->surfaceType == MST_PATCH)
- {
- mesh = test->detailMesh;
- VectorCopy( mesh->verts[y*mesh->width+x].xyz, base);
- VectorCopy( mesh->verts[y*mesh->width+x].normal, normal);
- }
- else
- {
- VectorMA(ds->lightmapOrigin, (float) x, ds->lightmapVecs[0], base);
- VectorMA(base, (float) y, ds->lightmapVecs[1], base);
- VectorCopy(test->facets[0].plane.normal, normal);
- }
- // create ligth from base
- memset(&vsound, 0, sizeof(vsound_t));
- color = &oldLightFloats[k*3];
- // a few units away from the surface
- VectorMA(base, 5, normal, vsound.origin);
- ColorNormalize(color, vsound.color);
- // ok this is crap
- vsound.photons = VectorLength(color) * 0.05 * lightPointScale / (area * radiosity_scale);
- // what about using a front facing light only ?
- vsound.type = LIGHT_POINTRADIAL;
- // flood the light from this lightmap pixel
- VS_FloodLight(&vsound);
- // only one thread at a time may write to the lightmap of this surface
- MutexLock(test->mutex);
- // don't light the lightmap pixel itself
- lightFloats[k*3] = oldLightFloats[k*3];
- lightFloats[k*3+1] = oldLightFloats[k*3+1];
- lightFloats[k*3+2] = oldLightFloats[k*3+2];
- //
- MutexUnlock(test->mutex);
- }
- }
-}
-
-/*
-=============
-VS_Radiosity
-
-this aint working real well but it's fun to play with.
-=============
-*/
-void VS_Radiosity(void) {
-
- oldLightFloats = lightFloats;
- lightFloats = (float *) malloc(numLightBytes * sizeof(float));
- memcpy(lightFloats, oldLightFloats, numLightBytes * sizeof(float));
- _printf("%7i surfaces\n", numDrawSurfaces);
- RunThreadsOnIndividual( numDrawSurfaces, qtrue, VS_SurfaceRadiosity );
- free(oldLightFloats);
-}
-
-/*
-=============
-VS_LightWorld
-=============
-*/
-void VS_LightWorld(void)
-{
- int i, numcastedvolumes, numvsoundsinsolid;
- float f;
-
- // find the optional world ambient
- GetVectorForKey( &entities[0], "_color", lightAmbientColor );
- f = FloatForKey( &entities[0], "ambient" );
- VectorScale( lightAmbientColor, f, lightAmbientColor );
- /*
- _printf("\r%6d lights out of %d", 0, numvsounds);
- for (i = 0; i < numvsounds; i++)
- {
- _printf("\r%6d", i);
- VS_FloodLight(vsounds[i]);
- }
- _printf("\r%6d lights out of %d\n", i, numvsounds);
- */
- _printf("%7i lights\n", numvsounds);
- RunThreadsOnIndividual( numvsounds, qtrue, VS_FloodLightThread );
-
- numcastedvolumes = 0;
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- if (lsurfaceTest[i])
- numcastedvolumes += lsurfaceTest[i]->numvolumes;
- }
- _printf("%7i light volumes casted\n", numcastedvolumes);
- numvsoundsinsolid = 0;
- for (i = 0; i < numvsounds; i++)
- {
- if (vsounds[i]->insolid)
- numvsoundsinsolid++;
- }
- _printf("%7i lights in solid\n", numvsoundsinsolid);
- //
- radiosity_scale = 1;
- for (i = 0; i < radiosity; i++) {
- VS_Radiosity();
- radiosity_scale <<= 1;
- }
- //
- VS_StoreLightmap();
- // redo surfaces with the old light algorithm when needed
- VS_DoForcedTraceLightSurfaces();
-}
-
-/*
-=============
-VS_CreateEntitySpeakers
-=============
-*/
-entity_t *FindTargetEntity( const char *target );
-
-void VS_CreateEntitySpeakers (void)
-{
- int i, c_entityLights;
- vsound_t *dl;
- entity_t *e, *e2;
- const char *name;
- const char *target;
- vec3_t dest;
- const char *_color;
- float intensity;
- int spawnflags;
-
- //
- c_entityLights = 0;
- _printf("Creating entity lights...\n");
- //
- for ( i = 0 ; i < num_entities ; i++ ) {
- e = &entities[i];
- name = ValueForKey (e, "classname");
- if (strncmp (name, "speaker", 7))
- continue;
-
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
-
- spawnflags = FloatForKey (e, "spawnflags");
- if ( spawnflags & 1 ) {
- dl->atten_disttype = LDAT_LINEAR;
- }
- if ( spawnflags & 2 ) {
- dl->atten_disttype = LDAT_NOSCALE;
- }
- if ( spawnflags & 4 ) {
- dl->atten_angletype = LAAT_QUADRATIC;
- }
- if ( spawnflags & 8 ) {
- dl->atten_angletype = LAAT_DOUBLEQUADRATIC;
- }
-
- dl->atten_distscale = FloatForKey(e, "atten_distscale");
- dl->atten_anglescale = FloatForKey(e, "atten_anglescale");
-
- GetVectorForKey (e, "origin", dl->origin);
- dl->style = FloatForKey (e, "_style");
- if (!dl->style)
- dl->style = FloatForKey (e, "style");
- if (dl->style < 0)
- dl->style = 0;
-
- intensity = FloatForKey (e, "light");
- if (!intensity)
- intensity = FloatForKey (e, "_light");
- if (!intensity)
- intensity = 300;
- _color = ValueForKey (e, "_color");
- if (_color && _color[0])
- {
- sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);
- ColorNormalize (dl->color, dl->color);
- }
- else
- dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
-
- intensity = intensity * lightPointScale;
- dl->photons = intensity;
-
- dl->type = LIGHT_POINTRADIAL;
-
- // lights with a target will be spotlights
- target = ValueForKey (e, "target");
-
- if ( target[0] ) {
- float radius;
- float dist;
-
- e2 = FindTargetEntity (target);
- if (!e2) {
- _printf ("WARNING: light at (%i %i %i) has missing target\n",
- (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]);
- } else {
- GetVectorForKey (e2, "origin", dest);
- VectorSubtract (dest, dl->origin, dl->normal);
- dist = VectorNormalize (dl->normal, dl->normal);
- radius = FloatForKey (e, "radius");
- if ( !radius ) {
- radius = 64;
- }
- if ( !dist ) {
- dist = 64;
- }
- dl->radiusByDist = (radius + 16) / dist;
- dl->type = LIGHT_POINTSPOT;
- }
- }
- vsounds[numvsounds++] = dl;
- c_entityLights++;
- }
- _printf("%7i entity lights\n", c_entityLights);
-}
-
-/*
-==================
-VS_SubdivideAreaLight
-==================
-*/
-void VS_SubdivideAreaLight( shaderInfo_t *ls, winding_t *w, vec3_t normal,
- float areaSubdivide, qboolean backsplash ) {
- float area, value, intensity;
- vsound_t *dl, *dl2;
- vec3_t mins, maxs;
- int axis;
- winding_t *front, *back;
- vec3_t planeNormal;
- float planeDist;
-
- if ( !w ) {
- return;
- }
-
- WindingBounds( w, mins, maxs );
-
- // check for subdivision
- for ( axis = 0 ; axis < 3 ; axis++ ) {
- if ( maxs[axis] - mins[axis] > areaSubdivide ) {
- VectorClear( planeNormal );
- planeNormal[axis] = 1;
- planeDist = ( maxs[axis] + mins[axis] ) * 0.5;
- ClipWindingEpsilon ( w, planeNormal, planeDist, ON_EPSILON, &front, &back );
- VS_SubdivideAreaLight( ls, front, normal, areaSubdivide, qfalse );
- VS_SubdivideAreaLight( ls, back, normal, areaSubdivide, qfalse );
- FreeWinding( w );
- return;
- }
- }
-
- // create a light from this
- area = WindingArea (w);
- if ( area <= 0 || area > 20000000 ) {
- return;
- }
-
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
- dl->type = LIGHT_POINTFAKESURFACE;
-
- WindingCenter( w, dl->origin );
- memcpy(dl->w.points, w->points, sizeof(vec3_t) * w->numpoints);
- dl->w.numpoints = w->numpoints;
- VectorCopy ( normal, dl->normal);
- VectorCopy ( normal, dl->plane);
- dl->plane[3] = DotProduct( dl->origin, normal );
-
- value = ls->value;
- intensity = value * area * lightAreaScale;
- VectorAdd( dl->origin, dl->normal, dl->origin );
-
- VectorCopy( ls->color, dl->color );
-
- dl->photons = intensity;
-
- // emitColor is irrespective of the area
- VectorScale( ls->color, value*lightFormFactorValueScale*lightAreaScale, dl->emitColor );
- //
- VectorCopy(dl->emitColor, dl->color);
-
- dl->si = ls;
-
- if ( ls->contents & CONTENTS_FOG ) {
- dl->twosided = qtrue;
- }
-
- vsounds[numvsounds++] = dl;
-
- // optionally create a point backsplash light
- if ( backsplash && ls->backsplashFraction > 0 ) {
-
- dl2 = malloc(sizeof(*dl));
- memset (dl2, 0, sizeof(*dl2));
- dl2->type = LIGHT_POINTRADIAL;
-
- VectorMA( dl->origin, ls->backsplashDistance, normal, dl2->origin );
-
- VectorCopy( ls->color, dl2->color );
-
- dl2->photons = dl->photons * ls->backsplashFraction;
- dl2->si = ls;
-
- vsounds[numvsounds++] = dl2;
- }
-}
-
-/*
-==================
-VS_CreateFakeSurfaceLights
-==================
-*/
-void VS_CreateFakeSurfaceLights( void ) {
- int i, j, side;
- dsurface_t *ds;
- shaderInfo_t *ls;
- winding_t *w;
- lFacet_t *f;
- vsound_t *dl;
- vec3_t origin;
- drawVert_t *dv;
- int c_surfaceLights;
- float lightSubdivide;
- vec3_t normal;
-
-
- c_surfaceLights = 0;
- _printf ("Creating surface lights...\n");
-
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- // see if this surface is light emiting
- ds = &drawSurfaces[i];
-
- ls = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
- if ( ls->value == 0 ) {
- continue;
- }
-
- // determine how much we need to chop up the surface
- if ( ls->lightSubdivide ) {
- lightSubdivide = ls->lightSubdivide;
- } else {
- lightSubdivide = lightDefaultSubdivide;
- }
-
- c_surfaceLights++;
-
- // an autosprite shader will become
- // a point light instead of an area light
- if ( ls->autosprite ) {
- // autosprite geometry should only have four vertexes
- if ( lsurfaceTest[i] ) {
- // curve or misc_model
- f = lsurfaceTest[i]->facets;
- if ( lsurfaceTest[i]->numFacets != 1 || f->numpoints != 4 ) {
- _printf( "WARNING: surface at (%i %i %i) has autosprite shader but isn't a quad\n",
- (int)f->points[0], (int)f->points[1], (int)f->points[2] );
- }
- VectorAdd( f->points[0], f->points[1], origin );
- VectorAdd( f->points[2], origin, origin );
- VectorAdd( f->points[3], origin, origin );
- VectorScale( origin, 0.25, origin );
- } else {
- // normal polygon
- dv = &drawVerts[ ds->firstVert ];
- if ( ds->numVerts != 4 ) {
- _printf( "WARNING: surface at (%i %i %i) has autosprite shader but %i verts\n",
- (int)dv->xyz[0], (int)dv->xyz[1], (int)dv->xyz[2] );
- continue;
- }
-
- VectorAdd( dv[0].xyz, dv[1].xyz, origin );
- VectorAdd( dv[2].xyz, origin, origin );
- VectorAdd( dv[3].xyz, origin, origin );
- VectorScale( origin, 0.25, origin );
- }
-
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
- VectorCopy( origin, dl->origin );
- VectorCopy( ls->color, dl->color );
- dl->photons = ls->value * lightPointScale;
- dl->type = LIGHT_POINTRADIAL;
- vsounds[numvsounds++] = dl;
- continue;
- }
-
- // possibly create for both sides of the polygon
- for ( side = 0 ; side <= ls->twoSided ; side++ ) {
- // create area lights
- if ( lsurfaceTest[i] ) {
- // curve or misc_model
- for ( j = 0 ; j < lsurfaceTest[i]->numFacets ; j++ ) {
- f = lsurfaceTest[i]->facets + j;
- w = AllocWinding( f->numpoints );
- w->numpoints = f->numpoints;
- memcpy( w->points, f->points, f->numpoints * 12 );
-
- VectorCopy( f->plane.normal, normal );
- if ( side ) {
- winding_t *t;
-
- t = w;
- w = ReverseWinding( t );
- FreeWinding( t );
- VectorSubtract( vec3_origin, normal, normal );
- }
- VS_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
- }
- } else {
- // normal polygon
-
- w = AllocWinding( ds->numVerts );
- w->numpoints = ds->numVerts;
- for ( j = 0 ; j < ds->numVerts ; j++ ) {
- VectorCopy( drawVerts[ds->firstVert+j].xyz, w->points[j] );
- }
- VectorCopy( ds->lightmapVecs[2], normal );
- if ( side ) {
- winding_t *t;
-
- t = w;
- w = ReverseWinding( t );
- FreeWinding( t );
- VectorSubtract( vec3_origin, normal, normal );
- }
- VS_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
- }
- }
- }
-
- _printf( "%7i light emitting surfaces\n", c_surfaceLights );
-}
-
-
-/*
-==================
-VS_WindingForBrushSide
-==================
-*/
-winding_t *VS_WindingForBrushSide(dbrush_t *brush, int side, winding_t *w)
-{
- int i, res;
- winding_t *tmpw;
- plane_t plane;
-
- VectorCopy(dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].normal, plane.normal);
- VectorInverse(plane.normal);
- plane.dist = -dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].dist;
- tmpw = BaseWindingForPlane( plane.normal, plane.dist );
- memcpy(w->points, tmpw->points, sizeof(vec3_t) * tmpw->numpoints);
- w->numpoints = tmpw->numpoints;
-
- for (i = 0; i < brush->numSides; i++)
- {
- if (i == side)
- continue;
- VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal);
- VectorInverse(plane.normal);
- plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist;
- res = VS_ChopWinding(w, &plane, 0.1);
- if (res == SIDE_BACK)
- return NULL;
- }
- return w;
-}
-
-/*
-==================
-VS_CreateSkyLights
-==================
-*/
-void VS_CreateSkyLights(void)
-{
- int i, j, c_skyLights;
- dbrush_t *b;
- shaderInfo_t *si;
- dbrushside_t *s;
- vsound_t *dl;
- vec3_t sunColor, sunDir = { 0.45, 0.3, 0.9 };
- float d;
-
- VectorNormalize(sunDir, sunDir);
- VectorInverse(sunDir);
-
- c_skyLights = 0;
- _printf("Creating sky lights...\n");
- // find the sky shader
- for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
- si = ShaderInfoForShader( dshaders[ drawSurfaces[i].shaderNum ].shader );
- if ( si->surfaceFlags & SURF_SKY ) {
- VectorCopy( si->sunLight, sunColor );
- VectorCopy( si->sunDirection, sunDir );
- VectorInverse(sunDir);
- break;
- }
- }
-
- // find the brushes
- for ( i = 0 ; i < numbrushes ; i++ ) {
- b = &dbrushes[i];
- for ( j = 0 ; j < b->numSides ; j++ ) {
- s = &dbrushsides[ b->firstSide + j ];
- if ( dshaders[ s->shaderNum ].surfaceFlags & SURF_SKY ) {
- //if this surface doesn't face in the same direction as the sun
- d = DotProduct(dplanes[ s->planeNum ].normal, sunDir);
- if (d <= 0)
- continue;
- //
- dl = malloc(sizeof(*dl));
- memset (dl, 0, sizeof(*dl));
- VectorCopy(sunColor, dl->color);
- VectorCopy(sunDir, dl->normal);
- VectorCopy(dplanes[ s->planeNum ].normal, dl->plane);
- dl->plane[3] = dplanes[ s->planeNum ].dist;
- dl->type = LIGHT_SURFACEDIRECTED;
- dl->atten_disttype = LDAT_NOSCALE;
- VS_WindingForBrushSide(b, j, &dl->w);
-// DebugNet_DrawWinding(&dl->w, 2);
- //
- vsounds[numvsounds++] = dl;
- c_skyLights++;
- }
- }
- }
- _printf("%7i light emitting sky surfaces\n", c_skyLights);
-}
-
-/*
-==================
-VS_SetPortalSphere
-==================
-*/
-void VS_SetPortalSphere (lportal_t *p)
-{
- int i;
- vec3_t total, dist;
- winding_t *w;
- float r, bestr;
-
- w = p->winding;
- VectorCopy (vec3_origin, total);
- for (i=0 ; i<w->numpoints ; i++)
- {
- VectorAdd (total, w->points[i], total);
- }
-
- for (i=0 ; i<3 ; i++)
- total[i] /= w->numpoints;
-
- bestr = 0;
- for (i=0 ; i<w->numpoints ; i++)
- {
- VectorSubtract (w->points[i], total, dist);
- r = VectorLength (dist);
- if (r > bestr)
- bestr = r;
- }
- VectorCopy (total, p->origin);
- p->radius = bestr;
-}
-
-/*
-==================
-VS_PlaneFromWinding
-==================
-*/
-void VS_PlaneFromWinding (winding_t *w, plane_t *plane)
-{
- vec3_t v1, v2;
-
- //calc plane
- VectorSubtract (w->points[2], w->points[1], v1);
- VectorSubtract (w->points[0], w->points[1], v2);
- CrossProduct (v2, v1, plane->normal);
- VectorNormalize (plane->normal, plane->normal);
- plane->dist = DotProduct (w->points[0], plane->normal);
-}
-
-/*
-==================
-VS_AllocWinding
-==================
-*/
-winding_t *VS_AllocWinding (int points)
-{
- winding_t *w;
- int size;
-
- if (points > MAX_POINTS_ON_WINDING)
- Error ("NewWinding: %i points", points);
-
- size = (int)((winding_t *)0)->points[points];
- w = malloc (size);
- memset (w, 0, size);
-
- return w;
-}
-
-/*
-============
-VS_LoadPortals
-============
-*/
-void VS_LoadPortals (char *name)
-{
- int i, j, hint;
- lportal_t *p;
- lleaf_t *l;
- char magic[80];
- FILE *f;
- int numpoints;
- winding_t *w;
- int leafnums[2];
- plane_t plane;
- //
-
- if (!strcmp(name,"-"))
- f = stdin;
- else
- {
- f = fopen(name, "r");
- if (!f)
- Error ("LoadPortals: couldn't read %s\n",name);
- }
-
- if (fscanf (f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces) != 4)
- Error ("LoadPortals: failed to read header");
- if (strcmp(magic, PORTALFILE))
- Error ("LoadPortals: not a portal file");
-
- _printf ("%6i portalclusters\n", portalclusters);
- _printf ("%6i numportals\n", numportals);
- _printf ("%6i numfaces\n", numfaces);
-
- if (portalclusters >= MAX_CLUSTERS)
- Error ("more than %d clusters in portal file\n", MAX_CLUSTERS);
-
- // each file portal is split into two memory portals
- portals = malloc(2*numportals*sizeof(lportal_t));
- memset (portals, 0, 2*numportals*sizeof(lportal_t));
-
- leafs = malloc(portalclusters*sizeof(lleaf_t));
- memset (leafs, 0, portalclusters*sizeof(lleaf_t));
-
- for (i=0, p=portals ; i<numportals ; i++)
- {
- if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3)
- Error ("LoadPortals: reading portal %i", i);
- if (numpoints > MAX_POINTS_ON_WINDING)
- Error ("LoadPortals: portal %i has too many points", i);
- if ( (unsigned)leafnums[0] > portalclusters
- || (unsigned)leafnums[1] > portalclusters)
- Error ("LoadPortals: reading portal %i", i);
- if (fscanf (f, "%i ", &hint) != 1)
- Error ("LoadPortals: reading hint state");
-
- w = p->winding = VS_AllocWinding (numpoints);
- w->numpoints = numpoints;
-
- for (j=0 ; j<numpoints ; j++)
- {
- double v[3];
- int k;
-
- // scanf into double, then assign to vec_t
- // so we don't care what size vec_t is
- if (fscanf (f, "(%lf %lf %lf ) "
- , &v[0], &v[1], &v[2]) != 3)
- Error ("LoadPortals: reading portal %i", i);
- for (k=0 ; k<3 ; k++)
- w->points[j][k] = v[k];
- }
- fscanf (f, "\n");
-
- // calc plane
- VS_PlaneFromWinding (w, &plane);
-
- // create forward portal
- l = &leafs[leafnums[0]];
- if (l->numportals == MAX_PORTALS_ON_LEAF)
- Error ("Leaf with too many portals");
- l->portals[l->numportals] = p;
- l->numportals++;
-
- p->winding = w;
- VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
- p->plane.dist = -plane.dist;
- p->leaf = leafnums[1];
- VS_SetPortalSphere (p);
- p++;
-
- // create backwards portal
- l = &leafs[leafnums[1]];
- if (l->numportals == MAX_PORTALS_ON_LEAF)
- Error ("Leaf with too many portals");
- l->portals[l->numportals] = p;
- l->numportals++;
-
- p->winding = VS_AllocWinding(w->numpoints);
- p->winding->numpoints = w->numpoints;
- for (j=0 ; j<w->numpoints ; j++)
- {
- VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]);
- }
-
- p->plane = plane;
- p->leaf = leafnums[0];
- VS_SetPortalSphere (p);
- p++;
-
- }
-
- fclose (f);
-}
-
-/*
-============
-VLightMain
-============
-*/
-int VSoundMain (int argc, char **argv) {
- int i;
- double start, end;
- const char *value;
-
- _printf ("----- VLighting ----\n");
-
- for (i=1 ; i<argc ; i++) {
- if (!strcmp(argv[i],"-v")) {
- verbose = qtrue;
- } else if (!strcmp(argv[i],"-threads")) {
- numthreads = atoi (argv[i+1]);
- _printf("num threads = %d\n", numthreads);
- i++;
- } else if (!strcmp(argv[i],"-area")) {
- lightAreaScale *= atof(argv[i+1]);
- _printf ("area light scaling at %f\n", lightAreaScale);
- i++;
- } else if (!strcmp(argv[i],"-point")) {
- lightPointScale *= atof(argv[i+1]);
- _printf ("point light scaling at %f\n", lightPointScale);
- i++;
- } else if (!strcmp(argv[i], "-samplesize")) {
- samplesize = atoi(argv[i+1]);
- if (samplesize < 1) samplesize = 1;
- i++;
- _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize);
- } else if (!strcmp(argv[i], "-nostitching")) {
- nostitching = qtrue;
- _printf("no stitching = true\n");
- } else if (!strcmp(argv[i], "-noalphashading")) {
- noalphashading = qtrue;
- _printf("no alpha shading = true\n");
- } else if (!strcmp(argv[i], "-nocolorshading")) {
- nocolorshading = qtrue;
- _printf("old style alpha shading = true\n");
- } else if (!strcmp(argv[i], "-nobackfaceculling")) {
- nobackfaceculling = qtrue;
- _printf("no backface culling = true\n");
- } else if (!strcmp(argv[i], "-tracelight")) {
- defaulttracelight = qtrue;
- _printf("default trace light = true\n");
- } else if (!strcmp(argv[i], "-radiosity")) {
- radiosity = atoi(argv[i+1]);
- _printf("radiosity = %d\n", radiosity);
- i++;
- } else {
- break;
- }
- }
-
- ThreadSetDefault ();
-
- if (i != argc - 1) {
- _printf("usage: q3map -vsound [-<switch> [-<switch> ...]] <mapname>\n"
- "\n"
- "Switches:\n"
- " v = verbose output\n"
- " threads <X> = set number of threads to X\n"
- " area <V> = set the area light scale to V\n"
- " point <W> = set the point light scale to W\n"
- " novertex = don't calculate vertex lighting\n"
- " nogrid = don't calculate light grid for dynamic model lighting\n"
- " nostitching = no polygon stitching before lighting\n"
- " noalphashading = don't use alpha shading\n"
- " nocolorshading = don't use color alpha shading\n"
- " tracelight = use old light algorithm by default\n"
- " samplesize <N> = set the lightmap pixel size to NxN units\n");
- exit(0);
- }
-
- SetQdirFromPath (argv[i]);
-
-#ifdef _WIN32
- InitPakFile(gamedir, NULL);
-#endif
-
- strcpy (source, ExpandArg(argv[i]));
- StripExtension (source);
- DefaultExtension (source, ".bsp");
-
- LoadShaderInfo();
-
- _printf ("reading %s\n", source);
-
- LoadBSPFile (source);
- ParseEntities();
-
- value = ValueForKey( &entities[0], "gridsize" );
- if (strlen(value)) {
- sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] );
- _printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]);
- }
-
- CountLightmaps();
-
- StripExtension (source);
- DefaultExtension (source, ".prt");
-
- VS_LoadPortals(source);
-
- // set surfaceOrigin
- SetEntityOrigins();
-
- // grid and vertex lighting
- GridAndVertexLighting();
-
-#ifdef DEBUGNET
- DebugNet_Setup();
-#endif
-
- start = clock();
-
- lightFloats = (float *) malloc(numLightBytes * sizeof(float));
- memset(lightFloats, 0, numLightBytes * sizeof(float));
-
- VS_InitSurfacesForTesting();
-
- VS_CalcVisibleLightmapPixelArea();
-
- numvsounds = 0;
- VS_CreateEntitySpeakers();
- VS_CreateFakeSurfaceLights();
- VS_CreateSkyLights();
-
- VS_TestLightLeafs();
-
- VS_LightWorld();
-
-#ifndef LIGHTPOLYS
- StripExtension (source);
- DefaultExtension (source, ".bsp");
- _printf ("writing %s\n", source);
- WriteBSPFile (source);
-#endif
-
- end = clock();
-
- _printf ("%5.2f seconds elapsed\n", (end-start) / CLK_TCK);
-
-#ifdef LIGHTPOLYS
- VS_DrawLightWindings();
-#endif
-
-#ifdef DEBUGNET
- DebugNet_Shutdown();
-#endif
- return 0;
-}
+/*****************************************************************************
+ * name: soundv.c
+ *****************************************************************************/
+
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "bspfile.h"
+#include "imagelib.h"
+#include "threads.h"
+#include "mutex.h"
+#include "scriplib.h"
+
+#include "shaders.h"
+#include "mesh.h"
+
+#ifdef _WIN32
+//Improve floating-point consistency.
+#pragma optimize( "p", on )
+#endif
+
+#ifdef _WIN32
+#include "../libs/pakstuff.h"
+#endif
+
+#define MAX_CLUSTERS 16384
+#define MAX_PORTALS 32768
+#define MAX_FACETS 65536
+#define MAX_LIGHTS 16384
+
+#define LIGHTMAP_SIZE 128
+
+#define LIGHTMAP_PIXELSHIFT 0.5
+
+//#define LIGHTMAP_PATCHSHIFT
+
+#define PORTALFILE "PRT1"
+
+#define ON_EPSILON 0.1
+
+#define VectorSet(v, x, y, z) v[0] = x;v[1] = y;v[2] = z;
+
+typedef struct
+{
+ vec3_t normal;
+ float dist;
+} plane_t;
+
+#define MAX_POINTS_ON_WINDING 64
+//NOTE: whenever this is overflowed parts of lightmaps might end up not being lit
+#define MAX_POINTS_ON_FIXED_WINDING 48
+
+typedef struct
+{
+ int numpoints;
+ vec3_t points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized
+} winding_t;
+
+typedef struct
+{
+ plane_t plane; // normal pointing into neighbor
+ int leaf; // neighbor
+ winding_t *winding;
+ vec3_t origin; // for fast clip testing
+ float radius;
+} lportal_t;
+
+#define MAX_PORTALS_ON_LEAF 128
+typedef struct lleaf_s
+{
+ int numportals;
+ lportal_t *portals[MAX_PORTALS_ON_LEAF];
+ //
+ int numSurfaces;
+ int firstSurface;
+} lleaf_t;
+
+typedef struct lFacet_s
+{
+ int num;
+ plane_t plane;
+ vec3_t points[4]; //
+ int numpoints;
+ float lightmapCoords[4][2];
+ plane_t boundaries[4]; // negative is outside the bounds
+ float textureMatrix[2][4]; // texture coordinates for translucency
+ float lightmapMatrix[2][4]; // lightmap texture coordinates
+ vec3_t mins;
+ int x, y, width, height;
+} lFacet_t;
+
+typedef struct lsurfaceTest_s
+{
+ vec3_t mins, maxs;
+ vec3_t origin;
+ float radius;
+ qboolean patch; // true if this is a patch
+ qboolean trisoup; // true if this is a triangle soup
+ int numFacets;
+ lFacet_t *facets;
+ mesh_t *detailMesh; // detailed mesh with points for each lmp
+ shaderInfo_t *shader; // for translucency
+ mutex_t *mutex;
+ int numvolumes; // number of volumes casted at this surface
+ //
+ int always_tracelight;
+ int always_vsound;
+} lsurfaceTest_t;
+
+//volume types
+#define VOLUME_NORMAL 0
+#define VOLUME_DIRECTED 1
+
+#define MAX_TRANSLUCENTFACETS 32
+
+typedef struct lightvolume_s
+{
+ int num;
+ int cluster; //cluster this light volume started in
+ plane_t endplane; //end plane
+ plane_t farplane; //original end plane
+ vec3_t points[MAX_POINTS_ON_WINDING]; //end winding points
+ plane_t planes[MAX_POINTS_ON_WINDING]; //volume bounding planes
+ int numplanes; //number of volume bounding planes
+ int type; //light volume type
+ //list with translucent surfaces the volume went through
+ int transFacets[MAX_TRANSLUCENTFACETS];
+ int transSurfaces[MAX_TRANSLUCENTFACETS];
+ int numtransFacets;
+ //clusters already tested
+ byte clusterTested[MAX_CLUSTERS/8];
+ //facets already tested
+ byte facetTested[MAX_FACETS/8];
+ int facetNum; //number of the facet blocking the light in this volume
+ int surfaceNum; //number of the surface blocking the light in this volume
+} lightvolume_t;
+
+//light types
+#define LIGHT_POINTRADIAL 1
+#define LIGHT_POINTSPOT 2
+#define LIGHT_POINTFAKESURFACE 3
+#define LIGHT_SURFACEDIRECTED 4
+#define LIGHT_SURFACERADIAL 5
+#define LIGHT_SURFACESPOT 6
+
+//light distance attenuation types
+#define LDAT_QUADRATIC 0
+#define LDAT_LINEAR 1
+#define LDAT_NOSCALE 2
+
+//light angle attenuation types
+#define LAAT_NORMAL 0
+#define LAAT_QUADRATIC 1
+#define LAAT_DOUBLEQUADRATIC 2
+
+typedef struct vsound_s
+{
+ vec3_t origin; //light origin, for point lights
+ winding_t w; //light winding, for area lights
+ vec4_t plane; //light winding plane
+ vec3_t normal; //direction of the light
+ int type; //light type
+ vec3_t color; //light color
+ qboolean twosided; //radiates light at both sides of the winding
+ int style; //light style (not used)
+ int atten_disttype; //light distance attenuation type
+ int atten_angletype; //light angle attenuation type
+ float atten_distscale; //distance attenuation scale
+ float atten_anglescale; //angle attenuation scale
+ float radiusByDist; //radius by distance for spot lights
+ float photons; //emitted photons
+ float intensity; //intensity
+ vec3_t emitColor; //full out-of-gamut value (not used)
+ struct shaderInfo_s *si; //shader info
+ int insolid; //set when light is in solid
+} vsound_t;
+
+static float lightLinearScale = 1.0 / 8000;
+static float lightPointScale = 7500;
+static float lightAreaScale = 0.25;
+static float lightFormFactorValueScale = 3;
+static int lightDefaultSubdivide = 999; // vary by surface size?
+static vec3_t lightAmbientColor;
+
+static int portalclusters, numportals, numfaces;
+static lleaf_t *leafs;
+static lportal_t *portals;
+static int numvsounds = 0;
+static vsound_t *vsounds[MAX_LIGHTS];
+static int nostitching = 0;
+static int noalphashading = 0;
+static int nocolorshading = 0;
+static int nobackfaceculling = 0;
+static int defaulttracelight = 0;
+static int radiosity = 0;
+static int radiosity_scale;
+
+static int clustersurfaces[MAX_MAP_LEAFFACES];
+static int numclustersurfaces = 0;
+static lsurfaceTest_t *lsurfaceTest[MAX_MAP_DRAW_SURFS];
+static int numfacets;
+static float lightmappixelarea[MAX_MAP_LIGHTING/3];
+static float *lightFloats;//[MAX_MAP_LIGHTING];
+
+// from polylib.c
+winding_t *AllocWinding (int points);
+void FreeWinding (winding_t *w);
+void WindingCenter (winding_t *w, vec3_t center);
+void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs);
+vec_t WindingArea (winding_t *w);
+winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist);
+void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist,
+ vec_t epsilon, winding_t **front, winding_t **back);
+winding_t *ReverseWinding (winding_t *w);
+
+// from light.c
+extern char source[1024];
+extern vec3_t surfaceOrigin[ MAX_MAP_DRAW_SURFS ];
+extern int entitySurface[ MAX_MAP_DRAW_SURFS ];
+extern int samplesize;
+extern qboolean patchshadows;
+extern vec3_t gridSize;
+
+float PointToPolygonFormFactor( const vec3_t point, const vec3_t normal, const winding_t *w );
+void ColorToBytes( const float *color, byte *colorBytes );
+void CountLightmaps( void );
+void GridAndVertexLighting( void );
+void SetEntityOrigins( void );
+
+
+//#define DEBUGNET
+
+#ifdef DEBUGNET
+
+#include "l_net.h"
+
+socket_t *debug_socket;
+
+/*
+=====================
+DebugNet_Setup
+=====================
+*/
+void DebugNet_Setup(void)
+{
+ address_t address;
+ int i;
+
+ Net_Setup();
+ Net_StringToAddress("127.0.0.1:28000", &address);
+ for (i = 0; i < 10; i++)
+ {
+ debug_socket = Net_Connect(&address, 28005 + i);
+ if (debug_socket)
+ break;
+ }
+}
+
+/*
+=====================
+DebugNet_Shutdown
+=====================
+*/
+void DebugNet_Shutdown(void)
+{
+ netmessage_t msg;
+
+ if (debug_socket)
+ {
+ NMSG_Clear(&msg);
+ NMSG_WriteByte(&msg, 1);
+ Net_Send(debug_socket, &msg);
+ Net_Disconnect(debug_socket);
+ }
+ debug_socket = NULL;
+ Net_Shutdown();
+}
+
+/*
+=====================
+DebugNet_RemoveAllPolys
+=====================
+*/
+void DebugNet_RemoveAllPolys(void)
+{
+ netmessage_t msg;
+
+ if (!debug_socket)
+ return;
+ NMSG_Clear(&msg);
+ NMSG_WriteByte(&msg, 2); //remove all debug polys
+ Net_Send(debug_socket, &msg);
+}
+
+/*
+====================
+DebugNet_DrawWinding
+=====================
+*/
+void DebugNet_DrawWinding(winding_t *w, int color)
+{
+ netmessage_t msg;
+ int i;
+
+ if (!debug_socket)
+ return;
+ NMSG_Clear(&msg);
+ NMSG_WriteByte(&msg, 0); //draw a winding
+ NMSG_WriteByte(&msg, w->numpoints); //number of points
+ NMSG_WriteLong(&msg, color); //color
+ for (i = 0; i < w->numpoints; i++)
+ {
+ NMSG_WriteFloat(&msg, w->points[i][0]);
+ NMSG_WriteFloat(&msg, w->points[i][1]);
+ NMSG_WriteFloat(&msg, w->points[i][2]);
+ }
+ Net_Send(debug_socket, &msg);
+}
+
+/*
+=====================
+DebugNet_DrawLine
+=====================
+*/
+void DebugNet_DrawLine(vec3_t p1, vec3_t p2, int color)
+{
+ netmessage_t msg;
+
+ if (!debug_socket)
+ return;
+ NMSG_Clear(&msg);
+ NMSG_WriteByte(&msg, 1); //draw a line
+ NMSG_WriteLong(&msg, color); //color
+ NMSG_WriteFloat(&msg, p1[0]);
+ NMSG_WriteFloat(&msg, p1[1]);
+ NMSG_WriteFloat(&msg, p1[2]);
+ NMSG_WriteFloat(&msg, p2[0]);
+ NMSG_WriteFloat(&msg, p2[1]);
+ NMSG_WriteFloat(&msg, p2[2]);
+ Net_Send(debug_socket, &msg);
+}
+
+/*
+=====================
+DebugNet_DrawMesh
+=====================
+*/
+void DebugNet_DrawMesh(mesh_t *mesh)
+{
+ int i, j;
+ float dot;
+ drawVert_t *v1, *v2, *v3, *v4;
+ winding_t winding;
+ plane_t plane;
+ vec3_t d1, d2;
+
+ for ( i = 0 ; i < mesh->width - 1 ; i++ ) {
+ for ( j = 0 ; j < mesh->height - 1 ; j++ ) {
+
+ v1 = mesh->verts + j * mesh->width + i;
+ v2 = v1 + 1;
+ v3 = v1 + mesh->width + 1;
+ v4 = v1 + mesh->width;
+
+ VectorSubtract( v4->xyz, v1->xyz, d1 );
+ VectorSubtract( v3->xyz, v1->xyz, d2 );
+ CrossProduct( d2, d1, plane.normal );
+ if ( VectorNormalize( plane.normal, plane.normal ) != 0 )
+ {
+ plane.dist = DotProduct( v1->xyz, plane.normal );
+ dot = DotProduct(plane.normal, v2->xyz) - plane.dist;
+ if (fabs(dot) < 0.1)
+ {
+ VectorCopy(v1->xyz, winding.points[0]);
+ VectorCopy(v4->xyz, winding.points[1]);
+ VectorCopy(v3->xyz, winding.points[2]);
+ VectorCopy(v2->xyz, winding.points[3]);
+ winding.numpoints = 4;
+ DebugNet_DrawWinding(&winding, 2);
+ continue;
+ }
+ }
+
+ winding.numpoints = 3;
+ VectorCopy(v1->xyz, winding.points[0]);
+ VectorCopy(v4->xyz, winding.points[1]);
+ VectorCopy(v3->xyz, winding.points[2]);
+ DebugNet_DrawWinding(&winding, 2);
+
+ VectorCopy(v1->xyz, winding.points[0]);
+ VectorCopy(v3->xyz, winding.points[1]);
+ VectorCopy(v2->xyz, winding.points[2]);
+ DebugNet_DrawWinding(&winding, 2);
+ }
+ }
+}
+
+/*
+=====================
+VS_DrawLightVolume
+=====================
+*/
+int VS_ChopWinding (winding_t *in, plane_t *split, float epsilon);
+
+void VS_DrawLightVolume(vsound_t *light, lightvolume_t *volume)
+{
+ winding_t w;
+ int i;
+ vec3_t p2, invsound;
+
+ memcpy(w.points, volume->points, volume->numplanes * sizeof(vec3_t));
+ w.numpoints = volume->numplanes;
+ DebugNet_DrawWinding(&w, 2);
+
+ if (volume->type == VOLUME_DIRECTED)
+ {
+ VectorCopy(light->normal, invsound);
+ VectorInverse(invsound);
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ VectorCopy(volume->points[i], w.points[0]);
+ VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[1]);
+ VectorMA(w.points[1], MAX_WORLD_COORD, invsound, w.points[2]);
+ VectorMA(w.points[0], MAX_WORLD_COORD, invsound, w.points[3]);
+ w.numpoints = 4;
+ DebugNet_DrawWinding(&w, 2);
+ VectorMA(volume->points[i], 8, volume->planes[i].normal, p2);
+ DebugNet_DrawLine(volume->points[i], p2, 3);
+ }
+ }
+ else
+ {
+ //
+ VectorCopy(light->origin, w.points[0]);
+ w.numpoints = 3;
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ VectorCopy(volume->points[i], w.points[1]);
+ VectorCopy(volume->points[(i+1) % volume->numplanes], w.points[2]);
+ VS_ChopWinding(&w, &volume->endplane, 0);
+ DebugNet_DrawWinding(&w, 2);
+ VectorMA(volume->points[i], 8, volume->planes[i].normal, p2);
+ DebugNet_DrawLine(volume->points[i], p2, 3);
+ }
+ }
+}
+
+/*
+=============
+VS_DrawLightmapPixel
+=============
+*/
+void VS_DrawLightmapPixel(int surfaceNum, int x, int y, int color)
+{
+ winding_t w;
+ dsurface_t *ds;
+ mesh_t *mesh;
+
+ ds = &drawSurfaces[surfaceNum];
+
+ if (ds->surfaceType == MST_PATCH)
+ {
+ mesh = lsurfaceTest[surfaceNum]->detailMesh;
+ VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]);
+ VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]);
+ VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]);
+ VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]);
+ w.numpoints = 4;
+ }
+ else
+ {
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]);
+ VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]);
+ VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]);
+ VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]);
+ VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]);
+ w.numpoints = 4;
+ }
+ DebugNet_DrawWinding(&w, color);
+}
+
+/*
+============
+VS_DrawPortals
+============
+*/
+void VS_DrawPortals(void)
+{
+ int j;
+ lportal_t *p;
+
+ for (j = 0; j < numportals * 2; j++)
+ {
+ p = portals + j;
+ DebugNet_DrawWinding(p->winding, 1);
+ }
+}
+
+/*
+============
+VS_DrawLeaf
+============
+*/
+void VS_DrawLeaf(int cluster)
+{
+ int i;
+ lleaf_t *leaf;
+ lportal_t *p;
+
+ leaf = &leafs[cluster];
+ for (i = 0; i < leaf->numportals; i++)
+ {
+ p = leaf->portals[i];
+ DebugNet_DrawWinding(p->winding, 1);
+ }
+}
+
+#endif //DEBUGNET
+
+/*
+=============
+VS_SplitWinding
+=============
+*/
+int VS_SplitWinding (winding_t *in, winding_t *back, plane_t *split, float epsilon)
+{
+ vec_t dists[128];
+ int sides[128];
+ int counts[3];
+ vec_t dot;
+ int i, j;
+ vec_t *p1, *p2;
+ vec3_t mid;
+ winding_t out;
+ winding_t *neww;
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+ // determine sides for each point
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ dot = DotProduct (in->points[i], split->normal);
+ dot -= split->dist;
+ dists[i] = dot;
+ if (dot > epsilon)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -epsilon)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+
+ if (!counts[SIDE_BACK])
+ {
+ if (!counts[SIDE_FRONT])
+ return SIDE_ON;
+ else
+ return SIDE_FRONT;
+ }
+
+ if (!counts[SIDE_FRONT])
+ {
+ return SIDE_BACK;
+ }
+
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ neww = &out;
+
+ neww->numpoints = 0;
+ back->numpoints = 0;
+
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ p1 = in->points[i];
+
+ if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VS_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return SIDE_FRONT; // can't chop -- fall back to original
+ }
+ if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VS_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return SIDE_FRONT;
+ }
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy (p1, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ VectorCopy (p1, back->points[back->numpoints]);
+ back->numpoints++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ }
+ if (sides[i] == SIDE_BACK)
+ {
+ VectorCopy (p1, back->points[back->numpoints]);
+ back->numpoints++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VS_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return SIDE_FRONT; // can't chop -- fall back to original
+ }
+
+ if (back->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VS_SplitWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return SIDE_FRONT; // can't chop -- fall back to original
+ }
+
+ // generate a split point
+ p2 = in->points[(i+1)%in->numpoints];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (split->normal[j] == 1)
+ mid[j] = split->dist;
+ else if (split->normal[j] == -1)
+ mid[j] = -split->dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ VectorCopy (mid, back->points[back->numpoints]);
+ back->numpoints++;
+ }
+ memcpy(in, &out, sizeof(winding_t));
+
+ return SIDE_CROSS;
+}
+
+/*
+=====================
+VS_LinkSurfaceIntoCluster
+=====================
+*/
+void VS_LinkSurfaceIntoCluster(int cluster, int surfaceNum)
+{
+ lleaf_t *leaf;
+ int i;
+
+ leaf = &leafs[cluster];
+
+ for (i = 0; i < leaf->numSurfaces; i++)
+ {
+ if (clustersurfaces[leaf->firstSurface + i] == surfaceNum)
+ return;
+ }
+ for (i = numclustersurfaces; i > leaf->firstSurface + leaf->numSurfaces; i--)
+ clustersurfaces[i] = clustersurfaces[i-1];
+ for (i = 0; i < portalclusters; i++)
+ {
+ if (i == cluster)
+ continue;
+ if (leafs[i].firstSurface >= leaf->firstSurface + leaf->numSurfaces)
+ leafs[i].firstSurface++;
+ }
+ clustersurfaces[leaf->firstSurface + leaf->numSurfaces] = surfaceNum;
+ leaf->numSurfaces++;
+ numclustersurfaces++;
+ if (numclustersurfaces >= MAX_MAP_LEAFFACES)
+ Error("MAX_MAP_LEAFFACES");
+}
+
+/*
+=====================
+VS_R_LinkSurface
+=====================
+*/
+void VS_R_LinkSurface(int nodenum, int surfaceNum, winding_t *w)
+{
+ int leafnum, cluster, res;
+ dnode_t *node;
+ dplane_t *plane;
+ winding_t back;
+ plane_t split;
+
+ while(nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+
+ VectorCopy(plane->normal, split.normal);
+ split.dist = plane->dist;
+ res = VS_SplitWinding (w, &back, &split, 0.1);
+
+ if (res == SIDE_FRONT)
+ {
+ nodenum = node->children[0];
+ }
+ else if (res == SIDE_BACK)
+ {
+ nodenum = node->children[1];
+ }
+ else if (res == SIDE_ON)
+ {
+ memcpy(&back, w, sizeof(winding_t));
+ VS_R_LinkSurface(node->children[1], surfaceNum, &back);
+ nodenum = node->children[0];
+ }
+ else
+ {
+ VS_R_LinkSurface(node->children[1], surfaceNum, &back);
+ nodenum = node->children[0];
+ }
+ }
+ leafnum = -nodenum - 1;
+ cluster = dleafs[leafnum].cluster;
+ if (cluster != -1)
+ {
+ VS_LinkSurfaceIntoCluster(cluster, surfaceNum);
+ }
+}
+
+/*
+=====================
+VS_LinkSurfaces
+
+maybe link each facet seperately instead of the test surfaces?
+=====================
+*/
+void VS_LinkSurfaces(void)
+{
+ int i, j;
+ lsurfaceTest_t *test;
+ lFacet_t *facet;
+ winding_t winding;
+
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ for (j = 0; j < test->numFacets; j++)
+ {
+ facet = &test->facets[j];
+ memcpy(winding.points, facet->points, facet->numpoints * sizeof(vec3_t));
+ winding.numpoints = facet->numpoints;
+ VS_R_LinkSurface(0, i, &winding);
+ }
+ }
+}
+
+/*
+=====================
+VS_TextureMatrixFromPoints
+=====================
+*/
+void VS_TextureMatrixFromPoints( lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
+ int i, j;
+ float t;
+ float m[3][4];
+ float s;
+
+ // This is an incredibly stupid way of solving a three variable equation
+ for ( i = 0 ; i < 2 ; i++ ) {
+
+ m[0][0] = a->xyz[0];
+ m[0][1] = a->xyz[1];
+ m[0][2] = a->xyz[2];
+ m[0][3] = a->st[i];
+
+ m[1][0] = b->xyz[0];
+ m[1][1] = b->xyz[1];
+ m[1][2] = b->xyz[2];
+ m[1][3] = b->st[i];
+
+ m[2][0] = c->xyz[0];
+ m[2][1] = c->xyz[1];
+ m[2][2] = c->xyz[2];
+ m[2][3] = c->st[i];
+
+ if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) > fabs(m[2][0]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[0][j];
+ m[0][j] = m[1][j];
+ m[1][j] = t;
+ }
+ } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) > fabs(m[1][0]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[0][j];
+ m[0][j] = m[2][j];
+ m[2][j] = t;
+ }
+ }
+
+ s = 1.0 / m[0][0];
+ m[0][0] *= s;
+ m[0][1] *= s;
+ m[0][2] *= s;
+ m[0][3] *= s;
+
+ s = m[1][0];
+ m[1][0] -= m[0][0] * s;
+ m[1][1] -= m[0][1] * s;
+ m[1][2] -= m[0][2] * s;
+ m[1][3] -= m[0][3] * s;
+
+ s = m[2][0];
+ m[2][0] -= m[0][0] * s;
+ m[2][1] -= m[0][1] * s;
+ m[2][2] -= m[0][2] * s;
+ m[2][3] -= m[0][3] * s;
+
+ if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[1][j];
+ m[1][j] = m[2][j];
+ m[2][j] = t;
+ }
+ }
+
+ s = 1.0 / m[1][1];
+ m[1][0] *= s;
+ m[1][1] *= s;
+ m[1][2] *= s;
+ m[1][3] *= s;
+
+ s = m[2][1];// / m[1][1];
+ m[2][0] -= m[1][0] * s;
+ m[2][1] -= m[1][1] * s;
+ m[2][2] -= m[1][2] * s;
+ m[2][3] -= m[1][3] * s;
+
+ s = 1.0 / m[2][2];
+ m[2][0] *= s;
+ m[2][1] *= s;
+ m[2][2] *= s;
+ m[2][3] *= s;
+
+ f->textureMatrix[i][2] = m[2][3];
+ f->textureMatrix[i][1] = m[1][3] - f->textureMatrix[i][2] * m[1][2];
+ f->textureMatrix[i][0] = m[0][3] - f->textureMatrix[i][2] * m[0][2] - f->textureMatrix[i][1] * m[0][1];
+
+ f->textureMatrix[i][3] = 0;
+/*
+ s = fabs( DotProduct( a->xyz, f->textureMatrix[i] ) - a->st[i] );
+ if ( s > 0.01 ) {
+ Error( "Bad textureMatrix" );
+ }
+ s = fabs( DotProduct( b->xyz, f->textureMatrix[i] ) - b->st[i] );
+ if ( s > 0.01 ) {
+ Error( "Bad textureMatrix" );
+ }
+ s = fabs( DotProduct( c->xyz, f->textureMatrix[i] ) - c->st[i] );
+ if ( s > 0.01 ) {
+ Error( "Bad textureMatrix" );
+ }
+*/
+ }
+}
+
+/*
+=====================
+VS_LightmapMatrixFromPoints
+=====================
+*/
+void VS_LightmapMatrixFromPoints( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
+ int i, j;
+ float t;
+ float m[3][4], al, bl, cl;
+ float s;
+ int h, w, ssize;
+ vec3_t mins, maxs, delta, size, planeNormal;
+ drawVert_t *verts;
+ static int message;
+
+ // vertex-lit triangle model
+ if ( dsurf->surfaceType == MST_TRIANGLE_SOUP ) {
+ return;
+ }
+
+ if ( dsurf->lightmapNum < 0 ) {
+ return; // doesn't need lighting
+ }
+
+ VectorClear(f->mins);
+ if (dsurf->surfaceType != MST_PATCH)
+ {
+ ssize = samplesize;
+ if (si->lightmapSampleSize)
+ ssize = si->lightmapSampleSize;
+ ClearBounds( mins, maxs );
+ verts = &drawVerts[dsurf->firstVert];
+ for ( i = 0 ; i < dsurf->numVerts ; i++ ) {
+ AddPointToBounds( verts[i].xyz, mins, maxs );
+ }
+ // round to the lightmap resolution
+ for ( i = 0 ; i < 3 ; i++ ) {
+ mins[i] = ssize * floor( mins[i] / ssize );
+ maxs[i] = ssize * ceil( maxs[i] / ssize );
+ f->mins[i] = mins[i];
+ size[i] = (maxs[i] - mins[i]) / ssize + 1;
+ }
+ // the two largest axis will be the lightmap size
+ VectorClear(f->lightmapMatrix[0]);
+ f->lightmapMatrix[0][3] = 0;
+ VectorClear(f->lightmapMatrix[1]);
+ f->lightmapMatrix[1][3] = 0;
+
+ planeNormal[0] = fabs( dsurf->lightmapVecs[2][0] );
+ planeNormal[1] = fabs( dsurf->lightmapVecs[2][1] );
+ planeNormal[2] = fabs( dsurf->lightmapVecs[2][2] );
+
+ if ( planeNormal[0] >= planeNormal[1] && planeNormal[0] >= planeNormal[2] ) {
+ w = size[1];
+ h = size[2];
+ f->lightmapMatrix[0][1] = 1.0 / ssize;
+ f->lightmapMatrix[1][2] = 1.0 / ssize;
+ } else if ( planeNormal[1] >= planeNormal[0] && planeNormal[1] >= planeNormal[2] ) {
+ w = size[0];
+ h = size[2];
+ f->lightmapMatrix[0][0] = 1.0 / ssize;
+ f->lightmapMatrix[1][2] = 1.0 / ssize;
+ } else {
+ w = size[0];
+ h = size[1];
+ f->lightmapMatrix[0][0] = 1.0 / ssize;
+ f->lightmapMatrix[1][1] = 1.0 / ssize;
+ }
+ if ( w > LIGHTMAP_WIDTH ) {
+ VectorScale ( f->lightmapMatrix[0], (float)LIGHTMAP_SIZE/w, f->lightmapMatrix[0] );
+ }
+
+ if ( h > LIGHTMAP_HEIGHT ) {
+ VectorScale ( f->lightmapMatrix[1], (float)LIGHTMAP_SIZE/h, f->lightmapMatrix[1] );
+ }
+ VectorSubtract(a->xyz, f->mins, delta);
+ s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
+ if ( fabs(s - a->lightmap[0]) > 0.01 ) {
+ _printf( "Bad lightmapMatrix" );
+ }
+ t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
+ if ( fabs(t - a->lightmap[1]) > 0.01 ) {
+ _printf( "Bad lightmapMatrix" );
+ }
+ VectorSubtract(b->xyz, f->mins, delta);
+ s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
+ if ( fabs(s - b->lightmap[0]) > 0.01 ) {
+ _printf( "Bad lightmapMatrix" );
+ }
+ t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
+ if ( fabs(t - b->lightmap[1]) > 0.01 ) {
+ _printf( "Bad lightmapMatrix" );
+ }
+ VectorSubtract(c->xyz, f->mins, delta);
+ s = (DotProduct( delta, f->lightmapMatrix[0] ) + dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
+ if ( fabs(s - c->lightmap[0]) > 0.01 ) {
+ _printf( "Bad lightmapMatrix" );
+ }
+ t = (DotProduct( delta, f->lightmapMatrix[1] ) + dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
+ if ( fabs(t - c->lightmap[1]) > 0.01 ) {
+ _printf( "Bad lightmapMatrix" );
+ }
+ VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins);
+ return;
+ }
+ // This is an incredibly stupid way of solving a three variable equation
+ for ( i = 0 ; i < 2 ; i++ ) {
+
+ if (i)
+ al = a->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
+ else
+ al = a->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
+
+ m[0][0] = a->xyz[0] - f->mins[0];
+ m[0][1] = a->xyz[1] - f->mins[1];
+ m[0][2] = a->xyz[2] - f->mins[2];
+ m[0][3] = al;
+
+ if (i)
+ bl = b->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
+ else
+ bl = b->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
+
+ m[1][0] = b->xyz[0] - f->mins[0];
+ m[1][1] = b->xyz[1] - f->mins[1];
+ m[1][2] = b->xyz[2] - f->mins[2];
+ m[1][3] = bl;
+
+ if (i)
+ cl = c->lightmap[i] - ((float) dsurf->lightmapY + 0.5) / LIGHTMAP_SIZE;
+ else
+ cl = c->lightmap[i] - ((float) dsurf->lightmapX + 0.5) / LIGHTMAP_SIZE;
+
+ m[2][0] = c->xyz[0] - f->mins[0];
+ m[2][1] = c->xyz[1] - f->mins[1];
+ m[2][2] = c->xyz[2] - f->mins[2];
+ m[2][3] = cl;
+
+ if ( fabs(m[1][0]) > fabs(m[0][0]) && fabs(m[1][0]) >= fabs(m[2][0]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[0][j];
+ m[0][j] = m[1][j];
+ m[1][j] = t;
+ }
+ } else if ( fabs(m[2][0]) > fabs(m[0][0]) && fabs(m[2][0]) >= fabs(m[1][0]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[0][j];
+ m[0][j] = m[2][j];
+ m[2][j] = t;
+ }
+ }
+
+ if (m[0][0])
+ {
+ s = 1.0 / m[0][0];
+ m[0][0] *= s;
+ m[0][1] *= s;
+ m[0][2] *= s;
+ m[0][3] *= s;
+
+ s = m[1][0];
+ m[1][0] -= m[0][0] * s;
+ m[1][1] -= m[0][1] * s;
+ m[1][2] -= m[0][2] * s;
+ m[1][3] -= m[0][3] * s;
+
+ s = m[2][0];
+ m[2][0] -= m[0][0] * s;
+ m[2][1] -= m[0][1] * s;
+ m[2][2] -= m[0][2] * s;
+ m[2][3] -= m[0][3] * s;
+ }
+
+ if ( fabs(m[2][1]) > fabs(m[1][1]) ) {
+ for ( j = 0 ; j < 4 ; j ++ ) {
+ t = m[1][j];
+ m[1][j] = m[2][j];
+ m[2][j] = t;
+ }
+ }
+
+ if (m[1][1])
+ {
+ s = 1.0 / m[1][1];
+ m[1][0] *= s;
+ m[1][1] *= s;
+ m[1][2] *= s;
+ m[1][3] *= s;
+
+ s = m[2][1];
+ m[2][0] -= m[1][0] * s;
+ m[2][1] -= m[1][1] * s;
+ m[2][2] -= m[1][2] * s;
+ m[2][3] -= m[1][3] * s;
+ }
+
+ if (m[2][2])
+ {
+ s = 1.0 / m[2][2];
+ m[2][0] *= s;
+ m[2][1] *= s;
+ m[2][2] *= s;
+ m[2][3] *= s;
+ }
+
+ f->lightmapMatrix[i][2] = m[2][3];
+ f->lightmapMatrix[i][1] = m[1][3] - f->lightmapMatrix[i][2] * m[1][2];
+ f->lightmapMatrix[i][0] = m[0][3] - f->lightmapMatrix[i][2] * m[0][2] - f->lightmapMatrix[i][1] * m[0][1];
+
+ f->lightmapMatrix[i][3] = 0;
+
+ VectorSubtract(a->xyz, f->mins, delta);
+ s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - al );
+ if ( s > 0.01 ) {
+ if (!message)
+ _printf( "Bad lightmapMatrix\n" );
+ message = qtrue;
+ }
+ VectorSubtract(b->xyz, f->mins, delta);
+ s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - bl );
+ if ( s > 0.01 ) {
+ if (!message)
+ _printf( "Bad lightmapMatrix\n" );
+ message = qtrue;
+ }
+ VectorSubtract(c->xyz, f->mins, delta);
+ s = fabs( DotProduct( delta, f->lightmapMatrix[i] ) - cl );
+ if ( s > 0.01 ) {
+ if (!message)
+ _printf( "Bad lightmapMatrix\n" );
+ message = qtrue;
+ }
+ VectorAdd(f->mins, surfaceOrigin[dsurf - drawSurfaces], f->mins);
+ }
+}
+
+/*
+=============
+Plane_Equal
+=============
+*/
+#define NORMAL_EPSILON 0.0001
+#define DIST_EPSILON 0.02
+
+static int Plane_Equal(plane_t *a, plane_t *b, int flip)
+{
+ vec3_t normal;
+ float dist;
+
+ if (flip) {
+ normal[0] = - b->normal[0];
+ normal[1] = - b->normal[1];
+ normal[2] = - b->normal[2];
+ dist = - b->dist;
+ }
+ else {
+ normal[0] = b->normal[0];
+ normal[1] = b->normal[1];
+ normal[2] = b->normal[2];
+ dist = b->dist;
+ }
+ if (
+ fabs(a->normal[0] - normal[0]) < NORMAL_EPSILON
+ && fabs(a->normal[1] - normal[1]) < NORMAL_EPSILON
+ && fabs(a->normal[2] - normal[2]) < NORMAL_EPSILON
+ && fabs(a->dist - dist) < DIST_EPSILON )
+ return qtrue;
+ return qfalse;
+}
+
+/*
+=============
+VS_PlaneFromPoints
+=============
+*/
+qboolean VS_PlaneFromPoints( plane_t *plane, const vec3_t a, const vec3_t b, const vec3_t c ) {
+ vec3_t d1, d2;
+
+ VectorSubtract( b, a, d1 );
+ VectorSubtract( c, a, d2 );
+ CrossProduct( d2, d1, plane->normal );
+ if ( VectorNormalize( plane->normal, plane->normal ) == 0 ) {
+ return qfalse;
+ }
+
+ plane->dist = DotProduct( a, plane->normal );
+ return qtrue;
+}
+
+/*
+=====================
+VS_GenerateBoundaryForPoints
+=====================
+*/
+void VS_GenerateBoundaryForPoints( plane_t *boundary, plane_t *plane, vec3_t a, vec3_t b ) {
+ vec3_t d1;
+
+ // make a perpendicular vector to the edge and the surface
+ VectorSubtract( a, b, d1 );
+ CrossProduct( plane->normal, d1, boundary->normal );
+ VectorNormalize( boundary->normal, boundary->normal );
+ boundary->dist = DotProduct( a, boundary->normal );
+}
+
+/*
+=====================
+VS_GenerateFacetFor3Points
+=====================
+*/
+qboolean VS_GenerateFacetFor3Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c ) {
+ //
+ vec3_t dir;
+ int i;
+
+ // if we can't generate a valid plane for the points, ignore the facet
+ if ( !VS_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) {
+ f->numpoints = 0;
+ return qfalse;
+ }
+
+ f->num = numfacets++;
+
+ VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] );
+ VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] );
+ VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] );
+
+ f->lightmapCoords[0][0] = a->lightmap[0];
+ f->lightmapCoords[0][1] = a->lightmap[1];
+ f->lightmapCoords[1][0] = b->lightmap[0];
+ f->lightmapCoords[1][1] = b->lightmap[1];
+ f->lightmapCoords[2][0] = c->lightmap[0];
+ f->lightmapCoords[2][1] = c->lightmap[1];
+
+ VS_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] );
+ VS_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] );
+ VS_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[0] );
+
+ for (i = 0; i < 3; i++)
+ {
+ VectorSubtract(f->points[(i+1)%3], f->points[i], dir);
+ if (VectorLength(dir) < 0.1)
+ return qfalse;
+ }
+
+ VS_TextureMatrixFromPoints( f, a, b, c );
+ VS_LightmapMatrixFromPoints( dsurf, si, f, a, b, c );
+
+ f->numpoints = 3;
+
+ return qtrue;
+}
+
+/*
+=====================
+VS_GenerateFacetFor4Points
+
+Attempts to use four points as a planar quad
+=====================
+*/
+#define PLANAR_EPSILON 0.1
+qboolean VS_GenerateFacetFor4Points( dsurface_t *dsurf, shaderInfo_t *si, lFacet_t *f, drawVert_t *a, drawVert_t *b, drawVert_t *c, drawVert_t *d ) {
+ float dist;
+ vec3_t dir;
+ int i;
+ plane_t plane;
+
+ // if we can't generate a valid plane for the points, ignore the facet
+ if ( !VS_PlaneFromPoints( &f->plane, a->xyz, b->xyz, c->xyz ) ) {
+ f->numpoints = 0;
+ return qfalse;
+ }
+
+ // if the fourth point is also on the plane, we can make a quad facet
+ dist = DotProduct( d->xyz, f->plane.normal ) - f->plane.dist;
+ if ( fabs( dist ) > PLANAR_EPSILON ) {
+ f->numpoints = 0;
+ return qfalse;
+ }
+
+ VectorAdd( a->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[0] );
+ VectorAdd( b->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[1] );
+ VectorAdd( c->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[2] );
+ VectorAdd( d->xyz, surfaceOrigin[dsurf - drawSurfaces], f->points[3] );
+
+ for (i = 1; i < 4; i++)
+ {
+ if ( !VS_PlaneFromPoints( &plane, f->points[i], f->points[(i+1) % 4], f->points[(i+2) % 4]) ) {
+ f->numpoints = 0;
+ return qfalse;
+ }
+
+ if (!Plane_Equal(&f->plane, &plane, qfalse)) {
+ f->numpoints = 0;
+ return qfalse;
+ }
+ }
+
+ f->lightmapCoords[0][0] = a->lightmap[0];
+ f->lightmapCoords[0][1] = a->lightmap[1];
+ f->lightmapCoords[1][0] = b->lightmap[0];
+ f->lightmapCoords[1][1] = b->lightmap[1];
+ f->lightmapCoords[2][0] = c->lightmap[0];
+ f->lightmapCoords[2][1] = c->lightmap[1];
+ f->lightmapCoords[3][0] = d->lightmap[0];
+ f->lightmapCoords[3][1] = d->lightmap[1];
+
+ VS_GenerateBoundaryForPoints( &f->boundaries[0], &f->plane, f->points[0], f->points[1] );
+ VS_GenerateBoundaryForPoints( &f->boundaries[1], &f->plane, f->points[1], f->points[2] );
+ VS_GenerateBoundaryForPoints( &f->boundaries[2], &f->plane, f->points[2], f->points[3] );
+ VS_GenerateBoundaryForPoints( &f->boundaries[3], &f->plane, f->points[3], f->points[0] );
+
+ for (i = 0; i < 4; i++)
+ {
+ VectorSubtract(f->points[(i+1)%4], f->points[i], dir);
+ if (VectorLength(dir) < 0.1)
+ return qfalse;
+ }
+
+ VS_TextureMatrixFromPoints( f, a, b, c );
+ VS_LightmapMatrixFromPoints( dsurf, si, f, a, b, c );
+
+ f->num = numfacets++;
+ f->numpoints = 4;
+
+ return qtrue;
+}
+
+/*
+===============
+VS_SphereFromBounds
+===============
+*/
+void VS_SphereFromBounds( vec3_t mins, vec3_t maxs, vec3_t origin, float *radius ) {
+ vec3_t temp;
+
+ VectorAdd( mins, maxs, origin );
+ VectorScale( origin, 0.5, origin );
+ VectorSubtract( maxs, origin, temp );
+ *radius = VectorLength( temp );
+}
+
+/*
+====================
+VS_FacetsForTriangleSurface
+====================
+*/
+void VS_FacetsForTriangleSurface( dsurface_t *dsurf, shaderInfo_t *si, lsurfaceTest_t *test ) {
+ int i;
+ drawVert_t *v1, *v2, *v3, *v4;
+ int count;
+ int i1, i2, i3, i4, i5, i6;
+
+ test->patch = qfalse;
+ if (dsurf->surfaceType == MST_TRIANGLE_SOUP)
+ test->trisoup = qtrue;
+ else
+ test->trisoup = qfalse;
+ test->numFacets = dsurf->numIndexes / 3;
+ test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
+ test->shader = si;
+
+ count = 0;
+ for ( i = 0 ; i < test->numFacets ; i++ ) {
+ i1 = drawIndexes[ dsurf->firstIndex + i*3 ];
+ i2 = drawIndexes[ dsurf->firstIndex + i*3 + 1 ];
+ i3 = drawIndexes[ dsurf->firstIndex + i*3 + 2 ];
+
+ v1 = &drawVerts[ dsurf->firstVert + i1 ];
+ v2 = &drawVerts[ dsurf->firstVert + i2 ];
+ v3 = &drawVerts[ dsurf->firstVert + i3 ];
+
+ // try and make a quad out of two triangles
+ if ( i != test->numFacets - 1 ) {
+ i4 = drawIndexes[ dsurf->firstIndex + i*3 + 3 ];
+ i5 = drawIndexes[ dsurf->firstIndex + i*3 + 4 ];
+ i6 = drawIndexes[ dsurf->firstIndex + i*3 + 5 ];
+ if ( i4 == i3 && i5 == i2 ) {
+ v4 = &drawVerts[ dsurf->firstVert + i6 ];
+ if ( VS_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v2, v4, v3 ) ) {
+ count++;
+ i++; // skip next tri
+ continue;
+ }
+ }
+ }
+
+ if (VS_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v2, v3 )) {
+ count++;
+ }
+ }
+
+ // we may have turned some pairs into quads
+ test->numFacets = count;
+}
+
+/*
+====================
+VS_FacetsForPatch
+====================
+*/
+void VS_FacetsForPatch( dsurface_t *dsurf, int surfaceNum, shaderInfo_t *si, lsurfaceTest_t *test ) {
+ int i, j, x, y;
+ drawVert_t *v1, *v2, *v3, *v4;
+ int count, ssize;
+ mesh_t mesh;
+ mesh_t *subdivided, *detailmesh, *newmesh;
+ int widthtable[LIGHTMAP_SIZE], heighttable[LIGHTMAP_SIZE];
+
+ mesh.width = dsurf->patchWidth;
+ mesh.height = dsurf->patchHeight;
+ mesh.verts = &drawVerts[ dsurf->firstVert ];
+
+ newmesh = SubdivideMesh( mesh, 8, 999 );
+ PutMeshOnCurve( *newmesh );
+ MakeMeshNormals( *newmesh );
+
+ subdivided = RemoveLinearMeshColumnsRows( newmesh );
+ FreeMesh(newmesh);
+
+ // DebugNet_RemoveAllPolys();
+ // DebugNet_DrawMesh(subdivided);
+
+ ssize = samplesize;
+ if (si->lightmapSampleSize)
+ ssize = si->lightmapSampleSize;
+
+ if ( dsurf->lightmapNum >= 0 ) {
+
+ detailmesh = SubdivideMeshQuads( subdivided, ssize, LIGHTMAP_SIZE, widthtable, heighttable);
+ test->detailMesh = detailmesh;
+
+ // DebugNet_RemoveAllPolys();
+ // DebugNet_DrawMesh(detailmesh);
+
+ if ( detailmesh->width != dsurf->lightmapWidth || detailmesh->height != dsurf->lightmapHeight ) {
+ Error( "Mesh lightmap miscount");
+ }
+ }
+ else {
+ test->detailMesh = NULL;
+ memset(widthtable, 0, sizeof(widthtable));
+ memset(heighttable, 0, sizeof(heighttable));
+ }
+
+ test->patch = qtrue;
+ test->trisoup = qfalse;
+ test->numFacets = ( subdivided->width - 1 ) * ( subdivided->height - 1 ) * 2;
+ test->facets = malloc( sizeof( test->facets[0] ) * test->numFacets );
+ test->shader = si;
+
+ count = 0;
+ x = 0;
+ for ( i = 0 ; i < subdivided->width - 1 ; i++ ) {
+ y = 0;
+ for ( j = 0 ; j < subdivided->height - 1 ; j++ ) {
+
+ v1 = subdivided->verts + j * subdivided->width + i;
+ v2 = v1 + 1;
+ v3 = v1 + subdivided->width + 1;
+ v4 = v1 + subdivided->width;
+
+ if ( VS_GenerateFacetFor4Points( dsurf, si, &test->facets[count], v1, v4, v3, v2 ) ) {
+ test->facets[count].x = x;
+ test->facets[count].y = y;
+ test->facets[count].width = widthtable[i];
+ test->facets[count].height = heighttable[j];
+ count++;
+ } else {
+ if (VS_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v4, v3 )) {
+ test->facets[count].x = x;
+ test->facets[count].y = y;
+ test->facets[count].width = widthtable[i];
+ test->facets[count].height = heighttable[j];
+ count++;
+ }
+ if (VS_GenerateFacetFor3Points( dsurf, si, &test->facets[count], v1, v3, v2 )) {
+ test->facets[count].x = x;
+ test->facets[count].y = y;
+ test->facets[count].width = widthtable[i];
+ test->facets[count].height = heighttable[j];
+ count++;
+ }
+ }
+ y += heighttable[j];
+ }
+ x += widthtable[i];
+ }
+ test->numFacets = count;
+
+ FreeMesh(subdivided);
+}
+
+/*
+=====================
+VS_InitSurfacesForTesting
+=====================
+*/
+void VS_InitSurfacesForTesting( void ) {
+
+ int i, j, k;
+ dsurface_t *dsurf;
+ lsurfaceTest_t *test;
+ shaderInfo_t *si;
+ lFacet_t *facet;
+
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ // don't light the entity surfaces with vsound
+ if ( entitySurface[i] )
+ continue;
+ //
+ dsurf = &drawSurfaces[ i ];
+ if ( !dsurf->numIndexes && !dsurf->patchWidth ) {
+ continue;
+ }
+
+ si = ShaderInfoForShader( dshaders[ dsurf->shaderNum].shader );
+ // if the surface is translucent and does not cast an alpha shadow
+ if ( (si->contents & CONTENTS_TRANSLUCENT) && !(si->surfaceFlags & SURF_ALPHASHADOW) ) {
+ // if the surface has no lightmap
+ if ( dsurf->lightmapNum < 0 )
+ continue;
+ }
+
+ test = malloc( sizeof( *test ) );
+ memset(test, 0, sizeof( *test ));
+ test->mutex = MutexAlloc();
+ test->numvolumes = 0;
+ if (si->forceTraceLight)
+ test->always_tracelight = qtrue;
+ else if (si->forceVLight)
+ test->always_vsound = qtrue;
+ lsurfaceTest[i] = test;
+
+ if ( dsurf->surfaceType == MST_TRIANGLE_SOUP || dsurf->surfaceType == MST_PLANAR ) {
+ VS_FacetsForTriangleSurface( dsurf, si, test );
+ } else if ( dsurf->surfaceType == MST_PATCH ) {
+ VS_FacetsForPatch( dsurf, i, si, test );
+ }
+ if (numfacets >= MAX_FACETS)
+ Error("numfacets >= MAX_FACETS (%d)", MAX_FACETS);
+
+ ClearBounds( test->mins, test->maxs );
+ for (j = 0; j < test->numFacets; j++)
+ {
+ facet = &test->facets[j];
+ for ( k = 0 ; k < facet->numpoints; k++) {
+ AddPointToBounds( facet->points[k], test->mins, test->maxs );
+ }
+ }
+ VS_SphereFromBounds( test->mins, test->maxs, test->origin, &test->radius );
+ }
+ _printf("%6d facets\n", numfacets);
+ _printf("linking surfaces...\n");
+ VS_LinkSurfaces();
+}
+
+/*
+=============
+VS_ChopWinding
+=============
+*/
+int VS_ChopWinding (winding_t *in, plane_t *split, float epsilon)
+{
+ vec_t dists[128];
+ int sides[128];
+ int counts[3];
+ vec_t dot;
+ int i, j;
+ vec_t *p1, *p2;
+ vec3_t mid;
+ winding_t out;
+ winding_t *neww;
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+ // determine sides for each point
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ dot = DotProduct (in->points[i], split->normal);
+ dot -= split->dist;
+ dists[i] = dot;
+ if (dot > epsilon)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -epsilon)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+
+ if (!counts[SIDE_BACK])
+ {
+ if (!counts[SIDE_FRONT])
+ return SIDE_ON;
+ else
+ return SIDE_FRONT;
+ }
+
+ if (!counts[SIDE_FRONT])
+ {
+ return SIDE_BACK;
+ }
+
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ neww = &out;
+
+ neww->numpoints = 0;
+
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ p1 = in->points[i];
+
+ if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VS_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return SIDE_FRONT; // can't chop -- fall back to original
+ }
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy (p1, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ if (neww->numpoints >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VS_ChopWinding -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return SIDE_FRONT; // can't chop -- fall back to original
+ }
+
+ // generate a split point
+ p2 = in->points[(i+1)%in->numpoints];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (split->normal[j] == 1)
+ mid[j] = split->dist;
+ else if (split->normal[j] == -1)
+ mid[j] = -split->dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ }
+ memcpy(in, &out, sizeof(winding_t));
+
+ return SIDE_CROSS;
+}
+
+/*
+=============
+VS_ChopWindingWithBrush
+
+ returns all winding fragments outside the brush
+=============
+*/
+int VS_ChopWindingWithBrush(winding_t *w, dbrush_t *brush, winding_t *outwindings, int maxout)
+{
+ int i, res, numout;
+ winding_t front, back;
+ plane_t plane;
+
+ numout = 0;
+ memcpy(front.points, w->points, w->numpoints * sizeof(vec3_t));
+ front.numpoints = w->numpoints;
+ for (i = 0; i < brush->numSides; i++)
+ {
+ VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal);
+ VectorInverse(plane.normal);
+ plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist;
+ res = VS_SplitWinding(&front, &back, &plane, 0.1);
+ if (res == SIDE_BACK || res == SIDE_ON)
+ {
+ memcpy(outwindings[0].points, w->points, w->numpoints * sizeof(vec3_t));
+ outwindings[0].numpoints = w->numpoints;
+ return 1; //did not intersect
+ }
+ if (res != SIDE_FRONT)
+ {
+ if (numout >= maxout)
+ {
+ _printf("WARNING: VS_ChopWindingWithBrush: more than %d windings\n", maxout);
+ return 0;
+ }
+ memcpy(outwindings[numout].points, back.points, back.numpoints * sizeof(vec3_t));
+ outwindings[numout].numpoints = back.numpoints;
+ numout++;
+ }
+ }
+ return numout;
+}
+
+/*
+=============
+VS_WindingAreaOutsideBrushes
+=============
+*/
+float VS_WindingAreaOutsideBrushes(winding_t *w, int *brushnums, int numbrushes)
+{
+ int i, j, numwindings[2], n;
+ winding_t windingsbuf[2][64];
+ dbrush_t *brush;
+ float area;
+
+ memcpy(windingsbuf[0][0].points, w->points, w->numpoints * sizeof(vec3_t));
+ windingsbuf[0][0].numpoints = w->numpoints;
+ numwindings[0] = 1;
+ for (i = 0; i < numbrushes; i++)
+ {
+ brush = &dbrushes[brushnums[i]];
+ if (!(dshaders[brush->shaderNum].contentFlags & (
+ CONTENTS_LAVA
+ | CONTENTS_SLIME
+ | CONTENTS_WATER
+ | CONTENTS_FOG
+ | CONTENTS_AREAPORTAL
+ | CONTENTS_PLAYERCLIP
+ | CONTENTS_MONSTERCLIP
+ | CONTENTS_CLUSTERPORTAL
+ | CONTENTS_DONOTENTER
+ | CONTENTS_BODY
+ | CONTENTS_CORPSE
+ | CONTENTS_TRANSLUCENT
+ | CONTENTS_TRIGGER
+ | CONTENTS_NODROP) ) &&
+ (dshaders[brush->shaderNum].contentFlags & CONTENTS_SOLID) )
+ {
+ numwindings[!(i & 1)] = 0;
+ for (j = 0; j < numwindings[i&1]; j++)
+ {
+ n = VS_ChopWindingWithBrush(&windingsbuf[i&1][j], brush,
+ &windingsbuf[!(i&1)][numwindings[!(i&1)]],
+ 64 - numwindings[!(i&1)]);
+ numwindings[!(i&1)] += n;
+ }
+ if (!numwindings[!(i&1)])
+ return 0;
+ }
+ else
+ {
+ for (j = 0; j < numwindings[i&1]; j++)
+ {
+ windingsbuf[!(i&1)][j] = windingsbuf[i&1][j];
+ }
+ numwindings[!(i&1)] = numwindings[i&1];
+ }
+ }
+ area = 0;
+ for (j = 0; j < numwindings[i&1]; j++)
+ {
+ area += WindingArea(&windingsbuf[i&1][j]);
+ }
+ return area;
+}
+
+/*
+=============
+VS_R_WindingAreaOutsideSolid
+=============
+*/
+float VS_R_WindingAreaOutsideSolid(winding_t *w, vec3_t normal, int nodenum)
+{
+ int leafnum, res;
+ float area;
+ dnode_t *node;
+ dleaf_t *leaf;
+ dplane_t *plane;
+ winding_t back;
+ plane_t split;
+
+ area = 0;
+ while(nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+
+ VectorCopy(plane->normal, split.normal);
+ split.dist = plane->dist;
+ res = VS_SplitWinding (w, &back, &split, 0.1);
+
+ if (res == SIDE_FRONT)
+ {
+ nodenum = node->children[0];
+ }
+ else if (res == SIDE_BACK)
+ {
+ nodenum = node->children[1];
+ }
+ else if (res == SIDE_ON)
+ {
+ if (DotProduct(normal, plane->normal) > 0)
+ nodenum = node->children[0];
+ else
+ nodenum = node->children[1];
+ }
+ else
+ {
+ area += VS_R_WindingAreaOutsideSolid(&back, normal, node->children[1]);
+ nodenum = node->children[0];
+ }
+ }
+ leafnum = -nodenum - 1;
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster != -1)
+ {
+ area += VS_WindingAreaOutsideBrushes(w, &dleafbrushes[leaf->firstLeafBrush], leaf->numLeafBrushes);
+ }
+ return area;
+}
+
+/*
+=============
+VS_WindingAreaOutsideSolid
+=============
+*/
+float VS_WindingAreaOutsideSolid(winding_t *w, vec3_t normal)
+{
+ return VS_R_WindingAreaOutsideSolid(w, normal, 0);
+}
+
+/*
+=============
+VS_ChopWindingWithFacet
+=============
+*/
+float VS_ChopWindingWithFacet(winding_t *w, lFacet_t *facet)
+{
+ int i;
+
+ for (i = 0; i < facet->numpoints; i++)
+ {
+ if (VS_ChopWinding(w, &facet->boundaries[i], 0) == SIDE_BACK)
+ return 0;
+ }
+ if (nostitching)
+ return WindingArea(w);
+ else
+ return VS_WindingAreaOutsideSolid(w, facet->plane.normal);
+}
+
+/*
+=============
+VS_CalcVisibleLightmapPixelArea
+
+nice brute force ;)
+=============
+*/
+void VS_CalcVisibleLightmapPixelArea(void)
+{
+ int i, j, x, y, k;
+ dsurface_t *ds;
+ lsurfaceTest_t *test;
+ mesh_t *mesh;
+ winding_t w, tmpw;
+ float area;
+
+ _printf("calculating visible lightmap pixel area...\n");
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ ds = &drawSurfaces[ i ];
+
+ if ( ds->lightmapNum < 0 )
+ continue;
+
+ for (y = 0; y < ds->lightmapHeight; y++)
+ {
+ for (x = 0; x < ds->lightmapWidth; x++)
+ {
+ if (ds->surfaceType == MST_PATCH)
+ {
+ if (y == ds->lightmapHeight-1)
+ continue;
+ if (x == ds->lightmapWidth-1)
+ continue;
+ mesh = lsurfaceTest[i]->detailMesh;
+ VectorCopy( mesh->verts[y*mesh->width+x].xyz, w.points[0]);
+ VectorCopy( mesh->verts[(y+1)*mesh->width+x].xyz, w.points[1]);
+ VectorCopy( mesh->verts[(y+1)*mesh->width+x+1].xyz, w.points[2]);
+ VectorCopy( mesh->verts[y*mesh->width+x+1].xyz, w.points[3]);
+ w.numpoints = 4;
+ if (nostitching)
+ area = WindingArea(&w);
+ else
+ area = VS_WindingAreaOutsideSolid(&w, mesh->verts[y*mesh->width+x].normal);
+ }
+ else
+ {
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[0]);
+ VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[0]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[0], w.points[3]);
+ VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[3]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[2]);
+ VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[1], w.points[2]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1, ds->lightmapVecs[0], w.points[1]);
+ VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT, ds->lightmapVecs[1], w.points[1]);
+ w.numpoints = 4;
+ area = 0;
+ for (j = 0; j < test->numFacets; j++)
+ {
+ memcpy(&tmpw, &w, sizeof(winding_t));
+ area += VS_ChopWindingWithFacet(&tmpw, &test->facets[j]);
+ }
+ }
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ lightmappixelarea[k] = area;
+ }
+ }
+ }
+}
+
+/*
+=============
+VS_FindAdjacentSurface
+=============
+*/
+int VS_FindAdjacentSurface(int surfaceNum, int facetNum, vec3_t p1, vec3_t p2, int *sNum, int *fNum, int *point)
+{
+ int i, j, k;
+ lsurfaceTest_t *test;
+ lFacet_t *facet;
+ dsurface_t *ds;
+ float *fp1, *fp2;
+ vec3_t dir;
+ plane_t *facetplane;
+ // winding_t w;
+
+ facetplane = &lsurfaceTest[surfaceNum]->facets[facetNum].plane;
+ // DebugNet_RemoveAllPolys();
+ // memcpy(w.points, lsurfaceTest[surfaceNum]->facets[facetNum].points,
+ // lsurfaceTest[surfaceNum]->facets[facetNum].numpoints * sizeof(vec3_t));
+ // w.numpoints = lsurfaceTest[surfaceNum]->facets[facetNum].numpoints;
+ // DebugNet_DrawWinding(&w, 2);
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ if (i == surfaceNum)
+ continue;
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ if (test->trisoup)// || test->patch)
+ continue;
+ ds = &drawSurfaces[i];
+ if ( ds->lightmapNum < 0 )
+ continue;
+ //if this surface is not even near the edge
+ VectorSubtract(p1, test->origin, dir);
+ if (fabs(dir[0]) > test->radius ||
+ fabs(dir[1]) > test->radius ||
+ fabs(dir[1]) > test->radius)
+ {
+ VectorSubtract(p2, test->origin, dir);
+ if (fabs(dir[0]) > test->radius ||
+ fabs(dir[1]) > test->radius ||
+ fabs(dir[1]) > test->radius)
+ {
+ continue;
+ }
+ }
+ //
+ for (j = 0; j < test->numFacets; j++)
+ {
+ facet = &test->facets[j];
+ //
+ //if (!Plane_Equal(&facet->plane, facetplane, qfalse))
+ if (DotProduct(facet->plane.normal, facetplane->normal) < 0.9)
+ {
+ if (!test->trisoup && !test->patch)
+ break;
+ continue;
+ }
+ //
+ for (k = 0; k < facet->numpoints; k++)
+ {
+ fp1 = facet->points[k];
+ if (fabs(p2[0] - fp1[0]) < 0.1 &&
+ fabs(p2[1] - fp1[1]) < 0.1 &&
+ fabs(p2[2] - fp1[2]) < 0.1)
+ {
+ fp2 = facet->points[(k+1) % facet->numpoints];
+ if (fabs(p1[0] - fp2[0]) < 0.1 &&
+ fabs(p1[1] - fp2[1]) < 0.1 &&
+ fabs(p1[2] - fp2[2]) < 0.1)
+ {
+ // memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t));
+ // w.numpoints = facet->numpoints;
+ // DebugNet_DrawWinding(&w, 1);
+ *sNum = i;
+ *fNum = j;
+ *point = k;
+ return qtrue;
+ }
+ }
+ /*
+ else if (fabs(p1[0] - fp1[0]) < 0.1 &&
+ fabs(p1[1] - fp1[1]) < 0.1 &&
+ fabs(p1[2] - fp1[2]) < 0.1)
+ {
+ fp2 = facet->points[(k+1) % facet->numpoints];
+ if (fabs(p2[0] - fp2[0]) < 0.1 &&
+ fabs(p2[1] - fp2[1]) < 0.1 &&
+ fabs(p2[2] - fp2[2]) < 0.1)
+ {
+ // memcpy(w.points, facet->points, facet->numpoints * sizeof(vec3_t));
+ // w.numpoints = facet->numpoints;
+ // DebugNet_DrawWinding(&w, 1);
+ *sNum = i;
+ *fNum = j;
+ *point = k;
+ return qtrue;
+ }
+ }
+ //*/
+ }
+ }
+ }
+ return qfalse;
+}
+
+/*
+=============
+VS_SmoothenLightmapEdges
+
+this code is used to smoothen lightmaps across surface edges
+=============
+*/
+void VS_SmoothenLightmapEdges(void)
+{
+ int i, j, k, coords1[2][2];
+ float coords2[2][2];
+ int x1, y1, xinc1, yinc1, k1, k2;
+ float x2, y2, xinc2, yinc2, length;
+ int surfaceNum, facetNum, point;
+ lsurfaceTest_t *test;
+ lFacet_t *facet1, *facet2;
+ dsurface_t *ds1, *ds2;
+ float *p[2], s, t, *color1, *color2;
+ vec3_t dir, cross;
+
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ if (test->trisoup)// || test->patch)
+ continue;
+ ds1 = &drawSurfaces[i];
+ if ( ds1->lightmapNum < 0 )
+ continue;
+ for (j = 0; j < test->numFacets; j++)
+ {
+ facet1 = &test->facets[j];
+ //
+ for (k = 0; k < facet1->numpoints; k++)
+ {
+ p[0] = facet1->points[k];
+ p[1] = facet1->points[(k+1)%facet1->numpoints];
+ //
+ coords1[0][0] = facet1->lightmapCoords[k][0] * LIGHTMAP_SIZE;
+ coords1[0][1] = facet1->lightmapCoords[k][1] * LIGHTMAP_SIZE;
+ coords1[1][0] = facet1->lightmapCoords[(k+1)%facet1->numpoints][0] * LIGHTMAP_SIZE;
+ coords1[1][1] = facet1->lightmapCoords[(k+1)%facet1->numpoints][1] * LIGHTMAP_SIZE;
+ if (coords1[0][0] >= LIGHTMAP_SIZE)
+ coords1[0][0] = LIGHTMAP_SIZE-1;
+ if (coords1[0][1] >= LIGHTMAP_SIZE)
+ coords1[0][1] = LIGHTMAP_SIZE-1;
+ if (coords1[1][0] >= LIGHTMAP_SIZE)
+ coords1[1][0] = LIGHTMAP_SIZE-1;
+ if (coords1[1][1] >= LIGHTMAP_SIZE)
+ coords1[1][1] = LIGHTMAP_SIZE-1;
+ // try one row or column further because on flat faces the lightmap can
+ // extend beyond the edge
+ VectorSubtract(p[1], p[0], dir);
+ VectorNormalize(dir, dir);
+ CrossProduct(dir, facet1->plane.normal, cross);
+ //
+ if (coords1[0][0] - coords1[1][0] == 0)
+ {
+ s = DotProduct( cross, facet1->lightmapMatrix[0] );
+ coords1[0][0] += s < 0 ? 1 : -1;
+ coords1[1][0] += s < 0 ? 1 : -1;
+ if (coords1[0][0] < ds1->lightmapX || coords1[0][0] >= ds1->lightmapX + ds1->lightmapWidth)
+ {
+ coords1[0][0] += s < 0 ? -1 : 1;
+ coords1[1][0] += s < 0 ? -1 : 1;
+ }
+ length = fabs(coords1[1][1] - coords1[0][1]);
+ }
+ else if (coords1[0][1] - coords1[1][1] == 0)
+ {
+ t = DotProduct( cross, facet1->lightmapMatrix[1] );
+ coords1[0][1] += t < 0 ? 1 : -1;
+ coords1[1][1] += t < 0 ? 1 : -1;
+ if (coords1[0][1] < ds1->lightmapY || coords1[0][1] >= ds1->lightmapY + ds1->lightmapHeight)
+ {
+ coords1[0][1] += t < 0 ? -1 : 1;
+ coords1[1][1] += t < 0 ? -1 : 1;
+ }
+ length = fabs(coords1[1][0] - coords1[0][0]);
+ }
+ else
+ {
+ //the edge is not parallell to one of the lightmap axis
+ continue;
+ }
+ //
+ x1 = coords1[0][0];
+ y1 = coords1[0][1];
+ xinc1 = coords1[1][0] - coords1[0][0];
+ if (xinc1 < 0) xinc1 = -1;
+ if (xinc1 > 0) xinc1 = 1;
+ yinc1 = coords1[1][1] - coords1[0][1];
+ if (yinc1 < 0) yinc1 = -1;
+ if (yinc1 > 0) yinc1 = 1;
+ // the edge should be parallell to one of the lightmap axis
+ if (xinc1 != 0 && yinc1 != 0)
+ continue;
+ //
+ if (!VS_FindAdjacentSurface(i, j, p[0], p[1], &surfaceNum, &facetNum, &point))
+ continue;
+ //
+ ds2 = &drawSurfaces[surfaceNum];
+ facet2 = &lsurfaceTest[surfaceNum]->facets[facetNum];
+ coords2[0][0] = facet2->lightmapCoords[(point+1)%facet2->numpoints][0] * LIGHTMAP_SIZE;
+ coords2[0][1] = facet2->lightmapCoords[(point+1)%facet2->numpoints][1] * LIGHTMAP_SIZE;
+ coords2[1][0] = facet2->lightmapCoords[point][0] * LIGHTMAP_SIZE;
+ coords2[1][1] = facet2->lightmapCoords[point][1] * LIGHTMAP_SIZE;
+ if (coords2[0][0] >= LIGHTMAP_SIZE)
+ coords2[0][0] = LIGHTMAP_SIZE-1;
+ if (coords2[0][1] >= LIGHTMAP_SIZE)
+ coords2[0][1] = LIGHTMAP_SIZE-1;
+ if (coords2[1][0] >= LIGHTMAP_SIZE)
+ coords2[1][0] = LIGHTMAP_SIZE-1;
+ if (coords2[1][1] >= LIGHTMAP_SIZE)
+ coords2[1][1] = LIGHTMAP_SIZE-1;
+ //
+ x2 = coords2[0][0];
+ y2 = coords2[0][1];
+ xinc2 = coords2[1][0] - coords2[0][0];
+ if (length)
+ xinc2 = xinc2 / length;
+ yinc2 = coords2[1][1] - coords2[0][1];
+ if (length)
+ yinc2 = yinc2 / length;
+ // the edge should be parallell to one of the lightmap axis
+ if ((int) xinc2 != 0 && (int) yinc2 != 0)
+ continue;
+ //
+ while(1)
+ {
+ k1 = ( ds1->lightmapNum * LIGHTMAP_HEIGHT + y1) * LIGHTMAP_WIDTH + x1;
+ k2 = ( ds2->lightmapNum * LIGHTMAP_HEIGHT + ((int) y2)) * LIGHTMAP_WIDTH + ((int) x2);
+ color1 = lightFloats + k1*3;
+ color2 = lightFloats + k2*3;
+ if (lightmappixelarea[k1] < 0.01)
+ {
+ color1[0] = color2[0];
+ color1[1] = color2[1];
+ color1[2] = color2[2];
+ }
+ else
+ {
+ color1[0] = (float) color2[0] * 0.7 + (float) color1[0] * 0.3;
+ color1[1] = (float) color2[1] * 0.7 + (float) color1[1] * 0.3;
+ color1[2] = (float) color2[2] * 0.7 + (float) color1[2] * 0.3;
+ }
+ //
+ if (x1 == coords1[1][0] &&
+ y1 == coords1[1][1])
+ break;
+ x1 += xinc1;
+ y1 += yinc1;
+ x2 += xinc2;
+ y2 += yinc2;
+ if (x2 < ds2->lightmapX)
+ x2 = ds2->lightmapX;
+ if (x2 >= ds2->lightmapX + ds2->lightmapWidth)
+ x2 = ds2->lightmapX + ds2->lightmapWidth-1;
+ if (y2 < ds2->lightmapY)
+ y2 = ds2->lightmapY;
+ if (y2 >= ds2->lightmapY + ds2->lightmapHeight)
+ y2 = ds2->lightmapY + ds2->lightmapHeight-1;
+ }
+ }
+ }
+ }
+}
+
+/*
+=============
+VS_FixLightmapEdges
+=============
+*/
+void VS_FixLightmapEdges(void)
+{
+ int i, j, x, y, k, foundvalue, height, width, index;
+ int pos, top, bottom;
+ dsurface_t *ds;
+ lsurfaceTest_t *test;
+ float color[3];
+ float *ptr;
+ byte filled[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8];
+ float lightmap_edge_epsilon;
+
+ lightmap_edge_epsilon = 0.1 * samplesize;
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ ds = &drawSurfaces[ i ];
+
+ if ( ds->lightmapNum < 0 )
+ continue;
+ if (ds->surfaceType == MST_PATCH)
+ {
+ height = ds->lightmapHeight - 1;
+ width = ds->lightmapWidth - 1;
+ }
+ else
+ {
+ height = ds->lightmapHeight;
+ width = ds->lightmapWidth;
+ }
+ memset(filled, 0, sizeof(filled));
+// printf("\n");
+ for (x = 0; x < width; x++)
+ {
+ for (y = 0; y < height; y++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (lightmappixelarea[k] > lightmap_edge_epsilon)
+ {
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ filled[index >> 3] |= 1 << (index & 7);
+// printf("*");
+ }
+// else
+// printf("_");
+ }
+// printf("\n");
+ }
+ for (y = 0; y < height; y++)
+ {
+ pos = -2;
+ for (x = 0; x < width; x++)
+ {
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (pos == -2)
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ pos = -1;
+ }
+ else if (pos == -1)
+ {
+ if (!(filled[index >> 3] & (1 << (index & 7))))
+ pos = x - 1;
+ }
+ else
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + pos;
+ top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ for (j = 0; j < (x - pos + 1) / 2; j++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1;
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + pos + j + 1;
+ filled[index >> 3] |= 1 << (index & 7);
+ (lightFloats + k*3)[0] = (lightFloats + top*3)[0];
+ (lightFloats + k*3)[1] = (lightFloats + top*3)[1];
+ (lightFloats + k*3)[2] = (lightFloats + top*3)[2];
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1;
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x - j - 1;
+ filled[index >> 3] |= 1 << (index & 7);
+ (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0];
+ (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1];
+ (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2];
+ }
+ pos = -1;
+ }
+ }
+ }
+ }
+ for (x = 0; x < width; x++)
+ {
+ pos = -2;
+ for (y = 0; y < height; y++)
+ {
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (pos == -2)
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ pos = -1;
+ }
+ else if (pos == -1)
+ {
+ if (!(filled[index >> 3] & (1 << (index & 7))))
+ pos = y - 1;
+ }
+ else
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ bottom = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ top = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ for (j = 0; j < (y - pos + 1) / 2; j++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + pos + j + 1)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ index = (ds->lightmapY + pos + j + 1) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ filled[index >> 3] |= 1 << (index & 7);
+ (lightFloats + k*3)[0] = (lightFloats + top*3)[0];
+ (lightFloats + k*3)[1] = (lightFloats + top*3)[1];
+ (lightFloats + k*3)[2] = (lightFloats + top*3)[2];
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y - j - 1)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ index = (ds->lightmapY + y - j - 1) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ filled[index >> 3] |= 1 << (index & 7);
+ (lightFloats + k*3)[0] = (lightFloats + bottom*3)[0];
+ (lightFloats + k*3)[1] = (lightFloats + bottom*3)[1];
+ (lightFloats + k*3)[2] = (lightFloats + bottom*3)[2];
+ }
+ pos = -1;
+ }
+ }
+ }
+ }
+ for (y = 0; y < height; y++)
+ {
+ foundvalue = qfalse;
+ for (x = 0; x < width; x++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (foundvalue)
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ }
+ else
+ {
+ ptr = lightFloats + k*3;
+ ptr[0] = color[0];
+ ptr[1] = color[1];
+ ptr[2] = color[2];
+ filled[index >> 3] |= 1 << (index & 7);
+ }
+ }
+ else
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ foundvalue = qtrue;
+ }
+ }
+ }
+ foundvalue = qfalse;
+ for (x = width-1; x >= 0; x--)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (foundvalue)
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ }
+ else
+ {
+ ptr = lightFloats + k*3;
+ ptr[0] = color[0];
+ ptr[1] = color[1];
+ ptr[2] = color[2];
+ filled[index >> 3] |= 1 << (index & 7);
+ }
+ }
+ else
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ foundvalue = qtrue;
+ }
+ }
+ }
+ }
+ for (x = 0; x < width; x++)
+ {
+ foundvalue = qfalse;
+ for (y = 0; y < height; y++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (foundvalue)
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ }
+ else
+ {
+ ptr = lightFloats + k*3;
+ ptr[0] = color[0];
+ ptr[1] = color[1];
+ ptr[2] = color[2];
+ filled[index >> 3] |= 1 << (index & 7);
+ }
+ }
+ else
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ foundvalue = qtrue;
+ }
+ }
+ }
+ foundvalue = qfalse;
+ for (y = height-1; y >= 0; y--)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ index = (ds->lightmapY + y) * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ if (foundvalue)
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ }
+ else
+ {
+ ptr = lightFloats + k*3;
+ ptr[0] = color[0];
+ ptr[1] = color[1];
+ ptr[2] = color[2];
+ filled[index >> 3] |= 1 << (index & 7);
+ }
+ }
+ else
+ {
+ if (filled[index >> 3] & (1 << (index & 7)))
+ {
+ ptr = lightFloats + k*3;
+ color[0] = ptr[0];
+ color[1] = ptr[1];
+ color[2] = ptr[2];
+ foundvalue = qtrue;
+ }
+ }
+ }
+ }
+ if (ds->surfaceType == MST_PATCH)
+ {
+ x = ds->lightmapWidth-1;
+ for (y = 0; y < ds->lightmapHeight; y++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ ptr = lightFloats + k*3;
+ ptr[0] = (lightFloats + (k-1)*3)[0];
+ ptr[1] = (lightFloats + (k-1)*3)[1];
+ ptr[2] = (lightFloats + (k-1)*3)[2];
+ }
+ y = ds->lightmapHeight-1;
+ for (x = 0; x < ds->lightmapWidth; x++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ ptr = lightFloats + k*3;
+ ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0];
+ ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1];
+ ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2];
+ }
+ }
+ /*
+ //colored debug edges
+ if (ds->surfaceType == MST_PATCH)
+ {
+ x = ds->lightmapWidth-1;
+ for (y = 0; y < ds->lightmapHeight; y++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ ptr = lightFloats + k*3;
+ ptr[0] = 255;
+ ptr[1] = 0;
+ ptr[2] = 0;
+ }
+ y = ds->lightmapHeight-1;
+ for (x = 0; x < ds->lightmapWidth; x++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ ptr = lightFloats + k*3;
+ ptr[0] = 0;
+ ptr[1] = 255;
+ ptr[2] = 0;
+ }
+ }
+ //*/
+ }
+ //
+ VS_SmoothenLightmapEdges();
+}
+
+/*
+=============
+VS_ShiftPatchLightmaps
+=============
+*/
+void VS_ShiftPatchLightmaps(void)
+{
+ int i, j, x, y, k;
+ drawVert_t *verts;
+ dsurface_t *ds;
+ lsurfaceTest_t *test;
+ float *ptr;
+
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ ds = &drawSurfaces[ i ];
+
+ if ( ds->lightmapNum < 0 )
+ continue;
+ if (ds->surfaceType != MST_PATCH)
+ continue;
+ for (x = ds->lightmapWidth; x > 0; x--)
+ {
+ for (y = 0; y <= ds->lightmapHeight; y++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ ptr = lightFloats + k*3;
+ ptr[0] = (lightFloats + (k-1)*3)[0];
+ ptr[1] = (lightFloats + (k-1)*3)[1];
+ ptr[2] = (lightFloats + (k-1)*3)[2];
+ }
+ }
+ for (y = ds->lightmapHeight; y > 0; y--)
+ {
+ for (x = 0; x <= ds->lightmapWidth; x++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ ptr = lightFloats + k*3;
+ ptr[0] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[0];
+ ptr[1] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[1];
+ ptr[2] = (lightFloats + (k-LIGHTMAP_WIDTH)*3)[2];
+ }
+ }
+ verts = &drawVerts[ ds->firstVert ];
+ for ( j = 0 ; j < ds->patchHeight * ds->patchWidth; j++ )
+ {
+ verts[j].lightmap[0] += 0.5 / LIGHTMAP_WIDTH;
+ verts[j].lightmap[1] += 0.5 / LIGHTMAP_HEIGHT;
+ }
+ ds->lightmapHeight++;
+ ds->lightmapWidth++;
+ }
+}
+
+/*
+=============
+VS_StoreLightmap
+=============
+*/
+void VS_StoreLightmap(void)
+{
+ int i, x, y, k;
+ dsurface_t *ds;
+ lsurfaceTest_t *test;
+ float *src;
+ byte *dst;
+
+ _printf("storing lightmaps...\n");
+ //fix lightmap edges before storing them
+ VS_FixLightmapEdges();
+ //
+#ifdef LIGHTMAP_PATCHSHIFT
+ VS_ShiftPatchLightmaps();
+#endif
+ //
+ for ( i = 0 ; i < numDrawSurfaces ; i++ )
+ {
+ test = lsurfaceTest[ i ];
+ if (!test)
+ continue;
+ ds = &drawSurfaces[ i ];
+
+ if ( ds->lightmapNum < 0 )
+ continue;
+
+ for (y = 0; y < ds->lightmapHeight; y++)
+ {
+ for (x = 0; x < ds->lightmapWidth; x++)
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ VectorAdd((lightFloats + k*3), lightAmbientColor, (lightFloats + k*3));
+ src = &lightFloats[k*3];
+ dst = lightBytes + k*3;
+ ColorToBytes(src, dst);
+ }
+ }
+ }
+}
+
+/*
+=============
+PointInLeafnum
+=============
+*/
+static int PointInLeafnum(vec3_t point)
+{
+ int nodenum;
+ vec_t dist;
+ dnode_t *node;
+ dplane_t *plane;
+
+ nodenum = 0;
+ while (nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+ dist = DotProduct (point, plane->normal) - plane->dist;
+ if (dist > 0)
+ nodenum = node->children[0];
+ else
+ nodenum = node->children[1];
+ }
+
+ return -nodenum - 1;
+}
+
+/*
+=============
+VS_PointInLeafnum_r
+=============
+*/
+int VS_PointInLeafnum_r(vec3_t point, int nodenum)
+{
+ int leafnum;
+ vec_t dist;
+ dnode_t *node;
+ dplane_t *plane;
+
+ while (nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+ dist = DotProduct (point, plane->normal) - plane->dist;
+ if (dist > 0.1)
+ {
+ nodenum = node->children[0];
+ }
+ else if (dist < -0.1)
+ {
+ nodenum = node->children[1];
+ }
+ else
+ {
+ leafnum = VS_PointInLeafnum_r(point, node->children[0]);
+ if (dleafs[leafnum].cluster != -1)
+ return leafnum;
+ nodenum = node->children[1];
+ }
+ }
+
+ leafnum = -nodenum - 1;
+ return leafnum;
+}
+
+/*
+=============
+VS_PointInLeafnum
+=============
+*/
+int VS_PointInLeafnum(vec3_t point)
+{
+ return VS_PointInLeafnum_r(point, 0);
+}
+
+/*
+=============
+VS_LightLeafnum
+=============
+*/
+int VS_LightLeafnum(vec3_t point)
+{
+ /*
+ int leafnum;
+ dleaf_t *leaf;
+ float x, y, z;
+ vec3_t test;
+
+ leafnum = VS_PointInLeafnum(point);
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster != -1)
+ return leafnum;
+ for (z = 1; z >= -1; z -= 1)
+ {
+ for (x = 1; x >= -1; x -= 1)
+ {
+ for (y = 1; y >= -1; y -= 1)
+ {
+ VectorCopy(point, test);
+ test[0] += x;
+ test[1] += y;
+ test[2] += z;
+ leafnum = VS_PointInLeafnum(test);
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster != -1)
+ {
+ VectorCopy(test, point);
+ return leafnum;
+ }
+ }
+ }
+ }
+ return leafnum;
+ */
+ return VS_PointInLeafnum(point);
+}
+
+//#define LIGHTPOLYS
+
+#ifdef LIGHTPOLYS
+
+winding_t *lightwindings[MAX_MAP_DRAW_SURFS];
+int numlightwindings;
+
+/*
+=============
+VS_DrawLightWindings
+=============
+*/
+void VS_DrawLightWindings(void)
+{
+ int i;
+ for (i = 0; i < numlightwindings; i++)
+ {
+#ifdef DEBUGNET
+ DebugNet_DrawWinding(lightwindings[i], 1);
+#endif
+ }
+}
+
+/*
+=============
+VS_LightSurfaceWithVolume
+=============
+*/
+void VS_LightSurfaceWithVolume(int surfaceNum, int facetNum, vsound_t *light, lightvolume_t *volume)
+{
+ winding_t *w;
+ lsurfaceTest_t *test;
+ lFacet_t *facet;
+ int i;
+
+ test = lsurfaceTest[ surfaceNum ];
+ facet = &test->facets[ facetNum ];
+
+ //
+ w = (winding_t *) malloc(sizeof(winding_t));
+ memcpy(w->points, facet->points, sizeof(vec3_t) * facet->numpoints);
+ w->numpoints = facet->numpoints;
+
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ //if totally on the back
+ if (VS_ChopWinding(w, &volume->planes[i], 0.01) == SIDE_BACK)
+ return;
+ }
+ lightwindings[numlightwindings] = w;
+ numlightwindings++;
+ if (numlightwindings >= MAX_MAP_DRAW_SURFS)
+ Error("MAX_LIGHTWINDINGS");
+}
+
+#else
+
+/*
+=============
+VS_LightSurfaceWithVolume
+=============
+*/
+/*
+int VS_PointInsideLightVolume(vec3_t point, lightvolume_t *volume)
+{
+ int i;
+ float d;
+
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ d = DotProduct(volume->planes[i].normal, point) - volume->planes[i].dist;
+ if (d < 0) return qfalse;
+ }
+ return qtrue;
+}
+
+void VS_LightSurfaceWithVolume( int surfaceNum, int facetNum, vsound_t *light, lightvolume_t *volume )
+{
+ dsurface_t *ds;
+ int i, j, k;
+ int numPositions;
+ vec3_t base, normal, color;
+ int sampleWidth, sampleHeight;
+ vec3_t lightmapOrigin, lightmapVecs[2], dir;
+ unsigned char *ptr;
+ float add, dist, angle;
+ mesh_t * mesh;
+
+ ds = &drawSurfaces[surfaceNum];
+
+ // vertex-lit triangle model
+ if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
+ return;
+ }
+
+ if ( ds->lightmapNum < 0 ) {
+ return; // doesn't need lighting
+ }
+
+ if ( ds->surfaceType == MST_PATCH ) {
+ mesh = lsurfaceTest[surfaceNum]->detailMesh;
+ } else {
+ VectorCopy( ds->lightmapVecs[2], normal );
+
+ VectorCopy( ds->lightmapOrigin, lightmapOrigin );
+ VectorCopy( ds->lightmapVecs[0], lightmapVecs[0] );
+ VectorCopy( ds->lightmapVecs[1], lightmapVecs[1] );
+ }
+
+ sampleWidth = ds->lightmapWidth;
+ sampleHeight = ds->lightmapHeight;
+
+ //calculate lightmap
+ for ( i = 0 ; i < sampleWidth; i++ ) {
+ for ( j = 0 ; j < sampleHeight; j++ ) {
+
+ if ( ds->patchWidth ) {
+ numPositions = 9;
+ VectorCopy( mesh->verts[j*mesh->width+i].normal, normal );
+ // VectorNormalize( normal, normal );
+ // push off of the curve a bit
+ VectorMA( mesh->verts[j*mesh->width+i].xyz, 1, normal, base );
+
+// MakeNormalVectors( normal, lightmapVecs[0], lightmapVecs[1] );
+ } else {
+ numPositions = 9;
+ for ( k = 0 ; k < 3 ; k++ ) {
+ base[k] = lightmapOrigin[k] + normal[k]
+ + ((float) i) * lightmapVecs[0][k]
+ + ((float) j) * lightmapVecs[1][k];
+ }
+ }
+ VectorAdd( base, surfaceOrigin[ surfaceNum ], base );
+
+ VectorSubtract(base, light->origin, dir);
+ dist = VectorNormalize(dir, dir);
+ if ( dist < 16 ) {
+ dist = 16;
+ }
+ angle = 1;//DotProduct( normal, dir ); //1;
+ if (angle > 1)
+ angle = 1;
+ if ( light->atten_disttype == LDAT_LINEAR ) {
+ add = angle * light->photons * lightLinearScale - dist;
+ if ( add < 0 ) {
+ add = 0;
+ }
+ } else {
+ add = light->photons / ( dist * dist ) * angle;
+ }
+ if (add <= 1.0)
+ continue;
+
+ if (VS_PointInsideLightVolume(base, volume))
+ {
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + j)
+ * LIGHTMAP_WIDTH + ds->lightmapX + i;
+ ptr = lightBytes + k*3;
+ color[0] = (float) ptr[0] + add * light->color[0];
+ color[1] = (float) ptr[1] + add * light->color[1];
+ color[2] = (float) ptr[2] + add * light->color[2];
+ ColorToBytes(color, ptr);
+ }
+ }
+ }
+}
+*/
+
+/*
+=============
+VS_GetFilter
+
+FIXME: don't use a lightmap pixel origin but use the four corner points
+ to map part of a translucent surface onto the lightmap pixel
+=============
+*/
+void VS_GetFilter(vsound_t *light, lightvolume_t *volume, vec3_t lmp, vec3_t filter)
+{
+ lFacet_t *facet;
+ lsurfaceTest_t *test;
+ float d, d1, d2, frac, s, t, ns;
+ int i, j, is, it, b;
+ int x, y, u, v, numsamples, radius, color[4], largest;
+ byte *image;
+ vec3_t point, origin, total;
+
+ VectorSet(filter, 1, 1, 1);
+
+ if (noalphashading)
+ return;
+
+ if (volume->numtransFacets <= 0)
+ return;
+
+ if (light->type == LIGHT_SURFACEDIRECTED)
+ {
+ // project the light map pixel origin onto the area light source plane
+ d = DotProduct(lmp, light->normal) - DotProduct(light->normal, light->w.points[0]);
+ VectorMA(lmp, -d, light->normal, origin);
+ }
+ else
+ {
+ VectorCopy(light->origin, origin);
+ }
+ for (i = 0; i < volume->numtransFacets; i++)
+ {
+ test = lsurfaceTest[ volume->transSurfaces[i] ];
+ facet = &test->facets[ volume->transFacets[i] ];
+ // if this surface does not cast an alpha shadow
+ if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) )
+ continue;
+ // if there are no texture pixel available
+ if ( !test->shader->pixels ) {
+ continue;
+ }
+ //
+ d1 = DotProduct( origin, facet->plane.normal) - facet->plane.dist;
+ d2 = DotProduct( lmp, facet->plane.normal ) - facet->plane.dist;
+ // this should never happen because the light volume went through the facet
+ if ( ( d1 < 0 ) == ( d2 < 0 ) ) {
+ continue;
+ }
+ // calculate the crossing point
+ frac = d1 / ( d1 - d2 );
+
+ for ( j = 0 ; j < 3 ; j++ ) {
+ point[j] = origin[j] + frac * ( lmp[j] - origin[j] );
+ }
+
+ s = DotProduct( point, facet->textureMatrix[0] ) + facet->textureMatrix[0][3];
+ t = DotProduct( point, facet->textureMatrix[1] ) + facet->textureMatrix[1][3];
+ if (s < 0)
+ s = 0;
+ if (t < 0)
+ t = 0;
+
+ s = s - floor( s );
+ t = t - floor( t );
+
+ is = s * test->shader->width;
+ it = t * test->shader->height;
+
+ //if old style alpha shading
+ if (nocolorshading) {
+ image = test->shader->pixels + 4 * ( it * test->shader->width + is );
+
+ // alpha filter
+ b = image[3];
+
+ // alpha test makes this a binary option
+ b = b < 128 ? 0 : 255;
+
+ filter[0] = filter[0] * (255-b) / 255;
+ filter[1] = filter[1] * (255-b) / 255;
+ filter[2] = filter[2] * (255-b) / 255;
+ }
+ else {
+ VectorClear(total);
+ numsamples = 0;
+ radius = 2;
+ for ( u = -radius; u <= radius; u++ )
+ {
+ x = is + u;
+ if ( x < 0 || x >= test->shader->width)
+ continue;
+ for ( v = -radius; v <= radius; v++ )
+ {
+ y = it + v;
+ if ( y < 0 || y >= test->shader->height)
+ continue;
+
+ image = test->shader->pixels + 4 * ( y * test->shader->width + x );
+ color[0] = image[0];
+ color[1] = image[1];
+ color[2] = image[2];
+ largest = 0;
+ for (j = 0; j < 3; j++)
+ if (image[j] > largest)
+ largest = image[j];
+ if (largest <= 0 || image[3] == 0) {
+ color[0] = 255;
+ color[1] = 255;
+ color[2] = 255;
+ largest = 255;
+ }
+ total[0] += ((float) color[0]/largest) * (255-image[3]) / 255.0;
+ total[1] += ((float) color[1]/largest) * (255-image[3]) / 255.0;
+ total[2] += ((float) color[2]/largest) * (255-image[3]) / 255.0;
+ numsamples++;
+ }
+ }
+ ns = numsamples;
+ //
+ filter[0] *= total[0] / ns;
+ filter[1] *= total[1] / ns;
+ filter[2] *= total[2] / ns;
+ }
+ }
+}
+
+/*
+=============
+VS_LightSurfaceWithVolume
+=============
+*/
+void VS_LightSurfaceWithVolume( int surfaceNum, int facetNum, vsound_t *light, lightvolume_t *volume )
+{
+ int i;
+ dsurface_t *ds;
+ lFacet_t *facet;
+ lsurfaceTest_t *test;
+ winding_t w;
+ vec3_t base, dir, delta, normal, filter, origin;
+ int min_x[LIGHTMAP_SIZE+2], max_x[LIGHTMAP_SIZE+2];
+ int min_y, max_y, k, x, y, n;
+ float *color, distscale;
+ float d, add, angle, dist, area, insidearea, coords[MAX_POINTS_ON_WINDING+1][2];
+ mesh_t *mesh;
+ byte polygonedges[(LIGHTMAP_SIZE+1) * (LIGHTMAP_SIZE+1) / 8];
+
+
+ ds = &drawSurfaces[surfaceNum];
+
+ // vertex-lit triangle model
+ if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
+ return;
+ }
+
+ if ( ds->lightmapNum < 0 ) {
+ return; // doesn't need lighting
+ }
+
+ test = lsurfaceTest[ surfaceNum ];
+ facet = &test->facets[ facetNum ];
+
+ if (defaulttracelight && !test->always_vsound)
+ return;
+ if (test->always_tracelight)
+ return;
+
+ memcpy(w.points, facet->points, sizeof(vec3_t) * facet->numpoints);
+ w.numpoints = facet->numpoints;
+
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ //if totally on the back
+ if (VS_ChopWinding(&w, &volume->planes[i], 0.01) == SIDE_BACK)
+ return;
+ }
+
+ // only one thread at a time may write to the lightmap of this surface
+ MutexLock(test->mutex);
+
+ test->numvolumes++;
+
+ if (ds->surfaceType == MST_PATCH)
+ {
+ // FIXME: reduce size and don't mark all as edge
+ min_y = ds->lightmapY + facet->y;
+ max_y = ds->lightmapY + facet->y + facet->height - 1;
+ for (y = min_y; y <= max_y; y++)
+ {
+ min_x[y] = ds->lightmapX + facet->x;
+ max_x[y] = ds->lightmapX + facet->x + facet->width - 1;
+ for (x = min_x[y]; x <= max_x[y]; x++)
+ {
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < w.numpoints; i++)
+ {
+ float s, t;
+
+ if (i >= MAX_POINTS_ON_WINDING)
+ _printf("coords overflow\n");
+ if (ds->surfaceType != MST_PATCH)
+ {
+ VectorSubtract(w.points[i], facet->mins, delta);
+ s = DotProduct( delta, facet->lightmapMatrix[0] ) + ds->lightmapX + 0.5;
+ t = DotProduct( delta, facet->lightmapMatrix[1] ) + ds->lightmapY + 0.5;
+ if (s >= LIGHTMAP_SIZE)
+ s = LIGHTMAP_SIZE - 0.5;
+ if (s < 0)
+ s = 0;
+ if (t >= LIGHTMAP_SIZE)
+ t = LIGHTMAP_SIZE - 0.5;
+ if (t < 0)
+ t = 0;
+ coords[i][0] = s;
+ coords[i][1] = t;
+ }
+ else
+ {
+ s = DotProduct( w.points[i], facet->lightmapMatrix[0] ) + facet->lightmapMatrix[0][3];
+ t = DotProduct( w.points[i], facet->lightmapMatrix[1] ) + facet->lightmapMatrix[1][3];
+
+ s = s - floor( s );
+ t = t - floor( t );
+
+ coords[i][0] = ds->lightmapX + s * LIGHTMAP_SIZE;// + 0.5;
+ coords[i][1] = ds->lightmapY + t * LIGHTMAP_SIZE;// + 0.5;
+
+ if (coords[i][0] >= LIGHTMAP_SIZE)
+ coords[i][0] -= LIGHTMAP_SIZE;
+ if (coords[i][1] >= LIGHTMAP_SIZE)
+ coords[i][1] -= LIGHTMAP_SIZE;
+ if (coords[i][0] < ds->lightmapX)
+ coords[i][0] = ds->lightmapX;
+ if (coords[i][1] < ds->lightmapY)
+ coords[i][1] = ds->lightmapY;
+ }
+ x = coords[i][0];
+ y = coords[i][1];
+ if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
+ _printf("VS_LightSurfaceWithVolume: x outside lightmap\n");
+ if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
+ _printf("VS_LightSurfaceWithVolume: y outside lightmap\n");
+ }
+ coords[i][0] = coords[0][0];
+ coords[i][1] = coords[0][1];
+
+ //
+ min_y = LIGHTMAP_SIZE;
+ max_y = 0;
+ for (i = 0; i < LIGHTMAP_SIZE; i++)
+ {
+ min_x[i] = LIGHTMAP_SIZE;
+ max_x[i] = 0;
+ }
+ memset(polygonedges, 0, sizeof(polygonedges));
+ // scan convert the polygon onto the lightmap
+ // for each edge it marks *every* lightmap pixel the edge goes through
+ // so no brasenham and no scan conversion used for texture mapping but
+ // more something like ray casting
+ // this is necesary because we need all lightmap pixels totally or partly
+ // inside the light volume. these lightmap pixels are only lit for the part
+ // that they are inside the light volume.
+ for (i = 0; i < w.numpoints; i++)
+ {
+ float xf, yf, dx, dy, xstep, ystep, xfrac, yfrac;
+ int xinc, yinc;
+
+ xf = coords[i][0];
+ yf = coords[i][1];
+ dx = coords[i+1][0] - xf;
+ dy = coords[i+1][1] - yf;
+ //
+ x = (int) xf;
+ y = (int) yf;
+ //
+ if (y < min_y)
+ min_y = y;
+ if (y > max_y)
+ max_y = y;
+ //
+ if (fabs(dx) > fabs(dy))
+ {
+ if (dx > 0)
+ {
+ // y fraction at integer x below fractional x
+ yfrac = yf + (floor(xf) - xf) * dy / dx;
+ xinc = 1;
+ }
+ else if (dx < 0)
+ {
+ // y fraction at integer x above fractional x
+ yfrac = yf + (floor(xf) + 1 - xf) * dy / dx;
+ xinc = -1;
+ }
+ else
+ {
+ yfrac = yf;
+ xinc = 0;
+ }
+ // step in y direction per 1 unit in x direction
+ if (dx)
+ ystep = dy / fabs(dx);
+ else
+ ystep = 0;
+ while(1)
+ {
+ if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
+ _printf("VS_LightSurfaceWithVolume: x outside lightmap\n");
+ if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
+ _printf("VS_LightSurfaceWithVolume: y outside lightmap\n");
+ //
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ if (x < min_x[y])
+ min_x[y] = x;
+ if (x > max_x[y])
+ max_x[y] = x;
+ if (x == (int) coords[i+1][0])
+ break;
+ yfrac += ystep;
+ if (dy > 0)
+ {
+ if (yfrac > (float) y + 1)
+ {
+ y += 1;
+ //
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ if (x < min_x[y])
+ min_x[y] = x;
+ if (x > max_x[y])
+ max_x[y] = x;
+ }
+ }
+ else
+ {
+ if (yfrac < (float) y)
+ {
+ y -= 1;
+ //
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ if (x < min_x[y])
+ min_x[y] = x;
+ if (x > max_x[y])
+ max_x[y] = x;
+ }
+ }
+ x += xinc;
+ }
+ }
+ else
+ {
+ if (dy > 0)
+ {
+ //x fraction at integer y below fractional y
+ xfrac = xf + (floor(yf) - yf) * dx / dy;
+ yinc = 1;
+ }
+ else if (dy < 0)
+ {
+ //x fraction at integer y above fractional y
+ xfrac = xf + (floor(yf) + 1 - yf) * dx / dy;
+ yinc = -1;
+ }
+ else
+ {
+ xfrac = xf;
+ yinc = 0;
+ }
+ // step in x direction per 1 unit in y direction
+ if (dy)
+ xstep = dx / fabs(dy);
+ else
+ xstep = 0;
+ while(1)
+ {
+ if (x < ds->lightmapX || x >= LIGHTMAP_SIZE)
+ _printf("VS_LightSurfaceWithVolume: x outside lightmap\n");
+ if (y < ds->lightmapY || y >= LIGHTMAP_SIZE)
+ _printf("VS_LightSurfaceWithVolume: y outside lightmap\n");
+ //
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ if (x < min_x[y])
+ min_x[y] = x;
+ if (x > max_x[y])
+ max_x[y] = x;
+ if (y == (int) coords[i+1][1])
+ break;
+ xfrac += xstep;
+ if (dx > 0)
+ {
+ if (xfrac > (float) x + 1)
+ {
+ x += 1;
+ //
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ if (x < min_x[y])
+ min_x[y] = x;
+ if (x > max_x[y])
+ max_x[y] = x;
+ }
+ }
+ else
+ {
+ if (xfrac < (float) x)
+ {
+ x -= 1;
+ //
+ n = y * LIGHTMAP_SIZE + x;
+ polygonedges[n >> 3] |= 1 << (n & 7);
+ if (x < min_x[y])
+ min_x[y] = x;
+ if (x > max_x[y])
+ max_x[y] = x;
+ }
+ }
+ y += yinc;
+ }
+ }
+ }
+ }
+ // map light onto the lightmap
+ for (y = min_y; y <= max_y; y++)
+ {
+ for (x = min_x[y]; x <= max_x[y]; x++)
+ {
+ if (ds->surfaceType == MST_PATCH)
+ {
+ mesh = test->detailMesh;
+ VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, base);
+ VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].normal, normal);
+ //VectorCopy(facet->plane.normal, normal);
+ }
+ else
+ {
+ VectorMA(ds->lightmapOrigin, (float) x - ds->lightmapX, ds->lightmapVecs[0], base);
+ VectorMA(base, (float) y - ds->lightmapY, ds->lightmapVecs[1], base);
+ VectorCopy(facet->plane.normal, normal);
+ }
+ if (light->type == LIGHT_POINTSPOT)
+ {
+ float distByNormal;
+ vec3_t pointAtDist;
+ float radiusAtDist;
+ float sampleRadius;
+ vec3_t distToSample;
+ float coneScale;
+
+ VectorSubtract( light->origin, base, dir );
+
+ distByNormal = -DotProduct( dir, light->normal );
+ if ( distByNormal < 0 ) {
+ continue;
+ }
+ VectorMA( light->origin, distByNormal, light->normal, pointAtDist );
+ radiusAtDist = light->radiusByDist * distByNormal;
+
+ VectorSubtract( base, pointAtDist, distToSample );
+ sampleRadius = VectorLength( distToSample );
+
+ if ( sampleRadius >= radiusAtDist ) {
+ continue; // outside the cone
+ }
+ if ( sampleRadius <= radiusAtDist - 32 ) {
+ coneScale = 1.0; // fully inside
+ } else {
+ coneScale = ( radiusAtDist - sampleRadius ) / 32.0;
+ }
+
+ dist = VectorNormalize( dir, dir );
+ // clamp the distance to prevent super hot spots
+ if ( dist < 16 ) {
+ dist = 16;
+ }
+ angle = DotProduct( normal, dir );
+ if (angle > 1)
+ angle = 1;
+ if (angle > 0) {
+ if ( light->atten_angletype == LAAT_QUADRATIC ) {
+ angle = 1 - angle;
+ angle *= angle;
+ angle = 1 - angle;
+ }
+ else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
+ angle = 1 - angle;
+ angle *= angle * angle;
+ angle = 1 - angle;
+ }
+ }
+ if (light->atten_anglescale > 0) {
+ angle /= light->atten_anglescale;
+ if (angle > 1)
+ angle = 1;
+ }
+ if (light->atten_distscale > 0) {
+ distscale = light->atten_distscale;
+ }
+ else {
+ distscale = 1;
+ }
+ //
+ if ( light->atten_disttype == LDAT_NOSCALE ) {
+ add = angle * coneScale;
+ }
+ else if ( light->atten_disttype == LDAT_LINEAR ) {
+ add = angle * light->photons * lightLinearScale * coneScale - dist * distscale;
+ if ( add < 0 ) {
+ add = 0;
+ }
+ }
+ else {
+ add = light->photons / ( dist * dist * distscale) * angle * coneScale;
+ }
+ if (add <= 1.0)
+ continue;
+ }
+ else if (light->type == LIGHT_POINTFAKESURFACE)
+ {
+ // calculate the contribution
+ add = PointToPolygonFormFactor( base, normal, &light->w );
+ if ( add <= 0 ) {
+ if ( light->twosided ) {
+ add = -add;
+ } else {
+ continue;
+ }
+ }
+ }
+ else if (light->type == LIGHT_SURFACEDIRECTED)
+ {
+ //VectorCopy(light->normal, dir);
+ //VectorInverse(dir);
+ // project the light map pixel origin onto the area light source plane
+ d = DotProduct(base, light->normal) - DotProduct(light->normal, light->w.points[0]);
+ VectorMA(base, -d, light->normal, origin);
+ VectorSubtract(origin, base, dir);
+ dist = VectorNormalize(dir, dir);
+ if ( dist < 16 ) {
+ dist = 16;
+ }
+ //
+ angle = DotProduct( normal, dir );
+ if (angle > 1)
+ angle = 1;
+ if (angle > 0) {
+ if ( light->atten_angletype == LAAT_QUADRATIC ) {
+ angle = 1 - angle;
+ angle *= angle;
+ angle = 1 - angle;
+ }
+ else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
+ angle = 1 - angle;
+ angle *= angle * angle;
+ angle = 1 - angle;
+ }
+ }
+ if (light->atten_anglescale > 0) {
+ angle /= light->atten_anglescale;
+ if (angle > 1)
+ angle = 1;
+ }
+ if (light->atten_distscale > 0) {
+ distscale = light->atten_distscale;
+ }
+ else {
+ distscale = 1;
+ }
+ if ( light->atten_disttype == LDAT_NOSCALE ) {
+ add = angle;
+ }
+ else if ( light->atten_disttype == LDAT_LINEAR ) {
+ add = angle * light->photons * lightLinearScale - dist * distscale;
+ if ( add < 0 ) {
+ add = 0;
+ }
+ } else { //default quadratic
+ add = light->photons / ( dist * dist * distscale) * angle;
+ }
+ if (add <= 0)
+ continue;
+ }
+ else //normal radial point light
+ {
+ VectorSubtract(light->origin, base, dir);
+ dist = VectorNormalize(dir, dir);
+ if ( dist < 16 ) {
+ dist = 16;
+ }
+ angle = DotProduct( normal, dir );
+ if (angle > 1)
+ angle = 1;
+ if (angle > 0) {
+ if ( light->atten_angletype == LAAT_QUADRATIC ) {
+ angle = 1 - angle;
+ angle *= angle;
+ angle = 1 - angle;
+ }
+ else if ( light->atten_angletype == LAAT_DOUBLEQUADRATIC ) {
+ angle = 1 - angle;
+ angle *= angle * angle;
+ angle = 1 - angle;
+ }
+ }
+ if (light->atten_anglescale > 0) {
+ angle /= light->atten_anglescale;
+ if (angle > 1)
+ angle = 1;
+ }
+ if (light->atten_distscale > 0) {
+ distscale = light->atten_distscale;
+ }
+ else {
+ distscale = 1;
+ }
+ if ( light->atten_disttype == LDAT_NOSCALE ) {
+ add = angle;
+ }
+ else if ( light->atten_disttype == LDAT_LINEAR ) {
+ add = angle * light->photons * lightLinearScale - dist * distscale;
+ if ( add < 0 ) {
+ add = 0;
+ }
+ } else {
+ add = light->photons / ( dist * dist * distscale) * angle;
+ }
+ if (add <= 1.0)
+ continue;
+ }
+ //
+ k = (ds->lightmapNum * LIGHTMAP_HEIGHT + y) * LIGHTMAP_WIDTH + x;
+ //if on one of the edges
+ n = y * LIGHTMAP_SIZE + x;
+ if ((polygonedges[n >> 3] & (1 << (n & 7)) ))
+ {
+ // multiply 'add' by the relative area being lit of the total visible lightmap pixel area
+ //
+ // first create a winding for the lightmap pixel
+ if (ds->surfaceType == MST_PATCH)
+ {
+ mesh = test->detailMesh;
+ if (y-ds->lightmapY >= mesh->height-1)
+ _printf("y outside mesh\n");
+ if (x-ds->lightmapX >= mesh->width-1)
+ _printf("x outside mesh\n");
+ VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[0]);
+ VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x-ds->lightmapX].xyz, w.points[1]);
+ VectorCopy( mesh->verts[(y+1-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[2]);
+ VectorCopy( mesh->verts[(y-ds->lightmapY)*mesh->width+x+1-ds->lightmapX].xyz, w.points[3]);
+ w.numpoints = 4;
+ }
+ else
+ {
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[0]);
+ VectorMA(w.points[0], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[0]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT - ds->lightmapX, ds->lightmapVecs[0], w.points[1]);
+ VectorMA(w.points[1], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[1]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[2]);
+ VectorMA(w.points[2], (float) y - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapY, ds->lightmapVecs[1], w.points[2]);
+ VectorMA(ds->lightmapOrigin, (float) x - LIGHTMAP_PIXELSHIFT + 1 - ds->lightmapX, ds->lightmapVecs[0], w.points[3]);
+ VectorMA(w.points[3], (float) y - LIGHTMAP_PIXELSHIFT - ds->lightmapY, ds->lightmapVecs[1], w.points[3]);
+ w.numpoints = 4;
+ }
+ //
+ // take the visible area of the lightmap pixel into account
+ //
+ //area = WindingArea(&w);
+ area = lightmappixelarea[k];
+ if (area <= 0)
+ continue;
+ // chop the lightmap pixel winding with the light volume
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ //if totally on the back
+ if (VS_ChopWinding(&w, &volume->planes[i], 0) == SIDE_BACK)
+ break;
+ }
+ // if the lightmap pixel is partly inside the light volume
+ if (i >= volume->numplanes)
+ {
+ insidearea = WindingArea(&w);
+ if (insidearea <= 0)
+ i = 0;
+ add = add * insidearea / area;
+ }
+ else
+ {
+ //DebugNet_DrawWinding(&w, 2);
+ continue; // this shouldn't happen
+ }
+ }
+ // get the light filter from all the translucent surfaces the light volume went through
+ VS_GetFilter(light, volume, base, filter);
+ //
+ color = &lightFloats[k*3];
+ color[0] += add * light->color[0] * filter[0];
+ color[1] += add * light->color[1] * filter[1];
+ color[2] += add * light->color[2] * filter[2];
+ }
+ }
+
+ MutexUnlock(test->mutex);
+}
+
+#endif
+
+/*
+=============
+VS_SplitLightVolume
+=============
+*/
+int VS_SplitLightVolume(lightvolume_t *volume, lightvolume_t *back, plane_t *split, float epsilon)
+{
+ lightvolume_t f, b;
+ vec_t dists[128];
+ int sides[128];
+ int counts[3];
+ vec_t dot;
+ int i, j;
+ vec_t *p1, *p2;
+ vec3_t mid;
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+ // determine sides for each point
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ dot = DotProduct (volume->points[i], split->normal);
+ dot -= split->dist;
+ dists[i] = dot;
+ if (dot > epsilon)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -epsilon)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+
+ if (!counts[1])
+ return 0; // completely on front side
+
+ if (!counts[0])
+ return 1; // completely on back side
+
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ f.numplanes = 0;
+ b.numplanes = 0;
+
+ for (i = 0; i < volume->numplanes; i++)
+ {
+ p1 = volume->points[i];
+
+ if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VS_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return 0; // can't chop -- fall back to original
+ }
+ if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VS_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return 0; // can't chop -- fall back to original
+ }
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy(p1, f.points[f.numplanes]);
+ VectorCopy(p1, b.points[b.numplanes]);
+ if (sides[i+1] == SIDE_BACK)
+ {
+ f.planes[f.numplanes] = *split;
+ b.planes[b.numplanes] = volume->planes[i];
+ }
+ else if (sides[i+1] == SIDE_FRONT)
+ {
+ f.planes[f.numplanes] = volume->planes[i];
+ b.planes[b.numplanes] = *split;
+ VectorInverse(b.planes[b.numplanes].normal);
+ b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
+ }
+ else //this shouldn't happen
+ {
+ f.planes[f.numplanes] = *split;
+ b.planes[b.numplanes] = *split;
+ VectorInverse(b.planes[b.numplanes].normal);
+ b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
+ }
+ f.numplanes++;
+ b.numplanes++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, f.points[f.numplanes]);
+ f.planes[f.numplanes] = volume->planes[i];
+ f.numplanes++;
+ }
+ if (sides[i] == SIDE_BACK)
+ {
+ VectorCopy (p1, b.points[b.numplanes]);
+ b.planes[b.numplanes] = volume->planes[i];
+ b.numplanes++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ if (f.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VS_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return 0; // can't chop -- fall back to original
+ }
+ if (b.numplanes >= MAX_POINTS_ON_FIXED_WINDING)
+ {
+ _printf("WARNING: VS_SplitLightVolume -> MAX_POINTS_ON_FIXED_WINDING overflowed\n");
+ return 0; // can't chop -- fall back to original
+ }
+
+ // generate a split point
+ p2 = volume->points[(i+1)%volume->numplanes];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (split->normal[j] == 1)
+ mid[j] = split->dist;
+ else if (split->normal[j] == -1)
+ mid[j] = -split->dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, f.points[f.numplanes]);
+ VectorCopy(mid, b.points[b.numplanes]);
+ if (sides[i+1] == SIDE_BACK)
+ {
+ f.planes[f.numplanes] = *split;
+ b.planes[b.numplanes] = volume->planes[i];
+ }
+ else
+ {
+ f.planes[f.numplanes] = volume->planes[i];
+ b.planes[b.numplanes] = *split;
+ VectorInverse(b.planes[b.numplanes].normal);
+ b.planes[b.numplanes].dist = -b.planes[b.numplanes].dist;
+ }
+ f.numplanes++;
+ b.numplanes++;
+ }
+ memcpy(volume->points, f.points, sizeof(vec3_t) * f.numplanes);
+ memcpy(volume->planes, f.planes, sizeof(plane_t) * f.numplanes);
+ volume->numplanes = f.numplanes;
+ memcpy(back->points, b.points, sizeof(vec3_t) * b.numplanes);
+ memcpy(back->planes, b.planes, sizeof(plane_t) * b.numplanes);
+ back->numplanes = b.numplanes;
+
+ return 2;
+}
+
+/*
+=============
+VS_PlaneForEdgeToWinding
+=============
+*/
+void VS_PlaneForEdgeToWinding(vec3_t p1, vec3_t p2, winding_t *w, int windingonfront, plane_t *plane)
+{
+ int i, j;
+ float length, d;
+ vec3_t v1, v2;
+
+ VectorSubtract(p2, p1, v1);
+ for (i = 0; i < w->numpoints; i++)
+ {
+ VectorSubtract (w->points[i], p1, v2);
+
+ plane->normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
+ plane->normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
+ plane->normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
+
+ // if points don't make a valid plane, skip it
+ length = plane->normal[0] * plane->normal[0]
+ + plane->normal[1] * plane->normal[1]
+ + plane->normal[2] * plane->normal[2];
+
+ if (length < ON_EPSILON)
+ continue;
+
+ length = 1/sqrt(length);
+
+ plane->normal[0] *= length;
+ plane->normal[1] *= length;
+ plane->normal[2] *= length;
+
+ plane->dist = DotProduct (w->points[i], plane->normal);
+ //
+ for (j = 0; j < w->numpoints; j++)
+ {
+ if (j == i)
+ continue;
+ d = DotProduct(w->points[j], plane->normal) - plane->dist;
+ if (windingonfront)
+ {
+ if (d < -ON_EPSILON)
+ break;
+ }
+ else
+ {
+ if (d > ON_EPSILON)
+ break;
+ }
+ }
+ if (j >= w->numpoints)
+ return;
+ }
+}
+
+/*
+=============
+VS_R_CastLightAtSurface
+=============
+*/
+void VS_R_FloodLight(vsound_t *light, lightvolume_t *volume, int cluster, int firstportal);
+
+void VS_R_CastLightAtSurface(vsound_t *light, lightvolume_t *volume)
+{
+ lsurfaceTest_t *test;
+ int i, n;
+
+ // light the surface with this volume
+ VS_LightSurfaceWithVolume(volume->surfaceNum, volume->facetNum, light, volume);
+ //
+ test = lsurfaceTest[ volume->surfaceNum ];
+ // if this is not a translucent surface
+ if ( !(test->shader->surfaceFlags & SURF_ALPHASHADOW) && !(test->shader->contents & CONTENTS_TRANSLUCENT))
+ return;
+ //
+ if (volume->numtransFacets >= MAX_TRANSLUCENTFACETS)
+ Error("a light valume went through more than %d translucent facets", MAX_TRANSLUCENTFACETS);
+ //add this translucent surface to the list
+ volume->transSurfaces[volume->numtransFacets] = volume->surfaceNum;
+ volume->transFacets[volume->numtransFacets] = volume->facetNum;
+ volume->numtransFacets++;
+ //clear the tested facets except the translucent ones
+ memset(volume->facetTested, 0, sizeof(volume->facetTested));
+ for (i = 0; i < volume->numtransFacets; i++)
+ {
+ test = lsurfaceTest[ volume->transSurfaces[i] ];
+ n = test->facets[volume->transFacets[i]].num;
+ volume->facetTested[n >> 3] |= 1 << (n & 7);
+ }
+ memset(volume->clusterTested, 0, sizeof(volume->clusterTested));
+ volume->endplane = volume->farplane;
+ volume->surfaceNum = -1;
+ volume->facetNum = 0;
+ VS_R_FloodLight(light, volume, volume->cluster, 0);
+ if (volume->surfaceNum >= 0)
+ {
+ VS_R_CastLightAtSurface(light, volume);
+ }
+}
+
+/*
+=============
+VS_R_SplitLightVolume
+=============
+*/
+static int numvolumes = 0;
+
+int VS_R_SplitLightVolume(vsound_t *light, lightvolume_t *volume, plane_t *split, int cluster, int firstportal)
+{
+ lightvolume_t back;
+ int res;
+
+ //
+ res = VS_SplitLightVolume(volume, &back, split, 0.1);
+ // if the volume was split
+ if (res == 2)
+ {
+ memcpy(back.clusterTested, volume->clusterTested, sizeof(back.clusterTested));
+ memcpy(back.facetTested, volume->facetTested, sizeof(back.facetTested));
+ back.num = numvolumes++;
+ back.endplane = volume->endplane;
+ back.surfaceNum = volume->surfaceNum;
+ back.facetNum = volume->facetNum;
+ back.type = volume->type;
+ back.cluster = volume->cluster;
+ back.farplane = volume->farplane;
+ if (volume->numtransFacets > 0)
+ {
+ memcpy(back.transFacets, volume->transFacets, sizeof(back.transFacets));
+ memcpy(back.transSurfaces, volume->transSurfaces, sizeof(back.transSurfaces));
+ }
+ back.numtransFacets = volume->numtransFacets;
+ //
+ // flood the volume at the back of the split plane
+ VS_R_FloodLight(light, &back, cluster, firstportal);
+ // if the back volume hit a surface
+ if (back.surfaceNum >= 0)
+ {
+ VS_R_CastLightAtSurface(light, &back);
+ }
+ }
+ return res;
+}
+
+/*
+=============
+VS_R_FloodLight
+=============
+*/
+void VS_R_FloodLight(vsound_t *light, lightvolume_t *volume, int cluster, int firstportal)
+{
+ int i, j, k, res, surfaceNum, backfaceculled, testculled;
+ float d;
+ winding_t winding, tmpwinding;
+ lleaf_t *leaf;
+ lportal_t *p;
+ lsurfaceTest_t *test;
+ lFacet_t *facet;
+ vec3_t dir1, dir2;
+ plane_t plane;
+
+ // DebugNet_RemoveAllPolys();
+ // VS_DrawLightVolume(light, volume);
+
+ // if the first portal is not zero then we've checked all occluders in this leaf already
+ if (firstportal == 0)
+ {
+ // check all potential occluders in this leaf
+ for (i = 0; i < leafs[cluster].numSurfaces; i++)
+ {
+ surfaceNum = clustersurfaces[leafs[cluster].firstSurface + i];
+ //
+ test = lsurfaceTest[ surfaceNum ];
+ if ( !test )
+ continue;
+ //
+ testculled = qfalse;
+ // use surface as an occluder
+ for (j = 0; j < test->numFacets; j++)
+ {
+ // use each facet as an occluder
+ facet = &test->facets[j];
+ //
+ // memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints);
+ // winding.numpoints = facet->numpoints;
+ // DebugNet_DrawWinding(&winding, 5);
+ //
+ // if the facet was tested already
+ if ( volume->facetTested[facet->num >> 3] & (1 << (facet->num & 7)) )
+ continue;
+ volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
+ // backface culling for planar surfaces
+ backfaceculled = qfalse;
+ if (!test->patch && !test->trisoup)
+ {
+ if (volume->type == VOLUME_NORMAL)
+ {
+ // facet backface culling
+ d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist;
+ if (d < 0)
+ {
+ // NOTE: this doesn't work too great because of sometimes very bad tesselation
+ // of surfaces that are supposed to be flat
+ // FIXME: to work around this problem we should make sure that all facets
+ // created from planar surfaces use the lightmapVecs normal vector
+ /*
+ if ( !test->shader->twoSided )
+ {
+ // skip all other facets of this surface as well because they are in the same plane
+ for (k = 0; k < test->numFacets; k++)
+ {
+ facet = &test->facets[k];
+ volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
+ }
+ }*/
+ backfaceculled = qtrue;
+ }
+ }
+ else
+ {
+ // FIXME: if all light source winding points are at the back of the facet
+ // plane then backfaceculled = qtrue
+ }
+ }
+ else // backface culling per facet for patches and triangle soups
+ {
+ if (volume->type == VOLUME_NORMAL)
+ {
+ // facet backface culling
+ d = DotProduct(light->origin, facet->plane.normal) - facet->plane.dist;
+ if (d < 0)
+ backfaceculled = qtrue;
+ }
+ else
+ {
+ // FIXME: if all light source winding points are at the back of the facet
+ // plane then backfaceculled = qtrue
+ }
+ }
+ /* chopping does this already
+ // check if this facet is totally or partly in front of the volume end plane
+ for (k = 0; k < facet->numpoints; k++)
+ {
+ d = DotProduct(volume->endplane.normal, facet->points[k]) - volume->endplane.dist;
+ if (d > ON_EPSILON)
+ break;
+ }
+ // if this facet is outside the light volume
+ if (k >= facet->numpoints)
+ continue;
+ */
+ //
+ if (backfaceculled)
+ {
+ // if the facet is not two sided
+ if ( !nobackfaceculling && !test->shader->twoSided )
+ continue;
+ // flip the winding
+ for (k = 0; k < facet->numpoints; k++)
+ VectorCopy(facet->points[k], winding.points[facet->numpoints - k - 1]);
+ winding.numpoints = facet->numpoints;
+ }
+ else
+ {
+ memcpy(winding.points, facet->points, sizeof(vec3_t) * facet->numpoints);
+ winding.numpoints = facet->numpoints;
+ }
+ //
+ if (!testculled)
+ {
+ testculled = qtrue;
+ // fast check if the surface sphere is totally behind the volume end plane
+ d = DotProduct(volume->endplane.normal, test->origin) - volume->endplane.dist;
+ if (d < -test->radius)
+ {
+ for (k = 0; k < test->numFacets; k++)
+ {
+ facet = &test->facets[k];
+ volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
+ }
+ break;
+ }
+ for (k = 0; k < volume->numplanes; k++)
+ {
+ d = DotProduct(volume->planes[k].normal, test->origin) - volume->planes[k].dist;
+ if (d < - test->radius)
+ {
+ for (k = 0; k < test->numFacets; k++)
+ {
+ facet = &test->facets[k];
+ volume->facetTested[facet->num >> 3] |= 1 << (facet->num & 7);
+ }
+ break;
+ }
+ }
+ if (k < volume->numplanes)
+ break;
+ }
+ //NOTE: we have to chop the facet winding with the volume end plane because
+ // the faces in Q3 are not stitched together nicely
+ res = VS_ChopWinding(&winding, &volume->endplane, 0.01);
+ // if the facet is on or at the back of the volume end plane
+ if (res == SIDE_BACK || res == SIDE_ON)
+ continue;
+ // check if the facet winding is totally or partly inside the light volume
+ memcpy(&tmpwinding, &winding, sizeof(winding_t));
+ for (k = 0; k < volume->numplanes; k++)
+ {
+ res = VS_ChopWinding(&tmpwinding, &volume->planes[k], 0.01);
+ if (res == SIDE_BACK || res == SIDE_ON)
+ break;
+ }
+ // if no part of the light volume is occluded by this facet
+ if (k < volume->numplanes)
+ continue;
+ //
+ for (k = 0; k < winding.numpoints; k++)
+ {
+ if (volume->type == VOLUME_DIRECTED)
+ {
+ VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1);
+ CrossProduct(light->normal, dir1, plane.normal);
+ VectorNormalize(plane.normal, plane.normal);
+ plane.dist = DotProduct(plane.normal, winding.points[k]);
+ }
+ else
+ {
+ VectorSubtract(winding.points[(k+1) % winding.numpoints], winding.points[k], dir1);
+ VectorSubtract(light->origin, winding.points[k], dir2);
+ CrossProduct(dir1, dir2, plane.normal);
+ VectorNormalize(plane.normal, plane.normal);
+ plane.dist = DotProduct(plane.normal, winding.points[k]);
+ }
+ res = VS_R_SplitLightVolume(light, volume, &plane, cluster, 0);
+ if (res == 1)
+ break; //the facet wasn't really inside the volume
+ }
+ if (k >= winding.numpoints)
+ {
+ volume->endplane = facet->plane;
+ if (backfaceculled)
+ {
+ VectorInverse(volume->endplane.normal);
+ volume->endplane.dist = -volume->endplane.dist;
+ }
+ volume->surfaceNum = surfaceNum;
+ volume->facetNum = j;
+ }
+ }
+ }
+ }
+ // we've tested all occluders in this cluster
+ volume->clusterTested[cluster >> 3] |= 1 << (cluster & 7);
+ // flood light through the portals of the current leaf
+ leaf = &leafs[cluster];
+ for (i = firstportal; i < leaf->numportals; i++)
+ {
+ p = leaf->portals[i];
+ //
+ // memcpy(&winding, p->winding, sizeof(winding_t));
+ // DebugNet_DrawWinding(&winding, 5);
+ // if already flooded into the cluster this portal leads to
+ if ( volume->clusterTested[p->leaf >> 3] & (1 << (p->leaf & 7)) )
+ continue;
+ //
+ if (volume->type == VOLUME_NORMAL)
+ {
+ // portal backface culling
+ d = DotProduct(light->origin, p->plane.normal) - p->plane.dist;
+ if (d > 0) // portal plane normal points into neighbour cluster
+ continue;
+ }
+ else
+ {
+ // FIXME: if all light source winding points are at the back of this portal
+ // plane then there's no need to flood through
+ }
+ // check if this portal is totally or partly in front of the volume end plane
+ // fast check with portal sphere
+ d = DotProduct(volume->endplane.normal, p->origin) - volume->endplane.dist;
+ if (d < -p->radius)
+ continue;
+ for (j = 0; j < p->winding->numpoints; j++)
+ {
+ d = DotProduct(volume->endplane.normal, p->winding->points[j]) - volume->endplane.dist;
+ if (d > -0.01)
+ break;
+ }
+ // if this portal is totally behind the light volume end plane
+ if (j >= p->winding->numpoints)
+ continue;
+ //distance from point light to portal
+ d = DotProduct(p->plane.normal, light->origin) - p->plane.dist;
+ // only check if a point light is Not *on* the portal
+ if (volume->type != VOLUME_NORMAL || fabs(d) > 0.1)
+ {
+ // check if the portal is partly or totally inside the light volume
+ memcpy(&winding, p->winding, sizeof(winding_t));
+ for (j = 0; j < volume->numplanes; j++)
+ {
+ res = VS_ChopWinding(&winding, &volume->planes[j], 0.01);
+ if (res == SIDE_BACK || res == SIDE_ON)
+ break;
+ }
+ // if the light volume does not go through this portal at all
+ if (j < volume->numplanes)
+ continue;
+ }
+ // chop the light volume with the portal
+ for (k = 0; k < p->winding->numpoints; k++)
+ {
+ if (volume->type == VOLUME_DIRECTED)
+ {
+ VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1);
+ CrossProduct(light->normal, dir1, plane.normal);
+ VectorNormalize(plane.normal, plane.normal);
+ plane.dist = DotProduct(plane.normal, p->winding->points[k]);
+ }
+ else
+ {
+ VectorSubtract(p->winding->points[(k+1) % p->winding->numpoints], p->winding->points[k], dir1);
+ VectorSubtract(light->origin, p->winding->points[k], dir2);
+ CrossProduct(dir1, dir2, plane.normal);
+ VectorNormalize(plane.normal, plane.normal);
+ plane.dist = DotProduct(plane.normal, p->winding->points[k]);
+ }
+ res = VS_R_SplitLightVolume(light, volume, &plane, cluster, i+1);
+ if (res == 1)
+ break; //volume didn't really go through the portal
+ }
+ // if the light volume went through the portal
+ if (k >= p->winding->numpoints)
+ {
+ // flood through the portal
+ VS_R_FloodLight(light, volume, p->leaf, 0);
+ }
+ }
+}
+
+/*
+=============
+VS_R_FloodAreaSpotLight
+=============
+*/
+void VS_FloodAreaSpotLight(vsound_t *light, winding_t *w, int leafnum)
+{
+}
+
+/*
+=============
+VS_R_SubdivideAreaSpotLight
+=============
+*/
+void VS_R_SubdivideAreaSpotLight(vsound_t *light, int nodenum, winding_t *w)
+{
+ int leafnum, res;
+ dnode_t *node;
+ dplane_t *plane;
+ winding_t back;
+ plane_t split;
+
+ while(nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+
+ VectorCopy(plane->normal, split.normal);
+ split.dist = plane->dist;
+ res = VS_SplitWinding (w, &back, &split, 0.1);
+
+ if (res == SIDE_FRONT)
+ {
+ nodenum = node->children[0];
+ }
+ else if (res == SIDE_BACK)
+ {
+ nodenum = node->children[1];
+ }
+ else if (res == SIDE_ON)
+ {
+ memcpy(&back, w, sizeof(winding_t));
+ VS_R_SubdivideAreaSpotLight(light, node->children[1], &back);
+ nodenum = node->children[0];
+ }
+ else
+ {
+ VS_R_SubdivideAreaSpotLight(light, node->children[1], &back);
+ nodenum = node->children[0];
+ }
+ }
+ leafnum = -nodenum - 1;
+ if (dleafs[leafnum].cluster != -1)
+ {
+ VS_FloodAreaSpotLight(light, w, leafnum);
+ }
+}
+
+/*
+=============
+VS_R_FloodRadialAreaLight
+=============
+*/
+void VS_FloodRadialAreaLight(vsound_t *light, winding_t *w, int leafnum)
+{
+}
+
+/*
+=============
+VS_R_SubdivideRadialAreaLight
+=============
+*/
+void VS_R_SubdivideRadialAreaLight(vsound_t *light, int nodenum, winding_t *w)
+{
+ int leafnum, res;
+ dnode_t *node;
+ dplane_t *plane;
+ winding_t back;
+ plane_t split;
+
+ while(nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+
+ VectorCopy(plane->normal, split.normal);
+ split.dist = plane->dist;
+ res = VS_SplitWinding (w, &back, &split, 0.1);
+
+ if (res == SIDE_FRONT)
+ {
+ nodenum = node->children[0];
+ }
+ else if (res == SIDE_BACK)
+ {
+ nodenum = node->children[1];
+ }
+ else if (res == SIDE_ON)
+ {
+ memcpy(&back, w, sizeof(winding_t));
+ VS_R_SubdivideRadialAreaLight(light, node->children[1], &back);
+ nodenum = node->children[0];
+ }
+ else
+ {
+ VS_R_SubdivideRadialAreaLight(light, node->children[1], &back);
+ nodenum = node->children[0];
+ }
+ }
+ leafnum = -nodenum - 1;
+ if (dleafs[leafnum].cluster != -1)
+ {
+ VS_FloodRadialAreaLight(light, w, leafnum);
+ }
+}
+
+/*
+=============
+VS_R_FloodDirectedLight
+=============
+*/
+void VS_FloodDirectedLight(vsound_t *light, winding_t *w, int leafnum)
+{
+ int i;
+ float dist;
+ lightvolume_t volume;
+ vec3_t dir;
+
+ if (light->atten_disttype == LDAT_NOSCALE)
+ {
+ // light travels without decrease in intensity over distance
+ dist = MAX_WORLD_COORD;
+ }
+ else
+ {
+ if ( light->atten_disttype == LDAT_LINEAR )
+ dist = light->photons * lightLinearScale;
+ else
+ dist = sqrt(light->photons);
+ }
+
+ memset(&volume, 0, sizeof(lightvolume_t));
+ for (i = 0; i < w->numpoints; i++)
+ {
+ VectorMA(w->points[i], dist, light->normal, volume.points[i]);
+ VectorSubtract(w->points[(i+1)%w->numpoints], w->points[i], dir);
+ CrossProduct(light->normal, dir, volume.planes[i].normal);
+ VectorNormalize(volume.planes[i].normal, volume.planes[i].normal);
+ volume.planes[i].dist = DotProduct(volume.planes[i].normal, w->points[i]);
+ }
+ volume.numplanes = w->numpoints;
+ VectorCopy(light->normal, volume.endplane.normal);
+ VectorInverse(volume.endplane.normal);
+ volume.endplane.dist = DotProduct(volume.endplane.normal, volume.points[0]);
+ volume.farplane = volume.endplane;
+ volume.surfaceNum = -1;
+ volume.type = VOLUME_DIRECTED;
+ volume.cluster = dleafs[leafnum].cluster;
+ VS_R_FloodLight(light, &volume, volume.cluster, 0);
+ if (volume.surfaceNum >= 0)
+ {
+ VS_R_CastLightAtSurface(light, &volume);
+ }
+}
+
+/*
+=============
+VS_R_SubdivideDirectedAreaLight
+=============
+*/
+void VS_R_SubdivideDirectedAreaLight(vsound_t *light, int nodenum, winding_t *w)
+{
+ int leafnum, res;
+ dnode_t *node;
+ dplane_t *plane;
+ winding_t back;
+ plane_t split;
+
+ while(nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planeNum];
+
+ VectorCopy(plane->normal, split.normal);
+ split.dist = plane->dist;
+ res = VS_SplitWinding (w, &back, &split, 0.1);
+
+ if (res == SIDE_FRONT)
+ {
+ nodenum = node->children[0];
+ }
+ else if (res == SIDE_BACK)
+ {
+ nodenum = node->children[1];
+ }
+ else if (res == SIDE_ON)
+ {
+ memcpy(&back, w, sizeof(winding_t));
+ VS_R_SubdivideDirectedAreaLight(light, node->children[1], &back);
+ nodenum = node->children[0];
+ }
+ else
+ {
+ VS_R_SubdivideDirectedAreaLight(light, node->children[1], &back);
+ nodenum = node->children[0];
+ }
+ }
+ leafnum = -nodenum - 1;
+ if (dleafs[leafnum].cluster != -1)
+ {
+ VS_FloodDirectedLight(light, w, leafnum);
+ }
+}
+
+/*
+=============
+VS_FloodLight
+=============
+*/
+void VS_FloodLight(vsound_t *light)
+{
+ lightvolume_t volume;
+ dleaf_t *leaf;
+ int leafnum, i, j, k, dir[2][4] = {{1, 1, -1, -1}, {1, -1, -1, 1}};
+ float a, step, dist, radius, windingdist;
+ vec3_t vec, r, p, temp;
+ winding_t winding;
+
+ switch(light->type)
+ {
+ case LIGHT_POINTRADIAL:
+ {
+ // source is a point
+ // light radiates in all directions
+ // creates sharp shadows
+ //
+ // create 6 volumes shining in the axis directions
+ // what about: 4 tetrahedrons instead?
+ //
+ if ( light->atten_disttype == LDAT_LINEAR )
+ dist = light->photons * lightLinearScale;
+ else
+ dist = sqrt(light->photons);
+ //always put the winding at a large distance to avoid epsilon issues
+ windingdist = MAX_WORLD_COORD;
+ if (dist > windingdist)
+ windingdist = dist;
+ //
+ leafnum = VS_LightLeafnum(light->origin);
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster == -1)
+ {
+ light->insolid = qtrue;
+ break;
+ }
+ // for each axis
+ for (i = 0; i < 3; i++)
+ {
+ // for both directions on the axis
+ for (j = -1; j <= 1; j += 2)
+ {
+ memset(&volume, 0, sizeof(lightvolume_t));
+ volume.numplanes = 0;
+ for (k = 0; k < 4; k ++)
+ {
+ volume.points[volume.numplanes][i] = light->origin[i] + j * windingdist;
+ volume.points[volume.numplanes][(i+1)%3] = light->origin[(i+1)%3] + dir[0][k] * windingdist;
+ volume.points[volume.numplanes][(i+2)%3] = light->origin[(i+2)%3] + dir[1][k] * windingdist;
+ volume.numplanes++;
+ }
+ if (j >= 0)
+ {
+ VectorCopy(volume.points[0], temp);
+ VectorCopy(volume.points[2], volume.points[0]);
+ VectorCopy(temp, volume.points[2]);
+ }
+ for (k = 0; k < volume.numplanes; k++)
+ {
+ VS_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]);
+ }
+ VectorCopy(light->origin, temp);
+ temp[i] += (float) j * dist;
+ VectorClear(volume.endplane.normal);
+ volume.endplane.normal[i] = -j;
+ volume.endplane.dist = DotProduct(volume.endplane.normal, temp); //DotProduct(volume.endplane.normal, volume.points[0]);
+ volume.farplane = volume.endplane;
+ volume.cluster = leaf->cluster;
+ volume.surfaceNum = -1;
+ volume.type = VOLUME_NORMAL;
+ //
+ memset(volume.facetTested, 0, sizeof(volume.facetTested));
+ memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
+ VS_R_FloodLight(light, &volume, leaf->cluster, 0);
+ if (volume.surfaceNum >= 0)
+ {
+ VS_R_CastLightAtSurface(light, &volume);
+ }
+ }
+ }
+ break;
+ }
+ case LIGHT_POINTSPOT:
+ {
+ // source is a point
+ // light is targetted
+ // creates sharp shadows
+ //
+ // what about using brushes to shape spot lights? that'd be pretty cool
+ //
+ if ( light->atten_disttype == LDAT_LINEAR )
+ dist = light->photons * lightLinearScale;
+ else
+ dist = sqrt(light->photons);
+ dist *= 2;
+ //
+ windingdist = 4096;
+ if (dist > windingdist)
+ windingdist = dist;
+ //take 8 times the cone radius because the spotlight also lights outside the cone
+ radius = 8 * windingdist * light->radiusByDist;
+ //
+ memset(&volume, 0, sizeof(lightvolume_t));
+ leafnum = VS_LightLeafnum(light->origin);
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster == -1)
+ {
+ light->insolid = qtrue;
+ break;
+ }
+ //
+ VectorClear(vec);
+ for (i = 0; i < 3; i++)
+ {
+ if (light->normal[i] > -0.9 && light->normal[i] < 0.9)
+ {
+ vec[i] = 1;
+ break;
+ }
+ }
+ CrossProduct(light->normal, vec, r);
+ VectorScale(r, radius, p);
+ volume.numplanes = 0;
+ step = 45;
+ for (a = step / 2; a < 360 + step / 2; a += step)
+ {
+ RotatePointAroundVector(volume.points[volume.numplanes], light->normal, p, a);
+ VectorAdd(light->origin, volume.points[volume.numplanes], volume.points[volume.numplanes]);
+ VectorMA(volume.points[volume.numplanes], windingdist, light->normal, volume.points[volume.numplanes]);
+ volume.numplanes++;
+ }
+ for (i = 0; i < volume.numplanes; i++)
+ {
+ VS_PlaneFromPoints(&volume.planes[i], light->origin, volume.points[(i+1)%volume.numplanes], volume.points[i]);
+ }
+ VectorMA(light->origin, dist, light->normal, temp);
+ VectorCopy(light->normal, volume.endplane.normal);
+ VectorInverse(volume.endplane.normal);
+ volume.endplane.dist = DotProduct(volume.endplane.normal, temp);//DotProduct(volume.endplane.normal, volume.points[0]);
+ volume.farplane = volume.endplane;
+ volume.cluster = leaf->cluster;
+ volume.surfaceNum = -1;
+ volume.type = VOLUME_NORMAL;
+ //
+ memset(volume.facetTested, 0, sizeof(volume.facetTested));
+ memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
+ VS_R_FloodLight(light, &volume, leaf->cluster, 0);
+ if (volume.surfaceNum >= 0)
+ {
+ VS_R_CastLightAtSurface(light, &volume);
+ }
+ break;
+ }
+ case LIGHT_POINTFAKESURFACE:
+ {
+ float value;
+ int n, axis;
+ vec3_t v, vecs[2];
+
+ if ( light->atten_disttype == LDAT_LINEAR )
+ dist = light->photons * lightLinearScale;
+ else
+ dist = sqrt(light->photons);
+ //always put the winding at a large distance to avoid epsilon issues
+ windingdist = 4096;
+ if (dist > windingdist)
+ windingdist = dist;
+ //
+ VectorMA(light->origin, 0.1, light->normal, light->origin);
+ //
+ leafnum = VS_LightLeafnum(light->origin);
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster == -1)
+ {
+ light->insolid = qtrue;
+ break;
+ }
+ value = 0;
+ for (i = 0; i < 3; i++)
+ {
+ if (fabs(light->normal[i]) > value)
+ {
+ value = fabs(light->normal[i]);
+ axis = i;
+ }
+ }
+ for (i = 0; i < 2; i++)
+ {
+ VectorClear(v);
+ v[(axis + 1 + i) % 3] = 1;
+ CrossProduct(light->normal, v, vecs[i]);
+ }
+ //cast 4 volumes at the front of the surface
+ for (i = -1; i <= 1; i += 2)
+ {
+ for (j = -1; j <= 1; j += 2)
+ {
+ for (n = 0; n < 2; n++)
+ {
+ memset(&volume, 0, sizeof(lightvolume_t));
+ volume.numplanes = 3;
+ VectorMA(light->origin, i * windingdist, vecs[0], volume.points[(i == j) == n]);
+ VectorMA(light->origin, j * windingdist, vecs[1], volume.points[(i != j) == n]);
+ VectorMA(light->origin, windingdist, light->normal, volume.points[2]);
+ for (k = 0; k < volume.numplanes; k++)
+ {
+ VS_PlaneFromPoints(&volume.planes[k], light->origin, volume.points[(k+1)%volume.numplanes], volume.points[k]);
+ }
+ VS_PlaneFromPoints(&volume.endplane, volume.points[0], volume.points[1], volume.points[2]);
+ VectorMA(light->origin, dist, light->normal, temp);
+ volume.endplane.dist = DotProduct(volume.endplane.normal, temp);
+ if (DotProduct(light->origin, volume.endplane.normal) - volume.endplane.dist > 0)
+ break;
+ }
+ volume.farplane = volume.endplane;
+ volume.cluster = leaf->cluster;
+ volume.surfaceNum = -1;
+ volume.type = VOLUME_NORMAL;
+ //
+ memset(volume.facetTested, 0, sizeof(volume.facetTested));
+ memset(volume.clusterTested, 0, sizeof(volume.clusterTested));
+
+ VS_R_FloodLight(light, &volume, leaf->cluster, 0);
+ if (volume.surfaceNum >= 0)
+ {
+ VS_R_CastLightAtSurface(light, &volume);
+ }
+ }
+ }
+ break;
+ }
+ case LIGHT_SURFACEDIRECTED:
+ {
+ // source is an area defined by a winding
+ // the light is unidirectional
+ // creates sharp shadows
+ // for instance sun light or laser light
+ //
+ memcpy(&winding, &light->w, sizeof(winding_t));
+ VS_R_SubdivideDirectedAreaLight(light, 0, &winding);
+ break;
+ }
+ case LIGHT_SURFACERADIAL:
+ {
+ // source is an area defined by a winding
+ // the light radiates in all directions at the front of the winding plane
+ //
+ memcpy(&winding, &light->w, sizeof(winding_t));
+ VS_R_SubdivideRadialAreaLight(light, 0, &winding);
+ break;
+ }
+ case LIGHT_SURFACESPOT:
+ {
+ // source is an area defined by a winding
+ // light is targetted but not unidirectional
+ //
+ memcpy(&winding, &light->w, sizeof(winding_t));
+ VS_R_SubdivideAreaSpotLight(light, 0, &winding);
+ break;
+ }
+ }
+}
+
+/*
+=============
+VS_FloodLightThread
+=============
+*/
+void VS_FloodLightThread(int num)
+{
+ VS_FloodLight(vsounds[num]);
+}
+
+/*
+=============
+VS_TestLightLeafs
+=============
+*/
+void VS_TestLightLeafs(void)
+{
+ int leafnum, i;
+ vsound_t *light;
+ dleaf_t *leaf;
+
+ for (i = 0; i < numvsounds; i++)
+ {
+ light = vsounds[i];
+ if (light->type != LIGHT_POINTRADIAL &&
+ light->type != LIGHT_POINTSPOT)
+ continue;
+ leafnum = VS_LightLeafnum(light->origin);
+ leaf = &dleafs[leafnum];
+ if (leaf->cluster == -1)
+ if (light->type == LIGHT_POINTRADIAL)
+ qprintf("light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]);
+ else if (light->type == LIGHT_POINTSPOT)
+ qprintf("spot light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]);
+ }
+}
+
+
+/*
+=============
+VS_DoForcedTraceLight
+=============
+*/
+// from light.c
+void TraceLtm( int num );
+
+void VS_DoForcedTraceLight(int num)
+{
+ dsurface_t *ds;
+ shaderInfo_t *si;
+
+ ds = &drawSurfaces[num];
+
+ if ( ds->surfaceType == MST_TRIANGLE_SOUP )
+ return;
+
+ if ( ds->lightmapNum < 0 )
+ return;
+
+ // always light entity surfaces with the old light algorithm
+ if ( !entitySurface[num] )
+ {
+ si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
+
+ if (defaulttracelight)
+ {
+ if (si->forceVLight)
+ return;
+ }
+ else
+ {
+ if (!si->forceTraceLight)
+ return;
+ }
+ }
+
+ TraceLtm(num);
+}
+
+/*
+=============
+VS_DoForcedTraceLightSurfaces
+=============
+*/
+void VS_DoForcedTraceLightSurfaces(void)
+{
+ _printf( "forced trace light\n" );
+ RunThreadsOnIndividual( numDrawSurfaces, qtrue, VS_DoForcedTraceLight );
+}
+
+float *oldLightFloats;
+
+/*
+=============
+VS_SurfaceRadiosity
+=============
+*/
+void VS_SurfaceRadiosity( int num ) {
+ dsurface_t *ds;
+ mesh_t *mesh;
+ shaderInfo_t *si;
+ lsurfaceTest_t *test;
+ int x, y, k;
+ vec3_t base, normal;
+ float *color, area;
+ vsound_t vsound;
+
+ ds = &drawSurfaces[num];
+
+ if ( ds->lightmapNum < 0 ) {
+ return; // doesn't have a lightmap
+ }
+
+ // vertex-lit triangle model
+ if ( ds->surfaceType == MST_TRIANGLE_SOUP ) {
+ return;
+ }
+
+ si = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
+ test = lsurfaceTest[ num ];
+
+ if (!test) {
+ return;
+ }
+
+ for (x = 0; x < ds->lightmapWidth; x++) {
+ for (y = 0; y < ds->lightmapHeight; y++) {
+ //
+ k = ( ds->lightmapNum * LIGHTMAP_HEIGHT + ds->lightmapY + y)
+ * LIGHTMAP_WIDTH + ds->lightmapX + x;
+ area = lightmappixelarea[k];
+ if (area <= 0)
+ continue;
+ //
+ if (ds->surfaceType == MST_PATCH)
+ {
+ mesh = test->detailMesh;
+ VectorCopy( mesh->verts[y*mesh->width+x].xyz, base);
+ VectorCopy( mesh->verts[y*mesh->width+x].normal, normal);
+ }
+ else
+ {
+ VectorMA(ds->lightmapOrigin, (float) x, ds->lightmapVecs[0], base);
+ VectorMA(base, (float) y, ds->lightmapVecs[1], base);
+ VectorCopy(test->facets[0].plane.normal, normal);
+ }
+ // create ligth from base
+ memset(&vsound, 0, sizeof(vsound_t));
+ color = &oldLightFloats[k*3];
+ // a few units away from the surface
+ VectorMA(base, 5, normal, vsound.origin);
+ ColorNormalize(color, vsound.color);
+ // ok this is crap
+ vsound.photons = VectorLength(color) * 0.05 * lightPointScale / (area * radiosity_scale);
+ // what about using a front facing light only ?
+ vsound.type = LIGHT_POINTRADIAL;
+ // flood the light from this lightmap pixel
+ VS_FloodLight(&vsound);
+ // only one thread at a time may write to the lightmap of this surface
+ MutexLock(test->mutex);
+ // don't light the lightmap pixel itself
+ lightFloats[k*3] = oldLightFloats[k*3];
+ lightFloats[k*3+1] = oldLightFloats[k*3+1];
+ lightFloats[k*3+2] = oldLightFloats[k*3+2];
+ //
+ MutexUnlock(test->mutex);
+ }
+ }
+}
+
+/*
+=============
+VS_Radiosity
+
+this aint working real well but it's fun to play with.
+=============
+*/
+void VS_Radiosity(void) {
+
+ oldLightFloats = lightFloats;
+ lightFloats = (float *) malloc(numLightBytes * sizeof(float));
+ memcpy(lightFloats, oldLightFloats, numLightBytes * sizeof(float));
+ _printf("%7i surfaces\n", numDrawSurfaces);
+ RunThreadsOnIndividual( numDrawSurfaces, qtrue, VS_SurfaceRadiosity );
+ free(oldLightFloats);
+}
+
+/*
+=============
+VS_LightWorld
+=============
+*/
+void VS_LightWorld(void)
+{
+ int i, numcastedvolumes, numvsoundsinsolid;
+ float f;
+
+ // find the optional world ambient
+ GetVectorForKey( &entities[0], "_color", lightAmbientColor );
+ f = FloatForKey( &entities[0], "ambient" );
+ VectorScale( lightAmbientColor, f, lightAmbientColor );
+ /*
+ _printf("\r%6d lights out of %d", 0, numvsounds);
+ for (i = 0; i < numvsounds; i++)
+ {
+ _printf("\r%6d", i);
+ VS_FloodLight(vsounds[i]);
+ }
+ _printf("\r%6d lights out of %d\n", i, numvsounds);
+ */
+ _printf("%7i lights\n", numvsounds);
+ RunThreadsOnIndividual( numvsounds, qtrue, VS_FloodLightThread );
+
+ numcastedvolumes = 0;
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ if (lsurfaceTest[i])
+ numcastedvolumes += lsurfaceTest[i]->numvolumes;
+ }
+ _printf("%7i light volumes casted\n", numcastedvolumes);
+ numvsoundsinsolid = 0;
+ for (i = 0; i < numvsounds; i++)
+ {
+ if (vsounds[i]->insolid)
+ numvsoundsinsolid++;
+ }
+ _printf("%7i lights in solid\n", numvsoundsinsolid);
+ //
+ radiosity_scale = 1;
+ for (i = 0; i < radiosity; i++) {
+ VS_Radiosity();
+ radiosity_scale <<= 1;
+ }
+ //
+ VS_StoreLightmap();
+ // redo surfaces with the old light algorithm when needed
+ VS_DoForcedTraceLightSurfaces();
+}
+
+/*
+=============
+VS_CreateEntitySpeakers
+=============
+*/
+entity_t *FindTargetEntity( const char *target );
+
+void VS_CreateEntitySpeakers (void)
+{
+ int i, c_entityLights;
+ vsound_t *dl;
+ entity_t *e, *e2;
+ const char *name;
+ const char *target;
+ vec3_t dest;
+ const char *_color;
+ float intensity;
+ int spawnflags;
+
+ //
+ c_entityLights = 0;
+ _printf("Creating entity lights...\n");
+ //
+ for ( i = 0 ; i < num_entities ; i++ ) {
+ e = &entities[i];
+ name = ValueForKey (e, "classname");
+ if (strncmp (name, "speaker", 7))
+ continue;
+
+ dl = malloc(sizeof(*dl));
+ memset (dl, 0, sizeof(*dl));
+
+ spawnflags = FloatForKey (e, "spawnflags");
+ if ( spawnflags & 1 ) {
+ dl->atten_disttype = LDAT_LINEAR;
+ }
+ if ( spawnflags & 2 ) {
+ dl->atten_disttype = LDAT_NOSCALE;
+ }
+ if ( spawnflags & 4 ) {
+ dl->atten_angletype = LAAT_QUADRATIC;
+ }
+ if ( spawnflags & 8 ) {
+ dl->atten_angletype = LAAT_DOUBLEQUADRATIC;
+ }
+
+ dl->atten_distscale = FloatForKey(e, "atten_distscale");
+ dl->atten_anglescale = FloatForKey(e, "atten_anglescale");
+
+ GetVectorForKey (e, "origin", dl->origin);
+ dl->style = FloatForKey (e, "_style");
+ if (!dl->style)
+ dl->style = FloatForKey (e, "style");
+ if (dl->style < 0)
+ dl->style = 0;
+
+ intensity = FloatForKey (e, "light");
+ if (!intensity)
+ intensity = FloatForKey (e, "_light");
+ if (!intensity)
+ intensity = 300;
+ _color = ValueForKey (e, "_color");
+ if (_color && _color[0])
+ {
+ sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]);
+ ColorNormalize (dl->color, dl->color);
+ }
+ else
+ dl->color[0] = dl->color[1] = dl->color[2] = 1.0;
+
+ intensity = intensity * lightPointScale;
+ dl->photons = intensity;
+
+ dl->type = LIGHT_POINTRADIAL;
+
+ // lights with a target will be spotlights
+ target = ValueForKey (e, "target");
+
+ if ( target[0] ) {
+ float radius;
+ float dist;
+
+ e2 = FindTargetEntity (target);
+ if (!e2) {
+ _printf ("WARNING: light at (%i %i %i) has missing target\n",
+ (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]);
+ } else {
+ GetVectorForKey (e2, "origin", dest);
+ VectorSubtract (dest, dl->origin, dl->normal);
+ dist = VectorNormalize (dl->normal, dl->normal);
+ radius = FloatForKey (e, "radius");
+ if ( !radius ) {
+ radius = 64;
+ }
+ if ( !dist ) {
+ dist = 64;
+ }
+ dl->radiusByDist = (radius + 16) / dist;
+ dl->type = LIGHT_POINTSPOT;
+ }
+ }
+ vsounds[numvsounds++] = dl;
+ c_entityLights++;
+ }
+ _printf("%7i entity lights\n", c_entityLights);
+}
+
+/*
+==================
+VS_SubdivideAreaLight
+==================
+*/
+void VS_SubdivideAreaLight( shaderInfo_t *ls, winding_t *w, vec3_t normal,
+ float areaSubdivide, qboolean backsplash ) {
+ float area, value, intensity;
+ vsound_t *dl, *dl2;
+ vec3_t mins, maxs;
+ int axis;
+ winding_t *front, *back;
+ vec3_t planeNormal;
+ float planeDist;
+
+ if ( !w ) {
+ return;
+ }
+
+ WindingBounds( w, mins, maxs );
+
+ // check for subdivision
+ for ( axis = 0 ; axis < 3 ; axis++ ) {
+ if ( maxs[axis] - mins[axis] > areaSubdivide ) {
+ VectorClear( planeNormal );
+ planeNormal[axis] = 1;
+ planeDist = ( maxs[axis] + mins[axis] ) * 0.5;
+ ClipWindingEpsilon ( w, planeNormal, planeDist, ON_EPSILON, &front, &back );
+ VS_SubdivideAreaLight( ls, front, normal, areaSubdivide, qfalse );
+ VS_SubdivideAreaLight( ls, back, normal, areaSubdivide, qfalse );
+ FreeWinding( w );
+ return;
+ }
+ }
+
+ // create a light from this
+ area = WindingArea (w);
+ if ( area <= 0 || area > 20000000 ) {
+ return;
+ }
+
+ dl = malloc(sizeof(*dl));
+ memset (dl, 0, sizeof(*dl));
+ dl->type = LIGHT_POINTFAKESURFACE;
+
+ WindingCenter( w, dl->origin );
+ memcpy(dl->w.points, w->points, sizeof(vec3_t) * w->numpoints);
+ dl->w.numpoints = w->numpoints;
+ VectorCopy ( normal, dl->normal);
+ VectorCopy ( normal, dl->plane);
+ dl->plane[3] = DotProduct( dl->origin, normal );
+
+ value = ls->value;
+ intensity = value * area * lightAreaScale;
+ VectorAdd( dl->origin, dl->normal, dl->origin );
+
+ VectorCopy( ls->color, dl->color );
+
+ dl->photons = intensity;
+
+ // emitColor is irrespective of the area
+ VectorScale( ls->color, value*lightFormFactorValueScale*lightAreaScale, dl->emitColor );
+ //
+ VectorCopy(dl->emitColor, dl->color);
+
+ dl->si = ls;
+
+ if ( ls->contents & CONTENTS_FOG ) {
+ dl->twosided = qtrue;
+ }
+
+ vsounds[numvsounds++] = dl;
+
+ // optionally create a point backsplash light
+ if ( backsplash && ls->backsplashFraction > 0 ) {
+
+ dl2 = malloc(sizeof(*dl));
+ memset (dl2, 0, sizeof(*dl2));
+ dl2->type = LIGHT_POINTRADIAL;
+
+ VectorMA( dl->origin, ls->backsplashDistance, normal, dl2->origin );
+
+ VectorCopy( ls->color, dl2->color );
+
+ dl2->photons = dl->photons * ls->backsplashFraction;
+ dl2->si = ls;
+
+ vsounds[numvsounds++] = dl2;
+ }
+}
+
+/*
+==================
+VS_CreateFakeSurfaceLights
+==================
+*/
+void VS_CreateFakeSurfaceLights( void ) {
+ int i, j, side;
+ dsurface_t *ds;
+ shaderInfo_t *ls;
+ winding_t *w;
+ lFacet_t *f;
+ vsound_t *dl;
+ vec3_t origin;
+ drawVert_t *dv;
+ int c_surfaceLights;
+ float lightSubdivide;
+ vec3_t normal;
+
+
+ c_surfaceLights = 0;
+ _printf ("Creating surface lights...\n");
+
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ // see if this surface is light emiting
+ ds = &drawSurfaces[i];
+
+ ls = ShaderInfoForShader( dshaders[ ds->shaderNum].shader );
+ if ( ls->value == 0 ) {
+ continue;
+ }
+
+ // determine how much we need to chop up the surface
+ if ( ls->lightSubdivide ) {
+ lightSubdivide = ls->lightSubdivide;
+ } else {
+ lightSubdivide = lightDefaultSubdivide;
+ }
+
+ c_surfaceLights++;
+
+ // an autosprite shader will become
+ // a point light instead of an area light
+ if ( ls->autosprite ) {
+ // autosprite geometry should only have four vertexes
+ if ( lsurfaceTest[i] ) {
+ // curve or misc_model
+ f = lsurfaceTest[i]->facets;
+ if ( lsurfaceTest[i]->numFacets != 1 || f->numpoints != 4 ) {
+ _printf( "WARNING: surface at (%i %i %i) has autosprite shader but isn't a quad\n",
+ (int)f->points[0], (int)f->points[1], (int)f->points[2] );
+ }
+ VectorAdd( f->points[0], f->points[1], origin );
+ VectorAdd( f->points[2], origin, origin );
+ VectorAdd( f->points[3], origin, origin );
+ VectorScale( origin, 0.25, origin );
+ } else {
+ // normal polygon
+ dv = &drawVerts[ ds->firstVert ];
+ if ( ds->numVerts != 4 ) {
+ _printf( "WARNING: surface at (%i %i %i) has autosprite shader but %i verts\n",
+ (int)dv->xyz[0], (int)dv->xyz[1], (int)dv->xyz[2] );
+ continue;
+ }
+
+ VectorAdd( dv[0].xyz, dv[1].xyz, origin );
+ VectorAdd( dv[2].xyz, origin, origin );
+ VectorAdd( dv[3].xyz, origin, origin );
+ VectorScale( origin, 0.25, origin );
+ }
+
+ dl = malloc(sizeof(*dl));
+ memset (dl, 0, sizeof(*dl));
+ VectorCopy( origin, dl->origin );
+ VectorCopy( ls->color, dl->color );
+ dl->photons = ls->value * lightPointScale;
+ dl->type = LIGHT_POINTRADIAL;
+ vsounds[numvsounds++] = dl;
+ continue;
+ }
+
+ // possibly create for both sides of the polygon
+ for ( side = 0 ; side <= ls->twoSided ; side++ ) {
+ // create area lights
+ if ( lsurfaceTest[i] ) {
+ // curve or misc_model
+ for ( j = 0 ; j < lsurfaceTest[i]->numFacets ; j++ ) {
+ f = lsurfaceTest[i]->facets + j;
+ w = AllocWinding( f->numpoints );
+ w->numpoints = f->numpoints;
+ memcpy( w->points, f->points, f->numpoints * 12 );
+
+ VectorCopy( f->plane.normal, normal );
+ if ( side ) {
+ winding_t *t;
+
+ t = w;
+ w = ReverseWinding( t );
+ FreeWinding( t );
+ VectorSubtract( vec3_origin, normal, normal );
+ }
+ VS_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
+ }
+ } else {
+ // normal polygon
+
+ w = AllocWinding( ds->numVerts );
+ w->numpoints = ds->numVerts;
+ for ( j = 0 ; j < ds->numVerts ; j++ ) {
+ VectorCopy( drawVerts[ds->firstVert+j].xyz, w->points[j] );
+ }
+ VectorCopy( ds->lightmapVecs[2], normal );
+ if ( side ) {
+ winding_t *t;
+
+ t = w;
+ w = ReverseWinding( t );
+ FreeWinding( t );
+ VectorSubtract( vec3_origin, normal, normal );
+ }
+ VS_SubdivideAreaLight( ls, w, normal, lightSubdivide, qtrue );
+ }
+ }
+ }
+
+ _printf( "%7i light emitting surfaces\n", c_surfaceLights );
+}
+
+
+/*
+==================
+VS_WindingForBrushSide
+==================
+*/
+winding_t *VS_WindingForBrushSide(dbrush_t *brush, int side, winding_t *w)
+{
+ int i, res;
+ winding_t *tmpw;
+ plane_t plane;
+
+ VectorCopy(dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].normal, plane.normal);
+ VectorInverse(plane.normal);
+ plane.dist = -dplanes[ dbrushsides[ brush->firstSide + side ].planeNum ].dist;
+ tmpw = BaseWindingForPlane( plane.normal, plane.dist );
+ memcpy(w->points, tmpw->points, sizeof(vec3_t) * tmpw->numpoints);
+ w->numpoints = tmpw->numpoints;
+
+ for (i = 0; i < brush->numSides; i++)
+ {
+ if (i == side)
+ continue;
+ VectorCopy(dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].normal, plane.normal);
+ VectorInverse(plane.normal);
+ plane.dist = -dplanes[ dbrushsides[ brush->firstSide + i ].planeNum ].dist;
+ res = VS_ChopWinding(w, &plane, 0.1);
+ if (res == SIDE_BACK)
+ return NULL;
+ }
+ return w;
+}
+
+/*
+==================
+VS_CreateSkyLights
+==================
+*/
+void VS_CreateSkyLights(void)
+{
+ int i, j, c_skyLights;
+ dbrush_t *b;
+ shaderInfo_t *si;
+ dbrushside_t *s;
+ vsound_t *dl;
+ vec3_t sunColor, sunDir = { 0.45, 0.3, 0.9 };
+ float d;
+
+ VectorNormalize(sunDir, sunDir);
+ VectorInverse(sunDir);
+
+ c_skyLights = 0;
+ _printf("Creating sky lights...\n");
+ // find the sky shader
+ for ( i = 0 ; i < numDrawSurfaces ; i++ ) {
+ si = ShaderInfoForShader( dshaders[ drawSurfaces[i].shaderNum ].shader );
+ if ( si->surfaceFlags & SURF_SKY ) {
+ VectorCopy( si->sunLight, sunColor );
+ VectorCopy( si->sunDirection, sunDir );
+ VectorInverse(sunDir);
+ break;
+ }
+ }
+
+ // find the brushes
+ for ( i = 0 ; i < numbrushes ; i++ ) {
+ b = &dbrushes[i];
+ for ( j = 0 ; j < b->numSides ; j++ ) {
+ s = &dbrushsides[ b->firstSide + j ];
+ if ( dshaders[ s->shaderNum ].surfaceFlags & SURF_SKY ) {
+ //if this surface doesn't face in the same direction as the sun
+ d = DotProduct(dplanes[ s->planeNum ].normal, sunDir);
+ if (d <= 0)
+ continue;
+ //
+ dl = malloc(sizeof(*dl));
+ memset (dl, 0, sizeof(*dl));
+ VectorCopy(sunColor, dl->color);
+ VectorCopy(sunDir, dl->normal);
+ VectorCopy(dplanes[ s->planeNum ].normal, dl->plane);
+ dl->plane[3] = dplanes[ s->planeNum ].dist;
+ dl->type = LIGHT_SURFACEDIRECTED;
+ dl->atten_disttype = LDAT_NOSCALE;
+ VS_WindingForBrushSide(b, j, &dl->w);
+// DebugNet_DrawWinding(&dl->w, 2);
+ //
+ vsounds[numvsounds++] = dl;
+ c_skyLights++;
+ }
+ }
+ }
+ _printf("%7i light emitting sky surfaces\n", c_skyLights);
+}
+
+/*
+==================
+VS_SetPortalSphere
+==================
+*/
+void VS_SetPortalSphere (lportal_t *p)
+{
+ int i;
+ vec3_t total, dist;
+ winding_t *w;
+ float r, bestr;
+
+ w = p->winding;
+ VectorCopy (vec3_origin, total);
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ VectorAdd (total, w->points[i], total);
+ }
+
+ for (i=0 ; i<3 ; i++)
+ total[i] /= w->numpoints;
+
+ bestr = 0;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ VectorSubtract (w->points[i], total, dist);
+ r = VectorLength (dist);
+ if (r > bestr)
+ bestr = r;
+ }
+ VectorCopy (total, p->origin);
+ p->radius = bestr;
+}
+
+/*
+==================
+VS_PlaneFromWinding
+==================
+*/
+void VS_PlaneFromWinding (winding_t *w, plane_t *plane)
+{
+ vec3_t v1, v2;
+
+ //calc plane
+ VectorSubtract (w->points[2], w->points[1], v1);
+ VectorSubtract (w->points[0], w->points[1], v2);
+ CrossProduct (v2, v1, plane->normal);
+ VectorNormalize (plane->normal, plane->normal);
+ plane->dist = DotProduct (w->points[0], plane->normal);
+}
+
+/*
+==================
+VS_AllocWinding
+==================
+*/
+winding_t *VS_AllocWinding (int points)
+{
+ winding_t *w;
+ int size;
+
+ if (points > MAX_POINTS_ON_WINDING)
+ Error ("NewWinding: %i points", points);
+
+ size = (int)((winding_t *)0)->points[points];
+ w = malloc (size);
+ memset (w, 0, size);
+
+ return w;
+}
+
+/*
+============
+VS_LoadPortals
+============
+*/
+void VS_LoadPortals (char *name)
+{
+ int i, j, hint;
+ lportal_t *p;
+ lleaf_t *l;
+ char magic[80];
+ FILE *f;
+ int numpoints;
+ winding_t *w;
+ int leafnums[2];
+ plane_t plane;
+ //
+
+ if (!strcmp(name,"-"))
+ f = stdin;
+ else
+ {
+ f = fopen(name, "r");
+ if (!f)
+ Error ("LoadPortals: couldn't read %s\n",name);
+ }
+
+ if (fscanf (f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces) != 4)
+ Error ("LoadPortals: failed to read header");
+ if (strcmp(magic, PORTALFILE))
+ Error ("LoadPortals: not a portal file");
+
+ _printf ("%6i portalclusters\n", portalclusters);
+ _printf ("%6i numportals\n", numportals);
+ _printf ("%6i numfaces\n", numfaces);
+
+ if (portalclusters >= MAX_CLUSTERS)
+ Error ("more than %d clusters in portal file\n", MAX_CLUSTERS);
+
+ // each file portal is split into two memory portals
+ portals = malloc(2*numportals*sizeof(lportal_t));
+ memset (portals, 0, 2*numportals*sizeof(lportal_t));
+
+ leafs = malloc(portalclusters*sizeof(lleaf_t));
+ memset (leafs, 0, portalclusters*sizeof(lleaf_t));
+
+ for (i=0, p=portals ; i<numportals ; i++)
+ {
+ if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3)
+ Error ("LoadPortals: reading portal %i", i);
+ if (numpoints > MAX_POINTS_ON_WINDING)
+ Error ("LoadPortals: portal %i has too many points", i);
+ if ( (unsigned)leafnums[0] > portalclusters
+ || (unsigned)leafnums[1] > portalclusters)
+ Error ("LoadPortals: reading portal %i", i);
+ if (fscanf (f, "%i ", &hint) != 1)
+ Error ("LoadPortals: reading hint state");
+
+ w = p->winding = VS_AllocWinding (numpoints);
+ w->numpoints = numpoints;
+
+ for (j=0 ; j<numpoints ; j++)
+ {
+ double v[3];
+ int k;
+
+ // scanf into double, then assign to vec_t
+ // so we don't care what size vec_t is
+ if (fscanf (f, "(%lf %lf %lf ) "
+ , &v[0], &v[1], &v[2]) != 3)
+ Error ("LoadPortals: reading portal %i", i);
+ for (k=0 ; k<3 ; k++)
+ w->points[j][k] = v[k];
+ }
+ fscanf (f, "\n");
+
+ // calc plane
+ VS_PlaneFromWinding (w, &plane);
+
+ // create forward portal
+ l = &leafs[leafnums[0]];
+ if (l->numportals == MAX_PORTALS_ON_LEAF)
+ Error ("Leaf with too many portals");
+ l->portals[l->numportals] = p;
+ l->numportals++;
+
+ p->winding = w;
+ VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
+ p->plane.dist = -plane.dist;
+ p->leaf = leafnums[1];
+ VS_SetPortalSphere (p);
+ p++;
+
+ // create backwards portal
+ l = &leafs[leafnums[1]];
+ if (l->numportals == MAX_PORTALS_ON_LEAF)
+ Error ("Leaf with too many portals");
+ l->portals[l->numportals] = p;
+ l->numportals++;
+
+ p->winding = VS_AllocWinding(w->numpoints);
+ p->winding->numpoints = w->numpoints;
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]);
+ }
+
+ p->plane = plane;
+ p->leaf = leafnums[0];
+ VS_SetPortalSphere (p);
+ p++;
+
+ }
+
+ fclose (f);
+}
+
+/*
+============
+VLightMain
+============
+*/
+int VSoundMain (int argc, char **argv) {
+ int i;
+ double start, end;
+ const char *value;
+
+ _printf ("----- VLighting ----\n");
+
+ for (i=1 ; i<argc ; i++) {
+ if (!strcmp(argv[i],"-v")) {
+ verbose = qtrue;
+ } else if (!strcmp(argv[i],"-threads")) {
+ numthreads = atoi (argv[i+1]);
+ _printf("num threads = %d\n", numthreads);
+ i++;
+ } else if (!strcmp(argv[i],"-area")) {
+ lightAreaScale *= atof(argv[i+1]);
+ _printf ("area light scaling at %f\n", lightAreaScale);
+ i++;
+ } else if (!strcmp(argv[i],"-point")) {
+ lightPointScale *= atof(argv[i+1]);
+ _printf ("point light scaling at %f\n", lightPointScale);
+ i++;
+ } else if (!strcmp(argv[i], "-samplesize")) {
+ samplesize = atoi(argv[i+1]);
+ if (samplesize < 1) samplesize = 1;
+ i++;
+ _printf("lightmap sample size is %dx%d units\n", samplesize, samplesize);
+ } else if (!strcmp(argv[i], "-nostitching")) {
+ nostitching = qtrue;
+ _printf("no stitching = true\n");
+ } else if (!strcmp(argv[i], "-noalphashading")) {
+ noalphashading = qtrue;
+ _printf("no alpha shading = true\n");
+ } else if (!strcmp(argv[i], "-nocolorshading")) {
+ nocolorshading = qtrue;
+ _printf("old style alpha shading = true\n");
+ } else if (!strcmp(argv[i], "-nobackfaceculling")) {
+ nobackfaceculling = qtrue;
+ _printf("no backface culling = true\n");
+ } else if (!strcmp(argv[i], "-tracelight")) {
+ defaulttracelight = qtrue;
+ _printf("default trace light = true\n");
+ } else if (!strcmp(argv[i], "-radiosity")) {
+ radiosity = atoi(argv[i+1]);
+ _printf("radiosity = %d\n", radiosity);
+ i++;
+ } else {
+ break;
+ }
+ }
+
+ ThreadSetDefault ();
+
+ if (i != argc - 1) {
+ _printf("usage: q3map -vsound [-<switch> [-<switch> ...]] <mapname>\n"
+ "\n"
+ "Switches:\n"
+ " v = verbose output\n"
+ " threads <X> = set number of threads to X\n"
+ " area <V> = set the area light scale to V\n"
+ " point <W> = set the point light scale to W\n"
+ " novertex = don't calculate vertex lighting\n"
+ " nogrid = don't calculate light grid for dynamic model lighting\n"
+ " nostitching = no polygon stitching before lighting\n"
+ " noalphashading = don't use alpha shading\n"
+ " nocolorshading = don't use color alpha shading\n"
+ " tracelight = use old light algorithm by default\n"
+ " samplesize <N> = set the lightmap pixel size to NxN units\n");
+ exit(0);
+ }
+
+ SetQdirFromPath (argv[i]);
+
+#ifdef _WIN32
+ InitPakFile(gamedir, NULL);
+#endif
+
+ strcpy (source, ExpandArg(argv[i]));
+ StripExtension (source);
+ DefaultExtension (source, ".bsp");
+
+ LoadShaderInfo();
+
+ _printf ("reading %s\n", source);
+
+ LoadBSPFile (source);
+ ParseEntities();
+
+ value = ValueForKey( &entities[0], "gridsize" );
+ if (strlen(value)) {
+ sscanf( value, "%f %f %f", &gridSize[0], &gridSize[1], &gridSize[2] );
+ _printf("grid size = {%1.1f, %1.1f, %1.1f}\n", gridSize[0], gridSize[1], gridSize[2]);
+ }
+
+ CountLightmaps();
+
+ StripExtension (source);
+ DefaultExtension (source, ".prt");
+
+ VS_LoadPortals(source);
+
+ // set surfaceOrigin
+ SetEntityOrigins();
+
+ // grid and vertex lighting
+ GridAndVertexLighting();
+
+#ifdef DEBUGNET
+ DebugNet_Setup();
+#endif
+
+ start = clock();
+
+ lightFloats = (float *) malloc(numLightBytes * sizeof(float));
+ memset(lightFloats, 0, numLightBytes * sizeof(float));
+
+ VS_InitSurfacesForTesting();
+
+ VS_CalcVisibleLightmapPixelArea();
+
+ numvsounds = 0;
+ VS_CreateEntitySpeakers();
+ VS_CreateFakeSurfaceLights();
+ VS_CreateSkyLights();
+
+ VS_TestLightLeafs();
+
+ VS_LightWorld();
+
+#ifndef LIGHTPOLYS
+ StripExtension (source);
+ DefaultExtension (source, ".bsp");
+ _printf ("writing %s\n", source);
+ WriteBSPFile (source);
+#endif
+
+ end = clock();
+
+ _printf ("%5.2f seconds elapsed\n", (end-start) / CLK_TCK);
+
+#ifdef LIGHTPOLYS
+ VS_DrawLightWindings();
+#endif
+
+#ifdef DEBUGNET
+ DebugNet_Shutdown();
+#endif
+ return 0;
+}
diff --git a/q3map/surface.c b/q3map/surface.c
index 462449d..75daf1c 100755
--- a/q3map/surface.c
+++ b/q3map/surface.c
@@ -19,1140 +19,1140 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-
-#include "qbsp.h"
-
-
-mapDrawSurface_t mapDrawSurfs[MAX_MAP_DRAW_SURFS];
-int numMapDrawSurfs;
-
-/*
-=============================================================================
-
-DRAWSURF CONSTRUCTION
-
-=============================================================================
-*/
-
-/*
-=================
-AllocDrawSurf
-=================
-*/
-mapDrawSurface_t *AllocDrawSurf( void ) {
- mapDrawSurface_t *ds;
-
- if ( numMapDrawSurfs >= MAX_MAP_DRAW_SURFS ) {
- Error( "MAX_MAP_DRAW_SURFS");
- }
- ds = &mapDrawSurfs[ numMapDrawSurfs ];
- numMapDrawSurfs++;
-
- return ds;
-}
-
-/*
-=================
-DrawSurfaceForSide
-=================
-*/
-#define SNAP_FLOAT_TO_INT 8
-#define SNAP_INT_TO_FLOAT (1.0/SNAP_FLOAT_TO_INT)
-
-mapDrawSurface_t *DrawSurfaceForSide( bspbrush_t *b, side_t *s, winding_t *w ) {
- mapDrawSurface_t *ds;
- int i, j;
- shaderInfo_t *si;
- drawVert_t *dv;
- float mins[2], maxs[2];
-
- // brush primitive :
- // axis base
- vec3_t texX,texY;
- vec_t x,y;
-
- if ( w->numpoints > 64 ) {
- Error( "DrawSurfaceForSide: w->numpoints = %i", w->numpoints );
- }
-
- si = s->shaderInfo;
-
- ds = AllocDrawSurf();
-
- ds->shaderInfo = si;
- ds->mapBrush = b;
- ds->side = s;
- ds->fogNum = -1;
- ds->numVerts = w->numpoints;
- ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
- memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
-
- mins[0] = mins[1] = 99999;
- maxs[0] = maxs[1] = -99999;
-
- // compute s/t coordinates from brush primitive texture matrix
- // compute axis base
- ComputeAxisBase( mapplanes[s->planenum].normal, texX, texY );
-
- for ( j = 0 ; j < w->numpoints ; j++ ) {
- dv = ds->verts + j;
-
- // round the xyz to a given precision
- for ( i = 0 ; i < 3 ; i++ ) {
- dv->xyz[i] = SNAP_INT_TO_FLOAT * floor( w->p[j][i] * SNAP_FLOAT_TO_INT + 0.5 );
- }
-
- if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
- {
- // calculate texture s/t
- dv->st[0] = s->vecs[0][3] + DotProduct( s->vecs[0], dv->xyz );
- dv->st[1] = s->vecs[1][3] + DotProduct( s->vecs[1], dv->xyz );
- dv->st[0] /= si->width;
- dv->st[1] /= si->height;
- }
- else
- {
- // calculate texture s/t from brush primitive texture matrix
- x = DotProduct( dv->xyz, texX );
- y = DotProduct( dv->xyz, texY );
- dv->st[0]=s->texMat[0][0]*x+s->texMat[0][1]*y+s->texMat[0][2];
- dv->st[1]=s->texMat[1][0]*x+s->texMat[1][1]*y+s->texMat[1][2];
- }
-
- for ( i = 0 ; i < 2 ; i++ ) {
- if ( dv->st[i] < mins[i] ) {
- mins[i] = dv->st[i];
- }
- if ( dv->st[i] > maxs[i] ) {
- maxs[i] = dv->st[i];
- }
- }
-
- // copy normal
- VectorCopy ( mapplanes[s->planenum].normal, dv->normal );
- }
-
- // adjust the texture coordinates to be as close to 0 as possible
- if ( !si->globalTexture ) {
- mins[0] = floor( mins[0] );
- mins[1] = floor( mins[1] );
- for ( i = 0 ; i < w->numpoints ; i++ ) {
- dv = ds->verts + i;
- dv->st[0] -= mins[0];
- dv->st[1] -= mins[1];
- }
- }
-
- return ds;
-}
-
-
-//=========================================================================
-
-
-
-
-typedef struct {
- int planenum;
- shaderInfo_t *shaderInfo;
- int count;
-} sideRef_t;
-
-#define MAX_SIDE_REFS MAX_MAP_PLANES
-
-sideRef_t sideRefs[MAX_SIDE_REFS];
-int numSideRefs;
-
-void AddSideRef( side_t *side ) {
- int i;
-
- for ( i = 0 ; i < numSideRefs ; i++ ) {
- if ( side->planenum == sideRefs[i].planenum
- && side->shaderInfo == sideRefs[i].shaderInfo ) {
- sideRefs[i].count++;
- return;
- }
- }
-
- if ( numSideRefs == MAX_SIDE_REFS ) {
- Error( "MAX_SIDE_REFS" );
- }
-
- sideRefs[i].planenum = side->planenum;
- sideRefs[i].shaderInfo = side->shaderInfo;
- sideRefs[i].count++;
- numSideRefs++;
-}
-
-
-/*
-=====================
-MergeSides
-
-=====================
-*/
-void MergeSides( entity_t *e, tree_t *tree ) {
- int i;
-
- qprintf( "----- MergeSides -----\n");
-
- for ( i = e->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
-// AddSideRef( side );
- }
-
- qprintf( "%5i siderefs\n", numSideRefs );
-}
-
-//=====================================================================
-
-/*
-===================
-SubdivideDrawSurf
-===================
-*/
-void SubdivideDrawSurf( mapDrawSurface_t *ds, winding_t *w, float subdivisions ) {
- int i;
- int axis;
- vec3_t bounds[2];
- const float epsilon = 0.1;
- int subFloor, subCeil;
- winding_t *frontWinding, *backWinding;
- mapDrawSurface_t *newds;
-
- if ( !w ) {
- return;
- }
- if ( w->numpoints < 3 ) {
- Error( "SubdivideDrawSurf: Bad w->numpoints" );
- }
-
- ClearBounds( bounds[0], bounds[1] );
- for ( i = 0 ; i < w->numpoints ; i++ ) {
- AddPointToBounds( w->p[i], bounds[0], bounds[1] );
- }
-
- for ( axis = 0 ; axis < 3 ; axis++ ) {
- vec3_t planePoint = { 0, 0, 0 };
- vec3_t planeNormal = { 0, 0, 0 };
- float d;
-
- subFloor = floor( bounds[0][axis] / subdivisions ) * subdivisions;
- subCeil = ceil( bounds[1][axis] / subdivisions ) * subdivisions;
-
- planePoint[axis] = subFloor + subdivisions;
- planeNormal[axis] = -1;
-
- d = DotProduct( planePoint, planeNormal );
-
- // subdivide if necessary
- if ( subCeil - subFloor > subdivisions ) {
- // gotta clip polygon into two polygons
- ClipWindingEpsilon( w, planeNormal, d, epsilon, &frontWinding, &backWinding );
-
- // the clip may not produce two polygons if it was epsilon close
- if ( !frontWinding ) {
- w = backWinding;
- } else if ( !backWinding ) {
- w = frontWinding;
- } else {
- SubdivideDrawSurf( ds, frontWinding, subdivisions );
- SubdivideDrawSurf( ds, backWinding, subdivisions );
-
- return;
- }
- }
- }
-
- // emit this polygon
- newds = DrawSurfaceForSide( ds->mapBrush, ds->side, w );
- newds->fogNum = ds->fogNum;
-}
-
-
-/*
-=====================
-SubdivideDrawSurfs
-
-Chop up surfaces that have subdivision attributes
-=====================
-*/
-void SubdivideDrawSurfs( entity_t *e, tree_t *tree ) {
- int i;
- mapDrawSurface_t *ds;
- int numBaseDrawSurfs;
- winding_t *w;
- float subdivision;
- shaderInfo_t *si;
-
- qprintf( "----- SubdivideDrawSurfs -----\n");
- numBaseDrawSurfs = numMapDrawSurfs;
- for ( i = e->firstDrawSurf ; i < numBaseDrawSurfs ; i++ ) {
- ds = &mapDrawSurfs[i];
-
- // only subdivide brush sides, not patches or misc_models
- if ( !ds->side ) {
- continue;
- }
-
- // check subdivision for shader
- si = ds->side->shaderInfo;
- if ( !si ) {
- continue;
- }
-
- if (ds->shaderInfo->autosprite || si->autosprite) {
- continue;
- }
-
- subdivision = si->subdivisions;
- if ( !subdivision ) {
- continue;
- }
-
- w = WindingFromDrawSurf( ds );
- ds->numVerts = 0; // remove this reference
- SubdivideDrawSurf( ds, w, subdivision );
- }
-
-}
-
-
-//===================================================================================
-
-/*
-====================
-ClipSideIntoTree_r
-
-Adds non-opaque leaf fragments to the convex hull
-====================
-*/
-void ClipSideIntoTree_r( winding_t *w, side_t *side, node_t *node ) {
- plane_t *plane;
- winding_t *front, *back;
-
- if ( !w ) {
- return;
- }
-
- if ( node->planenum != PLANENUM_LEAF ) {
- if ( side->planenum == node->planenum ) {
- ClipSideIntoTree_r( w, side, node->children[0] );
- return;
- }
- if ( side->planenum == ( node->planenum ^ 1) ) {
- ClipSideIntoTree_r( w, side, node->children[1] );
- return;
- }
-
- plane = &mapplanes[ node->planenum ];
- ClipWindingEpsilon ( w, plane->normal, plane->dist,
- ON_EPSILON, &front, &back );
- FreeWinding( w );
-
- ClipSideIntoTree_r( front, side, node->children[0] );
- ClipSideIntoTree_r( back, side, node->children[1] );
-
- return;
- }
-
- // if opaque leaf, don't add
- if ( !node->opaque ) {
- AddWindingToConvexHull( w, &side->visibleHull, mapplanes[ side->planenum ].normal );
- }
-
- FreeWinding( w );
- return;
-}
-
-
-/*
-=====================
-ClipSidesIntoTree
-
-Creates side->visibleHull for all visible sides
-
-The drawsurf for a side will consist of the convex hull of
-all points in non-opaque clusters, which allows overlaps
-to be trimmed off automatically.
-=====================
-*/
-void ClipSidesIntoTree( entity_t *e, tree_t *tree ) {
- bspbrush_t *b;
- int i;
- winding_t *w;
- side_t *side, *newSide;
- shaderInfo_t *si;
-
- qprintf( "----- ClipSidesIntoTree -----\n");
-
- for ( b = e->brushes ; b ; b = b->next ) {
- for ( i = 0 ; i < b->numsides ; i++ ) {
- side = &b->sides[i];
- if ( !side->winding) {
- continue;
- }
- w = CopyWinding( side->winding );
- side->visibleHull = NULL;
- ClipSideIntoTree_r( w, side, tree->headnode );
-
- w = side->visibleHull;
- if ( !w ) {
- continue;
- }
- si = side->shaderInfo;
- if ( !si ) {
- continue;
- }
- // don't create faces for non-visible sides
- if ( si->surfaceFlags & SURF_NODRAW ) {
- continue;
- }
-
- // always use the original quad winding for auto sprites
- if ( side->shaderInfo->autosprite ) {
- w = side->winding;
- }
- //
- if ( side->bevel ) {
- Error( "monkey tried to create draw surface for brush bevel" );
- }
- // save this winding as a visible surface
- DrawSurfaceForSide( b, side, w );
-
- // make a back side for it if needed
- if ( !(si->contents & CONTENTS_FOG) ) {
- continue;
- }
-
- // duplicate the up-facing side
- w = ReverseWinding( w );
-
- newSide = malloc( sizeof( *side ) );
- *newSide = *side;
- newSide->visibleHull = w;
- newSide->planenum ^= 1;
-
- // save this winding as a visible surface
- DrawSurfaceForSide( b, newSide, w );
-
- }
- }
-}
-
-/*
-===================================================================================
-
- FILTER REFERENCES DOWN THE TREE
-
-===================================================================================
-*/
-
-/*
-====================
-FilterDrawSurfIntoTree
-
-Place a reference to the given drawsurf in every leaf it contacts
-We assume that the point mesh aproximation to the curve will get a
-reference into all the leafs we need.
-====================
-*/
-int FilterMapDrawSurfIntoTree( vec3_t point, mapDrawSurface_t *ds, node_t *node ) {
- drawSurfRef_t *dsr;
- float d;
- plane_t *plane;
- int c;
-
- if ( node->planenum != PLANENUM_LEAF ) {
- plane = &mapplanes[ node->planenum ];
- d = DotProduct( point, plane->normal ) - plane->dist;
- c = 0;
- if ( d >= -ON_EPSILON ) {
- c += FilterMapDrawSurfIntoTree( point, ds, node->children[0] );
- }
- if ( d <= ON_EPSILON ) {
- c += FilterMapDrawSurfIntoTree( point, ds, node->children[1] );
- }
- return c;
- }
-
- // if opaque leaf, don't add
- if ( node->opaque ) {
- return 0;
- }
-
- // add the drawsurf if it hasn't been already
- for ( dsr = node->drawSurfReferences ; dsr ; dsr = dsr->nextRef ) {
- if ( dsr->outputNumber == numDrawSurfaces ) {
- return 0; // already referenced
- }
- }
-
- dsr = malloc( sizeof( *dsr ) );
- dsr->outputNumber = numDrawSurfaces;
- dsr->nextRef = node->drawSurfReferences;
- node->drawSurfReferences = dsr;
- return 1;
-}
-
-/*
-====================
-FilterDrawSurfIntoTree_r
-
-Place a reference to the given drawsurf in every leaf it is in
-====================
-*/
-int FilterMapDrawSurfIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node ) {
- drawSurfRef_t *dsr;
- plane_t *plane;
- int total;
- winding_t *front, *back;
-
- if ( node->planenum != PLANENUM_LEAF ) {
- plane = &mapplanes[ node->planenum ];
- ClipWindingEpsilon ( w, plane->normal, plane->dist,
- ON_EPSILON, &front, &back );
-
- total = 0;
- if ( front ) {
- total += FilterMapDrawSurfIntoTree_r( front, ds, node->children[0] );
- }
- if ( back ) {
- total += FilterMapDrawSurfIntoTree_r( back, ds, node->children[1] );
- }
-
- FreeWinding( w );
- return total;
- }
-
- // if opaque leaf, don't add
- if ( node->opaque ) {
- return 0;
- }
-
- // add the drawsurf if it hasn't been already
- for ( dsr = node->drawSurfReferences ; dsr ; dsr = dsr->nextRef ) {
- if ( dsr->outputNumber == numDrawSurfaces ) {
- return 0; // already referenced
- }
- }
-
- dsr = malloc( sizeof( *dsr ) );
- dsr->outputNumber = numDrawSurfaces;
- dsr->nextRef = node->drawSurfReferences;
- node->drawSurfReferences = dsr;
- return 1;
-}
-
-/*
-====================
-FilterSideIntoTree_r
-
-Place a reference to the given drawsurf in every leaf it contacts
-====================
-*/
-int FilterSideIntoTree_r( winding_t *w, side_t *side, mapDrawSurface_t *ds, node_t *node ) {
- drawSurfRef_t *dsr;
- plane_t *plane;
- winding_t *front, *back;
- int total;
-
- if ( !w ) {
- return 0;
- }
-
- if ( node->planenum != PLANENUM_LEAF ) {
- if ( side->planenum == node->planenum ) {
- return FilterSideIntoTree_r( w, side, ds, node->children[0] );
- }
- if ( side->planenum == ( node->planenum ^ 1) ) {
- return FilterSideIntoTree_r( w, side, ds, node->children[1] );
- }
-
- plane = &mapplanes[ node->planenum ];
- ClipWindingEpsilon ( w, plane->normal, plane->dist,
- ON_EPSILON, &front, &back );
-
- total = FilterSideIntoTree_r( front, side, ds, node->children[0] );
- total += FilterSideIntoTree_r( back, side, ds, node->children[1] );
-
- FreeWinding( w );
- return total;
- }
-
- // if opaque leaf, don't add
- if ( node->opaque ) {
- return 0;
- }
-
- dsr = malloc( sizeof( *dsr ) );
- dsr->outputNumber = numDrawSurfaces;
- dsr->nextRef = node->drawSurfReferences;
- node->drawSurfReferences = dsr;
-
- FreeWinding( w );
- return 1;
-}
-
-
-/*
-=====================
-FilterFaceIntoTree
-=====================
-*/
-int FilterFaceIntoTree( mapDrawSurface_t *ds, tree_t *tree ) {
- int l;
- winding_t *w;
-
- w = WindingFromDrawSurf( ds );
- l = FilterSideIntoTree_r( w, ds->side, ds, tree->headnode );
-
- return l;
-}
-
-
-
-/*
-=====================
-FilterPatchSurfIntoTree
-=====================
-*/
-#define SUBDIVISION_LIMIT 8.0
-int FilterPatchSurfIntoTree( mapDrawSurface_t *ds, tree_t *tree ) {
- int i, j;
- int l;
- mesh_t baseMesh, *subdividedMesh;
- winding_t *w;
-
- baseMesh.width = ds->patchWidth;
- baseMesh.height = ds->patchHeight;
- baseMesh.verts = ds->verts;
- subdividedMesh = SubdivideMesh( baseMesh, SUBDIVISION_LIMIT, 32 );
-
- l = 0;
- for (i = 0; i < subdividedMesh->width-1; i++) {
- for (j = 0; j < subdividedMesh->height-1; j++) {
- w = AllocWinding(3);
- VectorCopy(subdividedMesh->verts[j * subdividedMesh->width + i].xyz, w->p[0]);
- VectorCopy(subdividedMesh->verts[j * subdividedMesh->width + i + 1].xyz, w->p[1]);
- VectorCopy(subdividedMesh->verts[(j+1) * subdividedMesh->width + i].xyz, w->p[2]);
- w->numpoints = 3;
- l += FilterMapDrawSurfIntoTree_r( w, ds, tree->headnode );
- w = AllocWinding(3);
- VectorCopy(subdividedMesh->verts[j * subdividedMesh->width + i + 1].xyz, w->p[0]);
- VectorCopy(subdividedMesh->verts[(j+1) * subdividedMesh->width + i + 1].xyz, w->p[1]);
- VectorCopy(subdividedMesh->verts[(j+1) * subdividedMesh->width + i].xyz, w->p[2]);
- w->numpoints = 3;
- l += FilterMapDrawSurfIntoTree_r( w, ds, tree->headnode );
- }
- }
-
- // also use the old point filtering into the tree
- for ( i = 0 ; i < subdividedMesh->width * subdividedMesh->height ; i++ ) {
- l += FilterMapDrawSurfIntoTree( subdividedMesh->verts[i].xyz, ds, tree->headnode );
- }
-
- free(subdividedMesh);
-
- return l;
-}
-
-
-/*
-=====================
-FilterMiscModelSurfIntoTree
-=====================
-*/
-int FilterMiscModelSurfIntoTree( mapDrawSurface_t *ds, tree_t *tree ) {
- int i;
- int l;
- winding_t *w;
-
- l = 0;
- for (i = 0; i < ds->numIndexes-2; i++) {
- w = AllocWinding(3);
- VectorCopy(ds->verts[ds->indexes[i]].xyz, w->p[0]);
- VectorCopy(ds->verts[ds->indexes[i+1]].xyz, w->p[1]);
- VectorCopy(ds->verts[ds->indexes[i+2]].xyz, w->p[2]);
- w->numpoints = 3;
- l += FilterMapDrawSurfIntoTree_r( w, ds, tree->headnode );
- }
-
- // also use the old point filtering into the tree
- for ( i = 0 ; i < ds->numVerts ; i++ ) {
- l += FilterMapDrawSurfIntoTree( ds->verts[i].xyz, ds, tree->headnode );
- }
-
- return l;
-}
-
-/*
-=====================
-FilterFlareSurfIntoTree
-=====================
-*/
-int FilterFlareSurfIntoTree( mapDrawSurface_t *ds, tree_t *tree ) {
- return FilterMapDrawSurfIntoTree( ds->lightmapOrigin, ds, tree->headnode );
-}
-
-
-//======================================================================
-
-int c_stripSurfaces, c_fanSurfaces;
-
-/*
-==================
-IsTriangleDegenerate
-
-Returns qtrue if all three points are collinear or backwards
-===================
-*/
-#define COLINEAR_AREA 10
-static qboolean IsTriangleDegenerate( drawVert_t *points, int a, int b, int c ) {
- vec3_t v1, v2, v3;
- float d;
-
- VectorSubtract( points[b].xyz, points[a].xyz, v1 );
- VectorSubtract( points[c].xyz, points[a].xyz, v2 );
- CrossProduct( v1, v2, v3 );
- d = VectorLength( v3 );
-
- // assume all very small or backwards triangles will cause problems
- if ( d < COLINEAR_AREA ) {
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-===============
-SurfaceAsTriFan
-
-The surface can't be represented as a single tristrip without
-leaving a degenerate triangle (and therefore a crack), so add
-a point in the middle and create (points-1) triangles in fan order
-===============
-*/
-static void SurfaceAsTriFan( dsurface_t *ds ) {
- int i;
- int colorSum[4];
- drawVert_t *mid, *v;
-
- // create a new point in the center of the face
- if ( numDrawVerts == MAX_MAP_DRAW_VERTS ) {
- Error( "MAX_MAP_DRAW_VERTS" );
- }
- mid = &drawVerts[ numDrawVerts ];
- numDrawVerts++;
-
- colorSum[0] = colorSum[1] = colorSum[2] = colorSum[3] = 0;
-
- v = drawVerts + ds->firstVert;
- for (i = 0 ; i < ds->numVerts ; i++, v++ ) {
- VectorAdd( mid->xyz, v->xyz, mid->xyz );
- mid->st[0] += v->st[0];
- mid->st[1] += v->st[1];
- mid->lightmap[0] += v->lightmap[0];
- mid->lightmap[1] += v->lightmap[1];
-
- colorSum[0] += v->color[0];
- colorSum[1] += v->color[1];
- colorSum[2] += v->color[2];
- colorSum[3] += v->color[3];
- }
-
- mid->xyz[0] /= ds->numVerts;
- mid->xyz[1] /= ds->numVerts;
- mid->xyz[2] /= ds->numVerts;
-
- mid->st[0] /= ds->numVerts;
- mid->st[1] /= ds->numVerts;
-
- mid->lightmap[0] /= ds->numVerts;
- mid->lightmap[1] /= ds->numVerts;
-
- mid->color[0] = colorSum[0] / ds->numVerts;
- mid->color[1] = colorSum[1] / ds->numVerts;
- mid->color[2] = colorSum[2] / ds->numVerts;
- mid->color[3] = colorSum[3] / ds->numVerts;
-
- VectorCopy((drawVerts+ds->firstVert)->normal, mid->normal );
-
- // fill in indices in trifan order
- if ( numDrawIndexes + ds->numVerts*3 > MAX_MAP_DRAW_INDEXES ) {
- Error( "MAX_MAP_DRAWINDEXES" );
- }
- ds->firstIndex = numDrawIndexes;
- ds->numIndexes = ds->numVerts*3;
-
- //FIXME
- // should be: for ( i = 0 ; i < ds->numVerts ; i++ ) {
- // set a break point and test this in a map
- //for ( i = 0 ; i < ds->numVerts*3 ; i++ ) {
- for ( i = 0 ; i < ds->numVerts ; i++ ) {
- drawIndexes[numDrawIndexes++] = ds->numVerts;
- drawIndexes[numDrawIndexes++] = i;
- drawIndexes[numDrawIndexes++] = (i+1) % ds->numVerts;
- }
-
- ds->numVerts++;
-}
-
-
-/*
-================
-SurfaceAsTristrip
-
-Try to create indices that make (points-2) triangles in tristrip order
-================
-*/
-#define MAX_INDICES 1024
-static void SurfaceAsTristrip( dsurface_t *ds ) {
- int i;
- int rotate;
- int numIndices;
- int ni;
- int a, b, c;
- int indices[MAX_INDICES];
-
- // determine the triangle strip order
- numIndices = ( ds->numVerts - 2 ) * 3;
- if ( numIndices > MAX_INDICES ) {
- Error( "MAX_INDICES exceeded for surface" );
- }
-
- // try all possible orderings of the points looking
- // for a strip order that isn't degenerate
- for ( rotate = 0 ; rotate < ds->numVerts ; rotate++ ) {
- for ( ni = 0, i = 0 ; i < ds->numVerts - 2 - i ; i++ ) {
- a = ( ds->numVerts - 1 - i + rotate ) % ds->numVerts;
- b = ( i + rotate ) % ds->numVerts;
- c = ( ds->numVerts - 2 - i + rotate ) % ds->numVerts;
-
- if ( IsTriangleDegenerate( drawVerts + ds->firstVert, a, b, c ) ) {
- break;
- }
- indices[ni++] = a;
- indices[ni++] = b;
- indices[ni++] = c;
-
- if ( i + 1 != ds->numVerts - 1 - i ) {
- a = ( ds->numVerts - 2 - i + rotate ) % ds->numVerts;
- b = ( i + rotate ) % ds->numVerts;
- c = ( i + 1 + rotate ) % ds->numVerts;
-
- if ( IsTriangleDegenerate( drawVerts + ds->firstVert, a, b, c ) ) {
- break;
- }
- indices[ni++] = a;
- indices[ni++] = b;
- indices[ni++] = c;
- }
- }
- if ( ni == numIndices ) {
- break; // got it done without degenerate triangles
- }
- }
-
- // if any triangle in the strip is degenerate,
- // render from a centered fan point instead
- if ( ni < numIndices ) {
- c_fanSurfaces++;
- SurfaceAsTriFan( ds );
- return;
- }
-
- // a normal tristrip
- c_stripSurfaces++;
-
- if ( numDrawIndexes + ni > MAX_MAP_DRAW_INDEXES ) {
- Error( "MAX_MAP_DRAW_INDEXES" );
- }
- ds->firstIndex = numDrawIndexes;
- ds->numIndexes = ni;
-
- memcpy( drawIndexes + numDrawIndexes, indices, ni * sizeof(int) );
- numDrawIndexes += ni;
-}
-
-/*
-===============
-EmitPlanarSurf
-===============
-*/
-void EmitPlanarSurf( mapDrawSurface_t *ds ) {
- int j;
- dsurface_t *out;
- drawVert_t *outv;
-
- if ( numDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
- Error( "MAX_MAP_DRAW_SURFS" );
- }
- out = &drawSurfaces[ numDrawSurfaces ];
- numDrawSurfaces++;
-
- out->surfaceType = MST_PLANAR;
- out->shaderNum = EmitShader( ds->shaderInfo->shader );
- out->firstVert = numDrawVerts;
- out->numVerts = ds->numVerts;
- out->fogNum = ds->fogNum;
- out->lightmapNum = ds->lightmapNum;
- out->lightmapX = ds->lightmapX;
- out->lightmapY = ds->lightmapY;
- out->lightmapWidth = ds->lightmapWidth;
- out->lightmapHeight = ds->lightmapHeight;
-
- VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
- VectorCopy( ds->lightmapVecs[0], out->lightmapVecs[0] );
- VectorCopy( ds->lightmapVecs[1], out->lightmapVecs[1] );
- VectorCopy( ds->lightmapVecs[2], out->lightmapVecs[2] );
-
- for ( j = 0 ; j < ds->numVerts ; j++ ) {
- if ( numDrawVerts == MAX_MAP_DRAW_VERTS ) {
- Error( "MAX_MAP_DRAW_VERTS" );
- }
- outv = &drawVerts[ numDrawVerts ];
- numDrawVerts++;
- memcpy( outv, &ds->verts[ j ], sizeof( *outv ) );
- outv->color[0] = 255;
- outv->color[1] = 255;
- outv->color[2] = 255;
- outv->color[3] = 255;
- }
-
- // create the indexes
- SurfaceAsTristrip( out );
-}
-
-
-/*
-===============
-EmitPatchSurf
-===============
-*/
-void EmitPatchSurf( mapDrawSurface_t *ds ) {
- int j;
- dsurface_t *out;
- drawVert_t *outv;
-
- if ( numDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
- Error( "MAX_MAP_DRAW_SURFS" );
- }
- out = &drawSurfaces[ numDrawSurfaces ];
- numDrawSurfaces++;
-
- out->surfaceType = MST_PATCH;
- out->shaderNum = EmitShader( ds->shaderInfo->shader );
- out->firstVert = numDrawVerts;
- out->numVerts = ds->numVerts;
- out->firstIndex = numDrawIndexes;
- out->numIndexes = ds->numIndexes;
- out->patchWidth = ds->patchWidth;
- out->patchHeight = ds->patchHeight;
- out->fogNum = ds->fogNum;
- out->lightmapNum = ds->lightmapNum;
- out->lightmapX = ds->lightmapX;
- out->lightmapY = ds->lightmapY;
- out->lightmapWidth = ds->lightmapWidth;
- out->lightmapHeight = ds->lightmapHeight;
-
- VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
- VectorCopy( ds->lightmapVecs[0], out->lightmapVecs[0] );
- VectorCopy( ds->lightmapVecs[1], out->lightmapVecs[1] );
- VectorCopy( ds->lightmapVecs[2], out->lightmapVecs[2] );
-
- for ( j = 0 ; j < ds->numVerts ; j++ ) {
- if ( numDrawVerts == MAX_MAP_DRAW_VERTS ) {
- Error( "MAX_MAP_DRAW_VERTS" );
- }
- outv = &drawVerts[ numDrawVerts ];
- numDrawVerts++;
- memcpy( outv, &ds->verts[ j ], sizeof( *outv ) );
- outv->color[0] = 255;
- outv->color[1] = 255;
- outv->color[2] = 255;
- outv->color[3] = 255;
- }
-
- for ( j = 0 ; j < ds->numIndexes ; j++ ) {
- if ( numDrawIndexes == MAX_MAP_DRAW_INDEXES ) {
- Error( "MAX_MAP_DRAW_INDEXES" );
- }
- drawIndexes[ numDrawIndexes ] = ds->indexes[ j ];
- numDrawIndexes++;
- }
-}
-
-/*
-===============
-EmitFlareSurf
-===============
-*/
-void EmitFlareSurf( mapDrawSurface_t *ds ) {
- dsurface_t *out;
-
- if ( numDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
- Error( "MAX_MAP_DRAW_SURFS" );
- }
- out = &drawSurfaces[ numDrawSurfaces ];
- numDrawSurfaces++;
-
- out->surfaceType = MST_FLARE;
- out->shaderNum = EmitShader( ds->shaderInfo->shader );
- out->fogNum = ds->fogNum;
-
- VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
- VectorCopy( ds->lightmapVecs[0], out->lightmapVecs[0] ); // color
- VectorCopy( ds->lightmapVecs[2], out->lightmapVecs[2] );
-}
-
-
-/*
-===============
-EmitModelSurf
-===============
-*/
-void EmitModelSurf( mapDrawSurface_t *ds ) {
- int j;
- dsurface_t *out;
- drawVert_t *outv;
-
- if ( numDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
- Error( "MAX_MAP_DRAW_SURFS" );
- }
- out = &drawSurfaces[ numDrawSurfaces ];
- numDrawSurfaces++;
-
- out->surfaceType = MST_TRIANGLE_SOUP;
- out->shaderNum = EmitShader( ds->shaderInfo->shader );
- out->firstVert = numDrawVerts;
- out->numVerts = ds->numVerts;
- out->firstIndex = numDrawIndexes;
- out->numIndexes = ds->numIndexes;
- out->patchWidth = ds->patchWidth;
- out->patchHeight = ds->patchHeight;
- out->fogNum = ds->fogNum;
- out->lightmapNum = ds->lightmapNum;
- out->lightmapX = ds->lightmapX;
- out->lightmapY = ds->lightmapY;
- out->lightmapWidth = ds->lightmapWidth;
- out->lightmapHeight = ds->lightmapHeight;
-
- VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
- VectorCopy( ds->lightmapVecs[0], out->lightmapVecs[0] );
- VectorCopy( ds->lightmapVecs[1], out->lightmapVecs[1] );
- VectorCopy( ds->lightmapVecs[2], out->lightmapVecs[2] );
-
- for ( j = 0 ; j < ds->numVerts ; j++ ) {
- if ( numDrawVerts == MAX_MAP_DRAW_VERTS ) {
- Error( "MAX_MAP_DRAW_VERTS" );
- }
- outv = &drawVerts[ numDrawVerts ];
- numDrawVerts++;
- memcpy( outv, &ds->verts[ j ], sizeof( *outv ) );
- outv->color[0] = 255;
- outv->color[1] = 255;
- outv->color[2] = 255;
- }
-
- for ( j = 0 ; j < ds->numIndexes ; j++ ) {
- if ( numDrawIndexes == MAX_MAP_DRAW_INDEXES ) {
- Error( "MAX_MAP_DRAW_INDEXES" );
- }
- drawIndexes[ numDrawIndexes ] = ds->indexes[ j ];
- numDrawIndexes++;
- }
-}
-
-//======================================================================
-
-/*
-==================
-CreateFlareSurface
-
-Light flares from surface lights become
-==================
-*/
-void CreateFlareSurface( mapDrawSurface_t *faceDs ) {
- mapDrawSurface_t *ds;
- int i;
-
- ds = AllocDrawSurf();
-
- if ( faceDs->shaderInfo->flareShader[0] ) {
- ds->shaderInfo = ShaderInfoForShader( faceDs->shaderInfo->flareShader );
- } else {
- ds->shaderInfo = ShaderInfoForShader( "flareshader" );
- }
- ds->flareSurface = qtrue;
- VectorCopy( faceDs->lightmapVecs[2], ds->lightmapVecs[2] );
-
- // find midpoint
- VectorClear( ds->lightmapOrigin );
- for ( i = 0 ; i < faceDs->numVerts ; i++ ) {
- VectorAdd( ds->lightmapOrigin, faceDs->verts[i].xyz, ds->lightmapOrigin );
- }
- VectorScale( ds->lightmapOrigin, 1.0/faceDs->numVerts, ds->lightmapOrigin );
-
- VectorMA( ds->lightmapOrigin, 2, ds->lightmapVecs[2], ds->lightmapOrigin );
-
- VectorCopy( faceDs->shaderInfo->color, ds->lightmapVecs[0] );
-
- // FIXME: fog
-}
-
-/*
-=====================
-FilterDrawsurfsIntoTree
-
-Upon completion, all drawsurfs that actually generate a reference
-will have been emited to the bspfile arrays, and the references
-will have valid final indexes
-=====================
-*/
-void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ) {
- int i;
- mapDrawSurface_t *ds;
- int refs;
- int c_surfs, c_refs;
-
- qprintf( "----- FilterDrawsurfsIntoTree -----\n");
-
- c_surfs = 0;
- c_refs = 0;
- for ( i = e->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
- ds = &mapDrawSurfs[i];
-
- if ( !ds->numVerts && !ds->flareSurface ) {
- continue;
- }
- if ( ds->miscModel ) {
- refs = FilterMiscModelSurfIntoTree( ds, tree );
- EmitModelSurf( ds );
- } else if ( ds->patch ) {
- refs = FilterPatchSurfIntoTree( ds, tree );
- EmitPatchSurf( ds );
- } else if ( ds->flareSurface ) {
- refs = FilterFlareSurfIntoTree( ds, tree );
- EmitFlareSurf( ds );
- } else {
- refs = FilterFaceIntoTree( ds, tree );
-// if ( ds->shaderInfo->value >= 1000 ) { // ds->shaderInfo->flareShader[0] ) {
- if ( ds->shaderInfo->flareShader[0] ) {
- CreateFlareSurface( ds );
- }
- EmitPlanarSurf( ds );
- }
- if ( refs > 0 ) {
- c_surfs++;
- c_refs += refs;
- }
- }
- qprintf( "%5i emited drawsurfs\n", c_surfs );
- qprintf( "%5i references\n", c_refs );
- qprintf( "%5i stripfaces\n", c_stripSurfaces );
- qprintf( "%5i fanfaces\n", c_fanSurfaces );
-}
-
-
-
+
+#include "qbsp.h"
+
+
+mapDrawSurface_t mapDrawSurfs[MAX_MAP_DRAW_SURFS];
+int numMapDrawSurfs;
+
+/*
+=============================================================================
+
+DRAWSURF CONSTRUCTION
+
+=============================================================================
+*/
+
+/*
+=================
+AllocDrawSurf
+=================
+*/
+mapDrawSurface_t *AllocDrawSurf( void ) {
+ mapDrawSurface_t *ds;
+
+ if ( numMapDrawSurfs >= MAX_MAP_DRAW_SURFS ) {
+ Error( "MAX_MAP_DRAW_SURFS");
+ }
+ ds = &mapDrawSurfs[ numMapDrawSurfs ];
+ numMapDrawSurfs++;
+
+ return ds;
+}
+
+/*
+=================
+DrawSurfaceForSide
+=================
+*/
+#define SNAP_FLOAT_TO_INT 8
+#define SNAP_INT_TO_FLOAT (1.0/SNAP_FLOAT_TO_INT)
+
+mapDrawSurface_t *DrawSurfaceForSide( bspbrush_t *b, side_t *s, winding_t *w ) {
+ mapDrawSurface_t *ds;
+ int i, j;
+ shaderInfo_t *si;
+ drawVert_t *dv;
+ float mins[2], maxs[2];
+
+ // brush primitive :
+ // axis base
+ vec3_t texX,texY;
+ vec_t x,y;
+
+ if ( w->numpoints > 64 ) {
+ Error( "DrawSurfaceForSide: w->numpoints = %i", w->numpoints );
+ }
+
+ si = s->shaderInfo;
+
+ ds = AllocDrawSurf();
+
+ ds->shaderInfo = si;
+ ds->mapBrush = b;
+ ds->side = s;
+ ds->fogNum = -1;
+ ds->numVerts = w->numpoints;
+ ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
+ memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
+
+ mins[0] = mins[1] = 99999;
+ maxs[0] = maxs[1] = -99999;
+
+ // compute s/t coordinates from brush primitive texture matrix
+ // compute axis base
+ ComputeAxisBase( mapplanes[s->planenum].normal, texX, texY );
+
+ for ( j = 0 ; j < w->numpoints ; j++ ) {
+ dv = ds->verts + j;
+
+ // round the xyz to a given precision
+ for ( i = 0 ; i < 3 ; i++ ) {
+ dv->xyz[i] = SNAP_INT_TO_FLOAT * floor( w->p[j][i] * SNAP_FLOAT_TO_INT + 0.5 );
+ }
+
+ if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
+ {
+ // calculate texture s/t
+ dv->st[0] = s->vecs[0][3] + DotProduct( s->vecs[0], dv->xyz );
+ dv->st[1] = s->vecs[1][3] + DotProduct( s->vecs[1], dv->xyz );
+ dv->st[0] /= si->width;
+ dv->st[1] /= si->height;
+ }
+ else
+ {
+ // calculate texture s/t from brush primitive texture matrix
+ x = DotProduct( dv->xyz, texX );
+ y = DotProduct( dv->xyz, texY );
+ dv->st[0]=s->texMat[0][0]*x+s->texMat[0][1]*y+s->texMat[0][2];
+ dv->st[1]=s->texMat[1][0]*x+s->texMat[1][1]*y+s->texMat[1][2];
+ }
+
+ for ( i = 0 ; i < 2 ; i++ ) {
+ if ( dv->st[i] < mins[i] ) {
+ mins[i] = dv->st[i];
+ }
+ if ( dv->st[i] > maxs[i] ) {
+ maxs[i] = dv->st[i];
+ }
+ }
+
+ // copy normal
+ VectorCopy ( mapplanes[s->planenum].normal, dv->normal );
+ }
+
+ // adjust the texture coordinates to be as close to 0 as possible
+ if ( !si->globalTexture ) {
+ mins[0] = floor( mins[0] );
+ mins[1] = floor( mins[1] );
+ for ( i = 0 ; i < w->numpoints ; i++ ) {
+ dv = ds->verts + i;
+ dv->st[0] -= mins[0];
+ dv->st[1] -= mins[1];
+ }
+ }
+
+ return ds;
+}
+
+
+//=========================================================================
+
+
+
+
+typedef struct {
+ int planenum;
+ shaderInfo_t *shaderInfo;
+ int count;
+} sideRef_t;
+
+#define MAX_SIDE_REFS MAX_MAP_PLANES
+
+sideRef_t sideRefs[MAX_SIDE_REFS];
+int numSideRefs;
+
+void AddSideRef( side_t *side ) {
+ int i;
+
+ for ( i = 0 ; i < numSideRefs ; i++ ) {
+ if ( side->planenum == sideRefs[i].planenum
+ && side->shaderInfo == sideRefs[i].shaderInfo ) {
+ sideRefs[i].count++;
+ return;
+ }
+ }
+
+ if ( numSideRefs == MAX_SIDE_REFS ) {
+ Error( "MAX_SIDE_REFS" );
+ }
+
+ sideRefs[i].planenum = side->planenum;
+ sideRefs[i].shaderInfo = side->shaderInfo;
+ sideRefs[i].count++;
+ numSideRefs++;
+}
+
+
+/*
+=====================
+MergeSides
+
+=====================
+*/
+void MergeSides( entity_t *e, tree_t *tree ) {
+ int i;
+
+ qprintf( "----- MergeSides -----\n");
+
+ for ( i = e->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
+// AddSideRef( side );
+ }
+
+ qprintf( "%5i siderefs\n", numSideRefs );
+}
+
+//=====================================================================
+
+/*
+===================
+SubdivideDrawSurf
+===================
+*/
+void SubdivideDrawSurf( mapDrawSurface_t *ds, winding_t *w, float subdivisions ) {
+ int i;
+ int axis;
+ vec3_t bounds[2];
+ const float epsilon = 0.1;
+ int subFloor, subCeil;
+ winding_t *frontWinding, *backWinding;
+ mapDrawSurface_t *newds;
+
+ if ( !w ) {
+ return;
+ }
+ if ( w->numpoints < 3 ) {
+ Error( "SubdivideDrawSurf: Bad w->numpoints" );
+ }
+
+ ClearBounds( bounds[0], bounds[1] );
+ for ( i = 0 ; i < w->numpoints ; i++ ) {
+ AddPointToBounds( w->p[i], bounds[0], bounds[1] );
+ }
+
+ for ( axis = 0 ; axis < 3 ; axis++ ) {
+ vec3_t planePoint = { 0, 0, 0 };
+ vec3_t planeNormal = { 0, 0, 0 };
+ float d;
+
+ subFloor = floor( bounds[0][axis] / subdivisions ) * subdivisions;
+ subCeil = ceil( bounds[1][axis] / subdivisions ) * subdivisions;
+
+ planePoint[axis] = subFloor + subdivisions;
+ planeNormal[axis] = -1;
+
+ d = DotProduct( planePoint, planeNormal );
+
+ // subdivide if necessary
+ if ( subCeil - subFloor > subdivisions ) {
+ // gotta clip polygon into two polygons
+ ClipWindingEpsilon( w, planeNormal, d, epsilon, &frontWinding, &backWinding );
+
+ // the clip may not produce two polygons if it was epsilon close
+ if ( !frontWinding ) {
+ w = backWinding;
+ } else if ( !backWinding ) {
+ w = frontWinding;
+ } else {
+ SubdivideDrawSurf( ds, frontWinding, subdivisions );
+ SubdivideDrawSurf( ds, backWinding, subdivisions );
+
+ return;
+ }
+ }
+ }
+
+ // emit this polygon
+ newds = DrawSurfaceForSide( ds->mapBrush, ds->side, w );
+ newds->fogNum = ds->fogNum;
+}
+
+
+/*
+=====================
+SubdivideDrawSurfs
+
+Chop up surfaces that have subdivision attributes
+=====================
+*/
+void SubdivideDrawSurfs( entity_t *e, tree_t *tree ) {
+ int i;
+ mapDrawSurface_t *ds;
+ int numBaseDrawSurfs;
+ winding_t *w;
+ float subdivision;
+ shaderInfo_t *si;
+
+ qprintf( "----- SubdivideDrawSurfs -----\n");
+ numBaseDrawSurfs = numMapDrawSurfs;
+ for ( i = e->firstDrawSurf ; i < numBaseDrawSurfs ; i++ ) {
+ ds = &mapDrawSurfs[i];
+
+ // only subdivide brush sides, not patches or misc_models
+ if ( !ds->side ) {
+ continue;
+ }
+
+ // check subdivision for shader
+ si = ds->side->shaderInfo;
+ if ( !si ) {
+ continue;
+ }
+
+ if (ds->shaderInfo->autosprite || si->autosprite) {
+ continue;
+ }
+
+ subdivision = si->subdivisions;
+ if ( !subdivision ) {
+ continue;
+ }
+
+ w = WindingFromDrawSurf( ds );
+ ds->numVerts = 0; // remove this reference
+ SubdivideDrawSurf( ds, w, subdivision );
+ }
+
+}
+
+
+//===================================================================================
+
+/*
+====================
+ClipSideIntoTree_r
+
+Adds non-opaque leaf fragments to the convex hull
+====================
+*/
+void ClipSideIntoTree_r( winding_t *w, side_t *side, node_t *node ) {
+ plane_t *plane;
+ winding_t *front, *back;
+
+ if ( !w ) {
+ return;
+ }
+
+ if ( node->planenum != PLANENUM_LEAF ) {
+ if ( side->planenum == node->planenum ) {
+ ClipSideIntoTree_r( w, side, node->children[0] );
+ return;
+ }
+ if ( side->planenum == ( node->planenum ^ 1) ) {
+ ClipSideIntoTree_r( w, side, node->children[1] );
+ return;
+ }
+
+ plane = &mapplanes[ node->planenum ];
+ ClipWindingEpsilon ( w, plane->normal, plane->dist,
+ ON_EPSILON, &front, &back );
+ FreeWinding( w );
+
+ ClipSideIntoTree_r( front, side, node->children[0] );
+ ClipSideIntoTree_r( back, side, node->children[1] );
+
+ return;
+ }
+
+ // if opaque leaf, don't add
+ if ( !node->opaque ) {
+ AddWindingToConvexHull( w, &side->visibleHull, mapplanes[ side->planenum ].normal );
+ }
+
+ FreeWinding( w );
+ return;
+}
+
+
+/*
+=====================
+ClipSidesIntoTree
+
+Creates side->visibleHull for all visible sides
+
+The drawsurf for a side will consist of the convex hull of
+all points in non-opaque clusters, which allows overlaps
+to be trimmed off automatically.
+=====================
+*/
+void ClipSidesIntoTree( entity_t *e, tree_t *tree ) {
+ bspbrush_t *b;
+ int i;
+ winding_t *w;
+ side_t *side, *newSide;
+ shaderInfo_t *si;
+
+ qprintf( "----- ClipSidesIntoTree -----\n");
+
+ for ( b = e->brushes ; b ; b = b->next ) {
+ for ( i = 0 ; i < b->numsides ; i++ ) {
+ side = &b->sides[i];
+ if ( !side->winding) {
+ continue;
+ }
+ w = CopyWinding( side->winding );
+ side->visibleHull = NULL;
+ ClipSideIntoTree_r( w, side, tree->headnode );
+
+ w = side->visibleHull;
+ if ( !w ) {
+ continue;
+ }
+ si = side->shaderInfo;
+ if ( !si ) {
+ continue;
+ }
+ // don't create faces for non-visible sides
+ if ( si->surfaceFlags & SURF_NODRAW ) {
+ continue;
+ }
+
+ // always use the original quad winding for auto sprites
+ if ( side->shaderInfo->autosprite ) {
+ w = side->winding;
+ }
+ //
+ if ( side->bevel ) {
+ Error( "monkey tried to create draw surface for brush bevel" );
+ }
+ // save this winding as a visible surface
+ DrawSurfaceForSide( b, side, w );
+
+ // make a back side for it if needed
+ if ( !(si->contents & CONTENTS_FOG) ) {
+ continue;
+ }
+
+ // duplicate the up-facing side
+ w = ReverseWinding( w );
+
+ newSide = malloc( sizeof( *side ) );
+ *newSide = *side;
+ newSide->visibleHull = w;
+ newSide->planenum ^= 1;
+
+ // save this winding as a visible surface
+ DrawSurfaceForSide( b, newSide, w );
+
+ }
+ }
+}
+
+/*
+===================================================================================
+
+ FILTER REFERENCES DOWN THE TREE
+
+===================================================================================
+*/
+
+/*
+====================
+FilterDrawSurfIntoTree
+
+Place a reference to the given drawsurf in every leaf it contacts
+We assume that the point mesh aproximation to the curve will get a
+reference into all the leafs we need.
+====================
+*/
+int FilterMapDrawSurfIntoTree( vec3_t point, mapDrawSurface_t *ds, node_t *node ) {
+ drawSurfRef_t *dsr;
+ float d;
+ plane_t *plane;
+ int c;
+
+ if ( node->planenum != PLANENUM_LEAF ) {
+ plane = &mapplanes[ node->planenum ];
+ d = DotProduct( point, plane->normal ) - plane->dist;
+ c = 0;
+ if ( d >= -ON_EPSILON ) {
+ c += FilterMapDrawSurfIntoTree( point, ds, node->children[0] );
+ }
+ if ( d <= ON_EPSILON ) {
+ c += FilterMapDrawSurfIntoTree( point, ds, node->children[1] );
+ }
+ return c;
+ }
+
+ // if opaque leaf, don't add
+ if ( node->opaque ) {
+ return 0;
+ }
+
+ // add the drawsurf if it hasn't been already
+ for ( dsr = node->drawSurfReferences ; dsr ; dsr = dsr->nextRef ) {
+ if ( dsr->outputNumber == numDrawSurfaces ) {
+ return 0; // already referenced
+ }
+ }
+
+ dsr = malloc( sizeof( *dsr ) );
+ dsr->outputNumber = numDrawSurfaces;
+ dsr->nextRef = node->drawSurfReferences;
+ node->drawSurfReferences = dsr;
+ return 1;
+}
+
+/*
+====================
+FilterDrawSurfIntoTree_r
+
+Place a reference to the given drawsurf in every leaf it is in
+====================
+*/
+int FilterMapDrawSurfIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node ) {
+ drawSurfRef_t *dsr;
+ plane_t *plane;
+ int total;
+ winding_t *front, *back;
+
+ if ( node->planenum != PLANENUM_LEAF ) {
+ plane = &mapplanes[ node->planenum ];
+ ClipWindingEpsilon ( w, plane->normal, plane->dist,
+ ON_EPSILON, &front, &back );
+
+ total = 0;
+ if ( front ) {
+ total += FilterMapDrawSurfIntoTree_r( front, ds, node->children[0] );
+ }
+ if ( back ) {
+ total += FilterMapDrawSurfIntoTree_r( back, ds, node->children[1] );
+ }
+
+ FreeWinding( w );
+ return total;
+ }
+
+ // if opaque leaf, don't add
+ if ( node->opaque ) {
+ return 0;
+ }
+
+ // add the drawsurf if it hasn't been already
+ for ( dsr = node->drawSurfReferences ; dsr ; dsr = dsr->nextRef ) {
+ if ( dsr->outputNumber == numDrawSurfaces ) {
+ return 0; // already referenced
+ }
+ }
+
+ dsr = malloc( sizeof( *dsr ) );
+ dsr->outputNumber = numDrawSurfaces;
+ dsr->nextRef = node->drawSurfReferences;
+ node->drawSurfReferences = dsr;
+ return 1;
+}
+
+/*
+====================
+FilterSideIntoTree_r
+
+Place a reference to the given drawsurf in every leaf it contacts
+====================
+*/
+int FilterSideIntoTree_r( winding_t *w, side_t *side, mapDrawSurface_t *ds, node_t *node ) {
+ drawSurfRef_t *dsr;
+ plane_t *plane;
+ winding_t *front, *back;
+ int total;
+
+ if ( !w ) {
+ return 0;
+ }
+
+ if ( node->planenum != PLANENUM_LEAF ) {
+ if ( side->planenum == node->planenum ) {
+ return FilterSideIntoTree_r( w, side, ds, node->children[0] );
+ }
+ if ( side->planenum == ( node->planenum ^ 1) ) {
+ return FilterSideIntoTree_r( w, side, ds, node->children[1] );
+ }
+
+ plane = &mapplanes[ node->planenum ];
+ ClipWindingEpsilon ( w, plane->normal, plane->dist,
+ ON_EPSILON, &front, &back );
+
+ total = FilterSideIntoTree_r( front, side, ds, node->children[0] );
+ total += FilterSideIntoTree_r( back, side, ds, node->children[1] );
+
+ FreeWinding( w );
+ return total;
+ }
+
+ // if opaque leaf, don't add
+ if ( node->opaque ) {
+ return 0;
+ }
+
+ dsr = malloc( sizeof( *dsr ) );
+ dsr->outputNumber = numDrawSurfaces;
+ dsr->nextRef = node->drawSurfReferences;
+ node->drawSurfReferences = dsr;
+
+ FreeWinding( w );
+ return 1;
+}
+
+
+/*
+=====================
+FilterFaceIntoTree
+=====================
+*/
+int FilterFaceIntoTree( mapDrawSurface_t *ds, tree_t *tree ) {
+ int l;
+ winding_t *w;
+
+ w = WindingFromDrawSurf( ds );
+ l = FilterSideIntoTree_r( w, ds->side, ds, tree->headnode );
+
+ return l;
+}
+
+
+
+/*
+=====================
+FilterPatchSurfIntoTree
+=====================
+*/
+#define SUBDIVISION_LIMIT 8.0
+int FilterPatchSurfIntoTree( mapDrawSurface_t *ds, tree_t *tree ) {
+ int i, j;
+ int l;
+ mesh_t baseMesh, *subdividedMesh;
+ winding_t *w;
+
+ baseMesh.width = ds->patchWidth;
+ baseMesh.height = ds->patchHeight;
+ baseMesh.verts = ds->verts;
+ subdividedMesh = SubdivideMesh( baseMesh, SUBDIVISION_LIMIT, 32 );
+
+ l = 0;
+ for (i = 0; i < subdividedMesh->width-1; i++) {
+ for (j = 0; j < subdividedMesh->height-1; j++) {
+ w = AllocWinding(3);
+ VectorCopy(subdividedMesh->verts[j * subdividedMesh->width + i].xyz, w->p[0]);
+ VectorCopy(subdividedMesh->verts[j * subdividedMesh->width + i + 1].xyz, w->p[1]);
+ VectorCopy(subdividedMesh->verts[(j+1) * subdividedMesh->width + i].xyz, w->p[2]);
+ w->numpoints = 3;
+ l += FilterMapDrawSurfIntoTree_r( w, ds, tree->headnode );
+ w = AllocWinding(3);
+ VectorCopy(subdividedMesh->verts[j * subdividedMesh->width + i + 1].xyz, w->p[0]);
+ VectorCopy(subdividedMesh->verts[(j+1) * subdividedMesh->width + i + 1].xyz, w->p[1]);
+ VectorCopy(subdividedMesh->verts[(j+1) * subdividedMesh->width + i].xyz, w->p[2]);
+ w->numpoints = 3;
+ l += FilterMapDrawSurfIntoTree_r( w, ds, tree->headnode );
+ }
+ }
+
+ // also use the old point filtering into the tree
+ for ( i = 0 ; i < subdividedMesh->width * subdividedMesh->height ; i++ ) {
+ l += FilterMapDrawSurfIntoTree( subdividedMesh->verts[i].xyz, ds, tree->headnode );
+ }
+
+ free(subdividedMesh);
+
+ return l;
+}
+
+
+/*
+=====================
+FilterMiscModelSurfIntoTree
+=====================
+*/
+int FilterMiscModelSurfIntoTree( mapDrawSurface_t *ds, tree_t *tree ) {
+ int i;
+ int l;
+ winding_t *w;
+
+ l = 0;
+ for (i = 0; i < ds->numIndexes-2; i++) {
+ w = AllocWinding(3);
+ VectorCopy(ds->verts[ds->indexes[i]].xyz, w->p[0]);
+ VectorCopy(ds->verts[ds->indexes[i+1]].xyz, w->p[1]);
+ VectorCopy(ds->verts[ds->indexes[i+2]].xyz, w->p[2]);
+ w->numpoints = 3;
+ l += FilterMapDrawSurfIntoTree_r( w, ds, tree->headnode );
+ }
+
+ // also use the old point filtering into the tree
+ for ( i = 0 ; i < ds->numVerts ; i++ ) {
+ l += FilterMapDrawSurfIntoTree( ds->verts[i].xyz, ds, tree->headnode );
+ }
+
+ return l;
+}
+
+/*
+=====================
+FilterFlareSurfIntoTree
+=====================
+*/
+int FilterFlareSurfIntoTree( mapDrawSurface_t *ds, tree_t *tree ) {
+ return FilterMapDrawSurfIntoTree( ds->lightmapOrigin, ds, tree->headnode );
+}
+
+
+//======================================================================
+
+int c_stripSurfaces, c_fanSurfaces;
+
+/*
+==================
+IsTriangleDegenerate
+
+Returns qtrue if all three points are collinear or backwards
+===================
+*/
+#define COLINEAR_AREA 10
+static qboolean IsTriangleDegenerate( drawVert_t *points, int a, int b, int c ) {
+ vec3_t v1, v2, v3;
+ float d;
+
+ VectorSubtract( points[b].xyz, points[a].xyz, v1 );
+ VectorSubtract( points[c].xyz, points[a].xyz, v2 );
+ CrossProduct( v1, v2, v3 );
+ d = VectorLength( v3 );
+
+ // assume all very small or backwards triangles will cause problems
+ if ( d < COLINEAR_AREA ) {
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+/*
+===============
+SurfaceAsTriFan
+
+The surface can't be represented as a single tristrip without
+leaving a degenerate triangle (and therefore a crack), so add
+a point in the middle and create (points-1) triangles in fan order
+===============
+*/
+static void SurfaceAsTriFan( dsurface_t *ds ) {
+ int i;
+ int colorSum[4];
+ drawVert_t *mid, *v;
+
+ // create a new point in the center of the face
+ if ( numDrawVerts == MAX_MAP_DRAW_VERTS ) {
+ Error( "MAX_MAP_DRAW_VERTS" );
+ }
+ mid = &drawVerts[ numDrawVerts ];
+ numDrawVerts++;
+
+ colorSum[0] = colorSum[1] = colorSum[2] = colorSum[3] = 0;
+
+ v = drawVerts + ds->firstVert;
+ for (i = 0 ; i < ds->numVerts ; i++, v++ ) {
+ VectorAdd( mid->xyz, v->xyz, mid->xyz );
+ mid->st[0] += v->st[0];
+ mid->st[1] += v->st[1];
+ mid->lightmap[0] += v->lightmap[0];
+ mid->lightmap[1] += v->lightmap[1];
+
+ colorSum[0] += v->color[0];
+ colorSum[1] += v->color[1];
+ colorSum[2] += v->color[2];
+ colorSum[3] += v->color[3];
+ }
+
+ mid->xyz[0] /= ds->numVerts;
+ mid->xyz[1] /= ds->numVerts;
+ mid->xyz[2] /= ds->numVerts;
+
+ mid->st[0] /= ds->numVerts;
+ mid->st[1] /= ds->numVerts;
+
+ mid->lightmap[0] /= ds->numVerts;
+ mid->lightmap[1] /= ds->numVerts;
+
+ mid->color[0] = colorSum[0] / ds->numVerts;
+ mid->color[1] = colorSum[1] / ds->numVerts;
+ mid->color[2] = colorSum[2] / ds->numVerts;
+ mid->color[3] = colorSum[3] / ds->numVerts;
+
+ VectorCopy((drawVerts+ds->firstVert)->normal, mid->normal );
+
+ // fill in indices in trifan order
+ if ( numDrawIndexes + ds->numVerts*3 > MAX_MAP_DRAW_INDEXES ) {
+ Error( "MAX_MAP_DRAWINDEXES" );
+ }
+ ds->firstIndex = numDrawIndexes;
+ ds->numIndexes = ds->numVerts*3;
+
+ //FIXME
+ // should be: for ( i = 0 ; i < ds->numVerts ; i++ ) {
+ // set a break point and test this in a map
+ //for ( i = 0 ; i < ds->numVerts*3 ; i++ ) {
+ for ( i = 0 ; i < ds->numVerts ; i++ ) {
+ drawIndexes[numDrawIndexes++] = ds->numVerts;
+ drawIndexes[numDrawIndexes++] = i;
+ drawIndexes[numDrawIndexes++] = (i+1) % ds->numVerts;
+ }
+
+ ds->numVerts++;
+}
+
+
+/*
+================
+SurfaceAsTristrip
+
+Try to create indices that make (points-2) triangles in tristrip order
+================
+*/
+#define MAX_INDICES 1024
+static void SurfaceAsTristrip( dsurface_t *ds ) {
+ int i;
+ int rotate;
+ int numIndices;
+ int ni;
+ int a, b, c;
+ int indices[MAX_INDICES];
+
+ // determine the triangle strip order
+ numIndices = ( ds->numVerts - 2 ) * 3;
+ if ( numIndices > MAX_INDICES ) {
+ Error( "MAX_INDICES exceeded for surface" );
+ }
+
+ // try all possible orderings of the points looking
+ // for a strip order that isn't degenerate
+ for ( rotate = 0 ; rotate < ds->numVerts ; rotate++ ) {
+ for ( ni = 0, i = 0 ; i < ds->numVerts - 2 - i ; i++ ) {
+ a = ( ds->numVerts - 1 - i + rotate ) % ds->numVerts;
+ b = ( i + rotate ) % ds->numVerts;
+ c = ( ds->numVerts - 2 - i + rotate ) % ds->numVerts;
+
+ if ( IsTriangleDegenerate( drawVerts + ds->firstVert, a, b, c ) ) {
+ break;
+ }
+ indices[ni++] = a;
+ indices[ni++] = b;
+ indices[ni++] = c;
+
+ if ( i + 1 != ds->numVerts - 1 - i ) {
+ a = ( ds->numVerts - 2 - i + rotate ) % ds->numVerts;
+ b = ( i + rotate ) % ds->numVerts;
+ c = ( i + 1 + rotate ) % ds->numVerts;
+
+ if ( IsTriangleDegenerate( drawVerts + ds->firstVert, a, b, c ) ) {
+ break;
+ }
+ indices[ni++] = a;
+ indices[ni++] = b;
+ indices[ni++] = c;
+ }
+ }
+ if ( ni == numIndices ) {
+ break; // got it done without degenerate triangles
+ }
+ }
+
+ // if any triangle in the strip is degenerate,
+ // render from a centered fan point instead
+ if ( ni < numIndices ) {
+ c_fanSurfaces++;
+ SurfaceAsTriFan( ds );
+ return;
+ }
+
+ // a normal tristrip
+ c_stripSurfaces++;
+
+ if ( numDrawIndexes + ni > MAX_MAP_DRAW_INDEXES ) {
+ Error( "MAX_MAP_DRAW_INDEXES" );
+ }
+ ds->firstIndex = numDrawIndexes;
+ ds->numIndexes = ni;
+
+ memcpy( drawIndexes + numDrawIndexes, indices, ni * sizeof(int) );
+ numDrawIndexes += ni;
+}
+
+/*
+===============
+EmitPlanarSurf
+===============
+*/
+void EmitPlanarSurf( mapDrawSurface_t *ds ) {
+ int j;
+ dsurface_t *out;
+ drawVert_t *outv;
+
+ if ( numDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
+ Error( "MAX_MAP_DRAW_SURFS" );
+ }
+ out = &drawSurfaces[ numDrawSurfaces ];
+ numDrawSurfaces++;
+
+ out->surfaceType = MST_PLANAR;
+ out->shaderNum = EmitShader( ds->shaderInfo->shader );
+ out->firstVert = numDrawVerts;
+ out->numVerts = ds->numVerts;
+ out->fogNum = ds->fogNum;
+ out->lightmapNum = ds->lightmapNum;
+ out->lightmapX = ds->lightmapX;
+ out->lightmapY = ds->lightmapY;
+ out->lightmapWidth = ds->lightmapWidth;
+ out->lightmapHeight = ds->lightmapHeight;
+
+ VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
+ VectorCopy( ds->lightmapVecs[0], out->lightmapVecs[0] );
+ VectorCopy( ds->lightmapVecs[1], out->lightmapVecs[1] );
+ VectorCopy( ds->lightmapVecs[2], out->lightmapVecs[2] );
+
+ for ( j = 0 ; j < ds->numVerts ; j++ ) {
+ if ( numDrawVerts == MAX_MAP_DRAW_VERTS ) {
+ Error( "MAX_MAP_DRAW_VERTS" );
+ }
+ outv = &drawVerts[ numDrawVerts ];
+ numDrawVerts++;
+ memcpy( outv, &ds->verts[ j ], sizeof( *outv ) );
+ outv->color[0] = 255;
+ outv->color[1] = 255;
+ outv->color[2] = 255;
+ outv->color[3] = 255;
+ }
+
+ // create the indexes
+ SurfaceAsTristrip( out );
+}
+
+
+/*
+===============
+EmitPatchSurf
+===============
+*/
+void EmitPatchSurf( mapDrawSurface_t *ds ) {
+ int j;
+ dsurface_t *out;
+ drawVert_t *outv;
+
+ if ( numDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
+ Error( "MAX_MAP_DRAW_SURFS" );
+ }
+ out = &drawSurfaces[ numDrawSurfaces ];
+ numDrawSurfaces++;
+
+ out->surfaceType = MST_PATCH;
+ out->shaderNum = EmitShader( ds->shaderInfo->shader );
+ out->firstVert = numDrawVerts;
+ out->numVerts = ds->numVerts;
+ out->firstIndex = numDrawIndexes;
+ out->numIndexes = ds->numIndexes;
+ out->patchWidth = ds->patchWidth;
+ out->patchHeight = ds->patchHeight;
+ out->fogNum = ds->fogNum;
+ out->lightmapNum = ds->lightmapNum;
+ out->lightmapX = ds->lightmapX;
+ out->lightmapY = ds->lightmapY;
+ out->lightmapWidth = ds->lightmapWidth;
+ out->lightmapHeight = ds->lightmapHeight;
+
+ VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
+ VectorCopy( ds->lightmapVecs[0], out->lightmapVecs[0] );
+ VectorCopy( ds->lightmapVecs[1], out->lightmapVecs[1] );
+ VectorCopy( ds->lightmapVecs[2], out->lightmapVecs[2] );
+
+ for ( j = 0 ; j < ds->numVerts ; j++ ) {
+ if ( numDrawVerts == MAX_MAP_DRAW_VERTS ) {
+ Error( "MAX_MAP_DRAW_VERTS" );
+ }
+ outv = &drawVerts[ numDrawVerts ];
+ numDrawVerts++;
+ memcpy( outv, &ds->verts[ j ], sizeof( *outv ) );
+ outv->color[0] = 255;
+ outv->color[1] = 255;
+ outv->color[2] = 255;
+ outv->color[3] = 255;
+ }
+
+ for ( j = 0 ; j < ds->numIndexes ; j++ ) {
+ if ( numDrawIndexes == MAX_MAP_DRAW_INDEXES ) {
+ Error( "MAX_MAP_DRAW_INDEXES" );
+ }
+ drawIndexes[ numDrawIndexes ] = ds->indexes[ j ];
+ numDrawIndexes++;
+ }
+}
+
+/*
+===============
+EmitFlareSurf
+===============
+*/
+void EmitFlareSurf( mapDrawSurface_t *ds ) {
+ dsurface_t *out;
+
+ if ( numDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
+ Error( "MAX_MAP_DRAW_SURFS" );
+ }
+ out = &drawSurfaces[ numDrawSurfaces ];
+ numDrawSurfaces++;
+
+ out->surfaceType = MST_FLARE;
+ out->shaderNum = EmitShader( ds->shaderInfo->shader );
+ out->fogNum = ds->fogNum;
+
+ VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
+ VectorCopy( ds->lightmapVecs[0], out->lightmapVecs[0] ); // color
+ VectorCopy( ds->lightmapVecs[2], out->lightmapVecs[2] );
+}
+
+
+/*
+===============
+EmitModelSurf
+===============
+*/
+void EmitModelSurf( mapDrawSurface_t *ds ) {
+ int j;
+ dsurface_t *out;
+ drawVert_t *outv;
+
+ if ( numDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
+ Error( "MAX_MAP_DRAW_SURFS" );
+ }
+ out = &drawSurfaces[ numDrawSurfaces ];
+ numDrawSurfaces++;
+
+ out->surfaceType = MST_TRIANGLE_SOUP;
+ out->shaderNum = EmitShader( ds->shaderInfo->shader );
+ out->firstVert = numDrawVerts;
+ out->numVerts = ds->numVerts;
+ out->firstIndex = numDrawIndexes;
+ out->numIndexes = ds->numIndexes;
+ out->patchWidth = ds->patchWidth;
+ out->patchHeight = ds->patchHeight;
+ out->fogNum = ds->fogNum;
+ out->lightmapNum = ds->lightmapNum;
+ out->lightmapX = ds->lightmapX;
+ out->lightmapY = ds->lightmapY;
+ out->lightmapWidth = ds->lightmapWidth;
+ out->lightmapHeight = ds->lightmapHeight;
+
+ VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
+ VectorCopy( ds->lightmapVecs[0], out->lightmapVecs[0] );
+ VectorCopy( ds->lightmapVecs[1], out->lightmapVecs[1] );
+ VectorCopy( ds->lightmapVecs[2], out->lightmapVecs[2] );
+
+ for ( j = 0 ; j < ds->numVerts ; j++ ) {
+ if ( numDrawVerts == MAX_MAP_DRAW_VERTS ) {
+ Error( "MAX_MAP_DRAW_VERTS" );
+ }
+ outv = &drawVerts[ numDrawVerts ];
+ numDrawVerts++;
+ memcpy( outv, &ds->verts[ j ], sizeof( *outv ) );
+ outv->color[0] = 255;
+ outv->color[1] = 255;
+ outv->color[2] = 255;
+ }
+
+ for ( j = 0 ; j < ds->numIndexes ; j++ ) {
+ if ( numDrawIndexes == MAX_MAP_DRAW_INDEXES ) {
+ Error( "MAX_MAP_DRAW_INDEXES" );
+ }
+ drawIndexes[ numDrawIndexes ] = ds->indexes[ j ];
+ numDrawIndexes++;
+ }
+}
+
+//======================================================================
+
+/*
+==================
+CreateFlareSurface
+
+Light flares from surface lights become
+==================
+*/
+void CreateFlareSurface( mapDrawSurface_t *faceDs ) {
+ mapDrawSurface_t *ds;
+ int i;
+
+ ds = AllocDrawSurf();
+
+ if ( faceDs->shaderInfo->flareShader[0] ) {
+ ds->shaderInfo = ShaderInfoForShader( faceDs->shaderInfo->flareShader );
+ } else {
+ ds->shaderInfo = ShaderInfoForShader( "flareshader" );
+ }
+ ds->flareSurface = qtrue;
+ VectorCopy( faceDs->lightmapVecs[2], ds->lightmapVecs[2] );
+
+ // find midpoint
+ VectorClear( ds->lightmapOrigin );
+ for ( i = 0 ; i < faceDs->numVerts ; i++ ) {
+ VectorAdd( ds->lightmapOrigin, faceDs->verts[i].xyz, ds->lightmapOrigin );
+ }
+ VectorScale( ds->lightmapOrigin, 1.0/faceDs->numVerts, ds->lightmapOrigin );
+
+ VectorMA( ds->lightmapOrigin, 2, ds->lightmapVecs[2], ds->lightmapOrigin );
+
+ VectorCopy( faceDs->shaderInfo->color, ds->lightmapVecs[0] );
+
+ // FIXME: fog
+}
+
+/*
+=====================
+FilterDrawsurfsIntoTree
+
+Upon completion, all drawsurfs that actually generate a reference
+will have been emited to the bspfile arrays, and the references
+will have valid final indexes
+=====================
+*/
+void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ) {
+ int i;
+ mapDrawSurface_t *ds;
+ int refs;
+ int c_surfs, c_refs;
+
+ qprintf( "----- FilterDrawsurfsIntoTree -----\n");
+
+ c_surfs = 0;
+ c_refs = 0;
+ for ( i = e->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
+ ds = &mapDrawSurfs[i];
+
+ if ( !ds->numVerts && !ds->flareSurface ) {
+ continue;
+ }
+ if ( ds->miscModel ) {
+ refs = FilterMiscModelSurfIntoTree( ds, tree );
+ EmitModelSurf( ds );
+ } else if ( ds->patch ) {
+ refs = FilterPatchSurfIntoTree( ds, tree );
+ EmitPatchSurf( ds );
+ } else if ( ds->flareSurface ) {
+ refs = FilterFlareSurfIntoTree( ds, tree );
+ EmitFlareSurf( ds );
+ } else {
+ refs = FilterFaceIntoTree( ds, tree );
+// if ( ds->shaderInfo->value >= 1000 ) { // ds->shaderInfo->flareShader[0] ) {
+ if ( ds->shaderInfo->flareShader[0] ) {
+ CreateFlareSurface( ds );
+ }
+ EmitPlanarSurf( ds );
+ }
+ if ( refs > 0 ) {
+ c_surfs++;
+ c_refs += refs;
+ }
+ }
+ qprintf( "%5i emited drawsurfs\n", c_surfs );
+ qprintf( "%5i references\n", c_refs );
+ qprintf( "%5i stripfaces\n", c_stripSurfaces );
+ qprintf( "%5i fanfaces\n", c_fanSurfaces );
+}
+
+
+
diff --git a/q3map/terrain.c b/q3map/terrain.c
index 9446737..129ac08 100755
--- a/q3map/terrain.c
+++ b/q3map/terrain.c
@@ -19,1237 +19,1237 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-#include "qbsp.h"
-#include <assert.h>
-
-#define SURF_WIDTH 2048
-#define SURF_HEIGHT 2048
-
-#define GROW_VERTS 512
-#define GROW_INDICES 512
-#define GROW_SURFACES 128
-
-#define VectorSet(v, x, y, z) v[0] = x;v[1] = y;v[2] = z;
-
-void QuakeTextureVecs( plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2], vec_t mappingVecs[2][4] );
-
-typedef struct {
- shaderInfo_t *shader;
- int x, y;
-
- int maxVerts;
- int numVerts;
- drawVert_t *verts;
-
- int maxIndexes;
- int numIndexes;
- int *indexes;
-} terrainSurf_t;
-
-static terrainSurf_t *surfaces = NULL;
-static terrainSurf_t *lastSurface = NULL;
-static int numsurfaces = 0;
-static int maxsurfaces = 0;
-
-/*
-================
-ShaderForLayer
-================
-*/
-shaderInfo_t *ShaderForLayer( int minlayer, int maxlayer, const char *shadername ) {
- char shader[ MAX_QPATH ];
-
- if ( minlayer == maxlayer ) {
- sprintf( shader, "textures/%s_%d", shadername, maxlayer );
- } else {
- sprintf( shader, "textures/%s_%dto%d", shadername, minlayer, maxlayer );
- }
-
- return ShaderInfoForShader( shader );
-}
-
-/*
-================
-CompareVert
-================
-*/
-qboolean CompareVert( drawVert_t *v1, drawVert_t *v2, qboolean checkst ) {
- int i;
-
- for( i = 0; i < 3; i++ ) {
- if ( floor( v1->xyz[ i ] + 0.1 ) != floor( v2->xyz[ i ] + 0.1 ) ) {
- return qfalse;
- }
- if ( checkst && ( ( v1->st[ 0 ] != v2->st[ 0 ] ) || ( v1->st[ 1 ] != v2->st[ 1 ] ) ) ) {
- return qfalse;
- }
- }
-
- return qtrue;
-}
-
-/*
-================
-LoadAlphaMap
-================
-*/
-byte *LoadAlphaMap( int *num_layers, int *alphawidth, int *alphaheight ) {
- int *alphamap32;
- byte *alphamap;
- const char *alphamapname;
- char ext[ 128 ];
- int width;
- int height;
- int layers;
- int size;
- int i;
-
- assert( alphawidth );
- assert( alphaheight );
- assert( num_layers );
-
- layers = atoi( ValueForKey( mapent, "layers" ) );
- if ( layers < 1 ) {
- Error ("SetTerrainTextures: invalid value for 'layers' (%d)", layers );
- }
-
- alphamapname = ValueForKey( mapent, "alphamap" );
- if ( !alphamapname[ 0 ] ) {
- Error ("LoadAlphaMap: No alphamap specified on terrain" );
- }
-
- ExtractFileExtension( alphamapname, ext);
- if ( !Q_stricmp( ext, "tga" ) ) {
- Load32BitImage( ExpandGamePath( alphamapname ), &alphamap32, &width, &height );
-
- size = width * height;
- alphamap = malloc( size );
- for( i = 0; i < size; i++ ) {
- alphamap[ i ] = ( ( alphamap32[ i ] & 0xff ) * layers ) / 256;
- if ( alphamap[ i ] >= layers ) {
- alphamap[ i ] = layers - 1;
- }
- }
- } else {
- Load256Image( ExpandGamePath( alphamapname ), &alphamap, NULL, &width, &height );
- size = width * height;
- for( i = 0; i < size; i++ ) {
- if ( alphamap[ i ] >= layers ) {
- alphamap[ i ] = layers - 1;
- }
- }
- }
-
- if ( ( width < 2 ) || ( height < 2 ) ) {
- Error ("LoadAlphaMap: alphamap width/height must be at least 2x2." );
- }
-
- *num_layers = layers;
- *alphawidth = width;
- *alphaheight = height;
-
- return alphamap;
-}
-
-/*
-================
-CalcTerrainSize
-================
-*/
-void CalcTerrainSize( vec3_t mins, vec3_t maxs, vec3_t size ) {
- bspbrush_t *brush;
- int i;
- const char *key;
-
- // calculate the size of the terrain
- ClearBounds( mins, maxs );
- for( brush = mapent->brushes; brush != NULL; brush = brush->next ) {
- AddPointToBounds( brush->mins, mins, maxs );
- AddPointToBounds( brush->maxs, mins, maxs );
- }
-
- key = ValueForKey( mapent, "min" );
- if ( key[ 0 ] ) {
- GetVectorForKey( mapent, "min", mins );
- }
-
- key = ValueForKey( mapent, "max" );
- if ( key[ 0 ] ) {
- GetVectorForKey( mapent, "max", maxs );
- }
-
- for( i = 0; i < 3; i++ ) {
- mins[ i ] = floor( mins[ i ] + 0.1 );
- maxs[ i ] = floor( maxs[ i ] + 0.1 );
- }
-
- VectorSubtract( maxs, mins, size );
-
- if ( ( size[ 0 ] <= 0 ) || ( size[ 1 ] <= 0 ) ) {
- Error ("CalcTerrainSize: Invalid terrain size: %fx%f", size[ 0 ], size[ 1 ] );
- }
-}
-
-/*
-==================
-IsTriangleDegenerate
-
-Returns qtrue if all three points are collinear or backwards
-===================
-*/
-#define COLINEAR_AREA 10
-static qboolean IsTriangleDegenerate( drawVert_t *points, int a, int b, int c ) {
- vec3_t v1, v2, v3;
- float d;
-
- VectorSubtract( points[b].xyz, points[a].xyz, v1 );
- VectorSubtract( points[c].xyz, points[a].xyz, v2 );
- CrossProduct( v1, v2, v3 );
- d = VectorLength( v3 );
-
- // assume all very small or backwards triangles will cause problems
- if ( d < COLINEAR_AREA ) {
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-===============
-SideAsTriFan
-
-The surface can't be represented as a single tristrip without
-leaving a degenerate triangle (and therefore a crack), so add
-a point in the middle and create (points-1) triangles in fan order
-===============
-*/
-static void SideAsTriFan( terrainSurf_t *surf, int *index, int num ) {
- int i;
- int colorSum[4];
- drawVert_t *mid, *v;
-
- // make sure we have enough space for a new vert
- if ( surf->numVerts >= surf->maxVerts ) {
- surf->maxVerts += GROW_VERTS;
- surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
- }
-
- // create a new point in the center of the face
- mid = &surf->verts[ surf->numVerts ];
- surf->numVerts++;
-
- colorSum[0] = colorSum[1] = colorSum[2] = colorSum[3] = 0;
-
- for (i = 0 ; i < num; i++ ) {
- v = &surf->verts[ index[ i ] ];
- VectorAdd( mid->xyz, v->xyz, mid->xyz );
- mid->st[0] += v->st[0];
- mid->st[1] += v->st[1];
- mid->lightmap[0] += v->lightmap[0];
- mid->lightmap[1] += v->lightmap[1];
-
- colorSum[0] += v->color[0];
- colorSum[1] += v->color[1];
- colorSum[2] += v->color[2];
- colorSum[3] += v->color[3];
- }
-
- mid->xyz[0] /= num;
- mid->xyz[1] /= num;
- mid->xyz[2] /= num;
-
- mid->st[0] /= num;
- mid->st[1] /= num;
-
- mid->lightmap[0] /= num;
- mid->lightmap[1] /= num;
-
- mid->color[0] = colorSum[0] / num;
- mid->color[1] = colorSum[1] / num;
- mid->color[2] = colorSum[2] / num;
- mid->color[3] = colorSum[3] / num;
-
- // fill in indices in trifan order
- if ( surf->numIndexes + num * 3 > surf->maxIndexes ) {
- surf->maxIndexes = surf->numIndexes + num * 3;
- surf->indexes = realloc( surf->indexes, surf->maxIndexes * sizeof( *surf->indexes ) );
- }
-
-
- for ( i = 0 ; i < num; i++ ) {
- surf->indexes[ surf->numIndexes++ ] = surf->numVerts - 1;
- surf->indexes[ surf->numIndexes++ ] = index[ i ];
- surf->indexes[ surf->numIndexes++ ] = index[ (i+1) % ( surf->numVerts - 1 ) ];
- }
-}
-/*
-================
-SideAsTristrip
-
-Try to create indices that make (points-2) triangles in tristrip order
-================
-*/
-#define MAX_INDICES 1024
-static void SideAsTristrip( terrainSurf_t *surf, int *index, int num ) {
- int i;
- int rotate;
- int numIndices;
- int ni;
- int a, b, c;
- int indices[ MAX_INDICES ];
-
- // determine the triangle strip order
- numIndices = ( num - 2 ) * 3;
- if ( numIndices > MAX_INDICES ) {
- Error( "MAX_INDICES exceeded for surface" );
- }
-
- // try all possible orderings of the points looking
- // for a strip order that isn't degenerate
- for ( rotate = 0 ; rotate < num; rotate++ ) {
- for ( ni = 0, i = 0 ; i < num - 2 - i ; i++ ) {
- a = index[ ( num - 1 - i + rotate ) % num ];
- b = index[ ( i + rotate ) % num ];
- c = index[ ( num - 2 - i + rotate ) % num ];
-
- if ( IsTriangleDegenerate( surf->verts, a, b, c ) ) {
- break;
- }
- indices[ni++] = a;
- indices[ni++] = b;
- indices[ni++] = c;
-
- if ( i + 1 != num - 1 - i ) {
- a = index[ ( num - 2 - i + rotate ) % num ];
- b = index[ ( i + rotate ) % num ];
- c = index[ ( i + 1 + rotate ) % num ];
-
- if ( IsTriangleDegenerate( surf->verts, a, b, c ) ) {
- break;
- }
- indices[ni++] = a;
- indices[ni++] = b;
- indices[ni++] = c;
- }
- }
- if ( ni == numIndices ) {
- break; // got it done without degenerate triangles
- }
- }
-
- // if any triangle in the strip is degenerate,
- // render from a centered fan point instead
- if ( ni < numIndices ) {
- SideAsTriFan( surf, index, num );
- return;
- }
-
- // a normal tristrip
- if ( surf->numIndexes + ni > surf->maxIndexes ) {
- surf->maxIndexes = surf->numIndexes + ni;
- surf->indexes = realloc( surf->indexes, surf->maxIndexes * sizeof( *surf->indexes ) );
- }
-
- memcpy( surf->indexes + surf->numIndexes, indices, ni * sizeof( *surf->indexes ) );
- surf->numIndexes += ni;
-}
-
-/*
-================
-CreateTerrainSurface
-================
-*/
-void CreateTerrainSurface( terrainSurf_t *surf, shaderInfo_t *shader ) {
- int i, j, k;
- drawVert_t *out;
- drawVert_t *in;
- mapDrawSurface_t *newsurf;
-
- newsurf = AllocDrawSurf();
-
- newsurf->miscModel = qtrue;
- newsurf->shaderInfo = shader;
- newsurf->lightmapNum = -1;
- newsurf->fogNum = -1;
- newsurf->numIndexes = surf->numIndexes;
- newsurf->numVerts = surf->numVerts;
-
- // copy the indices
- newsurf->indexes = malloc( surf->numIndexes * sizeof( *newsurf->indexes ) );
- memcpy( newsurf->indexes, surf->indexes, surf->numIndexes * sizeof( *newsurf->indexes ) );
-
- // allocate the vertices
- newsurf->verts = malloc( surf->numVerts * sizeof( *newsurf->verts ) );
- memset( newsurf->verts, 0, surf->numVerts * sizeof( *newsurf->verts ) );
-
- // calculate the surface verts
- out = newsurf->verts;
- for( i = 0; i < newsurf->numVerts; i++, out++ ) {
- VectorCopy( surf->verts[ i ].xyz, out->xyz );
-
- // set the texture coordinates
- out->st[ 0 ] = surf->verts[ i ].st[ 0 ];
- out->st[ 1 ] = surf->verts[ i ].st[ 1 ];
-
- // the colors will be set by the lighting pass
- out->color[0] = 255;
- out->color[1] = 255;
- out->color[2] = 255;
- out->color[3] = surf->verts[ i ].color[ 3 ];
-
- // calculate the vertex normal
- VectorClear( out->normal );
- for( j = 0; j < numsurfaces; j++ ) {
- in = surfaces[ j ].verts;
- for( k = 0; k < surfaces[ j ].numVerts; k++, in++ ) {
- if ( CompareVert( out, in, qfalse ) ) {
- VectorAdd( out->normal, in->normal, out->normal );
- }
- }
- }
-
- VectorNormalize( out->normal, out->normal );
- }
-}
-
-/*
-================
-EmitTerrainVerts
-================
-*/
-void EmitTerrainVerts( side_t *side, terrainSurf_t *surf, int maxlayer, int alpha[ MAX_POINTS_ON_WINDING ], qboolean projecttexture ) {
- int i;
- int j;
- drawVert_t *vert;
- int *indices;
- int numindices;
- int maxindices;
- int xyplane;
- vec3_t xynorm = { 0, 0, 1 };
- vec_t shift[ 2 ] = { 0, 0 };
- vec_t scale[ 2 ] = { 0.5, 0.5 };
- float vecs[ 2 ][ 4 ];
- static int numtimes = 0;
-
- numtimes++;
-
- if ( !surf->verts ) {
- surf->numVerts = 0;
- surf->maxVerts = GROW_VERTS;
- surf->verts = malloc( surf->maxVerts * sizeof( *surf->verts ) );
-
- surf->numIndexes = 0;
- surf->maxIndexes = GROW_INDICES;
- surf->indexes = malloc( surf->maxIndexes * sizeof( *surf->indexes ) );
- }
-
- // calculate the texture coordinate vectors
- xyplane = FindFloatPlane( xynorm, 0 );
- QuakeTextureVecs( &mapplanes[ xyplane ], shift, 0, scale, vecs );
-
- // emit the vertexes
- numindices = 0;
- maxindices = surf->maxIndexes;
- indices = malloc ( maxindices * sizeof( *indices ) );
-
- for ( i = 0; i < side->winding->numpoints; i++ ) {
- vert = &surf->verts[ surf->numVerts ];
-
- // set the final alpha value--0 for texture 1, 255 for texture 2
- if ( alpha[ i ] < maxlayer ) {
- vert->color[3] = 0;
- } else {
- vert->color[3] = 255;
- }
-
- vert->xyz[ 0 ] = floor( side->winding->p[ i ][ 0 ] + 0.1f );
- vert->xyz[ 1 ] = floor( side->winding->p[ i ][ 1 ] + 0.1f );
- vert->xyz[ 2 ] = floor( side->winding->p[ i ][ 2 ] + 0.1f );
-
- // set the texture coordinates
- if ( projecttexture ) {
- vert->st[0] = ( vecs[0][3] + DotProduct( vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
- vert->st[1] = ( vecs[1][3] + DotProduct( vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
- } else {
- vert->st[0] = ( side->vecs[0][3] + DotProduct( side->vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
- vert->st[1] = ( side->vecs[1][3] + DotProduct( side->vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
- }
-
- VectorCopy( mapplanes[ side->planenum ].normal, vert->normal );
-
- for( j = 0; j < surf->numVerts; j++ ) {
- if ( CompareVert( vert, &surf->verts[ j ], qtrue ) ) {
- break;
- }
- }
-
- if ( numindices >= maxindices ) {
- maxindices += GROW_INDICES;
- indices = realloc( indices, maxindices * sizeof( *indices ) );
- }
-
- if ( j != surf->numVerts ) {
- indices[ numindices++ ] = j;
- } else {
- indices[ numindices++ ] = surf->numVerts;
- surf->numVerts++;
- if ( surf->numVerts >= surf->maxVerts ) {
- surf->maxVerts += GROW_VERTS;
- surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
- }
- }
- }
-
- SideAsTristrip( surf, indices, numindices );
-
- free( indices );
-}
-
-/*
-================
-SurfaceForShader
-================
-*/
-terrainSurf_t *SurfaceForShader( shaderInfo_t *shader, int x, int y ) {
- int i;
-
- if ( lastSurface && ( lastSurface->shader == shader ) && ( lastSurface->x == x ) && ( lastSurface->y == y ) ) {
- return lastSurface;
- }
-
- lastSurface = surfaces;
- for( i = 0; i < numsurfaces; i++, lastSurface++ ) {
- if ( ( lastSurface->shader == shader ) && ( lastSurface->x == x ) && ( lastSurface->y == y ) ) {
- return lastSurface;
- }
- }
-
- if ( numsurfaces >= maxsurfaces ) {
- maxsurfaces += GROW_SURFACES;
- surfaces = realloc( surfaces, maxsurfaces * sizeof( *surfaces ) );
- memset( surfaces + numsurfaces + 1, 0, ( maxsurfaces - numsurfaces - 1 ) * sizeof( *surfaces ) );
- }
-
- lastSurface= &surfaces[ numsurfaces++ ];
- lastSurface->shader = shader;
- lastSurface->x = x;
- lastSurface->y = y;
-
- return lastSurface;
-}
-
-/*
-================
-SetTerrainTextures
-================
-*/
-void SetTerrainTextures( void ) {
- int i;
- int x, y;
- int layer;
- int minlayer, maxlayer;
- float s, t;
- float min_s, min_t;
- int alpha[ MAX_POINTS_ON_WINDING ];
- shaderInfo_t *si, *terrainShader;
- bspbrush_t *brush;
- side_t *side;
- const char *shadername;
- vec3_t mins, maxs;
- vec3_t size;
- int surfwidth, surfheight, surfsize;
- terrainSurf_t *surf;
- byte *alphamap;
- int alphawidth, alphaheight;
- int num_layers;
- extern qboolean onlyents;
-
- if ( onlyents ) {
- return;
- }
-
- shadername = ValueForKey( mapent, "shader" );
- if ( !shadername[ 0 ] ) {
- Error ("SetTerrainTextures: shader not specified" );
- }
-
- alphamap = LoadAlphaMap( &num_layers, &alphawidth, &alphaheight );
-
- mapent->firstDrawSurf = numMapDrawSurfs;
-
- // calculate the size of the terrain
- CalcTerrainSize( mins, maxs, size );
-
- surfwidth = ( size[ 0 ] + SURF_WIDTH - 1 ) / SURF_WIDTH;
- surfheight = ( size[ 1 ] + SURF_HEIGHT - 1 ) / SURF_HEIGHT;
- surfsize = surfwidth * surfheight;
-
- lastSurface = NULL;
- numsurfaces = 0;
- maxsurfaces = 0;
- for( i = num_layers; i > 0; i-- ) {
- maxsurfaces += i * surfsize;
- }
- surfaces = malloc( maxsurfaces * sizeof( *surfaces ) );
- memset( surfaces, 0, maxsurfaces * sizeof( *surfaces ) );
-
- terrainShader = ShaderInfoForShader( "textures/common/terrain" );
-
- for( brush = mapent->brushes; brush != NULL; brush = brush->next ) {
- // only create surfaces for sides marked as terrain
- for( side = brush->sides; side < &brush->sides[ brush->numsides ]; side++ ) {
- if ( !side->shaderInfo ) {
- continue;
- }
-
- if ( ( ( side->surfaceFlags | side->shaderInfo->surfaceFlags ) & SURF_NODRAW ) && !strstr( side->shaderInfo->shader, "terrain" ) ) {
- continue;
- }
-
- minlayer = num_layers;
- maxlayer = 0;
-
- // project each point of the winding onto the alphamap to determine which
- // textures to blend
- min_s = 1.0;
- min_t = 1.0;
- for( i = 0; i < side->winding->numpoints; i++ ) {
- s = floor( side->winding->p[ i ][ 0 ] + 0.1f - mins[ 0 ] ) / size[ 0 ];
- t = floor( side->winding->p[ i ][ 1 ] + 0.1f - mins[ 0 ] ) / size[ 1 ];
-
- if ( s < 0 ) {
- s = 0;
- }
-
- if ( t < 0 ) {
- t = 0;
- }
-
- if ( s >= 1.0 ) {
- s = 1.0;
- }
-
- if ( t >= 1.0 ) {
- t = 1.0;
- }
-
- if ( s < min_s ) {
- min_s = s;
- }
-
- if ( t < min_t ) {
- min_t = t;
- }
-
- x = ( alphawidth - 1 ) * s;
- y = ( alphaheight - 1 ) * t;
-
- layer = alphamap[ x + y * alphawidth ];
- if ( layer < minlayer ) {
- minlayer = layer;
- }
-
- if ( layer > maxlayer ) {
- maxlayer = layer;
- }
-
- alpha[ i ] = layer;
- }
-
- x = min_s * surfwidth;
- if ( x >= surfwidth ) {
- x = surfwidth - 1;
- }
-
- y = min_t * surfheight;
- if ( y >= surfheight ) {
- y = surfheight - 1;
- }
-
- if ( strstr( side->shaderInfo->shader, "terrain" ) ) {
- si = ShaderForLayer( minlayer, maxlayer, shadername );
- if ( showseams ) {
- for( i = 0; i < side->winding->numpoints; i++ ) {
- if ( ( alpha[ i ] != minlayer ) && ( alpha[ i ] != maxlayer ) ) {
- si = ShaderInfoForShader( "textures/common/white" );
- break;
- }
- }
- }
- surf = SurfaceForShader( si, x, y );
- EmitTerrainVerts( side, surf, maxlayer, alpha, qtrue );
- } else {
- si = side->shaderInfo;
- side->shaderInfo = terrainShader;
- surf = SurfaceForShader( si, x, y );
- EmitTerrainVerts( side, surf, maxlayer, alpha, qfalse );
- }
- }
- }
-
- // create the final surfaces
- for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
- if ( surf->numVerts ) {
- CreateTerrainSurface( surf, surf->shader );
- }
- }
-
- //
- // clean up any allocated memory
- //
- for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
- if ( surf->verts ) {
- free( surf->verts );
- free( surf->indexes );
- }
- }
- free( alphamap );
- free( surfaces );
-
- surfaces = NULL;
- lastSurface = NULL;
- numsurfaces = 0;
- maxsurfaces = 0;
-}
-
-/*****************************************************************************
-
- New terrain code
-
-******************************************************************************/
-
-typedef struct terrainFace_s {
- shaderInfo_t *shaderInfo;
- //texdef_t texdef;
-
- float vecs[ 2 ][ 4 ]; // texture coordinate mapping
-} terrainFace_t;
-
-typedef struct terrainVert_s {
- vec3_t xyz;
- terrainFace_t tri;
-} terrainVert_t;
-
-typedef struct terrainMesh_s {
- float scale_x;
- float scale_y;
- vec3_t origin;
-
- int width, height;
- terrainVert_t *map;
-} terrainMesh_t;
-
-terrainVert_t *Terrain_GetVert( terrainMesh_t *pm, int x, int y ) {
- return &pm->map[ x + y * pm->width ];
-}
-
-void Terrain_GetTriangles( terrainMesh_t *pm, int x, int y, terrainVert_t **verts ) {
- if ( ( x + y ) & 1 ) {
- // first tri
- verts[ 0 ] = Terrain_GetVert( pm, x, y );
- verts[ 1 ] = Terrain_GetVert( pm, x, y + 1 );
- verts[ 2 ] = Terrain_GetVert( pm, x + 1, y + 1 );
-
- // second tri
- verts[ 3 ] = verts[ 2 ];
- verts[ 4 ] = Terrain_GetVert( pm, x + 1, y );
- verts[ 5 ] = verts[ 0 ];
- } else {
- // first tri
- verts[ 0 ] = Terrain_GetVert( pm, x, y );
- verts[ 1 ] = Terrain_GetVert( pm, x, y + 1 );
- verts[ 2 ] = Terrain_GetVert( pm, x + 1, y );
-
- // second tri
- verts[ 3 ] = verts[ 2 ];
- verts[ 4 ] = verts[ 1 ];
- verts[ 5 ] = Terrain_GetVert( pm, x + 1, y + 1 );
- }
-}
-
-/*
-================
-EmitTerrainVerts2
-================
-*/
-void EmitTerrainVerts2( terrainSurf_t *surf, terrainVert_t **verts, int alpha[ 3 ] ) {
- int i;
- int j;
- drawVert_t *vert;
- int *indices;
- int numindices;
- int maxindices;
- int xyplane;
- vec3_t xynorm = { 0, 0, 1 };
- vec_t shift[ 2 ] = { 0, 0 };
- vec_t scale[ 2 ] = { 0.5, 0.5 };
- float vecs[ 2 ][ 4 ];
- vec4_t plane;
-
- if ( !surf->verts ) {
- surf->numVerts = 0;
- surf->maxVerts = GROW_VERTS;
- surf->verts = malloc( surf->maxVerts * sizeof( *surf->verts ) );
-
- surf->numIndexes = 0;
- surf->maxIndexes = GROW_INDICES;
- surf->indexes = malloc( surf->maxIndexes * sizeof( *surf->indexes ) );
- }
-
- // calculate the texture coordinate vectors
- xyplane = FindFloatPlane( xynorm, 0 );
- QuakeTextureVecs( &mapplanes[ xyplane ], shift, 0, scale, vecs );
-
- // emit the vertexes
- numindices = 0;
- maxindices = surf->maxIndexes;
- assert( maxindices >= 0 );
- indices = malloc ( maxindices * sizeof( *indices ) );
-
- PlaneFromPoints( plane, verts[ 0 ]->xyz, verts[ 1 ]->xyz, verts[ 2 ]->xyz );
-
- for ( i = 0; i < 3; i++ ) {
- vert = &surf->verts[ surf->numVerts ];
-
- if ( alpha[ i ] ) {
- vert->color[3] = 255;
- } else {
- vert->color[3] = 0;
- }
-
- vert->xyz[ 0 ] = floor( verts[ i ]->xyz[ 0 ] + 0.1f );
- vert->xyz[ 1 ] = floor( verts[ i ]->xyz[ 1 ] + 0.1f );
- vert->xyz[ 2 ] = floor( verts[ i ]->xyz[ 2 ] + 0.1f );
-
- // set the texture coordinates
- vert->st[0] = ( vecs[0][3] + DotProduct( vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
- vert->st[1] = ( vecs[1][3] + DotProduct( vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
-
- VectorCopy( plane, vert->normal );
-
- for( j = 0; j < surf->numVerts; j++ ) {
- if ( CompareVert( vert, &surf->verts[ j ], qtrue ) ) {
- break;
- }
- }
-
- if ( numindices >= maxindices ) {
- maxindices += GROW_INDICES;
- indices = realloc( indices, maxindices * sizeof( *indices ) );
- }
-
- if ( j != surf->numVerts ) {
- indices[ numindices++ ] = j;
- } else {
- indices[ numindices++ ] = surf->numVerts;
- surf->numVerts++;
- if ( surf->numVerts >= surf->maxVerts ) {
- surf->maxVerts += GROW_VERTS;
- surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
- }
- }
- }
-
- SideAsTristrip( surf, indices, numindices );
-
- free( indices );
-}
-
-int MapPlaneFromPoints( vec3_t p0, vec3_t p1, vec3_t p2 );
-void QuakeTextureVecs( plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2], vec_t mappingVecs[2][4] );
-qboolean RemoveDuplicateBrushPlanes( bspbrush_t *b );
-void SetBrushContents( bspbrush_t *b );
-
-void AddBrushSide( vec3_t v1, vec3_t v2, vec3_t v3, shaderInfo_t *terrainShader ) {
- side_t *side;
- int planenum;
-
- side = &buildBrush->sides[ buildBrush->numsides ];
- memset( side, 0, sizeof( *side ) );
- buildBrush->numsides++;
-
- side->shaderInfo = terrainShader;
-
- // find the plane number
- planenum = MapPlaneFromPoints( v1, v2, v3 );
- side->planenum = planenum;
-}
-
-void MakeBrushFromTriangle( vec3_t v1, vec3_t v2, vec3_t v3, shaderInfo_t *terrainShader ) {
- bspbrush_t *b;
- vec3_t d1;
- vec3_t d2;
- vec3_t d3;
-
- VectorSet( d1, v1[ 0 ], v1[ 1 ], MIN_WORLD_COORD + 10 ); //FIXME
- VectorSet( d2, v2[ 0 ], v2[ 1 ], MIN_WORLD_COORD + 10 );
- VectorSet( d3, v3[ 0 ], v3[ 1 ], MIN_WORLD_COORD + 10 );
-
- buildBrush->numsides = 0;
- buildBrush->detail = qfalse;
-
- AddBrushSide( v1, v2, v3, terrainShader );
- AddBrushSide( v1, d1, v2, terrainShader );
- AddBrushSide( v2, d2, v3, terrainShader );
- AddBrushSide( v3, d3, v1, terrainShader );
- AddBrushSide( d3, d2, d1, terrainShader );
-
- buildBrush->portalareas[0] = -1;
- buildBrush->portalareas[1] = -1;
- buildBrush->entitynum = num_entities-1;
- buildBrush->brushnum = entitySourceBrushes;
-
- // if there are mirrored planes, the entire brush is invalid
- if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
- return;
- }
-
- // get the content for the entire brush
- SetBrushContents( buildBrush );
- buildBrush->contents |= CONTENTS_DETAIL;
-
- b = FinishBrush();
- if ( !b ) {
- return;
- }
-}
-
-void MakeTerrainIntoBrushes( terrainMesh_t *tm ) {
- int index[ 6 ];
- int y;
- int x;
- terrainVert_t *verts;
- shaderInfo_t *terrainShader;
-
- terrainShader = ShaderInfoForShader( "textures/common/terrain" );
-
- verts = tm->map;
- for( y = 0; y < tm->height - 1; y++ ) {
- for( x = 0; x < tm->width - 1; x++ ) {
- if ( ( x + y ) & 1 ) {
- // first tri
- index[ 0 ] = x + y * tm->width;
- index[ 1 ] = x + ( y + 1 ) * tm->width;
- index[ 2 ] = ( x + 1 ) + ( y + 1 ) * tm->width;
- index[ 3 ] = ( x + 1 ) + ( y + 1 ) * tm->width;
- index[ 4 ] = ( x + 1 ) + y * tm->width;
- index[ 5 ] = x + y * tm->width;
- } else {
- // first tri
- index[ 0 ] = x + y * tm->width;
- index[ 1 ] = x + ( y + 1 ) * tm->width;
- index[ 2 ] = ( x + 1 ) + y * tm->width;
- index[ 3 ] = ( x + 1 ) + y * tm->width;
- index[ 4 ] = x + ( y + 1 ) * tm->width;
- index[ 5 ] = ( x + 1 ) + ( y + 1 ) * tm->width;
- }
-
- MakeBrushFromTriangle( verts[ index[ 0 ] ].xyz, verts[ index[ 1 ] ].xyz, verts[ index[ 2 ] ].xyz, terrainShader );
- MakeBrushFromTriangle( verts[ index[ 3 ] ].xyz, verts[ index[ 4 ] ].xyz, verts[ index[ 5 ] ].xyz, terrainShader );
- }
- }
-}
-
-void Terrain_ParseFace( terrainFace_t *face ) {
- shaderInfo_t *si;
- vec_t shift[ 2 ];
- vec_t rotate;
- vec_t scale[ 2 ];
- char name[ MAX_QPATH ];
- char shader[ MAX_QPATH ];
- plane_t p;
-
- // read the texturedef
- GetToken( qfalse );
- strcpy( name, token );
-
- GetToken( qfalse );
- shift[ 0 ] = atof(token);
- GetToken( qfalse );
- shift[ 1 ] = atof( token );
- GetToken( qfalse );
- rotate = atof( token );
- GetToken( qfalse );
- scale[ 0 ] = atof( token );
- GetToken( qfalse );
- scale[ 1 ] = atof( token );
-
- // find default flags and values
- sprintf( shader, "textures/%s", name );
- si = ShaderInfoForShader( shader );
- face->shaderInfo = si;
- //face->texdef = si->texdef;
-
- // skip over old contents
- GetToken( qfalse );
-
- // skip over old flags
- GetToken( qfalse );
-
- // skip over old value
- GetToken( qfalse );
-
- //Surface_Parse( &face->texdef );
- //Surface_BuildTexdef( &face->texdef );
-
- // make a fake horizontal plane
- VectorSet( p.normal, 0, 0, 1 );
- p.dist = 0;
- p.type = PlaneTypeForNormal( p.normal );
-
- QuakeTextureVecs( &p, shift, rotate, scale, face->vecs );
-}
-
-#define MAX_TERRAIN_TEXTURES 128
-static int numtextures = 0;;
-static shaderInfo_t *textures[ MAX_TERRAIN_TEXTURES ];
-
-void Terrain_AddTexture( shaderInfo_t *texture ) {
- int i;
-
- if ( !texture ) {
- return;
- }
-
- for( i = 0; i < numtextures; i++ ) {
- if ( textures[ i ] == texture ) {
- return;
- }
- }
-
- if ( numtextures >= MAX_TERRAIN_TEXTURES ) {
- Error( "Too many textures on terrain" );
- return;
- }
-
- textures[ numtextures++ ] = texture;
-}
-
-int LayerForShader( shaderInfo_t *shader ) {
- int i;
- int l;
-
- l = strlen( shader->shader );
- for( i = l - 1; i >= 0; i-- ) {
- if ( shader->shader[ i ] == '_' ) {
- return atoi( &shader->shader[ i + 1 ] );
- break;
- }
- }
-
- return 0;
-}
-
-/*
-=================
-ParseTerrain
-
-Creates a mapDrawSurface_t from the terrain text
-=================
-*/
-
-void ParseTerrain( void ) {
- int i, j;
- int x, y;
- int x1, y1;
- terrainMesh_t t;
- int index;
- terrainVert_t *verts[ 6 ];
- int num_layers;
- int layer, minlayer, maxlayer;
- int alpha[ 6 ];
- shaderInfo_t *si, *terrainShader;
- int surfwidth, surfheight, surfsize;
- terrainSurf_t *surf;
- char shadername[ MAX_QPATH ];
-
- mapent->firstDrawSurf = numMapDrawSurfs;
-
- memset( &t, 0, sizeof( t ) );
-
- MatchToken( "{" );
-
- // get width
- GetToken( qtrue );
- t.width = atoi( token );
-
- // get height
- GetToken( qfalse );
- t.height = atoi( token );
-
- // get scale_x
- GetToken( qfalse );
- t.scale_x = atof( token );
-
- // get scale_y
- GetToken( qfalse );
- t.scale_y = atof( token );
-
- // get origin
- GetToken( qtrue );
- t.origin[ 0 ] = atof( token );
- GetToken( qfalse );
- t.origin[ 1 ] = atof( token );
- GetToken( qfalse );
- t.origin[ 2 ] = atof( token );
-
- t.map = malloc( t.width * t.height * sizeof( t.map[ 0 ] ) );
-
- if ( t.width <= 0 || t.height <= 0 ) {
- Error( "ParseTerrain: bad size" );
- }
-
- numtextures = 0;
- index = 0;
- for ( i = 0; i < t.height; i++ ) {
- for( j = 0; j < t.width; j++, index++ ) {
- // get height
- GetToken( qtrue );
- t.map[ index ].xyz[ 0 ] = t.origin[ 0 ] + t.scale_x * ( float )j;
- t.map[ index ].xyz[ 1 ] = t.origin[ 1 ] + t.scale_y * ( float )i;
- t.map[ index ].xyz[ 2 ] = t.origin[ 2 ] + atof( token );
-
- Terrain_ParseFace( &t.map[ index ].tri );
- Terrain_AddTexture( t.map[ index ].tri.shaderInfo );
- }
- }
-
- MatchToken( "}" );
- MatchToken( "}" );
-
- MakeTerrainIntoBrushes( &t );
-
- surfwidth = ( ( t.scale_x * t.width ) + SURF_WIDTH - 1 ) / SURF_WIDTH;
- surfheight = ( ( t.scale_y * t.height ) + SURF_HEIGHT - 1 ) / SURF_HEIGHT;
- surfsize = surfwidth * surfheight;
-
- //FIXME
- num_layers = 0;
- for( i = 0; i < numtextures; i++ ) {
- layer = LayerForShader( textures[ i ] ) + 1;
- if ( layer > num_layers ) {
- num_layers = layer;
- }
- }
- num_layers = 4;
-
- memset( alpha, 0, sizeof( alpha ) );
-
- lastSurface = NULL;
- numsurfaces = 0;
- maxsurfaces = 0;
- for( i = num_layers; i > 0; i-- ) {
- maxsurfaces += i * surfsize;
- }
-
- surfaces = malloc( maxsurfaces * sizeof( *surfaces ) );
- memset( surfaces, 0, maxsurfaces * sizeof( *surfaces ) );
-
- terrainShader = ShaderInfoForShader( "textures/common/terrain" );
-
- // get the shadername
- if ( Q_strncasecmp( textures[ 0 ]->shader, "textures/", 9 ) == 0 ) {
- strcpy( shadername, &textures[ 0 ]->shader[ 9 ] );
- } else {
- strcpy( shadername, textures[ 0 ]->shader );
- }
- j = strlen( shadername );
- for( i = j - 1; i >= 0; i-- ) {
- if ( shadername[ i ] == '_' ) {
- shadername[ i ] = 0;
- break;
- }
- }
-
- for( y = 0; y < t.height - 1; y++ ) {
- for( x = 0; x < t.width - 1; x++ ) {
- Terrain_GetTriangles( &t, x, y, verts );
-
- x1 = ( ( float )x / ( float )( t.width - 1 ) ) * surfwidth;
- if ( x1 >= surfwidth ) {
- x1 = surfwidth - 1;
- }
-
- y1 = ( ( float )y / ( float )( t.height - 1 ) ) * surfheight;
- if ( y1 >= surfheight ) {
- y1 = surfheight - 1;
- }
-
- maxlayer = minlayer = LayerForShader( verts[ 0 ]->tri.shaderInfo );
- for( i = 0; i < 3; i++ ) {
- layer = LayerForShader( verts[ i ]->tri.shaderInfo );
- if ( layer < minlayer ) {
- minlayer = layer;
- }
- if ( layer > maxlayer ) {
- maxlayer = layer;
- }
- }
-
- for( i = 0; i < 3; i++ ) {
- layer = LayerForShader( verts[ i ]->tri.shaderInfo );
- if ( layer > minlayer ) {
- alpha[ i ] = 1.0f;
- } else {
- alpha[ i ] = 0.0f;
- }
- }
-
- si = ShaderForLayer( minlayer, maxlayer, shadername );
- surf = SurfaceForShader( si, x1, y1 );
- EmitTerrainVerts2( surf, &verts[ 0 ], &alpha[ 0 ] );
-
- // second triangle
- maxlayer = minlayer = LayerForShader( verts[ 3 ]->tri.shaderInfo );
- for( i = 3; i < 6; i++ ) {
- layer = LayerForShader( verts[ i ]->tri.shaderInfo );
- if ( layer < minlayer ) {
- minlayer = layer;
- }
- if ( layer > maxlayer ) {
- maxlayer = layer;
- }
- }
-
- for( i = 3; i < 6; i++ ) {
- layer = LayerForShader( verts[ i ]->tri.shaderInfo );
- if ( layer > minlayer ) {
- alpha[ i ] = 1.0f;
- } else {
- alpha[ i ] = 0.0f;
- }
- }
-
- si = ShaderForLayer( minlayer, maxlayer, shadername );
- surf = SurfaceForShader( si, x1, y1 );
- EmitTerrainVerts2( surf, &verts[ 3 ], &alpha[ 3 ] );
- }
- }
-
- // create the final surfaces
- for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
- if ( surf->numVerts ) {
- CreateTerrainSurface( surf, surf->shader );
- }
- }
-
- //
- // clean up any allocated memory
- //
- for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
- if ( surf->verts ) {
- free( surf->verts );
- free( surf->indexes );
- }
- }
- free( surfaces );
-
- surfaces = NULL;
- lastSurface = NULL;
- numsurfaces = 0;
- maxsurfaces = 0;
-
- free( t.map );
-}
-
+#include "qbsp.h"
+#include <assert.h>
+
+#define SURF_WIDTH 2048
+#define SURF_HEIGHT 2048
+
+#define GROW_VERTS 512
+#define GROW_INDICES 512
+#define GROW_SURFACES 128
+
+#define VectorSet(v, x, y, z) v[0] = x;v[1] = y;v[2] = z;
+
+void QuakeTextureVecs( plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2], vec_t mappingVecs[2][4] );
+
+typedef struct {
+ shaderInfo_t *shader;
+ int x, y;
+
+ int maxVerts;
+ int numVerts;
+ drawVert_t *verts;
+
+ int maxIndexes;
+ int numIndexes;
+ int *indexes;
+} terrainSurf_t;
+
+static terrainSurf_t *surfaces = NULL;
+static terrainSurf_t *lastSurface = NULL;
+static int numsurfaces = 0;
+static int maxsurfaces = 0;
+
+/*
+================
+ShaderForLayer
+================
+*/
+shaderInfo_t *ShaderForLayer( int minlayer, int maxlayer, const char *shadername ) {
+ char shader[ MAX_QPATH ];
+
+ if ( minlayer == maxlayer ) {
+ sprintf( shader, "textures/%s_%d", shadername, maxlayer );
+ } else {
+ sprintf( shader, "textures/%s_%dto%d", shadername, minlayer, maxlayer );
+ }
+
+ return ShaderInfoForShader( shader );
+}
+
+/*
+================
+CompareVert
+================
+*/
+qboolean CompareVert( drawVert_t *v1, drawVert_t *v2, qboolean checkst ) {
+ int i;
+
+ for( i = 0; i < 3; i++ ) {
+ if ( floor( v1->xyz[ i ] + 0.1 ) != floor( v2->xyz[ i ] + 0.1 ) ) {
+ return qfalse;
+ }
+ if ( checkst && ( ( v1->st[ 0 ] != v2->st[ 0 ] ) || ( v1->st[ 1 ] != v2->st[ 1 ] ) ) ) {
+ return qfalse;
+ }
+ }
+
+ return qtrue;
+}
+
+/*
+================
+LoadAlphaMap
+================
+*/
+byte *LoadAlphaMap( int *num_layers, int *alphawidth, int *alphaheight ) {
+ int *alphamap32;
+ byte *alphamap;
+ const char *alphamapname;
+ char ext[ 128 ];
+ int width;
+ int height;
+ int layers;
+ int size;
+ int i;
+
+ assert( alphawidth );
+ assert( alphaheight );
+ assert( num_layers );
+
+ layers = atoi( ValueForKey( mapent, "layers" ) );
+ if ( layers < 1 ) {
+ Error ("SetTerrainTextures: invalid value for 'layers' (%d)", layers );
+ }
+
+ alphamapname = ValueForKey( mapent, "alphamap" );
+ if ( !alphamapname[ 0 ] ) {
+ Error ("LoadAlphaMap: No alphamap specified on terrain" );
+ }
+
+ ExtractFileExtension( alphamapname, ext);
+ if ( !Q_stricmp( ext, "tga" ) ) {
+ Load32BitImage( ExpandGamePath( alphamapname ), &alphamap32, &width, &height );
+
+ size = width * height;
+ alphamap = malloc( size );
+ for( i = 0; i < size; i++ ) {
+ alphamap[ i ] = ( ( alphamap32[ i ] & 0xff ) * layers ) / 256;
+ if ( alphamap[ i ] >= layers ) {
+ alphamap[ i ] = layers - 1;
+ }
+ }
+ } else {
+ Load256Image( ExpandGamePath( alphamapname ), &alphamap, NULL, &width, &height );
+ size = width * height;
+ for( i = 0; i < size; i++ ) {
+ if ( alphamap[ i ] >= layers ) {
+ alphamap[ i ] = layers - 1;
+ }
+ }
+ }
+
+ if ( ( width < 2 ) || ( height < 2 ) ) {
+ Error ("LoadAlphaMap: alphamap width/height must be at least 2x2." );
+ }
+
+ *num_layers = layers;
+ *alphawidth = width;
+ *alphaheight = height;
+
+ return alphamap;
+}
+
+/*
+================
+CalcTerrainSize
+================
+*/
+void CalcTerrainSize( vec3_t mins, vec3_t maxs, vec3_t size ) {
+ bspbrush_t *brush;
+ int i;
+ const char *key;
+
+ // calculate the size of the terrain
+ ClearBounds( mins, maxs );
+ for( brush = mapent->brushes; brush != NULL; brush = brush->next ) {
+ AddPointToBounds( brush->mins, mins, maxs );
+ AddPointToBounds( brush->maxs, mins, maxs );
+ }
+
+ key = ValueForKey( mapent, "min" );
+ if ( key[ 0 ] ) {
+ GetVectorForKey( mapent, "min", mins );
+ }
+
+ key = ValueForKey( mapent, "max" );
+ if ( key[ 0 ] ) {
+ GetVectorForKey( mapent, "max", maxs );
+ }
+
+ for( i = 0; i < 3; i++ ) {
+ mins[ i ] = floor( mins[ i ] + 0.1 );
+ maxs[ i ] = floor( maxs[ i ] + 0.1 );
+ }
+
+ VectorSubtract( maxs, mins, size );
+
+ if ( ( size[ 0 ] <= 0 ) || ( size[ 1 ] <= 0 ) ) {
+ Error ("CalcTerrainSize: Invalid terrain size: %fx%f", size[ 0 ], size[ 1 ] );
+ }
+}
+
+/*
+==================
+IsTriangleDegenerate
+
+Returns qtrue if all three points are collinear or backwards
+===================
+*/
+#define COLINEAR_AREA 10
+static qboolean IsTriangleDegenerate( drawVert_t *points, int a, int b, int c ) {
+ vec3_t v1, v2, v3;
+ float d;
+
+ VectorSubtract( points[b].xyz, points[a].xyz, v1 );
+ VectorSubtract( points[c].xyz, points[a].xyz, v2 );
+ CrossProduct( v1, v2, v3 );
+ d = VectorLength( v3 );
+
+ // assume all very small or backwards triangles will cause problems
+ if ( d < COLINEAR_AREA ) {
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+/*
+===============
+SideAsTriFan
+
+The surface can't be represented as a single tristrip without
+leaving a degenerate triangle (and therefore a crack), so add
+a point in the middle and create (points-1) triangles in fan order
+===============
+*/
+static void SideAsTriFan( terrainSurf_t *surf, int *index, int num ) {
+ int i;
+ int colorSum[4];
+ drawVert_t *mid, *v;
+
+ // make sure we have enough space for a new vert
+ if ( surf->numVerts >= surf->maxVerts ) {
+ surf->maxVerts += GROW_VERTS;
+ surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
+ }
+
+ // create a new point in the center of the face
+ mid = &surf->verts[ surf->numVerts ];
+ surf->numVerts++;
+
+ colorSum[0] = colorSum[1] = colorSum[2] = colorSum[3] = 0;
+
+ for (i = 0 ; i < num; i++ ) {
+ v = &surf->verts[ index[ i ] ];
+ VectorAdd( mid->xyz, v->xyz, mid->xyz );
+ mid->st[0] += v->st[0];
+ mid->st[1] += v->st[1];
+ mid->lightmap[0] += v->lightmap[0];
+ mid->lightmap[1] += v->lightmap[1];
+
+ colorSum[0] += v->color[0];
+ colorSum[1] += v->color[1];
+ colorSum[2] += v->color[2];
+ colorSum[3] += v->color[3];
+ }
+
+ mid->xyz[0] /= num;
+ mid->xyz[1] /= num;
+ mid->xyz[2] /= num;
+
+ mid->st[0] /= num;
+ mid->st[1] /= num;
+
+ mid->lightmap[0] /= num;
+ mid->lightmap[1] /= num;
+
+ mid->color[0] = colorSum[0] / num;
+ mid->color[1] = colorSum[1] / num;
+ mid->color[2] = colorSum[2] / num;
+ mid->color[3] = colorSum[3] / num;
+
+ // fill in indices in trifan order
+ if ( surf->numIndexes + num * 3 > surf->maxIndexes ) {
+ surf->maxIndexes = surf->numIndexes + num * 3;
+ surf->indexes = realloc( surf->indexes, surf->maxIndexes * sizeof( *surf->indexes ) );
+ }
+
+
+ for ( i = 0 ; i < num; i++ ) {
+ surf->indexes[ surf->numIndexes++ ] = surf->numVerts - 1;
+ surf->indexes[ surf->numIndexes++ ] = index[ i ];
+ surf->indexes[ surf->numIndexes++ ] = index[ (i+1) % ( surf->numVerts - 1 ) ];
+ }
+}
+/*
+================
+SideAsTristrip
+
+Try to create indices that make (points-2) triangles in tristrip order
+================
+*/
+#define MAX_INDICES 1024
+static void SideAsTristrip( terrainSurf_t *surf, int *index, int num ) {
+ int i;
+ int rotate;
+ int numIndices;
+ int ni;
+ int a, b, c;
+ int indices[ MAX_INDICES ];
+
+ // determine the triangle strip order
+ numIndices = ( num - 2 ) * 3;
+ if ( numIndices > MAX_INDICES ) {
+ Error( "MAX_INDICES exceeded for surface" );
+ }
+
+ // try all possible orderings of the points looking
+ // for a strip order that isn't degenerate
+ for ( rotate = 0 ; rotate < num; rotate++ ) {
+ for ( ni = 0, i = 0 ; i < num - 2 - i ; i++ ) {
+ a = index[ ( num - 1 - i + rotate ) % num ];
+ b = index[ ( i + rotate ) % num ];
+ c = index[ ( num - 2 - i + rotate ) % num ];
+
+ if ( IsTriangleDegenerate( surf->verts, a, b, c ) ) {
+ break;
+ }
+ indices[ni++] = a;
+ indices[ni++] = b;
+ indices[ni++] = c;
+
+ if ( i + 1 != num - 1 - i ) {
+ a = index[ ( num - 2 - i + rotate ) % num ];
+ b = index[ ( i + rotate ) % num ];
+ c = index[ ( i + 1 + rotate ) % num ];
+
+ if ( IsTriangleDegenerate( surf->verts, a, b, c ) ) {
+ break;
+ }
+ indices[ni++] = a;
+ indices[ni++] = b;
+ indices[ni++] = c;
+ }
+ }
+ if ( ni == numIndices ) {
+ break; // got it done without degenerate triangles
+ }
+ }
+
+ // if any triangle in the strip is degenerate,
+ // render from a centered fan point instead
+ if ( ni < numIndices ) {
+ SideAsTriFan( surf, index, num );
+ return;
+ }
+
+ // a normal tristrip
+ if ( surf->numIndexes + ni > surf->maxIndexes ) {
+ surf->maxIndexes = surf->numIndexes + ni;
+ surf->indexes = realloc( surf->indexes, surf->maxIndexes * sizeof( *surf->indexes ) );
+ }
+
+ memcpy( surf->indexes + surf->numIndexes, indices, ni * sizeof( *surf->indexes ) );
+ surf->numIndexes += ni;
+}
+
+/*
+================
+CreateTerrainSurface
+================
+*/
+void CreateTerrainSurface( terrainSurf_t *surf, shaderInfo_t *shader ) {
+ int i, j, k;
+ drawVert_t *out;
+ drawVert_t *in;
+ mapDrawSurface_t *newsurf;
+
+ newsurf = AllocDrawSurf();
+
+ newsurf->miscModel = qtrue;
+ newsurf->shaderInfo = shader;
+ newsurf->lightmapNum = -1;
+ newsurf->fogNum = -1;
+ newsurf->numIndexes = surf->numIndexes;
+ newsurf->numVerts = surf->numVerts;
+
+ // copy the indices
+ newsurf->indexes = malloc( surf->numIndexes * sizeof( *newsurf->indexes ) );
+ memcpy( newsurf->indexes, surf->indexes, surf->numIndexes * sizeof( *newsurf->indexes ) );
+
+ // allocate the vertices
+ newsurf->verts = malloc( surf->numVerts * sizeof( *newsurf->verts ) );
+ memset( newsurf->verts, 0, surf->numVerts * sizeof( *newsurf->verts ) );
+
+ // calculate the surface verts
+ out = newsurf->verts;
+ for( i = 0; i < newsurf->numVerts; i++, out++ ) {
+ VectorCopy( surf->verts[ i ].xyz, out->xyz );
+
+ // set the texture coordinates
+ out->st[ 0 ] = surf->verts[ i ].st[ 0 ];
+ out->st[ 1 ] = surf->verts[ i ].st[ 1 ];
+
+ // the colors will be set by the lighting pass
+ out->color[0] = 255;
+ out->color[1] = 255;
+ out->color[2] = 255;
+ out->color[3] = surf->verts[ i ].color[ 3 ];
+
+ // calculate the vertex normal
+ VectorClear( out->normal );
+ for( j = 0; j < numsurfaces; j++ ) {
+ in = surfaces[ j ].verts;
+ for( k = 0; k < surfaces[ j ].numVerts; k++, in++ ) {
+ if ( CompareVert( out, in, qfalse ) ) {
+ VectorAdd( out->normal, in->normal, out->normal );
+ }
+ }
+ }
+
+ VectorNormalize( out->normal, out->normal );
+ }
+}
+
+/*
+================
+EmitTerrainVerts
+================
+*/
+void EmitTerrainVerts( side_t *side, terrainSurf_t *surf, int maxlayer, int alpha[ MAX_POINTS_ON_WINDING ], qboolean projecttexture ) {
+ int i;
+ int j;
+ drawVert_t *vert;
+ int *indices;
+ int numindices;
+ int maxindices;
+ int xyplane;
+ vec3_t xynorm = { 0, 0, 1 };
+ vec_t shift[ 2 ] = { 0, 0 };
+ vec_t scale[ 2 ] = { 0.5, 0.5 };
+ float vecs[ 2 ][ 4 ];
+ static int numtimes = 0;
+
+ numtimes++;
+
+ if ( !surf->verts ) {
+ surf->numVerts = 0;
+ surf->maxVerts = GROW_VERTS;
+ surf->verts = malloc( surf->maxVerts * sizeof( *surf->verts ) );
+
+ surf->numIndexes = 0;
+ surf->maxIndexes = GROW_INDICES;
+ surf->indexes = malloc( surf->maxIndexes * sizeof( *surf->indexes ) );
+ }
+
+ // calculate the texture coordinate vectors
+ xyplane = FindFloatPlane( xynorm, 0 );
+ QuakeTextureVecs( &mapplanes[ xyplane ], shift, 0, scale, vecs );
+
+ // emit the vertexes
+ numindices = 0;
+ maxindices = surf->maxIndexes;
+ indices = malloc ( maxindices * sizeof( *indices ) );
+
+ for ( i = 0; i < side->winding->numpoints; i++ ) {
+ vert = &surf->verts[ surf->numVerts ];
+
+ // set the final alpha value--0 for texture 1, 255 for texture 2
+ if ( alpha[ i ] < maxlayer ) {
+ vert->color[3] = 0;
+ } else {
+ vert->color[3] = 255;
+ }
+
+ vert->xyz[ 0 ] = floor( side->winding->p[ i ][ 0 ] + 0.1f );
+ vert->xyz[ 1 ] = floor( side->winding->p[ i ][ 1 ] + 0.1f );
+ vert->xyz[ 2 ] = floor( side->winding->p[ i ][ 2 ] + 0.1f );
+
+ // set the texture coordinates
+ if ( projecttexture ) {
+ vert->st[0] = ( vecs[0][3] + DotProduct( vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
+ vert->st[1] = ( vecs[1][3] + DotProduct( vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
+ } else {
+ vert->st[0] = ( side->vecs[0][3] + DotProduct( side->vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
+ vert->st[1] = ( side->vecs[1][3] + DotProduct( side->vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
+ }
+
+ VectorCopy( mapplanes[ side->planenum ].normal, vert->normal );
+
+ for( j = 0; j < surf->numVerts; j++ ) {
+ if ( CompareVert( vert, &surf->verts[ j ], qtrue ) ) {
+ break;
+ }
+ }
+
+ if ( numindices >= maxindices ) {
+ maxindices += GROW_INDICES;
+ indices = realloc( indices, maxindices * sizeof( *indices ) );
+ }
+
+ if ( j != surf->numVerts ) {
+ indices[ numindices++ ] = j;
+ } else {
+ indices[ numindices++ ] = surf->numVerts;
+ surf->numVerts++;
+ if ( surf->numVerts >= surf->maxVerts ) {
+ surf->maxVerts += GROW_VERTS;
+ surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
+ }
+ }
+ }
+
+ SideAsTristrip( surf, indices, numindices );
+
+ free( indices );
+}
+
+/*
+================
+SurfaceForShader
+================
+*/
+terrainSurf_t *SurfaceForShader( shaderInfo_t *shader, int x, int y ) {
+ int i;
+
+ if ( lastSurface && ( lastSurface->shader == shader ) && ( lastSurface->x == x ) && ( lastSurface->y == y ) ) {
+ return lastSurface;
+ }
+
+ lastSurface = surfaces;
+ for( i = 0; i < numsurfaces; i++, lastSurface++ ) {
+ if ( ( lastSurface->shader == shader ) && ( lastSurface->x == x ) && ( lastSurface->y == y ) ) {
+ return lastSurface;
+ }
+ }
+
+ if ( numsurfaces >= maxsurfaces ) {
+ maxsurfaces += GROW_SURFACES;
+ surfaces = realloc( surfaces, maxsurfaces * sizeof( *surfaces ) );
+ memset( surfaces + numsurfaces + 1, 0, ( maxsurfaces - numsurfaces - 1 ) * sizeof( *surfaces ) );
+ }
+
+ lastSurface= &surfaces[ numsurfaces++ ];
+ lastSurface->shader = shader;
+ lastSurface->x = x;
+ lastSurface->y = y;
+
+ return lastSurface;
+}
+
+/*
+================
+SetTerrainTextures
+================
+*/
+void SetTerrainTextures( void ) {
+ int i;
+ int x, y;
+ int layer;
+ int minlayer, maxlayer;
+ float s, t;
+ float min_s, min_t;
+ int alpha[ MAX_POINTS_ON_WINDING ];
+ shaderInfo_t *si, *terrainShader;
+ bspbrush_t *brush;
+ side_t *side;
+ const char *shadername;
+ vec3_t mins, maxs;
+ vec3_t size;
+ int surfwidth, surfheight, surfsize;
+ terrainSurf_t *surf;
+ byte *alphamap;
+ int alphawidth, alphaheight;
+ int num_layers;
+ extern qboolean onlyents;
+
+ if ( onlyents ) {
+ return;
+ }
+
+ shadername = ValueForKey( mapent, "shader" );
+ if ( !shadername[ 0 ] ) {
+ Error ("SetTerrainTextures: shader not specified" );
+ }
+
+ alphamap = LoadAlphaMap( &num_layers, &alphawidth, &alphaheight );
+
+ mapent->firstDrawSurf = numMapDrawSurfs;
+
+ // calculate the size of the terrain
+ CalcTerrainSize( mins, maxs, size );
+
+ surfwidth = ( size[ 0 ] + SURF_WIDTH - 1 ) / SURF_WIDTH;
+ surfheight = ( size[ 1 ] + SURF_HEIGHT - 1 ) / SURF_HEIGHT;
+ surfsize = surfwidth * surfheight;
+
+ lastSurface = NULL;
+ numsurfaces = 0;
+ maxsurfaces = 0;
+ for( i = num_layers; i > 0; i-- ) {
+ maxsurfaces += i * surfsize;
+ }
+ surfaces = malloc( maxsurfaces * sizeof( *surfaces ) );
+ memset( surfaces, 0, maxsurfaces * sizeof( *surfaces ) );
+
+ terrainShader = ShaderInfoForShader( "textures/common/terrain" );
+
+ for( brush = mapent->brushes; brush != NULL; brush = brush->next ) {
+ // only create surfaces for sides marked as terrain
+ for( side = brush->sides; side < &brush->sides[ brush->numsides ]; side++ ) {
+ if ( !side->shaderInfo ) {
+ continue;
+ }
+
+ if ( ( ( side->surfaceFlags | side->shaderInfo->surfaceFlags ) & SURF_NODRAW ) && !strstr( side->shaderInfo->shader, "terrain" ) ) {
+ continue;
+ }
+
+ minlayer = num_layers;
+ maxlayer = 0;
+
+ // project each point of the winding onto the alphamap to determine which
+ // textures to blend
+ min_s = 1.0;
+ min_t = 1.0;
+ for( i = 0; i < side->winding->numpoints; i++ ) {
+ s = floor( side->winding->p[ i ][ 0 ] + 0.1f - mins[ 0 ] ) / size[ 0 ];
+ t = floor( side->winding->p[ i ][ 1 ] + 0.1f - mins[ 0 ] ) / size[ 1 ];
+
+ if ( s < 0 ) {
+ s = 0;
+ }
+
+ if ( t < 0 ) {
+ t = 0;
+ }
+
+ if ( s >= 1.0 ) {
+ s = 1.0;
+ }
+
+ if ( t >= 1.0 ) {
+ t = 1.0;
+ }
+
+ if ( s < min_s ) {
+ min_s = s;
+ }
+
+ if ( t < min_t ) {
+ min_t = t;
+ }
+
+ x = ( alphawidth - 1 ) * s;
+ y = ( alphaheight - 1 ) * t;
+
+ layer = alphamap[ x + y * alphawidth ];
+ if ( layer < minlayer ) {
+ minlayer = layer;
+ }
+
+ if ( layer > maxlayer ) {
+ maxlayer = layer;
+ }
+
+ alpha[ i ] = layer;
+ }
+
+ x = min_s * surfwidth;
+ if ( x >= surfwidth ) {
+ x = surfwidth - 1;
+ }
+
+ y = min_t * surfheight;
+ if ( y >= surfheight ) {
+ y = surfheight - 1;
+ }
+
+ if ( strstr( side->shaderInfo->shader, "terrain" ) ) {
+ si = ShaderForLayer( minlayer, maxlayer, shadername );
+ if ( showseams ) {
+ for( i = 0; i < side->winding->numpoints; i++ ) {
+ if ( ( alpha[ i ] != minlayer ) && ( alpha[ i ] != maxlayer ) ) {
+ si = ShaderInfoForShader( "textures/common/white" );
+ break;
+ }
+ }
+ }
+ surf = SurfaceForShader( si, x, y );
+ EmitTerrainVerts( side, surf, maxlayer, alpha, qtrue );
+ } else {
+ si = side->shaderInfo;
+ side->shaderInfo = terrainShader;
+ surf = SurfaceForShader( si, x, y );
+ EmitTerrainVerts( side, surf, maxlayer, alpha, qfalse );
+ }
+ }
+ }
+
+ // create the final surfaces
+ for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
+ if ( surf->numVerts ) {
+ CreateTerrainSurface( surf, surf->shader );
+ }
+ }
+
+ //
+ // clean up any allocated memory
+ //
+ for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
+ if ( surf->verts ) {
+ free( surf->verts );
+ free( surf->indexes );
+ }
+ }
+ free( alphamap );
+ free( surfaces );
+
+ surfaces = NULL;
+ lastSurface = NULL;
+ numsurfaces = 0;
+ maxsurfaces = 0;
+}
+
+/*****************************************************************************
+
+ New terrain code
+
+******************************************************************************/
+
+typedef struct terrainFace_s {
+ shaderInfo_t *shaderInfo;
+ //texdef_t texdef;
+
+ float vecs[ 2 ][ 4 ]; // texture coordinate mapping
+} terrainFace_t;
+
+typedef struct terrainVert_s {
+ vec3_t xyz;
+ terrainFace_t tri;
+} terrainVert_t;
+
+typedef struct terrainMesh_s {
+ float scale_x;
+ float scale_y;
+ vec3_t origin;
+
+ int width, height;
+ terrainVert_t *map;
+} terrainMesh_t;
+
+terrainVert_t *Terrain_GetVert( terrainMesh_t *pm, int x, int y ) {
+ return &pm->map[ x + y * pm->width ];
+}
+
+void Terrain_GetTriangles( terrainMesh_t *pm, int x, int y, terrainVert_t **verts ) {
+ if ( ( x + y ) & 1 ) {
+ // first tri
+ verts[ 0 ] = Terrain_GetVert( pm, x, y );
+ verts[ 1 ] = Terrain_GetVert( pm, x, y + 1 );
+ verts[ 2 ] = Terrain_GetVert( pm, x + 1, y + 1 );
+
+ // second tri
+ verts[ 3 ] = verts[ 2 ];
+ verts[ 4 ] = Terrain_GetVert( pm, x + 1, y );
+ verts[ 5 ] = verts[ 0 ];
+ } else {
+ // first tri
+ verts[ 0 ] = Terrain_GetVert( pm, x, y );
+ verts[ 1 ] = Terrain_GetVert( pm, x, y + 1 );
+ verts[ 2 ] = Terrain_GetVert( pm, x + 1, y );
+
+ // second tri
+ verts[ 3 ] = verts[ 2 ];
+ verts[ 4 ] = verts[ 1 ];
+ verts[ 5 ] = Terrain_GetVert( pm, x + 1, y + 1 );
+ }
+}
+
+/*
+================
+EmitTerrainVerts2
+================
+*/
+void EmitTerrainVerts2( terrainSurf_t *surf, terrainVert_t **verts, int alpha[ 3 ] ) {
+ int i;
+ int j;
+ drawVert_t *vert;
+ int *indices;
+ int numindices;
+ int maxindices;
+ int xyplane;
+ vec3_t xynorm = { 0, 0, 1 };
+ vec_t shift[ 2 ] = { 0, 0 };
+ vec_t scale[ 2 ] = { 0.5, 0.5 };
+ float vecs[ 2 ][ 4 ];
+ vec4_t plane;
+
+ if ( !surf->verts ) {
+ surf->numVerts = 0;
+ surf->maxVerts = GROW_VERTS;
+ surf->verts = malloc( surf->maxVerts * sizeof( *surf->verts ) );
+
+ surf->numIndexes = 0;
+ surf->maxIndexes = GROW_INDICES;
+ surf->indexes = malloc( surf->maxIndexes * sizeof( *surf->indexes ) );
+ }
+
+ // calculate the texture coordinate vectors
+ xyplane = FindFloatPlane( xynorm, 0 );
+ QuakeTextureVecs( &mapplanes[ xyplane ], shift, 0, scale, vecs );
+
+ // emit the vertexes
+ numindices = 0;
+ maxindices = surf->maxIndexes;
+ assert( maxindices >= 0 );
+ indices = malloc ( maxindices * sizeof( *indices ) );
+
+ PlaneFromPoints( plane, verts[ 0 ]->xyz, verts[ 1 ]->xyz, verts[ 2 ]->xyz );
+
+ for ( i = 0; i < 3; i++ ) {
+ vert = &surf->verts[ surf->numVerts ];
+
+ if ( alpha[ i ] ) {
+ vert->color[3] = 255;
+ } else {
+ vert->color[3] = 0;
+ }
+
+ vert->xyz[ 0 ] = floor( verts[ i ]->xyz[ 0 ] + 0.1f );
+ vert->xyz[ 1 ] = floor( verts[ i ]->xyz[ 1 ] + 0.1f );
+ vert->xyz[ 2 ] = floor( verts[ i ]->xyz[ 2 ] + 0.1f );
+
+ // set the texture coordinates
+ vert->st[0] = ( vecs[0][3] + DotProduct( vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
+ vert->st[1] = ( vecs[1][3] + DotProduct( vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
+
+ VectorCopy( plane, vert->normal );
+
+ for( j = 0; j < surf->numVerts; j++ ) {
+ if ( CompareVert( vert, &surf->verts[ j ], qtrue ) ) {
+ break;
+ }
+ }
+
+ if ( numindices >= maxindices ) {
+ maxindices += GROW_INDICES;
+ indices = realloc( indices, maxindices * sizeof( *indices ) );
+ }
+
+ if ( j != surf->numVerts ) {
+ indices[ numindices++ ] = j;
+ } else {
+ indices[ numindices++ ] = surf->numVerts;
+ surf->numVerts++;
+ if ( surf->numVerts >= surf->maxVerts ) {
+ surf->maxVerts += GROW_VERTS;
+ surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
+ }
+ }
+ }
+
+ SideAsTristrip( surf, indices, numindices );
+
+ free( indices );
+}
+
+int MapPlaneFromPoints( vec3_t p0, vec3_t p1, vec3_t p2 );
+void QuakeTextureVecs( plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2], vec_t mappingVecs[2][4] );
+qboolean RemoveDuplicateBrushPlanes( bspbrush_t *b );
+void SetBrushContents( bspbrush_t *b );
+
+void AddBrushSide( vec3_t v1, vec3_t v2, vec3_t v3, shaderInfo_t *terrainShader ) {
+ side_t *side;
+ int planenum;
+
+ side = &buildBrush->sides[ buildBrush->numsides ];
+ memset( side, 0, sizeof( *side ) );
+ buildBrush->numsides++;
+
+ side->shaderInfo = terrainShader;
+
+ // find the plane number
+ planenum = MapPlaneFromPoints( v1, v2, v3 );
+ side->planenum = planenum;
+}
+
+void MakeBrushFromTriangle( vec3_t v1, vec3_t v2, vec3_t v3, shaderInfo_t *terrainShader ) {
+ bspbrush_t *b;
+ vec3_t d1;
+ vec3_t d2;
+ vec3_t d3;
+
+ VectorSet( d1, v1[ 0 ], v1[ 1 ], MIN_WORLD_COORD + 10 ); //FIXME
+ VectorSet( d2, v2[ 0 ], v2[ 1 ], MIN_WORLD_COORD + 10 );
+ VectorSet( d3, v3[ 0 ], v3[ 1 ], MIN_WORLD_COORD + 10 );
+
+ buildBrush->numsides = 0;
+ buildBrush->detail = qfalse;
+
+ AddBrushSide( v1, v2, v3, terrainShader );
+ AddBrushSide( v1, d1, v2, terrainShader );
+ AddBrushSide( v2, d2, v3, terrainShader );
+ AddBrushSide( v3, d3, v1, terrainShader );
+ AddBrushSide( d3, d2, d1, terrainShader );
+
+ buildBrush->portalareas[0] = -1;
+ buildBrush->portalareas[1] = -1;
+ buildBrush->entitynum = num_entities-1;
+ buildBrush->brushnum = entitySourceBrushes;
+
+ // if there are mirrored planes, the entire brush is invalid
+ if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
+ return;
+ }
+
+ // get the content for the entire brush
+ SetBrushContents( buildBrush );
+ buildBrush->contents |= CONTENTS_DETAIL;
+
+ b = FinishBrush();
+ if ( !b ) {
+ return;
+ }
+}
+
+void MakeTerrainIntoBrushes( terrainMesh_t *tm ) {
+ int index[ 6 ];
+ int y;
+ int x;
+ terrainVert_t *verts;
+ shaderInfo_t *terrainShader;
+
+ terrainShader = ShaderInfoForShader( "textures/common/terrain" );
+
+ verts = tm->map;
+ for( y = 0; y < tm->height - 1; y++ ) {
+ for( x = 0; x < tm->width - 1; x++ ) {
+ if ( ( x + y ) & 1 ) {
+ // first tri
+ index[ 0 ] = x + y * tm->width;
+ index[ 1 ] = x + ( y + 1 ) * tm->width;
+ index[ 2 ] = ( x + 1 ) + ( y + 1 ) * tm->width;
+ index[ 3 ] = ( x + 1 ) + ( y + 1 ) * tm->width;
+ index[ 4 ] = ( x + 1 ) + y * tm->width;
+ index[ 5 ] = x + y * tm->width;
+ } else {
+ // first tri
+ index[ 0 ] = x + y * tm->width;
+ index[ 1 ] = x + ( y + 1 ) * tm->width;
+ index[ 2 ] = ( x + 1 ) + y * tm->width;
+ index[ 3 ] = ( x + 1 ) + y * tm->width;
+ index[ 4 ] = x + ( y + 1 ) * tm->width;
+ index[ 5 ] = ( x + 1 ) + ( y + 1 ) * tm->width;
+ }
+
+ MakeBrushFromTriangle( verts[ index[ 0 ] ].xyz, verts[ index[ 1 ] ].xyz, verts[ index[ 2 ] ].xyz, terrainShader );
+ MakeBrushFromTriangle( verts[ index[ 3 ] ].xyz, verts[ index[ 4 ] ].xyz, verts[ index[ 5 ] ].xyz, terrainShader );
+ }
+ }
+}
+
+void Terrain_ParseFace( terrainFace_t *face ) {
+ shaderInfo_t *si;
+ vec_t shift[ 2 ];
+ vec_t rotate;
+ vec_t scale[ 2 ];
+ char name[ MAX_QPATH ];
+ char shader[ MAX_QPATH ];
+ plane_t p;
+
+ // read the texturedef
+ GetToken( qfalse );
+ strcpy( name, token );
+
+ GetToken( qfalse );
+ shift[ 0 ] = atof(token);
+ GetToken( qfalse );
+ shift[ 1 ] = atof( token );
+ GetToken( qfalse );
+ rotate = atof( token );
+ GetToken( qfalse );
+ scale[ 0 ] = atof( token );
+ GetToken( qfalse );
+ scale[ 1 ] = atof( token );
+
+ // find default flags and values
+ sprintf( shader, "textures/%s", name );
+ si = ShaderInfoForShader( shader );
+ face->shaderInfo = si;
+ //face->texdef = si->texdef;
+
+ // skip over old contents
+ GetToken( qfalse );
+
+ // skip over old flags
+ GetToken( qfalse );
+
+ // skip over old value
+ GetToken( qfalse );
+
+ //Surface_Parse( &face->texdef );
+ //Surface_BuildTexdef( &face->texdef );
+
+ // make a fake horizontal plane
+ VectorSet( p.normal, 0, 0, 1 );
+ p.dist = 0;
+ p.type = PlaneTypeForNormal( p.normal );
+
+ QuakeTextureVecs( &p, shift, rotate, scale, face->vecs );
+}
+
+#define MAX_TERRAIN_TEXTURES 128
+static int numtextures = 0;;
+static shaderInfo_t *textures[ MAX_TERRAIN_TEXTURES ];
+
+void Terrain_AddTexture( shaderInfo_t *texture ) {
+ int i;
+
+ if ( !texture ) {
+ return;
+ }
+
+ for( i = 0; i < numtextures; i++ ) {
+ if ( textures[ i ] == texture ) {
+ return;
+ }
+ }
+
+ if ( numtextures >= MAX_TERRAIN_TEXTURES ) {
+ Error( "Too many textures on terrain" );
+ return;
+ }
+
+ textures[ numtextures++ ] = texture;
+}
+
+int LayerForShader( shaderInfo_t *shader ) {
+ int i;
+ int l;
+
+ l = strlen( shader->shader );
+ for( i = l - 1; i >= 0; i-- ) {
+ if ( shader->shader[ i ] == '_' ) {
+ return atoi( &shader->shader[ i + 1 ] );
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+=================
+ParseTerrain
+
+Creates a mapDrawSurface_t from the terrain text
+=================
+*/
+
+void ParseTerrain( void ) {
+ int i, j;
+ int x, y;
+ int x1, y1;
+ terrainMesh_t t;
+ int index;
+ terrainVert_t *verts[ 6 ];
+ int num_layers;
+ int layer, minlayer, maxlayer;
+ int alpha[ 6 ];
+ shaderInfo_t *si, *terrainShader;
+ int surfwidth, surfheight, surfsize;
+ terrainSurf_t *surf;
+ char shadername[ MAX_QPATH ];
+
+ mapent->firstDrawSurf = numMapDrawSurfs;
+
+ memset( &t, 0, sizeof( t ) );
+
+ MatchToken( "{" );
+
+ // get width
+ GetToken( qtrue );
+ t.width = atoi( token );
+
+ // get height
+ GetToken( qfalse );
+ t.height = atoi( token );
+
+ // get scale_x
+ GetToken( qfalse );
+ t.scale_x = atof( token );
+
+ // get scale_y
+ GetToken( qfalse );
+ t.scale_y = atof( token );
+
+ // get origin
+ GetToken( qtrue );
+ t.origin[ 0 ] = atof( token );
+ GetToken( qfalse );
+ t.origin[ 1 ] = atof( token );
+ GetToken( qfalse );
+ t.origin[ 2 ] = atof( token );
+
+ t.map = malloc( t.width * t.height * sizeof( t.map[ 0 ] ) );
+
+ if ( t.width <= 0 || t.height <= 0 ) {
+ Error( "ParseTerrain: bad size" );
+ }
+
+ numtextures = 0;
+ index = 0;
+ for ( i = 0; i < t.height; i++ ) {
+ for( j = 0; j < t.width; j++, index++ ) {
+ // get height
+ GetToken( qtrue );
+ t.map[ index ].xyz[ 0 ] = t.origin[ 0 ] + t.scale_x * ( float )j;
+ t.map[ index ].xyz[ 1 ] = t.origin[ 1 ] + t.scale_y * ( float )i;
+ t.map[ index ].xyz[ 2 ] = t.origin[ 2 ] + atof( token );
+
+ Terrain_ParseFace( &t.map[ index ].tri );
+ Terrain_AddTexture( t.map[ index ].tri.shaderInfo );
+ }
+ }
+
+ MatchToken( "}" );
+ MatchToken( "}" );
+
+ MakeTerrainIntoBrushes( &t );
+
+ surfwidth = ( ( t.scale_x * t.width ) + SURF_WIDTH - 1 ) / SURF_WIDTH;
+ surfheight = ( ( t.scale_y * t.height ) + SURF_HEIGHT - 1 ) / SURF_HEIGHT;
+ surfsize = surfwidth * surfheight;
+
+ //FIXME
+ num_layers = 0;
+ for( i = 0; i < numtextures; i++ ) {
+ layer = LayerForShader( textures[ i ] ) + 1;
+ if ( layer > num_layers ) {
+ num_layers = layer;
+ }
+ }
+ num_layers = 4;
+
+ memset( alpha, 0, sizeof( alpha ) );
+
+ lastSurface = NULL;
+ numsurfaces = 0;
+ maxsurfaces = 0;
+ for( i = num_layers; i > 0; i-- ) {
+ maxsurfaces += i * surfsize;
+ }
+
+ surfaces = malloc( maxsurfaces * sizeof( *surfaces ) );
+ memset( surfaces, 0, maxsurfaces * sizeof( *surfaces ) );
+
+ terrainShader = ShaderInfoForShader( "textures/common/terrain" );
+
+ // get the shadername
+ if ( Q_strncasecmp( textures[ 0 ]->shader, "textures/", 9 ) == 0 ) {
+ strcpy( shadername, &textures[ 0 ]->shader[ 9 ] );
+ } else {
+ strcpy( shadername, textures[ 0 ]->shader );
+ }
+ j = strlen( shadername );
+ for( i = j - 1; i >= 0; i-- ) {
+ if ( shadername[ i ] == '_' ) {
+ shadername[ i ] = 0;
+ break;
+ }
+ }
+
+ for( y = 0; y < t.height - 1; y++ ) {
+ for( x = 0; x < t.width - 1; x++ ) {
+ Terrain_GetTriangles( &t, x, y, verts );
+
+ x1 = ( ( float )x / ( float )( t.width - 1 ) ) * surfwidth;
+ if ( x1 >= surfwidth ) {
+ x1 = surfwidth - 1;
+ }
+
+ y1 = ( ( float )y / ( float )( t.height - 1 ) ) * surfheight;
+ if ( y1 >= surfheight ) {
+ y1 = surfheight - 1;
+ }
+
+ maxlayer = minlayer = LayerForShader( verts[ 0 ]->tri.shaderInfo );
+ for( i = 0; i < 3; i++ ) {
+ layer = LayerForShader( verts[ i ]->tri.shaderInfo );
+ if ( layer < minlayer ) {
+ minlayer = layer;
+ }
+ if ( layer > maxlayer ) {
+ maxlayer = layer;
+ }
+ }
+
+ for( i = 0; i < 3; i++ ) {
+ layer = LayerForShader( verts[ i ]->tri.shaderInfo );
+ if ( layer > minlayer ) {
+ alpha[ i ] = 1.0f;
+ } else {
+ alpha[ i ] = 0.0f;
+ }
+ }
+
+ si = ShaderForLayer( minlayer, maxlayer, shadername );
+ surf = SurfaceForShader( si, x1, y1 );
+ EmitTerrainVerts2( surf, &verts[ 0 ], &alpha[ 0 ] );
+
+ // second triangle
+ maxlayer = minlayer = LayerForShader( verts[ 3 ]->tri.shaderInfo );
+ for( i = 3; i < 6; i++ ) {
+ layer = LayerForShader( verts[ i ]->tri.shaderInfo );
+ if ( layer < minlayer ) {
+ minlayer = layer;
+ }
+ if ( layer > maxlayer ) {
+ maxlayer = layer;
+ }
+ }
+
+ for( i = 3; i < 6; i++ ) {
+ layer = LayerForShader( verts[ i ]->tri.shaderInfo );
+ if ( layer > minlayer ) {
+ alpha[ i ] = 1.0f;
+ } else {
+ alpha[ i ] = 0.0f;
+ }
+ }
+
+ si = ShaderForLayer( minlayer, maxlayer, shadername );
+ surf = SurfaceForShader( si, x1, y1 );
+ EmitTerrainVerts2( surf, &verts[ 3 ], &alpha[ 3 ] );
+ }
+ }
+
+ // create the final surfaces
+ for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
+ if ( surf->numVerts ) {
+ CreateTerrainSurface( surf, surf->shader );
+ }
+ }
+
+ //
+ // clean up any allocated memory
+ //
+ for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
+ if ( surf->verts ) {
+ free( surf->verts );
+ free( surf->indexes );
+ }
+ }
+ free( surfaces );
+
+ surfaces = NULL;
+ lastSurface = NULL;
+ numsurfaces = 0;
+ maxsurfaces = 0;
+
+ free( t.map );
+}
+
diff --git a/q3map/tjunction.c b/q3map/tjunction.c
index 9d41dc2..a1acabe 100755
--- a/q3map/tjunction.c
+++ b/q3map/tjunction.c
@@ -19,533 +19,533 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-#include "qbsp.h"
-
-typedef struct edgePoint_s {
- float intercept;
- vec3_t xyz;
- struct edgePoint_s *prev, *next;
-} edgePoint_t;
-
-typedef struct edgeLine_s {
- vec3_t normal1;
- float dist1;
-
- vec3_t normal2;
- float dist2;
-
- vec3_t origin;
- vec3_t dir;
-
- edgePoint_t chain; // unused element of doubly linked list
-} edgeLine_t;
-
-typedef struct {
- float length;
- drawVert_t *dv[2];
-} originalEdge_t;
-
-#define MAX_ORIGINAL_EDGES 0x10000
-originalEdge_t originalEdges[MAX_ORIGINAL_EDGES];
-int numOriginalEdges;
-
-
-#define MAX_EDGE_LINES 0x10000
-edgeLine_t edgeLines[MAX_EDGE_LINES];
-int numEdgeLines;
-
-int c_degenerateEdges;
-int c_addedVerts;
-int c_totalVerts;
-
-int c_natural, c_rotate, c_cant;
-
-// these should be whatever epsilon we actually expect,
-// plus SNAP_INT_TO_FLOAT
-#define LINE_POSITION_EPSILON 0.25
-#define POINT_ON_LINE_EPSILON 0.25
-
-/*
-====================
-InsertPointOnEdge
-====================
-*/
-void InsertPointOnEdge( vec3_t v, edgeLine_t *e ) {
- vec3_t delta;
- float d;
- edgePoint_t *p, *scan;
-
- VectorSubtract( v, e->origin, delta );
- d = DotProduct( delta, e->dir );
-
- p = malloc( sizeof(edgePoint_t) );
- p->intercept = d;
- VectorCopy( v, p->xyz );
-
- if ( e->chain.next == &e->chain ) {
- e->chain.next = e->chain.prev = p;
- p->next = p->prev = &e->chain;
- return;
- }
-
- scan = e->chain.next;
- for ( ; scan != &e->chain ; scan = scan->next ) {
- d = p->intercept - scan->intercept;
- if ( d > -LINE_POSITION_EPSILON && d < LINE_POSITION_EPSILON ) {
- free( p );
- return; // the point is already set
- }
-
- if ( p->intercept < scan->intercept ) {
- // insert here
- p->prev = scan->prev;
- p->next = scan;
- scan->prev->next = p;
- scan->prev = p;
- return;
- }
- }
-
- // add at the end
- p->prev = scan->prev;
- p->next = scan;
- scan->prev->next = p;
- scan->prev = p;
-}
-
-
-/*
-====================
-AddEdge
-====================
-*/
-int AddEdge( vec3_t v1, vec3_t v2, qboolean createNonAxial ) {
- int i;
- edgeLine_t *e;
- float d;
- vec3_t dir;
-
- VectorSubtract( v2, v1, dir );
- d = VectorNormalize( dir, dir );
- if ( d < 0.1 ) {
- // if we added a 0 length vector, it would make degenerate planes
- c_degenerateEdges++;
- return -1;
- }
-
- if ( !createNonAxial ) {
- if ( fabs( dir[0] + dir[1] + dir[2] ) != 1.0 ) {
- if ( numOriginalEdges == MAX_ORIGINAL_EDGES ) {
- Error( "MAX_ORIGINAL_EDGES" );
- }
- originalEdges[ numOriginalEdges ].dv[0] = (drawVert_t *)v1;
- originalEdges[ numOriginalEdges ].dv[1] = (drawVert_t *)v2;
- originalEdges[ numOriginalEdges ].length = d;
- numOriginalEdges++;
- return -1;
- }
- }
-
- for ( i = 0 ; i < numEdgeLines ; i++ ) {
- e = &edgeLines[i];
-
- d = DotProduct( v1, e->normal1 ) - e->dist1;
- if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
- continue;
- }
- d = DotProduct( v1, e->normal2 ) - e->dist2;
- if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
- continue;
- }
-
- d = DotProduct( v2, e->normal1 ) - e->dist1;
- if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
- continue;
- }
- d = DotProduct( v2, e->normal2 ) - e->dist2;
- if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
- continue;
- }
-
- // this is the edge
- InsertPointOnEdge( v1, e );
- InsertPointOnEdge( v2, e );
- return i;
- }
-
- // create a new edge
- if ( numEdgeLines >= MAX_EDGE_LINES ) {
- Error( "MAX_EDGE_LINES" );
- }
-
- e = &edgeLines[ numEdgeLines ];
- numEdgeLines++;
-
- e->chain.next = e->chain.prev = &e->chain;
-
- VectorCopy( v1, e->origin );
- VectorCopy( dir, e->dir );
-
- MakeNormalVectors( e->dir, e->normal1, e->normal2 );
- e->dist1 = DotProduct( e->origin, e->normal1 );
- e->dist2 = DotProduct( e->origin, e->normal2 );
-
- InsertPointOnEdge( v1, e );
- InsertPointOnEdge( v2, e );
-
- return numEdgeLines - 1;
-}
-
-/*
-====================
-AddSurfaceEdges
-====================
-*/
-void AddSurfaceEdges( mapDrawSurface_t *ds ) {
- int i;
-
- for ( i = 0 ; i < ds->numVerts ; i++ ) {
- // save the edge number in the lightmap field
- // so we don't need to look it up again
- ds->verts[i].lightmap[0] =
- AddEdge( ds->verts[i].xyz, ds->verts[(i+1) % ds->numVerts].xyz, qfalse );
- }
-}
-
-/*
-================
-ColinearEdge
-================
-*/
-qboolean ColinearEdge( vec3_t v1, vec3_t v2, vec3_t v3 ) {
- vec3_t midpoint, dir, offset, on;
- float d;
-
- VectorSubtract( v2, v1, midpoint );
- VectorSubtract( v3, v1, dir );
- d = VectorNormalize( dir, dir );
- if ( d == 0 ) {
- return qfalse; // degenerate
- }
-
- d = DotProduct( midpoint, dir );
- VectorScale( dir, d, on );
- VectorSubtract( midpoint, on, offset );
- d = VectorLength ( offset );
-
- if ( d < 0.1 ) {
- return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-====================
-AddPatchEdges
-
-Add colinear border edges, which will fix some classes of patch to
-brush tjunctions
-====================
-*/
-void AddPatchEdges( mapDrawSurface_t *ds ) {
- int i;
- float *v1, *v2, *v3;
-
- for ( i = 0 ; i < ds->patchWidth - 2; i+=2 ) {
- v1 = ds->verts[ i ].xyz;
- v2 = ds->verts[ i + 1 ].xyz;
- v3 = ds->verts[ i + 2 ].xyz;
-
- // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
- if ( ColinearEdge( v1, v2, v3 ) ) {
- AddEdge( v1, v3, qfalse );
- }
-
- v1 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i ].xyz;
- v2 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 1 ].xyz;
- v3 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 2 ].xyz;
-
- // if v2 is on the v1 to v3 line, add an edge from v1 to v3
- if ( ColinearEdge( v1, v2, v3 ) ) {
- AddEdge( v1, v3, qfalse );
- }
- }
-
- for ( i = 0 ; i < ds->patchHeight - 2 ; i+=2 ) {
- v1 = ds->verts[ i * ds->patchWidth ].xyz;
- v2 = ds->verts[ ( i + 1 ) * ds->patchWidth ].xyz;
- v3 = ds->verts[ ( i + 2 ) * ds->patchWidth ].xyz;
-
- // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
- if ( ColinearEdge( v1, v2, v3 ) ) {
- AddEdge( v1, v3, qfalse );
- }
-
- v1 = ds->verts[ ( ds->patchWidth - 1 ) + i * ds->patchWidth ].xyz;
- v2 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 1 ) * ds->patchWidth ].xyz;
- v3 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 2 ) * ds->patchWidth ].xyz;
-
- // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
- if ( ColinearEdge( v1, v2, v3 ) ) {
- AddEdge( v1, v3, qfalse );
- }
- }
-
-
-}
-
-
-/*
-====================
-FixSurfaceJunctions
-====================
-*/
-#define MAX_SURFACE_VERTS 256
-void FixSurfaceJunctions( mapDrawSurface_t *ds ) {
- int i, j, k;
- edgeLine_t *e;
- edgePoint_t *p;
- int originalVerts;
- int counts[MAX_SURFACE_VERTS];
- int originals[MAX_SURFACE_VERTS];
- int firstVert[MAX_SURFACE_VERTS];
- drawVert_t verts[MAX_SURFACE_VERTS], *v1, *v2;
- int numVerts;
- float start, end, frac;
- vec3_t delta;
-
- originalVerts = ds->numVerts;
-
- numVerts = 0;
- for ( i = 0 ; i < ds->numVerts ; i++ ) {
- counts[i] = 0;
- firstVert[i] = numVerts;
-
- // copy first vert
- if ( numVerts == MAX_SURFACE_VERTS ) {
- Error( "MAX_SURFACE_VERTS" );
- }
- verts[numVerts] = ds->verts[i];
- originals[numVerts] = i;
- numVerts++;
-
- // check to see if there are any t junctions before the next vert
- v1 = &ds->verts[i];
- v2 = &ds->verts[ (i+1) % ds->numVerts ];
-
- j = (int)ds->verts[i].lightmap[0];
- if ( j == -1 ) {
- continue; // degenerate edge
- }
- e = &edgeLines[ j ];
-
- VectorSubtract( v1->xyz, e->origin, delta );
- start = DotProduct( delta, e->dir );
-
- VectorSubtract( v2->xyz, e->origin, delta );
- end = DotProduct( delta, e->dir );
-
-
- if ( start < end ) {
- p = e->chain.next;
- } else {
- p = e->chain.prev;
- }
-
- for ( ; p != &e->chain ; ) {
- if ( start < end ) {
- if ( p->intercept > end - ON_EPSILON ) {
- break;
- }
- } else {
- if ( p->intercept < end + ON_EPSILON ) {
- break;
- }
- }
-
- if (
- ( start < end && p->intercept > start + ON_EPSILON ) ||
- ( start > end && p->intercept < start - ON_EPSILON ) ) {
- // insert this point
- if ( numVerts == MAX_SURFACE_VERTS ) {
- Error( "MAX_SURFACE_VERTS" );
- }
-
- // take the exact intercept point
- VectorCopy( p->xyz, verts[ numVerts ].xyz );
-
- // copy the normal
- VectorCopy( v1->normal, verts[ numVerts ].normal );
-
- // interpolate the texture coordinates
- frac = ( p->intercept - start ) / ( end - start );
- for ( j = 0 ; j < 2 ; j++ ) {
- verts[ numVerts ].st[j] = v1->st[j] +
- frac * ( v2->st[j] - v1->st[j] );
- }
- originals[numVerts] = i;
- numVerts++;
- counts[i]++;
- }
-
- if ( start < end ) {
- p = p->next;
- } else {
- p = p->prev;
- }
- }
- }
-
- c_addedVerts += numVerts - ds->numVerts;
- c_totalVerts += numVerts;
-
-
- // FIXME: check to see if the entire surface degenerated
- // after snapping
-
- // rotate the points so that the initial vertex is between
- // two non-subdivided edges
- for ( i = 0 ; i < numVerts ; i++ ) {
- if ( originals[ (i+1) % numVerts ] == originals[ i ] ) {
- continue;
- }
- j = (i + numVerts - 1 ) % numVerts;
- k = (i + numVerts - 2 ) % numVerts;
- if ( originals[ j ] == originals[ k ] ) {
- continue;
- }
- break;
- }
-
- if ( i == 0 ) {
- // fine the way it is
- c_natural++;
-
- ds->numVerts = numVerts;
- ds->verts = malloc( numVerts * sizeof( *ds->verts ) );
- memcpy( ds->verts, verts, numVerts * sizeof( *ds->verts ) );
-
- return;
- }
- if ( i == numVerts ) {
- // create a vertex in the middle to start the fan
- c_cant++;
-
-/*
- memset ( &verts[numVerts], 0, sizeof( verts[numVerts] ) );
- for ( i = 0 ; i < numVerts ; i++ ) {
- for ( j = 0 ; j < 10 ; j++ ) {
- verts[numVerts].xyz[j] += verts[i].xyz[j];
- }
- }
- for ( j = 0 ; j < 10 ; j++ ) {
- verts[numVerts].xyz[j] /= numVerts;
- }
-
- i = numVerts;
- numVerts++;
-*/
- } else {
- // just rotate the vertexes
- c_rotate++;
-
- }
-
- ds->numVerts = numVerts;
- ds->verts = malloc( numVerts * sizeof( *ds->verts ) );
-
- for ( j = 0 ; j < ds->numVerts ; j++ ) {
- ds->verts[j] = verts[ ( j + i ) % ds->numVerts ];
- }
-}
-
-/*
-================
-EdgeCompare
-================
-*/
-int EdgeCompare( const void *elem1, const void *elem2 ) {
- float d1, d2;
-
- d1 = ((originalEdge_t *)elem1)->length;
- d2 = ((originalEdge_t *)elem2)->length;
-
- if ( d1 < d2 ) {
- return -1;
- }
- if ( d2 > d1 ) {
- return 1;
- }
- return 0;
-}
-
-
-/*
-================
-FixTJunctions
-
-Call after the surface list has been pruned, but before lightmap allocation
-================
-*/
-void FixTJunctions( entity_t *ent ) {
- int i;
- mapDrawSurface_t *ds;
- int axialEdgeLines;
- originalEdge_t *e;
-
- qprintf("----- FixTJunctions -----\n");
-
- numEdgeLines = 0;
- numOriginalEdges = 0;
-
- // add all the edges
- // this actually creates axial edges, but it
- // only creates originalEdge_t structures
- // for non-axial edges
- for ( i = ent->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
- ds = &mapDrawSurfs[i];
- if ( ds->patch ) {
- AddPatchEdges( ds );
- } else if ( ds->shaderInfo->autosprite || ds->shaderInfo->notjunc || ds->miscModel ) {
- // miscModels don't add tjunctions
- } else {
- AddSurfaceEdges( ds );
- }
- }
-
- axialEdgeLines = numEdgeLines;
-
- // sort the non-axial edges by length
- qsort( originalEdges, numOriginalEdges, sizeof(originalEdges[0]), EdgeCompare );
-
- // add the non-axial edges, longest first
- // this gives the most accurate edge description
- for ( i = 0 ; i < numOriginalEdges ; i++ ) {
- e = &originalEdges[i];
- e->dv[0]->lightmap[0] = AddEdge( e->dv[0]->xyz, e->dv[1]->xyz, qtrue );
- }
-
- qprintf( "%6i axial edge lines\n", axialEdgeLines );
- qprintf( "%6i non-axial edge lines\n", numEdgeLines - axialEdgeLines );
- qprintf( "%6i degenerate edges\n", c_degenerateEdges );
-
- // insert any needed vertexes
- for ( i = ent->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
- ds = &mapDrawSurfs[i];
- if ( ds->patch ) {
- continue;
- }
- if ( ds->shaderInfo->autosprite || ds->shaderInfo->notjunc || ds->miscModel ) {
- continue;
- }
-
- FixSurfaceJunctions( ds );
- }
-
- qprintf( "%6i verts added for tjunctions\n", c_addedVerts );
- qprintf( "%6i total verts\n", c_totalVerts );
- qprintf( "%6i naturally ordered\n", c_natural );
- qprintf( "%6i rotated orders\n", c_rotate );
- qprintf( "%6i can't order\n", c_cant );
-}
+#include "qbsp.h"
+
+typedef struct edgePoint_s {
+ float intercept;
+ vec3_t xyz;
+ struct edgePoint_s *prev, *next;
+} edgePoint_t;
+
+typedef struct edgeLine_s {
+ vec3_t normal1;
+ float dist1;
+
+ vec3_t normal2;
+ float dist2;
+
+ vec3_t origin;
+ vec3_t dir;
+
+ edgePoint_t chain; // unused element of doubly linked list
+} edgeLine_t;
+
+typedef struct {
+ float length;
+ drawVert_t *dv[2];
+} originalEdge_t;
+
+#define MAX_ORIGINAL_EDGES 0x10000
+originalEdge_t originalEdges[MAX_ORIGINAL_EDGES];
+int numOriginalEdges;
+
+
+#define MAX_EDGE_LINES 0x10000
+edgeLine_t edgeLines[MAX_EDGE_LINES];
+int numEdgeLines;
+
+int c_degenerateEdges;
+int c_addedVerts;
+int c_totalVerts;
+
+int c_natural, c_rotate, c_cant;
+
+// these should be whatever epsilon we actually expect,
+// plus SNAP_INT_TO_FLOAT
+#define LINE_POSITION_EPSILON 0.25
+#define POINT_ON_LINE_EPSILON 0.25
+
+/*
+====================
+InsertPointOnEdge
+====================
+*/
+void InsertPointOnEdge( vec3_t v, edgeLine_t *e ) {
+ vec3_t delta;
+ float d;
+ edgePoint_t *p, *scan;
+
+ VectorSubtract( v, e->origin, delta );
+ d = DotProduct( delta, e->dir );
+
+ p = malloc( sizeof(edgePoint_t) );
+ p->intercept = d;
+ VectorCopy( v, p->xyz );
+
+ if ( e->chain.next == &e->chain ) {
+ e->chain.next = e->chain.prev = p;
+ p->next = p->prev = &e->chain;
+ return;
+ }
+
+ scan = e->chain.next;
+ for ( ; scan != &e->chain ; scan = scan->next ) {
+ d = p->intercept - scan->intercept;
+ if ( d > -LINE_POSITION_EPSILON && d < LINE_POSITION_EPSILON ) {
+ free( p );
+ return; // the point is already set
+ }
+
+ if ( p->intercept < scan->intercept ) {
+ // insert here
+ p->prev = scan->prev;
+ p->next = scan;
+ scan->prev->next = p;
+ scan->prev = p;
+ return;
+ }
+ }
+
+ // add at the end
+ p->prev = scan->prev;
+ p->next = scan;
+ scan->prev->next = p;
+ scan->prev = p;
+}
+
+
+/*
+====================
+AddEdge
+====================
+*/
+int AddEdge( vec3_t v1, vec3_t v2, qboolean createNonAxial ) {
+ int i;
+ edgeLine_t *e;
+ float d;
+ vec3_t dir;
+
+ VectorSubtract( v2, v1, dir );
+ d = VectorNormalize( dir, dir );
+ if ( d < 0.1 ) {
+ // if we added a 0 length vector, it would make degenerate planes
+ c_degenerateEdges++;
+ return -1;
+ }
+
+ if ( !createNonAxial ) {
+ if ( fabs( dir[0] + dir[1] + dir[2] ) != 1.0 ) {
+ if ( numOriginalEdges == MAX_ORIGINAL_EDGES ) {
+ Error( "MAX_ORIGINAL_EDGES" );
+ }
+ originalEdges[ numOriginalEdges ].dv[0] = (drawVert_t *)v1;
+ originalEdges[ numOriginalEdges ].dv[1] = (drawVert_t *)v2;
+ originalEdges[ numOriginalEdges ].length = d;
+ numOriginalEdges++;
+ return -1;
+ }
+ }
+
+ for ( i = 0 ; i < numEdgeLines ; i++ ) {
+ e = &edgeLines[i];
+
+ d = DotProduct( v1, e->normal1 ) - e->dist1;
+ if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
+ continue;
+ }
+ d = DotProduct( v1, e->normal2 ) - e->dist2;
+ if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
+ continue;
+ }
+
+ d = DotProduct( v2, e->normal1 ) - e->dist1;
+ if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
+ continue;
+ }
+ d = DotProduct( v2, e->normal2 ) - e->dist2;
+ if ( d < -POINT_ON_LINE_EPSILON || d > POINT_ON_LINE_EPSILON ) {
+ continue;
+ }
+
+ // this is the edge
+ InsertPointOnEdge( v1, e );
+ InsertPointOnEdge( v2, e );
+ return i;
+ }
+
+ // create a new edge
+ if ( numEdgeLines >= MAX_EDGE_LINES ) {
+ Error( "MAX_EDGE_LINES" );
+ }
+
+ e = &edgeLines[ numEdgeLines ];
+ numEdgeLines++;
+
+ e->chain.next = e->chain.prev = &e->chain;
+
+ VectorCopy( v1, e->origin );
+ VectorCopy( dir, e->dir );
+
+ MakeNormalVectors( e->dir, e->normal1, e->normal2 );
+ e->dist1 = DotProduct( e->origin, e->normal1 );
+ e->dist2 = DotProduct( e->origin, e->normal2 );
+
+ InsertPointOnEdge( v1, e );
+ InsertPointOnEdge( v2, e );
+
+ return numEdgeLines - 1;
+}
+
+/*
+====================
+AddSurfaceEdges
+====================
+*/
+void AddSurfaceEdges( mapDrawSurface_t *ds ) {
+ int i;
+
+ for ( i = 0 ; i < ds->numVerts ; i++ ) {
+ // save the edge number in the lightmap field
+ // so we don't need to look it up again
+ ds->verts[i].lightmap[0] =
+ AddEdge( ds->verts[i].xyz, ds->verts[(i+1) % ds->numVerts].xyz, qfalse );
+ }
+}
+
+/*
+================
+ColinearEdge
+================
+*/
+qboolean ColinearEdge( vec3_t v1, vec3_t v2, vec3_t v3 ) {
+ vec3_t midpoint, dir, offset, on;
+ float d;
+
+ VectorSubtract( v2, v1, midpoint );
+ VectorSubtract( v3, v1, dir );
+ d = VectorNormalize( dir, dir );
+ if ( d == 0 ) {
+ return qfalse; // degenerate
+ }
+
+ d = DotProduct( midpoint, dir );
+ VectorScale( dir, d, on );
+ VectorSubtract( midpoint, on, offset );
+ d = VectorLength ( offset );
+
+ if ( d < 0.1 ) {
+ return qtrue;
+ }
+
+ return qfalse;
+}
+
+/*
+====================
+AddPatchEdges
+
+Add colinear border edges, which will fix some classes of patch to
+brush tjunctions
+====================
+*/
+void AddPatchEdges( mapDrawSurface_t *ds ) {
+ int i;
+ float *v1, *v2, *v3;
+
+ for ( i = 0 ; i < ds->patchWidth - 2; i+=2 ) {
+ v1 = ds->verts[ i ].xyz;
+ v2 = ds->verts[ i + 1 ].xyz;
+ v3 = ds->verts[ i + 2 ].xyz;
+
+ // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
+ if ( ColinearEdge( v1, v2, v3 ) ) {
+ AddEdge( v1, v3, qfalse );
+ }
+
+ v1 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i ].xyz;
+ v2 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 1 ].xyz;
+ v3 = ds->verts[ ( ds->patchHeight - 1 ) * ds->patchWidth + i + 2 ].xyz;
+
+ // if v2 is on the v1 to v3 line, add an edge from v1 to v3
+ if ( ColinearEdge( v1, v2, v3 ) ) {
+ AddEdge( v1, v3, qfalse );
+ }
+ }
+
+ for ( i = 0 ; i < ds->patchHeight - 2 ; i+=2 ) {
+ v1 = ds->verts[ i * ds->patchWidth ].xyz;
+ v2 = ds->verts[ ( i + 1 ) * ds->patchWidth ].xyz;
+ v3 = ds->verts[ ( i + 2 ) * ds->patchWidth ].xyz;
+
+ // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
+ if ( ColinearEdge( v1, v2, v3 ) ) {
+ AddEdge( v1, v3, qfalse );
+ }
+
+ v1 = ds->verts[ ( ds->patchWidth - 1 ) + i * ds->patchWidth ].xyz;
+ v2 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 1 ) * ds->patchWidth ].xyz;
+ v3 = ds->verts[ ( ds->patchWidth - 1 ) + ( i + 2 ) * ds->patchWidth ].xyz;
+
+ // if v2 is the midpoint of v1 to v3, add an edge from v1 to v3
+ if ( ColinearEdge( v1, v2, v3 ) ) {
+ AddEdge( v1, v3, qfalse );
+ }
+ }
+
+
+}
+
+
+/*
+====================
+FixSurfaceJunctions
+====================
+*/
+#define MAX_SURFACE_VERTS 256
+void FixSurfaceJunctions( mapDrawSurface_t *ds ) {
+ int i, j, k;
+ edgeLine_t *e;
+ edgePoint_t *p;
+ int originalVerts;
+ int counts[MAX_SURFACE_VERTS];
+ int originals[MAX_SURFACE_VERTS];
+ int firstVert[MAX_SURFACE_VERTS];
+ drawVert_t verts[MAX_SURFACE_VERTS], *v1, *v2;
+ int numVerts;
+ float start, end, frac;
+ vec3_t delta;
+
+ originalVerts = ds->numVerts;
+
+ numVerts = 0;
+ for ( i = 0 ; i < ds->numVerts ; i++ ) {
+ counts[i] = 0;
+ firstVert[i] = numVerts;
+
+ // copy first vert
+ if ( numVerts == MAX_SURFACE_VERTS ) {
+ Error( "MAX_SURFACE_VERTS" );
+ }
+ verts[numVerts] = ds->verts[i];
+ originals[numVerts] = i;
+ numVerts++;
+
+ // check to see if there are any t junctions before the next vert
+ v1 = &ds->verts[i];
+ v2 = &ds->verts[ (i+1) % ds->numVerts ];
+
+ j = (int)ds->verts[i].lightmap[0];
+ if ( j == -1 ) {
+ continue; // degenerate edge
+ }
+ e = &edgeLines[ j ];
+
+ VectorSubtract( v1->xyz, e->origin, delta );
+ start = DotProduct( delta, e->dir );
+
+ VectorSubtract( v2->xyz, e->origin, delta );
+ end = DotProduct( delta, e->dir );
+
+
+ if ( start < end ) {
+ p = e->chain.next;
+ } else {
+ p = e->chain.prev;
+ }
+
+ for ( ; p != &e->chain ; ) {
+ if ( start < end ) {
+ if ( p->intercept > end - ON_EPSILON ) {
+ break;
+ }
+ } else {
+ if ( p->intercept < end + ON_EPSILON ) {
+ break;
+ }
+ }
+
+ if (
+ ( start < end && p->intercept > start + ON_EPSILON ) ||
+ ( start > end && p->intercept < start - ON_EPSILON ) ) {
+ // insert this point
+ if ( numVerts == MAX_SURFACE_VERTS ) {
+ Error( "MAX_SURFACE_VERTS" );
+ }
+
+ // take the exact intercept point
+ VectorCopy( p->xyz, verts[ numVerts ].xyz );
+
+ // copy the normal
+ VectorCopy( v1->normal, verts[ numVerts ].normal );
+
+ // interpolate the texture coordinates
+ frac = ( p->intercept - start ) / ( end - start );
+ for ( j = 0 ; j < 2 ; j++ ) {
+ verts[ numVerts ].st[j] = v1->st[j] +
+ frac * ( v2->st[j] - v1->st[j] );
+ }
+ originals[numVerts] = i;
+ numVerts++;
+ counts[i]++;
+ }
+
+ if ( start < end ) {
+ p = p->next;
+ } else {
+ p = p->prev;
+ }
+ }
+ }
+
+ c_addedVerts += numVerts - ds->numVerts;
+ c_totalVerts += numVerts;
+
+
+ // FIXME: check to see if the entire surface degenerated
+ // after snapping
+
+ // rotate the points so that the initial vertex is between
+ // two non-subdivided edges
+ for ( i = 0 ; i < numVerts ; i++ ) {
+ if ( originals[ (i+1) % numVerts ] == originals[ i ] ) {
+ continue;
+ }
+ j = (i + numVerts - 1 ) % numVerts;
+ k = (i + numVerts - 2 ) % numVerts;
+ if ( originals[ j ] == originals[ k ] ) {
+ continue;
+ }
+ break;
+ }
+
+ if ( i == 0 ) {
+ // fine the way it is
+ c_natural++;
+
+ ds->numVerts = numVerts;
+ ds->verts = malloc( numVerts * sizeof( *ds->verts ) );
+ memcpy( ds->verts, verts, numVerts * sizeof( *ds->verts ) );
+
+ return;
+ }
+ if ( i == numVerts ) {
+ // create a vertex in the middle to start the fan
+ c_cant++;
+
+/*
+ memset ( &verts[numVerts], 0, sizeof( verts[numVerts] ) );
+ for ( i = 0 ; i < numVerts ; i++ ) {
+ for ( j = 0 ; j < 10 ; j++ ) {
+ verts[numVerts].xyz[j] += verts[i].xyz[j];
+ }
+ }
+ for ( j = 0 ; j < 10 ; j++ ) {
+ verts[numVerts].xyz[j] /= numVerts;
+ }
+
+ i = numVerts;
+ numVerts++;
+*/
+ } else {
+ // just rotate the vertexes
+ c_rotate++;
+
+ }
+
+ ds->numVerts = numVerts;
+ ds->verts = malloc( numVerts * sizeof( *ds->verts ) );
+
+ for ( j = 0 ; j < ds->numVerts ; j++ ) {
+ ds->verts[j] = verts[ ( j + i ) % ds->numVerts ];
+ }
+}
+
+/*
+================
+EdgeCompare
+================
+*/
+int EdgeCompare( const void *elem1, const void *elem2 ) {
+ float d1, d2;
+
+ d1 = ((originalEdge_t *)elem1)->length;
+ d2 = ((originalEdge_t *)elem2)->length;
+
+ if ( d1 < d2 ) {
+ return -1;
+ }
+ if ( d2 > d1 ) {
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+================
+FixTJunctions
+
+Call after the surface list has been pruned, but before lightmap allocation
+================
+*/
+void FixTJunctions( entity_t *ent ) {
+ int i;
+ mapDrawSurface_t *ds;
+ int axialEdgeLines;
+ originalEdge_t *e;
+
+ qprintf("----- FixTJunctions -----\n");
+
+ numEdgeLines = 0;
+ numOriginalEdges = 0;
+
+ // add all the edges
+ // this actually creates axial edges, but it
+ // only creates originalEdge_t structures
+ // for non-axial edges
+ for ( i = ent->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
+ ds = &mapDrawSurfs[i];
+ if ( ds->patch ) {
+ AddPatchEdges( ds );
+ } else if ( ds->shaderInfo->autosprite || ds->shaderInfo->notjunc || ds->miscModel ) {
+ // miscModels don't add tjunctions
+ } else {
+ AddSurfaceEdges( ds );
+ }
+ }
+
+ axialEdgeLines = numEdgeLines;
+
+ // sort the non-axial edges by length
+ qsort( originalEdges, numOriginalEdges, sizeof(originalEdges[0]), EdgeCompare );
+
+ // add the non-axial edges, longest first
+ // this gives the most accurate edge description
+ for ( i = 0 ; i < numOriginalEdges ; i++ ) {
+ e = &originalEdges[i];
+ e->dv[0]->lightmap[0] = AddEdge( e->dv[0]->xyz, e->dv[1]->xyz, qtrue );
+ }
+
+ qprintf( "%6i axial edge lines\n", axialEdgeLines );
+ qprintf( "%6i non-axial edge lines\n", numEdgeLines - axialEdgeLines );
+ qprintf( "%6i degenerate edges\n", c_degenerateEdges );
+
+ // insert any needed vertexes
+ for ( i = ent->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
+ ds = &mapDrawSurfs[i];
+ if ( ds->patch ) {
+ continue;
+ }
+ if ( ds->shaderInfo->autosprite || ds->shaderInfo->notjunc || ds->miscModel ) {
+ continue;
+ }
+
+ FixSurfaceJunctions( ds );
+ }
+
+ qprintf( "%6i verts added for tjunctions\n", c_addedVerts );
+ qprintf( "%6i total verts\n", c_totalVerts );
+ qprintf( "%6i naturally ordered\n", c_natural );
+ qprintf( "%6i rotated orders\n", c_rotate );
+ qprintf( "%6i can't order\n", c_cant );
+}
diff --git a/q3map/tree.c b/q3map/tree.c
index 4addea6..f400db1 100755
--- a/q3map/tree.c
+++ b/q3map/tree.c
@@ -19,128 +19,128 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-#include "qbsp.h"
-
-
-extern int c_nodes;
-
-void RemovePortalFromNode (portal_t *portal, node_t *l);
-
-node_t *NodeForPoint (node_t *node, vec3_t origin)
-{
- plane_t *plane;
- vec_t d;
-
- while (node->planenum != PLANENUM_LEAF)
- {
- plane = &mapplanes[node->planenum];
- d = DotProduct (origin, plane->normal) - plane->dist;
- if (d >= 0)
- node = node->children[0];
- else
- node = node->children[1];
- }
-
- return node;
-}
-
-
-
-/*
-=============
-FreeTreePortals_r
-=============
-*/
-void FreeTreePortals_r (node_t *node)
-{
- portal_t *p, *nextp;
- int s;
-
- // free children
- if (node->planenum != PLANENUM_LEAF)
- {
- FreeTreePortals_r (node->children[0]);
- FreeTreePortals_r (node->children[1]);
- }
-
- // free portals
- for (p=node->portals ; p ; p=nextp)
- {
- s = (p->nodes[1] == node);
- nextp = p->next[s];
-
- RemovePortalFromNode (p, p->nodes[!s]);
- FreePortal (p);
- }
- node->portals = NULL;
-}
-
-/*
-=============
-FreeTree_r
-=============
-*/
-void FreeTree_r (node_t *node)
-{
- // free children
- if (node->planenum != PLANENUM_LEAF)
- {
- FreeTree_r (node->children[0]);
- FreeTree_r (node->children[1]);
- }
-
- // free bspbrushes
- FreeBrushList (node->brushlist);
-
- // free the node
- if (node->volume)
- FreeBrush (node->volume);
-
- if (numthreads == 1)
- c_nodes--;
- free (node);
-}
-
-
-/*
-=============
-FreeTree
-=============
-*/
-void FreeTree (tree_t *tree)
-{
- FreeTreePortals_r (tree->headnode);
- FreeTree_r (tree->headnode);
- free (tree);
-}
-
-//===============================================================
-
-void PrintTree_r (node_t *node, int depth)
-{
- int i;
- plane_t *plane;
- bspbrush_t *bb;
-
- for (i=0 ; i<depth ; i++)
- _printf (" ");
- if (node->planenum == PLANENUM_LEAF)
- {
- if (!node->brushlist)
- _printf ("NULL\n");
- else
- {
- for (bb=node->brushlist ; bb ; bb=bb->next)
- _printf ("%i ", bb->original->brushnum);
- _printf ("\n");
- }
- return;
- }
-
- plane = &mapplanes[node->planenum];
- _printf ("#%i (%5.2f %5.2f %5.2f):%5.2f\n", node->planenum,
- plane->normal[0], plane->normal[1], plane->normal[2],
- plane->dist);
- PrintTree_r (node->children[0], depth+1);
- PrintTree_r (node->children[1], depth+1);
-}
+#include "qbsp.h"
+
+
+extern int c_nodes;
+
+void RemovePortalFromNode (portal_t *portal, node_t *l);
+
+node_t *NodeForPoint (node_t *node, vec3_t origin)
+{
+ plane_t *plane;
+ vec_t d;
+
+ while (node->planenum != PLANENUM_LEAF)
+ {
+ plane = &mapplanes[node->planenum];
+ d = DotProduct (origin, plane->normal) - plane->dist;
+ if (d >= 0)
+ node = node->children[0];
+ else
+ node = node->children[1];
+ }
+
+ return node;
+}
+
+
+
+/*
+=============
+FreeTreePortals_r
+=============
+*/
+void FreeTreePortals_r (node_t *node)
+{
+ portal_t *p, *nextp;
+ int s;
+
+ // free children
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ FreeTreePortals_r (node->children[0]);
+ FreeTreePortals_r (node->children[1]);
+ }
+
+ // free portals
+ for (p=node->portals ; p ; p=nextp)
+ {
+ s = (p->nodes[1] == node);
+ nextp = p->next[s];
+
+ RemovePortalFromNode (p, p->nodes[!s]);
+ FreePortal (p);
+ }
+ node->portals = NULL;
+}
+
+/*
+=============
+FreeTree_r
+=============
+*/
+void FreeTree_r (node_t *node)
+{
+ // free children
+ if (node->planenum != PLANENUM_LEAF)
+ {
+ FreeTree_r (node->children[0]);
+ FreeTree_r (node->children[1]);
+ }
+
+ // free bspbrushes
+ FreeBrushList (node->brushlist);
+
+ // free the node
+ if (node->volume)
+ FreeBrush (node->volume);
+
+ if (numthreads == 1)
+ c_nodes--;
+ free (node);
+}
+
+
+/*
+=============
+FreeTree
+=============
+*/
+void FreeTree (tree_t *tree)
+{
+ FreeTreePortals_r (tree->headnode);
+ FreeTree_r (tree->headnode);
+ free (tree);
+}
+
+//===============================================================
+
+void PrintTree_r (node_t *node, int depth)
+{
+ int i;
+ plane_t *plane;
+ bspbrush_t *bb;
+
+ for (i=0 ; i<depth ; i++)
+ _printf (" ");
+ if (node->planenum == PLANENUM_LEAF)
+ {
+ if (!node->brushlist)
+ _printf ("NULL\n");
+ else
+ {
+ for (bb=node->brushlist ; bb ; bb=bb->next)
+ _printf ("%i ", bb->original->brushnum);
+ _printf ("\n");
+ }
+ return;
+ }
+
+ plane = &mapplanes[node->planenum];
+ _printf ("#%i (%5.2f %5.2f %5.2f):%5.2f\n", node->planenum,
+ plane->normal[0], plane->normal[1], plane->normal[2],
+ plane->dist);
+ PrintTree_r (node->children[0], depth+1);
+ PrintTree_r (node->children[1], depth+1);
+}
diff --git a/q3map/vis.c b/q3map/vis.c
index 6baab38..329d192 100755
--- a/q3map/vis.c
+++ b/q3map/vis.c
@@ -19,1179 +19,1179 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-// vis.c
-
-#include "vis.h"
-#include "threads.h"
-#include "stdlib.h"
-#ifdef _WIN32
-#include "../libs/pakstuff.h"
-#endif
-
-
-#define VIS_HEADER_SIZE 8
-
-extern char outbase[32];
-
-int numportals;
-int portalclusters;
-int numfaces;
-
-char inbase[32];
-
-vportal_t *portals;
-leaf_t *leafs;
-
-vportal_t *faces;
-leaf_t *faceleafs;
-
-int c_portaltest, c_portalpass, c_portalcheck;
-
-int leafbytes; // (portalclusters+63)>>3
-int leaflongs;
-
-int portalbytes, portallongs;
-
-qboolean fastvis;
-qboolean noPassageVis;
-qboolean passageVisOnly;
-qboolean mergevis;
-qboolean nosort;
-qboolean saveprt;
-
-int testlevel = 2;
-
-int totalvis;
-
-vportal_t *sorted_portals[MAX_MAP_PORTALS*2];
-
-void PassageMemory(void);
-
-
-//=============================================================================
-
-void PlaneFromWinding (winding_t *w, plane_t *plane)
-{
- vec3_t v1, v2;
-
-// calc plane
- VectorSubtract (w->points[2], w->points[1], v1);
- VectorSubtract (w->points[0], w->points[1], v2);
- CrossProduct (v2, v1, plane->normal);
- VectorNormalize (plane->normal, plane->normal);
- plane->dist = DotProduct (w->points[0], plane->normal);
-}
-
-
-/*
-==================
-NewWinding
-==================
-*/
-winding_t *NewWinding (int points)
-{
- winding_t *w;
- int size;
-
- if (points > MAX_POINTS_ON_WINDING)
- Error ("NewWinding: %i points", points);
-
- size = (int)((winding_t *)0)->points[points];
- w = malloc (size);
- memset (w, 0, size);
-
- return w;
-}
-
-
-
-void prl(leaf_t *l)
-{
- int i;
- vportal_t *p;
- plane_t pl;
-
- for (i=0 ; i<l->numportals ; i++)
- {
- p = l->portals[i];
- pl = p->plane;
- _printf ("portal %4i to leaf %4i : %7.1f : (%4.1f, %4.1f, %4.1f)\n",(int)(p-portals),p->leaf,pl.dist, pl.normal[0], pl.normal[1], pl.normal[2]);
- }
-}
-
-
-//=============================================================================
-
-/*
-=============
-SortPortals
-
-Sorts the portals from the least complex, so the later ones can reuse
-the earlier information.
-=============
-*/
-int PComp (const void *a, const void *b)
-{
- if ( (*(vportal_t **)a)->nummightsee == (*(vportal_t **)b)->nummightsee)
- return 0;
- if ( (*(vportal_t **)a)->nummightsee < (*(vportal_t **)b)->nummightsee)
- return -1;
- return 1;
-}
-void SortPortals (void)
-{
- int i;
-
- for (i=0 ; i<numportals*2 ; i++)
- sorted_portals[i] = &portals[i];
-
- if (nosort)
- return;
- qsort (sorted_portals, numportals*2, sizeof(sorted_portals[0]), PComp);
-}
-
-
-/*
-==============
-LeafVectorFromPortalVector
-==============
-*/
-int LeafVectorFromPortalVector (byte *portalbits, byte *leafbits)
-{
- int i, j, leafnum;
- vportal_t *p;
- int c_leafs;
-
-
- for (i=0 ; i<numportals*2 ; i++)
- {
- if (portalbits[i>>3] & (1<<(i&7)) )
- {
- p = portals+i;
- leafbits[p->leaf>>3] |= (1<<(p->leaf&7));
- }
- }
-
- for (j = 0; j < portalclusters; j++)
- {
- leafnum = j;
- while (leafs[leafnum].merged >= 0)
- leafnum = leafs[leafnum].merged;
- //if the merged leaf is visible then the original leaf is visible
- if (leafbits[leafnum>>3] & (1<<(leafnum&7)))
- {
- leafbits[j>>3] |= (1<<(j&7));
- }
- }
-
- c_leafs = CountBits (leafbits, portalclusters);
-
- return c_leafs;
-}
-
-
-/*
-===============
-ClusterMerge
-
-Merges the portal visibility for a leaf
-===============
-*/
-void ClusterMerge (int leafnum)
-{
- leaf_t *leaf;
- byte portalvector[MAX_PORTALS/8];
- byte uncompressed[MAX_MAP_LEAFS/8];
- int i, j;
- int numvis, mergedleafnum;
- vportal_t *p;
- int pnum;
-
- // OR together all the portalvis bits
-
- mergedleafnum = leafnum;
- while(leafs[mergedleafnum].merged >= 0)
- mergedleafnum = leafs[mergedleafnum].merged;
-
- memset (portalvector, 0, portalbytes);
- leaf = &leafs[mergedleafnum];
- for (i = 0; i < leaf->numportals; i++)
- {
- p = leaf->portals[i];
- if (p->removed)
- continue;
-
- if (p->status != stat_done)
- Error ("portal not done");
- for (j=0 ; j<portallongs ; j++)
- ((long *)portalvector)[j] |= ((long *)p->portalvis)[j];
- pnum = p - portals;
- portalvector[pnum>>3] |= 1<<(pnum&7);
- }
-
- memset (uncompressed, 0, leafbytes);
-
- uncompressed[mergedleafnum>>3] |= (1<<(mergedleafnum&7));
- // convert portal bits to leaf bits
- numvis = LeafVectorFromPortalVector (portalvector, uncompressed);
-
-// if (uncompressed[leafnum>>3] & (1<<(leafnum&7)))
-// _printf ("WARNING: Leaf portals saw into leaf\n");
-
-// uncompressed[leafnum>>3] |= (1<<(leafnum&7));
-
- numvis++; // count the leaf itself
-
- totalvis += numvis;
-
- qprintf ("cluster %4i : %4i visible\n", leafnum, numvis);
-
- memcpy (visBytes + VIS_HEADER_SIZE + leafnum*leafbytes, uncompressed, leafbytes);
-}
-
-/*
-==================
-CalcPortalVis
-==================
-*/
-void CalcPortalVis (void)
-{
-#ifdef MREDEBUG
- _printf("%6d portals out of %d", 0, numportals*2);
- //get rid of the counter
- RunThreadsOnIndividual (numportals*2, qfalse, PortalFlow);
-#else
- RunThreadsOnIndividual (numportals*2, qtrue, PortalFlow);
-#endif
-
-}
-
-/*
-==================
-CalcPassageVis
-==================
-*/
-void CalcPassageVis(void)
-{
- PassageMemory();
-
-#ifdef MREDEBUG
- _printf("%6d portals out of %d", 0, numportals*2);
- RunThreadsOnIndividual (numportals*2, qfalse, CreatePassages);
- _printf("\n");
- _printf("%6d portals out of %d", 0, numportals*2);
- RunThreadsOnIndividual (numportals*2, qfalse, PassageFlow);
- _printf("\n");
-#else
- RunThreadsOnIndividual (numportals*2, qtrue, CreatePassages);
- RunThreadsOnIndividual (numportals*2, qtrue, PassageFlow);
-#endif
-}
-
-/*
-==================
-CalcPassagePortalVis
-==================
-*/
-void CalcPassagePortalVis(void)
-{
- PassageMemory();
-
-#ifdef MREDEBUG
- _printf("%6d portals out of %d", 0, numportals*2);
- RunThreadsOnIndividual (numportals*2, qfalse, CreatePassages);
- _printf("\n");
- _printf("%6d portals out of %d", 0, numportals*2);
- RunThreadsOnIndividual (numportals*2, qfalse, PassagePortalFlow);
- _printf("\n");
-#else
- RunThreadsOnIndividual (numportals*2, qtrue, CreatePassages);
- RunThreadsOnIndividual (numportals*2, qtrue, PassagePortalFlow);
-#endif
-}
-
-/*
-==================
-CalcFastVis
-==================
-*/
-void CalcFastVis(void)
-{
- int i;
-
- // fastvis just uses mightsee for a very loose bound
- for (i=0 ; i<numportals*2 ; i++)
- {
- portals[i].portalvis = portals[i].portalflood;
- portals[i].status = stat_done;
- }
-}
-
-/*
-==================
-CalcVis
-==================
-*/
-void CalcVis (void)
-{
- int i;
-
- RunThreadsOnIndividual (numportals*2, qtrue, BasePortalVis);
-
-// RunThreadsOnIndividual (numportals*2, qtrue, BetterPortalVis);
-
- SortPortals ();
-
- if (fastvis) {
- CalcFastVis();
- }
- else if ( noPassageVis ) {
- CalcPortalVis();
- }
- else if ( passageVisOnly ) {
- CalcPassageVis();
- }
- else {
- CalcPassagePortalVis();
- }
- //
- // assemble the leaf vis lists by oring and compressing the portal lists
- //
- _printf("creating leaf vis...\n");
- for (i=0 ; i<portalclusters ; i++)
- ClusterMerge (i);
-
- _printf( "Total visible clusters: %i\n", totalvis );
- _printf( "Average clusters visible: %i\n", totalvis / portalclusters );
-}
-
-/*
-==================
-SetPortalSphere
-==================
-*/
-void SetPortalSphere (vportal_t *p)
-{
- int i;
- vec3_t total, dist;
- winding_t *w;
- float r, bestr;
-
- w = p->winding;
- VectorCopy (vec3_origin, total);
- for (i=0 ; i<w->numpoints ; i++)
- {
- VectorAdd (total, w->points[i], total);
- }
-
- for (i=0 ; i<3 ; i++)
- total[i] /= w->numpoints;
-
- bestr = 0;
- for (i=0 ; i<w->numpoints ; i++)
- {
- VectorSubtract (w->points[i], total, dist);
- r = VectorLength (dist);
- if (r > bestr)
- bestr = r;
- }
- VectorCopy (total, p->origin);
- p->radius = bestr;
-}
-
-/*
-=============
-Winding_PlanesConcave
-=============
-*/
-#define WCONVEX_EPSILON 0.2
-
-int Winding_PlanesConcave(winding_t *w1, winding_t *w2,
- vec3_t normal1, vec3_t normal2,
- float dist1, float dist2)
-{
- int i;
-
- if (!w1 || !w2) return qfalse;
-
- // check if one of the points of winding 1 is at the front of the plane of winding 2
- for (i = 0; i < w1->numpoints; i++)
- {
- if (DotProduct(normal2, w1->points[i]) - dist2 > WCONVEX_EPSILON) return qtrue;
- }
- // check if one of the points of winding 2 is at the front of the plane of winding 1
- for (i = 0; i < w2->numpoints; i++)
- {
- if (DotProduct(normal1, w2->points[i]) - dist1 > WCONVEX_EPSILON) return qtrue;
- }
-
- return qfalse;
-}
-
-/*
-============
-TryMergeLeaves
-============
-*/
-int TryMergeLeaves(int l1num, int l2num)
-{
- int i, j, k, n, numportals;
- plane_t plane1, plane2;
- leaf_t *l1, *l2;
- vportal_t *p1, *p2;
- vportal_t *portals[MAX_PORTALS_ON_LEAF];
-
- for (k = 0; k < 2; k++)
- {
- if (k) l1 = &leafs[l1num];
- else l1 = &faceleafs[l1num];
- for (i = 0; i < l1->numportals; i++)
- {
- p1 = l1->portals[i];
- if (p1->leaf == l2num) continue;
- for (n = 0; n < 2; n++)
- {
- if (n) l2 = &leafs[l2num];
- else l2 = &faceleafs[l2num];
- for (j = 0; j < l2->numportals; j++)
- {
- p2 = l2->portals[j];
- if (p2->leaf == l1num) continue;
- //
- plane1 = p1->plane;
- plane2 = p2->plane;
- if (Winding_PlanesConcave(p1->winding, p2->winding, plane1.normal, plane2.normal, plane1.dist, plane2.dist))
- return qfalse;
- }
- }
- }
- }
- for (k = 0; k < 2; k++)
- {
- if (k)
- {
- l1 = &leafs[l1num];
- l2 = &leafs[l2num];
- }
- else
- {
- l1 = &faceleafs[l1num];
- l2 = &faceleafs[l2num];
- }
- numportals = 0;
- //the leaves can be merged now
- for (i = 0; i < l1->numportals; i++)
- {
- p1 = l1->portals[i];
- if (p1->leaf == l2num)
- {
- p1->removed = qtrue;
- continue;
- }
- portals[numportals++] = p1;
- }
- for (j = 0; j < l2->numportals; j++)
- {
- p2 = l2->portals[j];
- if (p2->leaf == l1num)
- {
- p2->removed = qtrue;
- continue;
- }
- portals[numportals++] = p2;
- }
- for (i = 0; i < numportals; i++)
- {
- l2->portals[i] = portals[i];
- }
- l2->numportals = numportals;
- l1->merged = l2num;
- }
- return qtrue;
-}
-
-/*
-============
-UpdatePortals
-============
-*/
-void UpdatePortals(void)
-{
- int i;
- vportal_t *p;
-
- for (i = 0; i < numportals * 2; i++)
- {
- p = &portals[i];
- if (p->removed)
- continue;
- while(leafs[p->leaf].merged >= 0)
- p->leaf = leafs[p->leaf].merged;
- }
-}
-
-/*
-============
-MergeLeaves
-
-try to merge leaves but don't merge through hint splitters
-============
-*/
-void MergeLeaves(void)
-{
- int i, j, nummerges, totalnummerges;
- leaf_t *leaf;
- vportal_t *p;
-
- totalnummerges = 0;
- do
- {
- nummerges = 0;
- for (i = 0; i < portalclusters; i++)
- {
- leaf = &leafs[i];
- //if this leaf is merged already
- if (leaf->merged >= 0)
- continue;
- //
- for (j = 0; j < leaf->numportals; j++)
- {
- p = leaf->portals[j];
- //
- if (p->removed)
- continue;
- //never merge through hint portals
- if (p->hint)
- continue;
- if (TryMergeLeaves(i, p->leaf))
- {
- UpdatePortals();
- nummerges++;
- break;
- }
- }
- }
- totalnummerges += nummerges;
- } while (nummerges);
- _printf("%6d leaves merged\n", totalnummerges);
-}
-
-/*
-============
-TryMergeWinding
-============
-*/
-#define CONTINUOUS_EPSILON 0.005
-
-winding_t *TryMergeWinding (winding_t *f1, winding_t *f2, vec3_t planenormal)
-{
- vec_t *p1, *p2, *p3, *p4, *back;
- winding_t *newf;
- int i, j, k, l;
- vec3_t normal, delta;
- vec_t dot;
- qboolean keep1, keep2;
-
-
- //
- // find a common edge
- //
- p1 = p2 = NULL; // stop compiler warning
- j = 0; //
-
- for (i = 0; i < f1->numpoints; i++)
- {
- p1 = f1->points[i];
- p2 = f1->points[(i+1) % f1->numpoints];
- for (j = 0; j < f2->numpoints; j++)
- {
- p3 = f2->points[j];
- p4 = f2->points[(j+1) % f2->numpoints];
- for (k = 0; k < 3; k++)
- {
- if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME
- break;
- if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME
- break;
- } //end for
- if (k==3)
- break;
- } //end for
- if (j < f2->numpoints)
- break;
- } //end for
-
- if (i == f1->numpoints)
- return NULL; // no matching edges
-
- //
- // check slope of connected lines
- // if the slopes are colinear, the point can be removed
- //
- back = f1->points[(i+f1->numpoints-1)%f1->numpoints];
- VectorSubtract (p1, back, delta);
- CrossProduct (planenormal, delta, normal);
- VectorNormalize (normal, normal);
-
- back = f2->points[(j+2)%f2->numpoints];
- VectorSubtract (back, p1, delta);
- dot = DotProduct (delta, normal);
- if (dot > CONTINUOUS_EPSILON)
- return NULL; // not a convex polygon
- keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON);
-
- back = f1->points[(i+2)%f1->numpoints];
- VectorSubtract (back, p2, delta);
- CrossProduct (planenormal, delta, normal);
- VectorNormalize (normal, normal);
-
- back = f2->points[(j+f2->numpoints-1)%f2->numpoints];
- VectorSubtract (back, p2, delta);
- dot = DotProduct (delta, normal);
- if (dot > CONTINUOUS_EPSILON)
- return NULL; // not a convex polygon
- keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON);
-
- //
- // build the new polygon
- //
- newf = NewWinding (f1->numpoints + f2->numpoints);
-
- // copy first polygon
- for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
- {
- if (k==(i+1)%f1->numpoints && !keep2)
- continue;
-
- VectorCopy (f1->points[k], newf->points[newf->numpoints]);
- newf->numpoints++;
- }
-
- // copy second polygon
- for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
- {
- if (l==(j+1)%f2->numpoints && !keep1)
- continue;
- VectorCopy (f2->points[l], newf->points[newf->numpoints]);
- newf->numpoints++;
- }
-
- return newf;
-}
-
-/*
-============
-MergeLeafPortals
-============
-*/
-void MergeLeafPortals(void)
-{
- int i, j, k, nummerges, hintsmerged;
- leaf_t *leaf;
- vportal_t *p1, *p2;
- winding_t *w;
-
- nummerges = 0;
- hintsmerged = 0;
- for (i = 0; i < portalclusters; i++)
- {
- leaf = &leafs[i];
- if (leaf->merged >= 0) continue;
- for (j = 0; j < leaf->numportals; j++)
- {
- p1 = leaf->portals[j];
- if (p1->removed)
- continue;
- for (k = j+1; k < leaf->numportals; k++)
- {
- p2 = leaf->portals[k];
- if (p2->removed)
- continue;
- if (p1->leaf == p2->leaf)
- {
- w = TryMergeWinding(p1->winding, p2->winding, p1->plane.normal);
- if (w)
- {
- FreeWinding(p1->winding);
- p1->winding = w;
- if (p1->hint && p2->hint)
- hintsmerged++;
- p1->hint |= p2->hint;
- SetPortalSphere(p1);
- p2->removed = qtrue;
- nummerges++;
- i--;
- break;
- }
- }
- }
- if (k < leaf->numportals)
- break;
- }
- }
- _printf("%6d portals merged\n", nummerges);
- _printf("%6d hint portals merged\n", hintsmerged);
-}
-
-
-/*
-============
-WritePortals
-============
-*/
-int CountActivePortals(void)
-{
- int num, hints, j;
- vportal_t *p;
-
- num = 0;
- hints = 0;
- for (j = 0; j < numportals * 2; j++)
- {
- p = portals + j;
- if (p->removed)
- continue;
- if (p->hint)
- hints++;
- num++;
- }
- _printf("%6d active portals\n", num);
- _printf("%6d hint portals\n", hints);
- return num;
-}
-
-/*
-============
-WritePortals
-============
-*/
-void WriteFloat (FILE *f, vec_t v);
-
-void WritePortals(char *filename)
-{
- int i, j, num;
- FILE *pf;
- vportal_t *p;
- winding_t *w;
-
- // write the file
- pf = fopen (filename, "w");
- if (!pf)
- Error ("Error opening %s", filename);
-
- num = 0;
- for (j = 0; j < numportals * 2; j++)
- {
- p = portals + j;
- if (p->removed)
- continue;
-// if (!p->hint)
-// continue;
- num++;
- }
-
- fprintf (pf, "%s\n", PORTALFILE);
- fprintf (pf, "%i\n", 0);
- fprintf (pf, "%i\n", num);// + numfaces);
- fprintf (pf, "%i\n", 0);
-
- for (j = 0; j < numportals * 2; j++)
- {
- p = portals + j;
- if (p->removed)
- continue;
-// if (!p->hint)
-// continue;
- w = p->winding;
- fprintf (pf,"%i %i %i ",w->numpoints, 0, 0);
- fprintf (pf, "%d ", p->hint);
- for (i=0 ; i<w->numpoints ; i++)
- {
- fprintf (pf,"(");
- WriteFloat (pf, w->points[i][0]);
- WriteFloat (pf, w->points[i][1]);
- WriteFloat (pf, w->points[i][2]);
- fprintf (pf,") ");
- }
- fprintf (pf,"\n");
- }
-
- /*
- for (j = 0; j < numfaces; j++)
- {
- p = faces + j;
- w = p->winding;
- fprintf (pf,"%i %i %i ",w->numpoints, 0, 0);
- fprintf (pf, "0 ");
- for (i=0 ; i<w->numpoints ; i++)
- {
- fprintf (pf,"(");
- WriteFloat (pf, w->points[i][0]);
- WriteFloat (pf, w->points[i][1]);
- WriteFloat (pf, w->points[i][2]);
- fprintf (pf,") ");
- }
- fprintf (pf,"\n");
- }*/
-
- fclose (pf);
-}
-
-/*
-============
-LoadPortals
-============
-*/
-void LoadPortals (char *name)
-{
- int i, j, hint;
- vportal_t *p;
- leaf_t *l;
- char magic[80];
- FILE *f;
- int numpoints;
- winding_t *w;
- int leafnums[2];
- plane_t plane;
-
- if (!strcmp(name,"-"))
- f = stdin;
- else
- {
- f = fopen(name, "r");
- if (!f)
- Error ("LoadPortals: couldn't read %s\n",name);
- }
-
- if (fscanf (f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces) != 4)
- Error ("LoadPortals: failed to read header");
- if (strcmp(magic,PORTALFILE))
- Error ("LoadPortals: not a portal file");
-
- _printf ("%6i portalclusters\n", portalclusters);
- _printf ("%6i numportals\n", numportals);
- _printf ("%6i numfaces\n", numfaces);
-
- // these counts should take advantage of 64 bit systems automatically
- leafbytes = ((portalclusters+63)&~63)>>3;
- leaflongs = leafbytes/sizeof(long);
-
- portalbytes = ((numportals*2+63)&~63)>>3;
- portallongs = portalbytes/sizeof(long);
-
- // each file portal is split into two memory portals
- portals = malloc(2*numportals*sizeof(vportal_t));
- memset (portals, 0, 2*numportals*sizeof(vportal_t));
-
- leafs = malloc(portalclusters*sizeof(leaf_t));
- memset (leafs, 0, portalclusters*sizeof(leaf_t));
-
- for (i = 0; i < portalclusters; i++)
- leafs[i].merged = -1;
-
- numVisBytes = VIS_HEADER_SIZE + portalclusters*leafbytes;
-
- ((int *)visBytes)[0] = portalclusters;
- ((int *)visBytes)[1] = leafbytes;
-
- for (i=0, p=portals ; i<numportals ; i++)
- {
- if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3)
- Error ("LoadPortals: reading portal %i", i);
- if (numpoints > MAX_POINTS_ON_WINDING)
- Error ("LoadPortals: portal %i has too many points", i);
- if ( (unsigned)leafnums[0] > portalclusters
- || (unsigned)leafnums[1] > portalclusters)
- Error ("LoadPortals: reading portal %i", i);
- if (fscanf (f, "%i ", &hint) != 1)
- Error ("LoadPortals: reading hint state");
-
- w = p->winding = NewWinding (numpoints);
- w->numpoints = numpoints;
-
- for (j=0 ; j<numpoints ; j++)
- {
- double v[3];
- int k;
-
- // scanf into double, then assign to vec_t
- // so we don't care what size vec_t is
- if (fscanf (f, "(%lf %lf %lf ) "
- , &v[0], &v[1], &v[2]) != 3)
- Error ("LoadPortals: reading portal %i", i);
- for (k=0 ; k<3 ; k++)
- w->points[j][k] = v[k];
- }
- fscanf (f, "\n");
-
- // calc plane
- PlaneFromWinding (w, &plane);
-
- // create forward portal
- l = &leafs[leafnums[0]];
- if (l->numportals == MAX_PORTALS_ON_LEAF)
- Error ("Leaf with too many portals");
- l->portals[l->numportals] = p;
- l->numportals++;
-
- p->num = i+1;
- p->hint = hint;
- p->winding = w;
- VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
- p->plane.dist = -plane.dist;
- p->leaf = leafnums[1];
- SetPortalSphere (p);
- p++;
-
- // create backwards portal
- l = &leafs[leafnums[1]];
- if (l->numportals == MAX_PORTALS_ON_LEAF)
- Error ("Leaf with too many portals");
- l->portals[l->numportals] = p;
- l->numportals++;
-
- p->num = i+1;
- p->hint = hint;
- p->winding = NewWinding(w->numpoints);
- p->winding->numpoints = w->numpoints;
- for (j=0 ; j<w->numpoints ; j++)
- {
- VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]);
- }
-
- p->plane = plane;
- p->leaf = leafnums[0];
- SetPortalSphere (p);
- p++;
-
- }
-
- faces = malloc(2*numfaces*sizeof(vportal_t));
- memset (faces, 0, 2*numfaces*sizeof(vportal_t));
-
- faceleafs = malloc(portalclusters*sizeof(leaf_t));
- memset(faceleafs, 0, portalclusters*sizeof(leaf_t));
-
- for (i = 0, p = faces; i < numfaces; i++)
- {
- if (fscanf (f, "%i %i ", &numpoints, &leafnums[0]) != 2)
- Error ("LoadPortals: reading portal %i", i);
-
- w = p->winding = NewWinding (numpoints);
- w->numpoints = numpoints;
-
- for (j=0 ; j<numpoints ; j++)
- {
- double v[3];
- int k;
-
- // scanf into double, then assign to vec_t
- // so we don't care what size vec_t is
- if (fscanf (f, "(%lf %lf %lf ) "
- , &v[0], &v[1], &v[2]) != 3)
- Error ("LoadPortals: reading portal %i", i);
- for (k=0 ; k<3 ; k++)
- w->points[j][k] = v[k];
- }
- fscanf (f, "\n");
-
- // calc plane
- PlaneFromWinding (w, &plane);
-
- l = &faceleafs[leafnums[0]];
- l->merged = -1;
- if (l->numportals == MAX_PORTALS_ON_LEAF)
- Error ("Leaf with too many faces");
- l->portals[l->numportals] = p;
- l->numportals++;
-
- p->num = i+1;
- p->winding = w;
- // normal pointing out of the leaf
- VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
- p->plane.dist = -plane.dist;
- p->leaf = -1;
- SetPortalSphere (p);
- p++;
- }
-
- fclose (f);
-}
-
-
-/*
-================
-CalcPHS
-
-Calculate the PHS (Potentially Hearable Set)
-by ORing together all the PVS visible from a leaf
-================
-*/
-void CalcPHS (void)
-{
- int i, j, k, l, index;
- int bitbyte;
- long *dest, *src;
- byte *scan;
- int count;
- byte uncompressed[MAX_MAP_LEAFS/8];
-
- _printf ("Building PHS...\n");
-
- count = 0;
- for (i=0 ; i<portalclusters ; i++)
- {
- scan = visBytes + i*leafbytes;
- memcpy (uncompressed, scan, leafbytes);
- for (j=0 ; j<leafbytes ; j++)
- {
- bitbyte = scan[j];
- if (!bitbyte)
- continue;
- for (k=0 ; k<8 ; k++)
- {
- if (! (bitbyte & (1<<k)) )
- continue;
- // OR this pvs row into the phs
- index = ((j<<3)+k);
- if (index >= portalclusters)
- Error ("Bad bit in PVS"); // pad bits should be 0
- src = (long *)(visBytes + index*leafbytes);
- dest = (long *)uncompressed;
- for (l=0 ; l<leaflongs ; l++)
- ((long *)uncompressed)[l] |= src[l];
- }
- }
- for (j=0 ; j<portalclusters ; j++)
- if (uncompressed[j>>3] & (1<<(j&7)) )
- count++;
-
- // FIXME: copy it off
- }
-
- _printf ("Average clusters hearable: %i\n", count/portalclusters);
-}
-
-/*
-===========
-VisMain
-===========
-*/
-int VisMain (int argc, char **argv)
-{
- char portalfile[1024];
- char name[1024];
- int i;
- double start, end;
-
- _printf ("---- vis ----\n");
-
- verbose = qfalse;
- for (i=1 ; i<argc ; i++) {
- if (!strcmp(argv[i],"-threads")) {
- numthreads = atoi (argv[i+1]);
- i++;
- } else if (!strcmp(argv[i],"-threads")) {
- numthreads = atoi (argv[i+1]);
- i++;
- } else if (!strcmp(argv[i], "-fast")) {
- _printf ("fastvis = true\n");
- fastvis = qtrue;
- } else if (!strcmp(argv[i], "-merge")) {
- _printf ("merge = true\n");
- mergevis = qtrue;
- } else if (!strcmp(argv[i], "-nopassage")) {
- _printf ("nopassage = true\n");
- noPassageVis = qtrue;
- } else if (!strcmp(argv[i], "-passageOnly")) {
- _printf("passageOnly = true\n");
- passageVisOnly = qtrue;
- } else if (!strcmp(argv[i], "-level")) {
- testlevel = atoi(argv[i+1]);
- _printf ("testlevel = %i\n", testlevel);
- i++;
- } else if (!strcmp(argv[i], "-v")) {
- _printf ("verbose = true\n");
- verbose = qtrue;
- } else if (!strcmp (argv[i],"-nosort")) {
- _printf ("nosort = true\n");
- nosort = qtrue;
- } else if (!strcmp (argv[i],"-saveprt")) {
- _printf ("saveprt = true\n");
- saveprt = qtrue;
- } else if (!strcmp (argv[i],"-tmpin")) {
- strcpy (inbase, "/tmp");
- } else if (!strcmp (argv[i],"-tmpout")) {
- strcpy (outbase, "/tmp");
- } else if (argv[i][0] == '-') {
- Error ("Unknown option \"%s\"", argv[i]);
- } else {
- break;
- }
- }
-
- if (i != argc - 1)
- Error ("usage: vis [-threads #] [-level 0-4] [-fast] [-v] bspfile");
-
-#ifdef MREDEBUG
- start = clock();
-#else
- start = I_FloatTime ();
-#endif
-
- ThreadSetDefault ();
-
- SetQdirFromPath (argv[i]);
-
-#ifdef _WIN32
- InitPakFile(gamedir, NULL);
-#endif
-
- // load the bsp
- sprintf (name, "%s%s", inbase, ExpandArg(argv[i]));
- StripExtension (name);
- strcat (name, ".bsp");
- _printf ("reading %s\n", name);
- LoadBSPFile (name);
-
- // load the portal file
- sprintf (portalfile, "%s%s", inbase, ExpandArg(argv[i]));
- StripExtension (portalfile);
- strcat (portalfile, ".prt");
- _printf ("reading %s\n", portalfile);
- LoadPortals (portalfile);
-
- if (mergevis)
- {
- MergeLeaves();
- MergeLeafPortals();
- }
-
- CountActivePortals();
-// WritePortals("maps/hints.prs");
-
- _printf ("visdatasize:%i\n", numVisBytes);
-
- CalcVis ();
-
-// CalcPHS ();
-
- // delete the prt file
- if ( !saveprt ) {
- remove( portalfile );
- }
-
- // write the bsp file
- _printf ("writing %s\n", name);
- WriteBSPFile (name);
-
-#ifdef MREDEBUG
- end = clock();
- _printf ("%5.2f seconds elapsed\n", (end-start) / CLK_TCK);
-#else
- end = I_FloatTime ();
- _printf ("%5.2f seconds elapsed\n", end-start);
-#endif
- return 0;
-}
-
+// vis.c
+
+#include "vis.h"
+#include "threads.h"
+#include "stdlib.h"
+#ifdef _WIN32
+#include "../libs/pakstuff.h"
+#endif
+
+
+#define VIS_HEADER_SIZE 8
+
+extern char outbase[32];
+
+int numportals;
+int portalclusters;
+int numfaces;
+
+char inbase[32];
+
+vportal_t *portals;
+leaf_t *leafs;
+
+vportal_t *faces;
+leaf_t *faceleafs;
+
+int c_portaltest, c_portalpass, c_portalcheck;
+
+int leafbytes; // (portalclusters+63)>>3
+int leaflongs;
+
+int portalbytes, portallongs;
+
+qboolean fastvis;
+qboolean noPassageVis;
+qboolean passageVisOnly;
+qboolean mergevis;
+qboolean nosort;
+qboolean saveprt;
+
+int testlevel = 2;
+
+int totalvis;
+
+vportal_t *sorted_portals[MAX_MAP_PORTALS*2];
+
+void PassageMemory(void);
+
+
+//=============================================================================
+
+void PlaneFromWinding (winding_t *w, plane_t *plane)
+{
+ vec3_t v1, v2;
+
+// calc plane
+ VectorSubtract (w->points[2], w->points[1], v1);
+ VectorSubtract (w->points[0], w->points[1], v2);
+ CrossProduct (v2, v1, plane->normal);
+ VectorNormalize (plane->normal, plane->normal);
+ plane->dist = DotProduct (w->points[0], plane->normal);
+}
+
+
+/*
+==================
+NewWinding
+==================
+*/
+winding_t *NewWinding (int points)
+{
+ winding_t *w;
+ int size;
+
+ if (points > MAX_POINTS_ON_WINDING)
+ Error ("NewWinding: %i points", points);
+
+ size = (int)((winding_t *)0)->points[points];
+ w = malloc (size);
+ memset (w, 0, size);
+
+ return w;
+}
+
+
+
+void prl(leaf_t *l)
+{
+ int i;
+ vportal_t *p;
+ plane_t pl;
+
+ for (i=0 ; i<l->numportals ; i++)
+ {
+ p = l->portals[i];
+ pl = p->plane;
+ _printf ("portal %4i to leaf %4i : %7.1f : (%4.1f, %4.1f, %4.1f)\n",(int)(p-portals),p->leaf,pl.dist, pl.normal[0], pl.normal[1], pl.normal[2]);
+ }
+}
+
+
+//=============================================================================
+
+/*
+=============
+SortPortals
+
+Sorts the portals from the least complex, so the later ones can reuse
+the earlier information.
+=============
+*/
+int PComp (const void *a, const void *b)
+{
+ if ( (*(vportal_t **)a)->nummightsee == (*(vportal_t **)b)->nummightsee)
+ return 0;
+ if ( (*(vportal_t **)a)->nummightsee < (*(vportal_t **)b)->nummightsee)
+ return -1;
+ return 1;
+}
+void SortPortals (void)
+{
+ int i;
+
+ for (i=0 ; i<numportals*2 ; i++)
+ sorted_portals[i] = &portals[i];
+
+ if (nosort)
+ return;
+ qsort (sorted_portals, numportals*2, sizeof(sorted_portals[0]), PComp);
+}
+
+
+/*
+==============
+LeafVectorFromPortalVector
+==============
+*/
+int LeafVectorFromPortalVector (byte *portalbits, byte *leafbits)
+{
+ int i, j, leafnum;
+ vportal_t *p;
+ int c_leafs;
+
+
+ for (i=0 ; i<numportals*2 ; i++)
+ {
+ if (portalbits[i>>3] & (1<<(i&7)) )
+ {
+ p = portals+i;
+ leafbits[p->leaf>>3] |= (1<<(p->leaf&7));
+ }
+ }
+
+ for (j = 0; j < portalclusters; j++)
+ {
+ leafnum = j;
+ while (leafs[leafnum].merged >= 0)
+ leafnum = leafs[leafnum].merged;
+ //if the merged leaf is visible then the original leaf is visible
+ if (leafbits[leafnum>>3] & (1<<(leafnum&7)))
+ {
+ leafbits[j>>3] |= (1<<(j&7));
+ }
+ }
+
+ c_leafs = CountBits (leafbits, portalclusters);
+
+ return c_leafs;
+}
+
+
+/*
+===============
+ClusterMerge
+
+Merges the portal visibility for a leaf
+===============
+*/
+void ClusterMerge (int leafnum)
+{
+ leaf_t *leaf;
+ byte portalvector[MAX_PORTALS/8];
+ byte uncompressed[MAX_MAP_LEAFS/8];
+ int i, j;
+ int numvis, mergedleafnum;
+ vportal_t *p;
+ int pnum;
+
+ // OR together all the portalvis bits
+
+ mergedleafnum = leafnum;
+ while(leafs[mergedleafnum].merged >= 0)
+ mergedleafnum = leafs[mergedleafnum].merged;
+
+ memset (portalvector, 0, portalbytes);
+ leaf = &leafs[mergedleafnum];
+ for (i = 0; i < leaf->numportals; i++)
+ {
+ p = leaf->portals[i];
+ if (p->removed)
+ continue;
+
+ if (p->status != stat_done)
+ Error ("portal not done");
+ for (j=0 ; j<portallongs ; j++)
+ ((long *)portalvector)[j] |= ((long *)p->portalvis)[j];
+ pnum = p - portals;
+ portalvector[pnum>>3] |= 1<<(pnum&7);
+ }
+
+ memset (uncompressed, 0, leafbytes);
+
+ uncompressed[mergedleafnum>>3] |= (1<<(mergedleafnum&7));
+ // convert portal bits to leaf bits
+ numvis = LeafVectorFromPortalVector (portalvector, uncompressed);
+
+// if (uncompressed[leafnum>>3] & (1<<(leafnum&7)))
+// _printf ("WARNING: Leaf portals saw into leaf\n");
+
+// uncompressed[leafnum>>3] |= (1<<(leafnum&7));
+
+ numvis++; // count the leaf itself
+
+ totalvis += numvis;
+
+ qprintf ("cluster %4i : %4i visible\n", leafnum, numvis);
+
+ memcpy (visBytes + VIS_HEADER_SIZE + leafnum*leafbytes, uncompressed, leafbytes);
+}
+
+/*
+==================
+CalcPortalVis
+==================
+*/
+void CalcPortalVis (void)
+{
+#ifdef MREDEBUG
+ _printf("%6d portals out of %d", 0, numportals*2);
+ //get rid of the counter
+ RunThreadsOnIndividual (numportals*2, qfalse, PortalFlow);
+#else
+ RunThreadsOnIndividual (numportals*2, qtrue, PortalFlow);
+#endif
+
+}
+
+/*
+==================
+CalcPassageVis
+==================
+*/
+void CalcPassageVis(void)
+{
+ PassageMemory();
+
+#ifdef MREDEBUG
+ _printf("%6d portals out of %d", 0, numportals*2);
+ RunThreadsOnIndividual (numportals*2, qfalse, CreatePassages);
+ _printf("\n");
+ _printf("%6d portals out of %d", 0, numportals*2);
+ RunThreadsOnIndividual (numportals*2, qfalse, PassageFlow);
+ _printf("\n");
+#else
+ RunThreadsOnIndividual (numportals*2, qtrue, CreatePassages);
+ RunThreadsOnIndividual (numportals*2, qtrue, PassageFlow);
+#endif
+}
+
+/*
+==================
+CalcPassagePortalVis
+==================
+*/
+void CalcPassagePortalVis(void)
+{
+ PassageMemory();
+
+#ifdef MREDEBUG
+ _printf("%6d portals out of %d", 0, numportals*2);
+ RunThreadsOnIndividual (numportals*2, qfalse, CreatePassages);
+ _printf("\n");
+ _printf("%6d portals out of %d", 0, numportals*2);
+ RunThreadsOnIndividual (numportals*2, qfalse, PassagePortalFlow);
+ _printf("\n");
+#else
+ RunThreadsOnIndividual (numportals*2, qtrue, CreatePassages);
+ RunThreadsOnIndividual (numportals*2, qtrue, PassagePortalFlow);
+#endif
+}
+
+/*
+==================
+CalcFastVis
+==================
+*/
+void CalcFastVis(void)
+{
+ int i;
+
+ // fastvis just uses mightsee for a very loose bound
+ for (i=0 ; i<numportals*2 ; i++)
+ {
+ portals[i].portalvis = portals[i].portalflood;
+ portals[i].status = stat_done;
+ }
+}
+
+/*
+==================
+CalcVis
+==================
+*/
+void CalcVis (void)
+{
+ int i;
+
+ RunThreadsOnIndividual (numportals*2, qtrue, BasePortalVis);
+
+// RunThreadsOnIndividual (numportals*2, qtrue, BetterPortalVis);
+
+ SortPortals ();
+
+ if (fastvis) {
+ CalcFastVis();
+ }
+ else if ( noPassageVis ) {
+ CalcPortalVis();
+ }
+ else if ( passageVisOnly ) {
+ CalcPassageVis();
+ }
+ else {
+ CalcPassagePortalVis();
+ }
+ //
+ // assemble the leaf vis lists by oring and compressing the portal lists
+ //
+ _printf("creating leaf vis...\n");
+ for (i=0 ; i<portalclusters ; i++)
+ ClusterMerge (i);
+
+ _printf( "Total visible clusters: %i\n", totalvis );
+ _printf( "Average clusters visible: %i\n", totalvis / portalclusters );
+}
+
+/*
+==================
+SetPortalSphere
+==================
+*/
+void SetPortalSphere (vportal_t *p)
+{
+ int i;
+ vec3_t total, dist;
+ winding_t *w;
+ float r, bestr;
+
+ w = p->winding;
+ VectorCopy (vec3_origin, total);
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ VectorAdd (total, w->points[i], total);
+ }
+
+ for (i=0 ; i<3 ; i++)
+ total[i] /= w->numpoints;
+
+ bestr = 0;
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ VectorSubtract (w->points[i], total, dist);
+ r = VectorLength (dist);
+ if (r > bestr)
+ bestr = r;
+ }
+ VectorCopy (total, p->origin);
+ p->radius = bestr;
+}
+
+/*
+=============
+Winding_PlanesConcave
+=============
+*/
+#define WCONVEX_EPSILON 0.2
+
+int Winding_PlanesConcave(winding_t *w1, winding_t *w2,
+ vec3_t normal1, vec3_t normal2,
+ float dist1, float dist2)
+{
+ int i;
+
+ if (!w1 || !w2) return qfalse;
+
+ // check if one of the points of winding 1 is at the front of the plane of winding 2
+ for (i = 0; i < w1->numpoints; i++)
+ {
+ if (DotProduct(normal2, w1->points[i]) - dist2 > WCONVEX_EPSILON) return qtrue;
+ }
+ // check if one of the points of winding 2 is at the front of the plane of winding 1
+ for (i = 0; i < w2->numpoints; i++)
+ {
+ if (DotProduct(normal1, w2->points[i]) - dist1 > WCONVEX_EPSILON) return qtrue;
+ }
+
+ return qfalse;
+}
+
+/*
+============
+TryMergeLeaves
+============
+*/
+int TryMergeLeaves(int l1num, int l2num)
+{
+ int i, j, k, n, numportals;
+ plane_t plane1, plane2;
+ leaf_t *l1, *l2;
+ vportal_t *p1, *p2;
+ vportal_t *portals[MAX_PORTALS_ON_LEAF];
+
+ for (k = 0; k < 2; k++)
+ {
+ if (k) l1 = &leafs[l1num];
+ else l1 = &faceleafs[l1num];
+ for (i = 0; i < l1->numportals; i++)
+ {
+ p1 = l1->portals[i];
+ if (p1->leaf == l2num) continue;
+ for (n = 0; n < 2; n++)
+ {
+ if (n) l2 = &leafs[l2num];
+ else l2 = &faceleafs[l2num];
+ for (j = 0; j < l2->numportals; j++)
+ {
+ p2 = l2->portals[j];
+ if (p2->leaf == l1num) continue;
+ //
+ plane1 = p1->plane;
+ plane2 = p2->plane;
+ if (Winding_PlanesConcave(p1->winding, p2->winding, plane1.normal, plane2.normal, plane1.dist, plane2.dist))
+ return qfalse;
+ }
+ }
+ }
+ }
+ for (k = 0; k < 2; k++)
+ {
+ if (k)
+ {
+ l1 = &leafs[l1num];
+ l2 = &leafs[l2num];
+ }
+ else
+ {
+ l1 = &faceleafs[l1num];
+ l2 = &faceleafs[l2num];
+ }
+ numportals = 0;
+ //the leaves can be merged now
+ for (i = 0; i < l1->numportals; i++)
+ {
+ p1 = l1->portals[i];
+ if (p1->leaf == l2num)
+ {
+ p1->removed = qtrue;
+ continue;
+ }
+ portals[numportals++] = p1;
+ }
+ for (j = 0; j < l2->numportals; j++)
+ {
+ p2 = l2->portals[j];
+ if (p2->leaf == l1num)
+ {
+ p2->removed = qtrue;
+ continue;
+ }
+ portals[numportals++] = p2;
+ }
+ for (i = 0; i < numportals; i++)
+ {
+ l2->portals[i] = portals[i];
+ }
+ l2->numportals = numportals;
+ l1->merged = l2num;
+ }
+ return qtrue;
+}
+
+/*
+============
+UpdatePortals
+============
+*/
+void UpdatePortals(void)
+{
+ int i;
+ vportal_t *p;
+
+ for (i = 0; i < numportals * 2; i++)
+ {
+ p = &portals[i];
+ if (p->removed)
+ continue;
+ while(leafs[p->leaf].merged >= 0)
+ p->leaf = leafs[p->leaf].merged;
+ }
+}
+
+/*
+============
+MergeLeaves
+
+try to merge leaves but don't merge through hint splitters
+============
+*/
+void MergeLeaves(void)
+{
+ int i, j, nummerges, totalnummerges;
+ leaf_t *leaf;
+ vportal_t *p;
+
+ totalnummerges = 0;
+ do
+ {
+ nummerges = 0;
+ for (i = 0; i < portalclusters; i++)
+ {
+ leaf = &leafs[i];
+ //if this leaf is merged already
+ if (leaf->merged >= 0)
+ continue;
+ //
+ for (j = 0; j < leaf->numportals; j++)
+ {
+ p = leaf->portals[j];
+ //
+ if (p->removed)
+ continue;
+ //never merge through hint portals
+ if (p->hint)
+ continue;
+ if (TryMergeLeaves(i, p->leaf))
+ {
+ UpdatePortals();
+ nummerges++;
+ break;
+ }
+ }
+ }
+ totalnummerges += nummerges;
+ } while (nummerges);
+ _printf("%6d leaves merged\n", totalnummerges);
+}
+
+/*
+============
+TryMergeWinding
+============
+*/
+#define CONTINUOUS_EPSILON 0.005
+
+winding_t *TryMergeWinding (winding_t *f1, winding_t *f2, vec3_t planenormal)
+{
+ vec_t *p1, *p2, *p3, *p4, *back;
+ winding_t *newf;
+ int i, j, k, l;
+ vec3_t normal, delta;
+ vec_t dot;
+ qboolean keep1, keep2;
+
+
+ //
+ // find a common edge
+ //
+ p1 = p2 = NULL; // stop compiler warning
+ j = 0; //
+
+ for (i = 0; i < f1->numpoints; i++)
+ {
+ p1 = f1->points[i];
+ p2 = f1->points[(i+1) % f1->numpoints];
+ for (j = 0; j < f2->numpoints; j++)
+ {
+ p3 = f2->points[j];
+ p4 = f2->points[(j+1) % f2->numpoints];
+ for (k = 0; k < 3; k++)
+ {
+ if (fabs(p1[k] - p4[k]) > 0.1)//EQUAL_EPSILON) //ME
+ break;
+ if (fabs(p2[k] - p3[k]) > 0.1)//EQUAL_EPSILON) //ME
+ break;
+ } //end for
+ if (k==3)
+ break;
+ } //end for
+ if (j < f2->numpoints)
+ break;
+ } //end for
+
+ if (i == f1->numpoints)
+ return NULL; // no matching edges
+
+ //
+ // check slope of connected lines
+ // if the slopes are colinear, the point can be removed
+ //
+ back = f1->points[(i+f1->numpoints-1)%f1->numpoints];
+ VectorSubtract (p1, back, delta);
+ CrossProduct (planenormal, delta, normal);
+ VectorNormalize (normal, normal);
+
+ back = f2->points[(j+2)%f2->numpoints];
+ VectorSubtract (back, p1, delta);
+ dot = DotProduct (delta, normal);
+ if (dot > CONTINUOUS_EPSILON)
+ return NULL; // not a convex polygon
+ keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON);
+
+ back = f1->points[(i+2)%f1->numpoints];
+ VectorSubtract (back, p2, delta);
+ CrossProduct (planenormal, delta, normal);
+ VectorNormalize (normal, normal);
+
+ back = f2->points[(j+f2->numpoints-1)%f2->numpoints];
+ VectorSubtract (back, p2, delta);
+ dot = DotProduct (delta, normal);
+ if (dot > CONTINUOUS_EPSILON)
+ return NULL; // not a convex polygon
+ keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON);
+
+ //
+ // build the new polygon
+ //
+ newf = NewWinding (f1->numpoints + f2->numpoints);
+
+ // copy first polygon
+ for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints)
+ {
+ if (k==(i+1)%f1->numpoints && !keep2)
+ continue;
+
+ VectorCopy (f1->points[k], newf->points[newf->numpoints]);
+ newf->numpoints++;
+ }
+
+ // copy second polygon
+ for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints)
+ {
+ if (l==(j+1)%f2->numpoints && !keep1)
+ continue;
+ VectorCopy (f2->points[l], newf->points[newf->numpoints]);
+ newf->numpoints++;
+ }
+
+ return newf;
+}
+
+/*
+============
+MergeLeafPortals
+============
+*/
+void MergeLeafPortals(void)
+{
+ int i, j, k, nummerges, hintsmerged;
+ leaf_t *leaf;
+ vportal_t *p1, *p2;
+ winding_t *w;
+
+ nummerges = 0;
+ hintsmerged = 0;
+ for (i = 0; i < portalclusters; i++)
+ {
+ leaf = &leafs[i];
+ if (leaf->merged >= 0) continue;
+ for (j = 0; j < leaf->numportals; j++)
+ {
+ p1 = leaf->portals[j];
+ if (p1->removed)
+ continue;
+ for (k = j+1; k < leaf->numportals; k++)
+ {
+ p2 = leaf->portals[k];
+ if (p2->removed)
+ continue;
+ if (p1->leaf == p2->leaf)
+ {
+ w = TryMergeWinding(p1->winding, p2->winding, p1->plane.normal);
+ if (w)
+ {
+ FreeWinding(p1->winding);
+ p1->winding = w;
+ if (p1->hint && p2->hint)
+ hintsmerged++;
+ p1->hint |= p2->hint;
+ SetPortalSphere(p1);
+ p2->removed = qtrue;
+ nummerges++;
+ i--;
+ break;
+ }
+ }
+ }
+ if (k < leaf->numportals)
+ break;
+ }
+ }
+ _printf("%6d portals merged\n", nummerges);
+ _printf("%6d hint portals merged\n", hintsmerged);
+}
+
+
+/*
+============
+WritePortals
+============
+*/
+int CountActivePortals(void)
+{
+ int num, hints, j;
+ vportal_t *p;
+
+ num = 0;
+ hints = 0;
+ for (j = 0; j < numportals * 2; j++)
+ {
+ p = portals + j;
+ if (p->removed)
+ continue;
+ if (p->hint)
+ hints++;
+ num++;
+ }
+ _printf("%6d active portals\n", num);
+ _printf("%6d hint portals\n", hints);
+ return num;
+}
+
+/*
+============
+WritePortals
+============
+*/
+void WriteFloat (FILE *f, vec_t v);
+
+void WritePortals(char *filename)
+{
+ int i, j, num;
+ FILE *pf;
+ vportal_t *p;
+ winding_t *w;
+
+ // write the file
+ pf = fopen (filename, "w");
+ if (!pf)
+ Error ("Error opening %s", filename);
+
+ num = 0;
+ for (j = 0; j < numportals * 2; j++)
+ {
+ p = portals + j;
+ if (p->removed)
+ continue;
+// if (!p->hint)
+// continue;
+ num++;
+ }
+
+ fprintf (pf, "%s\n", PORTALFILE);
+ fprintf (pf, "%i\n", 0);
+ fprintf (pf, "%i\n", num);// + numfaces);
+ fprintf (pf, "%i\n", 0);
+
+ for (j = 0; j < numportals * 2; j++)
+ {
+ p = portals + j;
+ if (p->removed)
+ continue;
+// if (!p->hint)
+// continue;
+ w = p->winding;
+ fprintf (pf,"%i %i %i ",w->numpoints, 0, 0);
+ fprintf (pf, "%d ", p->hint);
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ fprintf (pf,"(");
+ WriteFloat (pf, w->points[i][0]);
+ WriteFloat (pf, w->points[i][1]);
+ WriteFloat (pf, w->points[i][2]);
+ fprintf (pf,") ");
+ }
+ fprintf (pf,"\n");
+ }
+
+ /*
+ for (j = 0; j < numfaces; j++)
+ {
+ p = faces + j;
+ w = p->winding;
+ fprintf (pf,"%i %i %i ",w->numpoints, 0, 0);
+ fprintf (pf, "0 ");
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ fprintf (pf,"(");
+ WriteFloat (pf, w->points[i][0]);
+ WriteFloat (pf, w->points[i][1]);
+ WriteFloat (pf, w->points[i][2]);
+ fprintf (pf,") ");
+ }
+ fprintf (pf,"\n");
+ }*/
+
+ fclose (pf);
+}
+
+/*
+============
+LoadPortals
+============
+*/
+void LoadPortals (char *name)
+{
+ int i, j, hint;
+ vportal_t *p;
+ leaf_t *l;
+ char magic[80];
+ FILE *f;
+ int numpoints;
+ winding_t *w;
+ int leafnums[2];
+ plane_t plane;
+
+ if (!strcmp(name,"-"))
+ f = stdin;
+ else
+ {
+ f = fopen(name, "r");
+ if (!f)
+ Error ("LoadPortals: couldn't read %s\n",name);
+ }
+
+ if (fscanf (f,"%79s\n%i\n%i\n%i\n",magic, &portalclusters, &numportals, &numfaces) != 4)
+ Error ("LoadPortals: failed to read header");
+ if (strcmp(magic,PORTALFILE))
+ Error ("LoadPortals: not a portal file");
+
+ _printf ("%6i portalclusters\n", portalclusters);
+ _printf ("%6i numportals\n", numportals);
+ _printf ("%6i numfaces\n", numfaces);
+
+ // these counts should take advantage of 64 bit systems automatically
+ leafbytes = ((portalclusters+63)&~63)>>3;
+ leaflongs = leafbytes/sizeof(long);
+
+ portalbytes = ((numportals*2+63)&~63)>>3;
+ portallongs = portalbytes/sizeof(long);
+
+ // each file portal is split into two memory portals
+ portals = malloc(2*numportals*sizeof(vportal_t));
+ memset (portals, 0, 2*numportals*sizeof(vportal_t));
+
+ leafs = malloc(portalclusters*sizeof(leaf_t));
+ memset (leafs, 0, portalclusters*sizeof(leaf_t));
+
+ for (i = 0; i < portalclusters; i++)
+ leafs[i].merged = -1;
+
+ numVisBytes = VIS_HEADER_SIZE + portalclusters*leafbytes;
+
+ ((int *)visBytes)[0] = portalclusters;
+ ((int *)visBytes)[1] = leafbytes;
+
+ for (i=0, p=portals ; i<numportals ; i++)
+ {
+ if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) != 3)
+ Error ("LoadPortals: reading portal %i", i);
+ if (numpoints > MAX_POINTS_ON_WINDING)
+ Error ("LoadPortals: portal %i has too many points", i);
+ if ( (unsigned)leafnums[0] > portalclusters
+ || (unsigned)leafnums[1] > portalclusters)
+ Error ("LoadPortals: reading portal %i", i);
+ if (fscanf (f, "%i ", &hint) != 1)
+ Error ("LoadPortals: reading hint state");
+
+ w = p->winding = NewWinding (numpoints);
+ w->numpoints = numpoints;
+
+ for (j=0 ; j<numpoints ; j++)
+ {
+ double v[3];
+ int k;
+
+ // scanf into double, then assign to vec_t
+ // so we don't care what size vec_t is
+ if (fscanf (f, "(%lf %lf %lf ) "
+ , &v[0], &v[1], &v[2]) != 3)
+ Error ("LoadPortals: reading portal %i", i);
+ for (k=0 ; k<3 ; k++)
+ w->points[j][k] = v[k];
+ }
+ fscanf (f, "\n");
+
+ // calc plane
+ PlaneFromWinding (w, &plane);
+
+ // create forward portal
+ l = &leafs[leafnums[0]];
+ if (l->numportals == MAX_PORTALS_ON_LEAF)
+ Error ("Leaf with too many portals");
+ l->portals[l->numportals] = p;
+ l->numportals++;
+
+ p->num = i+1;
+ p->hint = hint;
+ p->winding = w;
+ VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
+ p->plane.dist = -plane.dist;
+ p->leaf = leafnums[1];
+ SetPortalSphere (p);
+ p++;
+
+ // create backwards portal
+ l = &leafs[leafnums[1]];
+ if (l->numportals == MAX_PORTALS_ON_LEAF)
+ Error ("Leaf with too many portals");
+ l->portals[l->numportals] = p;
+ l->numportals++;
+
+ p->num = i+1;
+ p->hint = hint;
+ p->winding = NewWinding(w->numpoints);
+ p->winding->numpoints = w->numpoints;
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]);
+ }
+
+ p->plane = plane;
+ p->leaf = leafnums[0];
+ SetPortalSphere (p);
+ p++;
+
+ }
+
+ faces = malloc(2*numfaces*sizeof(vportal_t));
+ memset (faces, 0, 2*numfaces*sizeof(vportal_t));
+
+ faceleafs = malloc(portalclusters*sizeof(leaf_t));
+ memset(faceleafs, 0, portalclusters*sizeof(leaf_t));
+
+ for (i = 0, p = faces; i < numfaces; i++)
+ {
+ if (fscanf (f, "%i %i ", &numpoints, &leafnums[0]) != 2)
+ Error ("LoadPortals: reading portal %i", i);
+
+ w = p->winding = NewWinding (numpoints);
+ w->numpoints = numpoints;
+
+ for (j=0 ; j<numpoints ; j++)
+ {
+ double v[3];
+ int k;
+
+ // scanf into double, then assign to vec_t
+ // so we don't care what size vec_t is
+ if (fscanf (f, "(%lf %lf %lf ) "
+ , &v[0], &v[1], &v[2]) != 3)
+ Error ("LoadPortals: reading portal %i", i);
+ for (k=0 ; k<3 ; k++)
+ w->points[j][k] = v[k];
+ }
+ fscanf (f, "\n");
+
+ // calc plane
+ PlaneFromWinding (w, &plane);
+
+ l = &faceleafs[leafnums[0]];
+ l->merged = -1;
+ if (l->numportals == MAX_PORTALS_ON_LEAF)
+ Error ("Leaf with too many faces");
+ l->portals[l->numportals] = p;
+ l->numportals++;
+
+ p->num = i+1;
+ p->winding = w;
+ // normal pointing out of the leaf
+ VectorSubtract (vec3_origin, plane.normal, p->plane.normal);
+ p->plane.dist = -plane.dist;
+ p->leaf = -1;
+ SetPortalSphere (p);
+ p++;
+ }
+
+ fclose (f);
+}
+
+
+/*
+================
+CalcPHS
+
+Calculate the PHS (Potentially Hearable Set)
+by ORing together all the PVS visible from a leaf
+================
+*/
+void CalcPHS (void)
+{
+ int i, j, k, l, index;
+ int bitbyte;
+ long *dest, *src;
+ byte *scan;
+ int count;
+ byte uncompressed[MAX_MAP_LEAFS/8];
+
+ _printf ("Building PHS...\n");
+
+ count = 0;
+ for (i=0 ; i<portalclusters ; i++)
+ {
+ scan = visBytes + i*leafbytes;
+ memcpy (uncompressed, scan, leafbytes);
+ for (j=0 ; j<leafbytes ; j++)
+ {
+ bitbyte = scan[j];
+ if (!bitbyte)
+ continue;
+ for (k=0 ; k<8 ; k++)
+ {
+ if (! (bitbyte & (1<<k)) )
+ continue;
+ // OR this pvs row into the phs
+ index = ((j<<3)+k);
+ if (index >= portalclusters)
+ Error ("Bad bit in PVS"); // pad bits should be 0
+ src = (long *)(visBytes + index*leafbytes);
+ dest = (long *)uncompressed;
+ for (l=0 ; l<leaflongs ; l++)
+ ((long *)uncompressed)[l] |= src[l];
+ }
+ }
+ for (j=0 ; j<portalclusters ; j++)
+ if (uncompressed[j>>3] & (1<<(j&7)) )
+ count++;
+
+ // FIXME: copy it off
+ }
+
+ _printf ("Average clusters hearable: %i\n", count/portalclusters);
+}
+
+/*
+===========
+VisMain
+===========
+*/
+int VisMain (int argc, char **argv)
+{
+ char portalfile[1024];
+ char name[1024];
+ int i;
+ double start, end;
+
+ _printf ("---- vis ----\n");
+
+ verbose = qfalse;
+ for (i=1 ; i<argc ; i++) {
+ if (!strcmp(argv[i],"-threads")) {
+ numthreads = atoi (argv[i+1]);
+ i++;
+ } else if (!strcmp(argv[i],"-threads")) {
+ numthreads = atoi (argv[i+1]);
+ i++;
+ } else if (!strcmp(argv[i], "-fast")) {
+ _printf ("fastvis = true\n");
+ fastvis = qtrue;
+ } else if (!strcmp(argv[i], "-merge")) {
+ _printf ("merge = true\n");
+ mergevis = qtrue;
+ } else if (!strcmp(argv[i], "-nopassage")) {
+ _printf ("nopassage = true\n");
+ noPassageVis = qtrue;
+ } else if (!strcmp(argv[i], "-passageOnly")) {
+ _printf("passageOnly = true\n");
+ passageVisOnly = qtrue;
+ } else if (!strcmp(argv[i], "-level")) {
+ testlevel = atoi(argv[i+1]);
+ _printf ("testlevel = %i\n", testlevel);
+ i++;
+ } else if (!strcmp(argv[i], "-v")) {
+ _printf ("verbose = true\n");
+ verbose = qtrue;
+ } else if (!strcmp (argv[i],"-nosort")) {
+ _printf ("nosort = true\n");
+ nosort = qtrue;
+ } else if (!strcmp (argv[i],"-saveprt")) {
+ _printf ("saveprt = true\n");
+ saveprt = qtrue;
+ } else if (!strcmp (argv[i],"-tmpin")) {
+ strcpy (inbase, "/tmp");
+ } else if (!strcmp (argv[i],"-tmpout")) {
+ strcpy (outbase, "/tmp");
+ } else if (argv[i][0] == '-') {
+ Error ("Unknown option \"%s\"", argv[i]);
+ } else {
+ break;
+ }
+ }
+
+ if (i != argc - 1)
+ Error ("usage: vis [-threads #] [-level 0-4] [-fast] [-v] bspfile");
+
+#ifdef MREDEBUG
+ start = clock();
+#else
+ start = I_FloatTime ();
+#endif
+
+ ThreadSetDefault ();
+
+ SetQdirFromPath (argv[i]);
+
+#ifdef _WIN32
+ InitPakFile(gamedir, NULL);
+#endif
+
+ // load the bsp
+ sprintf (name, "%s%s", inbase, ExpandArg(argv[i]));
+ StripExtension (name);
+ strcat (name, ".bsp");
+ _printf ("reading %s\n", name);
+ LoadBSPFile (name);
+
+ // load the portal file
+ sprintf (portalfile, "%s%s", inbase, ExpandArg(argv[i]));
+ StripExtension (portalfile);
+ strcat (portalfile, ".prt");
+ _printf ("reading %s\n", portalfile);
+ LoadPortals (portalfile);
+
+ if (mergevis)
+ {
+ MergeLeaves();
+ MergeLeafPortals();
+ }
+
+ CountActivePortals();
+// WritePortals("maps/hints.prs");
+
+ _printf ("visdatasize:%i\n", numVisBytes);
+
+ CalcVis ();
+
+// CalcPHS ();
+
+ // delete the prt file
+ if ( !saveprt ) {
+ remove( portalfile );
+ }
+
+ // write the bsp file
+ _printf ("writing %s\n", name);
+ WriteBSPFile (name);
+
+#ifdef MREDEBUG
+ end = clock();
+ _printf ("%5.2f seconds elapsed\n", (end-start) / CLK_TCK);
+#else
+ end = I_FloatTime ();
+ _printf ("%5.2f seconds elapsed\n", end-start);
+#endif
+ return 0;
+}
+
diff --git a/q3map/vis.h b/q3map/vis.h
index e607184..8eed728 100755
--- a/q3map/vis.h
+++ b/q3map/vis.h
@@ -19,144 +19,144 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-// vis.h
-
-#include "cmdlib.h"
-#include "mathlib.h"
-#include "bspfile.h"
-
-#define MAX_PORTALS 32768
-
-#define PORTALFILE "PRT1"
-
-#define ON_EPSILON 0.1
-
-//#define MREDEBUG
-
-// seperator caching helps a bit
-#define SEPERATORCACHE
-
-// can't have more seperators than the max number of points on a winding
-#define MAX_SEPERATORS 64
-
-typedef struct
-{
- vec3_t normal;
- float dist;
-} plane_t;
-
-#define MAX_POINTS_ON_WINDING 64
-#define MAX_POINTS_ON_FIXED_WINDING 12
-
-typedef struct
-{
- int numpoints;
- vec3_t points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized
-} winding_t;
-
-winding_t *NewWinding (int points);
-void FreeWinding (winding_t *w);
-winding_t *CopyWinding (winding_t *w);
-
-
-typedef struct passage_s
-{
- struct passage_s *next;
- byte cansee[1]; //all portals that can be seen through this passage
-} passage_t;
-
-typedef enum {stat_none, stat_working, stat_done} vstatus_t;
-typedef struct
-{
- int num;
- qboolean hint; // true if this portal was created from a hint splitter
- qboolean removed;
- plane_t plane; // normal pointing into neighbor
- int leaf; // neighbor
-
- vec3_t origin; // for fast clip testing
- float radius;
-
- winding_t *winding;
- vstatus_t status;
- byte *portalfront; // [portals], preliminary
- byte *portalflood; // [portals], intermediate
- byte *portalvis; // [portals], final
-
- int nummightsee; // bit count on portalflood for sort
- passage_t *passages; // there are just as many passages as there
- // are portals in the leaf this portal leads to
-} vportal_t;
-
-#define MAX_PORTALS_ON_LEAF 128
-typedef struct leaf_s
-{
- int numportals;
- int merged;
- vportal_t *portals[MAX_PORTALS_ON_LEAF];
-} leaf_t;
-
-
-typedef struct pstack_s
-{
- byte mightsee[MAX_PORTALS/8]; // bit string
- struct pstack_s *next;
- leaf_t *leaf;
- vportal_t *portal; // portal exiting
- winding_t *source;
- winding_t *pass;
-
- winding_t windings[3]; // source, pass, temp in any order
- int freewindings[3];
-
- plane_t portalplane;
- int depth;
-#ifdef SEPERATORCACHE
- plane_t seperators[2][MAX_SEPERATORS];
- int numseperators[2];
-#endif
-} pstack_t;
-
-typedef struct
-{
- vportal_t *base;
- int c_chains;
- pstack_t pstack_head;
-} threaddata_t;
-
-
-
-extern int numportals;
-extern int portalclusters;
-
-extern vportal_t *portals;
-extern leaf_t *leafs;
-
-extern int c_portaltest, c_portalpass, c_portalcheck;
-extern int c_portalskip, c_leafskip;
-extern int c_vistest, c_mighttest;
-extern int c_chains;
-
-extern byte *vismap, *vismap_p, *vismap_end; // past visfile
-
-extern int testlevel;
-
-extern byte *uncompressed;
-
-extern int leafbytes, leaflongs;
-extern int portalbytes, portallongs;
-
-
-void LeafFlow (int leafnum);
-
-
-void BasePortalVis(int portalnum);
-void BetterPortalVis(int portalnum);
-void PortalFlow(int portalnum);
-void PassagePortalFlow(int portalnum);
-void CreatePassages(int portalnum);
-void PassageFlow(int portalnum);
-
-extern vportal_t *sorted_portals[MAX_MAP_PORTALS*2];
-
-int CountBits (byte *bits, int numbits);
+// vis.h
+
+#include "cmdlib.h"
+#include "mathlib.h"
+#include "bspfile.h"
+
+#define MAX_PORTALS 32768
+
+#define PORTALFILE "PRT1"
+
+#define ON_EPSILON 0.1
+
+//#define MREDEBUG
+
+// seperator caching helps a bit
+#define SEPERATORCACHE
+
+// can't have more seperators than the max number of points on a winding
+#define MAX_SEPERATORS 64
+
+typedef struct
+{
+ vec3_t normal;
+ float dist;
+} plane_t;
+
+#define MAX_POINTS_ON_WINDING 64
+#define MAX_POINTS_ON_FIXED_WINDING 12
+
+typedef struct
+{
+ int numpoints;
+ vec3_t points[MAX_POINTS_ON_FIXED_WINDING]; // variable sized
+} winding_t;
+
+winding_t *NewWinding (int points);
+void FreeWinding (winding_t *w);
+winding_t *CopyWinding (winding_t *w);
+
+
+typedef struct passage_s
+{
+ struct passage_s *next;
+ byte cansee[1]; //all portals that can be seen through this passage
+} passage_t;
+
+typedef enum {stat_none, stat_working, stat_done} vstatus_t;
+typedef struct
+{
+ int num;
+ qboolean hint; // true if this portal was created from a hint splitter
+ qboolean removed;
+ plane_t plane; // normal pointing into neighbor
+ int leaf; // neighbor
+
+ vec3_t origin; // for fast clip testing
+ float radius;
+
+ winding_t *winding;
+ vstatus_t status;
+ byte *portalfront; // [portals], preliminary
+ byte *portalflood; // [portals], intermediate
+ byte *portalvis; // [portals], final
+
+ int nummightsee; // bit count on portalflood for sort
+ passage_t *passages; // there are just as many passages as there
+ // are portals in the leaf this portal leads to
+} vportal_t;
+
+#define MAX_PORTALS_ON_LEAF 128
+typedef struct leaf_s
+{
+ int numportals;
+ int merged;
+ vportal_t *portals[MAX_PORTALS_ON_LEAF];
+} leaf_t;
+
+
+typedef struct pstack_s
+{
+ byte mightsee[MAX_PORTALS/8]; // bit string
+ struct pstack_s *next;
+ leaf_t *leaf;
+ vportal_t *portal; // portal exiting
+ winding_t *source;
+ winding_t *pass;
+
+ winding_t windings[3]; // source, pass, temp in any order
+ int freewindings[3];
+
+ plane_t portalplane;
+ int depth;
+#ifdef SEPERATORCACHE
+ plane_t seperators[2][MAX_SEPERATORS];
+ int numseperators[2];
+#endif
+} pstack_t;
+
+typedef struct
+{
+ vportal_t *base;
+ int c_chains;
+ pstack_t pstack_head;
+} threaddata_t;
+
+
+
+extern int numportals;
+extern int portalclusters;
+
+extern vportal_t *portals;
+extern leaf_t *leafs;
+
+extern int c_portaltest, c_portalpass, c_portalcheck;
+extern int c_portalskip, c_leafskip;
+extern int c_vistest, c_mighttest;
+extern int c_chains;
+
+extern byte *vismap, *vismap_p, *vismap_end; // past visfile
+
+extern int testlevel;
+
+extern byte *uncompressed;
+
+extern int leafbytes, leaflongs;
+extern int portalbytes, portallongs;
+
+
+void LeafFlow (int leafnum);
+
+
+void BasePortalVis(int portalnum);
+void BetterPortalVis(int portalnum);
+void PortalFlow(int portalnum);
+void PassagePortalFlow(int portalnum);
+void CreatePassages(int portalnum);
+void PassageFlow(int portalnum);
+
+extern vportal_t *sorted_portals[MAX_MAP_PORTALS*2];
+
+int CountBits (byte *bits, int numbits);
diff --git a/q3map/visflow.c b/q3map/visflow.c
index c62a33b..5948b08 100755
--- a/q3map/visflow.c
+++ b/q3map/visflow.c
@@ -19,1639 +19,1639 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-#include "vis.h"
-
-/*
-
- each portal will have a list of all possible to see from first portal
-
- if (!thread->portalmightsee[portalnum])
-
- portal mightsee
-
- for p2 = all other portals in leaf
- get sperating planes
- for all portals that might be seen by p2
- mark as unseen if not present in seperating plane
- flood fill a new mightsee
- save as passagemightsee
-
-
- void CalcMightSee (leaf_t *leaf,
-*/
-
-int CountBits (byte *bits, int numbits)
-{
- int i;
- int c;
-
- c = 0;
- for (i=0 ; i<numbits ; i++)
- if (bits[i>>3] & (1<<(i&7)) )
- c++;
-
- return c;
-}
-
-int c_fullskip;
-int c_portalskip, c_leafskip;
-int c_vistest, c_mighttest;
-
-int c_chop, c_nochop;
-
-int active;
-
-void CheckStack (leaf_t *leaf, threaddata_t *thread)
-{
- pstack_t *p, *p2;
-
- for (p=thread->pstack_head.next ; p ; p=p->next)
- {
-// _printf ("=");
- if (p->leaf == leaf)
- Error ("CheckStack: leaf recursion");
- for (p2=thread->pstack_head.next ; p2 != p ; p2=p2->next)
- if (p2->leaf == p->leaf)
- Error ("CheckStack: late leaf recursion");
- }
-// _printf ("\n");
-}
-
-
-winding_t *AllocStackWinding (pstack_t *stack)
-{
- int i;
-
- for (i=0 ; i<3 ; i++)
- {
- if (stack->freewindings[i])
- {
- stack->freewindings[i] = 0;
- return &stack->windings[i];
- }
- }
-
- Error ("AllocStackWinding: failed");
-
- return NULL;
-}
-
-void FreeStackWinding (winding_t *w, pstack_t *stack)
-{
- int i;
-
- i = w - stack->windings;
-
- if (i<0 || i>2)
- return; // not from local
-
- if (stack->freewindings[i])
- Error ("FreeStackWinding: allready free");
- stack->freewindings[i] = 1;
-}
-
-/*
-==============
-VisChopWinding
-
-==============
-*/
-winding_t *VisChopWinding (winding_t *in, pstack_t *stack, plane_t *split)
-{
- vec_t dists[128];
- int sides[128];
- int counts[3];
- vec_t dot;
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- winding_t *neww;
-
- counts[0] = counts[1] = counts[2] = 0;
-
- // determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > ON_EPSILON)
- sides[i] = SIDE_FRONT;
- else if (dot < -ON_EPSILON)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
-
- if (!counts[1])
- return in; // completely on front side
-
- if (!counts[0])
- {
- FreeStackWinding (in, stack);
- return NULL;
- }
-
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- neww = AllocStackWinding (stack);
-
- neww->numpoints = 0;
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->points[i];
-
- if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
- {
- FreeStackWinding (neww, stack);
- return in; // can't chop -- fall back to original
- }
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
- {
- FreeStackWinding (neww, stack);
- return in; // can't chop -- fall back to original
- }
-
- // generate a split point
- p2 = in->points[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
-
- // free the original winding
- FreeStackWinding (in, stack);
-
- return neww;
-}
-
-/*
-==============
-ClipToSeperators
-
-Source, pass, and target are an ordering of portals.
-
-Generates seperating planes canidates by taking two points from source and one
-point from pass, and clips target by them.
-
-If target is totally clipped away, that portal can not be seen through.
-
-Normal clip keeps target on the same side as pass, which is correct if the
-order goes source, pass, target. If the order goes pass, source, target then
-flipclip should be set.
-==============
-*/
-winding_t *ClipToSeperators (winding_t *source, winding_t *pass, winding_t *target, qboolean flipclip, pstack_t *stack)
-{
- int i, j, k, l;
- plane_t plane;
- vec3_t v1, v2;
- float d;
- vec_t length;
- int counts[3];
- qboolean fliptest;
-
- // check all combinations
- for (i=0 ; i<source->numpoints ; i++)
- {
- l = (i+1)%source->numpoints;
- VectorSubtract (source->points[l] , source->points[i], v1);
-
- // find a vertex of pass that makes a plane that puts all of the
- // vertexes of pass on the front side and all of the vertexes of
- // source on the back side
- for (j=0 ; j<pass->numpoints ; j++)
- {
- VectorSubtract (pass->points[j], source->points[i], v2);
-
- plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
- plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
- plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
-
- // if points don't make a valid plane, skip it
-
- length = plane.normal[0] * plane.normal[0]
- + plane.normal[1] * plane.normal[1]
- + plane.normal[2] * plane.normal[2];
-
- if (length < ON_EPSILON)
- continue;
-
- length = 1/sqrt(length);
-
- plane.normal[0] *= length;
- plane.normal[1] *= length;
- plane.normal[2] *= length;
-
- plane.dist = DotProduct (pass->points[j], plane.normal);
-
- //
- // find out which side of the generated seperating plane has the
- // source portal
- //
-#if 1
- fliptest = qfalse;
- for (k=0 ; k<source->numpoints ; k++)
- {
- if (k == i || k == l)
- continue;
- d = DotProduct (source->points[k], plane.normal) - plane.dist;
- if (d < -ON_EPSILON)
- { // source is on the negative side, so we want all
- // pass and target on the positive side
- fliptest = qfalse;
- break;
- }
- else if (d > ON_EPSILON)
- { // source is on the positive side, so we want all
- // pass and target on the negative side
- fliptest = qtrue;
- break;
- }
- }
- if (k == source->numpoints)
- continue; // planar with source portal
-#else
- fliptest = flipclip;
-#endif
- //
- // flip the normal if the source portal is backwards
- //
- if (fliptest)
- {
- VectorSubtract (vec3_origin, plane.normal, plane.normal);
- plane.dist = -plane.dist;
- }
-#if 1
- //
- // if all of the pass portal points are now on the positive side,
- // this is the seperating plane
- //
- counts[0] = counts[1] = counts[2] = 0;
- for (k=0 ; k<pass->numpoints ; k++)
- {
- if (k==j)
- continue;
- d = DotProduct (pass->points[k], plane.normal) - plane.dist;
- if (d < -ON_EPSILON)
- break;
- else if (d > ON_EPSILON)
- counts[0]++;
- else
- counts[2]++;
- }
- if (k != pass->numpoints)
- continue; // points on negative side, not a seperating plane
-
- if (!counts[0])
- continue; // planar with seperating plane
-#else
- k = (j+1)%pass->numpoints;
- d = DotProduct (pass->points[k], plane.normal) - plane.dist;
- if (d < -ON_EPSILON)
- continue;
- k = (j+pass->numpoints-1)%pass->numpoints;
- d = DotProduct (pass->points[k], plane.normal) - plane.dist;
- if (d < -ON_EPSILON)
- continue;
-#endif
- //
- // flip the normal if we want the back side
- //
- if (flipclip)
- {
- VectorSubtract (vec3_origin, plane.normal, plane.normal);
- plane.dist = -plane.dist;
- }
-
-#ifdef SEPERATORCACHE
- stack->seperators[flipclip][stack->numseperators[flipclip]] = plane;
- if (++stack->numseperators[flipclip] >= MAX_SEPERATORS)
- Error("MAX_SEPERATORS");
-#endif
- //MrE: fast check first
- d = DotProduct (stack->portal->origin, plane.normal) - plane.dist;
- //if completely at the back of the seperator plane
- if (d < -stack->portal->radius)
- return NULL;
- //if completely on the front of the seperator plane
- if (d > stack->portal->radius)
- break;
-
- //
- // clip target by the seperating plane
- //
- target = VisChopWinding (target, stack, &plane);
- if (!target)
- return NULL; // target is not visible
-
- break; // optimization by Antony Suter
- }
- }
-
- return target;
-}
-
-/*
-==================
-RecursiveLeafFlow
-
-Flood fill through the leafs
-If src_portal is NULL, this is the originating leaf
-==================
-*/
-void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack)
-{
- pstack_t stack;
- vportal_t *p;
- plane_t backplane;
- leaf_t *leaf;
- int i, j, n;
- long *test, *might, *prevmight, *vis, more;
- int pnum;
-
- thread->c_chains++;
-
- leaf = &leafs[leafnum];
-// CheckStack (leaf, thread);
-
- prevstack->next = &stack;
-
- stack.next = NULL;
- stack.leaf = leaf;
- stack.portal = NULL;
- stack.depth = prevstack->depth + 1;
-
-#ifdef SEPERATORCACHE
- stack.numseperators[0] = 0;
- stack.numseperators[1] = 0;
-#endif
-
- might = (long *)stack.mightsee;
- vis = (long *)thread->base->portalvis;
-
- // check all portals for flowing into other leafs
- for (i = 0; i < leaf->numportals; i++)
- {
- p = leaf->portals[i];
- if (p->removed)
- continue;
- pnum = p - portals;
-
- /* MrE: portal trace debug code
- {
- int portaltrace[] = {13, 16, 17, 37};
- pstack_t *s;
-
- s = &thread->pstack_head;
- for (j = 0; s->next && j < sizeof(portaltrace)/sizeof(int) - 1; j++, s = s->next)
- {
- if (s->portal->num != portaltrace[j])
- break;
- }
- if (j >= sizeof(portaltrace)/sizeof(int) - 1)
- {
- if (p->num == portaltrace[j])
- n = 0; //traced through all the portals
- }
- }
- */
-
- if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) )
- {
- continue; // can't possibly see it
- }
-
- // if the portal can't see anything we haven't allready seen, skip it
- if (p->status == stat_done)
- {
- test = (long *)p->portalvis;
- }
- else
- {
- test = (long *)p->portalflood;
- }
-
- more = 0;
- prevmight = (long *)prevstack->mightsee;
- for (j=0 ; j<portallongs ; j++)
- {
- might[j] = prevmight[j] & test[j];
- more |= (might[j] & ~vis[j]);
- }
-
- if (!more &&
- (thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) )
- { // can't see anything new
- continue;
- }
-
- // get plane of portal, point normal into the neighbor leaf
- stack.portalplane = p->plane;
- VectorSubtract (vec3_origin, p->plane.normal, backplane.normal);
- backplane.dist = -p->plane.dist;
-
-// c_portalcheck++;
-
- stack.portal = p;
- stack.next = NULL;
- stack.freewindings[0] = 1;
- stack.freewindings[1] = 1;
- stack.freewindings[2] = 1;
-
-#if 1
- {
- float d;
-
- d = DotProduct (p->origin, thread->pstack_head.portalplane.normal);
- d -= thread->pstack_head.portalplane.dist;
- if (d < -p->radius)
- {
- continue;
- }
- else if (d > p->radius)
- {
- stack.pass = p->winding;
- }
- else
- {
- stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
- if (!stack.pass)
- continue;
- }
- }
-#else
- stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
- if (!stack.pass)
- continue;
-#endif
-
-
-#if 1
- {
- float d;
-
- d = DotProduct (thread->base->origin, p->plane.normal);
- d -= p->plane.dist;
- //MrE: vis-bug fix
- //if (d > p->radius)
- if (d > thread->base->radius)
- {
- continue;
- }
- //MrE: vis-bug fix
- //if (d < -p->radius)
- else if (d < -thread->base->radius)
- {
- stack.source = prevstack->source;
- }
- else
- {
- stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
- //FIXME: shouldn't we create a new source origin and radius for fast checks?
- if (!stack.source)
- continue;
- }
- }
-#else
- stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
- if (!stack.source)
- continue;
-#endif
-
- if (!prevstack->pass)
- { // the second leaf can only be blocked if coplanar
-
- // mark the portal as visible
- thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
-
- RecursiveLeafFlow (p->leaf, thread, &stack);
- continue;
- }
-
-#ifdef SEPERATORCACHE
- if (stack.numseperators[0])
- {
- for (n = 0; n < stack.numseperators[0]; n++)
- {
- stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[0][n]);
- if (!stack.pass)
- break; // target is not visible
- }
- if (n < stack.numseperators[0])
- continue;
- }
- else
- {
- stack.pass = ClipToSeperators (prevstack->source, prevstack->pass, stack.pass, qfalse, &stack);
- }
-#else
- stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, qfalse, &stack);
-#endif
- if (!stack.pass)
- continue;
-
-#ifdef SEPERATORCACHE
- if (stack.numseperators[1])
- {
- for (n = 0; n < stack.numseperators[1]; n++)
- {
- stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[1][n]);
- if (!stack.pass)
- break; // target is not visible
- }
- }
- else
- {
- stack.pass = ClipToSeperators (prevstack->pass, prevstack->source, stack.pass, qtrue, &stack);
- }
-#else
- stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, qtrue, &stack);
-#endif
- if (!stack.pass)
- continue;
-
- // mark the portal as visible
- thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
-
- // flow through it for real
- RecursiveLeafFlow (p->leaf, thread, &stack);
- //
- stack.next = NULL;
- }
-}
-
-/*
-===============
-PortalFlow
-
-generates the portalvis bit vector
-===============
-*/
-void PortalFlow (int portalnum)
-{
- threaddata_t data;
- int i;
- vportal_t *p;
- int c_might, c_can;
-
-#ifdef MREDEBUG
- _printf("\r%6d", portalnum);
-#endif
-
- p = sorted_portals[portalnum];
-
- if (p->removed)
- {
- p->status = stat_done;
- return;
- }
-
- p->status = stat_working;
-
- c_might = CountBits (p->portalflood, numportals*2);
-
- memset (&data, 0, sizeof(data));
- data.base = p;
-
- data.pstack_head.portal = p;
- data.pstack_head.source = p->winding;
- data.pstack_head.portalplane = p->plane;
- data.pstack_head.depth = 0;
- for (i=0 ; i<portallongs ; i++)
- ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
-
- RecursiveLeafFlow (p->leaf, &data, &data.pstack_head);
-
- p->status = stat_done;
-
- c_can = CountBits (p->portalvis, numportals*2);
-
- qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n",
- (int)(p - portals), c_might, c_can, data.c_chains);
-}
-
-/*
-==================
-RecursivePassageFlow
-==================
-*/
-void RecursivePassageFlow (vportal_t *portal, threaddata_t *thread, pstack_t *prevstack)
-{
- pstack_t stack;
- vportal_t *p;
- leaf_t *leaf;
- passage_t *passage, *nextpassage;
- int i, j;
- long *might, *vis, *prevmight, *cansee, *portalvis, more;
- int pnum;
-
- leaf = &leafs[portal->leaf];
-
- prevstack->next = &stack;
-
- stack.next = NULL;
- stack.depth = prevstack->depth + 1;
-
- vis = (long *)thread->base->portalvis;
-
- passage = portal->passages;
- nextpassage = passage;
- // check all portals for flowing into other leafs
- for (i = 0; i < leaf->numportals; i++, passage = nextpassage)
- {
- p = leaf->portals[i];
- if ( p->removed ) {
- continue;
- }
- nextpassage = passage->next;
- pnum = p - portals;
-
- if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) ) {
- continue; // can't possibly see it
- }
-
- // mark the portal as visible
- thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
-
- prevmight = (long *)prevstack->mightsee;
- cansee = (long *)passage->cansee;
- might = (long *)stack.mightsee;
- memcpy(might, prevmight, portalbytes);
- if (p->status == stat_done)
- portalvis = (long *) p->portalvis;
- else
- portalvis = (long *) p->portalflood;
- more = 0;
- for (j = 0; j < portallongs; j++)
- {
- if (*might)
- {
- *might &= *cansee++ & *portalvis++;
- more |= (*might & ~vis[j]);
- }
- else
- {
- cansee++;
- portalvis++;
- }
- might++;
- }
-
- if ( !more ) {
- // can't see anything new
- continue;
- }
-
- // flow through it for real
- RecursivePassageFlow(p, thread, &stack);
-
- stack.next = NULL;
- }
-}
-
-/*
-===============
-PassageFlow
-===============
-*/
-void PassageFlow (int portalnum)
-{
- threaddata_t data;
- int i;
- vportal_t *p;
-// int c_might, c_can;
-
-#ifdef MREDEBUG
- _printf("\r%6d", portalnum);
-#endif
-
- p = sorted_portals[portalnum];
-
- if (p->removed)
- {
- p->status = stat_done;
- return;
- }
-
- p->status = stat_working;
-
-// c_might = CountBits (p->portalflood, numportals*2);
-
- memset (&data, 0, sizeof(data));
- data.base = p;
-
- data.pstack_head.portal = p;
- data.pstack_head.source = p->winding;
- data.pstack_head.portalplane = p->plane;
- data.pstack_head.depth = 0;
- for (i=0 ; i<portallongs ; i++)
- ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
-
- RecursivePassageFlow (p, &data, &data.pstack_head);
-
- p->status = stat_done;
-
- /*
- c_can = CountBits (p->portalvis, numportals*2);
-
- qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n",
- (int)(p - portals), c_might, c_can, data.c_chains);
- */
-}
-
-/*
-==================
-RecursivePassagePortalFlow
-==================
-*/
-void RecursivePassagePortalFlow (vportal_t *portal, threaddata_t *thread, pstack_t *prevstack)
-{
- pstack_t stack;
- vportal_t *p;
- leaf_t *leaf;
- plane_t backplane;
- passage_t *passage, *nextpassage;
- int i, j, n;
- long *might, *vis, *prevmight, *cansee, *portalvis, more;
- int pnum;
-
-// thread->c_chains++;
-
- leaf = &leafs[portal->leaf];
-// CheckStack (leaf, thread);
-
- prevstack->next = &stack;
-
- stack.next = NULL;
- stack.leaf = leaf;
- stack.portal = NULL;
- stack.depth = prevstack->depth + 1;
-
-#ifdef SEPERATORCACHE
- stack.numseperators[0] = 0;
- stack.numseperators[1] = 0;
-#endif
-
- vis = (long *)thread->base->portalvis;
-
- passage = portal->passages;
- nextpassage = passage;
- // check all portals for flowing into other leafs
- for (i = 0; i < leaf->numportals; i++, passage = nextpassage)
- {
- p = leaf->portals[i];
- if (p->removed)
- continue;
- nextpassage = passage->next;
- pnum = p - portals;
-
- if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) )
- continue; // can't possibly see it
-
- prevmight = (long *)prevstack->mightsee;
- cansee = (long *)passage->cansee;
- might = (long *)stack.mightsee;
- memcpy(might, prevmight, portalbytes);
- if (p->status == stat_done)
- portalvis = (long *) p->portalvis;
- else
- portalvis = (long *) p->portalflood;
- more = 0;
- for (j = 0; j < portallongs; j++)
- {
- if (*might)
- {
- *might &= *cansee++ & *portalvis++;
- more |= (*might & ~vis[j]);
- }
- else
- {
- cansee++;
- portalvis++;
- }
- might++;
- }
-
- if (!more && (thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) )
- { // can't see anything new
- continue;
- }
-
- // get plane of portal, point normal into the neighbor leaf
- stack.portalplane = p->plane;
- VectorSubtract (vec3_origin, p->plane.normal, backplane.normal);
- backplane.dist = -p->plane.dist;
-
-// c_portalcheck++;
-
- stack.portal = p;
- stack.next = NULL;
- stack.freewindings[0] = 1;
- stack.freewindings[1] = 1;
- stack.freewindings[2] = 1;
-
-#if 1
- {
- float d;
-
- d = DotProduct (p->origin, thread->pstack_head.portalplane.normal);
- d -= thread->pstack_head.portalplane.dist;
- if (d < -p->radius)
- {
- continue;
- }
- else if (d > p->radius)
- {
- stack.pass = p->winding;
- }
- else
- {
- stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
- if (!stack.pass)
- continue;
- }
- }
-#else
- stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
- if (!stack.pass)
- continue;
-#endif
-
-
-#if 1
- {
- float d;
-
- d = DotProduct (thread->base->origin, p->plane.normal);
- d -= p->plane.dist;
- //MrE: vis-bug fix
- //if (d > p->radius)
- if (d > thread->base->radius)
- {
- continue;
- }
- //MrE: vis-bug fix
- //if (d < -p->radius)
- else if (d < -thread->base->radius)
- {
- stack.source = prevstack->source;
- }
- else
- {
- stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
- //FIXME: shouldn't we create a new source origin and radius for fast checks?
- if (!stack.source)
- continue;
- }
- }
-#else
- stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
- if (!stack.source)
- continue;
-#endif
-
- if (!prevstack->pass)
- { // the second leaf can only be blocked if coplanar
-
- // mark the portal as visible
- thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
-
- RecursivePassagePortalFlow (p, thread, &stack);
- continue;
- }
-
-#ifdef SEPERATORCACHE
- if (stack.numseperators[0])
- {
- for (n = 0; n < stack.numseperators[0]; n++)
- {
- stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[0][n]);
- if (!stack.pass)
- break; // target is not visible
- }
- if (n < stack.numseperators[0])
- continue;
- }
- else
- {
- stack.pass = ClipToSeperators (prevstack->source, prevstack->pass, stack.pass, qfalse, &stack);
- }
-#else
- stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, qfalse, &stack);
-#endif
- if (!stack.pass)
- continue;
-
-#ifdef SEPERATORCACHE
- if (stack.numseperators[1])
- {
- for (n = 0; n < stack.numseperators[1]; n++)
- {
- stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[1][n]);
- if (!stack.pass)
- break; // target is not visible
- }
- }
- else
- {
- stack.pass = ClipToSeperators (prevstack->pass, prevstack->source, stack.pass, qtrue, &stack);
- }
-#else
- stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, qtrue, &stack);
-#endif
- if (!stack.pass)
- continue;
-
- // mark the portal as visible
- thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
-
- // flow through it for real
- RecursivePassagePortalFlow(p, thread, &stack);
- //
- stack.next = NULL;
- }
-}
-
-/*
-===============
-PassagePortalFlow
-===============
-*/
-void PassagePortalFlow (int portalnum)
-{
- threaddata_t data;
- int i;
- vportal_t *p;
-// int c_might, c_can;
-
-#ifdef MREDEBUG
- _printf("\r%6d", portalnum);
-#endif
-
- p = sorted_portals[portalnum];
-
- if (p->removed)
- {
- p->status = stat_done;
- return;
- }
-
- p->status = stat_working;
-
-// c_might = CountBits (p->portalflood, numportals*2);
-
- memset (&data, 0, sizeof(data));
- data.base = p;
-
- data.pstack_head.portal = p;
- data.pstack_head.source = p->winding;
- data.pstack_head.portalplane = p->plane;
- data.pstack_head.depth = 0;
- for (i=0 ; i<portallongs ; i++)
- ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
-
- RecursivePassagePortalFlow (p, &data, &data.pstack_head);
-
- p->status = stat_done;
-
- /*
- c_can = CountBits (p->portalvis, numportals*2);
-
- qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n",
- (int)(p - portals), c_might, c_can, data.c_chains);
- */
-}
-
-winding_t *PassageChopWinding (winding_t *in, winding_t *out, plane_t *split)
-{
- vec_t dists[128];
- int sides[128];
- int counts[3];
- vec_t dot;
- int i, j;
- vec_t *p1, *p2;
- vec3_t mid;
- winding_t *neww;
-
- counts[0] = counts[1] = counts[2] = 0;
-
- // determine sides for each point
- for (i=0 ; i<in->numpoints ; i++)
- {
- dot = DotProduct (in->points[i], split->normal);
- dot -= split->dist;
- dists[i] = dot;
- if (dot > ON_EPSILON)
- sides[i] = SIDE_FRONT;
- else if (dot < -ON_EPSILON)
- sides[i] = SIDE_BACK;
- else
- {
- sides[i] = SIDE_ON;
- }
- counts[sides[i]]++;
- }
-
- if (!counts[1])
- return in; // completely on front side
-
- if (!counts[0])
- {
- return NULL;
- }
-
- sides[i] = sides[0];
- dists[i] = dists[0];
-
- neww = out;
-
- neww->numpoints = 0;
-
- for (i=0 ; i<in->numpoints ; i++)
- {
- p1 = in->points[i];
-
- if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
- {
- return in; // can't chop -- fall back to original
- }
-
- if (sides[i] == SIDE_ON)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- continue;
- }
-
- if (sides[i] == SIDE_FRONT)
- {
- VectorCopy (p1, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
-
- if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
- continue;
-
- if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
- {
- return in; // can't chop -- fall back to original
- }
-
- // generate a split point
- p2 = in->points[(i+1)%in->numpoints];
-
- dot = dists[i] / (dists[i]-dists[i+1]);
- for (j=0 ; j<3 ; j++)
- { // avoid round off error when possible
- if (split->normal[j] == 1)
- mid[j] = split->dist;
- else if (split->normal[j] == -1)
- mid[j] = -split->dist;
- else
- mid[j] = p1[j] + dot*(p2[j]-p1[j]);
- }
-
- VectorCopy (mid, neww->points[neww->numpoints]);
- neww->numpoints++;
- }
-
- return neww;
-}
-
-/*
-===============
-AddSeperators
-===============
-*/
-int AddSeperators (winding_t *source, winding_t *pass, qboolean flipclip, plane_t *seperators, int maxseperators)
-{
- int i, j, k, l;
- plane_t plane;
- vec3_t v1, v2;
- float d;
- vec_t length;
- int counts[3], numseperators;
- qboolean fliptest;
-
- numseperators = 0;
- // check all combinations
- for (i=0 ; i<source->numpoints ; i++)
- {
- l = (i+1)%source->numpoints;
- VectorSubtract (source->points[l] , source->points[i], v1);
-
- // find a vertex of pass that makes a plane that puts all of the
- // vertexes of pass on the front side and all of the vertexes of
- // source on the back side
- for (j=0 ; j<pass->numpoints ; j++)
- {
- VectorSubtract (pass->points[j], source->points[i], v2);
-
- plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
- plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
- plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
-
- // if points don't make a valid plane, skip it
-
- length = plane.normal[0] * plane.normal[0]
- + plane.normal[1] * plane.normal[1]
- + plane.normal[2] * plane.normal[2];
-
- if (length < ON_EPSILON)
- continue;
-
- length = 1/sqrt(length);
-
- plane.normal[0] *= length;
- plane.normal[1] *= length;
- plane.normal[2] *= length;
-
- plane.dist = DotProduct (pass->points[j], plane.normal);
-
- //
- // find out which side of the generated seperating plane has the
- // source portal
- //
-#if 1
- fliptest = qfalse;
- for (k=0 ; k<source->numpoints ; k++)
- {
- if (k == i || k == l)
- continue;
- d = DotProduct (source->points[k], plane.normal) - plane.dist;
- if (d < -ON_EPSILON)
- { // source is on the negative side, so we want all
- // pass and target on the positive side
- fliptest = qfalse;
- break;
- }
- else if (d > ON_EPSILON)
- { // source is on the positive side, so we want all
- // pass and target on the negative side
- fliptest = qtrue;
- break;
- }
- }
- if (k == source->numpoints)
- continue; // planar with source portal
-#else
- fliptest = flipclip;
-#endif
- //
- // flip the normal if the source portal is backwards
- //
- if (fliptest)
- {
- VectorSubtract (vec3_origin, plane.normal, plane.normal);
- plane.dist = -plane.dist;
- }
-#if 1
- //
- // if all of the pass portal points are now on the positive side,
- // this is the seperating plane
- //
- counts[0] = counts[1] = counts[2] = 0;
- for (k=0 ; k<pass->numpoints ; k++)
- {
- if (k==j)
- continue;
- d = DotProduct (pass->points[k], plane.normal) - plane.dist;
- if (d < -ON_EPSILON)
- break;
- else if (d > ON_EPSILON)
- counts[0]++;
- else
- counts[2]++;
- }
- if (k != pass->numpoints)
- continue; // points on negative side, not a seperating plane
-
- if (!counts[0])
- continue; // planar with seperating plane
-#else
- k = (j+1)%pass->numpoints;
- d = DotProduct (pass->points[k], plane.normal) - plane.dist;
- if (d < -ON_EPSILON)
- continue;
- k = (j+pass->numpoints-1)%pass->numpoints;
- d = DotProduct (pass->points[k], plane.normal) - plane.dist;
- if (d < -ON_EPSILON)
- continue;
-#endif
- //
- // flip the normal if we want the back side
- //
- if (flipclip)
- {
- VectorSubtract (vec3_origin, plane.normal, plane.normal);
- plane.dist = -plane.dist;
- }
-
- if (numseperators >= maxseperators)
- Error("max seperators");
- seperators[numseperators] = plane;
- numseperators++;
- break;
- }
- }
- return numseperators;
-}
-
-/*
-===============
-CreatePassages
-
-MrE: create passages from one portal to all the portals in the leaf the portal leads to
- every passage has a cansee bit string with all the portals that can be
- seen through the passage
-===============
-*/
-void CreatePassages(int portalnum)
-{
- int i, j, k, n, numseperators, numsee;
- float d;
- vportal_t *portal, *p, *target;
- leaf_t *leaf;
- passage_t *passage, *lastpassage;
- plane_t seperators[MAX_SEPERATORS*2];
- winding_t *w;
- winding_t in, out, *res;
-
-#ifdef MREDEBUG
- _printf("\r%6d", portalnum);
-#endif
-
- portal = sorted_portals[portalnum];
-
- if (portal->removed)
- {
- portal->status = stat_done;
- return;
- }
-
- lastpassage = NULL;
- leaf = &leafs[portal->leaf];
- for (i = 0; i < leaf->numportals; i++)
- {
- target = leaf->portals[i];
- if (target->removed)
- continue;
-
- passage = (passage_t *) malloc(sizeof(passage_t) + portalbytes);
- memset(passage, 0, sizeof(passage_t) + portalbytes);
- numseperators = AddSeperators(portal->winding, target->winding, qfalse, seperators, MAX_SEPERATORS*2);
- numseperators += AddSeperators(target->winding, portal->winding, qtrue, &seperators[numseperators], MAX_SEPERATORS*2-numseperators);
-
- passage->next = NULL;
- if (lastpassage)
- lastpassage->next = passage;
- else
- portal->passages = passage;
- lastpassage = passage;
-
- numsee = 0;
- //create the passage->cansee
- for (j = 0; j < numportals * 2; j++)
- {
- p = &portals[j];
- if (p->removed)
- continue;
- if ( ! (target->portalflood[j >> 3] & (1<<(j&7)) ) )
- continue;
- if ( ! (portal->portalflood[j >> 3] & (1<<(j&7)) ) )
- continue;
- for (k = 0; k < numseperators; k++)
- {
- //
- d = DotProduct (p->origin, seperators[k].normal) - seperators[k].dist;
- //if completely at the back of the seperator plane
- if (d < -p->radius + ON_EPSILON)
- break;
- w = p->winding;
- for (n = 0; n < w->numpoints; n++)
- {
- d = DotProduct (w->points[n], seperators[k].normal) - seperators[k].dist;
- //if at the front of the seperator
- if (d > ON_EPSILON)
- break;
- }
- //if no points are at the front of the seperator
- if (n >= w->numpoints)
- break;
- }
- if (k < numseperators)
- continue;
- memcpy(&in, p->winding, sizeof(winding_t));
- for (k = 0; k < numseperators; k++)
- {
- res = PassageChopWinding(&in, &out, &seperators[k]);
- if (res == &out)
- memcpy(&in, &out, sizeof(winding_t));
- if (res == NULL)
- break;
- }
- if (k < numseperators)
- continue;
- passage->cansee[j >> 3] |= (1<<(j&7));
- numsee++;
- }
- }
-}
-
-void PassageMemory(void)
-{
- int i, j, totalmem, totalportals;
- vportal_t *portal, *target;
- leaf_t *leaf;
-
- totalmem = 0;
- totalportals = 0;
- for (i = 0; i < numportals; i++)
- {
- portal = sorted_portals[i];
- if (portal->removed)
- continue;
- leaf = &leafs[portal->leaf];
- for (j = 0; j < leaf->numportals; j++)
- {
- target = leaf->portals[j];
- if (target->removed)
- continue;
- totalmem += sizeof(passage_t) + portalbytes;
- totalportals++;
- }
- }
- _printf("%7i average number of passages per leaf\n", totalportals / numportals);
- _printf("%7i MB required passage memory\n", totalmem >> 10 >> 10);
-}
-
-/*
-===============================================================================
-
-This is a rough first-order aproximation that is used to trivially reject some
-of the final calculations.
-
-
-Calculates portalfront and portalflood bit vectors
-
-thinking about:
-
-typedef struct passage_s
-{
- struct passage_s *next;
- struct portal_s *to;
- stryct sep_s *seperators;
- byte *mightsee;
-} passage_t;
-
-typedef struct portal_s
-{
- struct passage_s *passages;
- int leaf; // leaf portal faces into
-} portal_s;
-
-leaf = portal->leaf
-clear
-for all portals
-
-
-calc portal visibility
- clear bit vector
- for all passages
- passage visibility
-
-
-for a portal to be visible to a passage, it must be on the front of
-all seperating planes, and both portals must be behind the new portal
-
-===============================================================================
-*/
-
-int c_flood, c_vis;
-
-
-/*
-==================
-SimpleFlood
-
-==================
-*/
-void SimpleFlood (vportal_t *srcportal, int leafnum)
-{
- int i;
- leaf_t *leaf;
- vportal_t *p;
- int pnum;
-
- leaf = &leafs[leafnum];
-
- for (i=0 ; i<leaf->numportals ; i++)
- {
- p = leaf->portals[i];
- if (p->removed)
- continue;
- pnum = p - portals;
- if ( ! (srcportal->portalfront[pnum>>3] & (1<<(pnum&7)) ) )
- continue;
-
- if (srcportal->portalflood[pnum>>3] & (1<<(pnum&7)) )
- continue;
-
- srcportal->portalflood[pnum>>3] |= (1<<(pnum&7));
-
- SimpleFlood (srcportal, p->leaf);
- }
-}
-
-/*
-==============
-BasePortalVis
-==============
-*/
-void BasePortalVis (int portalnum)
-{
- int j, k;
- vportal_t *tp, *p;
- float d;
- winding_t *w;
-
- p = portals+portalnum;
-
- if (p->removed)
- return;
-
- p->portalfront = malloc (portalbytes);
- memset (p->portalfront, 0, portalbytes);
-
- p->portalflood = malloc (portalbytes);
- memset (p->portalflood, 0, portalbytes);
-
- p->portalvis = malloc (portalbytes);
- memset (p->portalvis, 0, portalbytes);
-
- for (j=0, tp = portals ; j<numportals*2 ; j++, tp++)
- {
- if (j == portalnum)
- continue;
- if (tp->removed)
- continue;
- /*
- if (farplanedist >= 0)
- {
- vec3_t dir;
- VectorSubtract(p->origin, tp->origin, dir);
- if (VectorLength(dir) > farplanedist - p->radius - tp->radius)
- continue;
- }
- */
- w = tp->winding;
- for (k=0 ; k<w->numpoints ; k++)
- {
- d = DotProduct (w->points[k], p->plane.normal)
- - p->plane.dist;
- if (d > ON_EPSILON)
- break;
- }
- if (k == w->numpoints)
- continue; // no points on front
-
- w = p->winding;
- for (k=0 ; k<w->numpoints ; k++)
- {
- d = DotProduct (w->points[k], tp->plane.normal)
- - tp->plane.dist;
- if (d < -ON_EPSILON)
- break;
- }
- if (k == w->numpoints)
- continue; // no points on front
-
- p->portalfront[j>>3] |= (1<<(j&7));
- }
-
- SimpleFlood (p, p->leaf);
-
- p->nummightsee = CountBits (p->portalflood, numportals*2);
-// _printf ("portal %i: %i mightsee\n", portalnum, p->nummightsee);
- c_flood += p->nummightsee;
-}
-
-
-
-
-
-/*
-===============================================================================
-
-This is a second order aproximation
-
-Calculates portalvis bit vector
-
-WAAAAAAY too slow.
-
-===============================================================================
-*/
-
-/*
-==================
-RecursiveLeafBitFlow
-
-==================
-*/
-void RecursiveLeafBitFlow (int leafnum, byte *mightsee, byte *cansee)
-{
- vportal_t *p;
- leaf_t *leaf;
- int i, j;
- long more;
- int pnum;
- byte newmight[MAX_PORTALS/8];
-
- leaf = &leafs[leafnum];
-
- // check all portals for flowing into other leafs
- for (i=0 ; i<leaf->numportals ; i++)
- {
- p = leaf->portals[i];
- if (p->removed)
- continue;
- pnum = p - portals;
-
- // if some previous portal can't see it, skip
- if (! (mightsee[pnum>>3] & (1<<(pnum&7)) ) )
- continue;
-
- // if this portal can see some portals we mightsee, recurse
- more = 0;
- for (j=0 ; j<portallongs ; j++)
- {
- ((long *)newmight)[j] = ((long *)mightsee)[j]
- & ((long *)p->portalflood)[j];
- more |= ((long *)newmight)[j] & ~((long *)cansee)[j];
- }
-
- if (!more)
- continue; // can't see anything new
-
- cansee[pnum>>3] |= (1<<(pnum&7));
-
- RecursiveLeafBitFlow (p->leaf, newmight, cansee);
- }
-}
-
-/*
-==============
-BetterPortalVis
-==============
-*/
-void BetterPortalVis (int portalnum)
-{
- vportal_t *p;
-
- p = portals+portalnum;
-
- if (p->removed)
- return;
-
- RecursiveLeafBitFlow (p->leaf, p->portalflood, p->portalvis);
-
- // build leaf vis information
- p->nummightsee = CountBits (p->portalvis, numportals*2);
- c_vis += p->nummightsee;
-}
-
-
+#include "vis.h"
+
+/*
+
+ each portal will have a list of all possible to see from first portal
+
+ if (!thread->portalmightsee[portalnum])
+
+ portal mightsee
+
+ for p2 = all other portals in leaf
+ get sperating planes
+ for all portals that might be seen by p2
+ mark as unseen if not present in seperating plane
+ flood fill a new mightsee
+ save as passagemightsee
+
+
+ void CalcMightSee (leaf_t *leaf,
+*/
+
+int CountBits (byte *bits, int numbits)
+{
+ int i;
+ int c;
+
+ c = 0;
+ for (i=0 ; i<numbits ; i++)
+ if (bits[i>>3] & (1<<(i&7)) )
+ c++;
+
+ return c;
+}
+
+int c_fullskip;
+int c_portalskip, c_leafskip;
+int c_vistest, c_mighttest;
+
+int c_chop, c_nochop;
+
+int active;
+
+void CheckStack (leaf_t *leaf, threaddata_t *thread)
+{
+ pstack_t *p, *p2;
+
+ for (p=thread->pstack_head.next ; p ; p=p->next)
+ {
+// _printf ("=");
+ if (p->leaf == leaf)
+ Error ("CheckStack: leaf recursion");
+ for (p2=thread->pstack_head.next ; p2 != p ; p2=p2->next)
+ if (p2->leaf == p->leaf)
+ Error ("CheckStack: late leaf recursion");
+ }
+// _printf ("\n");
+}
+
+
+winding_t *AllocStackWinding (pstack_t *stack)
+{
+ int i;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if (stack->freewindings[i])
+ {
+ stack->freewindings[i] = 0;
+ return &stack->windings[i];
+ }
+ }
+
+ Error ("AllocStackWinding: failed");
+
+ return NULL;
+}
+
+void FreeStackWinding (winding_t *w, pstack_t *stack)
+{
+ int i;
+
+ i = w - stack->windings;
+
+ if (i<0 || i>2)
+ return; // not from local
+
+ if (stack->freewindings[i])
+ Error ("FreeStackWinding: allready free");
+ stack->freewindings[i] = 1;
+}
+
+/*
+==============
+VisChopWinding
+
+==============
+*/
+winding_t *VisChopWinding (winding_t *in, pstack_t *stack, plane_t *split)
+{
+ vec_t dists[128];
+ int sides[128];
+ int counts[3];
+ vec_t dot;
+ int i, j;
+ vec_t *p1, *p2;
+ vec3_t mid;
+ winding_t *neww;
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+ // determine sides for each point
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ dot = DotProduct (in->points[i], split->normal);
+ dot -= split->dist;
+ dists[i] = dot;
+ if (dot > ON_EPSILON)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -ON_EPSILON)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+
+ if (!counts[1])
+ return in; // completely on front side
+
+ if (!counts[0])
+ {
+ FreeStackWinding (in, stack);
+ return NULL;
+ }
+
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ neww = AllocStackWinding (stack);
+
+ neww->numpoints = 0;
+
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ p1 = in->points[i];
+
+ if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
+ {
+ FreeStackWinding (neww, stack);
+ return in; // can't chop -- fall back to original
+ }
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy (p1, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
+ {
+ FreeStackWinding (neww, stack);
+ return in; // can't chop -- fall back to original
+ }
+
+ // generate a split point
+ p2 = in->points[(i+1)%in->numpoints];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (split->normal[j] == 1)
+ mid[j] = split->dist;
+ else if (split->normal[j] == -1)
+ mid[j] = -split->dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ }
+
+ // free the original winding
+ FreeStackWinding (in, stack);
+
+ return neww;
+}
+
+/*
+==============
+ClipToSeperators
+
+Source, pass, and target are an ordering of portals.
+
+Generates seperating planes canidates by taking two points from source and one
+point from pass, and clips target by them.
+
+If target is totally clipped away, that portal can not be seen through.
+
+Normal clip keeps target on the same side as pass, which is correct if the
+order goes source, pass, target. If the order goes pass, source, target then
+flipclip should be set.
+==============
+*/
+winding_t *ClipToSeperators (winding_t *source, winding_t *pass, winding_t *target, qboolean flipclip, pstack_t *stack)
+{
+ int i, j, k, l;
+ plane_t plane;
+ vec3_t v1, v2;
+ float d;
+ vec_t length;
+ int counts[3];
+ qboolean fliptest;
+
+ // check all combinations
+ for (i=0 ; i<source->numpoints ; i++)
+ {
+ l = (i+1)%source->numpoints;
+ VectorSubtract (source->points[l] , source->points[i], v1);
+
+ // find a vertex of pass that makes a plane that puts all of the
+ // vertexes of pass on the front side and all of the vertexes of
+ // source on the back side
+ for (j=0 ; j<pass->numpoints ; j++)
+ {
+ VectorSubtract (pass->points[j], source->points[i], v2);
+
+ plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
+ plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
+ plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
+
+ // if points don't make a valid plane, skip it
+
+ length = plane.normal[0] * plane.normal[0]
+ + plane.normal[1] * plane.normal[1]
+ + plane.normal[2] * plane.normal[2];
+
+ if (length < ON_EPSILON)
+ continue;
+
+ length = 1/sqrt(length);
+
+ plane.normal[0] *= length;
+ plane.normal[1] *= length;
+ plane.normal[2] *= length;
+
+ plane.dist = DotProduct (pass->points[j], plane.normal);
+
+ //
+ // find out which side of the generated seperating plane has the
+ // source portal
+ //
+#if 1
+ fliptest = qfalse;
+ for (k=0 ; k<source->numpoints ; k++)
+ {
+ if (k == i || k == l)
+ continue;
+ d = DotProduct (source->points[k], plane.normal) - plane.dist;
+ if (d < -ON_EPSILON)
+ { // source is on the negative side, so we want all
+ // pass and target on the positive side
+ fliptest = qfalse;
+ break;
+ }
+ else if (d > ON_EPSILON)
+ { // source is on the positive side, so we want all
+ // pass and target on the negative side
+ fliptest = qtrue;
+ break;
+ }
+ }
+ if (k == source->numpoints)
+ continue; // planar with source portal
+#else
+ fliptest = flipclip;
+#endif
+ //
+ // flip the normal if the source portal is backwards
+ //
+ if (fliptest)
+ {
+ VectorSubtract (vec3_origin, plane.normal, plane.normal);
+ plane.dist = -plane.dist;
+ }
+#if 1
+ //
+ // if all of the pass portal points are now on the positive side,
+ // this is the seperating plane
+ //
+ counts[0] = counts[1] = counts[2] = 0;
+ for (k=0 ; k<pass->numpoints ; k++)
+ {
+ if (k==j)
+ continue;
+ d = DotProduct (pass->points[k], plane.normal) - plane.dist;
+ if (d < -ON_EPSILON)
+ break;
+ else if (d > ON_EPSILON)
+ counts[0]++;
+ else
+ counts[2]++;
+ }
+ if (k != pass->numpoints)
+ continue; // points on negative side, not a seperating plane
+
+ if (!counts[0])
+ continue; // planar with seperating plane
+#else
+ k = (j+1)%pass->numpoints;
+ d = DotProduct (pass->points[k], plane.normal) - plane.dist;
+ if (d < -ON_EPSILON)
+ continue;
+ k = (j+pass->numpoints-1)%pass->numpoints;
+ d = DotProduct (pass->points[k], plane.normal) - plane.dist;
+ if (d < -ON_EPSILON)
+ continue;
+#endif
+ //
+ // flip the normal if we want the back side
+ //
+ if (flipclip)
+ {
+ VectorSubtract (vec3_origin, plane.normal, plane.normal);
+ plane.dist = -plane.dist;
+ }
+
+#ifdef SEPERATORCACHE
+ stack->seperators[flipclip][stack->numseperators[flipclip]] = plane;
+ if (++stack->numseperators[flipclip] >= MAX_SEPERATORS)
+ Error("MAX_SEPERATORS");
+#endif
+ //MrE: fast check first
+ d = DotProduct (stack->portal->origin, plane.normal) - plane.dist;
+ //if completely at the back of the seperator plane
+ if (d < -stack->portal->radius)
+ return NULL;
+ //if completely on the front of the seperator plane
+ if (d > stack->portal->radius)
+ break;
+
+ //
+ // clip target by the seperating plane
+ //
+ target = VisChopWinding (target, stack, &plane);
+ if (!target)
+ return NULL; // target is not visible
+
+ break; // optimization by Antony Suter
+ }
+ }
+
+ return target;
+}
+
+/*
+==================
+RecursiveLeafFlow
+
+Flood fill through the leafs
+If src_portal is NULL, this is the originating leaf
+==================
+*/
+void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack)
+{
+ pstack_t stack;
+ vportal_t *p;
+ plane_t backplane;
+ leaf_t *leaf;
+ int i, j, n;
+ long *test, *might, *prevmight, *vis, more;
+ int pnum;
+
+ thread->c_chains++;
+
+ leaf = &leafs[leafnum];
+// CheckStack (leaf, thread);
+
+ prevstack->next = &stack;
+
+ stack.next = NULL;
+ stack.leaf = leaf;
+ stack.portal = NULL;
+ stack.depth = prevstack->depth + 1;
+
+#ifdef SEPERATORCACHE
+ stack.numseperators[0] = 0;
+ stack.numseperators[1] = 0;
+#endif
+
+ might = (long *)stack.mightsee;
+ vis = (long *)thread->base->portalvis;
+
+ // check all portals for flowing into other leafs
+ for (i = 0; i < leaf->numportals; i++)
+ {
+ p = leaf->portals[i];
+ if (p->removed)
+ continue;
+ pnum = p - portals;
+
+ /* MrE: portal trace debug code
+ {
+ int portaltrace[] = {13, 16, 17, 37};
+ pstack_t *s;
+
+ s = &thread->pstack_head;
+ for (j = 0; s->next && j < sizeof(portaltrace)/sizeof(int) - 1; j++, s = s->next)
+ {
+ if (s->portal->num != portaltrace[j])
+ break;
+ }
+ if (j >= sizeof(portaltrace)/sizeof(int) - 1)
+ {
+ if (p->num == portaltrace[j])
+ n = 0; //traced through all the portals
+ }
+ }
+ */
+
+ if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) )
+ {
+ continue; // can't possibly see it
+ }
+
+ // if the portal can't see anything we haven't allready seen, skip it
+ if (p->status == stat_done)
+ {
+ test = (long *)p->portalvis;
+ }
+ else
+ {
+ test = (long *)p->portalflood;
+ }
+
+ more = 0;
+ prevmight = (long *)prevstack->mightsee;
+ for (j=0 ; j<portallongs ; j++)
+ {
+ might[j] = prevmight[j] & test[j];
+ more |= (might[j] & ~vis[j]);
+ }
+
+ if (!more &&
+ (thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) )
+ { // can't see anything new
+ continue;
+ }
+
+ // get plane of portal, point normal into the neighbor leaf
+ stack.portalplane = p->plane;
+ VectorSubtract (vec3_origin, p->plane.normal, backplane.normal);
+ backplane.dist = -p->plane.dist;
+
+// c_portalcheck++;
+
+ stack.portal = p;
+ stack.next = NULL;
+ stack.freewindings[0] = 1;
+ stack.freewindings[1] = 1;
+ stack.freewindings[2] = 1;
+
+#if 1
+ {
+ float d;
+
+ d = DotProduct (p->origin, thread->pstack_head.portalplane.normal);
+ d -= thread->pstack_head.portalplane.dist;
+ if (d < -p->radius)
+ {
+ continue;
+ }
+ else if (d > p->radius)
+ {
+ stack.pass = p->winding;
+ }
+ else
+ {
+ stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
+ if (!stack.pass)
+ continue;
+ }
+ }
+#else
+ stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
+ if (!stack.pass)
+ continue;
+#endif
+
+
+#if 1
+ {
+ float d;
+
+ d = DotProduct (thread->base->origin, p->plane.normal);
+ d -= p->plane.dist;
+ //MrE: vis-bug fix
+ //if (d > p->radius)
+ if (d > thread->base->radius)
+ {
+ continue;
+ }
+ //MrE: vis-bug fix
+ //if (d < -p->radius)
+ else if (d < -thread->base->radius)
+ {
+ stack.source = prevstack->source;
+ }
+ else
+ {
+ stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
+ //FIXME: shouldn't we create a new source origin and radius for fast checks?
+ if (!stack.source)
+ continue;
+ }
+ }
+#else
+ stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
+ if (!stack.source)
+ continue;
+#endif
+
+ if (!prevstack->pass)
+ { // the second leaf can only be blocked if coplanar
+
+ // mark the portal as visible
+ thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
+
+ RecursiveLeafFlow (p->leaf, thread, &stack);
+ continue;
+ }
+
+#ifdef SEPERATORCACHE
+ if (stack.numseperators[0])
+ {
+ for (n = 0; n < stack.numseperators[0]; n++)
+ {
+ stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[0][n]);
+ if (!stack.pass)
+ break; // target is not visible
+ }
+ if (n < stack.numseperators[0])
+ continue;
+ }
+ else
+ {
+ stack.pass = ClipToSeperators (prevstack->source, prevstack->pass, stack.pass, qfalse, &stack);
+ }
+#else
+ stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, qfalse, &stack);
+#endif
+ if (!stack.pass)
+ continue;
+
+#ifdef SEPERATORCACHE
+ if (stack.numseperators[1])
+ {
+ for (n = 0; n < stack.numseperators[1]; n++)
+ {
+ stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[1][n]);
+ if (!stack.pass)
+ break; // target is not visible
+ }
+ }
+ else
+ {
+ stack.pass = ClipToSeperators (prevstack->pass, prevstack->source, stack.pass, qtrue, &stack);
+ }
+#else
+ stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, qtrue, &stack);
+#endif
+ if (!stack.pass)
+ continue;
+
+ // mark the portal as visible
+ thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
+
+ // flow through it for real
+ RecursiveLeafFlow (p->leaf, thread, &stack);
+ //
+ stack.next = NULL;
+ }
+}
+
+/*
+===============
+PortalFlow
+
+generates the portalvis bit vector
+===============
+*/
+void PortalFlow (int portalnum)
+{
+ threaddata_t data;
+ int i;
+ vportal_t *p;
+ int c_might, c_can;
+
+#ifdef MREDEBUG
+ _printf("\r%6d", portalnum);
+#endif
+
+ p = sorted_portals[portalnum];
+
+ if (p->removed)
+ {
+ p->status = stat_done;
+ return;
+ }
+
+ p->status = stat_working;
+
+ c_might = CountBits (p->portalflood, numportals*2);
+
+ memset (&data, 0, sizeof(data));
+ data.base = p;
+
+ data.pstack_head.portal = p;
+ data.pstack_head.source = p->winding;
+ data.pstack_head.portalplane = p->plane;
+ data.pstack_head.depth = 0;
+ for (i=0 ; i<portallongs ; i++)
+ ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
+
+ RecursiveLeafFlow (p->leaf, &data, &data.pstack_head);
+
+ p->status = stat_done;
+
+ c_can = CountBits (p->portalvis, numportals*2);
+
+ qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n",
+ (int)(p - portals), c_might, c_can, data.c_chains);
+}
+
+/*
+==================
+RecursivePassageFlow
+==================
+*/
+void RecursivePassageFlow (vportal_t *portal, threaddata_t *thread, pstack_t *prevstack)
+{
+ pstack_t stack;
+ vportal_t *p;
+ leaf_t *leaf;
+ passage_t *passage, *nextpassage;
+ int i, j;
+ long *might, *vis, *prevmight, *cansee, *portalvis, more;
+ int pnum;
+
+ leaf = &leafs[portal->leaf];
+
+ prevstack->next = &stack;
+
+ stack.next = NULL;
+ stack.depth = prevstack->depth + 1;
+
+ vis = (long *)thread->base->portalvis;
+
+ passage = portal->passages;
+ nextpassage = passage;
+ // check all portals for flowing into other leafs
+ for (i = 0; i < leaf->numportals; i++, passage = nextpassage)
+ {
+ p = leaf->portals[i];
+ if ( p->removed ) {
+ continue;
+ }
+ nextpassage = passage->next;
+ pnum = p - portals;
+
+ if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) ) {
+ continue; // can't possibly see it
+ }
+
+ // mark the portal as visible
+ thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
+
+ prevmight = (long *)prevstack->mightsee;
+ cansee = (long *)passage->cansee;
+ might = (long *)stack.mightsee;
+ memcpy(might, prevmight, portalbytes);
+ if (p->status == stat_done)
+ portalvis = (long *) p->portalvis;
+ else
+ portalvis = (long *) p->portalflood;
+ more = 0;
+ for (j = 0; j < portallongs; j++)
+ {
+ if (*might)
+ {
+ *might &= *cansee++ & *portalvis++;
+ more |= (*might & ~vis[j]);
+ }
+ else
+ {
+ cansee++;
+ portalvis++;
+ }
+ might++;
+ }
+
+ if ( !more ) {
+ // can't see anything new
+ continue;
+ }
+
+ // flow through it for real
+ RecursivePassageFlow(p, thread, &stack);
+
+ stack.next = NULL;
+ }
+}
+
+/*
+===============
+PassageFlow
+===============
+*/
+void PassageFlow (int portalnum)
+{
+ threaddata_t data;
+ int i;
+ vportal_t *p;
+// int c_might, c_can;
+
+#ifdef MREDEBUG
+ _printf("\r%6d", portalnum);
+#endif
+
+ p = sorted_portals[portalnum];
+
+ if (p->removed)
+ {
+ p->status = stat_done;
+ return;
+ }
+
+ p->status = stat_working;
+
+// c_might = CountBits (p->portalflood, numportals*2);
+
+ memset (&data, 0, sizeof(data));
+ data.base = p;
+
+ data.pstack_head.portal = p;
+ data.pstack_head.source = p->winding;
+ data.pstack_head.portalplane = p->plane;
+ data.pstack_head.depth = 0;
+ for (i=0 ; i<portallongs ; i++)
+ ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
+
+ RecursivePassageFlow (p, &data, &data.pstack_head);
+
+ p->status = stat_done;
+
+ /*
+ c_can = CountBits (p->portalvis, numportals*2);
+
+ qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n",
+ (int)(p - portals), c_might, c_can, data.c_chains);
+ */
+}
+
+/*
+==================
+RecursivePassagePortalFlow
+==================
+*/
+void RecursivePassagePortalFlow (vportal_t *portal, threaddata_t *thread, pstack_t *prevstack)
+{
+ pstack_t stack;
+ vportal_t *p;
+ leaf_t *leaf;
+ plane_t backplane;
+ passage_t *passage, *nextpassage;
+ int i, j, n;
+ long *might, *vis, *prevmight, *cansee, *portalvis, more;
+ int pnum;
+
+// thread->c_chains++;
+
+ leaf = &leafs[portal->leaf];
+// CheckStack (leaf, thread);
+
+ prevstack->next = &stack;
+
+ stack.next = NULL;
+ stack.leaf = leaf;
+ stack.portal = NULL;
+ stack.depth = prevstack->depth + 1;
+
+#ifdef SEPERATORCACHE
+ stack.numseperators[0] = 0;
+ stack.numseperators[1] = 0;
+#endif
+
+ vis = (long *)thread->base->portalvis;
+
+ passage = portal->passages;
+ nextpassage = passage;
+ // check all portals for flowing into other leafs
+ for (i = 0; i < leaf->numportals; i++, passage = nextpassage)
+ {
+ p = leaf->portals[i];
+ if (p->removed)
+ continue;
+ nextpassage = passage->next;
+ pnum = p - portals;
+
+ if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) )
+ continue; // can't possibly see it
+
+ prevmight = (long *)prevstack->mightsee;
+ cansee = (long *)passage->cansee;
+ might = (long *)stack.mightsee;
+ memcpy(might, prevmight, portalbytes);
+ if (p->status == stat_done)
+ portalvis = (long *) p->portalvis;
+ else
+ portalvis = (long *) p->portalflood;
+ more = 0;
+ for (j = 0; j < portallongs; j++)
+ {
+ if (*might)
+ {
+ *might &= *cansee++ & *portalvis++;
+ more |= (*might & ~vis[j]);
+ }
+ else
+ {
+ cansee++;
+ portalvis++;
+ }
+ might++;
+ }
+
+ if (!more && (thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) )
+ { // can't see anything new
+ continue;
+ }
+
+ // get plane of portal, point normal into the neighbor leaf
+ stack.portalplane = p->plane;
+ VectorSubtract (vec3_origin, p->plane.normal, backplane.normal);
+ backplane.dist = -p->plane.dist;
+
+// c_portalcheck++;
+
+ stack.portal = p;
+ stack.next = NULL;
+ stack.freewindings[0] = 1;
+ stack.freewindings[1] = 1;
+ stack.freewindings[2] = 1;
+
+#if 1
+ {
+ float d;
+
+ d = DotProduct (p->origin, thread->pstack_head.portalplane.normal);
+ d -= thread->pstack_head.portalplane.dist;
+ if (d < -p->radius)
+ {
+ continue;
+ }
+ else if (d > p->radius)
+ {
+ stack.pass = p->winding;
+ }
+ else
+ {
+ stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
+ if (!stack.pass)
+ continue;
+ }
+ }
+#else
+ stack.pass = VisChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
+ if (!stack.pass)
+ continue;
+#endif
+
+
+#if 1
+ {
+ float d;
+
+ d = DotProduct (thread->base->origin, p->plane.normal);
+ d -= p->plane.dist;
+ //MrE: vis-bug fix
+ //if (d > p->radius)
+ if (d > thread->base->radius)
+ {
+ continue;
+ }
+ //MrE: vis-bug fix
+ //if (d < -p->radius)
+ else if (d < -thread->base->radius)
+ {
+ stack.source = prevstack->source;
+ }
+ else
+ {
+ stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
+ //FIXME: shouldn't we create a new source origin and radius for fast checks?
+ if (!stack.source)
+ continue;
+ }
+ }
+#else
+ stack.source = VisChopWinding (prevstack->source, &stack, &backplane);
+ if (!stack.source)
+ continue;
+#endif
+
+ if (!prevstack->pass)
+ { // the second leaf can only be blocked if coplanar
+
+ // mark the portal as visible
+ thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
+
+ RecursivePassagePortalFlow (p, thread, &stack);
+ continue;
+ }
+
+#ifdef SEPERATORCACHE
+ if (stack.numseperators[0])
+ {
+ for (n = 0; n < stack.numseperators[0]; n++)
+ {
+ stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[0][n]);
+ if (!stack.pass)
+ break; // target is not visible
+ }
+ if (n < stack.numseperators[0])
+ continue;
+ }
+ else
+ {
+ stack.pass = ClipToSeperators (prevstack->source, prevstack->pass, stack.pass, qfalse, &stack);
+ }
+#else
+ stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, qfalse, &stack);
+#endif
+ if (!stack.pass)
+ continue;
+
+#ifdef SEPERATORCACHE
+ if (stack.numseperators[1])
+ {
+ for (n = 0; n < stack.numseperators[1]; n++)
+ {
+ stack.pass = VisChopWinding (stack.pass, &stack, &stack.seperators[1][n]);
+ if (!stack.pass)
+ break; // target is not visible
+ }
+ }
+ else
+ {
+ stack.pass = ClipToSeperators (prevstack->pass, prevstack->source, stack.pass, qtrue, &stack);
+ }
+#else
+ stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, qtrue, &stack);
+#endif
+ if (!stack.pass)
+ continue;
+
+ // mark the portal as visible
+ thread->base->portalvis[pnum>>3] |= (1<<(pnum&7));
+
+ // flow through it for real
+ RecursivePassagePortalFlow(p, thread, &stack);
+ //
+ stack.next = NULL;
+ }
+}
+
+/*
+===============
+PassagePortalFlow
+===============
+*/
+void PassagePortalFlow (int portalnum)
+{
+ threaddata_t data;
+ int i;
+ vportal_t *p;
+// int c_might, c_can;
+
+#ifdef MREDEBUG
+ _printf("\r%6d", portalnum);
+#endif
+
+ p = sorted_portals[portalnum];
+
+ if (p->removed)
+ {
+ p->status = stat_done;
+ return;
+ }
+
+ p->status = stat_working;
+
+// c_might = CountBits (p->portalflood, numportals*2);
+
+ memset (&data, 0, sizeof(data));
+ data.base = p;
+
+ data.pstack_head.portal = p;
+ data.pstack_head.source = p->winding;
+ data.pstack_head.portalplane = p->plane;
+ data.pstack_head.depth = 0;
+ for (i=0 ; i<portallongs ; i++)
+ ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[i];
+
+ RecursivePassagePortalFlow (p, &data, &data.pstack_head);
+
+ p->status = stat_done;
+
+ /*
+ c_can = CountBits (p->portalvis, numportals*2);
+
+ qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n",
+ (int)(p - portals), c_might, c_can, data.c_chains);
+ */
+}
+
+winding_t *PassageChopWinding (winding_t *in, winding_t *out, plane_t *split)
+{
+ vec_t dists[128];
+ int sides[128];
+ int counts[3];
+ vec_t dot;
+ int i, j;
+ vec_t *p1, *p2;
+ vec3_t mid;
+ winding_t *neww;
+
+ counts[0] = counts[1] = counts[2] = 0;
+
+ // determine sides for each point
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ dot = DotProduct (in->points[i], split->normal);
+ dot -= split->dist;
+ dists[i] = dot;
+ if (dot > ON_EPSILON)
+ sides[i] = SIDE_FRONT;
+ else if (dot < -ON_EPSILON)
+ sides[i] = SIDE_BACK;
+ else
+ {
+ sides[i] = SIDE_ON;
+ }
+ counts[sides[i]]++;
+ }
+
+ if (!counts[1])
+ return in; // completely on front side
+
+ if (!counts[0])
+ {
+ return NULL;
+ }
+
+ sides[i] = sides[0];
+ dists[i] = dists[0];
+
+ neww = out;
+
+ neww->numpoints = 0;
+
+ for (i=0 ; i<in->numpoints ; i++)
+ {
+ p1 = in->points[i];
+
+ if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
+ {
+ return in; // can't chop -- fall back to original
+ }
+
+ if (sides[i] == SIDE_ON)
+ {
+ VectorCopy (p1, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ continue;
+ }
+
+ if (sides[i] == SIDE_FRONT)
+ {
+ VectorCopy (p1, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ }
+
+ if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
+ continue;
+
+ if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING)
+ {
+ return in; // can't chop -- fall back to original
+ }
+
+ // generate a split point
+ p2 = in->points[(i+1)%in->numpoints];
+
+ dot = dists[i] / (dists[i]-dists[i+1]);
+ for (j=0 ; j<3 ; j++)
+ { // avoid round off error when possible
+ if (split->normal[j] == 1)
+ mid[j] = split->dist;
+ else if (split->normal[j] == -1)
+ mid[j] = -split->dist;
+ else
+ mid[j] = p1[j] + dot*(p2[j]-p1[j]);
+ }
+
+ VectorCopy (mid, neww->points[neww->numpoints]);
+ neww->numpoints++;
+ }
+
+ return neww;
+}
+
+/*
+===============
+AddSeperators
+===============
+*/
+int AddSeperators (winding_t *source, winding_t *pass, qboolean flipclip, plane_t *seperators, int maxseperators)
+{
+ int i, j, k, l;
+ plane_t plane;
+ vec3_t v1, v2;
+ float d;
+ vec_t length;
+ int counts[3], numseperators;
+ qboolean fliptest;
+
+ numseperators = 0;
+ // check all combinations
+ for (i=0 ; i<source->numpoints ; i++)
+ {
+ l = (i+1)%source->numpoints;
+ VectorSubtract (source->points[l] , source->points[i], v1);
+
+ // find a vertex of pass that makes a plane that puts all of the
+ // vertexes of pass on the front side and all of the vertexes of
+ // source on the back side
+ for (j=0 ; j<pass->numpoints ; j++)
+ {
+ VectorSubtract (pass->points[j], source->points[i], v2);
+
+ plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
+ plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2];
+ plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
+
+ // if points don't make a valid plane, skip it
+
+ length = plane.normal[0] * plane.normal[0]
+ + plane.normal[1] * plane.normal[1]
+ + plane.normal[2] * plane.normal[2];
+
+ if (length < ON_EPSILON)
+ continue;
+
+ length = 1/sqrt(length);
+
+ plane.normal[0] *= length;
+ plane.normal[1] *= length;
+ plane.normal[2] *= length;
+
+ plane.dist = DotProduct (pass->points[j], plane.normal);
+
+ //
+ // find out which side of the generated seperating plane has the
+ // source portal
+ //
+#if 1
+ fliptest = qfalse;
+ for (k=0 ; k<source->numpoints ; k++)
+ {
+ if (k == i || k == l)
+ continue;
+ d = DotProduct (source->points[k], plane.normal) - plane.dist;
+ if (d < -ON_EPSILON)
+ { // source is on the negative side, so we want all
+ // pass and target on the positive side
+ fliptest = qfalse;
+ break;
+ }
+ else if (d > ON_EPSILON)
+ { // source is on the positive side, so we want all
+ // pass and target on the negative side
+ fliptest = qtrue;
+ break;
+ }
+ }
+ if (k == source->numpoints)
+ continue; // planar with source portal
+#else
+ fliptest = flipclip;
+#endif
+ //
+ // flip the normal if the source portal is backwards
+ //
+ if (fliptest)
+ {
+ VectorSubtract (vec3_origin, plane.normal, plane.normal);
+ plane.dist = -plane.dist;
+ }
+#if 1
+ //
+ // if all of the pass portal points are now on the positive side,
+ // this is the seperating plane
+ //
+ counts[0] = counts[1] = counts[2] = 0;
+ for (k=0 ; k<pass->numpoints ; k++)
+ {
+ if (k==j)
+ continue;
+ d = DotProduct (pass->points[k], plane.normal) - plane.dist;
+ if (d < -ON_EPSILON)
+ break;
+ else if (d > ON_EPSILON)
+ counts[0]++;
+ else
+ counts[2]++;
+ }
+ if (k != pass->numpoints)
+ continue; // points on negative side, not a seperating plane
+
+ if (!counts[0])
+ continue; // planar with seperating plane
+#else
+ k = (j+1)%pass->numpoints;
+ d = DotProduct (pass->points[k], plane.normal) - plane.dist;
+ if (d < -ON_EPSILON)
+ continue;
+ k = (j+pass->numpoints-1)%pass->numpoints;
+ d = DotProduct (pass->points[k], plane.normal) - plane.dist;
+ if (d < -ON_EPSILON)
+ continue;
+#endif
+ //
+ // flip the normal if we want the back side
+ //
+ if (flipclip)
+ {
+ VectorSubtract (vec3_origin, plane.normal, plane.normal);
+ plane.dist = -plane.dist;
+ }
+
+ if (numseperators >= maxseperators)
+ Error("max seperators");
+ seperators[numseperators] = plane;
+ numseperators++;
+ break;
+ }
+ }
+ return numseperators;
+}
+
+/*
+===============
+CreatePassages
+
+MrE: create passages from one portal to all the portals in the leaf the portal leads to
+ every passage has a cansee bit string with all the portals that can be
+ seen through the passage
+===============
+*/
+void CreatePassages(int portalnum)
+{
+ int i, j, k, n, numseperators, numsee;
+ float d;
+ vportal_t *portal, *p, *target;
+ leaf_t *leaf;
+ passage_t *passage, *lastpassage;
+ plane_t seperators[MAX_SEPERATORS*2];
+ winding_t *w;
+ winding_t in, out, *res;
+
+#ifdef MREDEBUG
+ _printf("\r%6d", portalnum);
+#endif
+
+ portal = sorted_portals[portalnum];
+
+ if (portal->removed)
+ {
+ portal->status = stat_done;
+ return;
+ }
+
+ lastpassage = NULL;
+ leaf = &leafs[portal->leaf];
+ for (i = 0; i < leaf->numportals; i++)
+ {
+ target = leaf->portals[i];
+ if (target->removed)
+ continue;
+
+ passage = (passage_t *) malloc(sizeof(passage_t) + portalbytes);
+ memset(passage, 0, sizeof(passage_t) + portalbytes);
+ numseperators = AddSeperators(portal->winding, target->winding, qfalse, seperators, MAX_SEPERATORS*2);
+ numseperators += AddSeperators(target->winding, portal->winding, qtrue, &seperators[numseperators], MAX_SEPERATORS*2-numseperators);
+
+ passage->next = NULL;
+ if (lastpassage)
+ lastpassage->next = passage;
+ else
+ portal->passages = passage;
+ lastpassage = passage;
+
+ numsee = 0;
+ //create the passage->cansee
+ for (j = 0; j < numportals * 2; j++)
+ {
+ p = &portals[j];
+ if (p->removed)
+ continue;
+ if ( ! (target->portalflood[j >> 3] & (1<<(j&7)) ) )
+ continue;
+ if ( ! (portal->portalflood[j >> 3] & (1<<(j&7)) ) )
+ continue;
+ for (k = 0; k < numseperators; k++)
+ {
+ //
+ d = DotProduct (p->origin, seperators[k].normal) - seperators[k].dist;
+ //if completely at the back of the seperator plane
+ if (d < -p->radius + ON_EPSILON)
+ break;
+ w = p->winding;
+ for (n = 0; n < w->numpoints; n++)
+ {
+ d = DotProduct (w->points[n], seperators[k].normal) - seperators[k].dist;
+ //if at the front of the seperator
+ if (d > ON_EPSILON)
+ break;
+ }
+ //if no points are at the front of the seperator
+ if (n >= w->numpoints)
+ break;
+ }
+ if (k < numseperators)
+ continue;
+ memcpy(&in, p->winding, sizeof(winding_t));
+ for (k = 0; k < numseperators; k++)
+ {
+ res = PassageChopWinding(&in, &out, &seperators[k]);
+ if (res == &out)
+ memcpy(&in, &out, sizeof(winding_t));
+ if (res == NULL)
+ break;
+ }
+ if (k < numseperators)
+ continue;
+ passage->cansee[j >> 3] |= (1<<(j&7));
+ numsee++;
+ }
+ }
+}
+
+void PassageMemory(void)
+{
+ int i, j, totalmem, totalportals;
+ vportal_t *portal, *target;
+ leaf_t *leaf;
+
+ totalmem = 0;
+ totalportals = 0;
+ for (i = 0; i < numportals; i++)
+ {
+ portal = sorted_portals[i];
+ if (portal->removed)
+ continue;
+ leaf = &leafs[portal->leaf];
+ for (j = 0; j < leaf->numportals; j++)
+ {
+ target = leaf->portals[j];
+ if (target->removed)
+ continue;
+ totalmem += sizeof(passage_t) + portalbytes;
+ totalportals++;
+ }
+ }
+ _printf("%7i average number of passages per leaf\n", totalportals / numportals);
+ _printf("%7i MB required passage memory\n", totalmem >> 10 >> 10);
+}
+
+/*
+===============================================================================
+
+This is a rough first-order aproximation that is used to trivially reject some
+of the final calculations.
+
+
+Calculates portalfront and portalflood bit vectors
+
+thinking about:
+
+typedef struct passage_s
+{
+ struct passage_s *next;
+ struct portal_s *to;
+ stryct sep_s *seperators;
+ byte *mightsee;
+} passage_t;
+
+typedef struct portal_s
+{
+ struct passage_s *passages;
+ int leaf; // leaf portal faces into
+} portal_s;
+
+leaf = portal->leaf
+clear
+for all portals
+
+
+calc portal visibility
+ clear bit vector
+ for all passages
+ passage visibility
+
+
+for a portal to be visible to a passage, it must be on the front of
+all seperating planes, and both portals must be behind the new portal
+
+===============================================================================
+*/
+
+int c_flood, c_vis;
+
+
+/*
+==================
+SimpleFlood
+
+==================
+*/
+void SimpleFlood (vportal_t *srcportal, int leafnum)
+{
+ int i;
+ leaf_t *leaf;
+ vportal_t *p;
+ int pnum;
+
+ leaf = &leafs[leafnum];
+
+ for (i=0 ; i<leaf->numportals ; i++)
+ {
+ p = leaf->portals[i];
+ if (p->removed)
+ continue;
+ pnum = p - portals;
+ if ( ! (srcportal->portalfront[pnum>>3] & (1<<(pnum&7)) ) )
+ continue;
+
+ if (srcportal->portalflood[pnum>>3] & (1<<(pnum&7)) )
+ continue;
+
+ srcportal->portalflood[pnum>>3] |= (1<<(pnum&7));
+
+ SimpleFlood (srcportal, p->leaf);
+ }
+}
+
+/*
+==============
+BasePortalVis
+==============
+*/
+void BasePortalVis (int portalnum)
+{
+ int j, k;
+ vportal_t *tp, *p;
+ float d;
+ winding_t *w;
+
+ p = portals+portalnum;
+
+ if (p->removed)
+ return;
+
+ p->portalfront = malloc (portalbytes);
+ memset (p->portalfront, 0, portalbytes);
+
+ p->portalflood = malloc (portalbytes);
+ memset (p->portalflood, 0, portalbytes);
+
+ p->portalvis = malloc (portalbytes);
+ memset (p->portalvis, 0, portalbytes);
+
+ for (j=0, tp = portals ; j<numportals*2 ; j++, tp++)
+ {
+ if (j == portalnum)
+ continue;
+ if (tp->removed)
+ continue;
+ /*
+ if (farplanedist >= 0)
+ {
+ vec3_t dir;
+ VectorSubtract(p->origin, tp->origin, dir);
+ if (VectorLength(dir) > farplanedist - p->radius - tp->radius)
+ continue;
+ }
+ */
+ w = tp->winding;
+ for (k=0 ; k<w->numpoints ; k++)
+ {
+ d = DotProduct (w->points[k], p->plane.normal)
+ - p->plane.dist;
+ if (d > ON_EPSILON)
+ break;
+ }
+ if (k == w->numpoints)
+ continue; // no points on front
+
+ w = p->winding;
+ for (k=0 ; k<w->numpoints ; k++)
+ {
+ d = DotProduct (w->points[k], tp->plane.normal)
+ - tp->plane.dist;
+ if (d < -ON_EPSILON)
+ break;
+ }
+ if (k == w->numpoints)
+ continue; // no points on front
+
+ p->portalfront[j>>3] |= (1<<(j&7));
+ }
+
+ SimpleFlood (p, p->leaf);
+
+ p->nummightsee = CountBits (p->portalflood, numportals*2);
+// _printf ("portal %i: %i mightsee\n", portalnum, p->nummightsee);
+ c_flood += p->nummightsee;
+}
+
+
+
+
+
+/*
+===============================================================================
+
+This is a second order aproximation
+
+Calculates portalvis bit vector
+
+WAAAAAAY too slow.
+
+===============================================================================
+*/
+
+/*
+==================
+RecursiveLeafBitFlow
+
+==================
+*/
+void RecursiveLeafBitFlow (int leafnum, byte *mightsee, byte *cansee)
+{
+ vportal_t *p;
+ leaf_t *leaf;
+ int i, j;
+ long more;
+ int pnum;
+ byte newmight[MAX_PORTALS/8];
+
+ leaf = &leafs[leafnum];
+
+ // check all portals for flowing into other leafs
+ for (i=0 ; i<leaf->numportals ; i++)
+ {
+ p = leaf->portals[i];
+ if (p->removed)
+ continue;
+ pnum = p - portals;
+
+ // if some previous portal can't see it, skip
+ if (! (mightsee[pnum>>3] & (1<<(pnum&7)) ) )
+ continue;
+
+ // if this portal can see some portals we mightsee, recurse
+ more = 0;
+ for (j=0 ; j<portallongs ; j++)
+ {
+ ((long *)newmight)[j] = ((long *)mightsee)[j]
+ & ((long *)p->portalflood)[j];
+ more |= ((long *)newmight)[j] & ~((long *)cansee)[j];
+ }
+
+ if (!more)
+ continue; // can't see anything new
+
+ cansee[pnum>>3] |= (1<<(pnum&7));
+
+ RecursiveLeafBitFlow (p->leaf, newmight, cansee);
+ }
+}
+
+/*
+==============
+BetterPortalVis
+==============
+*/
+void BetterPortalVis (int portalnum)
+{
+ vportal_t *p;
+
+ p = portals+portalnum;
+
+ if (p->removed)
+ return;
+
+ RecursiveLeafBitFlow (p->leaf, p->portalflood, p->portalvis);
+
+ // build leaf vis information
+ p->nummightsee = CountBits (p->portalvis, numportals*2);
+ c_vis += p->nummightsee;
+}
+
+
diff --git a/q3map/writebsp.c b/q3map/writebsp.c
index 7a56d88..7b9e3ff 100755
--- a/q3map/writebsp.c
+++ b/q3map/writebsp.c
@@ -19,400 +19,400 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-#include "qbsp.h"
-
-/*
-============
-EmitShader
-============
-*/
-int EmitShader( const char *shader ) {
- int i;
- shaderInfo_t *si;
-
- if ( !shader ) {
- shader = "noshader";
- }
-
- for ( i = 0 ; i < numShaders ; i++ ) {
- if ( !Q_stricmp( shader, dshaders[i].shader ) ) {
- return i;
- }
- }
-
- if ( i == MAX_MAP_SHADERS ) {
- Error( "MAX_MAP_SHADERS" );
- }
- numShaders++;
- strcpy( dshaders[i].shader, shader );
-
- si = ShaderInfoForShader( shader );
- dshaders[i].surfaceFlags = si->surfaceFlags;
- dshaders[i].contentFlags = si->contents;
-
- return i;
-}
-
-
-/*
-============
-EmitPlanes
-
-There is no oportunity to discard planes, because all of the original
-brushes will be saved in the map.
-============
-*/
-void EmitPlanes (void)
-{
- int i;
- dplane_t *dp;
- plane_t *mp;
-
- mp = mapplanes;
- for (i=0 ; i<nummapplanes ; i++, mp++)
- {
- dp = &dplanes[numplanes];
- VectorCopy ( mp->normal, dp->normal);
- dp->dist = mp->dist;
- numplanes++;
- }
-}
-
-
-
-/*
-==================
-EmitLeaf
-==================
-*/
-void EmitLeaf (node_t *node)
-{
- dleaf_t *leaf_p;
- bspbrush_t *b;
- drawSurfRef_t *dsr;
-
- // emit a leaf
- if (numleafs >= MAX_MAP_LEAFS)
- Error ("MAX_MAP_LEAFS");
-
- leaf_p = &dleafs[numleafs];
- numleafs++;
-
- leaf_p->cluster = node->cluster;
- leaf_p->area = node->area;
-
- //
- // write bounding box info
- //
- VectorCopy (node->mins, leaf_p->mins);
- VectorCopy (node->maxs, leaf_p->maxs);
-
- //
- // write the leafbrushes
- //
- leaf_p->firstLeafBrush = numleafbrushes;
- for ( b = node->brushlist ; b ; b = b->next ) {
- if ( numleafbrushes >= MAX_MAP_LEAFBRUSHES ) {
- Error( "MAX_MAP_LEAFBRUSHES" );
- }
- dleafbrushes[numleafbrushes] = b->original->outputNumber;
- numleafbrushes++;
- }
- leaf_p->numLeafBrushes = numleafbrushes - leaf_p->firstLeafBrush;
-
- //
- // write the surfaces visible in this leaf
- //
- if ( node->opaque ) {
- return; // no leaffaces in solids
- }
-
- // add the drawSurfRef_t drawsurfs
- leaf_p->firstLeafSurface = numleafsurfaces;
- for ( dsr = node->drawSurfReferences ; dsr ; dsr = dsr->nextRef ) {
- if ( numleafsurfaces >= MAX_MAP_LEAFFACES)
- Error ("MAX_MAP_LEAFFACES");
- dleafsurfaces[numleafsurfaces] = dsr->outputNumber;
- numleafsurfaces++;
- }
-
-
- leaf_p->numLeafSurfaces = numleafsurfaces - leaf_p->firstLeafSurface;
-}
-
-
-/*
-============
-EmitDrawNode_r
-============
-*/
-int EmitDrawNode_r (node_t *node)
-{
- dnode_t *n;
- int i;
-
- if (node->planenum == PLANENUM_LEAF)
- {
- EmitLeaf (node);
- return -numleafs;
- }
-
- // emit a node
- if (numnodes == MAX_MAP_NODES)
- Error ("MAX_MAP_NODES");
- n = &dnodes[numnodes];
- numnodes++;
-
- VectorCopy (node->mins, n->mins);
- VectorCopy (node->maxs, n->maxs);
-
- if (node->planenum & 1)
- Error ("WriteDrawNodes_r: odd planenum");
- n->planeNum = node->planenum;
-
- //
- // recursively output the other nodes
- //
- for (i=0 ; i<2 ; i++)
- {
- if (node->children[i]->planenum == PLANENUM_LEAF)
- {
- n->children[i] = -(numleafs + 1);
- EmitLeaf (node->children[i]);
- }
- else
- {
- n->children[i] = numnodes;
- EmitDrawNode_r (node->children[i]);
- }
- }
-
- return n - dnodes;
-}
-
-//=========================================================
-
-
-
-/*
-============
-SetModelNumbers
-============
-*/
-void SetModelNumbers (void)
-{
- int i;
- int models;
- char value[10];
-
- models = 1;
- for ( i=1 ; i<num_entities ; i++ ) {
- if ( entities[i].brushes || entities[i].patches ) {
- sprintf ( value, "*%i", models );
- models++;
- SetKeyValue (&entities[i], "model", value);
- }
- }
-
-}
-
-/*
-============
-SetLightStyles
-============
-*/
-#define MAX_SWITCHED_LIGHTS 32
-void SetLightStyles (void)
-{
- int stylenum;
- const char *t;
- entity_t *e;
- int i, j;
- char value[10];
- char lighttargets[MAX_SWITCHED_LIGHTS][64];
-
-
- // any light that is controlled (has a targetname)
- // must have a unique style number generated for it
-
- stylenum = 0;
- for (i=1 ; i<num_entities ; i++)
- {
- e = &entities[i];
-
- t = ValueForKey (e, "classname");
- if (Q_strncasecmp (t, "light", 5))
- continue;
- t = ValueForKey (e, "targetname");
- if (!t[0])
- continue;
-
- // find this targetname
- for (j=0 ; j<stylenum ; j++)
- if (!strcmp (lighttargets[j], t))
- break;
- if (j == stylenum)
- {
- if (stylenum == MAX_SWITCHED_LIGHTS)
- Error ("stylenum == MAX_SWITCHED_LIGHTS");
- strcpy (lighttargets[j], t);
- stylenum++;
- }
- sprintf (value, "%i", 32 + j);
- SetKeyValue (e, "style", value);
- }
-
-}
-
-//===========================================================
-
-/*
-==================
-BeginBSPFile
-==================
-*/
-void BeginBSPFile( void ) {
- // these values may actually be initialized
- // if the file existed when loaded, so clear them explicitly
- nummodels = 0;
- numnodes = 0;
- numbrushsides = 0;
- numleafsurfaces = 0;
- numleafbrushes = 0;
-
- // leave leaf 0 as an error, because leafs are referenced as
- // negative number nodes
- numleafs = 1;
-}
-
-
-/*
-============
-EndBSPFile
-============
-*/
-void EndBSPFile( void ) {
- char path[1024];
-
- EmitPlanes ();
- UnparseEntities ();
-
- // write the map
- sprintf (path, "%s.bsp", source);
- _printf ("Writing %s\n", path);
- WriteBSPFile (path);
-}
-
-
-//===========================================================
-
-/*
-============
-EmitBrushes
-============
-*/
-void EmitBrushes ( bspbrush_t *brushes ) {
- int j;
- dbrush_t *db;
- bspbrush_t *b;
- dbrushside_t *cp;
-
- for ( b = brushes ; b ; b = b->next ) {
- if ( numbrushes == MAX_MAP_BRUSHES ) {
- Error( "MAX_MAP_BRUSHES" );
- }
- b->outputNumber = numbrushes;
- db = &dbrushes[numbrushes];
- numbrushes++;
-
- db->shaderNum = EmitShader( b->contentShader->shader );
- db->firstSide = numbrushsides;
-
- // don't emit any generated backSide sides
- db->numSides = 0;
- for ( j=0 ; j<b->numsides ; j++ ) {
- if ( b->sides[j].backSide ) {
- continue;
- }
- if ( numbrushsides == MAX_MAP_BRUSHSIDES ) {
- Error( "MAX_MAP_BRUSHSIDES ");
- }
- cp = &dbrushsides[numbrushsides];
- db->numSides++;
- numbrushsides++;
- cp->planeNum = b->sides[j].planenum;
- cp->shaderNum = EmitShader( b->sides[j].shaderInfo->shader );
- }
- }
-
-}
-
-
-/*
-==================
-BeginModel
-==================
-*/
-void BeginModel( void ) {
- dmodel_t *mod;
- bspbrush_t *b;
- entity_t *e;
- vec3_t mins, maxs;
- parseMesh_t *p;
- int i;
-
- if ( nummodels == MAX_MAP_MODELS ) {
- Error( "MAX_MAP_MODELS" );
- }
- mod = &dmodels[nummodels];
-
- //
- // bound the brushes
- //
- e = &entities[entity_num];
-
- ClearBounds (mins, maxs);
- for ( b = e->brushes ; b ; b = b->next ) {
- if ( !b->numsides ) {
- continue; // not a real brush (origin brush, etc)
- }
- AddPointToBounds (b->mins, mins, maxs);
- AddPointToBounds (b->maxs, mins, maxs);
- }
-
- for ( p = e->patches ; p ; p = p->next ) {
- for ( i = 0 ; i < p->mesh.width * p->mesh.height ; i++ ) {
- AddPointToBounds( p->mesh.verts[i].xyz, mins, maxs );
- }
- }
-
- VectorCopy (mins, mod->mins);
- VectorCopy (maxs, mod->maxs);
-
- mod->firstSurface = numDrawSurfaces;
- mod->firstBrush = numbrushes;
-
- EmitBrushes( e->brushes );
-}
-
-
-
-
-/*
-==================
-EndModel
-==================
-*/
-void EndModel( node_t *headnode ) {
- dmodel_t *mod;
-
- qprintf ("--- EndModel ---\n");
-
- mod = &dmodels[nummodels];
- EmitDrawNode_r (headnode);
- mod->numSurfaces = numDrawSurfaces - mod->firstSurface;
- mod->numBrushes = numbrushes - mod->firstBrush;
-
- nummodels++;
-}
-
+#include "qbsp.h"
+
+/*
+============
+EmitShader
+============
+*/
+int EmitShader( const char *shader ) {
+ int i;
+ shaderInfo_t *si;
+
+ if ( !shader ) {
+ shader = "noshader";
+ }
+
+ for ( i = 0 ; i < numShaders ; i++ ) {
+ if ( !Q_stricmp( shader, dshaders[i].shader ) ) {
+ return i;
+ }
+ }
+
+ if ( i == MAX_MAP_SHADERS ) {
+ Error( "MAX_MAP_SHADERS" );
+ }
+ numShaders++;
+ strcpy( dshaders[i].shader, shader );
+
+ si = ShaderInfoForShader( shader );
+ dshaders[i].surfaceFlags = si->surfaceFlags;
+ dshaders[i].contentFlags = si->contents;
+
+ return i;
+}
+
+
+/*
+============
+EmitPlanes
+
+There is no oportunity to discard planes, because all of the original
+brushes will be saved in the map.
+============
+*/
+void EmitPlanes (void)
+{
+ int i;
+ dplane_t *dp;
+ plane_t *mp;
+
+ mp = mapplanes;
+ for (i=0 ; i<nummapplanes ; i++, mp++)
+ {
+ dp = &dplanes[numplanes];
+ VectorCopy ( mp->normal, dp->normal);
+ dp->dist = mp->dist;
+ numplanes++;
+ }
+}
+
+
+
+/*
+==================
+EmitLeaf
+==================
+*/
+void EmitLeaf (node_t *node)
+{
+ dleaf_t *leaf_p;
+ bspbrush_t *b;
+ drawSurfRef_t *dsr;
+
+ // emit a leaf
+ if (numleafs >= MAX_MAP_LEAFS)
+ Error ("MAX_MAP_LEAFS");
+
+ leaf_p = &dleafs[numleafs];
+ numleafs++;
+
+ leaf_p->cluster = node->cluster;
+ leaf_p->area = node->area;
+
+ //
+ // write bounding box info
+ //
+ VectorCopy (node->mins, leaf_p->mins);
+ VectorCopy (node->maxs, leaf_p->maxs);
+
+ //
+ // write the leafbrushes
+ //
+ leaf_p->firstLeafBrush = numleafbrushes;
+ for ( b = node->brushlist ; b ; b = b->next ) {
+ if ( numleafbrushes >= MAX_MAP_LEAFBRUSHES ) {
+ Error( "MAX_MAP_LEAFBRUSHES" );
+ }
+ dleafbrushes[numleafbrushes] = b->original->outputNumber;
+ numleafbrushes++;
+ }
+ leaf_p->numLeafBrushes = numleafbrushes - leaf_p->firstLeafBrush;
+
+ //
+ // write the surfaces visible in this leaf
+ //
+ if ( node->opaque ) {
+ return; // no leaffaces in solids
+ }
+
+ // add the drawSurfRef_t drawsurfs
+ leaf_p->firstLeafSurface = numleafsurfaces;
+ for ( dsr = node->drawSurfReferences ; dsr ; dsr = dsr->nextRef ) {
+ if ( numleafsurfaces >= MAX_MAP_LEAFFACES)
+ Error ("MAX_MAP_LEAFFACES");
+ dleafsurfaces[numleafsurfaces] = dsr->outputNumber;
+ numleafsurfaces++;
+ }
+
+
+ leaf_p->numLeafSurfaces = numleafsurfaces - leaf_p->firstLeafSurface;
+}
+
+
+/*
+============
+EmitDrawNode_r
+============
+*/
+int EmitDrawNode_r (node_t *node)
+{
+ dnode_t *n;
+ int i;
+
+ if (node->planenum == PLANENUM_LEAF)
+ {
+ EmitLeaf (node);
+ return -numleafs;
+ }
+
+ // emit a node
+ if (numnodes == MAX_MAP_NODES)
+ Error ("MAX_MAP_NODES");
+ n = &dnodes[numnodes];
+ numnodes++;
+
+ VectorCopy (node->mins, n->mins);
+ VectorCopy (node->maxs, n->maxs);
+
+ if (node->planenum & 1)
+ Error ("WriteDrawNodes_r: odd planenum");
+ n->planeNum = node->planenum;
+
+ //
+ // recursively output the other nodes
+ //
+ for (i=0 ; i<2 ; i++)
+ {
+ if (node->children[i]->planenum == PLANENUM_LEAF)
+ {
+ n->children[i] = -(numleafs + 1);
+ EmitLeaf (node->children[i]);
+ }
+ else
+ {
+ n->children[i] = numnodes;
+ EmitDrawNode_r (node->children[i]);
+ }
+ }
+
+ return n - dnodes;
+}
+
+//=========================================================
+
+
+
+/*
+============
+SetModelNumbers
+============
+*/
+void SetModelNumbers (void)
+{
+ int i;
+ int models;
+ char value[10];
+
+ models = 1;
+ for ( i=1 ; i<num_entities ; i++ ) {
+ if ( entities[i].brushes || entities[i].patches ) {
+ sprintf ( value, "*%i", models );
+ models++;
+ SetKeyValue (&entities[i], "model", value);
+ }
+ }
+
+}
+
+/*
+============
+SetLightStyles
+============
+*/
+#define MAX_SWITCHED_LIGHTS 32
+void SetLightStyles (void)
+{
+ int stylenum;
+ const char *t;
+ entity_t *e;
+ int i, j;
+ char value[10];
+ char lighttargets[MAX_SWITCHED_LIGHTS][64];
+
+
+ // any light that is controlled (has a targetname)
+ // must have a unique style number generated for it
+
+ stylenum = 0;
+ for (i=1 ; i<num_entities ; i++)
+ {
+ e = &entities[i];
+
+ t = ValueForKey (e, "classname");
+ if (Q_strncasecmp (t, "light", 5))
+ continue;
+ t = ValueForKey (e, "targetname");
+ if (!t[0])
+ continue;
+
+ // find this targetname
+ for (j=0 ; j<stylenum ; j++)
+ if (!strcmp (lighttargets[j], t))
+ break;
+ if (j == stylenum)
+ {
+ if (stylenum == MAX_SWITCHED_LIGHTS)
+ Error ("stylenum == MAX_SWITCHED_LIGHTS");
+ strcpy (lighttargets[j], t);
+ stylenum++;
+ }
+ sprintf (value, "%i", 32 + j);
+ SetKeyValue (e, "style", value);
+ }
+
+}
+
+//===========================================================
+
+/*
+==================
+BeginBSPFile
+==================
+*/
+void BeginBSPFile( void ) {
+ // these values may actually be initialized
+ // if the file existed when loaded, so clear them explicitly
+ nummodels = 0;
+ numnodes = 0;
+ numbrushsides = 0;
+ numleafsurfaces = 0;
+ numleafbrushes = 0;
+
+ // leave leaf 0 as an error, because leafs are referenced as
+ // negative number nodes
+ numleafs = 1;
+}
+
+
+/*
+============
+EndBSPFile
+============
+*/
+void EndBSPFile( void ) {
+ char path[1024];
+
+ EmitPlanes ();
+ UnparseEntities ();
+
+ // write the map
+ sprintf (path, "%s.bsp", source);
+ _printf ("Writing %s\n", path);
+ WriteBSPFile (path);
+}
+
+
+//===========================================================
+
+/*
+============
+EmitBrushes
+============
+*/
+void EmitBrushes ( bspbrush_t *brushes ) {
+ int j;
+ dbrush_t *db;
+ bspbrush_t *b;
+ dbrushside_t *cp;
+
+ for ( b = brushes ; b ; b = b->next ) {
+ if ( numbrushes == MAX_MAP_BRUSHES ) {
+ Error( "MAX_MAP_BRUSHES" );
+ }
+ b->outputNumber = numbrushes;
+ db = &dbrushes[numbrushes];
+ numbrushes++;
+
+ db->shaderNum = EmitShader( b->contentShader->shader );
+ db->firstSide = numbrushsides;
+
+ // don't emit any generated backSide sides
+ db->numSides = 0;
+ for ( j=0 ; j<b->numsides ; j++ ) {
+ if ( b->sides[j].backSide ) {
+ continue;
+ }
+ if ( numbrushsides == MAX_MAP_BRUSHSIDES ) {
+ Error( "MAX_MAP_BRUSHSIDES ");
+ }
+ cp = &dbrushsides[numbrushsides];
+ db->numSides++;
+ numbrushsides++;
+ cp->planeNum = b->sides[j].planenum;
+ cp->shaderNum = EmitShader( b->sides[j].shaderInfo->shader );
+ }
+ }
+
+}
+
+
+/*
+==================
+BeginModel
+==================
+*/
+void BeginModel( void ) {
+ dmodel_t *mod;
+ bspbrush_t *b;
+ entity_t *e;
+ vec3_t mins, maxs;
+ parseMesh_t *p;
+ int i;
+
+ if ( nummodels == MAX_MAP_MODELS ) {
+ Error( "MAX_MAP_MODELS" );
+ }
+ mod = &dmodels[nummodels];
+
+ //
+ // bound the brushes
+ //
+ e = &entities[entity_num];
+
+ ClearBounds (mins, maxs);
+ for ( b = e->brushes ; b ; b = b->next ) {
+ if ( !b->numsides ) {
+ continue; // not a real brush (origin brush, etc)
+ }
+ AddPointToBounds (b->mins, mins, maxs);
+ AddPointToBounds (b->maxs, mins, maxs);
+ }
+
+ for ( p = e->patches ; p ; p = p->next ) {
+ for ( i = 0 ; i < p->mesh.width * p->mesh.height ; i++ ) {
+ AddPointToBounds( p->mesh.verts[i].xyz, mins, maxs );
+ }
+ }
+
+ VectorCopy (mins, mod->mins);
+ VectorCopy (maxs, mod->maxs);
+
+ mod->firstSurface = numDrawSurfaces;
+ mod->firstBrush = numbrushes;
+
+ EmitBrushes( e->brushes );
+}
+
+
+
+
+/*
+==================
+EndModel
+==================
+*/
+void EndModel( node_t *headnode ) {
+ dmodel_t *mod;
+
+ qprintf ("--- EndModel ---\n");
+
+ mod = &dmodels[nummodels];
+ EmitDrawNode_r (headnode);
+ mod->numSurfaces = numDrawSurfaces - mod->firstSurface;
+ mod->numBrushes = numbrushes - mod->firstBrush;
+
+ nummodels++;
+}
+