diff options
Diffstat (limited to 'code/bspc/map.c')
-rw-r--r-- | code/bspc/map.c | 1267 |
1 files changed, 0 insertions, 1267 deletions
diff --git a/code/bspc/map.c b/code/bspc/map.c deleted file mode 100644 index c3c5104..0000000 --- a/code/bspc/map.c +++ /dev/null @@ -1,1267 +0,0 @@ -/* -=========================================================================== -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 Quake III Arena source code; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -=========================================================================== -*/ - -#include "qbsp.h" -#include "l_bsp_hl.h" -#include "l_bsp_q1.h" -#include "l_bsp_q2.h" -#include "l_bsp_q3.h" -#include "l_bsp_sin.h" -#include "l_mem.h" -#include "../botlib/aasfile.h" //aas_bbox_t -#include "aas_store.h" //AAS_MAX_BBOXES -#include "aas_cfg.h" - -#define Sign(x) (x < 0 ? 1 : 0) - -int nummapbrushes; -mapbrush_t mapbrushes[MAX_MAPFILE_BRUSHES]; - -int nummapbrushsides; -side_t brushsides[MAX_MAPFILE_BRUSHSIDES]; -brush_texture_t side_brushtextures[MAX_MAPFILE_BRUSHSIDES]; - -int nummapplanes; -plane_t mapplanes[MAX_MAPFILE_PLANES]; -int mapplaneusers[MAX_MAPFILE_PLANES]; - -#define PLANE_HASHES 1024 -plane_t *planehash[PLANE_HASHES]; -vec3_t map_mins, map_maxs; - -#ifdef SIN -textureref_t side_newrefs[MAX_MAPFILE_BRUSHSIDES]; -#endif - -map_texinfo_t map_texinfo[MAX_MAPFILE_TEXINFO]; -int map_numtexinfo; -int loadedmaptype; //loaded map type - -// undefine to make plane finding use linear sort -#define USE_HASHING - -int c_boxbevels; -int c_edgebevels; -int c_areaportals; -int c_clipbrushes; -int c_squattbrushes; -int c_writtenbrushes; - -/* -============================================================================= - -PLANE FINDING - -============================================================================= -*/ - - -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int PlaneSignBits(vec3_t normal) -{ - int i, signbits; - - signbits = 0; - for (i = 2; i >= 0; i--) - { - signbits = (signbits << 1) + Sign(normal[i]); - } //end for - return signbits; -} //end of the function PlaneSignBits -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int PlaneTypeForNormal(vec3_t normal) -{ - vec_t ax, ay, az; - -// NOTE: should these have an epsilon around 1.0? - if (normal[0] == 1.0 || normal[0] == -1.0) - return PLANE_X; - if (normal[1] == 1.0 || normal[1] == -1.0) - return PLANE_Y; - if (normal[2] == 1.0 || normal[2] == -1.0) - return PLANE_Z; - - ax = fabs(normal[0]); - ay = fabs(normal[1]); - az = fabs(normal[2]); - - if (ax >= ay && ax >= az) - return PLANE_ANYX; - if (ay >= ax && ay >= az) - return PLANE_ANYY; - return PLANE_ANYZ; -} //end of the function PlaneTypeForNormal -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -//ME NOTE: changed from 0.00001 -#define NORMAL_EPSILON 0.0001 -//ME NOTE: changed from 0.01 -#define DIST_EPSILON 0.02 -qboolean PlaneEqual(plane_t *p, vec3_t normal, vec_t dist) -{ -#if 1 - if ( - fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON - && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON - && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON - && fabs(p->dist - dist) < DIST_EPSILON ) - return true; -#else - if (p->normal[0] == normal[0] - && p->normal[1] == normal[1] - && p->normal[2] == normal[2] - && p->dist == dist) - return true; -#endif - return false; -} //end of the function PlaneEqual -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AddPlaneToHash(plane_t *p) -{ - int hash; - - hash = (int)fabs(p->dist) / 8; - hash &= (PLANE_HASHES-1); - - p->hash_chain = planehash[hash]; - planehash[hash] = p; -} //end of the function AddPlaneToHash -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int CreateNewFloatPlane (vec3_t normal, vec_t dist) -{ - plane_t *p, temp; - - if (VectorLength(normal) < 0.5) - Error ("FloatPlane: bad normal"); - // create a new plane - if (nummapplanes+2 > MAX_MAPFILE_PLANES) - Error ("MAX_MAPFILE_PLANES"); - - p = &mapplanes[nummapplanes]; - VectorCopy (normal, p->normal); - p->dist = dist; - p->type = (p+1)->type = PlaneTypeForNormal (p->normal); - p->signbits = PlaneSignBits(p->normal); - - VectorSubtract (vec3_origin, normal, (p+1)->normal); - (p+1)->dist = -dist; - (p+1)->signbits = PlaneSignBits((p+1)->normal); - - nummapplanes += 2; - - // allways put axial planes facing positive first - if (p->type < 3) - { - if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0) - { - // flip order - temp = *p; - *p = *(p+1); - *(p+1) = temp; - - AddPlaneToHash (p); - AddPlaneToHash (p+1); - return nummapplanes - 1; - } - } - - AddPlaneToHash (p); - AddPlaneToHash (p+1); - return nummapplanes - 2; -} //end of the function CreateNewFloatPlane -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void SnapVector(vec3_t normal) -{ - int i; - - for (i=0 ; i<3 ; i++) - { - if ( fabs(normal[i] - 1) < NORMAL_EPSILON ) - { - VectorClear (normal); - normal[i] = 1; - break; - } - if ( fabs(normal[i] - -1) < NORMAL_EPSILON ) - { - VectorClear (normal); - normal[i] = -1; - break; - } - } -} //end of the function SnapVector -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void SnapPlane(vec3_t normal, vec_t *dist) -{ - SnapVector(normal); - - if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON) - *dist = Q_rint(*dist); -} //end of the function SnapPlane -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#ifndef USE_HASHING -int FindFloatPlane(vec3_t normal, vec_t dist) -{ - int i; - plane_t *p; - - SnapPlane(normal, &dist); - for (i = 0, p = mapplanes; i < nummapplanes; i++, p++) - { - if (PlaneEqual (p, normal, dist)) - { - mapplaneusers[i]++; - return i; - } //end if - } //end for - i = CreateNewFloatPlane (normal, dist); - mapplaneusers[i]++; - return i; -} //end of the function FindFloatPlane -#else -int FindFloatPlane (vec3_t normal, vec_t dist) -{ - int i; - plane_t *p; - int hash, h; - - SnapPlane (normal, &dist); - hash = (int)fabs(dist) / 8; - hash &= (PLANE_HASHES-1); - - // search the border bins as well - for (i = -1; i <= 1; i++) - { - h = (hash+i)&(PLANE_HASHES-1); - for (p = planehash[h]; p; p = p->hash_chain) - { - if (PlaneEqual(p, normal, dist)) - { - mapplaneusers[p-mapplanes]++; - return p - mapplanes; - } //end if - } //end for - } //end for - i = CreateNewFloatPlane (normal, dist); - mapplaneusers[i]++; - return i; -} //end of the function FindFloatPlane -#endif -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int PlaneFromPoints (int *p0, int *p1, int *p2) -{ - vec3_t t1, t2, normal; - vec_t dist; - - VectorSubtract (p0, p1, t1); - VectorSubtract (p2, p1, t2); - CrossProduct (t1, t2, normal); - VectorNormalize (normal); - - dist = DotProduct (p0, normal); - - return FindFloatPlane (normal, dist); -} //end of the function PlaneFromPoints -//=========================================================================== -// Adds any additional planes necessary to allow the brush to be expanded -// against axial bounding boxes -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void AddBrushBevels (mapbrush_t *b) -{ - int axis, dir; - int i, j, k, l, order; - side_t sidetemp; - brush_texture_t tdtemp; -#ifdef SIN - textureref_t trtemp; -#endif - side_t *s, *s2; - vec3_t normal; - float dist; - winding_t *w, *w2; - vec3_t vec, vec2; - float d; - - // - // add the axial planes - // - order = 0; - for (axis=0 ; axis <3 ; axis++) - { - for (dir=-1 ; dir <= 1 ; dir+=2, order++) - { - // see if the plane is allready present - for (i=0, s=b->original_sides ; i<b->numsides ; i++,s++) - { - if (mapplanes[s->planenum].normal[axis] == dir) - break; - } - - if (i == b->numsides) - { // add a new side - if (nummapbrushsides == MAX_MAP_BRUSHSIDES) - Error ("MAX_MAP_BRUSHSIDES"); - nummapbrushsides++; - b->numsides++; - VectorClear (normal); - normal[axis] = dir; - if (dir == 1) - dist = b->maxs[axis]; - else - dist = -b->mins[axis]; - s->planenum = FindFloatPlane (normal, dist); - s->texinfo = b->original_sides[0].texinfo; -#ifdef SIN - s->lightinfo = b->original_sides[0].lightinfo; -#endif - s->contents = b->original_sides[0].contents; - s->flags |= SFL_BEVEL; - c_boxbevels++; - } - - // if the plane is not in it canonical order, swap it - if (i != order) - { - sidetemp = b->original_sides[order]; - b->original_sides[order] = b->original_sides[i]; - b->original_sides[i] = sidetemp; - - j = b->original_sides - brushsides; - tdtemp = side_brushtextures[j+order]; - side_brushtextures[j+order] = side_brushtextures[j+i]; - side_brushtextures[j+i] = tdtemp; - -#ifdef SIN - trtemp = side_newrefs[j+order]; - side_newrefs[j+order] = side_newrefs[j+i]; - side_newrefs[j+i] = trtemp; -#endif - } - } - } - - // - // add the edge bevels - // - if (b->numsides == 6) - return; // pure axial - - // test the non-axial plane edges - for (i=6 ; i<b->numsides ; i++) - { - s = b->original_sides + i; - w = s->winding; - if (!w) - continue; - for (j=0 ; j<w->numpoints ; j++) - { - k = (j+1)%w->numpoints; - VectorSubtract (w->p[j], w->p[k], vec); - if (VectorNormalize (vec) < 0.5) - continue; - SnapVector (vec); - for (k=0 ; k<3 ; k++) - if ( vec[k] == -1 || vec[k] == 1) - break; // axial - if (k != 3) - continue; // only test non-axial edges - - // try the six possible slanted axials from this edge - for (axis=0 ; axis <3 ; axis++) - { - for (dir=-1 ; dir <= 1 ; dir+=2) - { - // construct a plane - VectorClear (vec2); - vec2[axis] = dir; - CrossProduct (vec, vec2, normal); - if (VectorNormalize (normal) < 0.5) - continue; - dist = DotProduct (w->p[j], normal); - - // if all the points on all the sides are - // behind this plane, it is a proper edge bevel - for (k=0 ; k<b->numsides ; k++) - { - // if this plane has allready been used, skip it - if (PlaneEqual (&mapplanes[b->original_sides[k].planenum] - , normal, dist) ) - break; - - w2 = b->original_sides[k].winding; - if (!w2) - continue; - for (l=0 ; l<w2->numpoints ; l++) - { - d = DotProduct (w2->p[l], normal) - dist; - if (d > 0.1) - break; // point in front - } - if (l != w2->numpoints) - break; - } - - if (k != b->numsides) - continue; // wasn't part of the outer hull - // add this plane - if (nummapbrushsides == MAX_MAP_BRUSHSIDES) - Error ("MAX_MAP_BRUSHSIDES"); - nummapbrushsides++; - s2 = &b->original_sides[b->numsides]; - s2->planenum = FindFloatPlane (normal, dist); - s2->texinfo = b->original_sides[0].texinfo; -#ifdef SIN - s2->lightinfo = b->original_sides[0].lightinfo; -#endif - s2->contents = b->original_sides[0].contents; - s2->flags |= SFL_BEVEL; - c_edgebevels++; - b->numsides++; - } - } - } - } -} //end of the function AddBrushBevels -//=========================================================================== -// creates windigs for sides and mins / maxs for the brush -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean MakeBrushWindings(mapbrush_t *ob) -{ - int i, j; - winding_t *w; - side_t *side; - plane_t *plane; - - ClearBounds (ob->mins, ob->maxs); - - for (i = 0; i < ob->numsides; i++) - { - plane = &mapplanes[ob->original_sides[i].planenum]; - w = BaseWindingForPlane(plane->normal, plane->dist); - for (j = 0; j <ob->numsides && w; j++) - { - if (i == j) continue; - if (ob->original_sides[j].flags & SFL_BEVEL) continue; - plane = &mapplanes[ob->original_sides[j].planenum^1]; - ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); - } - - side = &ob->original_sides[i]; - side->winding = w; - if (w) - { - side->flags |= SFL_VISIBLE; - for (j = 0; j < w->numpoints; j++) - AddPointToBounds (w->p[j], ob->mins, ob->maxs); - } - } - - for (i = 0; i < 3; i++) - { - //IDBUG: all the indexes into the mins and maxs were zero (not using i) - if (ob->mins[i] < -MAX_MAP_BOUNDS || ob->maxs[i] > MAX_MAP_BOUNDS) - { - Log_Print("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum); - ob->numsides = 0; //remove the brush - break; - } //end if - if (ob->mins[i] > MAX_MAP_BOUNDS || ob->maxs[i] < -MAX_MAP_BOUNDS) - { - Log_Print("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum); - ob->numsides = 0; //remove the brush - break; - } //end if - } //end for - return true; -} //end of the function MakeBrushWindings -//=========================================================================== -// FIXME: currently doesn't mark all bevels -// NOTE: when one brush bevel is found the remaining sides of the brush -// are bevels as well (when the brush isn't expanded for AAS :)) -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void MarkBrushBevels(mapbrush_t *brush) -{ - int i; - int we; - side_t *s; - - //check all the sides of the brush - for (i = 0; i < brush->numsides; i++) - { - s = brush->original_sides + i; - //if the side has no winding - if (!s->winding) - { - Log_Write("MarkBrushBevels: brush %d no winding", brush->brushnum); - s->flags |= SFL_BEVEL; - } //end if - //if the winding is tiny - else if (WindingIsTiny(s->winding)) - { - s->flags |= SFL_BEVEL; - Log_Write("MarkBrushBevels: brush %d tiny winding", brush->brushnum); - } //end else if - //if the winding has errors - else - { - we = WindingError(s->winding); - if (we == WE_NOTENOUGHPOINTS - || we == WE_SMALLAREA - || we == WE_POINTBOGUSRANGE -// || we == WE_NONCONVEX - ) - { - Log_Write("MarkBrushBevels: brush %d %s", brush->brushnum, WindingErrorString()); - s->flags |= SFL_BEVEL; - } //end else if - } //end else - if (s->flags & SFL_BEVEL) - { - s->flags &= ~SFL_VISIBLE; - //if the side has a valid plane - if (s->planenum > 0 && s->planenum < nummapplanes) - { - //if it is an axial plane - if (mapplanes[s->planenum].type < 3) c_boxbevels++; - else c_edgebevels++; - } //end if - } //end if - } //end for -} //end of the function MarkBrushBevels -//=========================================================================== -// returns true if the map brush already exists -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -int BrushExists(mapbrush_t *brush) -{ - int i, s1, s2; - side_t *side1, *side2; - mapbrush_t *brush1, *brush2; - - for (i = 0; i < nummapbrushes; i++) - { - brush1 = brush; - brush2 = &mapbrushes[i]; - //compare the brushes - if (brush1->entitynum != brush2->entitynum) continue; - //if (brush1->contents != brush2->contents) continue; - if (brush1->numsides != brush2->numsides) continue; - for (s1 = 0; s1 < brush1->numsides; s1++) - { - side1 = brush1->original_sides + s1; - // - for (s2 = 0; s2 < brush2->numsides; s2++) - { - side2 = brush2->original_sides + s2; - // - if ((side1->planenum & ~1) == (side2->planenum & ~1) -// && side1->texinfo == side2->texinfo -// && side1->contents == side2->contents -// && side1->surf == side2->surf - ) break; - } //end if - if (s2 >= brush2->numsides) break; - } //end for - if (s1 >= brush1->numsides) return true; - } //end for - return false; -} //end of the function BrushExists -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean WriteMapBrush(FILE *fp, mapbrush_t *brush, vec3_t origin) -{ - int sn, rotate, shift[2], sv, tv, planenum, p1, i, j; - float scale[2], originshift[2], ang1, ang2, newdist; - vec3_t vecs[2], axis[2]; - map_texinfo_t *ti; - winding_t *w; - side_t *s; - plane_t *plane; - - if (noliquids) - { - if (brush->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) - { - return true; - } //end if - } //end if - //if the brush has no contents - if (!brush->contents) return true; - //print the leading { - if (fprintf(fp, " { //brush %d\n", brush->brushnum) < 0) return false; - //write brush sides - for (sn = 0; sn < brush->numsides; sn++) - { - s = brush->original_sides + sn; - //don't write out bevels - if (!(s->flags & SFL_BEVEL)) - { - //if the entity has an origin set - if (origin[0] || origin[1] || origin[2]) - { - newdist = mapplanes[s->planenum].dist + - DotProduct(mapplanes[s->planenum].normal, origin); - planenum = FindFloatPlane(mapplanes[s->planenum].normal, newdist); - } //end if - else - { - planenum = s->planenum; - } //end else - //always take the first plane, then flip the points if necesary - plane = &mapplanes[planenum & ~1]; - w = BaseWindingForPlane(plane->normal, plane->dist); - // - for (i = 0; i < 3; i++) - { - for (j = 0; j < 3; j++) - { - if (fabs(w->p[i][j]) < 0.2) w->p[i][j] = 0; - else if (fabs((int)w->p[i][j] - w->p[i][j]) < 0.3) w->p[i][j] = (int) w->p[i][j]; - //w->p[i][j] = (int) (w->p[i][j] + 0.2); - } //end for - } //end for - //three non-colinear points to define the plane - if (planenum & 1) p1 = 1; - else p1 = 0; - if (fprintf(fp," ( %5i %5i %5i ) ", (int)w->p[p1][0], (int)w->p[p1][1], (int)w->p[p1][2]) < 0) return false; - if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[!p1][0], (int)w->p[!p1][1], (int)w->p[!p1][2]) < 0) return false; - if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false; - //free the winding - FreeWinding(w); - // - if (s->texinfo == TEXINFO_NODE) - { - if (brush->contents & CONTENTS_PLAYERCLIP) - { - //player clip - if (loadedmaptype == MAPTYPE_SIN) - { - if (fprintf(fp, "generic/misc/clip 0 0 0 1 1") < 0) return false; - } //end if - else if (loadedmaptype == MAPTYPE_QUAKE2) - { //FIXME: don't always use e1u1 - if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false; - } //end else - else if (loadedmaptype == MAPTYPE_QUAKE3) - { - if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false; - } //end else if - else - { - if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false; - } //end else - } //end if - else if (brush->contents == CONTENTS_MONSTERCLIP) - { - //monster clip - if (loadedmaptype == MAPTYPE_SIN) - { - if (fprintf(fp, "generic/misc/monster 0 0 0 1 1") < 0) return false; - } //end if - else if (loadedmaptype == MAPTYPE_QUAKE2) - { - if (fprintf(fp, "e1u1/clip_mon 0 0 0 1 1") < 0) return false; - } //end else - else - { - if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false; - } //end else - } //end else - else - { - if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false; - Log_Write("brush->contents = %d\n", brush->contents); - } //end else - } //end if - else if (loadedmaptype == MAPTYPE_SIN && s->texinfo == 0) - { - if (brush->contents & CONTENTS_DUMMYFENCE) - { - if (fprintf(fp, "generic/misc/fence 0 0 0 1 1") < 0) return false; - } //end if - else if (brush->contents & CONTENTS_MIST) - { - if (fprintf(fp, "generic/misc/volumetric_base 0 0 0 1 1") < 0) return false; - } //end if - else //unknown so far - { - if (fprintf(fp, "generic/misc/red 0 0 0 1 1") < 0) return false; - } //end else - } //end if - else if (loadedmaptype == MAPTYPE_QUAKE3) - { - //always use the same texture - if (fprintf(fp, "e2u3/floor1_2 0 0 0 1 1 1 0 0") < 0) return false; - } //end else if - else - { - //* - ti = &map_texinfo[s->texinfo]; - //the scaling of the texture - scale[0] = 1 / VectorNormalize2(ti->vecs[0], vecs[0]); - scale[1] = 1 / VectorNormalize2(ti->vecs[1], vecs[1]); - // - TextureAxisFromPlane(plane, axis[0], axis[1]); - //calculate texture shift done by entity origin - originshift[0] = DotProduct(origin, axis[0]); - originshift[1] = DotProduct(origin, axis[1]); - //the texture shift without origin shift - shift[0] = ti->vecs[0][3] - originshift[0]; - shift[1] = ti->vecs[1][3] - originshift[1]; - // - if (axis[0][0]) sv = 0; - else if (axis[0][1]) sv = 1; - else sv = 2; - if (axis[1][0]) tv = 0; - else if (axis[1][1]) tv = 1; - else tv = 2; - //calculate rotation of texture - if (vecs[0][tv] == 0) ang1 = vecs[0][sv] > 0 ? 90.0 : -90.0; - else ang1 = atan2(vecs[0][sv], vecs[0][tv]) * 180 / Q_PI; - if (ang1 < 0) ang1 += 360; - if (ang1 >= 360) ang1 -= 360; - if (axis[0][tv] == 0) ang2 = axis[0][sv] > 0 ? 90.0 : -90.0; - else ang2 = atan2(axis[0][sv], axis[0][tv]) * 180 / Q_PI; - if (ang2 < 0) ang2 += 360; - if (ang2 >= 360) ang2 -= 360; - rotate = ang2 - ang1; - if (rotate < 0) rotate += 360; - if (rotate >= 360) rotate -= 360; - //write the texture info - if (fprintf(fp, "%s %d %d %d", ti->texture, shift[0], shift[1], rotate) < 0) return false; - if (fabs(scale[0] - ((int) scale[0])) < 0.001) - { - if (fprintf(fp, " %d", (int) scale[0]) < 0) return false; - } //end if - else - { - if (fprintf(fp, " %4f", scale[0]) < 0) return false; - } //end if - if (fabs(scale[1] - ((int) scale[1])) < 0.001) - { - if (fprintf(fp, " %d", (int) scale[1]) < 0) return false; - } //end if - else - { - if (fprintf(fp, " %4f", scale[1]) < 0) return false; - } //end else - //write the extra brush side info - if (loadedmaptype == MAPTYPE_QUAKE2) - { - if (fprintf(fp, " %ld %ld %ld", s->contents, ti->flags, ti->value) < 0) return false; - } //end if - //*/ - } //end else - if (fprintf(fp, "\n") < 0) return false; - } //end if - } //end if - if (fprintf(fp, " }\n") < 0) return false; - c_writtenbrushes++; - return true; -} //end of the function WriteMapBrush -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean WriteOriginBrush(FILE *fp, vec3_t origin) -{ - vec3_t normal; - float dist; - int i, s; - winding_t *w; - - if (fprintf(fp, " {\n") < 0) return false; - // - for (i = 0; i < 3; i++) - { - for (s = -1; s <= 1; s += 2) - { - // - VectorClear(normal); - normal[i] = s; - dist = origin[i] * s + 16; - // - w = BaseWindingForPlane(normal, dist); - //three non-colinear points to define the plane - if (fprintf(fp," ( %5i %5i %5i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]) < 0) return false; - if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]) < 0) return false; - if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false; - //free the winding - FreeWinding(w); - //write origin texture: - // CONTENTS_ORIGIN = 16777216 - // SURF_NODRAW = 128 - if (loadedmaptype == MAPTYPE_SIN) - { - if (fprintf(fp, "generic/misc/origin 0 0 0 1 1") < 0) return false; - } //end if - else if (loadedmaptype == MAPTYPE_HALFLIFE) - { - if (fprintf(fp, "origin 0 0 0 1 1") < 0) return false; - } //end if - else - { - if (fprintf(fp, "e1u1/origin 0 0 0 1 1") < 0) return false; - } //end else - //Quake2 extra brush side info - if (loadedmaptype == MAPTYPE_QUAKE2) - { - //if (fprintf(fp, " 16777216 128 0") < 0) return false; - } //end if - if (fprintf(fp, "\n") < 0) return false; - } //end for - } //end for - if (fprintf(fp, " }\n") < 0) return false; - c_writtenbrushes++; - return true; -} //end of the function WriteOriginBrush -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -mapbrush_t *GetAreaPortalBrush(entity_t *mapent) -{ - int portalnum, bn; - mapbrush_t *brush; - - //the area portal number - portalnum = mapent->areaportalnum; - //find the area portal brush in the world brushes - for (bn = 0; bn < nummapbrushes && portalnum; bn++) - { - brush = &mapbrushes[bn]; - //must be in world entity - if (brush->entitynum == 0) - { - if (brush->contents & CONTENTS_AREAPORTAL) - { - portalnum--; - } //end if - } //end if - } //end for - if (bn < nummapbrushes) - { - return brush; - } //end if - else - { - Log_Print("area portal %d brush not found\n", mapent->areaportalnum); - return NULL; - } //end else -} //end of the function GetAreaPortalBrush -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -qboolean WriteMapFileSafe(FILE *fp) -{ - char key[1024], value[1024]; - int i, bn, entitybrushes; - epair_t *ep; - mapbrush_t *brush; - entity_t *mapent; - //vec3_t vec_origin = {0, 0, 0}; - - // - if (fprintf(fp,"//=====================================================\n" - "//\n" - "// map file created with BSPC "BSPC_VERSION"\n" - "//\n" - "// BSPC is designed to decompile material in which you own the copyright\n" - "// or have obtained permission to decompile from the copyright owner. Unless\n" - "// you own the copyright or have permission to decompile from the copyright\n" - "// owner, you may be violating copyright law and be subject to payment of\n" - "// damages and other remedies. If you are uncertain about your rights, contact\n" - "// your legal advisor.\n" - "//\n") < 0) return false; - if (loadedmaptype == MAPTYPE_SIN) - { - if (fprintf(fp, - "// generic/misc/red is used for unknown textures\n") < 0) return false; - } //end if - if (fprintf(fp,"//\n" - "//=====================================================\n") < 0) return false; - //write out all the entities - for (i = 0; i < num_entities; i++) - { - mapent = &entities[i]; - if (!mapent->epairs) - { - continue; - } //end if - if (fprintf(fp, "{\n") < 0) return false; - // - if (loadedmaptype == MAPTYPE_QUAKE3) - { - if (!stricmp(ValueForKey(mapent, "classname"), "light")) - { - SetKeyValue(mapent, "light", "10000"); - } //end if - } //end if - //write epairs - for (ep = mapent->epairs; ep; ep = ep->next) - { - strcpy(key, ep->key); - StripTrailing (key); - strcpy(value, ep->value); - StripTrailing(value); - // - if (loadedmaptype == MAPTYPE_QUAKE2 || - loadedmaptype == MAPTYPE_SIN) - { - //don't write an origin for BSP models - if (mapent->modelnum >= 0 && !strcmp(key, "origin")) continue; - } //end if - //don't write BSP model numbers - if (mapent->modelnum >= 0 && !strcmp(key, "model") && value[0] == '*') continue; - // - if (fprintf(fp, " \"%s\" \"%s\"\n", key, value) < 0) return false; - } //end for - // - if (ValueForKey(mapent, "origin")) GetVectorForKey(mapent, "origin", mapent->origin); - else mapent->origin[0] = mapent->origin[1] = mapent->origin[2] = 0; - //if this is an area portal entity - if (!strcmp("func_areaportal", ValueForKey(mapent, "classname"))) - { - brush = GetAreaPortalBrush(mapent); - if (!brush) return false; - if (!WriteMapBrush(fp, brush, mapent->origin)) return false; - } //end if - else - { - entitybrushes = false; - //write brushes - for (bn = 0; bn < nummapbrushes; bn++) - { - brush = &mapbrushes[bn]; - //if the brush is part of this entity - if (brush->entitynum == i) - { - //don't write out area portal brushes in the world - if (!((brush->contents & CONTENTS_AREAPORTAL) && brush->entitynum == 0)) - { - /* - if (!strcmp("func_door_rotating", ValueForKey(mapent, "classname"))) - { - AAS_PositionFuncRotatingBrush(mapent, brush); - if (!WriteMapBrush(fp, brush, vec_origin)) return false; - } //end if - else //*/ - { - if (!WriteMapBrush(fp, brush, mapent->origin)) return false; - } //end else - entitybrushes = true; - } //end if - } //end if - } //end for - //if the entity had brushes - if (entitybrushes) - { - //if the entity has an origin set - if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) - { - if (!WriteOriginBrush(fp, mapent->origin)) return false; - } //end if - } //end if - } //end else - if (fprintf(fp, "}\n") < 0) return false; - } //end for - if (fprintf(fp, "//total of %d brushes\n", c_writtenbrushes) < 0) return false; - return true; -} //end of the function WriteMapFileSafe -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void WriteMapFile(char *filename) -{ - FILE *fp; - double start_time; - - c_writtenbrushes = 0; - //the time started - start_time = I_FloatTime(); - // - Log_Print("writing %s\n", filename); - fp = fopen(filename, "wb"); - if (!fp) - { - Log_Print("can't open %s\n", filename); - return; - } //end if - if (!WriteMapFileSafe(fp)) - { - fclose(fp); - Log_Print("error writing map file %s\n", filename); - return; - } //end if - fclose(fp); - //display creation time - Log_Print("written %d brushes\n", c_writtenbrushes); - Log_Print("map file written in %5.0f seconds\n", I_FloatTime() - start_time); -} //end of the function WriteMapFile -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void PrintMapInfo(void) -{ - Log_Print("\n"); - Log_Print("%6i brushes\n", nummapbrushes); - Log_Print("%6i brush sides\n", nummapbrushsides); -// Log_Print("%6i clipbrushes\n", c_clipbrushes); -// Log_Print("%6i total sides\n", nummapbrushsides); -// Log_Print("%6i boxbevels\n", c_boxbevels); -// Log_Print("%6i edgebevels\n", c_edgebevels); -// Log_Print("%6i entities\n", num_entities); -// Log_Print("%6i planes\n", nummapplanes); -// Log_Print("%6i areaportals\n", c_areaportals); -// Log_Print("%6i squatt brushes\n", c_squattbrushes); -// Log_Print("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]); -} //end of the function PrintMapInfo -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -void ResetMapLoading(void) -{ - int i; - epair_t *ep, *nextep; - - Q2_ResetMapLoading(); - Sin_ResetMapLoading(); - - //free all map brush side windings - for (i = 0; i < nummapbrushsides; i++) - { - if (brushsides[i].winding) - { - FreeWinding(brushsides[i].winding); - } //end for - } //end for - - //reset regular stuff - nummapbrushes = 0; - memset(mapbrushes, 0, MAX_MAPFILE_BRUSHES * sizeof(mapbrush_t)); - // - nummapbrushsides = 0; - memset(brushsides, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(side_t)); - memset(side_brushtextures, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(brush_texture_t)); - // - nummapplanes = 0; - memset(mapplanes, 0, MAX_MAPFILE_PLANES * sizeof(plane_t)); - // - memset(planehash, 0, PLANE_HASHES * sizeof(plane_t *)); - // - memset(map_texinfo, 0, MAX_MAPFILE_TEXINFO * sizeof(map_texinfo_t)); - map_numtexinfo = 0; - // - VectorClear(map_mins); - VectorClear(map_maxs); - // - c_boxbevels = 0; - c_edgebevels = 0; - c_areaportals = 0; - c_clipbrushes = 0; - c_writtenbrushes = 0; - //clear the entities - for (i = 0; i < num_entities; i++) - { - for (ep = entities[i].epairs; ep; ep = nextep) - { - nextep = ep->next; - FreeMemory(ep->key); - FreeMemory(ep->value); - FreeMemory(ep); - } //end for - } //end for - num_entities = 0; - memset(entities, 0, MAX_MAP_ENTITIES * sizeof(entity_t)); -} //end of the function ResetMapLoading -//=========================================================================== -// -// Parameter: - -// Returns: - -// Changes Globals: - -//=========================================================================== -#ifndef Q1_BSPVERSION -#define Q1_BSPVERSION 29 -#endif -#ifndef HL_BSPVERSION -#define HL_BSPVERSION 30 -#endif - -#define Q2_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') //IBSP -#define Q2_BSPVERSION 38 - -#define SINGAME_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'R') //RBSP -#define SINGAME_BSPVERSION 1 - -#define SIN_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') //IBSP -#define SIN_BSPVERSION 41 - -typedef struct -{ - int ident; - int version; -} idheader_t; - -int LoadMapFromBSP(struct quakefile_s *qf) -{ - idheader_t idheader; - - if (ReadQuakeFile(qf, &idheader, 0, sizeof(idheader_t)) != sizeof(idheader_t)) - { - return false; - } //end if - - idheader.ident = LittleLong(idheader.ident); - idheader.version = LittleLong(idheader.version); - //Quake3 BSP file - if (idheader.ident == Q3_BSP_IDENT && idheader.version == Q3_BSP_VERSION) - { - ResetMapLoading(); - Q3_LoadMapFromBSP(qf); - Q3_FreeMaxBSP(); - } //end if - //Quake2 BSP file - else if (idheader.ident == Q2_BSPHEADER && idheader.version == Q2_BSPVERSION) - { - ResetMapLoading(); - Q2_AllocMaxBSP(); - Q2_LoadMapFromBSP(qf->filename, qf->offset, qf->length); - Q2_FreeMaxBSP(); - } //endif - //Sin BSP file - else if ((idheader.ident == SIN_BSPHEADER && idheader.version == SIN_BSPVERSION) || - //the dorks gave the same format another ident and verions - (idheader.ident == SINGAME_BSPHEADER && idheader.version == SINGAME_BSPVERSION)) - { - ResetMapLoading(); - Sin_AllocMaxBSP(); - Sin_LoadMapFromBSP(qf->filename, qf->offset, qf->length); - Sin_FreeMaxBSP(); - } //end if - //the Quake1 bsp files don't have a ident only a version - else if (idheader.ident == Q1_BSPVERSION) - { - ResetMapLoading(); - Q1_AllocMaxBSP(); - Q1_LoadMapFromBSP(qf->filename, qf->offset, qf->length); - Q1_FreeMaxBSP(); - } //end if - //Half-Life also only uses a version number - else if (idheader.ident == HL_BSPVERSION) - { - ResetMapLoading(); - HL_AllocMaxBSP(); - HL_LoadMapFromBSP(qf->filename, qf->offset, qf->length); - HL_FreeMaxBSP(); - } //end if - else - { - Error("unknown BSP format %c%c%c%c, version %d\n", - (idheader.ident & 0xFF), - ((idheader.ident >> 8) & 0xFF), - ((idheader.ident >> 16) & 0xFF), - ((idheader.ident >> 24) & 0xFF), idheader.version); - return false; - } //end if - // - return true; -} //end of the function LoadMapFromBSP |