1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 // console.c
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "client.h"
27 #include "ref_gl/qgl.h"
28
29
30 /* The console's main structure */
31 struct CON_console_s CON_console;
32
33 /* CVar for notifications display time */
34 cvar_t * con_notifytime;
35
36
37
38 /**************************************************************************/
39 /* VARIOUS COMMANDS */
40 /**************************************************************************/
41
42 /*
43 * Show or hide the console.
44 */
CON_ToggleConsole(void)45 void CON_ToggleConsole( void )
46 {
47 SCR_EndLoadingPlaque (); // get rid of loading plaque
48
49 Key_ClearTyping ();
50 CON_ClearNotify( );
51
52 if (cls.key_dest == key_console)
53 {
54 M_ForceMenuOff ();
55 Cvar_Set ("paused", "0");
56 }
57 else
58 {
59 M_ForceMenuOff ();
60 cls.key_dest = key_console;
61
62 if (Cvar_VariableValue ("maxclients") == 1
63 && Com_ServerState ())
64 Cvar_Set ("paused", "1");
65 }
66 }
67
68
69 /*
70 * Clear the chat area
71 */
_CON_ToggleChat(void)72 static void _CON_ToggleChat( void )
73 {
74 Key_ClearTyping( );
75
76 if ( cls.key_dest == key_console ) {
77 if ( cls.state == ca_active ) {
78 M_ForceMenuOff( );
79 cls.key_dest = key_game;
80 }
81 } else {
82 cls.key_dest = key_console;
83 }
84
85 CON_ClearNotify( );
86 }
87
88
89 /*
90 * Toggle the general chat input
91 */
_CON_GeneralChatInput(void)92 static void _CON_GeneralChatInput( void )
93 {
94 chat_team = false;
95 chat_irc = false;
96 cls.key_dest = key_message;
97 Cbuf_AddText("chatbubble\n");
98 Cbuf_Execute ();
99 }
100
101
102 /*
103 * Toggle the team chat input
104 */
_CON_TeamChatInput(void)105 static void _CON_TeamChatInput( void )
106 {
107 chat_team = true;
108 chat_irc = false;
109 cls.key_dest = key_message;
110 Cbuf_AddText("chatbubble\n");
111 Cbuf_Execute ();
112 }
113
114
115 /*
116 * Toggle the IRC input
117 */
_CON_IRCInput(void)118 static void _CON_IRCInput( void )
119 {
120 chat_team = false;
121 chat_irc = true;
122 cls.key_dest = key_message;
123 }
124
125
126
127 /**************************************************************************/
128 /* CONSOLE BUFFER ACCESS */
129 /**************************************************************************/
130
131 /*
132 * Find the start of the current line
133 *
134 * Parameters:
135 * line the initial line to look from
136 *
137 * Returns:
138 * the identifier of the current line in the buffer
139 */
_CON_FindLineStart(int line)140 static int _CON_FindLineStart( int line )
141 {
142 line = ( line + CON_MAX_LINES ) % CON_MAX_LINES;
143 while ( CON_console.lCount[ line ] == 0 ) {
144 line = ( line - 1 + CON_MAX_LINES ) % CON_MAX_LINES;
145 }
146 return line;
147 }
148
149
150 /*
151 * Find the start of the next line
152 *
153 * Parameters:
154 * line the current location
155 *
156 * Returns:
157 * the identifier of the next line in the buffer
158 */
_CON_FindNextLine(int line)159 static int _CON_FindNextLine( int line )
160 {
161 line = ( line + CON_MAX_LINES ) % CON_MAX_LINES;
162 if ( CON_console.lCount[ line ] == 0 ) {
163 while ( CON_console.lCount[ line ] == 0 ) {
164 line = ( line + 1 ) % CON_MAX_LINES;
165 }
166 } else {
167 line = ( line + CON_console.lCount[ line ] ) % CON_MAX_LINES;
168 }
169 return line;
170 }
171
172
173 /*
174 * Find the start of the previous line
175 *
176 * Parameters:
177 * line the current location
178 *
179 * Returns:
180 * the identifier of the previous line in the buffer
181 */
_CON_FindPreviousLine(int line)182 static int _CON_FindPreviousLine( int line )
183 {
184 return _CON_FindLineStart( _CON_FindLineStart( line ) - 1 );
185 }
186
187
188 /*
189 * End the current line and start a new one
190 */
_CON_NewLine()191 static void _CON_NewLine( )
192 {
193 CON_console.times[ CON_console.curTime ] = cls.realtime;
194 CON_console.curTime = ( CON_console.curTime + 1 ) % CON_MAX_NOTIFY;
195
196 CON_console.curLine = ( CON_console.curLine + 1 ) % CON_MAX_LINES;
197 CON_console.lines += 1 - CON_console.lCount[ CON_console.curLine ];
198 CON_console.lCount[ CON_console.curLine ] = 1;
199
200 CON_console.offset = 0;
201 memset( CON_console.text[ CON_console.curLine ] , 0 , CON_LINE_LENGTH );
202
203 CON_console.heights[ CON_console.curLine ] = 0;
204 }
205
206
207 /*
208 * Go back to the start of the current line
209 */
_CON_RestartLine()210 static void _CON_RestartLine( )
211 {
212 CON_console.curLine = _CON_FindLineStart( CON_console.curLine );
213 CON_console.offset = 0;
214 }
215
216
217 /*
218 * Append a character to the console buffer
219 *
220 * Parameters:
221 * new_char the character to append
222 */
_CON_AppendChar(char new_char)223 static void _CON_AppendChar( char new_char )
224 {
225 int lStart = _CON_FindLineStart( CON_console.curLine );
226
227 CON_console.text[ CON_console.curLine ][ CON_console.offset ] = new_char;
228 CON_console.offset = ( CON_console.offset + 1 ) % CON_LINE_LENGTH;
229 CON_console.heights[ lStart ] = 0;
230
231 if ( CON_console.offset == 0 ) {
232 // Start a new buffer line that is part of the current logical line
233 CON_console.lCount[ lStart ] ++;
234 CON_console.curLine = ( CON_console.curLine + 1 ) % CON_MAX_LINES;
235 CON_console.lines += 1 - CON_console.lCount[ CON_console.curLine ];
236 memset( CON_console.text[ CON_console.curLine ] , 0 , CON_LINE_LENGTH );
237 }
238 }
239
240
241 /*
242 * Copy the specified logical line into a buffer
243 *
244 * If the current buffer line is full, the logical line will be extended to
245 * include the next buffer line.
246 *
247 * Parameters:
248 * buffer the buffer to copy to
249 * line the first buffer line of the logical line
250 *
251 * Notes:
252 * The buffer should have a sufficient size, which can be computed
253 * using lCount[ line ] * CON_LINE_LENGTH.
254 */
_CON_CopyLine(char * buffer,int line)255 static void _CON_CopyLine( char * buffer , int line )
256 {
257 int len = CON_console.lCount[ line ];
258 int i;
259 for ( i = 0 ; i < len ; i ++ ) {
260 memcpy( buffer , CON_console.text[ line ] , CON_LINE_LENGTH );
261 buffer += CON_LINE_LENGTH;
262 line = ( line + 1 ) % CON_MAX_LINES;
263 }
264 }
265
266
267
268 /**************************************************************************/
269 /* NOTIFICATIONS */
270 /**************************************************************************/
271
272 /* Clear all notifications */
CON_ClearNotify()273 void CON_ClearNotify( )
274 {
275 int i;
276 for ( i = 0 ; i < CON_MAX_NOTIFY ; i ++ ) {
277 CON_console.times[ i ] = 0;
278 }
279 }
280
281
282 /* Draw the few last lines of the console transparently over the game */
CON_DrawNotify()283 void CON_DrawNotify( )
284 {
285 FNT_font_t font;
286 struct FNT_window_s box;
287 int line;
288 int bLines;
289 int count;
290 int timeIndex;
291
292 font = FNT_AutoGet( CL_gameFont );
293 box.x = 0;
294 box.y = 0;
295
296 if (cls.key_dest == key_message) {
297 const char * to_draw;
298 int height;
299
300 if (chat_team) {
301 to_draw = "say_team: ";
302 } else if (chat_irc) {
303 to_draw = "say_IRC: ";
304 } else {
305 to_draw = "say: ";
306 }
307 box.width = viddef.width;
308 box.height = 0;
309 FNT_BoundedPrint( font , to_draw , FNT_CMODE_NONE , FNT_ALIGN_LEFT , &box , FNT_colors[ 7 ] );
310 height = box.height;
311
312 box.x = box.width + 1;
313 box.width = viddef.width - box.width;
314 box.height = 0;
315 FNT_WrappedPrint( font , chat_buffer , FNT_CMODE_NONE , FNT_ALIGN_LEFT , 30 , &box , FNT_colors[ 7 ] );
316
317 box.x = 0;
318 box.y = ( height > box.height ) ? height : box.height;
319 }
320
321 // Find the first logical line to display
322 line = _CON_FindLineStart( CON_console.curLine );
323 bLines = CON_console.lines - CON_console.lCount[ line ];
324 timeIndex = ( CON_console.curTime - 1 + CON_MAX_NOTIFY ) % CON_MAX_NOTIFY;
325 for ( count = 0 ; count < CON_MAX_NOTIFY && bLines > 0 ; count ++ ) {
326 int time = CON_console.times[ timeIndex ];
327 if ( time == 0 || cls.realtime - time > con_notifytime->value * 1000 ) {
328 break;
329 }
330 timeIndex = ( timeIndex - 1 + CON_MAX_NOTIFY ) % CON_MAX_NOTIFY;
331
332 line = _CON_FindPreviousLine( line );
333 bLines -= CON_console.lCount[ line ];
334 }
335
336 // No lines to display
337 if ( count == 0 ) {
338 return;
339 }
340
341 // Display lines
342 while ( count > 0 ) {
343 box.width = viddef.width;
344 box.height = 0;
345 if ( CON_console.lCount[ line ] == 1 ) {
346 FNT_WrappedPrint( font , CON_console.text[ line ] , FNT_CMODE_QUAKE_SRS , FNT_ALIGN_LEFT , 30 , &box , FNT_colors[ 7 ] );
347 } else {
348 char * buffer = Z_Malloc( CON_LINE_LENGTH * CON_console.lCount[ line ] );
349 _CON_CopyLine( buffer , line );
350 FNT_WrappedPrint( font , buffer , FNT_CMODE_QUAKE_SRS , FNT_ALIGN_LEFT , 30 , &box , FNT_colors[ 7 ] );
351 Z_Free( buffer );
352 }
353 box.y += box.height;
354
355 line = _CON_FindNextLine( line );
356 timeIndex = ( timeIndex + 1 ) % CON_MAX_NOTIFY;
357 count --;
358 }
359 }
360
361
362
363 /**************************************************************************/
364 /* CONSOLE ACCESS FUNCTIONS */
365 /**************************************************************************/
366
367 /* Save the console contents out to a file. */
_CON_Dump(void)368 static void _CON_Dump( void )
369 {
370 char name[MAX_OSPATH];
371 int line , lastLine;
372 FILE * f;
373
374 if ( Cmd_Argc( ) != 2 ) {
375 Com_Printf ("usage: condump <filename>\n");
376 return;
377 }
378 Com_sprintf( name , sizeof( name ) , "%s/%s.txt" , FS_Gamedir( ) , Cmd_Argv( 1 ) );
379
380 Com_Printf( "Dumping console text to %s.\n" , name );
381 FS_CreatePath( name );
382 f = fopen( name, "w" );
383 if (!f) {
384 Com_Printf( "ERROR: couldn't open %s.\n" , name );
385 return;
386 }
387
388 lastLine = _CON_FindLineStart( CON_console.curLine );
389 line = ( CON_console.curLine + 1 + CON_MAX_LINES - CON_console.lines ) % CON_MAX_LINES;
390 while ( line != lastLine ) {
391 if ( CON_console.text[ line ][ 0 ] != 0 ) {
392 if ( CON_console.lCount[ line ] == 1 ) {
393 fprintf( f , "%s\n" , CON_console.text[ line ] );
394 } else {
395 char * buffer = Z_Malloc( CON_LINE_LENGTH * CON_console.lCount[ line ] );
396 _CON_CopyLine( buffer , line );
397 fprintf( f , "%s\n" , buffer );
398 Z_Free( buffer );
399 }
400 }
401 line = _CON_FindNextLine( line );
402 }
403
404 fclose( f );
405 }
406
407 /* Clears the console */
CON_Clear(void)408 void CON_Clear( void )
409 {
410 memset( &CON_console , 0 , sizeof( CON_console ) );
411 CON_console.lines = 1;
412 CON_console.lCount[ 0 ] = 1;
413 CON_console.curLine = 0;
414 CON_console.offset = 0;
415 CON_console.initialised = true;
416 }
417
418
419 /* Initialise the console. */
CON_Initialise()420 void CON_Initialise( )
421 {
422 CON_Clear( );
423 Com_Printf( "Console initialized.\n" );
424
425 // Register CVars
426 con_notifytime = Cvar_Get( "con_notifytime" , "3" , 0 );
427
428 // Register commands
429 Cmd_AddCommand( "toggleconsole", CON_ToggleConsole );
430 Cmd_AddCommand( "togglechat", _CON_ToggleChat );
431 Cmd_AddCommand( "messagemode", _CON_GeneralChatInput );
432 Cmd_AddCommand( "messagemode2", _CON_TeamChatInput );
433 Cmd_AddCommand( "messagemode3", _CON_IRCInput );
434 Cmd_AddCommand( "clear" , CON_Clear );
435 Cmd_AddCommand( "condump" , _CON_Dump );
436 }
437
438
439 /* Add text to the console. */
CON_Print(const char * text)440 void CON_Print( const char * text )
441 {
442 char curChar;
443
444 if ( ! CON_console.initialised ) {
445 return;
446 }
447
448 while ( ( curChar = *text ) != 0 ) {
449 if ( curChar == '\r' ) {
450 _CON_RestartLine( );
451 } else if ( curChar == '\n' ) {
452 _CON_NewLine( );
453 } else {
454 _CON_AppendChar( curChar );
455 }
456 text ++;
457 }
458 }
459
460
461
462 /**************************************************************************/
463 /* CONSOLE DISPLAY FUNCTIONS */
464 /**************************************************************************/
465
466 /*
467 * Compute the height of a logical console line and update the console's
468 * data structure accordingly.
469 *
470 * Parameters:
471 * font the current console font
472 * line the start of the logical line for which the computation will
473 * be performed
474 */
_CON_ComputeLineHeight(FNT_font_t font,int line)475 static void _CON_ComputeLineHeight( FNT_font_t font , int line )
476 {
477 if ( CON_console.text[ line ][ 0 ] == 0 ) {
478 // Empty lines are a special case, as we don't need to draw them
479 CON_console.heights[ line ] = font->size;
480 } else {
481 // "Print" the line outside of the screen
482 struct FNT_window_s box;
483 box.x = 0 , box.y = viddef.height;
484 box.width = viddef.width - font->size * 5 , box.height = 0;
485
486 if ( CON_console.lCount[ line ] == 1 ) {
487 FNT_WrappedPrint( font , CON_console.text[ line ] , FNT_CMODE_QUAKE_SRS ,
488 FNT_ALIGN_LEFT , 0 , &box , FNT_colors[ 0 ] );
489 } else {
490 char * buffer = Z_Malloc( CON_console.lCount[ line ] * CON_LINE_LENGTH );
491 _CON_CopyLine( buffer , line );
492 FNT_WrappedPrint( font , buffer , FNT_CMODE_QUAKE_SRS ,
493 FNT_ALIGN_LEFT , 0 , &box , FNT_colors[ 0 ] );
494 Z_Free( buffer );
495 }
496
497 if ( box.height == 0 ) {
498 CON_console.heights[ line ] = font->size;
499 } else {
500 CON_console.heights[ line ] = box.height;
501 }
502 }
503 }
504
505
506 /*
507 * Compute the height of all active lines in the console.
508 *
509 * Parameters:
510 * font the console's current font
511 *
512 * Returns:
513 * the total height of the console
514 */
_CON_ComputeHeight(FNT_font_t font)515 static unsigned int _CON_ComputeHeight( FNT_font_t font )
516 {
517 int line , lastLine;
518 unsigned int total = 0;
519
520 lastLine = _CON_FindLineStart( CON_console.curLine );
521 line = ( CON_console.curLine + 1 + CON_MAX_LINES - CON_console.lines ) % CON_MAX_LINES;
522 while ( 1 ) {
523 if ( ! CON_console.heights[ line ] ) {
524 _CON_ComputeLineHeight( font , line );
525 }
526
527 total += CON_console.heights[ line ];
528 if ( line == lastLine ) {
529 break;
530 }
531 line = _CON_FindNextLine( line );
532 }
533
534 return total;
535 }
536
537
538 /*
539 * Check for font or resolution changes.
540 *
541 * Parameters:
542 * font the console's current font
543 *
544 * Returns:
545 * true if the resolution or fonts have changed, false otherwise
546 */
_CON_CheckResize(FNT_font_t font)547 static qboolean _CON_CheckResize( FNT_font_t font )
548 {
549 return ( viddef.width != CON_console.pWidth || font->size != CON_console.pSize
550 || strcmp( font->face->name , CON_console.pFace ) );
551 }
552
553
554 /*
555 * Draw the console's text.
556 *
557 * Parameters:
558 * font the current console font
559 * start the vertical offset relative to the top of the console's
560 * contents at which drawing is to begin
561 * dHeight the height of the display area
562 */
_CON_DrawConsoleText(FNT_font_t font,int start,int dHeight)563 static void _CON_DrawConsoleText(
564 FNT_font_t font ,
565 int start ,
566 int dHeight
567 )
568 {
569 struct FNT_window_s box;
570 int line , lastLine , total;
571
572 qglScissor( 0 , viddef.height - dHeight , viddef.width , dHeight );
573 qglEnable( GL_SCISSOR_TEST );
574
575 total = 0;
576 lastLine = _CON_FindLineStart( CON_console.curLine );
577 line = ( CON_console.curLine + 1 + CON_MAX_LINES - CON_console.lines ) % CON_MAX_LINES;
578
579 do {
580 if ( total + CON_console.heights[ line ] >= start && CON_console.text[ line ][ 0 ] ) {
581 box.x = font->size*2;
582 box.y = total - start;
583 box.width = viddef.width - font->size * 5;
584 box.height = 0;
585
586 if ( CON_console.lCount[ line ] == 1 ) {
587 FNT_WrappedPrint( font , CON_console.text[ line ] , FNT_CMODE_QUAKE_SRS ,
588 FNT_ALIGN_LEFT , 0 , &box , FNT_colors[ 2 ] );
589 } else {
590 char * buffer = Z_Malloc( CON_console.lCount[ line ] * CON_LINE_LENGTH );
591 _CON_CopyLine( buffer , line );
592 FNT_WrappedPrint( font , buffer , FNT_CMODE_QUAKE_SRS ,
593 FNT_ALIGN_LEFT , 0 , &box , FNT_colors[ 2 ] );
594 Z_Free( buffer );
595 }
596 }
597
598 total += CON_console.heights[ line ];
599 if ( line == lastLine ) {
600 break;
601 }
602 line = _CON_FindNextLine( line );
603 } while ( total - start < dHeight );
604
605 qglDisable( GL_SCISSOR_TEST );
606 }
607
608
609 /*
610 * Draw the scroller on the right of the console.
611 *
612 * For now this is not interactive, it only exists to indicate where in the
613 * console's contents the current view is located.
614 *
615 * This function uses Draw_Fill to generate the scroller's graphics. It uses
616 * the following fill colours: 15 (white, outside of the box), 201 (dark
617 * green, inside of the box) and 208 (bright green, selected area).
618 *
619 * Parameters:
620 * font_size The size of the font (used as the vertical offset and
621 * the scroller's width)
622 * text_height Total height of the console's text contents.
623 * display_height Height of the viewing area.
624 */
_CON_DrawScroller(int font_size,int text_height,int display_height)625 static void _CON_DrawScroller(
626 int font_size ,
627 int text_height ,
628 int display_height )
629 {
630 // FIXME: lots of copy-pasted code here. Doesn't matter, we will
631 // eventually redo the whole console using the menu code.
632
633 int hStart = viddef.width - 3 * font_size;
634 int vStart = font_size / 2;
635 int tHeight = display_height - font_size;
636 int bHeight , bStart;
637
638 Draw_AlphaStretchTilingPic (hStart, vStart, font_size, font_size, "menu/scroll_border_end", 1);
639 Draw_AlphaStretchTilingPic (hStart, vStart+font_size, font_size, tHeight-vStart, "menu/scroll_border", 1);
640 Draw_AlphaStretchTilingPic (hStart+font_size, vStart+tHeight+font_size, -font_size, -font_size, "menu/scroll_border_end", 1);
641
642 if ( display_height >= text_height )
643 {
644 // Fill whole bar
645 bStart = vStart;
646 bHeight = tHeight;
647 }
648 else
649 {
650 bHeight = tHeight * display_height / text_height;
651 if ( bHeight < font_size )
652 bHeight = font_size;
653 // "Top" offset is height - dHeight, "bottom" offset is 0
654 // "Top" bar location is vStart, bottom location is vStart + tHeight - bHeight.
655 bStart = vStart + ( tHeight - bHeight )
656 * ( CON_console.displayOffset - text_height + display_height )
657 / ( display_height - text_height );
658 }
659
660 Draw_AlphaStretchTilingPic (hStart, bStart, font_size, font_size, "menu/scroll_cursor_end", 1);
661 Draw_AlphaStretchTilingPic (hStart, bStart+font_size, font_size, bHeight-font_size, "menu/scroll_cursor", 1);
662 Draw_AlphaStretchTilingPic (hStart+font_size, bStart+bHeight+font_size, -font_size, -font_size, "menu/scroll_cursor_end", 1);
663 }
664
665
666 /*
667 * Draw the console's input line.
668 *
669 * Parameters:
670 * font the current console font
671 * inputY the height at which the input line is located
672 */
_CON_DrawInputLine(FNT_font_t font,int inputY)673 static void _CON_DrawInputLine(
674 FNT_font_t font ,
675 int inputY )
676 {
677 struct FNT_window_s box;
678 char text[ MAXCMDLINE + 1 ];
679 unsigned int wToCursor;
680 unsigned int wAfterCursor;
681 unsigned int align;
682 char old;
683
684 if ( cls.key_dest == key_menu || ( cls.key_dest != key_console && cls.state == ca_active ) )
685 return;
686
687 // Copy current line
688 memcpy( text , key_lines[ edit_line ] , key_linelen );
689 text[ key_linelen ] = 0;
690
691 // Determine width of text before the cursor ...
692 old = text[ key_linepos ];
693 text[ key_linepos ] = 0;
694 box.x = 0;
695 box.y = viddef.height;
696 box.width = box.height = 0;
697 FNT_BoundedPrint( font , text , FNT_CMODE_QUAKE_SRS , FNT_ALIGN_LEFT , &box , FNT_colors[ 2 ] );
698 wToCursor = box.width;
699 text[ key_linepos ] = old;
700
701 // ... and after the cursor
702 if ( key_linelen > key_linepos ) {
703 box.width = box.height = 0;
704 FNT_BoundedPrint( font , text + key_linepos , FNT_CMODE_QUAKE_SRS , FNT_ALIGN_LEFT , &box , FNT_colors[ 2 ] );
705 wAfterCursor = box.width;
706 } else {
707 wAfterCursor = 0;
708 }
709
710 box.x = font->size;
711 box.y = inputY;
712 box.height = 0;
713 text[ key_linepos ] = 0;
714 if ( wToCursor + font->size * 5 < viddef.width ) {
715 // There is enough space for the start of the line
716 align = FNT_ALIGN_LEFT;
717 } else {
718 // Not enough space, print with right alignment
719 wToCursor = viddef.width * 0.9;
720 align = FNT_ALIGN_RIGHT;
721 }
722 box.width = wToCursor;
723 FNT_BoundedPrint( font , text , FNT_CMODE_QUAKE_SRS , align , &box , FNT_colors[ 2 ] );
724
725 // Draw cursor
726 if ( ( (int)( cls.realtime >> 8 ) & 1) != 0 ) {
727 Draw_Fill (box.x + box.width + 1 , box.y + 1 , font->size - 2 , font->size - 2 , RGBA(0,1,0,1));
728 }
729
730 // Draw whatever is after the cursor
731 if ( wAfterCursor ) {
732 text[ key_linepos ] = old;
733 box.x += box.width + font->size;
734 box.width = viddef.width - ( box.width + font->size * 5 );
735 box.height = 0;
736 FNT_BoundedPrint( font , text + key_linepos , FNT_CMODE_QUAKE_SRS , FNT_ALIGN_LEFT , &box , FNT_colors[ 2 ] );
737 }
738 }
739
740
741 /*
742 * Draw the line at the bottom of the console.
743 *
744 * This line includes the version string and the current download status.
745 *
746 * Parameters:
747 * y vertical offset of the bottom of the console
748 *
749 * Returns:
750 * vertical offset above the line at the bottom of the console
751 *
752 */
_CON_DrawConsoleBottom(int y)753 static int _CON_DrawConsoleBottom( int y )
754 {
755 FNT_font_t font;
756 char buffer[ MAX_STRING_CHARS ];
757 int kb , sz;
758
759 font = FNT_AutoGet( CL_gameFont );
760 y -= font->size;
761
762 // Draw version string
763 sz = sizeof( VERSION );
764 FNT_RawPrint( font , VERSION , sz , false ,
765 viddef.width - font->size * 5 * sz / 2 , y , FNT_colors[ 7 ] );
766
767 // Draw download status if needed
768 if ( ! ( cls.download && ( kb = (int)ftell( cls.download ) / 1024 ) ) ) {
769 return y;
770 }
771
772 Com_sprintf( buffer , MAX_STRING_CHARS , "Downloading %s [%s] ... %dKB" ,
773 cls.downloadname , ( cls.downloadhttp ? "HTTP" : "UDP" ), kb );
774 FNT_RawPrint( font , buffer , strlen( buffer ) , false ,
775 font->size * 3 , y , FNT_colors[ 3 ] );
776
777 return y;
778 }
779
780
781 /* Draw the console. */
CON_DrawConsole(float relSize)782 void CON_DrawConsole( float relSize )
783 {
784 FNT_font_t font;
785 int dHeight;
786 int height;
787 int start;
788 int fontSize;
789
790 // Don't draw if there's no video
791 if ( viddef.width < 1 ) {
792 return;
793 }
794
795 // Check for changes and act accordingly
796 font = FNT_AutoGet( CL_consoleFont );
797 if ( _CON_CheckResize( font ) ) {
798 CON_console.pWidth = viddef.width;
799 CON_console.pSize = font->size;
800 strcpy( CON_console.pFace , font->face->name );
801 memset( CON_console.heights , 0 , sizeof( CON_console.heights ) );
802 }
803 fontSize = font->size;
804
805 // Compute display height and draw background
806 dHeight = viddef.height * relSize;
807
808 // FIXME: lots of copy-pasted code here. Doesn't matter, we will
809 // eventually redo the whole console using the menu code.
810 {
811 int _tile_w, _tile_h;
812 float tile_w, tile_h;
813
814 // assume all tiles are the same size
815 Draw_GetPicSize (&_tile_w, &_tile_h, "menu/m_topcorner" );
816
817 tile_w = (float)_tile_w/64.0*(float)font->size*4.0;
818 tile_h = (float)_tile_h/64.0*(float)font->size*4.0;
819
820
821 Draw_AlphaStretchTilingPic( -tile_w/4, dHeight-tile_h/2, tile_w, tile_h, "menu/m_bottomcorner", 1 );
822 Draw_AlphaStretchTilingPic( viddef.width+tile_w/4, dHeight-tile_h/2, -tile_w, tile_h, "menu/m_bottomcorner", 1 );
823
824 Draw_AlphaStretchTilingPic( tile_w*0.75, dHeight-tile_h/2, viddef.width-tile_w*1.5, tile_h, "menu/m_bottom", 1 );
825
826 Draw_AlphaStretchTilingPic( -tile_w/4, 0, tile_w, dHeight-tile_h/2, "menu/m_side", 1 );
827 Draw_AlphaStretchTilingPic( viddef.width+tile_w/4, 0, -tile_w, dHeight-tile_h/2, "menu/m_side", 1 );
828 Draw_AlphaStretchTilingPic( tile_w*0.75, 0, viddef.width-tile_w, dHeight-tile_h/2, "menu/m_background", 1 );
829 }
830
831 // Draw version string and download status
832 dHeight = _CON_DrawConsoleBottom( dHeight ) - fontSize;
833
834 // Compute heights
835 height = _CON_ComputeHeight( font );
836 if ( height < dHeight ) {
837 CON_console.displayOffset = 0;
838 } else if ( CON_console.displayOffset > height - dHeight ) {
839 CON_console.displayOffset = height - dHeight;
840 }
841 start = height - dHeight - CON_console.displayOffset;
842
843 // Draw console contents & input line
844 _CON_DrawConsoleText( font , start , dHeight );
845 _CON_DrawScroller( font->size , height , dHeight );
846 _CON_DrawInputLine( font , dHeight );
847 }
848