1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: console.c 1566 2020-12-19 06:22:58Z wesleyjohnson $
5 //
6 // Copyright (C) 1998-2016 by DooM Legacy Team.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 //
19 // $Log: console.c,v $
20 // Revision 1.23 2003/08/11 13:50:03 hurdler
21 // go final + translucent HUD + fix spawn in net game
22 //
23 // Revision 1.22 2003/05/04 02:27:49 sburke
24 // Fix for big-endian machines.
25 //
26 // Revision 1.21 2002/09/10 19:29:46 hurdler
27 // Add log file under Linux
28 //
29 // Revision 1.20 2002/08/25 14:59:32 hurdler
30 //
31 // Revision 1.19 2002/07/23 15:07:09 mysterial
32 // Messages to second player appear on his half of the screen
33 //
34 // Revision 1.18 2001/12/26 17:24:46 hurdler
35 // Update Linux version
36 //
37 // Revision 1.17 2001/08/20 20:40:39 metzgermeister
38 // Revision 1.16 2001/05/16 21:21:14 bpereira
39 //
40 // Revision 1.15 2001/03/03 19:41:22 ydario
41 // I_OutputMsg not implemented in OS/2
42 //
43 // Revision 1.14 2001/03/03 06:17:33 bpereira
44 // Revision 1.13 2001/02/24 13:35:19 bpereira
45 //
46 // Revision 1.12 2001/01/25 22:15:41 bpereira
47 // added heretic support
48 //
49 // Revision 1.11 2000/11/12 09:48:15 bpereira
50 //
51 // Revision 1.10 2000/11/02 17:50:06 stroggonmeth
52 // Big 3Dfloors & FraggleScript commit!!
53 //
54 // Revision 1.9 2000/09/28 20:57:14 bpereira
55 // Revision 1.8 2000/08/31 14:30:55 bpereira
56 //
57 // Revision 1.7 2000/08/10 15:01:06 ydario
58 // OS/2 port
59 //
60 // Revision 1.6 2000/08/03 17:57:41 bpereira
61 //
62 // Revision 1.5 2000/04/24 15:10:56 hurdler
63 // Support colormap for text
64 //
65 // Revision 1.4 2000/04/16 18:38:06 bpereira
66 //
67 // Revision 1.3 2000/04/07 23:09:12 metzgermeister
68 // fixed array boundary error
69 //
70 // Revision 1.2 2000/02/27 00:42:10 hurdler
71 // Revision 1.1.1.1 2000/02/22 20:32:33 hurdler
72 // Initial import into CVS (v1.29 pr3)
73 //
74 //
75 // DESCRIPTION:
76 // console for Doom LEGACY
77 //
78 //-----------------------------------------------------------------------------
79
80
81 #include "doomincl.h"
82 #include "console.h"
83 #include "g_game.h"
84 #include "g_input.h"
85 // keys.h, gc_console
86 #include "hu_stuff.h"
87 #include "s_sound.h"
88 // sounds.h, S_StartSound
89 #include "v_video.h"
90 #include "i_video.h"
91 #include "i_system.h"
92 // I_OutputMessage
93 #include "z_zone.h"
94 #include "d_main.h"
95
96 //#include <unistd.h>
97
98 #ifdef HWRENDER
99 #include "hardware/hw_main.h"
100 #endif
101
102 #define CONSOLE_PROPORTIONAL
103
104 // External control
105 boolean con_self_refresh=false; // true at game startup, screen need refreshing
106 boolean con_recalc; // set true when screen size has changed
107
108 // Internal state
109 static boolean con_started=false; // console has been initialised
110 static boolean con_video=false; // text mode until video started
111 static boolean con_forcepic=true; // at startup toggle console translucency when
112 // first off
113
114 static int con_tick; // console ticker for anim or blinking prompt cursor
115 // con_scrollup should use time (currenttime - lasttime)..
116
117 static boolean consoletoggle; // true when console key pushed, ticker will handle
118 static boolean console_ready; // console prompt is ready
119 boolean console_open = false; // console is open
120
121 int con_destlines; // vid lines used by console at final position
122 static int con_curlines; // vid lines currently used by console
123
124 // Clip value for planes & sprites, so that the part of the view covered by the
125 // console is not drawn.
126 // It is set to the first drawable line under the console, and 0 when console is off.
127 int con_clipviewtop;
128
129 // TODO: choose max hud msg lines
130 #define CON_MAXHUDLINES 5
131
132 // Global interface with hu_stuff.
133 int con_clearlines; // top screen lines to refresh when view reduced
134 boolean con_hudupdate; // when messages scroll, we need a backgrnd refresh
135
136 // Internal state.
137 static int con_hudlines; // number of console heads up message lines
138 static int con_hudtime[CON_MAXHUDLINES]; // remaining time of display for hud msg lines
139
140 // To support splitscreen, 0=upper, 1=lower, 5=console only
141 static byte con_viewnum[CON_MAXHUDLINES];
142
143
144 // console text output
145 static char* con_line; // console text output current line
146 static int con_cx; // cursor position in current line
147 static int con_cy; // cursor line number in con_buffer, is always
148 // increasing, and wrapped around in the text
149 // buffer using modulo.
150
151 static int con_totallines; // lines of console text into the console buffer
152 static int con_width; // columns of chars, depend on vid mode width
153 static int con_indent; // pixel indent of console
154
155 static int con_scrollup; // how many rows of text to scroll up (pgup/pgdn)
156
157
158 #define CON_PROMPTCHAR '>'
159
160 // Hold last CON_MAX_LINEHIST prompt lines.
161 // [WDJ] Power 2 only, due to INDEXMASK.
162 #define CON_MAX_LINEHIST 32
163 #define CON_MAX_LINEHIST_INDEXMASK (CON_MAX_LINEHIST-1)
164 #define CON_MAX_LINELEN 256
165
166 // First char is prompt.
167 static char inputlines[CON_MAX_LINEHIST][CON_MAX_LINELEN];
168
169 static int inputline; // current input line number
170 static int inputhist; // line number of history input line to restore
171 static int input_cx; // position in current input line
172
173 static pic_t* con_backpic; // console background picture, loaded static
174 static pic_t* con_bordleft;
175 static pic_t* con_bordright; // console borders in translucent mode
176
177
178 // protos.
179 static void CON_Init_Input (void);
180 static void CON_Print (byte control, char *msg);
181 static void CONS_Clear_f (void);
182 static void CON_RecalcSize ( int width );
183
184 static void CONS_speed_Change (void);
185 static void CON_Draw_Backpic (pic_t *pic, int startx, int destwidth);
186
187
188 //======================================================================
189 // CONSOLE VARS AND COMMANDS
190 //======================================================================
191 #if defined( MACOS_DI ) && ! defined( __GNUC__ )
192 #define CON_BUFFERSIZE 4096 //my compiler cant handle local vars >32k
193 #else
194 #define CON_BUFFERSIZE 16384
195 #endif
196
197 static char con_buffer[CON_BUFFERSIZE];
198
199
200 // how many seconds the hud messages lasts on the screen
201 consvar_t cons_msgtimeout = {"con_hudtime","5",CV_VALUE|CV_SAVE,CV_Unsigned};
202
203 // number of lines console move per frame
204 consvar_t cons_speed = {"con_speed","8",CV_VALUE|CV_CALL|CV_SAVE,CV_Unsigned,&CONS_speed_Change};
205
206 // percentage of screen height to use for console
207 consvar_t cons_height = {"con_height","50",CV_SAVE,CV_Unsigned};
208
209 CV_PossibleValue_t backpic_cons_t[]={{0,"translucent"},{1,"picture"},{0,NULL}};
210 // whether to use console background picture, or translucent mode
211 consvar_t cons_backpic = {"con_backpic","0",CV_SAVE,backpic_cons_t};
212
213
214 // Check CONS_speed value (must be positive and >0)
215 //
CONS_speed_Change(void)216 static void CONS_speed_Change (void)
217 {
218 if (cons_speed.value<1)
219 CV_SetValue (&cons_speed,1);
220 }
221
222
223 // Clear console text buffer
224 //
CONS_Clear_f(void)225 static void CONS_Clear_f (void)
226 {
227 memset(con_buffer,0,CON_BUFFERSIZE);
228
229 con_cx = 0;
230 con_cy = con_totallines-1;
231 con_line = &con_buffer[con_cy*con_width];
232 con_scrollup = 0;
233 }
234
235 // Keys defined by the BIND command.
236 static char *bindtable[NUMINPUTS];
237
CONS_Bind_f(void)238 static void CONS_Bind_f(void)
239 {
240 int key;
241 COM_args_t carg;
242
243 COM_Args( &carg );
244
245 if ( carg.num!=2 && carg.num!=3 )
246 {
247 int nb = 0;
248 CONS_Printf("bind <keyname> [<command>]\n");
249 CONS_Printf("\2bind table :\n");
250 for(key=0;key<NUMINPUTS;key++)
251 {
252 if(bindtable[key])
253 {
254 CONS_Printf("%s : \"%s\"\n",G_KeynumToString (key),bindtable[key]);
255 nb=1;
256 }
257 }
258 if(!nb)
259 CONS_Printf("Empty\n");
260 return;
261 }
262
263 key=G_KeyStringtoNum( carg.arg[1] );
264 if(!key)
265 {
266 CONS_Printf("Invalid key name\n");
267 return;
268 }
269
270 if(bindtable[key]!=NULL)
271 {
272 Z_Free(bindtable[key]);
273 bindtable[key]=NULL;
274 }
275
276 if( carg.num==3 )
277 bindtable[key]=Z_StrDup( carg.arg[2] );
278 }
279
280
281 //======================================================================
282 // CONSOLE SETUP
283 //======================================================================
284
285 // Prepare a colormap for GREEN ONLY translucency over background
286 //
287 byte* whitemap = NULL;
288 byte* greenmap;
289 byte* graymap;
290
291 // May be called again after command_restart
CON_SetupBackColormap(void)292 static void CON_SetupBackColormap (void)
293 {
294 int i,j,k;
295 byte* pal;
296
297 //
298 // setup the green translucent background colormap
299 //
300 if( ! whitemap )
301 {
302 // setup the green translucent background colormap
303 greenmap = (byte *) Z_Malloc(256,PU_STATIC,NULL);
304 whitemap = (byte *) Z_Malloc(256,PU_STATIC,NULL);
305 graymap = (byte *) Z_Malloc(256,PU_STATIC,NULL);
306 }
307
308 // wad containing PLAYPAL may not be found yet.
309 if( ! VALID_LUMP( W_CheckNumForName( "PLAYPAL" ) ) )
310 return;
311
312 pal = W_CacheLumpName ("PLAYPAL",PU_CACHE); // temp, only used next loop
313
314 for(i=0,k=0; i<768; i+=3,k++)
315 {
316 j = pal[i] + pal[i+1] + pal[i+2];
317
318 if( EN_heretic )
319 {
320 greenmap[k] = 209 + (float)j*15/(3*255); //remaps to greens(209-224)
321 graymap[k] = (float)j*35/(3*255); //remaps to grays(0-35)
322 whitemap[k] = 145 + (float)j*15/(3*255); //remaps to reds(145-168)
323 }
324 else
325 greenmap[k] = 127 - (j>>6);
326 }
327
328 //
329 // setup the white and gray text colormap
330 //
331 // this one doesn't need to be aligned, unless you convert the
332 // V_DrawMappedPatch() into optimised asm.
333
334 if( EN_doom_etc )
335 {
336 for(i=0; i<256; i++)
337 {
338 whitemap[i] = i; //remap each color to itself...
339 graymap[i] = i;
340 }
341
342 for(i=168;i<192;i++)
343 {
344 whitemap[i]=i-88; //remaps reds(168-192) to whites(80-104)
345 graymap[i]=i-80; //remaps reds(168-192) to gray(88-...)
346 }
347 whitemap[45]=190-88; // the color[45]=color[190] !
348 graymap [45]=190-80;
349 whitemap[47]=191-88; // the color[47]=color[191] !
350 graymap [47]=191-80;
351 }
352 }
353
354
355 // Setup the console text buffer
356 //
357 // Init messaging, before zone memory, before video
358 // CON buffer will save all messages for display, so must be started very early
CON_Init_Setup(void)359 void CON_Init_Setup(void)
360 {
361 int i;
362
363 // clear all lines
364 con_width = 0; // no current text
365 CON_RecalcSize ( INITIAL_WINDOW_WIDTH ); // before vid is set
366 CONS_Clear_f (); // clear all lines
367 con_destlines = INITIAL_WINDOW_HEIGHT;
368 con_curlines = INITIAL_WINDOW_HEIGHT;
369
370 con_hudlines = CON_MAXHUDLINES;
371 CON_Clear_HUD ();
372
373 // setup console input filtering
374 CON_Init_Input ();
375
376 for(i=0;i<NUMINPUTS;i++)
377 bindtable[i]=NULL;
378
379 consoletoggle = false;
380 con_started = true;
381 }
382
383 // after zone memory init
CON_Register(void)384 void CON_Register(void)
385 {
386 // register our commands
387 CV_RegisterVar (&cons_msgtimeout);
388 CV_RegisterVar (&cons_speed);
389 CV_RegisterVar (&cons_height);
390 CV_RegisterVar (&cons_backpic);
391 COM_AddCommand ("cls", CONS_Clear_f, CC_console);
392 COM_AddCommand ("bind", CONS_Bind_f, CC_console);
393 }
394
395 // after FullGraphics
CON_Init_Video(void)396 void CON_Init_Video(void)
397 {
398 // vid : from video setup
399 if(dedicated)
400 return;
401
402 // make sure it is ready for the loading screen
403 CON_RecalcSize ( vid.width );
404
405 CON_SetupBackColormap ();
406
407 //note: CON_Ticker should always execute at least once before D_Display()
408 con_clipviewtop = 0; // does not clip
409
410 // load console background pic
411 con_backpic = (pic_t*) W_CachePicName ("CONSBACK",PU_STATIC);
412
413 // borders MUST be there
414 con_bordleft = (pic_t*) W_CachePicName ("CBLEFT",PU_STATIC);
415 con_bordright = (pic_t*) W_CachePicName ("CBRIGHT",PU_STATIC);
416
417 // set console full screen for game startup after FullGraphics
418 con_destlines = vid.height;
419 con_curlines = vid.height;
420
421 con_self_refresh = true; // need explicit screen refresh
422 // until we are in Doomloop
423 con_video = true; // if move CON init to before video startup
424 }
425
426
427 // Console input initialization
428 //
CON_Init_Input(void)429 static void CON_Init_Input (void)
430 {
431 int i;
432
433 // prepare the first prompt line
434 memset (inputlines,0,sizeof(inputlines));
435 for (i=0; i<CON_MAX_LINEHIST; i++)
436 inputlines[i][0] = CON_PROMPTCHAR;
437 inputline = 0;
438 input_cx = 1;
439 }
440
441
442
443 //======================================================================
444 // CONSOLE EXECUTION
445 //======================================================================
446
447 // [WDJ] This originally was (BASEVIDWIDTH>>3)-2, but that gives 38,
448 // and the LARGE font overruns the right margin at 30.
449 #define MIN_CONWIDTH 32
450 #define MAX_CONWIDTH 200
451
452 // Called at screen size change to set the rows and line size of the
453 // console text buffer.
454 //
CON_RecalcSize(int width)455 static void CON_RecalcSize ( int width )
456 {
457 int new_conwidth, oldcon_width, oldnumlines, oldcon_cy;
458 int i, conw;
459 char con2[CON_BUFFERSIZE];
460 char line2[MAX_CONWIDTH+4]; // BP: it is a line but who know ([WDJ] 30..94)
461
462 con_recalc = false;
463
464 // Calculate the new con_width.
465 if( width != vid.width )
466 {
467 // Before vid setup, so without any vid information
468 con_indent = 10;
469 if( width > 630 )
470 new_conwidth = (width>>4) - 2;
471 else
472 new_conwidth = (width>>3) - 2;
473 }
474 else
475 {
476 // Have graphics and vid information.
477 con_indent = vid.dupx * 10; // indent of console text to avoid edge
478 V_SetupFont( cv_con_fontsize.value, NULL, 0 );
479 #ifdef CONSOLE_PROPORTIONAL
480 // Averages shorter text, but could overrun right margin.
481 // Proportional width of print is (hu_font[c].width * dupx + 1).
482 // As drawfont.xinc is fixed, and some characters are wider ('M', 'W'),
483 // it is still possible to overrun the right margin.
484 new_conwidth = (width - con_indent - con_indent) / (drawfont.xinc + 1);
485 #else
486 // Fixed font size, between left and right margin.
487 new_conwidth = (width - con_indent - con_indent) / drawfont.xinc;
488 #endif
489 }
490 if ( new_conwidth < MIN_CONWIDTH )
491 {
492 con_indent -= MIN_CONWIDTH - new_conwidth;
493 if( con_indent < 2 ) con_indent = 2;
494 new_conwidth = MIN_CONWIDTH;
495 }
496 if (new_conwidth > MAX_CONWIDTH)
497 new_conwidth = MAX_CONWIDTH;
498
499 // check for change of video width
500 if (new_conwidth == con_width)
501 return; // didnt change
502
503
504 // save current
505 oldcon_width = con_width;
506 oldnumlines = con_totallines;
507 oldcon_cy = con_cy;
508 memcpy(con2, con_buffer, CON_BUFFERSIZE);
509
510 // setup to new width
511 con_width = new_conwidth;
512 con_totallines = CON_BUFFERSIZE / con_width;
513 CONS_Clear_f ();
514
515 // re-arrange console text buffer to keep text
516 if(oldcon_width) // not the first time
517 {
518 for(i=oldcon_cy+1; i<oldcon_cy+oldnumlines; i++)
519 {
520 char * con2p = &con2[(i% oldnumlines)*oldcon_width];
521 if( *con2p )
522 {
523 memcpy(line2, con2p, oldcon_width);
524 conw=oldcon_width-1;
525 while(line2[conw]==' ' && conw) conw--;
526 line2[conw+1]='\n';
527 line2[conw+2]='\0';
528 CON_Print( 5, line2); // console only
529 }
530 }
531 }
532 }
533
534
535 // Handles Console moves in/out of screen (per frame)
536 //
CON_MoveConsole(void)537 static void CON_MoveConsole (void)
538 {
539 // up/down move to dest
540 if (con_curlines < con_destlines)
541 {
542 con_curlines+=cons_speed.value;
543 if (con_curlines > con_destlines)
544 con_curlines = con_destlines;
545 }
546 else if (con_curlines > con_destlines)
547 {
548 con_curlines-=cons_speed.value;
549 if (con_curlines < con_destlines)
550 con_curlines = con_destlines;
551 }
552
553 }
554
555
556 // Clear time of console heads up messages
557 //
CON_Clear_HUD(void)558 void CON_Clear_HUD (void)
559 {
560 int i;
561
562 for(i=0; i<con_hudlines; i++)
563 con_hudtime[i]=0;
564 }
565
566
567 // Force console to move out immediately
568 // note: con_ticker will set console_ready false
CON_ToggleOff(void)569 void CON_ToggleOff (void)
570 {
571 if (!con_destlines)
572 return;
573
574 con_destlines = 0;
575 con_curlines = 0;
576 CON_Clear_HUD ();
577 con_forcepic = 0;
578 con_clipviewtop = 0; // turn off console clip
579 console_open = false; // instant off
580 }
581
582
583 static event_t con_autorepeat_ev;
584 static byte con_autorepeat_tick = 0;
585
586
587 // Console ticker : handles console move in/out, cursor blinking
588 //
589 // Call once per tic.
CON_Ticker(void)590 void CON_Ticker (void)
591 {
592 // vid : from video setup
593 int i;
594
595 // cursor blinking
596 con_tick++;
597 con_tick &= 7;
598
599 // console key was pushed
600 if (consoletoggle)
601 {
602 consoletoggle = false;
603
604 if (con_destlines > 0)
605 {
606 // toggle off console
607 con_destlines = 0;
608 CON_Clear_HUD ();
609 }
610 else
611 {
612 // toggle console in
613 con_destlines = (cons_height.value*vid.height)/100;
614 if (con_destlines < 20)
615 con_destlines = 20;
616 else
617 if (con_destlines > (vid.height - stbar_height) )
618 con_destlines = vid.height - stbar_height;
619
620 con_destlines &= ~0x3; // multiple of text row height
621 }
622 }
623
624 // console movement
625 if (con_destlines!=con_curlines)
626 CON_MoveConsole (); // update con_curlines
627
628
629 // clip the view, so that the part under the console is not drawn
630 con_clipviewtop = 0;
631 if (cons_backpic.value) // clip only when using an opaque background
632 {
633 if (con_curlines > 0)
634 {
635 // [WDJ] Set to highest drawable line under console.
636 // con_clipviewtop = con_curlines; // [WDJ] what it should be
637 con_clipviewtop = con_curlines - viewwindowy - 10;
638 //NOTE: BIG HACK::SUBTRACT 10, SO THAT WATER DON'T COPY LINES OF THE CONSOLE
639 // WINDOW!!! (draw some more lines behind the bottom of the console)
640 }
641
642 if (con_clipviewtop<0)
643 con_clipviewtop = 0; // limit to drawable window
644 }
645
646 // check if console ready for prompt
647 // if ((con_curlines==con_destlines) && (con_destlines>=20))
648 console_ready = (con_destlines >= 20);
649
650 // To detect console.
651 console_open = ((con_destlines + con_curlines) != 0);
652
653 // make overlay messages disappear after a while
654 for (i=0 ; i<con_hudlines; i++)
655 {
656 con_hudtime[i]--;
657 if (con_hudtime[i]<0)
658 con_hudtime[i]=0;
659 }
660
661 if( con_autorepeat_tick )
662 {
663 con_autorepeat_tick --;
664 if( con_autorepeat_tick == 1 )
665 CON_Responder( & con_autorepeat_ev );
666 }
667 }
668
669
670 // Handles console key input
671 //
CON_Responder(event_t * ev)672 boolean CON_Responder(event_t *ev)
673 {
674 // sequential completions a la 4dos
675 static char completion[80];
676 static int comskips,varskips;
677
678 const char * cmd = NULL;
679
680 // [WDJ] The compiler re-optimizes the returns. Collecting them
681 // into common return true, and return false, has no net effect.
682 //
683 // Return true: eat the key
684 // false: reject the key
685
686 if(chat_on)
687 return false;
688
689 // let go keyup events, don't eat them
690 if (ev->type != ev_keydown)
691 {
692 con_autorepeat_tick = 0;
693 return false;
694 }
695
696 int key = ev->data1;
697
698 // Detect console activate key (user definable).
699 if (key == gamecontrol[gc_console][0] ||
700 key == gamecontrol[gc_console][1] ) goto toggle_console;
701
702 if (! console_ready)
703 {
704 // Console prompt not active. This is the path during game play.
705 // Check game playing keys defined by BIND command.
706 // metzgermeister: boundary check !!
707 if((key < NUMINPUTS) && bindtable[key])
708 {
709 // [WDJ] Must be done as one string, it could try to execute a partial string.
710 COM_BufAddText ( va( "%s\n", bindtable[key] ) );
711 return true;
712 }
713 return false;
714 }
715
716 if( key >= KEY_NUMKB )
717 return false; // mouse, joystick button
718
719
720 // Console prompt active
721 // [WDJ] Trying to use a switch stmt, increases the size for unknown
722 // reasons related to optimization. It uses extra tests to gain speed.
723 // It optimizes the repeated tests of the key better than the switch.
724
725 // eat shift only if console active
726 if (key == KEY_RSHIFT || key == KEY_LSHIFT)
727 return true;
728
729 // escape key toggle off console
730 if (key == KEY_ESCAPE) goto toggle_console;
731
732 // command completion forward (tab) and backward (shift-tab)
733 if (key == KEY_TAB)
734 {
735 // TOTALLY UTTERLY UGLY NIGHT CODING BY FAB!!! :-)
736 //
737 // sequential command completion forward and backward
738
739 // remember typing for several completions (�-la-4dos)
740 if (inputlines[inputline][input_cx-1] != ' ')
741 {
742 if (strlen (inputlines[inputline]+1)<80)
743 strcpy (completion, inputlines[inputline]+1);
744 else
745 completion[0] = 0;
746
747 comskips = varskips = 0;
748 }
749 else
750 {
751 // comskips < 0 indicates var name completion
752 if (shiftdown)
753 {
754 if (comskips<0)
755 {
756 if (--varskips<0)
757 comskips = -(comskips+2);
758 }
759 else
760 if (comskips>0)
761 comskips--;
762 }
763 else
764 {
765 if (comskips<0)
766 varskips++;
767 else
768 comskips++;
769 }
770 }
771
772 if (comskips>=0)
773 {
774 cmd = COM_CompleteCommand (completion, comskips);
775 if (!cmd)
776 {
777 // No command, try var completion.
778 // dirty:make sure if comskips is zero, to have a neg value
779 comskips = -(comskips+1);
780 }
781 }
782 if (comskips<0)
783 cmd = CV_CompleteVar (completion, varskips);
784
785 if (cmd)
786 {
787 memset(inputlines[inputline]+1,0,CON_MAX_LINELEN-1);
788 strcpy (inputlines[inputline]+1, cmd);
789 input_cx = strlen(cmd)+1;
790 inputlines[inputline][input_cx] = ' ';
791 input_cx++;
792 inputlines[inputline][input_cx] = 0;
793 }
794 else
795 {
796 // No command, no var completion. Backup off this candidate.
797 if (comskips>0)
798 comskips--;
799 else
800 if (varskips>0)
801 varskips--;
802 }
803
804 return true;
805 }
806
807 // move up (backward) in console textbuffer
808 if (key == KEY_PGUP)
809 {
810 if (con_scrollup < (con_totallines-((con_curlines-16)>>3)) )
811 con_scrollup++;
812 goto enable_autorepeat;
813 }
814 if (key == KEY_PGDN)
815 {
816 if (con_scrollup>0)
817 con_scrollup--;
818 goto enable_autorepeat;
819 }
820
821 // oldset text in buffer
822 if (key == KEY_HOME)
823 {
824 con_scrollup = (con_totallines-((con_curlines-16)>>3));
825 return true;
826 }
827 // most recent text in buffer
828 if (key == KEY_END)
829 {
830 con_scrollup = 0;
831 return true;
832 }
833
834 // command enter
835 if (key == KEY_ENTER)
836 {
837 if (input_cx<2)
838 return true; // nothing significant
839
840 // push the command
841 // [WDJ] Must be done as one string, it could try to execute a partial string.
842 // The first char is prompt, not part of the command.
843 COM_BufAddText ( va( "%s\n", inputlines[inputline]+1 ));
844
845 CONS_Printf("%s\n",inputlines[inputline]);
846
847 // Advance to next inputline.
848 inputline = (inputline+1) & CON_MAX_LINEHIST_INDEXMASK;
849 inputhist = inputline;
850
851 memset(inputlines[inputline],0,CON_MAX_LINELEN);
852 inputlines[inputline][0] = CON_PROMPTCHAR;
853 input_cx = 1;
854
855 return true;
856 }
857
858 // backspace command prompt
859 if (key == KEY_BACKSPACE)
860 {
861 if (input_cx>1) // back to prompt
862 {
863 input_cx--;
864 inputlines[inputline][input_cx] = 0;
865 }
866 return true;
867 }
868
869 // move back in input history
870 if (key == KEY_UPARROW)
871 {
872 // copy one of the previous inputlines to the current
873 do{
874 inputhist = (inputhist - 1) & CON_MAX_LINEHIST_INDEXMASK; // cycle back
875 }while (inputhist!=inputline && !inputlines[inputhist][1]);
876
877 // stop at the last history input line, which is the
878 // current line + 1 because we cycle through the 32 input lines
879 if (inputhist==inputline)
880 inputhist = (inputline + 1) & CON_MAX_LINEHIST_INDEXMASK;
881
882 memcpy (inputlines[inputline],inputlines[inputhist],CON_MAX_LINELEN);
883 input_cx = strlen(inputlines[inputline]);
884
885 return true;
886 }
887
888 // move forward in input history
889 if (key == KEY_DOWNARROW)
890 {
891 if (inputhist==inputline) return true;
892
893 do{
894 inputhist = (inputhist + 1) & CON_MAX_LINEHIST_INDEXMASK;
895 } while (inputhist!=inputline && !inputlines[inputhist][1]);
896
897 memset (inputlines[inputline],0,CON_MAX_LINELEN);
898
899 // back to currentline
900 if (inputhist==inputline)
901 {
902 inputlines[inputline][0] = CON_PROMPTCHAR;
903 input_cx = 1;
904 }
905 else
906 {
907 // [WDJ] GCC 10 complains that strings may overlap so cannot use strcpy.
908 // But overlap case handled above.
909 memmove( inputlines[inputline], inputlines[inputhist], CON_MAX_LINELEN );
910 input_cx = strlen(inputlines[inputline]);
911 }
912 return true;
913 }
914
915 // interpret it as input char
916 char c = ev->data2;
917
918 // allow people to use keypad in console (good for typing IP addresses) - Calum
919 if (key >= KEY_KEYPAD0 && key <= KEY_PLUSPAD)
920 {
921 const char keypad_translation[] = {'0','1','2','3','4','5','6','7','8','9','.','/','*','-','+'};
922 c = keypad_translation[key - KEY_KEYPAD0];
923 }
924
925 // enter a printable char into the command prompt
926 if (c < ' ' || c > '~')
927 return false;
928
929 // add key to cmd line here
930 if (input_cx<CON_MAX_LINELEN)
931 {
932 // make sure letters are lowercase for commands & cvars
933 if (c >= 'A' && c <= 'Z')
934 c = c + 'a' - 'A';
935
936 inputlines[inputline][input_cx] = c;
937 input_cx++;
938 inputlines[inputline][input_cx] = 0;
939 }
940
941 return true;
942
943 toggle_console:
944 consoletoggle = true; // signal to CON_Ticker
945 return true;
946
947 enable_autorepeat:
948 con_autorepeat_ev = *ev;
949 con_autorepeat_tick = 4;
950 return true;
951 }
952
953
954 // Insert a new line in the console text buffer
955 //
956 // viewnum : splitscreen 0=upper, 1=lower, single player uses 0, 5=console only
CON_Linefeed(byte viewnum)957 static void CON_Linefeed (byte viewnum)
958 {
959 con_viewnum[con_cy%con_hudlines] = viewnum; // May be msg for player2
960
961 // set time for heads up messages
962 con_hudtime[con_cy%con_hudlines] =
963 (viewnum < 2)? cons_msgtimeout.value*TICRATE : 0;
964
965 con_cy++;
966 con_cx = 0;
967
968 con_line = &con_buffer[(con_cy%con_totallines)*con_width];
969 memset(con_line,' ',con_width);
970
971 // make sure the view borders are refreshed if hud messages scroll
972 con_hudupdate = true; // see HU_Erase()
973 }
974
975
976 // Outputs text into the console text buffer
977 //
CON_Print(byte control,char * msg)978 static void CON_Print (byte control, char *msg)
979 {
980 int l; // word length
981 int text_color=0; // 0x80 is white text flag
982 int viewnum=0; // 0=upper, 1=lower, Single player uses 0. 5=console only
983
984 viewnum = control & 0x0F;
985
986 //TODO: finish text colors
987 if (*msg<5)
988 {
989 switch( *msg )
990 {
991 case '\2' : // white text
992 text_color = 0x80;
993 break;
994 case '\3' : // white text + sound
995 text_color = 0x80; // white text
996 if ( gamemode == doom2_commercial )
997 S_StartSound(sfx_radio);
998 else
999 S_StartSound(sfx_tink);
1000 break;
1001 default:
1002 break;
1003 }
1004 }
1005
1006 while (*msg)
1007 {
1008 // handle non-printable characters and white spaces
1009 while ( *msg <= ' ' )
1010 {
1011 switch( *msg )
1012 {
1013 case '\r': // carriage return
1014 con_cy--;
1015 CON_Linefeed (viewnum);
1016 break;
1017 case '\n': // linefeed
1018 CON_Linefeed (viewnum);
1019 break;
1020 case ' ': // leading space
1021 con_line[con_cx++] = ' ';
1022 if (con_cx >= con_width)
1023 CON_Linefeed(viewnum);
1024 break;
1025 case '\t': // tab
1026 //adds tab spaces for nice layout in console
1027 do
1028 {
1029 con_line[con_cx++] = ' ';
1030 } while (con_cx%4 != 0);
1031
1032 if (con_cx>=con_width)
1033 CON_Linefeed(viewnum);
1034 break;
1035 case 0: // End of string
1036 return;
1037
1038 default:
1039 break;
1040 }
1041 msg++;
1042 }
1043
1044 // printable character
1045 // Find end of word
1046 for (l=0; l<con_width; l++)
1047 if( msg[l] <= ' ' ) break; // until space, or EOS
1048
1049 // word wrap when word is too long for the rest of the width
1050 if (con_cx+l>con_width)
1051 CON_Linefeed (viewnum);
1052
1053 // a word at a time
1054 for ( ; l>0; l--)
1055 con_line[con_cx++] = *(msg++) | text_color;
1056 }
1057 }
1058
1059
1060 // Console print! Wahooo! Lots o fun!
1061 //
1062 #define CONS_BUF_SIZE 1024
1063
1064
1065 // Tables for comparison to cv_gameplay.
1066 // {0,"Off"},{1,"Minimal"},{2,"Play"},{3,"Verbose"},{4,"Debug"},{5,"Dev"},
1067
1068 // Show messages on hud when cv_gameplay is set at or higher than this table.
1069 // Otherwise route message only to the console.
1070 // 0 always shows the message on the hud.
1071 // indexed by EMSG_cat
1072 static byte gameplay_hud_message_table[ 16 ] =
1073 {
1074 3, // EMSG_CONS
1075 0, // EMSG_playmsg
1076 0, // EMSG_playmsg2
1077 0, // unk3
1078 0, // unk4
1079 250, // EMSG_console
1080 1, // EMSG_hud
1081 0, // unk7
1082 2, // EMSG_info
1083 3, // EMSG_ver
1084 4, // EMSG_debug
1085 5, // EMSG_dev
1086 2, // EMSG_warn
1087 0, // EMSG_errlog
1088 0, // EMSG_error
1089 0 // EMSG_error2
1090 };
1091 // Show messages on console when cv_gameplay is set at or higher than this table.
1092 // 0 always shows the message on the console.
1093 // indexed by EMSG_cat
1094 static byte gameplay_con_message_table[ 16 ] =
1095 {
1096 0, // EMSG_CONS (cannot be blocking CONS_Printf from the console)
1097 0, // EMSG_playmsg
1098 0, // EMSG_playmsg2
1099 0, // unk3
1100 0, // unk4
1101 0, // EMSG_console (interactive console specific)
1102 0, // EMSG_hud
1103 0, // unk7
1104 1, // EMSG_info
1105 2, // EMSG_ver
1106 3, // EMSG_debug
1107 4, // EMSG_dev
1108 0, // EMSG_warn
1109 0, // EMSG_errlog
1110 0, // EMSG_error
1111 0 // EMSG_error2
1112 };
1113
1114 // [WDJ] print from va_list
1115 // Caller must have va_start, va_end, or else run-time segfault will occur.
GenPrintf_va(const byte emsg,const char * fmt,va_list ap)1116 void GenPrintf_va (const byte emsg, const char *fmt, va_list ap)
1117 {
1118 byte eout = EOUT_flags; // default for CONS_Printf
1119 byte ecat = emsg & EMSG_cat;
1120 byte viewnum = 0;
1121 // vid : from video setup
1122 char txt[CONS_BUF_SIZE];
1123
1124 // print the error
1125 vsnprintf(txt, CONS_BUF_SIZE, fmt, ap);
1126 txt[CONS_BUF_SIZE-1] = '\0'; // term, when length limited
1127
1128 // Route the message to various outputs according to category.
1129 switch( ecat )
1130 {
1131 case EMSG_playmsg:
1132 eout = EOUT_hud | EOUT_con;
1133 viewnum = 0;
1134 break;
1135 case EMSG_playmsg2: // player2 splitscreen
1136 eout = EOUT_hud | EOUT_con;
1137 viewnum = 1;
1138 break;
1139 case EMSG_console: // console interactive
1140 eout = EOUT_con; // console only
1141 viewnum = 5;
1142 break;
1143 case EMSG_hud:
1144 eout |= EOUT_hud | EOUT_con;
1145 break;
1146 case EMSG_warn:
1147 eout |= EOUT_all;
1148 break;
1149 case EMSG_errlog: // stderr and log, but not console
1150 eout = EOUT_text | EOUT_log;
1151 break;
1152 case EMSG_error: // error soft
1153 eout |= EOUT_all;
1154 break;
1155 case EMSG_error2: // error severe
1156 eout = EOUT_all | EOUT_hud;
1157 break;
1158 case EMSG_debug: // debug category
1159 #if defined(SMIF_PC_DOS) || defined(WIN32) || defined(SMIF_OS2_NATIVE)
1160 eout = EOUT_text | EOUT_con | EOUT_log;
1161 #else
1162 // Linux, Mac
1163 eout = EOUT_text | EOUT_log;
1164 #endif
1165 if( cv_showmessages.EV >= 4 )
1166 eout |= EOUT_con | EOUT_hud;
1167 break;
1168 case EMSG_dev: // development category
1169 eout &= ~EOUT_hud;
1170 #if defined(SMIF_PC_DOS) || defined(WIN32) || defined(SMIF_OS2_NATIVE)
1171 eout |= EOUT_con;
1172 #else
1173 // Linux, Mac
1174 eout = EOUT_text | EOUT_log;
1175 #endif
1176 break;
1177 default:
1178 break;
1179 }
1180
1181 if( emsg & EMSG_all )
1182 eout |= EOUT_text | EOUT_con | EOUT_log;
1183
1184 #ifdef LOGMESSAGES
1185 if( eout & EOUT_log )
1186 {
1187 // echo console prints to log file
1188 if (logstream)
1189 fputs(txt, logstream);
1190 }
1191 #endif
1192 DEBFILE(txt);
1193
1194 #ifndef DEBUG_MESSAGES_ON
1195 // Hide debug messages for release version
1196 if((ecat == EMSG_debug) && (verbose == 0) && (cv_showmessages.EV < 4))
1197 goto done; // disable debug messages
1198 #endif
1199
1200 if( (eout & EOUT_text) || (! vid.draw_ready) )
1201 {
1202 // Errors to terminal, and before graphics
1203 I_OutputMsg ("%s",txt);
1204 fflush(NULL);
1205 }
1206
1207 #if 0
1208 #ifdef LINUX
1209 // Keep debug messages off console, for some versions
1210 if( ecat == EMSG_debug ) goto done;
1211 #endif
1212 #endif
1213
1214 if( ! con_started ) goto done;
1215
1216 // During gameplay the hud is dedicated to the game, according
1217 // to the cv_showmessages setting.
1218 if( gameplay_msg )
1219 {
1220 // During game playing, honor the showmessage option.
1221 if( cv_showmessages.EV < gameplay_hud_message_table[ ecat ] )
1222 viewnum = 5; // console only
1223 if( cv_showmessages.EV < gameplay_con_message_table[ ecat ] )
1224 return;
1225 }
1226
1227 #if 0
1228 // Other ecat tests have already forced EOUT_con for error messages.
1229 #ifdef LAUNCHER
1230 // Allow errors to go to Launcher fatal error display.
1231 #else
1232 if( (ecat == EMSG_error) || (ecat == EMSG_error2) )
1233 {
1234 // Errors to CON, unless no con_video yet.
1235 if( ! con_video ) goto done;
1236 }
1237 #endif
1238 #endif
1239
1240 // Situations inherited from EMSG_ settings.
1241 if( (eout & (EOUT_hud|EOUT_con)) == 0 ) goto done; // no CONS flag
1242
1243 if( (eout & (EOUT_hud|EOUT_con)) == EOUT_con )
1244 viewnum = 5; // console only
1245
1246 // Output to EOUT_con, EOUT_hud, splitscreen.
1247 // Write the message in con text buffer.
1248 CON_Print ( viewnum, txt );
1249
1250 // make sure new text is visible
1251 con_scrollup = 0;
1252
1253 // if not in display loop, force screen update
1254 if ( con_self_refresh || (emsg & EMSG_now) )
1255 {
1256 // Protect against segfaults during video mode switch.
1257 if( ! vid.draw_ready ) goto done;
1258 // Have graphics, but do not have refresh loop running.
1259 #if defined(SMIF_WIN_NATIVE) || defined(SMIF_OS2_NATIVE)
1260 // show startup screen and message using only 'software' graphics
1261 // (rendermode may be hardware accelerated, but the video mode is not set yet)
1262 CON_Draw_Backpic (con_backpic, 0, vid.width); // put console background
1263 I_LoadingScreen ( txt );
1264 #else
1265 V_Clear_Display();
1266 // here we display the console background and console text
1267 // (no hardware accelerated support for these versions)
1268 CON_Drawer ();
1269 I_FinishUpdate (); // page flip or blit buffer
1270 #endif
1271 }
1272 else if ( ! con_video )
1273 {
1274 // Protect against segfaults during video mode switch.
1275 if( ! vid.draw_ready ) goto done;
1276 // Text messages without con_video graphics.
1277 CON_Draw_Console (); // Text with or without con_video
1278 I_FinishUpdate ();
1279 }
1280 done:
1281 return;
1282 }
1283
1284 // General printf interface for CONS_Printf
1285 // Due to script files and indirect commands, many error messages
1286 // still go through here, so they are seen on stderr.
1287 // Global param: EOUT_flags
CONS_Printf(const char * fmt,...)1288 void CONS_Printf (const char *fmt, ...)
1289 {
1290 va_list ap;
1291
1292 va_start(ap, fmt);
1293 GenPrintf_va( EMSG_CONS, fmt, ap );
1294 va_end(ap);
1295 }
1296
1297 // Print an error message, and wait for ENTER key to continue.
1298 // To make sure the user has seen the message
1299 //
CONS_Error(char * msg)1300 void CONS_Error (char *msg)
1301 {
1302 #ifdef SMIF_WIN_NATIVE
1303 if( graphics_state < VGS_active )
1304 {
1305 I_MsgBox (msg);
1306 return;
1307 }
1308 #endif
1309 // Must pass msg through an interface that uses va_start, va_end.
1310 GenPrintf( EMSG_error, "\2%s", msg); // write error msg in different colour
1311
1312 // CONS_Printf ("Press ENTER to continue\n");
1313 // dirty quick hack, but for the good cause
1314 // while (I_GetKey() != KEY_ENTER)
1315 // ;
1316 }
1317
1318 // Console interaction printf interface.
1319 // This only routes the print to the console, not the logs, not to stderr.
1320 // Do not use this for command error messages, because many commands are
1321 // used in scripts, or exec indirectly, and the user would not see
1322 // the error messages.
con_Printf(const char * fmt,...)1323 void con_Printf (const char *fmt, ...)
1324 {
1325 va_list ap;
1326
1327 va_start(ap, fmt);
1328 GenPrintf_va( EMSG_console, fmt, ap );
1329 va_end(ap);
1330 }
1331
1332 // Debug printf interface.
1333 // Easy to use replacement for debug messages going through CONS_Printf.
debug_Printf(const char * fmt,...)1334 void debug_Printf (const char *fmt, ...)
1335 {
1336 va_list ap;
1337
1338 // It is still possible to use GenPrintf(EMSG_debug, ) which is
1339 // why there will be no special tests here.
1340 va_start(ap, fmt);
1341 GenPrintf_va( EMSG_debug, fmt, ap );
1342 va_end(ap);
1343 }
1344
1345 // For info, debug, dev, verbose messages.
1346 // Print to output set by EOUT_flags.
GenPrintf(const byte emsg,const char * fmt,...)1347 void GenPrintf (const byte emsg, const char *fmt, ...)
1348 {
1349 va_list ap;
1350 va_start(ap, fmt);
1351 GenPrintf_va( emsg, fmt, ap ); // print to text, console, and logs
1352 va_end(ap);
1353 }
1354
1355
1356 //======================================================================
1357 // CONSOLE DRAW
1358 //======================================================================
1359
1360
1361 // draw console prompt line
1362 //
CON_DrawInput(int y)1363 static void CON_DrawInput ( int y )
1364 {
1365 char *p;
1366 int x;
1367
1368 // Draw console text, screen0
1369 // V_SetupDraw( 0 | V_NOSCALE );
1370
1371 // input line scrolls left if it gets too long
1372 //
1373 p = inputlines[inputline];
1374 if (input_cx >= con_width)
1375 p += input_cx - con_width + 1;
1376
1377 #ifdef CONSOLE_PROPORTIONAL
1378 int xj, xcursor = 0;
1379 x = con_indent;
1380 for(xj=0; xj<con_width; xj++)
1381 {
1382 if( xj == input_cx )
1383 xcursor = x;
1384 x += V_DrawCharacter( x, y, p[xj] ); // red
1385 }
1386 #else
1387 // Fixed width font.
1388 for(x=0; x<con_width; x++)
1389 V_DrawCharacter( x * drawfont.xinc + con_indent, y, p[x] ); // red
1390 #endif
1391
1392 // draw the blinking cursor
1393 //
1394 #ifdef CONSOLE_PROPORTIONAL
1395 if (con_tick<4)
1396 V_DrawCharacter( xcursor, y, 0x80 | '_' ); // white
1397 #else
1398 x = (input_cx>=con_width) ? con_width - 1 : input_cx;
1399 if (con_tick<4)
1400 V_DrawCharacter( x * drawfont.xinc + con_indent, y, 0x80 | '_' ); // white
1401 #endif
1402 }
1403
1404
1405 // draw the last lines of console text to the top of the screen
1406 //
1407 #ifdef HWRENDER //Added by Mysterial
1408 extern float gr_viewheight; //needed for drawing second player's messages
1409 //halfway down
1410 #endif
1411
CON_Draw_Hudlines(void)1412 static void CON_Draw_Hudlines (void)
1413 {
1414 fontinfo_t * fip = V_FontInfo(); // draw font1 and wad font strings
1415 byte viewnum;
1416 char *p;
1417 int y1,y2,x,y,i;
1418
1419 if (con_hudlines<=0)
1420 return;
1421
1422 V_SetupFont( cv_msg_fontsize.value, fip, V_NOSCALE );
1423
1424 // player1 message y
1425 y1 = (chat_on) ?
1426 drawfont.yinc // leave place for chat input in the first row of text
1427 : 0;
1428 y = y1;
1429 // player2 message y in splitscreen
1430 #ifdef HWRENDER
1431 // by Mysterial, moved by [WDJ]
1432 y2 = (rendermode==render_soft)? rdraw_viewheight : gr_viewheight;
1433 #else
1434 y2 = rdraw_viewheight;
1435 #endif
1436
1437 for (i= con_cy-con_hudlines+1; i<=con_cy; i++)
1438 {
1439 if (i < 0)
1440 continue;
1441 if (con_hudtime[i%con_hudlines] == 0)
1442 continue;
1443
1444 viewnum = con_viewnum[i%con_hudlines];
1445 // viewnum: 0=upper, 1=lower, 5=console only
1446 if( viewnum > 1 ) continue; // console only
1447 y = (viewnum == 1)? y2 : y1;
1448
1449 p = &con_buffer[(i%con_totallines)*con_width];
1450
1451 #ifdef CONSOLE_PROPORTIONAL
1452 x = drawfont.xinc; // indent
1453 int xj;
1454 for (xj=0; xj<con_width; xj++)
1455 {
1456 // red, proportional width font
1457 x += V_DrawCharacter ( x, y, p[xj] );
1458 // x += V_DrawCharacter ( x, y, (p[x]&0x7f) ); // force red
1459 }
1460 #else
1461 for (x=0; x<con_width; x++)
1462 {
1463 // red, fixed width font
1464 V_DrawCharacter ( (x+1)*drawfont.xinc, y, p[x] );
1465 // V_DrawCharacter ( (x+1)*drawfont.xinc, y, (p[x]&0x7f) );
1466 }
1467 #endif
1468
1469 // viewnum: 0=upper, 1=lower
1470 if ( viewnum == 1 )
1471 y2 += drawfont.yinc;
1472 else
1473 y1 += drawfont.yinc;
1474 }
1475
1476 // top screen lines that might need clearing when view is reduced
1477 con_clearlines = y; // this is handled by HU_Erase ();
1478 }
1479
1480
1481 // Scale a pic_t at 'startx' pos, to 'destwidth' columns.
1482 // startx,destwidth is resolution dependent
1483 // Used to draw console borders, console background.
1484 // The pic must be sized BASEVIDHEIGHT height.
1485 //
1486 // TODO: ASM routine!!! lazy Fab!!
1487 //
CON_Draw_Backpic(pic_t * pic,int startx,int destwidth)1488 static void CON_Draw_Backpic (pic_t *pic, int startx, int destwidth)
1489 {
1490 // vid : from video setup
1491 int pic_h = pic->height;
1492 int pic_w = pic->width;
1493 int x, y;
1494 int v;
1495 fixed_t frac, fracstep;
1496 byte *src;
1497 byte *dest; // within screen buffer
1498
1499 // [WDJ] Draw picture for all bpp, bytepp, and padded lines.
1500 dest = V_GetDrawAddr( startx, 0 ); // screen0 buffer
1501
1502 for (y=0 ; y<con_curlines ; y++, dest += vid.ybytes)
1503 {
1504 // scale the picture to the resolution
1505 v = pic_h - ((con_curlines - y)*(BASEVIDHEIGHT-1)/vid.height) - 1;
1506
1507 src = pic->data + v*pic_w;
1508
1509 // in case of the console backpic, simplify
1510 if (pic_w == destwidth && vid.bytepp == 1)
1511 memcpy (dest, src, destwidth);
1512 else
1513 {
1514 // scale pic to screen width
1515 frac = 0;
1516 fracstep = (pic_w<<16)/destwidth;
1517 for (x=0 ; x<destwidth ; x+=4)
1518 {
1519 V_DrawPixel( dest, x, src[frac>>16] );
1520 frac += fracstep;
1521 V_DrawPixel( dest, x+1, src[frac>>16] );
1522 frac += fracstep;
1523 V_DrawPixel( dest, x+2, src[frac>>16] );
1524 frac += fracstep;
1525 V_DrawPixel( dest, x+3, src[frac>>16] );
1526 frac += fracstep;
1527 }
1528 }
1529 }
1530
1531 }
1532
1533
1534 // Draw the console background, text, and prompt if enough places.
1535 // May use font1 or wad fonts.
1536 // Uses screens[0].
1537 //
CON_Draw_Console(void)1538 void CON_Draw_Console (void)
1539 {
1540 // vid : from video setup
1541 fontinfo_t * fip = V_FontInfo(); // draw font1 and wad font strings
1542 char *p;
1543 int i,x,y;
1544 int w = 0, x2 = 0;
1545
1546 if (con_curlines <= 0)
1547 return;
1548
1549 if ( rendermode != render_soft && use_font1 )
1550 return; // opengl graphics, hu_font not loaded yet
1551
1552 V_SetupFont( cv_con_fontsize.value, fip, V_NOSCALE );
1553
1554 //FIXME: refresh borders only when console bg is translucent
1555 con_clearlines = con_curlines; // clear console draw from view borders
1556 con_hudupdate = true; // always refresh while console is on
1557
1558 // draw console background
1559 if (!con_video)
1560 {
1561 V_Clear_Display();
1562 }
1563 else
1564 if (cons_backpic.value || con_forcepic)
1565 {
1566 #ifdef HWRENDER // not win32 only 19990829 by Kin
1567 if (rendermode!=render_soft)
1568 V_DrawScalePic_Num (0, con_curlines-200*vid.fdupy,
1569 W_GetNumForName ("CONSBACK") );
1570 else
1571 #endif
1572 CON_Draw_Backpic (con_backpic,0,vid.width); // picture as background
1573 }
1574 else
1575 {
1576 #ifdef HWRENDER // not win32 only 19990829 by Kin
1577 if( rendermode == render_soft )
1578 #endif
1579 {
1580 w = fip->xinc * vid.dupx; // font1 or wad font
1581 x2 = vid.width - w;
1582 CON_Draw_Backpic (con_bordleft,0,w);
1583 CON_Draw_Backpic (con_bordright,x2,w);
1584 }
1585 // translucent background
1586 //Hurdler: what's the correct value of w and x2 in hardware mode ???
1587 #if 0
1588 // Darken the borders too
1589 if( cv_darkback.value )
1590 V_FadeConsBack (0, vid.width, con_curlines);
1591 else
1592 V_FadeConsBack (w, x2, con_curlines);
1593 #else
1594 V_FadeConsBack (w, x2, con_curlines);
1595 #endif
1596 }
1597
1598 // draw console text lines from bottom to top
1599 // (going backward in console buffer text)
1600 //
1601 if (con_curlines <20) //8+8+4
1602 return;
1603
1604 i = con_cy - con_scrollup;
1605
1606 // skip the last empty line due to the cursor being at the start
1607 // of a new line
1608 if (!con_scrollup && !con_cx)
1609 i--;
1610
1611 // draw lines with font1 or wad font
1612 for (y=con_curlines - (drawfont.yinc * 2); y>=0; y-=drawfont.yinc)
1613 {
1614 if (i<0)
1615 i=0;
1616
1617 p = &con_buffer[(i%con_totallines)*con_width];
1618
1619 #ifdef CONSOLE_PROPORTIONAL
1620 x = con_indent; // indent
1621 int xj;
1622 for (xj=0; xj<con_width; xj++)
1623 {
1624 // red, proportional width font
1625 x += V_DrawCharacter ( x, y, p[xj] );
1626 // x += V_DrawCharacter ( x, y, (p[x]&0x7f) ); // force red
1627 }
1628 #else
1629 // red, fixed width font
1630 for (x=0;x<con_width;x++)
1631 V_DrawCharacter( x * drawfont.xinc + con_indent, y, p[x] );
1632 #endif
1633 i--;
1634 }
1635
1636
1637 // draw prompt if enough place (not while game startup)
1638 //
1639 if ((con_curlines==con_destlines) && (con_curlines>=20) && !con_self_refresh)
1640 CON_DrawInput ( con_curlines - drawfont.yinc );
1641 }
1642
1643
1644 // Console refresh drawer, call each frame
1645 //
CON_Drawer(void)1646 void CON_Drawer (void)
1647 {
1648 if (!con_started)
1649 return;
1650
1651 if (con_recalc)
1652 CON_RecalcSize ( vid.width );
1653
1654 if ( use_font1 )
1655 return; // hu_font not loaded yet
1656
1657 #ifndef CONSOLE_PROPORTIONAL
1658 //Fab: bighack: patch 'I' letter leftoffset so it centers
1659 hu_font['I'-HU_FONTSTART]->leftoffset = -2;
1660 #endif
1661
1662 if (con_curlines>0)
1663 CON_Draw_Console ();
1664 else
1665 if (gamestate==GS_LEVEL)
1666 CON_Draw_Hudlines ();
1667
1668 #ifndef CONSOLE_PROPORTIONAL
1669 hu_font['I'-HU_FONTSTART]->leftoffset = 0;
1670 #endif
1671 }
1672