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 d18a2ac81f..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 ) ); } @@ -1303,9 +1305,20 @@ void CG_AddPModel( centity_t *cent ) if( !( cent->effects & EF_RACEGHOST ) ) { CG_AddCentityOutLineEffect( cent ); + + 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; + 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; 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; diff --git a/source/cgame/ref.h b/source/cgame/ref.h index b22a4e7dbf..33b1410c46 100644 --- a/source/cgame/ref.h +++ b/source/cgame/ref.h @@ -41,6 +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_STENCIL_0 0x2000 +#define RF_OUTLINE_STENCIL_1 0x4000 // refdef flags #define RDF_UNDERWATER 0x1 // warp the screen as apropriate @@ -161,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/qcommon/common.c b/source/qcommon/common.c index f4a3549ff6..5bd17940d1 100644 --- a/source/qcommon/common.c +++ b/source/qcommon/common.c @@ -230,7 +230,6 @@ void Com_Printf( const char *format, ... ) Q_vsnprintfz( msg, sizeof( msg ), format, argptr ); va_end( argptr ); - QMutex_Lock( com_print_mutex ); if( rd_target ) diff --git a/source/qcommon/snap_write.c b/source/qcommon/snap_write.c index e87bab5f71..656880e025 100644 --- a/source/qcommon/snap_write.c +++ b/source/qcommon/snap_write.c @@ -909,6 +909,7 @@ static bool SNAP_SnapCullEntity( cmodel_state_t *cms, edict_t *ent, edict_t *cle if( frame->allentities ) 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_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.c b/source/ref_gl/r_backend.c index 6b7eadf70b..795264efaf 100644 --- a/source/ref_gl/r_backend.c +++ b/source/ref_gl/r_backend.c @@ -145,6 +145,42 @@ void RB_StatsMessage( char *msg, size_t size ) ); } +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; + + 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( !glConfig.stencilBits ) + return; + 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( !glConfig.stencilBits ) + return; + if( rb.gl.stencilMask == mask ) + return; + qglStencilMask( mask ); + rb.gl.stencilMask = mask; +} + /* * RB_SetGLDefaults */ @@ -152,9 +188,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 ); @@ -335,9 +371,8 @@ void RB_Cull( int cull ) */ void RB_SetState( int state ) { - int diff; - diff = rb.gl.state ^ state; + const int diff = rb.gl.state ^ state; if( !diff ) return; 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..ae7a256c55 100644 --- a/source/ref_gl/r_backend_program.c +++ b/source/ref_gl/r_backend_program.c @@ -34,6 +34,9 @@ enum BUILTIN_GLSLPASS_SHADOWMAP, BUILTIN_GLSLPASS_OUTLINE, BUILTIN_GLSLPASS_SKYBOX, + BUILTIN_GLSLPASS_OVERLAY_OUTLINE_0, + BUILTIN_GLSLPASS_OVERLAY_OUTLINE_1, + BUILTIN_GLSLPASS_OVERLAY_OUTLINE_2, MAX_BUILTIN_GLSLPASSES }; @@ -101,6 +104,31 @@ 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_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_STENCIL_BACK; + + // 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_STENCIL_FRONT; + + // 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_GHOST_FINAL; + + // skybox pass = &r_GLSLpasses[BUILTIN_GLSLPASS_SKYBOX]; pass->program_type = GLSL_PROGRAM_TYPE_Q3A_SHADER; @@ -1363,6 +1391,114 @@ 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] ); } +static void RB_RenderMeshGLSL_StencilOutline_0( const shaderpass_t *pass, r_glslfeat_t programFeatures ) +{ + 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 ); + // 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 ); + + // 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_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 ) +{ + 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; + + mat4_t texMatrix; + Matrix4_Identity( texMatrix ); + RB_UpdateCommonUniforms( program, pass, texMatrix ); + + // 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 ); + + 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 ) +{ + 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 ); + + 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); +} + /* * RB_RenderMeshGLSL_Outline */ @@ -1392,7 +1528,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 ); @@ -1408,8 +1544,11 @@ static void RB_RenderMeshGLSL_Outline( const shaderpass_t *pass, r_glslfeat_t pr } RB_DrawElementsReal( &rb.drawElements ); - + RB_Cull( faceCull ); + + if(rb.currentEntity->outlineGhost) { + } } /* @@ -1893,6 +2032,15 @@ 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_STENCIL_BACK: + RB_RenderMeshGLSL_StencilOutline_0(pass, features ); + break; + case GLSL_PROGRAM_TYPE_OUTLINE_STENCIL_FRONT: + RB_RenderMeshGLSL_StencilOutline_1(pass, features ); + break; + case GLSL_PROGRAM_TYPE_OUTLINE_GHOST_FINAL: + RB_RenderMeshGLSL_StencilOutline_2(pass, features ); + break; case GLSL_PROGRAM_TYPE_OUTLINE: RB_RenderMeshGLSL_Outline( pass, features ); break; @@ -1989,7 +2137,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_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); } @@ -2375,6 +2523,16 @@ void RB_DrawShadedElements( void ) RB_SetShaderState(); + 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; + } + for( i = 0, pass = rb.currentShader->passes; i < rb.currentShader->numpasses; i++, pass++ ) { if( ( pass->flags & SHADERPASS_DETAIL ) && !r_detailtextures->integer ) @@ -2393,6 +2551,9 @@ void RB_DrawShadedElements( void ) if( addGLSLOutline ) RB_RenderPass( &r_GLSLpasses[BUILTIN_GLSLPASS_OUTLINE] ); + if(rb.currentEntity->outlineGhost && glConfig.stencilBits) + 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 5b999dd04d..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 ) - 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_image.c b/source/ref_gl/r_image.c index d8a7c1ab65..831a88e8c5 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, ( 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 8fd6327c20..151e6f0094 100644 --- a/source/ref_gl/r_mesh.c +++ b/source/ref_gl/r_mesh.c @@ -139,9 +139,15 @@ 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_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 |= 0x300; + } return order; } @@ -155,7 +161,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 +189,9 @@ 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_STENCIL_0 | RF_OUTLINE_STENCIL_1)) { + shaderSort = SHADER_SORT_OPAQUE; + } 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 +220,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 +414,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 +444,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 ); @@ -497,7 +503,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_program.h b/source/ref_gl/r_program.h index 7dc45610ca..12d4fb2861 100644 --- a/source/ref_gl/r_program.h +++ b/source/ref_gl/r_program.h @@ -54,6 +54,9 @@ enum GLSL_PROGRAM_TYPE_FXAA, GLSL_PROGRAM_TYPE_YUV, GLSL_PROGRAM_TYPE_COLORCORRECTION, + 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_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_scene.c b/source/ref_gl/r_scene.c index 0d3ab76dee..860f5ccf3a 100644 --- a/source/ref_gl/r_scene.c +++ b/source/ref_gl/r_scene.c @@ -111,6 +111,20 @@ 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 ); + } + if(glConfig.stencilBits) + { + entity_t tent = *ent; + tent.renderfx |= RF_OUTLINE_STENCIL_1; + R_AddEntityToScene( &tent ); + } + } } } diff --git a/source/ref_gl/r_skm.c b/source/ref_gl/r_skm.c index 07eeb01335..1a5b189d7a 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 ); } }