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

surface.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 
00025 
00026 mapDrawSurface_t    mapDrawSurfs[MAX_MAP_DRAW_SURFS];
00027 int         numMapDrawSurfs;
00028 
00029 /*
00030 =============================================================================
00031 
00032 DRAWSURF CONSTRUCTION
00033 
00034 =============================================================================
00035 */
00036 
00037 /*
00038 =================
00039 AllocDrawSurf
00040 =================
00041 */
00042 mapDrawSurface_t    *AllocDrawSurf( void ) {
00043     mapDrawSurface_t    *ds;
00044 
00045     if ( numMapDrawSurfs >= MAX_MAP_DRAW_SURFS ) {
00046         Error( "MAX_MAP_DRAW_SURFS");
00047     }
00048     ds = &mapDrawSurfs[ numMapDrawSurfs ];
00049     numMapDrawSurfs++;
00050 
00051     return ds;
00052 }
00053 
00054 /*
00055 =================
00056 DrawSurfaceForSide
00057 =================
00058 */
00059 #define SNAP_FLOAT_TO_INT   8
00060 #define SNAP_INT_TO_FLOAT   (1.0/SNAP_FLOAT_TO_INT)
00061 
00062 mapDrawSurface_t    *DrawSurfaceForSide( bspbrush_t *b, side_t *s, winding_t *w ) {
00063     mapDrawSurface_t    *ds;
00064     int                 i, j;
00065     shaderInfo_t        *si;
00066     drawVert_t          *dv;
00067     float               mins[2], maxs[2];
00068 
00069     // brush primitive :
00070     // axis base
00071     vec3_t      texX,texY;
00072     vec_t       x,y;
00073 
00074     if ( w->numpoints > 64 ) {
00075         Error( "DrawSurfaceForSide: w->numpoints = %i", w->numpoints );
00076     }
00077 
00078     si = s->shaderInfo;
00079 
00080     ds = AllocDrawSurf();
00081 
00082     ds->shaderInfo = si;
00083     ds->mapBrush = b;
00084     ds->side = s;
00085     ds->fogNum = -1;
00086     ds->numVerts = w->numpoints;
00087     ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
00088     memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
00089 
00090     mins[0] = mins[1] = 99999;
00091     maxs[0] = maxs[1] = -99999;
00092 
00093     // compute s/t coordinates from brush primitive texture matrix
00094     // compute axis base
00095     ComputeAxisBase( mapplanes[s->planenum].normal, texX, texY );
00096 
00097     for ( j = 0 ; j < w->numpoints ; j++ ) {
00098         dv = ds->verts + j;
00099 
00100         // round the xyz to a given precision
00101         for ( i = 0 ; i < 3 ; i++ ) {
00102             dv->xyz[i] = SNAP_INT_TO_FLOAT * floor( w->p[j][i] * SNAP_FLOAT_TO_INT + 0.5 );
00103         }
00104     
00105         if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
00106         {
00107             // calculate texture s/t
00108             dv->st[0] = s->vecs[0][3] + DotProduct( s->vecs[0], dv->xyz );
00109             dv->st[1] = s->vecs[1][3] + DotProduct( s->vecs[1], dv->xyz );
00110             dv->st[0] /= si->width;
00111             dv->st[1] /= si->height;
00112         } 
00113         else
00114         {
00115             // calculate texture s/t from brush primitive texture matrix
00116             x = DotProduct( dv->xyz, texX );
00117             y = DotProduct( dv->xyz, texY );
00118             dv->st[0]=s->texMat[0][0]*x+s->texMat[0][1]*y+s->texMat[0][2];
00119             dv->st[1]=s->texMat[1][0]*x+s->texMat[1][1]*y+s->texMat[1][2];
00120         }
00121 
00122         for ( i = 0 ; i < 2 ; i++ ) {
00123             if ( dv->st[i] < mins[i] ) {
00124                 mins[i] = dv->st[i];
00125             }
00126             if ( dv->st[i] > maxs[i] ) {
00127                 maxs[i] = dv->st[i];
00128             }
00129         }
00130 
00131         // copy normal
00132         VectorCopy ( mapplanes[s->planenum].normal, dv->normal );
00133     }
00134 
00135     // adjust the texture coordinates to be as close to 0 as possible
00136     if ( !si->globalTexture ) {
00137         mins[0] = floor( mins[0] );
00138         mins[1] = floor( mins[1] );
00139         for ( i = 0 ; i < w->numpoints ; i++ ) {
00140             dv = ds->verts + i;
00141             dv->st[0] -= mins[0];
00142             dv->st[1] -= mins[1];
00143         }
00144     }
00145 
00146     return ds;
00147 }
00148 
00149 
00150 //=========================================================================
00151 
00152 
00153 
00154 
00155 typedef struct {
00156     int             planenum;
00157     shaderInfo_t    *shaderInfo;
00158     int             count;
00159 } sideRef_t;
00160 
00161 #define MAX_SIDE_REFS   MAX_MAP_PLANES
00162 
00163 sideRef_t   sideRefs[MAX_SIDE_REFS];
00164 int         numSideRefs;
00165 
00166 void AddSideRef( side_t *side ) {
00167     int     i;
00168 
00169     for ( i = 0 ; i < numSideRefs ; i++ ) {
00170         if ( side->planenum == sideRefs[i].planenum
00171             && side->shaderInfo == sideRefs[i].shaderInfo ) {
00172             sideRefs[i].count++;
00173             return;
00174         }
00175     }
00176 
00177     if ( numSideRefs == MAX_SIDE_REFS ) {
00178         Error( "MAX_SIDE_REFS" );
00179     }
00180 
00181     sideRefs[i].planenum = side->planenum;
00182     sideRefs[i].shaderInfo = side->shaderInfo;
00183     sideRefs[i].count++;
00184     numSideRefs++;
00185 }
00186 
00187 
00188 /*
00189 =====================
00190 MergeSides
00191 
00192 =====================
00193 */
00194 void MergeSides( entity_t *e, tree_t *tree ) {
00195     int             i;
00196 
00197     qprintf( "----- MergeSides -----\n");
00198 
00199     for ( i = e->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
00200 //          AddSideRef( side );
00201     }
00202 
00203     qprintf( "%5i siderefs\n", numSideRefs );
00204 }
00205 
00206 //=====================================================================
00207 
00208 /*
00209 ===================
00210 SubdivideDrawSurf
00211 ===================
00212 */
00213 void SubdivideDrawSurf( mapDrawSurface_t *ds, winding_t *w, float subdivisions ) {
00214     int             i;
00215     int             axis;
00216     vec3_t          bounds[2];
00217     const float     epsilon = 0.1;
00218     int             subFloor, subCeil;
00219     winding_t       *frontWinding, *backWinding;
00220     mapDrawSurface_t    *newds;
00221 
00222     if ( !w ) {
00223         return;
00224     }
00225     if ( w->numpoints < 3 ) {
00226         Error( "SubdivideDrawSurf: Bad w->numpoints" );
00227     }
00228 
00229     ClearBounds( bounds[0], bounds[1] );
00230     for ( i = 0 ; i < w->numpoints ; i++ ) {
00231         AddPointToBounds( w->p[i], bounds[0], bounds[1] );
00232     }
00233 
00234     for ( axis = 0 ; axis < 3 ; axis++ ) {
00235         vec3_t planePoint = { 0, 0, 0 };
00236         vec3_t planeNormal = { 0, 0, 0 };
00237         float d;
00238 
00239         subFloor = floor( bounds[0][axis]  / subdivisions ) * subdivisions;
00240         subCeil = ceil( bounds[1][axis] / subdivisions ) * subdivisions;
00241 
00242         planePoint[axis] = subFloor + subdivisions;
00243         planeNormal[axis] = -1;
00244 
00245         d = DotProduct( planePoint, planeNormal );
00246 
00247         // subdivide if necessary
00248         if ( subCeil - subFloor > subdivisions ) {
00249             // gotta clip polygon into two polygons
00250             ClipWindingEpsilon( w, planeNormal, d, epsilon, &frontWinding, &backWinding );
00251 
00252             // the clip may not produce two polygons if it was epsilon close
00253             if ( !frontWinding ) {
00254                 w = backWinding;
00255             } else if ( !backWinding ) {
00256                 w = frontWinding;
00257             } else {
00258                 SubdivideDrawSurf( ds, frontWinding, subdivisions );
00259                 SubdivideDrawSurf( ds, backWinding, subdivisions );
00260 
00261                 return;
00262             }
00263         }
00264     }
00265 
00266     // emit this polygon
00267     newds = DrawSurfaceForSide( ds->mapBrush, ds->side, w );
00268     newds->fogNum = ds->fogNum;
00269 }
00270 
00271 
00272 /*
00273 =====================
00274 SubdivideDrawSurfs
00275 
00276 Chop up surfaces that have subdivision attributes
00277 =====================
00278 */
00279 void SubdivideDrawSurfs( entity_t *e, tree_t *tree ) {
00280     int             i;
00281     mapDrawSurface_t    *ds;
00282     int             numBaseDrawSurfs;
00283     winding_t       *w;
00284     float           subdivision;
00285     shaderInfo_t    *si;
00286 
00287     qprintf( "----- SubdivideDrawSurfs -----\n");
00288     numBaseDrawSurfs = numMapDrawSurfs;
00289     for ( i = e->firstDrawSurf ; i < numBaseDrawSurfs ; i++ ) {
00290         ds = &mapDrawSurfs[i];
00291 
00292         // only subdivide brush sides, not patches or misc_models
00293         if ( !ds->side ) {
00294             continue;
00295         }
00296 
00297         // check subdivision for shader
00298         si = ds->side->shaderInfo;
00299         if ( !si ) {
00300             continue;
00301         }
00302 
00303         if (ds->shaderInfo->autosprite || si->autosprite) {
00304             continue;
00305         }
00306 
00307         subdivision = si->subdivisions;
00308         if ( !subdivision ) {
00309             continue;
00310         }
00311 
00312         w = WindingFromDrawSurf( ds );
00313         ds->numVerts = 0;       // remove this reference
00314         SubdivideDrawSurf( ds, w, subdivision );
00315     }
00316 
00317 }
00318 
00319 
00320 //===================================================================================
00321 
00322 /*
00323 ====================
00324 ClipSideIntoTree_r
00325 
00326 Adds non-opaque leaf fragments to the convex hull
00327 ====================
00328 */
00329 void ClipSideIntoTree_r( winding_t *w, side_t *side, node_t *node ) {
00330     plane_t         *plane;
00331     winding_t       *front, *back;
00332 
00333     if ( !w ) {
00334         return;
00335     }
00336 
00337     if ( node->planenum != PLANENUM_LEAF ) {
00338         if ( side->planenum == node->planenum ) {
00339             ClipSideIntoTree_r( w, side, node->children[0] );
00340             return;
00341         }
00342         if ( side->planenum == ( node->planenum ^ 1) ) {
00343             ClipSideIntoTree_r( w, side, node->children[1] );
00344             return;
00345         }
00346 
00347         plane = &mapplanes[ node->planenum ];
00348         ClipWindingEpsilon ( w, plane->normal, plane->dist,
00349                 ON_EPSILON, &front, &back );
00350         FreeWinding( w );
00351 
00352         ClipSideIntoTree_r( front, side, node->children[0] );
00353         ClipSideIntoTree_r( back, side, node->children[1] );
00354 
00355         return;
00356     }
00357 
00358     // if opaque leaf, don't add
00359     if ( !node->opaque ) {
00360         AddWindingToConvexHull( w, &side->visibleHull, mapplanes[ side->planenum ].normal );
00361     }
00362 
00363     FreeWinding( w );
00364     return;
00365 }
00366 
00367 
00368 /*
00369 =====================
00370 ClipSidesIntoTree
00371 
00372 Creates side->visibleHull for all visible sides
00373 
00374 The drawsurf for a side will consist of the convex hull of
00375 all points in non-opaque clusters, which allows overlaps
00376 to be trimmed off automatically.
00377 =====================
00378 */
00379 void ClipSidesIntoTree( entity_t *e, tree_t *tree ) {
00380     bspbrush_t      *b;
00381     int             i;
00382     winding_t       *w;
00383     side_t          *side, *newSide;
00384     shaderInfo_t    *si;
00385 
00386     qprintf( "----- ClipSidesIntoTree -----\n");
00387 
00388     for ( b = e->brushes ; b ; b = b->next ) {
00389         for ( i = 0 ; i < b->numsides ; i++ ) {
00390             side = &b->sides[i];
00391             if ( !side->winding) {
00392                 continue;
00393             }
00394             w = CopyWinding( side->winding );
00395             side->visibleHull = NULL;
00396             ClipSideIntoTree_r( w, side, tree->headnode );
00397 
00398             w = side->visibleHull;
00399             if ( !w ) {
00400                 continue;
00401             }
00402             si = side->shaderInfo;
00403             if ( !si ) {
00404                 continue;
00405             }
00406             // don't create faces for non-visible sides
00407             if ( si->surfaceFlags & SURF_NODRAW ) {
00408                 continue;
00409             }
00410 
00411             // always use the original quad winding for auto sprites
00412             if ( side->shaderInfo->autosprite ) {
00413                 w = side->winding;
00414             }
00415             //
00416             if ( side->bevel ) {
00417                 Error( "monkey tried to create draw surface for brush bevel" );
00418             }
00419             // save this winding as a visible surface
00420             DrawSurfaceForSide( b, side, w );
00421 
00422             // make a back side for it if needed
00423             if ( !(si->contents & CONTENTS_FOG) ) {
00424                 continue;
00425             }
00426 
00427             // duplicate the up-facing side
00428             w = ReverseWinding( w );
00429         
00430             newSide = malloc( sizeof( *side ) );
00431             *newSide = *side;
00432             newSide->visibleHull = w;
00433             newSide->planenum ^= 1;
00434 
00435             // save this winding as a visible surface
00436             DrawSurfaceForSide( b, newSide, w );
00437 
00438         }
00439     }
00440 }
00441 
00442 /*
00443 ===================================================================================
00444 
00445   FILTER REFERENCES DOWN THE TREE
00446 
00447 ===================================================================================
00448 */
00449 
00450 /*
00451 ====================
00452 FilterDrawSurfIntoTree
00453 
00454 Place a reference to the given drawsurf in every leaf it contacts
00455 We assume that the point mesh aproximation to the curve will get a 
00456 reference into all the leafs we need.
00457 ====================
00458 */
00459 int FilterMapDrawSurfIntoTree( vec3_t point, mapDrawSurface_t *ds, node_t *node ) {
00460     drawSurfRef_t   *dsr;
00461     float           d;
00462     plane_t         *plane;
00463     int             c;
00464 
00465     if ( node->planenum != PLANENUM_LEAF ) {
00466         plane = &mapplanes[ node->planenum ];
00467         d = DotProduct( point, plane->normal ) - plane->dist;
00468         c = 0;
00469         if ( d >= -ON_EPSILON ) {
00470             c += FilterMapDrawSurfIntoTree( point, ds, node->children[0] );
00471         }
00472         if ( d <= ON_EPSILON ) {
00473             c += FilterMapDrawSurfIntoTree( point, ds, node->children[1] );
00474         }
00475         return c;
00476     }
00477 
00478     // if opaque leaf, don't add
00479     if ( node->opaque ) {
00480         return 0;
00481     }
00482 
00483     // add the drawsurf if it hasn't been already
00484     for ( dsr = node->drawSurfReferences ; dsr ; dsr = dsr->nextRef ) {
00485         if ( dsr->outputNumber == numDrawSurfaces ) {
00486             return 0;       // already referenced
00487         }
00488     }
00489 
00490     dsr = malloc( sizeof( *dsr ) );
00491     dsr->outputNumber = numDrawSurfaces;
00492     dsr->nextRef = node->drawSurfReferences;
00493     node->drawSurfReferences = dsr;
00494     return 1;
00495 }
00496 
00497 /*
00498 ====================
00499 FilterDrawSurfIntoTree_r
00500 
00501 Place a reference to the given drawsurf in every leaf it is in
00502 ====================
00503 */
00504 int FilterMapDrawSurfIntoTree_r( winding_t *w, mapDrawSurface_t *ds, node_t *node ) {
00505     drawSurfRef_t   *dsr;
00506     plane_t         *plane;
00507     int             total;
00508     winding_t       *front, *back;
00509 
00510     if ( node->planenum != PLANENUM_LEAF ) {
00511         plane = &mapplanes[ node->planenum ];
00512         ClipWindingEpsilon ( w, plane->normal, plane->dist,
00513                 ON_EPSILON, &front, &back );
00514 
00515         total = 0;
00516         if ( front ) {
00517             total += FilterMapDrawSurfIntoTree_r( front, ds, node->children[0] );
00518         }
00519         if ( back ) {
00520             total += FilterMapDrawSurfIntoTree_r( back, ds, node->children[1] );
00521         }
00522 
00523         FreeWinding( w );
00524         return total;
00525     }
00526 
00527     // if opaque leaf, don't add
00528     if ( node->opaque ) {
00529         return 0;
00530     }
00531 
00532     // add the drawsurf if it hasn't been already
00533     for ( dsr = node->drawSurfReferences ; dsr ; dsr = dsr->nextRef ) {
00534         if ( dsr->outputNumber == numDrawSurfaces ) {
00535             return 0;       // already referenced
00536         }
00537     }
00538 
00539     dsr = malloc( sizeof( *dsr ) );
00540     dsr->outputNumber = numDrawSurfaces;
00541     dsr->nextRef = node->drawSurfReferences;
00542     node->drawSurfReferences = dsr;
00543     return 1;
00544 }
00545 
00546 /*
00547 ====================
00548 FilterSideIntoTree_r
00549 
00550 Place a reference to the given drawsurf in every leaf it contacts
00551 ====================
00552 */
00553 int FilterSideIntoTree_r( winding_t *w, side_t *side, mapDrawSurface_t *ds, node_t *node ) {
00554     drawSurfRef_t   *dsr;
00555     plane_t         *plane;
00556     winding_t       *front, *back;
00557     int             total;
00558 
00559     if ( !w ) {
00560         return 0;
00561     }
00562 
00563     if ( node->planenum != PLANENUM_LEAF ) {
00564         if ( side->planenum == node->planenum ) {
00565             return FilterSideIntoTree_r( w, side, ds, node->children[0] );
00566         }
00567         if ( side->planenum == ( node->planenum ^ 1) ) {
00568             return FilterSideIntoTree_r( w, side, ds, node->children[1] );
00569         }
00570 
00571         plane = &mapplanes[ node->planenum ];
00572         ClipWindingEpsilon ( w, plane->normal, plane->dist,
00573                 ON_EPSILON, &front, &back );
00574 
00575         total = FilterSideIntoTree_r( front, side, ds, node->children[0] );
00576         total += FilterSideIntoTree_r( back, side, ds, node->children[1] );
00577 
00578         FreeWinding( w );
00579         return total;
00580     }
00581 
00582     // if opaque leaf, don't add
00583     if ( node->opaque ) {
00584         return 0;
00585     }
00586 
00587     dsr = malloc( sizeof( *dsr ) );
00588     dsr->outputNumber = numDrawSurfaces;
00589     dsr->nextRef = node->drawSurfReferences;
00590     node->drawSurfReferences = dsr;
00591 
00592     FreeWinding( w );
00593     return 1;
00594 }
00595 
00596 
00597 /*
00598 =====================
00599 FilterFaceIntoTree
00600 =====================
00601 */
00602 int FilterFaceIntoTree( mapDrawSurface_t *ds, tree_t *tree ) {
00603     int         l;
00604     winding_t   *w;
00605 
00606     w = WindingFromDrawSurf( ds );
00607     l = FilterSideIntoTree_r( w, ds->side, ds, tree->headnode );
00608 
00609     return l;
00610 }
00611 
00612 
00613 
00614 /*
00615 =====================
00616 FilterPatchSurfIntoTree
00617 =====================
00618 */
00619 #define SUBDIVISION_LIMIT       8.0
00620 int FilterPatchSurfIntoTree( mapDrawSurface_t *ds, tree_t *tree ) {
00621     int                 i, j;
00622     int                 l;
00623     mesh_t              baseMesh, *subdividedMesh;
00624     winding_t           *w;
00625 
00626     baseMesh.width = ds->patchWidth;
00627     baseMesh.height = ds->patchHeight;
00628     baseMesh.verts = ds->verts;
00629     subdividedMesh = SubdivideMesh( baseMesh, SUBDIVISION_LIMIT, 32 );
00630 
00631     l = 0;
00632     for (i = 0; i < subdividedMesh->width-1; i++) {
00633         for (j = 0; j < subdividedMesh->height-1; j++) {
00634             w = AllocWinding(3);
00635             VectorCopy(subdividedMesh->verts[j * subdividedMesh->width + i].xyz, w->p[0]);
00636             VectorCopy(subdividedMesh->verts[j * subdividedMesh->width + i + 1].xyz, w->p[1]);
00637             VectorCopy(subdividedMesh->verts[(j+1) * subdividedMesh->width + i].xyz, w->p[2]);
00638             w->numpoints = 3;
00639             l += FilterMapDrawSurfIntoTree_r( w, ds, tree->headnode );
00640             w = AllocWinding(3);
00641             VectorCopy(subdividedMesh->verts[j * subdividedMesh->width + i + 1].xyz, w->p[0]);
00642             VectorCopy(subdividedMesh->verts[(j+1) * subdividedMesh->width + i + 1].xyz, w->p[1]);
00643             VectorCopy(subdividedMesh->verts[(j+1) * subdividedMesh->width + i].xyz, w->p[2]);
00644             w->numpoints = 3;
00645             l += FilterMapDrawSurfIntoTree_r( w, ds, tree->headnode );
00646         }
00647     }
00648 
00649     // also use the old point filtering into the tree
00650     for ( i = 0 ; i < subdividedMesh->width * subdividedMesh->height ; i++ ) {
00651         l += FilterMapDrawSurfIntoTree( subdividedMesh->verts[i].xyz, ds, tree->headnode );
00652     }
00653 
00654     free(subdividedMesh);
00655 
00656     return l;
00657 }
00658 
00659 
00660 /*
00661 =====================
00662 FilterMiscModelSurfIntoTree
00663 =====================
00664 */
00665 int FilterMiscModelSurfIntoTree( mapDrawSurface_t *ds, tree_t *tree ) {
00666     int         i;
00667     int         l;
00668     winding_t *w;
00669 
00670     l = 0;
00671     for (i = 0; i < ds->numIndexes-2; i++) {
00672         w = AllocWinding(3);
00673         VectorCopy(ds->verts[ds->indexes[i]].xyz, w->p[0]);
00674         VectorCopy(ds->verts[ds->indexes[i+1]].xyz, w->p[1]);
00675         VectorCopy(ds->verts[ds->indexes[i+2]].xyz, w->p[2]);
00676         w->numpoints = 3;
00677         l += FilterMapDrawSurfIntoTree_r( w, ds, tree->headnode );
00678     }
00679 
00680     // also use the old point filtering into the tree
00681     for ( i = 0 ; i < ds->numVerts ; i++ ) {
00682         l += FilterMapDrawSurfIntoTree( ds->verts[i].xyz, ds, tree->headnode );
00683     }
00684 
00685     return l;
00686 }
00687 
00688 /*
00689 =====================
00690 FilterFlareSurfIntoTree
00691 =====================
00692 */
00693 int FilterFlareSurfIntoTree( mapDrawSurface_t *ds, tree_t *tree ) {
00694     return FilterMapDrawSurfIntoTree( ds->lightmapOrigin, ds, tree->headnode );
00695 }
00696 
00697 
00698 //======================================================================
00699 
00700 int     c_stripSurfaces, c_fanSurfaces;
00701 
00702 /*
00703 ==================
00704 IsTriangleDegenerate
00705 
00706 Returns qtrue if all three points are collinear or backwards
00707 ===================
00708 */
00709 #define COLINEAR_AREA   10
00710 static qboolean IsTriangleDegenerate( drawVert_t *points, int a, int b, int c ) {
00711     vec3_t      v1, v2, v3;
00712     float       d;
00713 
00714     VectorSubtract( points[b].xyz, points[a].xyz, v1 );
00715     VectorSubtract( points[c].xyz, points[a].xyz, v2 );
00716     CrossProduct( v1, v2, v3 );
00717     d = VectorLength( v3 );
00718 
00719     // assume all very small or backwards triangles will cause problems
00720     if ( d < COLINEAR_AREA ) {
00721         return qtrue;
00722     }
00723 
00724     return qfalse;
00725 }
00726 
00727 /*
00728 ===============
00729 SurfaceAsTriFan
00730 
00731 The surface can't be represented as a single tristrip without
00732 leaving a degenerate triangle (and therefore a crack), so add
00733 a point in the middle and create (points-1) triangles in fan order
00734 ===============
00735 */
00736 static void SurfaceAsTriFan( dsurface_t *ds ) {
00737     int                 i;
00738     int                 colorSum[4];
00739     drawVert_t          *mid, *v;
00740 
00741     // create a new point in the center of the face
00742     if ( numDrawVerts == MAX_MAP_DRAW_VERTS ) {
00743         Error( "MAX_MAP_DRAW_VERTS" );
00744     }
00745     mid = &drawVerts[ numDrawVerts ];
00746     numDrawVerts++;
00747 
00748     colorSum[0] = colorSum[1] = colorSum[2] = colorSum[3] = 0;
00749 
00750     v = drawVerts + ds->firstVert;
00751     for (i = 0 ; i < ds->numVerts ; i++, v++ ) {
00752         VectorAdd( mid->xyz, v->xyz, mid->xyz );
00753         mid->st[0] += v->st[0];
00754         mid->st[1] += v->st[1];
00755         mid->lightmap[0] += v->lightmap[0];
00756         mid->lightmap[1] += v->lightmap[1];
00757 
00758         colorSum[0] += v->color[0];
00759         colorSum[1] += v->color[1];
00760         colorSum[2] += v->color[2];
00761         colorSum[3] += v->color[3];
00762     }
00763 
00764     mid->xyz[0] /= ds->numVerts;
00765     mid->xyz[1] /= ds->numVerts;
00766     mid->xyz[2] /= ds->numVerts;
00767 
00768     mid->st[0] /= ds->numVerts;
00769     mid->st[1] /= ds->numVerts;
00770 
00771     mid->lightmap[0] /= ds->numVerts;
00772     mid->lightmap[1] /= ds->numVerts;
00773 
00774     mid->color[0] = colorSum[0] / ds->numVerts;
00775     mid->color[1] = colorSum[1] / ds->numVerts;
00776     mid->color[2] = colorSum[2] / ds->numVerts;
00777     mid->color[3] = colorSum[3] / ds->numVerts;
00778 
00779     VectorCopy((drawVerts+ds->firstVert)->normal, mid->normal );
00780 
00781     // fill in indices in trifan order
00782     if ( numDrawIndexes + ds->numVerts*3 > MAX_MAP_DRAW_INDEXES ) {
00783         Error( "MAX_MAP_DRAWINDEXES" );
00784     }
00785     ds->firstIndex = numDrawIndexes;
00786     ds->numIndexes = ds->numVerts*3;
00787 
00788     //FIXME
00789     // should be: for ( i = 0 ; i < ds->numVerts ; i++ ) {
00790     // set a break point and test this in a map
00791     //for ( i = 0 ; i < ds->numVerts*3 ; i++ ) {
00792     for ( i = 0 ; i < ds->numVerts ; i++ ) {
00793         drawIndexes[numDrawIndexes++] = ds->numVerts;
00794         drawIndexes[numDrawIndexes++] = i;
00795         drawIndexes[numDrawIndexes++] = (i+1) % ds->numVerts;
00796     }
00797 
00798     ds->numVerts++;
00799 }
00800 
00801 
00802 /*
00803 ================
00804 SurfaceAsTristrip
00805 
00806 Try to create indices that make (points-2) triangles in tristrip order
00807 ================
00808 */
00809 #define MAX_INDICES 1024
00810 static void SurfaceAsTristrip( dsurface_t *ds ) {
00811     int                 i;
00812     int                 rotate;
00813     int                 numIndices;
00814     int                 ni;
00815     int                 a, b, c;
00816     int                 indices[MAX_INDICES];
00817 
00818     // determine the triangle strip order
00819     numIndices = ( ds->numVerts - 2 ) * 3;
00820     if ( numIndices > MAX_INDICES ) {
00821         Error( "MAX_INDICES exceeded for surface" );
00822     }
00823 
00824     // try all possible orderings of the points looking
00825     // for a strip order that isn't degenerate
00826     for ( rotate = 0 ; rotate < ds->numVerts ; rotate++ ) {
00827         for ( ni = 0, i = 0 ; i < ds->numVerts - 2 - i ; i++ ) {
00828             a = ( ds->numVerts - 1 - i + rotate ) % ds->numVerts;
00829             b = ( i + rotate ) % ds->numVerts;
00830             c = ( ds->numVerts - 2 - i + rotate ) % ds->numVerts;
00831 
00832             if ( IsTriangleDegenerate( drawVerts + ds->firstVert, a, b, c ) ) {
00833                 break;
00834             }
00835             indices[ni++] = a;
00836             indices[ni++] = b;
00837             indices[ni++] = c;
00838 
00839             if ( i + 1 != ds->numVerts - 1 - i ) {
00840                 a = ( ds->numVerts - 2 - i + rotate ) % ds->numVerts;
00841                 b = ( i + rotate ) % ds->numVerts;
00842                 c = ( i + 1 + rotate ) % ds->numVerts;
00843 
00844                 if ( IsTriangleDegenerate( drawVerts + ds->firstVert, a, b, c ) ) {
00845                     break;
00846                 }
00847                 indices[ni++] = a;
00848                 indices[ni++] = b;
00849                 indices[ni++] = c;
00850             }
00851         }
00852         if ( ni == numIndices ) {
00853             break;      // got it done without degenerate triangles
00854         }
00855     }
00856 
00857     // if any triangle in the strip is degenerate,
00858     // render from a centered fan point instead
00859     if ( ni < numIndices ) {
00860         c_fanSurfaces++;
00861         SurfaceAsTriFan( ds );
00862         return;
00863     }
00864 
00865     // a normal tristrip
00866     c_stripSurfaces++;
00867 
00868     if ( numDrawIndexes + ni > MAX_MAP_DRAW_INDEXES ) {
00869         Error( "MAX_MAP_DRAW_INDEXES" );
00870     }
00871     ds->firstIndex = numDrawIndexes;
00872     ds->numIndexes = ni;
00873 
00874     memcpy( drawIndexes + numDrawIndexes, indices, ni * sizeof(int) );
00875     numDrawIndexes += ni;
00876 }
00877 
00878 /*
00879 ===============
00880 EmitPlanarSurf
00881 ===============
00882 */
00883 void EmitPlanarSurf( mapDrawSurface_t *ds ) {
00884     int             j;
00885     dsurface_t      *out;
00886     drawVert_t      *outv;
00887 
00888     if ( numDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
00889         Error( "MAX_MAP_DRAW_SURFS" );
00890     }
00891     out = &drawSurfaces[ numDrawSurfaces ];
00892     numDrawSurfaces++;
00893 
00894     out->surfaceType = MST_PLANAR;
00895     out->shaderNum = EmitShader( ds->shaderInfo->shader );
00896     out->firstVert = numDrawVerts;
00897     out->numVerts = ds->numVerts;
00898     out->fogNum = ds->fogNum;
00899     out->lightmapNum = ds->lightmapNum;
00900     out->lightmapX = ds->lightmapX;
00901     out->lightmapY = ds->lightmapY;
00902     out->lightmapWidth = ds->lightmapWidth;
00903     out->lightmapHeight = ds->lightmapHeight;
00904 
00905     VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
00906     VectorCopy( ds->lightmapVecs[0], out->lightmapVecs[0] );
00907     VectorCopy( ds->lightmapVecs[1], out->lightmapVecs[1] );
00908     VectorCopy( ds->lightmapVecs[2], out->lightmapVecs[2] );
00909 
00910     for ( j = 0 ; j < ds->numVerts ; j++ ) {
00911         if ( numDrawVerts == MAX_MAP_DRAW_VERTS ) {
00912             Error( "MAX_MAP_DRAW_VERTS" );
00913         }
00914         outv = &drawVerts[ numDrawVerts ];
00915         numDrawVerts++;
00916         memcpy( outv, &ds->verts[ j ], sizeof( *outv ) );
00917         outv->color[0] = 255;
00918         outv->color[1] = 255;
00919         outv->color[2] = 255;
00920         outv->color[3] = 255;
00921     }
00922 
00923     // create the indexes
00924     SurfaceAsTristrip( out );
00925 }
00926 
00927 
00928 /*
00929 ===============
00930 EmitPatchSurf
00931 ===============
00932 */
00933 void EmitPatchSurf( mapDrawSurface_t *ds ) {
00934     int             j;
00935     dsurface_t      *out;
00936     drawVert_t      *outv;
00937 
00938     if ( numDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
00939         Error( "MAX_MAP_DRAW_SURFS" );
00940     }
00941     out = &drawSurfaces[ numDrawSurfaces ];
00942     numDrawSurfaces++;
00943 
00944     out->surfaceType = MST_PATCH;
00945     out->shaderNum = EmitShader( ds->shaderInfo->shader );
00946     out->firstVert = numDrawVerts;
00947     out->numVerts = ds->numVerts;
00948     out->firstIndex = numDrawIndexes;
00949     out->numIndexes = ds->numIndexes;
00950     out->patchWidth = ds->patchWidth;
00951     out->patchHeight = ds->patchHeight;
00952     out->fogNum = ds->fogNum;
00953     out->lightmapNum = ds->lightmapNum;
00954     out->lightmapX = ds->lightmapX;
00955     out->lightmapY = ds->lightmapY;
00956     out->lightmapWidth = ds->lightmapWidth;
00957     out->lightmapHeight = ds->lightmapHeight;
00958 
00959     VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
00960     VectorCopy( ds->lightmapVecs[0], out->lightmapVecs[0] );
00961     VectorCopy( ds->lightmapVecs[1], out->lightmapVecs[1] );
00962     VectorCopy( ds->lightmapVecs[2], out->lightmapVecs[2] );
00963 
00964     for ( j = 0 ; j < ds->numVerts ; j++ ) {
00965         if ( numDrawVerts == MAX_MAP_DRAW_VERTS ) {
00966             Error( "MAX_MAP_DRAW_VERTS" );
00967         }
00968         outv = &drawVerts[ numDrawVerts ];
00969         numDrawVerts++;
00970         memcpy( outv, &ds->verts[ j ], sizeof( *outv ) );
00971         outv->color[0] = 255;
00972         outv->color[1] = 255;
00973         outv->color[2] = 255;
00974         outv->color[3] = 255;
00975     }
00976 
00977     for ( j = 0 ; j < ds->numIndexes ; j++ ) {
00978         if ( numDrawIndexes == MAX_MAP_DRAW_INDEXES ) {
00979             Error( "MAX_MAP_DRAW_INDEXES" );
00980         }
00981         drawIndexes[ numDrawIndexes ] = ds->indexes[ j ];
00982         numDrawIndexes++;
00983     }
00984 }
00985 
00986 /*
00987 ===============
00988 EmitFlareSurf
00989 ===============
00990 */
00991 void EmitFlareSurf( mapDrawSurface_t *ds ) {
00992     dsurface_t      *out;
00993 
00994     if ( numDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
00995         Error( "MAX_MAP_DRAW_SURFS" );
00996     }
00997     out = &drawSurfaces[ numDrawSurfaces ];
00998     numDrawSurfaces++;
00999 
01000     out->surfaceType = MST_FLARE;
01001     out->shaderNum = EmitShader( ds->shaderInfo->shader );
01002     out->fogNum = ds->fogNum;
01003 
01004     VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
01005     VectorCopy( ds->lightmapVecs[0], out->lightmapVecs[0] );    // color
01006     VectorCopy( ds->lightmapVecs[2], out->lightmapVecs[2] );
01007 }
01008 
01009 
01010 /*
01011 ===============
01012 EmitModelSurf
01013 ===============
01014 */
01015 void EmitModelSurf( mapDrawSurface_t *ds ) {
01016     int             j;
01017     dsurface_t      *out;
01018     drawVert_t      *outv;
01019 
01020     if ( numDrawSurfaces == MAX_MAP_DRAW_SURFS ) {
01021         Error( "MAX_MAP_DRAW_SURFS" );
01022     }
01023     out = &drawSurfaces[ numDrawSurfaces ];
01024     numDrawSurfaces++;
01025 
01026     out->surfaceType = MST_TRIANGLE_SOUP;
01027     out->shaderNum = EmitShader( ds->shaderInfo->shader );
01028     out->firstVert = numDrawVerts;
01029     out->numVerts = ds->numVerts;
01030     out->firstIndex = numDrawIndexes;
01031     out->numIndexes = ds->numIndexes;
01032     out->patchWidth = ds->patchWidth;
01033     out->patchHeight = ds->patchHeight;
01034     out->fogNum = ds->fogNum;
01035     out->lightmapNum = ds->lightmapNum;
01036     out->lightmapX = ds->lightmapX;
01037     out->lightmapY = ds->lightmapY;
01038     out->lightmapWidth = ds->lightmapWidth;
01039     out->lightmapHeight = ds->lightmapHeight;
01040 
01041     VectorCopy( ds->lightmapOrigin, out->lightmapOrigin );
01042     VectorCopy( ds->lightmapVecs[0], out->lightmapVecs[0] );
01043     VectorCopy( ds->lightmapVecs[1], out->lightmapVecs[1] );
01044     VectorCopy( ds->lightmapVecs[2], out->lightmapVecs[2] );
01045 
01046     for ( j = 0 ; j < ds->numVerts ; j++ ) {
01047         if ( numDrawVerts == MAX_MAP_DRAW_VERTS ) {
01048             Error( "MAX_MAP_DRAW_VERTS" );
01049         }
01050         outv = &drawVerts[ numDrawVerts ];
01051         numDrawVerts++;
01052         memcpy( outv, &ds->verts[ j ], sizeof( *outv ) );
01053         outv->color[0] = 255;
01054         outv->color[1] = 255;
01055         outv->color[2] = 255;
01056     }
01057 
01058     for ( j = 0 ; j < ds->numIndexes ; j++ ) {
01059         if ( numDrawIndexes == MAX_MAP_DRAW_INDEXES ) {
01060             Error( "MAX_MAP_DRAW_INDEXES" );
01061         }
01062         drawIndexes[ numDrawIndexes ] = ds->indexes[ j ];
01063         numDrawIndexes++;
01064     }
01065 }
01066 
01067 //======================================================================
01068 
01069 /*
01070 ==================
01071 CreateFlareSurface
01072 
01073 Light flares from surface lights become 
01074 ==================
01075 */
01076 void CreateFlareSurface( mapDrawSurface_t *faceDs ) {
01077     mapDrawSurface_t    *ds;
01078     int                 i;
01079 
01080     ds = AllocDrawSurf();
01081 
01082     if ( faceDs->shaderInfo->flareShader[0] ) {
01083         ds->shaderInfo = ShaderInfoForShader( faceDs->shaderInfo->flareShader );
01084     } else {
01085         ds->shaderInfo = ShaderInfoForShader( "flareshader" );
01086     }
01087     ds->flareSurface = qtrue;
01088     VectorCopy( faceDs->lightmapVecs[2], ds->lightmapVecs[2] );
01089 
01090     // find midpoint
01091     VectorClear( ds->lightmapOrigin );
01092     for ( i = 0 ; i < faceDs->numVerts ; i++ ) {
01093         VectorAdd( ds->lightmapOrigin, faceDs->verts[i].xyz, ds->lightmapOrigin );
01094     }
01095     VectorScale( ds->lightmapOrigin, 1.0/faceDs->numVerts, ds->lightmapOrigin );
01096 
01097     VectorMA( ds->lightmapOrigin, 2,  ds->lightmapVecs[2], ds->lightmapOrigin );
01098 
01099     VectorCopy( faceDs->shaderInfo->color, ds->lightmapVecs[0] );
01100 
01101     // FIXME: fog
01102 }
01103 
01104 /*
01105 =====================
01106 FilterDrawsurfsIntoTree
01107 
01108 Upon completion, all drawsurfs that actually generate a reference
01109 will have been emited to the bspfile arrays, and the references
01110 will have valid final indexes
01111 =====================
01112 */
01113 void FilterDrawsurfsIntoTree( entity_t *e, tree_t *tree ) {
01114     int             i;
01115     mapDrawSurface_t    *ds;
01116     int             refs;
01117     int             c_surfs, c_refs;
01118 
01119     qprintf( "----- FilterDrawsurfsIntoTree -----\n");
01120 
01121     c_surfs = 0;
01122     c_refs = 0;
01123     for ( i = e->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
01124         ds = &mapDrawSurfs[i];
01125 
01126         if ( !ds->numVerts && !ds->flareSurface ) {
01127             continue;
01128         }
01129         if ( ds->miscModel ) {
01130             refs = FilterMiscModelSurfIntoTree( ds, tree );
01131             EmitModelSurf( ds );        
01132         } else if ( ds->patch ) {
01133             refs = FilterPatchSurfIntoTree( ds, tree );
01134             EmitPatchSurf( ds );        
01135         } else if ( ds->flareSurface ) {
01136             refs = FilterFlareSurfIntoTree( ds, tree );
01137             EmitFlareSurf( ds );                    
01138         } else {
01139             refs = FilterFaceIntoTree( ds, tree );
01140 //          if ( ds->shaderInfo->value >= 1000 ) { // ds->shaderInfo->flareShader[0] ) {
01141             if ( ds->shaderInfo->flareShader[0] ) {
01142                 CreateFlareSurface( ds );
01143             }
01144             EmitPlanarSurf( ds );       
01145         }
01146         if ( refs > 0 ) {
01147             c_surfs++;
01148             c_refs += refs;
01149         }
01150     }
01151     qprintf( "%5i emited drawsurfs\n", c_surfs );
01152     qprintf( "%5i references\n", c_refs );
01153     qprintf( "%5i stripfaces\n", c_stripSurfaces );
01154     qprintf( "%5i fanfaces\n", c_fanSurfaces );
01155 }
01156 
01157 
01158 

Generated on Thu Aug 25 12:38:24 2005 for Quake III Arena by  doxygen 1.3.9.1