From cac4864df160106449860dd5d74dd92e832fb3c5 Mon Sep 17 00:00:00 2001 From: slipher Date: Mon, 9 Jun 2025 02:05:58 -0500 Subject: [PATCH 1/4] Fix r_showEntityTransforms drawing garbage for sprites For RT_SPRITE entities the bounds are not valid and it would draw something using garbage data from a previous entity. Skip anything that is not RT_MODEL. --- src/engine/renderer/tr_backend.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 087c629b31..670d611d2f 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -1595,6 +1595,11 @@ static void RB_RenderDebugUtils() for ( i = 0; i < backEnd.refdef.numEntities; i++, ent++ ) { + if ( ent->e.reType != refEntityType_t::RT_MODEL ) + { + continue; + } + if ( ( ent->e.renderfx & RF_THIRD_PERSON ) && backEnd.viewParms.portalLevel == 0 ) { From 99fcd19f8c936b23bde72ff3d4038b4873cadba2 Mon Sep 17 00:00:00 2001 From: slipher Date: Mon, 9 Jun 2025 00:58:35 -0500 Subject: [PATCH 2/4] Fix wrong culling with r_showEntityTransforms Sometimes I look directly at a door and its bbox is not shown. Looks like ent->cull is only used for IQM/MD5/MD3 models. --- src/engine/renderer/tr_backend.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 670d611d2f..565a5d4e51 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -1606,11 +1606,6 @@ static void RB_RenderDebugUtils() continue; } - if ( ent->cull == cullResult_t::CULL_OUT ) - { - continue; - } - // set up the transformation matrix R_RotateEntityForViewParms( ent, &backEnd.viewParms, &backEnd.orientation ); GL_LoadModelViewMatrix( backEnd.orientation.modelViewMatrix ); From a9e677c2847eeb4f70a0969a08097e7844c8e202 Mon Sep 17 00:00:00 2001 From: slipher Date: Mon, 9 Jun 2025 01:13:56 -0500 Subject: [PATCH 3/4] Remove field trRefEntity_t::cull It was pointless since it was only read immediately after being written. --- src/engine/renderer/tr_animation.cpp | 15 +++++---------- src/engine/renderer/tr_local.h | 1 - src/engine/renderer/tr_mesh.cpp | 27 +++++++++------------------ src/engine/renderer/tr_model_iqm.cpp | 18 +++++------------- src/engine/renderer/tr_world.cpp | 4 +--- 5 files changed, 20 insertions(+), 45 deletions(-) diff --git a/src/engine/renderer/tr_animation.cpp b/src/engine/renderer/tr_animation.cpp index bd28539090..617a233c3a 100644 --- a/src/engine/renderer/tr_animation.cpp +++ b/src/engine/renderer/tr_animation.cpp @@ -610,7 +610,7 @@ static ListAnimationsCmd listAnimationsCmdRegistration; R_CullMD5 ============= */ -static void R_CullMD5( trRefEntity_t *ent ) +static cullResult_t R_CullMD5( trRefEntity_t *ent ) { int i; @@ -638,19 +638,16 @@ static void R_CullMD5( trRefEntity_t *ent ) { case cullResult_t::CULL_IN: tr.pc.c_box_cull_md5_in++; - ent->cull = cullResult_t::CULL_IN; - return; + return cullResult_t::CULL_IN; case cullResult_t::CULL_CLIP: tr.pc.c_box_cull_md5_clip++; - ent->cull = cullResult_t::CULL_CLIP; - return; + return cullResult_t::CULL_CLIP; case cullResult_t::CULL_OUT: default: tr.pc.c_box_cull_md5_out++; - ent->cull = cullResult_t::CULL_OUT; - return; + return cullResult_t::CULL_OUT; } } @@ -674,9 +671,7 @@ void R_AddMD5Surfaces( trRefEntity_t *ent ) // cull the entire model if merged bounding box of both frames // is outside the view frustum - R_CullMD5( ent ); - - if ( ent->cull == cullResult_t::CULL_OUT ) + if ( R_CullMD5( ent ) == cullResult_t::CULL_OUT ) { return; } diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index a1405e9fd3..ac4885f75c 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -424,7 +424,6 @@ enum class ssaoMode { // local float axisLength; // compensate for non-normalized axis - cullResult_t cull; vec3_t localBounds[ 2 ]; vec3_t worldBounds[ 2 ]; }; diff --git a/src/engine/renderer/tr_mesh.cpp b/src/engine/renderer/tr_mesh.cpp index ecb0105eb3..be367a213b 100644 --- a/src/engine/renderer/tr_mesh.cpp +++ b/src/engine/renderer/tr_mesh.cpp @@ -29,7 +29,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA R_CullMDV ============= */ -static void R_CullMDV( mdvModel_t *model, trRefEntity_t *ent ) +static cullResult_t R_CullMDV( mdvModel_t *model, trRefEntity_t *ent ) { mdvFrame_t *oldFrame, *newFrame; int i; @@ -59,13 +59,11 @@ static void R_CullMDV( mdvModel_t *model, trRefEntity_t *ent ) { case cullResult_t::CULL_OUT: tr.pc.c_sphere_cull_mdv_out++; - ent->cull = cullResult_t::CULL_OUT; - return; + return cullResult_t::CULL_OUT; case cullResult_t::CULL_IN: tr.pc.c_sphere_cull_mdv_in++; - ent->cull = cullResult_t::CULL_IN; - return; + return cullResult_t::CULL_IN; case cullResult_t::CULL_CLIP: tr.pc.c_sphere_cull_mdv_clip++; @@ -91,14 +89,12 @@ static void R_CullMDV( mdvModel_t *model, trRefEntity_t *ent ) if ( sphereCull == cullResult_t::CULL_OUT ) { tr.pc.c_sphere_cull_mdv_out++; - ent->cull = cullResult_t::CULL_OUT; - return; + return cullResult_t::CULL_OUT; } else if ( sphereCull == cullResult_t::CULL_IN ) { tr.pc.c_sphere_cull_mdv_in++; - ent->cull = cullResult_t::CULL_IN; - return; + return cullResult_t::CULL_IN; } else { @@ -112,19 +108,16 @@ static void R_CullMDV( mdvModel_t *model, trRefEntity_t *ent ) { case cullResult_t::CULL_IN: tr.pc.c_box_cull_mdv_in++; - ent->cull = cullResult_t::CULL_IN; - return; + return cullResult_t::CULL_IN; case cullResult_t::CULL_CLIP: tr.pc.c_box_cull_mdv_clip++; - ent->cull = cullResult_t::CULL_CLIP; - return; + return cullResult_t::CULL_CLIP; case cullResult_t::CULL_OUT: default: tr.pc.c_box_cull_mdv_out++; - ent->cull = cullResult_t::CULL_OUT; - return; + return cullResult_t::CULL_OUT; } } @@ -296,9 +289,7 @@ void R_AddMDVSurfaces( trRefEntity_t *ent ) // cull the entire model if merged bounding box of both frames // is outside the view frustum. - R_CullMDV( model, ent ); - - if ( ent->cull == CULL_OUT ) + if ( R_CullMDV( model, ent ) == CULL_OUT ) { return; } diff --git a/src/engine/renderer/tr_model_iqm.cpp b/src/engine/renderer/tr_model_iqm.cpp index a23d0d56e9..d6a9413be9 100644 --- a/src/engine/renderer/tr_model_iqm.cpp +++ b/src/engine/renderer/tr_model_iqm.cpp @@ -930,7 +930,7 @@ bool R_LoadIQModel( model_t *mod, const void *buffer, int filesize, R_CullIQM ============= */ -static void R_CullIQM( trRefEntity_t *ent ) { +static cullResult_t R_CullIQM( trRefEntity_t *ent ) { vec3_t localBounds[ 2 ]; float scale = ent->e.skeleton.scale; IQModel_t *model = tr.currentModel->iqm; @@ -962,17 +962,14 @@ static void R_CullIQM( trRefEntity_t *ent ) { { case cullResult_t::CULL_IN: tr.pc.c_box_cull_md5_in++; - ent->cull = cullResult_t::CULL_IN; - return; + return cullResult_t::CULL_IN; case cullResult_t::CULL_CLIP: tr.pc.c_box_cull_md5_clip++; - ent->cull = cullResult_t::CULL_CLIP; - return; + return cullResult_t::CULL_CLIP; case cullResult_t::CULL_OUT: default: tr.pc.c_box_cull_md5_out++; - ent->cull = cullResult_t::CULL_OUT; - return; + return cullResult_t::CULL_OUT; } } @@ -999,14 +996,9 @@ void R_AddIQMSurfaces( trRefEntity_t *ent ) { personalModel = (ent->e.renderfx & RF_THIRD_PERSON) && tr.viewParms.portalLevel == 0; - // cull the entire model if merged bounding box of both frames - // is outside the view frustum. - R_CullIQM( ent ); - // HACK: Never cull first-person models, due to issues with a certain model's bounds // A first-person model not in the player's sight seems like something that should not happen in any case - // But R_CullIQM is always called because it sets some fields used by other code - if ( ent->cull == cullResult_t::CULL_OUT && !( ent->e.renderfx & RF_FIRST_PERSON ) ) + if ( !( ent->e.renderfx & RF_FIRST_PERSON ) && R_CullIQM( ent ) == cullResult_t::CULL_OUT ) { return; } diff --git a/src/engine/renderer/tr_world.cpp b/src/engine/renderer/tr_world.cpp index 2f846d4103..a8bac11e42 100644 --- a/src/engine/renderer/tr_world.cpp +++ b/src/engine/renderer/tr_world.cpp @@ -185,9 +185,7 @@ void R_AddBSPModelSurfaces( trRefEntity_t *ent ) VectorAdd( ent->worldBounds[ 0 ], ent->worldBounds[ 1 ], boundsCenter ); VectorScale( boundsCenter, 0.5f, boundsCenter ); - ent->cull = R_CullBox( ent->worldBounds ); - - if ( ent->cull == CULL_OUT ) + if ( R_CullBox( ent->worldBounds ) == CULL_OUT ) { return; } From 89d1fa44c153c8d16c663246e2ab78ca52335a6d Mon Sep 17 00:00:00 2001 From: slipher Date: Wed, 4 Jun 2025 19:55:26 -0500 Subject: [PATCH 4/4] Add translucent solid option for showing cull bbox Rename r_showEntityTransforms to r_showEntityBounds and add a new option (2) for showing the culling bounding boxes as a solid translucent surface, in addition to the old wireframe option. This makes it easier to see when the model is poking out of the box. --- src/engine/renderer/tr_backend.cpp | 31 ++++++++++++++++++++++++------ src/engine/renderer/tr_init.cpp | 2 -- src/engine/renderer/tr_local.h | 1 - 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 565a5d4e51..b0dbce22c9 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -34,6 +34,8 @@ backEndState_t backEnd; static Cvar::Cvar r_clear( "r_clear", "Clear screen before painting over it on every frame", Cvar::NONE, false ); Cvar::Cvar r_drawSky( "r_drawSky", "Draw the sky (clear the sky if disabled)", Cvar::NONE, true ); +static Cvar::Cvar r_showEntityBounds( + "r_showEntityBounds", "show bboxes used for culling (1: wireframe; 2: translucent solid)", Cvar::CHEAT, 0); void GL_Bind( image_t *image ) { @@ -1563,7 +1565,7 @@ static void RB_RenderDebugUtils() { GLIMP_LOGCOMMENT( "--- RB_RenderDebugUtils ---" ); - if ( r_showEntityTransforms->integer ) + if ( r_showEntityBounds.Get() ) { trRefEntity_t *ent; int i; @@ -1577,13 +1579,23 @@ static void RB_RenderDebugUtils() gl_genericShader->SetDepthFade( false ); gl_genericShader->BindProgram( 0 ); - GL_State( GLS_POLYMODE_LINE | GLS_DEPTHTEST_DISABLE ); + if ( r_showEntityBounds.Get() == 2 ) + { + GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); + glEnable( GL_POLYGON_OFFSET_FILL ); + GL_PolygonOffset( r_offsetFactor->value, r_offsetUnits->value ); + } + else + { + GL_State( GLS_POLYMODE_LINE | GLS_DEPTHTEST_DISABLE ); + } + GL_Cull( cullType_t::CT_TWO_SIDED ); // set uniforms gl_genericShader->SetUniform_AlphaTest( GLS_ATEST_NONE ); SetUniform_ColorModulateColorGen( gl_genericShader, colorGen_t::CGEN_VERTEX, alphaGen_t::AGEN_VERTEX ); - SetUniform_Color( gl_genericShader, Color::Black ); + SetUniform_Color( gl_genericShader, Color::Color(0, 0, 0, 0) ); // bind u_ColorMap gl_genericShader->SetUniform_ColorMapBindless( @@ -1613,9 +1625,15 @@ static void RB_RenderDebugUtils() Tess_Begin( Tess_StageIteratorDebug, nullptr, nullptr, true, -1, 0 ); - Tess_AddCube( vec3_origin, ent->localBounds[ 0 ], ent->localBounds[ 1 ], Color::Blue ); - - Tess_AddCube( vec3_origin, mins, maxs,Color::White ); + if ( r_showEntityBounds.Get() == 2) + { + Tess_AddCube( vec3_origin, ent->localBounds[ 0 ], ent->localBounds[ 1 ], Color::Color(0, 0, 0.5, 0.4) ); + } + else + { + Tess_AddCube( vec3_origin, ent->localBounds[ 0 ], ent->localBounds[ 1 ], Color::Blue ); + Tess_AddCube( vec3_origin, mins, maxs,Color::White ); + } Tess_End(); } @@ -1623,6 +1641,7 @@ static void RB_RenderDebugUtils() // go back to the world modelview matrix backEnd.orientation = backEnd.viewParms.world; GL_LoadModelViewMatrix( backEnd.viewParms.world.modelViewMatrix ); + glDisable( GL_POLYGON_OFFSET_FILL ); } if ( r_showSkeleton->integer ) diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index 65c645624b..76c31833b6 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -227,7 +227,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA cvar_t *r_showTris; cvar_t *r_showSky; cvar_t *r_showSkeleton; - cvar_t *r_showEntityTransforms; cvar_t *r_showLightGrid; cvar_t *r_showLightTiles; cvar_t *r_showBatches; @@ -1276,7 +1275,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p r_showTris = Cvar_Get( "r_showTris", "0", CVAR_CHEAT ); r_showSky = Cvar_Get( "r_showSky", "0", CVAR_CHEAT ); r_showSkeleton = Cvar_Get( "r_showSkeleton", "0", CVAR_CHEAT ); - r_showEntityTransforms = Cvar_Get( "r_showEntityTransforms", "0", CVAR_CHEAT ); r_showLightGrid = Cvar_Get( "r_showLightGrid", "0", CVAR_CHEAT ); r_showLightTiles = Cvar_Get("r_showLightTiles", "0", CVAR_CHEAT | CVAR_LATCH ); r_showBatches = Cvar_Get( "r_showBatches", "0", CVAR_CHEAT ); diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index ac4885f75c..2c29878b92 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -2833,7 +2833,6 @@ enum class ssaoMode { extern cvar_t *r_showTris; // enables wireframe rendering of the world extern cvar_t *r_showSky; // forces sky in front of all surfaces extern cvar_t *r_showSkeleton; - extern cvar_t *r_showEntityTransforms; extern cvar_t *r_showLightGrid; extern cvar_t *r_showLightTiles; extern cvar_t *r_showBatches;