/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (RTCW MP Source Code).
RTCW MP 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 3 of the License, or
(at your option) any later version.
RTCW MP 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 RTCW MP Source Code. If not, see .
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//-----------------------------------------------------------------------------
//
// $Logfile:: /Wolfenstein MP/src/bspc/map_sin.c $
#include "qbsp.h"
#include "l_bsp_sin.h"
#include "aas_map.h" //AAS_CreateMapBrushes
//====================================================================
/*
===========
Sin_BrushContents
===========
*/
int Sin_BrushContents( mapbrush_t *b ) {
int contents;
side_t *s;
int i;
#ifdef SIN
float trans = 0;
#else
int trans;
#endif
s = &b->original_sides[0];
contents = s->contents;
#ifdef SIN
trans = sin_texinfo[s->texinfo].translucence;
#else
trans = texinfo[s->texinfo].flags;
#endif
for ( i = 1 ; i < b->numsides ; i++, s++ )
{
s = &b->original_sides[i];
#ifdef SIN
trans += sin_texinfo[s->texinfo].translucence;
#else
trans |= texinfo[s->texinfo].flags;
#endif
if ( s->contents != contents ) {
#ifdef SIN
if (
( s->contents & CONTENTS_DETAIL && !( contents & CONTENTS_DETAIL ) ) ||
( !( s->contents & CONTENTS_DETAIL ) && contents & CONTENTS_DETAIL )
) {
s->contents |= CONTENTS_DETAIL;
contents |= CONTENTS_DETAIL;
continue;
}
#endif
printf( "Entity %i, Brush %i: mixed face contents\n"
, b->entitynum, b->brushnum );
break;
}
}
#ifdef SIN
if ( contents & CONTENTS_FENCE ) {
// contents |= CONTENTS_TRANSLUCENT;
contents |= CONTENTS_DETAIL;
contents |= CONTENTS_DUMMYFENCE;
contents &= ~CONTENTS_SOLID;
contents &= ~CONTENTS_FENCE;
contents |= CONTENTS_WINDOW;
}
#endif
// if any side is translucent, mark the contents
// and change solid to window
#ifdef SIN
if ( trans > 0 )
#else
if ( trans & ( SURF_TRANS33 | SURF_TRANS66 ) )
#endif
{
contents |= CONTENTS_Q2TRANSLUCENT;
if ( contents & CONTENTS_SOLID ) {
contents &= ~CONTENTS_SOLID;
contents |= CONTENTS_WINDOW;
}
}
return contents;
} //*/
//============================================================================
/*
=================
ParseBrush
=================
* /
void ParseBrush (entity_t *mapent)
{
mapbrush_t *b;
int i,j, k;
int mt;
side_t *side, *s2;
int planenum;
brush_texture_t td;
#ifdef SIN
textureref_t newref;
#endif
int planepts[3][3];
if (nummapbrushes == MAX_MAP_BRUSHES)
Error ("nummapbrushes == MAX_MAP_BRUSHES");
b = &mapbrushes[nummapbrushes];
b->original_sides = &brushsides[nummapbrushsides];
b->entitynum = num_entities-1;
b->brushnum = nummapbrushes - mapent->firstbrush;
do
{
if (!GetToken (true))
break;
if (!strcmp (token, "}") )
break;
if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
Error ("MAX_MAP_BRUSHSIDES");
side = &brushsides[nummapbrushsides];
// read the three point plane definition
for (i=0 ; i<3 ; i++)
{
if (i != 0)
GetToken (true);
if (strcmp (token, "(") )
Error ("parsing brush");
for (j=0 ; j<3 ; j++)
{
GetToken (false);
planepts[i][j] = atoi(token);
}
GetToken (false);
if (strcmp (token, ")") )
Error ("parsing brush");
}
//
// read the texturedef
//
GetToken (false);
strcpy (td.name, token);
GetToken (false);
td.shift[0] = atoi(token);
GetToken (false);
td.shift[1] = atoi(token);
GetToken (false);
#ifdef SIN
td.rotate = atof(token);
#else
td.rotate = atoi(token);
#endif
GetToken (false);
td.scale[0] = atof(token);
GetToken (false);
td.scale[1] = atof(token);
// find default flags and values
mt = FindMiptex (td.name);
#ifdef SIN
// clear out the masks on newref
memset(&newref,0,sizeof(newref));
// copy over the name
strcpy( newref.name, td.name );
ParseSurfaceInfo( &newref );
MergeRefs( &bsp_textureref[mt], &newref, &td.tref );
side->contents = td.tref.contents;
side->surf = td.tref.flags;
#else
td.flags = textureref[mt].flags;
td.value = textureref[mt].value;
side->contents = textureref[mt].contents;
side->surf = td.flags = textureref[mt].flags;
if (TokenAvailable())
{
GetToken (false);
side->contents = atoi(token);
GetToken (false);
side->surf = td.flags = atoi(token);
GetToken (false);
td.value = atoi(token);
}
#endif
// translucent objects are automatically classified as detail
#ifdef SIN
if ( td.tref.translucence > 0 )
#else
if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
#endif
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;
#ifndef SIN // I think this is a bug of some kind
side->surf &= ~CONTENTS_DETAIL;
#endif
}
//
// find the plane number
//
planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
if (planenum == -1)
{
printf ("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 ; knumsides ; k++)
{
s2 = b->original_sides + k;
if (s2->planenum == planenum)
{
printf ("Entity %i, Brush %i: duplicate plane\n"
, b->entitynum, b->brushnum);
break;
}
if ( s2->planenum == (planenum^1) )
{
printf ("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;
#ifdef SIN
side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
&td, vec3_origin, &newref);
//
// save off lightinfo
//
side->lightinfo = LightinfoForBrushTexture ( &td );
#else
side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
&td, vec3_origin);
#endif
// save the td off in case there is an origin brush and we
// have to recalculate the texinfo
side_brushtextures[nummapbrushsides] = td;
#ifdef SIN
// save off the merged tref for animating textures
side_newrefs[nummapbrushsides] = newref;
#endif
nummapbrushsides++;
b->numsides++;
} while (1);
// get the content for the entire brush
b->contents = Sin_BrushContents (b);
// 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 ; inumsides ; 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++;
} //*/
/*
================
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 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 = malloc(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 ; inumbrushes = 0;
} //*/
/*
================
ParseMapEntity
================
* /
qboolean Sin_ParseMapEntity (void)
{
entity_t *mapent;
epair_t *e;
side_t *s;
int i, j;
int startbrush, startsides;
vec_t newdist;
mapbrush_t *b;
if (!GetToken (true))
return false;
if (strcmp (token, "{") )
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 (!GetToken (true))
Error ("ParseEntity: EOF without closing brace");
if (!strcmp (token, "}") )
break;
if (!strcmp (token, "{") )
ParseBrush (mapent);
else
{
e = ParseEpair ();
#ifdef SIN
//HACK HACK HACK
// MED Gotta do this here
if ( !stricmp(e->key, "surfacefile") )
{
if (!surfacefile[0])
{
strcpy( surfacefile, e->value );
}
printf ("--- ParseSurfaceFile ---\n");
printf ("Surface script: %s\n", surfacefile);
if (!ParseSurfaceFile(surfacefile))
{
Error ("Script file not found: %s\n", surfacefile);
}
}
#endif
e->next = mapent->epairs;
mapent->epairs = e;
}
} while (1);
#ifdef SIN
if (!(strlen(ValueForKey(mapent, "origin"))) && ((num_entities-1) != 0))
{
mapbrush_t *brush;
vec3_t origin;
char string[32];
vec3_t mins, maxs;
int start, end;
// Calculate bounds
start = mapent->firstbrush;
end = start + mapent->numbrushes;
ClearBounds (mins, maxs);
for (j=start ; jnumsides)
continue; // not a real brush (origin brush) - shouldn't happen
AddPointToBounds (brush->mins, mins, maxs);
AddPointToBounds (brush->maxs, mins, maxs);
}
// Set the origin to be the centroid of the entity.
VectorAdd ( mins, maxs, origin);
VectorScale( origin, 0.5f, origin );
sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
SetKeyValue ( mapent, "origin", string);
// qprintf("Setting origin to %s\n",string);
}
#endif
GetVectorForKey (mapent, "origin", mapent->origin);
#ifdef SIN
if (
(!strcmp ("func_areaportal", ValueForKey (mapent, "classname"))) ||
(!strcmp ("func_group", ValueForKey (mapent, "classname"))) ||
(!strcmp ("detail", ValueForKey (mapent, "classname")) && !entitydetails)
)
{
VectorClear( mapent->origin );
}
#endif
//
// 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 ; inumbrushes ; i++)
{
b = &mapbrushes[mapent->firstbrush + i];
for (j=0 ; jnumsides ; 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);
#ifdef SIN
s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
&side_brushtextures[s-brushsides], mapent->origin, &side_newrefs[s-brushsides]);
//
// save off lightinfo
//
s->lightinfo = LightinfoForBrushTexture ( &side_brushtextures[s-brushsides] );
#else
s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum],
&side_brushtextures[s-brushsides], mapent->origin);
#endif
}
MakeBrushWindings (b);
}
}
// group entities are just for editor convenience
// toss all brushes into the world entity
if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
{
MoveBrushesToWorld (mapent);
mapent->numbrushes = 0;
mapent->wasdetail = true;
FreeValueKeys( mapent );
return true;
}
#ifdef SIN
// detail entities are just for editor convenience
// toss all brushes into the world entity as detail brushes
if (!strcmp ("detail", ValueForKey (mapent, "classname")) && !entitydetails)
{
for (i=0 ; inumbrushes ; i++)
{
int j;
side_t * s;
b = &mapbrushes[mapent->firstbrush + i];
if (nodetail)
{
b->numsides = 0;
continue;
}
if (!fulldetail)
{
// set the contents for the entire brush
b->contents |= CONTENTS_DETAIL;
// set the contents in the sides as well
for (j=0, s=b->original_sides ; jnumsides ; j++,s++)
{
s->contents |= CONTENTS_DETAIL;
}
}
else
{
// set the contents for the entire brush
b->contents |= CONTENTS_SOLID;
// set the contents in the sides as well
for (j=0, s=b->original_sides ; jnumsides ; j++,s++)
{
s->contents |= CONTENTS_SOLID;
}
}
}
MoveBrushesToWorld (mapent);
mapent->wasdetail = true;
FreeValueKeys( mapent );
// kill off the entity
// num_entities--;
return true;
}
#endif
// 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);
MoveBrushesToWorld (mapent);
return true;
}
return true;
} //end of the function Sin_ParseMapEntity */
//===================================================================
/*
================
LoadMapFile
================
* /
void Sin_LoadMapFile (char *filename)
{
int i;
#ifdef SIN
int num_detailsides=0;
int num_detailbrushes=0;
int num_worldsides=0;
int num_worldbrushes=0;
int j,k;
#endif
qprintf ("--- LoadMapFile ---\n");
LoadScriptFile (filename);
nummapbrushsides = 0;
num_entities = 0;
while (ParseMapEntity ())
{
}
ClearBounds (map_mins, map_maxs);
for (i=0 ; i 4096)
continue; // no valid points
AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs);
AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs);
}
#ifdef SIN
for (j=0; jnumsides && b->contents & CONTENTS_DETAIL)
num_detailbrushes++;
else if (b->numsides)
num_worldbrushes++;
for (k=0, s=b->original_sides ; knumsides ; k++,s++)
{
if (s->contents & CONTENTS_DETAIL)
num_detailsides++;
else
num_worldsides++;
}
}
}
#endif
qprintf ("%5i brushes\n", nummapbrushes);
qprintf ("%5i clipbrushes\n", c_clipbrushes);
qprintf ("%5i total sides\n", nummapbrushsides);
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]);
#ifdef SIN
qprintf ("%5i detailbrushes\n", num_detailbrushes);
qprintf ("%5i worldbrushes\n", num_worldbrushes);
qprintf ("%5i detailsides\n", num_detailsides);
qprintf ("%5i worldsides\n", num_worldsides);
#endif
} //end of the function Sin_LoadMap */
#ifdef ME //Begin MAP loading from BSP file
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Sin_CreateMapTexinfo( void ) {
int i;
vec_t defaultvec[4] = {1, 0, 0, 0};
memcpy( map_texinfo[0].vecs[0], defaultvec, sizeof( defaultvec ) );
memcpy( map_texinfo[0].vecs[1], defaultvec, sizeof( defaultvec ) );
map_texinfo[0].flags = 0;
map_texinfo[0].value = 0;
strcpy( map_texinfo[0].texture, "generic/misc/red" ); //no texture
map_texinfo[0].nexttexinfo = -1;
for ( i = 1; i < sin_numtexinfo; i++ )
{
memcpy( map_texinfo[i].vecs, sin_texinfo[i].vecs, sizeof( float ) * 2 * 4 );
map_texinfo[i].flags = sin_texinfo[i].flags;
map_texinfo[i].value = 0;
strcpy( map_texinfo[i].texture, sin_texinfo[i].texture );
map_texinfo[i].nexttexinfo = -1;
} //end for
} //end of the function Sin_CreateMapTexinfo
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Sin_SetLeafBrushesModelNumbers( int leafnum, int modelnum ) {
int i, brushnum;
sin_dleaf_t *leaf;
leaf = &sin_dleafs[leafnum];
for ( i = 0; i < leaf->numleafbrushes; i++ )
{
brushnum = sin_dleafbrushes[leaf->firstleafbrush + i];
brushmodelnumbers[brushnum] = modelnum;
dbrushleafnums[brushnum] = leafnum;
} //end for
} //end of the function Sin_SetLeafBrushesModelNumbers
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Sin_InitNodeStack( void ) {
nodestackptr = nodestack;
nodestacksize = 0;
} //end of the function Sin_InitNodeStack
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Sin_PushNodeStack( int num ) {
*nodestackptr = num;
nodestackptr++;
nodestacksize++;
//
if ( nodestackptr >= &nodestack[NODESTACKSIZE] ) {
Error( "Sin_PushNodeStack: stack overflow\n" );
} //end if
} //end of the function Sin_PushNodeStack
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int Sin_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 Sin_PopNodeStack
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Sin_SetBrushModelNumbers( entity_t *mapent ) {
int n, pn;
int leafnum;
//
Sin_InitNodeStack();
//head node (root) of the bsp tree
n = sin_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
Sin_SetLeafBrushesModelNumbers( leafnum, mapent->modelnum );
//walk back into the tree to find a second child to continue with
for ( pn = Sin_PopNodeStack(); pn >= 0; n = pn, pn = Sin_PopNodeStack() )
{
//if we took the first child at the parent node
if ( sin_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
Sin_PushNodeStack( pn );
//we proceed with the second child of the parent node
n = sin_dnodes[pn].children[1];
} //end if
} //end if
else
{
//push the current node onto the stack
Sin_PushNodeStack( n );
//walk forward into the tree to the first child
n = sin_dnodes[n].children[0];
} //end else
} while ( pn >= 0 );
} //end of the function Sin_SetBrushModelNumbers
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Sin_BSPBrushToMapBrush( sin_dbrush_t *bspbrush, entity_t *mapent ) {
mapbrush_t *b;
int i, k, n;
side_t *side, *s2;
int planenum;
sin_dbrushside_t *bspbrushside;
sin_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 - sin_dbrushes];
for ( n = 0; n < bspbrush->numsides; n++ )
{
//pointer to the bsp brush side
bspbrushside = &sin_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 ( sin_dbrushsidetextured[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 = sin_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 = &sin_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 ( 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 Sin_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;
Sin_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 Sin_BSPBrushToMapBrush
//===========================================================================
//===========================================================================
void Sin_ParseBSPBrushes( entity_t *mapent ) {
int i, testnum = 0;
//give all the brushes that belong to this entity the number of the
//BSP model used by this entity
Sin_SetBrushModelNumbers( mapent );
//now parse all the brushes with the correct mapent->modelnum
for ( i = 0; i < sin_numbrushes; i++ )
{
if ( brushmodelnumbers[i] == mapent->modelnum ) {
testnum++;
Sin_BSPBrushToMapBrush( &sin_dbrushes[i], mapent );
} //end if
} //end for
} //end of the function Sin_ParseBSPBrushes
//===========================================================================
//===========================================================================
qboolean Sin_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 && *model == '*' ) {
mapent->modelnum = atoi( &model[1] );
//Log_Print("model = %s\n", model);
//Log_Print("mapent->modelnum = %d\n", mapent->modelnum);
} //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
Sin_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 Sin_ParseBSPEntity
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Sin_LoadMapFromBSP( char *filename, int offset, int length ) {
int i;
Log_Print( "-- Sin_LoadMapFromBSP --\n" );
//loaded map type
loadedmaptype = MAPTYPE_SIN;
Log_Print( "Loading map from %s...\n", filename );
//load the bsp file
Sin_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;
Sin_ParseEntities();
//
for ( i = 0; i < num_entities; i++ )
{
Sin_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
//
Sin_CreateMapTexinfo();
} //end of the function Sin_LoadMapFromBSP
void Sin_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 Sin_ResetMapLoading
//End MAP loading from BSP file
#endif //ME