From 99375f8b5341f7584c97a77053004b0f1454c656 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 14 Sep 2024 08:20:47 -0700 Subject: [PATCH 1/7] stencil outline test Signed-off-by: Michael Pollind --- source/cgame/cg_pmodels.cpp | 13 +++++ source/cgame/ref.h | 1 + source/qcommon/common.c | 1 + source/ref_gl/r_backend.c | 33 ++++++++++-- source/ref_gl/r_backend.h | 4 ++ source/ref_gl/r_backend_local.h | 6 ++- source/ref_gl/r_backend_program.c | 88 +++++++++++++++++++++++++++++++ source/ref_gl/r_image.c | 6 +-- source/ref_gl/r_mesh.c | 16 +++--- source/ref_gl/r_program.h | 1 + 10 files changed, 156 insertions(+), 13 deletions(-) diff --git a/source/cgame/cg_pmodels.cpp b/source/cgame/cg_pmodels.cpp index d18a2ac81f..29a1060d0a 100644 --- a/source/cgame/cg_pmodels.cpp +++ b/source/cgame/cg_pmodels.cpp @@ -1306,9 +1306,22 @@ void CG_AddPModel( centity_t *cent ) CG_AddEntityToScene( ¢->ent ); } + if( !cent->ent.model ) return; + + { + entity_t shellOutline = cent->ent; + shellOutline.renderfx |= RF_OUTLINE_WRITE_THROUGH; + shellOutline.outlineColor[0] = 255; + shellOutline.outlineColor[1] = 0; + shellOutline.outlineColor[2] = 0; + shellOutline.outlineColor[3] = 255; + + CG_AddEntityToScene( &shellOutline ); + } + CG_PModel_AddFlag( cent ); CG_AddShellEffects( ¢->ent, cent->effects ); diff --git a/source/cgame/ref.h b/source/cgame/ref.h index b22a4e7dbf..defb589756 100644 --- a/source/cgame/ref.h +++ b/source/cgame/ref.h @@ -41,6 +41,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define RF_GREYSCALE 0x400 #define RF_NODEPTHTEST 0x800 #define RF_NOCOLORWRITE 0x1000 +#define RF_OUTLINE_WRITE_THROUGH 0x2000 // refdef flags #define RDF_UNDERWATER 0x1 // warp the screen as apropriate diff --git a/source/qcommon/common.c b/source/qcommon/common.c index f4a3549ff6..4e67ecffab 100644 --- a/source/qcommon/common.c +++ b/source/qcommon/common.c @@ -230,6 +230,7 @@ void Com_Printf( const char *format, ... ) Q_vsnprintfz( msg, sizeof( msg ), format, argptr ); va_end( argptr ); + printf("%s", msg); QMutex_Lock( com_print_mutex ); diff --git a/source/ref_gl/r_backend.c b/source/ref_gl/r_backend.c index 6b7eadf70b..ed8ab656c0 100644 --- a/source/ref_gl/r_backend.c +++ b/source/ref_gl/r_backend.c @@ -145,6 +145,34 @@ void RB_StatsMessage( char *msg, size_t size ) ); } +void RB_SetStencilFunc( int func, int ref, int mask ) { + if( rb.gl.stencilFunc == func && rb.gl.stencilRef == ref && rb.gl.stencilFuncMask == mask ) + return; + + qglStencilFunc( func, ref, mask ); + rb.gl.stencilFunc = func; + rb.gl.stencilRef = ref; + rb.gl.stencilFuncMask = mask; +} + +void RB_SetStencilOp( int sfail, int dpfail, int dppass ) { + if( rb.gl.stencilSFail == sfail && rb.gl.stencilDPFail == dpfail && rb.gl.stencilDPPass == dppass ) + return; + + qglStencilOp( sfail, dpfail, dppass ); + rb.gl.stencilSFail = sfail; + rb.gl.stencilDPFail = dpfail; + rb.gl.stencilDPPass = dppass; +} + +void RB_SetStencilMask( int mask ) { + if( rb.gl.stencilMask == mask ) + return; + qglStencilMask( mask ); + rb.gl.stencilMask = mask; +} + + /* * RB_SetGLDefaults */ @@ -335,9 +363,8 @@ void RB_Cull( int cull ) */ void RB_SetState( int state ) { - int diff; - diff = rb.gl.state ^ state; + int diff = rb.gl.state ^ state; if( !diff ) return; @@ -466,7 +493,7 @@ void RB_SetState( int state ) if( diff & GLSTATE_STENCIL_TEST ) { - if( glConfig.stencilBits ) + // if( glConfig.stencilBits ) { if( state & GLSTATE_STENCIL_TEST ) qglEnable( GL_STENCIL_TEST ); diff --git a/source/ref_gl/r_backend.h b/source/ref_gl/r_backend.h index f254ef9225..43662e4b36 100644 --- a/source/ref_gl/r_backend.h +++ b/source/ref_gl/r_backend.h @@ -48,6 +48,10 @@ void RB_LoadCameraMatrix( const mat4_t m ); void RB_LoadObjectMatrix( const mat4_t m ); void RB_LoadProjectionMatrix( const mat4_t m ); +void RB_SetStencilFunc( int func, int ref, int mask ); +void RB_SetStencilOp( int sfail, int dpfail, int dppass ); +void RB_SetStencilMask( int mask ); + void RB_DepthRange( float depthmin, float depthmax ); void RB_GetDepthRange( float* depthmin, float *depthmax ); void RB_DepthOffset( bool enable ); diff --git a/source/ref_gl/r_backend_local.h b/source/ref_gl/r_backend_local.h index fb50da2fa1..f12b02c8a4 100644 --- a/source/ref_gl/r_backend_local.h +++ b/source/ref_gl/r_backend_local.h @@ -100,7 +100,11 @@ typedef struct r_backend_s bool flushTextures; int currentTMU; - unsigned currentTextures[MAX_TEXTURE_UNITS]; + unsigned currentTextures[MAX_TEXTURE_UNITS]; + + int stencilFunc, stencilRef, stencilFuncMask; + int stencilSFail, stencilDPFail, stencilDPPass; + int stencilMask; } gl; unsigned int time; diff --git a/source/ref_gl/r_backend_program.c b/source/ref_gl/r_backend_program.c index 36df4e86b3..f2a5d2805f 100644 --- a/source/ref_gl/r_backend_program.c +++ b/source/ref_gl/r_backend_program.c @@ -34,6 +34,7 @@ enum BUILTIN_GLSLPASS_SHADOWMAP, BUILTIN_GLSLPASS_OUTLINE, BUILTIN_GLSLPASS_SKYBOX, + BUILTIN_GLSLPASS_OVERLAY_OUTLINE, MAX_BUILTIN_GLSLPASSES }; @@ -101,6 +102,15 @@ static void RB_InitBuiltinPasses( void ) pass->tcgen = TC_GEN_NONE; pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE; + // overlay outline + pass = &r_GLSLpasses[BUILTIN_GLSLPASS_OVERLAY_OUTLINE]; + pass->flags = 0; + pass->rgbgen.type = RGB_GEN_OUTLINE; + pass->alphagen.type = ALPHA_GEN_OUTLINE; + pass->tcgen = TC_GEN_NONE; + pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE_OVERLAY; + + // skybox pass = &r_GLSLpasses[BUILTIN_GLSLPASS_SKYBOX]; pass->program_type = GLSL_PROGRAM_TYPE_Q3A_SHADER; @@ -1363,6 +1373,76 @@ static void RB_RenderMeshGLSL_Shadowmap( const shaderpass_t *pass, r_glslfeat_t RB_Scissor( old_scissor[0], old_scissor[1], old_scissor[2], old_scissor[3] ); } + +/* +* RB_RenderMeshGLSL_Outline +*/ +static void RB_RenderMeshGLSL_OverlayOutline( const shaderpass_t *pass, r_glslfeat_t programFeatures ) +{ +// int faceCull = rb.gl.faceCull; + mat4_t texMatrix; + + if( rb.currentModelType == mod_brush ) { + programFeatures |= GLSL_SHADER_OUTLINE_OUTLINES_CUTOFF; + } + + programFeatures |= RB_RGBAlphaGenToProgramFeatures( &pass->rgbgen, &pass->alphagen ); + + programFeatures |= RB_FogProgramFeatures( pass, rb.fog ); + + // update uniforcms + int program = RB_RegisterProgram( GLSL_PROGRAM_TYPE_OUTLINE, NULL, + rb.currentShader->deformsKey, + rb.currentShader->deforms, + rb.currentShader->numdeforms, + programFeatures ); + if( !RB_BindProgram( program ) ) + return; + + Matrix4_Identity( texMatrix ); + + //RB_Cull( GL_BACK ); + + RB_UpdateCommonUniforms( program, pass, texMatrix ); + + if( programFeatures & GLSL_SHADER_COMMON_FOG ) { + RB_UpdateFogUniforms( program, rb.fog ); + } + + // submit animation data + if( programFeatures & GLSL_SHADER_COMMON_BONE_TRANSFORMS ) { + RP_UpdateBonesUniforms( program, rb.bonesData.numBones, rb.bonesData.dualQuats ); + } + + // set shaderpass state (blending, depthwrite, etc) + RB_SetStencilMask( 0xFF ); + RB_SetStencilOp( GL_REPLACE, GL_KEEP, GL_REPLACE); + RB_SetStencilFunc( GL_ALWAYS, 1, 0xFF ); + + RB_SetShaderpassState( pass->flags | GLSTATE_STENCIL_TEST | GLSTATE_DEPTHFUNC_GT | GLSTATE_NO_COLORWRITE ); + RP_UpdateOutlineUniforms( program, 2.0f ); + RB_DrawElementsReal( &rb.drawElements ); + + RB_SetStencilFunc( GL_ALWAYS, 0x0, 0xFF ); + RB_SetStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE ); + + RB_SetShaderpassState( pass->flags | GLSTATE_STENCIL_TEST | GLSTATE_NO_DEPTH_TEST | GLSTATE_NO_COLORWRITE ); + RP_UpdateOutlineUniforms( program, 0 ); + RB_DrawElementsReal( &rb.drawElements ); + + RB_SetStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); + RB_SetStencilFunc( GL_EQUAL, 1, 0xFF ); + RB_SetStencilMask( 0x00 ); + + RB_SetShaderpassState( pass->flags | GLSTATE_NO_DEPTH_TEST | GLSTATE_STENCIL_TEST ); + RP_UpdateOutlineUniforms( program, 2.0f ); + RB_DrawElementsReal( &rb.drawElements ); + + RB_SetShaderpassState( pass->flags ); + + //RB_Cull( faceCull ); +} + /* * RB_RenderMeshGLSL_Outline */ @@ -1893,6 +1973,9 @@ void RB_RenderMeshGLSLProgrammed( const shaderpass_t *pass, int programType ) case GLSL_PROGRAM_TYPE_SHADOWMAP: RB_RenderMeshGLSL_Shadowmap( pass, features ); break; + case GLSL_PROGRAM_TYPE_OUTLINE_OVERLAY: + RB_RenderMeshGLSL_OverlayOutline(pass, features ); + break; case GLSL_PROGRAM_TYPE_OUTLINE: RB_RenderMeshGLSL_Outline( pass, features ); break; @@ -2375,6 +2458,11 @@ void RB_DrawShadedElements( void ) RB_SetShaderState(); + if(rb.currentEntity->renderfx & RF_OUTLINE_WRITE_THROUGH) { + RB_RenderPass( &r_GLSLpasses[BUILTIN_GLSLPASS_OVERLAY_OUTLINE] ); + return; + } + for( i = 0, pass = rb.currentShader->passes; i < rb.currentShader->numpasses; i++, pass++ ) { if( ( pass->flags & SHADERPASS_DETAIL ) && !r_detailtextures->integer ) diff --git a/source/ref_gl/r_image.c b/source/ref_gl/r_image.c index d8a7c1ab65..e18cc0a29c 100644 --- a/source/ref_gl/r_image.c +++ b/source/ref_gl/r_image.c @@ -2301,7 +2301,7 @@ void R_InitViewportTexture( image_t **texture, const char *name, int id, } if( t->flags & IT_FRAMEBUFFER ) { t->fbo = RFB_RegisterObject( t->upload_width, t->upload_height, ( tags & IMAGE_TAG_BUILTIN ) != 0, - ( flags & IT_DEPTHRB ) != 0, ( flags & IT_STENCIL ) != 0 ); + ( flags & IT_DEPTHRB ) != 0, true ); RFB_AttachTextureToObject( t->fbo, t ); } } @@ -2426,8 +2426,8 @@ static void R_InitScreenImagePair( const char *name, image_t **color, image_t ** assert( !depth || glConfig.ext.depth_texture ); - if( !glConfig.stencilBits ) - stencil = false; + //if( !glConfig.stencilBits ) + // stencil = false; flags = IT_SPECIAL; diff --git a/source/ref_gl/r_mesh.c b/source/ref_gl/r_mesh.c index 8fd6327c20..24229551fd 100644 --- a/source/ref_gl/r_mesh.c +++ b/source/ref_gl/r_mesh.c @@ -155,7 +155,7 @@ unsigned R_PackOpaqueOrder( const entity_t *e, const shader_t *shader, bool ligh void *R_AddSurfToDrawList( drawList_t *list, const entity_t *e, const mfog_t *fog, const shader_t *shader, float dist, unsigned int order, const portalSurface_t *portalSurf, void *drawSurf ) { - sortedDrawSurf_t *sds; + int shaderSort; bool depthWrite; int renderFx; @@ -183,8 +183,13 @@ void *R_AddSurfToDrawList( drawList_t *list, const entity_t *e, const mfog_t *fo } R_ReserveDrawSurfaces( list, minMeshes ); } - - if( renderFx & RF_WEAPONMODEL ) { + if(renderFx & RF_OUTLINE_WRITE_THROUGH) { + shaderSort = SHADER_SORT_DECAL; + dist = -1; + if(portalSurf) { + return false; + } + } else if( renderFx & RF_WEAPONMODEL ) { if( renderFx & RF_NOCOLORWRITE ) { // depth-pass for alpha-blended weapon: // write to depth but do not write to color @@ -213,7 +218,7 @@ void *R_AddSurfToDrawList( drawList_t *list, const entity_t *e, const mfog_t *fo dist = 0; } - sds = &list->drawSurfs[list->numDrawSurfs++]; + sortedDrawSurf_t *sds = &list->drawSurfs[list->numDrawSurfs++]; sds->distKey = R_PackDistKey( shaderSort, (int)dist, order ); sds->sortKey = R_PackSortKey( shader->id, fog ? fog - rsh.worldBrushModel->fogs : -1, portalSurf ? portalSurf - rn.portalSurfaces : -1, R_ENT2NUM(e) ); @@ -407,7 +412,6 @@ static const batchDrawSurf_cb r_batchDrawSurfCb[ST_MAX_TYPES] = static void _R_DrawSurfaces( drawList_t *list ) { unsigned int i; - unsigned int sortKey; unsigned int shaderNum = 0, prevShaderNum = MAX_SHADERS; unsigned int entNum = 0, prevEntNum = MAX_REF_ENTITIES; int portalNum = -1, prevPortalNum = -100500; @@ -438,7 +442,7 @@ static void _R_DrawSurfaces( drawList_t *list ) for( i = 0; i < list->numDrawSurfs; i++ ) { sds = list->drawSurfs + i; - sortKey = sds->sortKey; + const unsigned int sortKey = sds->sortKey; drawSurfType = *(int *)sds->drawSurf; assert( drawSurfType > ST_NONE && drawSurfType < ST_MAX_TYPES ); diff --git a/source/ref_gl/r_program.h b/source/ref_gl/r_program.h index 7dc45610ca..c082d0a626 100644 --- a/source/ref_gl/r_program.h +++ b/source/ref_gl/r_program.h @@ -54,6 +54,7 @@ enum GLSL_PROGRAM_TYPE_FXAA, GLSL_PROGRAM_TYPE_YUV, GLSL_PROGRAM_TYPE_COLORCORRECTION, + GLSL_PROGRAM_TYPE_OUTLINE_OVERLAY, GLSL_PROGRAM_TYPE_MAXTYPE }; From bb715f954e24ac50754eab7fdaec0ba0e33c76ac Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Sat, 14 Sep 2024 21:41:22 -0700 Subject: [PATCH 2/7] feat: cleanup changes Signed-off-by: Michael Pollind --- source/cgame/cg_pmodels.cpp | 7 ++++--- source/ref_gl/r_backend.c | 6 +++--- source/ref_gl/r_backend_program.c | 22 +++++++--------------- source/ref_gl/r_cull.c | 2 +- source/ref_gl/r_image.c | 2 +- source/ref_gl/r_mesh.c | 16 ++++++++-------- source/ref_gl/r_register.c | 3 +-- source/ref_gl/r_skm.c | 6 +++++- 8 files changed, 30 insertions(+), 34 deletions(-) diff --git a/source/cgame/cg_pmodels.cpp b/source/cgame/cg_pmodels.cpp index 29a1060d0a..783fee55e1 100644 --- a/source/cgame/cg_pmodels.cpp +++ b/source/cgame/cg_pmodels.cpp @@ -1310,6 +1310,9 @@ void CG_AddPModel( centity_t *cent ) if( !cent->ent.model ) return; + CG_PModel_AddFlag( cent ); + + CG_AddShellEffects( ¢->ent, cent->effects ); { entity_t shellOutline = cent->ent; @@ -1318,13 +1321,11 @@ void CG_AddPModel( centity_t *cent ) shellOutline.outlineColor[1] = 0; shellOutline.outlineColor[2] = 0; shellOutline.outlineColor[3] = 255; + shellOutline.outlineHeight = 1.5f; CG_AddEntityToScene( &shellOutline ); } - CG_PModel_AddFlag( cent ); - - CG_AddShellEffects( ¢->ent, cent->effects ); CG_AddHeadIcon( cent ); diff --git a/source/ref_gl/r_backend.c b/source/ref_gl/r_backend.c index ed8ab656c0..620f1e8b32 100644 --- a/source/ref_gl/r_backend.c +++ b/source/ref_gl/r_backend.c @@ -180,9 +180,9 @@ static void RB_SetGLDefaults( void ) { if( glConfig.stencilBits ) { - qglStencilMask( ( GLuint ) ~0 ); - qglStencilFunc( GL_EQUAL, 128, 0xFF ); - qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); + RB_SetStencilOp(GL_KEEP, GL_KEEP, GL_INCR); + RB_SetStencilMask(( GLuint ) ~0); + RB_SetStencilFunc(GL_EQUAL, 128, 0xFF ) ; } qglDisable( GL_CULL_FACE ); diff --git a/source/ref_gl/r_backend_program.c b/source/ref_gl/r_backend_program.c index f2a5d2805f..d56371d71e 100644 --- a/source/ref_gl/r_backend_program.c +++ b/source/ref_gl/r_backend_program.c @@ -1379,9 +1379,6 @@ static void RB_RenderMeshGLSL_Shadowmap( const shaderpass_t *pass, r_glslfeat_t */ static void RB_RenderMeshGLSL_OverlayOutline( const shaderpass_t *pass, r_glslfeat_t programFeatures ) { -// int faceCull = rb.gl.faceCull; - mat4_t texMatrix; - if( rb.currentModelType == mod_brush ) { programFeatures |= GLSL_SHADER_OUTLINE_OUTLINES_CUTOFF; } @@ -1399,10 +1396,8 @@ static void RB_RenderMeshGLSL_OverlayOutline( const shaderpass_t *pass, r_glslfe if( !RB_BindProgram( program ) ) return; + mat4_t texMatrix; Matrix4_Identity( texMatrix ); - - //RB_Cull( GL_BACK ); - RB_UpdateCommonUniforms( program, pass, texMatrix ); if( programFeatures & GLSL_SHADER_COMMON_FOG ) { @@ -1413,14 +1408,14 @@ static void RB_RenderMeshGLSL_OverlayOutline( const shaderpass_t *pass, r_glslfe if( programFeatures & GLSL_SHADER_COMMON_BONE_TRANSFORMS ) { RP_UpdateBonesUniforms( program, rb.bonesData.numBones, rb.bonesData.dualQuats ); } - + // set shaderpass state (blending, depthwrite, etc) RB_SetStencilMask( 0xFF ); RB_SetStencilOp( GL_REPLACE, GL_KEEP, GL_REPLACE); RB_SetStencilFunc( GL_ALWAYS, 1, 0xFF ); RB_SetShaderpassState( pass->flags | GLSTATE_STENCIL_TEST | GLSTATE_DEPTHFUNC_GT | GLSTATE_NO_COLORWRITE ); - RP_UpdateOutlineUniforms( program, 2.0f ); + RP_UpdateOutlineUniforms( program, rb.currentEntity->outlineHeight * r_outlines_scale->value ); RB_DrawElementsReal( &rb.drawElements ); RB_SetStencilFunc( GL_ALWAYS, 0x0, 0xFF ); @@ -1435,12 +1430,9 @@ static void RB_RenderMeshGLSL_OverlayOutline( const shaderpass_t *pass, r_glslfe RB_SetStencilMask( 0x00 ); RB_SetShaderpassState( pass->flags | GLSTATE_NO_DEPTH_TEST | GLSTATE_STENCIL_TEST ); - RP_UpdateOutlineUniforms( program, 2.0f ); + RP_UpdateOutlineUniforms( program, rb.currentEntity->outlineHeight * r_outlines_scale->value ); RB_DrawElementsReal( &rb.drawElements ); - - RB_SetShaderpassState( pass->flags ); - - //RB_Cull( faceCull ); + } /* @@ -1472,7 +1464,7 @@ static void RB_RenderMeshGLSL_Outline( const shaderpass_t *pass, r_glslfeat_t pr RB_Cull( GL_BACK ); // set shaderpass state (blending, depthwrite, etc) - RB_SetShaderpassState( pass->flags ); + RB_SetShaderpassState( pass->flags); RB_UpdateCommonUniforms( program, pass, texMatrix ); @@ -2072,7 +2064,7 @@ void RB_BindShader( const entity_t *e, const shader_t *shader, const mfog_t *fog rb.alphaHack = e->renderfx & RF_ALPHAHACK ? true : false; rb.hackedAlpha = e->shaderRGBA[3] / 255.0; rb.greyscale = e->renderfx & RF_GREYSCALE ? true : false; - rb.noDepthTest = e->renderfx & RF_NODEPTHTEST && e->rtype == RT_SPRITE ? true : false; + rb.noDepthTest = e->renderfx & (RF_NODEPTHTEST | RF_OUTLINE_WRITE_THROUGH) && e->rtype == RT_SPRITE ? true : false; rb.noColorWrite = e->renderfx & RF_NOCOLORWRITE ? true : false; rb.depthEqual = rb.alphaHack && (e->renderfx & RF_WEAPONMODEL); } diff --git a/source/ref_gl/r_cull.c b/source/ref_gl/r_cull.c index 5b999dd04d..10836acfbb 100644 --- a/source/ref_gl/r_cull.c +++ b/source/ref_gl/r_cull.c @@ -302,7 +302,7 @@ int R_CullModelEntity( const entity_t *e, vec3_t mins, vec3_t maxs, float radius return 1; } - if( e->flags & RF_NODEPTHTEST ) + if( e->flags & (RF_NODEPTHTEST | RF_OUTLINE_WRITE_THROUGH) ) return 0; // account for possible outlines diff --git a/source/ref_gl/r_image.c b/source/ref_gl/r_image.c index e18cc0a29c..30aa0f04a1 100644 --- a/source/ref_gl/r_image.c +++ b/source/ref_gl/r_image.c @@ -2301,7 +2301,7 @@ void R_InitViewportTexture( image_t **texture, const char *name, int id, } if( t->flags & IT_FRAMEBUFFER ) { t->fbo = RFB_RegisterObject( t->upload_width, t->upload_height, ( tags & IMAGE_TAG_BUILTIN ) != 0, - ( flags & IT_DEPTHRB ) != 0, true ); + ( flags & IT_DEPTHRB ) != 0, ( flags & IT_STENCIL ) != 0 ); RFB_AttachTextureToObject( t->fbo, t ); } } diff --git a/source/ref_gl/r_mesh.c b/source/ref_gl/r_mesh.c index 24229551fd..534b9fbfde 100644 --- a/source/ref_gl/r_mesh.c +++ b/source/ref_gl/r_mesh.c @@ -139,9 +139,13 @@ unsigned R_PackOpaqueOrder( const entity_t *e, const shader_t *shader, bool ligh // group by dlight if( dlight ) order |= 0x80; - // draw game objects after the world - if( e != rsc.worldent ) + + if(e->renderfx & RF_OUTLINE_WRITE_THROUGH) { order |= 0x100; + } else if( e != rsc.worldent ) { + // draw game objects after the world + order |= 0x200; + } return order; } @@ -184,11 +188,7 @@ void *R_AddSurfToDrawList( drawList_t *list, const entity_t *e, const mfog_t *fo R_ReserveDrawSurfaces( list, minMeshes ); } if(renderFx & RF_OUTLINE_WRITE_THROUGH) { - shaderSort = SHADER_SORT_DECAL; - dist = -1; - if(portalSurf) { - return false; - } + shaderSort = SHADER_SORT_OPAQUE; } else if( renderFx & RF_WEAPONMODEL ) { if( renderFx & RF_NOCOLORWRITE ) { // depth-pass for alpha-blended weapon: @@ -501,7 +501,7 @@ static void _R_DrawSurfaces( drawList_t *list ) // sky and things that don't use depth test use infinite projection matrix // to not pollute the farclip - infiniteProj = entity->renderfx & RF_NODEPTHTEST ? true : (shader->flags & SHADER_SKY ? true : false); + infiniteProj = (entity->renderfx & RF_NODEPTHTEST) ? true : (shader->flags & SHADER_SKY ? true : false); if( infiniteProj != prevInfiniteProj ) { RB_FlushDynamicMeshes(); batchFlushed = true; diff --git a/source/ref_gl/r_register.c b/source/ref_gl/r_register.c index bfde6a6ad9..1aa32bc97b 100644 --- a/source/ref_gl/r_register.c +++ b/source/ref_gl/r_register.c @@ -703,8 +703,7 @@ static bool R_RegisterGLExtensions( void ) qglGetIntegerv( GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, &glConfig.maxTextureLayers ); /* GL_EXT_packed_depth_stencil * Many OpenGL implementation don't support separate depth and stencil renderbuffers. */ - if( !glConfig.ext.packed_depth_stencil ) - glConfig.stencilBits = 0; + glConfig.stencilBits = glConfig.ext.packed_depth_stencil; versionMajor = versionMinor = 0; sscanf( glConfig.shadingLanguageVersionString, "%d.%d", &versionMajor, &versionMinor ); diff --git a/source/ref_gl/r_skm.c b/source/ref_gl/r_skm.c index 07eeb01335..6d9580e8c1 100644 --- a/source/ref_gl/r_skm.c +++ b/source/ref_gl/r_skm.c @@ -1471,7 +1471,11 @@ bool R_AddSkeletalModelToDrawList( const entity_t *e ) } if( shader ) { - R_AddSurfToDrawList( rn.meshlist, e, fog, shader, distance, 0, NULL, skmodel->drawSurfs + i ); + int order = 0; + if( shader->sort == SHADER_SORT_OPAQUE ) { + order = R_PackOpaqueOrder(e, shader, false, false); + } + R_AddSurfToDrawList( rn.meshlist, e, fog, shader, distance, order, NULL, skmodel->drawSurfs + i ); } } From 9833f455090ec46ebd00699eb46b365d8b5e1cfa Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Mon, 16 Sep 2024 21:46:42 -0700 Subject: [PATCH 3/7] feat: tweak outline logic Signed-off-by: Michael Pollind --- source/cgame/cg_pmodels.cpp | 25 ++++---- source/cgame/ref.h | 9 ++- source/ref_gl/r_alias.c | 12 +++- source/ref_gl/r_backend_program.c | 99 ++++++++++++++++++++++++------- source/ref_gl/r_cull.c | 2 +- source/ref_gl/r_mesh.c | 8 ++- source/ref_gl/r_program.h | 3 +- source/ref_gl/r_scene.c | 13 ++++ 8 files changed, 128 insertions(+), 43 deletions(-) diff --git a/source/cgame/cg_pmodels.cpp b/source/cgame/cg_pmodels.cpp index 783fee55e1..56bffb6c6d 100644 --- a/source/cgame/cg_pmodels.cpp +++ b/source/cgame/cg_pmodels.cpp @@ -1303,9 +1303,19 @@ void CG_AddPModel( centity_t *cent ) if( !( cent->effects & EF_RACEGHOST ) ) { CG_AddCentityOutLineEffect( cent ); + + if( cent->current.team == cg.predictedPlayerState.stats[STAT_TEAM] ) { + vec4_t color; + CG_TeamColor( cg.predictedPlayerState.stats[STAT_TEAM], color ); + cent->ent.outlineColorGhost[0] = color[0] * 255.0f; + cent->ent.outlineColorGhost[1] = color[1] * 255.0f; + cent->ent.outlineColorGhost[2] = color[2] * 255.0f; + cent->ent.outlineColorGhost[3] = 255; + cent->ent.outlineGhost = 1.5f; + } + CG_AddEntityToScene( ¢->ent ); } - if( !cent->ent.model ) return; @@ -1314,19 +1324,6 @@ void CG_AddPModel( centity_t *cent ) CG_AddShellEffects( ¢->ent, cent->effects ); - { - entity_t shellOutline = cent->ent; - shellOutline.renderfx |= RF_OUTLINE_WRITE_THROUGH; - shellOutline.outlineColor[0] = 255; - shellOutline.outlineColor[1] = 0; - shellOutline.outlineColor[2] = 0; - shellOutline.outlineColor[3] = 255; - shellOutline.outlineHeight = 1.5f; - - CG_AddEntityToScene( &shellOutline ); - } - - CG_AddHeadIcon( cent ); // add teleporter sfx if needed diff --git a/source/cgame/ref.h b/source/cgame/ref.h index defb589756..33b1410c46 100644 --- a/source/cgame/ref.h +++ b/source/cgame/ref.h @@ -41,7 +41,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define RF_GREYSCALE 0x400 #define RF_NODEPTHTEST 0x800 #define RF_NOCOLORWRITE 0x1000 -#define RF_OUTLINE_WRITE_THROUGH 0x2000 +#define RF_OUTLINE_STENCIL_0 0x2000 +#define RF_OUTLINE_STENCIL_1 0x4000 // refdef flags #define RDF_UNDERWATER 0x1 // warp the screen as apropriate @@ -162,11 +163,17 @@ typedef struct entity_s float rotation; float outlineHeight; + float outlineGhost; union { byte_vec4_t outlineColor; uint8_t outlineRGBA[4]; }; + union + { + byte_vec4_t outlineColorGhost; + uint8_t outlineRGBAGhost[4]; + }; } entity_t; typedef struct refdef_s diff --git a/source/ref_gl/r_alias.c b/source/ref_gl/r_alias.c index 27078296de..c58f2ecb40 100644 --- a/source/ref_gl/r_alias.c +++ b/source/ref_gl/r_alias.c @@ -787,7 +787,7 @@ bool R_AddAliasModelToDrawList( const entity_t *e ) for( i = 0, mesh = aliasmodel->meshes; i < aliasmodel->nummeshes; i++, mesh++ ) { shader = NULL; - + int order = 0; if( e->customSkin ) { shader = R_FindShaderForSkinFile( e->customSkin, mesh->name ); } else if( e->customShader ) { @@ -795,15 +795,21 @@ bool R_AddAliasModelToDrawList( const entity_t *e ) } else if( mesh->numskins ) { for( j = 0; j < mesh->numskins; j++ ) { shader = mesh->skins[j].shader; + if( shader->sort == SHADER_SORT_OPAQUE ) { + order = R_PackOpaqueOrder( e, shader, false, false ); + } if( shader ) { - R_AddSurfToDrawList( rn.meshlist, e, fog, shader, distance, 0, NULL, aliasmodel->drawSurfs + i ); + R_AddSurfToDrawList( rn.meshlist, e, fog, shader, distance, order, NULL, aliasmodel->drawSurfs + i ); } } continue; } if( shader ) { - R_AddSurfToDrawList( rn.meshlist, e, fog, shader, distance, 0, NULL, aliasmodel->drawSurfs + i ); + if( shader->sort == SHADER_SORT_OPAQUE ) { + order = R_PackOpaqueOrder( e, shader, false, false ); + } + R_AddSurfToDrawList( rn.meshlist, e, fog, shader, distance, order, NULL, aliasmodel->drawSurfs + i ); } } diff --git a/source/ref_gl/r_backend_program.c b/source/ref_gl/r_backend_program.c index d56371d71e..57961db6e1 100644 --- a/source/ref_gl/r_backend_program.c +++ b/source/ref_gl/r_backend_program.c @@ -34,7 +34,8 @@ enum BUILTIN_GLSLPASS_SHADOWMAP, BUILTIN_GLSLPASS_OUTLINE, BUILTIN_GLSLPASS_SKYBOX, - BUILTIN_GLSLPASS_OVERLAY_OUTLINE, + BUILTIN_GLSLPASS_OVERLAY_OUTLINE_0, + BUILTIN_GLSLPASS_OVERLAY_OUTLINE_1, MAX_BUILTIN_GLSLPASSES }; @@ -103,12 +104,20 @@ static void RB_InitBuiltinPasses( void ) pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE; // overlay outline - pass = &r_GLSLpasses[BUILTIN_GLSLPASS_OVERLAY_OUTLINE]; + pass = &r_GLSLpasses[BUILTIN_GLSLPASS_OVERLAY_OUTLINE_0]; pass->flags = 0; pass->rgbgen.type = RGB_GEN_OUTLINE; pass->alphagen.type = ALPHA_GEN_OUTLINE; pass->tcgen = TC_GEN_NONE; - pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE_OVERLAY; + pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE_0; + + // overlay outline + pass = &r_GLSLpasses[BUILTIN_GLSLPASS_OVERLAY_OUTLINE_1]; + pass->flags = 0; + pass->rgbgen.type = RGB_GEN_OUTLINE; + pass->alphagen.type = ALPHA_GEN_OUTLINE; + pass->tcgen = TC_GEN_NONE; + pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE_1; // skybox @@ -1377,7 +1386,7 @@ static void RB_RenderMeshGLSL_Shadowmap( const shaderpass_t *pass, r_glslfeat_t /* * RB_RenderMeshGLSL_Outline */ -static void RB_RenderMeshGLSL_OverlayOutline( const shaderpass_t *pass, r_glslfeat_t programFeatures ) +static void RB_RenderMeshGLSL_StencilOutline_0( const shaderpass_t *pass, r_glslfeat_t programFeatures ) { if( rb.currentModelType == mod_brush ) { programFeatures |= GLSL_SHADER_OUTLINE_OUTLINES_CUTOFF; @@ -1411,28 +1420,57 @@ static void RB_RenderMeshGLSL_OverlayOutline( const shaderpass_t *pass, r_glslfe // set shaderpass state (blending, depthwrite, etc) RB_SetStencilMask( 0xFF ); - RB_SetStencilOp( GL_REPLACE, GL_KEEP, GL_REPLACE); + RB_SetStencilOp( GL_REPLACE, GL_ZERO, GL_REPLACE); RB_SetStencilFunc( GL_ALWAYS, 1, 0xFF ); RB_SetShaderpassState( pass->flags | GLSTATE_STENCIL_TEST | GLSTATE_DEPTHFUNC_GT | GLSTATE_NO_COLORWRITE ); RP_UpdateOutlineUniforms( program, rb.currentEntity->outlineHeight * r_outlines_scale->value ); RB_DrawElementsReal( &rb.drawElements ); +} + + +/* +* RB_RenderMeshGLSL_Outline +*/ +static void RB_RenderMeshGLSL_StencilOutline_1( const shaderpass_t *pass, r_glslfeat_t programFeatures ) +{ + if( rb.currentModelType == mod_brush ) { + programFeatures |= GLSL_SHADER_OUTLINE_OUTLINES_CUTOFF; + } + + programFeatures |= RB_RGBAlphaGenToProgramFeatures( &pass->rgbgen, &pass->alphagen ); + + programFeatures |= RB_FogProgramFeatures( pass, rb.fog ); + + // update uniforcms + int program = RB_RegisterProgram( GLSL_PROGRAM_TYPE_OUTLINE, NULL, + rb.currentShader->deformsKey, + rb.currentShader->deforms, + rb.currentShader->numdeforms, + programFeatures ); + if( !RB_BindProgram( program ) ) + return; + + mat4_t texMatrix; + Matrix4_Identity( texMatrix ); + RB_UpdateCommonUniforms( program, pass, texMatrix ); + + if( programFeatures & GLSL_SHADER_COMMON_FOG ) { + RB_UpdateFogUniforms( program, rb.fog ); + } + // submit animation data + if( programFeatures & GLSL_SHADER_COMMON_BONE_TRANSFORMS ) { + RP_UpdateBonesUniforms( program, rb.bonesData.numBones, rb.bonesData.dualQuats ); + } + + RB_SetStencilMask( 0xFF ); RB_SetStencilFunc( GL_ALWAYS, 0x0, 0xFF ); RB_SetStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE ); RB_SetShaderpassState( pass->flags | GLSTATE_STENCIL_TEST | GLSTATE_NO_DEPTH_TEST | GLSTATE_NO_COLORWRITE ); RP_UpdateOutlineUniforms( program, 0 ); RB_DrawElementsReal( &rb.drawElements ); - - RB_SetStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); - RB_SetStencilFunc( GL_EQUAL, 1, 0xFF ); - RB_SetStencilMask( 0x00 ); - - RB_SetShaderpassState( pass->flags | GLSTATE_NO_DEPTH_TEST | GLSTATE_STENCIL_TEST ); - RP_UpdateOutlineUniforms( program, rb.currentEntity->outlineHeight * r_outlines_scale->value ); - RB_DrawElementsReal( &rb.drawElements ); - } /* @@ -1480,8 +1518,21 @@ static void RB_RenderMeshGLSL_Outline( const shaderpass_t *pass, r_glslfeat_t pr } RB_DrawElementsReal( &rb.drawElements ); - + RB_Cull( faceCull ); + + if(rb.currentEntity->outlineGhost) { + Vector4Copy( rb.currentEntity->outlineColorGhost, rb.entityOutlineColor ); + RB_UpdateCommonUniforms( program, pass, texMatrix ); + + RB_SetStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); + RB_SetStencilFunc( GL_EQUAL, 1, 0xFF ); + RB_SetStencilMask( 0x00 ); + + RB_SetShaderpassState( pass->flags | GLSTATE_NO_DEPTH_TEST | GLSTATE_STENCIL_TEST ); + RP_UpdateOutlineUniforms( program, rb.currentEntity->outlineGhost * r_outlines_scale->value ); + RB_DrawElementsReal( &rb.drawElements ); + } } /* @@ -1965,8 +2016,11 @@ void RB_RenderMeshGLSLProgrammed( const shaderpass_t *pass, int programType ) case GLSL_PROGRAM_TYPE_SHADOWMAP: RB_RenderMeshGLSL_Shadowmap( pass, features ); break; - case GLSL_PROGRAM_TYPE_OUTLINE_OVERLAY: - RB_RenderMeshGLSL_OverlayOutline(pass, features ); + case GLSL_PROGRAM_TYPE_OUTLINE_0: + RB_RenderMeshGLSL_StencilOutline_0(pass, features ); + break; + case GLSL_PROGRAM_TYPE_OUTLINE_1: + RB_RenderMeshGLSL_StencilOutline_1(pass, features ); break; case GLSL_PROGRAM_TYPE_OUTLINE: RB_RenderMeshGLSL_Outline( pass, features ); @@ -2064,7 +2118,7 @@ void RB_BindShader( const entity_t *e, const shader_t *shader, const mfog_t *fog rb.alphaHack = e->renderfx & RF_ALPHAHACK ? true : false; rb.hackedAlpha = e->shaderRGBA[3] / 255.0; rb.greyscale = e->renderfx & RF_GREYSCALE ? true : false; - rb.noDepthTest = e->renderfx & (RF_NODEPTHTEST | RF_OUTLINE_WRITE_THROUGH) && e->rtype == RT_SPRITE ? true : false; + rb.noDepthTest = e->renderfx & (RF_NODEPTHTEST | RF_OUTLINE_STENCIL_0 | RF_OUTLINE_STENCIL_1) && e->rtype == RT_SPRITE ? true : false; rb.noColorWrite = e->renderfx & RF_NOCOLORWRITE ? true : false; rb.depthEqual = rb.alphaHack && (e->renderfx & RF_WEAPONMODEL); } @@ -2450,8 +2504,13 @@ void RB_DrawShadedElements( void ) RB_SetShaderState(); - if(rb.currentEntity->renderfx & RF_OUTLINE_WRITE_THROUGH) { - RB_RenderPass( &r_GLSLpasses[BUILTIN_GLSLPASS_OVERLAY_OUTLINE] ); + if(rb.currentEntity->renderfx & RF_OUTLINE_STENCIL_1) { + RB_RenderPass( &r_GLSLpasses[BUILTIN_GLSLPASS_OVERLAY_OUTLINE_1] ); + return; + } + + if(rb.currentEntity->renderfx & RF_OUTLINE_STENCIL_0) { + RB_RenderPass( &r_GLSLpasses[BUILTIN_GLSLPASS_OVERLAY_OUTLINE_0] ); return; } diff --git a/source/ref_gl/r_cull.c b/source/ref_gl/r_cull.c index 10836acfbb..2f35d728e4 100644 --- a/source/ref_gl/r_cull.c +++ b/source/ref_gl/r_cull.c @@ -302,7 +302,7 @@ int R_CullModelEntity( const entity_t *e, vec3_t mins, vec3_t maxs, float radius return 1; } - if( e->flags & (RF_NODEPTHTEST | RF_OUTLINE_WRITE_THROUGH) ) + if( e->flags & (RF_NODEPTHTEST | RF_OUTLINE_STENCIL_1 | RF_OUTLINE_STENCIL_0) ) return 0; // account for possible outlines diff --git a/source/ref_gl/r_mesh.c b/source/ref_gl/r_mesh.c index 534b9fbfde..151e6f0094 100644 --- a/source/ref_gl/r_mesh.c +++ b/source/ref_gl/r_mesh.c @@ -140,11 +140,13 @@ unsigned R_PackOpaqueOrder( const entity_t *e, const shader_t *shader, bool ligh if( dlight ) order |= 0x80; - if(e->renderfx & RF_OUTLINE_WRITE_THROUGH) { + if(e->renderfx & RF_OUTLINE_STENCIL_0) { order |= 0x100; + } else if(e->renderfx & RF_OUTLINE_STENCIL_1) { + order |= 0x200; } else if( e != rsc.worldent ) { // draw game objects after the world - order |= 0x200; + order |= 0x300; } return order; @@ -187,7 +189,7 @@ void *R_AddSurfToDrawList( drawList_t *list, const entity_t *e, const mfog_t *fo } R_ReserveDrawSurfaces( list, minMeshes ); } - if(renderFx & RF_OUTLINE_WRITE_THROUGH) { + if(renderFx & (RF_OUTLINE_STENCIL_0 | RF_OUTLINE_STENCIL_1)) { shaderSort = SHADER_SORT_OPAQUE; } else if( renderFx & RF_WEAPONMODEL ) { if( renderFx & RF_NOCOLORWRITE ) { diff --git a/source/ref_gl/r_program.h b/source/ref_gl/r_program.h index c082d0a626..8c503655b6 100644 --- a/source/ref_gl/r_program.h +++ b/source/ref_gl/r_program.h @@ -54,7 +54,8 @@ enum GLSL_PROGRAM_TYPE_FXAA, GLSL_PROGRAM_TYPE_YUV, GLSL_PROGRAM_TYPE_COLORCORRECTION, - GLSL_PROGRAM_TYPE_OUTLINE_OVERLAY, + GLSL_PROGRAM_TYPE_OUTLINE_0, + GLSL_PROGRAM_TYPE_OUTLINE_1, GLSL_PROGRAM_TYPE_MAXTYPE }; diff --git a/source/ref_gl/r_scene.c b/source/ref_gl/r_scene.c index 0d3ab76dee..b30e9b8173 100644 --- a/source/ref_gl/r_scene.c +++ b/source/ref_gl/r_scene.c @@ -111,6 +111,19 @@ void R_AddEntityToScene( const entity_t *ent ) tent.renderfx |= RF_NOCOLORWRITE|RF_NOSHADOW; R_AddEntityToScene( &tent ); } + + if(de->outlineGhost > 0 && (de->renderfx & (RF_OUTLINE_STENCIL_0 | RF_OUTLINE_STENCIL_1)) == 0) { + { + entity_t tent = *ent; + tent.renderfx |= RF_OUTLINE_STENCIL_0; + R_AddEntityToScene( &tent ); + } + { + entity_t tent = *ent; + tent.renderfx |= RF_OUTLINE_STENCIL_1; + R_AddEntityToScene( &tent ); + } + } } } From 0bf842b2c4fe64dfcbcbc12f4a2be4d79f22def9 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Tue, 17 Sep 2024 16:32:49 -0700 Subject: [PATCH 4/7] feat: add bodge for outline Signed-off-by: Michael Pollind --- source/qcommon/snap_write.c | 3 ++ source/ref_gl/r_backend_program.c | 90 ++++++++++++++++++------------- source/ref_gl/r_cull.c | 9 ++-- source/ref_gl/r_program.h | 1 + 4 files changed, 62 insertions(+), 41 deletions(-) diff --git a/source/qcommon/snap_write.c b/source/qcommon/snap_write.c index e87bab5f71..76815a5eaf 100644 --- a/source/qcommon/snap_write.c +++ b/source/qcommon/snap_write.c @@ -909,6 +909,9 @@ static bool SNAP_SnapCullEntity( cmodel_state_t *cms, edict_t *ent, edict_t *cle if( frame->allentities ) return false; + if(ent->s.type == ET_PLAYER || ent->s.type == ET_CORPSE) + return false; + // filters: transmit only to clients in the same team as this entity // broadcasting is less important than team specifics if( ( ent->r.svflags & SVF_ONLYTEAM ) && ( clent && ent->s.team != clent->s.team ) ) diff --git a/source/ref_gl/r_backend_program.c b/source/ref_gl/r_backend_program.c index 57961db6e1..e541e4d601 100644 --- a/source/ref_gl/r_backend_program.c +++ b/source/ref_gl/r_backend_program.c @@ -36,6 +36,7 @@ enum BUILTIN_GLSLPASS_SKYBOX, BUILTIN_GLSLPASS_OVERLAY_OUTLINE_0, BUILTIN_GLSLPASS_OVERLAY_OUTLINE_1, + BUILTIN_GLSLPASS_OVERLAY_OUTLINE_2, MAX_BUILTIN_GLSLPASSES }; @@ -118,6 +119,14 @@ static void RB_InitBuiltinPasses( void ) pass->alphagen.type = ALPHA_GEN_OUTLINE; pass->tcgen = TC_GEN_NONE; pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE_1; + + // overlay outline + pass = &r_GLSLpasses[BUILTIN_GLSLPASS_OVERLAY_OUTLINE_2]; + pass->flags = 0; + pass->rgbgen.type = RGB_GEN_OUTLINE; + pass->alphagen.type = ALPHA_GEN_OUTLINE; + pass->tcgen = TC_GEN_NONE; + pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE_2; // skybox @@ -1388,14 +1397,11 @@ static void RB_RenderMeshGLSL_Shadowmap( const shaderpass_t *pass, r_glslfeat_t */ static void RB_RenderMeshGLSL_StencilOutline_0( const shaderpass_t *pass, r_glslfeat_t programFeatures ) { - if( rb.currentModelType == mod_brush ) { - programFeatures |= GLSL_SHADER_OUTLINE_OUTLINES_CUTOFF; - } - + Vector4Copy( rb.currentEntity->outlineColorGhost, rb.entityOutlineColor ); + rb.entityOutlineColor[0] *= .7f; + rb.entityOutlineColor[1] *= .7f; + rb.entityOutlineColor[2] *= .7f; programFeatures |= RB_RGBAlphaGenToProgramFeatures( &pass->rgbgen, &pass->alphagen ); - - programFeatures |= RB_FogProgramFeatures( pass, rb.fog ); - // update uniforcms int program = RB_RegisterProgram( GLSL_PROGRAM_TYPE_OUTLINE, NULL, rb.currentShader->deformsKey, @@ -1408,10 +1414,6 @@ static void RB_RenderMeshGLSL_StencilOutline_0( const shaderpass_t *pass, r_glsl mat4_t texMatrix; Matrix4_Identity( texMatrix ); RB_UpdateCommonUniforms( program, pass, texMatrix ); - - if( programFeatures & GLSL_SHADER_COMMON_FOG ) { - RB_UpdateFogUniforms( program, rb.fog ); - } // submit animation data if( programFeatures & GLSL_SHADER_COMMON_BONE_TRANSFORMS ) { @@ -1423,25 +1425,15 @@ static void RB_RenderMeshGLSL_StencilOutline_0( const shaderpass_t *pass, r_glsl RB_SetStencilOp( GL_REPLACE, GL_ZERO, GL_REPLACE); RB_SetStencilFunc( GL_ALWAYS, 1, 0xFF ); - RB_SetShaderpassState( pass->flags | GLSTATE_STENCIL_TEST | GLSTATE_DEPTHFUNC_GT | GLSTATE_NO_COLORWRITE ); - RP_UpdateOutlineUniforms( program, rb.currentEntity->outlineHeight * r_outlines_scale->value ); + RB_SetShaderpassState( pass->flags | GLSTATE_STENCIL_TEST | GLSTATE_DEPTHFUNC_GT);// | GLSTATE_NO_COLORWRITE ); + RP_UpdateOutlineUniforms( program, rb.currentEntity->outlineGhost); RB_DrawElementsReal( &rb.drawElements ); } - -/* -* RB_RenderMeshGLSL_Outline -*/ static void RB_RenderMeshGLSL_StencilOutline_1( const shaderpass_t *pass, r_glslfeat_t programFeatures ) { - if( rb.currentModelType == mod_brush ) { - programFeatures |= GLSL_SHADER_OUTLINE_OUTLINES_CUTOFF; - } - + Vector4Copy( rb.currentEntity->outlineColorGhost, rb.entityOutlineColor ); programFeatures |= RB_RGBAlphaGenToProgramFeatures( &pass->rgbgen, &pass->alphagen ); - - programFeatures |= RB_FogProgramFeatures( pass, rb.fog ); - // update uniforcms int program = RB_RegisterProgram( GLSL_PROGRAM_TYPE_OUTLINE, NULL, rb.currentShader->deformsKey, @@ -1454,10 +1446,6 @@ static void RB_RenderMeshGLSL_StencilOutline_1( const shaderpass_t *pass, r_glsl mat4_t texMatrix; Matrix4_Identity( texMatrix ); RB_UpdateCommonUniforms( program, pass, texMatrix ); - - if( programFeatures & GLSL_SHADER_COMMON_FOG ) { - RB_UpdateFogUniforms( program, rb.fog ); - } // submit animation data if( programFeatures & GLSL_SHADER_COMMON_BONE_TRANSFORMS ) { @@ -1473,6 +1461,36 @@ static void RB_RenderMeshGLSL_StencilOutline_1( const shaderpass_t *pass, r_glsl RB_DrawElementsReal( &rb.drawElements ); } +static void RB_RenderMeshGLSL_StencilOutline_2( const shaderpass_t *pass, r_glslfeat_t programFeatures ) +{ + Vector4Copy( rb.currentEntity->outlineColorGhost, rb.entityOutlineColor ); + programFeatures |= RB_RGBAlphaGenToProgramFeatures( &pass->rgbgen, &pass->alphagen ); + // update uniforcms + int program = RB_RegisterProgram( GLSL_PROGRAM_TYPE_OUTLINE, NULL, + rb.currentShader->deformsKey, + rb.currentShader->deforms, + rb.currentShader->numdeforms, + programFeatures ); + if( !RB_BindProgram( program ) ) + return; + + // submit animation data + if( programFeatures & GLSL_SHADER_COMMON_BONE_TRANSFORMS ) { + RP_UpdateBonesUniforms( program, rb.bonesData.numBones, rb.bonesData.dualQuats ); + } + mat4_t texMatrix; + Matrix4_Identity( texMatrix ); + RB_UpdateCommonUniforms( program, pass, texMatrix ); + + RB_SetStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); + RB_SetStencilFunc( GL_EQUAL, 1, 0xFF ); + RB_SetStencilMask( 0x00 ); + + RB_SetShaderpassState( pass->flags | GLSTATE_NO_DEPTH_TEST | GLSTATE_STENCIL_TEST ); + RP_UpdateOutlineUniforms( program, rb.currentEntity->outlineGhost ); + RB_DrawElementsReal( &rb.drawElements ); +} + /* * RB_RenderMeshGLSL_Outline */ @@ -1522,16 +1540,6 @@ static void RB_RenderMeshGLSL_Outline( const shaderpass_t *pass, r_glslfeat_t pr RB_Cull( faceCull ); if(rb.currentEntity->outlineGhost) { - Vector4Copy( rb.currentEntity->outlineColorGhost, rb.entityOutlineColor ); - RB_UpdateCommonUniforms( program, pass, texMatrix ); - - RB_SetStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); - RB_SetStencilFunc( GL_EQUAL, 1, 0xFF ); - RB_SetStencilMask( 0x00 ); - - RB_SetShaderpassState( pass->flags | GLSTATE_NO_DEPTH_TEST | GLSTATE_STENCIL_TEST ); - RP_UpdateOutlineUniforms( program, rb.currentEntity->outlineGhost * r_outlines_scale->value ); - RB_DrawElementsReal( &rb.drawElements ); } } @@ -2022,6 +2030,9 @@ void RB_RenderMeshGLSLProgrammed( const shaderpass_t *pass, int programType ) case GLSL_PROGRAM_TYPE_OUTLINE_1: RB_RenderMeshGLSL_StencilOutline_1(pass, features ); break; + case GLSL_PROGRAM_TYPE_OUTLINE_2: + RB_RenderMeshGLSL_StencilOutline_2(pass, features ); + break; case GLSL_PROGRAM_TYPE_OUTLINE: RB_RenderMeshGLSL_Outline( pass, features ); break; @@ -2532,6 +2543,9 @@ void RB_DrawShadedElements( void ) if( addGLSLOutline ) RB_RenderPass( &r_GLSLpasses[BUILTIN_GLSLPASS_OUTLINE] ); + if(rb.currentEntity->outlineGhost) + RB_RenderPass( &r_GLSLpasses[BUILTIN_GLSLPASS_OVERLAY_OUTLINE_2] ); + // fog if( rb.texFog && rb.texFog->shader ) { diff --git a/source/ref_gl/r_cull.c b/source/ref_gl/r_cull.c index 2f35d728e4..3ee0ee067d 100644 --- a/source/ref_gl/r_cull.c +++ b/source/ref_gl/r_cull.c @@ -302,13 +302,16 @@ int R_CullModelEntity( const entity_t *e, vec3_t mins, vec3_t maxs, float radius return 1; } - if( e->flags & (RF_NODEPTHTEST | RF_OUTLINE_STENCIL_1 | RF_OUTLINE_STENCIL_0) ) - return 0; - // account for possible outlines if( e->outlineHeight ) radius += e->outlineHeight * r_outlines_scale->value * 1.73/*sqrt(3)*/; + if( e->outlineGhost > 0) + return 0; + + if( e->flags & (RF_NODEPTHTEST | RF_OUTLINE_STENCIL_1 | RF_OUTLINE_STENCIL_0) ) + return 0; + if( sphereCull ) { if( R_CullSphere( e->origin, radius, rn.clipFlags ) ) diff --git a/source/ref_gl/r_program.h b/source/ref_gl/r_program.h index 8c503655b6..fc81b2edd6 100644 --- a/source/ref_gl/r_program.h +++ b/source/ref_gl/r_program.h @@ -56,6 +56,7 @@ enum GLSL_PROGRAM_TYPE_COLORCORRECTION, GLSL_PROGRAM_TYPE_OUTLINE_0, GLSL_PROGRAM_TYPE_OUTLINE_1, + GLSL_PROGRAM_TYPE_OUTLINE_2, GLSL_PROGRAM_TYPE_MAXTYPE }; From 994ef7a2a0f67742595a3b6bb909264a2c027c07 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 18 Sep 2024 07:42:37 -0700 Subject: [PATCH 5/7] feat: cleanup Signed-off-by: Michael Pollind --- source/qcommon/common.c | 2 -- source/qcommon/snap_write.c | 2 -- source/ref_gl/r_backend.c | 24 ++++++++++++++++-------- source/ref_gl/r_backend_program.c | 20 ++++++++------------ source/ref_gl/r_image.c | 4 ++-- source/ref_gl/r_program.h | 6 +++--- source/ref_gl/r_scene.c | 1 + source/ref_gl/r_skm.c | 10 +++++----- 8 files changed, 35 insertions(+), 34 deletions(-) diff --git a/source/qcommon/common.c b/source/qcommon/common.c index 4e67ecffab..5bd17940d1 100644 --- a/source/qcommon/common.c +++ b/source/qcommon/common.c @@ -230,8 +230,6 @@ void Com_Printf( const char *format, ... ) Q_vsnprintfz( msg, sizeof( msg ), format, argptr ); va_end( argptr ); - printf("%s", msg); - QMutex_Lock( com_print_mutex ); if( rd_target ) diff --git a/source/qcommon/snap_write.c b/source/qcommon/snap_write.c index 76815a5eaf..656880e025 100644 --- a/source/qcommon/snap_write.c +++ b/source/qcommon/snap_write.c @@ -909,8 +909,6 @@ static bool SNAP_SnapCullEntity( cmodel_state_t *cms, edict_t *ent, edict_t *cle if( frame->allentities ) return false; - if(ent->s.type == ET_PLAYER || ent->s.type == ET_CORPSE) - return false; // filters: transmit only to clients in the same team as this entity // broadcasting is less important than team specifics diff --git a/source/ref_gl/r_backend.c b/source/ref_gl/r_backend.c index 620f1e8b32..795264efaf 100644 --- a/source/ref_gl/r_backend.c +++ b/source/ref_gl/r_backend.c @@ -145,7 +145,10 @@ void RB_StatsMessage( char *msg, size_t size ) ); } -void RB_SetStencilFunc( int func, int ref, int mask ) { +void RB_SetStencilFunc( int func, int ref, int mask ) +{ + if( !glConfig.stencilBits ) + return; if( rb.gl.stencilFunc == func && rb.gl.stencilRef == ref && rb.gl.stencilFuncMask == mask ) return; @@ -155,7 +158,10 @@ void RB_SetStencilFunc( int func, int ref, int mask ) { rb.gl.stencilFuncMask = mask; } -void RB_SetStencilOp( int sfail, int dpfail, int dppass ) { +void RB_SetStencilOp( int sfail, int dpfail, int dppass ) +{ + if( !glConfig.stencilBits ) + return; if( rb.gl.stencilSFail == sfail && rb.gl.stencilDPFail == dpfail && rb.gl.stencilDPPass == dppass ) return; @@ -165,14 +171,16 @@ void RB_SetStencilOp( int sfail, int dpfail, int dppass ) { rb.gl.stencilDPPass = dppass; } -void RB_SetStencilMask( int mask ) { - if( rb.gl.stencilMask == mask ) - return; +void RB_SetStencilMask( int mask ) +{ + if( !glConfig.stencilBits ) + return; + if( rb.gl.stencilMask == mask ) + return; qglStencilMask( mask ); rb.gl.stencilMask = mask; } - /* * RB_SetGLDefaults */ @@ -364,7 +372,7 @@ void RB_Cull( int cull ) void RB_SetState( int state ) { - int diff = rb.gl.state ^ state; + const int diff = rb.gl.state ^ state; if( !diff ) return; @@ -493,7 +501,7 @@ void RB_SetState( int state ) if( diff & GLSTATE_STENCIL_TEST ) { - // if( glConfig.stencilBits ) + if( glConfig.stencilBits ) { if( state & GLSTATE_STENCIL_TEST ) qglEnable( GL_STENCIL_TEST ); diff --git a/source/ref_gl/r_backend_program.c b/source/ref_gl/r_backend_program.c index e541e4d601..141aba5bef 100644 --- a/source/ref_gl/r_backend_program.c +++ b/source/ref_gl/r_backend_program.c @@ -110,7 +110,7 @@ static void RB_InitBuiltinPasses( void ) pass->rgbgen.type = RGB_GEN_OUTLINE; pass->alphagen.type = ALPHA_GEN_OUTLINE; pass->tcgen = TC_GEN_NONE; - pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE_0; + pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE_STENCIL_BACK; // overlay outline pass = &r_GLSLpasses[BUILTIN_GLSLPASS_OVERLAY_OUTLINE_1]; @@ -118,7 +118,7 @@ static void RB_InitBuiltinPasses( void ) pass->rgbgen.type = RGB_GEN_OUTLINE; pass->alphagen.type = ALPHA_GEN_OUTLINE; pass->tcgen = TC_GEN_NONE; - pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE_1; + pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE_STENCIL_FRONT; // overlay outline pass = &r_GLSLpasses[BUILTIN_GLSLPASS_OVERLAY_OUTLINE_2]; @@ -126,7 +126,7 @@ static void RB_InitBuiltinPasses( void ) pass->rgbgen.type = RGB_GEN_OUTLINE; pass->alphagen.type = ALPHA_GEN_OUTLINE; pass->tcgen = TC_GEN_NONE; - pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE_2; + pass->program_type = GLSL_PROGRAM_TYPE_OUTLINE_GHOST_FINAL; // skybox @@ -1391,10 +1391,6 @@ static void RB_RenderMeshGLSL_Shadowmap( const shaderpass_t *pass, r_glslfeat_t RB_Scissor( old_scissor[0], old_scissor[1], old_scissor[2], old_scissor[3] ); } - -/* -* RB_RenderMeshGLSL_Outline -*/ static void RB_RenderMeshGLSL_StencilOutline_0( const shaderpass_t *pass, r_glslfeat_t programFeatures ) { Vector4Copy( rb.currentEntity->outlineColorGhost, rb.entityOutlineColor ); @@ -1425,7 +1421,7 @@ static void RB_RenderMeshGLSL_StencilOutline_0( const shaderpass_t *pass, r_glsl RB_SetStencilOp( GL_REPLACE, GL_ZERO, GL_REPLACE); RB_SetStencilFunc( GL_ALWAYS, 1, 0xFF ); - RB_SetShaderpassState( pass->flags | GLSTATE_STENCIL_TEST | GLSTATE_DEPTHFUNC_GT);// | GLSTATE_NO_COLORWRITE ); + RB_SetShaderpassState( pass->flags | GLSTATE_STENCIL_TEST | GLSTATE_DEPTHFUNC_GT);; RP_UpdateOutlineUniforms( program, rb.currentEntity->outlineGhost); RB_DrawElementsReal( &rb.drawElements ); } @@ -2024,13 +2020,13 @@ void RB_RenderMeshGLSLProgrammed( const shaderpass_t *pass, int programType ) case GLSL_PROGRAM_TYPE_SHADOWMAP: RB_RenderMeshGLSL_Shadowmap( pass, features ); break; - case GLSL_PROGRAM_TYPE_OUTLINE_0: + case GLSL_PROGRAM_TYPE_OUTLINE_STENCIL_BACK: RB_RenderMeshGLSL_StencilOutline_0(pass, features ); break; - case GLSL_PROGRAM_TYPE_OUTLINE_1: + case GLSL_PROGRAM_TYPE_OUTLINE_STENCIL_FRONT: RB_RenderMeshGLSL_StencilOutline_1(pass, features ); break; - case GLSL_PROGRAM_TYPE_OUTLINE_2: + case GLSL_PROGRAM_TYPE_OUTLINE_GHOST_FINAL: RB_RenderMeshGLSL_StencilOutline_2(pass, features ); break; case GLSL_PROGRAM_TYPE_OUTLINE: @@ -2543,7 +2539,7 @@ void RB_DrawShadedElements( void ) if( addGLSLOutline ) RB_RenderPass( &r_GLSLpasses[BUILTIN_GLSLPASS_OUTLINE] ); - if(rb.currentEntity->outlineGhost) + if(rb.currentEntity->outlineGhost && glConfig.stencilBits) RB_RenderPass( &r_GLSLpasses[BUILTIN_GLSLPASS_OVERLAY_OUTLINE_2] ); // fog diff --git a/source/ref_gl/r_image.c b/source/ref_gl/r_image.c index 30aa0f04a1..831a88e8c5 100644 --- a/source/ref_gl/r_image.c +++ b/source/ref_gl/r_image.c @@ -2426,8 +2426,8 @@ static void R_InitScreenImagePair( const char *name, image_t **color, image_t ** assert( !depth || glConfig.ext.depth_texture ); - //if( !glConfig.stencilBits ) - // stencil = false; + if( !glConfig.stencilBits ) + stencil = false; flags = IT_SPECIAL; diff --git a/source/ref_gl/r_program.h b/source/ref_gl/r_program.h index fc81b2edd6..12d4fb2861 100644 --- a/source/ref_gl/r_program.h +++ b/source/ref_gl/r_program.h @@ -54,9 +54,9 @@ enum GLSL_PROGRAM_TYPE_FXAA, GLSL_PROGRAM_TYPE_YUV, GLSL_PROGRAM_TYPE_COLORCORRECTION, - GLSL_PROGRAM_TYPE_OUTLINE_0, - GLSL_PROGRAM_TYPE_OUTLINE_1, - GLSL_PROGRAM_TYPE_OUTLINE_2, + GLSL_PROGRAM_TYPE_OUTLINE_STENCIL_BACK, + GLSL_PROGRAM_TYPE_OUTLINE_STENCIL_FRONT, + GLSL_PROGRAM_TYPE_OUTLINE_GHOST_FINAL, GLSL_PROGRAM_TYPE_MAXTYPE }; diff --git a/source/ref_gl/r_scene.c b/source/ref_gl/r_scene.c index b30e9b8173..860f5ccf3a 100644 --- a/source/ref_gl/r_scene.c +++ b/source/ref_gl/r_scene.c @@ -118,6 +118,7 @@ void R_AddEntityToScene( const entity_t *ent ) tent.renderfx |= RF_OUTLINE_STENCIL_0; R_AddEntityToScene( &tent ); } + if(glConfig.stencilBits) { entity_t tent = *ent; tent.renderfx |= RF_OUTLINE_STENCIL_1; diff --git a/source/ref_gl/r_skm.c b/source/ref_gl/r_skm.c index 6d9580e8c1..1a5b189d7a 100644 --- a/source/ref_gl/r_skm.c +++ b/source/ref_gl/r_skm.c @@ -1471,11 +1471,11 @@ bool R_AddSkeletalModelToDrawList( const entity_t *e ) } if( shader ) { - int order = 0; - if( shader->sort == SHADER_SORT_OPAQUE ) { - order = R_PackOpaqueOrder(e, shader, false, false); - } - R_AddSurfToDrawList( rn.meshlist, e, fog, shader, distance, order, NULL, skmodel->drawSurfs + i ); + int order = 0; + if( shader->sort == SHADER_SORT_OPAQUE ) { + order = R_PackOpaqueOrder( e, shader, false, false ); + } + R_AddSurfToDrawList( rn.meshlist, e, fog, shader, distance, order, NULL, skmodel->drawSurfs + i ); } } From 84b16ade494163ff104f815e72e7cd3704f7adb7 Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 18 Sep 2024 19:28:13 -0700 Subject: [PATCH 6/7] feat: remove arrows Signed-off-by: Michael Pollind --- source/cgame/cg_hud.cpp | 16 ---------------- source/cgame/cg_pmodels.cpp | 4 +++- source/cgame/cg_screen.cpp | 5 ++--- 3 files changed, 5 insertions(+), 20 deletions(-) diff --git a/source/cgame/cg_hud.cpp b/source/cgame/cg_hud.cpp index 55955bb08d..82877d02e2 100644 --- a/source/cgame/cg_hud.cpp +++ b/source/cgame/cg_hud.cpp @@ -2350,12 +2350,6 @@ static bool CG_LFuncDrawHelpMessage( struct cg_layoutnode_s *commandnode, struct return true; } -static bool CG_LFuncDrawTeamMates( struct cg_layoutnode_s *commandnode, struct cg_layoutnode_s *argumentnode, int numArguments ) -{ - CG_DrawTeamMates(); - return true; -} - static bool CG_LFuncDrawDamageNumbers( struct cg_layoutnode_s *commandnode, struct cg_layoutnode_s *argumentnode, int numArguments ) { CG_DrawDamageNumbers(); return true; @@ -3238,16 +3232,6 @@ static const cg_layoutcommand_t cg_LayoutCommands[] = "Draws the name of the player in the crosshair", false }, - - { - "drawTeamMates", - CG_LFuncDrawTeamMates, - NULL, - 0, - "Draws indicators where team mates are", - false - }, - { "drawDamageNumbers", CG_LFuncDrawDamageNumbers, diff --git a/source/cgame/cg_pmodels.cpp b/source/cgame/cg_pmodels.cpp index 56bffb6c6d..0f2a3414b0 100644 --- a/source/cgame/cg_pmodels.cpp +++ b/source/cgame/cg_pmodels.cpp @@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. pmodel_t cg_entPModels[MAX_EDICTS]; pmodelinfo_t *cg_PModelInfos; +static cvar_t *cg_showTeamMates; //====================================================================== // PlayerModel Registering @@ -42,6 +43,7 @@ pmodelinfo_t *cg_PModelInfos; */ void CG_PModelsInit( void ) { + cg_showTeamMates = trap_Cvar_Get( "cg_showTeamMates", "1", CVAR_ARCHIVE ); memset( cg_entPModels, 0, sizeof( cg_entPModels ) ); } @@ -1304,7 +1306,7 @@ void CG_AddPModel( centity_t *cent ) { CG_AddCentityOutLineEffect( cent ); - if( cent->current.team == cg.predictedPlayerState.stats[STAT_TEAM] ) { + if( cent->current.team == cg.predictedPlayerState.stats[STAT_TEAM] && cg_showTeamMates->integer) { vec4_t color; CG_TeamColor( cg.predictedPlayerState.stats[STAT_TEAM], color ); cent->ent.outlineColorGhost[0] = color[0] * 255.0f; diff --git a/source/cgame/cg_screen.cpp b/source/cgame/cg_screen.cpp index fe48cb9fc4..e3bf519b92 100644 --- a/source/cgame/cg_screen.cpp +++ b/source/cgame/cg_screen.cpp @@ -863,9 +863,8 @@ void CG_DrawPlayerNames( struct qfontface_s *font, vec4_t color ) } } -/* -* CG_DrawTeamMates -*/ +// ref: https://github.com/TeamForbiddenLLC/warfork-qfusion/pull/395 +// Note: replaced with player outline void CG_DrawTeamMates( void ) { centity_t *cent; From a010bee7c832539fd02e34188f6b814c8826afea Mon Sep 17 00:00:00 2001 From: Michael Pollind Date: Wed, 18 Sep 2024 19:55:29 -0700 Subject: [PATCH 7/7] feat: cleanup edge of meshes a little Signed-off-by: Michael Pollind --- source/ref_gl/r_backend_program.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source/ref_gl/r_backend_program.c b/source/ref_gl/r_backend_program.c index 141aba5bef..ae7a256c55 100644 --- a/source/ref_gl/r_backend_program.c +++ b/source/ref_gl/r_backend_program.c @@ -1420,10 +1420,14 @@ static void RB_RenderMeshGLSL_StencilOutline_0( const shaderpass_t *pass, r_glsl RB_SetStencilMask( 0xFF ); RB_SetStencilOp( GL_REPLACE, GL_ZERO, GL_REPLACE); RB_SetStencilFunc( GL_ALWAYS, 1, 0xFF ); + + int faceCull = rb.gl.faceCull; + RB_Cull(0); RB_SetShaderpassState( pass->flags | GLSTATE_STENCIL_TEST | GLSTATE_DEPTHFUNC_GT);; RP_UpdateOutlineUniforms( program, rb.currentEntity->outlineGhost); RB_DrawElementsReal( &rb.drawElements ); + RB_Cull(faceCull); } static void RB_RenderMeshGLSL_StencilOutline_1( const shaderpass_t *pass, r_glslfeat_t programFeatures ) @@ -1451,10 +1455,14 @@ static void RB_RenderMeshGLSL_StencilOutline_1( const shaderpass_t *pass, r_glsl RB_SetStencilMask( 0xFF ); RB_SetStencilFunc( GL_ALWAYS, 0x0, 0xFF ); RB_SetStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE ); + + int faceCull = rb.gl.faceCull; + RB_Cull(0); RB_SetShaderpassState( pass->flags | GLSTATE_STENCIL_TEST | GLSTATE_NO_DEPTH_TEST | GLSTATE_NO_COLORWRITE ); RP_UpdateOutlineUniforms( program, 0 ); RB_DrawElementsReal( &rb.drawElements ); + RB_Cull(faceCull); } static void RB_RenderMeshGLSL_StencilOutline_2( const shaderpass_t *pass, r_glslfeat_t programFeatures ) @@ -1482,9 +1490,13 @@ static void RB_RenderMeshGLSL_StencilOutline_2( const shaderpass_t *pass, r_glsl RB_SetStencilFunc( GL_EQUAL, 1, 0xFF ); RB_SetStencilMask( 0x00 ); + int faceCull = rb.gl.faceCull; + RB_Cull(0); + RB_SetShaderpassState( pass->flags | GLSTATE_NO_DEPTH_TEST | GLSTATE_STENCIL_TEST ); RP_UpdateOutlineUniforms( program, rb.currentEntity->outlineGhost ); RB_DrawElementsReal( &rb.drawElements ); + RB_Cull(faceCull); } /*