mirror of
https://github.com/id-Software/Quake-2-Tools.git
synced 2026-03-20 09:00:02 +01:00
The Quake 2 tools as originally released under the GPL license.
This commit is contained in:
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++;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user