2011-11-22 21:28:15 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 GPL Source Code
2011-12-06 18:20:15 +00:00
Copyright ( C ) 1999 - 2011 id Software LLC , a ZeniMax Media company .
2011-11-22 21:28:15 +00:00
2011-12-06 16:14:59 +00:00
This file is part of the Doom 3 GPL Source Code ( " Doom 3 Source Code " ) .
2011-11-22 21:28:15 +00:00
Doom 3 Source Code is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Doom 3 Source Code is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code . If not , see < http : //www.gnu.org/licenses/>.
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 .
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 .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2011-12-16 22:28:29 +00:00
# include "sys/platform.h"
# include "idlib/math/Vector.h"
# include "framework/async/AsyncNetwork.h"
# include "framework/BuildVersion.h"
# include "framework/CVarSystem.h"
# include "framework/Session.h"
# include "framework/EditField.h"
# include "framework/KeyInput.h"
# include "framework/EventLoop.h"
# include "renderer/RenderSystem.h"
# include "sound/sound.h"
# include "framework/Console.h"
2011-11-22 21:28:15 +00:00
2019-01-07 04:19:20 +00:00
# include "tools/edit_public.h"
2011-11-22 21:28:15 +00:00
void SCR_DrawTextLeftAlign ( float & y , const char * text , . . . ) id_attribute ( ( format ( printf , 2 , 3 ) ) ) ;
void SCR_DrawTextRightAlign ( float & y , const char * text , . . . ) id_attribute ( ( format ( printf , 2 , 3 ) ) ) ;
# define LINE_WIDTH 78
# define NUM_CON_TIMES 4
# define CON_TEXTSIZE 0x30000
# define TOTAL_LINES (CON_TEXTSIZE / LINE_WIDTH)
# define CONSOLE_FIRSTREPEAT 200
# define CONSOLE_REPEAT 100
# define COMMAND_HISTORY 64
// the console will query the cvar and command systems for
// command completion information
class idConsoleLocal : public idConsole {
public :
virtual void Init ( void ) ;
virtual void Shutdown ( void ) ;
virtual void LoadGraphics ( void ) ;
virtual bool ProcessEvent ( const sysEvent_t * event , bool forceAccept ) ;
virtual bool Active ( void ) ;
virtual void ClearNotifyLines ( void ) ;
virtual void Close ( void ) ;
virtual void Print ( const char * text ) ;
virtual void Draw ( bool forceFullScreen ) ;
void Dump ( const char * toFile ) ;
void Clear ( ) ;
2012-09-16 00:58:14 +00:00
virtual void SaveHistory ( ) ;
virtual void LoadHistory ( ) ;
2011-11-22 21:28:15 +00:00
//============================
const idMaterial * charSetShader ;
private :
void KeyDownEvent ( int key ) ;
void Linefeed ( ) ;
void PageUp ( ) ;
void PageDown ( ) ;
void Top ( ) ;
void Bottom ( ) ;
void DrawInput ( ) ;
void DrawNotify ( ) ;
void DrawSolidConsole ( float frac ) ;
void Scroll ( ) ;
void SetDisplayFraction ( float frac ) ;
void UpdateDisplayFraction ( void ) ;
//============================
bool keyCatching ;
short text [ CON_TEXTSIZE ] ;
int current ; // line where next message will be printed
int x ; // offset in current line for next print
int display ; // bottom of console displays this line
int lastKeyEvent ; // time of last key event for scroll delay
int nextKeyEvent ; // keyboard repeat rate
float displayFrac ; // approaches finalFrac at scr_conspeed
float finalFrac ; // 0.0 to 1.0 lines of console to display
int fracTime ; // time of last displayFrac update
int vislines ; // in scanlines
int times [ NUM_CON_TIMES ] ; // cls.realtime time the line was generated
// for transparent notify lines
idVec4 color ;
idEditField historyEditLines [ COMMAND_HISTORY ] ;
int nextHistoryLine ; // the last line in the history buffer, not masked
int historyLine ; // the line being displayed from history buffer
// will be <= nextHistoryLine
idEditField consoleField ;
static idCVar con_speed ;
static idCVar con_notifyTime ;
static idCVar con_noPrint ;
const idMaterial * whiteShader ;
const idMaterial * consoleShader ;
} ;
static idConsoleLocal localConsole ;
idConsole * console = & localConsole ;
idCVar idConsoleLocal : : con_speed ( " con_speed " , " 3 " , CVAR_SYSTEM , " speed at which the console moves up and down " ) ;
idCVar idConsoleLocal : : con_notifyTime ( " con_notifyTime " , " 3 " , CVAR_SYSTEM , " time messages are displayed onscreen when console is pulled up " ) ;
# ifdef DEBUG
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 " ) ;
# else
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 " ) ;
# endif
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Misc stats
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = =
SCR_DrawTextLeftAlign
= = = = = = = = = = = = = = = = = =
*/
void SCR_DrawTextLeftAlign ( float & y , const char * text , . . . ) {
char string [ MAX_STRING_CHARS ] ;
va_list argptr ;
va_start ( argptr , text ) ;
idStr : : vsnPrintf ( string , sizeof ( string ) , text , argptr ) ;
va_end ( argptr ) ;
renderSystem - > DrawSmallStringExt ( 0 , y + 2 , string , colorWhite , true , localConsole . charSetShader ) ;
y + = SMALLCHAR_HEIGHT + 4 ;
}
/*
= = = = = = = = = = = = = = = = = =
SCR_DrawTextRightAlign
= = = = = = = = = = = = = = = = = =
*/
void SCR_DrawTextRightAlign ( float & y , const char * text , . . . ) {
char string [ MAX_STRING_CHARS ] ;
va_list argptr ;
va_start ( argptr , text ) ;
int i = idStr : : vsnPrintf ( string , sizeof ( string ) , text , argptr ) ;
va_end ( argptr ) ;
renderSystem - > DrawSmallStringExt ( 635 - i * SMALLCHAR_WIDTH , y + 2 , string , colorWhite , true , localConsole . charSetShader ) ;
y + = SMALLCHAR_HEIGHT + 4 ;
}
/*
= = = = = = = = = = = = = = = = = =
SCR_DrawFPS
= = = = = = = = = = = = = = = = = =
*/
# define FPS_FRAMES 4
float SCR_DrawFPS ( float y ) {
char * s ;
int w ;
static int previousTimes [ FPS_FRAMES ] ;
static int index ;
int i , total ;
int fps ;
static int previous ;
int t , frameTime ;
// don't use serverTime, because that will be drifting to
// correct for internet lag changes, timescales, timedemos, etc
t = Sys_Milliseconds ( ) ;
frameTime = t - previous ;
previous = t ;
previousTimes [ index % FPS_FRAMES ] = frameTime ;
index + + ;
if ( index > FPS_FRAMES ) {
// average multiple frames together to smooth changes out a bit
total = 0 ;
for ( i = 0 ; i < FPS_FRAMES ; i + + ) {
total + = previousTimes [ i ] ;
}
if ( ! total ) {
total = 1 ;
}
fps = 10000 * FPS_FRAMES / total ;
fps = ( fps + 5 ) / 10 ;
s = va ( " %ifps " , fps ) ;
w = strlen ( s ) * BIGCHAR_WIDTH ;
renderSystem - > DrawBigStringExt ( 635 - w , idMath : : FtoiFast ( y ) + 2 , s , colorWhite , true , localConsole . charSetShader ) ;
}
return y + BIGCHAR_HEIGHT + 4 ;
}
/*
= = = = = = = = = = = = = = = = = =
SCR_DrawMemoryUsage
= = = = = = = = = = = = = = = = = =
*/
float SCR_DrawMemoryUsage ( float y ) {
memoryStats_t allocs , frees ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
Mem_GetStats ( allocs ) ;
SCR_DrawTextRightAlign ( y , " total allocated memory: %4d, %4dkB " , allocs . num , allocs . totalSize > > 10 ) ;
Mem_GetFrameStats ( allocs , frees ) ;
SCR_DrawTextRightAlign ( y , " frame alloc: %4d, %4dkB frame free: %4d, %4dkB " , allocs . num , allocs . totalSize > > 10 , frees . num , frees . totalSize > > 10 ) ;
Mem_ClearFrameStats ( ) ;
return y ;
}
/*
= = = = = = = = = = = = = = = = = =
SCR_DrawAsyncStats
= = = = = = = = = = = = = = = = = =
*/
float SCR_DrawAsyncStats ( float y ) {
int i , outgoingRate , incomingRate ;
float outgoingCompression , incomingCompression ;
if ( idAsyncNetwork : : server . IsActive ( ) ) {
SCR_DrawTextRightAlign ( y , " server delay = %d msec " , idAsyncNetwork : : server . GetDelay ( ) ) ;
SCR_DrawTextRightAlign ( y , " total outgoing rate = %d KB/s " , idAsyncNetwork : : server . GetOutgoingRate ( ) > > 10 ) ;
SCR_DrawTextRightAlign ( y , " total incoming rate = %d KB/s " , idAsyncNetwork : : server . GetIncomingRate ( ) > > 10 ) ;
for ( i = 0 ; i < MAX_ASYNC_CLIENTS ; i + + ) {
outgoingRate = idAsyncNetwork : : server . GetClientOutgoingRate ( i ) ;
incomingRate = idAsyncNetwork : : server . GetClientIncomingRate ( i ) ;
outgoingCompression = idAsyncNetwork : : server . GetClientOutgoingCompression ( i ) ;
incomingCompression = idAsyncNetwork : : server . GetClientIncomingCompression ( i ) ;
if ( outgoingRate ! = - 1 & & incomingRate ! = - 1 ) {
SCR_DrawTextRightAlign ( y , " client %d: out rate = %d B/s (% -2.1f%%), in rate = %d B/s (% -2.1f%%) " ,
i , outgoingRate , outgoingCompression , incomingRate , incomingCompression ) ;
}
}
idStr msg ;
idAsyncNetwork : : server . GetAsyncStatsAvgMsg ( msg ) ;
2022-12-29 04:38:13 +00:00
SCR_DrawTextRightAlign ( y , " %s " , msg . c_str ( ) ) ;
2011-11-22 21:28:15 +00:00
} else if ( idAsyncNetwork : : client . IsActive ( ) ) {
outgoingRate = idAsyncNetwork : : client . GetOutgoingRate ( ) ;
incomingRate = idAsyncNetwork : : client . GetIncomingRate ( ) ;
outgoingCompression = idAsyncNetwork : : client . GetOutgoingCompression ( ) ;
incomingCompression = idAsyncNetwork : : client . GetIncomingCompression ( ) ;
if ( outgoingRate ! = - 1 & & incomingRate ! = - 1 ) {
SCR_DrawTextRightAlign ( y , " out rate = %d B/s (% -2.1f%%), in rate = %d B/s (% -2.1f%%) " ,
outgoingRate , outgoingCompression , incomingRate , incomingCompression ) ;
}
SCR_DrawTextRightAlign ( y , " packet loss = %d%%, client prediction = %d " ,
( int ) idAsyncNetwork : : client . GetIncomingPacketLoss ( ) , idAsyncNetwork : : client . GetPrediction ( ) ) ;
SCR_DrawTextRightAlign ( y , " predicted frames: %d " , idAsyncNetwork : : client . GetPredictedFrames ( ) ) ;
}
return y ;
}
/*
= = = = = = = = = = = = = = = = = =
SCR_DrawSoundDecoders
= = = = = = = = = = = = = = = = = =
*/
float SCR_DrawSoundDecoders ( float y ) {
int index , numActiveDecoders ;
soundDecoderInfo_t decoderInfo ;
index = - 1 ;
numActiveDecoders = 0 ;
while ( ( index = soundSystem - > GetSoundDecoderInfo ( index , decoderInfo ) ) ! = - 1 ) {
int localTime = decoderInfo . current44kHzTime - decoderInfo . start44kHzTime ;
int sampleTime = decoderInfo . num44kHzSamples / decoderInfo . numChannels ;
int percent ;
if ( localTime > sampleTime ) {
if ( decoderInfo . looping ) {
percent = ( localTime % sampleTime ) * 100 / sampleTime ;
} else {
percent = 100 ;
}
} else {
percent = localTime * 100 / sampleTime ;
}
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 ) ;
numActiveDecoders + + ;
}
return y ;
}
//=========================================================================
/*
= = = = = = = = = = = = = =
Con_Clear_f
= = = = = = = = = = = = = =
*/
static void Con_Clear_f ( const idCmdArgs & args ) {
localConsole . Clear ( ) ;
}
/*
= = = = = = = = = = = = = =
Con_Dump_f
= = = = = = = = = = = = = =
*/
static void Con_Dump_f ( const idCmdArgs & args ) {
if ( args . Argc ( ) ! = 2 ) {
common - > Printf ( " usage: conDump <filename> \n " ) ;
return ;
}
idStr fileName = args . Argv ( 1 ) ;
fileName . DefaultFileExtension ( " .txt " ) ;
common - > Printf ( " Dumped console text to %s. \n " , fileName . c_str ( ) ) ;
localConsole . Dump ( fileName . c_str ( ) ) ;
}
/*
= = = = = = = = = = = = = =
idConsoleLocal : : Init
= = = = = = = = = = = = = =
*/
void idConsoleLocal : : Init ( void ) {
int i ;
keyCatching = false ;
lastKeyEvent = - 1 ;
nextKeyEvent = CONSOLE_FIRSTREPEAT ;
consoleField . Clear ( ) ;
consoleField . SetWidthInChars ( LINE_WIDTH ) ;
for ( i = 0 ; i < COMMAND_HISTORY ; i + + ) {
historyEditLines [ i ] . Clear ( ) ;
historyEditLines [ i ] . SetWidthInChars ( LINE_WIDTH ) ;
}
cmdSystem - > AddCommand ( " clear " , Con_Clear_f , CMD_FL_SYSTEM , " clears the console " ) ;
cmdSystem - > AddCommand ( " conDump " , Con_Dump_f , CMD_FL_SYSTEM , " dumps the console text to a file " ) ;
}
/*
= = = = = = = = = = = = = =
idConsoleLocal : : Shutdown
= = = = = = = = = = = = = =
*/
void idConsoleLocal : : Shutdown ( void ) {
cmdSystem - > RemoveCommand ( " clear " ) ;
cmdSystem - > RemoveCommand ( " conDump " ) ;
}
/*
= = = = = = = = = = = = = =
LoadGraphics
Can ' t be combined with init , because init happens before
the renderSystem is initialized
= = = = = = = = = = = = = =
*/
void idConsoleLocal : : LoadGraphics ( ) {
charSetShader = declManager - > FindMaterial ( " textures/bigchars " ) ;
whiteShader = declManager - > FindMaterial ( " _white " ) ;
consoleShader = declManager - > FindMaterial ( " console " ) ;
}
/*
= = = = = = = = = = = = = = = =
idConsoleLocal : : Active
= = = = = = = = = = = = = = = =
*/
bool idConsoleLocal : : Active ( void ) {
return keyCatching ;
}
/*
= = = = = = = = = = = = = = = =
idConsoleLocal : : ClearNotifyLines
= = = = = = = = = = = = = = = =
*/
void idConsoleLocal : : ClearNotifyLines ( ) {
int i ;
for ( i = 0 ; i < NUM_CON_TIMES ; i + + ) {
times [ i ] = 0 ;
}
}
/*
= = = = = = = = = = = = = = = =
idConsoleLocal : : Close
= = = = = = = = = = = = = = = =
*/
void idConsoleLocal : : Close ( ) {
keyCatching = false ;
SetDisplayFraction ( 0 ) ;
displayFrac = 0 ; // don't scroll to that point, go immediately
ClearNotifyLines ( ) ;
}
/*
= = = = = = = = = = = = = = = =
idConsoleLocal : : Clear
= = = = = = = = = = = = = = = =
*/
void idConsoleLocal : : Clear ( ) {
int i ;
for ( i = 0 ; i < CON_TEXTSIZE ; i + + ) {
text [ i ] = ( idStr : : ColorIndex ( C_COLOR_CYAN ) < < 8 ) | ' ' ;
}
Bottom ( ) ; // go to end
}
/*
= = = = = = = = = = = = = = = =
idConsoleLocal : : Dump
Save the console contents out to a file
= = = = = = = = = = = = = = = =
*/
void idConsoleLocal : : Dump ( const char * fileName ) {
int l , x , i ;
short * line ;
idFile * f ;
char buffer [ LINE_WIDTH + 3 ] ;
f = fileSystem - > OpenFileWrite ( fileName ) ;
if ( ! f ) {
common - > Warning ( " couldn't open %s " , fileName ) ;
return ;
}
// skip empty lines
l = current - TOTAL_LINES + 1 ;
if ( l < 0 ) {
l = 0 ;
}
for ( ; l < = current ; l + + )
{
line = text + ( l % TOTAL_LINES ) * LINE_WIDTH ;
for ( x = 0 ; x < LINE_WIDTH ; x + + )
if ( ( line [ x ] & 0xff ) > ' ' )
break ;
if ( x ! = LINE_WIDTH )
break ;
}
// write the remaining lines
for ( ; l < = current ; l + + ) {
line = text + ( l % TOTAL_LINES ) * LINE_WIDTH ;
for ( i = 0 ; i < LINE_WIDTH ; i + + ) {
buffer [ i ] = line [ i ] & 0xff ;
}
for ( x = LINE_WIDTH - 1 ; x > = 0 ; x - - ) {
if ( buffer [ x ] < = ' ' ) {
buffer [ x ] = 0 ;
} else {
break ;
}
}
buffer [ x + 1 ] = ' \r ' ;
buffer [ x + 2 ] = ' \n ' ;
buffer [ x + 3 ] = 0 ;
f - > Write ( buffer , strlen ( buffer ) ) ;
}
fileSystem - > CloseFile ( f ) ;
}
2012-09-16 00:58:14 +00:00
void idConsoleLocal : : SaveHistory ( ) {
idFile * f = fileSystem - > OpenFileWrite ( " consolehistory.dat " ) ;
for ( int i = 0 ; i < COMMAND_HISTORY ; + + i ) {
// make sure the history is in the right order
int line = ( nextHistoryLine + i ) % COMMAND_HISTORY ;
const char * s = historyEditLines [ line ] . GetBuffer ( ) ;
if ( s & & s [ 0 ] ) {
f - > WriteString ( s ) ;
}
}
fileSystem - > CloseFile ( f ) ;
}
void idConsoleLocal : : LoadHistory ( ) {
idFile * f = fileSystem - > OpenFileRead ( " consolehistory.dat " ) ;
if ( f = = NULL ) // file doesn't exist
return ;
historyLine = 0 ;
idStr tmp ;
for ( int i = 0 ; i < COMMAND_HISTORY ; + + i ) {
if ( f - > Tell ( ) > = f - > Length ( ) ) {
break ; // EOF is reached
}
f - > ReadString ( tmp ) ;
historyEditLines [ i ] . SetBuffer ( tmp . c_str ( ) ) ;
+ + historyLine ;
}
nextHistoryLine = historyLine ;
fileSystem - > CloseFile ( f ) ;
}
2011-11-22 21:28:15 +00:00
/*
= = = = = = = = = = = = = = = =
idConsoleLocal : : PageUp
= = = = = = = = = = = = = = = =
*/
void idConsoleLocal : : PageUp ( void ) {
display - = 2 ;
if ( current - display > = TOTAL_LINES ) {
display = current - TOTAL_LINES + 1 ;
}
}
/*
= = = = = = = = = = = = = = = =
idConsoleLocal : : PageDown
= = = = = = = = = = = = = = = =
*/
void idConsoleLocal : : PageDown ( void ) {
display + = 2 ;
if ( display > current ) {
display = current ;
}
}
/*
= = = = = = = = = = = = = = = =
idConsoleLocal : : Top
= = = = = = = = = = = = = = = =
*/
void idConsoleLocal : : Top ( void ) {
display = 0 ;
}
/*
= = = = = = = = = = = = = = = =
idConsoleLocal : : Bottom
= = = = = = = = = = = = = = = =
*/
void idConsoleLocal : : Bottom ( void ) {
display = current ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
CONSOLE LINE EDITING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = = =
KeyDownEvent
Handles history and console scrollback
= = = = = = = = = = = = = = = = = = = =
*/
void idConsoleLocal : : KeyDownEvent ( int key ) {
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// Execute F key bindings
if ( key > = K_F1 & & key < = K_F12 ) {
idKeyInput : : ExecKeyBinding ( key ) ;
return ;
}
// ctrl-L clears screen
if ( key = = ' l ' & & idKeyInput : : IsDown ( K_CTRL ) ) {
Clear ( ) ;
return ;
}
// enter finishes the line
if ( key = = K_ENTER | | key = = K_KP_ENTER ) {
common - > Printf ( " ]%s \n " , consoleField . GetBuffer ( ) ) ;
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , consoleField . GetBuffer ( ) ) ; // valid command
cmdSystem - > BufferCommandText ( CMD_EXEC_APPEND , " \n " ) ;
2012-09-16 14:21:39 +00:00
// copy line to history buffer, if it isn't the same as the last command
if ( idStr : : Cmp ( consoleField . GetBuffer ( ) ,
historyEditLines [ ( nextHistoryLine + COMMAND_HISTORY - 1 ) % COMMAND_HISTORY ] . GetBuffer ( ) ) ! = 0 )
{
historyEditLines [ nextHistoryLine % COMMAND_HISTORY ] = consoleField ;
nextHistoryLine + + ;
}
2011-11-22 21:28:15 +00:00
historyLine = nextHistoryLine ;
2012-09-16 14:21:39 +00:00
// clear the next line from old garbage, else the oldest history entry turns up when pressing DOWN
historyEditLines [ nextHistoryLine % COMMAND_HISTORY ] . Clear ( ) ;
2011-11-22 21:28:15 +00:00
consoleField . Clear ( ) ;
consoleField . SetWidthInChars ( LINE_WIDTH ) ;
session - > UpdateScreen ( ) ; // force an update, because the command
// may take some time
return ;
}
// command completion
if ( key = = K_TAB ) {
consoleField . AutoComplete ( ) ;
return ;
}
// command history (ctrl-p ctrl-n for unix style)
if ( ( key = = K_UPARROW ) | |
( ( tolower ( key ) = = ' p ' ) & & idKeyInput : : IsDown ( K_CTRL ) ) ) {
if ( nextHistoryLine - historyLine < COMMAND_HISTORY & & historyLine > 0 ) {
historyLine - - ;
}
consoleField = historyEditLines [ historyLine % COMMAND_HISTORY ] ;
return ;
}
if ( ( key = = K_DOWNARROW ) | |
( ( tolower ( key ) = = ' n ' ) & & idKeyInput : : IsDown ( K_CTRL ) ) ) {
if ( historyLine = = nextHistoryLine ) {
return ;
}
historyLine + + ;
consoleField = historyEditLines [ historyLine % COMMAND_HISTORY ] ;
return ;
}
// console scrolling
if ( key = = K_PGUP ) {
PageUp ( ) ;
lastKeyEvent = eventLoop - > Milliseconds ( ) ;
nextKeyEvent = CONSOLE_FIRSTREPEAT ;
return ;
}
if ( key = = K_PGDN ) {
PageDown ( ) ;
lastKeyEvent = eventLoop - > Milliseconds ( ) ;
nextKeyEvent = CONSOLE_FIRSTREPEAT ;
return ;
}
if ( key = = K_MWHEELUP ) {
PageUp ( ) ;
return ;
}
if ( key = = K_MWHEELDOWN ) {
PageDown ( ) ;
return ;
}
// ctrl-home = top of console
if ( key = = K_HOME & & idKeyInput : : IsDown ( K_CTRL ) ) {
Top ( ) ;
return ;
}
// ctrl-end = bottom of console
if ( key = = K_END & & idKeyInput : : IsDown ( K_CTRL ) ) {
Bottom ( ) ;
return ;
}
// pass to the normal editline routine
consoleField . KeyDownEvent ( key ) ;
}
/*
= = = = = = = = = = = = = =
Scroll
deals with scrolling text because we don ' t have key repeat
= = = = = = = = = = = = = =
*/
void idConsoleLocal : : Scroll ( ) {
if ( lastKeyEvent = = - 1 | | ( lastKeyEvent + 200 ) > eventLoop - > Milliseconds ( ) ) {
return ;
}
// console scrolling
if ( idKeyInput : : IsDown ( K_PGUP ) ) {
PageUp ( ) ;
nextKeyEvent = CONSOLE_REPEAT ;
return ;
}
if ( idKeyInput : : IsDown ( K_PGDN ) ) {
PageDown ( ) ;
nextKeyEvent = CONSOLE_REPEAT ;
return ;
}
}
/*
= = = = = = = = = = = = = =
SetDisplayFraction
Causes the console to start opening the desired amount .
= = = = = = = = = = = = = =
*/
void idConsoleLocal : : SetDisplayFraction ( float frac ) {
finalFrac = frac ;
fracTime = com_frameTime ;
}
/*
= = = = = = = = = = = = = =
UpdateDisplayFraction
Scrolls the console up or down based on conspeed
= = = = = = = = = = = = = =
*/
void idConsoleLocal : : UpdateDisplayFraction ( void ) {
if ( con_speed . GetFloat ( ) < = 0.1f ) {
fracTime = com_frameTime ;
displayFrac = finalFrac ;
return ;
}
// scroll towards the destination height
if ( finalFrac < displayFrac ) {
displayFrac - = con_speed . GetFloat ( ) * ( com_frameTime - fracTime ) * 0.001f ;
if ( finalFrac > displayFrac ) {
displayFrac = finalFrac ;
}
fracTime = com_frameTime ;
} else if ( finalFrac > displayFrac ) {
displayFrac + = con_speed . GetFloat ( ) * ( com_frameTime - fracTime ) * 0.001f ;
if ( finalFrac < displayFrac ) {
displayFrac = finalFrac ;
}
fracTime = com_frameTime ;
}
}
/*
= = = = = = = = = = = = = =
ProcessEvent
= = = = = = = = = = = = = =
*/
bool idConsoleLocal : : ProcessEvent ( const sysEvent_t * event , bool forceAccept ) {
2015-09-27 19:09:19 +00:00
bool consoleKey = false ;
if ( event - > evType = = SE_KEY )
{
Improve handling of "console key", add in_ignoreConsoleKey CVar
If in_ignoreConsoleKey is set, the console can only be opened with
Shift+Esc, not `/^/whatever, so you can easily type whatever character
is on your "console key" into the game, or even bind that key.
Otherwise, with SDL2, that key (KEY_SCANCODE_GRAVE) always generates the
newly added K_CONSOLE.
in_kbd has a new (SDL2-only) "auto" mode which tries to detect the
keyboard layout based on SDL_GetKeyFromScancode( SDL_SCANCODE_GRAVE ).
Wherever Sys_GetConsoleKey() is called, I now take the current state of
Shift into account, so we don't discard more chars than necessary, esp.
when they keyboard-layout (in_kbd) is *not* correctly set.
(TBH the only reason besides SDL1.2 to keep in_kbd around is to ignore
the char generated by the "console key" in the console..)
2021-07-12 04:15:22 +00:00
bool shiftPressed = idKeyInput : : IsDown ( K_SHIFT ) ;
if ( event - > evValue = = K_CONSOLE | | event - > evValue = = Sys_GetConsoleKey ( shiftPressed )
| | ( event - > evValue = = K_ESCAPE & & shiftPressed ) ) // shift+esc should also open console
2015-09-27 19:09:19 +00:00
{
consoleKey = true ;
}
}
2011-11-22 21:28:15 +00:00
# if ID_CONSOLE_LOCK
// If the console's not already down, and we have it turned off, check for ctrl+alt
if ( ! keyCatching & & ! com_allowConsole . GetBool ( ) ) {
if ( ! idKeyInput : : IsDown ( K_CTRL ) | | ! idKeyInput : : IsDown ( K_ALT ) ) {
consoleKey = false ;
}
}
# endif
// we always catch the console key event
if ( ! forceAccept & & consoleKey ) {
// ignore up events
if ( event - > evValue2 = = 0 ) {
return true ;
}
consoleField . ClearAutoComplete ( ) ;
// a down event will toggle the destination lines
if ( keyCatching ) {
Close ( ) ;
cvarSystem - > SetCVarBool ( " ui_chat " , false ) ;
} else {
consoleField . Clear ( ) ;
keyCatching = true ;
2015-09-27 19:09:19 +00:00
if ( idKeyInput : : IsDown ( K_SHIFT ) & & event - > evValue ! = K_ESCAPE ) {
2011-11-22 21:28:15 +00:00
// if the shift key is down, don't open the console as much
2015-09-27 19:09:19 +00:00
// except we used shift+esc.
2011-11-22 21:28:15 +00:00
SetDisplayFraction ( 0.2f ) ;
} else {
SetDisplayFraction ( 0.5f ) ;
}
cvarSystem - > SetCVarBool ( " ui_chat " , true ) ;
}
return true ;
}
// if we aren't key catching, dump all the other events
if ( ! forceAccept & & ! keyCatching ) {
return false ;
}
// handle key and character events
if ( event - > evType = = SE_CHAR ) {
// never send the console key as a character
Improve handling of "console key", add in_ignoreConsoleKey CVar
If in_ignoreConsoleKey is set, the console can only be opened with
Shift+Esc, not `/^/whatever, so you can easily type whatever character
is on your "console key" into the game, or even bind that key.
Otherwise, with SDL2, that key (KEY_SCANCODE_GRAVE) always generates the
newly added K_CONSOLE.
in_kbd has a new (SDL2-only) "auto" mode which tries to detect the
keyboard layout based on SDL_GetKeyFromScancode( SDL_SCANCODE_GRAVE ).
Wherever Sys_GetConsoleKey() is called, I now take the current state of
Shift into account, so we don't discard more chars than necessary, esp.
when they keyboard-layout (in_kbd) is *not* correctly set.
(TBH the only reason besides SDL1.2 to keep in_kbd around is to ignore
the char generated by the "console key" in the console..)
2021-07-12 04:15:22 +00:00
if ( event - > evValue ! = Sys_GetConsoleKey ( idKeyInput : : IsDown ( K_SHIFT ) ) ) {
2011-11-22 21:28:15 +00:00
consoleField . CharEvent ( event - > evValue ) ;
}
return true ;
}
if ( event - > evType = = SE_KEY ) {
// ignore up key events
if ( event - > evValue2 = = 0 ) {
return true ;
}
KeyDownEvent ( event - > evValue ) ;
return true ;
}
// we don't handle things like mouse, joystick, and network packets
return false ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
PRINTING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = =
Linefeed
= = = = = = = = = = = = = = =
*/
void idConsoleLocal : : Linefeed ( ) {
int i ;
// mark time for transparent overlay
if ( current > = 0 ) {
times [ current % NUM_CON_TIMES ] = com_frameTime ;
}
x = 0 ;
if ( display = = current ) {
display + + ;
}
current + + ;
for ( i = 0 ; i < LINE_WIDTH ; i + + ) {
text [ ( current % TOTAL_LINES ) * LINE_WIDTH + i ] = ( idStr : : ColorIndex ( C_COLOR_CYAN ) < < 8 ) | ' ' ;
}
}
/*
= = = = = = = = = = = = = = = =
Print
Handles cursor positioning , line wrapping , etc
= = = = = = = = = = = = = = = =
*/
void idConsoleLocal : : Print ( const char * txt ) {
int y ;
int c , l ;
int color ;
# ifdef ID_ALLOW_TOOLS
RadiantPrint ( txt ) ;
if ( com_editors & EDITOR_MATERIAL ) {
MaterialEditorPrintConsole ( txt ) ;
}
# endif
color = idStr : : ColorIndex ( C_COLOR_CYAN ) ;
while ( ( c = * ( const unsigned char * ) txt ) ! = 0 ) {
if ( idStr : : IsColor ( txt ) ) {
if ( * ( txt + 1 ) = = C_COLOR_DEFAULT ) {
color = idStr : : ColorIndex ( C_COLOR_CYAN ) ;
} else {
color = idStr : : ColorIndex ( * ( txt + 1 ) ) ;
}
txt + = 2 ;
continue ;
}
y = current % TOTAL_LINES ;
// if we are about to print a new word, check to see
// if we should wrap to the new line
if ( c > ' ' & & ( x = = 0 | | text [ y * LINE_WIDTH + x - 1 ] < = ' ' ) ) {
// count word length
for ( l = 0 ; l < LINE_WIDTH ; l + + ) {
if ( txt [ l ] < = ' ' ) {
break ;
}
}
// word wrap
if ( l ! = LINE_WIDTH & & ( x + l > = LINE_WIDTH ) ) {
Linefeed ( ) ;
}
}
txt + + ;
switch ( c ) {
case ' \n ' :
Linefeed ( ) ;
break ;
case ' \t ' :
do {
text [ y * LINE_WIDTH + x ] = ( color < < 8 ) | ' ' ;
x + + ;
if ( x > = LINE_WIDTH ) {
Linefeed ( ) ;
x = 0 ;
}
} while ( x & 3 ) ;
break ;
case ' \r ' :
x = 0 ;
break ;
default : // display character and advance
text [ y * LINE_WIDTH + x ] = ( color < < 8 ) | c ;
x + + ;
if ( x > = LINE_WIDTH ) {
Linefeed ( ) ;
x = 0 ;
}
break ;
}
}
// mark time for transparent overlay
if ( current > = 0 ) {
times [ current % NUM_CON_TIMES ] = com_frameTime ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
DRAWING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = =
DrawInput
Draw the editline after a ] prompt
= = = = = = = = = = = = = = = =
*/
void idConsoleLocal : : DrawInput ( ) {
int y , autoCompleteLength ;
y = vislines - ( SMALLCHAR_HEIGHT * 2 ) ;
if ( consoleField . GetAutoCompleteLength ( ) ! = 0 ) {
autoCompleteLength = strlen ( consoleField . GetBuffer ( ) ) - consoleField . GetAutoCompleteLength ( ) ;
if ( autoCompleteLength > 0 ) {
renderSystem - > SetColor4 ( .8f , .2f , .2f , .45f ) ;
renderSystem - > DrawStretchPic ( 2 * SMALLCHAR_WIDTH + consoleField . GetAutoCompleteLength ( ) * SMALLCHAR_WIDTH ,
y + 2 , autoCompleteLength * SMALLCHAR_WIDTH , SMALLCHAR_HEIGHT - 2 , 0 , 0 , 0 , 0 , whiteShader ) ;
}
}
renderSystem - > SetColor ( idStr : : ColorForIndex ( C_COLOR_CYAN ) ) ;
renderSystem - > DrawSmallChar ( 1 * SMALLCHAR_WIDTH , y , ' ] ' , localConsole . charSetShader ) ;
consoleField . Draw ( 2 * SMALLCHAR_WIDTH , y , SCREEN_WIDTH - 3 * SMALLCHAR_WIDTH , true , charSetShader ) ;
}
/*
= = = = = = = = = = = = = = = =
DrawNotify
Draws the last few lines of output transparently over the game top
= = = = = = = = = = = = = = = =
*/
void idConsoleLocal : : DrawNotify ( ) {
int x , v ;
short * text_p ;
int i ;
int time ;
int currentColor ;
if ( con_noPrint . GetBool ( ) ) {
return ;
}
currentColor = idStr : : ColorIndex ( C_COLOR_WHITE ) ;
renderSystem - > SetColor ( idStr : : ColorForIndex ( currentColor ) ) ;
v = 0 ;
for ( i = current - NUM_CON_TIMES + 1 ; i < = current ; i + + ) {
if ( i < 0 ) {
continue ;
}
time = times [ i % NUM_CON_TIMES ] ;
if ( time = = 0 ) {
continue ;
}
time = com_frameTime - time ;
if ( time > con_notifyTime . GetFloat ( ) * 1000 ) {
continue ;
}
text_p = text + ( i % TOTAL_LINES ) * LINE_WIDTH ;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
for ( x = 0 ; x < LINE_WIDTH ; x + + ) {
if ( ( text_p [ x ] & 0xff ) = = ' ' ) {
continue ;
}
if ( idStr : : ColorIndex ( text_p [ x ] > > 8 ) ! = currentColor ) {
currentColor = idStr : : ColorIndex ( text_p [ x ] > > 8 ) ;
renderSystem - > SetColor ( idStr : : ColorForIndex ( currentColor ) ) ;
}
renderSystem - > DrawSmallChar ( ( x + 1 ) * SMALLCHAR_WIDTH , v , text_p [ x ] & 0xff , localConsole . charSetShader ) ;
}
v + = SMALLCHAR_HEIGHT ;
}
renderSystem - > SetColor ( colorCyan ) ;
}
/*
= = = = = = = = = = = = = = = =
DrawSolidConsole
Draws the console with the solid background
= = = = = = = = = = = = = = = =
*/
void idConsoleLocal : : DrawSolidConsole ( float frac ) {
int i , x ;
float y ;
int rows ;
short * text_p ;
int row ;
int lines ;
int currentColor ;
lines = idMath : : FtoiFast ( SCREEN_HEIGHT * frac ) ;
if ( lines < = 0 ) {
return ;
}
if ( lines > SCREEN_HEIGHT ) {
lines = SCREEN_HEIGHT ;
}
// draw the background
y = frac * SCREEN_HEIGHT - 2 ;
if ( y < 1.0f ) {
y = 0.0f ;
} else {
renderSystem - > DrawStretchPic ( 0 , 0 , SCREEN_WIDTH , y , 0 , 1.0f - displayFrac , 1 , 1 , consoleShader ) ;
}
renderSystem - > SetColor ( colorCyan ) ;
renderSystem - > DrawStretchPic ( 0 , y , SCREEN_WIDTH , 2 , 0 , 0 , 0 , 0 , whiteShader ) ;
renderSystem - > SetColor ( colorWhite ) ;
// draw the version number
renderSystem - > SetColor ( idStr : : ColorForIndex ( C_COLOR_CYAN ) ) ;
idStr version = va ( " %s.%i " , ENGINE_VERSION , BUILD_NUMBER ) ;
i = version . Length ( ) ;
for ( x = 0 ; x < i ; x + + ) {
2011-12-06 18:20:15 +00:00
renderSystem - > DrawSmallChar ( SCREEN_WIDTH - ( i - x ) * SMALLCHAR_WIDTH ,
2011-11-22 21:28:15 +00:00
( lines - ( SMALLCHAR_HEIGHT + SMALLCHAR_HEIGHT / 2 ) ) , version [ x ] , localConsole . charSetShader ) ;
}
// draw the text
vislines = lines ;
rows = ( lines - SMALLCHAR_WIDTH ) / SMALLCHAR_WIDTH ; // rows of text to draw
y = lines - ( SMALLCHAR_HEIGHT * 3 ) ;
// draw from the bottom up
if ( display ! = current ) {
// draw arrows to show the buffer is backscrolled
renderSystem - > SetColor ( idStr : : ColorForIndex ( C_COLOR_CYAN ) ) ;
for ( x = 0 ; x < LINE_WIDTH ; x + = 4 ) {
renderSystem - > DrawSmallChar ( ( x + 1 ) * SMALLCHAR_WIDTH , idMath : : FtoiFast ( y ) , ' ^ ' , localConsole . charSetShader ) ;
}
y - = SMALLCHAR_HEIGHT ;
rows - - ;
}
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
row = display ;
if ( x = = 0 ) {
row - - ;
}
currentColor = idStr : : ColorIndex ( C_COLOR_WHITE ) ;
renderSystem - > SetColor ( idStr : : ColorForIndex ( currentColor ) ) ;
for ( i = 0 ; i < rows ; i + + , y - = SMALLCHAR_HEIGHT , row - - ) {
if ( row < 0 ) {
break ;
}
if ( current - row > = TOTAL_LINES ) {
// past scrollback wrap point
2011-12-06 18:20:15 +00:00
continue ;
2011-11-22 21:28:15 +00:00
}
text_p = text + ( row % TOTAL_LINES ) * LINE_WIDTH ;
for ( x = 0 ; x < LINE_WIDTH ; x + + ) {
if ( ( text_p [ x ] & 0xff ) = = ' ' ) {
continue ;
}
if ( idStr : : ColorIndex ( text_p [ x ] > > 8 ) ! = currentColor ) {
currentColor = idStr : : ColorIndex ( text_p [ x ] > > 8 ) ;
renderSystem - > SetColor ( idStr : : ColorForIndex ( currentColor ) ) ;
}
renderSystem - > DrawSmallChar ( ( x + 1 ) * SMALLCHAR_WIDTH , idMath : : FtoiFast ( y ) , text_p [ x ] & 0xff , localConsole . charSetShader ) ;
}
}
// draw the input prompt, user text, and cursor if desired
DrawInput ( ) ;
renderSystem - > SetColor ( colorCyan ) ;
}
/*
= = = = = = = = = = = = = =
Draw
ForceFullScreen is used by the editor
= = = = = = = = = = = = = =
*/
void idConsoleLocal : : Draw ( bool forceFullScreen ) {
float y = 0.0f ;
if ( ! charSetShader ) {
return ;
}
if ( forceFullScreen ) {
2011-12-06 18:20:15 +00:00
// if we are forced full screen because of a disconnect,
2011-11-22 21:28:15 +00:00
// we want the console closed when we go back to a session state
Close ( ) ;
// we are however catching keyboard input
keyCatching = true ;
}
Scroll ( ) ;
UpdateDisplayFraction ( ) ;
if ( forceFullScreen ) {
DrawSolidConsole ( 1.0f ) ;
} else if ( displayFrac ) {
DrawSolidConsole ( displayFrac ) ;
} else {
// only draw the notify lines if the developer cvar is set,
// or we are a debug build
if ( ! con_noPrint . GetBool ( ) ) {
DrawNotify ( ) ;
}
}
if ( com_showFPS . GetBool ( ) ) {
y = SCR_DrawFPS ( 0 ) ;
}
if ( com_showMemoryUsage . GetBool ( ) ) {
y = SCR_DrawMemoryUsage ( y ) ;
}
if ( com_showAsyncStats . GetBool ( ) ) {
y = SCR_DrawAsyncStats ( y ) ;
}
if ( com_showSoundDecoders . GetBool ( ) ) {
y = SCR_DrawSoundDecoders ( y ) ;
}
}