mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2026-03-20 09:00:25 +01:00
Initial commit
This commit is contained in:
518
neo/framework/Common_demos.cpp
Normal file
518
neo/framework/Common_demos.cpp
Normal file
@@ -0,0 +1,518 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "../idlib/precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "Common_local.h"
|
||||
|
||||
/*
|
||||
================
|
||||
FindUnusedFileName
|
||||
================
|
||||
*/
|
||||
static idStr FindUnusedFileName( const char *format ) {
|
||||
idStr filename;
|
||||
|
||||
for ( int i = 0 ; i < 999 ; i++ ) {
|
||||
filename.Format( format, i );
|
||||
int len = fileSystem->ReadFile( filename, NULL, NULL );
|
||||
if ( len <= 0 ) {
|
||||
return filename; // file doesn't exist
|
||||
}
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idCommonLocal::StartRecordingRenderDemo
|
||||
================
|
||||
*/
|
||||
void idCommonLocal::StartRecordingRenderDemo( const char *demoName ) {
|
||||
if ( writeDemo ) {
|
||||
// allow it to act like a toggle
|
||||
StopRecordingRenderDemo();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !demoName[0] ) {
|
||||
common->Printf( "idCommonLocal::StartRecordingRenderDemo: no name specified\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
console->Close();
|
||||
|
||||
writeDemo = new (TAG_SYSTEM) idDemoFile;
|
||||
if ( !writeDemo->OpenForWriting( demoName ) ) {
|
||||
common->Printf( "error opening %s\n", demoName );
|
||||
delete writeDemo;
|
||||
writeDemo = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
common->Printf( "recording to %s\n", writeDemo->GetName() );
|
||||
|
||||
writeDemo->WriteInt( DS_VERSION );
|
||||
writeDemo->WriteInt( RENDERDEMO_VERSION );
|
||||
|
||||
// if we are in a map already, dump the current state
|
||||
soundWorld->StartWritingDemo( writeDemo );
|
||||
renderWorld->StartWritingDemo( writeDemo );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idCommonLocal::StopRecordingRenderDemo
|
||||
================
|
||||
*/
|
||||
void idCommonLocal::StopRecordingRenderDemo() {
|
||||
if ( !writeDemo ) {
|
||||
common->Printf( "idCommonLocal::StopRecordingRenderDemo: not recording\n" );
|
||||
return;
|
||||
}
|
||||
soundWorld->StopWritingDemo();
|
||||
renderWorld->StopWritingDemo();
|
||||
|
||||
writeDemo->Close();
|
||||
common->Printf( "stopped recording %s.\n", writeDemo->GetName() );
|
||||
delete writeDemo;
|
||||
writeDemo = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idCommonLocal::StopPlayingRenderDemo
|
||||
|
||||
Reports timeDemo numbers and finishes any avi recording
|
||||
================
|
||||
*/
|
||||
void idCommonLocal::StopPlayingRenderDemo() {
|
||||
if ( !readDemo ) {
|
||||
timeDemo = TD_NO;
|
||||
return;
|
||||
}
|
||||
|
||||
// Record the stop time before doing anything that could be time consuming
|
||||
int timeDemoStopTime = Sys_Milliseconds();
|
||||
|
||||
EndAVICapture();
|
||||
|
||||
readDemo->Close();
|
||||
|
||||
soundWorld->StopAllSounds();
|
||||
soundSystem->SetPlayingSoundWorld( menuSoundWorld );
|
||||
|
||||
common->Printf( "stopped playing %s.\n", readDemo->GetName() );
|
||||
delete readDemo;
|
||||
readDemo = NULL;
|
||||
|
||||
if ( timeDemo ) {
|
||||
// report the stats
|
||||
float demoSeconds = ( timeDemoStopTime - timeDemoStartTime ) * 0.001f;
|
||||
float demoFPS = numDemoFrames / demoSeconds;
|
||||
idStr message = va( "%i frames rendered in %3.1f seconds = %3.1f fps\n", numDemoFrames, demoSeconds, demoFPS );
|
||||
|
||||
common->Printf( message );
|
||||
if ( timeDemo == TD_YES_THEN_QUIT ) {
|
||||
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "quit\n" );
|
||||
}
|
||||
timeDemo = TD_NO;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idCommonLocal::DemoShot
|
||||
|
||||
A demoShot is a single frame demo
|
||||
================
|
||||
*/
|
||||
void idCommonLocal::DemoShot( const char *demoName ) {
|
||||
StartRecordingRenderDemo( demoName );
|
||||
|
||||
// force draw one frame
|
||||
const bool captureToImage = false;
|
||||
UpdateScreen( captureToImage );
|
||||
|
||||
StopRecordingRenderDemo();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idCommonLocal::StartPlayingRenderDemo
|
||||
================
|
||||
*/
|
||||
void idCommonLocal::StartPlayingRenderDemo( idStr demoName ) {
|
||||
if ( !demoName[0] ) {
|
||||
common->Printf( "idCommonLocal::StartPlayingRenderDemo: no name specified\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure localSound / GUI intro music shuts up
|
||||
soundWorld->StopAllSounds();
|
||||
soundWorld->PlayShaderDirectly( "", 0 );
|
||||
menuSoundWorld->StopAllSounds();
|
||||
menuSoundWorld->PlayShaderDirectly( "", 0 );
|
||||
|
||||
// exit any current game
|
||||
Stop();
|
||||
|
||||
// automatically put the console away
|
||||
console->Close();
|
||||
|
||||
readDemo = new (TAG_SYSTEM) idDemoFile;
|
||||
demoName.DefaultFileExtension( ".demo" );
|
||||
if ( !readDemo->OpenForReading( demoName ) ) {
|
||||
common->Printf( "couldn't open %s\n", demoName.c_str() );
|
||||
delete readDemo;
|
||||
readDemo = NULL;
|
||||
Stop();
|
||||
StartMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
const bool captureToImage = false;
|
||||
UpdateScreen( captureToImage );
|
||||
|
||||
AdvanceRenderDemo( true );
|
||||
|
||||
numDemoFrames = 1;
|
||||
|
||||
timeDemoStartTime = Sys_Milliseconds();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idCommonLocal::TimeRenderDemo
|
||||
================
|
||||
*/
|
||||
void idCommonLocal::TimeRenderDemo( const char *demoName, bool twice, bool quit ) {
|
||||
idStr demo = demoName;
|
||||
|
||||
StartPlayingRenderDemo( demo );
|
||||
|
||||
if ( twice && readDemo ) {
|
||||
while ( readDemo ) {
|
||||
const bool captureToImage = false;
|
||||
UpdateScreen( captureToImage );
|
||||
AdvanceRenderDemo( true );
|
||||
}
|
||||
|
||||
StartPlayingRenderDemo( demo );
|
||||
}
|
||||
|
||||
|
||||
if ( !readDemo ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( quit ) {
|
||||
// this allows hardware vendors to automate some testing
|
||||
timeDemo = TD_YES_THEN_QUIT;
|
||||
} else {
|
||||
timeDemo = TD_YES;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
idCommonLocal::BeginAVICapture
|
||||
================
|
||||
*/
|
||||
void idCommonLocal::BeginAVICapture( const char *demoName ) {
|
||||
idStr name = demoName;
|
||||
name.ExtractFileBase( aviDemoShortName );
|
||||
aviCaptureMode = true;
|
||||
aviDemoFrameCount = 0;
|
||||
soundWorld->AVIOpen( va( "demos/%s/", aviDemoShortName.c_str() ), aviDemoShortName.c_str() );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idCommonLocal::EndAVICapture
|
||||
================
|
||||
*/
|
||||
void idCommonLocal::EndAVICapture() {
|
||||
if ( !aviCaptureMode ) {
|
||||
return;
|
||||
}
|
||||
|
||||
soundWorld->AVIClose();
|
||||
|
||||
// write a .roqParam file so the demo can be converted to a roq file
|
||||
idFile *f = fileSystem->OpenFileWrite( va( "demos/%s/%s.roqParam",
|
||||
aviDemoShortName.c_str(), aviDemoShortName.c_str() ) );
|
||||
f->Printf( "INPUT_DIR demos/%s\n", aviDemoShortName.c_str() );
|
||||
f->Printf( "FILENAME demos/%s/%s.RoQ\n", aviDemoShortName.c_str(), aviDemoShortName.c_str() );
|
||||
f->Printf( "\nINPUT\n" );
|
||||
f->Printf( "%s_*.tga [00000-%05i]\n", aviDemoShortName.c_str(), (int)( aviDemoFrameCount-1 ) );
|
||||
f->Printf( "END_INPUT\n" );
|
||||
delete f;
|
||||
|
||||
common->Printf( "captured %i frames for %s.\n", ( int )aviDemoFrameCount, aviDemoShortName.c_str() );
|
||||
|
||||
aviCaptureMode = false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================
|
||||
idCommonLocal::AVIRenderDemo
|
||||
================
|
||||
*/
|
||||
void idCommonLocal::AVIRenderDemo( const char *_demoName ) {
|
||||
idStr demoName = _demoName; // copy off from va() buffer
|
||||
|
||||
StartPlayingRenderDemo( demoName );
|
||||
if ( !readDemo ) {
|
||||
return;
|
||||
}
|
||||
|
||||
BeginAVICapture( demoName.c_str() ) ;
|
||||
|
||||
// I don't understand why I need to do this twice, something
|
||||
// strange with the nvidia swapbuffers?
|
||||
const bool captureToImage = false;
|
||||
UpdateScreen( captureToImage );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idCommonLocal::AVIGame
|
||||
|
||||
Start AVI recording the current game session
|
||||
================
|
||||
*/
|
||||
void idCommonLocal::AVIGame( const char *demoName ) {
|
||||
if ( aviCaptureMode ) {
|
||||
EndAVICapture();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !mapSpawned ) {
|
||||
common->Printf( "No map spawned.\n" );
|
||||
}
|
||||
|
||||
if ( !demoName || !demoName[0] ) {
|
||||
idStr filename = FindUnusedFileName( "demos/game%03i.game" );
|
||||
demoName = filename.c_str();
|
||||
|
||||
// write a one byte stub .game file just so the FindUnusedFileName works,
|
||||
fileSystem->WriteFile( demoName, demoName, 1 );
|
||||
}
|
||||
|
||||
BeginAVICapture( demoName ) ;
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
idCommonLocal::CompressDemoFile
|
||||
================
|
||||
*/
|
||||
void idCommonLocal::CompressDemoFile( const char *scheme, const char *demoName ) {
|
||||
idStr fullDemoName = "demos/";
|
||||
fullDemoName += demoName;
|
||||
fullDemoName.DefaultFileExtension( ".demo" );
|
||||
idStr compressedName = fullDemoName;
|
||||
compressedName.StripFileExtension();
|
||||
compressedName.Append( "_compressed.demo" );
|
||||
|
||||
int savedCompression = cvarSystem->GetCVarInteger("com_compressDemos");
|
||||
bool savedPreload = cvarSystem->GetCVarBool("com_preloadDemos");
|
||||
cvarSystem->SetCVarBool( "com_preloadDemos", false );
|
||||
cvarSystem->SetCVarInteger("com_compressDemos", atoi(scheme) );
|
||||
|
||||
idDemoFile demoread, demowrite;
|
||||
if ( !demoread.OpenForReading( fullDemoName ) ) {
|
||||
common->Printf( "Could not open %s for reading\n", fullDemoName.c_str() );
|
||||
return;
|
||||
}
|
||||
if ( !demowrite.OpenForWriting( compressedName ) ) {
|
||||
common->Printf( "Could not open %s for writing\n", compressedName.c_str() );
|
||||
demoread.Close();
|
||||
cvarSystem->SetCVarBool( "com_preloadDemos", savedPreload );
|
||||
cvarSystem->SetCVarInteger("com_compressDemos", savedCompression);
|
||||
return;
|
||||
}
|
||||
common->SetRefreshOnPrint( true );
|
||||
common->Printf( "Compressing %s to %s...\n", fullDemoName.c_str(), compressedName.c_str() );
|
||||
|
||||
static const int bufferSize = 65535;
|
||||
char buffer[bufferSize];
|
||||
int bytesRead;
|
||||
while ( 0 != (bytesRead = demoread.Read( buffer, bufferSize ) ) ) {
|
||||
demowrite.Write( buffer, bytesRead );
|
||||
common->Printf( "." );
|
||||
}
|
||||
|
||||
demoread.Close();
|
||||
demowrite.Close();
|
||||
|
||||
cvarSystem->SetCVarBool( "com_preloadDemos", savedPreload );
|
||||
cvarSystem->SetCVarInteger("com_compressDemos", savedCompression);
|
||||
|
||||
common->Printf( "Done\n" );
|
||||
common->SetRefreshOnPrint( false );
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
===============
|
||||
idCommonLocal::AdvanceRenderDemo
|
||||
===============
|
||||
*/
|
||||
void idCommonLocal::AdvanceRenderDemo( bool singleFrameOnly ) {
|
||||
int ds = DS_FINISHED;
|
||||
readDemo->ReadInt( ds );
|
||||
|
||||
switch ( ds ) {
|
||||
case DS_FINISHED:
|
||||
if ( numDemoFrames != 1 ) {
|
||||
// if the demo has a single frame (a demoShot), continuously replay
|
||||
// the renderView that has already been read
|
||||
Stop();
|
||||
StartMenu();
|
||||
}
|
||||
return;
|
||||
case DS_RENDER:
|
||||
if ( renderWorld->ProcessDemoCommand( readDemo, ¤tDemoRenderView, &demoTimeOffset ) ) {
|
||||
// a view is ready to render
|
||||
numDemoFrames++;
|
||||
}
|
||||
break;
|
||||
case DS_SOUND:
|
||||
soundWorld->ProcessDemoCommand( readDemo );
|
||||
break;
|
||||
default:
|
||||
common->Error( "Bad render demo token" );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Common_DemoShot_f
|
||||
================
|
||||
*/
|
||||
CONSOLE_COMMAND( demoShot, "writes a screenshot as a demo", NULL ) {
|
||||
if ( args.Argc() != 2 ) {
|
||||
idStr filename = FindUnusedFileName( "demos/shot%03i.demo" );
|
||||
commonLocal.DemoShot( filename );
|
||||
} else {
|
||||
commonLocal.DemoShot( va( "demos/shot_%s.demo", args.Argv(1) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Common_RecordDemo_f
|
||||
================
|
||||
*/
|
||||
CONSOLE_COMMAND( recordDemo, "records a demo", NULL ) {
|
||||
if ( args.Argc() != 2 ) {
|
||||
idStr filename = FindUnusedFileName( "demos/demo%03i.demo" );
|
||||
commonLocal.StartRecordingRenderDemo( filename );
|
||||
} else {
|
||||
commonLocal.StartRecordingRenderDemo( va( "demos/%s.demo", args.Argv(1) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Common_CompressDemo_f
|
||||
================
|
||||
*/
|
||||
CONSOLE_COMMAND( compressDemo, "compresses a demo file", idCmdSystem::ArgCompletion_DemoName ) {
|
||||
if ( args.Argc() == 2 ) {
|
||||
commonLocal.CompressDemoFile( "2", args.Argv(1) );
|
||||
} else if ( args.Argc() == 3 ) {
|
||||
commonLocal.CompressDemoFile( args.Argv(2), args.Argv(1) );
|
||||
} else {
|
||||
common->Printf("use: CompressDemo <file> [scheme]\nscheme is the same as com_compressDemo, defaults to 2" );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Common_StopRecordingDemo_f
|
||||
================
|
||||
*/
|
||||
CONSOLE_COMMAND( stopRecording, "stops demo recording", NULL ) {
|
||||
commonLocal.StopRecordingRenderDemo();
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Common_PlayDemo_f
|
||||
================
|
||||
*/
|
||||
CONSOLE_COMMAND( playDemo, "plays back a demo", idCmdSystem::ArgCompletion_DemoName ) {
|
||||
if ( args.Argc() >= 2 ) {
|
||||
commonLocal.StartPlayingRenderDemo( va( "demos/%s", args.Argv(1) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Common_TimeDemo_f
|
||||
================
|
||||
*/
|
||||
CONSOLE_COMMAND( timeDemo, "times a demo", idCmdSystem::ArgCompletion_DemoName ) {
|
||||
if ( args.Argc() >= 2 ) {
|
||||
commonLocal.TimeRenderDemo( va( "demos/%s", args.Argv(1) ), ( args.Argc() > 2 ), false );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Common_TimeDemoQuit_f
|
||||
================
|
||||
*/
|
||||
CONSOLE_COMMAND( timeDemoQuit, "times a demo and quits", idCmdSystem::ArgCompletion_DemoName ) {
|
||||
commonLocal.TimeRenderDemo( va( "demos/%s", args.Argv(1) ), true );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Common_AVIDemo_f
|
||||
================
|
||||
*/
|
||||
CONSOLE_COMMAND( aviDemo, "writes AVIs for a demo", idCmdSystem::ArgCompletion_DemoName ) {
|
||||
commonLocal.AVIRenderDemo( va( "demos/%s", args.Argv(1) ) );
|
||||
}
|
||||
|
||||
/*
|
||||
================
|
||||
Common_AVIGame_f
|
||||
================
|
||||
*/
|
||||
CONSOLE_COMMAND( aviGame, "writes AVIs for the current game", NULL ) {
|
||||
commonLocal.AVIGame( args.Argv(1) );
|
||||
}
|
||||
Reference in New Issue
Block a user