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 // map.c
00023 
00024 #include "qbsp.h"
00025 
00026 
00027 int         entitySourceBrushes;        // to track editor brush numbers
00028 
00029 int         numMapPatches;
00030 
00031 // undefine to make plane finding use linear sort
00032 #define USE_HASHING
00033 #define PLANE_HASHES    1024
00034 plane_t     *planehash[PLANE_HASHES];
00035 
00036 plane_t     mapplanes[MAX_MAP_PLANES];
00037 int         nummapplanes;
00038 
00039 // as brushes and patches are read in, the shaders are stored out in order
00040 // here, so -onlytextures can just copy them out over the existing shaders
00041 // in the drawSurfaces
00042 char        mapIndexedShaders[MAX_MAP_BRUSHSIDES][MAX_QPATH];
00043 int         numMapIndexedShaders;
00044 
00045 vec3_t      map_mins, map_maxs;
00046 
00047 entity_t    *mapent;
00048 
00049 
00050 
00051 int     c_boxbevels;
00052 int     c_edgebevels;
00053 
00054 int     c_areaportals;
00055 int     c_detail;
00056 int     c_structural;
00057 
00058 // brushes are parsed into a temporary array of sides,
00059 // which will have the bevels added and duplicates
00060 // removed before the final brush is allocated
00061 bspbrush_t  *buildBrush;
00062 
00063 
00064 void TestExpandBrushes (void);
00065 void SetTerrainTextures( void );
00066 void ParseTerrain( void );
00067 
00068 
00069 /*
00070 =============================================================================
00071 
00072 PLANE FINDING
00073 
00074 =============================================================================
00075 */
00076 
00077 
00078 /*
00079 ================
00080 PlaneEqual
00081 ================
00082 */
00083 #define NORMAL_EPSILON  0.00001
00084 #define DIST_EPSILON    0.01
00085 qboolean    PlaneEqual (plane_t *p, vec3_t normal, vec_t dist)
00086 {
00087 #if 1
00088     if (
00089        fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
00090     && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
00091     && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
00092     && fabs(p->dist - dist) < DIST_EPSILON )
00093         return qtrue;
00094 #else
00095     if (p->normal[0] == normal[0]
00096         && p->normal[1] == normal[1]
00097         && p->normal[2] == normal[2]
00098         && p->dist == dist)
00099         return qtrue;
00100 #endif
00101     return qfalse;
00102 }
00103 
00104 /*
00105 ================
00106 AddPlaneToHash
00107 ================
00108 */
00109 void    AddPlaneToHash (plane_t *p)
00110 {
00111     int     hash;
00112 
00113     hash = (int)fabs(p->dist) / 8;
00114     hash &= (PLANE_HASHES-1);
00115 
00116     p->hash_chain = planehash[hash];
00117     planehash[hash] = p;
00118 }
00119 
00120 /*
00121 ================
00122 CreateNewFloatPlane
00123 ================
00124 */
00125 int CreateNewFloatPlane (vec3_t normal, vec_t dist)
00126 {
00127     plane_t *p, temp;
00128 
00129     if (VectorLength(normal) < 0.5)
00130     {
00131         _printf( "FloatPlane: bad normal\n");
00132         return -1;
00133     }
00134 
00135     // create a new plane
00136     if (nummapplanes+2 > MAX_MAP_PLANES)
00137         Error ("MAX_MAP_PLANES");
00138 
00139     p = &mapplanes[nummapplanes];
00140     VectorCopy (normal, p->normal);
00141     p->dist = dist;
00142     p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
00143 
00144     VectorSubtract (vec3_origin, normal, (p+1)->normal);
00145     (p+1)->dist = -dist;
00146 
00147     nummapplanes += 2;
00148 
00149     // allways put axial planes facing positive first
00150     if (p->type < 3)
00151     {
00152         if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
00153         {
00154             // flip order
00155             temp = *p;
00156             *p = *(p+1);
00157             *(p+1) = temp;
00158 
00159             AddPlaneToHash (p);
00160             AddPlaneToHash (p+1);
00161             return nummapplanes - 1;
00162         }
00163     }
00164 
00165     AddPlaneToHash (p);
00166     AddPlaneToHash (p+1);
00167     return nummapplanes - 2;
00168 }
00169 
00170 /*
00171 ==============
00172 SnapVector
00173 ==============
00174 */
00175 void    SnapVector (vec3_t normal)
00176 {
00177     int     i;
00178 
00179     for (i=0 ; i<3 ; i++)
00180     {
00181         if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
00182         {
00183             VectorClear (normal);
00184             normal[i] = 1;
00185             break;
00186         }
00187         if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
00188         {
00189             VectorClear (normal);
00190             normal[i] = -1;
00191             break;
00192         }
00193     }
00194 }
00195 
00196 /*
00197 ==============
00198 SnapPlane
00199 ==============
00200 */
00201 void    SnapPlane (vec3_t normal, vec_t *dist)
00202 {
00203     SnapVector (normal);
00204 
00205     if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
00206         *dist = Q_rint(*dist);
00207 }
00208 
00209 /*
00210 =============
00211 FindFloatPlane
00212 
00213 =============
00214 */
00215 #ifndef USE_HASHING
00216 int     FindFloatPlane (vec3_t normal, vec_t dist)
00217 {
00218     int     i;
00219     plane_t *p;
00220 
00221     SnapPlane (normal, &dist);
00222     for (i=0, p=mapplanes ; i<nummapplanes ; i++, p++)
00223     {
00224         if (PlaneEqual (p, normal, dist))
00225             return i;
00226     }
00227 
00228     return CreateNewFloatPlane (normal, dist);
00229 }
00230 #else
00231 int     FindFloatPlane (vec3_t normal, vec_t dist)
00232 {
00233     int     i;
00234     plane_t *p;
00235     int     hash, h;
00236 
00237     SnapPlane (normal, &dist);
00238     hash = (int)fabs(dist) / 8;
00239     hash &= (PLANE_HASHES-1);
00240 
00241     // search the border bins as well
00242     for (i=-1 ; i<=1 ; i++)
00243     {
00244         h = (hash+i)&(PLANE_HASHES-1);
00245         for (p = planehash[h] ; p ; p=p->hash_chain)
00246         {
00247             if (PlaneEqual (p, normal, dist))
00248                 return p-mapplanes;
00249         }
00250     }
00251 
00252     return CreateNewFloatPlane (normal, dist);
00253 }
00254 #endif
00255 
00256 /*
00257 ================
00258 MapPlaneFromPoints
00259 ================
00260 */
00261 int MapPlaneFromPoints (vec3_t p0, vec3_t p1, vec3_t p2) {
00262     vec3_t  t1, t2, normal;
00263     vec_t   dist;
00264 
00265     VectorSubtract (p0, p1, t1);
00266     VectorSubtract (p2, p1, t2);
00267     CrossProduct (t1, t2, normal);
00268     VectorNormalize (normal, normal);
00269 
00270     dist = DotProduct (p0, normal);
00271 
00272     return FindFloatPlane (normal, dist);
00273 }
00274 
00275 
00276 //====================================================================
00277 
00278 /*
00279 ===========
00280 SetBrushContents
00281 
00282 The contents on all sides of a brush should be the same
00283 Sets contentsShader, contents, opaque, and detail
00284 ===========
00285 */
00286 void SetBrushContents( bspbrush_t *b ) {
00287     int         contents, c2;
00288     side_t      *s;
00289     int         i;
00290     qboolean    mixed;
00291     int         allFlags;
00292 
00293     s = &b->sides[0];
00294     contents = s->contents;
00295     b->contentShader = s->shaderInfo;
00296     mixed = qfalse;
00297 
00298     allFlags = 0;
00299 
00300     for ( i=1 ; i<b->numsides ; i++, s++ ) {
00301         s = &b->sides[i];
00302 
00303         if ( !s->shaderInfo ) {
00304             continue;
00305         }
00306 
00307         c2 = s->contents;
00308         if (c2 != contents) {
00309             mixed = qtrue;
00310         }
00311 
00312         allFlags |= s->surfaceFlags;
00313     }
00314 
00315     if ( mixed ) {
00316         qprintf ("Entity %i, Brush %i: mixed face contents\n"
00317             , b->entitynum, b->brushnum);
00318     }
00319 
00320     if ( ( contents & CONTENTS_DETAIL ) && ( contents & CONTENTS_STRUCTURAL ) ) {
00321         _printf ("Entity %i, Brush %i: mixed CONTENTS_DETAIL and CONTENTS_STRUCTURAL\n"
00322             , num_entities-1, entitySourceBrushes );
00323         contents &= ~CONTENTS_DETAIL;
00324     }
00325 
00326     // the fulldetail flag will cause detail brushes to be
00327     // treated like normal brushes
00328     if ( fulldetail ) {
00329         contents &= ~CONTENTS_DETAIL;
00330     }
00331 
00332     // all translucent brushes that aren't specirically made structural will
00333     // be detail
00334     if ( ( contents & CONTENTS_TRANSLUCENT ) && !( contents & CONTENTS_STRUCTURAL ) ) {
00335         contents |= CONTENTS_DETAIL;
00336     }
00337 
00338     if ( contents & CONTENTS_DETAIL ) {
00339         c_detail++;
00340         b->detail = qtrue;
00341     } else {
00342         c_structural++;
00343         b->detail = qfalse;
00344     }
00345 
00346     if ( contents & CONTENTS_TRANSLUCENT ) {
00347         b->opaque = qfalse;
00348     } else {
00349         b->opaque = qtrue;
00350     }
00351 
00352     if ( contents & CONTENTS_AREAPORTAL ) {
00353         c_areaportals++;
00354     }
00355 
00356     b->contents = contents;
00357 }
00358 
00359 
00360 //============================================================================
00361 
00362 /*
00363 =================
00364 AddBrushBevels
00365 
00366 Adds any additional planes necessary to allow the brush being
00367 built to be expanded against axial bounding boxes
00368 =================
00369 */
00370 void AddBrushBevels( void ) {
00371     int     axis, dir;
00372     int     i, order;
00373     side_t  sidetemp;
00374     side_t  *s;
00375     vec3_t  normal;
00376     float   dist;
00377 
00378     //
00379     // add the axial planes
00380     //
00381     order = 0;
00382     for (axis=0 ; axis <3 ; axis++)
00383     {
00384         for (dir=-1 ; dir <= 1 ; dir+=2, order++)
00385         {
00386             // see if the plane is allready present
00387             for ( i=0, s=buildBrush->sides ; i < buildBrush->numsides ; i++,s++ ) {
00388                 if (mapplanes[s->planenum].normal[axis] == dir)
00389                     break;
00390             }
00391 
00392             if (i == buildBrush->numsides )
00393             {   // add a new side
00394                 if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
00395                     Error( "MAX_BUILD_SIDES" );
00396                 }
00397                 memset( s, 0, sizeof( *s ) );
00398                 buildBrush->numsides++;
00399                 VectorClear (normal);
00400                 normal[axis] = dir;
00401                 if (dir == 1)
00402                     dist = buildBrush->maxs[axis];
00403                 else
00404                     dist = -buildBrush->mins[axis];
00405                 s->planenum = FindFloatPlane (normal, dist);
00406                 s->contents = buildBrush->sides[0].contents;
00407                 s->bevel = qtrue;
00408                 c_boxbevels++;
00409             }
00410 
00411             // if the plane is not in it canonical order, swap it
00412             if (i != order)
00413             {
00414                 sidetemp = buildBrush->sides[order];
00415                 buildBrush->sides[order] = buildBrush->sides[i];
00416                 buildBrush->sides[i] = sidetemp;
00417             }
00418         }
00419     }
00420 
00421     //
00422     // add the edge bevels
00423     //
00424     if ( buildBrush->numsides == 6 ) {
00425         return;     // pure axial
00426   } else {
00427       int           j, k, l;
00428       float     d;
00429       winding_t *w, *w2;
00430       side_t        *s2;
00431       vec3_t        vec, vec2;
00432 
00433       // test the non-axial plane edges
00434       // this code tends to cause some problems...
00435       for (i=6 ; i<buildBrush->numsides ; i++)
00436       {
00437           s = buildBrush->sides + i;
00438           w = s->winding;
00439           if (!w)
00440               continue;
00441           for (j=0 ; j<w->numpoints ; j++)
00442           {
00443               k = (j+1)%w->numpoints;
00444               VectorSubtract (w->p[j], w->p[k], vec);
00445               if (VectorNormalize (vec, vec) < 0.5)
00446                   continue;
00447               SnapVector (vec);
00448               for (k=0 ; k<3 ; k++)
00449                   if ( vec[k] == -1 || vec[k] == 1)
00450                       break;    // axial
00451               if (k != 3)
00452                   continue; // only test non-axial edges
00453 
00454               // try the six possible slanted axials from this edge
00455               for (axis=0 ; axis <3 ; axis++)
00456               {
00457                   for (dir=-1 ; dir <= 1 ; dir+=2)
00458                   {
00459                       // construct a plane
00460                       VectorClear (vec2);
00461                       vec2[axis] = dir;
00462                       CrossProduct (vec, vec2, normal);
00463                       if (VectorNormalize (normal, normal) < 0.5)
00464                           continue;
00465                       dist = DotProduct (w->p[j], normal);
00466 
00467                       // if all the points on all the sides are
00468                       // behind this plane, it is a proper edge bevel
00469                       for (k=0 ; k < buildBrush->numsides ; k++)
00470                       {
00471                           // if this plane has allready been used, skip it
00472                           if (PlaneEqual (&mapplanes[buildBrush->sides[k].planenum]
00473                               , normal, dist) )
00474                               break;
00475 
00476                           w2 = buildBrush->sides[k].winding;
00477                           if (!w2)
00478                               continue;
00479                           for (l=0 ; l<w2->numpoints ; l++)
00480                           {
00481                               d = DotProduct (w2->p[l], normal) - dist;
00482                               if (d > 0.1)
00483                                   break;    // point in front
00484                           }
00485                           if (l != w2->numpoints)
00486                               break;
00487                       }
00488 
00489                       if (k != buildBrush->numsides)
00490                           continue; // wasn't part of the outer hull
00491                       // add this plane
00492                       if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
00493                           Error( "MAX_BUILD_SIDES" );
00494                       }
00495 
00496                       s2 = &buildBrush->sides[buildBrush->numsides];
00497                       buildBrush->numsides++;
00498                       memset( s2, 0, sizeof( *s2 ) );
00499 
00500                       s2->planenum = FindFloatPlane (normal, dist);
00501                       s2->contents = buildBrush->sides[0].contents;
00502                       s2->bevel = qtrue;
00503                       c_edgebevels++;
00504                   }
00505               }
00506           }
00507       }
00508   }
00509 }
00510 
00511 /*
00512 ===============
00513 AddBackSides
00514 
00515 fog volumes need to have inside faces created
00516 ===============
00517 */
00518 void AddBackSides( void ) {
00519 /*
00520     bspbrush_t  *b;
00521     int         i, originalSides;
00522     side_t      *s;
00523     side_t      *newSide;
00524 
00525     b = buildBrush;
00526     originalSides = b->numsides;
00527     for ( i = 0 ; i < originalSides ; i++ ) {
00528         s = &b->sides[i];
00529         if ( !s->shaderInfo ) {
00530             continue;
00531         }
00532         if ( !(s->shaderInfo->contents & CONTENTS_FOG) ) {
00533             continue;
00534         }
00535 
00536         // duplicate the up-facing side
00537         if ( mapplanes[ s->planenum ].normal[2] == 1 ) {
00538             newSide = &b->sides[ b->numsides ];
00539             b->numsides++;
00540 
00541             *newSide = *s;
00542             newSide->backSide = qtrue;
00543             newSide->planenum = s->planenum ^ 1;    // opposite side
00544         }
00545     }
00546 */
00547 }
00548 
00549 /*
00550 ===============
00551 FinishBrush
00552 
00553 Produces a final brush based on the buildBrush->sides array
00554 and links it to the current entity
00555 ===============
00556 */
00557 bspbrush_t *FinishBrush( void ) {
00558     bspbrush_t  *b;
00559 
00560     // liquids may need to have extra sides created for back sides
00561     AddBackSides();
00562 
00563     // create windings for sides and bounds for brush
00564     if ( !CreateBrushWindings( buildBrush ) ) {
00565         // don't keep this brush
00566         return NULL;
00567     }
00568 
00569     // brushes that will not be visible at all are forced to be detail
00570     if ( buildBrush->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) )
00571     {
00572         buildBrush->detail = qtrue;
00573         c_detail++;
00574     }
00575 
00576     //
00577     // origin brushes are removed, but they set
00578     // the rotation origin for the rest of the brushes
00579     // in the entity.  After the entire entity is parsed,
00580     // the planenums and texinfos will be adjusted for
00581     // the origin brush
00582     //
00583     if ( buildBrush->contents & CONTENTS_ORIGIN )
00584     {
00585         char    string[32];
00586         vec3_t  origin;
00587 
00588         if (num_entities == 1) {
00589             _printf ("Entity %i, Brush %i: origin brushes not allowed in world\n"
00590                 ,  num_entities - 1, entitySourceBrushes);
00591             return NULL;
00592         }
00593 
00594         VectorAdd (buildBrush->mins, buildBrush->maxs, origin);
00595         VectorScale (origin, 0.5, origin);
00596 
00597         sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
00598         SetKeyValue (&entities[num_entities - 1], "origin", string);
00599 
00600         VectorCopy (origin, entities[num_entities - 1].origin);
00601 
00602         // don't keep this brush
00603         return NULL;
00604     }
00605 
00606     if ( buildBrush->contents & CONTENTS_AREAPORTAL ) {
00607         if (num_entities != 1) {
00608             _printf ("Entity %i, Brush %i: areaportals only allowed in world\n"
00609                 ,  num_entities - 1, entitySourceBrushes);
00610             return NULL;
00611         }
00612     }
00613 
00614     AddBrushBevels ();
00615 
00616     // keep it
00617     b = CopyBrush( buildBrush );
00618 
00619     b->entitynum = num_entities-1;
00620     b->brushnum = entitySourceBrushes;
00621 
00622     b->original = b;
00623 
00624     b->next = mapent->brushes;
00625     mapent->brushes = b;
00626 
00627     return b;
00628 }
00629 
00630 //======================================================================
00631 
00632 
00633 /*
00634 ==================
00635 textureAxisFromPlane
00636 ==================
00637 */
00638 vec3_t  baseaxis[18] =
00639 {
00640 {0,0,1}, {1,0,0}, {0,-1,0},         // floor
00641 {0,0,-1}, {1,0,0}, {0,-1,0},        // ceiling
00642 {1,0,0}, {0,1,0}, {0,0,-1},         // west wall
00643 {-1,0,0}, {0,1,0}, {0,0,-1},        // east wall
00644 {0,1,0}, {1,0,0}, {0,0,-1},         // south wall
00645 {0,-1,0}, {1,0,0}, {0,0,-1}         // north wall
00646 };
00647 
00648 void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
00649 {
00650     int     bestaxis;
00651     vec_t   dot,best;
00652     int     i;
00653     
00654     best = 0;
00655     bestaxis = 0;
00656     
00657     for (i=0 ; i<6 ; i++)
00658     {
00659         dot = DotProduct (pln->normal, baseaxis[i*3]);
00660         if (dot > best)
00661         {
00662             best = dot;
00663             bestaxis = i;
00664         }
00665     }
00666     
00667     VectorCopy (baseaxis[bestaxis*3+1], xv);
00668     VectorCopy (baseaxis[bestaxis*3+2], yv);
00669 }
00670 
00671 
00672 
00673 /*
00674 =================
00675 QuakeTextureVecs
00676 
00677 Creates world-to-texture mapping vecs for crappy quake plane arrangements
00678 =================
00679 */
00680 void QuakeTextureVecs(  plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2],
00681                       vec_t mappingVecs[2][4] ) {
00682  
00683     vec3_t  vecs[2];
00684     int     sv, tv;
00685     vec_t   ang, sinv, cosv;
00686     vec_t   ns, nt;
00687     int     i, j;
00688 
00689     TextureAxisFromPlane(plane, vecs[0], vecs[1]);
00690 
00691     if (!scale[0])
00692         scale[0] = 1;
00693     if (!scale[1])
00694         scale[1] = 1;
00695 
00696     // rotate axis
00697     if (rotate == 0)
00698         { sinv = 0 ; cosv = 1; }
00699     else if (rotate == 90)
00700         { sinv = 1 ; cosv = 0; }
00701     else if (rotate == 180)
00702         { sinv = 0 ; cosv = -1; }
00703     else if (rotate == 270)
00704         { sinv = -1 ; cosv = 0; }
00705     else
00706     {   
00707         ang = rotate / 180 * Q_PI;
00708         sinv = sin(ang);
00709         cosv = cos(ang);
00710     }
00711 
00712     if (vecs[0][0])
00713         sv = 0;
00714     else if (vecs[0][1])
00715         sv = 1;
00716     else
00717         sv = 2;
00718                 
00719     if (vecs[1][0])
00720         tv = 0;
00721     else if (vecs[1][1])
00722         tv = 1;
00723     else
00724         tv = 2;
00725                     
00726     for (i=0 ; i<2 ; i++) {
00727         ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
00728         nt = sinv * vecs[i][sv] +  cosv * vecs[i][tv];
00729         vecs[i][sv] = ns;
00730         vecs[i][tv] = nt;
00731     }
00732 
00733     for (i=0 ; i<2 ; i++)
00734         for (j=0 ; j<3 ; j++)
00735             mappingVecs[i][j] = vecs[i][j] / scale[i];
00736 
00737     mappingVecs[0][3] = shift[0];
00738     mappingVecs[1][3] = shift[1];
00739 }
00740 
00741 //======================================================================
00742 
00743 /*
00744 =================
00745 ParseRawBrush
00746 
00747 Just parses the sides into buildBrush->sides[], nothing else.
00748 no validation, back plane removal, etc.
00749 
00750 Timo - 08/26/99
00751 added brush epairs parsing ( ignoring actually )
00752 Timo - 08/04/99
00753 added exclusive brush primitive parsing
00754 Timo - 08/08/99
00755 support for old brush format back in
00756 NOTE : it would be "cleaner" to have seperate functions to parse between old and new brushes
00757 =================
00758 */
00759 void    ParseRawBrush( ) {
00760     side_t      *side;
00761     vec3_t      planepts[3];
00762     int         planenum;
00763     shaderInfo_t    *si;
00764     // old brushes
00765     vec_t       shift[2];
00766     vec_t       rotate;
00767     vec_t       scale[2];
00768     char        name[MAX_QPATH];
00769     char        shader[MAX_QPATH];
00770     int         flags;
00771 
00772     buildBrush->numsides = 0;
00773     buildBrush->detail = qfalse;
00774 
00775     if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
00776         MatchToken( "{" );
00777 
00778     do
00779     {
00780         if (!GetToken (qtrue))
00781             break;
00782         if (!strcmp (token, "}") )
00783             break;
00784         //Timo : brush primitive : here we may have to jump over brush epairs ( only used in editor )
00785         if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
00786         {
00787             do
00788             {
00789                 if (strcmp (token, "(") )
00790                     GetToken( qfalse );
00791                 else
00792                     break;
00793                 GetToken( qtrue );
00794             } while (1);
00795         }
00796         UnGetToken();
00797 
00798         if ( buildBrush->numsides == MAX_BUILD_SIDES ) {
00799             Error( "MAX_BUILD_SIDES" );
00800         }
00801 
00802         side = &buildBrush->sides[ buildBrush->numsides ];
00803         memset( side, 0, sizeof( *side ) );
00804         buildBrush->numsides++;
00805 
00806         // read the three point plane definition
00807         Parse1DMatrix( 3, planepts[0] );
00808         Parse1DMatrix( 3, planepts[1] );
00809         Parse1DMatrix( 3, planepts[2] );
00810 
00811         if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
00812             // read the texture matrix
00813             Parse2DMatrix( 2, 3, (float *)side->texMat );
00814 
00815         // read the texturedef
00816         GetToken (qfalse);
00817         strcpy (name, token);
00818 
00819         // save the shader name for retexturing
00820         if ( numMapIndexedShaders == MAX_MAP_BRUSHSIDES ) {
00821             Error( "MAX_MAP_BRUSHSIDES" );
00822         }
00823         strcpy( mapIndexedShaders[numMapIndexedShaders], name );
00824         numMapIndexedShaders++;
00825 
00826         if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
00827         {
00828             GetToken (qfalse);
00829             shift[0] = atoi(token);
00830             GetToken (qfalse);
00831             shift[1] = atoi(token);
00832             GetToken (qfalse);
00833             rotate = atoi(token);   
00834             GetToken (qfalse);
00835             scale[0] = atof(token);
00836             GetToken (qfalse);
00837             scale[1] = atof(token);
00838         }
00839 
00840         // find default flags and values
00841         sprintf( shader, "textures/%s", name );
00842         si = ShaderInfoForShader( shader );
00843         side->shaderInfo = si;
00844         side->surfaceFlags = si->surfaceFlags;
00845         side->value = si->value;
00846         side->contents = si->contents;
00847 
00848         // allow override of default flags and values
00849         // in Q3, the only thing you can override is DETAIL
00850         if (TokenAvailable())
00851         {
00852             GetToken (qfalse);
00853 //          side->contents = atoi(token);
00854             flags = atoi(token);
00855             if ( flags & CONTENTS_DETAIL ) {
00856                 side->contents |= CONTENTS_DETAIL;
00857             }
00858 
00859             GetToken (qfalse);
00860 //          td.flags = atoi(token);
00861 
00862             GetToken (qfalse);
00863 //          td.value = atoi(token);
00864         }
00865 
00866 
00867         // find the plane number
00868         planenum = MapPlaneFromPoints (planepts[0], planepts[1], planepts[2]);
00869         side->planenum = planenum;
00870 
00871         if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
00872             // get the texture mapping for this texturedef / plane combination
00873             QuakeTextureVecs( &mapplanes[planenum], shift, rotate, scale, side->vecs );
00874 
00875     } while (1);
00876 
00877     if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
00878     {
00879         UnGetToken();
00880         MatchToken( "}" );
00881         MatchToken( "}" );
00882     }
00883 }
00884 
00885 /*
00886 =================
00887 RemoveDuplicateBrushPlanes
00888 
00889 Returns false if the brush has a mirrored set of planes,
00890 meaning it encloses no volume.
00891 Also removes planes without any normal
00892 =================
00893 */
00894 qboolean RemoveDuplicateBrushPlanes( bspbrush_t * b ) {
00895     int         i, j, k;
00896     side_t      *sides;
00897 
00898     sides = b->sides;
00899 
00900     for ( i = 1 ; i < b->numsides ; i++ ) {
00901 
00902         // check for a degenerate plane
00903         if ( sides[i].planenum == -1) {
00904             _printf ("Entity %i, Brush %i: degenerate plane\n"
00905                 , b->entitynum, b->brushnum);
00906             // remove it
00907             for ( k = i + 1 ; k < b->numsides ; k++ ) {
00908                 sides[k-1] = sides[k];
00909             }
00910             b->numsides--;
00911             i--;
00912             continue;
00913         }
00914 
00915         // check for duplication and mirroring
00916         for ( j = 0 ; j < i ; j++ ) {
00917             if ( sides[i].planenum == sides[j].planenum ) {
00918                 _printf ("Entity %i, Brush %i: duplicate plane\n"
00919                     , b->entitynum, b->brushnum);
00920                 // remove the second duplicate
00921                 for ( k = i + 1 ; k < b->numsides ; k++ ) {
00922                     sides[k-1] = sides[k];
00923                 }
00924                 b->numsides--;
00925                 i--;
00926                 break;
00927             }
00928 
00929             if ( sides[i].planenum == (sides[j].planenum ^ 1) ) {
00930                 // mirror plane, brush is invalid
00931                 _printf ("Entity %i, Brush %i: mirrored plane\n"
00932                     , b->entitynum, b->brushnum);
00933                 return qfalse;
00934             }
00935         }
00936     }
00937     return qtrue;
00938 }
00939 
00940 
00941 /*
00942 =================
00943 ParseBrush
00944 
00945   qboolean parameter to true -> parse new brush primitive format ( else use old format )
00946 =================
00947 */
00948 void ParseBrush (void) {
00949     bspbrush_t  *b;
00950 
00951     ParseRawBrush();
00952 
00953     buildBrush->portalareas[0] = -1;
00954     buildBrush->portalareas[1] = -1;
00955     buildBrush->entitynum = num_entities-1;
00956     buildBrush->brushnum = entitySourceBrushes;
00957 
00958     // if there are mirrored planes, the entire brush is invalid
00959     if ( !RemoveDuplicateBrushPlanes( buildBrush ) ) {
00960         return;
00961     }
00962 
00963     // get the content for the entire brush
00964     SetBrushContents( buildBrush );
00965 
00966     // allow detail brushes to be removed 
00967     if (nodetail && (buildBrush->contents & CONTENTS_DETAIL) ) {
00968         FreeBrush( buildBrush );
00969         return;
00970     }
00971 
00972     // allow water brushes to be removed
00973     if (nowater && (buildBrush->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) ) {
00974         FreeBrush( buildBrush );
00975         return;
00976     }
00977 
00978     b = FinishBrush( );
00979     if ( !b ) {
00980         return;
00981     }
00982 }
00983 
00984 
00985 /*
00986 ================
00987 MoveBrushesToWorld
00988 
00989 Takes all of the brushes from the current entity and
00990 adds them to the world's brush list.
00991 
00992 Used by func_group
00993 ================
00994 */
00995 void MoveBrushesToWorld (entity_t *mapent) {
00996     bspbrush_t  *b, *next;
00997     parseMesh_t *pm;
00998 
00999     // move brushes
01000     for ( b = mapent->brushes ; b ; b = next ) {
01001         next = b->next;
01002 
01003         b->next = entities[0].brushes;
01004         entities[0].brushes = b;
01005     }
01006     mapent->brushes = NULL;
01007 
01008     // move patches
01009     if ( mapent->patches ) {
01010 
01011         for ( pm = mapent->patches ; pm->next ; pm = pm->next ) {
01012         }
01013 
01014         pm->next = entities[0].patches;
01015         entities[0].patches = mapent->patches;
01016 
01017         mapent->patches = NULL;
01018     }
01019 }
01020 
01021 
01022 /*
01023 ================
01024 AdjustBrushesForOrigin
01025 ================
01026 */
01027 void AdjustBrushesForOrigin( entity_t *ent ) {
01028     bspbrush_t  *b;
01029     int         i;
01030     side_t      *s;
01031     vec_t       newdist;
01032     parseMesh_t *p;
01033 
01034     for ( b = ent->brushes ; b ; b = b->next ) {
01035         for (i=0 ; i<b->numsides ; i++) {
01036             s = &b->sides[i];
01037             newdist = mapplanes[s->planenum].dist -
01038                 DotProduct (mapplanes[s->planenum].normal, ent->origin);
01039             s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist);
01040         }
01041         CreateBrushWindings(b);
01042     }
01043 
01044     for ( p = ent->patches ; p ; p = p->next ) {
01045         for ( i = 0 ; i < p->mesh.width*p->mesh.height ; i++ ) {
01046             VectorSubtract( p->mesh.verts[i].xyz, ent->origin, p->mesh.verts[i].xyz );
01047         }
01048     }
01049 
01050 }
01051 
01052 /*
01053 ================
01054 ParseMapEntity
01055 ================
01056 */
01057 qboolean    ParseMapEntity (void) {
01058     epair_t     *e;
01059 
01060     if (!GetToken (qtrue))
01061         return qfalse;
01062 
01063     if (strcmp (token, "{") )
01064     {
01065         Error ("ParseEntity: { not found, found %s on line %d - last entity was at: <%4.2f, %4.2f, %4.2f>...", token, scriptline, entities[num_entities].origin[0], entities[num_entities].origin[1], entities[num_entities].origin[2]);
01066     }
01067     
01068     if (num_entities == MAX_MAP_ENTITIES)
01069         Error ("num_entities == MAX_MAP_ENTITIES");
01070 
01071     entitySourceBrushes = 0;
01072 
01073     mapent = &entities[num_entities];
01074     num_entities++;
01075     memset (mapent, 0, sizeof(*mapent));
01076 
01077     do
01078     {
01079         if (!GetToken (qtrue))
01080             Error ("ParseEntity: EOF without closing brace");
01081         if (!strcmp (token, "}") )
01082             break;
01083 
01084         if (!strcmp (token, "{") ) {
01085             // parse a brush or patch
01086             if (!GetToken (qtrue))
01087                 break;
01088             if ( !strcmp( token, "patchDef2" ) ) {
01089                 numMapPatches++;
01090                 ParsePatch();
01091             } else if ( !strcmp( token, "terrainDef" ) ) {
01092                 ParseTerrain();
01093             } else if ( !strcmp( token, "brushDef" ) ) {
01094                 if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
01095                     Error("old brush format not allowed in new brush format map");
01096                 g_bBrushPrimit=BPRIMIT_NEWBRUSHES;
01097                 // parse brush primitive
01098                 ParseBrush();
01099             }
01100             else
01101             {
01102                 if (g_bBrushPrimit==BPRIMIT_NEWBRUSHES)
01103                     Error("new brush format not allowed in old brush format map");
01104                 g_bBrushPrimit=BPRIMIT_OLDBRUSHES;
01105                 // parse old brush format
01106                 UnGetToken();
01107                 ParseBrush();
01108             }
01109             entitySourceBrushes++;
01110         }
01111         else
01112         {
01113             // parse a key / value pair
01114             e = ParseEpair ();
01115             e->next = mapent->epairs;
01116             mapent->epairs = e;
01117         }
01118     } while (1);
01119 
01120     GetVectorForKey (mapent, "origin", mapent->origin);
01121 
01122     //
01123     // if there was an origin brush, offset all of the planes and texinfo
01124     // for all the brushes in the entity
01125     if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) {
01126         AdjustBrushesForOrigin( mapent );
01127     }
01128 
01129   // group_info entities are just for editor grouping
01130   // ignored
01131   // FIXME: leak!
01132   if (!strcmp("group_info", ValueForKey (mapent, "classname")))
01133   {
01134     num_entities--;
01135     return qtrue;
01136   }
01137 
01138     // group entities are just for editor convenience
01139     // toss all brushes into the world entity
01140     if (!strcmp ("func_group", ValueForKey (mapent, "classname")))
01141     {
01142         if ( !strcmp ("1", ValueForKey (mapent, "terrain"))) {
01143             SetTerrainTextures();
01144         }
01145         MoveBrushesToWorld (mapent);
01146         num_entities--;
01147         return qtrue;
01148     }
01149 
01150     return qtrue;
01151 }
01152 
01153 //===================================================================
01154 
01155 
01156 /*
01157 ================
01158 LoadMapFile
01159 ================
01160 */
01161 void LoadMapFile (char *filename) {     
01162     bspbrush_t  *b;
01163 
01164     qprintf ("--- LoadMapFile ---\n");
01165     _printf ("Loading map file %s\n", filename);
01166 
01167     LoadScriptFile (filename);
01168 
01169     num_entities = 0;
01170     numMapDrawSurfs = 0;
01171     c_detail = 0;
01172 
01173     g_bBrushPrimit = BPRIMIT_UNDEFINED;
01174 
01175     // allocate a very large temporary brush for building
01176     // the brushes as they are loaded
01177     buildBrush = AllocBrush( MAX_BUILD_SIDES );
01178 
01179     while (ParseMapEntity ())
01180     {
01181     }
01182 
01183     ClearBounds (map_mins, map_maxs);
01184     for ( b = entities[0].brushes ; b ; b=b->next ) {
01185         AddPointToBounds( b->mins, map_mins, map_maxs );
01186         AddPointToBounds( b->maxs, map_mins, map_maxs );
01187     }
01188 
01189     qprintf ("%5i total world brushes\n", CountBrushList( entities[0].brushes ) );
01190     qprintf ("%5i detail brushes\n", c_detail );
01191     qprintf ("%5i patches\n", numMapPatches);
01192     qprintf ("%5i boxbevels\n", c_boxbevels);
01193     qprintf ("%5i edgebevels\n", c_edgebevels);
01194     qprintf ("%5i entities\n", num_entities);
01195     qprintf ("%5i planes\n", nummapplanes);
01196     qprintf ("%5i areaportals\n", c_areaportals);
01197     qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
01198         map_maxs[0],map_maxs[1],map_maxs[2]);
01199 
01200     if ( fakemap ) {
01201         WriteBspBrushMap ("fakemap.map", entities[0].brushes );
01202     }
01203 
01204     if ( testExpand ) {
01205         TestExpandBrushes ();
01206     }
01207 }
01208 
01209 
01210 //====================================================================
01211 
01212 
01213 /*
01214 ================
01215 TestExpandBrushes
01216 
01217 Expands all the brush planes and saves a new map out to
01218 allow visual inspection of the clipping bevels
01219 ================
01220 */
01221 void TestExpandBrushes( void ) {
01222     side_t  *s;
01223     int     i, j;
01224     bspbrush_t  *brush, *list, *copy;
01225     vec_t   dist;
01226     plane_t     *plane;
01227 
01228     list = NULL;
01229 
01230     for ( brush = entities[0].brushes ; brush ; brush = brush->next ) {
01231         copy = CopyBrush( brush );
01232         copy->next = list;
01233         list = copy;
01234 
01235         // expand all the planes
01236         for ( i=0 ; i<brush->numsides ; i++ ) {
01237             s = brush->sides + i;
01238             plane = &mapplanes[s->planenum];
01239             dist = plane->dist;
01240             for (j=0 ; j<3 ; j++) {
01241                 dist += fabs( 16 * plane->normal[j] );
01242             }
01243             s->planenum = FindFloatPlane( plane->normal, dist );
01244         }
01245 
01246     }
01247 
01248     WriteBspBrushMap ( "expanded.map", entities[0].brushes );
01249 
01250     Error ("can't proceed after expanding brushes");
01251 }

Generated on Thu Aug 25 12:37:18 2005 for Quake III Arena by  doxygen 1.3.9.1