DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

EventLoop.cpp (6985B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 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.
     23 
     24 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.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #include "../idlib/precompiled.h"
     30 #pragma hdrstop
     31 
     32 idCVar idEventLoop::com_journal( "com_journal", "0", CVAR_INIT|CVAR_SYSTEM, "1 = record journal, 2 = play back journal", 0, 2, idCmdSystem::ArgCompletion_Integer<0,2> );
     33 
     34 idEventLoop eventLoopLocal;
     35 idEventLoop *eventLoop = &eventLoopLocal;
     36 
     37 
     38 /*
     39 =================
     40 idEventLoop::idEventLoop
     41 =================
     42 */
     43 idEventLoop::idEventLoop() {
     44 	com_journalFile = NULL;
     45 	com_journalDataFile = NULL;
     46 	initialTimeOffset = 0;
     47 }
     48 
     49 /*
     50 =================
     51 idEventLoop::~idEventLoop
     52 =================
     53 */
     54 idEventLoop::~idEventLoop() {
     55 }
     56 
     57 /*
     58 =================
     59 idEventLoop::GetRealEvent
     60 =================
     61 */
     62 sysEvent_t	idEventLoop::GetRealEvent() {
     63 	int			r;
     64 	sysEvent_t	ev;
     65 
     66 	// either get an event from the system or the journal file
     67 	if ( com_journal.GetInteger() == 2 ) {
     68 		r = com_journalFile->Read( &ev, sizeof(ev) );
     69 		if ( r != sizeof(ev) ) {
     70 			common->FatalError( "Error reading from journal file" );
     71 		}
     72 		if ( ev.evPtrLength ) {
     73 			ev.evPtr = Mem_ClearedAlloc( ev.evPtrLength, TAG_EVENTS );
     74 			r = com_journalFile->Read( ev.evPtr, ev.evPtrLength );
     75 			if ( r != ev.evPtrLength ) {
     76 				common->FatalError( "Error reading from journal file" );
     77 			}
     78 		}
     79 	} else {
     80 		ev = Sys_GetEvent();
     81 
     82 		// write the journal value out if needed
     83 		if ( com_journal.GetInteger() == 1 ) {
     84 			r = com_journalFile->Write( &ev, sizeof(ev) );
     85 			if ( r != sizeof(ev) ) {
     86 				common->FatalError( "Error writing to journal file" );
     87 			}
     88 			if ( ev.evPtrLength ) {
     89 				r = com_journalFile->Write( ev.evPtr, ev.evPtrLength );
     90 				if ( r != ev.evPtrLength ) {
     91 					common->FatalError( "Error writing to journal file" );
     92 				}
     93 			}
     94 		}
     95 	}
     96 
     97 	return ev;
     98 }
     99 
    100 /*
    101 =================
    102 idEventLoop::PushEvent
    103 =================
    104 */
    105 void idEventLoop::PushEvent( sysEvent_t *event ) {
    106 	sysEvent_t		*ev;
    107 	static			bool printedWarning;
    108 
    109 	ev = &com_pushedEvents[ com_pushedEventsHead & (MAX_PUSHED_EVENTS-1) ];
    110 
    111 	if ( com_pushedEventsHead - com_pushedEventsTail >= MAX_PUSHED_EVENTS ) {
    112 
    113 		// don't print the warning constantly, or it can give time for more...
    114 		if ( !printedWarning ) {
    115 			printedWarning = true;
    116 			common->Printf( "WARNING: Com_PushEvent overflow\n" );
    117 		}
    118 
    119 		if ( ev->evPtr ) {
    120 			Mem_Free( ev->evPtr );
    121 		}
    122 		com_pushedEventsTail++;
    123 	} else {
    124 		printedWarning = false;
    125 	}
    126 
    127 	*ev = *event;
    128 	com_pushedEventsHead++;
    129 }
    130 
    131 /*
    132 =================
    133 idEventLoop::GetEvent
    134 =================
    135 */
    136 sysEvent_t idEventLoop::GetEvent() {
    137 	if ( com_pushedEventsHead > com_pushedEventsTail ) {
    138 		com_pushedEventsTail++;
    139 		return com_pushedEvents[ (com_pushedEventsTail-1) & (MAX_PUSHED_EVENTS-1) ];
    140 	}
    141 	return GetRealEvent();
    142 }
    143 
    144 /*
    145 =================
    146 idEventLoop::ProcessEvent
    147 =================
    148 */
    149 void idEventLoop::ProcessEvent( sysEvent_t ev ) {
    150 	// track key up / down states
    151 	if ( ev.evType == SE_KEY ) {
    152 		idKeyInput::PreliminaryKeyEvent( ev.evValue, ( ev.evValue2 != 0 ) );
    153 	}
    154 
    155 	if ( ev.evType == SE_CONSOLE ) {
    156 		// from a text console outside the game window
    157 		cmdSystem->BufferCommandText( CMD_EXEC_APPEND, (char *)ev.evPtr );
    158 		cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "\n" );
    159 	} else {
    160 		common->ProcessEvent( &ev );
    161 	}
    162 
    163 	// free any block data
    164 	if ( ev.evPtr ) {
    165 		Mem_Free( ev.evPtr );
    166 	}
    167 }
    168 
    169 /*
    170 ===============
    171 idEventLoop::RunEventLoop
    172 ===============
    173 */
    174 int idEventLoop::RunEventLoop( bool commandExecution ) {
    175 	sysEvent_t	ev;
    176 
    177 	while ( 1 ) {
    178 
    179 		if ( commandExecution ) {
    180 			// execute any bound commands before processing another event
    181 			cmdSystem->ExecuteCommandBuffer();
    182 		}
    183 
    184 		ev = GetEvent();
    185 
    186 		// if no more events are available
    187 		if ( ev.evType == SE_NONE ) {
    188 			return 0;
    189 		}
    190 		ProcessEvent( ev );
    191 	}
    192 
    193 	return 0;	// never reached
    194 }
    195 
    196 /*
    197 =============
    198 idEventLoop::Init
    199 =============
    200 */
    201 void idEventLoop::Init() {
    202 
    203 	initialTimeOffset = Sys_Milliseconds();
    204 
    205 	common->StartupVariable( "journal" );
    206 
    207 	if ( com_journal.GetInteger() == 1 ) {
    208 		common->Printf( "Journaling events\n" );
    209 		com_journalFile = fileSystem->OpenFileWrite( "journal.dat" );
    210 		com_journalDataFile = fileSystem->OpenFileWrite( "journaldata.dat" );
    211 	} else if ( com_journal.GetInteger() == 2 ) {
    212 		common->Printf( "Replaying journaled events\n" );
    213 		com_journalFile = fileSystem->OpenFileRead( "journal.dat" );
    214 		com_journalDataFile = fileSystem->OpenFileRead( "journaldata.dat" );
    215 	}
    216 
    217 	if ( !com_journalFile || !com_journalDataFile ) {
    218 		com_journal.SetInteger( 0 );
    219 		com_journalFile = 0;
    220 		com_journalDataFile = 0;
    221 		common->Printf( "Couldn't open journal files\n" );
    222 	}
    223 }
    224 
    225 /*
    226 =============
    227 idEventLoop::Shutdown
    228 =============
    229 */
    230 void idEventLoop::Shutdown() {
    231 	if ( com_journalFile ) {
    232 		fileSystem->CloseFile( com_journalFile );
    233 		com_journalFile = NULL;
    234 	}
    235 	if ( com_journalDataFile ) {
    236 		fileSystem->CloseFile( com_journalDataFile );
    237 		com_journalDataFile = NULL;
    238 	}
    239 }
    240 
    241 /*
    242 ================
    243 idEventLoop::Milliseconds
    244 
    245 Can be used for profiling, but will be journaled accurately
    246 ================
    247 */
    248 int idEventLoop::Milliseconds() {
    249 #if 1	// FIXME!
    250 	return Sys_Milliseconds() - initialTimeOffset;
    251 #else
    252 	sysEvent_t	ev;
    253 
    254 	// get events and push them until we get a null event with the current time
    255 	do {
    256 
    257 		ev = Com_GetRealEvent();
    258 		if ( ev.evType != SE_NONE ) {
    259 			Com_PushEvent( &ev );
    260 		}
    261 	} while ( ev.evType != SE_NONE );
    262 	
    263 	return ev.evTime;
    264 #endif
    265 }
    266 
    267 /*
    268 ================
    269 idEventLoop::JournalLevel
    270 ================
    271 */
    272 int idEventLoop::JournalLevel() const {
    273 	return com_journal.GetInteger();
    274 }