2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2016-07-15 06:36:34 +00:00
Copyright ( C ) 2012 - 2016 Robert Beckebans
Copyright ( C ) 2014 - 2016 Kot in Action Creative Artel
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition Source Code is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-12-22 15:18:19 +00:00
# include "precompiled.h"
2012-11-26 18:58:24 +00:00
# pragma hdrstop
# include "Common_local.h"
2016-07-06 22:32:44 +00:00
# include "../renderer/Image.h"
2012-12-06 23:09:53 +00:00
// RB begin
# if defined(USE_DOOMCLASSIC)
2019-11-11 19:27:44 +00:00
# include "../../doomclassic/doom/doomlib.h"
# include "../../doomclassic/doom/globaldata.h"
2012-12-06 23:09:53 +00:00
# endif
// RB end
2012-11-26 18:58:24 +00:00
/*
New for tech4x :
Unlike previous SMP work , the actual GPU command drawing is done in the main thread , which avoids the
OpenGL problems with needing windows to be created by the same thread that creates the context , as well
as the issues with passing context ownership back and forth on the 360.
The game tic and the generation of the draw command list is now run in a separate thread , and overlapped
with the interpretation of the previous draw command list .
While the game tic should be nicely contained , the draw command generation winds through the user interface
code , and is potentially hazardous . For now , the overlap will be restricted to the renderer back end ,
which should also be nicely contained .
*/
# define DEFAULT_FIXED_TIC "0"
# define DEFAULT_NO_SLEEP "0"
idCVar com_deltaTimeClamp ( " com_deltaTimeClamp " , " 50 " , CVAR_INTEGER , " don't process more than this time in a single frame " ) ;
idCVar com_fixedTic ( " com_fixedTic " , DEFAULT_FIXED_TIC , CVAR_BOOL , " run a single game frame per render frame " ) ;
idCVar com_noSleep ( " com_noSleep " , DEFAULT_NO_SLEEP , CVAR_BOOL , " don't sleep if the game is running too fast " ) ;
2017-09-10 15:28:27 +00:00
idCVar com_smp ( " com_smp " , " 1 " , CVAR_INTEGER | CVAR_SYSTEM | CVAR_NOCHEAT , " run the game and draw code in a separate thread " ) ;
2012-11-26 18:58:24 +00:00
idCVar com_aviDemoSamples ( " com_aviDemoSamples " , " 16 " , CVAR_SYSTEM , " " ) ;
idCVar com_aviDemoWidth ( " com_aviDemoWidth " , " 256 " , CVAR_SYSTEM , " " ) ;
idCVar com_aviDemoHeight ( " com_aviDemoHeight " , " 256 " , CVAR_SYSTEM , " " ) ;
idCVar com_skipGameDraw ( " com_skipGameDraw " , " 0 " , CVAR_SYSTEM | CVAR_BOOL , " " ) ;
idCVar com_sleepGame ( " com_sleepGame " , " 0 " , CVAR_SYSTEM | CVAR_INTEGER , " intentionally add a sleep in the game time " ) ;
idCVar com_sleepDraw ( " com_sleepDraw " , " 0 " , CVAR_SYSTEM | CVAR_INTEGER , " intentionally add a sleep in the draw time " ) ;
idCVar com_sleepRender ( " com_sleepRender " , " 0 " , CVAR_SYSTEM | CVAR_INTEGER , " intentionally add a sleep in the render time " ) ;
idCVar net_drawDebugHud ( " net_drawDebugHud " , " 0 " , CVAR_SYSTEM | CVAR_INTEGER , " 0 = None, 1 = Hud 1, 2 = Hud 2, 3 = Snapshots " ) ;
idCVar timescale ( " timescale " , " 1 " , CVAR_SYSTEM | CVAR_FLOAT , " Number of game frames to run per render frame " , 0.001f , 100.0f ) ;
extern idCVar in_useJoystick ;
extern idCVar in_joystickRumble ;
/*
= = = = = = = = = = = = = = =
idGameThread : : Run
Run in a background thread for performance , but can also
be called directly in the foreground thread for comparison .
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
int idGameThread : : Run ( )
{
2012-11-26 18:58:24 +00:00
commonLocal . frameTiming . startGameTime = Sys_Microseconds ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// debugging tool to test frame dropping behavior
2012-11-28 15:47:07 +00:00
if ( com_sleepGame . GetInteger ( ) )
{
2012-11-26 18:58:24 +00:00
Sys_Sleep ( com_sleepGame . GetInteger ( ) ) ;
}
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
if ( numGameFrames = = 0 )
{
2012-11-26 18:58:24 +00:00
// Ensure there's no stale gameReturn data from a paused game
ret = gameReturn_t ( ) ;
}
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
if ( isClient )
{
2012-11-26 18:58:24 +00:00
// run the game logic
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < numGameFrames ; i + + )
{
2012-11-26 18:58:24 +00:00
SCOPED_PROFILE_EVENT ( " Client Prediction " ) ;
2012-11-28 15:47:07 +00:00
if ( userCmdMgr )
{
2012-11-26 18:58:24 +00:00
game - > ClientRunFrame ( * userCmdMgr , ( i = = numGameFrames - 1 ) , ret ) ;
}
2012-11-28 15:47:07 +00:00
if ( ret . syncNextGameFrame | | ret . sessionCommand [ 0 ] ! = 0 )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// run the game logic
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < numGameFrames ; i + + )
{
2012-11-26 18:58:24 +00:00
SCOPED_PROFILE_EVENT ( " GameTic " ) ;
2012-11-28 15:47:07 +00:00
if ( userCmdMgr )
{
2012-11-26 18:58:24 +00:00
game - > RunFrame ( * userCmdMgr , ret ) ;
}
2012-11-28 15:47:07 +00:00
if ( ret . syncNextGameFrame | | ret . sessionCommand [ 0 ] ! = 0 )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// we should have consumed all of our usercmds
2012-11-28 15:47:07 +00:00
if ( userCmdMgr )
{
2012-12-06 23:09:53 +00:00
// RB begin
# if defined(USE_DOOMCLASSIC)
2012-11-28 15:47:07 +00:00
if ( userCmdMgr - > HasUserCmdForPlayer ( game - > GetLocalClientNum ( ) ) & & common - > GetCurrentGame ( ) = = DOOM3_BFG )
2012-12-06 23:09:53 +00:00
# else
if ( userCmdMgr - > HasUserCmdForPlayer ( game - > GetLocalClientNum ( ) ) )
# endif
2012-12-08 17:20:13 +00:00
// RB end
2012-11-28 15:47:07 +00:00
{
2012-11-26 18:58:24 +00:00
idLib : : Printf ( " idGameThread::Run: didn't consume all usercmds \n " ) ;
}
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
commonLocal . frameTiming . finishGameTime = Sys_Microseconds ( ) ;
2019-11-11 19:27:44 +00:00
2021-09-28 02:58:32 +00:00
SetThreadGameTime ( commonLocal . frameTiming . finishGameTime - commonLocal . frameTiming . startGameTime ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// build render commands and geometry
{
SCOPED_PROFILE_EVENT ( " Draw " ) ;
commonLocal . Draw ( ) ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
commonLocal . frameTiming . finishDrawTime = Sys_Microseconds ( ) ;
2019-11-11 19:27:44 +00:00
2021-09-28 02:58:32 +00:00
SetThreadRenderTime ( commonLocal . frameTiming . finishDrawTime - commonLocal . frameTiming . finishGameTime ) ;
2019-11-11 19:27:44 +00:00
2021-09-28 02:58:32 +00:00
SetThreadTotalTime ( commonLocal . frameTiming . finishDrawTime - commonLocal . frameTiming . startGameTime ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
return 0 ;
}
/*
= = = = = = = = = = = = = = =
idGameThread : : RunGameAndDraw
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
gameReturn_t idGameThread : : RunGameAndDraw ( int numGameFrames_ , idUserCmdMgr & userCmdMgr_ , bool isClient_ , int startGameFrame )
{
2012-11-26 18:58:24 +00:00
// this should always immediately return
this - > WaitForThread ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// save the usercmds for the background thread to pick up
userCmdMgr = & userCmdMgr_ ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
isClient = isClient_ ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// grab the return value created by the last thread execution
gameReturn_t latchedRet = ret ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
numGameFrames = numGameFrames_ ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// start the thread going
2016-07-06 22:32:44 +00:00
// foresthale 2014-05-12: also check com_editors as many of them are not particularly thread-safe (editLights for example)
2021-04-19 18:31:15 +00:00
if ( com_smp . GetInteger ( ) < = 0 | | com_editors ! = 0 )
2012-11-28 15:47:07 +00:00
{
2012-11-26 18:58:24 +00:00
// run it in the main thread so PIX profiling catches everything
Run ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
this - > SignalWork ( ) ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// return the latched result while the thread runs in the background
return latchedRet ;
}
/*
= = = = = = = = = = = = = = =
idCommonLocal : : DrawWipeModel
Draw the fade material over everything that has been drawn
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCommonLocal : : DrawWipeModel ( )
{
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
if ( wipeStartTime > = wipeStopTime )
{
2012-11-26 18:58:24 +00:00
return ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
int currentTime = Sys_Milliseconds ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
if ( ! wipeHold & & currentTime > wipeStopTime )
{
2012-11-26 18:58:24 +00:00
return ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
float fade = ( float ) ( currentTime - wipeStartTime ) / ( wipeStopTime - wipeStartTime ) ;
renderSystem - > SetColor4 ( 1 , 1 , 1 , fade ) ;
2013-09-21 12:12:42 +00:00
renderSystem - > DrawStretchPic ( 0 , 0 , renderSystem - > GetVirtualWidth ( ) , renderSystem - > GetVirtualHeight ( ) , 0 , 0 , 1 , 1 , wipeMaterial ) ;
2012-11-26 18:58:24 +00:00
}
/*
= = = = = = = = = = = = = = =
idCommonLocal : : Draw
= = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCommonLocal : : Draw ( )
{
2012-11-26 18:58:24 +00:00
// debugging tool to test frame dropping behavior
2012-11-28 15:47:07 +00:00
if ( com_sleepDraw . GetInteger ( ) )
{
2012-11-26 18:58:24 +00:00
Sys_Sleep ( com_sleepDraw . GetInteger ( ) ) ;
}
2019-11-11 19:27:44 +00:00
2016-07-06 22:32:44 +00:00
if ( loadPacifierBinarizeActive )
2012-11-28 15:47:07 +00:00
{
2016-07-06 22:32:44 +00:00
// foresthale 2014-05-30: when binarizing an asset we show a special
// overlay indicating progress
renderSystem - > SetColor ( colorBlack ) ;
2021-02-26 18:26:52 +00:00
renderSystem - > DrawStretchPic ( 0 , 0 , renderSystem - > GetVirtualWidth ( ) , renderSystem - > GetVirtualHeight ( ) , 0 , 0 , 1 , 1 , whiteMaterial ) ;
2019-11-11 19:27:44 +00:00
2016-07-06 22:32:44 +00:00
// render the loading gui (idSWF actually) if it is loaded
// (we want to see progress of the loading gui binarize too)
if ( loadGUI ! = NULL )
2019-11-11 19:27:44 +00:00
{
2016-07-06 22:32:44 +00:00
loadGUI - > Render ( renderSystem , Sys_Milliseconds ( ) ) ;
2019-11-11 19:27:44 +00:00
}
2016-07-06 22:32:44 +00:00
// update our progress estimates
int time = Sys_Milliseconds ( ) ;
if ( loadPacifierBinarizeProgress > 0.0f )
2019-11-11 19:27:44 +00:00
{
2016-07-06 22:32:44 +00:00
loadPacifierBinarizeTimeLeft = ( 1.0 - loadPacifierBinarizeProgress ) * ( time - loadPacifierBinarizeStartTime ) * 0.001f / loadPacifierBinarizeProgress ;
2019-11-11 19:27:44 +00:00
}
2016-07-06 22:32:44 +00:00
else
2019-11-11 19:27:44 +00:00
{
2016-07-06 22:32:44 +00:00
loadPacifierBinarizeTimeLeft = - 1.0f ;
2019-11-11 19:27:44 +00:00
}
2016-07-06 22:32:44 +00:00
// prepare our strings
const char * text ;
if ( loadPacifierBinarizeTimeLeft > = 99.5f )
2019-11-11 19:27:44 +00:00
{
2016-07-06 22:32:44 +00:00
text = va ( " Binarizing %3.0f%% ETA %2.0f minutes " , loadPacifierBinarizeProgress * 100.0f , loadPacifierBinarizeTimeLeft / 60.0f ) ;
2019-11-11 19:27:44 +00:00
}
2016-07-06 22:32:44 +00:00
else if ( loadPacifierBinarizeTimeLeft )
2019-11-11 19:27:44 +00:00
{
2016-07-06 22:32:44 +00:00
text = va ( " Binarizing %3.0f%% ETA %2.0f seconds " , loadPacifierBinarizeProgress * 100.0f , loadPacifierBinarizeTimeLeft ) ;
2019-11-11 19:27:44 +00:00
}
2016-07-06 22:32:44 +00:00
else
2019-11-11 19:27:44 +00:00
{
2016-07-06 22:32:44 +00:00
text = va ( " Binarizing %3.0f%% " , loadPacifierBinarizeProgress * 100.0f ) ;
2019-11-11 19:27:44 +00:00
}
2016-07-06 22:32:44 +00:00
// draw our basic overlay
renderSystem - > SetColor ( idVec4 ( 0.0f , 0.0f , 0.5f , 1.0f ) ) ;
2021-02-26 18:26:52 +00:00
renderSystem - > DrawStretchPic ( 0 , renderSystem - > GetVirtualHeight ( ) - 48 , renderSystem - > GetVirtualWidth ( ) , 48 , 0 , 0 , 1 , 1 , whiteMaterial ) ;
2016-07-06 22:32:44 +00:00
renderSystem - > SetColor ( idVec4 ( 0.0f , 0.5f , 0.8f , 1.0f ) ) ;
2021-02-26 18:26:52 +00:00
renderSystem - > DrawStretchPic ( 0 , renderSystem - > GetVirtualHeight ( ) - 48 , loadPacifierBinarizeProgress * renderSystem - > GetVirtualWidth ( ) , 32 , 0 , 0 , 1 , 1 , whiteMaterial ) ;
renderSystem - > DrawSmallStringExt ( 0 , renderSystem - > GetVirtualHeight ( ) - 48 , loadPacifierBinarizeFilename . c_str ( ) , idVec4 ( 1.0f , 1.0f , 1.0f , 1.0f ) , true ) ;
renderSystem - > DrawSmallStringExt ( 0 , renderSystem - > GetVirtualHeight ( ) - 32 , va ( " %s %d/%d lvls " , loadPacifierBinarizeInfo . c_str ( ) , loadPacifierBinarizeMiplevel , loadPacifierBinarizeMiplevelTotal ) , idVec4 ( 1.0f , 1.0f , 1.0f , 1.0f ) , true ) ;
renderSystem - > DrawSmallStringExt ( 0 , renderSystem - > GetVirtualHeight ( ) - 16 , text , idVec4 ( 1.0f , 1.0f , 1.0f , 1.0f ) , true ) ;
2016-07-06 22:32:44 +00:00
}
else if ( loadGUI ! = NULL )
{
// foresthale 2014-05-30: showing a black background looks better than flickering in widescreen
renderSystem - > SetColor ( colorBlack ) ;
2021-02-26 18:26:52 +00:00
renderSystem - > DrawStretchPic ( 0 , 0 , renderSystem - > GetVirtualWidth ( ) , renderSystem - > GetVirtualHeight ( ) , 0 , 0 , 1 , 1 , whiteMaterial ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
loadGUI - > Render ( renderSystem , Sys_Milliseconds ( ) ) ;
2012-11-28 15:47:07 +00:00
}
2012-12-06 23:09:53 +00:00
// RB begin
# if defined(USE_DOOMCLASSIC)
2012-11-28 15:47:07 +00:00
else if ( currentGame = = DOOM_CLASSIC | | currentGame = = DOOM2_CLASSIC )
{
2012-11-26 18:58:24 +00:00
const float sysWidth = renderSystem - > GetWidth ( ) * renderSystem - > GetPixelAspect ( ) ;
const float sysHeight = renderSystem - > GetHeight ( ) ;
const float sysAspect = sysWidth / sysHeight ;
const float doomAspect = 4.0f / 3.0f ;
const float adjustment = sysAspect / doomAspect ;
2013-09-21 12:12:42 +00:00
const float barHeight = ( adjustment > = 1.0f ) ? 0.0f : ( 1.0f - adjustment ) * ( float ) renderSystem - > GetVirtualHeight ( ) * 0.25f ;
const float barWidth = ( adjustment < = 1.0f ) ? 0.0f : ( adjustment - 1.0f ) * ( float ) renderSystem - > GetVirtualWidth ( ) * 0.25f ;
2012-11-28 15:47:07 +00:00
if ( barHeight > 0.0f )
{
2012-11-26 18:58:24 +00:00
renderSystem - > SetColor ( colorBlack ) ;
2013-09-21 12:12:42 +00:00
renderSystem - > DrawStretchPic ( 0 , 0 , renderSystem - > GetVirtualWidth ( ) , barHeight , 0 , 0 , 1 , 1 , whiteMaterial ) ;
renderSystem - > DrawStretchPic ( 0 , renderSystem - > GetVirtualHeight ( ) - barHeight , renderSystem - > GetVirtualWidth ( ) , barHeight , 0 , 0 , 1 , 1 , whiteMaterial ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
if ( barWidth > 0.0f )
{
2012-11-26 18:58:24 +00:00
renderSystem - > SetColor ( colorBlack ) ;
2013-09-21 12:12:42 +00:00
renderSystem - > DrawStretchPic ( 0 , 0 , barWidth , renderSystem - > GetVirtualHeight ( ) , 0 , 0 , 1 , 1 , whiteMaterial ) ;
renderSystem - > DrawStretchPic ( renderSystem - > GetVirtualWidth ( ) - barWidth , 0 , barWidth , renderSystem - > GetVirtualHeight ( ) , 0 , 0 , 1 , 1 , whiteMaterial ) ;
2012-11-26 18:58:24 +00:00
}
renderSystem - > SetColor4 ( 1 , 1 , 1 , 1 ) ;
2013-09-21 12:12:42 +00:00
renderSystem - > DrawStretchPic ( barWidth , barHeight , renderSystem - > GetVirtualWidth ( ) - barWidth * 2.0f , renderSystem - > GetVirtualHeight ( ) - barHeight * 2.0f , 0 , 0 , 1 , 1 , doomClassicMaterial ) ;
2012-11-28 15:47:07 +00:00
}
2012-12-06 23:09:53 +00:00
# endif
// RB end
2012-11-28 15:47:07 +00:00
else if ( game & & game - > Shell_IsActive ( ) )
{
2012-11-26 18:58:24 +00:00
bool gameDraw = game - > Draw ( game - > GetLocalClientNum ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( ! gameDraw )
{
2012-11-26 18:58:24 +00:00
renderSystem - > SetColor ( colorBlack ) ;
2013-09-21 12:12:42 +00:00
renderSystem - > DrawStretchPic ( 0 , 0 , renderSystem - > GetVirtualWidth ( ) , renderSystem - > GetVirtualHeight ( ) , 0 , 0 , 1 , 1 , whiteMaterial ) ;
2012-11-26 18:58:24 +00:00
}
game - > Shell_Render ( ) ;
2012-11-28 15:47:07 +00:00
}
else if ( readDemo )
{
2021-04-29 13:20:45 +00:00
// SRS - Advance demo inside Frame() instead of Draw() to support smp mode playback
// AdvanceRenderDemo( true );
2012-11-26 18:58:24 +00:00
renderWorld - > RenderScene ( & currentDemoRenderView ) ;
renderSystem - > DrawDemoPics ( ) ;
2012-11-28 15:47:07 +00:00
}
else if ( mapSpawned )
{
2012-11-26 18:58:24 +00:00
bool gameDraw = false ;
// normal drawing for both single and multi player
2012-11-28 15:47:07 +00:00
if ( ! com_skipGameDraw . GetBool ( ) & & Game ( ) - > GetLocalClientNum ( ) > = 0 )
{
2012-11-26 18:58:24 +00:00
// draw the game view
int start = Sys_Milliseconds ( ) ;
2012-11-28 15:47:07 +00:00
if ( game )
{
2012-11-26 18:58:24 +00:00
gameDraw = game - > Draw ( Game ( ) - > GetLocalClientNum ( ) ) ;
}
int end = Sys_Milliseconds ( ) ;
time_gameDraw + = ( end - start ) ; // note time used for com_speeds
}
2012-11-28 15:47:07 +00:00
if ( ! gameDraw )
{
2012-11-26 18:58:24 +00:00
renderSystem - > SetColor ( colorBlack ) ;
2013-09-21 12:12:42 +00:00
renderSystem - > DrawStretchPic ( 0 , 0 , renderSystem - > GetVirtualWidth ( ) , renderSystem - > GetVirtualHeight ( ) , 0 , 0 , 1 , 1 , whiteMaterial ) ;
2012-11-26 18:58:24 +00:00
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// save off the 2D drawing from the game
2012-11-28 15:47:07 +00:00
if ( writeDemo )
{
2012-11-26 18:58:24 +00:00
renderSystem - > WriteDemoPics ( ) ;
2016-07-15 06:36:34 +00:00
renderSystem - > WriteEndFrame ( ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
renderSystem - > SetColor4 ( 0 , 0 , 0 , 1 ) ;
2013-09-21 12:12:42 +00:00
renderSystem - > DrawStretchPic ( 0 , 0 , renderSystem - > GetVirtualWidth ( ) , renderSystem - > GetVirtualHeight ( ) , 0 , 0 , 1 , 1 , whiteMaterial ) ;
2012-11-26 18:58:24 +00:00
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
{
SCOPED_PROFILE_EVENT ( " Post-Draw " ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// draw the wipe material on top of this if it hasn't completed yet
DrawWipeModel ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
Dialog ( ) . Render ( loadGUI ! = NULL ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// draw the half console / notify console on top of everything
console - > Draw ( false ) ;
}
}
/*
= = = = = = = = = = = = = = =
idCommonLocal : : UpdateScreen
This is an out - of - sequence screen update , not the normal game rendering
= = = = = = = = = = = = = = =
*/
2012-12-23 05:21:01 +00:00
// DG: added possibility to *not* release mouse in UpdateScreen(), it fucks up the view angle for screenshots
void idCommonLocal : : UpdateScreen ( bool captureToImage , bool releaseMouse )
2012-11-28 15:47:07 +00:00
{
if ( insideUpdateScreen )
{
2012-11-26 18:58:24 +00:00
return ;
}
insideUpdateScreen = true ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// make sure the game / draw thread has completed
gameThread . WaitForThread ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// release the mouse capture back to the desktop
2012-12-23 05:21:01 +00:00
if ( releaseMouse )
2019-11-11 19:27:44 +00:00
{
2012-12-23 05:21:01 +00:00
Sys_GrabMouseCursor ( false ) ;
2019-11-11 19:27:44 +00:00
}
2012-12-23 05:21:01 +00:00
// DG end
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// build all the draw commands without running a new game tic
Draw ( ) ;
2019-11-11 19:27:44 +00:00
2016-07-06 22:32:44 +00:00
// foresthale 2014-03-01: note: the only place that has captureToImage=true is idAutoRender::StartBackgroundAutoSwaps
2012-11-28 15:47:07 +00:00
if ( captureToImage )
{
2012-11-26 18:58:24 +00:00
renderSystem - > CaptureRenderToImage ( " _currentRender " , false ) ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// this should exit right after vsync, with the GPU idle and ready to draw
2020-03-29 15:12:11 +00:00
const emptyCommand_t * cmd = renderSystem - > SwapCommandBuffers ( & time_frontend , & time_backend , & time_shadows , & time_gpu , & stats_backend , & stats_frontend ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// get the GPU busy with new commands
renderSystem - > RenderCommandBuffers ( cmd ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
insideUpdateScreen = false ;
}
/*
= = = = = = = = = = = = = = = =
idCommonLocal : : ProcessGameReturn
= = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCommonLocal : : ProcessGameReturn ( const gameReturn_t & ret )
{
2012-11-26 18:58:24 +00:00
// set joystick rumble
2012-11-28 15:47:07 +00:00
if ( in_useJoystick . GetBool ( ) & & in_joystickRumble . GetBool ( ) & & ! game - > Shell_IsActive ( ) & & session - > GetSignInManager ( ) . GetMasterInputDevice ( ) > = 0 )
{
2012-11-26 18:58:24 +00:00
Sys_SetRumble ( session - > GetSignInManager ( ) . GetMasterInputDevice ( ) , ret . vibrationLow , ret . vibrationHigh ) ; // Only set the rumble on the active controller
2012-11-28 15:47:07 +00:00
}
else
{
for ( int i = 0 ; i < MAX_INPUT_DEVICES ; i + + )
{
2012-11-26 18:58:24 +00:00
Sys_SetRumble ( i , 0 , 0 ) ;
}
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
syncNextGameFrame = ret . syncNextGameFrame ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
if ( ret . sessionCommand [ 0 ] )
{
2012-11-26 18:58:24 +00:00
idCmdArgs args ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
args . TokenizeString ( ret . sessionCommand , false ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
if ( ! idStr : : Icmp ( args . Argv ( 0 ) , " map " ) )
{
2012-11-26 18:58:24 +00:00
MoveToNewMap ( args . Argv ( 1 ) , false ) ;
2012-11-28 15:47:07 +00:00
}
else if ( ! idStr : : Icmp ( args . Argv ( 0 ) , " devmap " ) )
{
2012-11-26 18:58:24 +00:00
MoveToNewMap ( args . Argv ( 1 ) , true ) ;
2012-11-28 15:47:07 +00:00
}
else if ( ! idStr : : Icmp ( args . Argv ( 0 ) , " died " ) )
{
if ( ! IsMultiplayer ( ) )
{
2012-11-26 18:58:24 +00:00
game - > Shell_Show ( true ) ;
}
2012-11-28 15:47:07 +00:00
}
else if ( ! idStr : : Icmp ( args . Argv ( 0 ) , " disconnect " ) )
{
2012-11-26 18:58:24 +00:00
cmdSystem - > BufferCommandText ( CMD_EXEC_INSERT , " stoprecording ; disconnect " ) ;
2012-11-28 15:47:07 +00:00
}
else if ( ! idStr : : Icmp ( args . Argv ( 0 ) , " endOfDemo " ) )
{
2012-11-26 18:58:24 +00:00
cmdSystem - > BufferCommandText ( CMD_EXEC_NOW , " endOfDemo " ) ;
}
}
}
extern idCVar com_forceGenericSIMD ;
2013-01-03 11:39:16 +00:00
extern idCVar com_pause ;
2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = =
idCommonLocal : : Frame
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCommonLocal : : Frame ( )
{
try
{
2012-11-26 18:58:24 +00:00
SCOPED_PROFILE_EVENT ( " Common::Frame " ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// This is the only place this is incremented
idLib : : frameNumber + + ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// allow changing SIMD usage on the fly
2012-11-28 15:47:07 +00:00
if ( com_forceGenericSIMD . IsModified ( ) )
{
2012-11-26 18:58:24 +00:00
idSIMD : : InitProcessor ( " doom " , com_forceGenericSIMD . GetBool ( ) ) ;
com_forceGenericSIMD . ClearModified ( ) ;
}
2019-11-11 19:27:44 +00:00
2012-12-06 23:09:53 +00:00
// RB begin
# if defined(USE_DOOMCLASSIC)
2012-11-26 18:58:24 +00:00
// Do the actual switch between Doom 3 and the classics here so
// that things don't get confused in the middle of the frame.
PerformGameSwitch ( ) ;
2012-12-06 23:09:53 +00:00
# endif
// RB end
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// pump all the events
Sys_GenerateEvents ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// write config file if anything changed
2012-11-28 15:47:07 +00:00
WriteConfiguration ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
eventLoop - > RunEventLoop ( ) ;
2019-11-11 19:27:44 +00:00
2016-07-06 22:32:44 +00:00
renderSystem - > OnFrame ( ) ;
2019-11-11 19:27:44 +00:00
2016-02-07 16:19:07 +00:00
// DG: prepare new ImGui frame - I guess this is a good place, as all new events should be available?
ImGuiHook : : NewFrame ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// Activate the shell if it's been requested
2012-11-28 15:47:07 +00:00
if ( showShellRequested & & game )
{
2012-11-26 18:58:24 +00:00
game - > Shell_Show ( true ) ;
showShellRequested = false ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// if the console or another gui is down, we don't need to hold the mouse cursor
bool chatting = false ;
2019-11-11 19:27:44 +00:00
2013-01-03 11:39:16 +00:00
// DG: Add pause from com_pause cvar
2012-12-06 23:09:53 +00:00
// RB begin
# if defined(USE_DOOMCLASSIC)
2013-01-05 15:42:24 +00:00
if ( com_pause . GetInteger ( ) | | console - > Active ( ) | | Dialog ( ) . IsDialogActive ( ) | | session - > IsSystemUIShowing ( )
2016-02-08 15:40:00 +00:00
| | ( game & & game - > InhibitControls ( ) & & ! IsPlayingDoomClassic ( ) ) | | ImGuiTools : : ReleaseMouseForTools ( ) )
2012-12-06 23:09:53 +00:00
# else
2013-01-03 11:39:16 +00:00
if ( com_pause . GetInteger ( ) | | console - > Active ( ) | | Dialog ( ) . IsDialogActive ( ) | | session - > IsSystemUIShowing ( )
2021-02-20 11:03:11 +00:00
| | ( game & & game - > InhibitControls ( ) ) | | ImGuiTools : : ReleaseMouseForTools ( ) )
2012-12-06 23:09:53 +00:00
# endif
2013-01-03 11:39:16 +00:00
// RB end, DG end
2012-11-28 15:47:07 +00:00
{
2014-05-20 21:50:53 +00:00
// RB: don't release the mouse when opening a PDA or menu
2021-06-14 01:10:47 +00:00
// SRS - but always release at main menu after exiting game or demo
if ( console - > Active ( ) | | ! mapSpawned | | ImGuiTools : : ReleaseMouseForTools ( ) )
2014-05-20 21:33:57 +00:00
{
Sys_GrabMouseCursor ( false ) ;
}
2012-11-26 18:58:24 +00:00
usercmdGen - > InhibitUsercmd ( INHIBIT_SESSION , true ) ;
chatting = true ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
Sys_GrabMouseCursor ( true ) ;
usercmdGen - > InhibitUsercmd ( INHIBIT_SESSION , false ) ;
}
2019-11-11 19:27:44 +00:00
2012-12-06 23:09:53 +00:00
// RB begin
# if defined(USE_DOOMCLASSIC)
2013-01-03 11:39:16 +00:00
const bool pauseGame = ( ! mapSpawned
| | ( ! IsMultiplayer ( )
& & ( Dialog ( ) . IsDialogPausing ( ) | | session - > IsSystemUIShowing ( )
| | ( game & & game - > Shell_IsActive ( ) ) | | com_pause . GetInteger ( ) ) ) )
& & ! IsPlayingDoomClassic ( ) ;
2012-12-06 23:09:53 +00:00
# else
2013-01-03 11:39:16 +00:00
const bool pauseGame = ( ! mapSpawned
| | ( ! IsMultiplayer ( )
& & ( Dialog ( ) . IsDialogPausing ( ) | | session - > IsSystemUIShowing ( )
| | ( game & & game - > Shell_IsActive ( ) ) | | com_pause . GetInteger ( ) ) ) ) ;
2012-12-06 23:09:53 +00:00
# endif
// RB end
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// save the screenshot and audio from the last draw if needed
2012-11-28 15:47:07 +00:00
if ( aviCaptureMode )
{
2014-08-25 13:25:54 +00:00
idStr name ;
name . Format ( " demos/%s/%s_%05i " , aviDemoShortName . c_str ( ) , aviDemoShortName . c_str ( ) , aviDemoFrameCount + + ) ;
2014-08-19 09:35:50 +00:00
renderSystem - > TakeScreenshot ( com_aviDemoWidth . GetInteger ( ) , com_aviDemoHeight . GetInteger ( ) , name , com_aviDemoSamples . GetInteger ( ) , NULL , TGA ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// remove any printed lines at the top before taking the screenshot
console - > ClearNotifyLines ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// this will call Draw, possibly multiple times if com_aviDemoSamples is > 1
2014-08-19 09:35:50 +00:00
renderSystem - > TakeScreenshot ( com_aviDemoWidth . GetInteger ( ) , com_aviDemoHeight . GetInteger ( ) , name , com_aviDemoSamples . GetInteger ( ) , NULL , TGA ) ;
2012-11-26 18:58:24 +00:00
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
//--------------------------------------------
// wait for the GPU to finish drawing
//
// It is imporant to minimize the time spent between this
// section and the call to renderSystem->RenderCommandBuffers(),
// because the GPU is completely idle.
//--------------------------------------------
// this should exit right after vsync, with the GPU idle and ready to draw
// This may block if the GPU isn't finished renderng the previous frame.
frameTiming . startSyncTime = Sys_Microseconds ( ) ;
2012-11-28 15:47:07 +00:00
const emptyCommand_t * renderCommands = NULL ;
2019-11-11 19:27:44 +00:00
2016-07-06 22:32:44 +00:00
// foresthale 2014-05-12: also check com_editors as many of them are not particularly thread-safe (editLights for example)
if ( com_smp . GetInteger ( ) > 0 & & com_editors = = 0 )
2012-11-28 15:47:07 +00:00
{
2020-03-29 15:12:11 +00:00
renderCommands = renderSystem - > SwapCommandBuffers ( & time_frontend , & time_backend , & time_shadows , & time_gpu , & stats_backend , & stats_frontend ) ;
2012-11-28 15:47:07 +00:00
}
2017-09-10 15:28:27 +00:00
else if ( com_smp . GetInteger ( ) < 0 )
{
// RB: this is the same as Doom 3 renderSystem->BeginFrame()
renderCommands = renderSystem - > SwapCommandBuffers_FinishCommandBuffers ( ) ;
}
2012-11-28 15:47:07 +00:00
else
{
2012-11-26 18:58:24 +00:00
// the GPU will stay idle through command generation for minimal
// input latency
2020-03-29 15:12:11 +00:00
renderSystem - > SwapCommandBuffers_FinishRendering ( & time_frontend , & time_backend , & time_shadows , & time_gpu , & stats_backend , & stats_frontend ) ;
2012-11-26 18:58:24 +00:00
}
frameTiming . finishSyncTime = Sys_Microseconds ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
//--------------------------------------------
// Determine how many game tics we are going to run,
// now that the previous frame is completely finished.
//
// It is important that any waiting on the GPU be done
// before this, or there will be a bad stuttering when
// dropping frames for performance management.
//--------------------------------------------
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// input:
// thisFrameTime
// com_noSleep
// com_engineHz
// com_fixedTic
// com_deltaTimeClamp
// IsMultiplayer
//
// in/out state:
// gameFrame
// gameTimeResidual
// lastFrameTime
// syncNextFrame
//
// Output:
// numGameFrames
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// How many game frames to run
int numGameFrames = 0 ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
for ( ; ; )
{
2012-11-26 18:58:24 +00:00
const int thisFrameTime = Sys_Milliseconds ( ) ;
static int lastFrameTime = thisFrameTime ; // initialized only the first time
const int deltaMilliseconds = thisFrameTime - lastFrameTime ;
lastFrameTime = thisFrameTime ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// if there was a large gap in time since the last frame, or the frame
// rate is very very low, limit the number of frames we will run
const int clampedDeltaMilliseconds = Min ( deltaMilliseconds , com_deltaTimeClamp . GetInteger ( ) ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
gameTimeResidual + = clampedDeltaMilliseconds * timescale . GetFloat ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// don't run any frames when paused
2016-07-16 01:24:06 +00:00
// jpcy: the game is paused when playing a demo, but playDemo should wait like the game does
2021-04-29 13:20:45 +00:00
// SRS - don't wait if window not in focus and playDemo itself paused
2021-04-19 18:31:15 +00:00
if ( pauseGame & & ( ! ( readDemo & & ! timeDemo ) | | session - > IsSystemUIShowing ( ) | | com_pause . GetInteger ( ) ) )
2012-11-28 15:47:07 +00:00
{
2012-11-26 18:58:24 +00:00
gameFrame + + ;
gameTimeResidual = 0 ;
break ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// debug cvar to force multiple game tics
2012-11-28 15:47:07 +00:00
if ( com_fixedTic . GetInteger ( ) > 0 )
{
2012-11-26 18:58:24 +00:00
numGameFrames = com_fixedTic . GetInteger ( ) ;
gameFrame + = numGameFrames ;
gameTimeResidual = 0 ;
break ;
}
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
if ( syncNextGameFrame )
{
2012-11-26 18:58:24 +00:00
// don't sleep at all
syncNextGameFrame = false ;
gameFrame + + ;
numGameFrames + + ;
gameTimeResidual = 0 ;
break ;
}
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
for ( ; ; )
{
2012-11-26 18:58:24 +00:00
// How much time to wait before running the next frame,
// based on com_engineHz
const int frameDelay = FRAME_TO_MSEC ( gameFrame + 1 ) - FRAME_TO_MSEC ( gameFrame ) ;
2012-11-28 15:47:07 +00:00
if ( gameTimeResidual < frameDelay )
{
2012-11-26 18:58:24 +00:00
break ;
}
gameTimeResidual - = frameDelay ;
gameFrame + + ;
numGameFrames + + ;
// if there is enough residual left, we may run additional frames
}
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
if ( numGameFrames > 0 )
{
2012-11-26 18:58:24 +00:00
// ready to actually run them
break ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// if we are vsyncing, we always want to run at least one game
// frame and never sleep, which might happen due to scheduling issues
// if we were just looking at real time.
2012-11-28 15:47:07 +00:00
if ( com_noSleep . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
numGameFrames = 1 ;
gameFrame + = numGameFrames ;
gameTimeResidual = 0 ;
break ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// not enough time has passed to run a frame, as might happen if
// we don't have vsync on, or the monitor is running at 120hz while
// com_engineHz is 60, so sleep a bit and check again
Sys_Sleep ( 0 ) ;
}
2019-11-11 19:27:44 +00:00
2016-07-16 01:24:06 +00:00
// jpcy: playDemo uses the game frame wait logic, but shouldn't run any game frames
if ( readDemo & & ! timeDemo )
2019-11-11 19:27:44 +00:00
{
2016-07-16 01:24:06 +00:00
numGameFrames = 0 ;
2019-11-11 19:27:44 +00:00
}
2012-11-26 18:58:24 +00:00
//--------------------------------------------
// It would be better to push as much of this as possible
// either before or after the renderSystem->SwapCommandBuffers(),
// because the GPU is completely idle.
//--------------------------------------------
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// Update session and syncronize to the new session state after sleeping
session - > UpdateSignInManager ( ) ;
session - > Pump ( ) ;
session - > ProcessSnapAckQueue ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
if ( session - > GetState ( ) = = idSession : : LOADING )
{
2012-11-26 18:58:24 +00:00
// If the session reports we should be loading a map, load it!
ExecuteMapChange ( ) ;
mapSpawnData . savegameFile = NULL ;
mapSpawnData . persistentPlayerInfo . Clear ( ) ;
2021-04-29 13:20:45 +00:00
// SRS - If in Doom 3 mode (com_smp = -1) on map change, must obey fence before returning to avoid command buffer sync issues
if ( com_smp . GetInteger ( ) < 0 )
{
renderSystem - > SwapCommandBuffers_FinishRendering ( & time_frontend , & time_backend , & time_shadows , & time_gpu , & stats_backend , & stats_frontend ) ;
}
2012-11-26 18:58:24 +00:00
return ;
2012-11-28 15:47:07 +00:00
}
else if ( session - > GetState ( ) ! = idSession : : INGAME & & mapSpawned )
{
2012-11-26 18:58:24 +00:00
// If the game is running, but the session reports we are not in a game, disconnect
// This happens when a server disconnects us or we sign out
LeaveGame ( ) ;
return ;
}
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
if ( mapSpawned & & ! pauseGame )
{
if ( IsClient ( ) )
{
2012-11-26 18:58:24 +00:00
RunNetworkSnapshotFrame ( ) ;
}
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
ExecuteReliableMessages ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// send frame and mouse events to active guis
GuiFrameEvents ( ) ;
2021-04-29 13:20:45 +00:00
// SRS - Advance demos inside Frame() vs. Draw() to support smp mode playback
// SRS - Pause playDemo (but not timeDemo) when window not in focus
if ( readDemo & & ( ! ( session - > IsSystemUIShowing ( ) | | com_pause . GetInteger ( ) ) | | timeDemo ) )
{
AdvanceRenderDemo ( true ) ;
if ( ! readDemo )
{
// SRS - Important to return after demo playback is finished to avoid command buffer sync issues
return ;
}
}
2012-11-26 18:58:24 +00:00
//--------------------------------------------
// Prepare usercmds and kick off the game processing
// in a background thread
//--------------------------------------------
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// get the previous usercmd for bypassed head tracking transform
const usercmd_t previousCmd = usercmdGen - > GetCurrentUsercmd ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// build a new usercmd
int deviceNum = session - > GetSignInManager ( ) . GetMasterInputDevice ( ) ;
usercmdGen - > BuildCurrentUsercmd ( deviceNum ) ;
2012-11-28 15:47:07 +00:00
if ( deviceNum = = - 1 )
{
for ( int i = 0 ; i < MAX_INPUT_DEVICES ; i + + )
{
2012-11-26 18:58:24 +00:00
Sys_PollJoystickInputEvents ( i ) ;
Sys_EndJoystickInputEvents ( ) ;
}
}
2012-11-28 15:47:07 +00:00
if ( pauseGame )
{
2012-11-26 18:58:24 +00:00
usercmdGen - > Clear ( ) ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
usercmd_t newCmd = usercmdGen - > GetCurrentUsercmd ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// Store server game time - don't let time go past last SS time in case we are extrapolating
2012-11-28 15:47:07 +00:00
if ( IsClient ( ) )
{
2012-11-26 18:58:24 +00:00
newCmd . serverGameMilliseconds = std : : min ( Game ( ) - > GetServerGameTimeMs ( ) , Game ( ) - > GetSSEndTime ( ) ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
newCmd . serverGameMilliseconds = Game ( ) - > GetServerGameTimeMs ( ) ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
userCmdMgr . MakeReadPtrCurrentForPlayer ( Game ( ) - > GetLocalClientNum ( ) ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// Stuff a copy of this userCmd for each game frame we are going to run.
// Ideally, the usercmds would be built in another thread so you could
// still get 60hz control accuracy when the game is running slower.
2012-11-28 15:47:07 +00:00
for ( int i = 0 ; i < numGameFrames ; i + + )
{
newCmd . clientGameMilliseconds = FRAME_TO_MSEC ( gameFrame - numGameFrames + i + 1 ) ;
2012-11-26 18:58:24 +00:00
userCmdMgr . PutUserCmdForPlayer ( game - > GetLocalClientNum ( ) , newCmd ) ;
}
2019-11-11 19:27:44 +00:00
2012-12-06 23:09:53 +00:00
// RB begin
# if defined(USE_DOOMCLASSIC)
2012-11-26 18:58:24 +00:00
// If we're in Doom or Doom 2, run tics and upload the new texture.
2021-04-29 13:20:45 +00:00
// SRS - Add check for com_pause cvar to make sure window is in focus - if not classic game should be paused (FIXME: but classic music still plays in background)
2021-04-19 18:31:15 +00:00
if ( ( GetCurrentGame ( ) = = DOOM_CLASSIC | | GetCurrentGame ( ) = = DOOM2_CLASSIC ) & & ! ( Dialog ( ) . IsDialogPausing ( ) | | session - > IsSystemUIShowing ( ) | | com_pause . GetInteger ( ) ) )
2012-11-28 15:47:07 +00:00
{
2012-11-26 18:58:24 +00:00
RunDoomClassicFrame ( ) ;
}
2012-12-06 23:09:53 +00:00
# endif
// RB end
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// start the game / draw command generation thread going in the background
gameReturn_t ret = gameThread . RunGameAndDraw ( numGameFrames , userCmdMgr , IsClient ( ) , gameFrame - numGameFrames ) ;
2019-11-11 19:27:44 +00:00
2016-07-06 22:32:44 +00:00
// foresthale 2014-05-12: also check com_editors as many of them are not particularly thread-safe (editLights for example)
2021-05-20 06:10:50 +00:00
// SRS - if com_editors is active make sure com_smp != -1, otherwise skip and call SwapCommandBuffers_FinishRendering later
2021-09-28 07:58:48 +00:00
frameTiming . startRenderTime = Sys_Microseconds ( ) ;
2021-05-06 16:21:12 +00:00
if ( com_smp . GetInteger ( ) = = 0 | | ( com_smp . GetInteger ( ) > 0 & & com_editors ! = 0 ) )
2012-11-28 15:47:07 +00:00
{
2012-11-26 18:58:24 +00:00
// in non-smp mode, run the commands we just generated, instead of
// frame-delayed ones from a background thread
renderCommands = renderSystem - > SwapCommandBuffers_FinishCommandBuffers ( ) ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
//----------------------------------------
// Run the render back end, getting the GPU busy with new commands
// ASAP to minimize the pipeline bubble.
//----------------------------------------
renderSystem - > RenderCommandBuffers ( renderCommands ) ;
2012-11-28 15:47:07 +00:00
if ( com_sleepRender . GetInteger ( ) > 0 )
{
2012-11-26 18:58:24 +00:00
// debug tool to test frame adaption
Sys_Sleep ( com_sleepRender . GetInteger ( ) ) ;
}
frameTiming . finishRenderTime = Sys_Microseconds ( ) ;
2019-11-11 19:27:44 +00:00
2021-04-29 13:20:45 +00:00
// SRS - If in Doom 3 mode (com_smp = -1), must sync after RenderCommandBuffers() otherwise get artifacts due to improper command buffer swap timing
if ( com_smp . GetInteger ( ) < 0 )
{
// RB: this is the same as Doom 3 renderSystem->EndFrame()
renderSystem - > SwapCommandBuffers_FinishRendering ( & time_frontend , & time_backend , & time_shadows , & time_gpu , & stats_backend , & stats_frontend ) ;
}
2021-09-28 07:58:48 +00:00
// SRS - Use finishSyncTime_EndFrame to record timing after sync for com_smp = -1, and just before gameThread.WaitForThread() for com_smp = 1
frameTiming . finishSyncTime_EndFrame = Sys_Microseconds ( ) ;
2021-04-19 18:31:15 +00:00
2012-11-26 18:58:24 +00:00
// make sure the game / draw thread has completed
// This may block if the game is taking longer than the render back end
gameThread . WaitForThread ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// Send local usermds to the server.
// This happens after the game frame has run so that prediction data is up to date.
SendUsercmds ( Game ( ) - > GetLocalClientNum ( ) ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// Now that we have an updated game frame, we can send out new snapshots to our clients
session - > Pump ( ) ; // Pump to get updated usercmds to relay
SendSnapshots ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// Render the sound system using the latest commands from the game thread
2021-04-29 13:20:45 +00:00
// SRS - Enable sound during normal playDemo playback but not during timeDemo
2021-04-19 18:31:15 +00:00
if ( pauseGame & & ! ( readDemo & & ! timeDemo ) )
2012-11-28 15:47:07 +00:00
{
2012-11-26 18:58:24 +00:00
soundWorld - > Pause ( ) ;
soundSystem - > SetPlayingSoundWorld ( menuSoundWorld ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
soundWorld - > UnPause ( ) ;
soundSystem - > SetPlayingSoundWorld ( soundWorld ) ;
}
2021-04-29 13:20:45 +00:00
// SRS - Play silence when dialog waiting or window not in focus
if ( Dialog ( ) . IsDialogPausing ( ) | | session - > IsSystemUIShowing ( ) | | com_pause . GetInteger ( ) )
{
soundSystem - > SetPlayingSoundWorld ( NULL ) ;
}
2012-11-26 18:58:24 +00:00
soundSystem - > Render ( ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// process the game return for map changes, etc
ProcessGameReturn ( ret ) ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
idLobbyBase & lobby = session - > GetActivePlatformLobbyBase ( ) ;
if ( lobby . HasActivePeers ( ) )
{
if ( net_drawDebugHud . GetInteger ( ) = = 1 )
{
2012-11-26 18:58:24 +00:00
lobby . DrawDebugNetworkHUD ( ) ;
}
2012-11-28 15:47:07 +00:00
if ( net_drawDebugHud . GetInteger ( ) = = 2 )
{
2012-11-26 18:58:24 +00:00
lobby . DrawDebugNetworkHUD2 ( ) ;
}
lobby . DrawDebugNetworkHUD_ServerSnapshotMetrics ( net_drawDebugHud . GetInteger ( ) = = 3 ) ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// report timing information
2012-11-28 15:47:07 +00:00
if ( com_speeds . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
static int lastTime = Sys_Milliseconds ( ) ;
int nowTime = Sys_Milliseconds ( ) ;
int com_frameMsec = nowTime - lastTime ;
lastTime = nowTime ;
Printf ( " frame:%d all:%3d gfr:%3d rf:%3lld bk:%3lld \n " , idLib : : frameNumber , com_frameMsec , time_gameFrame , time_frontend / 1000 , time_backend / 1000 ) ;
time_gameFrame = 0 ;
time_gameDraw = 0 ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// the FPU stack better be empty at this point or some bad code or compiler bug left values on the stack
2012-11-28 15:47:07 +00:00
if ( ! Sys_FPU_StackIsEmpty ( ) )
{
2014-02-22 18:13:06 +00:00
Printf ( " %s " , Sys_FPU_GetState ( ) ) ;
2012-11-26 18:58:24 +00:00
FatalError ( " idCommon::Frame: the FPU stack is not empty at the end of the frame \n " ) ;
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
mainFrameTiming = frameTiming ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
session - > GetSaveGameManager ( ) . Pump ( ) ;
2012-11-28 15:47:07 +00:00
}
catch ( idException & )
{
2013-09-29 11:03:32 +00:00
// an ERP_DROP was thrown
# if defined(USE_DOOMCLASSIC)
if ( currentGame = = DOOM_CLASSIC | | currentGame = = DOOM2_CLASSIC )
{
return ;
}
# endif
2019-11-11 19:27:44 +00:00
2013-09-29 11:03:32 +00:00
// kill loading gui
delete loadGUI ;
loadGUI = NULL ;
2019-11-11 19:27:44 +00:00
2013-09-29 11:03:32 +00:00
// drop back to main menu
LeaveGame ( ) ;
2019-11-11 19:27:44 +00:00
2013-09-29 11:03:32 +00:00
// force the console open to show error messages
console - > Open ( ) ;
return ;
2012-11-26 18:58:24 +00:00
}
}
2012-12-06 23:09:53 +00:00
// RB begin
# if defined(USE_DOOMCLASSIC)
2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = =
idCommonLocal : : RunDoomClassicFrame
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void idCommonLocal : : RunDoomClassicFrame ( )
{
2012-11-26 18:58:24 +00:00
static int doomTics = 0 ;
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
if ( DoomLib : : expansionDirty )
{
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// re-Initialize the Doom Engine.
DoomLib : : Interface . Shutdown ( ) ;
DoomLib : : Interface . Startup ( 1 , false ) ;
DoomLib : : expansionDirty = false ;
}
2019-11-11 19:27:44 +00:00
2012-11-28 15:47:07 +00:00
if ( DoomLib : : Interface . Frame ( doomTics , & userCmdMgr ) )
{
Globals * data = ( Globals * ) DoomLib : : GetGlobalData ( 0 ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
idArray < unsigned int , 256 > palette ;
std : : copy ( data - > XColorMap , data - > XColorMap + palette . Num ( ) , palette . Ptr ( ) ) ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
// Do the palette lookup.
2012-11-28 15:47:07 +00:00
for ( int row = 0 ; row < DOOMCLASSIC_RENDERHEIGHT ; + + row )
{
for ( int column = 0 ; column < DOOMCLASSIC_RENDERWIDTH ; + + column )
{
2012-11-26 18:58:24 +00:00
const int doomScreenPixelIndex = row * DOOMCLASSIC_RENDERWIDTH + column ;
const byte paletteIndex = data - > screens [ 0 ] [ doomScreenPixelIndex ] ;
const unsigned int paletteColor = palette [ paletteIndex ] ;
2012-11-28 15:47:07 +00:00
const byte red = ( paletteColor & 0xFF000000 ) > > 24 ;
const byte green = ( paletteColor & 0x00FF0000 ) > > 16 ;
const byte blue = ( paletteColor & 0x0000FF00 ) > > 8 ;
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
const int imageDataPixelIndex = row * DOOMCLASSIC_RENDERWIDTH * DOOMCLASSIC_BYTES_PER_PIXEL + column * DOOMCLASSIC_BYTES_PER_PIXEL ;
doomClassicImageData [ imageDataPixelIndex ] = red ;
doomClassicImageData [ imageDataPixelIndex + 1 ] = green ;
doomClassicImageData [ imageDataPixelIndex + 2 ] = blue ;
doomClassicImageData [ imageDataPixelIndex + 3 ] = 255 ;
}
}
}
2019-11-11 19:27:44 +00:00
2012-11-26 18:58:24 +00:00
renderSystem - > UploadImage ( " _doomClassic " , doomClassicImageData . Ptr ( ) , DOOMCLASSIC_RENDERWIDTH , DOOMCLASSIC_RENDERHEIGHT ) ;
doomTics + + ;
}
2012-12-06 23:09:53 +00:00
# endif
// RB end