12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268 |
- /*
- ===========================================================================
- 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
- ===========================================================================
- */
- #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
|