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

lightmaps.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 #include "qbsp.h"
00023 
00024 
00025 /*
00026 
00027   Lightmap allocation has to be done after all flood filling and
00028   visible surface determination.
00029 
00030 */
00031 
00032 int                 numSortShaders;
00033 mapDrawSurface_t    *surfsOnShader[MAX_MAP_SHADERS];
00034 
00035 
00036 int     allocated[LIGHTMAP_WIDTH];
00037 
00038 int     numLightmaps = 1;
00039 int     c_exactLightmap;
00040 
00041 
00042 void PrepareNewLightmap( void ) {
00043     memset( allocated, 0, sizeof( allocated ) );
00044     numLightmaps++;
00045 }
00046 
00047 /*
00048 ===============
00049 AllocLMBlock
00050 
00051 returns a texture number and the position inside it
00052 ===============
00053 */
00054 qboolean AllocLMBlock (int w, int h, int *x, int *y)
00055 {
00056     int     i, j;
00057     int     best, best2;
00058 
00059     best = LIGHTMAP_HEIGHT;
00060 
00061     for ( i=0 ; i <= LIGHTMAP_WIDTH-w ; i++ ) {
00062         best2 = 0;
00063 
00064         for (j=0 ; j<w ; j++) {
00065             if (allocated[i+j] >= best) {
00066                 break;
00067             }
00068             if (allocated[i+j] > best2) {
00069                 best2 = allocated[i+j];
00070             }
00071         }
00072         if (j == w) {   // this is a valid spot
00073             *x = i;
00074             *y = best = best2;
00075         }
00076     }
00077 
00078     if (best + h > LIGHTMAP_HEIGHT) {
00079         return qfalse;
00080     }
00081 
00082     for (i=0 ; i<w ; i++) {
00083         allocated[*x + i] = best + h;
00084     }
00085 
00086     return qtrue;
00087 }
00088 
00089 
00090 /*
00091 ===================
00092 AllocateLightmapForPatch
00093 ===================
00094 */
00095 //#define LIGHTMAP_PATCHSHIFT
00096 
00097 void AllocateLightmapForPatch( mapDrawSurface_t *ds ) {
00098     int         i, j, k;
00099     drawVert_t  *verts;
00100     int         w, h;
00101     int         x, y;
00102     float       s, t;
00103     mesh_t      mesh, *subdividedMesh, *tempMesh, *newmesh;
00104     int         widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize;
00105 
00106     verts = ds->verts;
00107 
00108     mesh.width = ds->patchWidth;
00109     mesh.height = ds->patchHeight;
00110     mesh.verts = verts;
00111     newmesh = SubdivideMesh( mesh, 8, 999 );
00112 
00113     PutMeshOnCurve( *newmesh );
00114     tempMesh = RemoveLinearMeshColumnsRows( newmesh );
00115     FreeMesh(newmesh);
00116 
00117     ssize = samplesize;
00118     if (ds->shaderInfo->lightmapSampleSize)
00119         ssize = ds->shaderInfo->lightmapSampleSize;
00120 
00121 #ifdef LIGHTMAP_PATCHSHIFT
00122     subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH-1, widthtable, heighttable);
00123 #else
00124     subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH, widthtable, heighttable);
00125 #endif
00126 
00127     w = subdividedMesh->width;
00128     h = subdividedMesh->height;
00129 
00130 #ifdef LIGHTMAP_PATCHSHIFT
00131     w++;
00132     h++;
00133 #endif
00134 
00135     FreeMesh(subdividedMesh);
00136 
00137     // allocate the lightmap
00138     c_exactLightmap += w * h;
00139 
00140     if ( !AllocLMBlock( w, h, &x, &y ) ) {
00141         PrepareNewLightmap();
00142         if ( !AllocLMBlock( w, h, &x, &y ) ) {
00143             Error("Entity %i, brush %i: Lightmap allocation failed", 
00144                 ds->mapBrush->entitynum, ds->mapBrush->brushnum );
00145         }
00146     }
00147 
00148 #ifdef LIGHTMAP_PATCHSHIFT
00149     w--;
00150     h--;
00151 #endif
00152 
00153     // set the lightmap texture coordinates in the drawVerts
00154     ds->lightmapNum = numLightmaps - 1;
00155     ds->lightmapWidth = w;
00156     ds->lightmapHeight = h;
00157     ds->lightmapX = x;
00158     ds->lightmapY = y;
00159 
00160     for ( i = 0 ; i < ds->patchWidth ; i++ ) {
00161         for ( k = 0 ; k < w ; k++ ) {
00162             if ( originalWidths[k] >= i ) {
00163                 break;
00164             }
00165         }
00166         if (k >= w)
00167             k = w-1;
00168         s = x + k;
00169         for ( j = 0 ; j < ds->patchHeight ; j++ ) {
00170             for ( k = 0 ; k < h ; k++ ) {
00171                 if ( originalHeights[k] >= j ) {
00172                     break;
00173                 }
00174             }
00175             if (k >= h)
00176                 k = h-1;
00177             t = y + k;
00178             verts[i + j * ds->patchWidth].lightmap[0] = ( s + 0.5 ) / LIGHTMAP_WIDTH;
00179             verts[i + j * ds->patchWidth].lightmap[1] = ( t + 0.5 ) / LIGHTMAP_HEIGHT;
00180         }
00181     }
00182 }
00183 
00184 
00185 /*
00186 ===================
00187 AllocateLightmapForSurface
00188 ===================
00189 */
00190 //#define   LIGHTMAP_BLOCK  16
00191 void AllocateLightmapForSurface( mapDrawSurface_t *ds ) {
00192     vec3_t      mins, maxs, size, exactSize, delta;
00193     int         i;
00194     drawVert_t  *verts;
00195     int         w, h;
00196     int         x, y, ssize;
00197     int         axis;
00198     vec3_t      vecs[2];
00199     float       s, t;
00200     vec3_t      origin;
00201     plane_t     *plane;
00202     float       d;
00203     vec3_t      planeNormal;
00204 
00205     if ( ds->patch ) {
00206         AllocateLightmapForPatch( ds );
00207         return;
00208     }
00209 
00210     ssize = samplesize;
00211     if (ds->shaderInfo->lightmapSampleSize)
00212         ssize = ds->shaderInfo->lightmapSampleSize;
00213 
00214     plane = &mapplanes[ ds->side->planenum ];
00215 
00216     // bound the surface
00217     ClearBounds( mins, maxs );
00218     verts = ds->verts;
00219     for ( i = 0 ; i < ds->numVerts ; i++ ) {
00220         AddPointToBounds( verts[i].xyz, mins, maxs );
00221     }
00222 
00223     // round to the lightmap resolution
00224     for ( i = 0 ; i < 3 ; i++ ) {
00225         exactSize[i] = maxs[i] - mins[i];
00226         mins[i] = ssize * floor( mins[i] / ssize );
00227         maxs[i] = ssize * ceil( maxs[i] / ssize );
00228         size[i] = (maxs[i] - mins[i]) / ssize + 1;
00229     }
00230 
00231     // the two largest axis will be the lightmap size
00232     memset( vecs, 0, sizeof( vecs ) );
00233 
00234     planeNormal[0] = fabs( plane->normal[0] );
00235     planeNormal[1] = fabs( plane->normal[1] );
00236     planeNormal[2] = fabs( plane->normal[2] );
00237 
00238     if ( planeNormal[0] >= planeNormal[1] && planeNormal[0] >= planeNormal[2] ) {
00239         w = size[1];
00240         h = size[2];
00241         axis = 0;
00242         vecs[0][1] = 1.0 / ssize;
00243         vecs[1][2] = 1.0 / ssize;
00244     } else if ( planeNormal[1] >= planeNormal[0] && planeNormal[1] >= planeNormal[2] ) {
00245         w = size[0];
00246         h = size[2];
00247         axis = 1;
00248         vecs[0][0] = 1.0 / ssize;
00249         vecs[1][2] = 1.0 / ssize;
00250     } else {
00251         w = size[0];
00252         h = size[1];
00253         axis = 2;
00254         vecs[0][0] = 1.0 / ssize;
00255         vecs[1][1] = 1.0 / ssize;
00256     }
00257 
00258     if ( !plane->normal[axis] ) {
00259         Error( "Chose a 0 valued axis" );
00260     }
00261 
00262     if ( w > LIGHTMAP_WIDTH ) {
00263         VectorScale ( vecs[0], (float)LIGHTMAP_WIDTH/w, vecs[0] );
00264         w = LIGHTMAP_WIDTH;
00265     }
00266     
00267     if ( h > LIGHTMAP_HEIGHT ) {
00268         VectorScale ( vecs[1], (float)LIGHTMAP_HEIGHT/h, vecs[1] );
00269         h = LIGHTMAP_HEIGHT;
00270     }
00271     
00272     c_exactLightmap += w * h;
00273 
00274     if ( !AllocLMBlock( w, h, &x, &y ) ) {
00275         PrepareNewLightmap();
00276         if ( !AllocLMBlock( w, h, &x, &y ) ) {
00277             Error("Entity %i, brush %i: Lightmap allocation failed", 
00278                 ds->mapBrush->entitynum, ds->mapBrush->brushnum );
00279         }
00280     }
00281 
00282     // set the lightmap texture coordinates in the drawVerts
00283     ds->lightmapNum = numLightmaps - 1;
00284     ds->lightmapWidth = w;
00285     ds->lightmapHeight = h;
00286     ds->lightmapX = x;
00287     ds->lightmapY = y;
00288 
00289     for ( i = 0 ; i < ds->numVerts ; i++ ) {
00290         VectorSubtract( verts[i].xyz, mins, delta );
00291         s = DotProduct( delta, vecs[0] ) + x + 0.5;
00292         t = DotProduct( delta, vecs[1] ) + y + 0.5;
00293         verts[i].lightmap[0] = s / LIGHTMAP_WIDTH;
00294         verts[i].lightmap[1] = t / LIGHTMAP_HEIGHT;
00295     }
00296 
00297     // calculate the world coordinates of the lightmap samples
00298 
00299     // project mins onto plane to get origin
00300     d = DotProduct( mins, plane->normal ) - plane->dist;
00301     d /= plane->normal[ axis ];
00302     VectorCopy( mins, origin );
00303     origin[axis] -= d;
00304 
00305     // project stepped lightmap blocks and subtract to get planevecs
00306     for ( i = 0 ; i < 2 ; i++ ) {
00307         vec3_t  normalized;
00308         float   len;
00309 
00310         len = VectorNormalize( vecs[i], normalized );
00311         VectorScale( normalized, (1.0/len), vecs[i] );
00312         d = DotProduct( vecs[i], plane->normal );
00313         d /= plane->normal[ axis ];
00314         vecs[i][axis] -= d;
00315     }
00316 
00317     VectorCopy( origin, ds->lightmapOrigin );
00318     VectorCopy( vecs[0], ds->lightmapVecs[0] );
00319     VectorCopy( vecs[1], ds->lightmapVecs[1] );
00320     VectorCopy( plane->normal, ds->lightmapVecs[2] );
00321 }
00322 
00323 /*
00324 ===================
00325 AllocateLightmaps
00326 ===================
00327 */
00328 void AllocateLightmaps( entity_t *e ) {
00329     int             i, j;
00330     mapDrawSurface_t    *ds;
00331     shaderInfo_t    *si;
00332 
00333     qprintf ("--- AllocateLightmaps ---\n");
00334 
00335 
00336     // sort all surfaces by shader so common shaders will usually
00337     // be in the same lightmap
00338     numSortShaders = 0;
00339 
00340     for ( i = e->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
00341         ds = &mapDrawSurfs[i];
00342         if ( !ds->numVerts ) {
00343             continue;       // leftover from a surface subdivision
00344         }
00345         if ( ds->miscModel ) {
00346             continue;
00347         }
00348         if ( !ds->patch ) {
00349             VectorCopy( mapplanes[ds->side->planenum].normal, ds->lightmapVecs[2] );
00350         }
00351 
00352         // search for this shader
00353         for ( j = 0 ; j < numSortShaders ; j++ ) {
00354             if ( ds->shaderInfo == surfsOnShader[j]->shaderInfo ) {
00355                 ds->nextOnShader = surfsOnShader[j];
00356                 surfsOnShader[j] = ds;
00357                 break;
00358             }
00359         }
00360         if ( j == numSortShaders ) {
00361             if ( numSortShaders >= MAX_MAP_SHADERS ) {
00362                 Error( "MAX_MAP_SHADERS" );
00363             }
00364             surfsOnShader[j] = ds;
00365             numSortShaders++;
00366         }
00367     }
00368     qprintf( "%5i unique shaders\n", numSortShaders );
00369 
00370     // for each shader, allocate lightmaps for each surface
00371 
00372 //  numLightmaps = 0;
00373 //  PrepareNewLightmap();
00374 
00375     for ( i = 0 ; i < numSortShaders ; i++ ) {
00376         si = surfsOnShader[i]->shaderInfo;
00377 
00378         for ( ds = surfsOnShader[i] ; ds ; ds = ds->nextOnShader ) {
00379             // some surfaces don't need lightmaps allocated for them
00380             if ( si->surfaceFlags & SURF_NOLIGHTMAP ) {
00381                 ds->lightmapNum = -1;
00382             } else if ( si->surfaceFlags & SURF_POINTLIGHT ) {
00383                 ds->lightmapNum = -3;
00384             } else {
00385                 AllocateLightmapForSurface( ds );
00386             }
00387         }
00388     }
00389 
00390     qprintf( "%7i exact lightmap texels\n", c_exactLightmap );
00391     qprintf( "%7i block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH*LIGHTMAP_HEIGHT );
00392 }
00393 
00394 
00395 

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