0% found this document useful (0 votes)
7 views23 pages

Map Sin

The document contains source code for the Quake III Arena game, specifically related to the parsing and handling of map brushes and entities. It includes functions for determining brush contents, parsing brush definitions, and moving brushes to the world entity. The code is structured with conditional compilation for different versions and includes error handling for various scenarios during map parsing.

Uploaded by

KinjalKishor
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views23 pages

Map Sin

The document contains source code for the Quake III Arena game, specifically related to the parsing and handling of map brushes and entities. It includes functions for determining brush contents, parsing brush definitions, and moving brushes to the world entity. The code is structured with conditional compilation for different versions and includes error handling for various scenarios during map parsing.

Uploaded by

KinjalKishor
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 23

/*

===========================================================================
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
===========================================================================
*/
//-----------------------------------------------------------------------------
//
// $Logfile:: /MissionPack/code/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;

map_sin.txt[2025-02-15 10:39:45 PM]


#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;

map_sin.txt[2025-02-15 10:39:45 PM]


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++)

map_sin.txt[2025-02-15 10:39:45 PM]


{
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;

map_sin.txt[2025-02-15 10:39:45 PM]


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 ; k<b->numsides ; k++)

map_sin.txt[2025-02-15 10:39:45 PM]


{
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) )

map_sin.txt[2025-02-15 10:39:45 PM]


{
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;

map_sin.txt[2025-02-15 10:39:45 PM]


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 ; 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;
free (temp);

map_sin.txt[2025-02-15 10:39:45 PM]


mapent->numbrushes = 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") )
{

map_sin.txt[2025-02-15 10:39:45 PM]


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 ; j<end ; j++)


{
brush = &mapbrushes[j];
if (!brush->numsides)
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 (

map_sin.txt[2025-02-15 10:39:45 PM]


(!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 ; 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);
#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)
{

map_sin.txt[2025-02-15 10:39:45 PM]


for (i=0 ; i<mapent->numbrushes ; 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 ; j<b->numsides ; 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 ; j<b->numsides ; 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"

map_sin.txt[2025-02-15 10:39:45 PM]


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<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);
}
#ifdef SIN
for (j=0; j<num_entities; j++)
{
for (i=0 ; i<entities[j].numbrushes ; i++)
{
side_t * s;
mapbrush_t *b;
b = &mapbrushes[entities[j].firstbrush + i];

map_sin.txt[2025-02-15 10:39:45 PM]


if (b->numsides && b->contents & CONTENTS_DETAIL)
num_detailbrushes++;
else if (b->numsides)
num_worldbrushes++;
for (k=0, s=b->original_sides ; k<b->numsides ; 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++)

map_sin.txt[2025-02-15 10:39:45 PM]


{
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

map_sin.txt[2025-02-15 10:39:45 PM]


} //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);

map_sin.txt[2025-02-15 10:39:45 PM]


//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

map_sin.txt[2025-02-15 10:39:45 PM]


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)

map_sin.txt[2025-02-15 10:39:45 PM]


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);

map_sin.txt[2025-02-15 10:39:45 PM]


//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++;

map_sin.txt[2025-02-15 10:39:45 PM]


} //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)

map_sin.txt[2025-02-15 10:39:45 PM]


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

map_sin.txt[2025-02-15 10:39:45 PM]


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

map_sin.txt[2025-02-15 10:39:45 PM]

You might also like