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

tr_bsp.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 // tr_map.c
00023 
00024 #include "tr_local.h"
00025 
00026 /*
00027 
00028 Loads and prepares a map file for scene rendering.
00029 
00030 A single entry point:
00031 
00032 void RE_LoadWorldMap( const char *name );
00033 
00034 */
00035 
00036 static  world_t     s_worldData;
00037 static  byte        *fileBase;
00038 
00039 int         c_subdivisions;
00040 int         c_gridVerts;
00041 
00042 //===============================================================================
00043 
00044 static void HSVtoRGB( float h, float s, float v, float rgb[3] )
00045 {
00046     int i;
00047     float f;
00048     float p, q, t;
00049 
00050     h *= 5;
00051 
00052     i = floor( h );
00053     f = h - i;
00054 
00055     p = v * ( 1 - s );
00056     q = v * ( 1 - s * f );
00057     t = v * ( 1 - s * ( 1 - f ) );
00058 
00059     switch ( i )
00060     {
00061     case 0:
00062         rgb[0] = v;
00063         rgb[1] = t;
00064         rgb[2] = p;
00065         break;
00066     case 1:
00067         rgb[0] = q;
00068         rgb[1] = v;
00069         rgb[2] = p;
00070         break;
00071     case 2:
00072         rgb[0] = p;
00073         rgb[1] = v;
00074         rgb[2] = t;
00075         break;
00076     case 3:
00077         rgb[0] = p;
00078         rgb[1] = q;
00079         rgb[2] = v;
00080         break;
00081     case 4:
00082         rgb[0] = t;
00083         rgb[1] = p;
00084         rgb[2] = v;
00085         break;
00086     case 5:
00087         rgb[0] = v;
00088         rgb[1] = p;
00089         rgb[2] = q;
00090         break;
00091     }
00092 }
00093 
00094 /*
00095 ===============
00096 R_ColorShiftLightingBytes
00097 
00098 ===============
00099 */
00100 static  void R_ColorShiftLightingBytes( byte in[4], byte out[4] ) {
00101     int     shift, r, g, b;
00102 
00103     // shift the color data based on overbright range
00104     shift = r_mapOverBrightBits->integer - tr.overbrightBits;
00105 
00106     // shift the data based on overbright range
00107     r = in[0] << shift;
00108     g = in[1] << shift;
00109     b = in[2] << shift;
00110     
00111     // normalize by color instead of saturating to white
00112     if ( ( r | g | b ) > 255 ) {
00113         int     max;
00114 
00115         max = r > g ? r : g;
00116         max = max > b ? max : b;
00117         r = r * 255 / max;
00118         g = g * 255 / max;
00119         b = b * 255 / max;
00120     }
00121 
00122     out[0] = r;
00123     out[1] = g;
00124     out[2] = b;
00125     out[3] = in[3];
00126 }
00127 
00128 /*
00129 ===============
00130 R_LoadLightmaps
00131 
00132 ===============
00133 */
00134 #define LIGHTMAP_SIZE   128
00135 static  void R_LoadLightmaps( lump_t *l ) {
00136     byte        *buf, *buf_p;
00137     int         len;
00138     MAC_STATIC byte     image[LIGHTMAP_SIZE*LIGHTMAP_SIZE*4];
00139     int         i, j;
00140     float maxIntensity = 0;
00141     double sumIntensity = 0;
00142 
00143     len = l->filelen;
00144     if ( !len ) {
00145         return;
00146     }
00147     buf = fileBase + l->fileofs;
00148 
00149     // we are about to upload textures
00150     R_SyncRenderThread();
00151 
00152     // create all the lightmaps
00153     tr.numLightmaps = len / (LIGHTMAP_SIZE * LIGHTMAP_SIZE * 3);
00154     if ( tr.numLightmaps == 1 ) {
00155         //FIXME: HACK: maps with only one lightmap turn up fullbright for some reason.
00156         //this avoids this, but isn't the correct solution.
00157         tr.numLightmaps++;
00158     }
00159 
00160     // if we are in r_vertexLight mode, we don't need the lightmaps at all
00161     if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
00162         return;
00163     }
00164 
00165     for ( i = 0 ; i < tr.numLightmaps ; i++ ) {
00166         // expand the 24 bit on-disk to 32 bit
00167         buf_p = buf + i * LIGHTMAP_SIZE*LIGHTMAP_SIZE * 3;
00168 
00169         if ( r_lightmap->integer == 2 )
00170         {   // color code by intensity as development tool  (FIXME: check range)
00171             for ( j = 0; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ )
00172             {
00173                 float r = buf_p[j*3+0];
00174                 float g = buf_p[j*3+1];
00175                 float b = buf_p[j*3+2];
00176                 float intensity;
00177                 float out[3];
00178 
00179                 intensity = 0.33f * r + 0.685f * g + 0.063f * b;
00180 
00181                 if ( intensity > 255 )
00182                     intensity = 1.0f;
00183                 else
00184                     intensity /= 255.0f;
00185 
00186                 if ( intensity > maxIntensity )
00187                     maxIntensity = intensity;
00188 
00189                 HSVtoRGB( intensity, 1.00, 0.50, out );
00190 
00191                 image[j*4+0] = out[0] * 255;
00192                 image[j*4+1] = out[1] * 255;
00193                 image[j*4+2] = out[2] * 255;
00194                 image[j*4+3] = 255;
00195 
00196                 sumIntensity += intensity;
00197             }
00198         } else {
00199             for ( j = 0 ; j < LIGHTMAP_SIZE * LIGHTMAP_SIZE; j++ ) {
00200                 R_ColorShiftLightingBytes( &buf_p[j*3], &image[j*4] );
00201                 image[j*4+3] = 255;
00202             }
00203         }
00204         tr.lightmaps[i] = R_CreateImage( va("*lightmap%d",i), image, 
00205             LIGHTMAP_SIZE, LIGHTMAP_SIZE, qfalse, qfalse, GL_CLAMP );
00206     }
00207 
00208     if ( r_lightmap->integer == 2 ) {
00209         ri.Printf( PRINT_ALL, "Brightest lightmap value: %d\n", ( int ) ( maxIntensity * 255 ) );
00210     }
00211 }
00212 
00213 
00214 /*
00215 =================
00216 RE_SetWorldVisData
00217 
00218 This is called by the clipmodel subsystem so we can share the 1.8 megs of
00219 space in big maps...
00220 =================
00221 */
00222 void        RE_SetWorldVisData( const byte *vis ) {
00223     tr.externalVisData = vis;
00224 }
00225 
00226 
00227 /*
00228 =================
00229 R_LoadVisibility
00230 =================
00231 */
00232 static  void R_LoadVisibility( lump_t *l ) {
00233     int     len;
00234     byte    *buf;
00235 
00236     len = ( s_worldData.numClusters + 63 ) & ~63;
00237     s_worldData.novis = ri.Hunk_Alloc( len, h_low );
00238     Com_Memset( s_worldData.novis, 0xff, len );
00239 
00240     len = l->filelen;
00241     if ( !len ) {
00242         return;
00243     }
00244     buf = fileBase + l->fileofs;
00245 
00246     s_worldData.numClusters = LittleLong( ((int *)buf)[0] );
00247     s_worldData.clusterBytes = LittleLong( ((int *)buf)[1] );
00248 
00249     // CM_Load should have given us the vis data to share, so
00250     // we don't need to allocate another copy
00251     if ( tr.externalVisData ) {
00252         s_worldData.vis = tr.externalVisData;
00253     } else {
00254         byte    *dest;
00255 
00256         dest = ri.Hunk_Alloc( len - 8, h_low );
00257         Com_Memcpy( dest, buf + 8, len - 8 );
00258         s_worldData.vis = dest;
00259     }
00260 }
00261 
00262 //===============================================================================
00263 
00264 
00265 /*
00266 ===============
00267 ShaderForShaderNum
00268 ===============
00269 */
00270 static shader_t *ShaderForShaderNum( int shaderNum, int lightmapNum ) {
00271     shader_t    *shader;
00272     dshader_t   *dsh;
00273 
00274     shaderNum = LittleLong( shaderNum );
00275     if ( shaderNum < 0 || shaderNum >= s_worldData.numShaders ) {
00276         ri.Error( ERR_DROP, "ShaderForShaderNum: bad num %i", shaderNum );
00277     }
00278     dsh = &s_worldData.shaders[ shaderNum ];
00279 
00280     if ( r_vertexLight->integer || glConfig.hardwareType == GLHW_PERMEDIA2 ) {
00281         lightmapNum = LIGHTMAP_BY_VERTEX;
00282     }
00283 
00284     if ( r_fullbright->integer ) {
00285         lightmapNum = LIGHTMAP_WHITEIMAGE;
00286     }
00287 
00288     shader = R_FindShader( dsh->shader, lightmapNum, qtrue );
00289 
00290     // if the shader had errors, just use default shader
00291     if ( shader->defaultShader ) {
00292         return tr.defaultShader;
00293     }
00294 
00295     return shader;
00296 }
00297 
00298 /*
00299 ===============
00300 ParseFace
00301 ===============
00302 */
00303 static void ParseFace( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes  ) {
00304     int         i, j;
00305     srfSurfaceFace_t    *cv;
00306     int         numPoints, numIndexes;
00307     int         lightmapNum;
00308     int         sfaceSize, ofsIndexes;
00309 
00310     lightmapNum = LittleLong( ds->lightmapNum );
00311 
00312     // get fog volume
00313     surf->fogIndex = LittleLong( ds->fogNum ) + 1;
00314 
00315     // get shader value
00316     surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum );
00317     if ( r_singleShader->integer && !surf->shader->isSky ) {
00318         surf->shader = tr.defaultShader;
00319     }
00320 
00321     numPoints = LittleLong( ds->numVerts );
00322     if (numPoints > MAX_FACE_POINTS) {
00323         ri.Printf( PRINT_WARNING, "WARNING: MAX_FACE_POINTS exceeded: %i\n", numPoints);
00324     numPoints = MAX_FACE_POINTS;
00325     surf->shader = tr.defaultShader;
00326     }
00327 
00328     numIndexes = LittleLong( ds->numIndexes );
00329 
00330     // create the srfSurfaceFace_t
00331     sfaceSize = ( int ) &((srfSurfaceFace_t *)0)->points[numPoints];
00332     ofsIndexes = sfaceSize;
00333     sfaceSize += sizeof( int ) * numIndexes;
00334 
00335     cv = ri.Hunk_Alloc( sfaceSize, h_low );
00336     cv->surfaceType = SF_FACE;
00337     cv->numPoints = numPoints;
00338     cv->numIndices = numIndexes;
00339     cv->ofsIndices = ofsIndexes;
00340 
00341     verts += LittleLong( ds->firstVert );
00342     for ( i = 0 ; i < numPoints ; i++ ) {
00343         for ( j = 0 ; j < 3 ; j++ ) {
00344             cv->points[i][j] = LittleFloat( verts[i].xyz[j] );
00345         }
00346         for ( j = 0 ; j < 2 ; j++ ) {
00347             cv->points[i][3+j] = LittleFloat( verts[i].st[j] );
00348             cv->points[i][5+j] = LittleFloat( verts[i].lightmap[j] );
00349         }
00350         R_ColorShiftLightingBytes( verts[i].color, (byte *)&cv->points[i][7] );
00351     }
00352 
00353     indexes += LittleLong( ds->firstIndex );
00354     for ( i = 0 ; i < numIndexes ; i++ ) {
00355         ((int *)((byte *)cv + cv->ofsIndices ))[i] = LittleLong( indexes[ i ] );
00356     }
00357 
00358     // take the plane information from the lightmap vector
00359     for ( i = 0 ; i < 3 ; i++ ) {
00360         cv->plane.normal[i] = LittleFloat( ds->lightmapVecs[2][i] );
00361     }
00362     cv->plane.dist = DotProduct( cv->points[0], cv->plane.normal );
00363     SetPlaneSignbits( &cv->plane );
00364     cv->plane.type = PlaneTypeForNormal( cv->plane.normal );
00365 
00366     surf->data = (surfaceType_t *)cv;
00367 }
00368 
00369 
00370 /*
00371 ===============
00372 ParseMesh
00373 ===============
00374 */
00375 static void ParseMesh ( dsurface_t *ds, drawVert_t *verts, msurface_t *surf ) {
00376     srfGridMesh_t   *grid;
00377     int             i, j;
00378     int             width, height, numPoints;
00379     MAC_STATIC drawVert_t points[MAX_PATCH_SIZE*MAX_PATCH_SIZE];
00380     int             lightmapNum;
00381     vec3_t          bounds[2];
00382     vec3_t          tmpVec;
00383     static surfaceType_t    skipData = SF_SKIP;
00384 
00385     lightmapNum = LittleLong( ds->lightmapNum );
00386 
00387     // get fog volume
00388     surf->fogIndex = LittleLong( ds->fogNum ) + 1;
00389 
00390     // get shader value
00391     surf->shader = ShaderForShaderNum( ds->shaderNum, lightmapNum );
00392     if ( r_singleShader->integer && !surf->shader->isSky ) {
00393         surf->shader = tr.defaultShader;
00394     }
00395 
00396     // we may have a nodraw surface, because they might still need to
00397     // be around for movement clipping
00398     if ( s_worldData.shaders[ LittleLong( ds->shaderNum ) ].surfaceFlags & SURF_NODRAW ) {
00399         surf->data = &skipData;
00400         return;
00401     }
00402 
00403     width = LittleLong( ds->patchWidth );
00404     height = LittleLong( ds->patchHeight );
00405 
00406     verts += LittleLong( ds->firstVert );
00407     numPoints = width * height;
00408     for ( i = 0 ; i < numPoints ; i++ ) {
00409         for ( j = 0 ; j < 3 ; j++ ) {
00410             points[i].xyz[j] = LittleFloat( verts[i].xyz[j] );
00411             points[i].normal[j] = LittleFloat( verts[i].normal[j] );
00412         }
00413         for ( j = 0 ; j < 2 ; j++ ) {
00414             points[i].st[j] = LittleFloat( verts[i].st[j] );
00415             points[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] );
00416         }
00417         R_ColorShiftLightingBytes( verts[i].color, points[i].color );
00418     }
00419 
00420     // pre-tesseleate
00421     grid = R_SubdividePatchToGrid( width, height, points );
00422     surf->data = (surfaceType_t *)grid;
00423 
00424     // copy the level of detail origin, which is the center
00425     // of the group of all curves that must subdivide the same
00426     // to avoid cracking
00427     for ( i = 0 ; i < 3 ; i++ ) {
00428         bounds[0][i] = LittleFloat( ds->lightmapVecs[0][i] );
00429         bounds[1][i] = LittleFloat( ds->lightmapVecs[1][i] );
00430     }
00431     VectorAdd( bounds[0], bounds[1], bounds[1] );
00432     VectorScale( bounds[1], 0.5f, grid->lodOrigin );
00433     VectorSubtract( bounds[0], grid->lodOrigin, tmpVec );
00434     grid->lodRadius = VectorLength( tmpVec );
00435 }
00436 
00437 /*
00438 ===============
00439 ParseTriSurf
00440 ===============
00441 */
00442 static void ParseTriSurf( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
00443     srfTriangles_t  *tri;
00444     int             i, j;
00445     int             numVerts, numIndexes;
00446 
00447     // get fog volume
00448     surf->fogIndex = LittleLong( ds->fogNum ) + 1;
00449 
00450     // get shader
00451     surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );
00452     if ( r_singleShader->integer && !surf->shader->isSky ) {
00453         surf->shader = tr.defaultShader;
00454     }
00455 
00456     numVerts = LittleLong( ds->numVerts );
00457     numIndexes = LittleLong( ds->numIndexes );
00458 
00459     tri = ri.Hunk_Alloc( sizeof( *tri ) + numVerts * sizeof( tri->verts[0] ) 
00460         + numIndexes * sizeof( tri->indexes[0] ), h_low );
00461     tri->surfaceType = SF_TRIANGLES;
00462     tri->numVerts = numVerts;
00463     tri->numIndexes = numIndexes;
00464     tri->verts = (drawVert_t *)(tri + 1);
00465     tri->indexes = (int *)(tri->verts + tri->numVerts );
00466 
00467     surf->data = (surfaceType_t *)tri;
00468 
00469     // copy vertexes
00470     ClearBounds( tri->bounds[0], tri->bounds[1] );
00471     verts += LittleLong( ds->firstVert );
00472     for ( i = 0 ; i < numVerts ; i++ ) {
00473         for ( j = 0 ; j < 3 ; j++ ) {
00474             tri->verts[i].xyz[j] = LittleFloat( verts[i].xyz[j] );
00475             tri->verts[i].normal[j] = LittleFloat( verts[i].normal[j] );
00476         }
00477         AddPointToBounds( tri->verts[i].xyz, tri->bounds[0], tri->bounds[1] );
00478         for ( j = 0 ; j < 2 ; j++ ) {
00479             tri->verts[i].st[j] = LittleFloat( verts[i].st[j] );
00480             tri->verts[i].lightmap[j] = LittleFloat( verts[i].lightmap[j] );
00481         }
00482 
00483         R_ColorShiftLightingBytes( verts[i].color, tri->verts[i].color );
00484     }
00485 
00486     // copy indexes
00487     indexes += LittleLong( ds->firstIndex );
00488     for ( i = 0 ; i < numIndexes ; i++ ) {
00489         tri->indexes[i] = LittleLong( indexes[i] );
00490         if ( tri->indexes[i] < 0 || tri->indexes[i] >= numVerts ) {
00491             ri.Error( ERR_DROP, "Bad index in triangle surface" );
00492         }
00493     }
00494 }
00495 
00496 /*
00497 ===============
00498 ParseFlare
00499 ===============
00500 */
00501 static void ParseFlare( dsurface_t *ds, drawVert_t *verts, msurface_t *surf, int *indexes ) {
00502     srfFlare_t      *flare;
00503     int             i;
00504 
00505     // get fog volume
00506     surf->fogIndex = LittleLong( ds->fogNum ) + 1;
00507 
00508     // get shader
00509     surf->shader = ShaderForShaderNum( ds->shaderNum, LIGHTMAP_BY_VERTEX );
00510     if ( r_singleShader->integer && !surf->shader->isSky ) {
00511         surf->shader = tr.defaultShader;
00512     }
00513 
00514     flare = ri.Hunk_Alloc( sizeof( *flare ), h_low );
00515     flare->surfaceType = SF_FLARE;
00516 
00517     surf->data = (surfaceType_t *)flare;
00518 
00519     for ( i = 0 ; i < 3 ; i++ ) {
00520         flare->origin[i] = LittleFloat( ds->lightmapOrigin[i] );
00521         flare->color[i] = LittleFloat( ds->lightmapVecs[0][i] );
00522         flare->normal[i] = LittleFloat( ds->lightmapVecs[2][i] );
00523     }
00524 }
00525 
00526 
00527 /*
00528 =================
00529 R_MergedWidthPoints
00530 
00531 returns true if there are grid points merged on a width edge
00532 =================
00533 */
00534 int R_MergedWidthPoints(srfGridMesh_t *grid, int offset) {
00535     int i, j;
00536 
00537     for (i = 1; i < grid->width-1; i++) {
00538         for (j = i + 1; j < grid->width-1; j++) {
00539             if ( fabs(grid->verts[i + offset].xyz[0] - grid->verts[j + offset].xyz[0]) > .1) continue;
00540             if ( fabs(grid->verts[i + offset].xyz[1] - grid->verts[j + offset].xyz[1]) > .1) continue;
00541             if ( fabs(grid->verts[i + offset].xyz[2] - grid->verts[j + offset].xyz[2]) > .1) continue;
00542             return qtrue;
00543         }
00544     }
00545     return qfalse;
00546 }
00547 
00548 /*
00549 =================
00550 R_MergedHeightPoints
00551 
00552 returns true if there are grid points merged on a height edge
00553 =================
00554 */
00555 int R_MergedHeightPoints(srfGridMesh_t *grid, int offset) {
00556     int i, j;
00557 
00558     for (i = 1; i < grid->height-1; i++) {
00559         for (j = i + 1; j < grid->height-1; j++) {
00560             if ( fabs(grid->verts[grid->width * i + offset].xyz[0] - grid->verts[grid->width * j + offset].xyz[0]) > .1) continue;
00561             if ( fabs(grid->verts[grid->width * i + offset].xyz[1] - grid->verts[grid->width * j + offset].xyz[1]) > .1) continue;
00562             if ( fabs(grid->verts[grid->width * i + offset].xyz[2] - grid->verts[grid->width * j + offset].xyz[2]) > .1) continue;
00563             return qtrue;
00564         }
00565     }
00566     return qfalse;
00567 }
00568 
00569 /*
00570 =================
00571 R_FixSharedVertexLodError_r
00572 
00573 NOTE: never sync LoD through grid edges with merged points!
00574 
00575 FIXME: write generalized version that also avoids cracks between a patch and one that meets half way?
00576 =================
00577 */
00578 void R_FixSharedVertexLodError_r( int start, srfGridMesh_t *grid1 ) {
00579     int j, k, l, m, n, offset1, offset2, touch;
00580     srfGridMesh_t *grid2;
00581 
00582     for ( j = start; j < s_worldData.numsurfaces; j++ ) {
00583         //
00584         grid2 = (srfGridMesh_t *) s_worldData.surfaces[j].data;
00585         // if this surface is not a grid
00586         if ( grid2->surfaceType != SF_GRID ) continue;
00587         // if the LOD errors are already fixed for this patch
00588         if ( grid2->lodFixed == 2 ) continue;
00589         // grids in the same LOD group should have the exact same lod radius
00590         if ( grid1->lodRadius != grid2->lodRadius ) continue;
00591         // grids in the same LOD group should have the exact same lod origin
00592         if ( grid1->lodOrigin[0] != grid2->lodOrigin[0] ) continue;
00593         if ( grid1->lodOrigin[1] != grid2->lodOrigin[1] ) continue;
00594         if ( grid1->lodOrigin[2] != grid2->lodOrigin[2] ) continue;
00595         //
00596         touch = qfalse;
00597         for (n = 0; n < 2; n++) {
00598             //
00599             if (n) offset1 = (grid1->height-1) * grid1->width;
00600             else offset1 = 0;
00601             if (R_MergedWidthPoints(grid1, offset1)) continue;
00602             for (k = 1; k < grid1->width-1; k++) {
00603                 for (m = 0; m < 2; m++) {
00604 
00605                     if (m) offset2 = (grid2->height-1) * grid2->width;
00606                     else offset2 = 0;
00607                     if (R_MergedWidthPoints(grid2, offset2)) continue;
00608                     for ( l = 1; l < grid2->width-1; l++) {
00609                     //
00610                         if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;
00611                         if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;
00612                         if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;
00613                         // ok the points are equal and should have the same lod error
00614                         grid2->widthLodError[l] = grid1->widthLodError[k];
00615                         touch = qtrue;
00616                     }
00617                 }
00618                 for (m = 0; m < 2; m++) {
00619 
00620                     if (m) offset2 = grid2->width-1;
00621                     else offset2 = 0;
00622                     if (R_MergedHeightPoints(grid2, offset2)) continue;
00623                     for ( l = 1; l < grid2->height-1; l++) {
00624                     //
00625                         if ( fabs(grid1->verts[k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;
00626                         if ( fabs(grid1->verts[k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;
00627                         if ( fabs(grid1->verts[k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;
00628                         // ok the points are equal and should have the same lod error
00629                         grid2->heightLodError[l] = grid1->widthLodError[k];
00630                         touch = qtrue;
00631                     }
00632                 }
00633             }
00634         }
00635         for (n = 0; n < 2; n++) {
00636             //
00637             if (n) offset1 = grid1->width-1;
00638             else offset1 = 0;
00639             if (R_MergedHeightPoints(grid1, offset1)) continue;
00640             for (k = 1; k < grid1->height-1; k++) {
00641                 for (m = 0; m < 2; m++) {
00642 
00643                     if (m) offset2 = (grid2->height-1) * grid2->width;
00644                     else offset2 = 0;
00645                     if (R_MergedWidthPoints(grid2, offset2)) continue;
00646                     for ( l = 1; l < grid2->width-1; l++) {
00647                     //
00648                         if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[l + offset2].xyz[0]) > .1) continue;
00649                         if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[l + offset2].xyz[1]) > .1) continue;
00650                         if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[l + offset2].xyz[2]) > .1) continue;
00651                         // ok the points are equal and should have the same lod error
00652                         grid2->widthLodError[l] = grid1->heightLodError[k];
00653                         touch = qtrue;
00654                     }
00655                 }
00656                 for (m = 0; m < 2; m++) {
00657 
00658                     if (m) offset2 = grid2->width-1;
00659                     else offset2 = 0;
00660                     if (R_MergedHeightPoints(grid2, offset2)) continue;
00661                     for ( l = 1; l < grid2->height-1; l++) {
00662                     //
00663                         if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[0] - grid2->verts[grid2->width * l + offset2].xyz[0]) > .1) continue;
00664                         if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[1] - grid2->verts[grid2->width * l + offset2].xyz[1]) > .1) continue;
00665                         if ( fabs(grid1->verts[grid1->width * k + offset1].xyz[2] - grid2->verts[grid2->width * l + offset2].xyz[2]) > .1) continue;
00666                         // ok the points are equal and should have the same lod error
00667                         grid2->heightLodError[l] = grid1->heightLodError[k];
00668                         touch = qtrue;
00669                     }
00670                 }
00671             }
00672         }
00673         if (touch) {
00674             grid2->lodFixed = 2;
00675             R_FixSharedVertexLodError_r ( start, grid2 );
00676             //NOTE: this would be correct but makes things really slow
00677             //grid2->lodFixed = 1;
00678         }
00679     }
00680 }
00681 
00682 /*
00683 =================
00684 R_FixSharedVertexLodError
00685 
00686 This function assumes that all patches in one group are nicely stitched together for the highest LoD.
00687 If this is not the case this function will still do its job but won't fix the highest LoD cracks.
00688 =================
00689 */
00690 void R_FixSharedVertexLodError( void ) {
00691     int i;
00692     srfGridMesh_t *grid1;
00693 
00694     for ( i = 0; i < s_worldData.numsurfaces; i++ ) {
00695         //
00696         grid1 = (srfGridMesh_t *) s_worldData.surfaces[i].data;
00697         // if this surface is not a grid
00698         if ( grid1->surfaceType != SF_GRID )
00699             continue;
00700         //
00701         if ( grid1->lodFixed )
00702             continue;
00703         //
00704         grid1->lodFixed = 2;
00705         // recursively fix other patches in the same LOD group
00706         R_FixSharedVertexLodError_r( i + 1, grid1);
00707     }
00708 }
00709 
00710 
00711 /*
00712 ===============
00713 R_StitchPatches
00714 ===============
00715 */
00716 int R_StitchPatches( int grid1num, int grid2num ) {
00717     float *v1, *v2;
00718     srfGridMesh_t *grid1, *grid2;
00719     int k, l, m, n, offset1, offset2, row, column;
00720 
00721     grid1 = (srfGridMesh_t *) s_worldData.surfaces[grid1num].data;
00722     grid2 = (srfGridMesh_t *) s_worldData.surfaces[grid2num].data;
00723     for (n = 0; n < 2; n++) {
00724         //
00725         if (n) offset1 = (grid1->height-1) * grid1->width;
00726         else offset1 = 0;
00727         if (R_MergedWidthPoints(grid1, offset1))
00728             continue;
00729         for (k = 0; k < grid1->width-2; k += 2) {
00730 
00731             for (m = 0; m < 2; m++) {
00732 
00733                 if ( grid2->width >= MAX_GRID_SIZE )
00734                     break;
00735                 if (m) offset2 = (grid2->height-1) * grid2->width;
00736                 else offset2 = 0;
00737                 for ( l = 0; l < grid2->width-1; l++) {
00738                 //
00739                     v1 = grid1->verts[k + offset1].xyz;
00740                     v2 = grid2->verts[l + offset2].xyz;
00741                     if ( fabs(v1[0] - v2[0]) > .1)
00742                         continue;
00743                     if ( fabs(v1[1] - v2[1]) > .1)
00744                         continue;
00745                     if ( fabs(v1[2] - v2[2]) > .1)
00746                         continue;
00747 
00748                     v1 = grid1->verts[k + 2 + offset1].xyz;
00749                     v2 = grid2->verts[l + 1 + offset2].xyz;
00750                     if ( fabs(v1[0] - v2[0]) > .1)
00751                         continue;
00752                     if ( fabs(v1[1] - v2[1]) > .1)
00753                         continue;
00754                     if ( fabs(v1[2] - v2[2]) > .1)
00755                         continue;
00756                     //
00757                     v1 = grid2->verts[l + offset2].xyz;
00758                     v2 = grid2->verts[l + 1 + offset2].xyz;
00759                     if ( fabs(v1[0] - v2[0]) < .01 &&
00760                             fabs(v1[1] - v2[1]) < .01 &&
00761                             fabs(v1[2] - v2[2]) < .01)
00762                         continue;
00763                     //
00764                     //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
00765                     // insert column into grid2 right after after column l
00766                     if (m) row = grid2->height-1;
00767                     else row = 0;
00768                     grid2 = R_GridInsertColumn( grid2, l+1, row,
00769                                     grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);
00770                     grid2->lodStitched = qfalse;
00771                     s_worldData.surfaces[grid2num].data = (void *) grid2;
00772                     return qtrue;
00773                 }
00774             }
00775             for (m = 0; m < 2; m++) {
00776 
00777                 if (grid2->height >= MAX_GRID_SIZE)
00778                     break;
00779                 if (m) offset2 = grid2->width-1;
00780                 else offset2 = 0;
00781                 for ( l = 0; l < grid2->height-1; l++) {
00782                     //
00783                     v1 = grid1->verts[k + offset1].xyz;
00784                     v2 = grid2->verts[grid2->width * l + offset2].xyz;
00785                     if ( fabs(v1[0] - v2[0]) > .1)
00786                         continue;
00787                     if ( fabs(v1[1] - v2[1]) > .1)
00788                         continue;
00789                     if ( fabs(v1[2] - v2[2]) > .1)
00790                         continue;
00791 
00792                     v1 = grid1->verts[k + 2 + offset1].xyz;
00793                     v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
00794                     if ( fabs(v1[0] - v2[0]) > .1)
00795                         continue;
00796                     if ( fabs(v1[1] - v2[1]) > .1)
00797                         continue;
00798                     if ( fabs(v1[2] - v2[2]) > .1)
00799                         continue;
00800                     //
00801                     v1 = grid2->verts[grid2->width * l + offset2].xyz;
00802                     v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
00803                     if ( fabs(v1[0] - v2[0]) < .01 &&
00804                             fabs(v1[1] - v2[1]) < .01 &&
00805                             fabs(v1[2] - v2[2]) < .01)
00806                         continue;
00807                     //
00808                     //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
00809                     // insert row into grid2 right after after row l
00810                     if (m) column = grid2->width-1;
00811                     else column = 0;
00812                     grid2 = R_GridInsertRow( grid2, l+1, column,
00813                                         grid1->verts[k + 1 + offset1].xyz, grid1->widthLodError[k+1]);
00814                     grid2->lodStitched = qfalse;
00815                     s_worldData.surfaces[grid2num].data = (void *) grid2;
00816                     return qtrue;
00817                 }
00818             }
00819         }
00820     }
00821     for (n = 0; n < 2; n++) {
00822         //
00823         if (n) offset1 = grid1->width-1;
00824         else offset1 = 0;
00825         if (R_MergedHeightPoints(grid1, offset1))
00826             continue;
00827         for (k = 0; k < grid1->height-2; k += 2) {
00828             for (m = 0; m < 2; m++) {
00829 
00830                 if ( grid2->width >= MAX_GRID_SIZE )
00831                     break;
00832                 if (m) offset2 = (grid2->height-1) * grid2->width;
00833                 else offset2 = 0;
00834                 for ( l = 0; l < grid2->width-1; l++) {
00835                 //
00836                     v1 = grid1->verts[grid1->width * k + offset1].xyz;
00837                     v2 = grid2->verts[l + offset2].xyz;
00838                     if ( fabs(v1[0] - v2[0]) > .1)
00839                         continue;
00840                     if ( fabs(v1[1] - v2[1]) > .1)
00841                         continue;
00842                     if ( fabs(v1[2] - v2[2]) > .1)
00843                         continue;
00844 
00845                     v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
00846                     v2 = grid2->verts[l + 1 + offset2].xyz;
00847                     if ( fabs(v1[0] - v2[0]) > .1)
00848                         continue;
00849                     if ( fabs(v1[1] - v2[1]) > .1)
00850                         continue;
00851                     if ( fabs(v1[2] - v2[2]) > .1)
00852                         continue;
00853                     //
00854                     v1 = grid2->verts[l + offset2].xyz;
00855                     v2 = grid2->verts[(l + 1) + offset2].xyz;
00856                     if ( fabs(v1[0] - v2[0]) < .01 &&
00857                             fabs(v1[1] - v2[1]) < .01 &&
00858                             fabs(v1[2] - v2[2]) < .01)
00859                         continue;
00860                     //
00861                     //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
00862                     // insert column into grid2 right after after column l
00863                     if (m) row = grid2->height-1;
00864                     else row = 0;
00865                     grid2 = R_GridInsertColumn( grid2, l+1, row,
00866                                     grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);
00867                     grid2->lodStitched = qfalse;
00868                     s_worldData.surfaces[grid2num].data = (void *) grid2;
00869                     return qtrue;
00870                 }
00871             }
00872             for (m = 0; m < 2; m++) {
00873 
00874                 if (grid2->height >= MAX_GRID_SIZE)
00875                     break;
00876                 if (m) offset2 = grid2->width-1;
00877                 else offset2 = 0;
00878                 for ( l = 0; l < grid2->height-1; l++) {
00879                 //
00880                     v1 = grid1->verts[grid1->width * k + offset1].xyz;
00881                     v2 = grid2->verts[grid2->width * l + offset2].xyz;
00882                     if ( fabs(v1[0] - v2[0]) > .1)
00883                         continue;
00884                     if ( fabs(v1[1] - v2[1]) > .1)
00885                         continue;
00886                     if ( fabs(v1[2] - v2[2]) > .1)
00887                         continue;
00888 
00889                     v1 = grid1->verts[grid1->width * (k + 2) + offset1].xyz;
00890                     v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
00891                     if ( fabs(v1[0] - v2[0]) > .1)
00892                         continue;
00893                     if ( fabs(v1[1] - v2[1]) > .1)
00894                         continue;
00895                     if ( fabs(v1[2] - v2[2]) > .1)
00896                         continue;
00897                     //
00898                     v1 = grid2->verts[grid2->width * l + offset2].xyz;
00899                     v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
00900                     if ( fabs(v1[0] - v2[0]) < .01 &&
00901                             fabs(v1[1] - v2[1]) < .01 &&
00902                             fabs(v1[2] - v2[2]) < .01)
00903                         continue;
00904                     //
00905                     //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
00906                     // insert row into grid2 right after after row l
00907                     if (m) column = grid2->width-1;
00908                     else column = 0;
00909                     grid2 = R_GridInsertRow( grid2, l+1, column,
00910                                     grid1->verts[grid1->width * (k + 1) + offset1].xyz, grid1->heightLodError[k+1]);
00911                     grid2->lodStitched = qfalse;
00912                     s_worldData.surfaces[grid2num].data = (void *) grid2;
00913                     return qtrue;
00914                 }
00915             }
00916         }
00917     }
00918     for (n = 0; n < 2; n++) {
00919         //
00920         if (n) offset1 = (grid1->height-1) * grid1->width;
00921         else offset1 = 0;
00922         if (R_MergedWidthPoints(grid1, offset1))
00923             continue;
00924         for (k = grid1->width-1; k > 1; k -= 2) {
00925 
00926             for (m = 0; m < 2; m++) {
00927 
00928                 if ( grid2->width >= MAX_GRID_SIZE )
00929                     break;
00930                 if (m) offset2 = (grid2->height-1) * grid2->width;
00931                 else offset2 = 0;
00932                 for ( l = 0; l < grid2->width-1; l++) {
00933                 //
00934                     v1 = grid1->verts[k + offset1].xyz;
00935                     v2 = grid2->verts[l + offset2].xyz;
00936                     if ( fabs(v1[0] - v2[0]) > .1)
00937                         continue;
00938                     if ( fabs(v1[1] - v2[1]) > .1)
00939                         continue;
00940                     if ( fabs(v1[2] - v2[2]) > .1)
00941                         continue;
00942 
00943                     v1 = grid1->verts[k - 2 + offset1].xyz;
00944                     v2 = grid2->verts[l + 1 + offset2].xyz;
00945                     if ( fabs(v1[0] - v2[0]) > .1)
00946                         continue;
00947                     if ( fabs(v1[1] - v2[1]) > .1)
00948                         continue;
00949                     if ( fabs(v1[2] - v2[2]) > .1)
00950                         continue;
00951                     //
00952                     v1 = grid2->verts[l + offset2].xyz;
00953                     v2 = grid2->verts[(l + 1) + offset2].xyz;
00954                     if ( fabs(v1[0] - v2[0]) < .01 &&
00955                             fabs(v1[1] - v2[1]) < .01 &&
00956                             fabs(v1[2] - v2[2]) < .01)
00957                         continue;
00958                     //
00959                     //ri.Printf( PRINT_ALL, "found highest LoD crack between two patches\n" );
00960                     // insert column into grid2 right after after column l
00961                     if (m) row = grid2->height-1;
00962                     else row = 0;
00963                     grid2 = R_GridInsertColumn( grid2, l+1, row,
00964                                         grid1->verts[k - 1 + offset1].xyz, grid1->widthLodError[k+1]);
00965                     grid2->lodStitched = qfalse;
00966                     s_worldData.surfaces[grid2num].data = (void *) grid2;
00967                     return qtrue;
00968                 }
00969             }
00970             for (m = 0; m < 2; m++) {
00971 
00972                 if (grid2->height >= MAX_GRID_SIZE)
00973                     break;
00974                 if (m) offset2 = grid2->width-1;
00975                 else offset2 = 0;
00976                 for ( l = 0; l < grid2->height-1; l++) {
00977                 //
00978                     v1 = grid1->verts[k + offset1].xyz;
00979                     v2 = grid2->verts[grid2->width * l + offset2].xyz;
00980                     if ( fabs(v1[0] - v2[0]) > .1)
00981                         continue;
00982                     if ( fabs(v1[1] - v2[1]) > .1)
00983                         continue;
00984                     if ( fabs(v1[2] - v2[2]) > .1)
00985                         continue;
00986 
00987                     v1 = grid1->verts[k - 2 + offset1].xyz;
00988                     v2 = grid2->verts[grid2->width * (l + 1) + offset2].xyz;
00989                     if ( fabs(v1[0] - v2[0]) > .1)
00990                         continue;
00991                     if ( fabs(v1[1] - v2[1]) > .1)
00992                         continue;
00993                     if ( fabs(v1[2] - v2[2]) > .1)
00994                         continue;
00995                     //
00996