2 * Code for controlling the console
3 * Based on an early version of SDL_Console
5 * Written By: Garrett Banuk <mongoose@mongeese.org>
6 * Code Cleanup and heavily extended by: Clemens Wacha <reflex-2000@gmx.net>
7 * Ported to use native Descent interfaces by: Bradley Bell <btb@icculus.org>
9 * This is free, just be sure to give us credit when using it
10 * in any of your programs.
40 int text_console_enabled = 1;
43 #define text_console_enabled (!isvga())
47 /* How discriminating we are about which messages are displayed */
48 cvar_t con_threshold = { "con_threshold", "0", CVAR_NONE };
50 #define CON_BG_HIRES (cfexist("scoresb.pcx")?"scoresb.pcx":"scores.pcx")
51 #define CON_BG_LORES (cfexist("scores.pcx")?"scores.pcx":"scoresb.pcx") // Mac datafiles only have scoresb.pcx
52 #define CON_BG ((SWIDTH>=640)?CON_BG_HIRES:CON_BG_LORES)
53 #define CON_FONT SMALL_FONT
54 #define CON_DEFAULT_COLOR gr_find_closest_color(29, 29, 47)
56 #define CON_NUM_LINES 128
57 // Cut the buffer line if it becomes longer than this
58 #define CON_CHARS_PER_LINE 128
59 // Border in pixels from the most left to the first letter
60 #define CON_CHAR_BORDER 4
61 // Spacing in pixels between lines
62 #define CON_LINE_SPACE 1
63 // Scroll this many lines at a time (when pressing PGUP or PGDOWN)
64 #define CON_LINE_SCROLL 2
65 // Indicator showing that you scrolled up the history
66 #define CON_SCROLL_INDICATOR "^"
67 // Defines the opening/closing speed
68 #define CON_OPENCLOSE_SPEED 50
71 /* The console's data */
72 static int Visible; // Enum that tells which visible state we are in CON_HIDE, CON_SHOW, CON_RAISE, CON_LOWER
73 static int RaiseOffset; // Offset used when scrolling in the console
74 static char **ConsoleLines; // List of all the past lines
75 static int TotalConsoleLines; // Total number of lines in the console
76 static int ConsoleScrollBack; // How much the user scrolled back in the console
77 static int LineBuffer; // The number of visible lines in the console (autocalculated)
78 static int VChars; // The number of visible characters in one console line (autocalculated)
79 static grs_canvas *ConsoleSurface; // Canvas of the console
80 static grs_bitmap *BackgroundImage; // Background image for the console
81 static grs_bitmap *InputBackground; // Dirty rectangle to draw over behind the users background
83 /* console is ready to be written to */
84 static int con_initialized;
86 /* text foreground color */
91 static void con_update_offset(void);
92 /* Frees all the memory loaded by the console */
93 static void con_free(void);
94 static int con_background(grs_bitmap *image);
95 /* Sets font info for the console */
96 static void con_font(grs_font *font);
97 /* makes newline (same as printf("\n") or CON_Out("\n") ) */
98 static void con_newline(void);
99 /* updates console after resize etc. */
100 static void con_update(void);
101 /* Called if you press Ctrl-L (deletes the History) */
102 static void con_clear(void);
105 /* Takes keys from the keyboard and inputs them to the console
106 * If the event was not handled (i.e. WM events or unknown ctrl-shift
107 * sequences) the function returns the event for further processing. */
108 int con_key_handler(int key)
110 unsigned char character = key_to_ascii(key);
112 if (!con_is_visible())
118 case KEY_SHIFTED + KEY_ESC:
121 case KEY_CTRLED + KEY_L:
125 case KEY_SHIFTED + KEY_HOME:
126 ConsoleScrollBack = LineBuffer-1;
129 case KEY_SHIFTED + KEY_END:
130 ConsoleScrollBack = 0;
134 ConsoleScrollBack += CON_LINE_SCROLL;
135 if(ConsoleScrollBack > LineBuffer-1)
136 ConsoleScrollBack = LineBuffer-1;
140 ConsoleScrollBack -= CON_LINE_SCROLL;
141 if(ConsoleScrollBack < 0)
142 ConsoleScrollBack = 0;
145 case KEY_CTRLED + KEY_A:
146 case KEY_HOME: cli_cursor_home(); break;
148 case KEY_CTRLED + KEY_E: cli_cursor_end(); break;
149 case KEY_CTRLED + KEY_C: cli_clear(); break;
150 case KEY_LEFT: cli_cursor_left(); break;
151 case KEY_RIGHT: cli_cursor_right(); break;
152 case KEY_BACKSP: cli_cursor_backspace(); break;
153 case KEY_CTRLED + KEY_D:
154 case KEY_DELETE: cli_cursor_del(); break;
155 case KEY_UP: cli_history_prev(); break;
156 case KEY_DOWN: cli_history_next(); break;
157 case KEY_TAB: cli_autocomplete(); break;
158 case KEY_ENTER: cli_execute(); break;
160 CLI_insert_mode = !CLI_insert_mode;
163 if (character == 255)
165 cli_add_character(character);
172 /* Updates the console buffer */
173 static void con_update(void)
178 grs_canvas *canv_save;
180 /* Due to the Blits, the update is not very fast: So only update if it's worth it */
181 if (!con_is_visible())
184 Screenlines = ConsoleSurface->cv_h / (CON_LINE_SPACE + ConsoleSurface->cv_font->ft_h);
186 canv_save = grd_curcanv;
187 gr_set_current_canvas(ConsoleSurface);
189 gr_set_fontcolor(CON_color, -1);
191 /* draw the background image if there is one */
193 gr_bitmap(0, 0, BackgroundImage);
195 // now draw text from last but second line to top
196 for (loop = 0; loop < Screenlines-1 && loop < LineBuffer - ConsoleScrollBack; loop++) {
197 if (ConsoleScrollBack != 0 && loop == 0)
198 for (loop2 = 0; loop2 < (VChars / 5) + 1; loop2++)
200 gr_string(CON_CHAR_BORDER + (loop2*5*ConsoleSurface->cv_font->ft_w), (Screenlines - loop - 2) * (CON_LINE_SPACE + ConsoleSurface->cv_font->ft_h), CON_SCROLL_INDICATOR);
204 gr_string(CON_CHAR_BORDER, (Screenlines - loop - 2) * (CON_LINE_SPACE + ConsoleSurface->cv_font->ft_h), ConsoleLines[ConsoleScrollBack + loop]);
208 gr_set_current_canvas(canv_save);
212 static void con_update_offset(void)
216 RaiseOffset -= CON_OPENCLOSE_SPEED;
217 if(RaiseOffset <= 0) {
219 Visible = CON_CLOSED;
223 RaiseOffset += CON_OPENCLOSE_SPEED;
224 if(RaiseOffset >= ConsoleSurface->cv_h) {
225 RaiseOffset = ConsoleSurface->cv_h;
236 /* Draws the console buffer to the screen if the console is "visible" */
239 grs_canvas *canv_save;
242 /* only draw if console is visible: here this means, that the console is not CON_CLOSED */
243 if (Visible == CON_CLOSED)
246 /* Update the scrolling offset */
249 canv_save = grd_curcanv;
251 /* Update the command line since it has a blinking cursor */
252 gr_set_current_canvas(ConsoleSurface);
254 // restore InputBackground
255 gr_bitmap(0, ConsoleSurface->cv_h - ConsoleSurface->cv_font->ft_h, InputBackground);
257 cli_draw(ConsoleSurface->cv_h);
259 gr_set_current_canvas(&grd_curscreen->sc_canvas);
261 clip = gr_create_sub_bitmap(&ConsoleSurface->cv_bitmap, 0, ConsoleSurface->cv_h - RaiseOffset, ConsoleSurface->cv_w, RaiseOffset);
263 gr_bitmap(0, 0, clip);
264 gr_free_sub_bitmap(clip);
266 gr_set_current_canvas(canv_save);
270 void con_cmd_toggleconsole(int argc, char **argv)
273 cmd_appendf("help %s", argv[0]);
277 if (con_is_visible())
284 /* Initializes the console */
289 Visible = CON_CLOSED;
292 TotalConsoleLines = 0;
293 ConsoleScrollBack = 0;
294 BackgroundImage = NULL;
296 /* load the console surface */
297 ConsoleSurface = NULL;
299 /* Load the dirty rectangle for user input */
300 InputBackground = NULL;
302 VChars = CON_CHARS_PER_LINE - 1;
303 LineBuffer = CON_NUM_LINES;
305 ConsoleLines = (char **)d_malloc(sizeof(char *) * LineBuffer);
306 for (loop = 0; loop <= LineBuffer - 1; loop++) {
307 ConsoleLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
314 cmd_addcommand("toggleconsole", con_cmd_toggleconsole, "toggleconsole\n" " show or hide the console");
315 cvar_registervariable (&con_threshold);
323 void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline);
324 void con_init_gfx(int w, int h)
330 if (ConsoleSurface) {
331 /* resize console surface */
332 gr_free_bitmap_data(&ConsoleSurface->cv_bitmap);
333 gr_init_bitmap_alloc(&ConsoleSurface->cv_bitmap, BM_LINEAR, 0, 0, w, h, w);
335 /* load the console surface */
336 ConsoleSurface = gr_create_canvas(w, h);
339 CON_color = CON_DEFAULT_COLOR;
341 /* Load the consoles font */
344 /* make sure that the size of the console is valid */
345 if (w > grd_curscreen->sc_w || w < ConsoleSurface->cv_font->ft_w * 32)
346 w = grd_curscreen->sc_w;
347 if (h > grd_curscreen->sc_h || h < ConsoleSurface->cv_font->ft_h)
348 h = grd_curscreen->sc_h;
350 /* Load the dirty rectangle for user input */
352 gr_free_bitmap(InputBackground);
353 InputBackground = gr_create_bitmap(w, ConsoleSurface->cv_font->ft_h);
355 /* calculate the number of visible characters in the command line */
356 #if 0 // doesn't work because proportional font
357 VChars = (w - CON_CHAR_BORDER) / ConsoleSurface->cv_font->ft_w;
358 if (VChars >= CON_CHARS_PER_LINE)
359 VChars = CON_CHARS_PER_LINE - 1;
362 gr_init_bitmap_data(&bmp);
363 pcx_error = pcx_read_bitmap(CON_BG, &bmp, BM_LINEAR, pal);
364 Assert(pcx_error == PCX_ERROR_NONE);
365 gr_remap_bitmap_good(&bmp, pal, -1, -1);
366 con_background(&bmp);
367 gr_free_bitmap_data(&bmp);
371 /* Makes the console visible */
374 Visible = CON_OPENING;
379 /* Hides the console (make it invisible) */
382 Visible = CON_CLOSING;
387 /* tells wether the console is visible or not */
388 int con_is_visible(void)
390 return((Visible == CON_OPEN) || (Visible == CON_OPENING));
394 /* Frees all the memory loaded by the console */
395 static void con_free(void)
399 for (i = 0; i <= LineBuffer - 1; i++) {
400 d_free(ConsoleLines[i]);
402 d_free(ConsoleLines);
407 gr_free_canvas(ConsoleSurface);
408 ConsoleSurface = NULL;
411 gr_free_bitmap(BackgroundImage);
412 BackgroundImage = NULL;
415 gr_free_bitmap(InputBackground);
416 InputBackground = NULL;
422 /* Increments the console lines */
423 static void con_newline(void)
428 temp = ConsoleLines[LineBuffer - 1];
430 for (loop = LineBuffer - 1; loop > 0; loop--)
431 ConsoleLines[loop] = ConsoleLines[loop - 1];
433 ConsoleLines[0] = temp;
435 memset(ConsoleLines[0], 0, CON_CHARS_PER_LINE);
436 if (TotalConsoleLines < LineBuffer - 1)
439 //Now adjust the ConsoleScrollBack
440 //dont scroll if not at bottom
441 if(ConsoleScrollBack != 0)
444 if(ConsoleScrollBack > LineBuffer-1)
445 ConsoleScrollBack = LineBuffer-1;
449 static inline int con_get_width(void)
454 return ConsoleSurface->cv_bitmap.bm_w - CON_CHAR_BORDER;
458 static inline int con_get_string_width(char *string)
460 grs_canvas *canv_save;
466 canv_save = grd_curcanv;
467 gr_set_current_canvas(ConsoleSurface);
468 gr_get_string_size(string, &w, &h, &aw);
469 gr_set_current_canvas(canv_save);
476 # define vsnprintf _vsnprintf
479 /* Outputs text to the console (in game), up to CON_CHARS_PER_LINE chars can be entered */
480 static void con_out(const char *str, ...)
483 //keep some space free for stuff like CON_Out("blablabla %s", Command);
484 char temp[CON_CHARS_PER_LINE + 128];
487 va_start(marker, str);
488 vsnprintf(temp, CON_CHARS_PER_LINE + 127, str, marker);
493 // temp now contains the complete string we want to output
494 // the only problem is that temp is maybe longer than the console
495 // width so we have to cut it into several pieces
504 strcat(ConsoleLines[0], ptemp);
506 } else if (p - ptemp > VChars - strlen(ConsoleLines[0]) ||
507 con_get_string_width(ptemp) > con_get_width()) {
509 strncat(ConsoleLines[0], ptemp, VChars - strlen(ConsoleLines[0]));
510 ConsoleLines[0][VChars] = '\0';
516 strncat(ConsoleLines[0], ptemp, VChars - strlen(ConsoleLines[0]));
517 ConsoleLines[0][VChars] = '\0';
524 /* Adds background image to the console, scaled to size of console*/
525 static int con_background(grs_bitmap *image)
527 /* Free the background from the console */
530 gr_free_bitmap(BackgroundImage);
531 BackgroundImage = NULL;
535 /* Load a new background */
537 gr_free_bitmap(BackgroundImage);
538 BackgroundImage = gr_create_bitmap(ConsoleSurface->cv_w, ConsoleSurface->cv_h);
539 gr_bitmap_scale_to(image, BackgroundImage);
541 gr_bm_bitblt(BackgroundImage->bm_w, InputBackground->bm_h, 0, 0, 0, ConsoleSurface->cv_h - ConsoleSurface->cv_font->ft_h, BackgroundImage, InputBackground);
547 /* Sets font info for the console */
548 static void con_font(grs_font *font)
550 grs_canvas *canv_save;
552 canv_save = grd_curcanv;
553 gr_set_current_canvas(ConsoleSurface);
554 gr_set_curfont(font);
555 gr_set_current_canvas(canv_save);
559 static void con_clear(void)
563 for (loop = 0; loop <= LineBuffer - 1; loop++)
564 memset(ConsoleLines[loop], 0, CON_CHARS_PER_LINE);
568 /* convert to ansi rgb colors 17-231 */
569 #define PAL2ANSI(x) ((36*gr_palette[(x)*3]/11) + (6*gr_palette[(x)*3+1]/11) + (gr_palette[(x)*3+2]/11) + 16)
571 /* Print a message to the console */
572 void con_printf(int priority, char *fmt, ...)
577 if (priority <= (con_threshold.intval))
579 va_start (arglist, fmt);
580 vsprintf (buffer, fmt, arglist);
586 if (!text_console_enabled)
589 if (isatty(fileno(stdout))) {
591 unsigned char color, spacing, underline;
601 printf("\x1B[38;5;%dm", PAL2ANSI(color));
608 //printf("<SPACING %d>", color);
615 //printf("<UNDERLINE>");
626 /* Produce a sanitised version and send it to the standard output */
645 printf("%s", buffer);