Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

map.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 
00023 #include "qbsp.h"
00024 #include "l_bsp_hl.h"
00025 #include "l_bsp_q1.h"
00026 #include "l_bsp_q2.h"
00027 #include "l_bsp_q3.h"
00028 #include "l_bsp_sin.h"
00029 #include "l_mem.h"
00030 #include "../botlib/aasfile.h"      //aas_bbox_t
00031 #include "aas_store.h"      //AAS_MAX_BBOXES
00032 #include "aas_cfg.h"
00033 
00034 #define Sign(x)     (x < 0 ? 1 : 0)
00035 
00036 int                 nummapbrushes;
00037 mapbrush_t          mapbrushes[MAX_MAPFILE_BRUSHES];
00038 
00039 int                 nummapbrushsides;
00040 side_t              brushsides[MAX_MAPFILE_BRUSHSIDES];
00041 brush_texture_t     side_brushtextures[MAX_MAPFILE_BRUSHSIDES];
00042 
00043 int                 nummapplanes;
00044 plane_t             mapplanes[MAX_MAPFILE_PLANES];
00045 int                 mapplaneusers[MAX_MAPFILE_PLANES];
00046 
00047 #define             PLANE_HASHES    1024
00048 plane_t             *planehash[PLANE_HASHES];
00049 vec3_t              map_mins, map_maxs;
00050 
00051 #ifdef SIN
00052 textureref_t        side_newrefs[MAX_MAPFILE_BRUSHSIDES];
00053 #endif
00054 
00055 map_texinfo_t       map_texinfo[MAX_MAPFILE_TEXINFO];
00056 int                 map_numtexinfo;
00057 int                 loadedmaptype;      //loaded map type
00058 
00059 // undefine to make plane finding use linear sort
00060 #define USE_HASHING
00061 
00062 int c_boxbevels;
00063 int c_edgebevels;
00064 int c_areaportals;
00065 int c_clipbrushes;
00066 int c_squattbrushes;
00067 int c_writtenbrushes;
00068 
00069 /*
00070 =============================================================================
00071 
00072 PLANE FINDING
00073 
00074 =============================================================================
00075 */
00076 
00077 
00078 //===========================================================================
00079 //
00080 // Parameter:               -
00081 // Returns:                 -
00082 // Changes Globals:     -
00083 //===========================================================================
00084 int PlaneSignBits(vec3_t normal)
00085 {
00086     int i, signbits;
00087 
00088     signbits = 0;
00089     for (i = 2; i >= 0; i--)
00090     {
00091         signbits = (signbits << 1) + Sign(normal[i]);
00092     } //end for
00093     return signbits;
00094 } //end of the function PlaneSignBits
00095 //===========================================================================
00096 //
00097 // Parameter:               -
00098 // Returns:                 -
00099 // Changes Globals:     -
00100 //===========================================================================
00101 int PlaneTypeForNormal(vec3_t normal)
00102 {
00103     vec_t   ax, ay, az;
00104     
00105 // NOTE: should these have an epsilon around 1.0?       
00106     if (normal[0] == 1.0 || normal[0] == -1.0)
00107         return PLANE_X;
00108     if (normal[1] == 1.0 || normal[1] == -1.0)
00109         return PLANE_Y;
00110     if (normal[2] == 1.0 || normal[2] == -1.0)
00111         return PLANE_Z;
00112         
00113     ax = fabs(normal[0]);
00114     ay = fabs(normal[1]);
00115     az = fabs(normal[2]);
00116     
00117     if (ax >= ay && ax >= az)
00118         return PLANE_ANYX;
00119     if (ay >= ax && ay >= az)
00120         return PLANE_ANYY;
00121     return PLANE_ANYZ;
00122 } //end of the function PlaneTypeForNormal
00123 //===========================================================================
00124 //
00125 // Parameter:               -
00126 // Returns:                 -
00127 // Changes Globals:     -
00128 //===========================================================================
00129 //ME NOTE: changed from 0.00001
00130 #define NORMAL_EPSILON  0.0001
00131 //ME NOTE: changed from 0.01
00132 #define DIST_EPSILON    0.02
00133 qboolean    PlaneEqual(plane_t *p, vec3_t normal, vec_t dist)
00134 {
00135 #if 1
00136     if (
00137        fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
00138     && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
00139     && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
00140     && fabs(p->dist - dist) < DIST_EPSILON )
00141         return true;
00142 #else
00143     if (p->normal[0] == normal[0]
00144         && p->normal[1] == normal[1]
00145         && p->normal[2] == normal[2]
00146         && p->dist == dist)
00147         return true;
00148 #endif
00149     return false;
00150 } //end of the function PlaneEqual
00151 //===========================================================================
00152 //
00153 // Parameter:               -
00154 // Returns:                 -
00155 // Changes Globals:     -
00156 //===========================================================================
00157 void AddPlaneToHash(plane_t *p)
00158 {
00159     int     hash;
00160 
00161     hash = (int)fabs(p->dist) / 8;
00162     hash &= (PLANE_HASHES-1);
00163 
00164     p->hash_chain = planehash[hash];
00165     planehash[hash] = p;
00166 } //end of the function AddPlaneToHash
00167 //===========================================================================
00168 //
00169 // Parameter:               -
00170 // Returns:                 -
00171 // Changes Globals:     -
00172 //===========================================================================
00173 int CreateNewFloatPlane (vec3_t normal, vec_t dist)
00174 {
00175     plane_t *p, temp;
00176 
00177     if (VectorLength(normal) < 0.5)
00178         Error ("FloatPlane: bad normal");
00179     // create a new plane
00180     if (nummapplanes+2 > MAX_MAPFILE_PLANES)
00181         Error ("MAX_MAPFILE_PLANES");
00182 
00183     p = &mapplanes[nummapplanes];
00184     VectorCopy (normal, p->normal);
00185     p->dist = dist;
00186     p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
00187     p->signbits = PlaneSignBits(p->normal);
00188 
00189     VectorSubtract (vec3_origin, normal, (p+1)->normal);
00190     (p+1)->dist = -dist;
00191     (p+1)->signbits = PlaneSignBits((p+1)->normal);
00192 
00193     nummapplanes += 2;
00194 
00195     // allways put axial planes facing positive first
00196     if (p->type < 3)
00197     {
00198         if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
00199         {
00200             // flip order
00201             temp = *p;
00202             *p = *(p+1);
00203             *(p+1) = temp;
00204 
00205             AddPlaneToHash (p);
00206             AddPlaneToHash (p+1);
00207             return nummapplanes - 1;
00208         }
00209     }
00210 
00211     AddPlaneToHash (p);
00212     AddPlaneToHash (p+1);
00213     return nummapplanes - 2;
00214 } //end of the function CreateNewFloatPlane
00215 //===========================================================================
00216 //
00217 // Parameter:               -
00218 // Returns:                 -
00219 // Changes Globals:     -
00220 //===========================================================================
00221 void SnapVector(vec3_t normal)
00222 {
00223     int     i;
00224 
00225     for (i=0 ; i<3 ; i++)
00226     {
00227         if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
00228         {
00229             VectorClear (normal);
00230             normal[i] = 1;
00231             break;
00232         }
00233         if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
00234         {
00235             VectorClear (normal);
00236             normal[i] = -1;
00237             break;
00238         }
00239     }
00240 } //end of the function SnapVector
00241 //===========================================================================
00242 //
00243 // Parameter:               -
00244 // Returns:                 -
00245 // Changes Globals:     -
00246 //===========================================================================
00247 void SnapPlane(vec3_t normal, vec_t *dist)
00248 {
00249     SnapVector(normal);
00250 
00251     if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
00252         *dist = Q_rint(*dist);
00253 } //end of the function SnapPlane
00254 //===========================================================================
00255 //
00256 // Parameter:               -
00257 // Returns:                 -
00258 // Changes Globals:     -
00259 //===========================================================================
00260 #ifndef USE_HASHING
00261 int FindFloatPlane(vec3_t normal, vec_t dist)
00262 {
00263     int i;
00264     plane_t *p;
00265 
00266     SnapPlane(normal, &dist);
00267     for (i = 0, p = mapplanes; i < nummapplanes; i++, p++)
00268     {
00269         if (PlaneEqual (p, normal, dist))
00270         {
00271             mapplaneusers[i]++;
00272             return i;
00273         } //end if
00274     } //end for
00275     i = CreateNewFloatPlane (normal, dist);
00276     mapplaneusers[i]++;
00277     return i;
00278 } //end of the function FindFloatPlane
00279 #else
00280 int FindFloatPlane (vec3_t normal, vec_t dist)
00281 {
00282     int i;
00283     plane_t *p;
00284     int hash, h;
00285 
00286     SnapPlane (normal, &dist);
00287     hash = (int)fabs(dist) / 8;
00288     hash &= (PLANE_HASHES-1);
00289 
00290     // search the border bins as well
00291     for (i = -1; i <= 1; i++)
00292     {
00293         h = (hash+i)&(PLANE_HASHES-1);
00294         for (p = planehash[h]; p; p = p->hash_chain)
00295         {
00296             if (PlaneEqual(p, normal, dist))
00297             {
00298                 mapplaneusers[p-mapplanes]++;
00299                 return p - mapplanes;
00300             } //end if
00301         } //end for
00302     } //end for
00303     i = CreateNewFloatPlane (normal, dist);
00304     mapplaneusers[i]++;
00305     return i;
00306 } //end of the function FindFloatPlane
00307 #endif
00308 //===========================================================================
00309 //
00310 // Parameter:               -
00311 // Returns:                 -
00312 // Changes Globals:     -
00313 //===========================================================================
00314 int PlaneFromPoints (int *p0, int *p1, int *p2)
00315 {
00316     vec3_t  t1, t2, normal;
00317     vec_t   dist;
00318 
00319     VectorSubtract (p0, p1, t1);
00320     VectorSubtract (p2, p1, t2);
00321     CrossProduct (t1, t2, normal);
00322     VectorNormalize (normal);
00323 
00324     dist = DotProduct (p0, normal);
00325 
00326     return FindFloatPlane (normal, dist);
00327 } //end of the function PlaneFromPoints
00328 //===========================================================================
00329 // Adds any additional planes necessary to allow the brush to be expanded
00330 // against axial bounding boxes
00331 //
00332 // Parameter:               -
00333 // Returns:                 -
00334 // Changes Globals:     -
00335 //===========================================================================
00336 void AddBrushBevels (mapbrush_t *b)
00337 {
00338     int     axis, dir;
00339     int     i, j, k, l, order;
00340     side_t  sidetemp;
00341     brush_texture_t tdtemp;
00342 #ifdef SIN
00343    textureref_t trtemp;
00344 #endif
00345     side_t  *s, *s2;
00346     vec3_t  normal;
00347     float   dist;
00348     winding_t   *w, *w2;
00349     vec3_t  vec, vec2;
00350     float   d;
00351 
00352     //
00353     // add the axial planes
00354     //
00355     order = 0;
00356     for (axis=0 ; axis <3 ; axis++)
00357     {
00358         for (dir=-1 ; dir <= 1 ; dir+=2, order++)
00359         {
00360             // see if the plane is allready present
00361             for (i=0, s=b->original_sides ; i<b->numsides ; i++,s++)
00362             {
00363                 if (mapplanes[s->planenum].normal[axis] == dir)
00364                     break;
00365             }
00366 
00367             if (i == b->numsides)
00368             {   // add a new side
00369                 if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
00370                     Error ("MAX_MAP_BRUSHSIDES");
00371                 nummapbrushsides++;
00372                 b->numsides++;
00373                 VectorClear (normal);
00374                 normal[axis] = dir;
00375                 if (dir == 1)
00376                     dist = b->maxs[axis];
00377                 else
00378                     dist = -b->mins[axis];
00379                 s->planenum = FindFloatPlane (normal, dist);
00380                 s->texinfo = b->original_sides[0].texinfo;
00381 #ifdef SIN
00382                 s->lightinfo = b->original_sides[0].lightinfo;
00383 #endif
00384                 s->contents = b->original_sides[0].contents;
00385                 s->flags |= SFL_BEVEL;
00386                 c_boxbevels++;
00387             }
00388 
00389             // if the plane is not in it canonical order, swap it
00390             if (i != order)
00391             {
00392                 sidetemp = b->original_sides[order];
00393                 b->original_sides[order] = b->original_sides[i];
00394                 b->original_sides[i] = sidetemp;
00395 
00396                 j = b->original_sides - brushsides;
00397                 tdtemp = side_brushtextures[j+order];
00398                 side_brushtextures[j+order] = side_brushtextures[j+i];
00399                 side_brushtextures[j+i] = tdtemp;
00400 
00401 #ifdef SIN
00402                 trtemp = side_newrefs[j+order];
00403                 side_newrefs[j+order] = side_newrefs[j+i];
00404                 side_newrefs[j+i] = trtemp;
00405 #endif
00406             }
00407         }
00408     }
00409 
00410     //
00411     // add the edge bevels
00412     //
00413     if (b->numsides == 6)
00414         return;     // pure axial
00415 
00416     // test the non-axial plane edges
00417     for (i=6 ; i<b->numsides ; i++)
00418     {
00419         s = b->original_sides + i;
00420         w = s->winding;
00421         if (!w)
00422             continue;
00423         for (j=0 ; j<w->numpoints ; j++)
00424         {
00425             k = (j+1)%w->numpoints;
00426             VectorSubtract (w->p[j], w->p[k], vec);
00427             if (VectorNormalize (vec) < 0.5)
00428                 continue;
00429             SnapVector (vec);
00430             for (k=0 ; k<3 ; k++)
00431                 if ( vec[k] == -1 || vec[k] == 1)
00432                     break;  // axial
00433             if (k != 3)
00434                 continue;   // only test non-axial edges
00435 
00436             // try the six possible slanted axials from this edge
00437             for (axis=0 ; axis <3 ; axis++)
00438             {
00439                 for (dir=-1 ; dir <= 1 ; dir+=2)
00440                 {
00441                     // construct a plane
00442                     VectorClear (vec2);
00443                     vec2[axis] = dir;
00444                     CrossProduct (vec, vec2, normal);
00445                     if (VectorNormalize (normal) < 0.5)
00446                         continue;
00447                     dist = DotProduct (w->p[j], normal);
00448 
00449                     // if all the points on all the sides are
00450                     // behind this plane, it is a proper edge bevel
00451                     for (k=0 ; k<b->numsides ; k++)
00452                     {
00453                         // if this plane has allready been used, skip it
00454                         if (PlaneEqual (&mapplanes[b->original_sides[k].planenum]
00455                             , normal, dist) )
00456                             break;
00457 
00458                         w2 = b->original_sides[k].winding;
00459                         if (!w2)
00460                             continue;
00461                         for (l=0 ; l<w2->numpoints ; l++)
00462                         {
00463                             d = DotProduct (w2->p[l], normal) - dist;
00464                             if (d > 0.1)
00465                                 break;  // point in front
00466                         }
00467                         if (l != w2->numpoints)
00468                             break;
00469                     }
00470 
00471                     if (k != b->numsides)
00472                         continue;   // wasn't part of the outer hull
00473                     // add this plane
00474                     if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
00475                         Error ("MAX_MAP_BRUSHSIDES");
00476                     nummapbrushsides++;
00477                     s2 = &b->original_sides[b->numsides];
00478                     s2->planenum = FindFloatPlane (normal, dist);
00479                     s2->texinfo = b->original_sides[0].texinfo;
00480 #ifdef SIN
00481                     s2->lightinfo = b->original_sides[0].lightinfo;
00482 #endif
00483                     s2->contents = b->original_sides[0].contents;
00484                     s2->flags |= SFL_BEVEL;
00485                     c_edgebevels++;
00486                     b->numsides++;
00487                 }
00488             }
00489         }
00490     }
00491 } //end of the function AddBrushBevels
00492 //===========================================================================
00493 // creates windigs for sides and mins / maxs for the brush
00494 //
00495 // Parameter:               -
00496 // Returns:                 -
00497 // Changes Globals:     -
00498 //===========================================================================
00499 qboolean MakeBrushWindings(mapbrush_t *ob)
00500 {
00501     int         i, j;
00502     winding_t   *w;
00503     side_t      *side;
00504     plane_t     *plane;
00505 
00506     ClearBounds (ob->mins, ob->maxs);
00507 
00508     for (i = 0; i < ob->numsides; i++)
00509     {
00510         plane = &mapplanes[ob->original_sides[i].planenum];
00511         w = BaseWindingForPlane(plane->normal, plane->dist);
00512         for (j = 0; j <ob->numsides && w; j++)
00513         {
00514             if (i == j) continue;
00515             if (ob->original_sides[j].flags & SFL_BEVEL) continue;
00516             plane = &mapplanes[ob->original_sides[j].planenum^1];
00517             ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
00518         }
00519 
00520         side = &ob->original_sides[i];
00521         side->winding = w;
00522         if (w)
00523         {
00524             side->flags |= SFL_VISIBLE;
00525             for (j = 0; j < w->numpoints; j++)
00526                 AddPointToBounds (w->p[j], ob->mins, ob->maxs);
00527         }
00528     }
00529 
00530     for (i = 0; i < 3; i++)
00531     {
00532         //IDBUG: all the indexes into the mins and maxs were zero (not using i)
00533         if (ob->mins[i] < -MAX_MAP_BOUNDS || ob->maxs[i] > MAX_MAP_BOUNDS)
00534         {
00535             Log_Print("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum);
00536             ob->numsides = 0; //remove the brush
00537             break;
00538         } //end if
00539         if (ob->mins[i] > MAX_MAP_BOUNDS || ob->maxs[i] < -MAX_MAP_BOUNDS)
00540         {
00541             Log_Print("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum);
00542             ob->numsides = 0; //remove the brush
00543             break;
00544         } //end if
00545     } //end for
00546     return true;
00547 } //end of the function MakeBrushWindings
00548 //===========================================================================
00549 // FIXME: currently doesn't mark all bevels
00550 // NOTE: when one brush bevel is found the remaining sides of the brush
00551 //       are bevels as well (when the brush isn't expanded for AAS :))
00552 //
00553 // Parameter:               -
00554 // Returns:                 -
00555 // Changes Globals:     -
00556 //===========================================================================
00557 void MarkBrushBevels(mapbrush_t *brush)
00558 {
00559     int i;
00560     int we;
00561     side_t *s;
00562 
00563     //check all the sides of the brush
00564     for (i = 0; i < brush->numsides; i++)
00565     {
00566         s = brush->original_sides + i;
00567         //if the side has no winding
00568         if (!s->winding)
00569         {
00570             Log_Write("MarkBrushBevels: brush %d no winding", brush->brushnum);
00571             s->flags |= SFL_BEVEL;
00572         } //end if
00573         //if the winding is tiny
00574         else if (WindingIsTiny(s->winding))
00575         {
00576             s->flags |= SFL_BEVEL;
00577             Log_Write("MarkBrushBevels: brush %d tiny winding", brush->brushnum);
00578         } //end else if
00579         //if the winding has errors
00580         else
00581         {
00582             we = WindingError(s->winding);
00583             if (we == WE_NOTENOUGHPOINTS
00584                     || we == WE_SMALLAREA
00585                     || we == WE_POINTBOGUSRANGE
00586 //                  || we == WE_NONCONVEX
00587                     )
00588             {
00589                 Log_Write("MarkBrushBevels: brush %d %s", brush->brushnum, WindingErrorString());
00590                 s->flags |= SFL_BEVEL;
00591             } //end else if
00592         } //end else
00593         if (s->flags & SFL_BEVEL)
00594         {
00595             s->flags &= ~SFL_VISIBLE;
00596             //if the side has a valid plane
00597             if (s->planenum > 0 && s->planenum < nummapplanes)
00598             {
00599                 //if it is an axial plane
00600                 if (mapplanes[s->planenum].type < 3) c_boxbevels++;
00601                 else c_edgebevels++;
00602             } //end if
00603         } //end if
00604     } //end for
00605 } //end of the function MarkBrushBevels
00606 //===========================================================================
00607 // returns true if the map brush already exists
00608 //
00609 // Parameter:               -
00610 // Returns:                 -
00611 // Changes Globals:     -
00612 //===========================================================================
00613 int BrushExists(mapbrush_t *brush)
00614 {
00615     int i, s1, s2;
00616     side_t *side1, *side2;
00617     mapbrush_t *brush1, *brush2;
00618 
00619     for (i = 0; i < nummapbrushes; i++)
00620     {
00621         brush1 = brush;
00622         brush2 = &mapbrushes[i];
00623         //compare the brushes
00624         if (brush1->entitynum != brush2->entitynum) continue;
00625         //if (brush1->contents != brush2->contents) continue;
00626         if (brush1->numsides != brush2->numsides) continue;
00627         for (s1 = 0; s1 < brush1->numsides; s1++)
00628         {
00629             side1 = brush1->original_sides + s1;
00630             //
00631             for (s2 = 0; s2 < brush2->numsides; s2++)
00632             {
00633                 side2 = brush2->original_sides + s2;
00634                 //
00635                 if ((side1->planenum & ~1) == (side2->planenum & ~1)
00636 //                      && side1->texinfo == side2->texinfo
00637 //                      && side1->contents == side2->contents
00638 //                      && side1->surf == side2->surf
00639                     ) break;
00640             } //end if
00641             if (s2 >= brush2->numsides) break;
00642         } //end for
00643         if (s1 >= brush1->numsides) return true;
00644     } //end for
00645     return false;
00646 } //end of the function BrushExists
00647 //===========================================================================
00648 //
00649 // Parameter:               -
00650 // Returns:                 -
00651 // Changes Globals:     -
00652 //===========================================================================
00653 qboolean WriteMapBrush(FILE *fp, mapbrush_t *brush, vec3_t origin)
00654 {
00655     int sn, rotate, shift[2], sv, tv, planenum, p1, i, j;
00656     float scale[2], originshift[2], ang1, ang2, newdist;
00657     vec3_t vecs[2], axis[2];
00658     map_texinfo_t *ti;
00659     winding_t *w;
00660     side_t *s;
00661     plane_t *plane;
00662 
00663     if (noliquids)
00664     {
00665         if (brush->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))
00666         {
00667             return true;
00668         } //end if
00669     } //end if
00670     //if the brush has no contents
00671     if (!brush->contents) return true;
00672     //print the leading {
00673     if (fprintf(fp, " { //brush %d\n", brush->brushnum) < 0) return false;
00674     //write brush sides
00675     for (sn = 0; sn < brush->numsides; sn++)
00676     {
00677         s = brush->original_sides + sn;
00678         //don't write out bevels
00679         if (!(s->flags & SFL_BEVEL))
00680         {
00681             //if the entity has an origin set
00682             if (origin[0] || origin[1] || origin[2])
00683             {
00684                 newdist = mapplanes[s->planenum].dist +
00685                     DotProduct(mapplanes[s->planenum].normal, origin);
00686                 planenum = FindFloatPlane(mapplanes[s->planenum].normal, newdist);
00687             } //end if
00688             else
00689             {
00690                 planenum = s->planenum;
00691             } //end else
00692             //always take the first plane, then flip the points if necesary
00693             plane = &mapplanes[planenum & ~1];
00694             w = BaseWindingForPlane(plane->normal, plane->dist);
00695             //
00696             for (i = 0; i < 3; i++)
00697             {
00698                 for (j = 0; j < 3; j++)
00699                 {
00700                     if (fabs(w->p[i][j]) < 0.2) w->p[i][j] = 0;
00701                     else if (fabs((int)w->p[i][j] - w->p[i][j]) < 0.3) w->p[i][j] = (int) w->p[i][j];
00702                     //w->p[i][j] = (int) (w->p[i][j] + 0.2);
00703                 } //end for
00704             } //end for
00705             //three non-colinear points to define the plane
00706             if (planenum & 1) p1 = 1;
00707             else p1 = 0;
00708             if (fprintf(fp,"  ( %5i %5i %5i ) ", (int)w->p[p1][0], (int)w->p[p1][1], (int)w->p[p1][2]) < 0) return false;
00709             if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[!p1][0], (int)w->p[!p1][1], (int)w->p[!p1][2]) < 0) return false;
00710             if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false;
00711             //free the winding
00712             FreeWinding(w);
00713             //
00714             if (s->texinfo == TEXINFO_NODE)
00715             {
00716                 if (brush->contents & CONTENTS_PLAYERCLIP)
00717                 {
00718                     //player clip
00719                     if (loadedmaptype == MAPTYPE_SIN)
00720                     {
00721                         if (fprintf(fp, "generic/misc/clip 0 0 0 1 1") < 0) return false;
00722                     } //end if
00723                     else if (loadedmaptype == MAPTYPE_QUAKE2)
00724                     {   //FIXME: don't always use e1u1
00725                         if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false;
00726                     } //end else
00727                     else if (loadedmaptype == MAPTYPE_QUAKE3)
00728                     {
00729                         if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false;
00730                     } //end else if
00731                     else
00732                     {
00733                         if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
00734                     } //end else
00735                 } //end if
00736                 else if (brush->contents == CONTENTS_MONSTERCLIP)
00737                 {
00738                     //monster clip
00739                     if (loadedmaptype == MAPTYPE_SIN)
00740                     {
00741                         if (fprintf(fp, "generic/misc/monster 0 0 0 1 1") < 0) return false;
00742                     } //end if
00743                     else if (loadedmaptype == MAPTYPE_QUAKE2)
00744                     {
00745                         if (fprintf(fp, "e1u1/clip_mon 0 0 0 1 1") < 0) return false;
00746                     } //end else
00747                     else
00748                     {
00749                         if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
00750                     } //end else
00751                 } //end else
00752                 else
00753                 {
00754                     if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
00755                     Log_Write("brush->contents = %d\n", brush->contents);
00756                 } //end else
00757             } //end if
00758             else if (loadedmaptype == MAPTYPE_SIN && s->texinfo == 0)
00759             {
00760                 if (brush->contents & CONTENTS_DUMMYFENCE)
00761                 {
00762                     if (fprintf(fp, "generic/misc/fence 0 0 0 1 1") < 0) return false;
00763                 } //end if
00764                 else if (brush->contents & CONTENTS_MIST)
00765                 {
00766                     if (fprintf(fp, "generic/misc/volumetric_base 0 0 0 1 1") < 0) return false;
00767                 } //end if
00768                 else //unknown so far
00769                 {
00770                     if (fprintf(fp, "generic/misc/red 0 0 0 1 1") < 0) return false;
00771                 } //end else
00772             } //end if
00773             else if (loadedmaptype == MAPTYPE_QUAKE3)
00774             {
00775                 //always use the same texture
00776                 if (fprintf(fp, "e2u3/floor1_2 0 0 0 1 1 1 0 0") < 0) return false;
00777             } //end else if
00778             else
00779             {
00780                 //*
00781                 ti = &map_texinfo[s->texinfo];
00782                 //the scaling of the texture
00783                 scale[0] = 1 / VectorNormalize2(ti->vecs[0], vecs[0]);
00784                 scale[1] = 1 / VectorNormalize2(ti->vecs[1], vecs[1]);
00785                 //
00786                 TextureAxisFromPlane(plane, axis[0], axis[1]);
00787                 //calculate texture shift done by entity origin
00788                 originshift[0] = DotProduct(origin, axis[0]);
00789                 originshift[1] = DotProduct(origin, axis[1]);
00790                 //the texture shift without origin shift
00791                 shift[0] = ti->vecs[0][3] - originshift[0];
00792                 shift[1] = ti->vecs[1][3] - originshift[1];
00793                 //
00794                 if (axis[0][0]) sv = 0;
00795                 else if (axis[0][1]) sv = 1;
00796                 else sv = 2;
00797                 if (axis[1][0]) tv = 0;
00798                 else if (axis[1][1]) tv = 1;
00799                 else tv = 2;
00800                 //calculate rotation of texture
00801                 if (vecs[0][tv] == 0) ang1 = vecs[0][sv] > 0 ? 90.0 : -90.0;
00802                 else ang1 = atan2(vecs[0][sv], vecs[0][tv]) * 180 / Q_PI;
00803                 if (ang1 < 0) ang1 += 360;
00804                 if (ang1 >= 360) ang1 -= 360;
00805                 if (axis[0][tv] == 0) ang2 = axis[0][sv] > 0 ? 90.0 : -90.0;
00806                 else ang2 = atan2(axis[0][sv], axis[0][tv]) * 180 / Q_PI;
00807                 if (ang2 < 0) ang2 += 360;
00808                 if (ang2 >= 360) ang2 -= 360;
00809                 rotate = ang2 - ang1;
00810                 if (rotate < 0) rotate += 360;
00811                 if (rotate >= 360) rotate -= 360;
00812                 //write the texture info
00813                 if (fprintf(fp, "%s %d %d %d", ti->texture, shift[0], shift[1], rotate) < 0) return false;
00814                 if (fabs(scale[0] - ((int) scale[0])) < 0.001)
00815                 {
00816                     if (fprintf(fp, " %d", (int) scale[0]) < 0) return false;
00817                 } //end if
00818                 else
00819                 {
00820                     if (fprintf(fp, " %4f", scale[0]) < 0) return false;
00821                 } //end if
00822                 if (fabs(scale[1] - ((int) scale[1])) < 0.001)
00823                 {
00824                     if (fprintf(fp, " %d", (int) scale[1]) < 0) return false;
00825                 } //end if
00826                 else
00827                 {
00828                     if (fprintf(fp, " %4f", scale[1]) < 0) return false;
00829                 } //end else
00830                 //write the extra brush side info
00831                 if (loadedmaptype == MAPTYPE_QUAKE2)
00832                 {
00833                     if (fprintf(fp, " %ld %ld %ld", s->contents, ti->flags, ti->value) < 0) return false;
00834                 } //end if
00835                 //*/
00836             } //end else
00837             if (fprintf(fp, "\n") < 0) return false;
00838         } //end if
00839     } //end if
00840     if (fprintf(fp, " }\n") < 0) return false;
00841     c_writtenbrushes++;
00842     return true;
00843 } //end of the function WriteMapBrush
00844 //===========================================================================
00845 //
00846 // Parameter:               -
00847 // Returns:                 -
00848 // Changes Globals:     -
00849 //===========================================================================
00850 qboolean WriteOriginBrush(FILE *fp, vec3_t origin)
00851 {
00852     vec3_t normal;
00853     float dist;
00854     int i, s;
00855     winding_t *w;
00856 
00857     if (fprintf(fp, " {\n") < 0) return false;
00858     //
00859     for (i = 0; i < 3; i++)
00860     {
00861         for (s = -1; s <= 1; s += 2)
00862         {
00863             //
00864             VectorClear(normal);
00865             normal[i] = s;
00866             dist = origin[i] * s + 16;
00867             //
00868             w = BaseWindingForPlane(normal, dist);
00869             //three non-colinear points to define the plane
00870             if (fprintf(fp,"  ( %5i %5i %5i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]) < 0) return false;
00871             if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]) < 0) return false;
00872             if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false;
00873             //free the winding
00874             FreeWinding(w);
00875             //write origin texture:
00876             // CONTENTS_ORIGIN = 16777216
00877             // SURF_NODRAW = 128
00878             if (loadedmaptype == MAPTYPE_SIN)
00879             {
00880                 if (fprintf(fp, "generic/misc/origin 0 0 0 1 1") < 0) return false;
00881             } //end if
00882             else if (loadedmaptype == MAPTYPE_HALFLIFE)
00883             {
00884                 if (fprintf(fp, "origin 0 0 0 1 1") < 0) return false;
00885             } //end if
00886             else
00887             {
00888                 if (fprintf(fp, "e1u1/origin 0 0 0 1 1") < 0) return false;
00889             } //end else
00890             //Quake2 extra brush side info
00891             if (loadedmaptype == MAPTYPE_QUAKE2)
00892             {
00893                 //if (fprintf(fp, " 16777216 128 0") < 0) return false;
00894             } //end if
00895             if (fprintf(fp, "\n") < 0) return false;
00896         } //end for
00897     } //end for
00898     if (fprintf(fp, " }\n") < 0) return false;
00899     c_writtenbrushes++;
00900     return true;
00901 } //end of the function WriteOriginBrush
00902 //===========================================================================
00903 //
00904 // Parameter:               -
00905 // Returns:                 -
00906 // Changes Globals:     -
00907 //===========================================================================
00908 mapbrush_t *GetAreaPortalBrush(entity_t *mapent)
00909 {
00910     int portalnum, bn;
00911     mapbrush_t *brush;
00912 
00913     //the area portal number
00914     portalnum = mapent->areaportalnum;
00915     //find the area portal brush in the world brushes
00916     for (bn = 0; bn < nummapbrushes && portalnum; bn++)
00917     {
00918         brush = &mapbrushes[bn];
00919         //must be in world entity
00920         if (brush->entitynum == 0)
00921         {
00922             if (brush->contents & CONTENTS_AREAPORTAL)
00923             {
00924                 portalnum--;
00925             } //end if
00926         } //end if
00927     } //end for
00928     if (bn < nummapbrushes)
00929     {
00930         return brush;
00931     } //end if
00932     else
00933     {
00934         Log_Print("area portal %d brush not found\n", mapent->areaportalnum);
00935         return NULL;
00936     } //end else
00937 } //end of the function GetAreaPortalBrush
00938 //===========================================================================
00939 //
00940 // Parameter:               -
00941 // Returns:                 -
00942 // Changes Globals:     -
00943 //===========================================================================
00944 qboolean WriteMapFileSafe(FILE *fp)
00945 {
00946     char key[1024], value[1024];
00947     int i, bn, entitybrushes;
00948     epair_t *ep;
00949     mapbrush_t *brush;
00950     entity_t *mapent;
00951     //vec3_t vec_origin = {0, 0, 0};
00952 
00953     //
00954     if (fprintf(fp,"//=====================================================\n"
00955             "//\n"
00956             "// map file created with BSPC "BSPC_VERSION"\n"
00957             "//\n"
00958             "// BSPC is designed to decompile material in which you own the copyright\n"
00959             "// or have obtained permission to decompile from the copyright owner. Unless\n"
00960             "// you own the copyright or have permission to decompile from the copyright\n"
00961             "// owner, you may be violating copyright law and be subject to payment of\n"
00962             "// damages and other remedies. If you are uncertain about your rights, contact\n"
00963             "// your legal advisor.\n"
00964             "//\n") < 0) return false;
00965     if (loadedmaptype == MAPTYPE_SIN)
00966     {
00967         if (fprintf(fp,
00968                         "// generic/misc/red is used for unknown textures\n") < 0) return false;
00969     } //end if
00970     if (fprintf(fp,"//\n"
00971                         "//=====================================================\n") < 0) return false;
00972     //write out all the entities
00973     for (i = 0; i < num_entities; i++)
00974     {
00975         mapent = &entities[i];
00976         if (!mapent->epairs)
00977         {
00978             continue;
00979         } //end if
00980         if (fprintf(fp, "{\n") < 0) return false;
00981         //
00982         if (loadedmaptype == MAPTYPE_QUAKE3)
00983         {
00984             if (!stricmp(ValueForKey(mapent, "classname"), "light"))
00985             {
00986                 SetKeyValue(mapent, "light", "10000");
00987             } //end if
00988         } //end if
00989         //write epairs
00990         for (ep = mapent->epairs; ep; ep = ep->next)
00991         {
00992             strcpy(key, ep->key);
00993             StripTrailing (key);
00994             strcpy(value, ep->value);
00995             StripTrailing(value);
00996             //
00997             if (loadedmaptype == MAPTYPE_QUAKE2 ||
00998                     loadedmaptype == MAPTYPE_SIN)
00999             {
01000                 //don't write an origin for BSP models
01001                 if (mapent->modelnum >= 0 && !strcmp(key, "origin")) continue;
01002             } //end if
01003             //don't write BSP model numbers
01004             if (mapent->modelnum >= 0 && !strcmp(key, "model") && value[0] == '*') continue;
01005             //
01006             if (fprintf(fp, " \"%s\" \"%s\"\n", key, value) < 0) return false;
01007         } //end for
01008         //
01009         if (ValueForKey(mapent, "origin")) GetVectorForKey(mapent, "origin", mapent->origin);
01010         else mapent->origin[0] = mapent->origin[1] = mapent->origin[2] = 0;
01011         //if this is an area portal entity
01012         if (!strcmp("func_areaportal", ValueForKey(mapent, "classname")))
01013         {
01014             brush = GetAreaPortalBrush(mapent);
01015             if (!brush) return false;
01016             if (!WriteMapBrush(fp, brush, mapent->origin)) return false;
01017         } //end if
01018         else
01019         {
01020             entitybrushes = false;
01021             //write brushes
01022             for (bn = 0; bn < nummapbrushes; bn++)
01023             {
01024                 brush = &mapbrushes[bn];
01025                 //if the brush is part of this entity
01026                 if (brush->entitynum == i)
01027                 {
01028                     //don't write out area portal brushes in the world
01029                     if (!((brush->contents & CONTENTS_AREAPORTAL) && brush->entitynum == 0))
01030                     {
01031                         /*
01032                         if (!strcmp("func_door_rotating", ValueForKey(mapent, "classname")))
01033                         {
01034                             AAS_PositionFuncRotatingBrush(mapent, brush);
01035                             if (!WriteMapBrush(fp, brush, vec_origin)) return false;
01036                         } //end if
01037                         else //*/
01038                         {
01039                             if (!WriteMapBrush(fp, brush, mapent->origin)) return false;
01040                         } //end else
01041                         entitybrushes = true;
01042                     } //end if
01043                 } //end if
01044             } //end for
01045             //if the entity had brushes
01046             if (entitybrushes)
01047             {
01048                 //if the entity has an origin set
01049                 if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
01050                 {
01051                     if (!WriteOriginBrush(fp, mapent->origin)) return false;
01052                 } //end if
01053             } //end if
01054         } //end else
01055         if (fprintf(fp, "}\n") < 0) return false;
01056     } //end for
01057     if (fprintf(fp, "//total of %d brushes\n", c_writtenbrushes) < 0) return false;
01058     return true;
01059 } //end of the function WriteMapFileSafe
01060 //===========================================================================
01061 //
01062 // Parameter:               -
01063 // Returns:                 -
01064 // Changes Globals:     -
01065 //===========================================================================
01066 void WriteMapFile(char *filename)
01067 {
01068     FILE *fp;
01069     double start_time;
01070 
01071     c_writtenbrushes = 0;
01072     //the time started
01073     start_time = I_FloatTime();
01074     //
01075     Log_Print("writing %s\n", filename);
01076     fp = fopen(filename, "wb");
01077     if (!fp)
01078     {
01079         Log_Print("can't open %s\n", filename);
01080         return;
01081     } //end if
01082     if (!WriteMapFileSafe(fp))
01083     {
01084         fclose(fp);
01085         Log_Print("error writing map file %s\n", filename);
01086         return;
01087     } //end if
01088     fclose(fp);
01089     //display creation time
01090     Log_Print("written %d brushes\n", c_writtenbrushes);
01091     Log_Print("map file written in %5.0f seconds\n", I_FloatTime() - start_time);
01092 } //end of the function WriteMapFile
01093 //===========================================================================
01094 //
01095 // Parameter:               -
01096 // Returns:                 -
01097 // Changes Globals:     -
01098 //===========================================================================
01099 void PrintMapInfo(void)
01100 {
01101     Log_Print("\n");
01102     Log_Print("%6i brushes\n", nummapbrushes);
01103     Log_Print("%6i brush sides\n", nummapbrushsides);
01104 //  Log_Print("%6i clipbrushes\n", c_clipbrushes);
01105 //  Log_Print("%6i total sides\n", nummapbrushsides);
01106 //  Log_Print("%6i boxbevels\n", c_boxbevels);
01107 //  Log_Print("%6i edgebevels\n", c_edgebevels);
01108 //  Log_Print("%6i entities\n", num_entities);
01109 //  Log_Print("%6i planes\n", nummapplanes);
01110 //  Log_Print("%6i areaportals\n", c_areaportals);
01111 //  Log_Print("%6i squatt brushes\n", c_squattbrushes);
01112 //  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],
01113 //      map_maxs[0],map_maxs[1],map_maxs[2]);
01114 } //end of the function PrintMapInfo
01115 //===========================================================================
01116 //
01117 // Parameter:               -
01118 // Returns:                 -
01119 // Changes Globals:     -
01120 //===========================================================================
01121 void ResetMapLoading(void)
01122 {
01123     int i;
01124     epair_t *ep, *nextep;
01125 
01126     Q2_ResetMapLoading();
01127     Sin_ResetMapLoading();
01128 
01129     //free all map brush side windings
01130     for (i = 0; i < nummapbrushsides; i++)
01131     {
01132         if (brushsides[i].winding)
01133         {
01134             FreeWinding(brushsides[i].winding);
01135         } //end for
01136     } //end for
01137 
01138     //reset regular stuff
01139     nummapbrushes = 0;
01140     memset(mapbrushes, 0, MAX_MAPFILE_BRUSHES * sizeof(mapbrush_t));
01141     //
01142     nummapbrushsides = 0;
01143     memset(brushsides, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(side_t));
01144     memset(side_brushtextures, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(brush_texture_t));
01145     //
01146     nummapplanes = 0;
01147     memset(mapplanes, 0, MAX_MAPFILE_PLANES * sizeof(plane_t));
01148     //
01149