📄 map_q2.c
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
This file is part of Quake III Arena source code.
Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//===========================================================================
// ANSI, Area Navigational System Interface
// AAS, Area Awareness System
//===========================================================================
#include "qbsp.h"
#include "l_mem.h"
#include "../botlib/aasfile.h" //aas_bbox_t
#include "aas_store.h" //AAS_MAX_BBOXES
#include "aas_cfg.h"
#include "aas_map.h" //AAS_CreateMapBrushes
#include "l_bsp_q2.h"
#ifdef ME
#define NODESTACKSIZE 1024
int nodestack[NODESTACKSIZE];
int *nodestackptr;
int nodestacksize = 0;
int brushmodelnumbers[MAX_MAPFILE_BRUSHES];
int dbrushleafnums[MAX_MAPFILE_BRUSHES];
int dplanes2mapplanes[MAX_MAPFILE_PLANES];
#endif //ME
//====================================================================
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void Q2_CreateMapTexinfo(void)
{
int i;
for (i = 0; i < numtexinfo; i++)
{
memcpy(map_texinfo[i].vecs, texinfo[i].vecs, sizeof(float) * 2 * 4);
map_texinfo[i].flags = texinfo[i].flags;
map_texinfo[i].value = texinfo[i].value;
strcpy(map_texinfo[i].texture, texinfo[i].texture);
map_texinfo[i].nexttexinfo = 0;
} //end for
} //end of the function Q2_CreateMapTexinfo
/*
===========
Q2_BrushContents
===========
*/
int Q2_BrushContents (mapbrush_t *b)
{
int contents;
side_t *s;
int i;
int trans;
s = &b->original_sides[0];
contents = s->contents;
trans = texinfo[s->texinfo].flags;
for (i = 1; i < b->numsides; i++, s++)
{
s = &b->original_sides[i];
trans |= texinfo[s->texinfo].flags;
if (s->contents != contents)
{
Log_Print("Entity %i, Brush %i: mixed face contents\n"
, b->entitynum, b->brushnum);
Log_Print("texture name = %s\n", texinfo[s->texinfo].texture);
break;
}
}
// if any side is translucent, mark the contents
// and change solid to window
if ( trans & (SURF_TRANS33|SURF_TRANS66) )
{
contents |= CONTENTS_Q2TRANSLUCENT;
if (contents & CONTENTS_SOLID)
{
contents &= ~CONTENTS_SOLID;
contents |= CONTENTS_WINDOW;
}
}
return contents;
}
#ifdef ME
#define BBOX_NORMAL_EPSILON 0.0001
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void MakeAreaPortalBrush(mapbrush_t *brush)
{
int sn;
side_t *s;
brush->contents = CONTENTS_AREAPORTAL;
for (sn = 0; sn < brush->numsides; sn++)
{
s = brush->original_sides + sn;
//make sure the surfaces are not hint or skip
s->surf &= ~(SURF_HINT|SURF_SKIP);
//
s->texinfo = 0;
s->contents = CONTENTS_AREAPORTAL;
} //end for
} //end of the function MakeAreaPortalBrush
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void DPlanes2MapPlanes(void)
{
int i;
for (i = 0; i < numplanes; i++)
{
dplanes2mapplanes[i] = FindFloatPlane(dplanes[i].normal, dplanes[i].dist);
} //end for
} //end of the function DPlanes2MapPlanes
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void MarkVisibleBrushSides(mapbrush_t *brush)
{
int n, i, planenum;
side_t *side;
dface_t *face;
//
for (n = 0; n < brush->numsides; n++)
{
side = brush->original_sides + n;
//if this side is a bevel or the leaf number of the brush is unknown
if ((side->flags & SFL_BEVEL) || brush->leafnum < 0)
{
//this side is a valid splitter
side->flags |= SFL_VISIBLE;
continue;
} //end if
//assum this side will not be used as a splitter
side->flags &= ~SFL_VISIBLE;
//check if the side plane is used by a visible face
for (i = 0; i < numfaces; i++)
{
face = &dfaces[i];
planenum = dplanes2mapplanes[face->planenum];
if ((planenum & ~1) == (side->planenum & ~1))
{
//this side is a valid splitter
side->flags |= SFL_VISIBLE;
} //end if
} //end for
} //end for
} //end of the function MarkVisibleBrushSides
#endif //ME
/*
=================
Q2_ParseBrush
=================
*/
void Q2_ParseBrush (script_t *script, entity_t *mapent)
{
mapbrush_t *b;
int i, j, k;
int mt;
side_t *side, *s2;
int planenum;
brush_texture_t td;
int planepts[3][3];
token_t token;
if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
Error ("nummapbrushes == MAX_MAPFILE_BRUSHES");
b = &mapbrushes[nummapbrushes];
b->original_sides = &brushsides[nummapbrushsides];
b->entitynum = num_entities-1;
b->brushnum = nummapbrushes - mapent->firstbrush;
b->leafnum = -1;
do
{
if (!PS_ReadToken(script, &token))
break;
if (!strcmp(token.string, "}") )
break;
//IDBUG: mixed use of MAX_MAPFILE_? and MAX_MAP_? this could
// lead to out of bound indexing of the arrays
if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
Error ("MAX_MAPFILE_BRUSHSIDES");
side = &brushsides[nummapbrushsides];
//read the three point plane definition
for (i = 0; i < 3; i++)
{
if (i != 0) PS_ExpectTokenString(script, "(");
for (j = 0; j < 3; j++)
{
PS_ExpectAnyToken(script, &token);
planepts[i][j] = atof(token.string);
} //end for
PS_ExpectTokenString(script, ")");
} //end for
//
//read the texturedef
//
PS_ExpectAnyToken(script, &token);
strcpy(td.name, token.string);
PS_ExpectAnyToken(script, &token);
td.shift[0] = atol(token.string);
PS_ExpectAnyToken(script, &token);
td.shift[1] = atol(token.string);
PS_ExpectAnyToken(script, &token);
td.rotate = atol(token.string);
PS_ExpectAnyToken(script, &token);
td.scale[0] = atof(token.string);
PS_ExpectAnyToken(script, &token);
td.scale[1] = atof(token.string);
//find default flags and values
mt = FindMiptex (td.name);
td.flags = textureref[mt].flags;
td.value = textureref[mt].value;
side->contents = textureref[mt].contents;
side->surf = td.flags = textureref[mt].flags;
//check if there's a number available
if (PS_CheckTokenType(script, TT_NUMBER, 0, &token))
{
side->contents = token.intvalue;
PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
side->surf = td.flags = token.intvalue;
PS_ExpectTokenType(script, TT_NUMBER, 0, &token);
td.value = token.intvalue;
}
// translucent objects are automatically classified as detail
if (side->surf & (SURF_TRANS33|SURF_TRANS66) )
side->contents |= CONTENTS_DETAIL;
if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
side->contents |= CONTENTS_DETAIL;
if (fulldetail)
side->contents &= ~CONTENTS_DETAIL;
if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1)
| CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) )
side->contents |= CONTENTS_SOLID;
// hints and skips are never detail, and have no content
if (side->surf & (SURF_HINT|SURF_SKIP) )
{
side->contents = 0;
side->surf &= ~CONTENTS_DETAIL;
}
#ifdef ME
//for creating AAS... this side is textured
side->flags |= SFL_TEXTURED;
#endif //ME
//
// find the plane number
//
planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]);
if (planenum == -1)
{
Log_Print("Entity %i, Brush %i: plane with no normal\n"
, b->entitynum, b->brushnum);
continue;
}
//
// see if the plane has been used already
//
for (k=0 ; k<b->numsides ; k++)
{
s2 = b->original_sides + k;
if (s2->planenum == planenum)
{
Log_Print("Entity %i, Brush %i: duplicate plane\n"
, b->entitynum, b->brushnum);
break;
}
if ( s2->planenum == (planenum^1) )
{
Log_Print("Entity %i, Brush %i: mirrored plane\n"
, b->entitynum, b->brushnum);
break;
}
}
if (k != b->numsides)
continue; // duplicated
//
// keep this side
//
side = b->original_sides + b->numsides;
side->planenum = planenum;
side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum],
&td, vec3_origin);
// save the td off in case there is an origin brush and we
// have to recalculate the texinfo
side_brushtextures[nummapbrushsides] = td;
nummapbrushsides++;
b->numsides++;
} while (1);
// get the content for the entire brush
b->contents = Q2_BrushContents (b);
#ifdef ME
if (BrushExists(b))
{
c_squattbrushes++;
b->numsides = 0;
return;
} //end if
if (create_aas)
{
//create AAS brushes, and add brush bevels
AAS_CreateMapBrushes(b, mapent, true);
//NOTE: if we return here then duplicate plane errors occur for the non world entities
return;
} //end if
#endif //ME
// allow detail brushes to be removed
if (nodetail && (b->contents & CONTENTS_DETAIL) )
{
b->numsides = 0;
return;
}
// allow water brushes to be removed
if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) )
{
b->numsides = 0;
return;
}
// create windings for sides and bounds for brush
MakeBrushWindings (b);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -