Console.cpp 31 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  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. #pragma hdrstop
  21. #include "../idlib/precompiled.h"
  22. #include "ConsoleHistory.h"
  23. #include "../renderer/ResolutionScale.h"
  24. #include "Common_local.h"
  25. #define CON_TEXTSIZE 0x30000
  26. #define NUM_CON_TIMES 4
  27. #define CONSOLE_FIRSTREPEAT 200
  28. #define CONSOLE_REPEAT 100
  29. #define COMMAND_HISTORY 64
  30. struct overlayText_t {
  31. idStr text;
  32. justify_t justify;
  33. int time;
  34. };
  35. // the console will query the cvar and command systems for
  36. // command completion information
  37. class idConsoleLocal : public idConsole {
  38. public:
  39. virtual void Init();
  40. virtual void Shutdown();
  41. virtual bool ProcessEvent( const sysEvent_t * event, bool forceAccept );
  42. virtual bool Active();
  43. virtual void ClearNotifyLines();
  44. virtual void Close();
  45. virtual void Print( const char *text );
  46. virtual void Draw( bool forceFullScreen );
  47. virtual void PrintOverlay( idOverlayHandle &handle, justify_t justify, const char *text, ... );
  48. virtual idDebugGraph * CreateGraph( int numItems );
  49. virtual void DestroyGraph( idDebugGraph * graph );
  50. void Dump( const char *toFile );
  51. void Clear();
  52. private:
  53. void KeyDownEvent( int key );
  54. void Linefeed();
  55. void PageUp();
  56. void PageDown();
  57. void Top();
  58. void Bottom();
  59. void DrawInput();
  60. void DrawNotify();
  61. void DrawSolidConsole( float frac );
  62. void Scroll();
  63. void SetDisplayFraction( float frac );
  64. void UpdateDisplayFraction();
  65. void DrawTextLeftAlign( float x, float &y, const char *text, ... );
  66. void DrawTextRightAlign( float x, float &y, const char *text, ... );
  67. float DrawFPS( float y );
  68. float DrawMemoryUsage( float y );
  69. void DrawOverlayText( float & leftY, float & rightY, float & centerY );
  70. void DrawDebugGraphs();
  71. //============================
  72. // allow these constants to be adjusted for HMD
  73. int LOCALSAFE_LEFT;
  74. int LOCALSAFE_RIGHT;
  75. int LOCALSAFE_TOP;
  76. int LOCALSAFE_BOTTOM;
  77. int LOCALSAFE_WIDTH;
  78. int LOCALSAFE_HEIGHT;
  79. int LINE_WIDTH;
  80. int TOTAL_LINES;
  81. bool keyCatching;
  82. short text[CON_TEXTSIZE];
  83. int current; // line where next message will be printed
  84. int x; // offset in current line for next print
  85. int display; // bottom of console displays this line
  86. int lastKeyEvent; // time of last key event for scroll delay
  87. int nextKeyEvent; // keyboard repeat rate
  88. float displayFrac; // approaches finalFrac at con_speed
  89. float finalFrac; // 0.0 to 1.0 lines of console to display
  90. int fracTime; // time of last displayFrac update
  91. int vislines; // in scanlines
  92. int times[NUM_CON_TIMES]; // cls.realtime time the line was generated
  93. // for transparent notify lines
  94. idVec4 color;
  95. idEditField historyEditLines[COMMAND_HISTORY];
  96. int nextHistoryLine;// the last line in the history buffer, not masked
  97. int historyLine; // the line being displayed from history buffer
  98. // will be <= nextHistoryLine
  99. idEditField consoleField;
  100. idList< overlayText_t > overlayText;
  101. idList< idDebugGraph *> debugGraphs;
  102. static idCVar con_speed;
  103. static idCVar con_notifyTime;
  104. static idCVar con_noPrint;
  105. };
  106. static idConsoleLocal localConsole;
  107. idConsole * console = &localConsole;
  108. idCVar idConsoleLocal::con_speed( "con_speed", "3", CVAR_SYSTEM, "speed at which the console moves up and down" );
  109. idCVar idConsoleLocal::con_notifyTime( "con_notifyTime", "3", CVAR_SYSTEM, "time messages are displayed onscreen when console is pulled up" );
  110. #ifdef DEBUG
  111. 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" );
  112. #else
  113. 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" );
  114. #endif
  115. /*
  116. =============================================================================
  117. Misc stats
  118. =============================================================================
  119. */
  120. /*
  121. ==================
  122. idConsoleLocal::DrawTextLeftAlign
  123. ==================
  124. */
  125. void idConsoleLocal::DrawTextLeftAlign( float x, float &y, const char *text, ... ) {
  126. char string[MAX_STRING_CHARS];
  127. va_list argptr;
  128. va_start( argptr, text );
  129. idStr::vsnPrintf( string, sizeof( string ), text, argptr );
  130. va_end( argptr );
  131. renderSystem->DrawSmallStringExt( x, y + 2, string, colorWhite, true );
  132. y += SMALLCHAR_HEIGHT + 4;
  133. }
  134. /*
  135. ==================
  136. idConsoleLocal::DrawTextRightAlign
  137. ==================
  138. */
  139. void idConsoleLocal::DrawTextRightAlign( float x, float &y, const char *text, ... ) {
  140. char string[MAX_STRING_CHARS];
  141. va_list argptr;
  142. va_start( argptr, text );
  143. int i = idStr::vsnPrintf( string, sizeof( string ), text, argptr );
  144. va_end( argptr );
  145. renderSystem->DrawSmallStringExt( x - i * SMALLCHAR_WIDTH, y + 2, string, colorWhite, true );
  146. y += SMALLCHAR_HEIGHT + 4;
  147. }
  148. /*
  149. ==================
  150. idConsoleLocal::DrawFPS
  151. ==================
  152. */
  153. #define FPS_FRAMES 6
  154. float idConsoleLocal::DrawFPS( float y ) {
  155. static int previousTimes[FPS_FRAMES];
  156. static int index;
  157. static int previous;
  158. // don't use serverTime, because that will be drifting to
  159. // correct for internet lag changes, timescales, timedemos, etc
  160. int t = Sys_Milliseconds();
  161. int frameTime = t - previous;
  162. previous = t;
  163. previousTimes[index % FPS_FRAMES] = frameTime;
  164. index++;
  165. if ( index > FPS_FRAMES ) {
  166. // average multiple frames together to smooth changes out a bit
  167. int total = 0;
  168. for ( int i = 0 ; i < FPS_FRAMES ; i++ ) {
  169. total += previousTimes[i];
  170. }
  171. if ( !total ) {
  172. total = 1;
  173. }
  174. int fps = 1000000 * FPS_FRAMES / total;
  175. fps = ( fps + 500 ) / 1000;
  176. const char * s = va( "%ifps", fps );
  177. int w = strlen( s ) * BIGCHAR_WIDTH;
  178. renderSystem->DrawBigStringExt( LOCALSAFE_RIGHT - w, idMath::Ftoi( y ) + 2, s, colorWhite, true );
  179. }
  180. y += BIGCHAR_HEIGHT + 4;
  181. // print the resolution scale so we can tell when we are at reduced resolution
  182. idStr resolutionText;
  183. resolutionScale.GetConsoleText( resolutionText );
  184. int w = resolutionText.Length() * BIGCHAR_WIDTH;
  185. renderSystem->DrawBigStringExt( LOCALSAFE_RIGHT - w, idMath::Ftoi( y ) + 2, resolutionText.c_str(), colorWhite, true );
  186. const int gameThreadTotalTime = commonLocal.GetGameThreadTotalTime();
  187. const int gameThreadGameTime = commonLocal.GetGameThreadGameTime();
  188. const int gameThreadRenderTime = commonLocal.GetGameThreadRenderTime();
  189. const int rendererBackEndTime = commonLocal.GetRendererBackEndMicroseconds();
  190. const int rendererShadowsTime = commonLocal.GetRendererShadowsMicroseconds();
  191. const int rendererGPUIdleTime = commonLocal.GetRendererIdleMicroseconds();
  192. const int rendererGPUTime = commonLocal.GetRendererGPUMicroseconds();
  193. const int maxTime = 16;
  194. y += SMALLCHAR_HEIGHT + 4;
  195. idStr timeStr;
  196. timeStr.Format( "%sG+RF: %4d", gameThreadTotalTime > maxTime ? S_COLOR_RED : "", gameThreadTotalTime );
  197. w = timeStr.LengthWithoutColors() * SMALLCHAR_WIDTH;
  198. renderSystem->DrawSmallStringExt( LOCALSAFE_RIGHT - w, idMath::Ftoi( y ) + 2, timeStr.c_str(), colorWhite, false );
  199. y += SMALLCHAR_HEIGHT + 4;
  200. timeStr.Format( "%sG: %4d", gameThreadGameTime > maxTime ? S_COLOR_RED : "", gameThreadGameTime );
  201. w = timeStr.LengthWithoutColors() * SMALLCHAR_WIDTH;
  202. renderSystem->DrawSmallStringExt( LOCALSAFE_RIGHT - w, idMath::Ftoi( y ) + 2, timeStr.c_str(), colorWhite, false );
  203. y += SMALLCHAR_HEIGHT + 4;
  204. timeStr.Format( "%sRF: %4d", gameThreadRenderTime > maxTime ? S_COLOR_RED : "", gameThreadRenderTime );
  205. w = timeStr.LengthWithoutColors() * SMALLCHAR_WIDTH;
  206. renderSystem->DrawSmallStringExt( LOCALSAFE_RIGHT - w, idMath::Ftoi( y ) + 2, timeStr.c_str(), colorWhite, false );
  207. y += SMALLCHAR_HEIGHT + 4;
  208. timeStr.Format( "%sRB: %4.1f", rendererBackEndTime > maxTime * 1000 ? S_COLOR_RED : "", rendererBackEndTime / 1000.0f );
  209. w = timeStr.LengthWithoutColors() * SMALLCHAR_WIDTH;
  210. renderSystem->DrawSmallStringExt( LOCALSAFE_RIGHT - w, idMath::Ftoi( y ) + 2, timeStr.c_str(), colorWhite, false );
  211. y += SMALLCHAR_HEIGHT + 4;
  212. timeStr.Format( "%sSV: %4.1f", rendererShadowsTime > maxTime * 1000 ? S_COLOR_RED : "", rendererShadowsTime / 1000.0f );
  213. w = timeStr.LengthWithoutColors() * SMALLCHAR_WIDTH;
  214. renderSystem->DrawSmallStringExt( LOCALSAFE_RIGHT - w, idMath::Ftoi( y ) + 2, timeStr.c_str(), colorWhite, false );
  215. y += SMALLCHAR_HEIGHT + 4;
  216. timeStr.Format( "%sIDLE: %4.1f", rendererGPUIdleTime > maxTime * 1000 ? S_COLOR_RED : "", rendererGPUIdleTime / 1000.0f );
  217. w = timeStr.LengthWithoutColors() * SMALLCHAR_WIDTH;
  218. renderSystem->DrawSmallStringExt( LOCALSAFE_RIGHT - w, idMath::Ftoi( y ) + 2, timeStr.c_str(), colorWhite, false );
  219. y += SMALLCHAR_HEIGHT + 4;
  220. timeStr.Format( "%sGPU: %4.1f", rendererGPUTime > maxTime * 1000 ? S_COLOR_RED : "", rendererGPUTime / 1000.0f );
  221. w = timeStr.LengthWithoutColors() * SMALLCHAR_WIDTH;
  222. renderSystem->DrawSmallStringExt( LOCALSAFE_RIGHT - w, idMath::Ftoi( y ) + 2, timeStr.c_str(), colorWhite, false );
  223. return y + BIGCHAR_HEIGHT + 4;
  224. }
  225. /*
  226. ==================
  227. idConsoleLocal::DrawMemoryUsage
  228. ==================
  229. */
  230. float idConsoleLocal::DrawMemoryUsage( float y ) {
  231. return y;
  232. }
  233. //=========================================================================
  234. /*
  235. ==============
  236. Con_Clear_f
  237. ==============
  238. */
  239. static void Con_Clear_f( const idCmdArgs &args ) {
  240. localConsole.Clear();
  241. }
  242. /*
  243. ==============
  244. Con_Dump_f
  245. ==============
  246. */
  247. static void Con_Dump_f( const idCmdArgs &args ) {
  248. if ( args.Argc() != 2 ) {
  249. common->Printf( "usage: conDump <filename>\n" );
  250. return;
  251. }
  252. idStr fileName = args.Argv(1);
  253. fileName.DefaultFileExtension(".txt");
  254. common->Printf( "Dumped console text to %s.\n", fileName.c_str() );
  255. localConsole.Dump( fileName.c_str() );
  256. }
  257. /*
  258. ==============
  259. idConsoleLocal::Init
  260. ==============
  261. */
  262. void idConsoleLocal::Init() {
  263. int i;
  264. keyCatching = false;
  265. LOCALSAFE_LEFT = 32;
  266. LOCALSAFE_RIGHT = 608;
  267. LOCALSAFE_TOP = 24;
  268. LOCALSAFE_BOTTOM = 456;
  269. LOCALSAFE_WIDTH = LOCALSAFE_RIGHT - LOCALSAFE_LEFT;
  270. LOCALSAFE_HEIGHT = LOCALSAFE_BOTTOM - LOCALSAFE_TOP;
  271. LINE_WIDTH = ( ( LOCALSAFE_WIDTH / SMALLCHAR_WIDTH ) - 2 );
  272. TOTAL_LINES = (CON_TEXTSIZE / LINE_WIDTH);
  273. lastKeyEvent = -1;
  274. nextKeyEvent = CONSOLE_FIRSTREPEAT;
  275. consoleField.Clear();
  276. consoleField.SetWidthInChars( LINE_WIDTH );
  277. for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) {
  278. historyEditLines[i].Clear();
  279. historyEditLines[i].SetWidthInChars( LINE_WIDTH );
  280. }
  281. cmdSystem->AddCommand( "clear", Con_Clear_f, CMD_FL_SYSTEM, "clears the console" );
  282. cmdSystem->AddCommand( "conDump", Con_Dump_f, CMD_FL_SYSTEM, "dumps the console text to a file" );
  283. }
  284. /*
  285. ==============
  286. idConsoleLocal::Shutdown
  287. ==============
  288. */
  289. void idConsoleLocal::Shutdown() {
  290. cmdSystem->RemoveCommand( "clear" );
  291. cmdSystem->RemoveCommand( "conDump" );
  292. debugGraphs.DeleteContents( true );
  293. }
  294. /*
  295. ================
  296. idConsoleLocal::Active
  297. ================
  298. */
  299. bool idConsoleLocal::Active() {
  300. return keyCatching;
  301. }
  302. /*
  303. ================
  304. idConsoleLocal::ClearNotifyLines
  305. ================
  306. */
  307. void idConsoleLocal::ClearNotifyLines() {
  308. int i;
  309. for ( i = 0 ; i < NUM_CON_TIMES ; i++ ) {
  310. times[i] = 0;
  311. }
  312. }
  313. /*
  314. ================
  315. idConsoleLocal::Close
  316. ================
  317. */
  318. void idConsoleLocal::Close() {
  319. keyCatching = false;
  320. SetDisplayFraction( 0 );
  321. displayFrac = 0; // don't scroll to that point, go immediately
  322. ClearNotifyLines();
  323. }
  324. /*
  325. ================
  326. idConsoleLocal::Clear
  327. ================
  328. */
  329. void idConsoleLocal::Clear() {
  330. int i;
  331. for ( i = 0 ; i < CON_TEXTSIZE ; i++ ) {
  332. text[i] = (idStr::ColorIndex(C_COLOR_CYAN)<<8) | ' ';
  333. }
  334. Bottom(); // go to end
  335. }
  336. /*
  337. ================
  338. idConsoleLocal::Dump
  339. Save the console contents out to a file
  340. ================
  341. */
  342. void idConsoleLocal::Dump( const char *fileName ) {
  343. int l, x, i;
  344. short * line;
  345. idFile *f;
  346. char * buffer = (char *)alloca( LINE_WIDTH + 3 );
  347. f = fileSystem->OpenFileWrite( fileName );
  348. if ( !f ) {
  349. common->Warning( "couldn't open %s", fileName );
  350. return;
  351. }
  352. // skip empty lines
  353. l = current - TOTAL_LINES + 1;
  354. if ( l < 0 ) {
  355. l = 0;
  356. }
  357. for ( ; l <= current ; l++ )
  358. {
  359. line = text + ( l % TOTAL_LINES ) * LINE_WIDTH;
  360. for ( x = 0; x < LINE_WIDTH; x++ )
  361. if ( ( line[x] & 0xff ) > ' ' )
  362. break;
  363. if ( x != LINE_WIDTH )
  364. break;
  365. }
  366. // write the remaining lines
  367. for ( ; l <= current; l++ ) {
  368. line = text + ( l % TOTAL_LINES ) * LINE_WIDTH;
  369. for( i = 0; i < LINE_WIDTH; i++ ) {
  370. buffer[i] = line[i] & 0xff;
  371. }
  372. for ( x = LINE_WIDTH-1; x >= 0; x-- ) {
  373. if ( buffer[x] <= ' ' ) {
  374. buffer[x] = 0;
  375. } else {
  376. break;
  377. }
  378. }
  379. buffer[x+1] = '\r';
  380. buffer[x+2] = '\n';
  381. buffer[x+3] = 0;
  382. f->Write( buffer, strlen( buffer ) );
  383. }
  384. fileSystem->CloseFile( f );
  385. }
  386. /*
  387. ================
  388. idConsoleLocal::PageUp
  389. ================
  390. */
  391. void idConsoleLocal::PageUp() {
  392. display -= 2;
  393. if ( current - display >= TOTAL_LINES ) {
  394. display = current - TOTAL_LINES + 1;
  395. }
  396. }
  397. /*
  398. ================
  399. idConsoleLocal::PageDown
  400. ================
  401. */
  402. void idConsoleLocal::PageDown() {
  403. display += 2;
  404. if ( display > current ) {
  405. display = current;
  406. }
  407. }
  408. /*
  409. ================
  410. idConsoleLocal::Top
  411. ================
  412. */
  413. void idConsoleLocal::Top() {
  414. display = 0;
  415. }
  416. /*
  417. ================
  418. idConsoleLocal::Bottom
  419. ================
  420. */
  421. void idConsoleLocal::Bottom() {
  422. display = current;
  423. }
  424. /*
  425. =============================================================================
  426. CONSOLE LINE EDITING
  427. ==============================================================================
  428. */
  429. /*
  430. ====================
  431. KeyDownEvent
  432. Handles history and console scrollback
  433. ====================
  434. */
  435. void idConsoleLocal::KeyDownEvent( int key ) {
  436. // Execute F key bindings
  437. if ( key >= K_F1 && key <= K_F12 ) {
  438. idKeyInput::ExecKeyBinding( key );
  439. return;
  440. }
  441. // ctrl-L clears screen
  442. if ( key == K_L && ( idKeyInput::IsDown( K_LCTRL ) || idKeyInput::IsDown( K_RCTRL ) ) ) {
  443. Clear();
  444. return;
  445. }
  446. // enter finishes the line
  447. if ( key == K_ENTER || key == K_KP_ENTER ) {
  448. common->Printf ( "]%s\n", consoleField.GetBuffer() );
  449. cmdSystem->BufferCommandText( CMD_EXEC_APPEND, consoleField.GetBuffer() ); // valid command
  450. cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "\n" );
  451. // copy line to history buffer
  452. if ( consoleField.GetBuffer()[ 0 ] != '\n' && consoleField.GetBuffer()[ 0 ] != '\0' ) {
  453. consoleHistory.AddToHistory( consoleField.GetBuffer() );
  454. }
  455. consoleField.Clear();
  456. consoleField.SetWidthInChars( LINE_WIDTH );
  457. const bool captureToImage = false;
  458. common->UpdateScreen( captureToImage );// force an update, because the command
  459. // may take some time
  460. return;
  461. }
  462. // command completion
  463. if ( key == K_TAB ) {
  464. consoleField.AutoComplete();
  465. return;
  466. }
  467. // command history (ctrl-p ctrl-n for unix style)
  468. if ( ( key == K_UPARROW ) ||
  469. ( key == K_P && ( idKeyInput::IsDown( K_LCTRL ) || idKeyInput::IsDown( K_RCTRL ) ) ) ) {
  470. idStr hist = consoleHistory.RetrieveFromHistory( true );
  471. if ( !hist.IsEmpty() ) {
  472. consoleField.SetBuffer( hist );
  473. }
  474. return;
  475. }
  476. if ( ( key == K_DOWNARROW ) ||
  477. ( key == K_N && ( idKeyInput::IsDown( K_LCTRL ) || idKeyInput::IsDown( K_RCTRL ) ) ) ) {
  478. idStr hist = consoleHistory.RetrieveFromHistory( false );
  479. if ( !hist.IsEmpty() ) {
  480. consoleField.SetBuffer( hist );
  481. }
  482. return;
  483. }
  484. // console scrolling
  485. if ( key == K_PGUP ) {
  486. PageUp();
  487. lastKeyEvent = eventLoop->Milliseconds();
  488. nextKeyEvent = CONSOLE_FIRSTREPEAT;
  489. return;
  490. }
  491. if ( key == K_PGDN ) {
  492. PageDown();
  493. lastKeyEvent = eventLoop->Milliseconds();
  494. nextKeyEvent = CONSOLE_FIRSTREPEAT;
  495. return;
  496. }
  497. if ( key == K_MWHEELUP ) {
  498. PageUp();
  499. return;
  500. }
  501. if ( key == K_MWHEELDOWN ) {
  502. PageDown();
  503. return;
  504. }
  505. // ctrl-home = top of console
  506. if ( key == K_HOME && ( idKeyInput::IsDown( K_LCTRL ) || idKeyInput::IsDown( K_RCTRL ) ) ) {
  507. Top();
  508. return;
  509. }
  510. // ctrl-end = bottom of console
  511. if ( key == K_END && ( idKeyInput::IsDown( K_LCTRL ) || idKeyInput::IsDown( K_RCTRL ) ) ) {
  512. Bottom();
  513. return;
  514. }
  515. // pass to the normal editline routine
  516. consoleField.KeyDownEvent( key );
  517. }
  518. /*
  519. ==============
  520. Scroll
  521. deals with scrolling text because we don't have key repeat
  522. ==============
  523. */
  524. void idConsoleLocal::Scroll( ) {
  525. if (lastKeyEvent == -1 || (lastKeyEvent+200) > eventLoop->Milliseconds()) {
  526. return;
  527. }
  528. // console scrolling
  529. if ( idKeyInput::IsDown( K_PGUP ) ) {
  530. PageUp();
  531. nextKeyEvent = CONSOLE_REPEAT;
  532. return;
  533. }
  534. if ( idKeyInput::IsDown( K_PGDN ) ) {
  535. PageDown();
  536. nextKeyEvent = CONSOLE_REPEAT;
  537. return;
  538. }
  539. }
  540. /*
  541. ==============
  542. SetDisplayFraction
  543. Causes the console to start opening the desired amount.
  544. ==============
  545. */
  546. void idConsoleLocal::SetDisplayFraction( float frac ) {
  547. finalFrac = frac;
  548. fracTime = Sys_Milliseconds();
  549. }
  550. /*
  551. ==============
  552. UpdateDisplayFraction
  553. Scrolls the console up or down based on conspeed
  554. ==============
  555. */
  556. void idConsoleLocal::UpdateDisplayFraction() {
  557. if ( con_speed.GetFloat() <= 0.1f ) {
  558. fracTime = Sys_Milliseconds();
  559. displayFrac = finalFrac;
  560. return;
  561. }
  562. // scroll towards the destination height
  563. if ( finalFrac < displayFrac ) {
  564. displayFrac -= con_speed.GetFloat() * ( Sys_Milliseconds() - fracTime ) * 0.001f;
  565. if ( finalFrac > displayFrac ) {
  566. displayFrac = finalFrac;
  567. }
  568. fracTime = Sys_Milliseconds();
  569. } else if ( finalFrac > displayFrac ) {
  570. displayFrac += con_speed.GetFloat() * ( Sys_Milliseconds() - fracTime ) * 0.001f;
  571. if ( finalFrac < displayFrac ) {
  572. displayFrac = finalFrac;
  573. }
  574. fracTime = Sys_Milliseconds();
  575. }
  576. }
  577. /*
  578. ==============
  579. ProcessEvent
  580. ==============
  581. */
  582. bool idConsoleLocal::ProcessEvent( const sysEvent_t *event, bool forceAccept ) {
  583. const bool consoleKey = event->evType == SE_KEY && event->evValue == K_GRAVE && com_allowConsole.GetBool();
  584. // we always catch the console key event
  585. if ( !forceAccept && consoleKey ) {
  586. // ignore up events
  587. if ( event->evValue2 == 0 ) {
  588. return true;
  589. }
  590. consoleField.ClearAutoComplete();
  591. // a down event will toggle the destination lines
  592. if ( keyCatching ) {
  593. Close();
  594. Sys_GrabMouseCursor( true );
  595. } else {
  596. consoleField.Clear();
  597. keyCatching = true;
  598. if ( idKeyInput::IsDown( K_LSHIFT ) || idKeyInput::IsDown( K_RSHIFT ) ) {
  599. // if the shift key is down, don't open the console as much
  600. SetDisplayFraction( 0.2f );
  601. } else {
  602. SetDisplayFraction( 0.5f );
  603. }
  604. }
  605. return true;
  606. }
  607. // if we aren't key catching, dump all the other events
  608. if ( !forceAccept && !keyCatching ) {
  609. return false;
  610. }
  611. // handle key and character events
  612. if ( event->evType == SE_CHAR ) {
  613. // never send the console key as a character
  614. if ( event->evValue != '`' && event->evValue != '~' ) {
  615. consoleField.CharEvent( event->evValue );
  616. }
  617. return true;
  618. }
  619. if ( event->evType == SE_KEY ) {
  620. // ignore up key events
  621. if ( event->evValue2 == 0 ) {
  622. return true;
  623. }
  624. KeyDownEvent( event->evValue );
  625. return true;
  626. }
  627. // we don't handle things like mouse, joystick, and network packets
  628. return false;
  629. }
  630. /*
  631. ==============================================================================
  632. PRINTING
  633. ==============================================================================
  634. */
  635. /*
  636. ===============
  637. Linefeed
  638. ===============
  639. */
  640. void idConsoleLocal::Linefeed() {
  641. int i;
  642. // mark time for transparent overlay
  643. if ( current >= 0 ) {
  644. times[current % NUM_CON_TIMES] = Sys_Milliseconds();
  645. }
  646. x = 0;
  647. if ( display == current ) {
  648. display++;
  649. }
  650. current++;
  651. for ( i = 0; i < LINE_WIDTH; i++ ) {
  652. int offset = ( (unsigned int)current % TOTAL_LINES ) * LINE_WIDTH + i;
  653. text[offset] = (idStr::ColorIndex(C_COLOR_CYAN)<<8) | ' ';
  654. }
  655. }
  656. /*
  657. ================
  658. Print
  659. Handles cursor positioning, line wrapping, etc
  660. ================
  661. */
  662. void idConsoleLocal::Print( const char *txt ) {
  663. int y;
  664. int c, l;
  665. int color;
  666. if ( TOTAL_LINES == 0 ) {
  667. // not yet initialized
  668. return;
  669. }
  670. color = idStr::ColorIndex( C_COLOR_CYAN );
  671. while ( (c = *(const unsigned char*)txt) != 0 ) {
  672. if ( idStr::IsColor( txt ) ) {
  673. if ( *(txt+1) == C_COLOR_DEFAULT ) {
  674. color = idStr::ColorIndex( C_COLOR_CYAN );
  675. } else {
  676. color = idStr::ColorIndex( *(txt+1) );
  677. }
  678. txt += 2;
  679. continue;
  680. }
  681. y = current % TOTAL_LINES;
  682. // if we are about to print a new word, check to see
  683. // if we should wrap to the new line
  684. if ( c > ' ' && ( x == 0 || text[y*LINE_WIDTH+x-1] <= ' ' ) ) {
  685. // count word length
  686. for (l=0 ; l< LINE_WIDTH ; l++) {
  687. if ( txt[l] <= ' ') {
  688. break;
  689. }
  690. }
  691. // word wrap
  692. if (l != LINE_WIDTH && (x + l >= LINE_WIDTH) ) {
  693. Linefeed();
  694. }
  695. }
  696. txt++;
  697. switch( c ) {
  698. case '\n':
  699. Linefeed ();
  700. break;
  701. case '\t':
  702. do {
  703. text[y*LINE_WIDTH+x] = (color << 8) | ' ';
  704. x++;
  705. if ( x >= LINE_WIDTH ) {
  706. Linefeed();
  707. x = 0;
  708. }
  709. } while ( x & 3 );
  710. break;
  711. case '\r':
  712. x = 0;
  713. break;
  714. default: // display character and advance
  715. text[y*LINE_WIDTH+x] = (color << 8) | c;
  716. x++;
  717. if ( x >= LINE_WIDTH ) {
  718. Linefeed();
  719. x = 0;
  720. }
  721. break;
  722. }
  723. }
  724. // mark time for transparent overlay
  725. if ( current >= 0 ) {
  726. times[current % NUM_CON_TIMES] = Sys_Milliseconds();
  727. }
  728. }
  729. /*
  730. ==============================================================================
  731. DRAWING
  732. ==============================================================================
  733. */
  734. /*
  735. ================
  736. DrawInput
  737. Draw the editline after a ] prompt
  738. ================
  739. */
  740. void idConsoleLocal::DrawInput() {
  741. int y, autoCompleteLength;
  742. y = vislines - ( SMALLCHAR_HEIGHT * 2 );
  743. if ( consoleField.GetAutoCompleteLength() != 0 ) {
  744. autoCompleteLength = strlen( consoleField.GetBuffer() ) - consoleField.GetAutoCompleteLength();
  745. if ( autoCompleteLength > 0 ) {
  746. renderSystem->DrawFilled( idVec4( 0.8f, 0.2f, 0.2f, 0.45f ),
  747. LOCALSAFE_LEFT + 2 * SMALLCHAR_WIDTH + consoleField.GetAutoCompleteLength() * SMALLCHAR_WIDTH,
  748. y + 2, autoCompleteLength * SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT - 2 );
  749. }
  750. }
  751. renderSystem->SetColor( idStr::ColorForIndex( C_COLOR_CYAN ) );
  752. renderSystem->DrawSmallChar( LOCALSAFE_LEFT + 1 * SMALLCHAR_WIDTH, y, ']' );
  753. consoleField.Draw( LOCALSAFE_LEFT + 2 * SMALLCHAR_WIDTH, y, SCREEN_WIDTH - 3 * SMALLCHAR_WIDTH, true );
  754. }
  755. /*
  756. ================
  757. DrawNotify
  758. Draws the last few lines of output transparently over the game top
  759. ================
  760. */
  761. void idConsoleLocal::DrawNotify() {
  762. int x, v;
  763. short *text_p;
  764. int i;
  765. int time;
  766. int currentColor;
  767. if ( con_noPrint.GetBool() ) {
  768. return;
  769. }
  770. currentColor = idStr::ColorIndex( C_COLOR_WHITE );
  771. renderSystem->SetColor( idStr::ColorForIndex( currentColor ) );
  772. v = 0;
  773. for ( i = current-NUM_CON_TIMES+1; i <= current; i++ ) {
  774. if ( i < 0 ) {
  775. continue;
  776. }
  777. time = times[i % NUM_CON_TIMES];
  778. if ( time == 0 ) {
  779. continue;
  780. }
  781. time = Sys_Milliseconds() - time;
  782. if ( time > con_notifyTime.GetFloat() * 1000 ) {
  783. continue;
  784. }
  785. text_p = text + (i % TOTAL_LINES)*LINE_WIDTH;
  786. for ( x = 0; x < LINE_WIDTH; x++ ) {
  787. if ( ( text_p[x] & 0xff ) == ' ' ) {
  788. continue;
  789. }
  790. if ( idStr::ColorIndex(text_p[x]>>8) != currentColor ) {
  791. currentColor = idStr::ColorIndex(text_p[x]>>8);
  792. renderSystem->SetColor( idStr::ColorForIndex( currentColor ) );
  793. }
  794. renderSystem->DrawSmallChar( LOCALSAFE_LEFT + (x+1)*SMALLCHAR_WIDTH, v, text_p[x] & 0xff );
  795. }
  796. v += SMALLCHAR_HEIGHT;
  797. }
  798. renderSystem->SetColor( colorCyan );
  799. }
  800. /*
  801. ================
  802. DrawSolidConsole
  803. Draws the console with the solid background
  804. ================
  805. */
  806. void idConsoleLocal::DrawSolidConsole( float frac ) {
  807. int i, x;
  808. float y;
  809. int rows;
  810. short *text_p;
  811. int row;
  812. int lines;
  813. int currentColor;
  814. lines = idMath::Ftoi( SCREEN_HEIGHT * frac );
  815. if ( lines <= 0 ) {
  816. return;
  817. }
  818. if ( lines > SCREEN_HEIGHT ) {
  819. lines = SCREEN_HEIGHT;
  820. }
  821. // draw the background
  822. y = frac * SCREEN_HEIGHT - 2;
  823. if ( y < 1.0f ) {
  824. y = 0.0f;
  825. } else {
  826. renderSystem->DrawFilled( idVec4( 0.0f, 0.0f, 0.0f, 0.75f ), 0, 0, SCREEN_WIDTH, y );
  827. }
  828. renderSystem->DrawFilled( colorCyan, 0, y, SCREEN_WIDTH, 2 );
  829. // draw the version number
  830. renderSystem->SetColor( idStr::ColorForIndex( C_COLOR_CYAN ) );
  831. idStr version = va( "%s.%i.%i", ENGINE_VERSION, BUILD_NUMBER, BUILD_NUMBER_MINOR );
  832. i = version.Length();
  833. for ( x = 0; x < i; x++ ) {
  834. renderSystem->DrawSmallChar( LOCALSAFE_WIDTH - ( i - x ) * SMALLCHAR_WIDTH,
  835. (lines-(SMALLCHAR_HEIGHT+SMALLCHAR_HEIGHT/4)), version[x] );
  836. }
  837. // draw the text
  838. vislines = lines;
  839. rows = (lines-SMALLCHAR_WIDTH)/SMALLCHAR_WIDTH; // rows of text to draw
  840. y = lines - (SMALLCHAR_HEIGHT*3);
  841. // draw from the bottom up
  842. if ( display != current ) {
  843. // draw arrows to show the buffer is backscrolled
  844. renderSystem->SetColor( idStr::ColorForIndex( C_COLOR_CYAN ) );
  845. for ( x = 0; x < LINE_WIDTH; x += 4 ) {
  846. renderSystem->DrawSmallChar( LOCALSAFE_LEFT + (x+1)*SMALLCHAR_WIDTH, idMath::Ftoi( y ), '^' );
  847. }
  848. y -= SMALLCHAR_HEIGHT;
  849. rows--;
  850. }
  851. row = display;
  852. if ( x == 0 ) {
  853. row--;
  854. }
  855. currentColor = idStr::ColorIndex( C_COLOR_WHITE );
  856. renderSystem->SetColor( idStr::ColorForIndex( currentColor ) );
  857. for ( i = 0; i < rows; i++, y -= SMALLCHAR_HEIGHT, row-- ) {
  858. if ( row < 0 ) {
  859. break;
  860. }
  861. if ( current - row >= TOTAL_LINES ) {
  862. // past scrollback wrap point
  863. continue;
  864. }
  865. text_p = text + (row % TOTAL_LINES)*LINE_WIDTH;
  866. for ( x = 0; x < LINE_WIDTH; x++ ) {
  867. if ( ( text_p[x] & 0xff ) == ' ' ) {
  868. continue;
  869. }
  870. if ( idStr::ColorIndex(text_p[x]>>8) != currentColor ) {
  871. currentColor = idStr::ColorIndex(text_p[x]>>8);
  872. renderSystem->SetColor( idStr::ColorForIndex( currentColor ) );
  873. }
  874. renderSystem->DrawSmallChar( LOCALSAFE_LEFT + (x+1)*SMALLCHAR_WIDTH, idMath::Ftoi( y ), text_p[x] & 0xff );
  875. }
  876. }
  877. // draw the input prompt, user text, and cursor if desired
  878. DrawInput();
  879. renderSystem->SetColor( colorCyan );
  880. }
  881. /*
  882. ==============
  883. Draw
  884. ForceFullScreen is used by the editor
  885. ==============
  886. */
  887. void idConsoleLocal::Draw( bool forceFullScreen ) {
  888. if ( forceFullScreen ) {
  889. // if we are forced full screen because of a disconnect,
  890. // we want the console closed when we go back to a session state
  891. Close();
  892. // we are however catching keyboard input
  893. keyCatching = true;
  894. }
  895. Scroll();
  896. UpdateDisplayFraction();
  897. if ( forceFullScreen ) {
  898. DrawSolidConsole( 1.0f );
  899. } else if ( displayFrac ) {
  900. DrawSolidConsole( displayFrac );
  901. } else {
  902. // only draw the notify lines if the developer cvar is set,
  903. // or we are a debug build
  904. if ( !con_noPrint.GetBool() ) {
  905. DrawNotify();
  906. }
  907. }
  908. float lefty = LOCALSAFE_TOP;
  909. float righty = LOCALSAFE_TOP;
  910. float centery = LOCALSAFE_TOP;
  911. if ( com_showFPS.GetBool() ) {
  912. righty = DrawFPS( righty );
  913. }
  914. if ( com_showMemoryUsage.GetBool() ) {
  915. righty = DrawMemoryUsage( righty );
  916. }
  917. DrawOverlayText( lefty, righty, centery );
  918. DrawDebugGraphs();
  919. }
  920. /*
  921. ========================
  922. idConsoleLocal::PrintOverlay
  923. ========================
  924. */
  925. void idConsoleLocal::PrintOverlay( idOverlayHandle &handle, justify_t justify, const char *text, ... ) {
  926. if ( handle.index >= 0 && handle.index < overlayText.Num() ) {
  927. if ( overlayText[handle.index].time == handle.time ) {
  928. return;
  929. }
  930. }
  931. char string[MAX_PRINT_MSG];
  932. va_list argptr;
  933. va_start( argptr, text );
  934. idStr::vsnPrintf( string, sizeof( string ), text, argptr );
  935. va_end( argptr );
  936. overlayText_t &overlay = overlayText.Alloc();
  937. overlay.text = string;
  938. overlay.justify = justify;
  939. overlay.time = Sys_Milliseconds();
  940. handle.index = overlayText.Num() - 1;
  941. handle.time = overlay.time;
  942. }
  943. /*
  944. ========================
  945. idConsoleLocal::DrawOverlayText
  946. ========================
  947. */
  948. void idConsoleLocal::DrawOverlayText( float & leftY, float & rightY, float & centerY ) {
  949. for ( int i = 0; i < overlayText.Num(); i++ ) {
  950. const idStr & text = overlayText[i].text;
  951. int maxWidth = 0;
  952. int numLines = 0;
  953. for ( int j = 0; j < text.Length(); j++ ) {
  954. int width = 1;
  955. for (; j < text.Length() && text[j] != '\n'; j++ ) {
  956. width++;
  957. }
  958. numLines++;
  959. if ( width > maxWidth ) {
  960. maxWidth = width;
  961. }
  962. }
  963. idVec4 bgColor( 0.0f, 0.0f, 0.0f, 0.75f );
  964. const float width = maxWidth * SMALLCHAR_WIDTH;
  965. const float height = numLines * ( SMALLCHAR_HEIGHT + 4 );
  966. const float bgAdjust = - 0.5f * SMALLCHAR_WIDTH;
  967. if ( overlayText[i].justify == JUSTIFY_LEFT ) {
  968. renderSystem->DrawFilled( bgColor, LOCALSAFE_LEFT + bgAdjust, leftY, width, height );
  969. } else if ( overlayText[i].justify == JUSTIFY_RIGHT ) {
  970. renderSystem->DrawFilled( bgColor, LOCALSAFE_RIGHT - width + bgAdjust, rightY, width, height );
  971. } else if ( overlayText[i].justify == JUSTIFY_CENTER_LEFT || overlayText[i].justify == JUSTIFY_CENTER_RIGHT ) {
  972. renderSystem->DrawFilled( bgColor, LOCALSAFE_LEFT + ( LOCALSAFE_WIDTH - width + bgAdjust ) * 0.5f, centerY, width, height );
  973. } else {
  974. assert( false );
  975. }
  976. idStr singleLine;
  977. for ( int j = 0; j < text.Length(); j += singleLine.Length() + 1 ) {
  978. singleLine = "";
  979. for ( int k = j; k < text.Length() && text[k] != '\n'; k++ ) {
  980. singleLine.Append( text[k] );
  981. }
  982. if ( overlayText[i].justify == JUSTIFY_LEFT ) {
  983. DrawTextLeftAlign( LOCALSAFE_LEFT, leftY, "%s", singleLine.c_str() );
  984. } else if ( overlayText[i].justify == JUSTIFY_RIGHT ) {
  985. DrawTextRightAlign( LOCALSAFE_RIGHT, rightY, "%s", singleLine.c_str() );
  986. } else if ( overlayText[i].justify == JUSTIFY_CENTER_LEFT ) {
  987. DrawTextLeftAlign( LOCALSAFE_LEFT + ( LOCALSAFE_WIDTH - width ) * 0.5f, centerY, "%s", singleLine.c_str() );
  988. } else if ( overlayText[i].justify == JUSTIFY_CENTER_RIGHT ) {
  989. DrawTextRightAlign( LOCALSAFE_LEFT + ( LOCALSAFE_WIDTH + width ) * 0.5f, centerY, "%s", singleLine.c_str() );
  990. } else {
  991. assert( false );
  992. }
  993. }
  994. }
  995. overlayText.SetNum( 0 );
  996. }
  997. /*
  998. ========================
  999. idConsoleLocal::CreateGraph
  1000. ========================
  1001. */
  1002. idDebugGraph * idConsoleLocal::CreateGraph( int numItems ) {
  1003. idDebugGraph * graph = new (TAG_SYSTEM) idDebugGraph( numItems );
  1004. debugGraphs.Append( graph );
  1005. return graph;
  1006. }
  1007. /*
  1008. ========================
  1009. idConsoleLocal::DestroyGraph
  1010. ========================
  1011. */
  1012. void idConsoleLocal::DestroyGraph( idDebugGraph * graph ) {
  1013. debugGraphs.Remove( graph );
  1014. delete graph;
  1015. }
  1016. /*
  1017. ========================
  1018. idConsoleLocal::DrawDebugGraphs
  1019. ========================
  1020. */
  1021. void idConsoleLocal::DrawDebugGraphs() {
  1022. for ( int i = 0; i < debugGraphs.Num(); i++ ) {
  1023. debugGraphs[i]->Render( renderSystem );
  1024. }
  1025. }