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

map_hl.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 "aas_map.h"            //AAS_CreateMapBrushes
00026 
00027 int hl_numbrushes;
00028 int hl_numclipbrushes;
00029 
00030 //#define HL_PRINT
00031 #define HLCONTENTS
00032 
00033 //===========================================================================
00034 //
00035 // Parameter:               -
00036 // Returns:                 -
00037 // Changes Globals:     -
00038 //===========================================================================
00039 int HL_TextureContents(char *name)
00040 {
00041     if (!Q_strncasecmp (name, "sky",3))
00042         return CONTENTS_SOLID;
00043 
00044     if (!Q_strncasecmp(name+1,"!lava",5))
00045         return CONTENTS_LAVA;
00046 
00047     if (!Q_strncasecmp(name+1,"!slime",6))
00048         return CONTENTS_SLIME;
00049 
00050     /*
00051     if (!Q_strncasecmp (name, "!cur_90",7))
00052         return CONTENTS_CURRENT_90;
00053     if (!Q_strncasecmp (name, "!cur_0",6))
00054         return CONTENTS_CURRENT_0;
00055     if (!Q_strncasecmp (name, "!cur_270",8))
00056         return CONTENTS_CURRENT_270;
00057     if (!Q_strncasecmp (name, "!cur_180",8))
00058         return CONTENTS_CURRENT_180;
00059     if (!Q_strncasecmp (name, "!cur_up",7))
00060         return CONTENTS_CURRENT_UP;
00061     if (!Q_strncasecmp (name, "!cur_dwn",8))
00062         return CONTENTS_CURRENT_DOWN;
00063     //*/
00064     if (name[0] == '!')
00065         return CONTENTS_WATER;
00066     /*
00067     if (!Q_strncasecmp (name, "origin",6))
00068         return CONTENTS_ORIGIN;
00069     if (!Q_strncasecmp (name, "clip",4))
00070         return CONTENTS_CLIP;
00071     if( !Q_strncasecmp( name, "translucent", 11 ) )
00072         return CONTENTS_TRANSLUCENT;
00073     if( name[0] == '@' )
00074         return CONTENTS_TRANSLUCENT;
00075     //*/
00076 
00077     return CONTENTS_SOLID;
00078 } //end of the function HL_TextureContents
00079 //===========================================================================
00080 // Generates two new brushes, leaving the original
00081 // unchanged
00082 //
00083 // modified for Half-Life because there are quite a lot of tiny node leaves
00084 // in the Half-Life bsps
00085 //
00086 // Parameter:               -
00087 // Returns:                 -
00088 // Changes Globals:     -
00089 //===========================================================================
00090 void HL_SplitBrush(bspbrush_t *brush, int planenum, int nodenum,
00091                          bspbrush_t **front, bspbrush_t **back)
00092 {
00093     bspbrush_t *b[2];
00094     int i, j;
00095     winding_t *w, *cw[2], *midwinding;
00096     plane_t *plane, *plane2;
00097     side_t *s, *cs;
00098     float d, d_front, d_back;
00099 
00100     *front = *back = NULL;
00101     plane = &mapplanes[planenum];
00102 
00103     // check all points
00104     d_front = d_back = 0;
00105     for (i=0 ; i<brush->numsides ; i++)
00106     {
00107         w = brush->sides[i].winding;
00108         if (!w)
00109             continue;
00110         for (j=0 ; j<w->numpoints ; j++)
00111         {
00112             d = DotProduct (w->p[j], plane->normal) - plane->dist;
00113             if (d > 0 && d > d_front)
00114                 d_front = d;
00115             if (d < 0 && d < d_back)
00116                 d_back = d;
00117         } //end for
00118     } //end for
00119 
00120     if (d_front < 0.1) // PLANESIDE_EPSILON)
00121     {   // only on back
00122         *back = CopyBrush (brush);
00123         Log_Print("HL_SplitBrush: only on back\n");
00124         return;
00125     } //end if
00126     if (d_back > -0.1) // PLANESIDE_EPSILON)
00127     {   // only on front
00128         *front = CopyBrush (brush);
00129         Log_Print("HL_SplitBrush: only on front\n");
00130         return;
00131     } //end if
00132 
00133     // create a new winding from the split plane
00134 
00135     w = BaseWindingForPlane (plane->normal, plane->dist);
00136     for (i = 0; i < brush->numsides && w; i++)
00137     {
00138         plane2 = &mapplanes[brush->sides[i].planenum ^ 1];
00139         ChopWindingInPlace(&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON);
00140     } //end for
00141 
00142     if (!w || WindingIsTiny(w))
00143     {   // the brush isn't really split
00144         int     side;
00145 
00146         Log_Print("HL_SplitBrush: no split winding\n");
00147         side = BrushMostlyOnSide (brush, plane);
00148         if (side == PSIDE_FRONT)
00149             *front = CopyBrush (brush);
00150         if (side == PSIDE_BACK)
00151             *back = CopyBrush (brush);
00152         return;
00153     }
00154 
00155     if (WindingIsHuge(w))
00156     {
00157         Log_Print("HL_SplitBrush: WARNING huge split winding\n");
00158     } //end of
00159 
00160     midwinding = w;
00161 
00162     // split it for real
00163 
00164     for (i = 0; i < 2; i++)
00165     {
00166         b[i] = AllocBrush (brush->numsides+1);
00167         b[i]->original = brush->original;
00168     } //end for
00169 
00170     // split all the current windings
00171 
00172     for (i=0 ; i<brush->numsides ; i++)
00173     {
00174         s = &brush->sides[i];
00175         w = s->winding;
00176         if (!w)
00177             continue;
00178         ClipWindingEpsilon (w, plane->normal, plane->dist,
00179             0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]);
00180         for (j=0 ; j<2 ; j++)
00181         {
00182             if (!cw[j])
00183                 continue;
00184 #if 0
00185             if (WindingIsTiny (cw[j]))
00186             {
00187                 FreeWinding (cw[j]);
00188                 continue;
00189             }
00190 #endif
00191             cs = &b[j]->sides[b[j]->numsides];
00192             b[j]->numsides++;
00193             *cs = *s;
00194 //          cs->planenum = s->planenum;
00195 //          cs->texinfo = s->texinfo;
00196 //          cs->visible = s->visible;
00197 //          cs->original = s->original;
00198             cs->winding = cw[j];
00199             cs->flags &= ~SFL_TESTED;
00200         } //end for
00201     } //end for
00202 
00203 
00204     // see if we have valid polygons on both sides
00205 
00206     for (i=0 ; i<2 ; i++)
00207     {
00208         BoundBrush (b[i]);
00209         for (j=0 ; j<3 ; j++)
00210         {
00211             if (b[i]->mins[j] < -4096 || b[i]->maxs[j] > 4096)
00212             {
00213                 Log_Print("HL_SplitBrush: bogus brush after clip\n");
00214                 break;
00215             } //end if
00216         } //end for
00217 
00218         if (b[i]->numsides < 3 || j < 3)
00219         {
00220             FreeBrush (b[i]);
00221             b[i] = NULL;
00222             Log_Print("HL_SplitBrush: numsides < 3\n");
00223         } //end if
00224     } //end for
00225 
00226     if ( !(b[0] && b[1]) )
00227     {
00228         if (!b[0] && !b[1])
00229             Log_Print("HL_SplitBrush: split removed brush\n");
00230         else
00231             Log_Print("HL_SplitBrush: split not on both sides\n");
00232         if (b[0])
00233         {
00234             FreeBrush (b[0]);
00235             *front = CopyBrush (brush);
00236         } //end if
00237         if (b[1])
00238         {
00239             FreeBrush (b[1]);
00240             *back = CopyBrush (brush);
00241         } //end if
00242         return;
00243     } //end if
00244 
00245     // add the midwinding to both sides
00246     for (i = 0; i < 2; i++)
00247     {
00248         cs = &b[i]->sides[b[i]->numsides];
00249         b[i]->numsides++;
00250 
00251         cs->planenum = planenum^i^1;
00252         cs->texinfo = 0;
00253         //store the node number in the surf to find the texinfo later on
00254         cs->surf = nodenum;
00255         //
00256         cs->flags &= ~SFL_VISIBLE;
00257         cs->flags &= ~SFL_TESTED;
00258         if (i==0)
00259             cs->winding = CopyWinding (midwinding);
00260         else
00261             cs->winding = midwinding;
00262     } //end for
00263 
00264 
00265 {
00266     vec_t v1;
00267     int i;
00268 
00269     for (i=0 ; i<2 ; i++)
00270     {
00271         v1 = BrushVolume (b[i]);
00272         if (v1 < 1)
00273         {
00274             FreeBrush (b[i]);
00275             b[i] = NULL;
00276             Log_Print("HL_SplitBrush: tiny volume after clip\n");
00277         } //end if
00278     } //end for
00279 } //*/
00280 
00281     *front = b[0];
00282     *back = b[1];
00283 } //end of the function HL_SplitBrush
00284 //===========================================================================
00285 // returns true if the tree starting at nodenum has only solid leaves
00286 //
00287 // Parameter:               -
00288 // Returns:                 -
00289 // Changes Globals:     -
00290 //===========================================================================
00291 int HL_SolidTree_r(int nodenum)
00292 {
00293     if (nodenum < 0)
00294     {
00295         switch(hl_dleafs[(-nodenum) - 1].contents)
00296         {
00297             case HL_CONTENTS_EMPTY:
00298             {
00299                 return false;
00300             } //end case
00301             case HL_CONTENTS_SOLID:
00302 #ifdef HLCONTENTS
00303             case HL_CONTENTS_CLIP:
00304 #endif //HLCONTENTS
00305             case HL_CONTENTS_SKY:
00306 #ifdef HLCONTENTS
00307             case HL_CONTENTS_TRANSLUCENT:
00308 #endif //HLCONTENTS
00309             {
00310                 return true;
00311             } //end case
00312             case HL_CONTENTS_WATER:
00313             case HL_CONTENTS_SLIME:
00314             case HL_CONTENTS_LAVA:
00315 #ifdef HLCONTENTS
00316             //these contents should not be found in the BSP
00317             case HL_CONTENTS_ORIGIN:
00318             case HL_CONTENTS_CURRENT_0:
00319             case HL_CONTENTS_CURRENT_90:
00320             case HL_CONTENTS_CURRENT_180:
00321             case HL_CONTENTS_CURRENT_270:
00322             case HL_CONTENTS_CURRENT_UP:
00323             case HL_CONTENTS_CURRENT_DOWN:
00324 #endif //HLCONTENTS
00325             default:
00326             {
00327                 return false;
00328             } //end default
00329         } //end switch
00330         return false;
00331     } //end if
00332     if (!HL_SolidTree_r(hl_dnodes[nodenum].children[0])) return false;
00333     if (!HL_SolidTree_r(hl_dnodes[nodenum].children[1])) return false;
00334     return true;
00335 } //end of the function HL_SolidTree_r
00336 //===========================================================================
00337 //
00338 // Parameter:               -
00339 // Returns:                 -
00340 // Changes Globals:     -
00341 //===========================================================================
00342 bspbrush_t *HL_CreateBrushes_r(bspbrush_t *brush, int nodenum)
00343 {
00344     int planenum;
00345     bspbrush_t *front, *back;
00346     hl_dleaf_t *leaf;
00347 
00348     //if it is a leaf
00349     if (nodenum < 0)
00350     {
00351         leaf = &hl_dleafs[(-nodenum) - 1];
00352         if (leaf->contents != HL_CONTENTS_EMPTY)
00353         {
00354 #ifdef HL_PRINT
00355             qprintf("\r%5i", ++hl_numbrushes);
00356 #endif //HL_PRINT
00357         } //end if
00358         switch(leaf->contents)
00359         {
00360             case HL_CONTENTS_EMPTY:
00361             {
00362                 FreeBrush(brush);
00363                 return NULL;
00364             } //end case
00365             case HL_CONTENTS_SOLID:
00366 #ifdef HLCONTENTS
00367             case HL_CONTENTS_CLIP:
00368 #endif //HLCONTENTS
00369             case HL_CONTENTS_SKY:
00370 #ifdef HLCONTENTS
00371             case HL_CONTENTS_TRANSLUCENT:
00372 #endif //HLCONTENTS
00373             {
00374                 brush->side = CONTENTS_SOLID;
00375                 return brush;
00376             } //end case
00377             case HL_CONTENTS_WATER:
00378             {
00379                 brush->side = CONTENTS_WATER;
00380                 return brush;
00381             } //end case
00382             case HL_CONTENTS_SLIME:
00383             {
00384                 brush->side = CONTENTS_SLIME;
00385                 return brush;
00386             } //end case
00387             case HL_CONTENTS_LAVA:
00388             {
00389                 brush->side = CONTENTS_LAVA;
00390                 return brush;
00391             } //end case
00392 #ifdef HLCONTENTS
00393             //these contents should not be found in the BSP
00394             case HL_CONTENTS_ORIGIN:
00395             case HL_CONTENTS_CURRENT_0:
00396             case HL_CONTENTS_CURRENT_90:
00397             case HL_CONTENTS_CURRENT_180:
00398             case HL_CONTENTS_CURRENT_270:
00399             case HL_CONTENTS_CURRENT_UP:
00400             case HL_CONTENTS_CURRENT_DOWN:
00401             {
00402                 Error("HL_CreateBrushes_r: found contents %d in Half-Life BSP", leaf->contents);
00403                 return NULL;
00404             } //end case
00405 #endif //HLCONTENTS
00406             default:
00407             {
00408                 Error("HL_CreateBrushes_r: unknown contents %d in Half-Life BSP", leaf->contents);
00409                 return NULL;
00410             } //end default
00411         } //end switch
00412         return NULL;
00413     } //end if
00414     //if the rest of the tree is solid
00415     /*if (HL_SolidTree_r(nodenum))
00416     {
00417         brush->side = CONTENTS_SOLID;
00418         return brush;
00419     } //end if*/
00420     //
00421     planenum = hl_dnodes[nodenum].planenum;
00422     planenum = FindFloatPlane(hl_dplanes[planenum].normal, hl_dplanes[planenum].dist);
00423     //split the brush with the node plane
00424     HL_SplitBrush(brush, planenum, nodenum, &front, &back);
00425     //free the original brush
00426     FreeBrush(brush);
00427     //every node must split the brush in two
00428     if (!front || !back)
00429     {
00430         Log_Print("HL_CreateBrushes_r: WARNING node not splitting brush\n");
00431         //return NULL;
00432     } //end if
00433     //create brushes recursively
00434     if (front) front = HL_CreateBrushes_r(front, hl_dnodes[nodenum].children[0]);
00435     if (back) back = HL_CreateBrushes_r(back, hl_dnodes[nodenum].children[1]);
00436     //link the brushes if possible and return them
00437     if (front)
00438     {
00439         for (brush = front; brush->next; brush = brush->next);
00440         brush->next = back;
00441         return front;
00442     } //end if
00443     else
00444     {
00445         return back;
00446     } //end else
00447 } //end of the function HL_CreateBrushes_r
00448 //===========================================================================
00449 //
00450 // Parameter:               -
00451 // Returns:                 -
00452 // Changes Globals:     -
00453 //===========================================================================
00454 bspbrush_t *HL_CreateBrushesFromBSP(int modelnum)
00455 {
00456     bspbrush_t *brushlist;
00457     bspbrush_t *brush;
00458     hl_dnode_t *headnode;
00459     vec3_t mins, maxs;
00460     int i;
00461 
00462     //
00463     headnode = &hl_dnodes[hl_dmodels[modelnum].headnode[0]];
00464     //get the mins and maxs of the world
00465     VectorCopy(headnode->mins, mins);
00466     VectorCopy(headnode->maxs, maxs);
00467     //enlarge these mins and maxs
00468     for (i = 0; i < 3; i++)
00469     {
00470         mins[i] -= 8;
00471         maxs[i] += 8;
00472     } //end for
00473     //NOTE: have to add the BSP tree mins and maxs to the MAP mins and maxs
00474     AddPointToBounds(mins, map_mins, map_maxs);
00475     AddPointToBounds(maxs, map_mins, map_maxs);
00476     //
00477     if (!modelnum)
00478     {
00479         Log_Print("brush size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n",
00480                             map_mins[0], map_mins[1], map_mins[2],
00481                             map_maxs[0], map_maxs[1], map_maxs[2]);
00482     } //end if
00483     //create one huge brush containing the whole world
00484     brush = BrushFromBounds(mins, maxs);
00485     VectorCopy(mins, brush->mins);
00486     VectorCopy(maxs, brush->maxs);
00487     //
00488 #ifdef HL_PRINT
00489     qprintf("creating Half-Life brushes\n");
00490     qprintf("%5d brushes", hl_numbrushes = 0);
00491 #endif //HL_PRINT
00492     //create the brushes
00493     brushlist = HL_CreateBrushes_r(brush, hl_dmodels[modelnum].headnode[0]);
00494     //
00495 #ifdef HL_PRINT
00496     qprintf("\n");
00497 #endif //HL_PRINT
00498     //now we've got a list with brushes!
00499     return brushlist;
00500 } //end of the function HL_CreateBrushesFromBSP
00501 //===========================================================================
00502 //
00503 // Parameter:               -
00504 // Returns:                 -
00505 // Changes Globals:     -
00506 //===========================================================================
00507 bspbrush_t *HL_MergeBrushes(bspbrush_t *brushlist, int modelnum)
00508 {
00509     int nummerges, merged;
00510     bspbrush_t *b1, *b2, *tail, *newbrush, *newbrushlist;
00511     bspbrush_t *lastb2;
00512 
00513     if (!brushlist) return NULL;
00514 
00515     if (!modelnum) qprintf("%5d brushes merged", nummerges = 0);
00516     do
00517     {
00518         for (tail = brushlist; tail; tail = tail->next)
00519         {
00520             if (!tail->next) break;
00521         } //end for
00522         merged = 0;
00523         newbrushlist = NULL;
00524         for (b1 = brushlist; b1; b1 = brushlist)
00525         {
00526             lastb2 = b1;
00527             for (b2 = b1->next; b2; b2 = b2->next)
00528             {
00529                 //can't merge brushes with different contents
00530                 if (b1->side != b2->side) newbrush = NULL;
00531                 else newbrush = TryMergeBrushes(b1, b2);
00532                 //if a merged brush is created
00533                 if (newbrush)
00534                 {
00535                     //copy the brush contents
00536                     newbrush->side = b1->side;
00537                     //add the new brush to the end of the list
00538                     tail->next = newbrush;
00539                     //remove the second brush from the list
00540                     lastb2->next = b2->next;
00541                     //remove the first brush from the list
00542                     brushlist = brushlist->next;
00543                     //free the merged brushes
00544                     FreeBrush(b1);
00545                     FreeBrush(b2);
00546                     //get a new tail brush
00547                     for (tail = brushlist; tail; tail = tail->next)
00548                     {
00549                         if (!tail->next) break;
00550                     } //end for
00551                     merged++;
00552                     if (!modelnum) qprintf("\r%5d", nummerges++);
00553                     break;
00554                 } //end if
00555                 lastb2 = b2;
00556             } //end for
00557             //if b1 can't be merged with any of the other brushes
00558             if (!b2)
00559             {
00560                 brushlist = brushlist->next;
00561                 //keep b1
00562                 b1->next = newbrushlist;
00563                 newbrushlist = b1;
00564             } //end else
00565         } //end for
00566         brushlist = newbrushlist;
00567     } while(merged);
00568     if (!modelnum) qprintf("\n");
00569     return newbrushlist;
00570 } //end of the function HL_MergeBrushes
00571 //===========================================================================
00572 // returns the amount the face and the winding have overlap
00573 //
00574 // Parameter:               -
00575 // Returns:                 -
00576 // Changes Globals:     -
00577 //===========================================================================
00578 float HL_FaceOnWinding(hl_dface_t *face, winding_t *winding)
00579 {
00580     int i, edgenum, side;
00581     float dist, area;
00582     hl_dplane_t plane;
00583     vec_t *v1, *v2;
00584     vec3_t normal, edgevec;
00585     winding_t *w;
00586 
00587     //
00588     w = CopyWinding(winding);
00589     memcpy(&plane, &hl_dplanes[face->planenum], sizeof(hl_dplane_t));
00590     //check on which side of the plane the face is
00591     if (face->side)
00592     {
00593         VectorNegate(plane.normal, plane.normal);
00594         plane.dist = -plane.dist;
00595     } //end if
00596     for (i = 0; i < face->numedges && w; i++)
00597     {
00598         //get the first and second vertex of the edge
00599         edgenum = hl_dsurfedges[face->firstedge + i];
00600         side = edgenum > 0;
00601         //if the face plane is flipped
00602         v1 = hl_dvertexes[hl_dedges[abs(edgenum)].v[side]].point;
00603         v2 = hl_dvertexes[hl_dedges[abs(edgenum)].v[!side]].point;
00604         //create a plane through the edge vector, orthogonal to the face plane
00605         //and with the normal vector pointing out of the face
00606         VectorSubtract(v1, v2, edgevec);
00607         CrossProduct(edgevec, plane.normal, normal);
00608         VectorNormalize(normal);
00609         dist = DotProduct(normal, v1);
00610         //
00611         ChopWindingInPlace(&w, normal, dist, 0.9); //CLIP_EPSILON
00612     } //end for
00613     if (w)
00614     {
00615         area = WindingArea(w);
00616         FreeWinding(w);
00617         return area;
00618     } //end if
00619     return 0;
00620 } //end of the function HL_FaceOnWinding
00621 //===========================================================================
00622 // returns a list with brushes created by splitting the given brush with
00623 // planes that go through the face edges and are orthogonal to the face plane
00624 //
00625 // Parameter:               -
00626 // Returns:                 -
00627 // Changes Globals:     -
00628 //===========================================================================
00629 bspbrush_t *HL_SplitBrushWithFace(bspbrush_t *brush, hl_dface_t *face)
00630 {
00631     int i, edgenum, side, planenum, splits;
00632     float dist;
00633     hl_dplane_t plane;
00634     vec_t *v1, *v2;
00635     vec3_t normal, edgevec;
00636     bspbrush_t *front, *back, *brushlist;
00637 
00638     memcpy(&plane, &hl_dplanes[face->planenum], sizeof(hl_dplane_t));
00639     //check on which side of the plane the face is
00640     if (face->side)
00641     {
00642         VectorNegate(plane.normal, plane.normal);
00643         plane.dist = -plane.dist;
00644     } //end if
00645     splits = 0;
00646     brushlist = NULL;
00647     for (i = 0; i < face->numedges; i++)
00648     {
00649         //get the first and second vertex of the edge
00650         edgenum = hl_dsurfedges[face->firstedge + i];
00651         side = edgenum > 0;
00652         //if the face plane is flipped
00653         v1 = hl_dvertexes[hl_dedges[abs(edgenum)].v[side]].point;
00654         v2 = hl_dvertexes[hl_dedges[abs(edgenum)].v[!side]].point;
00655         //create a plane through the edge vector, orthogonal to the face plane
00656         //and with the normal vector pointing out of the face
00657         VectorSubtract(v1, v2, edgevec);
00658         CrossProduct(edgevec, plane.normal, normal);
00659         VectorNormalize(normal);
00660         dist = DotProduct(normal, v1);
00661         //
00662         planenum = FindFloatPlane(normal, dist);
00663         //split the current brush
00664         SplitBrush(brush, planenum, &front, &back);
00665         //if there is a back brush just put it in the list
00666         if (back)
00667         {
00668             //copy the brush contents
00669             back->side = brush->side;
00670             //
00671             back->next = brushlist;
00672             brushlist = back;
00673             splits++;
00674         } //end if
00675         if (!front)
00676         {
00677             Log_Print("HL_SplitBrushWithFace: no new brush\n");
00678             FreeBrushList(brushlist);
00679             return NULL;
00680         } //end if
00681         //copy the brush contents
00682         front->side = brush->side;
00683         //continue splitting the front brush
00684         brush = front;
00685     } //end for
00686     if (!splits)
00687     {
00688         FreeBrush(front);
00689         return NULL;
00690     } //end if
00691     front->next = brushlist;
00692     brushlist = front;
00693     return brushlist;
00694 } //end of the function HL_SplitBrushWithFace
00695 //===========================================================================
00696 //
00697 // Parameter:               -
00698 // Returns:                 -
00699 // Changes Globals:     -
00700 //===========================================================================
00701 bspbrush_t *HL_TextureBrushes(bspbrush_t *brushlist, int modelnum)
00702 {
00703     float area, largestarea;
00704     int i, n, texinfonum, sn, numbrushes, ofs;
00705     int bestfacenum, sidenodenum;
00706     side_t *side;
00707     hl_dmiptexlump_t *miptexlump;
00708     hl_miptex_t *miptex;
00709     bspbrush_t *brush, *nextbrush, *prevbrush, *newbrushes, *brushlistend;
00710     vec_t defaultvec[4] = {1, 0, 0, 0};
00711 
00712     if (!modelnum) qprintf("texturing brushes\n");
00713     if (!modelnum) qprintf("%5d brushes", numbrushes = 0);
00714     //get a pointer to the last brush in the list
00715     for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next)
00716     {
00717         if (!brushlistend->next) break;
00718     } //end for
00719     //there's no previous brush when at the start of the list
00720     prevbrush = NULL;
00721     //go over the brush list
00722     for (brush = brushlist; brush; brush = nextbrush)
00723     {
00724         nextbrush = brush->next;
00725         //find a texinfo for every brush side
00726         for (sn = 0; sn < brush->numsides; sn++)
00727         {
00728             side = &brush->sides[sn];
00729             //
00730             if (side->flags & SFL_TEXTURED) continue;
00731             //number of the node that created this brush side
00732             sidenodenum = side->surf;   //see midwinding in HL_SplitBrush
00733             //no face found yet
00734             bestfacenum = -1;
00735             //minimum face size
00736             largestarea = 1;
00737             //if optimizing the texture placement and not going for the
00738             //least number of brushes
00739             if (!lessbrushes)
00740             {
00741                 for (i = 0; i < hl_numfaces; i++)
00742                 {
00743                     //the face must be in the same plane as the node plane that created
00744                     //this brush side
00745                     if (hl_dfaces[i].planenum == hl_dnodes[sidenodenum].planenum)
00746                     {
00747                         //get the area the face and the brush side overlap
00748                         area = HL_FaceOnWinding(&hl_dfaces[i], side->winding);
00749                         //if this face overlaps the brush side winding more than previous faces
00750                         if (area > largestarea)
00751                         {
00752                             //if there already was a face for texturing this brush side with
00753                             //a different texture
00754                             if (bestfacenum >= 0 &&
00755                                     (hl_dfaces[bestfacenum].texinfo != hl_dfaces[i].texinfo))
00756                             {
00757                                 //split the brush to fit the texture
00758                                 newbrushes = HL_SplitBrushWithFace(brush, &hl_dfaces[i]);
00759                                 //if new brushes where created
00760                                 if (newbrushes)
00761                                 {
00762                                     //remove the current brush from the list
00763                                     if (prevbrush) prevbrush->next = brush->next;
00764                                     else brushlist = brush->next;
00765                                     if (brushlistend == brush)
00766                                     {
00767                                         brushlistend = prevbrush;
00768                                         nextbrush = newbrushes;
00769                                     } //end if
00770                                     //add the new brushes to the end of the list
00771                                     if (brushlistend) brushlistend->next = newbrushes;
00772                                     else brushlist = newbrushes;
00773                                     //free the current brush
00774                                     FreeBrush(brush);
00775                                     //don't forget about the prevbrush pointer at the bottom of
00776                                     //the outer loop
00777                                     brush = prevbrush;
00778                                     //find the end of the list
00779                                     for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next)
00780                                     {
00781                                         if (!brushlistend->next) break;
00782                                     } //end for
00783                                     break;
00784                                 } //end if
00785                                 else
00786                                 {
00787                                     Log_Write("brush %d: no real texture split", numbrushes);
00788                                 } //end else
00789                             } //end if
00790                             else
00791                             {
00792                                 //best face for texturing this brush side
00793                                 bestfacenum = i;
00794                             } //end else
00795                         } //end if
00796                     } //end if
00797                 } //end for
00798                 //if the brush was split the original brush is removed
00799                 //and we just continue with the next one in the list
00800                 if (i < hl_numfaces) break;
00801             } //end if
00802             else
00803             {
00804                 //find the face with the largest overlap with this brush side
00805                 //for texturing the brush side
00806                 for (i = 0; i < hl_numfaces; i++)
00807                 {
00808                     //the face must be in the same plane as the node plane that created
00809                     //this brush side
00810                     if (hl_dfaces[i].planenum == hl_dnodes[sidenodenum].planenum)
00811                     {
00812                         //get the area the face and the brush side overlap
00813                         area = HL_FaceOnWinding(&hl_dfaces[i], side->winding);
00814                         //if this face overlaps the brush side winding more than previous faces
00815                         if (area > largestarea)
00816                         {
00817                             largestarea = area;
00818                             bestfacenum = i;
00819                         } //end if
00820                     } //end if
00821                 } //end for
00822             } //end else
00823             //if a face was found for texturing this brush side
00824             if (bestfacenum >= 0)
00825             {
00826                 //set the MAP texinfo values
00827                 texinfonum = hl_dfaces[bestfacenum].texinfo;
00828                 for (n = 0; n < 4; n++)
00829                 {
00830                     map_texinfo[texinfonum].vecs[0][n] = hl_texinfo[texinfonum].vecs[0][n];
00831                     map_texinfo[texinfonum].vecs[1][n] = hl_texinfo[texinfonum].vecs[1][n];
00832                 } //end for
00833                 //make sure the two vectors aren't of zero length otherwise use the default
00834                 //vector to prevent a divide by zero in the map writing
00835                 if (VectorLength(map_texinfo[texinfonum].vecs[0]) < 0.01)
00836                     memcpy(map_texinfo[texinfonum].vecs[0], defaultvec, sizeof(defaultvec));
00837                 if (VectorLength(map_texinfo[texinfonum].vecs[1]) < 0.01)
00838                     memcpy(map_texinfo[texinfonum].vecs[1], defaultvec, sizeof(defaultvec));
00839                 //
00840                 map_texinfo[texinfonum].flags = hl_texinfo[texinfonum].flags;
00841                 map_texinfo[texinfonum].value = 0; //HL_ and HL texinfos don't have a value
00842                 //the mip texture
00843                 miptexlump = (hl_dmiptexlump_t *) hl_dtexdata;
00844                 ofs = miptexlump->dataofs[hl_texinfo[texinfonum].miptex];
00845                 if ( ofs > hl_texdatasize ) {
00846                     ofs = miptexlump->dataofs[0];
00847                 }
00848                 miptex = (hl_miptex_t *)((byte *)miptexlump + ofs );
00849                 //get the mip texture name
00850                 strcpy(map_texinfo[texinfonum].texture, miptex->name);
00851                 //no animations in Quake1 and Half-Life mip textures
00852                 map_texinfo[texinfonum].nexttexinfo = -1;
00853                 //store the texinfo number
00854                 side->texinfo = texinfonum;
00855                 //
00856                 if (texinfonum > map_numtexinfo) map_numtexinfo = texinfonum;
00857                 //this side is textured
00858                 side->flags |= SFL_TEXTURED;
00859             } //end if
00860             else
00861             {
00862                 //no texture for this side
00863                 side->texinfo = TEXINFO_NODE;
00864                 //this side is textured
00865                 side->flags |= SFL_TEXTURED;
00866             } //end if
00867         } //end for
00868         //
00869         if (!modelnum && prevbrush != brush) qprintf("\r%5d", ++numbrushes);
00870         //previous brush in the list
00871         prevbrush = brush;
00872     } //end for
00873     if (!modelnum) qprintf("\n");
00874     //return the new list with brushes
00875     return brushlist;
00876 } //end of the function HL_TextureBrushes
00877 //===========================================================================
00878 //
00879 // Parameter:               -
00880 // Returns:                 -
00881 // Changes Globals:     -
00882 //===========================================================================
00883 void HL_FixContentsTextures(bspbrush_t *brushlist)
00884 {
00885     int i, texinfonum;
00886     bspbrush_t *brush;
00887 
00888     for (brush = brushlist; brush; brush = brush->next)
00889     {
00890         //only fix the textures of water, slime and lava brushes
00891         if (brush->side != CONTENTS_WATER &&
00892             brush->side != CONTENTS_SLIME &&
00893             brush->side != CONTENTS_LAVA) continue;
00894         //
00895         for (i = 0; i < brush->numsides; i++)
00896         {
00897             texinfonum = brush->sides[i].texinfo;
00898             if (HL_TextureContents(map_texinfo[texinfonum].texture) == brush->side) break;
00899         } //end for
00900         //if no specific contents texture was found
00901         if (i >= brush->numsides)
00902         {
00903             texinfonum = -1;
00904             for (i = 0; i < map_numtexinfo; i++)
00905             {
00906                 if (HL_TextureContents(map_texinfo[i].texture) == brush->side)
00907                 {
00908                     texinfonum = i;
00909                     break;
00910                 } //end if
00911             } //end for
00912         } //end if
00913         //
00914         if (texinfonum >= 0)
00915         {
00916             //give all the brush sides this contents texture
00917             for (i = 0; i < brush->numsides; i++)
00918             {
00919                 brush->sides[i].texinfo = texinfonum;
00920             } //end for
00921         } //end if
00922         else Log_Print("brush contents %d with wrong textures\n", brush->side);
00923         //
00924     } //end for
00925     /*
00926     for (brush = brushlist; brush; brush = brush->next)
00927     {
00928         //give all the brush sides this contents texture
00929         for (i = 0; i < brush->numsides; i++)
00930         {
00931             if (HL_TextureContents(map_texinfo[texinfonum].texture) != brush->side)
00932             {
00933                 Error("brush contents %d with wrong contents textures %s\n", brush->side,
00934                             HL_TextureContents(map_texinfo[texinfonum].texture));
00935             } //end if
00936         } //end for
00937     } //end for*/
00938 } //end of the function HL_FixContentsTextures
00939 //===========================================================================
00940 //
00941 // Parameter:               -
00942 // Returns:                 -
00943 // Changes Globals:     -
00944 //===========================================================================
00945 void HL_BSPBrushToMapBrush(bspbrush_t *bspbrush, entity_t *mapent)
00946 {
00947     mapbrush_t *mapbrush;
00948     side_t *side;
00949     int i, besttexinfo;
00950 
00951     if (nummapbrushes >= MAX_MAPFILE_BRUSHES)
00952     Error ("nummapbrushes == MAX_MAPFILE_BRUSHES");
00953 
00954     mapbrush = &mapbrushes[nummapbrushes];
00955     mapbrush->original_sides = &brushsides[nummapbrushsides];
00956     mapbrush->entitynum = mapent - entities;
00957     mapbrush->brushnum = nummapbrushes - mapent->firstbrush;
00958     mapbrush->leafnum = -1;
00959     mapbrush->numsides = 0;
00960 
00961     besttexinfo = TEXINFO_NODE;
00962     for (i = 0; i < bspbrush->numsides; i++)
00963     {
00964         if (!bspbrush->sides[i].winding) continue;
00965         //
00966         if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES)
00967             Error ("MAX_MAPFILE_BRUSHSIDES");
00968         side = &brushsides[nummapbrushsides];
00969         //the contents of the bsp brush is stored in the side variable
00970         side->contents = bspbrush->side;
00971         side->surf = 0;
00972         side->planenum = bspbrush->sides[i].planenum;
00973         side->texinfo = bspbrush->sides[i].texinfo;
00974         if (side->texinfo != TEXINFO_NODE)
00975         {
00976             //this brush side is textured
00977             side->flags |= SFL_TEXTURED;
00978             besttexinfo = side->texinfo;
00979         } //end if
00980         //
00981         nummapbrushsides++;
00982         mapbrush->numsides++;
00983     } //end for
00984     //
00985     if (besttexinfo == TEXINFO_NODE)
00986     {
00987         mapbrush->numsides = 0;
00988         hl_numclipbrushes++;
00989         return;
00990     } //end if
00991     //set the texinfo for all the brush sides without texture
00992     for (i = 0; i < mapbrush->numsides; i++)
00993     {
00994         if (mapbrush->original_sides[i].texinfo == TEXINFO_NODE)
00995         {
00996             mapbrush->original_sides[i].texinfo = besttexinfo;
00997         } //end if
00998     } //end for
00999     //contents of the brush
01000     mapbrush->contents = bspbrush->side;
01001     //
01002     if (create_aas)
01003     {
01004         //create the AAS brushes from this brush, add brush bevels
01005         AAS_CreateMapBrushes(mapbrush, mapent, true);
01006         return;
01007     } //end if
01008     //create windings for sides and bounds for brush
01009     MakeBrushWindings(mapbrush);
01010     //add brush bevels
01011     AddBrushBevels(mapbrush);
01012     //a new brush has been created
01013     nummapbrushes++;
01014     mapent->numbrushes++;
01015 } //end of the function HL_BSPBrushToMapBrush
01016 //===========================================================================
01017 //
01018 // Parameter:               -
01019 // Returns:                 -
01020 // Changes Globals:     -
01021 //===========================================================================
01022 void HL_CreateMapBrushes(entity_t *mapent, int modelnum)
01023 {
01024     bspbrush_t *brushlist, *brush, *nextbrush;
01025     int i;
01026 
01027     //create brushes from the model BSP tree
01028     brushlist = HL_CreateBrushesFromBSP(modelnum);
01029     //texture the brushes and split them when necesary
01030     brushlist = HL_TextureBrushes(brushlist, modelnum);
01031     //fix the contents textures of all brushes
01032     HL_FixContentsTextures(brushlist);
01033     //
01034     if (!nobrushmerge)
01035     {
01036         brushlist = HL_MergeBrushes(brushlist, modelnum);
01037         //brushlist = HL_MergeBrushes(brushlist, modelnum);
01038     } //end if
01039     //
01040     if (!modelnum) qprintf("converting brushes to map brushes\n");
01041     if (!modelnum) qprintf("%5d brushes", i = 0);
01042     for (brush = brushlist; brush; brush = nextbrush)
01043     {
01044         nextbrush = brush->next;
01045         HL_BSPBrushToMapBrush(brush, mapent);
01046         brush->next = NULL;
01047         FreeBrush(brush);
01048         if (!modelnum) qprintf("\r%5d", ++i);
01049     } //end for
01050     if (!modelnum) qprintf("\n");
01051 } //end of the function HL_CreateMapBrushes
01052 //===========================================================================
01053 //
01054 // Parameter:               -
01055 // Returns:                 -
01056 // Changes Globals:     -
01057 //===========================================================================
01058 void HL_ResetMapLoading(void)
01059 {
01060 } //end of the function HL_ResetMapLoading
01061 //===========================================================================
01062 //
01063 // Parameter:               -
01064 // Returns:                 -
01065 // Changes Globals:     -
01066 //===========================================================================
01067 void HL_LoadMapFromBSP(char *filename, int offset, int length)
01068 {
01069     int i, modelnum;
01070     char *model, *classname;
01071 
01072     Log_Print("-- HL_LoadMapFromBSP --\n");
01073     //loaded map type
01074     loadedmaptype = MAPTYPE_HALFLIFE;
01075     //
01076     qprintf("loading map from %s at %d\n", filename, offset);
01077     //load the Half-Life BSP file
01078     HL_LoadBSPFile(filename, offset, length);
01079     //
01080     hl_numclipbrushes = 0;
01081     //parse the entities from the BSP
01082     HL_ParseEntities();
01083     //clear the map mins and maxs
01084     ClearBounds(map_mins, map_maxs);
01085     //
01086     qprintf("creating Half-Life brushes\n");
01087     if (lessbrushes) qprintf("creating minimum number of brushes\n");
01088     else qprintf("placing textures correctly\n");
01089     //
01090     for (i = 0; i < num_entities; i++)
01091     {
01092         entities[i].firstbrush = nummapbrushes;
01093         entities[i].numbrushes = 0;
01094         //
01095         classname = ValueForKey(&entities[i], "classname");
01096         if (classname && !strcmp(classname, "worldspawn"))
01097         {
01098             modelnum = 0;
01099         } //end if
01100         else
01101         {
01102             //
01103             model = ValueForKey(&entities[i], "model");
01104             if (!model || *model != '*') continue;
01105             model++;
01106             modelnum = atoi(model);
01107         } //end else
01108         //create map brushes for the entity
01109         HL_CreateMapBrushes(&entities[i], modelnum);
01110     } //end for
01111     //
01112     qprintf("%5d map brushes\n", nummapbrushes);
01113     qprintf("%5d clip brushes\n", hl_numclipbrushes);
01114 } //end of the function HL_LoadMapFromBSP

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