From f6b5a1b352e9dec3f58a786205a9a425a9d94ddc Mon Sep 17 00:00:00 2001 From: fuzun Date: Fri, 19 Jan 2018 06:08:06 +0300 Subject: [PATCH 1/2] Initial Software Based Strobing Implementation --- engine/client/cl_scrn.c | 23 ++++++++++- engine/client/console.c | 16 ++++++-- engine/client/gl_local.h | 4 +- engine/client/gl_rmain.c | 79 +++++++++++++++++++++++++++++++++++++- engine/client/vid_common.c | 14 +++++++ engine/common/common.h | 14 +++++++ 6 files changed, 141 insertions(+), 9 deletions(-) diff --git a/engine/client/cl_scrn.c b/engine/client/cl_scrn.c index 651266bb0..347013f6c 100644 --- a/engine/client/cl_scrn.c +++ b/engine/client/cl_scrn.c @@ -101,6 +101,18 @@ void SCR_DrawFPS( void ) /*if( !avgrate ) avgrate = ( maxfps - minfps ) / 2.0f; else */avgrate += ( calc - avgrate ) / host.framecount; + int strobeInterval = r_strobe->integer; + int eFPS; //Effective FPS (strobing effect) + if (strobeInterval > 0) + { + eFPS = (int)((curfps) / (strobeInterval + 1)); + } + else if (strobeInterval < 0) + { + strobeInterval = abs(strobeInterval); + eFPS = (int)((curfps * strobeInterval) / (strobeInterval + 1)); + } + switch( cl_showfps->integer ) { case 3: @@ -111,14 +123,21 @@ void SCR_DrawFPS( void ) break; case 1: default: - Q_snprintf( fpsstring, sizeof( fpsstring ), "%4i fps", curfps ); + if (strobeInterval == 0) + { + Q_snprintf(fpsstring, sizeof(fpsstring), "%4i fps", curfps); + } + else + { + Q_snprintf(fpsstring, sizeof(fpsstring), "%4i FPS\n%3i eFPS", curfps, eFPS); + } } MakeRGBA( color, 255, 255, 255, 255 ); } Con_DrawStringLen( fpsstring, &offset, NULL ); - Con_DrawString( scr_width->integer - offset - 2, 4, fpsstring, color ); + Con_DrawString( scr_width->integer - offset - 5, 4, fpsstring, color ); } /* diff --git a/engine/client/console.c b/engine/client/console.c index ea170f192..51615c34c 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -33,6 +33,8 @@ convar_t *con_fontscale; convar_t *con_fontnum; convar_t *vgui_utf8; +conrect_t con_rect; + static int g_codepage = 0; static qboolean g_utf8 = false; @@ -1698,18 +1700,24 @@ void Con_DrawSolidConsole( float frac, qboolean fill ) y *= frac; if( y >= 1 ) { + con_rect.x = 0; + con_rect.y = y - scr_width->value * 3 / 4; + con_rect.w = scr_width->value; + con_rect.h = scr_width->value * 3 / 4; + if( fill ) { GL_SetRenderMode( kRenderNormal ); if( con_black->integer ) { pglColor4ub( 0, 0, 0, 255 ); - R_DrawStretchPic( 0, y - scr_width->value * 3 / 4, scr_width->value, scr_width->value * 3 / 4, 0, 0, 1, 1, cls.fillImage ); + + R_DrawStretchPic( con_rect.x, con_rect.y, con_rect.w, con_rect.h, 0, 0, 1, 1, cls.fillImage ); } else { pglColor4ub( 255, 255, 255, 255 ); - R_DrawStretchPic( 0, y - scr_width->value * 3 / 4, scr_width->value, scr_width->value * 3 / 4, 0, 0, 1, 1, con.background ); + R_DrawStretchPic( con_rect.x, con_rect.y, con_rect.w, con_rect.h, 0, 0, 1, 1, con.background ); } } else @@ -1718,12 +1726,12 @@ void Con_DrawSolidConsole( float frac, qboolean fill ) if( con_black->value ) { pglColor4ub( 0, 0, 0, 255 * con_alpha->value ); - R_DrawStretchPic( 0, y - scr_width->value * 3 / 4, scr_width->value, scr_width->value * 3 / 4, 0, 0, 1, 1, cls.fillImage ); + R_DrawStretchPic( con_rect.x, con_rect.y, con_rect.w, con_rect.h, 0, 0, 1, 1, cls.fillImage ); } else { pglColor4ub( 255, 255, 255, 255 * con_alpha->value ); - R_DrawStretchPic( 0, y - scr_width->value * 3 / 4, scr_width->value, scr_width->value * 3 / 4, 0, 0, 1, 1, con.background ); + R_DrawStretchPic( con_rect.x, con_rect.y, con_rect.w, con_rect.h, 0, 0, 1, 1, con.background ); } } pglColor4ub( 255, 255, 255, 255 ); diff --git a/engine/client/gl_local.h b/engine/client/gl_local.h index c4f74cd58..6dc0ae21a 100644 --- a/engine/client/gl_local.h +++ b/engine/client/gl_local.h @@ -363,6 +363,7 @@ qboolean R_InitRenderAPI( void ); void R_SetupFrustum( void ); void R_FindViewLeaf( void ); void R_DrawFog( void ); +void R_Strobe( void ); #define cmatrix3x4 vec4_t *const #define cmatrix4x4 vec4_t *const @@ -699,6 +700,7 @@ extern convar_t *r_lightmap; extern convar_t *r_fastsky; extern convar_t *r_vbo; extern convar_t *r_bump; +extern convar_t *r_strobe; extern convar_t *mp_decals; @@ -709,4 +711,4 @@ extern convar_t *vid_texgamma; extern convar_t *vid_mode; extern convar_t *vid_highdpi; -#endif//GL_LOCAL_H +#endif //GL_LOCAL_H diff --git a/engine/client/gl_rmain.c b/engine/client/gl_rmain.c index d358206c5..f2cb1aba9 100644 --- a/engine/client/gl_rmain.c +++ b/engine/client/gl_rmain.c @@ -31,6 +31,7 @@ const char *r_debug_hitbox; float gldepthmin, gldepthmax; ref_params_t r_lastRefdef; ref_instance_t RI, prevRI; +int sCounter = 0; mleaf_t *r_viewleaf, *r_oldviewleaf; mleaf_t *r_viewleaf2, *r_oldviewleaf2; @@ -1326,6 +1327,79 @@ void R_RenderFrame( const ref_params_t *fd, qboolean drawWorld ) GL_BackendEndFrame(); } +inline static void gl_InsertBlackFrame( void ) +{ + if (CL_IsInConsole()) // No strobing on the console + { + pglEnable(GL_SCISSOR_TEST); + pglScissor(con_rect.x, (-con_rect.y) - (con_rect.h*1.25), con_rect.w, con_rect.h); + pglClearColor(0.0f, 0.0f, 0.0f, 1.0f); + pglClear(GL_COLOR_BUFFER_BIT); + pglDisable(GL_SCISSOR_TEST); + } + else + { + pglClearColor(0.0f, 0.0f, 0.0f, 1.0f); + pglClear(GL_COLOR_BUFFER_BIT); + } +} + +/* +=============== +R_Strobe + +TODO: Consider vsync timings and do not render the supposed black frame at all. +=============== +*/ +void R_Strobe( void ) +{ + int getInterval = r_strobe->integer; // Check through modified tag first? + int swapInterval = gl_swapInterval->integer; + if ( (getInterval == 0) || ((swapInterval == 0) && (getInterval != 0)) ) + { + if (getInterval != 0) //If v-sync is off, turn off strobing + Cvar_Set("r_strobe", "0"); + else if (sCounter != 0) + sCounter = 0; + + // flush any remaining 2D bits + R_Set2DMode(false); + return; + } + + // If interval is positive, insert (replace with) black frames. + // For example result of interval = 3 will be: "black-black-black-normal-black-black-black-normal-black-black-black-normal" + if (getInterval > 0) + { + if (sCounter < getInterval) + { + gl_InsertBlackFrame(); + ++sCounter; + } + else + { + sCounter = 0; + R_Set2DMode(false); + } + } + // If interval is negative, the procedure will be the opposite reverse. + // For example result of interval = -4 will be: "normal-normal-normal-normal-black-normal-normal-normal-normal-black" + else + { + getInterval = abs(getInterval); + if (sCounter < getInterval) + { + ++sCounter; + R_Set2DMode(false); + } + else + { + gl_InsertBlackFrame(); + sCounter = 0; + } + } +} + /* =============== R_EndFrame @@ -1333,8 +1407,9 @@ R_EndFrame */ void R_EndFrame( void ) { - // flush any remaining 2D bits - R_Set2DMode( false ); + if (!CL_IsInMenu()) + R_Strobe(); + #ifdef XASH_SDL SDL_GL_SwapWindow( host.hWnd ); #elif defined __ANDROID__ // For direct android backend diff --git a/engine/client/vid_common.c b/engine/client/vid_common.c index dc7e9ad21..80e3fb277 100644 --- a/engine/client/vid_common.c +++ b/engine/client/vid_common.c @@ -78,6 +78,7 @@ convar_t *r_lightmap; convar_t *r_fastsky; convar_t *r_vbo; convar_t *r_bump; +convar_t *r_strobe; convar_t *mp_decals; convar_t *vid_displayfrequency; @@ -1005,6 +1006,18 @@ static void R_CheckVBO( void ) r_bump = Cvar_Get( "r_bump", def, flags, "enable bump-mapping (r_vbo required)" ); } +/* +=============== +R_initStrobe + +register strobe cvar +=============== +*/ +static inline void R_initStrobe( void ) +{ + r_strobe = Cvar_Get("r_strobe", "0", CVAR_ARCHIVE, "black frame insertion interval"); +} + /* =============== R_Init @@ -1047,6 +1060,7 @@ qboolean R_Init( void ) R_StudioInit(); R_ClearDecals(); R_ClearScene(); + R_initStrobe(); // initialize screen SCR_Init(); diff --git a/engine/common/common.h b/engine/common/common.h index 767d90210..0f31f5925 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -24,6 +24,8 @@ extern "C" { #include "backends.h" #include "defaults.h" +//#include "wrect.h" + // // check if selected backend not allowed // @@ -1075,6 +1077,18 @@ void Con_ClearAutoComplete(); // // console.c // + +//#define SolidConsoleX 0 +//#define SolidConsoleY (y - scr_width->value * 3 / 4) +//#define SolidConsoleW (scr_width->value) +//#define SolidConsoleH (scr_width->value * 3 / 4) +//extern wrect_t con_rect; //Float - Int incompatibility +typedef struct conrect_s +{ + float x, y, w, h; +}conrect_t; +extern conrect_t con_rect; + void Con_Clear( void ); extern const char *svc_strings[256]; From 828393a6784a47542a986496472924e2a38cf115 Mon Sep 17 00:00:00 2001 From: fuzun Date: Sat, 20 Jan 2018 02:27:42 +0300 Subject: [PATCH 2/2] Refactored --- engine/client/cl_scrn.c | 4 ++-- engine/client/console.c | 2 -- engine/client/gl_rmain.c | 14 +++++++++----- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/engine/client/cl_scrn.c b/engine/client/cl_scrn.c index 347013f6c..279d80fb1 100644 --- a/engine/client/cl_scrn.c +++ b/engine/client/cl_scrn.c @@ -59,6 +59,8 @@ void SCR_DrawFPS( void ) double newtime; char fpsstring[64]; int offset; + int strobeInterval = r_strobe->integer; //cvar: r_strobe + int eFPS; //Effective FPS (strobing effect) if( cls.state != ca_active ) return; if( !cl_showfps->integer || cl.background ) return; @@ -101,8 +103,6 @@ void SCR_DrawFPS( void ) /*if( !avgrate ) avgrate = ( maxfps - minfps ) / 2.0f; else */avgrate += ( calc - avgrate ) / host.framecount; - int strobeInterval = r_strobe->integer; - int eFPS; //Effective FPS (strobing effect) if (strobeInterval > 0) { eFPS = (int)((curfps) / (strobeInterval + 1)); diff --git a/engine/client/console.c b/engine/client/console.c index 51615c34c..5a9fe7abb 100644 --- a/engine/client/console.c +++ b/engine/client/console.c @@ -1704,14 +1704,12 @@ void Con_DrawSolidConsole( float frac, qboolean fill ) con_rect.y = y - scr_width->value * 3 / 4; con_rect.w = scr_width->value; con_rect.h = scr_width->value * 3 / 4; - if( fill ) { GL_SetRenderMode( kRenderNormal ); if( con_black->integer ) { pglColor4ub( 0, 0, 0, 255 ); - R_DrawStretchPic( con_rect.x, con_rect.y, con_rect.w, con_rect.h, 0, 0, 1, 1, cls.fillImage ); } else diff --git a/engine/client/gl_rmain.c b/engine/client/gl_rmain.c index f2cb1aba9..67f17b034 100644 --- a/engine/client/gl_rmain.c +++ b/engine/client/gl_rmain.c @@ -31,7 +31,6 @@ const char *r_debug_hitbox; float gldepthmin, gldepthmax; ref_params_t r_lastRefdef; ref_instance_t RI, prevRI; -int sCounter = 0; mleaf_t *r_viewleaf, *r_oldviewleaf; mleaf_t *r_viewleaf2, *r_oldviewleaf2; @@ -1327,12 +1326,12 @@ void R_RenderFrame( const ref_params_t *fd, qboolean drawWorld ) GL_BackendEndFrame(); } -inline static void gl_InsertBlackFrame( void ) +inline static void gl_sBlackFrame( void ) { if (CL_IsInConsole()) // No strobing on the console { pglEnable(GL_SCISSOR_TEST); - pglScissor(con_rect.x, (-con_rect.y) - (con_rect.h*1.25), con_rect.w, con_rect.h); + pglScissor(con_rect.x, (-con_rect.y) - (con_rect.h*1.25), con_rect.w, con_rect.h); // Preview strobe setting on static pglClearColor(0.0f, 0.0f, 0.0f, 1.0f); pglClear(GL_COLOR_BUFFER_BIT); pglDisable(GL_SCISSOR_TEST); @@ -1353,12 +1352,17 @@ TODO: Consider vsync timings and do not render the supposed black frame at all. */ void R_Strobe( void ) { + static int sCounter = 0; int getInterval = r_strobe->integer; // Check through modified tag first? int swapInterval = gl_swapInterval->integer; if ( (getInterval == 0) || ((swapInterval == 0) && (getInterval != 0)) ) { if (getInterval != 0) //If v-sync is off, turn off strobing + { Cvar_Set("r_strobe", "0"); + MsgDev(D_WARN, "Strobing (Black Frame Replacement) requires V-SYNC not being turned off! (gl_swapInterval != 0) \n"); + Msg("Strobing (Black Frame Insertion) requires Vertical Sync to be enabled!\n"); + } else if (sCounter != 0) sCounter = 0; @@ -1373,7 +1377,7 @@ void R_Strobe( void ) { if (sCounter < getInterval) { - gl_InsertBlackFrame(); + gl_sBlackFrame(); ++sCounter; } else @@ -1394,7 +1398,7 @@ void R_Strobe( void ) } else { - gl_InsertBlackFrame(); + gl_sBlackFrame(); sCounter = 0; } }