123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- /*
- ===========================================================================
- Copyright (C) 1999-2005 Id Software, Inc.
- This file is part of Quake III Arena source code.
- Quake III Arena source code is free software; you can redistribute it
- and/or modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the License,
- or (at your option) any later version.
- Quake III Arena source code is distributed in the hope that it will be
- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Foobar; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- ===========================================================================
- */
- #include "qbsp.h"
- /*
- Lightmap allocation has to be done after all flood filling and
- visible surface determination.
- */
- int numSortShaders;
- mapDrawSurface_t *surfsOnShader[MAX_MAP_SHADERS];
- int allocated[LIGHTMAP_WIDTH];
- int numLightmaps = 1;
- int c_exactLightmap;
- void PrepareNewLightmap( void ) {
- memset( allocated, 0, sizeof( allocated ) );
- numLightmaps++;
- }
- /*
- ===============
- AllocLMBlock
- returns a texture number and the position inside it
- ===============
- */
- qboolean AllocLMBlock (int w, int h, int *x, int *y)
- {
- int i, j;
- int best, best2;
- best = LIGHTMAP_HEIGHT;
- for ( i=0 ; i <= LIGHTMAP_WIDTH-w ; i++ ) {
- best2 = 0;
- for (j=0 ; j<w ; j++) {
- if (allocated[i+j] >= best) {
- break;
- }
- if (allocated[i+j] > best2) {
- best2 = allocated[i+j];
- }
- }
- if (j == w) { // this is a valid spot
- *x = i;
- *y = best = best2;
- }
- }
- if (best + h > LIGHTMAP_HEIGHT) {
- return qfalse;
- }
- for (i=0 ; i<w ; i++) {
- allocated[*x + i] = best + h;
- }
- return qtrue;
- }
- /*
- ===================
- AllocateLightmapForPatch
- ===================
- */
- //#define LIGHTMAP_PATCHSHIFT
- void AllocateLightmapForPatch( mapDrawSurface_t *ds ) {
- int i, j, k;
- drawVert_t *verts;
- int w, h;
- int x, y;
- float s, t;
- mesh_t mesh, *subdividedMesh, *tempMesh, *newmesh;
- int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize;
- verts = ds->verts;
- mesh.width = ds->patchWidth;
- mesh.height = ds->patchHeight;
- mesh.verts = verts;
- newmesh = SubdivideMesh( mesh, 8, 999 );
- PutMeshOnCurve( *newmesh );
- tempMesh = RemoveLinearMeshColumnsRows( newmesh );
- FreeMesh(newmesh);
- ssize = samplesize;
- if (ds->shaderInfo->lightmapSampleSize)
- ssize = ds->shaderInfo->lightmapSampleSize;
- #ifdef LIGHTMAP_PATCHSHIFT
- subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH-1, widthtable, heighttable);
- #else
- subdividedMesh = SubdivideMeshQuads( tempMesh, ssize, LIGHTMAP_WIDTH, widthtable, heighttable);
- #endif
- w = subdividedMesh->width;
- h = subdividedMesh->height;
- #ifdef LIGHTMAP_PATCHSHIFT
- w++;
- h++;
- #endif
- FreeMesh(subdividedMesh);
- // allocate the lightmap
- c_exactLightmap += w * h;
- if ( !AllocLMBlock( w, h, &x, &y ) ) {
- PrepareNewLightmap();
- if ( !AllocLMBlock( w, h, &x, &y ) ) {
- Error("Entity %i, brush %i: Lightmap allocation failed",
- ds->mapBrush->entitynum, ds->mapBrush->brushnum );
- }
- }
- #ifdef LIGHTMAP_PATCHSHIFT
- w--;
- h--;
- #endif
- // set the lightmap texture coordinates in the drawVerts
- ds->lightmapNum = numLightmaps - 1;
- ds->lightmapWidth = w;
- ds->lightmapHeight = h;
- ds->lightmapX = x;
- ds->lightmapY = y;
- for ( i = 0 ; i < ds->patchWidth ; i++ ) {
- for ( k = 0 ; k < w ; k++ ) {
- if ( originalWidths[k] >= i ) {
- break;
- }
- }
- if (k >= w)
- k = w-1;
- s = x + k;
- for ( j = 0 ; j < ds->patchHeight ; j++ ) {
- for ( k = 0 ; k < h ; k++ ) {
- if ( originalHeights[k] >= j ) {
- break;
- }
- }
- if (k >= h)
- k = h-1;
- t = y + k;
- verts[i + j * ds->patchWidth].lightmap[0] = ( s + 0.5 ) / LIGHTMAP_WIDTH;
- verts[i + j * ds->patchWidth].lightmap[1] = ( t + 0.5 ) / LIGHTMAP_HEIGHT;
- }
- }
- }
- /*
- ===================
- AllocateLightmapForSurface
- ===================
- */
- //#define LIGHTMAP_BLOCK 16
- void AllocateLightmapForSurface( mapDrawSurface_t *ds ) {
- vec3_t mins, maxs, size, exactSize, delta;
- int i;
- drawVert_t *verts;
- int w, h;
- int x, y, ssize;
- int axis;
- vec3_t vecs[2];
- float s, t;
- vec3_t origin;
- plane_t *plane;
- float d;
- vec3_t planeNormal;
- if ( ds->patch ) {
- AllocateLightmapForPatch( ds );
- return;
- }
- ssize = samplesize;
- if (ds->shaderInfo->lightmapSampleSize)
- ssize = ds->shaderInfo->lightmapSampleSize;
- plane = &mapplanes[ ds->side->planenum ];
- // bound the surface
- ClearBounds( mins, maxs );
- verts = ds->verts;
- for ( i = 0 ; i < ds->numVerts ; i++ ) {
- AddPointToBounds( verts[i].xyz, mins, maxs );
- }
- // round to the lightmap resolution
- for ( i = 0 ; i < 3 ; i++ ) {
- exactSize[i] = maxs[i] - mins[i];
- mins[i] = ssize * floor( mins[i] / ssize );
- maxs[i] = ssize * ceil( maxs[i] / ssize );
- size[i] = (maxs[i] - mins[i]) / ssize + 1;
- }
- // the two largest axis will be the lightmap size
- memset( vecs, 0, sizeof( vecs ) );
- planeNormal[0] = fabs( plane->normal[0] );
- planeNormal[1] = fabs( plane->normal[1] );
- planeNormal[2] = fabs( plane->normal[2] );
- if ( planeNormal[0] >= planeNormal[1] && planeNormal[0] >= planeNormal[2] ) {
- w = size[1];
- h = size[2];
- axis = 0;
- vecs[0][1] = 1.0 / ssize;
- vecs[1][2] = 1.0 / ssize;
- } else if ( planeNormal[1] >= planeNormal[0] && planeNormal[1] >= planeNormal[2] ) {
- w = size[0];
- h = size[2];
- axis = 1;
- vecs[0][0] = 1.0 / ssize;
- vecs[1][2] = 1.0 / ssize;
- } else {
- w = size[0];
- h = size[1];
- axis = 2;
- vecs[0][0] = 1.0 / ssize;
- vecs[1][1] = 1.0 / ssize;
- }
- if ( !plane->normal[axis] ) {
- Error( "Chose a 0 valued axis" );
- }
- if ( w > LIGHTMAP_WIDTH ) {
- VectorScale ( vecs[0], (float)LIGHTMAP_WIDTH/w, vecs[0] );
- w = LIGHTMAP_WIDTH;
- }
-
- if ( h > LIGHTMAP_HEIGHT ) {
- VectorScale ( vecs[1], (float)LIGHTMAP_HEIGHT/h, vecs[1] );
- h = LIGHTMAP_HEIGHT;
- }
-
- c_exactLightmap += w * h;
- if ( !AllocLMBlock( w, h, &x, &y ) ) {
- PrepareNewLightmap();
- if ( !AllocLMBlock( w, h, &x, &y ) ) {
- Error("Entity %i, brush %i: Lightmap allocation failed",
- ds->mapBrush->entitynum, ds->mapBrush->brushnum );
- }
- }
- // set the lightmap texture coordinates in the drawVerts
- ds->lightmapNum = numLightmaps - 1;
- ds->lightmapWidth = w;
- ds->lightmapHeight = h;
- ds->lightmapX = x;
- ds->lightmapY = y;
- for ( i = 0 ; i < ds->numVerts ; i++ ) {
- VectorSubtract( verts[i].xyz, mins, delta );
- s = DotProduct( delta, vecs[0] ) + x + 0.5;
- t = DotProduct( delta, vecs[1] ) + y + 0.5;
- verts[i].lightmap[0] = s / LIGHTMAP_WIDTH;
- verts[i].lightmap[1] = t / LIGHTMAP_HEIGHT;
- }
- // calculate the world coordinates of the lightmap samples
- // project mins onto plane to get origin
- d = DotProduct( mins, plane->normal ) - plane->dist;
- d /= plane->normal[ axis ];
- VectorCopy( mins, origin );
- origin[axis] -= d;
- // project stepped lightmap blocks and subtract to get planevecs
- for ( i = 0 ; i < 2 ; i++ ) {
- vec3_t normalized;
- float len;
- len = VectorNormalize( vecs[i], normalized );
- VectorScale( normalized, (1.0/len), vecs[i] );
- d = DotProduct( vecs[i], plane->normal );
- d /= plane->normal[ axis ];
- vecs[i][axis] -= d;
- }
- VectorCopy( origin, ds->lightmapOrigin );
- VectorCopy( vecs[0], ds->lightmapVecs[0] );
- VectorCopy( vecs[1], ds->lightmapVecs[1] );
- VectorCopy( plane->normal, ds->lightmapVecs[2] );
- }
- /*
- ===================
- AllocateLightmaps
- ===================
- */
- void AllocateLightmaps( entity_t *e ) {
- int i, j;
- mapDrawSurface_t *ds;
- shaderInfo_t *si;
- qprintf ("--- AllocateLightmaps ---\n");
- // sort all surfaces by shader so common shaders will usually
- // be in the same lightmap
- numSortShaders = 0;
- for ( i = e->firstDrawSurf ; i < numMapDrawSurfs ; i++ ) {
- ds = &mapDrawSurfs[i];
- if ( !ds->numVerts ) {
- continue; // leftover from a surface subdivision
- }
- if ( ds->miscModel ) {
- continue;
- }
- if ( !ds->patch ) {
- VectorCopy( mapplanes[ds->side->planenum].normal, ds->lightmapVecs[2] );
- }
- // search for this shader
- for ( j = 0 ; j < numSortShaders ; j++ ) {
- if ( ds->shaderInfo == surfsOnShader[j]->shaderInfo ) {
- ds->nextOnShader = surfsOnShader[j];
- surfsOnShader[j] = ds;
- break;
- }
- }
- if ( j == numSortShaders ) {
- if ( numSortShaders >= MAX_MAP_SHADERS ) {
- Error( "MAX_MAP_SHADERS" );
- }
- surfsOnShader[j] = ds;
- numSortShaders++;
- }
- }
- qprintf( "%5i unique shaders\n", numSortShaders );
- // for each shader, allocate lightmaps for each surface
- // numLightmaps = 0;
- // PrepareNewLightmap();
- for ( i = 0 ; i < numSortShaders ; i++ ) {
- si = surfsOnShader[i]->shaderInfo;
- for ( ds = surfsOnShader[i] ; ds ; ds = ds->nextOnShader ) {
- // some surfaces don't need lightmaps allocated for them
- if ( si->surfaceFlags & SURF_NOLIGHTMAP ) {
- ds->lightmapNum = -1;
- } else if ( si->surfaceFlags & SURF_POINTLIGHT ) {
- ds->lightmapNum = -3;
- } else {
- AllocateLightmapForSurface( ds );
- }
- }
- }
- qprintf( "%7i exact lightmap texels\n", c_exactLightmap );
- qprintf( "%7i block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH*LIGHTMAP_HEIGHT );
- }
|