-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-*/\r
-#include "qbsp.h"\r
-\r
-int c_nofaces;\r
-int c_facenodes;\r
-\r
-\r
-/*\r
-=========================================================\r
-\r
-ONLY SAVE OUT PLANES THAT ARE ACTUALLY USED AS NODES\r
-\r
-=========================================================\r
-*/\r
-\r
-int planeused[MAX_MAP_PLANES];\r
-\r
-/*\r
-============\r
-EmitPlanes\r
-\r
-There is no oportunity to discard planes, because all of the original\r
-brushes will be saved in the map.\r
-============\r
-*/\r
-void EmitPlanes (void)\r
-{\r
- int i;\r
- dplane_t *dp;\r
- plane_t *mp;\r
- int planetranslate[MAX_MAP_PLANES];\r
-\r
- mp = mapplanes;\r
- for (i=0 ; i<nummapplanes ; i++, mp++)\r
- {\r
- dp = &dplanes[numplanes];\r
- planetranslate[i] = numplanes;\r
- VectorCopy ( mp->normal, dp->normal);\r
- dp->dist = mp->dist;\r
- dp->type = mp->type;\r
- numplanes++;\r
- }\r
-}\r
-\r
-\r
-//========================================================\r
-\r
-void EmitMarkFace (dleaf_t *leaf_p, face_t *f)\r
-{\r
- int i;\r
- int facenum;\r
-\r
- while (f->merged)\r
- f = f->merged;\r
-\r
- if (f->split[0])\r
- {\r
- EmitMarkFace (leaf_p, f->split[0]);\r
- EmitMarkFace (leaf_p, f->split[1]);\r
- return;\r
- }\r
-\r
- facenum = f->outputnumber;\r
- if (facenum == -1)\r
- return; // degenerate face\r
-\r
- if (facenum < 0 || facenum >= numfaces)\r
- Error ("Bad leafface");\r
- for (i=leaf_p->firstleafface ; i<numleaffaces ; i++)\r
- if (dleaffaces[i] == facenum)\r
- break; // merged out face\r
- if (i == numleaffaces)\r
- {\r
- if (numleaffaces >= MAX_MAP_LEAFFACES)\r
- Error ("MAX_MAP_LEAFFACES");\r
-\r
- dleaffaces[numleaffaces] = facenum;\r
- numleaffaces++;\r
- }\r
-\r
-}\r
-\r
-\r
-/*\r
-==================\r
-EmitLeaf\r
-==================\r
-*/\r
-void EmitLeaf (node_t *node)\r
-{\r
- dleaf_t *leaf_p;\r
- portal_t *p;\r
- int s;\r
- face_t *f;\r
- bspbrush_t *b;\r
- int i;\r
- int brushnum;\r
-\r
- // emit a leaf\r
- if (numleafs >= MAX_MAP_LEAFS)\r
- Error ("MAX_MAP_LEAFS");\r
-\r
- leaf_p = &dleafs[numleafs];\r
- numleafs++;\r
-\r
- leaf_p->contents = node->contents;\r
- leaf_p->cluster = node->cluster;\r
- leaf_p->area = node->area;\r
-\r
- //\r
- // write bounding box info\r
- // \r
- VectorCopy ((short) node->mins, leaf_p->mins);\r
- VectorCopy ((short) node->maxs, leaf_p->maxs);\r
- \r
- //\r
- // write the leafbrushes\r
- //\r
- leaf_p->firstleafbrush = numleafbrushes;\r
- for (b=node->brushlist ; b ; b=b->next)\r
- {\r
- if (numleafbrushes >= MAX_MAP_LEAFBRUSHES)\r
- Error ("MAX_MAP_LEAFBRUSHES");\r
-\r
- brushnum = b->original - mapbrushes;\r
- for (i=leaf_p->firstleafbrush ; i<numleafbrushes ; i++)\r
- if (dleafbrushes[i] == brushnum)\r
- break;\r
- if (i == numleafbrushes)\r
- {\r
- dleafbrushes[numleafbrushes] = brushnum;\r
- numleafbrushes++;\r
- }\r
- }\r
- leaf_p->numleafbrushes = numleafbrushes - leaf_p->firstleafbrush;\r
-\r
- //\r
- // write the leaffaces\r
- //\r
- if (leaf_p->contents & CONTENTS_SOLID)\r
- return; // no leaffaces in solids\r
-\r
- leaf_p->firstleafface = numleaffaces;\r
-\r
- for (p = node->portals ; p ; p = p->next[s]) \r
- {\r
- s = (p->nodes[1] == node);\r
- f = p->face[s];\r
- if (!f)\r
- continue; // not a visible portal\r
-\r
- EmitMarkFace (leaf_p, f);\r
- }\r
- \r
- leaf_p->numleaffaces = numleaffaces - leaf_p->firstleafface;\r
-}\r
-\r
-\r
-/*\r
-==================\r
-EmitFace\r
-==================\r
-*/\r
-void EmitFace (face_t *f)\r
-{\r
- dface_t *df;\r
- int i;\r
- int e;\r
-\r
- f->outputnumber = -1;\r
-\r
- if (f->numpoints < 3)\r
- {\r
- return; // degenerated\r
- }\r
- if (f->merged || f->split[0] || f->split[1])\r
- {\r
- return; // not a final face\r
- }\r
-\r
- // save output number so leaffaces can use\r
- f->outputnumber = numfaces;\r
-\r
- if (numfaces >= MAX_MAP_FACES)\r
- Error ("numfaces == MAX_MAP_FACES");\r
- df = &dfaces[numfaces];\r
- numfaces++;\r
-\r
- // planenum is used by qlight, but not quake\r
- df->planenum = f->planenum & (~1);\r
- df->side = f->planenum & 1;\r
-\r
- df->firstedge = numsurfedges;\r
- df->numedges = f->numpoints;\r
- df->texinfo = f->texinfo;\r
- for (i=0 ; i<f->numpoints ; i++)\r
- {\r
-// e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f);\r
- e = GetEdge2 (f->vertexnums[i], f->vertexnums[(i+1)%f->numpoints], f);\r
- if (numsurfedges >= MAX_MAP_SURFEDGES)\r
- Error ("numsurfedges == MAX_MAP_SURFEDGES");\r
- dsurfedges[numsurfedges] = e;\r
- numsurfedges++;\r
- }\r
-}\r
-\r
-/*\r
-============\r
-EmitDrawingNode_r\r
-============\r
-*/\r
-int EmitDrawNode_r (node_t *node)\r
-{\r
- dnode_t *n;\r
- face_t *f;\r
- int i;\r
-\r
- if (node->planenum == PLANENUM_LEAF)\r
- {\r
- EmitLeaf (node);\r
- return -numleafs;\r
- }\r
-\r
- // emit a node \r
- if (numnodes == MAX_MAP_NODES)\r
- Error ("MAX_MAP_NODES");\r
- n = &dnodes[numnodes];\r
- numnodes++;\r
-\r
- VectorCopy ((short) node->mins, n->mins);\r
- VectorCopy ((short) node->maxs, n->maxs);\r
-\r
- planeused[node->planenum]++;\r
- planeused[node->planenum^1]++;\r
-\r
- if (node->planenum & 1)\r
- Error ("WriteDrawNodes_r: odd planenum");\r
- n->planenum = node->planenum;\r
- n->firstface = numfaces;\r
-\r
- if (!node->faces)\r
- c_nofaces++;\r
- else\r
- c_facenodes++;\r
-\r
- for (f=node->faces ; f ; f=f->next)\r
- EmitFace (f);\r
-\r
- n->numfaces = numfaces - n->firstface;\r
-\r
-\r
- //\r
- // recursively output the other nodes\r
- // \r
- for (i=0 ; i<2 ; i++)\r
- {\r
- if (node->children[i]->planenum == PLANENUM_LEAF)\r
- {\r
- n->children[i] = -(numleafs + 1);\r
- EmitLeaf (node->children[i]);\r
- }\r
- else\r
- {\r
- n->children[i] = numnodes; \r
- EmitDrawNode_r (node->children[i]);\r
- }\r
- }\r
-\r
- return n - dnodes;\r
-}\r
-\r
-//=========================================================\r
-\r
-\r
-/*\r
-============\r
-WriteBSP\r
-============\r
-*/\r
-void WriteBSP (node_t *headnode)\r
-{\r
- int oldfaces;\r
-\r
- c_nofaces = 0;\r
- c_facenodes = 0;\r
-\r
- Sys_FPrintf( SYS_VRB, "--- WriteBSP ---\n");\r
-\r
- oldfaces = numfaces;\r
- dmodels[nummodels].headnode = EmitDrawNode_r (headnode);\r
- EmitAreaPortals (headnode);\r
-\r
- Sys_FPrintf( SYS_VRB, "%5i nodes with faces\n", c_facenodes);\r
- Sys_FPrintf( SYS_VRB, "%5i nodes without faces\n", c_nofaces);\r
- Sys_FPrintf( SYS_VRB, "%5i faces\n", numfaces-oldfaces);\r
-}\r
-\r
-//===========================================================\r
-\r
-/*\r
-============\r
-SetModelNumbers\r
-============\r
-*/\r
-void SetModelNumbers (void)\r
-{\r
- int i;\r
- int models;\r
- char value[10];\r
-\r
- models = 1;\r
- for (i=1 ; i<num_entities ; i++)\r
- {\r
- if (entities[i].numbrushes)\r
- {\r
- sprintf (value, "*%i", models);\r
- models++;\r
- SetKeyValue (&entities[i], "model", value);\r
- }\r
- }\r
-\r
-}\r
-\r
-/*\r
-============\r
-SetLightStyles\r
-============\r
-*/\r
-#define MAX_SWITCHED_LIGHTS 32\r
-void SetLightStyles (void)\r
-{\r
- int stylenum;\r
- char *t;\r
- entity_t *e;\r
- int i, j;\r
- char value[10];\r
- char lighttargets[MAX_SWITCHED_LIGHTS][64];\r
-\r
-\r
- // any light that is controlled (has a targetname)\r
- // must have a unique style number generated for it\r
-\r
- stylenum = 0;\r
- for (i=1 ; i<num_entities ; i++)\r
- {\r
- e = &entities[i];\r
-\r
- t = ValueForKey (e, "classname");\r
- if (Q_strncasecmp (t, "light", 5))\r
- continue;\r
- t = ValueForKey (e, "targetname");\r
- if (!t[0])\r
- continue;\r
- \r
- // find this targetname\r
- for (j=0 ; j<stylenum ; j++)\r
- if (!strcmp (lighttargets[j], t))\r
- break;\r
- if (j == stylenum)\r
- {\r
- if (stylenum == MAX_SWITCHED_LIGHTS)\r
- Error ("stylenum == MAX_SWITCHED_LIGHTS");\r
- strcpy (lighttargets[j], t);\r
- stylenum++;\r
- }\r
- sprintf (value, "%i", 32 + j);\r
- SetKeyValue (e, "style", value);\r
- }\r
-\r
-}\r
-\r
-//===========================================================\r
-\r
-/*\r
-============\r
-EmitBrushes\r
-============\r
-*/\r
-void EmitBrushes (void)\r
-{\r
- int i, j, bnum, s, x;\r
- dbrush_t *db;\r
- mapbrush_t *b;\r
- dbrushside_t *cp;\r
- vec3_t normal;\r
- vec_t dist;\r
- int planenum;\r
-\r
- numbrushsides = 0;\r
- numbrushes = nummapbrushes;\r
-\r
- for (bnum=0 ; bnum<nummapbrushes ; bnum++)\r
- {\r
- b = &mapbrushes[bnum];\r
- db = &dbrushes[bnum];\r
-\r
- db->contents = b->contents;\r
- db->firstside = numbrushsides;\r
- db->numsides = b->numsides;\r
- for (j=0 ; j<b->numsides ; j++)\r
- {\r
- if (numbrushsides == MAX_MAP_BRUSHSIDES)\r
- Error ("MAX_MAP_BRUSHSIDES");\r
- cp = &dbrushsides[numbrushsides];\r
- numbrushsides++;\r
- cp->planenum = b->original_sides[j].planenum;\r
- cp->texinfo = b->original_sides[j].texinfo;\r
- }\r
-\r
- // add any axis planes not contained in the brush to bevel off corners\r
- for (x=0 ; x<3 ; x++)\r
- for (s=-1 ; s<=1 ; s+=2)\r
- {\r
- // add the plane\r
- VectorCopy (vec3_origin, normal);\r
- normal[x] = (float) s;\r
- if (s == -1)\r
- dist = -b->mins[x];\r
- else\r
- dist = b->maxs[x];\r
- planenum = FindFloatPlane (normal, dist);\r
- for (i=0 ; i<b->numsides ; i++)\r
- if (b->original_sides[i].planenum == planenum)\r
- break;\r
- if (i == b->numsides)\r
- {\r
- if (numbrushsides >= MAX_MAP_BRUSHSIDES)\r
- Error ("MAX_MAP_BRUSHSIDES");\r
-\r
- dbrushsides[numbrushsides].planenum = planenum;\r
- dbrushsides[numbrushsides].texinfo =\r
- dbrushsides[numbrushsides-1].texinfo;\r
- numbrushsides++;\r
- db->numsides++;\r
- }\r
- }\r
-\r
- }\r
-\r
-}\r
-\r
-//===========================================================\r
-\r
-/*\r
-==================\r
-BeginBSPFile\r
-==================\r
-*/\r
-void BeginBSPFile (void)\r
-{\r
- // these values may actually be initialized\r
- // if the file existed when loaded, so clear them explicitly\r
- nummodels = 0;\r
- numfaces = 0;\r
- numnodes = 0;\r
- numbrushsides = 0;\r
- numvertexes = 0;\r
- numleaffaces = 0;\r
- numleafbrushes = 0;\r
- numsurfedges = 0;\r
-\r
- // edge 0 is not used, because 0 can't be negated\r
- numedges = 1;\r
-\r
- // leave vertex 0 as an error\r
- numvertexes = 1;\r
-\r
- // leave leaf 0 as an error\r
- numleafs = 1;\r
- dleafs[0].contents = CONTENTS_SOLID;\r
-}\r
-\r
-\r
-/*\r
-============\r
-EndBSPFile\r
-============\r
-*/\r
-void EndBSPFile (void)\r
-{\r
- char path[1024];\r
-\r
-#if 0\r
- int len;\r
- byte *buf;\r
-#endif\r
-\r
- EmitBrushes ();\r
- EmitPlanes ();\r
- UnparseEntities ();\r
-\r
- // load the pop\r
-#if 0\r
- sprintf (path, "%s/pics/pop.lmp", gamedir);\r
- len = LoadFile (path, &buf);\r
- memcpy (dpop, buf, sizeof(dpop));\r
- free (buf);\r
-#endif\r
-\r
- // write the map\r
- sprintf (path, "%s.bsp", source);\r
- Sys_Printf ("Writing %s\n", path);\r
- WriteBSPFile (path);\r
-}\r
-\r
-\r
-/*\r
-==================\r
-BeginModel\r
-==================\r
-*/\r
-int firstmodleaf;\r
-extern int firstmodeledge;\r
-extern int firstmodelface;\r
-void BeginModel (void)\r
-{\r
- dmodel_t *mod;\r
- int start, end;\r
- mapbrush_t *b;\r
- int j;\r
- entity_t *e;\r
- vec3_t mins, maxs;\r
-\r
- if (nummodels == MAX_MAP_MODELS)\r
- Error ("MAX_MAP_MODELS");\r
- mod = &dmodels[nummodels];\r
-\r
- mod->firstface = numfaces;\r
-\r
- firstmodleaf = numleafs;\r
- firstmodeledge = numedges;\r
- firstmodelface = numfaces;\r
-\r
- //\r
- // bound the brushes\r
- //\r
- e = &entities[entity_num];\r
-\r
- start = e->firstbrush;\r
- end = start + e->numbrushes;\r
- ClearBounds (mins, maxs);\r
-\r
- for (j=start ; j<end ; j++)\r
- {\r
- b = &mapbrushes[j];\r
- if (!b->numsides)\r
- continue; // not a real brush (origin brush)\r
- AddPointToBounds (b->mins, mins, maxs);\r
- AddPointToBounds (b->maxs, mins, maxs);\r
- }\r
-\r
- VectorCopy (mins, mod->mins);\r
- VectorCopy (maxs, mod->maxs);\r
-}\r
-\r
-\r
-/*\r
-==================\r
-EndModel\r
-==================\r
-*/\r
-void EndModel (void)\r
-{\r
- dmodel_t *mod;\r
-\r
- mod = &dmodels[nummodels];\r
-\r
- mod->numfaces = numfaces - mod->firstface;\r
-\r
- nummodels++;\r
-}\r
-\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant 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.
+
+GtkRadiant 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 GtkRadiant; 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 ((short) node->mins, leaf_p->mins);
+ VectorCopy ((short) 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 ((short) node->mins, n->mins);
+ VectorCopy ((short) 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;
+
+ Sys_FPrintf( SYS_VRB, "--- WriteBSP ---\n");
+
+ oldfaces = numfaces;
+ dmodels[nummodels].headnode = EmitDrawNode_r (headnode);
+ EmitAreaPortals (headnode);
+
+ Sys_FPrintf( SYS_VRB, "%5i nodes with faces\n", c_facenodes);
+ Sys_FPrintf( SYS_VRB, "%5i nodes without faces\n", c_nofaces);
+ Sys_FPrintf( SYS_VRB, "%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] = (float) 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];
+
+ EmitBrushes();
+ EmitPlanes();
+ UnparseEntities();
+
+ // write the map
+ sprintf( path, "%s.bsp", source );
+ Sys_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++;
+}
+