//#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] ); }
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; } } }
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; vec4_t plane; float d; /* debug code */ #if 0 if( ds->type == SURF_META && ds->planar == qfalse ) Sys_Printf( "NPMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader ); else if( ds->type == SURF_META && ds->planar == qtrue ) Sys_Printf( "PMS: %3d vertexes, %s\n", ds->numVerts, ds->shaderInfo->shader ); #endif /* ydnar: handle planar patches */ if( noPatchFix == qtrue || (ds->type == SURF_PATCH && ds->planeNum < 0) ) { AllocateLightmapForPatch( ds ); return; } /* get sample size */ ssize = ds->sampleSize; /* 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; } /* ydnar: lightmap projection axis is already stored */ memset( vecs, 0, sizeof( vecs ) ); /* classify the plane (x y or z major) (ydnar: biased to z axis projection) */ if( ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 0 ] && ds->lightmapAxis[ 2 ] >= ds->lightmapAxis[ 1 ] ) { w = size[ 0 ]; h = size[ 1 ]; axis = 2; vecs[ 0 ][ 0 ] = 1.0 / ssize; vecs[ 1 ][ 1 ] = 1.0 / ssize; } else if( ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 1 ] && ds->lightmapAxis[ 0 ] >= ds->lightmapAxis[ 2 ] ) { w = size[ 1 ]; h = size[ 2 ]; axis = 0; vecs[ 0 ][ 1 ] = 1.0 / ssize; vecs[ 1 ][ 2 ] = 1.0 / ssize; } else { w = size[ 0 ]; h = size[ 2 ]; axis = 1; vecs[ 0 ][ 0 ] = 1.0 / ssize; vecs[ 1 ][ 2 ] = 1.0 / ssize; } /* odd check, given projection is now precalculated */ if( ds->lightmapAxis[ axis ] == 0 ) Error( "Chose a 0 valued axis" ); /* clamp to lightmap texture resolution */ 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; } /* ydnar */ if( ds->planar == qfalse ) c_nonplanarLightmap += w * h; 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 */ /* construct a plane from the first vert and clear bounding box */ /* project mins onto plane to get origin */ VectorCopy( ds->lightmapVecs[ 2 ], plane ); plane[ 3 ] = DotProduct( ds->verts[ 0 ].xyz, plane ); d = DotProduct( mins, plane ) - plane[ 3 ]; d /= plane[ axis ]; //% 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 ); d /= plane[ axis ]; //%d = DotProduct( vecs[i], plane->normal ); //%d /= plane->normal[ axis ]; vecs[i][axis] -= d; } /* store lightmap origin and vectors (fixme: make this work right) */ VectorCopy( origin, ds->lightmapOrigin ); //% VectorCopy( plane->normal, ds->lightmapVecs[ 2 ] ); /* ydnar: lightmap vectors 0 and 1 are used for lod bounds, so don't overwrite */ if( ds->type == SURF_PATCH ) c_planarPatch++; /* store lightmap vectors */ VectorCopy( vecs[ 0 ], ds->lightmapVecs[ 0 ] ); VectorCopy( vecs[ 1 ], ds->lightmapVecs[ 1 ] ); /* ydnar: print some stats */ //Sys_FPrintf( SYS_VRB, "Lightmap block %3d (%3d, %3d) (%3d x %3d) emitted\n", (numLightmaps - 1), x, y, w, h ); }