aboutsummaryrefslogtreecommitdiffstats
path: root/q3map/map.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 /q3map/map.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 'q3map/map.c')
-rwxr-xr-xq3map/map.c2460
1 files changed, 1230 insertions, 1230 deletions
diff --git a/q3map/map.c b/q3map/map.c
index e275e34..3de6ede 100755
--- a/q3map/map.c
+++ b/q3map/map.c
@@ -19,1233 +19,1233 @@ along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
-// map.c
-
-#include "qbsp.h"
-
-
-int entitySourceBrushes; // to track editor brush numbers
-
-int numMapPatches;
-
-// undefine to make plane finding use linear sort
-#define USE_HASHING
-#define PLANE_HASHES 1024
-plane_t *planehash[PLANE_HASHES];
-
-plane_t mapplanes[MAX_MAP_PLANES];
-int nummapplanes;
-
-// as brushes and patches are read in, the shaders are stored out in order
-// here, so -onlytextures can just copy them out over the existing shaders
-// in the drawSurfaces
-char mapIndexedShaders[MAX_MAP_BRUSHSIDES][MAX_QPATH];
-int numMapIndexedShaders;
-
-vec3_t map_mins, map_maxs;
-
-entity_t *mapent;
-
-
-
-int c_boxbevels;
-int c_edgebevels;
-
-int c_areaportals;
-int c_detail;
-int c_structural;
-
-// brushes are parsed into a temporary array of sides,
-// which will have the bevels added and duplicates
-// removed before the final brush is allocated
-bspbrush_t *buildBrush;
-
-
-void TestExpandBrushes (void);
-void SetTerrainTextures( void );
-void ParseTerrain( void );
-
-
-/*
-=============================================================================
-
-PLANE FINDING
-
-=============================================================================
-*/
-
-
-/*
-================
-PlaneEqual
-================
-*/
-#define NORMAL_EPSILON 0.00001
-#define DIST_EPSILON 0.01
-qboolean PlaneEqual (plane_t *p, vec3_t normal, vec_t dist)
-{
-#if 1
- if (
- fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
- && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
- && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
- && fabs(p->dist - dist) < DIST_EPSILON )
- return qtrue;
-#else
- if (p->normal[0] == normal[0]
- && p->normal[1] == normal[1]
- && p->normal[2] == normal[2]
- && p->dist == dist)
- return qtrue;
-#endif
- return qfalse;
-}
-
-/*
-================
-AddPlaneToHash
-================
-*/
-void AddPlaneToHash (plane_t *p)
-{
- int hash;
-
- hash = (int)fabs(p->dist) / 8;
- hash &= (PLANE_HASHES-1);
-
- p->hash_chain = planehash[hash];
- planehash[hash] = p;
-}
-
-/*
-================
-CreateNewFloatPlane
-================
-*/
-int CreateNewFloatPlane (vec3_t normal, vec_t dist)
-{
- plane_t *p, temp;
-
- if (VectorLength(normal) < 0.5)
- {
- _printf( "FloatPlane: bad normal\n");
- return -1;
- }
-
- // create a new plane
- if (nummapplanes+2 > MAX_MAP_PLANES)
- Error ("MAX_MAP_PLANES");
-
- p = &mapplanes[nummapplanes];
- VectorCopy (normal, p->normal);
- p->dist = dist;
- p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
-
- VectorSubtract (vec3_origin, normal, (p+1)->normal);
- (p+1)->dist = -dist;
-
- nummapplanes += 2;
-
- // allways put axial planes facing positive first
- if (p->type < 3)
- {
- if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
- {
- // flip order
- temp = *p;
- *p = *(p+1);
- *(p+1) = temp;
-
- AddPlaneToHash (p);
- AddPlaneToHash (p+1);
- return nummapplanes - 1;
- }
- }
-
- AddPlaneToHash (p);
- AddPlaneToHash (p+1);
- return nummapplanes - 2;
-}
-
-/*
-==============
-SnapVector
-==============
-*/
-void SnapVector (vec3_t normal)
-{
- int i;
-
- for (i=0 ; i<3 ; i++)
- {
- if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
- {
- VectorClear (normal);
- normal[i] = 1;
- break;
- }
- if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
- {
- VectorClear (normal);
- normal[i] = -1;
- break;
- }
- }
-}
-
-/*
-==============
-SnapPlane
-==============
-*/
-void SnapPlane (vec3_t normal, vec_t *dist)
-{
- SnapVector (normal);
-
- if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
- *dist = Q_rint(*dist);
-}
-
-/*
-=============
-FindFloatPlane
-
-=============
-*/
-#ifndef USE_HASHING
-int FindFloatPlane (vec3_t normal, vec_t dist)
-{
- int i;
- plane_t *p;
-
- SnapPlane (normal, &dist);
- for (i=0, p=mapplanes ; i<nummapplanes ; i++, p++)
- {
- if (PlaneEqual (p, normal, dist))
- return i;
- }
-
- return CreateNewFloatPlane (normal, dist);
-}
-#else
-int FindFloatPlane (vec3_t normal, vec_t dist)
-{
- int i;
- plane_t *p;
- int hash, h;
-
- SnapPlane (normal, &dist);
- hash = (int)fabs(dist) / 8;
- hash &= (PLANE_HASHES-1);
-
- // search the border bins as well
- for (i=-1 ; i<=1 ; i++)
- {
- h = (hash+i)&(PLANE_HASHES-1);
- for (p = planehash[h] ; p ; p=p->hash_chain)
- {
- if (PlaneEqual (p, normal, dist))
- return p-mapplanes;
- }
- }
-
- return CreateNewFloatPlane (normal, dist);
-}
-#endif
-
-/*
-================
-MapPlaneFromPoints
-================
-*/
-int MapPlaneFromPoints (vec3_t p0, vec3_t p1, vec3_t p2) {
- vec3_t t1, t2, normal;
- vec_t dist;
-
- VectorSubtract (p0, p1, t1);
- VectorSubtract (p2, p1, t2);
- CrossProduct (t1, t2, normal);
- VectorNormalize (normal, normal);
-
- dist = DotProduct (p0, normal);
-
- return FindFloatPlane (normal, dist);
-}
-
-
-//====================================================================
-
-/*
-===========
-SetBrushContents
-
-The contents on all sides of a brush should be the same
-Sets contentsShader, contents, opaque, and detail
-===========
-*/
-void SetBrushContents( bspbrush_t *b ) {
- int contents, c2;
- side_t *s;
- int i;
- qboolean mixed;
- int allFlags;
-
- s = &b->sides[0];
- contents = s->contents;
- b->contentShader = s->shaderInfo;
- mixed = qfalse;
-
- allFlags = 0;
-
- for ( i=1 ; i<b->numsides ; i++, s++ ) {
- s = &b->sides[i];
-
- if ( !s->shaderInfo ) {
- continue;
- }
-
- c2 = s->contents;
- if (c2 != contents) {
- mixed = qtrue;
- }
-
- allFlags |= s->surfaceFlags;
- }
-
- if ( mixed ) {
- qprintf ("Entity %i, Brush %i: mixed face contents\n"
- , b->entitynum, b->brushnum);
- }
-
- if ( ( contents & CONTENTS_DETAIL ) && ( contents & CONTENTS_STRUCTURAL ) ) {
- _printf ("Entity %i, Brush %i: mixed CONTENTS_DETAIL and CONTENTS_STRUCTURAL\n"
- , num_entities-1, entitySourceBrushes );
- contents &= ~CONTENTS_DETAIL;
- }
-
- // the fulldetail flag will cause detail brushes to be
- // treated like normal brushes
- if ( fulldetail ) {
- contents &= ~CONTENTS_DETAIL;
- }
-
- // all translucent brushes that aren't specirically made structural will
- // be detail
- if ( ( contents & CONTENTS_TRANSLUCENT ) && !( contents & CONTENTS_STRUCTURAL ) ) {
- contents |= CONTENTS_DETAIL;
- }
-
- if ( contents & CONTENTS_DETAIL ) {
- c_detail++;
- b->detail = qtrue;
- } else {
- c_structural++;
- b->detail = qfalse;
- }
-
- if ( contents & CONTENTS_TRANSLUCENT ) {
- b->opaque = qfalse;
- } else {
- b->opaque = qtrue;
- }
-
- if ( contents & CONTENTS_AREAPORTAL ) {
- c_areaportals++;
- }
-
- b->contents = contents;
-}
-
-
-//============================================================================
-
-/*
-=================
-AddBrushBevels
-
-Adds any additional planes necessary to allow the brush being
-built to be expanded against axial bounding boxes
-=================
-*/
-void AddBrushBevels( void ) {
- int axis, dir;
- int i, order;
- side_t sidetemp;
- side_t *s;
- vec3_t normal;
- float dist;
-
- //
- // add the axial planes
- //
- order = 0;
- for (axis=0 ; axis <3 ; axis++)
- {
- for (dir=-1 ; dir <= 1 ; dir+=2, order++)
- {
- // see if the plane is allready present
- for ( i=0, s=buildBrush->sides ; i < buildBrush->numsides ; i++,s++ ) {
- if (mapplanes[s->planenum].normal[axis] == dir)
- break;
- }
-
- if (i == buildBrush->numsides )
- { // add a new side
- if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
- Error( "MAX_BUILD_SIDES" );
- }
- memset( s, 0, sizeof( *s ) );
- buildBrush->numsides++;
- VectorClear (normal);
- normal[axis] = dir;
- if (dir == 1)
- dist = buildBrush->maxs[axis];
- else
- dist = -buildBrush->mins[axis];
- s->planenum = FindFloatPlane (normal, dist);
- s->contents = buildBrush->sides[0].contents;
- s->bevel = qtrue;
- c_boxbevels++;
- }
-
- // if the plane is not in it canonical order, swap it
- if (i != order)
- {
- sidetemp = buildBrush->sides[order];
- buildBrush->sides[order] = buildBrush->sides[i];
- buildBrush->sides[i] = sidetemp;
- }
- }
- }
-
- //
- // add the edge bevels
- //
- if ( buildBrush->numsides == 6 ) {
- return; // pure axial
- } else {
- int j, k, l;
- float d;
- winding_t *w, *w2;
- side_t *s2;
- vec3_t vec, vec2;
-
- // test the non-axial plane edges
- // this code tends to cause some problems...
- for (i=6 ; i<buildBrush->numsides ; i++)
- {
- s = buildBrush->sides + i;
- w = s->winding;
- if (!w)
- continue;
- for (j=0 ; j<w->numpoints ; j++)
- {
- k = (j+1)%w->numpoints;
- VectorSubtract (w->p[j], w->p[k], vec);
- if (VectorNormalize (vec, vec) < 0.5)
- continue;
- SnapVector (vec);
- for (k=0 ; k<3 ; k++)
- if ( vec[k] == -1 || vec[k] == 1)
- break; // axial
- if (k != 3)
- continue; // only test non-axial edges
-
- // try the six possible slanted axials from this edge
- for (axis=0 ; axis <3 ; axis++)
- {
- for (dir=-1 ; dir <= 1 ; dir+=2)
- {
- // construct a plane
- VectorClear (vec2);
- vec2[axis] = dir;
- CrossProduct (vec, vec2, normal);
- if (VectorNormalize (normal, normal) < 0.5)
- continue;
- dist = DotProduct (w->p[j], normal);
-
- // if all the points on all the sides are
- // behind this plane, it is a proper edge bevel
- for (k=0 ; k < buildBrush->numsides ; k++)
- {
- // if this plane has allready been used, skip it
- if (PlaneEqual (&mapplanes[buildBrush->sides[k].planenum]
- , normal, dist) )
- break;
-
- w2 = buildBrush->sides[k].winding;
- if (!w2)
- continue;
- for (l=0 ; l<w2->numpoints ; l++)
- {
- d = DotProduct (w2->p[l], normal) - dist;
- if (d > 0.1)
- break; // point in front
- }
- if (l != w2->numpoints)
- break;
- }
-
- if (k != buildBrush->numsides)
- continue; // wasn't part of the outer hull
- // add this plane
- if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
- Error( "MAX_BUILD_SIDES" );
- }
-
- s2 = &buildBrush->sides[buildBrush->numsides];
- buildBrush->numsides++;
- memset( s2, 0, sizeof( *s2 ) );
-
- s2->planenum = FindFloatPlane (normal, dist);
- s2->contents = buildBrush->sides[0].contents;
- s2->bevel = qtrue;
- c_edgebevels++;
- }
- }
- }
- }
- }
-}
-
-/*
-===============
-AddBackSides
-
-fog volumes need to have inside faces created
-===============
-*/
-void AddBackSides( void ) {
-/*
- bspbrush_t *b;
- int i, originalSides;
- side_t *s;
- side_t *newSide;
-
- b = buildBrush;
- originalSides = b->numsides;
- for ( i = 0 ; i < originalSides ; i++ ) {
- s = &b->sides[i];
- if ( !s->shaderInfo ) {
- continue;
- }
- if ( !(s->shaderInfo->contents & CONTENTS_FOG) ) {
- continue;
- }
-
- // duplicate the up-facing side
- if ( mapplanes[ s->planenum ].normal[2] == 1 ) {
- newSide = &b->sides[ b->numsides ];
- b->numsides++;
-
- *newSide = *s;
- newSide->backSide = qtrue;
- newSide->planenum = s->planenum ^ 1; // opposite side
- }
- }
-*/
-}
-
-/*
-===============
-FinishBrush
-
-Produces a final brush based on the buildBrush->sides array
-and links it to the current entity
-===============
-*/
-bspbrush_t *FinishBrush( void ) {
- bspbrush_t *b;
-
- // liquids may need to have extra sides created for back sides
- AddBackSides();
-
- // create windings for sides and bounds for brush
- if ( !CreateBrushWindings( buildBrush ) ) {
- // don't keep this brush
- return NULL;
- }
-
- // brushes that will not be visible at all are forced to be detail
- if ( buildBrush->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
- {
- buildBrush->detail = qtrue;
- c_detail++;
- }
-
- //
- // 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 ( buildBrush->contents & CONTENTS_ORIGIN )
- {
- char string[32];
- vec3_t origin;
-
- if (num_entities == 1) {
- _printf ("Entity %i, Brush %i: origin brushes not allowed in world\n"
- , num_entities - 1, entitySourceBrushes);
- return NULL;
- }
-
- VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
- VectorScale (origin, 0.5, origin);
-
- sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
- SetKeyValue (&entities[num_entities - 1], "origin", string);
-
- VectorCopy (origin, entities[num_entities - 1].origin);
-
- // don't keep this brush
- return NULL;
- }
-
- if ( buildBrush->contents & CONTENTS_AREAPORTAL ) {
- if (num_entities != 1) {
- _printf ("Entity %i, Brush %i: areaportals only allowed in world\n"
- , num_entities - 1, entitySourceBrushes);
- return NULL;
- }
- }
-
- AddBrushBevels ();
-
- // keep it
- b = CopyBrush( buildBrush );
-
- b->entitynum = num_entities-1;
- b->brushnum = entitySourceBrushes;
-
- b->original = b;
-
- b->next = mapent->brushes;
- mapent->brushes = b;
-
- return b;
-}
-
-//======================================================================
-
-
-/*
-==================
-textureAxisFromPlane
-==================
-*/
-vec3_t baseaxis[18] =
-{
-{0,0,1}, {1,0,0}, {0,-1,0}, // floor
-{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
-{1,0,0}, {0,1,0}, {0,0,-1}, // west wall
-{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
-{0,1,0}, {1,0,0}, {0,0,-1}, // south wall
-{0,-1,0}, {1,0,0}, {0,0,-1} // north wall
-};
-
-void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
-{
- int bestaxis;
- vec_t dot,best;
- int i;
-
- best = 0;
- bestaxis = 0;
-
- for (i=0 ; i<6 ; i++)
- {
- dot = DotProduct (pln->normal, baseaxis[i*3]);
- if (dot > best)
- {
- best = dot;
- bestaxis = i;
- }
- }
-
- VectorCopy (baseaxis[bestaxis*3+1], xv);
- VectorCopy (baseaxis[bestaxis*3+2], yv);
-}
-
-
-
-/*
-=================
-QuakeTextureVecs
-
-Creates world-to-texture mapping vecs for crappy quake plane arrangements
-=================
-*/
-void QuakeTextureVecs( plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2],
- vec_t mappingVecs[2][4] ) {
-
- vec3_t vecs[2];
- int sv, tv;
- vec_t ang, sinv, cosv;
- vec_t ns, nt;
- int i, j;
-
- TextureAxisFromPlane(plane, vecs[0], vecs[1]);
-
- if (!scale[0])
- scale[0] = 1;
- if (!scale[1])
- scale[1] = 1;
-
- // rotate axis
- if (rotate == 0)
- { sinv = 0 ; cosv = 1; }
- else if (rotate == 90)
- { sinv = 1 ; cosv = 0; }
- else if (rotate == 180)
- { sinv = 0 ; cosv = -1; }
- else if (rotate == 270)
- { sinv = -1 ; cosv = 0; }
- else
- {
- ang = rotate / 180 * Q_PI;
- sinv = sin(ang);
- cosv = cos(ang);
- }
-
- if (vecs[0][0])
- sv = 0;
- else if (vecs[0][1])
- sv = 1;
- else
- sv = 2;
-
- if (vecs[1][0])
- tv = 0;
- else if (vecs[1][1])
- tv = 1;
- else
- tv = 2;
-
- for (i=0 ; i<2 ; i++) {
- ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
- nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
- vecs[i][sv] = ns;
- vecs[i][tv] = nt;
- }
-
- for (i=0 ; i<2 ; i++)
- for (j=0 ; j<3 ; j++)
- mappingVecs[i][j] = vecs[i][j] / scale[i];
-
- mappingVecs[0][3] = shift[0];
- mappingVecs[1][3] = shift[1];
-}
-
-//======================================================================
-
-/*
-=================
-ParseRawBrush
-
-Just parses the sides into buildBrush->sides[], nothing else.
-no validation, back plane removal, etc.
-
-Timo - 08/26/99
-added brush epairs parsing ( ignoring actually )
-Timo - 08/04/99
-added exclusive brush primitive parsing
-Timo - 08/08/99
-support for old brush format back in
-NOTE : it would be "cleaner" to have seperate functions to parse between old and new brushes
-=================
-*/
-void ParseRawBrush( ) {
- side_t *side;
- vec3_t planepts[3];
- int planenum;
- shaderInfo_t *si;
- // old brushes
- vec_t shift[2];
- vec_t rotate;
- vec_t scale[2];
- char name[MAX_QPATH];
- char shader[MAX_QPATH];
- int flags;
-
- buildBrush->numsides = 0;
- buildBrush->detail = qfalse;
-
- if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
- MatchToken( "{" );
-
- do
- {
- if (!GetToken (qtrue))
- break;
- if (!strcmp (token, "}") )
- break;
- //Timo : brush primitive : here we may have to jump over brush epairs ( only used in editor )
- if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
- {
- do
- {
- if (strcmp (token, "(") )
- GetToken( qfalse );
- else
- break;
- GetToken( qtrue );
- } while (1);
- }
- UnGetToken();
-
- if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
- Error( "MAX_BUILD_SIDES" );
- }
-
- side = &buildBrush->sides[ buildBrush->numsides ];
- memset( side, 0, sizeof( *side ) );
- buildBrush->numsides++;
-
- // read the three point plane definition
- Parse1DMatrix( 3, planepts[0] );
- Parse1DMatrix( 3, planepts[1] );
- Parse1DMatrix( 3, planepts[2] );
-
- if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
- // read the texture matrix
- Parse2DMatrix( 2, 3, (float *)side->texMat );
-
- // read the texturedef
- GetToken (qfalse);
- strcpy (name, token);
-
- // save the shader name for retexturing
- if ( numMapIndexedShaders == MAX_MAP_BRUSHSIDES ) {
- Error( "MAX_MAP_BRUSHSIDES" );
- }
- strcpy( mapIndexedShaders[numMapIndexedShaders], name );
- numMapIndexedShaders++;
-
- if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
- {
- GetToken (qfalse);
- shift[0] = atoi(token);
- GetToken (qfalse);
- shift[1] = atoi(token);
- GetToken (qfalse);
- rotate = atoi(token);
- GetToken (qfalse);
- scale[0] = atof(token);
- GetToken (qfalse);
- scale[1] = atof(token);
- }
-
- // find default flags and values
- sprintf( shader, "textures/%s", name );
- si = ShaderInfoForShader( shader );
- side->shaderInfo = si;
- side->surfaceFlags = si->surfaceFlags;
- side->value = si->value;
- side->contents = si->contents;
-
- // allow override of default flags and values
- // in Q3, the only thing you can override is DETAIL
- if (TokenAvailable())
- {
- GetToken (qfalse);
-// side->contents = atoi(token);
- flags = atoi(token);
- if ( flags & CONTENTS_DETAIL ) {
- side->contents |= CONTENTS_DETAIL;
- }
-
- GetToken (qfalse);
-// td.flags = atoi(token);
-
- GetToken (qfalse);
-// td.value = atoi(token);
- }
-
-
- // find the plane number
- planenum = MapPlaneFromPoints (planepts[0], planepts[1], planepts[2]);
- side->planenum = planenum;
-
- if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
- // get the texture mapping for this texturedef / plane combination
- QuakeTextureVecs( &mapplanes[planenum], shift, rotate, scale, side->vecs );
-
- } while (1);
-
- if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
- {
- UnGetToken();
- MatchToken( "}" );
- MatchToken( "}" );
- }
-}
-
-/*
-=================
-RemoveDuplicateBrushPlanes
-
-Returns false if the brush has a mirrored set of planes,
-meaning it encloses no volume.
-Also removes planes without any normal
-=================
-*/
-qboolean RemoveDuplicateBrushPlanes( bspbrush_t * b ) {
- int i, j, k;
- side_t *sides;
-
- sides = b->sides;
-
- for ( i = 1 ; i < b->numsides ; i++ ) {
-
- // check for a degenerate plane
- if ( sides[i].planenum == -1) {
- _printf ("Entity %i, Brush %i: degenerate plane\n"
- , b->entitynum, b->brushnum);
- // remove it
- for ( k = i + 1 ; k < b->numsides ; k++ ) {
- sides[k-1] = sides[k];
- }
- b->numsides--;
- i--;
- continue;
- }
-
- // check for duplication and mirroring
- for ( j = 0 ; j < i ; j++ ) {
- if ( sides[i].planenum == sides[j].planenum ) {
- _printf ("Entity %i, Brush %i: duplicate plane\n"
- , b->entitynum, b->brushnum);
- // remove the second duplicate
- for ( k = i + 1 ; k < b->numsides ; k++ ) {
- sides[k-1] = sides[k];
- }
- b->numsides--;
- i--;
- break;
- }
-
- if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
- // mirror plane, brush is invalid
- _printf ("Entity %i, Brush %i: mirrored plane\n"
- , b->entitynum, b->brushnum);
- return qfalse;
- }
- }
- }
- return qtrue;
-}
-
-
-/*
-=================
-ParseBrush
-
- qboolean parameter to true -> parse new brush primitive format ( else use old format )
-=================
-*/
-void ParseBrush (void) {
- bspbrush_t *b;
-
- ParseRawBrush();
-
- buildBrush->portalareas[0] = -1;
- buildBrush->portalareas[1] = -1;
- buildBrush->entitynum = num_entities-1;
- buildBrush->brushnum = entitySourceBrushes;
-
- // if there are mirrored planes, the entire brush is invalid
- if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
- return;
- }
-
- // get the content for the entire brush
- SetBrushContents( buildBrush );
-
- // allow detail brushes to be removed
- if (nodetail && (buildBrush->contents & CONTENTS_DETAIL) ) {
- FreeBrush( buildBrush );
- return;
- }
-
- // allow water brushes to be removed
- if (nowater && (buildBrush->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) ) {
- FreeBrush( buildBrush );
- return;
- }
-
- b = FinishBrush( );
- if ( !b ) {
- return;
- }
-}
-
-
-/*
-================
-MoveBrushesToWorld
-
-Takes all of the brushes from the current entity and
-adds them to the world's brush list.
-
-Used by func_group
-================
-*/
-void MoveBrushesToWorld (entity_t *mapent) {
- bspbrush_t *b, *next;
- parseMesh_t *pm;
-
- // move brushes
- for ( b = mapent->brushes ; b ; b = next ) {
- next = b->next;
-
- b->next = entities[0].brushes;
- entities[0].brushes = b;
- }
- mapent->brushes = NULL;
-
- // move patches
- if ( mapent->patches ) {
-
- for ( pm = mapent->patches ; pm->next ; pm = pm->next ) {
- }
-
- pm->next = entities[0].patches;
- entities[0].patches = mapent->patches;
-
- mapent->patches = NULL;
- }
-}
-
-
-/*
-================
-AdjustBrushesForOrigin
-================
-*/
-void AdjustBrushesForOrigin( entity_t *ent ) {
- bspbrush_t *b;
- int i;
- side_t *s;
- vec_t newdist;
- parseMesh_t *p;
-
- for ( b = ent->brushes ; b ; b = b->next ) {
- for (i=0 ; i<b->numsides ; i++) {
- s = &b->sides[i];
- newdist = mapplanes[s->planenum].dist -
- DotProduct (mapplanes[s->planenum].normal, ent->origin);
- s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
- }
- CreateBrushWindings(b);
- }
-
- for ( p = ent->patches ; p ; p = p->next ) {
- for ( i = 0 ; i < p->mesh.width*p->mesh.height ; i++ ) {
- VectorSubtract( p->mesh.verts[i].xyz, ent->origin, p->mesh.verts[i].xyz );
- }
- }
-
-}
-
-/*
-================
-ParseMapEntity
-================
-*/
-qboolean ParseMapEntity (void) {
- epair_t *e;
-
- if (!GetToken (qtrue))
- return qfalse;
-
- if (strcmp (token, "{") )
- {
- Error ("ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...", token, scriptline, entities[num_entities].origin[0], entities[num_entities].origin[1], entities[num_entities].origin[2]);
- }
-
- if (num_entities == MAX_MAP_ENTITIES)
- Error ("num_entities == MAX_MAP_ENTITIES");
-
- entitySourceBrushes = 0;
-
- mapent = &entities[num_entities];
- num_entities++;
- memset (mapent, 0, sizeof(*mapent));
-
- do
- {
- if (!GetToken (qtrue))
- Error ("ParseEntity: EOF without closing brace");
- if (!strcmp (token, "}") )
- break;
-
- if (!strcmp (token, "{") ) {
- // parse a brush or patch
- if (!GetToken (qtrue))
- break;
- if ( !strcmp( token, "patchDef2" ) ) {
- numMapPatches++;
- ParsePatch();
- } else if ( !strcmp( token, "terrainDef" ) ) {
- ParseTerrain();
- } else if ( !strcmp( token, "brushDef" ) ) {
- if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
- Error("old brush format not allowed in new brush format map");
- g_bBrushPrimit=BPRIMIT_NEWBRUSHES;
- // parse brush primitive
- ParseBrush();
- }
- else
- {
- if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
- Error("new brush format not allowed in old brush format map");
- g_bBrushPrimit=BPRIMIT_OLDBRUSHES;
- // parse old brush format
- UnGetToken();
- ParseBrush();
- }
- entitySourceBrushes++;
- }
- else
- {
- // parse a key / value pair
- e = ParseEpair ();
- e->next = mapent->epairs;
- mapent->epairs = e;
- }
- } while (1);
-
- GetVectorForKey (mapent, "origin", mapent->origin);
-
- //
- // if there was an origin brush, offset all of the planes and texinfo
- // for all the brushes in the entity
- if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) {
- AdjustBrushesForOrigin( mapent );
- }
-
- // group_info entities are just for editor grouping
- // ignored
- // FIXME: leak!
- if (!strcmp("group_info", ValueForKey (mapent, "classname")))
- {
- num_entities--;
- return qtrue;
- }
-
- // group entities are just for editor convenience
- // toss all brushes into the world entity
- if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
- {
- if ( !strcmp ("1", ValueForKey (mapent, "terrain"))) {
- SetTerrainTextures();
- }
- MoveBrushesToWorld (mapent);
- num_entities--;
- return qtrue;
- }
-
- return qtrue;
-}
-
-//===================================================================
-
-
-/*
-================
-LoadMapFile
-================
-*/
-void LoadMapFile (char *filename) {
- bspbrush_t *b;
-
- qprintf ("--- LoadMapFile ---\n");
- _printf ("Loading map file %s\n", filename);
-
- LoadScriptFile (filename);
-
- num_entities = 0;
- numMapDrawSurfs = 0;
- c_detail = 0;
-
- g_bBrushPrimit = BPRIMIT_UNDEFINED;
-
- // allocate a very large temporary brush for building
- // the brushes as they are loaded
- buildBrush = AllocBrush( MAX_BUILD_SIDES );
-
- while (ParseMapEntity ())
- {
- }
-
- ClearBounds (map_mins, map_maxs);
- for ( b = entities[0].brushes ; b ; b=b->next ) {
- AddPointToBounds( b->mins, map_mins, map_maxs );
- AddPointToBounds( b->maxs, map_mins, map_maxs );
- }
-
- qprintf ("%5i total world brushes\n", CountBrushList( entities[0].brushes ) );
- qprintf ("%5i detail brushes\n", c_detail );
- qprintf ("%5i patches\n", numMapPatches);
- qprintf ("%5i boxbevels\n", c_boxbevels);
- qprintf ("%5i edgebevels\n", c_edgebevels);
- qprintf ("%5i entities\n", num_entities);
- qprintf ("%5i planes\n", nummapplanes);
- qprintf ("%5i areaportals\n", c_areaportals);
- qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
- map_maxs[0],map_maxs[1],map_maxs[2]);
-
- if ( fakemap ) {
- WriteBspBrushMap ("fakemap.map", entities[0].brushes );
- }
-
- if ( testExpand ) {
- TestExpandBrushes ();
- }
-}
-
-
-//====================================================================
-
-
-/*
-================
-TestExpandBrushes
-
-Expands all the brush planes and saves a new map out to
-allow visual inspection of the clipping bevels
-================
-*/
-void TestExpandBrushes( void ) {
- side_t *s;
- int i, j;
- bspbrush_t *brush, *list, *copy;
- vec_t dist;
- plane_t *plane;
-
- list = NULL;
-
- for ( brush = entities[0].brushes ; brush ; brush = brush->next ) {
- copy = CopyBrush( brush );
- copy->next = list;
- list = copy;
-
- // expand all the planes
- for ( i=0 ; i<brush->numsides ; i++ ) {
- s = brush->sides + i;
- plane = &mapplanes[s->planenum];
- dist = plane->dist;
- for (j=0 ; j<3 ; j++) {
- dist += fabs( 16 * plane->normal[j] );
- }
- s->planenum = FindFloatPlane( plane->normal, dist );
- }
-
- }
-
- WriteBspBrushMap ( "expanded.map", entities[0].brushes );
-
- Error ("can't proceed after expanding brushes");
-}
+// map.c
+
+#include "qbsp.h"
+
+
+int entitySourceBrushes; // to track editor brush numbers
+
+int numMapPatches;
+
+// undefine to make plane finding use linear sort
+#define USE_HASHING
+#define PLANE_HASHES 1024
+plane_t *planehash[PLANE_HASHES];
+
+plane_t mapplanes[MAX_MAP_PLANES];
+int nummapplanes;
+
+// as brushes and patches are read in, the shaders are stored out in order
+// here, so -onlytextures can just copy them out over the existing shaders
+// in the drawSurfaces
+char mapIndexedShaders[MAX_MAP_BRUSHSIDES][MAX_QPATH];
+int numMapIndexedShaders;
+
+vec3_t map_mins, map_maxs;
+
+entity_t *mapent;
+
+
+
+int c_boxbevels;
+int c_edgebevels;
+
+int c_areaportals;
+int c_detail;
+int c_structural;
+
+// brushes are parsed into a temporary array of sides,
+// which will have the bevels added and duplicates
+// removed before the final brush is allocated
+bspbrush_t *buildBrush;
+
+
+void TestExpandBrushes (void);
+void SetTerrainTextures( void );
+void ParseTerrain( void );
+
+
+/*
+=============================================================================
+
+PLANE FINDING
+
+=============================================================================
+*/
+
+
+/*
+================
+PlaneEqual
+================
+*/
+#define NORMAL_EPSILON 0.00001
+#define DIST_EPSILON 0.01
+qboolean PlaneEqual (plane_t *p, vec3_t normal, vec_t dist)
+{
+#if 1
+ if (
+ fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
+ && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
+ && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
+ && fabs(p->dist - dist) < DIST_EPSILON )
+ return qtrue;
+#else
+ if (p->normal[0] == normal[0]
+ && p->normal[1] == normal[1]
+ && p->normal[2] == normal[2]
+ && p->dist == dist)
+ return qtrue;
+#endif
+ return qfalse;
+}
+
+/*
+================
+AddPlaneToHash
+================
+*/
+void AddPlaneToHash (plane_t *p)
+{
+ int hash;
+
+ hash = (int)fabs(p->dist) / 8;
+ hash &= (PLANE_HASHES-1);
+
+ p->hash_chain = planehash[hash];
+ planehash[hash] = p;
+}
+
+/*
+================
+CreateNewFloatPlane
+================
+*/
+int CreateNewFloatPlane (vec3_t normal, vec_t dist)
+{
+ plane_t *p, temp;
+
+ if (VectorLength(normal) < 0.5)
+ {
+ _printf( "FloatPlane: bad normal\n");
+ return -1;
+ }
+
+ // create a new plane
+ if (nummapplanes+2 > MAX_MAP_PLANES)
+ Error ("MAX_MAP_PLANES");
+
+ p = &mapplanes[nummapplanes];
+ VectorCopy (normal, p->normal);
+ p->dist = dist;
+ p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
+
+ VectorSubtract (vec3_origin, normal, (p+1)->normal);
+ (p+1)->dist = -dist;
+
+ nummapplanes += 2;
+
+ // allways put axial planes facing positive first
+ if (p->type < 3)
+ {
+ if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
+ {
+ // flip order
+ temp = *p;
+ *p = *(p+1);
+ *(p+1) = temp;
+
+ AddPlaneToHash (p);
+ AddPlaneToHash (p+1);
+ return nummapplanes - 1;
+ }
+ }
+
+ AddPlaneToHash (p);
+ AddPlaneToHash (p+1);
+ return nummapplanes - 2;
+}
+
+/*
+==============
+SnapVector
+==============
+*/
+void SnapVector (vec3_t normal)
+{
+ int i;
+
+ for (i=0 ; i<3 ; i++)
+ {
+ if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
+ {
+ VectorClear (normal);
+ normal[i] = 1;
+ break;
+ }
+ if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
+ {
+ VectorClear (normal);
+ normal[i] = -1;
+ break;
+ }
+ }
+}
+
+/*
+==============
+SnapPlane
+==============
+*/
+void SnapPlane (vec3_t normal, vec_t *dist)
+{
+ SnapVector (normal);
+
+ if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
+ *dist = Q_rint(*dist);
+}
+
+/*
+=============
+FindFloatPlane
+
+=============
+*/
+#ifndef USE_HASHING
+int FindFloatPlane (vec3_t normal, vec_t dist)
+{
+ int i;
+ plane_t *p;
+
+ SnapPlane (normal, &dist);
+ for (i=0, p=mapplanes ; i<nummapplanes ; i++, p++)
+ {
+ if (PlaneEqual (p, normal, dist))
+ return i;
+ }
+
+ return CreateNewFloatPlane (normal, dist);
+}
+#else
+int FindFloatPlane (vec3_t normal, vec_t dist)
+{
+ int i;
+ plane_t *p;
+ int hash, h;
+
+ SnapPlane (normal, &dist);
+ hash = (int)fabs(dist) / 8;
+ hash &= (PLANE_HASHES-1);
+
+ // search the border bins as well
+ for (i=-1 ; i<=1 ; i++)
+ {
+ h = (hash+i)&(PLANE_HASHES-1);
+ for (p = planehash[h] ; p ; p=p->hash_chain)
+ {
+ if (PlaneEqual (p, normal, dist))
+ return p-mapplanes;
+ }
+ }
+
+ return CreateNewFloatPlane (normal, dist);
+}
+#endif
+
+/*
+================
+MapPlaneFromPoints
+================
+*/
+int MapPlaneFromPoints (vec3_t p0, vec3_t p1, vec3_t p2) {
+ vec3_t t1, t2, normal;
+ vec_t dist;
+
+ VectorSubtract (p0, p1, t1);
+ VectorSubtract (p2, p1, t2);
+ CrossProduct (t1, t2, normal);
+ VectorNormalize (normal, normal);
+
+ dist = DotProduct (p0, normal);
+
+ return FindFloatPlane (normal, dist);
+}
+
+
+//====================================================================
+
+/*
+===========
+SetBrushContents
+
+The contents on all sides of a brush should be the same
+Sets contentsShader, contents, opaque, and detail
+===========
+*/
+void SetBrushContents( bspbrush_t *b ) {
+ int contents, c2;
+ side_t *s;
+ int i;
+ qboolean mixed;
+ int allFlags;
+
+ s = &b->sides[0];
+ contents = s->contents;
+ b->contentShader = s->shaderInfo;
+ mixed = qfalse;
+
+ allFlags = 0;
+
+ for ( i=1 ; i<b->numsides ; i++, s++ ) {
+ s = &b->sides[i];
+
+ if ( !s->shaderInfo ) {
+ continue;
+ }
+
+ c2 = s->contents;
+ if (c2 != contents) {
+ mixed = qtrue;
+ }
+
+ allFlags |= s->surfaceFlags;
+ }
+
+ if ( mixed ) {
+ qprintf ("Entity %i, Brush %i: mixed face contents\n"
+ , b->entitynum, b->brushnum);
+ }
+
+ if ( ( contents & CONTENTS_DETAIL ) && ( contents & CONTENTS_STRUCTURAL ) ) {
+ _printf ("Entity %i, Brush %i: mixed CONTENTS_DETAIL and CONTENTS_STRUCTURAL\n"
+ , num_entities-1, entitySourceBrushes );
+ contents &= ~CONTENTS_DETAIL;
+ }
+
+ // the fulldetail flag will cause detail brushes to be
+ // treated like normal brushes
+ if ( fulldetail ) {
+ contents &= ~CONTENTS_DETAIL;
+ }
+
+ // all translucent brushes that aren't specirically made structural will
+ // be detail
+ if ( ( contents & CONTENTS_TRANSLUCENT ) && !( contents & CONTENTS_STRUCTURAL ) ) {
+ contents |= CONTENTS_DETAIL;
+ }
+
+ if ( contents & CONTENTS_DETAIL ) {
+ c_detail++;
+ b->detail = qtrue;
+ } else {
+ c_structural++;
+ b->detail = qfalse;
+ }
+
+ if ( contents & CONTENTS_TRANSLUCENT ) {
+ b->opaque = qfalse;
+ } else {
+ b->opaque = qtrue;
+ }
+
+ if ( contents & CONTENTS_AREAPORTAL ) {
+ c_areaportals++;
+ }
+
+ b->contents = contents;
+}
+
+
+//============================================================================
+
+/*
+=================
+AddBrushBevels
+
+Adds any additional planes necessary to allow the brush being
+built to be expanded against axial bounding boxes
+=================
+*/
+void AddBrushBevels( void ) {
+ int axis, dir;
+ int i, order;
+ side_t sidetemp;
+ side_t *s;
+ vec3_t normal;
+ float dist;
+
+ //
+ // add the axial planes
+ //
+ order = 0;
+ for (axis=0 ; axis <3 ; axis++)
+ {
+ for (dir=-1 ; dir <= 1 ; dir+=2, order++)
+ {
+ // see if the plane is allready present
+ for ( i=0, s=buildBrush->sides ; i < buildBrush->numsides ; i++,s++ ) {
+ if (mapplanes[s->planenum].normal[axis] == dir)
+ break;
+ }
+
+ if (i == buildBrush->numsides )
+ { // add a new side
+ if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
+ Error( "MAX_BUILD_SIDES" );
+ }
+ memset( s, 0, sizeof( *s ) );
+ buildBrush->numsides++;
+ VectorClear (normal);
+ normal[axis] = dir;
+ if (dir == 1)
+ dist = buildBrush->maxs[axis];
+ else
+ dist = -buildBrush->mins[axis];
+ s->planenum = FindFloatPlane (normal, dist);
+ s->contents = buildBrush->sides[0].contents;
+ s->bevel = qtrue;
+ c_boxbevels++;
+ }
+
+ // if the plane is not in it canonical order, swap it
+ if (i != order)
+ {
+ sidetemp = buildBrush->sides[order];
+ buildBrush->sides[order] = buildBrush->sides[i];
+ buildBrush->sides[i] = sidetemp;
+ }
+ }
+ }
+
+ //
+ // add the edge bevels
+ //
+ if ( buildBrush->numsides == 6 ) {
+ return; // pure axial
+ } else {
+ int j, k, l;
+ float d;
+ winding_t *w, *w2;
+ side_t *s2;
+ vec3_t vec, vec2;
+
+ // test the non-axial plane edges
+ // this code tends to cause some problems...
+ for (i=6 ; i<buildBrush->numsides ; i++)
+ {
+ s = buildBrush->sides + i;
+ w = s->winding;
+ if (!w)
+ continue;
+ for (j=0 ; j<w->numpoints ; j++)
+ {
+ k = (j+1)%w->numpoints;
+ VectorSubtract (w->p[j], w->p[k], vec);
+ if (VectorNormalize (vec, vec) < 0.5)
+ continue;
+ SnapVector (vec);
+ for (k=0 ; k<3 ; k++)
+ if ( vec[k] == -1 || vec[k] == 1)
+ break; // axial
+ if (k != 3)
+ continue; // only test non-axial edges
+
+ // try the six possible slanted axials from this edge
+ for (axis=0 ; axis <3 ; axis++)
+ {
+ for (dir=-1 ; dir <= 1 ; dir+=2)
+ {
+ // construct a plane
+ VectorClear (vec2);
+ vec2[axis] = dir;
+ CrossProduct (vec, vec2, normal);
+ if (VectorNormalize (normal, normal) < 0.5)
+ continue;
+ dist = DotProduct (w->p[j], normal);
+
+ // if all the points on all the sides are
+ // behind this plane, it is a proper edge bevel
+ for (k=0 ; k < buildBrush->numsides ; k++)
+ {
+ // if this plane has allready been used, skip it
+ if (PlaneEqual (&mapplanes[buildBrush->sides[k].planenum]
+ , normal, dist) )
+ break;
+
+ w2 = buildBrush->sides[k].winding;
+ if (!w2)
+ continue;
+ for (l=0 ; l<w2->numpoints ; l++)
+ {
+ d = DotProduct (w2->p[l], normal) - dist;
+ if (d > 0.1)
+ break; // point in front
+ }
+ if (l != w2->numpoints)
+ break;
+ }
+
+ if (k != buildBrush->numsides)
+ continue; // wasn't part of the outer hull
+ // add this plane
+ if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
+ Error( "MAX_BUILD_SIDES" );
+ }
+
+ s2 = &buildBrush->sides[buildBrush->numsides];
+ buildBrush->numsides++;
+ memset( s2, 0, sizeof( *s2 ) );
+
+ s2->planenum = FindFloatPlane (normal, dist);
+ s2->contents = buildBrush->sides[0].contents;
+ s2->bevel = qtrue;
+ c_edgebevels++;
+ }
+ }
+ }
+ }
+ }
+}
+
+/*
+===============
+AddBackSides
+
+fog volumes need to have inside faces created
+===============
+*/
+void AddBackSides( void ) {
+/*
+ bspbrush_t *b;
+ int i, originalSides;
+ side_t *s;
+ side_t *newSide;
+
+ b = buildBrush;
+ originalSides = b->numsides;
+ for ( i = 0 ; i < originalSides ; i++ ) {
+ s = &b->sides[i];
+ if ( !s->shaderInfo ) {
+ continue;
+ }
+ if ( !(s->shaderInfo->contents & CONTENTS_FOG) ) {
+ continue;
+ }
+
+ // duplicate the up-facing side
+ if ( mapplanes[ s->planenum ].normal[2] == 1 ) {
+ newSide = &b->sides[ b->numsides ];
+ b->numsides++;
+
+ *newSide = *s;
+ newSide->backSide = qtrue;
+ newSide->planenum = s->planenum ^ 1; // opposite side
+ }
+ }
+*/
+}
+
+/*
+===============
+FinishBrush
+
+Produces a final brush based on the buildBrush->sides array
+and links it to the current entity
+===============
+*/
+bspbrush_t *FinishBrush( void ) {
+ bspbrush_t *b;
+
+ // liquids may need to have extra sides created for back sides
+ AddBackSides();
+
+ // create windings for sides and bounds for brush
+ if ( !CreateBrushWindings( buildBrush ) ) {
+ // don't keep this brush
+ return NULL;
+ }
+
+ // brushes that will not be visible at all are forced to be detail
+ if ( buildBrush->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
+ {
+ buildBrush->detail = qtrue;
+ c_detail++;
+ }
+
+ //
+ // 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 ( buildBrush->contents & CONTENTS_ORIGIN )
+ {
+ char string[32];
+ vec3_t origin;
+
+ if (num_entities == 1) {
+ _printf ("Entity %i, Brush %i: origin brushes not allowed in world\n"
+ , num_entities - 1, entitySourceBrushes);
+ return NULL;
+ }
+
+ VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
+ VectorScale (origin, 0.5, origin);
+
+ sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
+ SetKeyValue (&entities[num_entities - 1], "origin", string);
+
+ VectorCopy (origin, entities[num_entities - 1].origin);
+
+ // don't keep this brush
+ return NULL;
+ }
+
+ if ( buildBrush->contents & CONTENTS_AREAPORTAL ) {
+ if (num_entities != 1) {
+ _printf ("Entity %i, Brush %i: areaportals only allowed in world\n"
+ , num_entities - 1, entitySourceBrushes);
+ return NULL;
+ }
+ }
+
+ AddBrushBevels ();
+
+ // keep it
+ b = CopyBrush( buildBrush );
+
+ b->entitynum = num_entities-1;
+ b->brushnum = entitySourceBrushes;
+
+ b->original = b;
+
+ b->next = mapent->brushes;
+ mapent->brushes = b;
+
+ return b;
+}
+
+//======================================================================
+
+
+/*
+==================
+textureAxisFromPlane
+==================
+*/
+vec3_t baseaxis[18] =
+{
+{0,0,1}, {1,0,0}, {0,-1,0}, // floor
+{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
+{1,0,0}, {0,1,0}, {0,0,-1}, // west wall
+{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
+{0,1,0}, {1,0,0}, {0,0,-1}, // south wall
+{0,-1,0}, {1,0,0}, {0,0,-1} // north wall
+};
+
+void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
+{
+ int bestaxis;
+ vec_t dot,best;
+ int i;
+
+ best = 0;
+ bestaxis = 0;
+
+ for (i=0 ; i<6 ; i++)
+ {
+ dot = DotProduct (pln->normal, baseaxis[i*3]);
+ if (dot > best)
+ {
+ best = dot;
+ bestaxis = i;
+ }
+ }
+
+ VectorCopy (baseaxis[bestaxis*3+1], xv);
+ VectorCopy (baseaxis[bestaxis*3+2], yv);
+}
+
+
+
+/*
+=================
+QuakeTextureVecs
+
+Creates world-to-texture mapping vecs for crappy quake plane arrangements
+=================
+*/
+void QuakeTextureVecs( plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2],
+ vec_t mappingVecs[2][4] ) {
+
+ vec3_t vecs[2];
+ int sv, tv;
+ vec_t ang, sinv, cosv;
+ vec_t ns, nt;
+ int i, j;
+
+ TextureAxisFromPlane(plane, vecs[0], vecs[1]);
+
+ if (!scale[0])
+ scale[0] = 1;
+ if (!scale[1])
+ scale[1] = 1;
+
+ // rotate axis
+ if (rotate == 0)
+ { sinv = 0 ; cosv = 1; }
+ else if (rotate == 90)
+ { sinv = 1 ; cosv = 0; }
+ else if (rotate == 180)
+ { sinv = 0 ; cosv = -1; }
+ else if (rotate == 270)
+ { sinv = -1 ; cosv = 0; }
+ else
+ {
+ ang = rotate / 180 * Q_PI;
+ sinv = sin(ang);
+ cosv = cos(ang);
+ }
+
+ if (vecs[0][0])
+ sv = 0;
+ else if (vecs[0][1])
+ sv = 1;
+ else
+ sv = 2;
+
+ if (vecs[1][0])
+ tv = 0;
+ else if (vecs[1][1])
+ tv = 1;
+ else
+ tv = 2;
+
+ for (i=0 ; i<2 ; i++) {
+ ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
+ nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
+ vecs[i][sv] = ns;
+ vecs[i][tv] = nt;
+ }
+
+ for (i=0 ; i<2 ; i++)
+ for (j=0 ; j<3 ; j++)
+ mappingVecs[i][j] = vecs[i][j] / scale[i];
+
+ mappingVecs[0][3] = shift[0];
+ mappingVecs[1][3] = shift[1];
+}
+
+//======================================================================
+
+/*
+=================
+ParseRawBrush
+
+Just parses the sides into buildBrush->sides[], nothing else.
+no validation, back plane removal, etc.
+
+Timo - 08/26/99
+added brush epairs parsing ( ignoring actually )
+Timo - 08/04/99
+added exclusive brush primitive parsing
+Timo - 08/08/99
+support for old brush format back in
+NOTE : it would be "cleaner" to have seperate functions to parse between old and new brushes
+=================
+*/
+void ParseRawBrush( ) {
+ side_t *side;
+ vec3_t planepts[3];
+ int planenum;
+ shaderInfo_t *si;
+ // old brushes
+ vec_t shift[2];
+ vec_t rotate;
+ vec_t scale[2];
+ char name[MAX_QPATH];
+ char shader[MAX_QPATH];
+ int flags;
+
+ buildBrush->numsides = 0;
+ buildBrush->detail = qfalse;
+
+ if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
+ MatchToken( "{" );
+
+ do
+ {
+ if (!GetToken (qtrue))
+ break;
+ if (!strcmp (token, "}") )
+ break;
+ //Timo : brush primitive : here we may have to jump over brush epairs ( only used in editor )
+ if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
+ {
+ do
+ {
+ if (strcmp (token, "(") )
+ GetToken( qfalse );
+ else
+ break;
+ GetToken( qtrue );
+ } while (1);
+ }
+ UnGetToken();
+
+ if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
+ Error( "MAX_BUILD_SIDES" );
+ }
+
+ side = &buildBrush->sides[ buildBrush->numsides ];
+ memset( side, 0, sizeof( *side ) );
+ buildBrush->numsides++;
+
+ // read the three point plane definition
+ Parse1DMatrix( 3, planepts[0] );
+ Parse1DMatrix( 3, planepts[1] );
+ Parse1DMatrix( 3, planepts[2] );
+
+ if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
+ // read the texture matrix
+ Parse2DMatrix( 2, 3, (float *)side->texMat );
+
+ // read the texturedef
+ GetToken (qfalse);
+ strcpy (name, token);
+
+ // save the shader name for retexturing
+ if ( numMapIndexedShaders == MAX_MAP_BRUSHSIDES ) {
+ Error( "MAX_MAP_BRUSHSIDES" );
+ }
+ strcpy( mapIndexedShaders[numMapIndexedShaders], name );
+ numMapIndexedShaders++;
+
+ if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
+ {
+ GetToken (qfalse);
+ shift[0] = atoi(token);
+ GetToken (qfalse);
+ shift[1] = atoi(token);
+ GetToken (qfalse);
+ rotate = atoi(token);
+ GetToken (qfalse);
+ scale[0] = atof(token);
+ GetToken (qfalse);
+ scale[1] = atof(token);
+ }
+
+ // find default flags and values
+ sprintf( shader, "textures/%s", name );
+ si = ShaderInfoForShader( shader );
+ side->shaderInfo = si;
+ side->surfaceFlags = si->surfaceFlags;
+ side->value = si->value;
+ side->contents = si->contents;
+
+ // allow override of default flags and values
+ // in Q3, the only thing you can override is DETAIL
+ if (TokenAvailable())
+ {
+ GetToken (qfalse);
+// side->contents = atoi(token);
+ flags = atoi(token);
+ if ( flags & CONTENTS_DETAIL ) {
+ side->contents |= CONTENTS_DETAIL;
+ }
+
+ GetToken (qfalse);
+// td.flags = atoi(token);
+
+ GetToken (qfalse);
+// td.value = atoi(token);
+ }
+
+
+ // find the plane number
+ planenum = MapPlaneFromPoints (planepts[0], planepts[1], planepts[2]);
+ side->planenum = planenum;
+
+ if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
+ // get the texture mapping for this texturedef / plane combination
+ QuakeTextureVecs( &mapplanes[planenum], shift, rotate, scale, side->vecs );
+
+ } while (1);
+
+ if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
+ {
+ UnGetToken();
+ MatchToken( "}" );
+ MatchToken( "}" );
+ }
+}
+
+/*
+=================
+RemoveDuplicateBrushPlanes
+
+Returns false if the brush has a mirrored set of planes,
+meaning it encloses no volume.
+Also removes planes without any normal
+=================
+*/
+qboolean RemoveDuplicateBrushPlanes( bspbrush_t * b ) {
+ int i, j, k;
+ side_t *sides;
+
+ sides = b->sides;
+
+ for ( i = 1 ; i < b->numsides ; i++ ) {
+
+ // check for a degenerate plane
+ if ( sides[i].planenum == -1) {
+ _printf ("Entity %i, Brush %i: degenerate plane\n"
+ , b->entitynum, b->brushnum);
+ // remove it
+ for ( k = i + 1 ; k < b->numsides ; k++ ) {
+ sides[k-1] = sides[k];
+ }
+ b->numsides--;
+ i--;
+ continue;
+ }
+
+ // check for duplication and mirroring
+ for ( j = 0 ; j < i ; j++ ) {
+ if ( sides[i].planenum == sides[j].planenum ) {
+ _printf ("Entity %i, Brush %i: duplicate plane\n"
+ , b->entitynum, b->brushnum);
+ // remove the second duplicate
+ for ( k = i + 1 ; k < b->numsides ; k++ ) {
+ sides[k-1] = sides[k];
+ }
+ b->numsides--;
+ i--;
+ break;
+ }
+
+ if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
+ // mirror plane, brush is invalid
+ _printf ("Entity %i, Brush %i: mirrored plane\n"
+ , b->entitynum, b->brushnum);
+ return qfalse;
+ }
+ }
+ }
+ return qtrue;
+}
+
+
+/*
+=================
+ParseBrush
+
+ qboolean parameter to true -> parse new brush primitive format ( else use old format )
+=================
+*/
+void ParseBrush (void) {
+ bspbrush_t *b;
+
+ ParseRawBrush();
+
+ buildBrush->portalareas[0] = -1;
+ buildBrush->portalareas[1] = -1;
+ buildBrush->entitynum = num_entities-1;
+ buildBrush->brushnum = entitySourceBrushes;
+
+ // if there are mirrored planes, the entire brush is invalid
+ if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
+ return;
+ }
+
+ // get the content for the entire brush
+ SetBrushContents( buildBrush );
+
+ // allow detail brushes to be removed
+ if (nodetail && (buildBrush->contents & CONTENTS_DETAIL) ) {
+ FreeBrush( buildBrush );
+ return;
+ }
+
+ // allow water brushes to be removed
+ if (nowater && (buildBrush->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) ) {
+ FreeBrush( buildBrush );
+ return;
+ }
+
+ b = FinishBrush( );
+ if ( !b ) {
+ return;
+ }
+}
+
+
+/*
+================
+MoveBrushesToWorld
+
+Takes all of the brushes from the current entity and
+adds them to the world's brush list.
+
+Used by func_group
+================
+*/
+void MoveBrushesToWorld (entity_t *mapent) {
+ bspbrush_t *b, *next;
+ parseMesh_t *pm;
+
+ // move brushes
+ for ( b = mapent->brushes ; b ; b = next ) {
+ next = b->next;
+
+ b->next = entities[0].brushes;
+ entities[0].brushes = b;
+ }
+ mapent->brushes = NULL;
+
+ // move patches
+ if ( mapent->patches ) {
+
+ for ( pm = mapent->patches ; pm->next ; pm = pm->next ) {
+ }
+
+ pm->next = entities[0].patches;
+ entities[0].patches = mapent->patches;
+
+ mapent->patches = NULL;
+ }
+}
+
+
+/*
+================
+AdjustBrushesForOrigin
+================
+*/
+void AdjustBrushesForOrigin( entity_t *ent ) {
+ bspbrush_t *b;
+ int i;
+ side_t *s;
+ vec_t newdist;
+ parseMesh_t *p;
+
+ for ( b = ent->brushes ; b ; b = b->next ) {
+ for (i=0 ; i<b->numsides ; i++) {
+ s = &b->sides[i];
+ newdist = mapplanes[s->planenum].dist -
+ DotProduct (mapplanes[s->planenum].normal, ent->origin);
+ s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
+ }
+ CreateBrushWindings(b);
+ }
+
+ for ( p = ent->patches ; p ; p = p->next ) {
+ for ( i = 0 ; i < p->mesh.width*p->mesh.height ; i++ ) {
+ VectorSubtract( p->mesh.verts[i].xyz, ent->origin, p->mesh.verts[i].xyz );
+ }
+ }
+
+}
+
+/*
+================
+ParseMapEntity
+================
+*/
+qboolean ParseMapEntity (void) {
+ epair_t *e;
+
+ if (!GetToken (qtrue))
+ return qfalse;
+
+ if (strcmp (token, "{") )
+ {
+ Error ("ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...", token, scriptline, entities[num_entities].origin[0], entities[num_entities].origin[1], entities[num_entities].origin[2]);
+ }
+
+ if (num_entities == MAX_MAP_ENTITIES)
+ Error ("num_entities == MAX_MAP_ENTITIES");
+
+ entitySourceBrushes = 0;
+
+ mapent = &entities[num_entities];
+ num_entities++;
+ memset (mapent, 0, sizeof(*mapent));
+
+ do
+ {
+ if (!GetToken (qtrue))
+ Error ("ParseEntity: EOF without closing brace");
+ if (!strcmp (token, "}") )
+ break;
+
+ if (!strcmp (token, "{") ) {
+ // parse a brush or patch
+ if (!GetToken (qtrue))
+ break;
+ if ( !strcmp( token, "patchDef2" ) ) {
+ numMapPatches++;
+ ParsePatch();
+ } else if ( !strcmp( token, "terrainDef" ) ) {
+ ParseTerrain();
+ } else if ( !strcmp( token, "brushDef" ) ) {
+ if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
+ Error("old brush format not allowed in new brush format map");
+ g_bBrushPrimit=BPRIMIT_NEWBRUSHES;
+ // parse brush primitive
+ ParseBrush();
+ }
+ else
+ {
+ if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
+ Error("new brush format not allowed in old brush format map");
+ g_bBrushPrimit=BPRIMIT_OLDBRUSHES;
+ // parse old brush format
+ UnGetToken();
+ ParseBrush();
+ }
+ entitySourceBrushes++;
+ }
+ else
+ {
+ // parse a key / value pair
+ e = ParseEpair ();
+ e->next = mapent->epairs;
+ mapent->epairs = e;
+ }
+ } while (1);
+
+ GetVectorForKey (mapent, "origin", mapent->origin);
+
+ //
+ // if there was an origin brush, offset all of the planes and texinfo
+ // for all the brushes in the entity
+ if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) {
+ AdjustBrushesForOrigin( mapent );
+ }
+
+ // group_info entities are just for editor grouping
+ // ignored
+ // FIXME: leak!
+ if (!strcmp("group_info", ValueForKey (mapent, "classname")))
+ {
+ num_entities--;
+ return qtrue;
+ }
+
+ // group entities are just for editor convenience
+ // toss all brushes into the world entity
+ if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
+ {
+ if ( !strcmp ("1", ValueForKey (mapent, "terrain"))) {
+ SetTerrainTextures();
+ }
+ MoveBrushesToWorld (mapent);
+ num_entities--;
+ return qtrue;
+ }
+
+ return qtrue;
+}
+
+//===================================================================
+
+
+/*
+================
+LoadMapFile
+================
+*/
+void LoadMapFile (char *filename) {
+ bspbrush_t *b;
+
+ qprintf ("--- LoadMapFile ---\n");
+ _printf ("Loading map file %s\n", filename);
+
+ LoadScriptFile (filename);
+
+ num_entities = 0;
+ numMapDrawSurfs = 0;
+ c_detail = 0;
+
+ g_bBrushPrimit = BPRIMIT_UNDEFINED;
+
+ // allocate a very large temporary brush for building
+ // the brushes as they are loaded
+ buildBrush = AllocBrush( MAX_BUILD_SIDES );
+
+ while (ParseMapEntity ())
+ {
+ }
+
+ ClearBounds (map_mins, map_maxs);
+ for ( b = entities[0].brushes ; b ; b=b->next ) {
+ AddPointToBounds( b->mins, map_mins, map_maxs );
+ AddPointToBounds( b->maxs, map_mins, map_maxs );
+ }
+
+ qprintf ("%5i total world brushes\n", CountBrushList( entities[0].brushes ) );
+ qprintf ("%5i detail brushes\n", c_detail );
+ qprintf ("%5i patches\n", numMapPatches);
+ qprintf ("%5i boxbevels\n", c_boxbevels);
+ qprintf ("%5i edgebevels\n", c_edgebevels);
+ qprintf ("%5i entities\n", num_entities);
+ qprintf ("%5i planes\n", nummapplanes);
+ qprintf ("%5i areaportals\n", c_areaportals);
+ qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
+ map_maxs[0],map_maxs[1],map_maxs[2]);
+
+ if ( fakemap ) {
+ WriteBspBrushMap ("fakemap.map", entities[0].brushes );
+ }
+
+ if ( testExpand ) {
+ TestExpandBrushes ();
+ }
+}
+
+
+//====================================================================
+
+
+/*
+================
+TestExpandBrushes
+
+Expands all the brush planes and saves a new map out to
+allow visual inspection of the clipping bevels
+================
+*/
+void TestExpandBrushes( void ) {
+ side_t *s;
+ int i, j;
+ bspbrush_t *brush, *list, *copy;
+ vec_t dist;
+ plane_t *plane;
+
+ list = NULL;
+
+ for ( brush = entities[0].brushes ; brush ; brush = brush->next ) {
+ copy = CopyBrush( brush );
+ copy->next = list;
+ list = copy;
+
+ // expand all the planes
+ for ( i=0 ; i<brush->numsides ; i++ ) {
+ s = brush->sides + i;
+ plane = &mapplanes[s->planenum];
+ dist = plane->dist;
+ for (j=0 ; j<3 ; j++) {
+ dist += fabs( 16 * plane->normal[j] );
+ }
+ s->planenum = FindFloatPlane( plane->normal, dist );
+ }
+
+ }
+
+ WriteBspBrushMap ( "expanded.map", entities[0].brushes );
+
+ Error ("can't proceed after expanding brushes");
+}