home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 58 / pcpp58a.iso / extras / quake 3 source / Q3A_ToolSource.exe / Main / fog.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-02  |  12.0 KB  |  534 lines

  1. #include "qbsp.h"
  2.  
  3.  
  4. int            c_fogFragment;
  5. int            c_fogPatchFragments;
  6.  
  7. /*
  8. ====================
  9. DrawSurfToMesh
  10. ====================
  11. */
  12. mesh_t    *DrawSurfToMesh( mapDrawSurface_t *ds ) {
  13.     mesh_t        *m;
  14.  
  15.     m = malloc( sizeof( *m ) );
  16.     m->width = ds->patchWidth;
  17.     m->height = ds->patchHeight;
  18.     m->verts = malloc( sizeof(m->verts[0]) * m->width * m->height );
  19.     memcpy( m->verts, ds->verts, sizeof(m->verts[0]) * m->width * m->height );
  20.  
  21.     return m;
  22. }
  23.  
  24.  
  25. /*
  26. ====================
  27. SplitMeshByPlane
  28. ====================
  29. */
  30. void SplitMeshByPlane( mesh_t *in, vec3_t normal, float dist, mesh_t **front, mesh_t **back ) {
  31.     int        w, h, split;
  32.     float    d[MAX_PATCH_SIZE][MAX_PATCH_SIZE];
  33.     drawVert_t    *dv, *v1, *v2;
  34.     int        c_front, c_back, c_on;
  35.     mesh_t    *f, *b;
  36.     int        i;
  37.     float    frac;
  38.     int        frontAprox, backAprox;
  39.  
  40.     for ( i = 0 ; i < 2 ; i++ ) {
  41.         dv = in->verts;
  42.         c_front = 0;
  43.         c_back = 0;
  44.         c_on = 0;
  45.         for ( h = 0 ; h < in->height ; h++ ) {
  46.             for ( w = 0 ; w < in->width ; w++, dv++ ) {
  47.                 d[h][w] = DotProduct( dv->xyz, normal ) - dist;
  48.                 if ( d[h][w] > ON_EPSILON ) {
  49.                     c_front++;
  50.                 } else if ( d[h][w] < -ON_EPSILON ) {
  51.                     c_back++;
  52.                 } else {
  53.                     c_on++;
  54.                 }
  55.             }
  56.         }
  57.  
  58.         *front = NULL;
  59.         *back = NULL;
  60.  
  61.         if ( !c_front ) {
  62.             *back = in;
  63.             return;
  64.         }
  65.         if ( !c_back ) {
  66.             *front = in;
  67.             return;
  68.         }
  69.  
  70.         // find a split point
  71.         split = -1;
  72.         for ( w = 0 ; w < in->width -1 ; w++ ) {
  73.             if ( ( d[0][w] < 0 ) != ( d[0][w+1] < 0 ) ) {
  74.                 if ( split == -1 ) {
  75.                     split = w;
  76.                     break;
  77.                 }
  78.             }
  79.         }
  80.  
  81.         if ( split == -1 ) {
  82.             if ( i == 1 ) {
  83.                 qprintf( "No crossing points in patch\n");
  84.                 *front = in;
  85.                 return;
  86.             }
  87.  
  88.             in = TransposeMesh( in );
  89.             InvertMesh( in );
  90.             continue;
  91.         }
  92.  
  93.         // make sure the split point stays the same for all other rows
  94.         for ( h = 1 ; h < in->height ; h++ ) {
  95.             for ( w = 0 ; w < in->width -1 ; w++ ) {
  96.                 if ( ( d[h][w] < 0 ) != ( d[h][w+1] < 0 ) ) {
  97.                     if ( w != split ) {
  98.                         _printf( "multiple crossing points for patch -- can't clip\n");
  99.                         *front = in;
  100.                         return;
  101.                     }
  102.                 }
  103.             }
  104.             if ( ( d[h][split] < 0 ) == ( d[h][split+1] < 0 ) ) {
  105.                 _printf( "differing crossing points for patch -- can't clip\n");
  106.                 *front = in;
  107.                 return;
  108.             }
  109.         }
  110.  
  111.         break;
  112.     }
  113.  
  114.  
  115.     // create two new meshes
  116.     f = malloc( sizeof( *f ) );
  117.     f->width = split + 2;
  118.     if ( ! (f->width & 1) ) {
  119.         f->width++;
  120.         frontAprox = 1;
  121.     } else {
  122.         frontAprox = 0;
  123.     }
  124.     if ( f->width > MAX_PATCH_SIZE ) {
  125.         Error( "MAX_PATCH_SIZE after split");
  126.     }
  127.     f->height = in->height;
  128.     f->verts = malloc( sizeof(f->verts[0]) * f->width * f->height );
  129.  
  130.     b = malloc( sizeof( *b ) );
  131.     b->width = in->width - split;
  132.     if ( ! (b->width & 1) ) {
  133.         b->width++;
  134.         backAprox = 1;
  135.     } else {
  136.         backAprox = 0;
  137.     }
  138.     if ( b->width > MAX_PATCH_SIZE ) {
  139.         Error( "MAX_PATCH_SIZE after split");
  140.     }
  141.     b->height = in->height;
  142.     b->verts = malloc( sizeof(b->verts[0]) * b->width * b->height );
  143.  
  144.     if ( d[0][0] > 0 ) {
  145.         *front = f;
  146.         *back = b;
  147.     } else {
  148.         *front = b;
  149.         *back = f;
  150.     }
  151.  
  152.     // distribute the points
  153.     for ( w = 0 ; w < in->width ; w++ ) {
  154.         for ( h = 0 ; h < in->height ; h++ ) {
  155.             if ( w <= split ) {
  156.                 f->verts[ h * f->width + w ] = in->verts[ h * in->width + w ];
  157.             } else {
  158.                 b->verts[ h * b->width + w - split + backAprox ] = in->verts[ h * in->width + w ];
  159.             }
  160.         }
  161.     }
  162.  
  163.     // clip the crossing line
  164.     for ( h = 0 ; h < in->height ; h++ ) {
  165.         dv = &f->verts[ h * f->width + split + 1 ];
  166.         v1 = &in->verts[ h * in->width + split ];
  167.         v2 = &in->verts[ h * in->width + split + 1 ];
  168.         frac = d[h][split] / ( d[h][split] - d[h][split+1] );
  169.         for ( i = 0 ; i < 10 ; i++ ) {
  170.             dv->xyz[i] = v1->xyz[i] + frac * ( v2->xyz[i] - v1->xyz[i] );
  171.         }
  172.         dv->xyz[10] = 0;//set all 4 colors to 0 
  173.         if ( frontAprox ) {
  174.             f->verts[ h * f->width + split + 2 ] = *dv;
  175.         }
  176.         b->verts[ h * b->width ] = *dv;
  177.         if ( backAprox ) {
  178.             b->verts[ h * b->width + 1 ] = *dv;
  179.         }
  180.     }
  181.  
  182.     /*
  183. PrintMesh( in );
  184. _printf("\n");
  185. PrintMesh( f );
  186. _printf("\n");
  187. PrintMesh( b );
  188. _printf("\n");
  189.     */
  190.  
  191.     FreeMesh( in );
  192. }
  193.  
  194.  
  195. /*
  196. ====================
  197. ChopPatchByBrush
  198. ====================
  199. */
  200. qboolean ChopPatchByBrush( mapDrawSurface_t *ds, bspbrush_t *b ) {
  201.     int            i, j;
  202.     side_t        *s;
  203.     plane_t        *plane;
  204.     mesh_t        *outside[MAX_BRUSH_SIDES];
  205.     int            numOutside;
  206.     mesh_t        *m, *front, *back;
  207.     mapDrawSurface_t    *newds;
  208.  
  209.     m = DrawSurfToMesh( ds );
  210.     numOutside = 0;
  211.  
  212.     // only split by the top and bottom planes to avoid
  213.     // some messy patch clipping issues
  214.  
  215.     for ( i = 4 ; i <= 5 ; i++ ) {
  216.         s = &b->sides[ i ];
  217.         plane = &mapplanes[ s->planenum ];
  218.  
  219.         SplitMeshByPlane( m, plane->normal, plane->dist, &front, &back );
  220.  
  221.         if ( !back ) {
  222.             // nothing actually contained inside
  223.             for ( j = 0 ; j < numOutside ; j++ ) {
  224.                 FreeMesh( outside[j] );
  225.             }
  226.             return qfalse;
  227.         }
  228.         m = back;
  229.  
  230.         if ( front ) {
  231.             if ( numOutside == MAX_BRUSH_SIDES ) {
  232.                 Error( "MAX_BRUSH_SIDES" );
  233.             }
  234.             outside[ numOutside ] = front;
  235.             numOutside++;
  236.         }
  237.     }
  238.  
  239.     // all of outside fragments become seperate drawsurfs
  240.     c_fogPatchFragments += numOutside;
  241.     for ( i = 0 ; i < numOutside ; i++ ) {
  242.         newds = DrawSurfaceForMesh( outside[ i ] );
  243.         newds->shaderInfo = ds->shaderInfo;
  244.         FreeMesh( outside[ i ] );
  245.     }
  246.  
  247.     // replace ds with m
  248.     ds->patchWidth = m->width;
  249.     ds->patchHeight = m->height;
  250.     ds->numVerts = m->width * m->height;
  251.     free( ds->verts );
  252.     ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
  253.     memcpy( ds->verts, m->verts, ds->numVerts * sizeof( *ds->verts ) );
  254.  
  255.     FreeMesh( m );
  256.  
  257.     return qtrue;
  258. }
  259.  
  260. //===============================================================================
  261.  
  262. /*
  263. ====================
  264. WindingFromDrawSurf
  265. ====================
  266. */
  267. winding_t    *WindingFromDrawSurf( mapDrawSurface_t *ds ) {
  268.     winding_t    *w;
  269.     int            i;
  270.  
  271.     w = AllocWinding( ds->numVerts );
  272.     w->numpoints = ds->numVerts;
  273.     for ( i = 0 ; i < ds->numVerts ; i++ ) {
  274.         VectorCopy( ds->verts[i].xyz, w->p[i] );
  275.     }
  276.     return w;
  277. }
  278.  
  279. /*
  280. ====================
  281. ChopFaceByBrush
  282.  
  283. There may be a fragment contained in the brush
  284. ====================
  285. */
  286. qboolean ChopFaceByBrush( mapDrawSurface_t *ds, bspbrush_t *b ) {
  287.     int            i, j;
  288.     side_t        *s;
  289.     plane_t        *plane;
  290.     winding_t    *w;
  291.     winding_t    *front, *back;
  292.     winding_t    *outside[MAX_BRUSH_SIDES];
  293.     int            numOutside;
  294.     mapDrawSurface_t    *newds;
  295.     drawVert_t        *dv;
  296.     shaderInfo_t    *si;
  297.     float        mins[2];
  298.  
  299.     // brush primitive :
  300.     // axis base
  301.     vec3_t        texX,texY;
  302.     vec_t        x,y;
  303.  
  304.     w = WindingFromDrawSurf( ds );
  305.     numOutside = 0;
  306.  
  307.     for ( i = 0 ; i < b->numsides ; i++ ) {
  308.         s = &b->sides[ i ];
  309.         if ( s->backSide ) {
  310.             continue;
  311.         }
  312.         plane = &mapplanes[ s->planenum ];
  313.  
  314.         // handle coplanar outfacing (don't fog)
  315.         if ( ds->side->planenum == s->planenum ) {
  316.             return qfalse;
  317.         }
  318.  
  319.         // handle coplanar infacing (keep inside)
  320.         if ( ( ds->side->planenum ^ 1 ) == s->planenum ) {
  321.             continue;
  322.         }
  323.  
  324.         // general case
  325.         ClipWindingEpsilon( w, plane->normal, plane->dist, ON_EPSILON,
  326.             &front, &back );
  327.         FreeWinding( w );
  328.         if ( !back ) {
  329.             // nothing actually contained inside
  330.             for ( j = 0 ; j < numOutside ; j++ ) {
  331.                 FreeWinding( outside[j] );
  332.             }
  333.             return qfalse;
  334.         }
  335.         if ( front ) {
  336.             if ( numOutside == MAX_BRUSH_SIDES ) {
  337.                 Error( "MAX_BRUSH_SIDES" );
  338.             }
  339.             outside[ numOutside ] = front;
  340.             numOutside++;
  341.         }
  342.         w = back;
  343.     }
  344.  
  345.     // all of outside fragments become seperate drawsurfs
  346.     // linked to the same side
  347.     c_fogFragment += numOutside;
  348.     s = ds->side;
  349.  
  350.     for ( i = 0 ; i < numOutside ; i++ ) {
  351.         newds = DrawSurfaceForSide( ds->mapBrush, s, outside[i] );
  352.         FreeWinding( outside[i] );
  353.     }
  354.  
  355.  
  356.     // replace ds->verts with the verts for w
  357.     ds->numVerts = w->numpoints;
  358.     free( ds->verts );
  359.  
  360.     ds->verts = malloc( ds->numVerts * sizeof( *ds->verts ) );
  361.     memset( ds->verts, 0, ds->numVerts * sizeof( *ds->verts ) );
  362.  
  363.     si = s->shaderInfo;
  364.  
  365.     mins[0] = 9999;
  366.     mins[1] = 9999;
  367.  
  368.     // compute s/t coordinates from brush primitive texture matrix
  369.     // compute axis base
  370.     ComputeAxisBase( mapplanes[s->planenum].normal, texX, texY );
  371.  
  372.     for ( j = 0 ; j < w->numpoints ; j++ ) {
  373.         dv = ds->verts + j;
  374.         VectorCopy( w->p[j], dv->xyz );
  375.     
  376.         if (g_bBrushPrimit==BPRIMIT_OLDBRUSHES)
  377.         {
  378.             // calculate texture s/t
  379.             dv->st[0] = s->vecs[0][3] + DotProduct( s->vecs[0],    dv->xyz );
  380.             dv->st[1] = s->vecs[1][3] + DotProduct( s->vecs[1],    dv->xyz );    
  381.             dv->st[0] /= si->width;
  382.             dv->st[1] /= si->height;
  383.         }
  384.         else
  385.         {
  386.             // calculate texture s/t from brush primitive texture matrix
  387.             x = DotProduct( dv->xyz, texX );
  388.             y = DotProduct( dv->xyz, texY );
  389.             dv->st[0]=s->texMat[0][0]*x+s->texMat[0][1]*y+s->texMat[0][2];
  390.             dv->st[1]=s->texMat[1][0]*x+s->texMat[1][1]*y+s->texMat[1][2];
  391.         }
  392.  
  393.         if ( dv->st[0] < mins[0] ) {
  394.             mins[0] = dv->st[0];
  395.         }
  396.         if ( dv->st[1] < mins[1] ) {
  397.             mins[1] = dv->st[1];
  398.         }
  399.  
  400.         // copy normal
  401.         VectorCopy ( mapplanes[s->planenum].normal, dv->normal );
  402.     }
  403.  
  404.     // adjust the texture coordinates to be as close to 0 as possible
  405.     if ( !si->globalTexture ) {
  406.         mins[0] = floor( mins[0] );
  407.         mins[1] = floor( mins[1] );
  408.         for ( i = 0 ; i < w->numpoints ; i++ ) {
  409.             dv = ds->verts + i;
  410.             dv->st[0] -= mins[0];
  411.             dv->st[1] -= mins[1];
  412.         }
  413.     }
  414.  
  415.     return qtrue;
  416. }
  417.  
  418. //===============================================================================
  419.  
  420.  
  421. /*
  422. =====================
  423. FogDrawSurfs
  424.  
  425. Call after the surface list has been pruned, 
  426. before tjunction fixing
  427. before lightmap allocation
  428. =====================
  429. */
  430. void FogDrawSurfs( void ) {
  431.     int                    i, j, k;
  432.     mapDrawSurface_t    *ds;
  433.     bspbrush_t            *b;
  434.     vec3_t                mins, maxs;
  435.     int                    c_fogged;
  436.     int                    numBaseDrawSurfs;
  437.     dfog_t                *fog;
  438.  
  439.     qprintf("----- FogDrawsurfs -----\n");
  440.  
  441.     c_fogged = 0;
  442.     c_fogFragment = 0;
  443.  
  444.     // find all fog brushes
  445.     for ( b = entities[0].brushes ; b ; b = b->next ) {
  446.         if ( !(b->contents & CONTENTS_FOG) ) {
  447.             continue;
  448.         }
  449.  
  450.         if ( numFogs == MAX_MAP_FOGS ) {
  451.             Error( "MAX_MAP_FOGS" );
  452.         }
  453.         fog = &dfogs[numFogs];
  454.         numFogs++;
  455.         fog->brushNum = b->outputNumber;
  456.  
  457.         // find a side with a valid shaderInfo
  458.         // non-axial fog columns may have bevel planes that need to be skipped
  459.         for ( i = 0 ; i < b->numsides ; i++ ) {
  460.             if ( b->sides[i].shaderInfo && (b->sides[i].shaderInfo->contents & CONTENTS_FOG) ) {
  461.                 strcpy( fog->shader, b->sides[i].shaderInfo->shader );
  462.                 break;
  463.             }
  464.         }
  465.         if ( i == b->numsides ) {
  466.             continue;        // shouldn't happen
  467.         }
  468.  
  469.         fog->visibleSide = -1;
  470.  
  471.         // clip each surface into this, but don't clip any of
  472.         // the resulting fragments to the same brush
  473.         numBaseDrawSurfs = numMapDrawSurfs;
  474.         for ( i = 0 ; i < numBaseDrawSurfs ; i++ ) {
  475.             ds = &mapDrawSurfs[i];
  476.  
  477.             // bound the drawsurf
  478.             ClearBounds( mins, maxs );
  479.             for ( j = 0 ; j < ds->numVerts ; j++ ) {
  480.                 AddPointToBounds( ds->verts[j].xyz, mins, maxs );
  481.             }
  482.  
  483.             // check against the fog brush
  484.             for ( k = 0 ; k < 3 ; k++ ) {
  485.                 if ( mins[k] > b->maxs[k] ) {
  486.                     break;
  487.                 }
  488.                 if ( maxs[k] < b->mins[k] ) {
  489.                     break;
  490.                 }
  491.             }
  492.             if ( k < 3 ) {
  493.                 continue;        // bboxes don't intersect
  494.             }
  495.  
  496.             if ( ds->mapBrush == b ) {
  497.                 int        s;
  498.  
  499.                 s = ds->side - b->sides;
  500.                 if ( s <= 6 ) {    // not one of the reversed inside faces
  501.                     // this is a visible fog plane
  502.                     if ( fog->visibleSide != -1 ) {
  503.                         _printf( "WARNING: fog brush %i has multiple visible sides\n", b->brushnum );
  504.                     }
  505.                     fog->visibleSide = s;
  506.                 }
  507.             }
  508.  
  509.             if ( ds->miscModel ) {
  510.                 // we could write splitting code for trimodels if we wanted to...
  511.                 c_fogged++;
  512.                 ds->fogNum = numFogs - 1;
  513.             } else if ( ds->patch ) {
  514.                 if ( ChopPatchByBrush( ds, b ) ) {
  515.                     c_fogged++;
  516.                     ds->fogNum = numFogs - 1;
  517.                 }
  518.             } else {
  519.                 if ( ChopFaceByBrush( ds, b ) ) {
  520.                     c_fogged++;
  521.                     ds->fogNum = numFogs - 1;
  522.                 }
  523.             }
  524.         }
  525.     }
  526.  
  527.     // split the drawsurfs by the fog brushes
  528.  
  529.     qprintf( "%5i fogs\n", numFogs );
  530.     qprintf( "%5i fog polygon fragments\n", c_fogFragment );
  531.     qprintf( "%5i fog patch fragments\n", c_fogPatchFragments );
  532.     qprintf( "%5i fogged drawsurfs\n", c_fogged );
  533. }
  534.