mirror of
https://github.com/id-Software/Quake-2-Tools.git
synced 2026-03-19 16:39:44 +01:00
The Quake 2 tools as originally released under the GPL license.
This commit is contained in:
1776
bsp/bsp.mak
Normal file
1776
bsp/bsp.mak
Normal file
File diff suppressed because it is too large
Load Diff
56
bsp/bspinfo3/bspinfo3.c
Normal file
56
bsp/bspinfo3/bspinfo3.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; 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"
|
||||
|
||||
void main (int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
char source[1024];
|
||||
int size;
|
||||
FILE *f;
|
||||
|
||||
if (argc == 1)
|
||||
Error ("usage: bspinfo bspfile [bspfiles]");
|
||||
|
||||
for (i=1 ; i<argc ; i++)
|
||||
{
|
||||
printf ("---------------------\n");
|
||||
strcpy (source, argv[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");
|
||||
}
|
||||
}
|
||||
53
bsp/bspinfo3/makefile
Normal file
53
bsp/bspinfo3/makefile
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
CFLAGS = -c
|
||||
LDFLAGS =
|
||||
ODIR = baddir
|
||||
|
||||
EXEBASE = bspinfo3
|
||||
EXE = $(ODIR)/bspinfo3
|
||||
all: $(EXE)
|
||||
|
||||
_next:
|
||||
make "CFLAGS = -c -g -I../../common -DDOUBLEVEC_T" "ODIR = next"
|
||||
|
||||
_irix:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
|
||||
_irixdebug:
|
||||
make "CFLAGS = -c -O2 -g -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -g" "ODIR = irix"
|
||||
|
||||
_irixinst:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
_irixclean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
_osf:
|
||||
make "CFLAGS = -c -O4 -I../../common -threads -DDOUBLEVEC_T" "LDFLAGS = -threads" "ODIR = osf"
|
||||
|
||||
clean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
install:
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
|
||||
FILES = $(ODIR)/bspinfo3.o $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/scriplib.o
|
||||
|
||||
$(EXE) : $(FILES)
|
||||
cc -o $(EXE) $(LDFLAGS) $(FILES)
|
||||
|
||||
$(ODIR)/bspinfo3.o : bspinfo3.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)/scriplib.o : ../../common/scriplib.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
|
||||
1330
bsp/qbsp3/brushbsp.c
Normal file
1330
bsp/qbsp3/brushbsp.c
Normal file
File diff suppressed because it is too large
Load Diff
635
bsp/qbsp3/csg.c
Normal file
635
bsp/qbsp3/csg.c
Normal file
@@ -0,0 +1,635 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qbsp.h"
|
||||
|
||||
/*
|
||||
|
||||
tag all brushes with original contents
|
||||
brushes may contain multiple contents
|
||||
there will be no brush overlap after csg phase
|
||||
|
||||
|
||||
|
||||
|
||||
each side has a count of the other sides it splits
|
||||
|
||||
the best split will be the one that minimizes the total split counts
|
||||
of all remaining sides
|
||||
|
||||
precalc side on plane table
|
||||
|
||||
evaluate split side
|
||||
{
|
||||
cost = 0
|
||||
for all sides
|
||||
for all sides
|
||||
get
|
||||
if side splits side and splitside is on same child
|
||||
cost++;
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
void SplitBrush2 (bspbrush_t *brush, int planenum,
|
||||
bspbrush_t **front, bspbrush_t **back)
|
||||
{
|
||||
SplitBrush (brush, planenum, front, back);
|
||||
#if 0
|
||||
if (*front && (*front)->sides[(*front)->numsides-1].texinfo == -1)
|
||||
(*front)->sides[(*front)->numsides-1].texinfo = (*front)->sides[0].texinfo; // not -1
|
||||
if (*back && (*back)->sides[(*back)->numsides-1].texinfo == -1)
|
||||
(*back)->sides[(*back)->numsides-1].texinfo = (*back)->sides[0].texinfo; // not -1
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
SubtractBrush
|
||||
|
||||
Returns a list of brushes that remain after B is subtracted from A.
|
||||
May by empty if A is contained inside B.
|
||||
|
||||
The originals are undisturbed.
|
||||
===============
|
||||
*/
|
||||
bspbrush_t *SubtractBrush (bspbrush_t *a, bspbrush_t *b)
|
||||
{ // a - b = out (list)
|
||||
int i;
|
||||
bspbrush_t *front, *back;
|
||||
bspbrush_t *out, *in;
|
||||
|
||||
in = a;
|
||||
out = NULL;
|
||||
for (i=0 ; i<b->numsides && in ; i++)
|
||||
{
|
||||
SplitBrush2 (in, b->sides[i].planenum, &front, &back);
|
||||
if (in != a)
|
||||
FreeBrush (in);
|
||||
if (front)
|
||||
{ // add to list
|
||||
front->next = out;
|
||||
out = front;
|
||||
}
|
||||
in = back;
|
||||
}
|
||||
if (in)
|
||||
FreeBrush (in);
|
||||
else
|
||||
{ // didn't really intersect
|
||||
FreeBrushList (out);
|
||||
return a;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
IntersectBrush
|
||||
|
||||
Returns a single brush made up by the intersection of the
|
||||
two provided brushes, or NULL if they are disjoint.
|
||||
|
||||
The originals are undisturbed.
|
||||
===============
|
||||
*/
|
||||
bspbrush_t *IntersectBrush (bspbrush_t *a, bspbrush_t *b)
|
||||
{
|
||||
int i;
|
||||
bspbrush_t *front, *back;
|
||||
bspbrush_t *in;
|
||||
|
||||
in = a;
|
||||
for (i=0 ; i<b->numsides && in ; i++)
|
||||
{
|
||||
SplitBrush2 (in, b->sides[i].planenum, &front, &back);
|
||||
if (in != a)
|
||||
FreeBrush (in);
|
||||
if (front)
|
||||
FreeBrush (front);
|
||||
in = back;
|
||||
}
|
||||
|
||||
if (in == a)
|
||||
return NULL;
|
||||
|
||||
in->next = NULL;
|
||||
return in;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
BrushesDisjoint
|
||||
|
||||
Returns true if the two brushes definately do not intersect.
|
||||
There will be false negatives for some non-axial combinations.
|
||||
===============
|
||||
*/
|
||||
qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
// check bounding boxes
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (a->mins[i] >= b->maxs[i]
|
||||
|| a->maxs[i] <= b->mins[i])
|
||||
return true; // bounding boxes don't overlap
|
||||
|
||||
// check for opposing planes
|
||||
for (i=0 ; i<a->numsides ; i++)
|
||||
{
|
||||
for (j=0 ; j<b->numsides ; j++)
|
||||
{
|
||||
if (a->sides[i].planenum ==
|
||||
(b->sides[j].planenum^1) )
|
||||
return true; // opposite planes, so not touching
|
||||
}
|
||||
}
|
||||
|
||||
return false; // might intersect
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
IntersectionContents
|
||||
|
||||
Returns a content word for the intersection of two brushes.
|
||||
Some combinations will generate a combination (water + clip),
|
||||
but most will be the stronger of the two contents.
|
||||
===============
|
||||
*/
|
||||
int IntersectionContents (int c1, int c2)
|
||||
{
|
||||
int out;
|
||||
|
||||
out = c1 | c2;
|
||||
|
||||
if (out & CONTENTS_SOLID)
|
||||
out = CONTENTS_SOLID;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
int minplanenums[3];
|
||||
int maxplanenums[3];
|
||||
|
||||
/*
|
||||
===============
|
||||
ClipBrushToBox
|
||||
|
||||
Any planes shared with the box edge will be set to no texinfo
|
||||
===============
|
||||
*/
|
||||
bspbrush_t *ClipBrushToBox (bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs)
|
||||
{
|
||||
int i, j;
|
||||
bspbrush_t *front, *back;
|
||||
int p;
|
||||
|
||||
for (j=0 ; j<2 ; j++)
|
||||
{
|
||||
if (brush->maxs[j] > clipmaxs[j])
|
||||
{
|
||||
SplitBrush (brush, maxplanenums[j], &front, &back);
|
||||
if (front)
|
||||
FreeBrush (front);
|
||||
brush = back;
|
||||
if (!brush)
|
||||
return NULL;
|
||||
}
|
||||
if (brush->mins[j] < clipmins[j])
|
||||
{
|
||||
SplitBrush (brush, minplanenums[j], &front, &back);
|
||||
if (back)
|
||||
FreeBrush (back);
|
||||
brush = front;
|
||||
if (!brush)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// remove any colinear faces
|
||||
|
||||
for (i=0 ; i<brush->numsides ; i++)
|
||||
{
|
||||
p = brush->sides[i].planenum & ~1;
|
||||
if (p == maxplanenums[0] || p == maxplanenums[1]
|
||||
|| p == minplanenums[0] || p == minplanenums[1])
|
||||
{
|
||||
brush->sides[i].texinfo = TEXINFO_NODE;
|
||||
brush->sides[i].visible = false;
|
||||
}
|
||||
}
|
||||
return brush;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
MakeBspBrushList
|
||||
===============
|
||||
*/
|
||||
bspbrush_t *MakeBspBrushList (int startbrush, int endbrush,
|
||||
vec3_t clipmins, vec3_t clipmaxs)
|
||||
{
|
||||
mapbrush_t *mb;
|
||||
bspbrush_t *brushlist, *newbrush;
|
||||
int i, j;
|
||||
int c_faces;
|
||||
int c_brushes;
|
||||
int numsides;
|
||||
int vis;
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
VectorClear (normal);
|
||||
normal[i] = 1;
|
||||
dist = clipmaxs[i];
|
||||
maxplanenums[i] = FindFloatPlane (normal, dist);
|
||||
dist = clipmins[i];
|
||||
minplanenums[i] = FindFloatPlane (normal, dist);
|
||||
}
|
||||
|
||||
brushlist = NULL;
|
||||
c_faces = 0;
|
||||
c_brushes = 0;
|
||||
|
||||
for (i=startbrush ; i<endbrush ; i++)
|
||||
{
|
||||
mb = &mapbrushes[i];
|
||||
|
||||
numsides = mb->numsides;
|
||||
if (!numsides)
|
||||
continue;
|
||||
// make sure the brush has at least one face showing
|
||||
vis = 0;
|
||||
for (j=0 ; j<numsides ; j++)
|
||||
if (mb->original_sides[j].visible && mb->original_sides[j].winding)
|
||||
vis++;
|
||||
#if 0
|
||||
if (!vis)
|
||||
continue; // no faces at all
|
||||
#endif
|
||||
// if the brush is outside the clip area, skip it
|
||||
for (j=0 ; j<3 ; j++)
|
||||
if (mb->mins[j] >= clipmaxs[j]
|
||||
|| mb->maxs[j] <= clipmins[j])
|
||||
break;
|
||||
if (j != 3)
|
||||
continue;
|
||||
|
||||
//
|
||||
// make a copy of the brush
|
||||
//
|
||||
newbrush = AllocBrush (mb->numsides);
|
||||
newbrush->original = mb;
|
||||
newbrush->numsides = mb->numsides;
|
||||
memcpy (newbrush->sides, mb->original_sides, numsides*sizeof(side_t));
|
||||
for (j=0 ; j<numsides ; j++)
|
||||
{
|
||||
if (newbrush->sides[j].winding)
|
||||
newbrush->sides[j].winding = CopyWinding (newbrush->sides[j].winding);
|
||||
if (newbrush->sides[j].surf & SURF_HINT)
|
||||
newbrush->sides[j].visible = true; // hints are always visible
|
||||
}
|
||||
VectorCopy (mb->mins, newbrush->mins);
|
||||
VectorCopy (mb->maxs, newbrush->maxs);
|
||||
|
||||
//
|
||||
// carve off anything outside the clip box
|
||||
//
|
||||
newbrush = ClipBrushToBox (newbrush, clipmins, clipmaxs);
|
||||
if (!newbrush)
|
||||
continue;
|
||||
|
||||
c_faces += vis;
|
||||
c_brushes++;
|
||||
|
||||
newbrush->next = brushlist;
|
||||
brushlist = newbrush;
|
||||
}
|
||||
|
||||
return brushlist;
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
AddBspBrushListToTail
|
||||
===============
|
||||
*/
|
||||
bspbrush_t *AddBrushListToTail (bspbrush_t *list, bspbrush_t *tail)
|
||||
{
|
||||
bspbrush_t *walk, *next;
|
||||
|
||||
for (walk=list ; walk ; walk=next)
|
||||
{ // add to end of list
|
||||
next = walk->next;
|
||||
walk->next = NULL;
|
||||
tail->next = walk;
|
||||
tail = walk;
|
||||
}
|
||||
|
||||
return tail;
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
CullList
|
||||
|
||||
Builds a new list that doesn't hold the given brush
|
||||
===========
|
||||
*/
|
||||
bspbrush_t *CullList (bspbrush_t *list, bspbrush_t *skip1)
|
||||
{
|
||||
bspbrush_t *newlist;
|
||||
bspbrush_t *next;
|
||||
|
||||
newlist = NULL;
|
||||
|
||||
for ( ; list ; list = next)
|
||||
{
|
||||
next = list->next;
|
||||
if (list == skip1)
|
||||
{
|
||||
FreeBrush (list);
|
||||
continue;
|
||||
}
|
||||
list->next = newlist;
|
||||
newlist = list;
|
||||
}
|
||||
return newlist;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
WriteBrushMap
|
||||
==================
|
||||
*/
|
||||
void WriteBrushMap (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, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture);
|
||||
FreeWinding (w);
|
||||
}
|
||||
fprintf (f, "}\n");
|
||||
}
|
||||
fprintf (f, "}\n");
|
||||
|
||||
fclose (f);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
==================
|
||||
BrushGE
|
||||
|
||||
Returns true if b1 is allowed to bite b2
|
||||
==================
|
||||
*/
|
||||
qboolean BrushGE (bspbrush_t *b1, bspbrush_t *b2)
|
||||
{
|
||||
// detail brushes never bite structural brushes
|
||||
if ( (b1->original->contents & CONTENTS_DETAIL)
|
||||
&& !(b2->original->contents & CONTENTS_DETAIL) )
|
||||
return false;
|
||||
if (b1->original->contents & CONTENTS_SOLID)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
ChopBrushes
|
||||
|
||||
Carves any intersecting solid brushes into the minimum number
|
||||
of non-intersecting brushes.
|
||||
=================
|
||||
*/
|
||||
bspbrush_t *ChopBrushes (bspbrush_t *head)
|
||||
{
|
||||
bspbrush_t *b1, *b2, *next;
|
||||
bspbrush_t *tail;
|
||||
bspbrush_t *keep;
|
||||
bspbrush_t *sub, *sub2;
|
||||
int c1, c2;
|
||||
|
||||
qprintf ("---- ChopBrushes ----\n");
|
||||
qprintf ("original brushes: %i\n", CountBrushList (head));
|
||||
|
||||
#if 0
|
||||
if (startbrush == 0)
|
||||
WriteBrushList ("before.gl", head, false);
|
||||
#endif
|
||||
keep = NULL;
|
||||
|
||||
newlist:
|
||||
// find tail
|
||||
if (!head)
|
||||
return NULL;
|
||||
for (tail=head ; tail->next ; tail=tail->next)
|
||||
;
|
||||
|
||||
for (b1=head ; b1 ; b1=next)
|
||||
{
|
||||
next = b1->next;
|
||||
for (b2=b1->next ; b2 ; b2 = b2->next)
|
||||
{
|
||||
if (BrushesDisjoint (b1, b2))
|
||||
continue;
|
||||
|
||||
sub = NULL;
|
||||
sub2 = NULL;
|
||||
c1 = 999999;
|
||||
c2 = 999999;
|
||||
|
||||
if ( BrushGE (b2, b1) )
|
||||
{
|
||||
sub = SubtractBrush (b1, b2);
|
||||
if (sub == b1)
|
||||
continue; // didn't really intersect
|
||||
if (!sub)
|
||||
{ // b1 is swallowed by b2
|
||||
head = CullList (b1, b1);
|
||||
goto newlist;
|
||||
}
|
||||
c1 = CountBrushList (sub);
|
||||
}
|
||||
|
||||
if ( BrushGE (b1, b2) )
|
||||
{
|
||||
sub2 = SubtractBrush (b2, b1);
|
||||
if (sub2 == b2)
|
||||
continue; // didn't really intersect
|
||||
if (!sub2)
|
||||
{ // b2 is swallowed by b1
|
||||
FreeBrushList (sub);
|
||||
head = CullList (b1, b2);
|
||||
goto newlist;
|
||||
}
|
||||
c2 = CountBrushList (sub2);
|
||||
}
|
||||
|
||||
if (!sub && !sub2)
|
||||
continue; // neither one can bite
|
||||
|
||||
// only accept if it didn't fragment
|
||||
// (commening this out allows full fragmentation)
|
||||
if (c1 > 1 && c2 > 1)
|
||||
{
|
||||
if (sub2)
|
||||
FreeBrushList (sub2);
|
||||
if (sub)
|
||||
FreeBrushList (sub);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c1 < c2)
|
||||
{
|
||||
if (sub2)
|
||||
FreeBrushList (sub2);
|
||||
tail = AddBrushListToTail (sub, tail);
|
||||
head = CullList (b1, b1);
|
||||
goto newlist;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sub)
|
||||
FreeBrushList (sub);
|
||||
tail = AddBrushListToTail (sub2, tail);
|
||||
head = CullList (b1, b2);
|
||||
goto newlist;
|
||||
}
|
||||
}
|
||||
|
||||
if (!b2)
|
||||
{ // b1 is no longer intersecting anything, so keep it
|
||||
b1->next = keep;
|
||||
keep = b1;
|
||||
}
|
||||
}
|
||||
|
||||
qprintf ("output brushes: %i\n", CountBrushList (keep));
|
||||
#if 0
|
||||
{
|
||||
WriteBrushList ("after.gl", keep, false);
|
||||
WriteBrushMap ("after.map", keep);
|
||||
}
|
||||
#endif
|
||||
return keep;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=================
|
||||
InitialBrushList
|
||||
=================
|
||||
*/
|
||||
bspbrush_t *InitialBrushList (bspbrush_t *list)
|
||||
{
|
||||
bspbrush_t *b;
|
||||
bspbrush_t *out, *newb;
|
||||
int i;
|
||||
|
||||
// only return brushes that have visible faces
|
||||
out = NULL;
|
||||
for (b=list ; b ; b=b->next)
|
||||
{
|
||||
#if 0
|
||||
for (i=0 ; i<b->numsides ; i++)
|
||||
if (b->sides[i].visible)
|
||||
break;
|
||||
if (i == b->numsides)
|
||||
continue;
|
||||
#endif
|
||||
newb = CopyBrush (b);
|
||||
newb->next = out;
|
||||
out = newb;
|
||||
|
||||
// clear visible, so it must be set by MarkVisibleFaces_r
|
||||
// to be used in the optimized list
|
||||
for (i=0 ; i<b->numsides ; i++)
|
||||
{
|
||||
newb->sides[i].original = &b->sides[i];
|
||||
// newb->sides[i].visible = true;
|
||||
b->sides[i].visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/*
|
||||
=================
|
||||
OptimizedBrushList
|
||||
=================
|
||||
*/
|
||||
bspbrush_t *OptimizedBrushList (bspbrush_t *list)
|
||||
{
|
||||
bspbrush_t *b;
|
||||
bspbrush_t *out, *newb;
|
||||
int i;
|
||||
|
||||
// only return brushes that have visible faces
|
||||
out = NULL;
|
||||
for (b=list ; b ; b=b->next)
|
||||
{
|
||||
for (i=0 ; i<b->numsides ; i++)
|
||||
if (b->sides[i].visible)
|
||||
break;
|
||||
if (i == b->numsides)
|
||||
continue;
|
||||
newb = CopyBrush (b);
|
||||
newb->next = out;
|
||||
out = newb;
|
||||
}
|
||||
|
||||
// WriteBrushList ("vis.gl", out, true);
|
||||
|
||||
return out;
|
||||
}
|
||||
1076
bsp/qbsp3/faces.c
Normal file
1076
bsp/qbsp3/faces.c
Normal file
File diff suppressed because it is too large
Load Diff
232
bsp/qbsp3/gldraw.c
Normal file
232
bsp/qbsp3/gldraw.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; 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 = true;
|
||||
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 = true;
|
||||
|
||||
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;
|
||||
}
|
||||
149
bsp/qbsp3/glfile.c
Normal file
149
bsp/qbsp3/glfile.c
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; 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]->contents;
|
||||
bcon = p->nodes[1]->contents;
|
||||
|
||||
// same contents never create a face
|
||||
if (fcon == bcon)
|
||||
return 0;
|
||||
|
||||
// FIXME: is this correct now?
|
||||
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);
|
||||
}
|
||||
|
||||
100
bsp/qbsp3/leakfile.c
Normal file
100
bsp/qbsp3/leakfile.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; 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);
|
||||
}
|
||||
|
||||
98
bsp/qbsp3/makefile
Normal file
98
bsp/qbsp3/makefile
Normal file
@@ -0,0 +1,98 @@
|
||||
|
||||
CFLAGS = -c
|
||||
LDFLAGS =
|
||||
ODIR = baddir
|
||||
|
||||
EXEBASE = qbsp3
|
||||
EXE = $(ODIR)/qbsp3
|
||||
all: $(EXE)
|
||||
|
||||
_next:
|
||||
make "CFLAGS = -c -g -I../../common -DDOUBLEVEC_T" "ODIR = next"
|
||||
|
||||
_irix:
|
||||
make "CFLAGS = -c -Ofast=ip27 -OPT:IEEE_arithmetic=3 -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip27 -OPT:IEEE_arithmetic=3" "ODIR = irix"
|
||||
|
||||
_irixdebug:
|
||||
make "CFLAGS = -c -O2 -g -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -g" "ODIR = irix"
|
||||
|
||||
_irixinst:
|
||||
make "CFLAGS = -c -Ofast=ip27 -OPT:IEEE_arithmetic=3 -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip27 -OPT:IEEE_arithmetic=3" "ODIR = irix"
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
_irixclean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
_osf:
|
||||
make "CFLAGS = -c -O4 -I../../common -threads -DDOUBLEVEC_T" "LDFLAGS = -threads" "ODIR = osf"
|
||||
|
||||
clean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
install:
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
|
||||
FILES = $(ODIR)/brushbsp.o $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/faces.o $(ODIR)/nodraw.o $(ODIR)/glfile.o $(ODIR)/leakfile.o $(ODIR)/map.o $(ODIR)/mathlib.o $(ODIR)/polylib.o $(ODIR)/portals.o $(ODIR)/prtfile.o $(ODIR)/qbsp3.o $(ODIR)/scriplib.o $(ODIR)/textures.o $(ODIR)/threads.o $(ODIR)/tree.o $(ODIR)/writebsp.o $(ODIR)/csg.o
|
||||
|
||||
$(EXE) : $(FILES)
|
||||
cc -o $(EXE) $(LDFLAGS) $(FILES) -lm
|
||||
|
||||
$(ODIR)/brushbsp.o : brushbsp.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/faces.o : faces.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)/qbsp3.o : qbsp3.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)/textures.o : textures.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)/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)/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
|
||||
1017
bsp/qbsp3/map.c
Normal file
1017
bsp/qbsp3/map.c
Normal file
File diff suppressed because it is too large
Load Diff
47
bsp/qbsp3/nodraw.c
Normal file
47
bsp/qbsp3/nodraw.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; 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)
|
||||
{
|
||||
}
|
||||
1111
bsp/qbsp3/portals.c
Normal file
1111
bsp/qbsp3/portals.c
Normal file
File diff suppressed because it is too large
Load Diff
287
bsp/qbsp3/prtfile.c
Normal file
287
bsp/qbsp3/prtfile.c
Normal file
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; 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;
|
||||
|
||||
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 && !node->detail_seperator)
|
||||
{
|
||||
WritePortalFile_r (node->children[0]);
|
||||
WritePortalFile_r (node->children[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (node->contents & CONTENTS_SOLID)
|
||||
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_VisFlood (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);
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FillLeafNumbers_r
|
||||
|
||||
All of the leafs under node will have the same cluster
|
||||
================
|
||||
*/
|
||||
void FillLeafNumbers_r (node_t *node, int num)
|
||||
{
|
||||
if (node->planenum == PLANENUM_LEAF)
|
||||
{
|
||||
if (node->contents & CONTENTS_SOLID)
|
||||
node->cluster = -1;
|
||||
else
|
||||
node->cluster = num;
|
||||
return;
|
||||
}
|
||||
node->cluster = num;
|
||||
FillLeafNumbers_r (node->children[0], num);
|
||||
FillLeafNumbers_r (node->children[1], num);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
NumberLeafs_r
|
||||
================
|
||||
*/
|
||||
void NumberLeafs_r (node_t *node)
|
||||
{
|
||||
portal_t *p;
|
||||
|
||||
if (node->planenum != PLANENUM_LEAF && !node->detail_seperator)
|
||||
{ // decision node
|
||||
node->cluster = -99;
|
||||
NumberLeafs_r (node->children[0]);
|
||||
NumberLeafs_r (node->children[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
// either a leaf or a detail cluster
|
||||
|
||||
if ( node->contents & CONTENTS_SOLID )
|
||||
{ // solid block, viewpoint never inside
|
||||
node->cluster = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
FillLeafNumbers_r (node, 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_VisFlood (p))
|
||||
num_visportals++;
|
||||
p = p->next[0];
|
||||
}
|
||||
else
|
||||
p = p->next[1];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
CreateVisPortals_r
|
||||
================
|
||||
*/
|
||||
void CreateVisPortals_r (node_t *node)
|
||||
{
|
||||
// stop as soon as we get to a detail_seperator, which
|
||||
// means that everything below is in a single cluster
|
||||
if (node->planenum == PLANENUM_LEAF || node->detail_seperator )
|
||||
return;
|
||||
|
||||
MakeNodePortal (node);
|
||||
SplitNodePortals (node);
|
||||
|
||||
CreateVisPortals_r (node->children[0]);
|
||||
CreateVisPortals_r (node->children[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
FinishVisPortals_r
|
||||
================
|
||||
*/
|
||||
void FinishVisPortals2_r (node_t *node)
|
||||
{
|
||||
if (node->planenum == PLANENUM_LEAF)
|
||||
return;
|
||||
|
||||
MakeNodePortal (node);
|
||||
SplitNodePortals (node);
|
||||
|
||||
FinishVisPortals2_r (node->children[0]);
|
||||
FinishVisPortals2_r (node->children[1]);
|
||||
}
|
||||
|
||||
void FinishVisPortals_r (node_t *node)
|
||||
{
|
||||
if (node->planenum == PLANENUM_LEAF)
|
||||
return;
|
||||
|
||||
if (node->detail_seperator)
|
||||
{
|
||||
FinishVisPortals2_r (node);
|
||||
return;
|
||||
}
|
||||
|
||||
FinishVisPortals_r (node->children[0]);
|
||||
FinishVisPortals_r (node->children[1]);
|
||||
}
|
||||
|
||||
|
||||
int clusterleaf;
|
||||
void SaveClusters_r (node_t *node)
|
||||
{
|
||||
if (node->planenum == PLANENUM_LEAF)
|
||||
{
|
||||
dleafs[clusterleaf++].cluster = node->cluster;
|
||||
return;
|
||||
}
|
||||
SaveClusters_r (node->children[0]);
|
||||
SaveClusters_r (node->children[1]);
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
WritePortalFile
|
||||
================
|
||||
*/
|
||||
void WritePortalFile (tree_t *tree)
|
||||
{
|
||||
char filename[1024];
|
||||
node_t *headnode;
|
||||
|
||||
qprintf ("--- WritePortalFile ---\n");
|
||||
|
||||
headnode = tree->headnode;
|
||||
num_visclusters = 0;
|
||||
num_visportals = 0;
|
||||
|
||||
FreeTreePortals_r (headnode);
|
||||
|
||||
MakeHeadnodePortals (tree);
|
||||
|
||||
CreateVisPortals_r (headnode);
|
||||
|
||||
// set the cluster field in every leaf and count the total number of portals
|
||||
|
||||
NumberLeafs_r (headnode);
|
||||
|
||||
// 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);
|
||||
|
||||
qprintf ("%5i visclusters\n", num_visclusters);
|
||||
qprintf ("%5i visportals\n", num_visportals);
|
||||
|
||||
WritePortalFile_r (headnode);
|
||||
|
||||
fclose (pf);
|
||||
|
||||
// we need to store the clusters out now because ordering
|
||||
// issues made us do this after writebsp...
|
||||
clusterleaf = 1;
|
||||
SaveClusters_r (headnode);
|
||||
}
|
||||
|
||||
355
bsp/qbsp3/qbsp.h
Normal file
355
bsp/qbsp3/qbsp.h
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; 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 "threads.h"
|
||||
#include "bspfile.h"
|
||||
|
||||
#define MAX_BRUSH_SIDES 128
|
||||
#define CLIP_EPSILON 0.1
|
||||
|
||||
#define BOGUS_RANGE 8192
|
||||
|
||||
#define TEXINFO_NODE -1 // side is allready on a node
|
||||
|
||||
typedef struct plane_s
|
||||
{
|
||||
vec3_t normal;
|
||||
vec_t dist;
|
||||
int type;
|
||||
struct plane_s *hash_chain;
|
||||
} plane_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec_t shift[2];
|
||||
vec_t rotate;
|
||||
vec_t scale[2];
|
||||
char name[32];
|
||||
int flags;
|
||||
int value;
|
||||
} brush_texture_t;
|
||||
|
||||
typedef struct side_s
|
||||
{
|
||||
int planenum;
|
||||
int texinfo;
|
||||
winding_t *winding;
|
||||
struct side_s *original; // bspbrush_t sides will reference the mapbrush_t sides
|
||||
int contents; // from miptex
|
||||
int surf; // from miptex
|
||||
qboolean visible; // choose visble planes first
|
||||
qboolean tested; // this plane allready checked as a split
|
||||
qboolean bevel; // don't ever use for bsp splitting
|
||||
} side_t;
|
||||
|
||||
typedef struct brush_s
|
||||
{
|
||||
int entitynum;
|
||||
int brushnum;
|
||||
|
||||
int contents;
|
||||
|
||||
vec3_t mins, maxs;
|
||||
|
||||
int numsides;
|
||||
side_t *original_sides;
|
||||
} mapbrush_t;
|
||||
|
||||
#define PLANENUM_LEAF -1
|
||||
|
||||
#define MAXEDGES 20
|
||||
|
||||
typedef struct face_s
|
||||
{
|
||||
struct face_s *next; // on node
|
||||
|
||||
// the chain of faces off of a node can be merged or split,
|
||||
// but each face_t along the way will remain in the chain
|
||||
// until the entire tree is freed
|
||||
struct face_s *merged; // if set, this face isn't valid anymore
|
||||
struct face_s *split[2]; // if set, this face isn't valid anymore
|
||||
|
||||
struct portal_s *portal;
|
||||
int texinfo;
|
||||
int planenum;
|
||||
int contents; // faces in different contents can't merge
|
||||
int outputnumber;
|
||||
winding_t *w;
|
||||
int numpoints;
|
||||
qboolean badstartvert; // tjunctions cannot be fixed without a midpoint vertex
|
||||
int vertexnums[MAXEDGES];
|
||||
} face_t;
|
||||
|
||||
|
||||
|
||||
typedef struct bspbrush_s
|
||||
{
|
||||
struct bspbrush_s *next;
|
||||
vec3_t mins, maxs;
|
||||
int side, testside; // side of node during construction
|
||||
mapbrush_t *original;
|
||||
int numsides;
|
||||
side_t sides[6]; // variably sized
|
||||
} bspbrush_t;
|
||||
|
||||
|
||||
|
||||
#define MAX_NODE_BRUSHES 8
|
||||
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
|
||||
qboolean detail_seperator; // a detail brush caused the split
|
||||
side_t *side; // the side that created the node
|
||||
struct node_s *children[2];
|
||||
face_t *faces;
|
||||
|
||||
// leafs only
|
||||
bspbrush_t *brushlist; // fragments of all brushes in this leaf
|
||||
int contents; // OR of all brush contents
|
||||
int occupied; // 1 or greater can reach entity
|
||||
entity_t *occupant; // for leak file testing
|
||||
int cluster; // for portalfile writing
|
||||
int area; // for areaportals
|
||||
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
|
||||
side_t *side; // NULL = non-visible
|
||||
face_t *face[2]; // output face in bsp file
|
||||
} portal_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
node_t *headnode;
|
||||
node_t outside_node;
|
||||
vec3_t mins, maxs;
|
||||
} tree_t;
|
||||
|
||||
extern int entity_num;
|
||||
|
||||
extern plane_t mapplanes[MAX_MAP_PLANES];
|
||||
extern int nummapplanes;
|
||||
|
||||
extern int nummapbrushes;
|
||||
extern mapbrush_t mapbrushes[MAX_MAP_BRUSHES];
|
||||
|
||||
extern vec3_t map_mins, map_maxs;
|
||||
|
||||
#define MAX_MAP_SIDES (MAX_MAP_BRUSHES*6)
|
||||
|
||||
extern int nummapbrushsides;
|
||||
extern side_t brushsides[MAX_MAP_SIDES];
|
||||
|
||||
extern qboolean noprune;
|
||||
extern qboolean nodetail;
|
||||
extern qboolean fulldetail;
|
||||
extern qboolean nomerge;
|
||||
extern qboolean nosubdiv;
|
||||
extern qboolean nowater;
|
||||
extern qboolean noweld;
|
||||
extern qboolean noshare;
|
||||
extern qboolean notjunc;
|
||||
|
||||
extern vec_t microvolume;
|
||||
|
||||
extern char outbase[32];
|
||||
|
||||
extern char source[1024];
|
||||
|
||||
void LoadMapFile (char *filename);
|
||||
int FindFloatPlane (vec3_t normal, vec_t dist);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// textures.c
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[64];
|
||||
int flags;
|
||||
int value;
|
||||
int contents;
|
||||
char animname[64];
|
||||
} textureref_t;
|
||||
|
||||
#define MAX_MAP_TEXTURES 1024
|
||||
|
||||
extern textureref_t textureref[MAX_MAP_TEXTURES];
|
||||
|
||||
int FindMiptex (char *name);
|
||||
|
||||
int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, vec3_t origin);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void FindGCD (int *v);
|
||||
|
||||
mapbrush_t *Brush_LoadEntity (entity_t *ent);
|
||||
int PlaneTypeForNormal (vec3_t normal);
|
||||
qboolean MakeBrushPlanes (mapbrush_t *b);
|
||||
int FindIntPlane (int *inormal, int *iorigin);
|
||||
void CreateBrush (int brushnum);
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// 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 (int startbrush, int endbrush,
|
||||
vec3_t clipmins, vec3_t clipmaxs);
|
||||
bspbrush_t *ChopBrushes (bspbrush_t *head);
|
||||
bspbrush_t *InitialBrushList (bspbrush_t *list);
|
||||
bspbrush_t *OptimizedBrushList (bspbrush_t *list);
|
||||
|
||||
void WriteBrushMap (char *name, bspbrush_t *list);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// brushbsp
|
||||
|
||||
void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis);
|
||||
|
||||
bspbrush_t *CopyBrush (bspbrush_t *brush);
|
||||
|
||||
void SplitBrush (bspbrush_t *brush, int planenum,
|
||||
bspbrush_t **front, bspbrush_t **back);
|
||||
|
||||
tree_t *AllocTree (void);
|
||||
node_t *AllocNode (void);
|
||||
bspbrush_t *AllocBrush (int numsides);
|
||||
int CountBrushList (bspbrush_t *brushes);
|
||||
void FreeBrush (bspbrush_t *brushes);
|
||||
vec_t BrushVolume (bspbrush_t *brush);
|
||||
|
||||
void BoundBrush (bspbrush_t *brush);
|
||||
void FreeBrushList (bspbrush_t *brushes);
|
||||
|
||||
tree_t *BrushBSP (bspbrush_t *brushlist, vec3_t mins, vec3_t maxs);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// portals.c
|
||||
|
||||
int VisibleContents (int contents);
|
||||
|
||||
void MakeHeadnodePortals (tree_t *tree);
|
||||
void MakeNodePortal (node_t *node);
|
||||
void SplitNodePortals (node_t *node);
|
||||
|
||||
qboolean Portal_VisFlood (portal_t *p);
|
||||
|
||||
qboolean FloodEntities (tree_t *tree);
|
||||
void FillOutside (node_t *headnode);
|
||||
void FloodAreas (tree_t *tree);
|
||||
void MarkVisibleSides (tree_t *tree, int start, int end);
|
||||
void FreePortal (portal_t *p);
|
||||
void EmitAreaPortals (node_t *headnode);
|
||||
|
||||
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 WritePortalFile (tree_t *tree);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// writebsp.c
|
||||
|
||||
void SetModelNumbers (void);
|
||||
void SetLightStyles (void);
|
||||
|
||||
void BeginBSPFile (void);
|
||||
void WriteBSP (node_t *headnode);
|
||||
void EndBSPFile (void);
|
||||
void BeginModel (void);
|
||||
void EndModel (void);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// faces.c
|
||||
|
||||
void MakeFaces (node_t *headnode);
|
||||
void FixTjuncs (node_t *headnode);
|
||||
int GetEdge2 (int v1, int v2, face_t *f);
|
||||
|
||||
face_t *AllocFace (void);
|
||||
void FreeFace (face_t *f);
|
||||
|
||||
void MergeNodeFaces (node_t *node);
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// 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);
|
||||
void PruneNodes_r (node_t *node);
|
||||
void PruneNodes (node_t *node);
|
||||
537
bsp/qbsp3/qbsp3.c
Normal file
537
bsp/qbsp3/qbsp3.c
Normal file
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qbsp.h"
|
||||
|
||||
extern float subdivide_size;
|
||||
|
||||
char source[1024];
|
||||
char name[1024];
|
||||
|
||||
vec_t microvolume = 1.0;
|
||||
qboolean noprune;
|
||||
qboolean glview;
|
||||
qboolean nodetail;
|
||||
qboolean fulldetail;
|
||||
qboolean onlyents;
|
||||
qboolean nomerge;
|
||||
qboolean nowater;
|
||||
qboolean nofill;
|
||||
qboolean nocsg;
|
||||
qboolean noweld;
|
||||
qboolean noshare;
|
||||
qboolean nosubdiv;
|
||||
qboolean notjunc;
|
||||
qboolean noopt;
|
||||
qboolean leaktest;
|
||||
qboolean verboseentities;
|
||||
|
||||
char outbase[32];
|
||||
|
||||
int block_xl = -8, block_xh = 7, block_yl = -8, block_yh = 7;
|
||||
|
||||
int entity_num;
|
||||
|
||||
|
||||
node_t *block_nodes[10][10];
|
||||
|
||||
/*
|
||||
============
|
||||
BlockTree
|
||||
|
||||
============
|
||||
*/
|
||||
node_t *BlockTree (int xl, int yl, int xh, int yh)
|
||||
{
|
||||
node_t *node;
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
int mid;
|
||||
|
||||
if (xl == xh && yl == yh)
|
||||
{
|
||||
node = block_nodes[xl+5][yl+5];
|
||||
if (!node)
|
||||
{ // return an empty leaf
|
||||
node = AllocNode ();
|
||||
node->planenum = PLANENUM_LEAF;
|
||||
node->contents = 0; //CONTENTS_SOLID;
|
||||
return node;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
// create a seperator along the largest axis
|
||||
node = AllocNode ();
|
||||
|
||||
if (xh - xl > yh - yl)
|
||||
{ // split x axis
|
||||
mid = xl + (xh-xl)/2 + 1;
|
||||
normal[0] = 1;
|
||||
normal[1] = 0;
|
||||
normal[2] = 0;
|
||||
dist = mid*1024;
|
||||
node->planenum = FindFloatPlane (normal, dist);
|
||||
node->children[0] = BlockTree ( mid, yl, xh, yh);
|
||||
node->children[1] = BlockTree ( xl, yl, mid-1, yh);
|
||||
}
|
||||
else
|
||||
{
|
||||
mid = yl + (yh-yl)/2 + 1;
|
||||
normal[0] = 0;
|
||||
normal[1] = 1;
|
||||
normal[2] = 0;
|
||||
dist = mid*1024;
|
||||
node->planenum = FindFloatPlane (normal, dist);
|
||||
node->children[0] = BlockTree ( xl, mid, xh, yh);
|
||||
node->children[1] = BlockTree ( xl, yl, xh, mid-1);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
ProcessBlock_Thread
|
||||
|
||||
============
|
||||
*/
|
||||
int brush_start, brush_end;
|
||||
void ProcessBlock_Thread (int blocknum)
|
||||
{
|
||||
int xblock, yblock;
|
||||
vec3_t mins, maxs;
|
||||
bspbrush_t *brushes;
|
||||
tree_t *tree;
|
||||
node_t *node;
|
||||
|
||||
yblock = block_yl + blocknum / (block_xh-block_xl+1);
|
||||
xblock = block_xl + blocknum % (block_xh-block_xl+1);
|
||||
|
||||
qprintf ("############### block %2i,%2i ###############\n", xblock, yblock);
|
||||
|
||||
mins[0] = xblock*1024;
|
||||
mins[1] = yblock*1024;
|
||||
mins[2] = -4096;
|
||||
maxs[0] = (xblock+1)*1024;
|
||||
maxs[1] = (yblock+1)*1024;
|
||||
maxs[2] = 4096;
|
||||
|
||||
// the makelist and chopbrushes could be cached between the passes...
|
||||
brushes = MakeBspBrushList (brush_start, brush_end, mins, maxs);
|
||||
if (!brushes)
|
||||
{
|
||||
node = AllocNode ();
|
||||
node->planenum = PLANENUM_LEAF;
|
||||
node->contents = CONTENTS_SOLID;
|
||||
block_nodes[xblock+5][yblock+5] = node;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nocsg)
|
||||
brushes = ChopBrushes (brushes);
|
||||
|
||||
tree = BrushBSP (brushes, mins, maxs);
|
||||
|
||||
block_nodes[xblock+5][yblock+5] = tree->headnode;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
ProcessWorldModel
|
||||
|
||||
============
|
||||
*/
|
||||
void ProcessWorldModel (void)
|
||||
{
|
||||
entity_t *e;
|
||||
tree_t *tree;
|
||||
qboolean leaked;
|
||||
qboolean optimize;
|
||||
|
||||
e = &entities[entity_num];
|
||||
|
||||
brush_start = e->firstbrush;
|
||||
brush_end = brush_start + e->numbrushes;
|
||||
leaked = false;
|
||||
|
||||
//
|
||||
// perform per-block operations
|
||||
//
|
||||
if (block_xh * 1024 > map_maxs[0])
|
||||
block_xh = floor(map_maxs[0]/1024.0);
|
||||
if ( (block_xl+1) * 1024 < map_mins[0])
|
||||
block_xl = floor(map_mins[0]/1024.0);
|
||||
if (block_yh * 1024 > map_maxs[1])
|
||||
block_yh = floor(map_maxs[1]/1024.0);
|
||||
if ( (block_yl+1) * 1024 < map_mins[1])
|
||||
block_yl = floor(map_mins[1]/1024.0);
|
||||
|
||||
if (block_xl <-4)
|
||||
block_xl = -4;
|
||||
if (block_yl <-4)
|
||||
block_yl = -4;
|
||||
if (block_xh > 3)
|
||||
block_xh = 3;
|
||||
if (block_yh > 3)
|
||||
block_yh = 3;
|
||||
|
||||
for (optimize = false ; optimize <= true ; optimize++)
|
||||
{
|
||||
qprintf ("--------------------------------------------\n");
|
||||
|
||||
RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1),
|
||||
!verbose, ProcessBlock_Thread);
|
||||
|
||||
//
|
||||
// build the division tree
|
||||
// oversizing the blocks guarantees that all the boundaries
|
||||
// will also get nodes.
|
||||
//
|
||||
|
||||
qprintf ("--------------------------------------------\n");
|
||||
|
||||
tree = AllocTree ();
|
||||
tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1);
|
||||
|
||||
tree->mins[0] = (block_xl)*1024;
|
||||
tree->mins[1] = (block_yl)*1024;
|
||||
tree->mins[2] = map_mins[2] - 8;
|
||||
|
||||
tree->maxs[0] = (block_xh+1)*1024;
|
||||
tree->maxs[1] = (block_yh+1)*1024;
|
||||
tree->maxs[2] = map_maxs[2] + 8;
|
||||
|
||||
//
|
||||
// perform the global operations
|
||||
//
|
||||
MakeTreePortals (tree);
|
||||
|
||||
if (FloodEntities (tree))
|
||||
FillOutside (tree->headnode);
|
||||
else
|
||||
{
|
||||
printf ("**** leaked ****\n");
|
||||
leaked = true;
|
||||
LeakFile (tree);
|
||||
if (leaktest)
|
||||
{
|
||||
printf ("--- MAP LEAKED ---\n");
|
||||
exit (0);
|
||||
}
|
||||
}
|
||||
|
||||
MarkVisibleSides (tree, brush_start, brush_end);
|
||||
if (noopt || leaked)
|
||||
break;
|
||||
if (!optimize)
|
||||
{
|
||||
FreeTree (tree);
|
||||
}
|
||||
}
|
||||
|
||||
FloodAreas (tree);
|
||||
if (glview)
|
||||
WriteGLView (tree, source);
|
||||
MakeFaces (tree->headnode);
|
||||
FixTjuncs (tree->headnode);
|
||||
|
||||
if (!noprune)
|
||||
PruneNodes (tree->headnode);
|
||||
|
||||
WriteBSP (tree->headnode);
|
||||
|
||||
if (!leaked)
|
||||
WritePortalFile (tree);
|
||||
|
||||
FreeTree (tree);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
ProcessSubModel
|
||||
|
||||
============
|
||||
*/
|
||||
void ProcessSubModel (void)
|
||||
{
|
||||
entity_t *e;
|
||||
int start, end;
|
||||
tree_t *tree;
|
||||
bspbrush_t *list;
|
||||
vec3_t mins, maxs;
|
||||
|
||||
e = &entities[entity_num];
|
||||
|
||||
start = e->firstbrush;
|
||||
end = start + e->numbrushes;
|
||||
|
||||
mins[0] = mins[1] = mins[2] = -4096;
|
||||
maxs[0] = maxs[1] = maxs[2] = 4096;
|
||||
list = MakeBspBrushList (start, end, mins, maxs);
|
||||
if (!nocsg)
|
||||
list = ChopBrushes (list);
|
||||
tree = BrushBSP (list, mins, maxs);
|
||||
MakeTreePortals (tree);
|
||||
MarkVisibleSides (tree, start, end);
|
||||
MakeFaces (tree->headnode);
|
||||
FixTjuncs (tree->headnode);
|
||||
WriteBSP (tree->headnode);
|
||||
FreeTree (tree);
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
ProcessModels
|
||||
============
|
||||
*/
|
||||
void ProcessModels (void)
|
||||
{
|
||||
BeginBSPFile ();
|
||||
|
||||
for (entity_num=0 ; entity_num< num_entities ; entity_num++)
|
||||
{
|
||||
if (!entities[entity_num].numbrushes)
|
||||
continue;
|
||||
|
||||
qprintf ("############### model %i ###############\n", nummodels);
|
||||
BeginModel ();
|
||||
if (entity_num == 0)
|
||||
ProcessWorldModel ();
|
||||
else
|
||||
ProcessSubModel ();
|
||||
EndModel ();
|
||||
|
||||
if (!verboseentities)
|
||||
verbose = false; // don't bother printing submodels
|
||||
}
|
||||
|
||||
EndBSPFile ();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
main
|
||||
============
|
||||
*/
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
double start, end;
|
||||
char path[1024];
|
||||
|
||||
printf ("---- qbsp3 ----\n");
|
||||
|
||||
for (i=1 ; i<argc ; i++)
|
||||
{
|
||||
if (!strcmp(argv[i],"-threads"))
|
||||
{
|
||||
numthreads = atoi (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-glview"))
|
||||
{
|
||||
glview = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-v"))
|
||||
{
|
||||
printf ("verbose = true\n");
|
||||
verbose = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-draw"))
|
||||
{
|
||||
printf ("drawflag = true\n");
|
||||
drawflag = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-noweld"))
|
||||
{
|
||||
printf ("noweld = true\n");
|
||||
noweld = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-nocsg"))
|
||||
{
|
||||
printf ("nocsg = true\n");
|
||||
nocsg = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-noshare"))
|
||||
{
|
||||
printf ("noshare = true\n");
|
||||
noshare = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-notjunc"))
|
||||
{
|
||||
printf ("notjunc = true\n");
|
||||
notjunc = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-nowater"))
|
||||
{
|
||||
printf ("nowater = true\n");
|
||||
nowater = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-noopt"))
|
||||
{
|
||||
printf ("noopt = true\n");
|
||||
noopt = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-noprune"))
|
||||
{
|
||||
printf ("noprune = true\n");
|
||||
noprune = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-nofill"))
|
||||
{
|
||||
printf ("nofill = true\n");
|
||||
nofill = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-nomerge"))
|
||||
{
|
||||
printf ("nomerge = true\n");
|
||||
nomerge = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-nosubdiv"))
|
||||
{
|
||||
printf ("nosubdiv = true\n");
|
||||
nosubdiv = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-nodetail"))
|
||||
{
|
||||
printf ("nodetail = true\n");
|
||||
nodetail = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-fulldetail"))
|
||||
{
|
||||
printf ("fulldetail = true\n");
|
||||
fulldetail = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-onlyents"))
|
||||
{
|
||||
printf ("onlyents = true\n");
|
||||
onlyents = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-micro"))
|
||||
{
|
||||
microvolume = atof(argv[i+1]);
|
||||
printf ("microvolume = %f\n", microvolume);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-leaktest"))
|
||||
{
|
||||
printf ("leaktest = true\n");
|
||||
leaktest = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-verboseentities"))
|
||||
{
|
||||
printf ("verboseentities = true\n");
|
||||
verboseentities = true;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-chop"))
|
||||
{
|
||||
subdivide_size = atof(argv[i+1]);
|
||||
printf ("subdivide_size = %f\n", subdivide_size);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-block"))
|
||||
{
|
||||
block_xl = block_xh = atoi(argv[i+1]);
|
||||
block_yl = block_yh = atoi(argv[i+2]);
|
||||
printf ("block: %i,%i\n", block_xl, block_yl);
|
||||
i+=2;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-blocks"))
|
||||
{
|
||||
block_xl = atoi(argv[i+1]);
|
||||
block_yl = atoi(argv[i+2]);
|
||||
block_xh = atoi(argv[i+3]);
|
||||
block_yh = atoi(argv[i+4]);
|
||||
printf ("blocks: %i,%i to %i,%i\n",
|
||||
block_xl, block_yl, block_xh, block_yh);
|
||||
i+=4;
|
||||
}
|
||||
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: qbsp3 [options] mapfile");
|
||||
|
||||
start = I_FloatTime ();
|
||||
|
||||
ThreadSetDefault ();
|
||||
numthreads = 1; // multiple threads aren't helping...
|
||||
SetQdirFromPath (argv[i]);
|
||||
|
||||
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]));
|
||||
DefaultExtension (name, ".map"); // might be .reg
|
||||
|
||||
//
|
||||
// if onlyents, just grab the entites and resave
|
||||
//
|
||||
if (onlyents)
|
||||
{
|
||||
char out[1024];
|
||||
|
||||
sprintf (out, "%s.bsp", source);
|
||||
LoadBSPFile (out);
|
||||
num_entities = 0;
|
||||
|
||||
LoadMapFile (name);
|
||||
SetModelNumbers ();
|
||||
SetLightStyles ();
|
||||
|
||||
UnparseEntities ();
|
||||
|
||||
WriteBSPFile (out);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// start from scratch
|
||||
//
|
||||
LoadMapFile (name);
|
||||
SetModelNumbers ();
|
||||
SetLightStyles ();
|
||||
|
||||
ProcessModels ();
|
||||
}
|
||||
|
||||
end = I_FloatTime ();
|
||||
printf ("%5.0f seconds elapsed\n", end-start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
221
bsp/qbsp3/textures.c
Normal file
221
bsp/qbsp3/textures.c
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qbsp.h"
|
||||
|
||||
int nummiptex;
|
||||
textureref_t textureref[MAX_MAP_TEXTURES];
|
||||
|
||||
//==========================================================================
|
||||
|
||||
|
||||
int FindMiptex (char *name)
|
||||
{
|
||||
int i;
|
||||
char path[1024];
|
||||
miptex_t *mt;
|
||||
|
||||
for (i=0 ; i<nummiptex ; i++)
|
||||
if (!strcmp (name, textureref[i].name))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
if (nummiptex == MAX_MAP_TEXTURES)
|
||||
Error ("MAX_MAP_TEXTURES");
|
||||
strcpy (textureref[i].name, name);
|
||||
|
||||
// load the miptex to get the flags and values
|
||||
sprintf (path, "%stextures/%s.wal", gamedir, name);
|
||||
if (TryLoadFile (path, (void **)&mt) != -1)
|
||||
{
|
||||
textureref[i].value = LittleLong (mt->value);
|
||||
textureref[i].flags = LittleLong (mt->flags);
|
||||
textureref[i].contents = LittleLong (mt->contents);
|
||||
strcpy (textureref[i].animname, mt->animname);
|
||||
free (mt);
|
||||
}
|
||||
nummiptex++;
|
||||
|
||||
if (textureref[i].animname[0])
|
||||
FindMiptex (textureref[i].animname);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, vec3_t origin)
|
||||
{
|
||||
vec3_t vecs[2];
|
||||
int sv, tv;
|
||||
vec_t ang, sinv, cosv;
|
||||
vec_t ns, nt;
|
||||
texinfo_t tx, *tc;
|
||||
int i, j, k;
|
||||
float shift[2];
|
||||
brush_texture_t anim;
|
||||
int mt;
|
||||
|
||||
if (!bt->name[0])
|
||||
return 0;
|
||||
|
||||
memset (&tx, 0, sizeof(tx));
|
||||
strcpy (tx.texture, bt->name);
|
||||
|
||||
TextureAxisFromPlane(plane, vecs[0], vecs[1]);
|
||||
|
||||
shift[0] = DotProduct (origin, vecs[0]);
|
||||
shift[1] = DotProduct (origin, vecs[1]);
|
||||
|
||||
if (!bt->scale[0])
|
||||
bt->scale[0] = 1;
|
||||
if (!bt->scale[1])
|
||||
bt->scale[1] = 1;
|
||||
|
||||
|
||||
// rotate axis
|
||||
if (bt->rotate == 0)
|
||||
{ sinv = 0 ; cosv = 1; }
|
||||
else if (bt->rotate == 90)
|
||||
{ sinv = 1 ; cosv = 0; }
|
||||
else if (bt->rotate == 180)
|
||||
{ sinv = 0 ; cosv = -1; }
|
||||
else if (bt->rotate == 270)
|
||||
{ sinv = -1 ; cosv = 0; }
|
||||
else
|
||||
{
|
||||
ang = bt->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++)
|
||||
tx.vecs[i][j] = vecs[i][j] / bt->scale[i];
|
||||
|
||||
tx.vecs[0][3] = bt->shift[0] + shift[0];
|
||||
tx.vecs[1][3] = bt->shift[1] + shift[1];
|
||||
tx.flags = bt->flags;
|
||||
tx.value = bt->value;
|
||||
|
||||
//
|
||||
// find the texinfo
|
||||
//
|
||||
tc = texinfo;
|
||||
for (i=0 ; i<numtexinfo ; i++, tc++)
|
||||
{
|
||||
if (tc->flags != tx.flags)
|
||||
continue;
|
||||
if (tc->value != tx.value)
|
||||
continue;
|
||||
for (j=0 ; j<2 ; j++)
|
||||
{
|
||||
if (strcmp (tc->texture, tx.texture))
|
||||
goto skip;
|
||||
for (k=0 ; k<4 ; k++)
|
||||
{
|
||||
if (tc->vecs[j][k] != tx.vecs[j][k])
|
||||
goto skip;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
skip:;
|
||||
}
|
||||
*tc = tx;
|
||||
numtexinfo++;
|
||||
|
||||
// load the next animation
|
||||
mt = FindMiptex (bt->name);
|
||||
if (textureref[mt].animname[0])
|
||||
{
|
||||
anim = *bt;
|
||||
strcpy (anim.name, textureref[mt].animname);
|
||||
tc->nexttexinfo = TexinfoForBrushTexture (plane, &anim, origin);
|
||||
}
|
||||
else
|
||||
tc->nexttexinfo = -1;
|
||||
|
||||
|
||||
return i;
|
||||
}
|
||||
219
bsp/qbsp3/tree.c
Normal file
219
bsp/qbsp3/tree.c
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; 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)
|
||||
{
|
||||
face_t *f, *nextf;
|
||||
|
||||
// free children
|
||||
if (node->planenum != PLANENUM_LEAF)
|
||||
{
|
||||
FreeTree_r (node->children[0]);
|
||||
FreeTree_r (node->children[1]);
|
||||
}
|
||||
|
||||
// free bspbrushes
|
||||
FreeBrushList (node->brushlist);
|
||||
|
||||
// free faces
|
||||
for (f=node->faces ; f ; f=nextf)
|
||||
{
|
||||
nextf = f->next;
|
||||
FreeFace (f);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/*
|
||||
=========================================================
|
||||
|
||||
NODES THAT DON'T SEPERATE DIFFERENT CONTENTS CAN BE PRUNED
|
||||
|
||||
=========================================================
|
||||
*/
|
||||
|
||||
int c_pruned;
|
||||
|
||||
/*
|
||||
============
|
||||
PruneNodes_r
|
||||
============
|
||||
*/
|
||||
void PruneNodes_r (node_t *node)
|
||||
{
|
||||
bspbrush_t *b, *next;
|
||||
|
||||
if (node->planenum == PLANENUM_LEAF)
|
||||
return;
|
||||
PruneNodes_r (node->children[0]);
|
||||
PruneNodes_r (node->children[1]);
|
||||
|
||||
if ( (node->children[0]->contents & CONTENTS_SOLID)
|
||||
&& (node->children[1]->contents & CONTENTS_SOLID) )
|
||||
{
|
||||
if (node->faces)
|
||||
Error ("node->faces seperating CONTENTS_SOLID");
|
||||
if (node->children[0]->faces || node->children[1]->faces)
|
||||
Error ("!node->faces with children");
|
||||
|
||||
// FIXME: free stuff
|
||||
node->planenum = PLANENUM_LEAF;
|
||||
node->contents = CONTENTS_SOLID;
|
||||
node->detail_seperator = false;
|
||||
|
||||
if (node->brushlist)
|
||||
Error ("PruneNodes: node->brushlist");
|
||||
|
||||
// combine brush lists
|
||||
node->brushlist = node->children[1]->brushlist;
|
||||
|
||||
for (b=node->children[0]->brushlist ; b ; b=next)
|
||||
{
|
||||
next = b->next;
|
||||
b->next = node->brushlist;
|
||||
node->brushlist = b;
|
||||
}
|
||||
|
||||
c_pruned++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PruneNodes (node_t *node)
|
||||
{
|
||||
qprintf ("--- PruneNodes ---\n");
|
||||
c_pruned = 0;
|
||||
PruneNodes_r (node);
|
||||
qprintf ("%5i pruned nodes\n", c_pruned);
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
590
bsp/qbsp3/writebsp.c
Normal file
590
bsp/qbsp3/writebsp.c
Normal file
@@ -0,0 +1,590 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
#include "qbsp.h"
|
||||
|
||||
int c_nofaces;
|
||||
int c_facenodes;
|
||||
|
||||
|
||||
/*
|
||||
=========================================================
|
||||
|
||||
ONLY SAVE OUT PLANES THAT ARE ACTUALLY USED AS NODES
|
||||
|
||||
=========================================================
|
||||
*/
|
||||
|
||||
int planeused[MAX_MAP_PLANES];
|
||||
|
||||
/*
|
||||
============
|
||||
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;
|
||||
int planetranslate[MAX_MAP_PLANES];
|
||||
|
||||
mp = mapplanes;
|
||||
for (i=0 ; i<nummapplanes ; i++, mp++)
|
||||
{
|
||||
dp = &dplanes[numplanes];
|
||||
planetranslate[i] = numplanes;
|
||||
VectorCopy ( mp->normal, dp->normal);
|
||||
dp->dist = mp->dist;
|
||||
dp->type = mp->type;
|
||||
numplanes++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//========================================================
|
||||
|
||||
void EmitMarkFace (dleaf_t *leaf_p, face_t *f)
|
||||
{
|
||||
int i;
|
||||
int facenum;
|
||||
|
||||
while (f->merged)
|
||||
f = f->merged;
|
||||
|
||||
if (f->split[0])
|
||||
{
|
||||
EmitMarkFace (leaf_p, f->split[0]);
|
||||
EmitMarkFace (leaf_p, f->split[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
facenum = f->outputnumber;
|
||||
if (facenum == -1)
|
||||
return; // degenerate face
|
||||
|
||||
if (facenum < 0 || facenum >= numfaces)
|
||||
Error ("Bad leafface");
|
||||
for (i=leaf_p->firstleafface ; i<numleaffaces ; i++)
|
||||
if (dleaffaces[i] == facenum)
|
||||
break; // merged out face
|
||||
if (i == numleaffaces)
|
||||
{
|
||||
if (numleaffaces >= MAX_MAP_LEAFFACES)
|
||||
Error ("MAX_MAP_LEAFFACES");
|
||||
|
||||
dleaffaces[numleaffaces] = facenum;
|
||||
numleaffaces++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
EmitLeaf
|
||||
==================
|
||||
*/
|
||||
void EmitLeaf (node_t *node)
|
||||
{
|
||||
dleaf_t *leaf_p;
|
||||
portal_t *p;
|
||||
int s;
|
||||
face_t *f;
|
||||
bspbrush_t *b;
|
||||
int i;
|
||||
int brushnum;
|
||||
|
||||
// emit a leaf
|
||||
if (numleafs >= MAX_MAP_LEAFS)
|
||||
Error ("MAX_MAP_LEAFS");
|
||||
|
||||
leaf_p = &dleafs[numleafs];
|
||||
numleafs++;
|
||||
|
||||
leaf_p->contents = node->contents;
|
||||
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");
|
||||
|
||||
brushnum = b->original - mapbrushes;
|
||||
for (i=leaf_p->firstleafbrush ; i<numleafbrushes ; i++)
|
||||
if (dleafbrushes[i] == brushnum)
|
||||
break;
|
||||
if (i == numleafbrushes)
|
||||
{
|
||||
dleafbrushes[numleafbrushes] = brushnum;
|
||||
numleafbrushes++;
|
||||
}
|
||||
}
|
||||
leaf_p->numleafbrushes = numleafbrushes - leaf_p->firstleafbrush;
|
||||
|
||||
//
|
||||
// write the leaffaces
|
||||
//
|
||||
if (leaf_p->contents & CONTENTS_SOLID)
|
||||
return; // no leaffaces in solids
|
||||
|
||||
leaf_p->firstleafface = numleaffaces;
|
||||
|
||||
for (p = node->portals ; p ; p = p->next[s])
|
||||
{
|
||||
s = (p->nodes[1] == node);
|
||||
f = p->face[s];
|
||||
if (!f)
|
||||
continue; // not a visible portal
|
||||
|
||||
EmitMarkFace (leaf_p, f);
|
||||
}
|
||||
|
||||
leaf_p->numleaffaces = numleaffaces - leaf_p->firstleafface;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
EmitFace
|
||||
==================
|
||||
*/
|
||||
void EmitFace (face_t *f)
|
||||
{
|
||||
dface_t *df;
|
||||
int i;
|
||||
int e;
|
||||
|
||||
f->outputnumber = -1;
|
||||
|
||||
if (f->numpoints < 3)
|
||||
{
|
||||
return; // degenerated
|
||||
}
|
||||
if (f->merged || f->split[0] || f->split[1])
|
||||
{
|
||||
return; // not a final face
|
||||
}
|
||||
|
||||
// save output number so leaffaces can use
|
||||
f->outputnumber = numfaces;
|
||||
|
||||
if (numfaces >= MAX_MAP_FACES)
|
||||
Error ("numfaces == MAX_MAP_FACES");
|
||||
df = &dfaces[numfaces];
|
||||
numfaces++;
|
||||
|
||||
// planenum is used by qlight, but not quake
|
||||
df->planenum = f->planenum & (~1);
|
||||
df->side = f->planenum & 1;
|
||||
|
||||
df->firstedge = numsurfedges;
|
||||
df->numedges = f->numpoints;
|
||||
df->texinfo = f->texinfo;
|
||||
for (i=0 ; i<f->numpoints ; i++)
|
||||
{
|
||||
// e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f);
|
||||
e = GetEdge2 (f->vertexnums[i], f->vertexnums[(i+1)%f->numpoints], f);
|
||||
if (numsurfedges >= MAX_MAP_SURFEDGES)
|
||||
Error ("numsurfedges == MAX_MAP_SURFEDGES");
|
||||
dsurfedges[numsurfedges] = e;
|
||||
numsurfedges++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
EmitDrawingNode_r
|
||||
============
|
||||
*/
|
||||
int EmitDrawNode_r (node_t *node)
|
||||
{
|
||||
dnode_t *n;
|
||||
face_t *f;
|
||||
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);
|
||||
|
||||
planeused[node->planenum]++;
|
||||
planeused[node->planenum^1]++;
|
||||
|
||||
if (node->planenum & 1)
|
||||
Error ("WriteDrawNodes_r: odd planenum");
|
||||
n->planenum = node->planenum;
|
||||
n->firstface = numfaces;
|
||||
|
||||
if (!node->faces)
|
||||
c_nofaces++;
|
||||
else
|
||||
c_facenodes++;
|
||||
|
||||
for (f=node->faces ; f ; f=f->next)
|
||||
EmitFace (f);
|
||||
|
||||
n->numfaces = numfaces - n->firstface;
|
||||
|
||||
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
|
||||
//=========================================================
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
WriteBSP
|
||||
============
|
||||
*/
|
||||
void WriteBSP (node_t *headnode)
|
||||
{
|
||||
int oldfaces;
|
||||
|
||||
c_nofaces = 0;
|
||||
c_facenodes = 0;
|
||||
|
||||
qprintf ("--- WriteBSP ---\n");
|
||||
|
||||
oldfaces = numfaces;
|
||||
dmodels[nummodels].headnode = EmitDrawNode_r (headnode);
|
||||
EmitAreaPortals (headnode);
|
||||
|
||||
qprintf ("%5i nodes with faces\n", c_facenodes);
|
||||
qprintf ("%5i nodes without faces\n", c_nofaces);
|
||||
qprintf ("%5i faces\n", numfaces-oldfaces);
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
|
||||
/*
|
||||
============
|
||||
SetModelNumbers
|
||||
============
|
||||
*/
|
||||
void SetModelNumbers (void)
|
||||
{
|
||||
int i;
|
||||
int models;
|
||||
char value[10];
|
||||
|
||||
models = 1;
|
||||
for (i=1 ; i<num_entities ; i++)
|
||||
{
|
||||
if (entities[i].numbrushes)
|
||||
{
|
||||
sprintf (value, "*%i", models);
|
||||
models++;
|
||||
SetKeyValue (&entities[i], "model", value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
SetLightStyles
|
||||
============
|
||||
*/
|
||||
#define MAX_SWITCHED_LIGHTS 32
|
||||
void SetLightStyles (void)
|
||||
{
|
||||
int stylenum;
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
|
||||
/*
|
||||
============
|
||||
EmitBrushes
|
||||
============
|
||||
*/
|
||||
void EmitBrushes (void)
|
||||
{
|
||||
int i, j, bnum, s, x;
|
||||
dbrush_t *db;
|
||||
mapbrush_t *b;
|
||||
dbrushside_t *cp;
|
||||
vec3_t normal;
|
||||
vec_t dist;
|
||||
int planenum;
|
||||
|
||||
numbrushsides = 0;
|
||||
numbrushes = nummapbrushes;
|
||||
|
||||
for (bnum=0 ; bnum<nummapbrushes ; bnum++)
|
||||
{
|
||||
b = &mapbrushes[bnum];
|
||||
db = &dbrushes[bnum];
|
||||
|
||||
db->contents = b->contents;
|
||||
db->firstside = numbrushsides;
|
||||
db->numsides = b->numsides;
|
||||
for (j=0 ; j<b->numsides ; j++)
|
||||
{
|
||||
if (numbrushsides == MAX_MAP_BRUSHSIDES)
|
||||
Error ("MAX_MAP_BRUSHSIDES");
|
||||
cp = &dbrushsides[numbrushsides];
|
||||
numbrushsides++;
|
||||
cp->planenum = b->original_sides[j].planenum;
|
||||
cp->texinfo = b->original_sides[j].texinfo;
|
||||
}
|
||||
|
||||
// add any axis planes not contained in the brush to bevel off corners
|
||||
for (x=0 ; x<3 ; x++)
|
||||
for (s=-1 ; s<=1 ; s+=2)
|
||||
{
|
||||
// add the plane
|
||||
VectorCopy (vec3_origin, normal);
|
||||
normal[x] = s;
|
||||
if (s == -1)
|
||||
dist = -b->mins[x];
|
||||
else
|
||||
dist = b->maxs[x];
|
||||
planenum = FindFloatPlane (normal, dist);
|
||||
for (i=0 ; i<b->numsides ; i++)
|
||||
if (b->original_sides[i].planenum == planenum)
|
||||
break;
|
||||
if (i == b->numsides)
|
||||
{
|
||||
if (numbrushsides >= MAX_MAP_BRUSHSIDES)
|
||||
Error ("MAX_MAP_BRUSHSIDES");
|
||||
|
||||
dbrushsides[numbrushsides].planenum = planenum;
|
||||
dbrushsides[numbrushsides].texinfo =
|
||||
dbrushsides[numbrushsides-1].texinfo;
|
||||
numbrushsides++;
|
||||
db->numsides++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//===========================================================
|
||||
|
||||
/*
|
||||
==================
|
||||
BeginBSPFile
|
||||
==================
|
||||
*/
|
||||
void BeginBSPFile (void)
|
||||
{
|
||||
// these values may actually be initialized
|
||||
// if the file existed when loaded, so clear them explicitly
|
||||
nummodels = 0;
|
||||
numfaces = 0;
|
||||
numnodes = 0;
|
||||
numbrushsides = 0;
|
||||
numvertexes = 0;
|
||||
numleaffaces = 0;
|
||||
numleafbrushes = 0;
|
||||
numsurfedges = 0;
|
||||
|
||||
// edge 0 is not used, because 0 can't be negated
|
||||
numedges = 1;
|
||||
|
||||
// leave vertex 0 as an error
|
||||
numvertexes = 1;
|
||||
|
||||
// leave leaf 0 as an error
|
||||
numleafs = 1;
|
||||
dleafs[0].contents = CONTENTS_SOLID;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
============
|
||||
EndBSPFile
|
||||
============
|
||||
*/
|
||||
void EndBSPFile (void)
|
||||
{
|
||||
char path[1024];
|
||||
int len;
|
||||
byte *buf;
|
||||
|
||||
|
||||
EmitBrushes ();
|
||||
EmitPlanes ();
|
||||
UnparseEntities ();
|
||||
|
||||
// load the pop
|
||||
#if 0
|
||||
sprintf (path, "%s/pics/pop.lmp", gamedir);
|
||||
len = LoadFile (path, &buf);
|
||||
memcpy (dpop, buf, sizeof(dpop));
|
||||
free (buf);
|
||||
#endif
|
||||
|
||||
// write the map
|
||||
sprintf (path, "%s.bsp", source);
|
||||
printf ("Writing %s\n", path);
|
||||
WriteBSPFile (path);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
BeginModel
|
||||
==================
|
||||
*/
|
||||
int firstmodleaf;
|
||||
extern int firstmodeledge;
|
||||
extern int firstmodelface;
|
||||
void BeginModel (void)
|
||||
{
|
||||
dmodel_t *mod;
|
||||
int start, end;
|
||||
mapbrush_t *b;
|
||||
int j;
|
||||
entity_t *e;
|
||||
vec3_t mins, maxs;
|
||||
|
||||
if (nummodels == MAX_MAP_MODELS)
|
||||
Error ("MAX_MAP_MODELS");
|
||||
mod = &dmodels[nummodels];
|
||||
|
||||
mod->firstface = numfaces;
|
||||
|
||||
firstmodleaf = numleafs;
|
||||
firstmodeledge = numedges;
|
||||
firstmodelface = numfaces;
|
||||
|
||||
//
|
||||
// bound the brushes
|
||||
//
|
||||
e = &entities[entity_num];
|
||||
|
||||
start = e->firstbrush;
|
||||
end = start + e->numbrushes;
|
||||
ClearBounds (mins, maxs);
|
||||
|
||||
for (j=start ; j<end ; j++)
|
||||
{
|
||||
b = &mapbrushes[j];
|
||||
if (!b->numsides)
|
||||
continue; // not a real brush (origin brush)
|
||||
AddPointToBounds (b->mins, mins, maxs);
|
||||
AddPointToBounds (b->maxs, mins, maxs);
|
||||
}
|
||||
|
||||
VectorCopy (mins, mod->mins);
|
||||
VectorCopy (maxs, mod->maxs);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
EndModel
|
||||
==================
|
||||
*/
|
||||
void EndModel (void)
|
||||
{
|
||||
dmodel_t *mod;
|
||||
|
||||
mod = &dmodels[nummodels];
|
||||
|
||||
mod->numfaces = numfaces - mod->firstface;
|
||||
|
||||
nummodels++;
|
||||
}
|
||||
|
||||
1316
bsp/qrad3/lightmap.c
Normal file
1316
bsp/qrad3/lightmap.c
Normal file
File diff suppressed because it is too large
Load Diff
77
bsp/qrad3/makefile
Normal file
77
bsp/qrad3/makefile
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
CFLAGS = -c
|
||||
LDFLAGS =
|
||||
ODIR = baddir
|
||||
|
||||
EXEBASE = qrad3
|
||||
EXE = $(ODIR)/qrad3
|
||||
all: $(EXE)
|
||||
|
||||
_next:
|
||||
make "CFLAGS = -c -g -I../../common" "ODIR = next"
|
||||
|
||||
_irix:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
|
||||
_irixdebug:
|
||||
make "CFLAGS = -c -g -I../../common -Xcpluscomm" "LDFLAGS = " "ODIR = irix"
|
||||
|
||||
_irixinst:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
_irixclean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
_osf:
|
||||
make "CFLAGS = -c -O4 -I../../common -threads" "LDFLAGS = -threads" "ODIR = osf"
|
||||
|
||||
clean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
install:
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
|
||||
FILES = $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/lbmlib.o $(ODIR)/mathlib.o $(ODIR)/scriplib.o $(ODIR)/polylib.o $(ODIR)/qrad3.o $(ODIR)/threads.o $(ODIR)/trace.o $(ODIR)/lightmap.o $(ODIR)/patches.o
|
||||
|
||||
$(EXE) : $(FILES)
|
||||
cc -o $(EXE) $(LDFLAGS) $(FILES) -lm
|
||||
|
||||
$(ODIR)/qrad3.o : qrad3.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/patches.o : patches.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/trace.o : trace.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/vismat.o : vismat.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/lightmap.o : lightmap.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)/lbmlib.o : ../../common/lbmlib.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)/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
|
||||
515
bsp/qrad3/patches.c
Normal file
515
bsp/qrad3/patches.c
Normal file
@@ -0,0 +1,515 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qrad.h"
|
||||
|
||||
vec3_t texture_reflectivity[MAX_MAP_TEXINFO];
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
TEXTURE LIGHT VALUES
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
======================
|
||||
CalcTextureReflectivity
|
||||
======================
|
||||
*/
|
||||
void CalcTextureReflectivity (void)
|
||||
{
|
||||
int i;
|
||||
int j, k, texels;
|
||||
int color[3];
|
||||
int texel;
|
||||
byte *palette;
|
||||
char path[1024];
|
||||
float r, scale;
|
||||
miptex_t *mt;
|
||||
|
||||
sprintf (path, "%spics/colormap.pcx", gamedir);
|
||||
|
||||
// get the game palette
|
||||
Load256Image (path, NULL, &palette, NULL, NULL);
|
||||
|
||||
// allways set index 0 even if no textures
|
||||
texture_reflectivity[0][0] = 0.5;
|
||||
texture_reflectivity[0][1] = 0.5;
|
||||
texture_reflectivity[0][2] = 0.5;
|
||||
|
||||
for (i=0 ; i<numtexinfo ; i++)
|
||||
{
|
||||
// see if an earlier texinfo allready got the value
|
||||
for (j=0 ; j<i ; j++)
|
||||
{
|
||||
if (!strcmp (texinfo[i].texture, texinfo[j].texture))
|
||||
{
|
||||
VectorCopy (texture_reflectivity[j], texture_reflectivity[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j != i)
|
||||
continue;
|
||||
|
||||
// load the wal file
|
||||
sprintf (path, "%stextures/%s.wal", gamedir, texinfo[i].texture);
|
||||
if (TryLoadFile (path, (void **)&mt) == -1)
|
||||
{
|
||||
printf ("Couldn't load %s\n", path);
|
||||
texture_reflectivity[i][0] = 0.5;
|
||||
texture_reflectivity[i][1] = 0.5;
|
||||
texture_reflectivity[i][2] = 0.5;
|
||||
continue;
|
||||
}
|
||||
texels = LittleLong(mt->width)*LittleLong(mt->height);
|
||||
color[0] = color[1] = color[2] = 0;
|
||||
|
||||
for (j=0 ; j<texels ; j++)
|
||||
{
|
||||
texel = ((byte *)mt)[LittleLong(mt->offsets[0]) + j];
|
||||
for (k=0 ; k<3 ; k++)
|
||||
color[k] += palette[texel*3+k];
|
||||
}
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
r = color[j]/texels/255.0;
|
||||
texture_reflectivity[i][j] = r;
|
||||
}
|
||||
// scale the reflectivity up, because the textures are
|
||||
// so dim
|
||||
scale = ColorNormalize (texture_reflectivity[i],
|
||||
texture_reflectivity[i]);
|
||||
if (scale < 0.5)
|
||||
{
|
||||
scale *= 2;
|
||||
VectorScale (texture_reflectivity[i], scale, texture_reflectivity[i]);
|
||||
}
|
||||
#if 0
|
||||
texture_reflectivity[i][0] = 0.5;
|
||||
texture_reflectivity[i][1] = 0.5;
|
||||
texture_reflectivity[i][2] = 0.5;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
MAKE FACES
|
||||
|
||||
=======================================================================
|
||||
*/
|
||||
|
||||
/*
|
||||
=============
|
||||
WindingFromFace
|
||||
=============
|
||||
*/
|
||||
winding_t *WindingFromFace (dface_t *f)
|
||||
{
|
||||
int i;
|
||||
int se;
|
||||
dvertex_t *dv;
|
||||
int v;
|
||||
winding_t *w;
|
||||
|
||||
w = AllocWinding (f->numedges);
|
||||
w->numpoints = f->numedges;
|
||||
|
||||
for (i=0 ; i<f->numedges ; i++)
|
||||
{
|
||||
se = dsurfedges[f->firstedge + i];
|
||||
if (se < 0)
|
||||
v = dedges[-se].v[1];
|
||||
else
|
||||
v = dedges[se].v[0];
|
||||
|
||||
dv = &dvertexes[v];
|
||||
VectorCopy (dv->point, w->p[i]);
|
||||
}
|
||||
|
||||
RemoveColinearPoints (w);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
BaseLightForFace
|
||||
=============
|
||||
*/
|
||||
void BaseLightForFace (dface_t *f, vec3_t color)
|
||||
{
|
||||
texinfo_t *tx;
|
||||
|
||||
//
|
||||
// check for light emited by texture
|
||||
//
|
||||
tx = &texinfo[f->texinfo];
|
||||
if (!(tx->flags & SURF_LIGHT) || tx->value == 0)
|
||||
{
|
||||
VectorClear (color);
|
||||
return;
|
||||
}
|
||||
|
||||
VectorScale (texture_reflectivity[f->texinfo], tx->value, color);
|
||||
}
|
||||
|
||||
qboolean IsSky (dface_t *f)
|
||||
{
|
||||
texinfo_t *tx;
|
||||
|
||||
tx = &texinfo[f->texinfo];
|
||||
if (tx->flags & SURF_SKY)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
MakePatchForFace
|
||||
=============
|
||||
*/
|
||||
float totalarea;
|
||||
void MakePatchForFace (int fn, winding_t *w)
|
||||
{
|
||||
dface_t *f;
|
||||
float area;
|
||||
patch_t *patch;
|
||||
dplane_t *pl;
|
||||
int i;
|
||||
vec3_t color;
|
||||
dleaf_t *leaf;
|
||||
|
||||
f = &dfaces[fn];
|
||||
|
||||
area = WindingArea (w);
|
||||
totalarea += area;
|
||||
|
||||
patch = &patches[num_patches];
|
||||
if (num_patches == MAX_PATCHES)
|
||||
Error ("num_patches == MAX_PATCHES");
|
||||
patch->next = face_patches[fn];
|
||||
face_patches[fn] = patch;
|
||||
|
||||
patch->winding = w;
|
||||
|
||||
if (f->side)
|
||||
patch->plane = &backplanes[f->planenum];
|
||||
else
|
||||
patch->plane = &dplanes[f->planenum];
|
||||
if (face_offset[fn][0] || face_offset[fn][1] || face_offset[fn][2] )
|
||||
{ // origin offset faces must create new planes
|
||||
if (numplanes + fakeplanes >= MAX_MAP_PLANES)
|
||||
Error ("numplanes + fakeplanes >= MAX_MAP_PLANES");
|
||||
pl = &dplanes[numplanes + fakeplanes];
|
||||
fakeplanes++;
|
||||
|
||||
*pl = *(patch->plane);
|
||||
pl->dist += DotProduct (face_offset[fn], pl->normal);
|
||||
patch->plane = pl;
|
||||
}
|
||||
|
||||
WindingCenter (w, patch->origin);
|
||||
VectorAdd (patch->origin, patch->plane->normal, patch->origin);
|
||||
leaf = PointInLeaf(patch->origin);
|
||||
patch->cluster = leaf->cluster;
|
||||
if (patch->cluster == -1)
|
||||
qprintf ("patch->cluster == -1\n");
|
||||
|
||||
patch->area = area;
|
||||
if (patch->area <= 1)
|
||||
patch->area = 1;
|
||||
patch->sky = IsSky (f);
|
||||
|
||||
VectorCopy (texture_reflectivity[f->texinfo], patch->reflectivity);
|
||||
|
||||
// non-bmodel patches can emit light
|
||||
if (fn < dmodels[0].numfaces)
|
||||
{
|
||||
BaseLightForFace (f, patch->baselight);
|
||||
|
||||
ColorNormalize (patch->reflectivity, color);
|
||||
|
||||
for (i=0 ; i<3 ; i++)
|
||||
patch->baselight[i] *= color[i];
|
||||
|
||||
VectorCopy (patch->baselight, patch->totallight);
|
||||
}
|
||||
num_patches++;
|
||||
}
|
||||
|
||||
|
||||
entity_t *EntityForModel (int modnum)
|
||||
{
|
||||
int i;
|
||||
char *s;
|
||||
char name[16];
|
||||
|
||||
sprintf (name, "*%i", modnum);
|
||||
// search the entities for one using modnum
|
||||
for (i=0 ; i<num_entities ; i++)
|
||||
{
|
||||
s = ValueForKey (&entities[i], "model");
|
||||
if (!strcmp (s, name))
|
||||
return &entities[i];
|
||||
}
|
||||
|
||||
return &entities[0];
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
MakePatches
|
||||
=============
|
||||
*/
|
||||
void MakePatches (void)
|
||||
{
|
||||
int i, j, k;
|
||||
dface_t *f;
|
||||
int fn;
|
||||
winding_t *w;
|
||||
dmodel_t *mod;
|
||||
vec3_t origin;
|
||||
entity_t *ent;
|
||||
|
||||
qprintf ("%i faces\n", numfaces);
|
||||
|
||||
for (i=0 ; i<nummodels ; i++)
|
||||
{
|
||||
mod = &dmodels[i];
|
||||
ent = EntityForModel (i);
|
||||
// bmodels with origin brushes need to be offset into their
|
||||
// in-use position
|
||||
GetVectorForKey (ent, "origin", origin);
|
||||
//VectorCopy (vec3_origin, origin);
|
||||
|
||||
for (j=0 ; j<mod->numfaces ; j++)
|
||||
{
|
||||
fn = mod->firstface + j;
|
||||
face_entity[fn] = ent;
|
||||
VectorCopy (origin, face_offset[fn]);
|
||||
f = &dfaces[fn];
|
||||
w = WindingFromFace (f);
|
||||
for (k=0 ; k<w->numpoints ; k++)
|
||||
{
|
||||
VectorAdd (w->p[k], origin, w->p[k]);
|
||||
}
|
||||
MakePatchForFace (fn, w);
|
||||
}
|
||||
}
|
||||
|
||||
qprintf ("%i sqaure feet\n", (int)(totalarea/64));
|
||||
}
|
||||
|
||||
/*
|
||||
=======================================================================
|
||||
|
||||
SUBDIVIDE
|
||||
|
||||
=======================================================================
|
||||
*/
|
||||
|
||||
void FinishSplit (patch_t *patch, patch_t *newp)
|
||||
{
|
||||
dleaf_t *leaf;
|
||||
|
||||
VectorCopy (patch->baselight, newp->baselight);
|
||||
VectorCopy (patch->totallight, newp->totallight);
|
||||
VectorCopy (patch->reflectivity, newp->reflectivity);
|
||||
newp->plane = patch->plane;
|
||||
newp->sky = patch->sky;
|
||||
|
||||
patch->area = WindingArea (patch->winding);
|
||||
newp->area = WindingArea (newp->winding);
|
||||
|
||||
if (patch->area <= 1)
|
||||
patch->area = 1;
|
||||
if (newp->area <= 1)
|
||||
newp->area = 1;
|
||||
|
||||
WindingCenter (patch->winding, patch->origin);
|
||||
VectorAdd (patch->origin, patch->plane->normal, patch->origin);
|
||||
leaf = PointInLeaf(patch->origin);
|
||||
patch->cluster = leaf->cluster;
|
||||
if (patch->cluster == -1)
|
||||
qprintf ("patch->cluster == -1\n");
|
||||
|
||||
WindingCenter (newp->winding, newp->origin);
|
||||
VectorAdd (newp->origin, newp->plane->normal, newp->origin);
|
||||
leaf = PointInLeaf(newp->origin);
|
||||
newp->cluster = leaf->cluster;
|
||||
if (newp->cluster == -1)
|
||||
qprintf ("patch->cluster == -1\n");
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
SubdividePatch
|
||||
|
||||
Chops the patch only if its local bounds exceed the max size
|
||||
=============
|
||||
*/
|
||||
void SubdividePatch (patch_t *patch)
|
||||
{
|
||||
winding_t *w, *o1, *o2;
|
||||
vec3_t mins, maxs, total;
|
||||
vec3_t split;
|
||||
vec_t dist;
|
||||
int i, j;
|
||||
vec_t v;
|
||||
patch_t *newp;
|
||||
|
||||
w = patch->winding;
|
||||
mins[0] = mins[1] = mins[2] = 99999;
|
||||
maxs[0] = maxs[1] = maxs[2] = -99999;
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
v = w->p[i][j];
|
||||
if (v < mins[j])
|
||||
mins[j] = v;
|
||||
if (v > maxs[j])
|
||||
maxs[j] = v;
|
||||
}
|
||||
}
|
||||
VectorSubtract (maxs, mins, total);
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (total[i] > (subdiv+1) )
|
||||
break;
|
||||
if (i == 3)
|
||||
{
|
||||
// no splitting needed
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// split the winding
|
||||
//
|
||||
VectorCopy (vec3_origin, split);
|
||||
split[i] = 1;
|
||||
dist = (mins[i] + maxs[i])*0.5;
|
||||
ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2);
|
||||
|
||||
//
|
||||
// create a new patch
|
||||
//
|
||||
if (num_patches == MAX_PATCHES)
|
||||
Error ("MAX_PATCHES");
|
||||
newp = &patches[num_patches];
|
||||
num_patches++;
|
||||
|
||||
newp->next = patch->next;
|
||||
patch->next = newp;
|
||||
|
||||
patch->winding = o1;
|
||||
newp->winding = o2;
|
||||
|
||||
FinishSplit (patch, newp);
|
||||
|
||||
SubdividePatch (patch);
|
||||
SubdividePatch (newp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
DicePatch
|
||||
|
||||
Chops the patch by a global grid
|
||||
=============
|
||||
*/
|
||||
void DicePatch (patch_t *patch)
|
||||
{
|
||||
winding_t *w, *o1, *o2;
|
||||
vec3_t mins, maxs;
|
||||
vec3_t split;
|
||||
vec_t dist;
|
||||
int i;
|
||||
patch_t *newp;
|
||||
|
||||
w = patch->winding;
|
||||
WindingBounds (w, mins, maxs);
|
||||
for (i=0 ; i<3 ; i++)
|
||||
if (floor((mins[i]+1)/subdiv) < floor((maxs[i]-1)/subdiv))
|
||||
break;
|
||||
if (i == 3)
|
||||
{
|
||||
// no splitting needed
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// split the winding
|
||||
//
|
||||
VectorCopy (vec3_origin, split);
|
||||
split[i] = 1;
|
||||
dist = subdiv*(1+floor((mins[i]+1)/subdiv));
|
||||
ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2);
|
||||
|
||||
//
|
||||
// create a new patch
|
||||
//
|
||||
if (num_patches == MAX_PATCHES)
|
||||
Error ("MAX_PATCHES");
|
||||
newp = &patches[num_patches];
|
||||
num_patches++;
|
||||
|
||||
newp->next = patch->next;
|
||||
patch->next = newp;
|
||||
|
||||
patch->winding = o1;
|
||||
newp->winding = o2;
|
||||
|
||||
FinishSplit (patch, newp);
|
||||
|
||||
DicePatch (patch);
|
||||
DicePatch (newp);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
SubdividePatches
|
||||
=============
|
||||
*/
|
||||
void SubdividePatches (void)
|
||||
{
|
||||
int i, num;
|
||||
|
||||
if (subdiv < 1)
|
||||
return;
|
||||
|
||||
num = num_patches; // because the list will grow
|
||||
for (i=0 ; i<num ; i++)
|
||||
{
|
||||
// SubdividePatch (&patches[i]);
|
||||
DicePatch (&patches[i]);
|
||||
}
|
||||
qprintf ("%i patches after subdivision\n", num_patches);
|
||||
}
|
||||
|
||||
//=====================================================================
|
||||
158
bsp/qrad3/qrad.h
Normal file
158
bsp/qrad3/qrad.h
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; 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 "threads.h"
|
||||
#include "lbmlib.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
typedef enum
|
||||
{
|
||||
emit_surface,
|
||||
emit_point,
|
||||
emit_spotlight
|
||||
} emittype_t;
|
||||
|
||||
|
||||
|
||||
typedef struct directlight_s
|
||||
{
|
||||
struct directlight_s *next;
|
||||
emittype_t type;
|
||||
|
||||
float intensity;
|
||||
int style;
|
||||
vec3_t origin;
|
||||
vec3_t color;
|
||||
vec3_t normal; // for surfaces and spotlights
|
||||
float stopdot; // for spotlights
|
||||
} directlight_t;
|
||||
|
||||
|
||||
// the sum of all tranfer->transfer values for a given patch
|
||||
// should equal exactly 0x10000, showing that all radiance
|
||||
// reaches other patches
|
||||
typedef struct
|
||||
{
|
||||
unsigned short patch;
|
||||
unsigned short transfer;
|
||||
} transfer_t;
|
||||
|
||||
|
||||
#define MAX_PATCHES 65000 // larger will cause 32 bit overflows
|
||||
|
||||
typedef struct patch_s
|
||||
{
|
||||
winding_t *winding;
|
||||
struct patch_s *next; // next in face
|
||||
int numtransfers;
|
||||
transfer_t *transfers;
|
||||
|
||||
int cluster; // for pvs checking
|
||||
vec3_t origin;
|
||||
dplane_t *plane;
|
||||
|
||||
qboolean sky;
|
||||
|
||||
vec3_t totallight; // accumulated by radiosity
|
||||
// does NOT include light
|
||||
// accounted for by direct lighting
|
||||
float area;
|
||||
|
||||
// illuminance * reflectivity = radiosity
|
||||
vec3_t reflectivity;
|
||||
vec3_t baselight; // emissivity only
|
||||
|
||||
// each style 0 lightmap sample in the patch will be
|
||||
// added up to get the average illuminance of the entire patch
|
||||
vec3_t samplelight;
|
||||
int samples; // for averaging direct light
|
||||
} patch_t;
|
||||
|
||||
extern patch_t *face_patches[MAX_MAP_FACES];
|
||||
extern entity_t *face_entity[MAX_MAP_FACES];
|
||||
extern vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels
|
||||
extern patch_t patches[MAX_PATCHES];
|
||||
extern unsigned num_patches;
|
||||
|
||||
extern int leafparents[MAX_MAP_LEAFS];
|
||||
extern int nodeparents[MAX_MAP_NODES];
|
||||
|
||||
extern float lightscale;
|
||||
|
||||
|
||||
void MakeShadowSplits (void);
|
||||
|
||||
//==============================================
|
||||
|
||||
|
||||
void BuildVisMatrix (void);
|
||||
qboolean CheckVisBit (unsigned p1, unsigned p2);
|
||||
|
||||
//==============================================
|
||||
|
||||
extern float ambient, maxlight;
|
||||
|
||||
void LinkPlaneFaces (void);
|
||||
|
||||
extern qboolean extrasamples;
|
||||
extern int numbounce;
|
||||
|
||||
extern directlight_t *directlights[MAX_MAP_LEAFS];
|
||||
|
||||
extern byte nodehit[MAX_MAP_NODES];
|
||||
|
||||
void BuildLightmaps (void);
|
||||
|
||||
void BuildFacelights (int facenum);
|
||||
|
||||
void FinalLightFace (int facenum);
|
||||
|
||||
qboolean PvsForOrigin (vec3_t org, byte *pvs);
|
||||
|
||||
int TestLine_r (int node, vec3_t start, vec3_t stop);
|
||||
|
||||
void CreateDirectLights (void);
|
||||
|
||||
dleaf_t *PointInLeaf (vec3_t point);
|
||||
|
||||
|
||||
extern dplane_t backplanes[MAX_MAP_PLANES];
|
||||
extern int fakeplanes; // created planes for origin offset
|
||||
|
||||
extern float subdiv;
|
||||
|
||||
extern float direct_scale;
|
||||
extern float entity_scale;
|
||||
|
||||
int PointInLeafnum (vec3_t point);
|
||||
void MakeTnodes (dmodel_t *bm);
|
||||
void MakePatches (void);
|
||||
void SubdividePatches (void);
|
||||
void PairEdges (void);
|
||||
void CalcTextureReflectivity (void);
|
||||
717
bsp/qrad3/qrad3.c
Normal file
717
bsp/qrad3/qrad3.c
Normal file
@@ -0,0 +1,717 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "qrad.h"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
NOTES
|
||||
-----
|
||||
|
||||
every surface must be divided into at least two patches each axis
|
||||
|
||||
*/
|
||||
|
||||
patch_t *face_patches[MAX_MAP_FACES];
|
||||
entity_t *face_entity[MAX_MAP_FACES];
|
||||
patch_t patches[MAX_PATCHES];
|
||||
unsigned num_patches;
|
||||
|
||||
vec3_t radiosity[MAX_PATCHES]; // light leaving a patch
|
||||
vec3_t illumination[MAX_PATCHES]; // light arriving at a patch
|
||||
|
||||
vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels
|
||||
dplane_t backplanes[MAX_MAP_PLANES];
|
||||
|
||||
char inbase[32], outbase[32];
|
||||
|
||||
int fakeplanes; // created planes for origin offset
|
||||
|
||||
int numbounce = 8;
|
||||
qboolean extrasamples;
|
||||
|
||||
float subdiv = 64;
|
||||
qboolean dumppatches;
|
||||
|
||||
void BuildLightmaps (void);
|
||||
int TestLine (vec3_t start, vec3_t stop);
|
||||
|
||||
int junk;
|
||||
|
||||
float ambient = 0;
|
||||
float maxlight = 196;
|
||||
|
||||
float lightscale = 1.0;
|
||||
|
||||
qboolean glview;
|
||||
|
||||
qboolean nopvs;
|
||||
|
||||
char source[1024];
|
||||
|
||||
float direct_scale = 0.4;
|
||||
float entity_scale = 1.0;
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
MISC
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
MakeBackplanes
|
||||
=============
|
||||
*/
|
||||
void MakeBackplanes (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<numplanes ; i++)
|
||||
{
|
||||
backplanes[i].dist = -dplanes[i].dist;
|
||||
VectorSubtract (vec3_origin, dplanes[i].normal, backplanes[i].normal);
|
||||
}
|
||||
}
|
||||
|
||||
int leafparents[MAX_MAP_LEAFS];
|
||||
int nodeparents[MAX_MAP_NODES];
|
||||
|
||||
/*
|
||||
=============
|
||||
MakeParents
|
||||
=============
|
||||
*/
|
||||
void MakeParents (int nodenum, int parent)
|
||||
{
|
||||
int i, j;
|
||||
dnode_t *node;
|
||||
|
||||
nodeparents[nodenum] = parent;
|
||||
node = &dnodes[nodenum];
|
||||
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
j = node->children[i];
|
||||
if (j < 0)
|
||||
leafparents[-j - 1] = nodenum;
|
||||
else
|
||||
MakeParents (j, nodenum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===================================================================
|
||||
|
||||
TRANSFER SCALES
|
||||
|
||||
===================================================================
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
dleaf_t *PointInLeaf (vec3_t point)
|
||||
{
|
||||
int num;
|
||||
|
||||
num = PointInLeafnum (point);
|
||||
return &dleafs[num];
|
||||
}
|
||||
|
||||
|
||||
qboolean PvsForOrigin (vec3_t org, byte *pvs)
|
||||
{
|
||||
dleaf_t *leaf;
|
||||
|
||||
if (!visdatasize)
|
||||
{
|
||||
memset (pvs, 255, (numleafs+7)/8 );
|
||||
return true;
|
||||
}
|
||||
|
||||
leaf = PointInLeaf (org);
|
||||
if (leaf->cluster == -1)
|
||||
return false; // in solid leaf
|
||||
|
||||
DecompressVis (dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
MakeTransfers
|
||||
|
||||
=============
|
||||
*/
|
||||
int total_transfer;
|
||||
|
||||
void MakeTransfers (int i)
|
||||
{
|
||||
int j;
|
||||
vec3_t delta;
|
||||
vec_t dist, scale;
|
||||
float trans;
|
||||
int itrans;
|
||||
patch_t *patch, *patch2;
|
||||
float total;
|
||||
dplane_t plane;
|
||||
vec3_t origin;
|
||||
float transfers[MAX_PATCHES], *all_transfers;
|
||||
int s;
|
||||
int itotal;
|
||||
byte pvs[(MAX_MAP_LEAFS+7)/8];
|
||||
int cluster;
|
||||
|
||||
patch = patches + i;
|
||||
total = 0;
|
||||
|
||||
VectorCopy (patch->origin, origin);
|
||||
plane = *patch->plane;
|
||||
|
||||
if (!PvsForOrigin (patch->origin, pvs))
|
||||
return;
|
||||
|
||||
// find out which patch2s will collect light
|
||||
// from patch
|
||||
|
||||
all_transfers = transfers;
|
||||
patch->numtransfers = 0;
|
||||
for (j=0, patch2 = patches ; j<num_patches ; j++, patch2++)
|
||||
{
|
||||
transfers[j] = 0;
|
||||
|
||||
if (j == i)
|
||||
continue;
|
||||
|
||||
// check pvs bit
|
||||
if (!nopvs)
|
||||
{
|
||||
cluster = patch2->cluster;
|
||||
if (cluster == -1)
|
||||
continue;
|
||||
if ( ! ( pvs[cluster>>3] & (1<<(cluster&7)) ) )
|
||||
continue; // not in pvs
|
||||
}
|
||||
|
||||
// calculate vector
|
||||
VectorSubtract (patch2->origin, origin, delta);
|
||||
dist = VectorNormalize (delta, delta);
|
||||
if (!dist)
|
||||
continue; // should never happen
|
||||
|
||||
// reletive angles
|
||||
scale = DotProduct (delta, plane.normal);
|
||||
scale *= -DotProduct (delta, patch2->plane->normal);
|
||||
if (scale <= 0)
|
||||
continue;
|
||||
|
||||
// check exact tramsfer
|
||||
if (TestLine_r (0, patch->origin, patch2->origin) )
|
||||
continue;
|
||||
|
||||
trans = scale * patch2->area / (dist*dist);
|
||||
|
||||
if (trans < 0)
|
||||
trans = 0; // rounding errors...
|
||||
|
||||
transfers[j] = trans;
|
||||
if (trans > 0)
|
||||
{
|
||||
total += trans;
|
||||
patch->numtransfers++;
|
||||
}
|
||||
}
|
||||
|
||||
// copy the transfers out and normalize
|
||||
// total should be somewhere near PI if everything went right
|
||||
// because partial occlusion isn't accounted for, and nearby
|
||||
// patches have underestimated form factors, it will usually
|
||||
// be higher than PI
|
||||
if (patch->numtransfers)
|
||||
{
|
||||
transfer_t *t;
|
||||
|
||||
if (patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES)
|
||||
Error ("Weird numtransfers");
|
||||
s = patch->numtransfers * sizeof(transfer_t);
|
||||
patch->transfers = malloc (s);
|
||||
if (!patch->transfers)
|
||||
Error ("Memory allocation failure");
|
||||
|
||||
//
|
||||
// normalize all transfers so all of the light
|
||||
// is transfered to the surroundings
|
||||
//
|
||||
t = patch->transfers;
|
||||
itotal = 0;
|
||||
for (j=0 ; j<num_patches ; j++)
|
||||
{
|
||||
if (transfers[j] <= 0)
|
||||
continue;
|
||||
itrans = transfers[j]*0x10000 / total;
|
||||
itotal += itrans;
|
||||
t->transfer = itrans;
|
||||
t->patch = j;
|
||||
t++;
|
||||
}
|
||||
}
|
||||
|
||||
// don't bother locking around this. not that important.
|
||||
total_transfer += patch->numtransfers;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
FreeTransfers
|
||||
=============
|
||||
*/
|
||||
void FreeTransfers (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0 ; i<num_patches ; i++)
|
||||
{
|
||||
free (patches[i].transfers);
|
||||
patches[i].transfers = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//===================================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
WriteWorld
|
||||
=============
|
||||
*/
|
||||
void WriteWorld (char *name)
|
||||
{
|
||||
int i, j;
|
||||
FILE *out;
|
||||
patch_t *patch;
|
||||
winding_t *w;
|
||||
|
||||
out = fopen (name, "w");
|
||||
if (!out)
|
||||
Error ("Couldn't open %s", name);
|
||||
|
||||
for (j=0, patch=patches ; j<num_patches ; j++, patch++)
|
||||
{
|
||||
w = patch->winding;
|
||||
fprintf (out, "%i\n", w->numpoints);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
fprintf (out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
|
||||
w->p[i][0],
|
||||
w->p[i][1],
|
||||
w->p[i][2],
|
||||
patch->totallight[0],
|
||||
patch->totallight[1],
|
||||
patch->totallight[2]);
|
||||
}
|
||||
fprintf (out, "\n");
|
||||
}
|
||||
|
||||
fclose (out);
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
WriteGlView
|
||||
=============
|
||||
*/
|
||||
void WriteGlView (void)
|
||||
{
|
||||
char name[1024];
|
||||
FILE *f;
|
||||
int i, j;
|
||||
patch_t *p;
|
||||
winding_t *w;
|
||||
|
||||
strcpy (name, source);
|
||||
StripExtension (name);
|
||||
strcat (name, ".glr");
|
||||
|
||||
f = fopen (name, "w");
|
||||
if (!f)
|
||||
Error ("Couldn't open %s", f);
|
||||
|
||||
for (j=0 ; j<num_patches ; j++)
|
||||
{
|
||||
p = &patches[j];
|
||||
w = p->winding;
|
||||
fprintf (f, "%i\n", w->numpoints);
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
{
|
||||
fprintf (f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
|
||||
w->p[i][0],
|
||||
w->p[i][1],
|
||||
w->p[i][2],
|
||||
p->totallight[0]/128,
|
||||
p->totallight[1]/128,
|
||||
p->totallight[2]/128);
|
||||
}
|
||||
fprintf (f, "\n");
|
||||
}
|
||||
|
||||
fclose (f);
|
||||
}
|
||||
|
||||
|
||||
//==============================================================
|
||||
|
||||
/*
|
||||
=============
|
||||
CollectLight
|
||||
=============
|
||||
*/
|
||||
float CollectLight (void)
|
||||
{
|
||||
int i, j;
|
||||
patch_t *patch;
|
||||
vec_t total;
|
||||
|
||||
total = 0;
|
||||
|
||||
for (i=0, patch=patches ; i<num_patches ; i++, patch++)
|
||||
{
|
||||
// skys never collect light, it is just dropped
|
||||
if (patch->sky)
|
||||
{
|
||||
VectorClear (radiosity[i]);
|
||||
VectorClear (illumination[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
patch->totallight[j] += illumination[i][j] / patch->area;
|
||||
radiosity[i][j] = illumination[i][j] * patch->reflectivity[j];
|
||||
}
|
||||
|
||||
total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2];
|
||||
VectorClear (illumination[i]);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
ShootLight
|
||||
|
||||
Send light out to other patches
|
||||
Run multi-threaded
|
||||
=============
|
||||
*/
|
||||
void ShootLight (int patchnum)
|
||||
{
|
||||
int k, l;
|
||||
transfer_t *trans;
|
||||
int num;
|
||||
patch_t *patch;
|
||||
vec3_t send;
|
||||
|
||||
// this is the amount of light we are distributing
|
||||
// prescale it so that multiplying by the 16 bit
|
||||
// transfer values gives a proper output value
|
||||
for (k=0 ; k<3 ; k++)
|
||||
send[k] = radiosity[patchnum][k] / 0x10000;
|
||||
patch = &patches[patchnum];
|
||||
|
||||
trans = patch->transfers;
|
||||
num = patch->numtransfers;
|
||||
|
||||
for (k=0 ; k<num ; k++, trans++)
|
||||
{
|
||||
for (l=0 ; l<3 ; l++)
|
||||
illumination[trans->patch][l] += send[l]*trans->transfer;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
BounceLight
|
||||
=============
|
||||
*/
|
||||
void BounceLight (void)
|
||||
{
|
||||
int i, j;
|
||||
float added;
|
||||
char name[64];
|
||||
patch_t *p;
|
||||
|
||||
for (i=0 ; i<num_patches ; i++)
|
||||
{
|
||||
p = &patches[i];
|
||||
for (j=0 ; j<3 ; j++)
|
||||
{
|
||||
// p->totallight[j] = p->samplelight[j];
|
||||
radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0 ; i<numbounce ; i++)
|
||||
{
|
||||
RunThreadsOnIndividual (num_patches, false, ShootLight);
|
||||
added = CollectLight ();
|
||||
|
||||
qprintf ("bounce:%i added:%f\n", i, added);
|
||||
if ( dumppatches && (i==0 || i == numbounce-1) )
|
||||
{
|
||||
sprintf (name, "bounce%i.txt", i);
|
||||
WriteWorld (name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============================================================
|
||||
|
||||
void CheckPatches (void)
|
||||
{
|
||||
int i;
|
||||
patch_t *patch;
|
||||
|
||||
for (i=0 ; i<num_patches ; i++)
|
||||
{
|
||||
patch = &patches[i];
|
||||
if (patch->totallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0)
|
||||
Error ("negative patch totallight\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
=============
|
||||
RadWorld
|
||||
=============
|
||||
*/
|
||||
void RadWorld (void)
|
||||
{
|
||||
if (numnodes == 0 || numfaces == 0)
|
||||
Error ("Empty map");
|
||||
MakeBackplanes ();
|
||||
MakeParents (0, -1);
|
||||
MakeTnodes (&dmodels[0]);
|
||||
|
||||
// turn each face into a single patch
|
||||
MakePatches ();
|
||||
|
||||
// subdivide patches to a maximum dimension
|
||||
SubdividePatches ();
|
||||
|
||||
// create directlights out of patches and lights
|
||||
CreateDirectLights ();
|
||||
|
||||
// build initial facelights
|
||||
RunThreadsOnIndividual (numfaces, true, BuildFacelights);
|
||||
|
||||
if (numbounce > 0)
|
||||
{
|
||||
// build transfer lists
|
||||
RunThreadsOnIndividual (num_patches, true, MakeTransfers);
|
||||
qprintf ("transfer lists: %5.1f megs\n"
|
||||
, (float)total_transfer * sizeof(transfer_t) / (1024*1024));
|
||||
|
||||
// spread light around
|
||||
BounceLight ();
|
||||
|
||||
FreeTransfers ();
|
||||
|
||||
CheckPatches ();
|
||||
}
|
||||
|
||||
if (glview)
|
||||
WriteGlView ();
|
||||
|
||||
// blend bounced light into direct light and save
|
||||
PairEdges ();
|
||||
LinkPlaneFaces ();
|
||||
|
||||
lightdatasize = 0;
|
||||
RunThreadsOnIndividual (numfaces, true, FinalLightFace);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
========
|
||||
main
|
||||
|
||||
light modelfile
|
||||
========
|
||||
*/
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
double start, end;
|
||||
char name[1024];
|
||||
|
||||
printf ("----- Radiosity ----\n");
|
||||
|
||||
verbose = false;
|
||||
|
||||
for (i=1 ; i<argc ; i++)
|
||||
{
|
||||
if (!strcmp(argv[i],"-dump"))
|
||||
dumppatches = true;
|
||||
else if (!strcmp(argv[i],"-bounce"))
|
||||
{
|
||||
numbounce = atoi (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-v"))
|
||||
{
|
||||
verbose = true;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-extra"))
|
||||
{
|
||||
extrasamples = true;
|
||||
printf ("extrasamples = true\n");
|
||||
}
|
||||
else if (!strcmp(argv[i],"-threads"))
|
||||
{
|
||||
numthreads = atoi (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-chop"))
|
||||
{
|
||||
subdiv = atoi (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-scale"))
|
||||
{
|
||||
lightscale = atof (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-direct"))
|
||||
{
|
||||
direct_scale *= atof(argv[i+1]);
|
||||
printf ("direct light scaling at %f\n", direct_scale);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-entity"))
|
||||
{
|
||||
entity_scale *= atof(argv[i+1]);
|
||||
printf ("entity light scaling at %f\n", entity_scale);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-glview"))
|
||||
{
|
||||
glview = true;
|
||||
printf ("glview = true\n");
|
||||
}
|
||||
else if (!strcmp(argv[i],"-nopvs"))
|
||||
{
|
||||
nopvs = true;
|
||||
printf ("nopvs = true\n");
|
||||
}
|
||||
else if (!strcmp(argv[i],"-ambient"))
|
||||
{
|
||||
ambient = atof (argv[i+1]) * 128;
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i],"-maxlight"))
|
||||
{
|
||||
maxlight = atof (argv[i+1]) * 128;
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp (argv[i],"-tmpin"))
|
||||
strcpy (inbase, "/tmp");
|
||||
else if (!strcmp (argv[i],"-tmpout"))
|
||||
strcpy (outbase, "/tmp");
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
ThreadSetDefault ();
|
||||
|
||||
if (maxlight > 255)
|
||||
maxlight = 255;
|
||||
|
||||
if (i != argc - 1)
|
||||
Error ("usage: qrad [-v] [-chop num] [-scale num] [-ambient num] [-maxlight num] [-threads num] bspfile");
|
||||
|
||||
start = I_FloatTime ();
|
||||
|
||||
SetQdirFromPath (argv[i]);
|
||||
strcpy (source, ExpandArg(argv[i]));
|
||||
StripExtension (source);
|
||||
DefaultExtension (source, ".bsp");
|
||||
|
||||
// ReadLightFile ();
|
||||
|
||||
sprintf (name, "%s%s", inbase, source);
|
||||
printf ("reading %s\n", name);
|
||||
LoadBSPFile (name);
|
||||
ParseEntities ();
|
||||
CalcTextureReflectivity ();
|
||||
|
||||
if (!visdatasize)
|
||||
{
|
||||
printf ("No vis information, direct lighting only.\n");
|
||||
numbounce = 0;
|
||||
ambient = 0.1;
|
||||
}
|
||||
|
||||
RadWorld ();
|
||||
|
||||
sprintf (name, "%s%s", outbase, source);
|
||||
printf ("writing %s\n", name);
|
||||
WriteBSPFile (name);
|
||||
|
||||
end = I_FloatTime ();
|
||||
printf ("%5.0f seconds elapsed\n", end-start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
295
bsp/qrad3/trace.c
Normal file
295
bsp/qrad3/trace.c
Normal file
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; 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"
|
||||
|
||||
#define ON_EPSILON 0.1
|
||||
|
||||
typedef struct tnode_s
|
||||
{
|
||||
int type;
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
int children[2];
|
||||
int pad;
|
||||
} tnode_t;
|
||||
|
||||
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;
|
||||
|
||||
t = tnode_p++;
|
||||
|
||||
node = dnodes + nodenum;
|
||||
plane = dplanes + node->planenum;
|
||||
|
||||
t->type = plane->type;
|
||||
VectorCopy (plane->normal, t->normal);
|
||||
t->dist = plane->dist;
|
||||
|
||||
for (i=0 ; i<2 ; i++)
|
||||
{
|
||||
if (node->children[i] < 0)
|
||||
t->children[i] = (dleafs[-node->children[i] - 1].contents & CONTENTS_SOLID) | (1<<31);
|
||||
else
|
||||
{
|
||||
t->children[i] = tnode_p - tnodes;
|
||||
MakeTnode (node->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
=============
|
||||
MakeTnodes
|
||||
|
||||
Loads the node structure out of a .bsp file to be used for light occlusion
|
||||
=============
|
||||
*/
|
||||
void MakeTnodes (dmodel_t *bm)
|
||||
{
|
||||
// 32 byte align the structs
|
||||
tnodes = malloc( (numnodes+1) * sizeof(tnode_t));
|
||||
tnodes = (tnode_t *)(((int)tnodes + 31)&~31);
|
||||
tnode_p = tnodes;
|
||||
|
||||
MakeTnode (0);
|
||||
}
|
||||
|
||||
|
||||
//==========================================================
|
||||
|
||||
|
||||
int TestLine_r (int node, vec3_t start, vec3_t stop)
|
||||
{
|
||||
tnode_t *tnode;
|
||||
float front, back;
|
||||
vec3_t mid;
|
||||
float frac;
|
||||
int side;
|
||||
int r;
|
||||
|
||||
if (node & (1<<31))
|
||||
return node & ~(1<<31); // leaf node
|
||||
|
||||
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 >= -ON_EPSILON && back >= -ON_EPSILON)
|
||||
return TestLine_r (tnode->children[0], start, stop);
|
||||
|
||||
if (front < ON_EPSILON && back < ON_EPSILON)
|
||||
return TestLine_r (tnode->children[1], start, stop);
|
||||
|
||||
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 = TestLine_r (tnode->children[side], start, mid);
|
||||
if (r)
|
||||
return r;
|
||||
return TestLine_r (tnode->children[!side], mid, stop);
|
||||
}
|
||||
|
||||
int TestLine (vec3_t start, vec3_t stop)
|
||||
{
|
||||
return TestLine_r (0, start, stop);
|
||||
}
|
||||
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
LINE TRACING
|
||||
|
||||
The major lighting operation is a point to point visibility test, performed
|
||||
by recursive subdivision of the line by the BSP tree.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3_t backpt;
|
||||
int side;
|
||||
int node;
|
||||
} tracestack_t;
|
||||
|
||||
|
||||
/*
|
||||
==============
|
||||
TestLine
|
||||
==============
|
||||
*/
|
||||
qboolean _TestLine (vec3_t start, vec3_t stop)
|
||||
{
|
||||
int node;
|
||||
float front, back;
|
||||
tracestack_t *tstack_p;
|
||||
int side;
|
||||
float frontx,fronty, frontz, backx, backy, backz;
|
||||
tracestack_t tracestack[64];
|
||||
tnode_t *tnode;
|
||||
|
||||
frontx = start[0];
|
||||
fronty = start[1];
|
||||
frontz = start[2];
|
||||
backx = stop[0];
|
||||
backy = stop[1];
|
||||
backz = stop[2];
|
||||
|
||||
tstack_p = tracestack;
|
||||
node = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (node == CONTENTS_SOLID)
|
||||
{
|
||||
#if 0
|
||||
float d1, d2, d3;
|
||||
|
||||
d1 = backx - frontx;
|
||||
d2 = backy - fronty;
|
||||
d3 = backz - frontz;
|
||||
|
||||
if (d1*d1 + d2*d2 + d3*d3 > 1)
|
||||
#endif
|
||||
return false; // DONE!
|
||||
}
|
||||
|
||||
while (node < 0)
|
||||
{
|
||||
// pop up the stack for a back side
|
||||
tstack_p--;
|
||||
if (tstack_p < tracestack)
|
||||
return true;
|
||||
node = tstack_p->node;
|
||||
|
||||
// set the hit point for this plane
|
||||
|
||||
frontx = backx;
|
||||
fronty = backy;
|
||||
frontz = backz;
|
||||
|
||||
// go down the back side
|
||||
|
||||
backx = tstack_p->backpt[0];
|
||||
backy = tstack_p->backpt[1];
|
||||
backz = tstack_p->backpt[2];
|
||||
|
||||
node = tnodes[tstack_p->node].children[!tstack_p->side];
|
||||
}
|
||||
|
||||
tnode = &tnodes[node];
|
||||
|
||||
switch (tnode->type)
|
||||
{
|
||||
case PLANE_X:
|
||||
front = frontx - tnode->dist;
|
||||
back = backx - tnode->dist;
|
||||
break;
|
||||
case PLANE_Y:
|
||||
front = fronty - tnode->dist;
|
||||
back = backy - tnode->dist;
|
||||
break;
|
||||
case PLANE_Z:
|
||||
front = frontz - tnode->dist;
|
||||
back = backz - tnode->dist;
|
||||
break;
|
||||
default:
|
||||
front = (frontx*tnode->normal[0] + fronty*tnode->normal[1] + frontz*tnode->normal[2]) - tnode->dist;
|
||||
back = (backx*tnode->normal[0] + backy*tnode->normal[1] + backz*tnode->normal[2]) - tnode->dist;
|
||||
break;
|
||||
}
|
||||
|
||||
if (front > -ON_EPSILON && back > -ON_EPSILON)
|
||||
// if (front > 0 && back > 0)
|
||||
{
|
||||
node = tnode->children[0];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (front < ON_EPSILON && back < ON_EPSILON)
|
||||
// if (front <= 0 && back <= 0)
|
||||
{
|
||||
node = tnode->children[1];
|
||||
continue;
|
||||
}
|
||||
|
||||
side = front < 0;
|
||||
|
||||
front = front / (front-back);
|
||||
|
||||
tstack_p->node = node;
|
||||
tstack_p->side = side;
|
||||
tstack_p->backpt[0] = backx;
|
||||
tstack_p->backpt[1] = backy;
|
||||
tstack_p->backpt[2] = backz;
|
||||
|
||||
tstack_p++;
|
||||
|
||||
backx = frontx + front*(backx-frontx);
|
||||
backy = fronty + front*(backy-fronty);
|
||||
backz = frontz + front*(backz-frontz);
|
||||
|
||||
node = tnode->children[side];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
788
bsp/qvis3/flow.c
Normal file
788
bsp/qvis3/flow.c
Normal file
@@ -0,0 +1,788 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; 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;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
ChopWinding
|
||||
|
||||
==============
|
||||
*/
|
||||
winding_t *ChopWinding (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);
|
||||
|
||||
// fing 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 = false;
|
||||
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 = false;
|
||||
break;
|
||||
}
|
||||
else if (d > ON_EPSILON)
|
||||
{ // source is on the positive side, so we want all
|
||||
// pass and target on the negative side
|
||||
fliptest = true;
|
||||
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;
|
||||
}
|
||||
|
||||
//
|
||||
// clip target by the seperating plane
|
||||
//
|
||||
target = ChopWinding (target, stack, &plane);
|
||||
if (!target)
|
||||
return NULL; // target is not visible
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
portal_t *p;
|
||||
plane_t backplane;
|
||||
leaf_t *leaf;
|
||||
int i, j;
|
||||
long *test, *might, *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;
|
||||
|
||||
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];
|
||||
pnum = p - 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;
|
||||
for (j=0 ; j<portallongs ; j++)
|
||||
{
|
||||
might[j] = ((long *)prevstack->mightsee)[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 = ChopWinding (p->winding, &stack, &thread->pstack_head.portalplane);
|
||||
if (!stack.pass)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#else
|
||||
stack.pass = ChopWinding (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;
|
||||
if (d > p->radius)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (d < -p->radius)
|
||||
{
|
||||
stack.source = prevstack->source;
|
||||
}
|
||||
else
|
||||
{
|
||||
stack.source = ChopWinding (prevstack->source, &stack, &backplane);
|
||||
if (!stack.source)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#else
|
||||
stack.source = ChopWinding (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;
|
||||
}
|
||||
|
||||
stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, false, &stack);
|
||||
if (!stack.pass)
|
||||
continue;
|
||||
|
||||
stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, true, &stack);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============
|
||||
PortalFlow
|
||||
|
||||
generates the portalvis bit vector
|
||||
===============
|
||||
*/
|
||||
void PortalFlow (int portalnum)
|
||||
{
|
||||
threaddata_t data;
|
||||
int i;
|
||||
portal_t *p;
|
||||
int c_might, c_can;
|
||||
|
||||
p = sorted_portals[portalnum];
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
===============================================================================
|
||||
|
||||
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 mew portal
|
||||
|
||||
===============================================================================
|
||||
*/
|
||||
|
||||
int c_flood, c_vis;
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
SimpleFlood
|
||||
|
||||
==================
|
||||
*/
|
||||
void SimpleFlood (portal_t *srcportal, int leafnum)
|
||||
{
|
||||
int i;
|
||||
leaf_t *leaf;
|
||||
portal_t *p;
|
||||
int pnum;
|
||||
|
||||
leaf = &leafs[leafnum];
|
||||
|
||||
for (i=0 ; i<leaf->numportals ; i++)
|
||||
{
|
||||
p = leaf->portals[i];
|
||||
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;
|
||||
portal_t *tp, *p;
|
||||
float d;
|
||||
winding_t *w;
|
||||
|
||||
p = portals+portalnum;
|
||||
|
||||
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;
|
||||
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)
|
||||
{
|
||||
portal_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];
|
||||
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)
|
||||
{
|
||||
portal_t *p;
|
||||
|
||||
p = portals+portalnum;
|
||||
|
||||
RecursiveLeafBitFlow (p->leaf, p->portalflood, p->portalvis);
|
||||
|
||||
// build leaf vis information
|
||||
p->nummightsee = CountBits (p->portalvis, numportals*2);
|
||||
c_vis += p->nummightsee;
|
||||
}
|
||||
|
||||
|
||||
62
bsp/qvis3/makefile
Normal file
62
bsp/qvis3/makefile
Normal file
@@ -0,0 +1,62 @@
|
||||
|
||||
CFLAGS = -c
|
||||
LDFLAGS =
|
||||
ODIR = baddir
|
||||
|
||||
EXEBASE = qvis3
|
||||
EXE = $(ODIR)/qvis3
|
||||
all: $(EXE)
|
||||
|
||||
_next:
|
||||
make "CFLAGS = -c -g -I../../common" "ODIR = next"
|
||||
|
||||
_irix:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
|
||||
_irixinst:
|
||||
make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix"
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
_irixclean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
_osf:
|
||||
make "CFLAGS = -c -O4 -I../../common -threads" "LDFLAGS = -threads -lm" "ODIR = osf"
|
||||
|
||||
clean:
|
||||
rm -f irix/*.o irix/$(EXEBASE)
|
||||
|
||||
install:
|
||||
cp irix/$(EXEBASE) /limbo/quake2/bin_irix
|
||||
|
||||
|
||||
FILES = $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/mathlib.o $(ODIR)/scriplib.o $(ODIR)/threads.o $(ODIR)/qvis3.o $(ODIR)/flow.o
|
||||
|
||||
$(EXE) : $(FILES)
|
||||
cc -o $(EXE) $(LDFLAGS) $(FILES)
|
||||
|
||||
$(ODIR)/qvis3.o : qvis3.c
|
||||
cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i
|
||||
cc $(CFLAGS) -o $@ /tmp/temp.i
|
||||
$(ODIR)/flow.o : flow.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)/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
|
||||
615
bsp/qvis3/qvis3.c
Normal file
615
bsp/qvis3/qvis3.c
Normal file
@@ -0,0 +1,615 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "vis.h"
|
||||
#include "threads.h"
|
||||
#include "stdlib.h"
|
||||
|
||||
int numportals;
|
||||
int portalclusters;
|
||||
|
||||
char inbase[32];
|
||||
char outbase[32];
|
||||
|
||||
portal_t *portals;
|
||||
leaf_t *leafs;
|
||||
|
||||
int c_portaltest, c_portalpass, c_portalcheck;
|
||||
|
||||
byte *uncompressedvis;
|
||||
|
||||
byte *vismap, *vismap_p, *vismap_end; // past visfile
|
||||
int originalvismapsize;
|
||||
|
||||
int leafbytes; // (portalclusters+63)>>3
|
||||
int leaflongs;
|
||||
|
||||
int portalbytes, portallongs;
|
||||
|
||||
qboolean fastvis;
|
||||
qboolean nosort;
|
||||
|
||||
int testlevel = 2;
|
||||
|
||||
int totalvis;
|
||||
|
||||
portal_t *sorted_portals[MAX_MAP_PORTALS*2];
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
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 pw(winding_t *w)
|
||||
{
|
||||
int i;
|
||||
for (i=0 ; i<w->numpoints ; i++)
|
||||
printf ("(%5.1f, %5.1f, %5.1f)\n",w->points[i][0], w->points[i][1],w->points[i][2]);
|
||||
}
|
||||
|
||||
void prl(leaf_t *l)
|
||||
{
|
||||
int i;
|
||||
portal_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 ( (*(portal_t **)a)->nummightsee == (*(portal_t **)b)->nummightsee)
|
||||
return 0;
|
||||
if ( (*(portal_t **)a)->nummightsee < (*(portal_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;
|
||||
portal_t *p;
|
||||
int c_leafs;
|
||||
|
||||
|
||||
memset (leafbits, 0, leafbytes);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
byte compressed[MAX_MAP_LEAFS/8];
|
||||
int i, j;
|
||||
int numvis;
|
||||
byte *dest;
|
||||
portal_t *p;
|
||||
int pnum;
|
||||
|
||||
// OR together all the portalvis bits
|
||||
|
||||
memset (portalvector, 0, portalbytes);
|
||||
leaf = &leafs[leafnum];
|
||||
for (i=0 ; i<leaf->numportals ; i++)
|
||||
{
|
||||
p = leaf->portals[i];
|
||||
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);
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
// save uncompressed for PHS calculation
|
||||
memcpy (uncompressedvis + leafnum*leafbytes, uncompressed, leafbytes);
|
||||
|
||||
//
|
||||
// compress the bit string
|
||||
//
|
||||
qprintf ("cluster %4i : %4i visible\n", leafnum, numvis);
|
||||
totalvis += numvis;
|
||||
|
||||
i = CompressVis (uncompressed, compressed);
|
||||
|
||||
dest = vismap_p;
|
||||
vismap_p += i;
|
||||
|
||||
if (vismap_p > vismap_end)
|
||||
Error ("Vismap expansion overflow");
|
||||
|
||||
dvis->bitofs[leafnum][DVIS_PVS] = dest-vismap;
|
||||
|
||||
memcpy (dest, compressed, i);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CalcPortalVis
|
||||
==================
|
||||
*/
|
||||
void CalcPortalVis (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
// fastvis just uses mightsee for a very loose bound
|
||||
if (fastvis)
|
||||
{
|
||||
for (i=0 ; i<numportals*2 ; i++)
|
||||
{
|
||||
portals[i].portalvis = portals[i].portalflood;
|
||||
portals[i].status = stat_done;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
RunThreadsOnIndividual (numportals*2, true, PortalFlow);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
==================
|
||||
CalcVis
|
||||
==================
|
||||
*/
|
||||
void CalcVis (void)
|
||||
{
|
||||
int i;
|
||||
|
||||
RunThreadsOnIndividual (numportals*2, true, BasePortalVis);
|
||||
|
||||
// RunThreadsOnIndividual (numportals*2, true, BetterPortalVis);
|
||||
|
||||
SortPortals ();
|
||||
|
||||
CalcPortalVis ();
|
||||
|
||||
//
|
||||
// assemble the leaf vis lists by oring and compressing the portal lists
|
||||
//
|
||||
for (i=0 ; i<portalclusters ; i++)
|
||||
ClusterMerge (i);
|
||||
|
||||
printf ("Average clusters visible: %i\n", totalvis / portalclusters);
|
||||
}
|
||||
|
||||
|
||||
void SetPortalSphere (portal_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;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
LoadPortals
|
||||
============
|
||||
*/
|
||||
void LoadPortals (char *name)
|
||||
{
|
||||
int i, j;
|
||||
portal_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",magic, &portalclusters, &numportals) != 3)
|
||||
Error ("LoadPortals: failed to read header");
|
||||
if (strcmp(magic,PORTALFILE))
|
||||
Error ("LoadPortals: not a portal file");
|
||||
|
||||
printf ("%4i portalclusters\n", portalclusters);
|
||||
printf ("%4i numportals\n", numportals);
|
||||
|
||||
// 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(portal_t));
|
||||
memset (portals, 0, 2*numportals*sizeof(portal_t));
|
||||
|
||||
leafs = malloc(portalclusters*sizeof(leaf_t));
|
||||
memset (leafs, 0, portalclusters*sizeof(leaf_t));
|
||||
|
||||
originalvismapsize = portalclusters*leafbytes;
|
||||
uncompressedvis = malloc(originalvismapsize);
|
||||
|
||||
vismap = vismap_p = dvisdata;
|
||||
dvis->numclusters = portalclusters;
|
||||
vismap_p = (byte *)&dvis->bitofs[portalclusters];
|
||||
|
||||
vismap_end = vismap + MAX_MAP_VISIBILITY;
|
||||
|
||||
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);
|
||||
|
||||
w = p->winding = NewWinding (numpoints);
|
||||
w->original = true;
|
||||
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->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->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++;
|
||||
|
||||
}
|
||||
|
||||
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];
|
||||
byte compressed[MAX_MAP_LEAFS/8];
|
||||
|
||||
printf ("Building PHS...\n");
|
||||
|
||||
count = 0;
|
||||
for (i=0 ; i<portalclusters ; i++)
|
||||
{
|
||||
scan = uncompressedvis + 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 *)(uncompressedvis + 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++;
|
||||
|
||||
//
|
||||
// compress the bit string
|
||||
//
|
||||
j = CompressVis (uncompressed, compressed);
|
||||
|
||||
dest = (long *)vismap_p;
|
||||
vismap_p += j;
|
||||
|
||||
if (vismap_p > vismap_end)
|
||||
Error ("Vismap expansion overflow");
|
||||
|
||||
dvis->bitofs[i][DVIS_PHS] = (byte *)dest-vismap;
|
||||
|
||||
memcpy (dest, compressed, j);
|
||||
}
|
||||
|
||||
printf ("Average clusters hearable: %i\n", count/portalclusters);
|
||||
}
|
||||
|
||||
/*
|
||||
===========
|
||||
main
|
||||
===========
|
||||
*/
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
char portalfile[1024];
|
||||
char source[1024];
|
||||
char name[1024];
|
||||
int i;
|
||||
double start, end;
|
||||
|
||||
printf ("---- vis ----\n");
|
||||
|
||||
verbose = false;
|
||||
for (i=1 ; i<argc ; i++)
|
||||
{
|
||||
if (!strcmp(argv[i],"-threads"))
|
||||
{
|
||||
numthreads = atoi (argv[i+1]);
|
||||
i++;
|
||||
}
|
||||
else if (!strcmp(argv[i], "-fast"))
|
||||
{
|
||||
printf ("fastvis = true\n");
|
||||
fastvis = true;
|
||||
}
|
||||
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 = true;
|
||||
}
|
||||
else if (!strcmp (argv[i],"-nosort"))
|
||||
{
|
||||
printf ("nosort = true\n");
|
||||
nosort = true;
|
||||
}
|
||||
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");
|
||||
|
||||
start = I_FloatTime ();
|
||||
|
||||
ThreadSetDefault ();
|
||||
|
||||
SetQdirFromPath (argv[i]);
|
||||
strcpy (source, ExpandArg(argv[i]));
|
||||
StripExtension (source);
|
||||
DefaultExtension (source, ".bsp");
|
||||
|
||||
sprintf (name, "%s%s", inbase, source);
|
||||
printf ("reading %s\n", name);
|
||||
LoadBSPFile (name);
|
||||
if (numnodes == 0 || numfaces == 0)
|
||||
Error ("Empty map");
|
||||
|
||||
sprintf (portalfile, "%s%s", inbase, ExpandArg(argv[i]));
|
||||
StripExtension (portalfile);
|
||||
strcat (portalfile, ".prt");
|
||||
|
||||
printf ("reading %s\n", portalfile);
|
||||
LoadPortals (portalfile);
|
||||
|
||||
CalcVis ();
|
||||
|
||||
CalcPHS ();
|
||||
|
||||
visdatasize = vismap_p - dvisdata;
|
||||
printf ("visdatasize:%i compressed from %i\n", visdatasize, originalvismapsize*2);
|
||||
|
||||
sprintf (name, "%s%s", outbase, source);
|
||||
printf ("writing %s\n", name);
|
||||
WriteBSPFile (name);
|
||||
|
||||
end = I_FloatTime ();
|
||||
printf ("%5.1f seconds elapsed\n", end-start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
149
bsp/qvis3/vis.h
Normal file
149
bsp/qvis3/vis.h
Normal file
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
===========================================================================
|
||||
Copyright (C) 1997-2006 Id Software, Inc.
|
||||
|
||||
This file is part of Quake 2 Tools source code.
|
||||
|
||||
Quake 2 Tools source code is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the License,
|
||||
or (at your option) any later version.
|
||||
|
||||
Quake 2 Tools source code is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Quake 2 Tools source code; 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"
|
||||
|
||||
#define MAX_PORTALS 32768
|
||||
|
||||
#define PORTALFILE "PRT1"
|
||||
|
||||
#define ON_EPSILON 0.1
|
||||
|
||||
typedef struct
|
||||
{
|
||||
vec3_t normal;
|
||||
float dist;
|
||||
} plane_t;
|
||||
|
||||
#define MAX_POINTS_ON_WINDING 64
|
||||
#define MAX_POINTS_ON_FIXED_WINDING 12
|
||||
|
||||
typedef struct
|
||||
{
|
||||
qboolean original; // don't free, it's part of the portal
|
||||
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 enum {stat_none, stat_working, stat_done} vstatus_t;
|
||||
typedef struct
|
||||
{
|
||||
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
|
||||
} portal_t;
|
||||
|
||||
typedef struct seperating_plane_s
|
||||
{
|
||||
struct seperating_plane_s *next;
|
||||
plane_t plane; // from portal is on positive side
|
||||
} sep_t;
|
||||
|
||||
|
||||
typedef struct passage_s
|
||||
{
|
||||
struct passage_s *next;
|
||||
int from, to; // leaf numbers
|
||||
sep_t *planes;
|
||||
} passage_t;
|
||||
|
||||
#define MAX_PORTALS_ON_LEAF 128
|
||||
typedef struct leaf_s
|
||||
{
|
||||
int numportals;
|
||||
passage_t *passages;
|
||||
portal_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;
|
||||
portal_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;
|
||||
} pstack_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
portal_t *base;
|
||||
int c_chains;
|
||||
pstack_t pstack_head;
|
||||
} threaddata_t;
|
||||
|
||||
|
||||
|
||||
extern int numportals;
|
||||
extern int portalclusters;
|
||||
|
||||
extern portal_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);
|
||||
|
||||
extern portal_t *sorted_portals[MAX_MAP_PORTALS*2];
|
||||
|
||||
int CountBits (byte *bits, int numbits);
|
||||
Reference in New Issue
Block a user