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

  1. #include "qbsp.h"
  2. #include <assert.h>
  3.  
  4. #define SURF_WIDTH    2048
  5. #define SURF_HEIGHT 2048
  6.  
  7. #define GROW_VERTS        512
  8. #define GROW_INDICES    512
  9. #define GROW_SURFACES    128
  10.  
  11. void QuakeTextureVecs(     plane_t *plane, vec_t shift[2], vec_t rotate, vec_t scale[2], vec_t mappingVecs[2][4] );
  12.  
  13. typedef struct {
  14.     shaderInfo_t    *shader;
  15.     int                x, y;
  16.  
  17.     int                maxVerts;
  18.     int                numVerts;
  19.     drawVert_t        *verts;
  20.  
  21.     int                maxIndexes;
  22.     int                numIndexes;
  23.     int                *indexes;
  24. } terrainSurf_t;
  25.  
  26. static terrainSurf_t    *surfaces = NULL;
  27. static terrainSurf_t    *lastSurface = NULL;
  28. static int                numsurfaces = 0;
  29. static int                maxsurfaces = 0;
  30.  
  31. /*
  32. ================
  33. ShaderForLayer
  34. ================
  35. */
  36. shaderInfo_t *ShaderForLayer( int minlayer, int maxlayer, const char *shadername ) {
  37.     char    shader[ MAX_QPATH ];
  38.  
  39.     if ( minlayer == maxlayer ) {
  40.         sprintf( shader, "textures/%s_%d", shadername, maxlayer );
  41.     } else {
  42.         sprintf( shader, "textures/%s_%dto%d", shadername, minlayer, maxlayer );
  43.     }
  44.  
  45.     return ShaderInfoForShader( shader );
  46. }
  47.  
  48. /*
  49. ================
  50. CompareVert
  51. ================
  52. */
  53. qboolean CompareVert( drawVert_t *v1, drawVert_t *v2, qboolean checkst ) {
  54.     int i;
  55.  
  56.     for( i = 0; i < 3; i++ ) {
  57.         if ( floor( v1->xyz[ i ] + 0.1 ) != floor( v2->xyz[ i ] + 0.1 ) ) {
  58.             return qfalse;
  59.         }
  60.         if ( checkst && ( ( v1->st[ 0 ] != v2->st[ 0 ] ) || ( v1->st[ 1 ] != v2->st[ 1 ] ) ) ) {
  61.             return qfalse;
  62.         }
  63.     }
  64.  
  65.     return qtrue;
  66. }
  67.  
  68. /*
  69. ================
  70. LoadAlphaMap
  71. ================
  72. */
  73. byte *LoadAlphaMap( int *num_layers, int *alphawidth, int *alphaheight ) {
  74.     int            *alphamap32;
  75.     byte        *alphamap;
  76.     const char    *alphamapname;
  77.     char        ext[ 128 ];
  78.     int            width;
  79.     int            height;
  80.     int            layers;
  81.     int            size;
  82.     int            i;
  83.  
  84.     assert( alphawidth );
  85.     assert( alphaheight );
  86.     assert( num_layers );
  87.  
  88.     layers = atoi( ValueForKey( mapent, "layers" ) );
  89.     if ( layers < 1 ) {
  90.         Error ("SetTerrainTextures: invalid value for 'layers' (%d)", layers );
  91.     }
  92.  
  93.     alphamapname = ValueForKey( mapent, "alphamap" );
  94.     if ( !alphamapname[ 0 ] ) {
  95.         Error ("LoadAlphaMap: No alphamap specified on terrain" );
  96.     }
  97.  
  98.     ExtractFileExtension( alphamapname, ext);
  99.     if ( !Q_stricmp( ext, "tga" ) ) {
  100.         Load32BitImage( ExpandGamePath( alphamapname ), &alphamap32, &width, &height );
  101.  
  102.         size = width * height;
  103.         alphamap = malloc( size );
  104.         for( i = 0; i < size; i++ ) {
  105.             alphamap[ i ] = ( ( alphamap32[ i ] & 0xff ) * layers ) / 256;
  106.             if ( alphamap[ i ] >= layers ) {
  107.                 alphamap[ i ] = layers - 1;
  108.             }
  109.         }
  110.     } else {
  111.         Load256Image( ExpandGamePath( alphamapname ), &alphamap, NULL, &width, &height );
  112.         size = width * height;
  113.         for( i = 0; i < size; i++ ) {
  114.             if ( alphamap[ i ] >= layers ) {
  115.                 alphamap[ i ] = layers - 1;
  116.             }
  117.         }
  118.     }
  119.  
  120.     if ( ( width < 2 ) || ( height < 2 ) ) {
  121.         Error ("LoadAlphaMap: alphamap width/height must be at least 2x2." );
  122.     }
  123.  
  124.     *num_layers        = layers;
  125.     *alphawidth        = width;
  126.     *alphaheight    = height;
  127.  
  128.     return alphamap;
  129. }
  130.  
  131. /*
  132. ================
  133. CalcTerrainSize
  134. ================
  135. */
  136. void CalcTerrainSize( vec3_t mins, vec3_t maxs, vec3_t size ) {
  137.     bspbrush_t    *brush;
  138.     int            i;
  139.     const char  *key;
  140.  
  141.     // calculate the size of the terrain
  142.     ClearBounds( mins, maxs );
  143.     for( brush = mapent->brushes; brush != NULL; brush = brush->next ) {
  144.         AddPointToBounds( brush->mins, mins, maxs );
  145.         AddPointToBounds( brush->maxs, mins, maxs );
  146.     }
  147.  
  148.     key = ValueForKey( mapent, "min" ); 
  149.     if ( key[ 0 ] ) {
  150.         GetVectorForKey( mapent, "min", mins );
  151.     }
  152.  
  153.     key = ValueForKey( mapent, "max" ); 
  154.     if ( key[ 0 ] ) {
  155.         GetVectorForKey( mapent, "max", maxs );
  156.     }
  157.  
  158.     for( i = 0; i < 3; i++ ) {
  159.         mins[ i ] =  floor( mins[ i ] + 0.1 );
  160.         maxs[ i ] =  floor( maxs[ i ] + 0.1 );
  161.     }
  162.  
  163.     VectorSubtract( maxs, mins, size );
  164.  
  165.     if ( ( size[ 0 ] <= 0 ) || ( size[ 1 ] <= 0 ) ) {
  166.         Error ("CalcTerrainSize: Invalid terrain size: %fx%f", size[ 0 ], size[ 1 ] );
  167.     }
  168. }
  169.  
  170. /*
  171. ==================
  172. IsTriangleDegenerate
  173.  
  174. Returns qtrue if all three points are collinear or backwards
  175. ===================
  176. */
  177. #define    COLINEAR_AREA    10
  178. static qboolean    IsTriangleDegenerate( drawVert_t *points, int a, int b, int c ) {
  179.     vec3_t        v1, v2, v3;
  180.     float        d;
  181.  
  182.     VectorSubtract( points[b].xyz, points[a].xyz, v1 );
  183.     VectorSubtract( points[c].xyz, points[a].xyz, v2 );
  184.     CrossProduct( v1, v2, v3 );
  185.     d = VectorLength( v3 );
  186.  
  187.     // assume all very small or backwards triangles will cause problems
  188.     if ( d < COLINEAR_AREA ) {
  189.         return qtrue;
  190.     }
  191.  
  192.     return qfalse;
  193. }
  194.  
  195. /*
  196. ===============
  197. SideAsTriFan
  198.  
  199. The surface can't be represented as a single tristrip without
  200. leaving a degenerate triangle (and therefore a crack), so add
  201. a point in the middle and create (points-1) triangles in fan order
  202. ===============
  203. */
  204. static void SideAsTriFan( terrainSurf_t *surf, int *index, int num ) {
  205.     int                    i;
  206.     int                    colorSum[4];
  207.     drawVert_t            *mid, *v;
  208.  
  209.     // make sure we have enough space for a new vert
  210.     if ( surf->numVerts >= surf->maxVerts ) {
  211.         surf->maxVerts += GROW_VERTS;
  212.         surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
  213.     }
  214.  
  215.     // create a new point in the center of the face
  216.     mid = &surf->verts[ surf->numVerts ];
  217.     surf->numVerts++;
  218.  
  219.     colorSum[0] = colorSum[1] = colorSum[2] = colorSum[3] = 0;
  220.  
  221.     for (i = 0 ; i < num; i++ ) {
  222.         v = &surf->verts[ index[ i ] ];
  223.         VectorAdd( mid->xyz, v->xyz, mid->xyz );
  224.         mid->st[0] += v->st[0];
  225.         mid->st[1] += v->st[1];
  226.         mid->lightmap[0] += v->lightmap[0];
  227.         mid->lightmap[1] += v->lightmap[1];
  228.  
  229.         colorSum[0] += v->color[0];
  230.         colorSum[1] += v->color[1];
  231.         colorSum[2] += v->color[2];
  232.         colorSum[3] += v->color[3];
  233.     }
  234.  
  235.     mid->xyz[0] /= num;
  236.     mid->xyz[1] /= num;
  237.     mid->xyz[2] /= num;
  238.  
  239.     mid->st[0] /= num;
  240.     mid->st[1] /= num;
  241.  
  242.     mid->lightmap[0] /= num;
  243.     mid->lightmap[1] /= num;
  244.  
  245.     mid->color[0] = colorSum[0] / num;
  246.     mid->color[1] = colorSum[1] / num;
  247.     mid->color[2] = colorSum[2] / num;
  248.     mid->color[3] = colorSum[3] / num;
  249.  
  250.     // fill in indices in trifan order
  251.     if ( surf->numIndexes + num * 3 > surf->maxIndexes ) {
  252.         surf->maxIndexes = surf->numIndexes + num * 3;
  253.         surf->indexes = realloc( surf->indexes, surf->maxIndexes * sizeof( *surf->indexes ) );
  254.     }
  255.  
  256.  
  257.     for ( i = 0 ; i < num; i++ ) {
  258.         surf->indexes[ surf->numIndexes++ ] = surf->numVerts - 1;
  259.         surf->indexes[ surf->numIndexes++ ] = index[ i ];
  260.         surf->indexes[ surf->numIndexes++ ] = index[ (i+1) % ( surf->numVerts - 1 ) ];
  261.     }
  262. }
  263. /*
  264. ================
  265. SideAsTristrip
  266.  
  267. Try to create indices that make (points-2) triangles in tristrip order
  268. ================
  269. */
  270. #define    MAX_INDICES    1024
  271. static void SideAsTristrip( terrainSurf_t *surf, int *index, int num ) {
  272.     int                    i;
  273.     int                    rotate;
  274.     int                    numIndices;
  275.     int                    ni;
  276.     int                    a, b, c;
  277.     int                    indices[ MAX_INDICES ];
  278.  
  279.     // determine the triangle strip order
  280.     numIndices = ( num - 2 ) * 3;
  281.     if ( numIndices > MAX_INDICES ) {
  282.         Error( "MAX_INDICES exceeded for surface" );
  283.     }
  284.  
  285.     // try all possible orderings of the points looking
  286.     // for a strip order that isn't degenerate
  287.     for ( rotate = 0 ; rotate < num; rotate++ ) {
  288.         for ( ni = 0, i = 0 ; i < num - 2 - i ; i++ ) {
  289.             a = index[ ( num - 1 - i + rotate ) % num ];
  290.             b = index[ ( i + rotate ) % num ];
  291.             c = index[ ( num - 2 - i + rotate ) % num ];
  292.  
  293.             if ( IsTriangleDegenerate( surf->verts, a, b, c ) ) {
  294.                 break;
  295.             }
  296.             indices[ni++] = a;
  297.             indices[ni++] = b;
  298.             indices[ni++] = c;
  299.  
  300.             if ( i + 1 != num - 1 - i ) {
  301.                 a = index[ ( num - 2 - i + rotate ) % num ];
  302.                 b = index[ ( i + rotate ) % num ];
  303.                 c = index[ ( i + 1 + rotate ) % num ];
  304.  
  305.                 if ( IsTriangleDegenerate( surf->verts, a, b, c ) ) {
  306.                     break;
  307.                 }
  308.                 indices[ni++] = a;
  309.                 indices[ni++] = b;
  310.                 indices[ni++] = c;
  311.             }
  312.         }
  313.         if ( ni == numIndices ) {
  314.             break;        // got it done without degenerate triangles
  315.         }
  316.     }
  317.  
  318.     // if any triangle in the strip is degenerate,
  319.     // render from a centered fan point instead
  320.     if ( ni < numIndices ) {
  321.         SideAsTriFan( surf, index, num );
  322.         return;
  323.     }
  324.  
  325.     // a normal tristrip
  326.     if ( surf->numIndexes + ni > surf->maxIndexes ) {
  327.         surf->maxIndexes = surf->numIndexes + ni;
  328.         surf->indexes = realloc( surf->indexes, surf->maxIndexes * sizeof( *surf->indexes ) );
  329.     }
  330.  
  331.     memcpy( surf->indexes + surf->numIndexes, indices, ni * sizeof( *surf->indexes ) );
  332.     surf->numIndexes += ni;
  333. }
  334.  
  335. /*
  336. ================
  337. CreateTerrainSurface
  338. ================
  339. */
  340. void CreateTerrainSurface( terrainSurf_t *surf, shaderInfo_t *shader ) {
  341.     int                    i, j, k;
  342.     drawVert_t            *out;
  343.     drawVert_t            *in;
  344.     mapDrawSurface_t    *newsurf;
  345.  
  346.     newsurf = AllocDrawSurf();
  347.  
  348.     newsurf->miscModel        = qtrue;
  349.     newsurf->shaderInfo        = shader;
  350.     newsurf->lightmapNum    = -1;
  351.     newsurf->fogNum            = -1;
  352.     newsurf->numIndexes        = surf->numIndexes;
  353.     newsurf->numVerts        = surf->numVerts;
  354.  
  355.     // copy the indices
  356.     newsurf->indexes = malloc( surf->numIndexes * sizeof( *newsurf->indexes ) );
  357.     memcpy( newsurf->indexes, surf->indexes, surf->numIndexes * sizeof( *newsurf->indexes ) );
  358.  
  359.     // allocate the vertices
  360.     newsurf->verts = malloc( surf->numVerts * sizeof( *newsurf->verts ) );
  361.     memset( newsurf->verts, 0, surf->numVerts * sizeof( *newsurf->verts ) );
  362.  
  363.     // calculate the surface verts
  364.     out = newsurf->verts;
  365.     for( i = 0; i < newsurf->numVerts; i++, out++ ) {
  366.         VectorCopy( surf->verts[ i ].xyz, out->xyz );
  367.  
  368.         // set the texture coordinates
  369.         out->st[ 0 ] = surf->verts[ i ].st[ 0 ];
  370.         out->st[ 1 ] = surf->verts[ i ].st[ 1 ];
  371.  
  372.         // the colors will be set by the lighting pass
  373.         out->color[0] = 255;
  374.         out->color[1] = 255;
  375.         out->color[2] = 255;
  376.         out->color[3] = surf->verts[ i ].color[ 3 ];
  377.  
  378.         // calculate the vertex normal
  379.         VectorClear( out->normal );
  380.         for( j = 0; j < numsurfaces; j++ ) {
  381.             in = surfaces[ j ].verts;
  382.             for( k = 0; k < surfaces[ j ].numVerts; k++, in++ ) {
  383.                 if ( CompareVert( out, in, qfalse ) ) {
  384.                     VectorAdd( out->normal, in->normal, out->normal );
  385.                 }
  386.             }
  387.         }
  388.  
  389.         VectorNormalize( out->normal, out->normal );
  390.     }
  391. }
  392.  
  393. /*
  394. ================
  395. EmitTerrainVerts
  396. ================
  397. */
  398. void EmitTerrainVerts( side_t *side, terrainSurf_t *surf, int maxlayer, int alpha[ MAX_POINTS_ON_WINDING ], qboolean projecttexture ) {
  399.     int            i;
  400.     int            j;
  401.     drawVert_t    *vert;
  402.     int            *indices;
  403.     int            numindices;
  404.     int            maxindices;
  405.     int            xyplane;
  406.     vec3_t        xynorm = { 0, 0, 1 };
  407.     vec_t        shift[ 2 ] = { 0, 0 };
  408.     vec_t        scale[ 2 ] = { 0.5, 0.5 };
  409.     float        vecs[ 2 ][ 4 ];
  410.  
  411.     if ( !surf->verts ) {
  412.         surf->numVerts        = 0;
  413.         surf->maxVerts        = GROW_VERTS;
  414.         surf->verts            = malloc( surf->maxVerts * sizeof( *surf->verts ) );
  415.  
  416.         surf->numIndexes    = 0;
  417.         surf->maxIndexes    = GROW_INDICES;
  418.         surf->indexes        = malloc( surf->maxIndexes * sizeof( *surf->indexes ) );
  419.     }
  420.  
  421.     // calculate the texture coordinate vectors
  422.     xyplane = FindFloatPlane( xynorm, 0 );
  423.     QuakeTextureVecs( &mapplanes[ xyplane ], shift, 0, scale, vecs );
  424.  
  425.     // emit the vertexes
  426.     numindices = 0;
  427.     maxindices = surf->maxIndexes;
  428.     indices = malloc ( maxindices * sizeof( *indices ) );
  429.  
  430.     for ( i = 0; i < side->winding->numpoints; i++ ) {
  431.         vert = &surf->verts[ surf->numVerts ];
  432.  
  433.         // set the final alpha value--0 for texture 1, 255 for texture 2
  434.         if ( alpha[ i ] < maxlayer ) {
  435.             vert->color[3] = 0;
  436.         } else {
  437.             vert->color[3] = 255;
  438.         }
  439.  
  440.         vert->xyz[ 0 ] = floor( side->winding->p[ i ][ 0 ] + 0.1f );
  441.         vert->xyz[ 1 ] = floor( side->winding->p[ i ][ 1 ] + 0.1f );
  442.         vert->xyz[ 2 ] = floor( side->winding->p[ i ][ 2 ] + 0.1f );
  443.  
  444.         // set the texture coordinates
  445.         if ( projecttexture ) {
  446.             vert->st[0] = ( vecs[0][3] + DotProduct( vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
  447.             vert->st[1] = ( vecs[1][3] + DotProduct( vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
  448.         } else {
  449.             vert->st[0] = ( side->vecs[0][3] + DotProduct( side->vecs[ 0 ], vert->xyz ) ) / surf->shader->width;
  450.             vert->st[1] = ( side->vecs[1][3] + DotProduct( side->vecs[ 1 ], vert->xyz ) ) / surf->shader->height;
  451.         }
  452.  
  453.         VectorCopy( mapplanes[ side->planenum ].normal, vert->normal );
  454.  
  455.         for( j = 0; j < surf->numVerts; j++ ) {
  456.             if ( CompareVert( vert, &surf->verts[ j ], qtrue ) ) {
  457.                 break;
  458.             }
  459.         }
  460.         
  461.         if ( numindices >= maxindices ) {
  462.             maxindices += GROW_INDICES;
  463.             indices = realloc( indices, maxindices * sizeof( *indices ) );
  464.         }
  465.  
  466.         if ( j != surf->numVerts ) {
  467.             indices[ numindices++ ] = j;
  468.         } else {
  469.             if ( surf->numVerts >= surf->maxVerts ) {
  470.                 surf->maxVerts += GROW_VERTS;
  471.                 surf->verts = realloc( surf->verts, surf->maxVerts * sizeof( *surf->verts ) );
  472.             }
  473.  
  474.             indices[ numindices++ ] = surf->numVerts;
  475.             surf->numVerts++;
  476.         }
  477.     }
  478.  
  479.     SideAsTristrip( surf, indices, numindices );
  480.  
  481.     free( indices );
  482. }
  483.  
  484. /*
  485. ================
  486. SurfaceForShader
  487. ================
  488. */
  489. terrainSurf_t *SurfaceForShader( shaderInfo_t *shader, int x, int y ) {
  490.     int i;
  491.  
  492.     if ( lastSurface && ( lastSurface->shader == shader ) && ( lastSurface->x == x ) && ( lastSurface->y == y ) ) {
  493.         return lastSurface;
  494.     }
  495.  
  496.     lastSurface = surfaces;
  497.     for( i = 0; i < numsurfaces; i++, lastSurface++ ) {
  498.         if ( ( lastSurface->shader == shader ) && ( lastSurface->x == x ) && ( lastSurface->y == y ) ) {
  499.             return lastSurface;
  500.         }
  501.     }
  502.  
  503.     if ( numsurfaces >= maxsurfaces ) {
  504.         maxsurfaces += GROW_SURFACES;
  505.         surfaces = realloc( surfaces, maxsurfaces * sizeof( *surfaces ) );
  506.         memset( surfaces + numsurfaces + 1, 0, ( maxsurfaces - numsurfaces - 1 ) * sizeof( *surfaces ) );
  507.     }
  508.  
  509.     lastSurface= &surfaces[ numsurfaces++ ];
  510.     lastSurface->shader = shader;
  511.     lastSurface->x = x;
  512.     lastSurface->y = y;
  513.  
  514.     return lastSurface;
  515. }
  516.  
  517. /*
  518. ================
  519. SetTerrainTextures
  520. ================
  521. */
  522. void SetTerrainTextures( void ) {
  523.     int                i;
  524.     int                x, y;
  525.     int                layer;
  526.     int                minlayer, maxlayer;
  527.     float            s, t;
  528.     float            min_s, min_t;
  529.     int                alpha[ MAX_POINTS_ON_WINDING ];
  530.     shaderInfo_t    *si, *terrainShader;
  531.     bspbrush_t        *brush;
  532.     side_t            *side;
  533.     const char        *shadername;
  534.     vec3_t            mins, maxs;
  535.     vec3_t            size;
  536.     int                surfwidth, surfheight, surfsize;
  537.     terrainSurf_t    *surf;
  538.     byte            *alphamap;
  539.     int                alphawidth, alphaheight;
  540.     int                num_layers;
  541.     extern qboolean    onlyents;
  542.  
  543.     if ( onlyents ) {
  544.         return;
  545.     }
  546.  
  547.     shadername = ValueForKey( mapent, "shader" );
  548.     if ( !shadername[ 0 ] ) {
  549.         Error ("SetTerrainTextures: shader not specified" );
  550.     }
  551.  
  552.     alphamap = LoadAlphaMap( &num_layers, &alphawidth, &alphaheight );
  553.     num_layers = 3;
  554.  
  555.     mapent->firstDrawSurf = numMapDrawSurfs;
  556.  
  557.     // calculate the size of the terrain
  558.     CalcTerrainSize( mins, maxs, size );
  559.  
  560.     surfwidth    = ( size[ 0 ] + SURF_WIDTH - 1 ) / SURF_WIDTH;
  561.     surfheight    = ( size[ 1 ] + SURF_HEIGHT - 1 ) / SURF_HEIGHT;
  562.     surfsize = surfwidth * surfheight;
  563.  
  564.     lastSurface = NULL;
  565.     numsurfaces = 0;
  566.     maxsurfaces = 0;
  567.     for( i = num_layers; i > 0; i-- ) {
  568.         maxsurfaces += i * surfsize;
  569.     }
  570.     surfaces = malloc( maxsurfaces * sizeof( *surfaces ) );
  571.     memset( surfaces, 0, maxsurfaces * sizeof( *surfaces ) );
  572.  
  573.     terrainShader = ShaderInfoForShader( "textures/common/terrain" );
  574.  
  575.     for( brush = mapent->brushes; brush != NULL; brush = brush->next ) {
  576.         // only create surfaces for sides marked as terrain
  577.         for( side = brush->sides; side < &brush->sides[ brush->numsides ]; side++ ) {
  578.             if ( !side->shaderInfo ) {
  579.                 continue;
  580.             }
  581.  
  582.             if ( ( ( side->surfaceFlags | side->shaderInfo->surfaceFlags ) & SURF_NODRAW ) && !strstr( side->shaderInfo->shader, "terrain" ) ) {
  583.                 continue;
  584.             }
  585.  
  586.             minlayer = num_layers;
  587.             maxlayer = 0;
  588.  
  589.             // project each point of the winding onto the alphamap to determine which
  590.             // textures to blend
  591.             min_s = 1.0;
  592.             min_t = 1.0;
  593.             for( i = 0; i < side->winding->numpoints; i++ ) {
  594.                 s = floor( side->winding->p[ i ][ 0 ] + 0.1f - mins[ 0 ] ) / size[ 0 ];
  595.                 t = floor( maxs[ 1 ] - side->winding->p[ i ][ 1 ] + 0.1f ) / size[ 1 ];
  596.  
  597.                 if ( s < 0 ) {
  598.                     s = 0;
  599.                 }
  600.                 
  601.                 if ( t < 0 ) {
  602.                     t = 0;
  603.                 }
  604.  
  605.                 if ( s >= 1.0 ) {
  606.                     s = 1.0;
  607.                 }
  608.  
  609.                 if ( t >= 1.0 ) {
  610.                     t = 1.0;
  611.                 }
  612.  
  613.                 if ( s < min_s ) {
  614.                     min_s = s;
  615.                 }
  616.  
  617.                 if ( t < min_t ) {
  618.                     min_t = t;
  619.                 }
  620.  
  621.                 x = ( alphawidth - 1 ) * s;
  622.                 y = ( alphaheight - 1 ) * t;
  623.  
  624.                 layer = alphamap[ x + y * alphawidth ];
  625.                 if ( layer < minlayer ) {
  626.                     minlayer = layer;
  627.                 }
  628.  
  629.                 if ( layer > maxlayer ) {
  630.                     maxlayer = layer;
  631.                 }
  632.  
  633.                 alpha[ i ] = layer;
  634.             }
  635.  
  636.             x = min_s * surfwidth;
  637.             if ( x >= surfwidth ) {
  638.                 x = surfwidth - 1;
  639.             }
  640.  
  641.             y = min_t * surfheight;
  642.             if ( y >= surfheight ) {
  643.                 y = surfheight - 1;
  644.             }
  645.  
  646.             if ( strstr( side->shaderInfo->shader, "terrain" ) ) {
  647.                 si = ShaderForLayer( minlayer, maxlayer, shadername );
  648.                 if ( showseams ) {
  649.                     for( i = 0; i < side->winding->numpoints; i++ ) {
  650.                         if ( ( alpha[ i ] != minlayer ) && ( alpha[ i ] != maxlayer ) ) {
  651.                             si = ShaderInfoForShader( "textures/common/white" );
  652.                             break;
  653.                         }
  654.                     }
  655.                 }
  656.                 surf = SurfaceForShader( si, x, y );
  657.                 EmitTerrainVerts( side, surf, maxlayer, alpha, qtrue );
  658.             } else {
  659.                 si = side->shaderInfo;
  660.                 side->shaderInfo = terrainShader;
  661.                 surf = SurfaceForShader( si, x, y );
  662.                 EmitTerrainVerts( side, surf, maxlayer, alpha, qfalse );
  663.             }
  664.         }
  665.     }
  666.  
  667.     // create the final surfaces
  668.     for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
  669.         if ( surf->numVerts ) {
  670.             CreateTerrainSurface( surf, surf->shader );
  671.         }
  672.     }
  673.  
  674.     //
  675.     // clean up any allocated memory
  676.     //
  677.     for( surf = surfaces, i = 0; i < numsurfaces; i++, surf++ ) {
  678.         if ( surf->verts ) {
  679.             free( surf->verts );
  680.             free( surf->indexes );
  681.         }
  682.     }
  683.     free( alphamap );
  684.     free( surfaces );
  685.  
  686.     surfaces = NULL;
  687.     lastSurface = NULL;
  688.     numsurfaces = 0;
  689.     maxsurfaces = 0;
  690. }
  691.