mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2025-02-21 03:11:57 +00:00
GL1 multitexture: fast dynamic lighting
Using MH's solution, which is keeping all lightmaps in memory to modify and upload them as a batch when possible. lightmap_buffer is now an array; index 0 is used as the legacy lightmap buffer (when no mtex), and the rest of the indexes are to store the different lightmaps (only when using mtex).
This commit is contained in:
parent
86528d7812
commit
ba71af2af8
4 changed files with 173 additions and 47 deletions
|
@ -35,23 +35,19 @@ void
|
|||
LM_InitBlock(void)
|
||||
{
|
||||
memset(gl_lms.allocated, 0, sizeof(gl_lms.allocated));
|
||||
|
||||
if (gl_config.multitexture && !gl_lms.lightmap_buffer[gl_lms.current_lightmap_texture]) {
|
||||
gl_lms.lightmap_buffer[gl_lms.current_lightmap_texture] = malloc (BLOCK_WIDTH*BLOCK_HEIGHT*LIGHTMAP_BYTES);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LM_UploadBlock(qboolean dynamic)
|
||||
{
|
||||
int texture;
|
||||
const int texture = (dynamic)? 0 : gl_lms.current_lightmap_texture;
|
||||
const int buffer = (gl_config.multitexture)? gl_lms.current_lightmap_texture : 0;
|
||||
int height = 0;
|
||||
|
||||
if (dynamic)
|
||||
{
|
||||
texture = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
texture = gl_lms.current_lightmap_texture;
|
||||
}
|
||||
|
||||
R_Bind(gl_state.lightmap_textures + texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
@ -70,14 +66,14 @@ LM_UploadBlock(qboolean dynamic)
|
|||
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, BLOCK_WIDTH,
|
||||
height, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE,
|
||||
gl_lms.lightmap_buffer);
|
||||
gl_lms.lightmap_buffer[buffer]);
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_lms.internal_format = GL_LIGHTMAP_FORMAT;
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_lms.internal_format,
|
||||
BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_LIGHTMAP_FORMAT,
|
||||
GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer);
|
||||
GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer[buffer]);
|
||||
|
||||
if (++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS)
|
||||
{
|
||||
|
@ -207,7 +203,7 @@ LM_BuildPolygonFromSurface(model_t *currentmodel, msurface_t *fa)
|
|||
void
|
||||
LM_CreateSurfaceLightmap(msurface_t *surf)
|
||||
{
|
||||
int smax, tmax;
|
||||
int smax, tmax, buffer;
|
||||
byte *base;
|
||||
|
||||
if (surf->flags & (SURF_DRAWSKY | SURF_DRAWTURB))
|
||||
|
@ -231,8 +227,9 @@ LM_CreateSurfaceLightmap(msurface_t *surf)
|
|||
}
|
||||
|
||||
surf->lightmaptexturenum = gl_lms.current_lightmap_texture;
|
||||
buffer = (gl_config.multitexture)? surf->lightmaptexturenum : 0;
|
||||
|
||||
base = gl_lms.lightmap_buffer;
|
||||
base = gl_lms.lightmap_buffer[buffer];
|
||||
base += (surf->light_t * BLOCK_WIDTH + surf->light_s) * LIGHTMAP_BYTES;
|
||||
|
||||
R_SetCacheState(surf);
|
||||
|
@ -242,12 +239,22 @@ LM_CreateSurfaceLightmap(msurface_t *surf)
|
|||
void
|
||||
LM_BeginBuildingLightmaps(model_t *m)
|
||||
{
|
||||
static const unsigned int lightmap_size = BLOCK_WIDTH*BLOCK_HEIGHT*LIGHTMAP_BYTES;
|
||||
static lightstyle_t lightstyles[MAX_LIGHTSTYLES];
|
||||
int i;
|
||||
unsigned dummy[128 * 128] = {0};
|
||||
|
||||
memset(gl_lms.allocated, 0, sizeof(gl_lms.allocated));
|
||||
|
||||
// free lightmap update buffers
|
||||
for (i=0; i<MAX_LIGHTMAPS; i++)
|
||||
{
|
||||
if (gl_lms.lightmap_buffer[i])
|
||||
{
|
||||
free(gl_lms.lightmap_buffer[i]);
|
||||
}
|
||||
gl_lms.lightmap_buffer[i] = NULL;
|
||||
}
|
||||
|
||||
r_framecount = 1; /* no dlightcache */
|
||||
|
||||
/* setup the base lightstyles so the lightmaps
|
||||
|
@ -271,13 +278,28 @@ LM_BeginBuildingLightmaps(model_t *m)
|
|||
gl_lms.current_lightmap_texture = 1;
|
||||
gl_lms.internal_format = GL_LIGHTMAP_FORMAT;
|
||||
|
||||
if (gl_config.multitexture)
|
||||
{
|
||||
// alloc lightmap update buffer if needed
|
||||
if (!gl_lms.lightmap_buffer[gl_lms.current_lightmap_texture]) {
|
||||
gl_lms.lightmap_buffer[gl_lms.current_lightmap_texture] = malloc (lightmap_size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// dynamic lightmap for classic rendering path (no multitexture)
|
||||
if (!gl_lms.lightmap_buffer[0]) {
|
||||
gl_lms.lightmap_buffer[0] = malloc (lightmap_size);
|
||||
memset (gl_lms.lightmap_buffer[0], 0, lightmap_size);
|
||||
}
|
||||
|
||||
/* initialize the dynamic lightmap texture */
|
||||
R_Bind(gl_state.lightmap_textures + 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, gl_lms.internal_format,
|
||||
BLOCK_WIDTH, BLOCK_HEIGHT, 0, GL_LIGHTMAP_FORMAT,
|
||||
GL_UNSIGNED_BYTE, dummy);
|
||||
GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer[0]);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -325,7 +325,7 @@ R_BlendLightmaps(const model_t *currentmodel)
|
|||
|
||||
if (LM_AllocBlock(smax, tmax, &surf->dlight_s, &surf->dlight_t))
|
||||
{
|
||||
base = gl_lms.lightmap_buffer;
|
||||
base = gl_lms.lightmap_buffer[0];
|
||||
base += (surf->dlight_t * BLOCK_WIDTH +
|
||||
surf->dlight_s) * LIGHTMAP_BYTES;
|
||||
|
||||
|
@ -371,7 +371,7 @@ R_BlendLightmaps(const model_t *currentmodel)
|
|||
smax, tmax);
|
||||
}
|
||||
|
||||
base = gl_lms.lightmap_buffer;
|
||||
base = gl_lms.lightmap_buffer[0];
|
||||
base += (surf->dlight_t * BLOCK_WIDTH +
|
||||
surf->dlight_s) * LIGHTMAP_BYTES;
|
||||
|
||||
|
@ -611,7 +611,8 @@ R_HasDynamicLights(msurface_t *surf, int *mapNum)
|
|||
}
|
||||
}
|
||||
|
||||
if ( !is_dynamic && surf->dlightframe == r_framecount )
|
||||
// No matter if it is this frame or was in the previous one: has dynamic lights
|
||||
if ( !is_dynamic && (surf->dlightframe == r_framecount || surf->dirty_lightmap) )
|
||||
{
|
||||
is_dynamic = true;
|
||||
}
|
||||
|
@ -623,40 +624,26 @@ R_HasDynamicLights(msurface_t *surf, int *mapNum)
|
|||
return is_dynamic;
|
||||
}
|
||||
|
||||
static void
|
||||
R_UpdateSurfCache(msurface_t *surf, int map)
|
||||
{
|
||||
if ( ((surf->styles[map] >= 32) || (surf->styles[map] == 0))
|
||||
&& (surf->dlightframe != r_framecount) )
|
||||
{
|
||||
R_SetCacheState(surf);
|
||||
}
|
||||
surf->dirty_lightmap = (surf->dlightframe == r_framecount);
|
||||
}
|
||||
|
||||
static void
|
||||
R_RenderLightmappedPoly(entity_t *currententity, msurface_t *surf)
|
||||
{
|
||||
int i, map, smax, tmax;
|
||||
int i;
|
||||
int nv = surf->polys->numverts;
|
||||
float scroll;
|
||||
float *v;
|
||||
unsigned lmtex = surf->lightmaptexturenum;
|
||||
unsigned temp[128 * 128];
|
||||
|
||||
if ( R_HasDynamicLights(surf, &map) )
|
||||
{
|
||||
smax = (surf->extents[0] >> 4) + 1;
|
||||
tmax = (surf->extents[1] >> 4) + 1;
|
||||
R_BuildLightMap(surf, (void *) temp, smax * 4);
|
||||
|
||||
// Dynamic lights on a surface
|
||||
if (((surf->styles[map] >= 32) || (surf->styles[map] == 0)) && (surf->dlightframe != r_framecount))
|
||||
{
|
||||
R_SetCacheState(surf);
|
||||
}
|
||||
else // Normal dynamic lights
|
||||
{
|
||||
lmtex = 0;
|
||||
}
|
||||
|
||||
R_MBind(GL_TEXTURE1, gl_state.lightmap_textures + lmtex);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax,
|
||||
tmax, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
R_MBind(GL_TEXTURE1, gl_state.lightmap_textures + lmtex);
|
||||
}
|
||||
R_MBind(GL_TEXTURE1, gl_state.lightmap_textures + surf->lightmaptexturenum);
|
||||
|
||||
// Apply overbrightbits to TMU 1 (lightmap)
|
||||
if (gl1_overbrightbits->value)
|
||||
|
@ -732,6 +719,114 @@ R_RenderLightmappedPoly(entity_t *currententity, msurface_t *surf)
|
|||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
|
||||
static void
|
||||
R_UploadDynamicLights(msurface_t *surf)
|
||||
{
|
||||
int map, smax, tmax;
|
||||
byte temp[BLOCK_WIDTH * BLOCK_HEIGHT];
|
||||
|
||||
if ( !gl_config.multitexture || !R_HasDynamicLights(surf, &map) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
smax = (surf->extents[0] >> 4) + 1;
|
||||
tmax = (surf->extents[1] >> 4) + 1;
|
||||
R_BuildLightMap(surf, (void *) temp, smax * LIGHTMAP_BYTES);
|
||||
R_UpdateSurfCache(surf, map);
|
||||
|
||||
R_Bind(gl_state.lightmap_textures + surf->lightmaptexturenum);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, surf->light_s, surf->light_t, smax,
|
||||
tmax, GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, temp);
|
||||
}
|
||||
|
||||
/* Upload dynamic lights to each lightmap texture (multitexture path only) */
|
||||
static void
|
||||
R_RegenAllLightmaps()
|
||||
{
|
||||
int i, map, smax, tmax, top, bottom, left, right, bt, bb, bl, br;
|
||||
qboolean affected_lightmap;
|
||||
msurface_t *surf;
|
||||
byte *base;
|
||||
|
||||
if ( !gl_config.multitexture )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, BLOCK_WIDTH);
|
||||
|
||||
for (i = 1; i < MAX_LIGHTMAPS; i++)
|
||||
{
|
||||
if (!gl_lms.lightmap_surfaces[i] || !gl_lms.lightmap_buffer[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
affected_lightmap = false;
|
||||
bt = BLOCK_HEIGHT;
|
||||
bl = BLOCK_WIDTH;
|
||||
bb = br = 0;
|
||||
|
||||
for (surf = gl_lms.lightmap_surfaces[i];
|
||||
surf != 0;
|
||||
surf = surf->lightmapchain)
|
||||
{
|
||||
if ( !R_HasDynamicLights(surf, &map) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
affected_lightmap = true;
|
||||
smax = (surf->extents[0] >> 4) + 1;
|
||||
tmax = (surf->extents[1] >> 4) + 1;
|
||||
|
||||
left = surf->light_s;
|
||||
right = surf->light_s + smax;
|
||||
top = surf->light_t;
|
||||
bottom = surf->light_t + tmax;
|
||||
|
||||
base = gl_lms.lightmap_buffer[i];
|
||||
base += (top * BLOCK_WIDTH + left) * LIGHTMAP_BYTES;
|
||||
|
||||
R_BuildLightMap(surf, base, BLOCK_WIDTH * LIGHTMAP_BYTES);
|
||||
R_UpdateSurfCache(surf, map);
|
||||
|
||||
if (left < bl)
|
||||
{
|
||||
bl = left;
|
||||
}
|
||||
if (right > br)
|
||||
{
|
||||
br = right;
|
||||
}
|
||||
if (top < bt)
|
||||
{
|
||||
bt = top;
|
||||
}
|
||||
if (bottom > bb)
|
||||
{
|
||||
bb = bottom;
|
||||
}
|
||||
}
|
||||
|
||||
if (!affected_lightmap)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
base = gl_lms.lightmap_buffer[i];
|
||||
base += (bt * BLOCK_WIDTH + bl) * LIGHTMAP_BYTES;
|
||||
|
||||
// upload changes
|
||||
R_Bind(gl_state.lightmap_textures + i);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, bl, bt, br - bl, bb - bt,
|
||||
GL_LIGHTMAP_FORMAT, GL_UNSIGNED_BYTE, base);
|
||||
}
|
||||
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
R_DrawTextureChains(entity_t *currententity)
|
||||
{
|
||||
|
@ -871,6 +966,7 @@ R_DrawInlineBModel(entity_t *currententity, const model_t *currentmodel)
|
|||
|
||||
if (gl_config.multitexture && !(psurf->flags & SURF_DRAWTURB))
|
||||
{
|
||||
R_UploadDynamicLights(psurf);
|
||||
R_EnableMultitexture(true);
|
||||
R_MBind(GL_TEXTURE0, image->texnum);
|
||||
R_RenderLightmappedPoly(currententity, psurf);
|
||||
|
@ -1098,6 +1194,12 @@ R_RecursiveWorldNode(entity_t *currententity, mnode_t *node)
|
|||
image = R_TextureAnimation(currententity, surf->texinfo);
|
||||
surf->texturechain = image->texturechain;
|
||||
image->texturechain = surf;
|
||||
|
||||
if (gl_config.multitexture && !(surf->texinfo->flags & SURF_WARP)) // needed for R_RegenAllLightmaps()
|
||||
{
|
||||
surf->lightmapchain = gl_lms.lightmap_surfaces[surf->lightmaptexturenum];
|
||||
gl_lms.lightmap_surfaces[surf->lightmaptexturenum] = surf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1133,6 +1235,7 @@ R_DrawWorld(void)
|
|||
|
||||
R_ClearSkyBox();
|
||||
R_RecursiveWorldNode(&ent, r_worldmodel->nodes);
|
||||
R_RegenAllLightmaps();
|
||||
R_DrawTextureChains(&ent);
|
||||
R_BlendLightmaps(r_worldmodel);
|
||||
R_DrawSkyBox();
|
||||
|
|
|
@ -403,7 +403,7 @@ typedef struct
|
|||
|
||||
/* the lightmap texture data needs to be kept in
|
||||
main memory so texsubimage can update properly */
|
||||
byte lightmap_buffer[4 * BLOCK_WIDTH * BLOCK_HEIGHT];
|
||||
byte *lightmap_buffer[MAX_LIGHTMAPS];
|
||||
} gllightmapstate_t;
|
||||
|
||||
extern glconfig_t gl_config;
|
||||
|
|
|
@ -65,6 +65,7 @@ typedef struct msurface_s
|
|||
/* lighting info */
|
||||
int dlightframe;
|
||||
int dlightbits;
|
||||
qboolean dirty_lightmap; // lightmap has dynamic lights from previous frame (mtex only)
|
||||
|
||||
int lightmaptexturenum;
|
||||
byte styles[MAXLIGHTMAPS];
|
||||
|
|
Loading…
Reference in a new issue