diff options
Diffstat (limited to 'q3map')
-rwxr-xr-x | q3map/brush.c | 1680 | ||||
-rwxr-xr-x | q3map/brush_primit.c | 62 | ||||
-rwxr-xr-x | q3map/bsp.c | 1168 | ||||
-rwxr-xr-x | q3map/facebsp.c | 716 | ||||
-rwxr-xr-x | q3map/fog.c | 1066 | ||||
-rwxr-xr-x | q3map/gldraw.c | 422 | ||||
-rwxr-xr-x | q3map/glfile.c | 254 | ||||
-rwxr-xr-x | q3map/leakfile.c | 158 | ||||
-rwxr-xr-x | q3map/light.c | 4256 | ||||
-rwxr-xr-x | q3map/light.h | 260 | ||||
-rwxr-xr-x | q3map/light_trace.c | 1846 | ||||
-rwxr-xr-x | q3map/lightmaps.c | 748 | ||||
-rwxr-xr-x | q3map/lightv.c | 11452 | ||||
-rwxr-xr-x | q3map/makefile | 296 | ||||
-rwxr-xr-x | q3map/map.c | 2460 | ||||
-rwxr-xr-x | q3map/mesh.c | 1322 | ||||
-rwxr-xr-x | q3map/mesh.h | 54 | ||||
-rwxr-xr-x | q3map/misc_model.c | 902 | ||||
-rwxr-xr-x | q3map/nodraw.c | 52 | ||||
-rwxr-xr-x | q3map/patch.c | 530 | ||||
-rwxr-xr-x | q3map/portals.c | 1644 | ||||
-rwxr-xr-x | q3map/prtfile.c | 502 | ||||
-rwxr-xr-x | q3map/q3map.sln | 112 | ||||
-rwxr-xr-x | q3map/q3map.vcproj | 3212 | ||||
-rwxr-xr-x | q3map/qbsp.h | 868 | ||||
-rwxr-xr-x | q3map/shaders.c | 1174 | ||||
-rwxr-xr-x | q3map/shaders.h | 100 | ||||
-rwxr-xr-x | q3map/soundv.c | 11442 | ||||
-rwxr-xr-x | q3map/surface.c | 2274 | ||||
-rwxr-xr-x | q3map/terrain.c | 2468 | ||||
-rwxr-xr-x | q3map/tjunction.c | 1060 | ||||
-rwxr-xr-x | q3map/tree.c | 250 | ||||
-rwxr-xr-x | q3map/vis.c | 2352 | ||||
-rwxr-xr-x | q3map/vis.h | 282 | ||||
-rwxr-xr-x | q3map/visflow.c | 3272 | ||||
-rwxr-xr-x | q3map/writebsp.c | 794 |
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=""$/source/q3map", 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=""$/source/q3map", 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++; +} + |