]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake2/q2map/writebsp.c
Merge branch 'fix-lightanglehl' into 'master'
[xonotic/netradiant.git] / tools / quake2 / q2map / writebsp.c
index 083f0ea769190ef39a035e4e3b9cc8305d89c0e5..0d3c6a480c371ff5aa09dd36e9a5cbf658c71aef 100644 (file)
-/*\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-2006 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];
+
+#if 0
+       int len;
+       byte    *buf;
+#endif
+
+       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 );
+       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++;
+}