xash3d-fwgs/ref_vk/vk_lightmap.c

229 lines
5.3 KiB
C
Raw Normal View History

#include "vk_lightmap.h"
#include "vk_common.h"
#include "vk_textures.h"
#include "com_strings.h"
#include "xash3d_mathlib.h"
#include <memory.h>
typedef struct
{
int allocated[BLOCK_SIZE_MAX];
int current_lightmap_texture;
//msurface_t *dynamic_surfaces;
//msurface_t *lightmap_surfaces[MAX_LIGHTMAPS];
byte lightmap_buffer[BLOCK_SIZE_MAX*BLOCK_SIZE_MAX*4];
} gllightmapstate_t;
static gllightmapstate_t gl_lms;
static uint r_blocklights[BLOCK_SIZE_MAX*BLOCK_SIZE_MAX*3]; // This is just a temp HDR-ish buffer for lightmap generation
static void LM_InitBlock( void )
{
memset( gl_lms.allocated, 0, sizeof( gl_lms.allocated ));
}
static int LM_AllocBlock( int w, int h, int *x, int *y )
{
int i, j;
int best, best2;
best = BLOCK_SIZE;
for( i = 0; i < BLOCK_SIZE - 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_SIZE )
return false;
for( i = 0; i < w; i++ )
gl_lms.allocated[*x + i] = best + h;
return true;
}
static void LM_UploadDynamicBlock( void )
{
int height = 0, i;
for( i = 0; i < BLOCK_SIZE; i++ )
{
if( gl_lms.allocated[i] > height )
height = gl_lms.allocated[i];
}
gEngine.Con_Printf(S_ERROR "VK NOT IMPLEMENTED %s\n", __FUNCTION__);
//pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, BLOCK_SIZE, height, GL_RGBA, GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer );
}
static void LM_UploadBlock( qboolean dynamic )
{
int i;
if( dynamic )
{
int height = 0;
for( i = 0; i < BLOCK_SIZE; i++ )
{
if( gl_lms.allocated[i] > height )
height = gl_lms.allocated[i];
}
gEngine.Con_Printf(S_ERROR "VK NOT IMPLEMENTED %s dynamic \n", __FUNCTION__);
/* GL_Bind( XASH_TEXTURE0, tr.dlightTexture ); */
/* pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, BLOCK_SIZE, height, GL_RGBA, GL_UNSIGNED_BYTE, gl_lms.lightmap_buffer ); */
}
else
{
rgbdata_t r_lightmap;
char lmName[16];
i = gl_lms.current_lightmap_texture;
// upload static lightmaps only during loading
memset( &r_lightmap, 0, sizeof( r_lightmap ));
Q_snprintf( lmName, sizeof( lmName ), "*lightmap%i", i );
r_lightmap.width = BLOCK_SIZE;
r_lightmap.height = BLOCK_SIZE;
r_lightmap.type = PF_RGBA_32;
r_lightmap.size = r_lightmap.width * r_lightmap.height * 4;
r_lightmap.flags = IMAGE_HAS_COLOR;
r_lightmap.buffer = gl_lms.lightmap_buffer;
tglob.lightmapTextures[i] = VK_LoadTextureInternal( lmName, &r_lightmap, TF_FONT|TF_ATLAS_PAGE );
if( ++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS )
gEngine.Host_Error( "AllocBlock: full\n" );
}
}
/*
=================
R_BuildLightmap
Combine and scale multiple lightmaps into the floating
format in r_blocklights
=================
*/
static void R_BuildLightMap( msurface_t *surf, byte *dest, int stride, qboolean dynamic )
{
int smax, tmax;
uint *bl, scale;
int i, map, size, s, t;
int sample_size;
mextrasurf_t *info = surf->info;
color24 *lm;
sample_size = gEngine.Mod_SampleSizeForFace( surf );
smax = ( info->lightextents[0] / sample_size ) + 1;
tmax = ( info->lightextents[1] / sample_size ) + 1;
size = smax * tmax;
lm = surf->samples;
memset( r_blocklights, 0, sizeof( uint ) * size * 3 );
// add all the lightmaps
for( map = 0; map < MAXLIGHTMAPS && surf->styles[map] != 255 && lm; map++ )
{
// FIXME we need to CL_RunLightStyles first to do this scale = tr.lightstylevalue[surf->styles[map]];
const int scale = 256;
for( i = 0, bl = r_blocklights; i < size; i++, bl += 3, lm++ )
{
bl[0] += gEngine.LightToTexGamma( lm->r ) * scale;
bl[1] += gEngine.LightToTexGamma( lm->g ) * scale;
bl[2] += gEngine.LightToTexGamma( lm->b ) * scale;
}
}
/* TODO
// add all the dynamic lights
if( surf->dlightframe == tr.framecount && dynamic )
R_AddDynamicLights( surf );
*/
// Put into texture format
stride -= (smax << 2);
bl = r_blocklights;
for( t = 0; t < tmax; t++, dest += stride )
{
for( s = 0; s < smax; s++ )
{
dest[0] = Q_min((bl[0] >> 7), 255 );
dest[1] = Q_min((bl[1] >> 7), 255 );
dest[2] = Q_min((bl[2] >> 7), 255 );
dest[3] = 255;
bl += 3;
dest += 4;
}
}
}
void VK_CreateSurfaceLightmap( msurface_t *surf, const model_t *loadmodel )
{
int smax, tmax;
int sample_size;
mextrasurf_t *info = surf->info;
byte *base;
if( !loadmodel->lightdata )
return;
if( FBitSet( surf->flags, SURF_DRAWTILED ))
return;
sample_size = gEngine.Mod_SampleSizeForFace( surf );
smax = ( info->lightextents[0] / sample_size ) + 1;
tmax = ( info->lightextents[1] / sample_size ) + 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 ))
gEngine.Host_Error( "AllocBlock: full\n" );
}
surf->lightmaptexturenum = gl_lms.current_lightmap_texture;
base = gl_lms.lightmap_buffer;
base += ( surf->light_t * BLOCK_SIZE + surf->light_s ) * 4;
// FIXME R_SetCacheState( surf );
R_BuildLightMap( surf, base, BLOCK_SIZE * 4, false );
}
void VK_UploadLightmap( void )
{
LM_UploadBlock( false );
}
void VK_ClearLightmap( void )
{
for (int i = 0; i < gl_lms.current_lightmap_texture; ++i)
VK_FreeTexture(tglob.lightmapTextures[i]);
gl_lms.current_lightmap_texture = 0;
}