From 50d3a9c833af75021f1a18f90f10d7d7c3b571b9 Mon Sep 17 00:00:00 2001 From: slipher Date: Sat, 5 Oct 2024 00:40:20 -0500 Subject: [PATCH 1/9] Nuke R_AddLightBoundsToVisBounds() visBounds is used only to choose zFar. A comment says that expanding the vis bounds was needed for occlusion queries (which were NUKED in 2014). I looked at the nuking commit ffd171413eab21bf81a1d8c7f456eef90a243bc3 and it seems that the occlusion code involved GL draw calls to "draw" the boundaries of the light and check whether anything would show up. So it's plausible that the expanded zFar would be needed for that stuff. But it shouldn't be needed now. --- src/engine/renderer/tr_main.cpp | 153 -------------------------------- 1 file changed, 153 deletions(-) diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp index 83fdd30a6e..6eecc77287 100644 --- a/src/engine/renderer/tr_main.cpp +++ b/src/engine/renderer/tr_main.cpp @@ -2517,155 +2517,6 @@ void R_AddLightInteractions() } } -void R_AddLightBoundsToVisBounds() -{ - int i; - trRefLight_t *light; - bspNode_t *leaf; - link_t *l; - - for ( i = 0; i < tr.refdef.numLights; i++ ) - { - light = tr.currentLight = &tr.refdef.lights[ i ]; - - if ( light->isStatic ) - { - if ( !glConfig2.staticLight ) - { - continue; - } - - if ( ( r_precomputedLighting->integer || tr.worldLight != lightMode_t::MAP ) && !light->noRadiosity ) - { - continue; - } - } - else - { - if ( !glConfig2.dynamicLight ) - { - continue; - } - - if( r_realtimeLightingRenderer.Get() == Util::ordinal( realtimeLightingRenderer_t::TILED ) ) - { - continue; - } - } - - // we must set up parts of tr.or for light culling - R_RotateLightForViewParms( light, &tr.viewParms, &tr.orientation ); - - // calc local bounds for culling - if ( light->isStatic ) - { - // ignore if not in PVS - if ( !r_noLightVisCull->integer ) - { - for ( l = light->leafs.next; l != &light->leafs; l = l->next ) - { - if ( !l || !l->data ) - { - // something odd happens with the prev/next pointers if ri.Hunk_Alloc was used - break; - } - - leaf = ( bspNode_t * ) l->data; - - if ( leaf->visCounts[ tr.visIndex ] == tr.visCounts[ tr.visIndex ] ) - { - light->visCounts[ tr.visIndex ] = tr.visCounts[ tr.visIndex ]; - } - } - - if ( light->visCounts[ tr.visIndex ] != tr.visCounts[ tr.visIndex ] ) - { - continue; - } - } - - // look if we have to draw the light including its interactions - switch ( R_CullLocalBox( light->localBounds ) ) - { - case cullResult_t::CULL_IN: - default: - break; - - case cullResult_t::CULL_CLIP: - break; - - case cullResult_t::CULL_OUT: - continue; - } - } - else - { - // set up light transform matrix - MatrixSetupTransformFromQuat( light->transformMatrix, light->l.rotation, light->l.origin ); - - // set up light origin for lighting and shadowing - R_SetupLightOrigin( light ); - - // set up model to light view matrix - R_SetupLightView( light ); - - // set up projection - R_SetupLightProjection( light ); - - // calc local bounds for culling - R_SetupLightLocalBounds( light ); - - // look if we have to draw the light including its interactions - switch ( R_CullLocalBox( light->localBounds ) ) - { - case cullResult_t::CULL_IN: - default: - break; - - case cullResult_t::CULL_CLIP: - break; - - case cullResult_t::CULL_OUT: - continue; - } - - // setup world bounds for intersection tests - R_SetupLightWorldBounds( light ); - } - - // add to z buffer bounds - if ( light->worldBounds[ 0 ][ 0 ] < tr.viewParms.visBounds[ 0 ][ 0 ] ) - { - tr.viewParms.visBounds[ 0 ][ 0 ] = light->worldBounds[ 0 ][ 0 ]; - } - - if ( light->worldBounds[ 0 ][ 1 ] < tr.viewParms.visBounds[ 0 ][ 1 ] ) - { - tr.viewParms.visBounds[ 0 ][ 1 ] = light->worldBounds[ 0 ][ 1 ]; - } - - if ( light->worldBounds[ 0 ][ 2 ] < tr.viewParms.visBounds[ 0 ][ 2 ] ) - { - tr.viewParms.visBounds[ 0 ][ 2 ] = light->worldBounds[ 0 ][ 2 ]; - } - - if ( light->worldBounds[ 1 ][ 0 ] > tr.viewParms.visBounds[ 1 ][ 0 ] ) - { - tr.viewParms.visBounds[ 1 ][ 0 ] = light->worldBounds[ 1 ][ 0 ]; - } - - if ( light->worldBounds[ 1 ][ 1 ] > tr.viewParms.visBounds[ 1 ][ 1 ] ) - { - tr.viewParms.visBounds[ 1 ][ 1 ] = light->worldBounds[ 1 ][ 1 ]; - } - - if ( light->worldBounds[ 1 ][ 2 ] > tr.viewParms.visBounds[ 1 ][ 2 ] ) - { - tr.viewParms.visBounds[ 1 ][ 2 ] = light->worldBounds[ 1 ][ 2 ]; - } - } -} - static std::vector botDebugDrawCommands; void RE_SendBotDebugDrawCommands( std::vector commands ) { @@ -2798,10 +2649,6 @@ void R_RenderView( viewParms_t *parms ) R_AddPolygonSurfaces(); - // we have tr.viewParms.visBounds set and now we need to add the light bounds - // or we get wrong occlusion query results - R_AddLightBoundsToVisBounds(); - // set the projection matrix now that we have the world bounded // this needs to be done before entities are // added, because they use the projection From ba3d4581a22b01ba4fbecde4a161fa9b5fb9443d Mon Sep 17 00:00:00 2001 From: slipher Date: Fri, 4 Oct 2024 07:48:26 -0500 Subject: [PATCH 2/9] Delete 2 unused renderer functions --- src/engine/null/null_renderer.cpp | 2 -- src/engine/renderer/tr_init.cpp | 2 -- src/engine/renderer/tr_light.cpp | 31 ------------------- src/engine/renderer/tr_local.h | 4 --- src/engine/renderer/tr_public.h | 2 -- src/engine/renderer/tr_scene.cpp | 51 ------------------------------- 6 files changed, 92 deletions(-) diff --git a/src/engine/null/null_renderer.cpp b/src/engine/null/null_renderer.cpp index 4c9c27dd6e..a95ad46380 100644 --- a/src/engine/null/null_renderer.cpp +++ b/src/engine/null/null_renderer.cpp @@ -126,7 +126,6 @@ bool RE_LoadDynamicShader( const char*, const char* ) } void RE_Finish() { } void RE_TakeVideoFrame( int, int, byte*, byte*, bool ) { } -void RE_AddRefLightToScene( const refLight_t* ) { } int RE_RegisterAnimation( const char* ) { return 1; @@ -259,7 +258,6 @@ refexport_t *GetRefAPI( int, refimport_t* ) re.Finish = RE_Finish; re.TakeVideoFrame = RE_TakeVideoFrame; - re.AddRefLightToScene = RE_AddRefLightToScene; // RB: alternative skeletal animation system re.RegisterAnimation = RE_RegisterAnimation; diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 84da539589..f408d553ef 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -1670,8 +1670,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p // XreaL BEGIN re.TakeVideoFrame = RE_TakeVideoFrame; - re.AddRefLightToScene = RE_AddRefLightToScene; - re.RegisterAnimation = RE_RegisterAnimation; re.CheckSkeleton = RE_CheckSkeleton; re.BuildSkeleton = RE_BuildSkeleton; diff --git a/src/engine/renderer/tr_light.cpp b/src/engine/renderer/tr_light.cpp index cbc60a7a37..ae49791401 100644 --- a/src/engine/renderer/tr_light.cpp +++ b/src/engine/renderer/tr_light.cpp @@ -1618,37 +1618,6 @@ void R_ComputeFinalAttenuation( shaderStage_t *pStage, trRefLight_t *light ) MatrixMultiply( matrix, light->attenuationMatrix, light->attenuationMatrix2 ); } -/* -================= -R_CullLightPoint - -Returns CULL_IN, CULL_CLIP, or CULL_OUT -================= -*/ -cullResult_t R_CullLightPoint( trRefLight_t *light, const vec3_t p ) -{ - int i; - cplane_t *frust; - float dist; - - // check against frustum planes - for ( i = 0; i < 6; i++ ) - { - frust = &light->frustum[ i ]; - - dist = DotProduct( p, frust->normal ) - frust->dist; - - if ( dist < 0 ) - { - // completely outside frustum - return cullResult_t::CULL_OUT; - } - } - - // completely inside frustum - return cullResult_t::CULL_IN; -} - /* ================= R_CullLightTriangle diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index ebba4b5c56..7c0604d5ed 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -401,7 +401,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; // the client game, as well as some locally derived info struct trRefLight_t { - // public from client game refLight_t l; // local @@ -3514,8 +3513,6 @@ inline bool checkGLErrors() byte R_CalcLightCubeSideBits( trRefLight_t *light, vec3_t worldBounds[ 2 ] ); - cullResult_t R_CullLightPoint( trRefLight_t *light, const vec3_t p ); - cullResult_t R_CullLightTriangle( trRefLight_t *light, vec3_t verts[ 3 ] ); cullResult_t R_CullLightWorldBounds( trRefLight_t *light, vec3_t worldBounds[ 2 ] ); @@ -3617,7 +3614,6 @@ inline bool checkGLErrors() void RE_ClearScene(); void RE_AddRefEntityToScene( const refEntity_t *ent ); - void RE_AddRefLightToScene( const refLight_t *light ); void RE_AddPolyToSceneQ3A( qhandle_t hShader, int numVerts, const polyVert_t *verts, int num ); void RE_AddPolyToSceneET( qhandle_t hShader, int numVerts, const polyVert_t *verts ); diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index 62ac333898..55a6bbd843 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -237,8 +237,6 @@ struct refexport_t // XreaL BEGIN void ( *TakeVideoFrame )( int h, int w, byte *captureBuffer, byte *encodeBuffer, bool motionJpeg ); - void ( *AddRefLightToScene )( const refLight_t *light ); - // RB: alternative skeletal animation system qhandle_t ( *RegisterAnimation )( const char *name ); int ( *CheckSkeleton )( refSkeleton_t *skel, qhandle_t model, qhandle_t anim ); diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index 659e195544..087f3566d0 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -276,57 +276,6 @@ void RE_AddRefEntityToScene( const refEntity_t *ent ) r_numEntities++; } -/* -===================== -RE_AddRefLightToScene -===================== -*/ -void RE_AddRefLightToScene( const refLight_t *l ) -{ - trRefLight_t *light; - - if ( !tr.registered ) - { - return; - } - - if ( r_numLights >= MAX_REF_LIGHTS ) - { - return; - } - - if ( l->radius <= 0 && !VectorLength( l->projTarget ) ) - { - return; - } - - if (l->rlType >= refLightType_t::RL_MAX_REF_LIGHT_TYPE) - { - Sys::Drop("RE_AddRefLightToScene: bad rlType %s", Util::enum_str(l->rlType)); - } - - light = &backEndData[ tr.smpFrame ]->lights[ r_numLights++ ]; - light->l = *l; - - light->isStatic = false; - light->additive = true; - - if ( light->l.scale <= 0 ) - { - light->l.scale = r_lightScale->value; - } - - if ( light->l.scale >= r_lightScale->value ) - { - light->l.scale = r_lightScale->value; - } - - if ( !r_realtimeLightingCastShadows->integer && !light->l.inverseShadows ) - { - light->l.noShadows = true; - } -} - /* ===================== R_AddWorldLightsToScene From 1ef8f9bf5aae6ebd09385615ef9c23a0a33bee18 Mon Sep 17 00:00:00 2001 From: slipher Date: Mon, 7 Oct 2024 11:35:47 -0500 Subject: [PATCH 3/9] NUKE static lights (realtime lights from BSP ents) A "static light" was a type of realtime light. It was instantiated by a BSP entity with classname "light", which must have the "noradiosity" keyword set in order to be rendered. Judging by https://users.unvanquished.net/~slipher/map-entity-directory.txt there are no Tremulous or Unvanquished maps using this. 90% of the code for this feature was optimizations specific to the deprecated forward renderer. (Optimizations in the sense that the code is intended to be faster than the dynamic light code path.) If we ever wanted to test real-time lights from map entities later, it could be done by just adding a dynamic light based on the BSP entity. The entity parser would be the only part that's needed. Closes #1051. --- src/engine/renderer/tr_backend.cpp | 35 - src/engine/renderer/tr_bsp.cpp | 2122 ++-------------------------- src/engine/renderer/tr_cmds.cpp | 6 +- src/engine/renderer/tr_init.cpp | 6 - src/engine/renderer/tr_light.cpp | 100 +- src/engine/renderer/tr_local.h | 90 -- src/engine/renderer/tr_main.cpp | 95 +- src/engine/renderer/tr_public.h | 1 - src/engine/renderer/tr_scene.cpp | 48 - src/engine/renderer/tr_shade.cpp | 1 - src/engine/renderer/tr_world.cpp | 161 +-- 11 files changed, 167 insertions(+), 2498 deletions(-) diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index df8cd92652..e75130bcf6 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -1977,23 +1977,6 @@ static void RB_SetupLightForLighting( trRefLight_t *light ) GL_VertexAttribsState( ATTR_POSITION | ATTR_COLOR ); Tess_DrawElements(); - // draw light volume - if ( light->isStatic && light->frustumVBO && light->frustumIBO ) - { - gl_genericShader->SetUniform_ColorModulate( colorGen_t::CGEN_CUSTOM_RGB, alphaGen_t::AGEN_CUSTOM ); - gl_genericShader->SetUniform_Color( Color::Yellow ); - - R_BindVBO( light->frustumVBO ); - R_BindIBO( light->frustumIBO ); - - GL_VertexAttribsState( ATTR_POSITION ); - - tess.numVertexes = light->frustumVerts; - tess.numIndexes = light->frustumIndexes; - - Tess_DrawElements(); - } - tess.multiDrawPrimitives = 0; tess.numIndexes = 0; tess.numVertexes = 0; @@ -3493,25 +3476,7 @@ static void RB_RenderDebugUtils() Tess_Begin( Tess_StageIteratorDebug, nullptr, nullptr, true, -1, 0 ); - if ( light->isStatic && light->frustumVBO && light->frustumIBO ) - { - // go back to the world modelview matrix - backEnd.orientation = backEnd.viewParms.world; - GL_LoadModelViewMatrix( backEnd.viewParms.world.modelViewMatrix ); - gl_genericShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); - gl_genericShader->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); - - R_BindVBO( light->frustumVBO ); - R_BindIBO( light->frustumIBO ); - - GL_VertexAttribsState( ATTR_POSITION ); - - tess.numVertexes = light->frustumVerts; - tess.numIndexes = light->frustumIndexes; - } - else { - // set up the transformation matrix R_RotateLightForViewParms( light, &backEnd.viewParms, &backEnd.orientation ); diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index ea9784a0a7..3f3cb9a0d2 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -35,15 +35,8 @@ RE_LoadWorldMap(const char *name); */ static world_t s_worldData; -static int s_lightCount; -static std::vector s_interactions; static byte *fileBase; -static int c_redundantInteractions; -static int c_vboWorldSurfaces; -static int c_vboLightSurfaces; -static int c_vboShadowSurfaces; - //=============================================================================== /* @@ -4272,19 +4265,11 @@ R_LoadEntities */ void R_LoadEntities( lump_t *l, std::string &externalEntities ) { - int i; - const char *p, *pOld, *token; + const char *p, *token; char *s; char keyname[ MAX_TOKEN_CHARS ]; char value[ MAX_TOKEN_CHARS ]; world_t *w; - bool isLight = false; - int numEntities = 0; - int numLights = 0; - int numOmniLights = 0; - int numProjLights = 0; - int numParallelLights = 0; - trRefLight_t *light; Log::Debug("...loading entities" ); @@ -4449,2012 +4434,211 @@ void R_LoadEntities( lump_t *l, std::string &externalEntities ) continue; } } +} + +/* +================= +R_GetEntityToken +================= +*/ +bool R_GetEntityToken( char *buffer, int size ) +{ + const char *s; - pOld = p; - numEntities = 1; // parsed worldspawn so far + s = COM_Parse2( &s_worldData.entityParsePoint ); + Q_strncpyz( buffer, s, size ); - // count lights - while ( true ) + if ( !s_worldData.entityParsePoint || !s[ 0 ] ) { - // parse { - token = COM_ParseExt2( &p, true ); + s_worldData.entityParsePoint = s_worldData.entityString; + return false; + } + else + { + return true; + } +} - if ( !*token ) - { - // end of entities string - break; - } +static const int HASHTABLE_SIZE = 7919; // 32749 // 2039 /* prime, use % */ +#define HASH_USE_EPSILON - if ( *token != '{' ) - { - Log::Warn("expected { found '%s'", token ); - break; - } +#ifdef HASH_USE_EPSILON +#define HASH_XYZ_EPSILON 256.0f +#define HASH_XYZ_EPSILONSPACE_MULTIPLIER 1.f / HASH_XYZ_EPSILON +#endif - // new entity - isLight = false; +unsigned int VertexCoordGenerateHash( const vec3_t xyz ) +{ + unsigned int hash = 0; - // parse epairs - while ( true ) - { - // parse key - token = COM_ParseExt2( &p, true ); +#ifndef HASH_USE_EPSILON + hash += ~( * ( ( unsigned int * ) &xyz[ 0 ] ) << 15 ); + hash ^= ( * ( ( unsigned int * ) &xyz[ 0 ] ) >> 10 ); + hash += ( * ( ( unsigned int * ) &xyz[ 1 ] ) << 3 ); + hash ^= ( * ( ( unsigned int * ) &xyz[ 1 ] ) >> 6 ); + hash += ~( * ( ( unsigned int * ) &xyz[ 2 ] ) << 11 ); + hash ^= ( * ( ( unsigned int * ) &xyz[ 2 ] ) >> 16 ); +#else + vec3_t xyz_epsilonspace; - if ( *token == '}' ) - { - break; - } + VectorScale( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace ); + xyz_epsilonspace[ 0 ] = floor( xyz_epsilonspace[ 0 ] ); + xyz_epsilonspace[ 1 ] = floor( xyz_epsilonspace[ 1 ] ); + xyz_epsilonspace[ 2 ] = floor( xyz_epsilonspace[ 2 ] ); - if ( !*token ) - { - Log::Warn("EOF without closing bracket" ); - break; - } + hash += ~( * ( ( unsigned int * ) &xyz_epsilonspace[ 0 ] ) << 15 ); + hash ^= ( * ( ( unsigned int * ) &xyz_epsilonspace[ 0 ] ) >> 10 ); + hash += ( * ( ( unsigned int * ) &xyz_epsilonspace[ 1 ] ) << 3 ); + hash ^= ( * ( ( unsigned int * ) &xyz_epsilonspace[ 1 ] ) >> 6 ); + hash += ~( * ( ( unsigned int * ) &xyz_epsilonspace[ 2 ] ) << 11 ); + hash ^= ( * ( ( unsigned int * ) &xyz_epsilonspace[ 2 ] ) >> 16 ); - Q_strncpyz( keyname, token, sizeof( keyname ) ); +#endif - // parse value - token = COM_ParseExt2( &p, false ); + hash = hash % ( HASHTABLE_SIZE ); + return hash; +} - if ( !*token ) - { - Log::Warn("missing value for key '%s'", keyname ); - continue; - } +vertexHash_t **NewVertexHashTable() +{ + vertexHash_t **hashTable = (vertexHash_t**) Z_Calloc( HASHTABLE_SIZE * sizeof( vertexHash_t * ) ); + return hashTable; +} - Q_strncpyz( value, token, sizeof( value ) ); +void FreeVertexHashTable( vertexHash_t **hashTable ) +{ + int i; + vertexHash_t *vertexHash; + vertexHash_t *nextVertexHash; - // check if this entity is a light - if ( !Q_stricmp( keyname, "classname" ) && !Q_stricmp( value, "light" ) ) - { - isLight = true; - } - } + if ( hashTable == nullptr ) + { + return; + } - if ( *token != '}' ) + for ( i = 0; i < HASHTABLE_SIZE; i++ ) + { + if ( hashTable[ i ] ) { - Log::Warn("expected } found '%s'", token ); - break; - } + nextVertexHash = nullptr; - if ( isLight ) - { - numLights++; - } + for ( vertexHash = hashTable[ i ]; vertexHash; vertexHash = nextVertexHash ) + { + nextVertexHash = vertexHash->next; - numEntities++; + Z_Free( vertexHash ); + } + } } - Log::Debug("%i total entities counted", numEntities ); - Log::Debug("%i total lights counted", numLights ); - - s_worldData.numLights = numLights; + Z_Free( hashTable ); +} - // Tr3B: FIXME add 1 dummy light so we don't trash the hunk memory system ... - s_worldData.lights = (trRefLight_t*) ri.Hunk_Alloc( ( s_worldData.numLights + 1 ) * sizeof( trRefLight_t ), ha_pref::h_low ); +vertexHash_t *FindVertexInHashTable( vertexHash_t **hashTable, const vec3_t xyz, float distance ) +{ + unsigned int hash; + vertexHash_t *vertexHash; - // basic light setup - for ( i = 0, light = s_worldData.lights; i < s_worldData.numLights; i++, light++ ) + if ( hashTable == nullptr || xyz == nullptr ) { - QuatClear( light->l.rotation ); - VectorClear( light->l.center ); - - light->l.color[ 0 ] = 1; - light->l.color[ 1 ] = 1; - light->l.color[ 2 ] = 1; - - light->l.scale = r_lightScale->value; - - light->l.radius = 300.0f; - - VectorClear( light->l.projTarget ); - VectorClear( light->l.projRight ); - VectorClear( light->l.projUp ); - VectorClear( light->l.projStart ); - VectorClear( light->l.projEnd ); - - light->l.inverseShadows = false; - - light->isStatic = true; - light->noRadiosity = false; - light->additive = true; - - light->shadowLOD = 0; + return nullptr; } - // parse lights - p = pOld; - numEntities = 1; - light = &s_worldData.lights[ 0 ]; + hash = VertexCoordGenerateHash( xyz ); - while ( true ) + for ( vertexHash = hashTable[ hash ]; vertexHash; vertexHash = vertexHash->next ) { - // parse { - token = COM_ParseExt2( &p, true ); +#ifndef HASH_USE_EPSILON - if ( !*token ) + if ( ( vertexHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexHash->vcd.xyz[ 1 ] != xyz[ 1 ] || + vertexHash->vcd.xyz[ 2 ] != xyz[ 2 ] ) ) { - // end of entities string - break; + continue; } - if ( *token != '{' ) +#elif 1 + + if ( Distance( xyz, vertexHash->xyz ) > distance ) { - Log::Warn("expected { found '%s'", token ); - break; + continue; } - // new entity - isLight = false; +#else - // parse epairs - while ( true ) + if ( ( fabsf( xyz[ 0 ] - vertexHash->vcd.xyz[ 0 ] ) ) > HASH_XYZ_EPSILON || + ( fabsf( xyz[ 1 ] - vertexHash->vcd.xyz[ 1 ] ) ) > HASH_XYZ_EPSILON || + ( fabsf( xyz[ 2 ] - vertexHash->vcd.xyz[ 2 ] ) ) > HASH_XYZ_EPSILON ) { - // parse key - token = COM_ParseExt2( &p, true ); - - if ( *token == '}' ) - { - break; - } + continue; + } - if ( !*token ) - { - Log::Warn("EOF without closing bracket" ); - break; - } +#endif + return vertexHash; + } - Q_strncpyz( keyname, token, sizeof( keyname ) ); + return nullptr; +} - // parse value - token = COM_ParseExt2( &p, false ); +vertexHash_t *AddVertexToHashTable( vertexHash_t **hashTable, vec3_t xyz, void *data ) +{ + unsigned int hash; + vertexHash_t *vertexHash; - if ( !*token ) - { - Log::Warn("missing value for key '%s'", keyname ); - continue; - } + if ( hashTable == nullptr || xyz == nullptr ) + { + return nullptr; + } - Q_strncpyz( value, token, sizeof( value ) ); + vertexHash = (vertexHash_t*) Z_AllocUninit( sizeof( vertexHash_t ) ); - // check if this entity is a light - if ( !Q_stricmp( keyname, "classname" ) && !Q_stricmp( value, "light" ) ) - { - isLight = true; - } - // check for origin - else if ( !Q_stricmp( keyname, "origin" ) || !Q_stricmp( keyname, "light_origin" ) ) - { - sscanf( value, "%f %f %f", &light->l.origin[ 0 ], &light->l.origin[ 1 ], &light->l.origin[ 2 ] ); - s = &value[ 0 ]; - } - // check for center - else if ( !Q_stricmp( keyname, "light_center" ) ) - { - sscanf( value, "%f %f %f", &light->l.center[ 0 ], &light->l.center[ 1 ], &light->l.center[ 2 ] ); - s = &value[ 0 ]; - } - // check for color - else if ( !Q_stricmp( keyname, "_color" ) ) - { - sscanf( value, "%f %f %f", &light->l.color[ 0 ], &light->l.color[ 1 ], &light->l.color[ 2 ] ); - s = &value[ 0 ]; - } - // check for radius - else if ( !Q_stricmp( keyname, "light_radius" ) ) - { - vec_t rad_y, rad_z; - sscanf( value, "%f %f %f", &light->l.radius, &rad_y, &rad_z ); - if( rad_y != light->l.radius || rad_z != light->l.radius ) - Log::Warn( "non-spherical light" ); - s = &value[ 0 ]; - } - // check for light_target - else if ( !Q_stricmp( keyname, "light_target" ) ) - { - sscanf( value, "%f %f %f", &light->l.projTarget[ 0 ], &light->l.projTarget[ 1 ], &light->l.projTarget[ 2 ] ); - s = &value[ 0 ]; - light->l.rlType = refLightType_t::RL_PROJ; - } - // check for light_right - else if ( !Q_stricmp( keyname, "light_right" ) ) - { - sscanf( value, "%f %f %f", &light->l.projRight[ 0 ], &light->l.projRight[ 1 ], &light->l.projRight[ 2 ] ); - s = &value[ 0 ]; - light->l.rlType = refLightType_t::RL_PROJ; - } - // check for light_up - else if ( !Q_stricmp( keyname, "light_up" ) ) - { - sscanf( value, "%f %f %f", &light->l.projUp[ 0 ], &light->l.projUp[ 1 ], &light->l.projUp[ 2 ] ); - s = &value[ 0 ]; - light->l.rlType = refLightType_t::RL_PROJ; - } - // check for light_start - else if ( !Q_stricmp( keyname, "light_start" ) ) - { - sscanf( value, "%f %f %f", &light->l.projStart[ 0 ], &light->l.projStart[ 1 ], &light->l.projStart[ 2 ] ); - s = &value[ 0 ]; - light->l.rlType = refLightType_t::RL_PROJ; - } - // check for light_end - else if ( !Q_stricmp( keyname, "light_end" ) ) - { - sscanf( value, "%f %f %f", &light->l.projEnd[ 0 ], &light->l.projEnd[ 1 ], &light->l.projEnd[ 2 ] ); - s = &value[ 0 ]; - light->l.rlType = refLightType_t::RL_PROJ; - } - // check for radius - else if ( !Q_stricmp( keyname, "light" ) || !Q_stricmp( keyname, "_light" ) ) - { - light->l.radius = atof( value ); - } - // check for scale - else if ( !Q_stricmp( keyname, "light_scale" ) ) - { - light->l.scale = atof( value ); + hash = VertexCoordGenerateHash( xyz ); - if ( light->l.scale >= r_lightScale->value ) - { - light->l.scale = r_lightScale->value; - } - } - // check for light shader - else if ( !Q_stricmp( keyname, "texture" ) ) - { - light->l.attenuationShader = RE_RegisterShader( value, RSF_LIGHT_ATTENUATION ); - } - // check for rotation - else if ( !Q_stricmp( keyname, "rotation" ) || !Q_stricmp( keyname, "light_rotation" ) ) - { - matrix_t rotation; + VectorCopy( xyz, vertexHash->xyz ); + vertexHash->data = data; - sscanf( value, "%f %f %f %f %f %f %f %f %f", &rotation[ 0 ], &rotation[ 1 ], &rotation[ 2 ], - &rotation[ 4 ], &rotation[ 5 ], &rotation[ 6 ], &rotation[ 8 ], &rotation[ 9 ], &rotation[ 10 ] ); + // link into table + vertexHash->next = hashTable[ hash ]; + hashTable[ hash ] = vertexHash; - QuatFromMatrix( light->l.rotation, rotation ); - } - // check if this light does not cast any shadows - else if ( !Q_stricmp( keyname, "noshadows" ) && !Q_stricmp( value, "1" ) ) - { - light->l.noShadows = true; - } - // check if this light does not contribute to the global lightmapping - else if ( !Q_stricmp( keyname, "noradiosity" ) && !Q_stricmp( value, "1" ) ) - { - light->noRadiosity = true; - } - // check if this light is a parallel sun light - else if ( !Q_stricmp( keyname, "parallel" ) && !Q_stricmp( value, "1" ) ) - { - light->l.rlType = refLightType_t::RL_DIRECTIONAL; - } - } + return vertexHash; +} - if ( *token != '}' ) - { - Log::Warn("expected } found '%s'", token ); - break; - } +void GL_BindNearestCubeMap( int unit, const vec3_t xyz ) +{ + float distance, maxDistance; + cubemapProbe_t *cubeProbe; + unsigned int hash; + vertexHash_t *vertexHash; - if ( !isLight ) - { - // reset rotation because it may be set to the rotation of other entities - QuatClear( light->l.rotation ); - } - else - { - if ( ( numOmniLights + numProjLights + numParallelLights ) < s_worldData.numLights ) - { - switch ( light->l.rlType ) - { - case refLightType_t::RL_OMNI: - numOmniLights++; - break; + if ( !r_reflectionMapping->integer ) + { + return; + } - case refLightType_t::RL_PROJ: - numProjLights++; - break; + if ( tr.cubeHashTable == nullptr || xyz == nullptr ) + { + return; + } - case refLightType_t::RL_DIRECTIONAL: - numParallelLights++; - break; + maxDistance = 9999999.0f; - default: - break; - } + hash = VertexCoordGenerateHash( xyz ); + image_t *autoCubeImage = tr.whiteCubeImage; - light++; - } - } + for ( vertexHash = tr.cubeHashTable[ hash ]; vertexHash; vertexHash = vertexHash->next ) + { + cubeProbe = (cubemapProbe_t*) vertexHash->data; - numEntities++; - } + distance = Distance( cubeProbe->origin, xyz ); - if ( ( numOmniLights + numProjLights + numParallelLights ) != s_worldData.numLights ) - { - Sys::Drop( "counted %i lights and parsed %i lights", s_worldData.numLights, ( numOmniLights + numProjLights + numParallelLights ) ); + if ( distance < maxDistance ) + { + autoCubeImage = cubeProbe->cubemap; + maxDistance = distance; + } } - Log::Debug("%i total entities parsed", numEntities ); - Log::Debug("%i total lights parsed", numOmniLights + numProjLights ); - Log::Debug("%i omni-directional lights parsed", numOmniLights ); - Log::Debug("%i projective lights parsed", numProjLights ); - Log::Debug("%i directional lights parsed", numParallelLights ); -} - -/* -================= -R_GetEntityToken -================= -*/ -bool R_GetEntityToken( char *buffer, int size ) -{ - const char *s; - - s = COM_Parse2( &s_worldData.entityParsePoint ); - Q_strncpyz( buffer, s, size ); - - if ( !s_worldData.entityParsePoint || !s[ 0 ] ) - { - s_worldData.entityParsePoint = s_worldData.entityString; - return false; - } - else - { - return true; - } -} - -/* -================= -R_PrecacheInteraction -================= -*/ -static void R_PrecacheInteraction( trRefLight_t *light, bspSurface_t *surface ) -{ - interactionCache_t *iaCache; - - iaCache = (interactionCache_t*) ri.Hunk_Alloc( sizeof( *iaCache ), ha_pref::h_low ); - s_interactions.push_back( iaCache ); - - // connect to interaction grid - if ( !light->firstInteractionCache ) - { - light->firstInteractionCache = iaCache; - } - - if ( light->lastInteractionCache ) - { - light->lastInteractionCache->next = iaCache; - } - - light->lastInteractionCache = iaCache; - - iaCache->next = nullptr; - iaCache->surface = surface; - - iaCache->redundant = false; -} - -/* -================ -R_PrecacheGenericSurfInteraction -================ -*/ -static bool R_PrecacheGenericSurfInteraction( srfGeneric_t *face, trRefLight_t *light ) -{ - return BoundsIntersect( face->bounds[ 0 ], face->bounds[ 1 ], light->worldBounds[ 0 ], light->worldBounds[ 1 ] ); -} - -/* -====================== -R_PrecacheInteractionSurface -====================== -*/ -static void R_PrecacheInteractionSurface( bspSurface_t *surf, trRefLight_t *light ) -{ - bool intersects; - - if ( surf->lightCount == s_lightCount ) - { - return; // already checked this surface - } - - surf->lightCount = s_lightCount; - - // skip all surfaces that don't matter for lighting only pass - if ( surf->shader->isSky || ( !surf->shader->interactLight && surf->shader->noShadows ) ) - { - return; - } - - switch ( *surf->data ) - { - case surfaceType_t::SF_FACE: - case surfaceType_t::SF_GRID: - case surfaceType_t::SF_TRIANGLES: - intersects = R_PrecacheGenericSurfInteraction( ( srfGeneric_t * ) surf->data, light ); - break; - default: - intersects = false; - break; - } - - if ( intersects ) - { - R_PrecacheInteraction( light, surf ); - } -} - -/* -================ -R_RecursivePrecacheInteractionNode -================ -*/ -static void R_RecursivePrecacheInteractionNode( bspNode_t *node, trRefLight_t *light ) -{ - int r; - - do - { - - if ( node->contents != -1 ) - { - break; - } - - // node is just a decision point, so go down both sides - // since we don't care about sort orders, just go positive to negative - r = BoxOnPlaneSide( light->worldBounds[ 0 ], light->worldBounds[ 1 ], node->plane ); - - switch ( r ) - { - case 1: - node = node->children[ 0 ]; - break; - - case 2: - node = node->children[ 1 ]; - break; - - case 3: - default: - // recurse down the children, front side first - R_RecursivePrecacheInteractionNode( node->children[ 0 ], light ); - - // tail recurse - node = node->children[ 1 ]; - break; - } - } - while ( true ); - - { - // leaf node, so add mark surfaces - int c; - bspSurface_t *surf, **mark; - vec3_t worldBounds[ 2 ]; - - // add the individual surfaces - mark = s_worldData.markSurfaces + node->firstMarkSurface; - c = node->numMarkSurfaces; - - while ( c-- ) - { - // the surface may have already been added if it - // spans multiple leafs - surf = *mark; - R_PrecacheInteractionSurface( surf, light ); - mark++; - } - - VectorCopy( node->mins, worldBounds[ 0 ] ); - VectorCopy( node->maxs, worldBounds[ 1 ] ); - - if ( node->numMarkSurfaces > 0 && R_CullLightWorldBounds( light, worldBounds ) != cullResult_t::CULL_OUT ) - { - link_t *l; - - l = ( link_t *)ri.Hunk_Alloc( sizeof( *l ), ha_pref::h_low ); - InitLink( l, node ); - - InsertLink( l, &light->leafs ); - } - } -} - -/* -================= -R_CreateInteractionVBO -================= -*/ -static interactionVBO_t *R_CreateInteractionVBO( trRefLight_t *light ) -{ - interactionVBO_t *iaVBO; - - iaVBO = (interactionVBO_t*) ri.Hunk_Alloc( sizeof( *iaVBO ), ha_pref::h_low ); - - // connect to interaction grid - if ( !light->firstInteractionVBO ) - { - light->firstInteractionVBO = iaVBO; - } - - if ( light->lastInteractionVBO ) - { - light->lastInteractionVBO->next = iaVBO; - } - - light->lastInteractionVBO = iaVBO; - iaVBO->next = nullptr; - - return iaVBO; -} - -/* -================= -InteractionCacheCompare -compare function for qsort() -================= -*/ -static int InteractionCacheCompare( const void *a, const void *b ) -{ - interactionCache_t *aa, *bb; - - aa = * ( interactionCache_t ** ) a; - bb = * ( interactionCache_t ** ) b; - - // shader first - if ( aa->surface->shader < bb->surface->shader ) - { - return -1; - } - - else if ( aa->surface->shader > bb->surface->shader ) - { - return 1; - } - - // then alphaTest - if ( aa->surface->shader->alphaTest < bb->surface->shader->alphaTest ) - { - return -1; - } - - else if ( aa->surface->shader->alphaTest > bb->surface->shader->alphaTest ) - { - return 1; - } - - return 0; -} - -static int UpdateLightTriangles( const srfVert_t *verts, int numTriangles, srfTriangle_t *triangles, shader_t *surfaceShader, - trRefLight_t *light ) -{ - int i; - srfTriangle_t *tri; - int numFacing; - - numFacing = 0; - - for ( i = 0, tri = triangles; i < numTriangles; i++, tri++ ) - { - vec3_t pos[ 3 ]; - float d; - - VectorCopy( verts[ tri->indexes[ 0 ] ].xyz, pos[ 0 ] ); - VectorCopy( verts[ tri->indexes[ 1 ] ].xyz, pos[ 1 ] ); - VectorCopy( verts[ tri->indexes[ 2 ] ].xyz, pos[ 2 ] ); - - plane_t triPlane; - if ( PlaneFromPoints( triPlane, pos[ 0 ], pos[ 1 ], pos[ 2 ] ) ) - { - - if ( light->l.rlType == refLightType_t::RL_DIRECTIONAL ) - { - vec3_t lightDirection; - - // light direction is from surface to light - VectorCopy( tr.sunDirection, lightDirection ); - - d = DotProduct( triPlane.normal, lightDirection ); - - tri->facingLight = surfaceShader->cullType == CT_TWO_SIDED || ( d > 0 && surfaceShader->cullType != CT_BACK_SIDED ); - } - else - { - // check if light origin is behind triangle - d = DotProduct( triPlane.normal, light->origin ) - triPlane.dist; - - tri->facingLight = surfaceShader->cullType == CT_TWO_SIDED || ( d > 0 && surfaceShader->cullType != CT_BACK_SIDED ); - } - } - else - { - tri->facingLight = true; // FIXME ? - } - - if ( R_CullLightTriangle( light, pos ) == cullResult_t::CULL_OUT ) - { - tri->facingLight = false; - } - - if ( tri->facingLight ) - { - numFacing++; - } - } - - return numFacing; -} - -/* -=============== -R_CreateVBOLightMeshes -=============== -*/ -static void R_CreateVBOLightMeshes( trRefLight_t *light ) -{ - int i, j, k, l; - - int numVerts; - - int numTriangles, numLitTriangles; - srfTriangle_t *tri; - glIndex_t *indexes; - - interactionVBO_t *iaVBO; - - interactionCache_t *iaCache, *iaCache2; - interactionCache_t **iaCachesSorted; - int numCaches; - - shader_t *shader, *oldShader; - - bspSurface_t *surface; - - srfVBOMesh_t *vboSurf; - vec3_t bounds[ 2 ]; - - if ( !r_vboLighting->integer ) - { - return; - } - - if ( !light->firstInteractionCache ) - { - // this light has no interactions precached - return; - } - - // count number of interaction caches - numCaches = 0; - - for ( iaCache = light->firstInteractionCache; iaCache; iaCache = iaCache->next ) - { - if ( iaCache->redundant ) - { - continue; - } - - surface = iaCache->surface; - - if ( !surface->shader->interactLight ) - { - continue; - } - - if ( surface->shader->isPortal ) - { - continue; - } - - numCaches++; - } - - // build interaction caches list - iaCachesSorted = (interactionCache_t**) ri.Hunk_AllocateTempMemory( numCaches * sizeof( iaCachesSorted[ 0 ] ) ); - - numCaches = 0; - - for ( iaCache = light->firstInteractionCache; iaCache; iaCache = iaCache->next ) - { - if ( iaCache->redundant ) - { - continue; - } - - surface = iaCache->surface; - - if ( !surface->shader->interactLight ) - { - continue; - } - - if ( surface->shader->isPortal ) - { - continue; - } - - iaCachesSorted[ numCaches ] = iaCache; - numCaches++; - } - - // sort interaction caches by shader - qsort( iaCachesSorted, numCaches, sizeof( *iaCachesSorted ), InteractionCacheCompare ); - - // create a VBO for each shader - shader = oldShader = nullptr; - - for ( k = 0; k < numCaches; k++ ) - { - iaCache = iaCachesSorted[ k ]; - - iaCache->mergedIntoVBO = true; - - shader = iaCache->surface->shader; - - if ( shader != oldShader ) - { - oldShader = shader; - - // count vertices and indices - numVerts = 0; - numTriangles = 0; - - ClearBounds( bounds[ 0 ], bounds[ 1 ] ); - - for ( l = k; l < numCaches; l++ ) - { - iaCache2 = iaCachesSorted[ l ]; - - surface = iaCache2->surface; - - if ( surface->shader != shader ) - { - continue; - } - - if ( *surface->data == surfaceType_t::SF_FACE ) - { - srfSurfaceFace_t *srf = ( srfSurfaceFace_t * ) surface->data; - - if ( srf->numTriangles ) - { - numLitTriangles = UpdateLightTriangles( s_worldData.verts, srf->numTriangles, s_worldData.triangles + srf->firstTriangle, surface->shader, light ); - - if ( numLitTriangles ) - { - BoundsAdd( bounds[ 0 ], bounds[ 1 ], srf->bounds[ 0 ], srf->bounds[ 1 ] ); - } - - numTriangles += numLitTriangles; - } - - if ( srf->numVerts ) - { - numVerts += srf->numVerts; - } - } - else if ( *surface->data == surfaceType_t::SF_GRID ) - { - srfGridMesh_t *srf = ( srfGridMesh_t * ) surface->data; - - if ( srf->numTriangles ) - { - numLitTriangles = UpdateLightTriangles( s_worldData.verts, srf->numTriangles, s_worldData.triangles + srf->firstTriangle, surface->shader, light ); - - if ( numLitTriangles ) - { - BoundsAdd( bounds[ 0 ], bounds[ 1 ], srf->bounds[ 0 ], srf->bounds[ 1 ] ); - } - - numTriangles += numLitTriangles; - } - - if ( srf->numVerts ) - { - numVerts += srf->numVerts; - } - } - else if ( *surface->data == surfaceType_t::SF_TRIANGLES ) - { - srfTriangles_t *srf = ( srfTriangles_t * ) surface->data; - - if ( srf->numTriangles ) - { - numLitTriangles = UpdateLightTriangles( s_worldData.verts, srf->numTriangles, s_worldData.triangles + srf->firstTriangle, surface->shader, light ); - - if ( numLitTriangles ) - { - BoundsAdd( bounds[ 0 ], bounds[ 1 ], srf->bounds[ 0 ], srf->bounds[ 1 ] ); - } - - numTriangles += numLitTriangles; - } - - if ( srf->numVerts ) - { - numVerts += srf->numVerts; - } - } - } - - if ( !numVerts || !numTriangles ) - { - continue; - } - - // create surface - vboSurf = (srfVBOMesh_t*) ri.Hunk_Alloc( sizeof( *vboSurf ), ha_pref::h_low ); - vboSurf->surfaceType = surfaceType_t::SF_VBO_MESH; - vboSurf->numIndexes = numTriangles * 3; - vboSurf->numVerts = numVerts; - vboSurf->lightmapNum = -1; - - VectorCopy( bounds[ 0 ], vboSurf->bounds[ 0 ] ); - VectorCopy( bounds[ 1 ], vboSurf->bounds[ 1 ] ); - - // create arrays - indexes = (glIndex_t*) ri.Hunk_AllocateTempMemory( 3 * numTriangles * sizeof( glIndex_t ) ); - numTriangles = 0; - - // build triangle indices - for ( l = k; l < numCaches; l++ ) - { - iaCache2 = iaCachesSorted[ l ]; - - surface = iaCache2->surface; - - if ( surface->shader != shader ) - { - continue; - } - - if ( *surface->data == surfaceType_t::SF_FACE ) - { - srfSurfaceFace_t *srf = ( srfSurfaceFace_t * ) surface->data; - - for ( i = 0, tri = s_worldData.triangles + srf->firstTriangle; i < srf->numTriangles; i++, tri++ ) - { - if ( tri->facingLight ) - { - for ( j = 0; j < 3; j++ ) - { - indexes[ 3 * numTriangles + j ] = tri->indexes[ j ]; - } - - numTriangles++; - } - } - } - else if ( *surface->data == surfaceType_t::SF_GRID ) - { - srfGridMesh_t *srf = ( srfGridMesh_t * ) surface->data; - - for ( i = 0, tri = s_worldData.triangles + srf->firstTriangle; i < srf->numTriangles; i++, tri++ ) - { - if ( tri->facingLight ) - { - for ( j = 0; j < 3; j++ ) - { - indexes[ 3 * numTriangles + j ] = tri->indexes[ j ]; - } - - numTriangles++; - } - } - } - else if ( *surface->data == surfaceType_t::SF_TRIANGLES ) - { - srfTriangles_t *srf = ( srfTriangles_t * ) surface->data; - - for ( i = 0, tri = s_worldData.triangles + srf->firstTriangle; i < srf->numTriangles; i++, tri++ ) - { - if ( tri->facingLight ) - { - for ( j = 0; j < 3; j++ ) - { - indexes[ 3 * numTriangles + j ] = tri->indexes[ j ]; - } - - numTriangles++; - } - } - } - } - - vboSurf->vbo = s_worldData.vbo; - vboSurf->ibo = R_CreateStaticIBO( va( "staticLightMesh_IBO %i", c_vboLightSurfaces ), indexes, 3 * numTriangles ); - - ri.Hunk_FreeTempMemory( indexes ); - - // add everything needed to the light - iaVBO = R_CreateInteractionVBO( light ); - iaVBO->shader = shader; - iaVBO->vboLightMesh = vboSurf; - - c_vboLightSurfaces++; - } - } - - ri.Hunk_FreeTempMemory( iaCachesSorted ); -} - -/* -=============== -R_CreateVBOShadowMeshes -=============== -*/ -static void R_CreateVBOShadowMeshes( trRefLight_t *light ) -{ - int i, j, k, l; - - int numVerts; - - int numTriangles, numLitTriangles; - glIndex_t *indexes; - srfTriangle_t *tri; - - interactionVBO_t *iaVBO; - - interactionCache_t *iaCache, *iaCache2; - interactionCache_t **iaCachesSorted; - int numCaches; - - shader_t *shader, *oldShader; - bool alphaTest, oldAlphaTest; - - bspSurface_t *surface; - - srfVBOMesh_t *vboSurf; - vec3_t bounds[ 2 ]; - - if ( !r_vboShadows->integer ) - { - return; - } - - if ( !glConfig2.shadowMapping ) - { - return; - } - - if ( !light->firstInteractionCache ) - { - // this light has no interactions precached - return; - } - - if ( light->l.noShadows ) - { - return; - } - - switch ( light->l.rlType ) - { - case refLightType_t::RL_OMNI: - return; - - case refLightType_t::RL_DIRECTIONAL: - case refLightType_t::RL_PROJ: - break; - - default: - return; - } - - // count number of interaction caches - numCaches = 0; - - for ( iaCache = light->firstInteractionCache; iaCache; iaCache = iaCache->next ) - { - if ( iaCache->redundant ) - { - continue; - } - - surface = iaCache->surface; - - if ( !surface->shader->interactLight ) - { - continue; - } - - if ( surface->shader->isSky ) - { - continue; - } - - if ( surface->shader->noShadows ) - { - continue; - } - - if (surface->shader->sort > Util::ordinal(shaderSort_t::SS_OPAQUE)) - { - continue; - } - - if ( surface->shader->isPortal ) - { - continue; - } - - numCaches++; - } - - // build interaction caches list - iaCachesSorted = (interactionCache_t**) ri.Hunk_AllocateTempMemory( numCaches * sizeof( iaCachesSorted[ 0 ] ) ); - - numCaches = 0; - - for ( iaCache = light->firstInteractionCache; iaCache; iaCache = iaCache->next ) - { - if ( iaCache->redundant ) - { - continue; - } - - surface = iaCache->surface; - - if ( !surface->shader->interactLight ) - { - continue; - } - - if ( surface->shader->isSky ) - { - continue; - } - - if ( surface->shader->noShadows ) - { - continue; - } - - if ( surface->shader->sort > Util::ordinal(shaderSort_t::SS_OPAQUE) ) - { - continue; - } - - if ( surface->shader->isPortal ) - { - continue; - } - - iaCachesSorted[ numCaches ] = iaCache; - numCaches++; - } - - // sort interaction caches by shader - qsort( iaCachesSorted, numCaches, sizeof( *iaCachesSorted ), InteractionCacheCompare ); - - // create a VBO for each shader - shader = oldShader = nullptr; - oldAlphaTest = alphaTest = true; - - for ( k = 0; k < numCaches; k++ ) - { - iaCache = iaCachesSorted[ k ]; - - shader = iaCache->surface->shader; - alphaTest = shader->alphaTest; - - iaCache->mergedIntoVBO = true; - - if ( alphaTest ? shader != oldShader : alphaTest != oldAlphaTest ) - { - oldShader = shader; - oldAlphaTest = alphaTest; - - // count vertices and indices - numVerts = 0; - numTriangles = 0; - - ClearBounds( bounds[ 0 ], bounds[ 1 ] ); - - for ( l = k; l < numCaches; l++ ) - { - iaCache2 = iaCachesSorted[ l ]; - - surface = iaCache2->surface; - - if ( alphaTest ) - { - if ( surface->shader != shader ) - { - break; - } - } - else - { - if ( surface->shader->alphaTest != alphaTest ) - { - break; - } - } - - if ( *surface->data == surfaceType_t::SF_FACE ) - { - srfSurfaceFace_t *srf = ( srfSurfaceFace_t * ) surface->data; - - if ( srf->numTriangles ) - { - numLitTriangles = UpdateLightTriangles( s_worldData.verts, srf->numTriangles, s_worldData.triangles + srf->firstTriangle, surface->shader, light ); - - if ( numLitTriangles ) - { - BoundsAdd( bounds[ 0 ], bounds[ 1 ], srf->bounds[ 0 ], srf->bounds[ 1 ] ); - } - - numTriangles += numLitTriangles; - } - - if ( srf->numVerts ) - { - numVerts += srf->numVerts; - } - } - else if ( *surface->data == surfaceType_t::SF_GRID ) - { - srfGridMesh_t *srf = ( srfGridMesh_t * ) surface->data; - - if ( srf->numTriangles ) - { - numLitTriangles = UpdateLightTriangles( s_worldData.verts, srf->numTriangles, s_worldData.triangles + srf->firstTriangle, surface->shader, light ); - - if ( numLitTriangles ) - { - BoundsAdd( bounds[ 0 ], bounds[ 1 ], srf->bounds[ 0 ], srf->bounds[ 1 ] ); - } - - numTriangles += numLitTriangles; - } - - if ( srf->numVerts ) - { - numVerts += srf->numVerts; - } - } - else if ( *surface->data == surfaceType_t::SF_TRIANGLES ) - { - srfTriangles_t *srf = ( srfTriangles_t * ) surface->data; - - if ( srf->numTriangles ) - { - numLitTriangles = UpdateLightTriangles( s_worldData.verts, srf->numTriangles, s_worldData.triangles + srf->firstTriangle, surface->shader, light ); - - if ( numLitTriangles ) - { - BoundsAdd( bounds[ 0 ], bounds[ 1 ], srf->bounds[ 0 ], srf->bounds[ 1 ] ); - } - - numTriangles += numLitTriangles; - } - - if ( srf->numVerts ) - { - numVerts += srf->numVerts; - } - } - } - - if ( !numVerts || !numTriangles ) - { - continue; - } - - // create surface - vboSurf = (srfVBOMesh_t*) ri.Hunk_Alloc( sizeof( *vboSurf ), ha_pref::h_low ); - vboSurf->surfaceType = surfaceType_t::SF_VBO_MESH; - vboSurf->numIndexes = numTriangles * 3; - vboSurf->numVerts = numVerts; - vboSurf->lightmapNum = -1; - - VectorCopy( bounds[ 0 ], vboSurf->bounds[ 0 ] ); - VectorCopy( bounds[ 1 ], vboSurf->bounds[ 1 ] ); - - // create arrays - indexes = (glIndex_t*) ri.Hunk_AllocateTempMemory( 3 * numTriangles * sizeof( glIndex_t ) ); - numTriangles = 0; - - // build triangle indices - for ( l = k; l < numCaches; l++ ) - { - iaCache2 = iaCachesSorted[ l ]; - - surface = iaCache2->surface; - - if ( alphaTest ) - { - if ( surface->shader != shader ) - { - break; - } - } - else - { - if ( surface->shader->alphaTest != alphaTest ) - { - break; - } - } - - if ( *surface->data == surfaceType_t::SF_FACE ) - { - srfSurfaceFace_t *srf = ( srfSurfaceFace_t * ) surface->data; - - for ( i = 0, tri = s_worldData.triangles + srf->firstTriangle; i < srf->numTriangles; i++, tri++ ) - { - if ( tri->facingLight ) - { - for ( j = 0; j < 3; j++ ) - { - indexes[ 3 * numTriangles + j ] = tri->indexes[ j ]; - } - - numTriangles++; - } - } - } - else if ( *surface->data == surfaceType_t::SF_GRID ) - { - srfGridMesh_t *srf = ( srfGridMesh_t * ) surface->data; - - for ( i = 0, tri = s_worldData.triangles + srf->firstTriangle; i < srf->numTriangles; i++, tri++ ) - { - if ( tri->facingLight ) - { - for ( j = 0; j < 3; j++ ) - { - indexes[ 3 * numTriangles + j ] = tri->indexes[ j ]; - } - - numTriangles++; - } - } - } - else if ( *surface->data == surfaceType_t::SF_TRIANGLES ) - { - srfTriangles_t *srf = ( srfTriangles_t * ) surface->data; - - for ( i = 0, tri = s_worldData.triangles + srf->firstTriangle; i < srf->numTriangles; i++, tri++ ) - { - if ( tri->facingLight ) - { - for ( j = 0; j < 3; j++ ) - { - indexes[ 3 * numTriangles + j ] = tri->indexes[ j ]; - } - - numTriangles++; - } - } - } - } - - vboSurf->vbo = s_worldData.vbo; - vboSurf->ibo = R_CreateStaticIBO( va( "staticShadowMesh_IBO %i", c_vboLightSurfaces ), indexes, 3 * numTriangles ); - - ri.Hunk_FreeTempMemory( indexes ); - - // add everything needed to the light - iaVBO = R_CreateInteractionVBO( light ); - iaVBO->shader = shader; - iaVBO->vboShadowMesh = vboSurf; - - c_vboShadowSurfaces++; - } - } - - ri.Hunk_FreeTempMemory( iaCachesSorted ); -} - -/* -=============== -R_CreateVBOShadowCubeMeshes -=============== -*/ -static void R_CreateVBOShadowCubeMeshes( trRefLight_t *light ) -{ - int i, j, k, l; - - int numVerts; - - int numTriangles; - glIndex_t *indexes; - srfTriangle_t *tri; - - interactionVBO_t *iaVBO; - - interactionCache_t *iaCache, *iaCache2; - interactionCache_t **iaCachesSorted; - int numCaches; - - shader_t *shader, *oldShader; - bool alphaTest, oldAlphaTest; - int cubeSide; - - bspSurface_t *surface; - - srfVBOMesh_t *vboSurf; - - if ( !r_vboShadows->integer ) - { - return; - } - - if ( !glConfig2.shadowMapping ) - { - return; - } - - if ( !light->firstInteractionCache ) - { - // this light has no interactions precached - return; - } - - if ( light->l.noShadows ) - { - return; - } - - if ( light->l.rlType != refLightType_t::RL_OMNI ) - { - return; - } - - // count number of interaction caches - numCaches = 0; - - for ( iaCache = light->firstInteractionCache; iaCache; iaCache = iaCache->next ) - { - if ( iaCache->redundant ) - { - continue; - } - - surface = iaCache->surface; - - if ( !surface->shader->interactLight ) - { - continue; - } - - if ( surface->shader->isSky ) - { - continue; - } - - if ( surface->shader->noShadows ) - { - continue; - } - - if ( surface->shader->sort > Util::ordinal(shaderSort_t::SS_OPAQUE)) - { - continue; - } - - if ( surface->shader->isPortal ) - { - continue; - } - - numCaches++; - } - - // build interaction caches list - iaCachesSorted = (interactionCache_t**) ri.Hunk_AllocateTempMemory( numCaches * sizeof( iaCachesSorted[ 0 ] ) ); - - numCaches = 0; - - for ( iaCache = light->firstInteractionCache; iaCache; iaCache = iaCache->next ) - { - if ( iaCache->redundant ) - { - continue; - } - - surface = iaCache->surface; - - if ( !surface->shader->interactLight ) - { - continue; - } - - if ( surface->shader->isSky ) - { - continue; - } - - if ( surface->shader->noShadows ) - { - continue; - } - - if ( surface->shader->sort > Util::ordinal(shaderSort_t::SS_OPAQUE) ) - { - continue; - } - - if ( surface->shader->isPortal ) - { - continue; - } - - iaCachesSorted[ numCaches ] = iaCache; - numCaches++; - } - - // sort interaction caches by shader - qsort( iaCachesSorted, numCaches, sizeof( *iaCachesSorted ), InteractionCacheCompare ); - - // create a VBO for each shader - for ( cubeSide = 0; cubeSide < 6; cubeSide++ ) - { - shader = oldShader = nullptr; - oldAlphaTest = alphaTest = true; - - for ( k = 0; k < numCaches; k++ ) - { - iaCache = iaCachesSorted[ k ]; - shader = iaCache->surface->shader; - alphaTest = shader->alphaTest; - - iaCache->mergedIntoVBO = true; - - if ( alphaTest ? shader != oldShader : alphaTest != oldAlphaTest ) - { - oldShader = shader; - oldAlphaTest = alphaTest; - - // count vertices and indices - numVerts = 0; - numTriangles = 0; - - for ( l = k; l < numCaches; l++ ) - { - iaCache2 = iaCachesSorted[ l ]; - - surface = iaCache2->surface; - - if ( alphaTest ) - { - if ( surface->shader != shader ) - { - break; - } - } - else - { - if ( surface->shader->alphaTest != alphaTest ) - { - break; - } - } - - if ( !( iaCache2->cubeSideBits & ( 1 << cubeSide ) ) ) - { - continue; - } - - if ( *surface->data == surfaceType_t::SF_FACE ) - { - srfSurfaceFace_t *srf = ( srfSurfaceFace_t * ) surface->data; - - if ( srf->numTriangles ) - { - numTriangles += - UpdateLightTriangles( s_worldData.verts, srf->numTriangles, - s_worldData.triangles + srf->firstTriangle, surface->shader, light ); - } - - if ( srf->numVerts ) - { - numVerts += srf->numVerts; - } - } - else if ( *surface->data == surfaceType_t::SF_GRID ) - { - srfGridMesh_t *srf = ( srfGridMesh_t * ) surface->data; - - if ( srf->numTriangles ) - { - numTriangles += - UpdateLightTriangles( s_worldData.verts, srf->numTriangles, - s_worldData.triangles + srf->firstTriangle, surface->shader, light ); - } - - if ( srf->numVerts ) - { - numVerts += srf->numVerts; - } - } - else if ( *surface->data == surfaceType_t::SF_TRIANGLES ) - { - srfTriangles_t *srf = ( srfTriangles_t * ) surface->data; - - if ( srf->numTriangles ) - { - numTriangles += - UpdateLightTriangles( s_worldData.verts, srf->numTriangles, - s_worldData.triangles + srf->firstTriangle, surface->shader, light ); - } - - if ( srf->numVerts ) - { - numVerts += srf->numVerts; - } - } - } - - if ( !numVerts || !numTriangles ) - { - continue; - } - - // create surface - vboSurf = (srfVBOMesh_t*) ri.Hunk_Alloc( sizeof( *vboSurf ), ha_pref::h_low ); - vboSurf->surfaceType = surfaceType_t::SF_VBO_MESH; - vboSurf->numIndexes = numTriangles * 3; - vboSurf->numVerts = numVerts; - vboSurf->lightmapNum = -1; - ZeroBounds( vboSurf->bounds[ 0 ], vboSurf->bounds[ 1 ] ); - - // create arrays - indexes = (glIndex_t*) ri.Hunk_AllocateTempMemory( 3 * numTriangles * sizeof( glIndex_t ) ); - numTriangles = 0; - - // build triangle indices - for ( l = k; l < numCaches; l++ ) - { - iaCache2 = iaCachesSorted[ l ]; - - surface = iaCache2->surface; - - if ( alphaTest ) - { - if ( surface->shader != shader ) - { - break; - } - } - else - { - if ( surface->shader->alphaTest != alphaTest ) - { - break; - } - } - - if ( !( iaCache2->cubeSideBits & ( 1 << cubeSide ) ) ) - { - continue; - } - - if ( *surface->data == surfaceType_t::SF_FACE ) - { - srfSurfaceFace_t *srf = ( srfSurfaceFace_t * ) surface->data; - - for ( i = 0, tri = s_worldData.triangles + srf->firstTriangle; i < srf->numTriangles; i++, tri++ ) - { - if ( tri->facingLight ) - { - for ( j = 0; j < 3; j++ ) - { - indexes[ 3 * numTriangles + j ] = tri->indexes[ j ]; - } - - numTriangles++; - } - } - } - else if ( *surface->data == surfaceType_t::SF_GRID ) - { - srfGridMesh_t *srf = ( srfGridMesh_t * ) surface->data; - - for ( i = 0, tri = s_worldData.triangles + srf->firstTriangle; i < srf->numTriangles; i++, tri++ ) - { - if ( tri->facingLight ) - { - for ( j = 0; j < 3; j++ ) - { - indexes[ 3 * numTriangles + j ] = tri->indexes[ j ]; - } - - numTriangles++; - } - } - } - else if ( *surface->data == surfaceType_t::SF_TRIANGLES ) - { - srfTriangles_t *srf = ( srfTriangles_t * ) surface->data; - - for ( i = 0, tri = s_worldData.triangles + srf->firstTriangle; i < srf->numTriangles; i++, tri++ ) - { - if ( tri->facingLight ) - { - for ( j = 0; j < 3; j++ ) - { - indexes[ 3 * numTriangles + j ] = tri->indexes[ j ]; - } - - numTriangles++; - } - } - } - } - - vboSurf->vbo = s_worldData.vbo; - vboSurf->ibo = R_CreateStaticIBO( va( "staticShadowPyramidMesh_IBO %i", c_vboShadowSurfaces ), indexes, numTriangles ); - - ri.Hunk_FreeTempMemory( indexes ); - - // add everything needed to the light - iaVBO = R_CreateInteractionVBO( light ); - iaVBO->cubeSideBits = ( 1 << cubeSide ); - iaVBO->shader = shader; - iaVBO->vboShadowMesh = vboSurf; - - c_vboShadowSurfaces++; - } - } - } - - ri.Hunk_FreeTempMemory( iaCachesSorted ); -} - -static void R_CalcInteractionCubeSideBits( trRefLight_t *light ) -{ - interactionCache_t *iaCache; - bspSurface_t *surface; - vec3_t localBounds[ 2 ]; - - if ( !glConfig2.shadowMapping ) - { - return; - } - - if ( !light->firstInteractionCache ) - { - // this light has no interactions precached - return; - } - - if ( light->l.noShadows ) - { - // actually noShadows lights are quite bad concerning this optimization - return; - } - - if ( light->l.rlType != refLightType_t::RL_OMNI ) - { - return; - } - - { - for ( iaCache = light->firstInteractionCache; iaCache; iaCache = iaCache->next ) - { - surface = iaCache->surface; - - if ( *surface->data == surfaceType_t::SF_FACE || *surface->data == surfaceType_t::SF_GRID || *surface->data == surfaceType_t::SF_TRIANGLES ) - { - srfGeneric_t *gen; - - gen = ( srfGeneric_t * ) surface->data; - - VectorCopy( gen->bounds[ 0 ], localBounds[ 0 ] ); - VectorCopy( gen->bounds[ 1 ], localBounds[ 1 ] ); - } - else - { - iaCache->cubeSideBits = CUBESIDE_CLIPALL; - continue; - } - - light->shadowLOD = 0; // important for R_CalcLightCubeSideBits - iaCache->cubeSideBits = R_CalcLightCubeSideBits( light, localBounds ); - } - } -} - -/* -============= -R_PrecacheInteractions -============= -*/ -void R_PrecacheInteractions() -{ - int i; - trRefLight_t *light; - bspSurface_t *surface; - int startTime, endTime; - - startTime = ri.Milliseconds(); - - // reset surfaces' viewCount - s_lightCount = 0; - - for ( i = 0, surface = s_worldData.surfaces; i < s_worldData.numSurfaces; i++, surface++ ) - { - surface->lightCount = -1; - } - - c_redundantInteractions = 0; - c_vboWorldSurfaces = 0; - c_vboLightSurfaces = 0; - c_vboShadowSurfaces = 0; - - Log::Debug("...precaching %i lights", s_worldData.numLights ); - - for ( i = 0; i < s_worldData.numLights; i++ ) - { - light = &s_worldData.lights[ i ]; - - if ( tr.worldLightMapping && !light->noRadiosity ) - { - continue; - } - - // set up light transform matrix - MatrixSetupTransformFromQuat( light->transformMatrix, light->l.rotation, light->l.origin ); - - // set up light origin for lighting and shadowing - R_SetupLightOrigin( light ); - - // set up model to light view matrix - R_SetupLightView( light ); - - // set up projection - R_SetupLightProjection( light ); - - // calc local bounds for culling - R_SetupLightLocalBounds( light ); - - // setup world bounds for intersection tests - R_SetupLightWorldBounds( light ); - - // setup frustum planes for intersection tests - R_SetupLightFrustum( light ); - - // setup interactions - light->firstInteractionCache = nullptr; - light->lastInteractionCache = nullptr; - - light->firstInteractionVBO = nullptr; - light->lastInteractionVBO = nullptr; - - // perform culling and add all the potentially visible surfaces - s_lightCount++; - QueueInit( &light->leafs ); - R_RecursivePrecacheInteractionNode( s_worldData.nodes, light ); - - // create a static VBO surface for each light geometry batch - R_CreateVBOLightMeshes( light ); - - // create a static VBO surface for each shadow geometry batch - R_CreateVBOShadowMeshes( light ); - - // calculate pyramid bits for each interaction in omni-directional lights - R_CalcInteractionCubeSideBits( light ); - - // create a static VBO surface for each light geometry batch inside a cubemap pyramid - R_CreateVBOShadowCubeMeshes( light ); - } - - // move interactions grow list to hunk - s_worldData.numInteractions = s_interactions.size(); - s_worldData.interactions = (interactionCache_t**) ri.Hunk_Alloc( s_worldData.numInteractions * sizeof( *s_worldData.interactions ), ha_pref::h_low ); - - for ( i = 0; i < s_worldData.numInteractions; i++ ) - { - s_worldData.interactions[ i ] = s_interactions[ i ]; - } - - s_interactions.clear(); - - Log::Debug("%i interactions precached", s_worldData.numInteractions ); - Log::Debug("%i interactions were hidden in shadows", c_redundantInteractions ); - - if ( glConfig2.shadowMapping ) - { - // only interesting for omni-directional shadow mapping - Log::Debug("%i omni pyramid tests", tr.pc.c_pyramidTests ); - Log::Debug("%i omni pyramid surfaces visible", tr.pc.c_pyramid_cull_ent_in ); - Log::Debug("%i omni pyramid surfaces clipped", tr.pc.c_pyramid_cull_ent_clip ); - Log::Debug("%i omni pyramid surfaces culled", tr.pc.c_pyramid_cull_ent_out ); - } - - endTime = ri.Milliseconds(); - - Log::Debug("lights precaching time = %5.2f seconds", ( endTime - startTime ) / 1000.0 ); -} - -static const int HASHTABLE_SIZE = 7919; // 32749 // 2039 /* prime, use % */ -#define HASH_USE_EPSILON - -#ifdef HASH_USE_EPSILON -#define HASH_XYZ_EPSILON 256.0f -#define HASH_XYZ_EPSILONSPACE_MULTIPLIER 1.f / HASH_XYZ_EPSILON -#endif - -unsigned int VertexCoordGenerateHash( const vec3_t xyz ) -{ - unsigned int hash = 0; - -#ifndef HASH_USE_EPSILON - hash += ~( * ( ( unsigned int * ) &xyz[ 0 ] ) << 15 ); - hash ^= ( * ( ( unsigned int * ) &xyz[ 0 ] ) >> 10 ); - hash += ( * ( ( unsigned int * ) &xyz[ 1 ] ) << 3 ); - hash ^= ( * ( ( unsigned int * ) &xyz[ 1 ] ) >> 6 ); - hash += ~( * ( ( unsigned int * ) &xyz[ 2 ] ) << 11 ); - hash ^= ( * ( ( unsigned int * ) &xyz[ 2 ] ) >> 16 ); -#else - vec3_t xyz_epsilonspace; - - VectorScale( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace ); - xyz_epsilonspace[ 0 ] = floor( xyz_epsilonspace[ 0 ] ); - xyz_epsilonspace[ 1 ] = floor( xyz_epsilonspace[ 1 ] ); - xyz_epsilonspace[ 2 ] = floor( xyz_epsilonspace[ 2 ] ); - - hash += ~( * ( ( unsigned int * ) &xyz_epsilonspace[ 0 ] ) << 15 ); - hash ^= ( * ( ( unsigned int * ) &xyz_epsilonspace[ 0 ] ) >> 10 ); - hash += ( * ( ( unsigned int * ) &xyz_epsilonspace[ 1 ] ) << 3 ); - hash ^= ( * ( ( unsigned int * ) &xyz_epsilonspace[ 1 ] ) >> 6 ); - hash += ~( * ( ( unsigned int * ) &xyz_epsilonspace[ 2 ] ) << 11 ); - hash ^= ( * ( ( unsigned int * ) &xyz_epsilonspace[ 2 ] ) >> 16 ); - -#endif - - hash = hash % ( HASHTABLE_SIZE ); - return hash; -} - -vertexHash_t **NewVertexHashTable() -{ - vertexHash_t **hashTable = (vertexHash_t**) Z_Calloc( HASHTABLE_SIZE * sizeof( vertexHash_t * ) ); - return hashTable; -} - -void FreeVertexHashTable( vertexHash_t **hashTable ) -{ - int i; - vertexHash_t *vertexHash; - vertexHash_t *nextVertexHash; - - if ( hashTable == nullptr ) - { - return; - } - - for ( i = 0; i < HASHTABLE_SIZE; i++ ) - { - if ( hashTable[ i ] ) - { - nextVertexHash = nullptr; - - for ( vertexHash = hashTable[ i ]; vertexHash; vertexHash = nextVertexHash ) - { - nextVertexHash = vertexHash->next; - - Z_Free( vertexHash ); - } - } - } - - Z_Free( hashTable ); -} - -vertexHash_t *FindVertexInHashTable( vertexHash_t **hashTable, const vec3_t xyz, float distance ) -{ - unsigned int hash; - vertexHash_t *vertexHash; - - if ( hashTable == nullptr || xyz == nullptr ) - { - return nullptr; - } - - hash = VertexCoordGenerateHash( xyz ); - - for ( vertexHash = hashTable[ hash ]; vertexHash; vertexHash = vertexHash->next ) - { -#ifndef HASH_USE_EPSILON - - if ( ( vertexHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexHash->vcd.xyz[ 1 ] != xyz[ 1 ] || - vertexHash->vcd.xyz[ 2 ] != xyz[ 2 ] ) ) - { - continue; - } - -#elif 1 - - if ( Distance( xyz, vertexHash->xyz ) > distance ) - { - continue; - } - -#else - - if ( ( fabsf( xyz[ 0 ] - vertexHash->vcd.xyz[ 0 ] ) ) > HASH_XYZ_EPSILON || - ( fabsf( xyz[ 1 ] - vertexHash->vcd.xyz[ 1 ] ) ) > HASH_XYZ_EPSILON || - ( fabsf( xyz[ 2 ] - vertexHash->vcd.xyz[ 2 ] ) ) > HASH_XYZ_EPSILON ) - { - continue; - } - -#endif - return vertexHash; - } - - return nullptr; -} - -vertexHash_t *AddVertexToHashTable( vertexHash_t **hashTable, vec3_t xyz, void *data ) -{ - unsigned int hash; - vertexHash_t *vertexHash; - - if ( hashTable == nullptr || xyz == nullptr ) - { - return nullptr; - } - - vertexHash = (vertexHash_t*) Z_AllocUninit( sizeof( vertexHash_t ) ); - - hash = VertexCoordGenerateHash( xyz ); - - VectorCopy( xyz, vertexHash->xyz ); - vertexHash->data = data; - - // link into table - vertexHash->next = hashTable[ hash ]; - hashTable[ hash ] = vertexHash; - - return vertexHash; -} - -void GL_BindNearestCubeMap( int unit, const vec3_t xyz ) -{ - float distance, maxDistance; - cubemapProbe_t *cubeProbe; - unsigned int hash; - vertexHash_t *vertexHash; - - if ( !r_reflectionMapping->integer ) - { - return; - } - - if ( tr.cubeHashTable == nullptr || xyz == nullptr ) - { - return; - } - - maxDistance = 9999999.0f; - - hash = VertexCoordGenerateHash( xyz ); - image_t *autoCubeImage = tr.whiteCubeImage; - - for ( vertexHash = tr.cubeHashTable[ hash ]; vertexHash; vertexHash = vertexHash->next ) - { - cubeProbe = (cubemapProbe_t*) vertexHash->data; - - distance = Distance( cubeProbe->origin, xyz ); - - if ( distance < maxDistance ) - { - autoCubeImage = cubeProbe->cubemap; - maxDistance = distance; - } - } - - GL_BindToTMU( unit, autoCubeImage ); + GL_BindToTMU( unit, autoCubeImage ); } void R_FindTwoNearestCubeMaps( const vec3_t position, cubemapProbe_t **cubeProbeNearest, cubemapProbe_t **cubeProbeSecondNearest ) @@ -6931,10 +5115,6 @@ void RE_LoadWorldMap( const char *name ) R_CreateWorldVBO(); R_CreateClusters(); - // we precache interactions between lights and surfaces - // to reduce the polygon count - R_PrecacheInteractions(); - if ( tr.hasSkybox ) { FinishSkybox(); } diff --git a/src/engine/renderer/tr_cmds.cpp b/src/engine/renderer/tr_cmds.cpp index 2a83149cfe..c4abd47350 100644 --- a/src/engine/renderer/tr_cmds.cpp +++ b/src/engine/renderer/tr_cmds.cpp @@ -47,10 +47,10 @@ void R_PerformanceCounters() backEnd.pc.c_vertexes, backEnd.pc.c_indexes / 3 ); Log::Notice("%i lights %i bout %i pvsout %i interactions", - tr.pc.c_dlights + tr.pc.c_slights, + tr.pc.c_dlights, tr.pc.c_box_cull_light_out, tr.pc.c_pvs_cull_light_out, - tr.pc.c_dlightInteractions + tr.pc.c_slightInteractions ); + tr.pc.c_dlightInteractions ); Log::Notice("%i draws %i vbos %i ibos %i verts %i tris", backEnd.pc.c_drawElements, @@ -84,8 +84,6 @@ void R_PerformanceCounters() Log::Notice("dlight srf:%i culled:%i", tr.pc.c_dlightSurfaces, tr.pc.c_dlightSurfacesCulled ); Log::Notice("dlights:%i interactions:%i", tr.pc.c_dlights, tr.pc.c_dlightInteractions ); - - Log::Notice("slights:%i interactions:%i", tr.pc.c_slights, tr.pc.c_slightInteractions ); } else if ( r_speeds->integer == Util::ordinal(renderSpeeds_t::RSPEEDS_SHADOWCUBE_CULLING )) { diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index f408d553ef..eacc142ac0 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -81,7 +81,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Util::ordinal(realtimeLightingRenderer_t::TILED) ); Cvar::Cvar r_realtimeLighting( "r_realtimeLighting", "enable realtime light rendering", Cvar::NONE, true ); Cvar::Cvar r_dynamicLight( "r_dynamicLight", "enable dynamic lights (if realtime lighting is enabled)", Cvar::NONE, true ); - Cvar::Cvar r_staticLight( "r_staticLight", "enable BSP entity lights (if realtime lighting is enabled)", Cvar::NONE, true ); cvar_t *r_realtimeLightingCastShadows; cvar_t *r_precomputedLighting; Cvar::Cvar r_mapOverBrightBits("r_mapOverBrightBits", "default map light color shift", Cvar::NONE, 2); @@ -249,8 +248,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA cvar_t *r_vboFaces; cvar_t *r_vboCurves; cvar_t *r_vboTriangles; - cvar_t *r_vboShadows; - cvar_t *r_vboLighting; cvar_t *r_vboModels; cvar_t *r_vboVertexSkinning; @@ -1187,8 +1184,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p r_vboFaces = Cvar_Get( "r_vboFaces", "1", CVAR_CHEAT ); r_vboCurves = Cvar_Get( "r_vboCurves", "1", CVAR_CHEAT ); r_vboTriangles = Cvar_Get( "r_vboTriangles", "1", CVAR_CHEAT ); - r_vboShadows = Cvar_Get( "r_vboShadows", "1", CVAR_CHEAT ); - r_vboLighting = Cvar_Get( "r_vboLighting", "1", CVAR_CHEAT ); r_vboModels = Cvar_Get( "r_vboModels", "1", CVAR_LATCH ); r_vboVertexSkinning = Cvar_Get( "r_vboVertexSkinning", "1", CVAR_LATCH ); @@ -1219,7 +1214,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p Cvar::Latch( r_realtimeLightingRenderer ); Cvar::Latch( r_realtimeLighting ); Cvar::Latch( r_dynamicLight ); - Cvar::Latch( r_staticLight ); Cvar::Latch( r_materialSystem ); r_drawworld = Cvar_Get( "r_drawworld", "1", CVAR_CHEAT ); diff --git a/src/engine/renderer/tr_light.cpp b/src/engine/renderer/tr_light.cpp index ae49791401..c134b3ea5f 100644 --- a/src/engine/renderer/tr_light.cpp +++ b/src/engine/renderer/tr_light.cpp @@ -684,36 +684,6 @@ void R_SetupLightFrustum( trRefLight_t *light ) default: break; } - - if ( light->isStatic ) - { - R_SyncRenderThread(); - - Tess_MapVBOs(true); - Tess_Begin( Tess_StageIteratorDummy, nullptr, nullptr, true, -1, 0 ); - - R_TessLight( light ); - - vboData_t data{}; - data.xyz = ( vec3_t * ) ri.Hunk_AllocateTempMemory( tess.numVertexes * sizeof( *data.xyz ) ); - - for (unsigned i = 0; i < tess.numVertexes; i++ ) - { - // transform to world space - MatrixTransformPoint( light->transformMatrix, tess.verts[ i ].xyz, data.xyz[ i ] ); - } - data.numVerts = tess.numVertexes; - - light->frustumVBO = R_CreateStaticVBO( "staticLightFrustum_VBO", data, vboLayout_t::VBO_LAYOUT_POSITION ); - light->frustumIBO = R_CreateStaticIBO( "staticLightFrustum_IBO", tess.indexes, tess.numIndexes ); - - ri.Hunk_FreeTempMemory( data.xyz ); - - light->frustumVerts = tess.numVertexes; - light->frustumIndexes = tess.numIndexes; - - Tess_Clear(); - } } /* @@ -966,14 +936,7 @@ bool R_AddLightInteraction( trRefLight_t *light, surfaceType_t *surface, shader_ ia->scissorWidth = light->scissor.coords[ 2 ] - light->scissor.coords[ 0 ]; ia->scissorHeight = light->scissor.coords[ 3 ] - light->scissor.coords[ 1 ]; - if ( light->isStatic ) - { - tr.pc.c_slightInteractions++; - } - else - { - tr.pc.c_dlightInteractions++; - } + tr.pc.c_dlightInteractions++; return true; } @@ -1567,33 +1530,16 @@ void R_SetupLightShader( trRefLight_t *light ) { if ( !light->l.attenuationShader ) { - if ( light->isStatic ) + switch ( light->l.rlType ) { - switch ( light->l.rlType ) - { - default: - case refLightType_t::RL_OMNI: - light->shader = tr.defaultPointLightShader; - break; - - case refLightType_t::RL_PROJ: - light->shader = tr.defaultProjectedLightShader; - break; - } - } - else - { - switch ( light->l.rlType ) - { - default: - case refLightType_t::RL_OMNI: - light->shader = tr.defaultDynamicLightShader; - break; + default: + case refLightType_t::RL_OMNI: + light->shader = tr.defaultDynamicLightShader; + break; - case refLightType_t::RL_PROJ: - light->shader = tr.defaultProjectedLightShader; - break; - } + case refLightType_t::RL_PROJ: + light->shader = tr.defaultProjectedLightShader; + break; } } else @@ -1622,34 +1568,6 @@ void R_ComputeFinalAttenuation( shaderStage_t *pStage, trRefLight_t *light ) ================= R_CullLightTriangle -Returns CULL_IN, CULL_CLIP, or CULL_OUT -================= -*/ -cullResult_t R_CullLightTriangle( trRefLight_t *light, vec3_t verts[ 3 ] ) -{ - int i; - vec3_t worldBounds[ 2 ]; - - if ( r_nocull->integer ) - { - return cullResult_t::CULL_CLIP; - } - - // calc AABB of the triangle - ClearBounds( worldBounds[ 0 ], worldBounds[ 1 ] ); - - for ( i = 0; i < 3; i++ ) - { - AddPointToBounds( verts[ i ], worldBounds[ 0 ], worldBounds[ 1 ] ); - } - - return R_CullLightWorldBounds( light, worldBounds ); -} - -/* -================= -R_CullLightTriangle - Returns CULL_IN, CULL_CLIP, or CULL_OUT ================= */ diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index 7c0604d5ed..eb5b200bde 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -370,33 +370,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; CUBESIDE_CLIPALL = 1 | 2 | 4 | 8 | 16 | 32 }; - struct link_t - { - void *data; - link_t *prev, *next; - }; - - inline void InitLink( link_t *l, void *data ) - { - l->data = data; - l->prev = l->next = l; - } - - inline void InsertLink( link_t *l, link_t *sentinel ) - { - l->next = sentinel->next; - l->prev = sentinel; - - l->next->prev = l; - l->prev->next = l; - } - - inline void QueueInit( link_t *l ) - { - l->data = nullptr; - l->prev = l->next = l; - } - // a trRefLight_t has all the information passed in by // the client game, as well as some locally derived info struct trRefLight_t @@ -404,8 +377,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; refLight_t l; // local - bool isStatic; // loaded from the BSP entities lump - bool noRadiosity; // this is a pure realtime light that was not considered by XMap2 bool additive; // texture detail is lost tho when the lightmap is dark vec3_t origin; // l.origin + rotated l.center vec3_t transformed; // origin in local coordinate system @@ -434,25 +405,11 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; frustum_t frustum; plane_t localFrustum[ 6 ]; - struct VBO_t *frustumVBO; - - struct IBO_t *frustumIBO; - - uint16_t frustumIndexes; - uint16_t frustumVerts; screenRect_t scissor; struct shader_t *shader; - struct interactionCache_t *firstInteractionCache; // only used by static lights - - struct interactionCache_t *lastInteractionCache; // only used by static lights - - struct interactionVBO_t *firstInteractionVBO; // only used by static lights - - struct interactionVBO_t *lastInteractionVBO; // only used by static lights - struct interaction_t *firstInteraction; struct interaction_t *lastInteraction; @@ -462,8 +419,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; uint16_t numLightOnlyInteractions; bool noSort; // don't sort interactions by material - link_t leafs; - int visCounts[ MAX_VISCOUNTS ]; // node needs to be traversed if current }; @@ -1685,35 +1640,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; IA_DEFAULTCLIP = IA_LIGHT | IA_SHADOWCLIP }; -// an interactionCache is a node between a light and a precached world surface - struct interactionCache_t - { - interactionType_t type; - - struct bspSurface_t *surface; - - byte cubeSideBits; - bool redundant; - bool mergedIntoVBO; - - interactionCache_t *next; - }; - - struct interactionVBO_t - { - interactionType_t type; - - byte cubeSideBits; - - struct shader_t *shader; - - struct srfVBOMesh_t *vboLightMesh; - - struct srfVBOMesh_t *vboShadowMesh; - - interactionVBO_t *next; - }; - // an interaction is a node between a light and any surface struct interaction_t { @@ -1770,7 +1696,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; struct srfTriangle_t { int indexes[ 3 ]; - bool facingLight; }; // ydnar: plain map drawsurfaces must match this header @@ -2040,12 +1965,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; bspGridPoint2_t *lightGridData2; int numLightGridPoints; - int numLights; - trRefLight_t *lights; - - int numInteractions; - interactionCache_t **interactions; - int numClusters; int clusterBytes; @@ -2410,10 +2329,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; int c_nodes; int c_leafs; - int c_slights; - int c_slightSurfaces; - int c_slightInteractions; - int c_dlights; int c_dlightSurfaces; int c_dlightSurfacesCulled; @@ -2823,7 +2738,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; extern Cvar::Range> r_realtimeLightingRenderer; extern Cvar::Cvar r_realtimeLighting; extern Cvar::Cvar r_dynamicLight; - extern Cvar::Cvar r_staticLight; extern cvar_t *r_realtimeLightingCastShadows; extern cvar_t *r_precomputedLighting; extern Cvar::Cvar r_mapOverBrightBits; @@ -2974,8 +2888,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; extern cvar_t *r_vboFaces; extern cvar_t *r_vboCurves; extern cvar_t *r_vboTriangles; - extern cvar_t *r_vboShadows; - extern cvar_t *r_vboLighting; extern cvar_t *r_vboModels; extern cvar_t *r_vboVertexSkinning; @@ -3463,7 +3375,6 @@ inline bool checkGLErrors() bool R_inPVVS( const vec3_t p1, const vec3_t p2 ); void R_AddWorldInteractions( trRefLight_t *light ); - void R_AddPrecachedWorldInteractions( trRefLight_t *light ); /* ============================================================ @@ -3513,7 +3424,6 @@ inline bool checkGLErrors() byte R_CalcLightCubeSideBits( trRefLight_t *light, vec3_t worldBounds[ 2 ] ); - cullResult_t R_CullLightTriangle( trRefLight_t *light, vec3_t verts[ 3 ] ); cullResult_t R_CullLightWorldBounds( trRefLight_t *light, vec3_t worldBounds[ 2 ] ); void R_ComputeFinalAttenuation( shaderStage_t *pStage, trRefLight_t *light ); diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp index 6eecc77287..43d94dc127 100644 --- a/src/engine/renderer/tr_main.cpp +++ b/src/engine/renderer/tr_main.cpp @@ -2299,8 +2299,6 @@ void R_AddLightInteractions() { int i; trRefLight_t *light; - bspNode_t *leaf; - link_t *l; realtimeLightingRenderer_t realtimeLightingRenderer = realtimeLightingRenderer_t( r_realtimeLightingRenderer.Get() ); @@ -2310,28 +2308,7 @@ void R_AddLightInteractions() { light = tr.currentLight = &tr.refdef.lights[ i ]; - if ( light->isStatic ) - { - if ( !glConfig2.staticLight ) - { - continue; - } - - if ( ( r_precomputedLighting->integer || tr.worldLight != lightMode_t::MAP ) && !light->noRadiosity ) - { - continue; - } - - if ( realtimeLightingRenderer == realtimeLightingRenderer_t::TILED ) - { - tr.refdef.numShaderLights++; - tr.pc.c_slights++; - } - - light->cull = cullResult_t::CULL_OUT; - continue; - } - else if ( light->l.inverseShadows ) + if ( light->l.inverseShadows ) { if ( !glConfig2.dynamicLight ) { @@ -2362,57 +2339,6 @@ void R_AddLightInteractions() R_RotateLightForViewParms( light, &tr.viewParms, &tr.orientation ); // calc local bounds for culling - if ( light->isStatic ) - { - // ignore if not in PVS - if ( !r_noLightVisCull->integer ) - { - for ( l = light->leafs.next; l != &light->leafs; l = l->next ) - { - if ( !l || !l->data ) - { - // something odd happens with the prev/next pointers if ri.Hunk_Alloc was used - break; - } - - leaf = ( bspNode_t * ) l->data; - - if ( leaf->visCounts[ tr.visIndex ] == tr.visCounts[ tr.visIndex ] ) - { - light->visCounts[ tr.visIndex ] = tr.visCounts[ tr.visIndex ]; - } - } - - if ( light->visCounts[ tr.visIndex ] != tr.visCounts[ tr.visIndex ] ) - { - tr.pc.c_pvs_cull_light_out++; - light->cull = cullResult_t::CULL_OUT; - continue; - } - } - - // look if we have to draw the light including its interactions - switch ( R_CullLocalBox( light->localBounds ) ) - { - case cullResult_t::CULL_IN: - default: - tr.pc.c_box_cull_light_in++; - light->cull = cullResult_t::CULL_IN; - break; - - case cullResult_t::CULL_CLIP: - tr.pc.c_box_cull_light_clip++; - light->cull = cullResult_t::CULL_CLIP; - break; - - case cullResult_t::CULL_OUT: - // light is not visible so skip other light setup stuff to save speed - tr.pc.c_box_cull_light_out++; - light->cull = cullResult_t::CULL_OUT; - continue; - } - } - else { // set up light transform matrix MatrixSetupTransformFromQuat( light->transformMatrix, light->l.rotation, light->l.origin ); @@ -2483,29 +2409,14 @@ void R_AddLightInteractions() light->numLightOnlyInteractions = 0; light->noSort = false; - if ( light->isStatic ) - { - R_AddPrecachedWorldInteractions( light ); - } - else - { - R_AddWorldInteractions( light ); - } - + R_AddWorldInteractions( light ); R_AddEntityInteractions( light ); if ( light->numInteractions && light->numInteractions != light->numShadowOnlyInteractions ) { R_SortInteractions( light ); - if ( light->isStatic ) - { - tr.pc.c_slights++; - } - else - { - tr.pc.c_dlights++; - } + tr.pc.c_dlights++; } else { diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index 55a6bbd843..be99b85817 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -134,7 +134,6 @@ struct glconfig2_t bool realtimeLighting; bool dynamicLight; - bool staticLight; bool shadowMapping; shadowingMode_t shadowingMode; bool deluxeMapping; diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index 087f3566d0..187d0018b7 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -276,51 +276,6 @@ void RE_AddRefEntityToScene( const refEntity_t *ent ) r_numEntities++; } -/* -===================== -R_AddWorldLightsToScene -===================== -*/ -static void R_AddWorldLightsToScene() -{ - int i; - trRefLight_t *light; - - if ( !glConfig2.staticLight ) - { - return; - } - - if ( !tr.registered ) - { - return; - } - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) - { - return; - } - - for ( i = 0; i < tr.world->numLights; i++ ) - { - light = tr.currentLight = &tr.world->lights[ i ]; - - if ( r_numLights >= MAX_REF_LIGHTS ) - { - return; - } - - if ( !light->firstInteractionCache ) - { - // this light has no interactions precached - continue; - } - - backEndData[ tr.smpFrame ]->lights[ r_numLights ] = *light; - r_numLights++; - } -} - /* ===================== RE_AddDynamicLightToScene @@ -394,7 +349,6 @@ void RE_AddDynamicLightToSceneET( const vec3_t org, float radius, float intensit light->restrictInteractionLast = -1; } - light->isStatic = false; light->additive = true; if( light->l.inverseShadows ) @@ -612,8 +566,6 @@ void RE_RenderScene( const refdef_t *fd ) } } - R_AddWorldLightsToScene(); - // derived info tr.refdef.floatTime = float(double(tr.refdef.time) * 0.001); diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index ff43b8e2aa..a17d68ef47 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -59,7 +59,6 @@ static void EnableAvailableFeatures() // Enable different kinds of dynamic lights. glConfig2.dynamicLight = glConfig2.realtimeLighting && r_dynamicLight.Get(); - glConfig2.staticLight = glConfig2.realtimeLighting && r_staticLight.Get(); glConfig2.shadowingMode = shadowingMode_t( r_shadows.Get() ); glConfig2.shadowMapping = glConfig2.shadowingMode >= shadowingMode_t::SHADOWING_ESM16; diff --git a/src/engine/renderer/tr_world.cpp b/src/engine/renderer/tr_world.cpp index f9863de2e0..e6918a4af6 100644 --- a/src/engine/renderer/tr_world.cpp +++ b/src/engine/renderer/tr_world.cpp @@ -240,7 +240,7 @@ static void R_AddInteractionSurface( bspSurface_t *surf, trRefLight_t *light, in if ( R_CullLightSurface( surf->data, surf->shader, light, &cubeSideBits ) ) { - if ( !light->isStatic && firstAddition ) + if ( firstAddition ) { tr.pc.c_dlightSurfacesCulled++; } @@ -251,14 +251,7 @@ static void R_AddInteractionSurface( bspSurface_t *surf, trRefLight_t *light, in if ( firstAddition ) { - if ( light->isStatic ) - { - tr.pc.c_slightSurfaces++; - } - else - { - tr.pc.c_dlightSurfaces++; - } + tr.pc.c_dlightSurfaces++; } } @@ -918,153 +911,3 @@ void R_AddWorldInteractions( trRefLight_t *light ) R_RecursiveInteractionNode( tr.world->nodes, light, FRUSTUM_CLIPALL, interactionBits ); } - -/* -============= -R_AddPrecachedWorldInteractions -============= -*/ -void R_AddPrecachedWorldInteractions( trRefLight_t *light ) -{ - interactionType_t iaType = IA_DEFAULT; - - if ( !r_drawworld->integer ) - { - return; - } - - if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) - { - return; - } - - if ( !light->firstInteractionCache ) - { - // this light has no interactions precached - return; - } - - tr.currentEntity = &tr.worldEntity; - - if ( ( r_vboShadows->integer || r_vboLighting->integer ) ) - { - interactionCache_t *iaCache; - interactionVBO_t *iaVBO; - srfVBOMesh_t *srf; - shader_t *shader; - bspSurface_t *surface; - - // this can be shadow mapping or shadowless lighting - for ( iaVBO = light->firstInteractionVBO; iaVBO; iaVBO = iaVBO->next ) - { - if ( !iaVBO->vboLightMesh ) - { - continue; - } - - srf = iaVBO->vboLightMesh; - shader = iaVBO->shader; - - switch ( light->l.rlType ) - { - case refLightType_t::RL_OMNI: - R_AddLightInteraction( light, ( surfaceType_t * ) srf, shader, CUBESIDE_CLIPALL, IA_LIGHT ); - break; - - case refLightType_t::RL_DIRECTIONAL: - case refLightType_t::RL_PROJ: - R_AddLightInteraction( light, ( surfaceType_t * ) srf, shader, CUBESIDE_CLIPALL, IA_LIGHT ); - break; - - default: - R_AddLightInteraction( light, ( surfaceType_t * ) srf, shader, CUBESIDE_CLIPALL, IA_DEFAULT ); - break; - } - } - - // add meshes for shadowmap generation if any - for ( iaVBO = light->firstInteractionVBO; iaVBO; iaVBO = iaVBO->next ) - { - if ( !iaVBO->vboShadowMesh ) - { - continue; - } - - srf = iaVBO->vboShadowMesh; - shader = iaVBO->shader; - - R_AddLightInteraction( light, ( surfaceType_t * ) srf, shader, iaVBO->cubeSideBits, IA_SHADOW ); - } - - // add interactions that couldn't be merged into VBOs - for ( iaCache = light->firstInteractionCache; iaCache; iaCache = iaCache->next ) - { - if ( iaCache->redundant ) - { - continue; - } - - if ( iaCache->mergedIntoVBO ) - { - continue; - } - - surface = iaCache->surface; - - // Tr3B - this surface is maybe not in this view but it may still cast a shadow - // into this view - if ( surface->viewCount != tr.viewCountNoReset ) - { - if ( !glConfig2.shadowMapping || light->l.noShadows ) - { - continue; - } - else - { - iaType = IA_SHADOW; - } - } - else - { - iaType = iaCache->type; - } - - R_AddLightInteraction( light, surface->data, surface->shader, iaCache->cubeSideBits, iaType ); - } - } - else - { - interactionCache_t *iaCache; - bspSurface_t *surface; - - for ( iaCache = light->firstInteractionCache; iaCache; iaCache = iaCache->next ) - { - if ( iaCache->redundant ) - { - continue; - } - - surface = iaCache->surface; - - // Tr3B - this surface is maybe not in this view but it may still cast a shadow - // into this view - if ( surface->viewCount != tr.viewCountNoReset ) - { - if ( !glConfig2.shadowMapping || light->l.noShadows ) - { - continue; - } - else - { - iaType = IA_SHADOW; - } - } - else - { - iaType = iaCache->type; - } - - R_AddLightInteraction( light, surface->data, surface->shader, iaCache->cubeSideBits, iaType ); - } - } -} From 44effb25faaabd75bb04c03977d0472d85861259 Mon Sep 17 00:00:00 2001 From: slipher Date: Fri, 4 Oct 2024 23:53:41 -0500 Subject: [PATCH 4/9] Remove unused GL extension cvar (occlusion_query) We do use GL_ARB_occlusion_query functionality, but the cvar is not actually consulted before doing it. --- src/engine/renderer/tr_init.cpp | 5 ----- src/engine/renderer/tr_public.h | 3 --- src/engine/sys/sdl_glimp.cpp | 12 ------------ 3 files changed, 20 deletions(-) diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index eacc142ac0..dce52037b0 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -930,11 +930,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p Log::Notice( "GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB: %d", glConfig2.maxTexIndirections ); } - if ( glConfig2.occlusionQueryAvailable ) - { - Log::Notice("Occlusion query bits: %d", glConfig2.occlusionQueryBits ); - } - if ( glConfig2.drawBuffersAvailable ) { Log::Notice("GL_MAX_DRAW_BUFFERS: %d", glConfig2.maxDrawBuffers ); diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index be99b85817..b9a2ace358 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -71,9 +71,6 @@ struct glconfig2_t int maxCubeMapTextureSize; - bool occlusionQueryAvailable; - int occlusionQueryBits; - char shadingLanguageVersionString[ MAX_STRING_CHARS ]; int shadingLanguageVersion; diff --git a/src/engine/sys/sdl_glimp.cpp b/src/engine/sys/sdl_glimp.cpp index d9f312789b..2298eba571 100644 --- a/src/engine/sys/sdl_glimp.cpp +++ b/src/engine/sys/sdl_glimp.cpp @@ -110,8 +110,6 @@ static Cvar::Cvar r_ext_draw_buffers( "r_ext_draw_buffers", "Use GL_EXT_draw_buffers if available", Cvar::NONE, true ); static Cvar::Cvar r_ext_gpu_shader4( "r_ext_gpu_shader4", "Use GL_EXT_gpu_shader4 if available", Cvar::NONE, true ); -static Cvar::Cvar r_ext_occlusion_query( "r_ext_occlusion_query", - "Use GL_EXT_occlusion_query if available", Cvar::NONE, true ); static Cvar::Range> r_ext_texture_filter_anisotropic( "r_ext_texture_filter_anisotropic", "Use GL_EXT_texture_filter_anisotropic if available: anisotropy value", Cvar::NONE, 4.0f, 0.0f, 16.0f ); static Cvar::Cvar r_ext_texture_float( "r_ext_texture_float", @@ -1981,7 +1979,6 @@ static void GLimp_InitExtensions() Cvar::Latch( r_arb_uniform_buffer_object ); Cvar::Latch( r_ext_draw_buffers ); Cvar::Latch( r_ext_gpu_shader4 ); - Cvar::Latch( r_ext_occlusion_query ); Cvar::Latch( r_ext_texture_filter_anisotropic ); Cvar::Latch( r_ext_texture_float ); Cvar::Latch( r_ext_texture_integer ); @@ -2242,15 +2239,6 @@ static void GLimp_InitExtensions() glGetIntegerv( GL_MAX_RENDERBUFFER_SIZE, &glConfig2.maxRenderbufferSize ); glGetIntegerv( GL_MAX_COLOR_ATTACHMENTS, &glConfig2.maxColorAttachments ); - // made required in OpenGL 1.5 - glConfig2.occlusionQueryAvailable = false; - glConfig2.occlusionQueryBits = 0; - if ( r_ext_occlusion_query.Get() ) - { - glConfig2.occlusionQueryAvailable = true; - glGetQueryiv( GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &glConfig2.occlusionQueryBits ); - } - // made required in OpenGL 2.0 glConfig2.drawBuffersAvailable = false; if ( r_ext_draw_buffers.Get() ) From 8c72fc9e32b6d7e235dae05f6b8de432f9167ad4 Mon Sep 17 00:00:00 2001 From: slipher Date: Sat, 5 Oct 2024 00:51:20 -0500 Subject: [PATCH 5/9] Remove never-read field trRefLight_t::cull --- src/engine/renderer/tr_local.h | 1 - src/engine/renderer/tr_main.cpp | 8 -------- 2 files changed, 9 deletions(-) diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index eb5b200bde..b407818222 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -393,7 +393,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; matrix_t attenuationMatrix; // attenuation * (light view * entity transform) matrix_t attenuationMatrix2; // attenuation * tcMod matrices - cullResult_t cull; vec3_t localBounds[ 2 ]; vec3_t worldBounds[ 2 ]; float sphereRadius; // calculated from localBounds diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp index 43d94dc127..cb38ae0341 100644 --- a/src/engine/renderer/tr_main.cpp +++ b/src/engine/renderer/tr_main.cpp @@ -2312,7 +2312,6 @@ void R_AddLightInteractions() { if ( !glConfig2.dynamicLight ) { - light->cull = CULL_OUT; continue; } } @@ -2320,7 +2319,6 @@ void R_AddLightInteractions() { if ( !glConfig2.dynamicLight ) { - light->cull = cullResult_t::CULL_OUT; continue; } else if ( realtimeLightingRenderer == realtimeLightingRenderer_t::TILED ) @@ -2328,7 +2326,6 @@ void R_AddLightInteractions() tr.refdef.numShaderLights++; tr.pc.c_dlights++; - light->cull = cullResult_t::CULL_OUT; continue; } } @@ -2361,18 +2358,15 @@ void R_AddLightInteractions() case cullResult_t::CULL_IN: default: tr.pc.c_box_cull_light_in++; - light->cull = cullResult_t::CULL_IN; break; case cullResult_t::CULL_CLIP: tr.pc.c_box_cull_light_clip++; - light->cull = cullResult_t::CULL_CLIP; break; case cullResult_t::CULL_OUT: // light is not visible so skip other light setup stuff to save speed tr.pc.c_box_cull_light_out++; - light->cull = cullResult_t::CULL_OUT; continue; } @@ -2386,7 +2380,6 @@ void R_AddLightInteractions() if ( !BoundsIntersect ( light->worldBounds[ 0 ], light->worldBounds[ 1 ], tr.viewParms.visBounds[ 0 ], tr.viewParms.visBounds[ 1 ] ) ) { - light->cull = cullResult_t::CULL_OUT; continue; } } @@ -2423,7 +2416,6 @@ void R_AddLightInteractions() // skip all interactions of this light because it caused only shadow volumes // but no lighting tr.refdef.numInteractions -= light->numInteractions; - light->cull = cullResult_t::CULL_OUT; } } } From d23e076cd3012ce373ba939397d71325bb28dd13 Mon Sep 17 00:00:00 2001 From: slipher Date: Sat, 5 Oct 2024 03:52:42 -0500 Subject: [PATCH 6/9] Run some tiled lighting code only in tiled mode --- src/engine/renderer/tr_backend.cpp | 5 ----- src/engine/renderer/tr_cmds.cpp | 6 ++++++ src/engine/renderer/tr_shade.cpp | 18 ++++++++++-------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index e75130bcf6..361a685842 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -5330,11 +5330,6 @@ RB_SetupLights */ const RenderCommand *SetupLightsCommand::ExecuteSelf( ) const { - if ( !glConfig2.realtimeLighting ) - { - return this + 1; - } - int numLights; GLenum bufferTarget = glConfig2.uniformBufferObjectAvailable ? GL_UNIFORM_BUFFER : GL_PIXEL_UNPACK_BUFFER; diff --git a/src/engine/renderer/tr_cmds.cpp b/src/engine/renderer/tr_cmds.cpp index c4abd47350..86fee74dfd 100644 --- a/src/engine/renderer/tr_cmds.cpp +++ b/src/engine/renderer/tr_cmds.cpp @@ -250,6 +250,12 @@ R_AddSetupLightsCmd */ void R_AddSetupLightsCmd() { + if ( !glConfig2.realtimeLighting || + r_realtimeLightingRenderer.Get() != Util::ordinal( realtimeLightingRenderer_t::TILED ) ) + { + return; + } + SetupLightsCommand *cmd; cmd = R_GetRenderCommand(); diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index a17d68ef47..88b5af62cf 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -1062,12 +1062,13 @@ void Render_lightMapping( shaderStage_t *pStage ) gl_lightMappingShader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); - gl_lightMappingShader->SetUniform_numLights( backEnd.refdef.numLights ); - - if( glConfig2.realtimeLighting ) + if ( glConfig2.realtimeLighting && + r_realtimeLightingRenderer.Get() == Util::ordinal( realtimeLightingRenderer_t::TILED ) ) { if ( backEnd.refdef.numShaderLights > 0 ) - { + { + gl_lightMappingShader->SetUniform_numLights( backEnd.refdef.numLights ); + if( glConfig2.uniformBufferObjectAvailable ) { gl_lightMappingShader->SetUniformBlock_Lights( tr.dlightUBO ); @@ -1077,15 +1078,16 @@ void Render_lightMapping( shaderStage_t *pStage ) GL_BindToTMU( BIND_LIGHTS, tr.dlightImage ) ); } - } - // bind u_LightTiles - if ( r_realtimeLightingRenderer.Get() == Util::ordinal( realtimeLightingRenderer_t::TILED ) ) - { + // bind u_LightTiles gl_lightMappingShader->SetUniform_LightTilesIntBindless( GL_BindToTMU( BIND_LIGHTTILES, tr.lighttileRenderImage ) ); } + else + { + gl_lightMappingShader->SetUniform_numLights( 0 ); + } } // u_DeformGen From 0139b9f426b3e3360e60e239b70ac9cfaa7f91b0 Mon Sep 17 00:00:00 2001 From: slipher Date: Fri, 4 Oct 2024 11:50:34 -0500 Subject: [PATCH 7/9] Remove redundant dynamic light enabled tests If a dynamic light is disabled, just don't add it to the scene. No need to check again later if it is disabled --- src/engine/renderer/tr_main.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp index cb38ae0341..97f23bb14b 100644 --- a/src/engine/renderer/tr_main.cpp +++ b/src/engine/renderer/tr_main.cpp @@ -2308,20 +2308,9 @@ void R_AddLightInteractions() { light = tr.currentLight = &tr.refdef.lights[ i ]; - if ( light->l.inverseShadows ) + if ( !light->l.inverseShadows ) { - if ( !glConfig2.dynamicLight ) - { - continue; - } - } - else - { - if ( !glConfig2.dynamicLight ) - { - continue; - } - else if ( realtimeLightingRenderer == realtimeLightingRenderer_t::TILED ) + if ( realtimeLightingRenderer == realtimeLightingRenderer_t::TILED ) { tr.refdef.numShaderLights++; tr.pc.c_dlights++; From fb741378661f5e0f3036fcad82efcc51519870eb Mon Sep 17 00:00:00 2001 From: slipher Date: Mon, 7 Oct 2024 12:21:45 -0500 Subject: [PATCH 8/9] Rename r_dynamicLight -> r_drawDynamicLights, unlatch Giving the cvar for whether to add dynamic lights at runtime a different name from r_realtimeLighting's old name will help it to avoid getting mistakenly set by old autogen.cfg values. The name name follows the convention that r_drawXXX cvars that can be used to disable something that is usually rendered. (showXXX cvars on the other hand are cheat cvars for drawing a representation of something that is usually unseen.) Remove Cvar::Latch so it can be toggled instantly. --- src/engine/renderer/tr_init.cpp | 2 -- src/engine/renderer/tr_local.h | 1 - src/engine/renderer/tr_public.h | 1 - src/engine/renderer/tr_scene.cpp | 5 ++++- src/engine/renderer/tr_shade.cpp | 3 --- 5 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index dce52037b0..6dbb0ed8b0 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -80,7 +80,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Util::ordinal(realtimeLightingRenderer_t::LEGACY), Util::ordinal(realtimeLightingRenderer_t::TILED) ); Cvar::Cvar r_realtimeLighting( "r_realtimeLighting", "enable realtime light rendering", Cvar::NONE, true ); - Cvar::Cvar r_dynamicLight( "r_dynamicLight", "enable dynamic lights (if realtime lighting is enabled)", Cvar::NONE, true ); cvar_t *r_realtimeLightingCastShadows; cvar_t *r_precomputedLighting; Cvar::Cvar r_mapOverBrightBits("r_mapOverBrightBits", "default map light color shift", Cvar::NONE, 2); @@ -1208,7 +1207,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p Cvar::Latch( r_realtimeLightingRenderer ); Cvar::Latch( r_realtimeLighting ); - Cvar::Latch( r_dynamicLight ); Cvar::Latch( r_materialSystem ); r_drawworld = Cvar_Get( "r_drawworld", "1", CVAR_CHEAT ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index b407818222..efb0ac4753 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2736,7 +2736,6 @@ enum class realtimeLightingRenderer_t { LEGACY, TILED }; extern Cvar::Cvar r_fastsky; // Controls whether sky should be cleared or drawn. extern Cvar::Range> r_realtimeLightingRenderer; extern Cvar::Cvar r_realtimeLighting; - extern Cvar::Cvar r_dynamicLight; extern cvar_t *r_realtimeLightingCastShadows; extern cvar_t *r_precomputedLighting; extern Cvar::Cvar r_mapOverBrightBits; diff --git a/src/engine/renderer/tr_public.h b/src/engine/renderer/tr_public.h index b9a2ace358..23e842858c 100644 --- a/src/engine/renderer/tr_public.h +++ b/src/engine/renderer/tr_public.h @@ -130,7 +130,6 @@ struct glconfig2_t bool depthClampAvailable; bool realtimeLighting; - bool dynamicLight; bool shadowMapping; shadowingMode_t shadowingMode; bool deluxeMapping; diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index 187d0018b7..a5157d54e8 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -24,6 +24,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "tr_local.h" #include "Material.h" +static Cvar::Cvar r_drawDynamicLights( + "r_drawDynamicLights", "render dynamic lights (if realtime lighting is enabled)", Cvar::NONE, true ); + static int r_firstSceneDrawSurf; static int r_firstSceneInteraction; @@ -287,7 +290,7 @@ void RE_AddDynamicLightToSceneET( const vec3_t org, float radius, float intensit { trRefLight_t *light; - if ( !glConfig2.dynamicLight ) + if ( !glConfig2.realtimeLighting || !r_drawDynamicLights.Get() ) { return; } diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 88b5af62cf..0901574057 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -57,9 +57,6 @@ static void EnableAvailableFeatures() } } - // Enable different kinds of dynamic lights. - glConfig2.dynamicLight = glConfig2.realtimeLighting && r_dynamicLight.Get(); - glConfig2.shadowingMode = shadowingMode_t( r_shadows.Get() ); glConfig2.shadowMapping = glConfig2.shadowingMode >= shadowingMode_t::SHADOWING_ESM16; From 7ec38eb55cd5cf76efb79e5a1d2fb3f0af817032 Mon Sep 17 00:00:00 2001 From: slipher Date: Sat, 5 Oct 2024 04:18:41 -0500 Subject: [PATCH 9/9] Fix forward lighting binding null image --- src/engine/renderer/tr_shade.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 0901574057..6022485a6f 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -1520,11 +1520,6 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, gl_forwardLightingShader_omniXYZ->SetUniform_NormalScale( normalScale ); } - // bind u_MaterialMap - gl_forwardLightingShader_omniXYZ->SetUniform_MaterialMapBindless( - GL_BindToTMU( 2, pStage->bundle[TB_MATERIALMAP].image[0] ) - ); - // FIXME: physical mapping is not implemented. if ( pStage->enableSpecularMapping ) { @@ -1532,6 +1527,11 @@ static void Render_forwardLighting_DBS_omni( shaderStage_t *pStage, float maxSpec = RB_EvalExpression( &pStage->specularExponentMax, r_specularExponentMax->value ); gl_forwardLightingShader_omniXYZ->SetUniform_SpecularExponent( minSpec, maxSpec ); + + // bind u_MaterialMap + gl_forwardLightingShader_omniXYZ->SetUniform_MaterialMapBindless( + GL_BindToTMU( 2, pStage->bundle[TB_MATERIALMAP].image[0] ) + ); } // bind u_AttenuationMapXY