aboutsummaryrefslogtreecommitdiffstats
path: root/code/bspc/map_q2.c
diff options
context:
space:
mode:
authorzakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea>2005-08-26 17:39:27 +0000
committerzakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea>2005-08-26 17:39:27 +0000
commit6bf20c78f5b69d40bcc4931df93d29198435ab67 (patch)
treee3eda937a05d7db42de725b7013bd0344b987f34 /code/bspc/map_q2.c
parent872d4d7f55af706737ffb361bb76ad13e7496770 (diff)
downloadioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.tar.gz
ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.zip
newlines fixed
git-svn-id: svn://svn.icculus.org/quake3/trunk@6 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'code/bspc/map_q2.c')
-rwxr-xr-xcode/bspc/map_q2.c2324
1 files changed, 1162 insertions, 1162 deletions
diff --git a/code/bspc/map_q2.c b/code/bspc/map_q2.c
index 0f15216..a91e78a 100755
--- a/code/bspc/map_q2.c
+++ b/code/bspc/map_q2.c
@@ -1,1162 +1,1162 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena 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 III Arena 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-
-//===========================================================================
-// ANSI, Area Navigational System Interface
-// AAS, Area Awareness System
-//===========================================================================
-
-#include "qbsp.h"
-#include "l_mem.h"
-#include "../botlib/aasfile.h" //aas_bbox_t
-#include "aas_store.h" //AAS_MAX_BBOXES
-#include "aas_cfg.h"
-#include "aas_map.h" //AAS_CreateMapBrushes
-#include "l_bsp_q2.h"
-
-
-#ifdef ME
-
-#define NODESTACKSIZE 1024
-
-int nodestack[NODESTACKSIZE];
-int *nodestackptr;
-int nodestacksize = 0;
-int brushmodelnumbers[MAX_MAPFILE_BRUSHES];
-int dbrushleafnums[MAX_MAPFILE_BRUSHES];
-int dplanes2mapplanes[MAX_MAPFILE_PLANES];
-
-#endif //ME
-
-//====================================================================
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_CreateMapTexinfo(void)
-{
- int i;
-
- for (i = 0; i < numtexinfo; i++)
- {
- memcpy(map_texinfo[i].vecs, texinfo[i].vecs, sizeof(float) * 2 * 4);
- map_texinfo[i].flags = texinfo[i].flags;
- map_texinfo[i].value = texinfo[i].value;
- strcpy(map_texinfo[i].texture, texinfo[i].texture);
- map_texinfo[i].nexttexinfo = 0;
- } //end for
-} //end of the function Q2_CreateMapTexinfo
-
-/*
-===========
-Q2_BrushContents
-===========
-*/
-int Q2_BrushContents (mapbrush_t *b)
-{
- int contents;
- side_t *s;
- int i;
- int trans;
-
- s = &b->original_sides[0];
- contents = s->contents;
- trans = texinfo[s->texinfo].flags;
- for (i = 1; i < b->numsides; i++, s++)
- {
- s = &b->original_sides[i];
- trans |= texinfo[s->texinfo].flags;
- if (s->contents != contents)
- {
- Log_Print("Entity %i, Brush %i: mixed face contents\n"
- , b->entitynum, b->brushnum);
- Log_Print("texture name = %s\n", texinfo[s->texinfo].texture);
- break;
- }
- }
-
- // if any side is translucent, mark the contents
- // and change solid to window
- if ( trans & (SURF_TRANS33|SURF_TRANS66) )
- {
- contents |= CONTENTS_Q2TRANSLUCENT;
- if (contents & CONTENTS_SOLID)
- {
- contents &= ~CONTENTS_SOLID;
- contents |= CONTENTS_WINDOW;
- }
- }
-
- return contents;
-}
-
-#ifdef ME
-
-#define BBOX_NORMAL_EPSILON 0.0001
-
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void MakeAreaPortalBrush(mapbrush_t *brush)
-{
- int sn;
- side_t *s;
-
- brush->contents = CONTENTS_AREAPORTAL;
-
- for (sn = 0; sn < brush->numsides; sn++)
- {
- s = brush->original_sides + sn;
- //make sure the surfaces are not hint or skip
- s->surf &= ~(SURF_HINT|SURF_SKIP);
- //
- s->texinfo = 0;
- s->contents = CONTENTS_AREAPORTAL;
- } //end for
-} //end of the function MakeAreaPortalBrush
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void DPlanes2MapPlanes(void)
-{
- int i;
-
- for (i = 0; i < numplanes; i++)
- {
- dplanes2mapplanes[i] = FindFloatPlane(dplanes[i].normal, dplanes[i].dist);
- } //end for
-} //end of the function DPlanes2MapPlanes
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void MarkVisibleBrushSides(mapbrush_t *brush)
-{
- int n, i, planenum;
- side_t *side;
- dface_t *face;
- //
- for (n = 0; n < brush->numsides; n++)
- {
- side = brush->original_sides + n;
- //if this side is a bevel or the leaf number of the brush is unknown
- if ((side->flags & SFL_BEVEL) || brush->leafnum < 0)
- {
- //this side is a valid splitter
- side->flags |= SFL_VISIBLE;
- continue;
- } //end if
- //assum this side will not be used as a splitter
- side->flags &= ~SFL_VISIBLE;
- //check if the side plane is used by a visible face
- for (i = 0; i < numfaces; i++)
- {
- face = &dfaces[i];
- planenum = dplanes2mapplanes[face->planenum];
- if ((planenum & ~1) == (side->planenum & ~1))
- {
- //this side is a valid splitter
- side->flags |= SFL_VISIBLE;
- } //end if
- } //end for
- } //end for
-} //end of the function MarkVisibleBrushSides
-
-#endif //ME
-
-/*
-=================
-Q2_ParseBrush
-=================
-*/
-void Q2_ParseBrush (script_t *script, entity_t *mapent)
-{
- mapbrush_t *b;
- int i, j, k;
- int mt;
- side_t *side, *s2;
- int planenum;
- brush_texture_t td;
- int planepts[3][3];
- token_t token;
-
- if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
- Error ("nummapbrushes == MAX_MAPFILE_BRUSHES");
-
- b = &mapbrushes[nummapbrushes];
- b->original_sides = &brushsides[nummapbrushsides];
- b->entitynum = num_entities-1;
- b->brushnum = nummapbrushes - mapent->firstbrush;
- b->leafnum = -1;
-
- do
- {
- if (!PS_ReadToken(script, &token))
- break;
- if (!strcmp(token.string, "}") )
- break;
-
- //IDBUG: mixed use of MAX_MAPFILE_? and MAX_MAP_? this could
- // lead to out of bound indexing of the arrays
- if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
- Error ("MAX_MAPFILE_BRUSHSIDES");
- side = &brushsides[nummapbrushsides];
-
- //read the three point plane definition
- for (i = 0; i < 3; i++)
- {
- if (i != 0) PS_ExpectTokenString(script, "(");
- for (j = 0; j < 3; j++)
- {
- PS_ExpectAnyToken(script, &token);
- planepts[i][j] = atof(token.string);
- } //end for
- PS_ExpectTokenString(script, ")");
- } //end for
-
- //
- //read the texturedef
- //
- PS_ExpectAnyToken(script, &token);
- strcpy(td.name, token.string);
-
- PS_ExpectAnyToken(script, &token);
- td.shift[0] = atol(token.string);
- PS_ExpectAnyToken(script, &token);
- td.shift[1] = atol(token.string);
- PS_ExpectAnyToken(script, &token);
- td.rotate = atol(token.string);
- PS_ExpectAnyToken(script, &token);
- td.scale[0] = atof(token.string);
- PS_ExpectAnyToken(script, &token);
- td.scale[1] = atof(token.string);
-
- //find default flags and values
- mt = FindMiptex (td.name);
- td.flags = textureref[mt].flags;
- td.value = textureref[mt].value;
- side->contents = textureref[mt].contents;
- side->surf = td.flags = textureref[mt].flags;
-
- //check if there's a number available
- if (PS_CheckTokenType(script, TT_NUMBER, 0, &token))
- {
- side->contents = token.intvalue;
- PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
- side->surf = td.flags = token.intvalue;
- PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
- td.value = token.intvalue;
- }
-
- // translucent objects are automatically classified as detail
- if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
- side->contents |= CONTENTS_DETAIL;
- if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- side->contents |= CONTENTS_DETAIL;
- if (fulldetail)
- side->contents &= ~CONTENTS_DETAIL;
- if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
- | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) )
- side->contents |= CONTENTS_SOLID;
-
- // hints and skips are never detail, and have no content
- if (side->surf & (SURF_HINT|SURF_SKIP) )
- {
- side->contents = 0;
- side->surf &= ~CONTENTS_DETAIL;
- }
-
-#ifdef ME
- //for creating AAS... this side is textured
- side->flags |= SFL_TEXTURED;
-#endif //ME
- //
- // find the plane number
- //
- planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
- if (planenum == -1)
- {
- Log_Print("Entity %i, Brush %i: plane with no normal\n"
- , b->entitynum, b->brushnum);
- continue;
- }
-
- //
- // see if the plane has been used already
- //
- for (k=0 ; k<b->numsides ; k++)
- {
- s2 = b->original_sides + k;
- if (s2->planenum == planenum)
- {
- Log_Print("Entity %i, Brush %i: duplicate plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- if ( s2->planenum == (planenum^1) )
- {
- Log_Print("Entity %i, Brush %i: mirrored plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- }
- if (k != b->numsides)
- continue; // duplicated
-
- //
- // keep this side
- //
-
- side = b->original_sides + b->numsides;
- side->planenum = planenum;
- side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
- &td, vec3_origin);
-
- // save the td off in case there is an origin brush and we
- // have to recalculate the texinfo
- side_brushtextures[nummapbrushsides] = td;
-
- nummapbrushsides++;
- b->numsides++;
- } while (1);
-
- // get the content for the entire brush
- b->contents = Q2_BrushContents (b);
-
-#ifdef ME
- if (BrushExists(b))
- {
- c_squattbrushes++;
- b->numsides = 0;
- return;
- } //end if
-
- if (create_aas)
- {
- //create AAS brushes, and add brush bevels
- AAS_CreateMapBrushes(b, mapent, true);
- //NOTE: if we return here then duplicate plane errors occur for the non world entities
- return;
- } //end if
-#endif //ME
-
- // allow detail brushes to be removed
- if (nodetail && (b->contents & CONTENTS_DETAIL) )
- {
- b->numsides = 0;
- return;
- }
-
- // allow water brushes to be removed
- if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
- {
- b->numsides = 0;
- return;
- }
-
- // create windings for sides and bounds for brush
- MakeBrushWindings (b);
-
- // brushes that will not be visible at all will never be
- // used as bsp splitters
- if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- {
- c_clipbrushes++;
- for (i=0 ; i<b->numsides ; i++)
- b->original_sides[i].texinfo = TEXINFO_NODE;
- }
-
- //
- // origin brushes are removed, but they set
- // the rotation origin for the rest of the brushes
- // in the entity. After the entire entity is parsed,
- // the planenums and texinfos will be adjusted for
- // the origin brush
- //
- if (b->contents & CONTENTS_ORIGIN)
- {
- char string[32];
- vec3_t origin;
-
- if (num_entities == 1)
- {
- Error ("Entity %i, Brush %i: origin brushes not allowed in world"
- , b->entitynum, b->brushnum);
- return;
- }
-
- VectorAdd (b->mins, b->maxs, origin);
- VectorScale (origin, 0.5, origin);
-
- sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
- SetKeyValue (&entities[b->entitynum], "origin", string);
-
- VectorCopy (origin, entities[b->entitynum].origin);
-
- // don't keep this brush
- b->numsides = 0;
-
- return;
- }
-
- AddBrushBevels(b);
-
- nummapbrushes++;
- mapent->numbrushes++;
-}
-
-/*
-================
-Q2_MoveBrushesToWorld
-
-Takes all of the brushes from the current entity and
-adds them to the world's brush list.
-
-Used by func_group and func_areaportal
-================
-*/
-void Q2_MoveBrushesToWorld (entity_t *mapent)
-{
- int newbrushes;
- int worldbrushes;
- mapbrush_t *temp;
- int i;
-
- // this is pretty gross, because the brushes are expected to be
- // in linear order for each entity
-
- newbrushes = mapent->numbrushes;
- worldbrushes = entities[0].numbrushes;
-
- temp = GetMemory(newbrushes*sizeof(mapbrush_t));
- memcpy (temp, mapbrushes + mapent->firstbrush, newbrushes*sizeof(mapbrush_t));
-
-#if 0 // let them keep their original brush numbers
- for (i=0 ; i<newbrushes ; i++)
- temp[i].entitynum = 0;
-#endif
-
- // make space to move the brushes (overlapped copy)
- memmove (mapbrushes + worldbrushes + newbrushes,
- mapbrushes + worldbrushes,
- sizeof(mapbrush_t) * (nummapbrushes - worldbrushes - newbrushes) );
-
- // copy the new brushes down
- memcpy (mapbrushes + worldbrushes, temp, sizeof(mapbrush_t) * newbrushes);
-
- // fix up indexes
- entities[0].numbrushes += newbrushes;
- for (i=1 ; i<num_entities ; i++)
- entities[i].firstbrush += newbrushes;
- FreeMemory(temp);
-
- mapent->numbrushes = 0;
-}
-
-/*
-================
-Q2_ParseMapEntity
-================
-*/
-qboolean Q2_ParseMapEntity(script_t *script)
-{
- entity_t *mapent;
- epair_t *e;
- side_t *s;
- int i, j;
- int startbrush, startsides;
- vec_t newdist;
- mapbrush_t *b;
- token_t token;
-
- if (!PS_ReadToken(script, &token)) return false;
-
- if (strcmp(token.string, "{") )
- Error ("ParseEntity: { not found");
-
- if (num_entities == MAX_MAP_ENTITIES)
- Error ("num_entities == MAX_MAP_ENTITIES");
-
- startbrush = nummapbrushes;
- startsides = nummapbrushsides;
-
- mapent = &entities[num_entities];
- num_entities++;
- memset (mapent, 0, sizeof(*mapent));
- mapent->firstbrush = nummapbrushes;
- mapent->numbrushes = 0;
-// mapent->portalareas[0] = -1;
-// mapent->portalareas[1] = -1;
-
- do
- {
- if (!PS_ReadToken(script, &token))
- {
- Error("ParseEntity: EOF without closing brace");
- } //end if
- if (!strcmp(token.string, "}")) break;
- if (!strcmp(token.string, "{"))
- {
- Q2_ParseBrush(script, mapent);
- } //end if
- else
- {
- PS_UnreadLastToken(script);
- e = ParseEpair(script);
- e->next = mapent->epairs;
- mapent->epairs = e;
- } //end else
- } while(1);
-
- GetVectorForKey(mapent, "origin", mapent->origin);
-
- //
- // if there was an origin brush, offset all of the planes and texinfo
- //
- if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
- {
- for (i=0 ; i<mapent->numbrushes ; i++)
- {
- b = &mapbrushes[mapent->firstbrush + i];
- for (j=0 ; j<b->numsides ; j++)
- {
- s = &b->original_sides[j];
- newdist = mapplanes[s->planenum].dist -
- DotProduct (mapplanes[s->planenum].normal, mapent->origin);
- s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
- s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
- &side_brushtextures[s-brushsides], mapent->origin);
- }
- MakeBrushWindings (b);
- }
- }
-
- // group entities are just for editor convenience
- // toss all brushes into the world entity
- if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
- {
- Q2_MoveBrushesToWorld (mapent);
- mapent->numbrushes = 0;
- return true;
- }
-
- // areaportal entities move their brushes, but don't eliminate
- // the entity
- if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
- {
- char str[128];
-
- if (mapent->numbrushes != 1)
- Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1);
-
- b = &mapbrushes[nummapbrushes-1];
- b->contents = CONTENTS_AREAPORTAL;
- c_areaportals++;
- mapent->areaportalnum = c_areaportals;
- // set the portal number as "style"
- sprintf (str, "%i", c_areaportals);
- SetKeyValue (mapent, "style", str);
- Q2_MoveBrushesToWorld (mapent);
- return true;
- }
-
- return true;
-}
-
-//===================================================================
-
-/*
-================
-LoadMapFile
-================
-*/
-void Q2_LoadMapFile(char *filename)
-{
- int i;
- script_t *script;
-
- Log_Print("-- Q2_LoadMapFile --\n");
-#ifdef ME
- //loaded map type
- loadedmaptype = MAPTYPE_QUAKE2;
- //reset the map loading
- ResetMapLoading();
-#endif //ME
-
- script = LoadScriptFile(filename);
- if (!script)
- {
- Log_Print("couldn't open %s\n", filename);
- return;
- } //end if
- //white spaces and escape characters inside a string are not allowed
- SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
- SCFL_NOSTRINGESCAPECHARS |
- SCFL_PRIMITIVE);
-
- nummapbrushsides = 0;
- num_entities = 0;
-
- while (Q2_ParseMapEntity(script))
- {
- }
-
- ClearBounds (map_mins, map_maxs);
- for (i=0 ; i<entities[0].numbrushes ; i++)
- {
- if (mapbrushes[i].mins[0] > 4096)
- continue; // no valid points
- AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
- AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
- } //end for
-
- PrintMapInfo();
-
- //free the script
- FreeScript(script);
-// TestExpandBrushes ();
- //
- Q2_CreateMapTexinfo();
-} //end of the function Q2_LoadMapFile
-
-#ifdef ME //Begin MAP loading from BSP file
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_SetLeafBrushesModelNumbers(int leafnum, int modelnum)
-{
- int i, brushnum;
- dleaf_t *leaf;
-
- leaf = &dleafs[leafnum];
- for (i = 0; i < leaf->numleafbrushes; i++)
- {
- brushnum = dleafbrushes[leaf->firstleafbrush + i];
- brushmodelnumbers[brushnum] = modelnum;
- dbrushleafnums[brushnum] = leafnum;
- } //end for
-} //end of the function Q2_SetLeafBrushesModelNumbers
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_InitNodeStack(void)
-{
- nodestackptr = nodestack;
- nodestacksize = 0;
-} //end of the function Q2_InitNodeStack
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_PushNodeStack(int num)
-{
- *nodestackptr = num;
- nodestackptr++;
- nodestacksize++;
- //
- if (nodestackptr >= &nodestack[NODESTACKSIZE])
- {
- Error("Q2_PushNodeStack: stack overflow\n");
- } //end if
-} //end of the function Q2_PushNodeStack
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-int Q2_PopNodeStack(void)
-{
- //if the stack is empty
- if (nodestackptr <= nodestack) return -1;
- //decrease stack pointer
- nodestackptr--;
- nodestacksize--;
- //return the top value from the stack
- return *nodestackptr;
-} //end of the function Q2_PopNodeStack
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_SetBrushModelNumbers(entity_t *mapent)
-{
- int n, pn;
- int leafnum;
-
- //
- Q2_InitNodeStack();
- //head node (root) of the bsp tree
- n = dmodels[mapent->modelnum].headnode;
- pn = 0;
-
- do
- {
- //if we are in a leaf (negative node number)
- if (n < 0)
- {
- //number of the leaf
- leafnum = (-n) - 1;
- //set the brush numbers
- Q2_SetLeafBrushesModelNumbers(leafnum, mapent->modelnum);
- //walk back into the tree to find a second child to continue with
- for (pn = Q2_PopNodeStack(); pn >= 0; n = pn, pn = Q2_PopNodeStack())
- {
- //if we took the first child at the parent node
- if (dnodes[pn].children[0] == n) break;
- } //end for
- //if the stack wasn't empty (if not processed whole tree)
- if (pn >= 0)
- {
- //push the parent node again
- Q2_PushNodeStack(pn);
- //we proceed with the second child of the parent node
- n = dnodes[pn].children[1];
- } //end if
- } //end if
- else
- {
- //push the current node onto the stack
- Q2_PushNodeStack(n);
- //walk forward into the tree to the first child
- n = dnodes[n].children[0];
- } //end else
- } while(pn >= 0);
-} //end of the function Q2_SetBrushModelNumbers
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_BSPBrushToMapBrush(dbrush_t *bspbrush, entity_t *mapent)
-{
- mapbrush_t *b;
- int i, k, n;
- side_t *side, *s2;
- int planenum;
- dbrushside_t *bspbrushside;
- dplane_t *bspplane;
-
- if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
- Error ("nummapbrushes >= MAX_MAPFILE_BRUSHES");
-
- b = &mapbrushes[nummapbrushes];
- b->original_sides = &brushsides[nummapbrushsides];
- b->entitynum = mapent-entities;
- b->brushnum = nummapbrushes - mapent->firstbrush;
- b->leafnum = dbrushleafnums[bspbrush - dbrushes];
-
- for (n = 0; n < bspbrush->numsides; n++)
- {
- //pointer to the bsp brush side
- bspbrushside = &dbrushsides[bspbrush->firstside + n];
-
- if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
- {
- Error ("MAX_MAPFILE_BRUSHSIDES");
- } //end if
- //pointer to the map brush side
- side = &brushsides[nummapbrushsides];
- //if the BSP brush side is textured
- if (brushsidetextured[bspbrush->firstside + n]) side->flags |= SFL_TEXTURED;
- else side->flags &= ~SFL_TEXTURED;
- //ME: can get side contents and surf directly from BSP file
- side->contents = bspbrush->contents;
- //if the texinfo is TEXINFO_NODE
- if (bspbrushside->texinfo < 0) side->surf = 0;
- else side->surf = texinfo[bspbrushside->texinfo].flags;
-
- // translucent objects are automatically classified as detail
- if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
- side->contents |= CONTENTS_DETAIL;
- if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- side->contents |= CONTENTS_DETAIL;
- if (fulldetail)
- side->contents &= ~CONTENTS_DETAIL;
- if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
- | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) )
- side->contents |= CONTENTS_SOLID;
-
- // hints and skips are never detail, and have no content
- if (side->surf & (SURF_HINT|SURF_SKIP) )
- {
- side->contents = 0;
- side->surf &= ~CONTENTS_DETAIL;
- }
-
- //ME: get a plane for this side
- bspplane = &dplanes[bspbrushside->planenum];
- planenum = FindFloatPlane(bspplane->normal, bspplane->dist);
- //
- // see if the plane has been used already
- //
- //ME: this really shouldn't happen!!!
- //ME: otherwise the bsp file is corrupted??
- //ME: still it seems to happen, maybe Johny Boy's
- //ME: brush bevel adding is crappy ?
- for (k = 0; k < b->numsides; k++)
- {
- s2 = b->original_sides + k;
-// if (DotProduct (mapplanes[s2->planenum].normal, mapplanes[planenum].normal) > 0.999
-// && fabs(mapplanes[s2->planenum].dist - mapplanes[planenum].dist) < 0.01 )
-
- if (s2->planenum == planenum)
- {
- Log_Print("Entity %i, Brush %i: duplicate plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- if ( s2->planenum == (planenum^1) )
- {
- Log_Print("Entity %i, Brush %i: mirrored plane\n"
- , b->entitynum, b->brushnum);
- break;
- }
- }
- if (k != b->numsides)
- continue; // duplicated
-
- //
- // keep this side
- //
- //ME: reset pointer to side, why? hell I dunno (pointer is set above already)
- side = b->original_sides + b->numsides;
- //ME: store the plane number
- side->planenum = planenum;
- //ME: texinfo is already stored when bsp is loaded
- //NOTE: check for TEXINFO_NODE, otherwise crash in Q2_BrushContents
- if (bspbrushside->texinfo < 0) side->texinfo = 0;
- else side->texinfo = bspbrushside->texinfo;
-
- // save the td off in case there is an origin brush and we
- // have to recalculate the texinfo
- // ME: don't need to recalculate because it's already done
- // (for non-world entities) in the BSP file
-// side_brushtextures[nummapbrushsides] = td;
-
- nummapbrushsides++;
- b->numsides++;
- } //end for
-
- // get the content for the entire brush
- b->contents = bspbrush->contents;
- Q2_BrushContents(b);
-
- if (BrushExists(b))
- {
- c_squattbrushes++;
- b->numsides = 0;
- return;
- } //end if
-
- //if we're creating AAS
- if (create_aas)
- {
- //create the AAS brushes from this brush, don't add brush bevels
- AAS_CreateMapBrushes(b, mapent, false);
- return;
- } //end if
-
- // allow detail brushes to be removed
- if (nodetail && (b->contents & CONTENTS_DETAIL) )
- {
- b->numsides = 0;
- return;
- } //end if
-
- // allow water brushes to be removed
- if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
- {
- b->numsides = 0;
- return;
- } //end if
-
- // create windings for sides and bounds for brush
- MakeBrushWindings(b);
-
- //mark brushes without winding or with a tiny window as bevels
- MarkBrushBevels(b);
-
- // brushes that will not be visible at all will never be
- // used as bsp splitters
- if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- {
- c_clipbrushes++;
- for (i = 0; i < b->numsides; i++)
- b->original_sides[i].texinfo = TEXINFO_NODE;
- } //end for
-
- //
- // origin brushes are removed, but they set
- // the rotation origin for the rest of the brushes
- // in the entity. After the entire entity is parsed,
- // the planenums and texinfos will be adjusted for
- // the origin brush
- //
- //ME: not needed because the entities in the BSP file already
- // have an origin set
-// if (b->contents & CONTENTS_ORIGIN)
-// {
-// char string[32];
-// vec3_t origin;
-//
-// if (num_entities == 1)
-// {
-// Error ("Entity %i, Brush %i: origin brushes not allowed in world"
-// , b->entitynum, b->brushnum);
-// return;
-// }
-//
-// VectorAdd (b->mins, b->maxs, origin);
-// VectorScale (origin, 0.5, origin);
-//
-// sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
-// SetKeyValue (&entities[b->entitynum], "origin", string);
-//
-// VectorCopy (origin, entities[b->entitynum].origin);
-//
-// // don't keep this brush
-// b->numsides = 0;
-//
-// return;
-// }
-
- //ME: the bsp brushes already have bevels, so we won't try to
- // add them again (especially since Johny Boy's bevel adding might
- // be crappy)
-// AddBrushBevels(b);
-
- nummapbrushes++;
- mapent->numbrushes++;
-} //end of the function Q2_BSPBrushToMapBrush
-//===========================================================================
-//===========================================================================
-void Q2_ParseBSPBrushes(entity_t *mapent)
-{
- int i;
-
- //give all the brushes that belong to this entity the number of the
- //BSP model used by this entity
- Q2_SetBrushModelNumbers(mapent);
- //now parse all the brushes with the correct mapent->modelnum
- for (i = 0; i < numbrushes; i++)
- {
- if (brushmodelnumbers[i] == mapent->modelnum)
- {
- Q2_BSPBrushToMapBrush(&dbrushes[i], mapent);
- } //end if
- } //end for
-} //end of the function Q2_ParseBSPBrushes
-//===========================================================================
-//===========================================================================
-qboolean Q2_ParseBSPEntity(int entnum)
-{
- entity_t *mapent;
- char *model;
- int startbrush, startsides;
-
- startbrush = nummapbrushes;
- startsides = nummapbrushsides;
-
- mapent = &entities[entnum];//num_entities];
- mapent->firstbrush = nummapbrushes;
- mapent->numbrushes = 0;
- mapent->modelnum = -1; //-1 = no model
-
- model = ValueForKey(mapent, "model");
- if (model && strlen(model))
- {
- if (*model != '*')
- {
- Error("Q2_ParseBSPEntity: model number without leading *");
- } //end if
- //get the model number of this entity (skip the leading *)
- mapent->modelnum = atoi(&model[1]);
- } //end if
-
- GetVectorForKey(mapent, "origin", mapent->origin);
-
- //if this is the world entity it has model number zero
- //the world entity has no model key
- if (!strcmp("worldspawn", ValueForKey(mapent, "classname")))
- {
- mapent->modelnum = 0;
- } //end if
- //if the map entity has a BSP model (a modelnum of -1 is used for
- //entities that aren't using a BSP model)
- if (mapent->modelnum >= 0)
- {
- //parse the bsp brushes
- Q2_ParseBSPBrushes(mapent);
- } //end if
- //
- //the origin of the entity is already taken into account
- //
- //func_group entities can't be in the bsp file
- //
- //check out the func_areaportal entities
- if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
- {
- c_areaportals++;
- mapent->areaportalnum = c_areaportals;
- return true;
- } //end if
- return true;
-} //end of the function Q2_ParseBSPEntity
-//===========================================================================
-//
-// Parameter: -
-// Returns: -
-// Changes Globals: -
-//===========================================================================
-void Q2_LoadMapFromBSP(char *filename, int offset, int length)
-{
- int i;
-
- Log_Print("-- Q2_LoadMapFromBSP --\n");
- //loaded map type
- loadedmaptype = MAPTYPE_QUAKE2;
-
- Log_Print("Loading map from %s...\n", filename);
- //load the bsp file
- Q2_LoadBSPFile(filename, offset, length);
-
- //create an index from bsp planes to map planes
- //DPlanes2MapPlanes();
- //clear brush model numbers
- for (i = 0; i < MAX_MAPFILE_BRUSHES; i++)
- brushmodelnumbers[i] = -1;
-
- nummapbrushsides = 0;
- num_entities = 0;
-
- Q2_ParseEntities();
- //
- for (i = 0; i < num_entities; i++)
- {
- Q2_ParseBSPEntity(i);
- } //end for
-
- //get the map mins and maxs from the world model
- ClearBounds(map_mins, map_maxs);
- for (i = 0; i < entities[0].numbrushes; i++)
- {
- if (mapbrushes[i].mins[0] > 4096)
- continue; //no valid points
- AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
- AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
- } //end for
-
- PrintMapInfo();
- //
- Q2_CreateMapTexinfo();
-} //end of the function Q2_LoadMapFromBSP
-
-void Q2_ResetMapLoading(void)
-{
- //reset for map loading from bsp
- memset(nodestack, 0, NODESTACKSIZE * sizeof(int));
- nodestackptr = NULL;
- nodestacksize = 0;
- memset(brushmodelnumbers, 0, MAX_MAPFILE_BRUSHES * sizeof(int));
-} //end of the function Q2_ResetMapLoading
-
-//End MAP loading from BSP file
-#endif //ME
-
-//====================================================================
-
-/*
-================
-TestExpandBrushes
-
-Expands all the brush planes and saves a new map out
-================
-*/
-void TestExpandBrushes (void)
-{
- FILE *f;
- side_t *s;
- int i, j, bn;
- winding_t *w;
- char *name = "expanded.map";
- mapbrush_t *brush;
- vec_t dist;
-
- Log_Print("writing %s\n", name);
- f = fopen (name, "wb");
- if (!f)
- Error ("Can't write %s\n", name);
-
- fprintf (f, "{\n\"classname\" \"worldspawn\"\n");
-
- for (bn=0 ; bn<nummapbrushes ; bn++)
- {
- brush = &mapbrushes[bn];
- fprintf (f, "{\n");
- for (i=0 ; i<brush->numsides ; i++)
- {
- s = brush->original_sides + i;
- dist = mapplanes[s->planenum].dist;
- for (j=0 ; j<3 ; j++)
- dist += fabs( 16 * mapplanes[s->planenum].normal[j] );
-
- w = BaseWindingForPlane (mapplanes[s->planenum].normal, 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);
-
- Error ("can't proceed after expanding brushes");
-} //end of the function TestExpandBrushes
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena 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 III Arena 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 Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+//===========================================================================
+// ANSI, Area Navigational System Interface
+// AAS, Area Awareness System
+//===========================================================================
+
+#include "qbsp.h"
+#include "l_mem.h"
+#include "../botlib/aasfile.h" //aas_bbox_t
+#include "aas_store.h" //AAS_MAX_BBOXES
+#include "aas_cfg.h"
+#include "aas_map.h" //AAS_CreateMapBrushes
+#include "l_bsp_q2.h"
+
+
+#ifdef ME
+
+#define NODESTACKSIZE 1024
+
+int nodestack[NODESTACKSIZE];
+int *nodestackptr;
+int nodestacksize = 0;
+int brushmodelnumbers[MAX_MAPFILE_BRUSHES];
+int dbrushleafnums[MAX_MAPFILE_BRUSHES];
+int dplanes2mapplanes[MAX_MAPFILE_PLANES];
+
+#endif //ME
+
+//====================================================================
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_CreateMapTexinfo(void)
+{
+ int i;
+
+ for (i = 0; i < numtexinfo; i++)
+ {
+ memcpy(map_texinfo[i].vecs, texinfo[i].vecs, sizeof(float) * 2 * 4);
+ map_texinfo[i].flags = texinfo[i].flags;
+ map_texinfo[i].value = texinfo[i].value;
+ strcpy(map_texinfo[i].texture, texinfo[i].texture);
+ map_texinfo[i].nexttexinfo = 0;
+ } //end for
+} //end of the function Q2_CreateMapTexinfo
+
+/*
+===========
+Q2_BrushContents
+===========
+*/
+int Q2_BrushContents (mapbrush_t *b)
+{
+ int contents;
+ side_t *s;
+ int i;
+ int trans;
+
+ s = &b->original_sides[0];
+ contents = s->contents;
+ trans = texinfo[s->texinfo].flags;
+ for (i = 1; i < b->numsides; i++, s++)
+ {
+ s = &b->original_sides[i];
+ trans |= texinfo[s->texinfo].flags;
+ if (s->contents != contents)
+ {
+ Log_Print("Entity %i, Brush %i: mixed face contents\n"
+ , b->entitynum, b->brushnum);
+ Log_Print("texture name = %s\n", texinfo[s->texinfo].texture);
+ break;
+ }
+ }
+
+ // if any side is translucent, mark the contents
+ // and change solid to window
+ if ( trans & (SURF_TRANS33|SURF_TRANS66) )
+ {
+ contents |= CONTENTS_Q2TRANSLUCENT;
+ if (contents & CONTENTS_SOLID)
+ {
+ contents &= ~CONTENTS_SOLID;
+ contents |= CONTENTS_WINDOW;
+ }
+ }
+
+ return contents;
+}
+
+#ifdef ME
+
+#define BBOX_NORMAL_EPSILON 0.0001
+
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void MakeAreaPortalBrush(mapbrush_t *brush)
+{
+ int sn;
+ side_t *s;
+
+ brush->contents = CONTENTS_AREAPORTAL;
+
+ for (sn = 0; sn < brush->numsides; sn++)
+ {
+ s = brush->original_sides + sn;
+ //make sure the surfaces are not hint or skip
+ s->surf &= ~(SURF_HINT|SURF_SKIP);
+ //
+ s->texinfo = 0;
+ s->contents = CONTENTS_AREAPORTAL;
+ } //end for
+} //end of the function MakeAreaPortalBrush
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void DPlanes2MapPlanes(void)
+{
+ int i;
+
+ for (i = 0; i < numplanes; i++)
+ {
+ dplanes2mapplanes[i] = FindFloatPlane(dplanes[i].normal, dplanes[i].dist);
+ } //end for
+} //end of the function DPlanes2MapPlanes
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void MarkVisibleBrushSides(mapbrush_t *brush)
+{
+ int n, i, planenum;
+ side_t *side;
+ dface_t *face;
+ //
+ for (n = 0; n < brush->numsides; n++)
+ {
+ side = brush->original_sides + n;
+ //if this side is a bevel or the leaf number of the brush is unknown
+ if ((side->flags & SFL_BEVEL) || brush->leafnum < 0)
+ {
+ //this side is a valid splitter
+ side->flags |= SFL_VISIBLE;
+ continue;
+ } //end if
+ //assum this side will not be used as a splitter
+ side->flags &= ~SFL_VISIBLE;
+ //check if the side plane is used by a visible face
+ for (i = 0; i < numfaces; i++)
+ {
+ face = &dfaces[i];
+ planenum = dplanes2mapplanes[face->planenum];
+ if ((planenum & ~1) == (side->planenum & ~1))
+ {
+ //this side is a valid splitter
+ side->flags |= SFL_VISIBLE;
+ } //end if
+ } //end for
+ } //end for
+} //end of the function MarkVisibleBrushSides
+
+#endif //ME
+
+/*
+=================
+Q2_ParseBrush
+=================
+*/
+void Q2_ParseBrush (script_t *script, entity_t *mapent)
+{
+ mapbrush_t *b;
+ int i, j, k;
+ int mt;
+ side_t *side, *s2;
+ int planenum;
+ brush_texture_t td;
+ int planepts[3][3];
+ token_t token;
+
+ if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
+ Error ("nummapbrushes == MAX_MAPFILE_BRUSHES");
+
+ b = &mapbrushes[nummapbrushes];
+ b->original_sides = &brushsides[nummapbrushsides];
+ b->entitynum = num_entities-1;
+ b->brushnum = nummapbrushes - mapent->firstbrush;
+ b->leafnum = -1;
+
+ do
+ {
+ if (!PS_ReadToken(script, &token))
+ break;
+ if (!strcmp(token.string, "}") )
+ break;
+
+ //IDBUG: mixed use of MAX_MAPFILE_? and MAX_MAP_? this could
+ // lead to out of bound indexing of the arrays
+ if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
+ Error ("MAX_MAPFILE_BRUSHSIDES");
+ side = &brushsides[nummapbrushsides];
+
+ //read the three point plane definition
+ for (i = 0; i < 3; i++)
+ {
+ if (i != 0) PS_ExpectTokenString(script, "(");
+ for (j = 0; j < 3; j++)
+ {
+ PS_ExpectAnyToken(script, &token);
+ planepts[i][j] = atof(token.string);
+ } //end for
+ PS_ExpectTokenString(script, ")");
+ } //end for
+
+ //
+ //read the texturedef
+ //
+ PS_ExpectAnyToken(script, &token);
+ strcpy(td.name, token.string);
+
+ PS_ExpectAnyToken(script, &token);
+ td.shift[0] = atol(token.string);
+ PS_ExpectAnyToken(script, &token);
+ td.shift[1] = atol(token.string);
+ PS_ExpectAnyToken(script, &token);
+ td.rotate = atol(token.string);
+ PS_ExpectAnyToken(script, &token);
+ td.scale[0] = atof(token.string);
+ PS_ExpectAnyToken(script, &token);
+ td.scale[1] = atof(token.string);
+
+ //find default flags and values
+ mt = FindMiptex (td.name);
+ td.flags = textureref[mt].flags;
+ td.value = textureref[mt].value;
+ side->contents = textureref[mt].contents;
+ side->surf = td.flags = textureref[mt].flags;
+
+ //check if there's a number available
+ if (PS_CheckTokenType(script, TT_NUMBER, 0, &token))
+ {
+ side->contents = token.intvalue;
+ PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
+ side->surf = td.flags = token.intvalue;
+ PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
+ td.value = token.intvalue;
+ }
+
+ // translucent objects are automatically classified as detail
+ if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
+ side->contents |= CONTENTS_DETAIL;
+ if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ side->contents |= CONTENTS_DETAIL;
+ if (fulldetail)
+ side->contents &= ~CONTENTS_DETAIL;
+ if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
+ | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) )
+ side->contents |= CONTENTS_SOLID;
+
+ // hints and skips are never detail, and have no content
+ if (side->surf & (SURF_HINT|SURF_SKIP) )
+ {
+ side->contents = 0;
+ side->surf &= ~CONTENTS_DETAIL;
+ }
+
+#ifdef ME
+ //for creating AAS... this side is textured
+ side->flags |= SFL_TEXTURED;
+#endif //ME
+ //
+ // find the plane number
+ //
+ planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
+ if (planenum == -1)
+ {
+ Log_Print("Entity %i, Brush %i: plane with no normal\n"
+ , b->entitynum, b->brushnum);
+ continue;
+ }
+
+ //
+ // see if the plane has been used already
+ //
+ for (k=0 ; k<b->numsides ; k++)
+ {
+ s2 = b->original_sides + k;
+ if (s2->planenum == planenum)
+ {
+ Log_Print("Entity %i, Brush %i: duplicate plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ if ( s2->planenum == (planenum^1) )
+ {
+ Log_Print("Entity %i, Brush %i: mirrored plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ }
+ if (k != b->numsides)
+ continue; // duplicated
+
+ //
+ // keep this side
+ //
+
+ side = b->original_sides + b->numsides;
+ side->planenum = planenum;
+ side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
+ &td, vec3_origin);
+
+ // save the td off in case there is an origin brush and we
+ // have to recalculate the texinfo
+ side_brushtextures[nummapbrushsides] = td;
+
+ nummapbrushsides++;
+ b->numsides++;
+ } while (1);
+
+ // get the content for the entire brush
+ b->contents = Q2_BrushContents (b);
+
+#ifdef ME
+ if (BrushExists(b))
+ {
+ c_squattbrushes++;
+ b->numsides = 0;
+ return;
+ } //end if
+
+ if (create_aas)
+ {
+ //create AAS brushes, and add brush bevels
+ AAS_CreateMapBrushes(b, mapent, true);
+ //NOTE: if we return here then duplicate plane errors occur for the non world entities
+ return;
+ } //end if
+#endif //ME
+
+ // allow detail brushes to be removed
+ if (nodetail && (b->contents & CONTENTS_DETAIL) )
+ {
+ b->numsides = 0;
+ return;
+ }
+
+ // allow water brushes to be removed
+ if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
+ {
+ b->numsides = 0;
+ return;
+ }
+
+ // create windings for sides and bounds for brush
+ MakeBrushWindings (b);
+
+ // brushes that will not be visible at all will never be
+ // used as bsp splitters
+ if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ {
+ c_clipbrushes++;
+ for (i=0 ; i<b->numsides ; i++)
+ b->original_sides[i].texinfo = TEXINFO_NODE;
+ }
+
+ //
+ // origin brushes are removed, but they set
+ // the rotation origin for the rest of the brushes
+ // in the entity. After the entire entity is parsed,
+ // the planenums and texinfos will be adjusted for
+ // the origin brush
+ //
+ if (b->contents & CONTENTS_ORIGIN)
+ {
+ char string[32];
+ vec3_t origin;
+
+ if (num_entities == 1)
+ {
+ Error ("Entity %i, Brush %i: origin brushes not allowed in world"
+ , b->entitynum, b->brushnum);
+ return;
+ }
+
+ VectorAdd (b->mins, b->maxs, origin);
+ VectorScale (origin, 0.5, origin);
+
+ sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
+ SetKeyValue (&entities[b->entitynum], "origin", string);
+
+ VectorCopy (origin, entities[b->entitynum].origin);
+
+ // don't keep this brush
+ b->numsides = 0;
+
+ return;
+ }
+
+ AddBrushBevels(b);
+
+ nummapbrushes++;
+ mapent->numbrushes++;
+}
+
+/*
+================
+Q2_MoveBrushesToWorld
+
+Takes all of the brushes from the current entity and
+adds them to the world's brush list.
+
+Used by func_group and func_areaportal
+================
+*/
+void Q2_MoveBrushesToWorld (entity_t *mapent)
+{
+ int newbrushes;
+ int worldbrushes;
+ mapbrush_t *temp;
+ int i;
+
+ // this is pretty gross, because the brushes are expected to be
+ // in linear order for each entity
+
+ newbrushes = mapent->numbrushes;
+ worldbrushes = entities[0].numbrushes;
+
+ temp = GetMemory(newbrushes*sizeof(mapbrush_t));
+ memcpy (temp, mapbrushes + mapent->firstbrush, newbrushes*sizeof(mapbrush_t));
+
+#if 0 // let them keep their original brush numbers
+ for (i=0 ; i<newbrushes ; i++)
+ temp[i].entitynum = 0;
+#endif
+
+ // make space to move the brushes (overlapped copy)
+ memmove (mapbrushes + worldbrushes + newbrushes,
+ mapbrushes + worldbrushes,
+ sizeof(mapbrush_t) * (nummapbrushes - worldbrushes - newbrushes) );
+
+ // copy the new brushes down
+ memcpy (mapbrushes + worldbrushes, temp, sizeof(mapbrush_t) * newbrushes);
+
+ // fix up indexes
+ entities[0].numbrushes += newbrushes;
+ for (i=1 ; i<num_entities ; i++)
+ entities[i].firstbrush += newbrushes;
+ FreeMemory(temp);
+
+ mapent->numbrushes = 0;
+}
+
+/*
+================
+Q2_ParseMapEntity
+================
+*/
+qboolean Q2_ParseMapEntity(script_t *script)
+{
+ entity_t *mapent;
+ epair_t *e;
+ side_t *s;
+ int i, j;
+ int startbrush, startsides;
+ vec_t newdist;
+ mapbrush_t *b;
+ token_t token;
+
+ if (!PS_ReadToken(script, &token)) return false;
+
+ if (strcmp(token.string, "{") )
+ Error ("ParseEntity: { not found");
+
+ if (num_entities == MAX_MAP_ENTITIES)
+ Error ("num_entities == MAX_MAP_ENTITIES");
+
+ startbrush = nummapbrushes;
+ startsides = nummapbrushsides;
+
+ mapent = &entities[num_entities];
+ num_entities++;
+ memset (mapent, 0, sizeof(*mapent));
+ mapent->firstbrush = nummapbrushes;
+ mapent->numbrushes = 0;
+// mapent->portalareas[0] = -1;
+// mapent->portalareas[1] = -1;
+
+ do
+ {
+ if (!PS_ReadToken(script, &token))
+ {
+ Error("ParseEntity: EOF without closing brace");
+ } //end if
+ if (!strcmp(token.string, "}")) break;
+ if (!strcmp(token.string, "{"))
+ {
+ Q2_ParseBrush(script, mapent);
+ } //end if
+ else
+ {
+ PS_UnreadLastToken(script);
+ e = ParseEpair(script);
+ e->next = mapent->epairs;
+ mapent->epairs = e;
+ } //end else
+ } while(1);
+
+ GetVectorForKey(mapent, "origin", mapent->origin);
+
+ //
+ // if there was an origin brush, offset all of the planes and texinfo
+ //
+ if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
+ {
+ for (i=0 ; i<mapent->numbrushes ; i++)
+ {
+ b = &mapbrushes[mapent->firstbrush + i];
+ for (j=0 ; j<b->numsides ; j++)
+ {
+ s = &b->original_sides[j];
+ newdist = mapplanes[s->planenum].dist -
+ DotProduct (mapplanes[s->planenum].normal, mapent->origin);
+ s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
+ s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
+ &side_brushtextures[s-brushsides], mapent->origin);
+ }
+ MakeBrushWindings (b);
+ }
+ }
+
+ // group entities are just for editor convenience
+ // toss all brushes into the world entity
+ if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
+ {
+ Q2_MoveBrushesToWorld (mapent);
+ mapent->numbrushes = 0;
+ return true;
+ }
+
+ // areaportal entities move their brushes, but don't eliminate
+ // the entity
+ if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
+ {
+ char str[128];
+
+ if (mapent->numbrushes != 1)
+ Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1);
+
+ b = &mapbrushes[nummapbrushes-1];
+ b->contents = CONTENTS_AREAPORTAL;
+ c_areaportals++;
+ mapent->areaportalnum = c_areaportals;
+ // set the portal number as "style"
+ sprintf (str, "%i", c_areaportals);
+ SetKeyValue (mapent, "style", str);
+ Q2_MoveBrushesToWorld (mapent);
+ return true;
+ }
+
+ return true;
+}
+
+//===================================================================
+
+/*
+================
+LoadMapFile
+================
+*/
+void Q2_LoadMapFile(char *filename)
+{
+ int i;
+ script_t *script;
+
+ Log_Print("-- Q2_LoadMapFile --\n");
+#ifdef ME
+ //loaded map type
+ loadedmaptype = MAPTYPE_QUAKE2;
+ //reset the map loading
+ ResetMapLoading();
+#endif //ME
+
+ script = LoadScriptFile(filename);
+ if (!script)
+ {
+ Log_Print("couldn't open %s\n", filename);
+ return;
+ } //end if
+ //white spaces and escape characters inside a string are not allowed
+ SetScriptFlags(script, SCFL_NOSTRINGWHITESPACES |
+ SCFL_NOSTRINGESCAPECHARS |
+ SCFL_PRIMITIVE);
+
+ nummapbrushsides = 0;
+ num_entities = 0;
+
+ while (Q2_ParseMapEntity(script))
+ {
+ }
+
+ ClearBounds (map_mins, map_maxs);
+ for (i=0 ; i<entities[0].numbrushes ; i++)
+ {
+ if (mapbrushes[i].mins[0] > 4096)
+ continue; // no valid points
+ AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
+ AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
+ } //end for
+
+ PrintMapInfo();
+
+ //free the script
+ FreeScript(script);
+// TestExpandBrushes ();
+ //
+ Q2_CreateMapTexinfo();
+} //end of the function Q2_LoadMapFile
+
+#ifdef ME //Begin MAP loading from BSP file
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_SetLeafBrushesModelNumbers(int leafnum, int modelnum)
+{
+ int i, brushnum;
+ dleaf_t *leaf;
+
+ leaf = &dleafs[leafnum];
+ for (i = 0; i < leaf->numleafbrushes; i++)
+ {
+ brushnum = dleafbrushes[leaf->firstleafbrush + i];
+ brushmodelnumbers[brushnum] = modelnum;
+ dbrushleafnums[brushnum] = leafnum;
+ } //end for
+} //end of the function Q2_SetLeafBrushesModelNumbers
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_InitNodeStack(void)
+{
+ nodestackptr = nodestack;
+ nodestacksize = 0;
+} //end of the function Q2_InitNodeStack
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_PushNodeStack(int num)
+{
+ *nodestackptr = num;
+ nodestackptr++;
+ nodestacksize++;
+ //
+ if (nodestackptr >= &nodestack[NODESTACKSIZE])
+ {
+ Error("Q2_PushNodeStack: stack overflow\n");
+ } //end if
+} //end of the function Q2_PushNodeStack
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+int Q2_PopNodeStack(void)
+{
+ //if the stack is empty
+ if (nodestackptr <= nodestack) return -1;
+ //decrease stack pointer
+ nodestackptr--;
+ nodestacksize--;
+ //return the top value from the stack
+ return *nodestackptr;
+} //end of the function Q2_PopNodeStack
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_SetBrushModelNumbers(entity_t *mapent)
+{
+ int n, pn;
+ int leafnum;
+
+ //
+ Q2_InitNodeStack();
+ //head node (root) of the bsp tree
+ n = dmodels[mapent->modelnum].headnode;
+ pn = 0;
+
+ do
+ {
+ //if we are in a leaf (negative node number)
+ if (n < 0)
+ {
+ //number of the leaf
+ leafnum = (-n) - 1;
+ //set the brush numbers
+ Q2_SetLeafBrushesModelNumbers(leafnum, mapent->modelnum);
+ //walk back into the tree to find a second child to continue with
+ for (pn = Q2_PopNodeStack(); pn >= 0; n = pn, pn = Q2_PopNodeStack())
+ {
+ //if we took the first child at the parent node
+ if (dnodes[pn].children[0] == n) break;
+ } //end for
+ //if the stack wasn't empty (if not processed whole tree)
+ if (pn >= 0)
+ {
+ //push the parent node again
+ Q2_PushNodeStack(pn);
+ //we proceed with the second child of the parent node
+ n = dnodes[pn].children[1];
+ } //end if
+ } //end if
+ else
+ {
+ //push the current node onto the stack
+ Q2_PushNodeStack(n);
+ //walk forward into the tree to the first child
+ n = dnodes[n].children[0];
+ } //end else
+ } while(pn >= 0);
+} //end of the function Q2_SetBrushModelNumbers
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_BSPBrushToMapBrush(dbrush_t *bspbrush, entity_t *mapent)
+{
+ mapbrush_t *b;
+ int i, k, n;
+ side_t *side, *s2;
+ int planenum;
+ dbrushside_t *bspbrushside;
+ dplane_t *bspplane;
+
+ if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
+ Error ("nummapbrushes >= MAX_MAPFILE_BRUSHES");
+
+ b = &mapbrushes[nummapbrushes];
+ b->original_sides = &brushsides[nummapbrushsides];
+ b->entitynum = mapent-entities;
+ b->brushnum = nummapbrushes - mapent->firstbrush;
+ b->leafnum = dbrushleafnums[bspbrush - dbrushes];
+
+ for (n = 0; n < bspbrush->numsides; n++)
+ {
+ //pointer to the bsp brush side
+ bspbrushside = &dbrushsides[bspbrush->firstside + n];
+
+ if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
+ {
+ Error ("MAX_MAPFILE_BRUSHSIDES");
+ } //end if
+ //pointer to the map brush side
+ side = &brushsides[nummapbrushsides];
+ //if the BSP brush side is textured
+ if (brushsidetextured[bspbrush->firstside + n]) side->flags |= SFL_TEXTURED;
+ else side->flags &= ~SFL_TEXTURED;
+ //ME: can get side contents and surf directly from BSP file
+ side->contents = bspbrush->contents;
+ //if the texinfo is TEXINFO_NODE
+ if (bspbrushside->texinfo < 0) side->surf = 0;
+ else side->surf = texinfo[bspbrushside->texinfo].flags;
+
+ // translucent objects are automatically classified as detail
+ if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
+ side->contents |= CONTENTS_DETAIL;
+ if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ side->contents |= CONTENTS_DETAIL;
+ if (fulldetail)
+ side->contents &= ~CONTENTS_DETAIL;
+ if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
+ | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) )
+ side->contents |= CONTENTS_SOLID;
+
+ // hints and skips are never detail, and have no content
+ if (side->surf & (SURF_HINT|SURF_SKIP) )
+ {
+ side->contents = 0;
+ side->surf &= ~CONTENTS_DETAIL;
+ }
+
+ //ME: get a plane for this side
+ bspplane = &dplanes[bspbrushside->planenum];
+ planenum = FindFloatPlane(bspplane->normal, bspplane->dist);
+ //
+ // see if the plane has been used already
+ //
+ //ME: this really shouldn't happen!!!
+ //ME: otherwise the bsp file is corrupted??
+ //ME: still it seems to happen, maybe Johny Boy's
+ //ME: brush bevel adding is crappy ?
+ for (k = 0; k < b->numsides; k++)
+ {
+ s2 = b->original_sides + k;
+// if (DotProduct (mapplanes[s2->planenum].normal, mapplanes[planenum].normal) > 0.999
+// && fabs(mapplanes[s2->planenum].dist - mapplanes[planenum].dist) < 0.01 )
+
+ if (s2->planenum == planenum)
+ {
+ Log_Print("Entity %i, Brush %i: duplicate plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ if ( s2->planenum == (planenum^1) )
+ {
+ Log_Print("Entity %i, Brush %i: mirrored plane\n"
+ , b->entitynum, b->brushnum);
+ break;
+ }
+ }
+ if (k != b->numsides)
+ continue; // duplicated
+
+ //
+ // keep this side
+ //
+ //ME: reset pointer to side, why? hell I dunno (pointer is set above already)
+ side = b->original_sides + b->numsides;
+ //ME: store the plane number
+ side->planenum = planenum;
+ //ME: texinfo is already stored when bsp is loaded
+ //NOTE: check for TEXINFO_NODE, otherwise crash in Q2_BrushContents
+ if (bspbrushside->texinfo < 0) side->texinfo = 0;
+ else side->texinfo = bspbrushside->texinfo;
+
+ // save the td off in case there is an origin brush and we
+ // have to recalculate the texinfo
+ // ME: don't need to recalculate because it's already done
+ // (for non-world entities) in the BSP file
+// side_brushtextures[nummapbrushsides] = td;
+
+ nummapbrushsides++;
+ b->numsides++;
+ } //end for
+
+ // get the content for the entire brush
+ b->contents = bspbrush->contents;
+ Q2_BrushContents(b);
+
+ if (BrushExists(b))
+ {
+ c_squattbrushes++;
+ b->numsides = 0;
+ return;
+ } //end if
+
+ //if we're creating AAS
+ if (create_aas)
+ {
+ //create the AAS brushes from this brush, don't add brush bevels
+ AAS_CreateMapBrushes(b, mapent, false);
+ return;
+ } //end if
+
+ // allow detail brushes to be removed
+ if (nodetail && (b->contents & CONTENTS_DETAIL) )
+ {
+ b->numsides = 0;
+ return;
+ } //end if
+
+ // allow water brushes to be removed
+ if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
+ {
+ b->numsides = 0;
+ return;
+ } //end if
+
+ // create windings for sides and bounds for brush
+ MakeBrushWindings(b);
+
+ //mark brushes without winding or with a tiny window as bevels
+ MarkBrushBevels(b);
+
+ // brushes that will not be visible at all will never be
+ // used as bsp splitters
+ if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ {
+ c_clipbrushes++;
+ for (i = 0; i < b->numsides; i++)
+ b->original_sides[i].texinfo = TEXINFO_NODE;
+ } //end for
+
+ //
+ // origin brushes are removed, but they set
+ // the rotation origin for the rest of the brushes
+ // in the entity. After the entire entity is parsed,
+ // the planenums and texinfos will be adjusted for
+ // the origin brush
+ //
+ //ME: not needed because the entities in the BSP file already
+ // have an origin set
+// if (b->contents & CONTENTS_ORIGIN)
+// {
+// char string[32];
+// vec3_t origin;
+//
+// if (num_entities == 1)
+// {
+// Error ("Entity %i, Brush %i: origin brushes not allowed in world"
+// , b->entitynum, b->brushnum);
+// return;
+// }
+//
+// VectorAdd (b->mins, b->maxs, origin);
+// VectorScale (origin, 0.5, origin);
+//
+// sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
+// SetKeyValue (&entities[b->entitynum], "origin", string);
+//
+// VectorCopy (origin, entities[b->entitynum].origin);
+//
+// // don't keep this brush
+// b->numsides = 0;
+//
+// return;
+// }
+
+ //ME: the bsp brushes already have bevels, so we won't try to
+ // add them again (especially since Johny Boy's bevel adding might
+ // be crappy)
+// AddBrushBevels(b);
+
+ nummapbrushes++;
+ mapent->numbrushes++;
+} //end of the function Q2_BSPBrushToMapBrush
+//===========================================================================
+//===========================================================================
+void Q2_ParseBSPBrushes(entity_t *mapent)
+{
+ int i;
+
+ //give all the brushes that belong to this entity the number of the
+ //BSP model used by this entity
+ Q2_SetBrushModelNumbers(mapent);
+ //now parse all the brushes with the correct mapent->modelnum
+ for (i = 0; i < numbrushes; i++)
+ {
+ if (brushmodelnumbers[i] == mapent->modelnum)
+ {
+ Q2_BSPBrushToMapBrush(&dbrushes[i], mapent);
+ } //end if
+ } //end for
+} //end of the function Q2_ParseBSPBrushes
+//===========================================================================
+//===========================================================================
+qboolean Q2_ParseBSPEntity(int entnum)
+{
+ entity_t *mapent;
+ char *model;
+ int startbrush, startsides;
+
+ startbrush = nummapbrushes;
+ startsides = nummapbrushsides;
+
+ mapent = &entities[entnum];//num_entities];
+ mapent->firstbrush = nummapbrushes;
+ mapent->numbrushes = 0;
+ mapent->modelnum = -1; //-1 = no model
+
+ model = ValueForKey(mapent, "model");
+ if (model && strlen(model))
+ {
+ if (*model != '*')
+ {
+ Error("Q2_ParseBSPEntity: model number without leading *");
+ } //end if
+ //get the model number of this entity (skip the leading *)
+ mapent->modelnum = atoi(&model[1]);
+ } //end if
+
+ GetVectorForKey(mapent, "origin", mapent->origin);
+
+ //if this is the world entity it has model number zero
+ //the world entity has no model key
+ if (!strcmp("worldspawn", ValueForKey(mapent, "classname")))
+ {
+ mapent->modelnum = 0;
+ } //end if
+ //if the map entity has a BSP model (a modelnum of -1 is used for
+ //entities that aren't using a BSP model)
+ if (mapent->modelnum >= 0)
+ {
+ //parse the bsp brushes
+ Q2_ParseBSPBrushes(mapent);
+ } //end if
+ //
+ //the origin of the entity is already taken into account
+ //
+ //func_group entities can't be in the bsp file
+ //
+ //check out the func_areaportal entities
+ if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname")))
+ {
+ c_areaportals++;
+ mapent->areaportalnum = c_areaportals;
+ return true;
+ } //end if
+ return true;
+} //end of the function Q2_ParseBSPEntity
+//===========================================================================
+//
+// Parameter: -
+// Returns: -
+// Changes Globals: -
+//===========================================================================
+void Q2_LoadMapFromBSP(char *filename, int offset, int length)
+{
+ int i;
+
+ Log_Print("-- Q2_LoadMapFromBSP --\n");
+ //loaded map type
+ loadedmaptype = MAPTYPE_QUAKE2;
+
+ Log_Print("Loading map from %s...\n", filename);
+ //load the bsp file
+ Q2_LoadBSPFile(filename, offset, length);
+
+ //create an index from bsp planes to map planes
+ //DPlanes2MapPlanes();
+ //clear brush model numbers
+ for (i = 0; i < MAX_MAPFILE_BRUSHES; i++)
+ brushmodelnumbers[i] = -1;
+
+ nummapbrushsides = 0;
+ num_entities = 0;
+
+ Q2_ParseEntities();
+ //
+ for (i = 0; i < num_entities; i++)
+ {
+ Q2_ParseBSPEntity(i);
+ } //end for
+
+ //get the map mins and maxs from the world model
+ ClearBounds(map_mins, map_maxs);
+ for (i = 0; i < entities[0].numbrushes; i++)
+ {
+ if (mapbrushes[i].mins[0] > 4096)
+ continue; //no valid points
+ AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
+ AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
+ } //end for
+
+ PrintMapInfo();
+ //
+ Q2_CreateMapTexinfo();
+} //end of the function Q2_LoadMapFromBSP
+
+void Q2_ResetMapLoading(void)
+{
+ //reset for map loading from bsp
+ memset(nodestack, 0, NODESTACKSIZE * sizeof(int));
+ nodestackptr = NULL;
+ nodestacksize = 0;
+ memset(brushmodelnumbers, 0, MAX_MAPFILE_BRUSHES * sizeof(int));
+} //end of the function Q2_ResetMapLoading
+
+//End MAP loading from BSP file
+#endif //ME
+
+//====================================================================
+
+/*
+================
+TestExpandBrushes
+
+Expands all the brush planes and saves a new map out
+================
+*/
+void TestExpandBrushes (void)
+{
+ FILE *f;
+ side_t *s;
+ int i, j, bn;
+ winding_t *w;
+ char *name = "expanded.map";
+ mapbrush_t *brush;
+ vec_t dist;
+
+ Log_Print("writing %s\n", name);
+ f = fopen (name, "wb");
+ if (!f)
+ Error ("Can't write %s\n", name);
+
+ fprintf (f, "{\n\"classname\" \"worldspawn\"\n");
+
+ for (bn=0 ; bn<nummapbrushes ; bn++)
+ {
+ brush = &mapbrushes[bn];
+ fprintf (f, "{\n");
+ for (i=0 ; i<brush->numsides ; i++)
+ {
+ s = brush->original_sides + i;
+ dist = mapplanes[s->planenum].dist;
+ for (j=0 ; j<3 ; j++)
+ dist += fabs( 16 * mapplanes[s->planenum].normal[j] );
+
+ w = BaseWindingForPlane (mapplanes[s->planenum].normal, 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);
+
+ Error ("can't proceed after expanding brushes");
+} //end of the function TestExpandBrushes
+