Console.cpp 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 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 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. 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.
  18. ===========================================================================
  19. */
  20. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. void SCR_DrawTextLeftAlign( float &y, const char *text, ... ) id_attribute((format(printf,2,3)));
  23. void SCR_DrawTextRightAlign( float &y, const char *text, ... ) id_attribute((format(printf,2,3)));
  24. #define LINE_WIDTH 78
  25. #define NUM_CON_TIMES 4
  26. #define CON_TEXTSIZE 0x30000
  27. #define TOTAL_LINES (CON_TEXTSIZE / LINE_WIDTH)
  28. #define CONSOLE_FIRSTREPEAT 200
  29. #define CONSOLE_REPEAT 100
  30. #define COMMAND_HISTORY 64
  31. // the console will query the cvar and command systems for
  32. // command completion information
  33. class idConsoleLocal : public idConsole {
  34. public:
  35. virtual void Init( void );
  36. virtual void Shutdown( void );
  37. virtual void LoadGraphics( void );
  38. virtual bool ProcessEvent( const sysEvent_t *event, bool forceAccept );
  39. virtual bool Active( void );
  40. virtual void ClearNotifyLines( void );
  41. virtual void Close( void );
  42. virtual void Print( const char *text );
  43. virtual void Draw( bool forceFullScreen );
  44. void Dump( const char *toFile );
  45. void Clear();
  46. //============================
  47. const idMaterial * charSetShader;
  48. private:
  49. void KeyDownEvent( int key );
  50. void Linefeed();
  51. void PageUp();
  52. void PageDown();
  53. void Top();
  54. void Bottom();
  55. void DrawInput();
  56. void DrawNotify();
  57. void DrawSolidConsole( float frac );
  58. void Scroll();
  59. void SetDisplayFraction( float frac );
  60. void UpdateDisplayFraction( void );
  61. //============================
  62. bool keyCatching;
  63. short text[CON_TEXTSIZE];
  64. int current; // line where next message will be printed
  65. int x; // offset in current line for next print
  66. int display; // bottom of console displays this line
  67. int lastKeyEvent; // time of last key event for scroll delay
  68. int nextKeyEvent; // keyboard repeat rate
  69. float displayFrac; // approaches finalFrac at scr_conspeed
  70. float finalFrac; // 0.0 to 1.0 lines of console to display
  71. int fracTime; // time of last displayFrac update
  72. int vislines; // in scanlines
  73. int times[NUM_CON_TIMES]; // cls.realtime time the line was generated
  74. // for transparent notify lines
  75. idVec4 color;
  76. idEditField historyEditLines[COMMAND_HISTORY];
  77. int nextHistoryLine;// the last line in the history buffer, not masked
  78. int historyLine; // the line being displayed from history buffer
  79. // will be <= nextHistoryLine
  80. idEditField consoleField;
  81. static idCVar con_speed;
  82. static idCVar con_notifyTime;
  83. static idCVar con_noPrint;
  84. const idMaterial * whiteShader;
  85. const idMaterial * consoleShader;
  86. };
  87. static idConsoleLocal localConsole;
  88. idConsole *console = &localConsole;
  89. idCVar idConsoleLocal::con_speed( "con_speed", "3", CVAR_SYSTEM, "speed at which the console moves up and down" );
  90. idCVar idConsoleLocal::con_notifyTime( "con_notifyTime", "3", CVAR_SYSTEM, "time messages are displayed onscreen when console is pulled up" );
  91. #ifdef DEBUG
  92. idCVar idConsoleLocal::con_noPrint( "con_noPrint", "0", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "print on the console but not onscreen when console is pulled up" );
  93. #else
  94. idCVar idConsoleLocal::con_noPrint( "con_noPrint", "1", CVAR_BOOL|CVAR_SYSTEM|CVAR_NOCHEAT, "print on the console but not onscreen when console is pulled up" );
  95. #endif
  96. /*
  97. =============================================================================
  98. Misc stats
  99. =============================================================================
  100. */
  101. /*
  102. ==================
  103. SCR_DrawTextLeftAlign
  104. ==================
  105. */
  106. void SCR_DrawTextLeftAlign( float &y, const char *text, ... ) {
  107. char string[MAX_STRING_CHARS];
  108. va_list argptr;
  109. va_start( argptr, text );
  110. idStr::vsnPrintf( string, sizeof( string ), text, argptr );
  111. va_end( argptr );
  112. renderSystem->DrawSmallStringExt( 0, y + 2, string, colorWhite, true, localConsole.charSetShader );
  113. y += SMALLCHAR_HEIGHT + 4;
  114. }
  115. /*
  116. ==================
  117. SCR_DrawTextRightAlign
  118. ==================
  119. */
  120. void SCR_DrawTextRightAlign( float &y, const char *text, ... ) {
  121. char string[MAX_STRING_CHARS];
  122. va_list argptr;
  123. va_start( argptr, text );
  124. int i = idStr::vsnPrintf( string, sizeof( string ), text, argptr );
  125. va_end( argptr );
  126. renderSystem->DrawSmallStringExt( 635 - i * SMALLCHAR_WIDTH, y + 2, string, colorWhite, true, localConsole.charSetShader );
  127. y += SMALLCHAR_HEIGHT + 4;
  128. }
  129. /*
  130. ==================
  131. SCR_DrawFPS
  132. ==================
  133. */
  134. #define FPS_FRAMES 4
  135. float SCR_DrawFPS( float y ) {
  136. char *s;
  137. int w;
  138. static int previousTimes[FPS_FRAMES];
  139. static int index;
  140. int i, total;
  141. int fps;
  142. static int previous;
  143. int t, frameTime;
  144. // don't use serverTime, because that will be drifting to
  145. // correct for internet lag changes, timescales, timedemos, etc
  146. t = Sys_Milliseconds();
  147. frameTime = t - previous;
  148. previous = t;
  149. previousTimes[index % FPS_FRAMES] = frameTime;
  150. index++;
  151. if ( index > FPS_FRAMES ) {
  152. // average multiple frames together to smooth changes out a bit
  153. total = 0;
  154. for ( i = 0 ; i < FPS_FRAMES ; i++ ) {
  155. total += previousTimes[i];
  156. }
  157. if ( !total ) {
  158. total = 1;
  159. }
  160. fps = 10000 * FPS_FRAMES / total;
  161. fps = (fps + 5)/10;
  162. s = va( "%ifps", fps );
  163. w = strlen( s ) * BIGCHAR_WIDTH;
  164. renderSystem->DrawBigStringExt( 635 - w, idMath::FtoiFast( y ) + 32, s, colorWhite, true, localConsole.charSetShader);
  165. }
  166. return y + BIGCHAR_HEIGHT + 4;
  167. }
  168. /*
  169. ==================
  170. SCR_DrawMemoryUsage
  171. ==================
  172. */
  173. float SCR_DrawMemoryUsage( float y ) {
  174. memoryStats_t allocs, frees;
  175. Mem_GetStats( allocs );
  176. SCR_DrawTextRightAlign( y, "total allocated memory: %4d, %4dkB", allocs.num, allocs.totalSize>>10 );
  177. Mem_GetFrameStats( allocs, frees );
  178. SCR_DrawTextRightAlign( y, "frame alloc: %4d, %4dkB frame free: %4d, %4dkB", allocs.num, allocs.totalSize>>10, frees.num, frees.totalSize>>10 );
  179. Mem_ClearFrameStats();
  180. return y;
  181. }
  182. /*
  183. ==================
  184. SCR_DrawAsyncStats
  185. ==================
  186. */
  187. float SCR_DrawAsyncStats( float y ) {
  188. int i, outgoingRate, incomingRate;
  189. float outgoingCompression, incomingCompression;
  190. if ( idAsyncNetwork::server.IsActive() ) {
  191. SCR_DrawTextRightAlign( y, "server delay = %d msec", idAsyncNetwork::server.GetDelay() );
  192. SCR_DrawTextRightAlign( y, "total outgoing rate = %d KB/s", idAsyncNetwork::server.GetOutgoingRate() >> 10 );
  193. SCR_DrawTextRightAlign( y, "total incoming rate = %d KB/s", idAsyncNetwork::server.GetIncomingRate() >> 10 );
  194. for ( i = 0; i < MAX_ASYNC_CLIENTS; i++ ) {
  195. outgoingRate = idAsyncNetwork::server.GetClientOutgoingRate( i );
  196. incomingRate = idAsyncNetwork::server.GetClientIncomingRate( i );
  197. outgoingCompression = idAsyncNetwork::server.GetClientOutgoingCompression( i );
  198. incomingCompression = idAsyncNetwork::server.GetClientIncomingCompression( i );
  199. if ( outgoingRate != -1 && incomingRate != -1 ) {
  200. SCR_DrawTextRightAlign( y, "client %d: out rate = %d B/s (% -2.1f%%), in rate = %d B/s (% -2.1f%%)",
  201. i, outgoingRate, outgoingCompression, incomingRate, incomingCompression );
  202. }
  203. }
  204. idStr msg;
  205. idAsyncNetwork::server.GetAsyncStatsAvgMsg( msg );
  206. SCR_DrawTextRightAlign( y, msg.c_str() );
  207. } else if ( idAsyncNetwork::client.IsActive() ) {
  208. outgoingRate = idAsyncNetwork::client.GetOutgoingRate();
  209. incomingRate = idAsyncNetwork::client.GetIncomingRate();
  210. outgoingCompression = idAsyncNetwork::client.GetOutgoingCompression();
  211. incomingCompression = idAsyncNetwork::client.GetIncomingCompression();
  212. if ( outgoingRate != -1 && incomingRate != -1 ) {
  213. SCR_DrawTextRightAlign( y, "out rate = %d B/s (% -2.1f%%), in rate = %d B/s (% -2.1f%%)",
  214. outgoingRate, outgoingCompression, incomingRate, incomingCompression );
  215. }
  216. SCR_DrawTextRightAlign( y, "packet loss = %d%%, client prediction = %d",
  217. (int)idAsyncNetwork::client.GetIncomingPacketLoss(), idAsyncNetwork::client.GetPrediction() );
  218. SCR_DrawTextRightAlign( y, "predicted frames: %d", idAsyncNetwork::client.GetPredictedFrames() );
  219. }
  220. return y;
  221. }
  222. /*
  223. ==================
  224. SCR_DrawSoundDecoders
  225. ==================
  226. */
  227. float SCR_DrawSoundDecoders( float y ) {
  228. int index, numActiveDecoders;
  229. soundDecoderInfo_t decoderInfo;
  230. index = -1;
  231. numActiveDecoders = 0;
  232. while( ( index = soundSystem->GetSoundDecoderInfo( index, decoderInfo ) ) != -1 ) {
  233. int localTime = decoderInfo.current44kHzTime - decoderInfo.start44kHzTime;
  234. int sampleTime = decoderInfo.num44kHzSamples / decoderInfo.numChannels;
  235. int percent;
  236. if ( localTime > sampleTime ) {
  237. if ( decoderInfo.looping ) {
  238. percent = ( localTime % sampleTime ) * 100 / sampleTime;
  239. } else {
  240. percent = 100;
  241. }
  242. } else {
  243. percent = localTime * 100 / sampleTime;
  244. }
  245. SCR_DrawTextLeftAlign( y, "%3d: %3d%% (%1.2f) %s: %s (%dkB)", numActiveDecoders, percent, decoderInfo.lastVolume, decoderInfo.format.c_str(), decoderInfo.name.c_str(), decoderInfo.numBytes >> 10 );
  246. numActiveDecoders++;
  247. }
  248. return y;
  249. }
  250. //=========================================================================
  251. /*
  252. ==============
  253. Con_Clear_f
  254. ==============
  255. */
  256. static void Con_Clear_f( const idCmdArgs &args ) {
  257. localConsole.Clear();
  258. }
  259. /*
  260. ==============
  261. Con_Dump_f
  262. ==============
  263. */
  264. static void Con_Dump_f( const idCmdArgs &args ) {
  265. if ( args.Argc() != 2 ) {
  266. common->Printf( "usage: conDump <filename>\n" );
  267. return;
  268. }
  269. idStr fileName = args.Argv(1);
  270. fileName.DefaultFileExtension(".txt");
  271. common->Printf( "Dumped console text to %s.\n", fileName.c_str() );
  272. localConsole.Dump( fileName.c_str() );
  273. }
  274. /*
  275. ==============
  276. idConsoleLocal::Init
  277. ==============
  278. */
  279. void idConsoleLocal::Init( void ) {
  280. int i;
  281. keyCatching = false;
  282. lastKeyEvent = -1;
  283. nextKeyEvent = CONSOLE_FIRSTREPEAT;
  284. consoleField.Clear();
  285. consoleField.SetWidthInChars( LINE_WIDTH );
  286. for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) {
  287. historyEditLines[i].Clear();
  288. historyEditLines[i].SetWidthInChars( LINE_WIDTH );
  289. }
  290. cmdSystem->AddCommand( "clear", Con_Clear_f, CMD_FL_SYSTEM, "clears the console" );
  291. cmdSystem->AddCommand( "conDump", Con_Dump_f, CMD_FL_SYSTEM, "dumps the console text to a file" );
  292. }
  293. /*
  294. ==============
  295. idConsoleLocal::Shutdown
  296. ==============
  297. */
  298. void idConsoleLocal::Shutdown( void ) {
  299. cmdSystem->RemoveCommand( "clear" );
  300. cmdSystem->RemoveCommand( "conDump" );
  301. }
  302. /*
  303. ==============
  304. LoadGraphics
  305. Can't be combined with init, because init happens before
  306. the renderSystem is initialized
  307. ==============
  308. */
  309. void idConsoleLocal::LoadGraphics() {
  310. charSetShader = declManager->FindMaterial( "textures/bigchars" );
  311. whiteShader = declManager->FindMaterial( "_white" );
  312. consoleShader = declManager->FindMaterial( "console" );
  313. }
  314. /*
  315. ================
  316. idConsoleLocal::Active
  317. ================
  318. */
  319. bool idConsoleLocal::Active( void ) {
  320. return keyCatching;
  321. }
  322. /*
  323. ================
  324. idConsoleLocal::ClearNotifyLines
  325. ================
  326. */
  327. void idConsoleLocal::ClearNotifyLines() {
  328. int i;
  329. for ( i = 0 ; i < NUM_CON_TIMES ; i++ ) {
  330. times[i] = 0;
  331. }
  332. }
  333. /*
  334. ================
  335. idConsoleLocal::Close
  336. ================
  337. */
  338. void idConsoleLocal::Close() {
  339. keyCatching = false;
  340. SetDisplayFraction( 0 );
  341. displayFrac = 0; // don't scroll to that point, go immediately
  342. ClearNotifyLines();
  343. }
  344. /*
  345. ================
  346. idConsoleLocal::Clear
  347. ================
  348. */
  349. void idConsoleLocal::Clear() {
  350. int i;
  351. for ( i = 0 ; i < CON_TEXTSIZE ; i++ ) {
  352. text[i] = (idStr::ColorIndex(C_COLOR_CYAN)<<8) | ' ';
  353. }
  354. Bottom(); // go to end
  355. }
  356. /*
  357. ================
  358. idConsoleLocal::Dump
  359. Save the console contents out to a file
  360. ================
  361. */
  362. void idConsoleLocal::Dump( const char *fileName ) {
  363. int l, x, i;
  364. short * line;
  365. idFile *f;
  366. char buffer[LINE_WIDTH + 3];
  367. f = fileSystem->OpenFileWrite( fileName );
  368. if ( !f ) {
  369. common->Warning( "couldn't open %s", fileName );
  370. return;
  371. }
  372. // skip empty lines
  373. l = current - TOTAL_LINES + 1;
  374. if ( l < 0 ) {
  375. l = 0;
  376. }
  377. for ( ; l <= current ; l++ )
  378. {
  379. line = text + ( l % TOTAL_LINES ) * LINE_WIDTH;
  380. for ( x = 0; x < LINE_WIDTH; x++ )
  381. if ( ( line[x] & 0xff ) > ' ' )
  382. break;
  383. if ( x != LINE_WIDTH )
  384. break;
  385. }
  386. // write the remaining lines
  387. for ( ; l <= current; l++ ) {
  388. line = text + ( l % TOTAL_LINES ) * LINE_WIDTH;
  389. for( i = 0; i < LINE_WIDTH; i++ ) {
  390. buffer[i] = line[i] & 0xff;
  391. }
  392. for ( x = LINE_WIDTH-1; x >= 0; x-- ) {
  393. if ( buffer[x] <= ' ' ) {
  394. buffer[x] = 0;
  395. } else {
  396. break;
  397. }
  398. }
  399. buffer[x+1] = '\r';
  400. buffer[x+2] = '\n';
  401. buffer[x+3] = 0;
  402. f->Write( buffer, strlen( buffer ) );
  403. }
  404. fileSystem->CloseFile( f );
  405. }
  406. /*
  407. ================
  408. idConsoleLocal::PageUp
  409. ================
  410. */
  411. void idConsoleLocal::PageUp( void ) {
  412. display -= 2;
  413. if ( current - display >= TOTAL_LINES ) {
  414. display = current - TOTAL_LINES + 1;
  415. }
  416. }
  417. /*
  418. ================
  419. idConsoleLocal::PageDown
  420. ================
  421. */
  422. void idConsoleLocal::PageDown( void ) {
  423. display += 2;
  424. if ( display > current ) {
  425. display = current;
  426. }
  427. }
  428. /*
  429. ================
  430. idConsoleLocal::Top
  431. ================
  432. */
  433. void idConsoleLocal::Top( void ) {
  434. display = 0;
  435. }
  436. /*
  437. ================
  438. idConsoleLocal::Bottom
  439. ================
  440. */
  441. void idConsoleLocal::Bottom( void ) {
  442. display = current;
  443. }
  444. /*
  445. =============================================================================
  446. CONSOLE LINE EDITING
  447. ==============================================================================
  448. */
  449. /*
  450. ====================
  451. KeyDownEvent
  452. Handles history and console scrollback
  453. ====================
  454. */
  455. void idConsoleLocal::KeyDownEvent( int key ) {
  456. // Execute F key bindings
  457. if ( key >= K_F1 && key <= K_F12 ) {
  458. idKeyInput::ExecKeyBinding( key );
  459. return;
  460. }
  461. // ctrl-L clears screen
  462. if ( key == 'l' && idKeyInput::IsDown( K_CTRL ) ) {
  463. Clear();
  464. return;
  465. }
  466. // enter finishes the line
  467. if ( key == K_ENTER || key == K_KP_ENTER ) {
  468. common->Printf ( "]%s\n", consoleField.GetBuffer() );
  469. cmdSystem->BufferCommandText( CMD_EXEC_APPEND, consoleField.GetBuffer() ); // valid command
  470. cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "\n" );
  471. // copy line to history buffer
  472. historyEditLines[nextHistoryLine % COMMAND_HISTORY] = consoleField;
  473. nextHistoryLine++;
  474. historyLine = nextHistoryLine;
  475. consoleField.Clear();
  476. consoleField.SetWidthInChars( LINE_WIDTH );
  477. session->UpdateScreen();// force an update, because the command
  478. // may take some time
  479. return;
  480. }
  481. // command completion
  482. if ( key == K_TAB ) {
  483. consoleField.AutoComplete();
  484. return;
  485. }
  486. // command history (ctrl-p ctrl-n for unix style)
  487. if ( ( key == K_UPARROW ) ||
  488. ( ( tolower(key) == 'p' ) && idKeyInput::IsDown( K_CTRL ) ) ) {
  489. if ( nextHistoryLine - historyLine < COMMAND_HISTORY && historyLine > 0 ) {
  490. historyLine--;
  491. }
  492. consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
  493. return;
  494. }
  495. if ( ( key == K_DOWNARROW ) ||
  496. ( ( tolower( key ) == 'n' ) && idKeyInput::IsDown( K_CTRL ) ) ) {
  497. if ( historyLine == nextHistoryLine ) {
  498. return;
  499. }
  500. historyLine++;
  501. consoleField = historyEditLines[ historyLine % COMMAND_HISTORY ];
  502. return;
  503. }
  504. // console scrolling
  505. if ( key == K_PGUP ) {
  506. PageUp();
  507. lastKeyEvent = eventLoop->Milliseconds();
  508. nextKeyEvent = CONSOLE_FIRSTREPEAT;
  509. return;
  510. }
  511. if ( key == K_PGDN ) {
  512. PageDown();
  513. lastKeyEvent = eventLoop->Milliseconds();
  514. nextKeyEvent = CONSOLE_FIRSTREPEAT;
  515. return;
  516. }
  517. if ( key == K_MWHEELUP ) {
  518. PageUp();
  519. return;
  520. }
  521. if ( key == K_MWHEELDOWN ) {
  522. PageDown();
  523. return;
  524. }
  525. // ctrl-home = top of console
  526. if ( key == K_HOME && idKeyInput::IsDown( K_CTRL ) ) {
  527. Top();
  528. return;
  529. }
  530. // ctrl-end = bottom of console
  531. if ( key == K_END && idKeyInput::IsDown( K_CTRL ) ) {
  532. Bottom();
  533. return;
  534. }
  535. // pass to the normal editline routine
  536. consoleField.KeyDownEvent( key );
  537. }
  538. /*
  539. ==============
  540. Scroll
  541. deals with scrolling text because we don't have key repeat
  542. ==============
  543. */
  544. void idConsoleLocal::Scroll( ) {
  545. if (lastKeyEvent == -1 || (lastKeyEvent+200) > eventLoop->Milliseconds()) {
  546. return;
  547. }
  548. // console scrolling
  549. if ( idKeyInput::IsDown( K_PGUP ) ) {
  550. PageUp();
  551. nextKeyEvent = CONSOLE_REPEAT;
  552. return;
  553. }
  554. if ( idKeyInput::IsDown( K_PGDN ) ) {
  555. PageDown();
  556. nextKeyEvent = CONSOLE_REPEAT;
  557. return;
  558. }
  559. }
  560. /*
  561. ==============
  562. SetDisplayFraction
  563. Causes the console to start opening the desired amount.
  564. ==============
  565. */
  566. void idConsoleLocal::SetDisplayFraction( float frac ) {
  567. finalFrac = frac;
  568. fracTime = com_frameTime;
  569. }
  570. /*
  571. ==============
  572. UpdateDisplayFraction
  573. Scrolls the console up or down based on conspeed
  574. ==============
  575. */
  576. void idConsoleLocal::UpdateDisplayFraction( void ) {
  577. if ( con_speed.GetFloat() <= 0.1f ) {
  578. fracTime = com_frameTime;
  579. displayFrac = finalFrac;
  580. return;
  581. }
  582. // scroll towards the destination height
  583. if ( finalFrac < displayFrac ) {
  584. displayFrac -= con_speed.GetFloat() * ( com_frameTime - fracTime ) * 0.001f;
  585. if ( finalFrac > displayFrac ) {
  586. displayFrac = finalFrac;
  587. }
  588. fracTime = com_frameTime;
  589. } else if ( finalFrac > displayFrac ) {
  590. displayFrac += con_speed.GetFloat() * ( com_frameTime - fracTime ) * 0.001f;
  591. if ( finalFrac < displayFrac ) {
  592. displayFrac = finalFrac;
  593. }
  594. fracTime = com_frameTime;
  595. }
  596. }
  597. /*
  598. ==============
  599. ProcessEvent
  600. ==============
  601. */
  602. bool idConsoleLocal::ProcessEvent( const sysEvent_t *event, bool forceAccept ) {
  603. bool consoleKey;
  604. consoleKey = event->evType == SE_KEY && ( event->evValue == Sys_GetConsoleKey( false ) || event->evValue == Sys_GetConsoleKey( true ) );
  605. #if ID_CONSOLE_LOCK
  606. // If the console's not already down, and we have it turned off, check for ctrl+alt
  607. if ( !keyCatching && !com_allowConsole.GetBool() ) {
  608. if ( !idKeyInput::IsDown( K_CTRL ) || !idKeyInput::IsDown( K_ALT ) ) {
  609. consoleKey = false;
  610. }
  611. }
  612. #endif
  613. // we always catch the console key event
  614. if ( !forceAccept && consoleKey ) {
  615. // ignore up events
  616. if ( event->evValue2 == 0 ) {
  617. return true;
  618. }
  619. consoleField.ClearAutoComplete();
  620. // a down event will toggle the destination lines
  621. if ( keyCatching ) {
  622. Close();
  623. Sys_GrabMouseCursor( true );
  624. cvarSystem->SetCVarBool( "ui_chat", false );
  625. } else {
  626. consoleField.Clear();
  627. keyCatching = true;
  628. if ( idKeyInput::IsDown( K_SHIFT ) ) {
  629. // if the shift key is down, don't open the console as much
  630. SetDisplayFraction( 0.2f );
  631. } else {
  632. SetDisplayFraction( 0.5f );
  633. }
  634. cvarSystem->SetCVarBool( "ui_chat", true );
  635. }
  636. return true;
  637. }
  638. // if we aren't key catching, dump all the other events
  639. if ( !forceAccept && !keyCatching ) {
  640. return false;
  641. }
  642. // handle key and character events
  643. if ( event->evType == SE_CHAR ) {
  644. // never send the console key as a character
  645. if ( event->evValue != Sys_GetConsoleKey( false ) && event->evValue != Sys_GetConsoleKey( true ) ) {
  646. consoleField.CharEvent( event->evValue );
  647. }
  648. return true;
  649. }
  650. if ( event->evType == SE_KEY ) {
  651. // ignore up key events
  652. if ( event->evValue2 == 0 ) {
  653. return true;
  654. }
  655. KeyDownEvent( event->evValue );
  656. return true;
  657. }
  658. // we don't handle things like mouse, joystick, and network packets
  659. return false;
  660. }
  661. /*
  662. ==============================================================================
  663. PRINTING
  664. ==============================================================================
  665. */
  666. /*
  667. ===============
  668. Linefeed
  669. ===============
  670. */
  671. void idConsoleLocal::Linefeed() {
  672. int i;
  673. // mark time for transparent overlay
  674. if ( current >= 0 ) {
  675. times[current % NUM_CON_TIMES] = com_frameTime;
  676. }
  677. x = 0;
  678. if ( display == current ) {
  679. display++;
  680. }
  681. current++;
  682. for ( i = 0; i < LINE_WIDTH; i++ ) {
  683. text[(current%TOTAL_LINES)*LINE_WIDTH+i] = (idStr::ColorIndex(C_COLOR_CYAN)<<8) | ' ';
  684. }
  685. }
  686. /*
  687. ================
  688. Print
  689. Handles cursor positioning, line wrapping, etc
  690. ================
  691. */
  692. void idConsoleLocal::Print( const char *txt ) {
  693. int y;
  694. int c, l;
  695. int color;
  696. #ifdef ID_ALLOW_TOOLS
  697. RadiantPrint( txt );
  698. if( com_editors & EDITOR_MATERIAL ) {
  699. MaterialEditorPrintConsole(txt);
  700. }
  701. #endif
  702. color = idStr::ColorIndex( C_COLOR_CYAN );
  703. while ( (c = *(const unsigned char*)txt) != 0 ) {
  704. if ( idStr::IsColor( txt ) ) {
  705. if ( *(txt+1) == C_COLOR_DEFAULT ) {
  706. color = idStr::ColorIndex( C_COLOR_CYAN );
  707. } else {
  708. color = idStr::ColorIndex( *(txt+1) );
  709. }
  710. txt += 2;
  711. continue;
  712. }
  713. y = current % TOTAL_LINES;
  714. // if we are about to print a new word, check to see
  715. // if we should wrap to the new line
  716. if ( c > ' ' && ( x == 0 || text[y*LINE_WIDTH+x-1] <= ' ' ) ) {
  717. // count word length
  718. for (l=0 ; l< LINE_WIDTH ; l++) {
  719. if ( txt[l] <= ' ') {
  720. break;
  721. }
  722. }
  723. // word wrap
  724. if (l != LINE_WIDTH && (x + l >= LINE_WIDTH) ) {
  725. Linefeed();
  726. }
  727. }
  728. txt++;
  729. switch( c ) {
  730. case '\n':
  731. Linefeed ();
  732. break;
  733. case '\t':
  734. do {
  735. text[y*LINE_WIDTH+x] = (color << 8) | ' ';
  736. x++;
  737. if ( x >= LINE_WIDTH ) {
  738. Linefeed();
  739. x = 0;
  740. }
  741. } while ( x & 3 );
  742. break;
  743. case '\r':
  744. x = 0;
  745. break;
  746. default: // display character and advance
  747. text[y*LINE_WIDTH+x] = (color << 8) | c;
  748. x++;
  749. if ( x >= LINE_WIDTH ) {
  750. Linefeed();
  751. x = 0;
  752. }
  753. break;
  754. }
  755. }
  756. // mark time for transparent overlay
  757. if ( current >= 0 ) {
  758. times[current % NUM_CON_TIMES] = com_frameTime;
  759. }
  760. }
  761. /*
  762. ==============================================================================
  763. DRAWING
  764. ==============================================================================
  765. */
  766. /*
  767. ================
  768. DrawInput
  769. Draw the editline after a ] prompt
  770. ================
  771. */
  772. void idConsoleLocal::DrawInput() {
  773. int y, autoCompleteLength;
  774. y = vislines - ( SMALLCHAR_HEIGHT * 2 );
  775. if ( consoleField.GetAutoCompleteLength() != 0 ) {
  776. autoCompleteLength = strlen( consoleField.GetBuffer() ) - consoleField.GetAutoCompleteLength();
  777. if ( autoCompleteLength > 0 ) {
  778. renderSystem->SetColor4( .8f, .2f, .2f, .45f );
  779. renderSystem->DrawStretchPic( 2 * SMALLCHAR_WIDTH + consoleField.GetAutoCompleteLength() * SMALLCHAR_WIDTH,
  780. y + 2, autoCompleteLength * SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT - 2, 0, 0, 0, 0, whiteShader );
  781. }
  782. }
  783. renderSystem->SetColor( idStr::ColorForIndex( C_COLOR_CYAN ) );
  784. renderSystem->DrawSmallChar( 1 * SMALLCHAR_WIDTH, y, ']', localConsole.charSetShader );
  785. consoleField.Draw(2 * SMALLCHAR_WIDTH, y, SCREEN_WIDTH - 3 * SMALLCHAR_WIDTH, true, charSetShader );
  786. }
  787. /*
  788. ================
  789. DrawNotify
  790. Draws the last few lines of output transparently over the game top
  791. ================
  792. */
  793. void idConsoleLocal::DrawNotify() {
  794. int x, v;
  795. short *text_p;
  796. int i;
  797. int time;
  798. int currentColor;
  799. if ( con_noPrint.GetBool() ) {
  800. return;
  801. }
  802. currentColor = idStr::ColorIndex( C_COLOR_WHITE );
  803. renderSystem->SetColor( idStr::ColorForIndex( currentColor ) );
  804. v = 0;
  805. for ( i = current-NUM_CON_TIMES+1; i <= current; i++ ) {
  806. if ( i < 0 ) {
  807. continue;
  808. }
  809. time = times[i % NUM_CON_TIMES];
  810. if ( time == 0 ) {
  811. continue;
  812. }
  813. time = com_frameTime - time;
  814. if ( time > con_notifyTime.GetFloat() * 1000 ) {
  815. continue;
  816. }
  817. text_p = text + (i % TOTAL_LINES)*LINE_WIDTH;
  818. for ( x = 0; x < LINE_WIDTH; x++ ) {
  819. if ( ( text_p[x] & 0xff ) == ' ' ) {
  820. continue;
  821. }
  822. if ( idStr::ColorIndex(text_p[x]>>8) != currentColor ) {
  823. currentColor = idStr::ColorIndex(text_p[x]>>8);
  824. renderSystem->SetColor( idStr::ColorForIndex( currentColor ) );
  825. }
  826. renderSystem->DrawSmallChar( (x+1)*SMALLCHAR_WIDTH, v, text_p[x] & 0xff, localConsole.charSetShader );
  827. }
  828. v += SMALLCHAR_HEIGHT;
  829. }
  830. renderSystem->SetColor( colorCyan );
  831. }
  832. /*
  833. ================
  834. DrawSolidConsole
  835. Draws the console with the solid background
  836. ================
  837. */
  838. void idConsoleLocal::DrawSolidConsole( float frac ) {
  839. int i, x;
  840. float y;
  841. int rows;
  842. short *text_p;
  843. int row;
  844. int lines;
  845. int currentColor;
  846. lines = idMath::FtoiFast( SCREEN_HEIGHT * frac );
  847. if ( lines <= 0 ) {
  848. return;
  849. }
  850. if ( lines > SCREEN_HEIGHT ) {
  851. lines = SCREEN_HEIGHT;
  852. }
  853. // draw the background
  854. y = frac * SCREEN_HEIGHT - 2;
  855. if ( y < 1.0f ) {
  856. y = 0.0f;
  857. } else {
  858. renderSystem->DrawStretchPic( 0, 0, SCREEN_WIDTH, y, 0, 1.0f - displayFrac, 1, 1, consoleShader );
  859. }
  860. renderSystem->SetColor( colorCyan );
  861. renderSystem->DrawStretchPic( 0, y, SCREEN_WIDTH, 2, 0, 0, 0, 0, whiteShader );
  862. renderSystem->SetColor( colorWhite );
  863. // draw the version number
  864. renderSystem->SetColor( idStr::ColorForIndex( C_COLOR_CYAN ) );
  865. //GENERATE BUILD NUMBER
  866. //build year.
  867. idStr year = __DATE__;
  868. year = year.Mid(year.Length() - 2 , 2 );
  869. //get month.
  870. idStr month;
  871. if (__DATE__[0] == 'J' && __DATE__[1] == 'a' && __DATE__[2] == 'n') month = "01";
  872. else if (__DATE__[0] == 'F' && __DATE__[1] == 'e' && __DATE__[2] == 'b') month = "02";
  873. else if (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'r') month = "03";
  874. else if (__DATE__[0] == 'A' && __DATE__[1] == 'p' && __DATE__[2] == 'r') month = "04";
  875. else if (__DATE__[0] == 'M' && __DATE__[1] == 'a' && __DATE__[2] == 'y') month = "05";
  876. else if (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'n') month = "06";
  877. else if (__DATE__[0] == 'J' && __DATE__[1] == 'u' && __DATE__[2] == 'l') month = "07";
  878. else if (__DATE__[0] == 'A' && __DATE__[1] == 'u' && __DATE__[2] == 'g') month = "08";
  879. else if (__DATE__[0] == 'S' && __DATE__[1] == 'e' && __DATE__[2] == 'p') month = "09";
  880. else if (__DATE__[0] == 'O' && __DATE__[1] == 'c' && __DATE__[2] == 't') month = "10";
  881. else if (__DATE__[0] == 'N' && __DATE__[1] == 'o' && __DATE__[2] == 'v') month = "11";
  882. else {month = "12";}
  883. //get day.
  884. idStr day = __DATE__;
  885. day = day.Mid(4 , 2 );
  886. day.StripLeading( ' ' );
  887. if (day.Length() <= 1)
  888. day = va("0%s", day.c_str()); //leading zero.
  889. //get hour.... limited to one digit because build # has a limited amount of digits
  890. int colonIndex;
  891. int k;
  892. idStr timestamp = __TIME__;
  893. for (k = 0; k < timestamp.Length(); k++)
  894. {
  895. if (timestamp[k] == ':')
  896. {
  897. colonIndex = k;
  898. break;
  899. }
  900. }
  901. timestamp = timestamp.Mid(0, colonIndex);
  902. float hour = atof(timestamp);
  903. float adjustedHour = hour / 24.0f;
  904. int intHour = idMath::ClampInt(0,9,adjustedHour * 10);
  905. idStr buildnumber = va("%s%s%s%d", year.c_str(), month.c_str(), day.c_str(), intHour);
  906. uint result;
  907. result = atoi( buildnumber.c_str() );
  908. idStr version = va("%s.%u", ENGINE_VERSION, result);
  909. i = version.Length() + 1;
  910. for ( x = 0; x < i; x++ )
  911. {
  912. renderSystem->DrawSmallChar( SCREEN_WIDTH - ( i - x ) * SMALLCHAR_WIDTH,
  913. (lines-(SMALLCHAR_HEIGHT+SMALLCHAR_HEIGHT/2)), version[x], localConsole.charSetShader );
  914. }
  915. // draw the text
  916. vislines = lines;
  917. rows = (lines-SMALLCHAR_WIDTH)/SMALLCHAR_WIDTH; // rows of text to draw
  918. y = lines - (SMALLCHAR_HEIGHT*3);
  919. // draw from the bottom up
  920. if ( display != current ) {
  921. // draw arrows to show the buffer is backscrolled
  922. renderSystem->SetColor( idStr::ColorForIndex( C_COLOR_CYAN ) );
  923. for ( x = 0; x < LINE_WIDTH; x += 4 ) {
  924. renderSystem->DrawSmallChar( (x+1)*SMALLCHAR_WIDTH, idMath::FtoiFast( y ), '^', localConsole.charSetShader );
  925. }
  926. y -= SMALLCHAR_HEIGHT;
  927. rows--;
  928. }
  929. row = display;
  930. if ( x == 0 ) {
  931. row--;
  932. }
  933. currentColor = idStr::ColorIndex( C_COLOR_WHITE );
  934. renderSystem->SetColor( idStr::ColorForIndex( currentColor ) );
  935. for ( i = 0; i < rows; i++, y -= SMALLCHAR_HEIGHT, row-- ) {
  936. if ( row < 0 ) {
  937. break;
  938. }
  939. if ( current - row >= TOTAL_LINES ) {
  940. // past scrollback wrap point
  941. continue;
  942. }
  943. text_p = text + (row % TOTAL_LINES)*LINE_WIDTH;
  944. for ( x = 0; x < LINE_WIDTH; x++ ) {
  945. if ( ( text_p[x] & 0xff ) == ' ' ) {
  946. continue;
  947. }
  948. if ( idStr::ColorIndex(text_p[x]>>8) != currentColor ) {
  949. currentColor = idStr::ColorIndex(text_p[x]>>8);
  950. renderSystem->SetColor( idStr::ColorForIndex( currentColor ) );
  951. }
  952. renderSystem->DrawSmallChar( (x+1)*SMALLCHAR_WIDTH, idMath::FtoiFast( y ), text_p[x] & 0xff, localConsole.charSetShader );
  953. }
  954. }
  955. // draw the input prompt, user text, and cursor if desired
  956. DrawInput();
  957. renderSystem->SetColor( colorCyan );
  958. }
  959. /*
  960. ==============
  961. Draw
  962. ForceFullScreen is used by the editor
  963. ==============
  964. */
  965. void idConsoleLocal::Draw( bool forceFullScreen ) {
  966. float y = 0.0f;
  967. if ( !charSetShader ) {
  968. return;
  969. }
  970. if ( forceFullScreen ) {
  971. // if we are forced full screen because of a disconnect,
  972. // we want the console closed when we go back to a session state
  973. Close();
  974. // we are however catching keyboard input
  975. keyCatching = true;
  976. }
  977. Scroll();
  978. UpdateDisplayFraction();
  979. if ( forceFullScreen ) {
  980. DrawSolidConsole( 1.0f );
  981. } else if ( displayFrac ) {
  982. DrawSolidConsole( displayFrac );
  983. } else {
  984. // only draw the notify lines if the developer cvar is set,
  985. // or we are a debug build
  986. if ( !con_noPrint.GetBool() ) {
  987. DrawNotify();
  988. }
  989. }
  990. if ( com_showFPS.GetBool() ) {
  991. y = SCR_DrawFPS( 0 );
  992. }
  993. if ( com_showMemoryUsage.GetBool() ) {
  994. y = SCR_DrawMemoryUsage( y );
  995. }
  996. if ( com_showAsyncStats.GetBool() ) {
  997. y = SCR_DrawAsyncStats( y );
  998. }
  999. if ( com_showSoundDecoders.GetBool() ) {
  1000. y = SCR_DrawSoundDecoders( y );
  1001. }
  1002. }