ref_gl: vbo dlights refactiring

This commit is contained in:
mittorn 2023-10-17 03:20:41 +03:00 committed by Alibek Omarov
parent 3e7847551a
commit 6b73d056b2
1 changed files with 504 additions and 397 deletions

View File

@ -2237,159 +2237,100 @@ static void R_AdditionalPasses( vboarray_t *vbo, int indexlen, void *indexarray,
}
#define MINIMIZE_UPLOAD
#define DISCARD_DLIGHTS
/*
=====================
R_DrawLightmappedVBO
Draw array for given vbotexture_t. build and draw dynamic lightmaps if present
=====================
*/
static void R_DrawLightmappedVBO( vboarray_t *vbo, vbotexture_t *vbotex, texture_t *texture, int lightmap, qboolean skiplighting )
static void R_DrawDlightedDecals( vboarray_t *vbo, msurface_t *newsurf, msurface_t *surf, int decalcount, texture_t *texture )
{
#if !defined XASH_NANOGL || defined XASH_WES && XASH_EMSCRIPTEN // WebGL need to know array sizes
if( pglDrawRangeElements )
pglDrawRangeElements( GL_TRIANGLES, 0, vbo->array_len, vbotex->curindex, GL_UNSIGNED_SHORT, vbotex->indexarray );
else
#endif
pglDrawElements( GL_TRIANGLES, vbotex->curindex, GL_UNSIGNED_SHORT, vbotex->indexarray );
msurface_t *decalsurf;
decal_t *pdecal;
int decali = 0;
// draw debug lines
if( gl_wireframe.value && !skiplighting )
{
pglDepthMask( GL_FALSE );
pglEnable( GL_BLEND );
pglEnable( GL_POLYGON_OFFSET_FILL );
if( RI.currententity->curstate.rendermode == kRenderTransAlpha )
pglDisable( GL_ALPHA_TEST );
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.decal_dlight_vbo );
R_SetDecalMode( true );
pglDisable( GL_TEXTURE_2D );
GL_SelectTexture( XASH_TEXTURE0 );
pglDisable( GL_TEXTURE_2D );
pglDisable( GL_DEPTH_TEST );
#if !defined XASH_NANOGL || defined XASH_WES && XASH_EMSCRIPTEN // WebGL need to know array sizes
if( pglDrawRangeElements )
pglDrawRangeElements( GL_LINES, 0, vbo->array_len, vbotex->curindex, GL_UNSIGNED_SHORT, vbotex->indexarray );
if( vbos.decal_dlight_vbo )
{
pglTexCoordPointer( 2, GL_FLOAT, sizeof( vbovertex_t ), (void*)offsetof( vbovertex_t, lm_tc ) );
GL_SelectTexture( mtst.tmu_gl );
pglTexCoordPointer( 2, GL_FLOAT, sizeof( vbovertex_t ), (void*)offsetof( vbovertex_t, gl_tc ) );
pglVertexPointer( 3, GL_FLOAT, sizeof( vbovertex_t ), (void*)offsetof( vbovertex_t, pos ) );
}
else
#endif
pglDrawElements( GL_LINES, vbotex->curindex, GL_UNSIGNED_SHORT, vbotex->indexarray );
pglEnable( GL_DEPTH_TEST );
pglEnable( GL_TEXTURE_2D );
GL_SelectTexture( XASH_TEXTURE1 );
pglEnable( GL_TEXTURE_2D );
R_SetDecalMode( false );
}
//Msg( "%d %d %d\n", vbo->array_len, vbotex->len, lightmap );
if( skiplighting )
{
vbotex->curindex = 0;
vbotex->dlightchain = NULL;
return;
pglTexCoordPointer( 2, GL_FLOAT, sizeof( vbovertex_t ), &vbos.decal_dlight[0].lm_tc );
GL_SelectTexture( mtst.tmu_gl );
pglTexCoordPointer( 2, GL_FLOAT, sizeof( vbovertex_t ), &vbos.decal_dlight[0].gl_tc );
pglVertexPointer( 3, GL_FLOAT, sizeof( vbovertex_t ), &vbos.decal_dlight[0].pos);
}
// draw dlights and dlighted decals
if( vbotex->dlightchain )
for( decalsurf = newsurf; ( decali < decalcount ) && (!surf ||( decalsurf != surf )); decalsurf = decalsurf->info->lightmapchain )
{
unsigned short *dlightarray = vbos.dlight_index; // preallocated array
unsigned int dlightindex = 0;
msurface_t *surf, *newsurf;
int decalcount = 0;
int min_index = 65536;
int max_index = 0;
for( pdecal = decalsurf->pdecals; pdecal; pdecal = pdecal->pnext )
{
gl_texture_t *glt;
if( !pdecal->texture )
continue;
glt = R_GetTexture( pdecal->texture );
GL_Bind( mtst.tmu_gl, pdecal->texture );
// normal HL decal with alpha-channel
if( glt->flags & TF_HAS_ALPHA )
{
// draw transparent decals with GL_MODULATE
if( glt->fogParams[3] > 230 )
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
else pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
pglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
}
else
{
// color decal like detail texture. Base color is 127 127 127
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
pglBlendFunc( GL_DST_COLOR, GL_SRC_COLOR );
}
pglDrawArrays( GL_TRIANGLE_FAN, decali * DECAL_VERTS_MAX, vbos.decal_numverts[decali] );
decali++;
}
newsurf = surf;
}
GL_Bind( mtst.tmu_lm, tr.dlightTexture );
// replace lightmap texcoord array by dlight array
// restore states pointers for next dynamic lightmap
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vbos.decal_dlight ), NULL, GL_STREAM_DRAW_ARB );
pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
pglDepthMask( GL_TRUE );
pglDisable( GL_BLEND );
pglDisable( GL_POLYGON_OFFSET_FILL );
if( RI.currententity->curstate.rendermode == kRenderTransAlpha )
pglEnable( GL_ALPHA_TEST );
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.dlight_vbo );
R_SetDecalMode( false );
GL_SelectTexture( mtst.tmu_lm );
if( vbos.dlight_vbo )
pglTexCoordPointer( 2, GL_FLOAT, sizeof( float ) * 2, 0 );
else
pglTexCoordPointer( 2, GL_FLOAT, sizeof( float ) * 2, vbos.dlight_tc );
// clear the block
LM_InitBlock();
if( vbos.dlight_vbo )
{
// calculate minimum indexbase
for( surf = newsurf = vbotex->dlightchain; surf; surf = surf->info->lightmapchain )
{
uint indexbase = vbos.surfdata[((char*)surf - (char*)WORLDMODEL->surfaces) / sizeof( *surf )].startindex;
if(min_index > indexbase)
min_index = indexbase;
#ifdef MINIMIZE_UPLOAD
if( max_index < indexbase + surf->polys->numverts )
max_index = indexbase + surf->polys->numverts;
#endif
}
#ifdef MINIMIZE_UPLOAD
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.dlight_vbo );
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vec2_t )* (max_index - min_index), NULL, GL_STREAM_DRAW_ARB );
#endif
}
else
{
min_index = 0;
}
// accumulate indexes for every dlighted surface until dlight block full
for( surf = newsurf = vbotex->dlightchain; surf; surf = surf->info->lightmapchain )
{
int smax, tmax;
byte *base;
uint indexbase = vbos.surfdata[((char*)surf - (char*)WORLDMODEL->surfaces) / sizeof( *surf )].startindex;
uint index;
mextrasurf_t *info; // this stores current dlight offset
decal_t *pdecal;
int sample_size;
info = surf->info;
sample_size = gEngfuncs.Mod_SampleSizeForFace( surf );
smax = ( info->lightextents[0] / sample_size ) + 1;
tmax = ( info->lightextents[1] / sample_size ) + 1;
// find space for this surface and get offsets
if( LM_AllocBlock( smax, tmax, &info->dlight_s, &info->dlight_t ))
{
base = gl_lms.lightmap_buffer;
base += ( info->dlight_t * BLOCK_SIZE + info->dlight_s ) * 4;
R_BuildLightMap( surf, base, BLOCK_SIZE * 4, true );
}
else
{
// out of free block space. Draw all generated index array and clear it
// upload already generated block
if( vbos.dlight_vbo )
{
#ifndef MINIMIZE_UPLOAD
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.dlight_vbo );
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vec2_t )* (max_index - min_index), vbos.dlight_tc + min_index, GL_STREAM_DRAW_ARB );
#endif
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbo->glindex );
pglVertexPointer( 3, GL_FLOAT, sizeof( vbovertex_t ), (void*)(min_index* sizeof( vbovertex_t ) + offsetof(vbovertex_t,pos)) );
GL_SelectTexture( XASH_TEXTURE0 );
pglTexCoordPointer( 2, GL_FLOAT, sizeof( vbovertex_t ), (void*)(min_index * sizeof( vbovertex_t ) + offsetof(vbovertex_t,gl_tc)) );
GL_SelectTexture( XASH_TEXTURE1 );
pglVertexPointer( 3, GL_FLOAT, sizeof( vbovertex_t ), (void*)offsetof(vbovertex_t,pos) );
R_SetupVBOTexture( texture, 0 );
pglTexCoordPointer( 2, GL_FLOAT, sizeof( vbovertex_t ), (void*)offsetof(vbovertex_t, gl_tc ) );
}
#ifdef DISCARD_DLIGHTS
pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, BLOCK_SIZE, BLOCK_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
#endif
LM_UploadDynamicBlock();
#if !defined XASH_NANOGL || defined XASH_WES && XASH_EMSCRIPTEN // WebGL need to know array sizes
if( pglDrawRangeElements )
pglDrawRangeElements( GL_TRIANGLES, min_index, max_index, dlightindex, GL_UNSIGNED_SHORT, dlightarray );
else
#endif
pglDrawElements( GL_TRIANGLES, dlightindex, GL_UNSIGNED_SHORT, dlightarray );
#ifdef MINIMIZE_UPLOAD
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.dlight_vbo );
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vec2_t )* (max_index - min_index), NULL, GL_STREAM_DRAW_ARB );
#else
max_index = 0;
#endif
// draw decals that lighted with this lightmap
if( decalcount )
#if 0
// two stages left for refenence if something break
void R_DrawDlightedDecals0( vboarray_t *vbo, msurface_t *newsurf, msurface_t *surf, int decalcount, texture_t *texture )
{
msurface_t *decalsurf;
decal_t *pdecal;
int decali = 0;
pglDepthMask( GL_FALSE );
@ -2471,127 +2412,11 @@ static void R_DrawLightmappedVBO( vboarray_t *vbo, vbotexture_t *vbotex, texture
pglVertexPointer( 3, GL_FLOAT, sizeof( vbovertex_t ), (void*)offsetof(vbovertex_t,pos) );
R_SetupVBOTexture( texture, 0 );
pglTexCoordPointer( 2, GL_FLOAT, sizeof( vbovertex_t ), (void*)offsetof(vbovertex_t, gl_tc ) );
decalcount = 0;
}
// clear the block
LM_InitBlock();
dlightindex = 0;
// try upload the block now
if( !LM_AllocBlock( smax, tmax, &info->dlight_s, &info->dlight_t ))
gEngfuncs.Host_Error( "AllocBlock: full\n" );
base = gl_lms.lightmap_buffer;
base += ( info->dlight_t * BLOCK_SIZE + info->dlight_s ) * 4;
R_BuildLightMap( surf, base, BLOCK_SIZE * 4, true );
}
// build index and texcoords arrays
vbos.dlight_tc[indexbase][0] = surf->polys->verts[0][5] - ( surf->light_s - info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE );
vbos.dlight_tc[indexbase][1] = surf->polys->verts[0][6] - ( surf->light_t - info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE );
vbos.dlight_tc[indexbase + 1][0] = surf->polys->verts[1][5] - ( surf->light_s - info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE );
vbos.dlight_tc[indexbase + 1][1] = surf->polys->verts[1][6] - ( surf->light_t - info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE );
for( index = indexbase + 2; index < indexbase + surf->polys->numverts; index++ )
{
dlightarray[dlightindex++] = indexbase - min_index;
dlightarray[dlightindex++] = index - 1 - min_index;
dlightarray[dlightindex++] = index - min_index;
vbos.dlight_tc[index][0] = surf->polys->verts[index - indexbase][5] - ( surf->light_s - info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE );
vbos.dlight_tc[index][1] = surf->polys->verts[index - indexbase][6] - ( surf->light_t - info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE );
}
#ifndef MINIMIZE_UPLOAD
if( max_index < indexbase + surf->polys->numverts )
max_index = indexbase + surf->polys->numverts;
#else
if( vbos.dlight_vbo )
{
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.dlight_vbo );
pglBufferSubDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vec2_t ) * (indexbase - min_index), sizeof( vec2_t )* surf->polys->numverts, vbos.dlight_tc + indexbase );
}
#endif
// if surface has decals, build decal array
for( pdecal = surf->pdecals; pdecal; pdecal = pdecal->pnext )
{
int decalindex = pdecal - &gDecalPool[0];
int numVerts = vbos.decaldata->decals[decalindex].numVerts;
int i;
if( numVerts == -1 )
{
// build decal array
float *v = R_DecalSetupVerts( pdecal, surf, pdecal->texture, &numVerts );
for( i = 0; i < numVerts; i++, v += VERTEXSIZE )
{
VectorCopy( v, vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].pos );
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].gl_tc[0] = v[3];
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].gl_tc[1] = v[4];
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].lm_tc[0] = v[5] - ( surf->light_s - info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE );
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].lm_tc[1] = v[6] - ( surf->light_t - info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE );
}
}
else
{
// copy from vbo
for( i = 0; i < numVerts; i++ )
{
VectorCopy( vbos.decaldata->decalarray[decalindex * DECAL_VERTS_CUT + i].pos, vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].pos );
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].gl_tc[0] = vbos.decaldata->decalarray[decalindex * DECAL_VERTS_CUT + i].gl_tc[0];
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].gl_tc[1] = vbos.decaldata->decalarray[decalindex * DECAL_VERTS_CUT + i].gl_tc[1];
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].lm_tc[0] = vbos.decaldata->decalarray[decalindex * DECAL_VERTS_CUT + i].lm_tc[0] - ( surf->light_s - info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE );
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].lm_tc[1] = vbos.decaldata->decalarray[decalindex * DECAL_VERTS_CUT + i].lm_tc[1] - ( surf->light_t - info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE );
}
}
if( vbos.dlight_vbo )
{
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.decal_dlight_vbo );
pglBufferSubDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vbovertex_t ) * decalcount * DECAL_VERTS_MAX, sizeof( vbovertex_t )* numVerts, vbos.decal_dlight + decalcount * DECAL_VERTS_MAX );
}
vbos.decal_numverts[decalcount] = numVerts;
decalcount++;
}
//info->dlight_s = info->dlight_t = 0;
}
if( dlightindex )
{
#ifdef DISCARD_DLIGHTS
pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, BLOCK_SIZE, BLOCK_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
#endif
// update block
LM_UploadDynamicBlock();
if( vbos.dlight_vbo )
{
#ifndef MINIMIZE_UPLOAD
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.dlight_vbo );
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vec2_t )* (max_index - min_index), vbos.dlight_tc + min_index, GL_STREAM_DRAW_ARB );
#endif
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbo->glindex );
pglVertexPointer( 3, GL_FLOAT, sizeof( vbovertex_t ), (void*)(min_index * sizeof( vbovertex_t ) + offsetof(vbovertex_t,pos)) );
GL_SelectTexture( XASH_TEXTURE0 );
pglTexCoordPointer( 2, GL_FLOAT, sizeof( vbovertex_t ), (void*)(min_index * sizeof( vbovertex_t ) + offsetof(vbovertex_t,gl_tc)) );
GL_SelectTexture( XASH_TEXTURE1 );
}
// draw remaining array
#if !defined XASH_NANOGL || defined XASH_WES && XASH_EMSCRIPTEN // WebGL need to know array sizes
if( pglDrawRangeElements )
pglDrawRangeElements( GL_TRIANGLES, min_index, max_index, dlightindex, GL_UNSIGNED_SHORT, dlightarray );
else
#endif
pglDrawElements( GL_TRIANGLES, dlightindex, GL_UNSIGNED_SHORT, dlightarray );
//R_AdditionalPasses( vbo, dlightindex, dlightarray, texture, true );
// draw remaining decals
if( decalcount )
void R_DrawDlightedDecals1( vboarray_t *vbo, msurface_t *newsurf, msurface_t *surf, int decalcount, texture_t *texture )
{
msurface_t *decalsurf;
int decali = 0;
@ -2669,6 +2494,232 @@ static void R_DrawLightmappedVBO( vboarray_t *vbo, vbotexture_t *vbotex, texture
R_SetupVBOTexture( texture, 0 );
pglTexCoordPointer( 2, GL_FLOAT, sizeof( vbovertex_t ), (void*)offsetof(vbovertex_t, gl_tc ) );
}
#endif
static void R_FlushDlights( vboarray_t *vbo, int min_index, int max_index, int dlightindex, unsigned short *dlightarray )
{
if( vbos.dlight_vbo )
{
#ifndef MINIMIZE_UPLOAD
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.dlight_vbo );
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vec2_t )* (max_index - min_index), vbos.dlight_tc + min_index, GL_STREAM_DRAW_ARB );
#endif
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbo->glindex );
pglVertexPointer( 3, GL_FLOAT, sizeof( vbovertex_t ), (void*)(min_index* sizeof( vbovertex_t ) + offsetof(vbovertex_t,pos)) );
GL_SelectTexture( XASH_TEXTURE0 );
pglTexCoordPointer( 2, GL_FLOAT, sizeof( vbovertex_t ), (void*)(min_index * sizeof( vbovertex_t ) + offsetof(vbovertex_t,gl_tc)) );
GL_SelectTexture( XASH_TEXTURE1 );
}
#ifdef DISCARD_DLIGHTS
pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, BLOCK_SIZE, BLOCK_SIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
#endif
LM_UploadDynamicBlock();
#if !defined XASH_NANOGL || defined XASH_WES && XASH_EMSCRIPTEN // WebGL need to know array sizes
if( pglDrawRangeElements )
pglDrawRangeElements( GL_TRIANGLES, min_index, max_index, dlightindex, GL_UNSIGNED_SHORT, dlightarray );
else
#endif
pglDrawElements( GL_TRIANGLES, dlightindex, GL_UNSIGNED_SHORT, dlightarray );
}
static void R_AddSurfaceDecalsDlight( msurface_t *surf, int *pdecalcount)
{
decal_t *pdecal;
int decalcount = *pdecalcount;
for( pdecal = surf->pdecals; pdecal; pdecal = pdecal->pnext )
{
int decalindex = pdecal - &gDecalPool[0];
int numVerts = vbos.decaldata->decals[decalindex].numVerts;
int i;
if( numVerts == -1 )
{
// build decal array
float *v = R_DecalSetupVerts( pdecal, surf, pdecal->texture, &numVerts );
for( i = 0; i < numVerts; i++, v += VERTEXSIZE )
{
VectorCopy( v, vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].pos );
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].gl_tc[0] = v[3];
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].gl_tc[1] = v[4];
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].lm_tc[0] = v[5] - ( surf->light_s - surf->info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE );
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].lm_tc[1] = v[6] - ( surf->light_t - surf->info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE );
}
}
else
{
// copy from vbo
for( i = 0; i < numVerts; i++ )
{
VectorCopy( vbos.decaldata->decalarray[decalindex * DECAL_VERTS_CUT + i].pos, vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].pos );
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].gl_tc[0] = vbos.decaldata->decalarray[decalindex * DECAL_VERTS_CUT + i].gl_tc[0];
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].gl_tc[1] = vbos.decaldata->decalarray[decalindex * DECAL_VERTS_CUT + i].gl_tc[1];
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].lm_tc[0] = vbos.decaldata->decalarray[decalindex * DECAL_VERTS_CUT + i].lm_tc[0] - ( surf->light_s - surf->info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE );
vbos.decal_dlight[decalcount * DECAL_VERTS_MAX + i].lm_tc[1] = vbos.decaldata->decalarray[decalindex * DECAL_VERTS_CUT + i].lm_tc[1] - ( surf->light_t - surf->info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE );
}
}
if( vbos.dlight_vbo )
{
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.decal_dlight_vbo );
pglBufferSubDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vbovertex_t ) * decalcount * DECAL_VERTS_MAX, sizeof( vbovertex_t )* numVerts, vbos.decal_dlight + decalcount * DECAL_VERTS_MAX );
}
vbos.decal_numverts[decalcount] = numVerts;
decalcount++;
}
*pdecalcount = decalcount;
}
static void R_DrawVBODlights( vboarray_t *vbo, vbotexture_t *vbotex, texture_t *texture, int lightmap )
{
// draw dlights and dlighted decals
if( vbotex->dlightchain )
{
unsigned short *dlightarray = vbos.dlight_index; // preallocated array
unsigned int dlightindex = 0;
msurface_t *surf, *newsurf;
int decalcount = 0;
int min_index = 65536;
int max_index = 0;
GL_Bind( mtst.tmu_lm, tr.dlightTexture );
// replace lightmap texcoord array by dlight array
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.dlight_vbo );
if( vbos.dlight_vbo )
pglTexCoordPointer( 2, GL_FLOAT, sizeof( float ) * 2, 0 );
else
pglTexCoordPointer( 2, GL_FLOAT, sizeof( float ) * 2, vbos.dlight_tc );
// clear the block
LM_InitBlock();
if( vbos.dlight_vbo )
{
// calculate minimum indexbase
for( surf = newsurf = vbotex->dlightchain; surf; surf = surf->info->lightmapchain )
{
uint indexbase = vbos.surfdata[((char*)surf - (char*)WORLDMODEL->surfaces) / sizeof( *surf )].startindex;
if(min_index > indexbase)
min_index = indexbase;
#ifdef MINIMIZE_UPLOAD
if( max_index < indexbase + surf->polys->numverts )
max_index = indexbase + surf->polys->numverts;
#endif
}
#ifdef MINIMIZE_UPLOAD
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.dlight_vbo );
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vec2_t )* (max_index - min_index), NULL, GL_STREAM_DRAW_ARB );
#endif
}
else
{
min_index = 0;
}
// accumulate indexes for every dlighted surface until dlight block full
for( surf = newsurf = vbotex->dlightchain; surf; surf = surf->info->lightmapchain )
{
int smax, tmax;
byte *base;
uint indexbase = vbos.surfdata[((char*)surf - (char*)WORLDMODEL->surfaces) / sizeof( *surf )].startindex;
uint index;
mextrasurf_t *info; // this stores current dlight offset
decal_t *pdecal;
int sample_size;
info = surf->info;
sample_size = gEngfuncs.Mod_SampleSizeForFace( surf );
smax = ( info->lightextents[0] / sample_size ) + 1;
tmax = ( info->lightextents[1] / sample_size ) + 1;
// find space for this surface and get offsets
if( LM_AllocBlock( smax, tmax, &info->dlight_s, &info->dlight_t ))
{
base = gl_lms.lightmap_buffer;
base += ( info->dlight_t * BLOCK_SIZE + info->dlight_s ) * 4;
R_BuildLightMap( surf, base, BLOCK_SIZE * 4, true );
}
else
{
// out of free block space. Draw all generated index array and clear it
// upload already generated block
R_FlushDlights( vbo, min_index, max_index, dlightindex, dlightarray );
#ifdef MINIMIZE_UPLOAD
// invalidate buffer to prevent blocking on SubData
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.dlight_vbo );
pglBufferDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vec2_t )* (max_index - min_index), NULL, GL_STREAM_DRAW_ARB );
#else
max_index = 0;
#endif
// draw decals that lighted with this lightmap
if( decalcount )
R_DrawDlightedDecals( vbo, newsurf, surf, decalcount, texture );
decalcount = 0;
// clear the block
LM_InitBlock();
dlightindex = 0;
// try upload the block now
if( !LM_AllocBlock( smax, tmax, &info->dlight_s, &info->dlight_t ))
gEngfuncs.Host_Error( "AllocBlock: full\n" );
base = gl_lms.lightmap_buffer;
base += ( info->dlight_t * BLOCK_SIZE + info->dlight_s ) * 4;
R_BuildLightMap( surf, base, BLOCK_SIZE * 4, true );
}
// build index and texcoords arrays
vbos.dlight_tc[indexbase][0] = surf->polys->verts[0][5] - ( surf->light_s - info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE );
vbos.dlight_tc[indexbase][1] = surf->polys->verts[0][6] - ( surf->light_t - info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE );
vbos.dlight_tc[indexbase + 1][0] = surf->polys->verts[1][5] - ( surf->light_s - info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE );
vbos.dlight_tc[indexbase + 1][1] = surf->polys->verts[1][6] - ( surf->light_t - info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE );
for( index = indexbase + 2; index < indexbase + surf->polys->numverts; index++ )
{
dlightarray[dlightindex++] = indexbase - min_index;
dlightarray[dlightindex++] = index - 1 - min_index;
dlightarray[dlightindex++] = index - min_index;
vbos.dlight_tc[index][0] = surf->polys->verts[index - indexbase][5] - ( surf->light_s - info->dlight_s ) * ( 1.0f / (float)BLOCK_SIZE );
vbos.dlight_tc[index][1] = surf->polys->verts[index - indexbase][6] - ( surf->light_t - info->dlight_t ) * ( 1.0f / (float)BLOCK_SIZE );
}
#ifndef MINIMIZE_UPLOAD
if( max_index < indexbase + surf->polys->numverts )
max_index = indexbase + surf->polys->numverts;
#else
if( vbos.dlight_vbo )
{
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.dlight_vbo );
pglBufferSubDataARB( GL_ARRAY_BUFFER_ARB, sizeof( vec2_t ) * (indexbase - min_index), sizeof( vec2_t )* surf->polys->numverts, vbos.dlight_tc + indexbase );
}
#endif
// if surface has decals, build decal array
R_AddSurfaceDecalsDlight( surf, &decalcount );
//info->dlight_s = info->dlight_t = 0;
}
if( dlightindex )
{
R_FlushDlights( vbo, min_index, max_index, dlightindex, dlightarray );
//R_AdditionalPasses( vbo, dlightindex, dlightarray, texture, true );
// draw remaining decals
if( decalcount )
{
R_DrawDlightedDecals( vbo, newsurf, NULL, decalcount, texture );
}
}
// restore static lightmap
@ -2682,6 +2733,55 @@ static void R_DrawLightmappedVBO( vboarray_t *vbo, vbotexture_t *vbotex, texture
// prepare to next frame
vbotex->dlightchain = NULL;
}
}
/*
=====================
R_DrawLightmappedVBO
Draw array for given vbotexture_t. build and draw dynamic lightmaps if present
=====================
*/
static void R_DrawLightmappedVBO( vboarray_t *vbo, vbotexture_t *vbotex, texture_t *texture, int lightmap, qboolean skiplighting )
{
#if !defined XASH_NANOGL || defined XASH_WES && XASH_EMSCRIPTEN // WebGL need to know array sizes
if( pglDrawRangeElements )
pglDrawRangeElements( GL_TRIANGLES, 0, vbo->array_len, vbotex->curindex, GL_UNSIGNED_SHORT, vbotex->indexarray );
else
#endif
pglDrawElements( GL_TRIANGLES, vbotex->curindex, GL_UNSIGNED_SHORT, vbotex->indexarray );
// draw debug lines
if( gl_wireframe.value && !skiplighting )
{
R_SetDecalMode( true );
pglDisable( GL_TEXTURE_2D );
GL_SelectTexture( XASH_TEXTURE0 );
pglDisable( GL_TEXTURE_2D );
pglDisable( GL_DEPTH_TEST );
#if !defined XASH_NANOGL || defined XASH_WES && XASH_EMSCRIPTEN // WebGL need to know array sizes
if( pglDrawRangeElements )
pglDrawRangeElements( GL_LINES, 0, vbo->array_len, vbotex->curindex, GL_UNSIGNED_SHORT, vbotex->indexarray );
else
#endif
pglDrawElements( GL_LINES, vbotex->curindex, GL_UNSIGNED_SHORT, vbotex->indexarray );
pglEnable( GL_DEPTH_TEST );
pglEnable( GL_TEXTURE_2D );
GL_SelectTexture( XASH_TEXTURE1 );
pglEnable( GL_TEXTURE_2D );
R_SetDecalMode( false );
}
//Msg( "%d %d %d\n", vbo->array_len, vbotex->len, lightmap );
if( skiplighting )
{
vbotex->curindex = 0;
vbotex->dlightchain = NULL;
return;
}
R_DrawVBODlights( vbo, vbotex, texture, lightmap );
R_AdditionalPasses( vbo, vbotex->curindex, vbotex->indexarray, texture, false );
// prepare to next frame
@ -2716,102 +2816,11 @@ void R_SetupVBOArray( vboarray_t *vbo, qboolean drawlightmap, qboolean drawtextu
}
}
/*
=====================
R_DrawVBO
Draw generated index arrays
=====================
*/
void R_DrawVBO( qboolean drawlightmap, qboolean drawtextures )
static void R_DrawStaticDecals( vboarray_t *vbo, qboolean drawlightmap, int ilightmap )
{
int numtextures = WORLDMODEL->numtextures;
int numlightmaps = gl_lms.current_lightmap_texture;
int k;
vboarray_t *vbo = vbos.arraylist;
if( !r_vbo.value )
return;
GL_SetupFogColorForSurfacesEx( 1, 0.5f );
R_SetupVBOArray( vbo, drawlightmap, drawtextures );
mtst.skiptexture = !drawtextures;
mtst.tmu_dt = glConfig.max_texture_units > 2 && r_vbo_detail.value == 2? XASH_TEXTURE2:-1;
// setup limits
if( vbos.minlightmap > vbos.minarraysplit_lm )
vbos.minlightmap = vbos.minarraysplit_lm;
if( vbos.maxlightmap < vbos.maxarraysplit_lm )
vbos.maxlightmap = vbos.maxarraysplit_lm;
if( vbos.maxlightmap > numlightmaps )
vbos.maxlightmap = numlightmaps;
if( vbos.mintexture > vbos.minarraysplit_tex )
vbos.mintexture = vbos.minarraysplit_tex;
if( vbos.maxtexture < vbos.maxarraysplit_tex )
vbos.maxtexture = vbos.maxarraysplit_tex;
if( vbos.maxtexture > numtextures )
vbos.maxtexture = numtextures;
for( k = vbos.minlightmap; k < vbos.maxlightmap; k++ )
{
int j;
int k = ilightmap;
msurface_t *lightmapchain;
if( drawlightmap )
{
GL_Bind( mtst.tmu_lm, mtst.lm = tr.lightmapTextures[k] );
}
for( j = vbos.mintexture; j < vbos.maxtexture; j++ )
{
vbotexture_t *vbotex = &vbos.textures[k * numtextures + j];
texture_t *tex = NULL;
if( !vbotex->vboarray )
continue;
// ASSERT( vbotex->vboarray == vbo );
if( vbotex->vboarray != vbo )
continue;
if( vbotex->curindex || vbotex->dlightchain )
{
// draw textures static lightmap first
if( drawtextures )
tex = R_SetupVBOTexture( NULL, j );
R_DrawLightmappedVBO( vbo, vbotex, tex, k, !drawlightmap );
}
// if we need to switch to next array (only if map has >65536 vertices)
while( vbotex->next )
{
vbotex = vbotex->next;
vbo = vbo->next;
if( drawtextures )
{
tex = R_SetupVBOTexture( tex, j );
}
// update texcoord pointers
R_SetupVBOArray( vbo, drawlightmap, drawtextures );
if( drawlightmap )
{
GL_Bind( mtst.tmu_lm, tr.lightmapTextures[k] );
}
// draw new array
if( (vbotex->curindex || vbotex->dlightchain) )
R_DrawLightmappedVBO( vbo, vbotex, tex, k, !drawlightmap );
}
}
if( drawtextures && drawlightmap && vbos.decaldata->lm[k] )
{
// prepare for decal draw
pglBindBufferARB( GL_ARRAY_BUFFER_ARB, vbos.decaldata->decalvbo );
pglDepthMask( GL_FALSE );
@ -2924,6 +2933,104 @@ void R_DrawVBO( qboolean drawlightmap, qboolean drawtextures )
if( RI.currententity->curstate.rendermode == kRenderTransAlpha )
pglEnable( GL_ALPHA_TEST );
}
/*
=====================
R_DrawVBO
Draw generated index arrays
=====================
*/
void R_DrawVBO( qboolean drawlightmap, qboolean drawtextures )
{
int numtextures = WORLDMODEL->numtextures;
int numlightmaps = gl_lms.current_lightmap_texture;
int k;
vboarray_t *vbo = vbos.arraylist;
if( !r_vbo.value )
return;
GL_SetupFogColorForSurfacesEx( 1, 0.5f );
R_SetupVBOArray( vbo, drawlightmap, drawtextures );
mtst.skiptexture = !drawtextures;
mtst.tmu_dt = glConfig.max_texture_units > 2 && r_vbo_detail.value == 2? XASH_TEXTURE2:-1;
// setup limits
if( vbos.minlightmap > vbos.minarraysplit_lm )
vbos.minlightmap = vbos.minarraysplit_lm;
if( vbos.maxlightmap < vbos.maxarraysplit_lm )
vbos.maxlightmap = vbos.maxarraysplit_lm;
if( vbos.maxlightmap > numlightmaps )
vbos.maxlightmap = numlightmaps;
if( vbos.mintexture > vbos.minarraysplit_tex )
vbos.mintexture = vbos.minarraysplit_tex;
if( vbos.maxtexture < vbos.maxarraysplit_tex )
vbos.maxtexture = vbos.maxarraysplit_tex;
if( vbos.maxtexture > numtextures )
vbos.maxtexture = numtextures;
for( k = vbos.minlightmap; k < vbos.maxlightmap; k++ )
{
int j;
if( drawlightmap )
{
GL_Bind( mtst.tmu_lm, mtst.lm = tr.lightmapTextures[k] );
}
for( j = vbos.mintexture; j < vbos.maxtexture; j++ )
{
vbotexture_t *vbotex = &vbos.textures[k * numtextures + j];
texture_t *tex = NULL;
if( !vbotex->vboarray )
continue;
// ASSERT( vbotex->vboarray == vbo );
if( vbotex->vboarray != vbo )
continue;
if( vbotex->curindex || vbotex->dlightchain )
{
// draw textures static lightmap first
if( drawtextures )
tex = R_SetupVBOTexture( NULL, j );
R_DrawLightmappedVBO( vbo, vbotex, tex, k, !drawlightmap );
}
// if we need to switch to next array (only if map has >65536 vertices)
while( vbotex->next )
{
vbotex = vbotex->next;
vbo = vbo->next;
if( drawtextures )
{
tex = R_SetupVBOTexture( tex, j );
}
// update texcoord pointers
R_SetupVBOArray( vbo, drawlightmap, drawtextures );
if( drawlightmap )
{
GL_Bind( mtst.tmu_lm, tr.lightmapTextures[k] );
}
// draw new array
if( (vbotex->curindex || vbotex->dlightchain) )
R_DrawLightmappedVBO( vbo, vbotex, tex, k, !drawlightmap );
}
}
if( drawtextures && drawlightmap && vbos.decaldata->lm[k] )
{
R_DrawStaticDecals( vbo, drawlightmap, k );
}
if( !drawtextures || !drawlightmap )
vbos.decaldata->lm[k] = NULL;
}