yquake2remaster/src/refresh/r_lightmap.c

304 lines
6.7 KiB
C
Raw Normal View History

/*
* Copyright (C) 1997-2001 Id Software, Inc.
*
* This program 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.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*
* =======================================================================
*
* Lightmap handling
*
* =======================================================================
*/
#include "header/local.h"
extern gllightmapstate_t gl_lms;
void R_SetCacheState ( msurface_t *surf );
void R_BuildLightMap ( msurface_t *surf, byte *dest, int stride );
2010-10-23 10:07:22 +00:00
void
LM_InitBlock ( void )
{
memset( gl_lms.allocated, 0, sizeof ( gl_lms.allocated ) );
}
2010-10-23 10:07:22 +00:00
void
LM_UploadBlock ( qboolean dynamic )
{
int texture;
int height = 0;
if ( dynamic )
{
texture = 0;
}
else
{
texture = gl_lms.current_lightmap_texture;
}
R_Bind( gl_state.lightmap_textures + texture );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
if ( dynamic )
{
int i;
for ( i = 0; i < BLOCK_WIDTH; i++ )
{
if ( gl_lms.allocated [ i ] > height )
{
height = gl_lms.allocated [ i ];
}
}
qglTexSubImage2D( GL_TEXTURE_2D,
0,
0, 0,
BLOCK_WIDTH, height,
GL_LIGHTMAP_FORMAT,
GL_UNSIGNED_BYTE,
gl_lms.lightmap_buffer );
}
else
{
qglTexImage2D( GL_TEXTURE_2D,
0,
gl_lms.internal_format,
BLOCK_WIDTH, BLOCK_HEIGHT,
0,
GL_LIGHTMAP_FORMAT,
GL_UNSIGNED_BYTE,
gl_lms.lightmap_buffer );
if ( ++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS )
{
ri.Sys_Error( ERR_DROP, "LM_UploadBlock() - MAX_LIGHTMAPS exceeded\n" );
}
}
}
/* returns a texture number and the position inside it */
2010-10-23 10:07:22 +00:00
qboolean
LM_AllocBlock ( int w, int h, int *x, int *y )
{
int i, j;
int best, best2;
best = BLOCK_HEIGHT;
for ( i = 0; i < BLOCK_WIDTH - w; i++ )
{
best2 = 0;
for ( j = 0; j < w; j++ )
{
if ( gl_lms.allocated [ i + j ] >= best )
{
break;
}
if ( gl_lms.allocated [ i + j ] > best2 )
{
best2 = gl_lms.allocated [ i + j ];
}
}
if ( j == w )
{
/* this is a valid spot */
*x = i;
*y = best = best2;
}
}
if ( best + h > BLOCK_HEIGHT )
{
return ( false );
}
for ( i = 0; i < w; i++ )
{
gl_lms.allocated [ *x + i ] = best + h;
}
return ( true );
}
void
LM_BuildPolygonFromSurface ( msurface_t *fa )
{
int i, lindex, lnumverts;
medge_t *pedges, *r_pedge;
int vertpage;
float *vec;
float s, t;
glpoly_t *poly;
vec3_t total;
/* reconstruct the polygon */
pedges = currentmodel->edges;
lnumverts = fa->numedges;
vertpage = 0;
VectorClear( total );
/* draw texture */
poly = Hunk_Alloc( sizeof ( glpoly_t ) + ( lnumverts - 4 ) * VERTEXSIZE * sizeof ( float ) );
poly->next = fa->polys;
poly->flags = fa->flags;
fa->polys = poly;
poly->numverts = lnumverts;
for ( i = 0; i < lnumverts; i++ )
{
lindex = currentmodel->surfedges [ fa->firstedge + i ];
if ( lindex > 0 )
{
r_pedge = &pedges [ lindex ];
vec = currentmodel->vertexes [ r_pedge->v [ 0 ] ].position;
}
else
{
r_pedge = &pedges [ -lindex ];
vec = currentmodel->vertexes [ r_pedge->v [ 1 ] ].position;
}
s = DotProduct( vec, fa->texinfo->vecs [ 0 ] ) + fa->texinfo->vecs [ 0 ] [ 3 ];
s /= fa->texinfo->image->width;
t = DotProduct( vec, fa->texinfo->vecs [ 1 ] ) + fa->texinfo->vecs [ 1 ] [ 3 ];
t /= fa->texinfo->image->height;
VectorAdd( total, vec, total );
VectorCopy( vec, poly->verts [ i ] );
poly->verts [ i ] [ 3 ] = s;
poly->verts [ i ] [ 4 ] = t;
/* lightmap texture coordinates */
s = DotProduct( vec, fa->texinfo->vecs [ 0 ] ) + fa->texinfo->vecs [ 0 ] [ 3 ];
s -= fa->texturemins [ 0 ];
s += fa->light_s * 16;
s += 8;
s /= BLOCK_WIDTH * 16; /* fa->texinfo->texture->width; */
t = DotProduct( vec, fa->texinfo->vecs [ 1 ] ) + fa->texinfo->vecs [ 1 ] [ 3 ];
t -= fa->texturemins [ 1 ];
t += fa->light_t * 16;
t += 8;
t /= BLOCK_HEIGHT * 16; /* fa->texinfo->texture->height; */
poly->verts [ i ] [ 5 ] = s;
poly->verts [ i ] [ 6 ] = t;
}
poly->numverts = lnumverts;
}
void
LM_CreateSurfaceLightmap ( msurface_t *surf )
{
int smax, tmax;
byte *base;
if ( surf->flags & ( SURF_DRAWSKY | SURF_DRAWTURB ) )
{
return;
}
smax = ( surf->extents [ 0 ] >> 4 ) + 1;
tmax = ( surf->extents [ 1 ] >> 4 ) + 1;
if ( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) )
{
LM_UploadBlock( false );
LM_InitBlock();
if ( !LM_AllocBlock( smax, tmax, &surf->light_s, &surf->light_t ) )
{
ri.Sys_Error( ERR_FATAL, "Consecutive calls to LM_AllocBlock(%d,%d) failed\n", smax, tmax );
}
}
surf->lightmaptexturenum = gl_lms.current_lightmap_texture;
base = gl_lms.lightmap_buffer;
base += ( surf->light_t * BLOCK_WIDTH + surf->light_s ) * LIGHTMAP_BYTES;
R_SetCacheState( surf );
R_BuildLightMap( surf, base, BLOCK_WIDTH * LIGHTMAP_BYTES );
}
void
LM_BeginBuildingLightmaps ( model_t *m )
{
static lightstyle_t lightstyles [ MAX_LIGHTSTYLES ];
int i;
unsigned dummy [ 128 * 128 ];
memset( gl_lms.allocated, 0, sizeof ( gl_lms.allocated ) );
r_framecount = 1; /* no dlightcache */
R_EnableMultitexture( true );
R_SelectTexture( QGL_TEXTURE1 );
/* setup the base lightstyles so the lightmaps won't have to be regenerated
* the first time they're seen */
for ( i = 0; i < MAX_LIGHTSTYLES; i++ )
{
lightstyles [ i ].rgb [ 0 ] = 1;
lightstyles [ i ].rgb [ 1 ] = 1;
lightstyles [ i ].rgb [ 2 ] = 1;
lightstyles [ i ].white = 3;
}
r_newrefdef.lightstyles = lightstyles;
if ( !gl_state.lightmap_textures )
{
gl_state.lightmap_textures = TEXNUM_LIGHTMAPS;
}
gl_lms.current_lightmap_texture = 1;
gl_lms.internal_format = gl_tex_solid_format;
/* initialize the dynamic lightmap texture */
R_Bind( gl_state.lightmap_textures + 0 );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
qglTexImage2D( GL_TEXTURE_2D,
0,
gl_lms.internal_format,
BLOCK_WIDTH, BLOCK_HEIGHT,
0,
GL_LIGHTMAP_FORMAT,
GL_UNSIGNED_BYTE,
dummy );
}
void
LM_EndBuildingLightmaps ( void )
{
LM_UploadBlock( false );
R_EnableMultitexture( false );
}