/* =========================================================================== 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; #ifdef SIN trans = sin_texinfo[s->texinfo].translucence; #else trans = texinfo[s->texinfo].flags; #endif for (i=1 ; inumsides ; 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