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 }