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

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

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