2 * Code for controlling the console
3 * Based on an old 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.
42 int text_console_enabled = 1;
45 #define text_console_enabled (!isvga())
49 /* Console specific cvars */
50 /* How discriminating we are about which messages are displayed */
51 cvar_t con_threshold = {"con_threshold", "0",};
53 /* Private console stuff */
54 #define CON_NUM_LINES 128
56 #define FG_COLOR grd_curcanv->cv_font_fg_color
57 #define get_msecs() approx_fsec_to_msec(timer_get_approx_seconds())
59 #define CON_BG_HIRES (cfexist("scoresb.pcx")?"scoresb.pcx":"scores.pcx")
60 #define CON_BG_LORES (cfexist("scores.pcx")?"scores.pcx":"scoresb.pcx") // Mac datafiles only have scoresb.pcx
61 #define CON_BG ((SWIDTH>=640)?CON_BG_HIRES:CON_BG_LORES)
63 //! Cut the buffer line if it becomes longer than this
64 #define CON_CHARS_PER_LINE 128
65 //! Cursor blink frequency in ms
66 #define CON_BLINK_RATE 500
67 //! Border in pixels from the most left to the first letter
68 #define CON_CHAR_BORDER 4
69 //! Spacing in pixels between lines
70 #define CON_LINE_SPACE 1
71 //! Default prompt used at the commandline
72 #define CON_DEFAULT_PROMPT "]"
73 //! Scroll this many lines at a time (when pressing PGUP or PGDOWN)
74 #define CON_LINE_SCROLL 2
75 //! Indicator showing that you scrolled up the history
76 #define CON_SCROLL_INDICATOR "^"
77 //! Cursor shown if we are in insert mode
78 #define CON_INS_CURSOR "_"
79 //! Cursor shown if we are in overwrite mode
80 #define CON_OVR_CURSOR "|"
81 //! Defines the default hide key (Hide() the console if pressed)
82 #define CON_DEFAULT_HIDEKEY KEY_ESC
83 //! Defines the opening/closing speed
84 #define CON_OPENCLOSE_SPEED 50
87 /*! This is a struct for the console's data */
88 typedef struct console_information_td {
89 int Visible; //! enum that tells which visible state we are in CON_HIDE, CON_SHOW, CON_RAISE, CON_LOWER
90 int RaiseOffset; //! Offset used when scrolling in the console
91 int HideKey; //! the key that can hide the console
92 char **ConsoleLines; //! List of all the past lines
93 char **CommandLines; //! List of all the past commands
94 int TotalConsoleLines; //! Total number of lines in the console
95 int ConsoleScrollBack; //! How much the user scrolled back in the console
96 int TotalCommands; //! Number of commands in the Back Commands
97 int LineBuffer; //! The number of visible lines in the console (autocalculated)
98 int VChars; //! The number of visible characters in one console line (autocalculated)
99 char* Prompt; //! Prompt displayed in command line
100 char Command[CON_CHARS_PER_LINE]; //! current command in command line = lcommand + rcommand
101 char RCommand[CON_CHARS_PER_LINE]; //! left hand side of cursor
102 char LCommand[CON_CHARS_PER_LINE]; //! right hand side of cursor
103 char VCommand[CON_CHARS_PER_LINE]; //! current visible command line
104 int CursorPos; //! Current cursor position in CurrentCommand
105 int Offset; //! CommandOffset (first visible char of command) - if command is too long to fit into console
106 int InsMode; //! Insert or Overwrite characters?
107 grs_canvas *ConsoleSurface; //! Canvas of the console
108 grs_bitmap *BackgroundImage; //! Background image for the console
109 grs_bitmap *InputBackground; //! Dirty rectangle to draw over behind the users background
111 unsigned char ConsoleAlpha; //! The consoles alpha level
113 int CommandScrollBack; //! How much the users scrolled back in the command lines
116 static ConsoleInformation Console;
117 #define console (&Console)
119 /* console is ready to be written to */
120 static int con_initialized;
124 void CON_UpdateOffset(void);
125 /*! Frees all the memory loaded by the console */
128 /*! Sets the alpha channel of an SDL_Surface to the specified value (0 - transparend,
129 255 - opaque). Use this function also for OpenGL. */
130 void CON_Alpha(unsigned char alpha);
131 /*! Internal: Sets the alpha channel of an SDL_Surface to the specified value.
132 Preconditions: the surface in question is RGBA. 0 <= a <= 255, where 0 is transparent and 255 opaque */
133 void CON_AlphaGL(SDL_Surface *s, int alpha);
134 /*! Sets a background image for the console */
136 int CON_Background(grs_bitmap *image);
137 /*! Sets font info for the console */
138 void CON_Font(grs_font *font, int fg, int bg);
139 /*! Modify the prompt of the console */
140 void CON_SetPrompt(char* newprompt);
141 /*! Set the key, that invokes a CON_Hide() after press. default is ESCAPE and you can always hide using
142 ESCAPE and the HideKey. compared against event->key.keysym.sym !! */
143 void CON_SetHideKey(int key);
144 /*! Internal: executes the command typed in at the console (called if you press ENTER)*/
145 void CON_Execute(char* command);
146 /*! Internal: Gets called when TAB was pressed */
147 void CON_TabCompletion(void);
148 /*! Internal: makes newline (same as printf("\n") or CON_Out("\n") ) */
149 void CON_NewLineConsole(void);
150 /*! Internal: shift command history (the one you can switch with the up/down keys) */
151 void CON_NewLineCommand(void);
152 /*! Internal: updates console after resize etc. */
153 void CON_UpdateConsole(void);
156 /*! Internal: draws the commandline the user is typing in to the screen. called by update? */
157 void DrawCommandLine();
159 /*! Internal: Gets called if you press the LEFT key (move cursor left) */
160 void Cursor_Left(void);
161 /*! Internal: Gets called if you press the RIGHT key (move cursor right) */
162 void Cursor_Right(void);
163 /*! Internal: Gets called if you press the HOME key (move cursor to the beginning
165 void Cursor_Home(void);
166 /*! Internal: Gets called if you press the END key (move cursor to the end of the line*/
167 void Cursor_End(void);
168 /*! Internal: Called if you press DELETE (deletes character under the cursor) */
169 void Cursor_Del(void);
170 /*! Internal: Called if you press BACKSPACE (deletes character left of cursor) */
171 void Cursor_BSpace(void);
172 /*! Internal: Called if you type in a character (add the char to the command) */
173 void Cursor_Add(int event);
175 /*! Internal: Called if you press Ctrl-C (deletes the commandline) */
176 void Clear_Command(void);
177 /*! Internal: Called if you press Ctrl-L (deletes the History) */
178 void Clear_History(void);
180 /*! Internal: Called if you press UP key (switches through recent typed in commands */
181 void Command_Up(void);
182 /*! Internal: Called if you press DOWN key (switches through recent typed in commands */
183 void Command_Down(void);
186 /* Takes keys from the keyboard and inputs them to the console
187 If the event was not handled (i.e. WM events or unknown ctrl-shift
188 sequences) the function returns the event for further processing. */
189 int CON_Events(int event)
194 if(event & KEY_CTRLED)
197 switch(event & ~KEY_CTRLED)
216 else if(event & KEY_ALTED)
218 //the console does not handle ALT combinations!
223 //first of all, check if the console hide key was pressed
224 if(event == console->HideKey)
229 switch (event & 0xff)
235 if(event & KEY_SHIFTED)
237 console->ConsoleScrollBack = console->LineBuffer-1;
244 if(event & KEY_SHIFTED)
246 console->ConsoleScrollBack = 0;
253 console->ConsoleScrollBack += CON_LINE_SCROLL;
254 if(console->ConsoleScrollBack > console->LineBuffer-1)
255 console->ConsoleScrollBack = console->LineBuffer-1;
260 console->ConsoleScrollBack -= CON_LINE_SCROLL;
261 if(console->ConsoleScrollBack < 0)
262 console->ConsoleScrollBack = 0;
284 console->InsMode = 1-console->InsMode;
290 if(strlen(console->Command) > 0) {
291 CON_NewLineCommand();
293 // copy the input into the past commands strings
294 strcpy(console->CommandLines[0], console->Command);
296 // display the command including the prompt
297 CON_Out("%s%s\n", console->Prompt, console->Command);
300 CON_Execute(console->Command);
303 console->CommandScrollBack = -1;
311 if (key_to_ascii(event) == 255)
325 /* CON_AlphaGL() -- sets the alpha channel of an SDL_Surface to the
326 * specified value. Preconditions: the surface in question is RGBA.
327 * 0 <= a <= 255, where 0 is transparent and 255 is opaque. */
328 void CON_AlphaGL(SDL_Surface *s, int alpha) {
333 SDL_PixelFormat *format;
334 static char errorPrinted = 0;
337 /* debugging assertions -- these slow you down, but hey, crashing sucks */
339 PRINT_ERROR("NULL Surface passed to CON_AlphaGL\n");
343 /* clamp alpha value to 0...255 */
344 if(alpha < SDL_ALPHA_TRANSPARENT)
345 val = SDL_ALPHA_TRANSPARENT;
346 else if(alpha > SDL_ALPHA_OPAQUE)
347 val = SDL_ALPHA_OPAQUE;
351 /* loop over alpha channels of each pixel, setting them appropriately. */
355 switch (format->BytesPerPixel) {
357 /* 16-bit surfaces don't seem to support alpha channels. */
360 PRINT_ERROR("16-bit SDL surfaces do not support alpha-blending under OpenGL.\n");
364 /* we can do this very quickly in 32-bit mode. 24-bit is more
365 * difficult. And since 24-bit mode is reall the same as 32-bit,
366 * so it usually ends up taking this route too. Win! Unroll loop
367 * and use pointer arithmetic for extra speed. */
368 int numpixels = h * (w << 2);
369 Uint8 *pix = (Uint8 *) (s->pixels);
370 Uint8 *last = pix + numpixels;
372 if((numpixels & 0x7) == 0)
373 for(pixel = pix + 3; pixel < last; pixel += 32)
374 *pixel = *(pixel + 4) = *(pixel + 8) = *(pixel + 12) = *(pixel + 16) = *(pixel + 20) = *(pixel + 24) = *(pixel + 28) = val;
376 for(pixel = pix + 3; pixel < last; pixel += 4)
381 /* we have no choice but to do this slowly. <sigh> */
382 for(y = 0; y < h; ++y)
383 for(x = 0; x < w; ++x) {
385 /* Lock the surface for direct access to the pixels */
386 if(SDL_MUSTLOCK(s) && SDL_LockSurface(s) < 0) {
387 PRINT_ERROR("Can't lock surface: ");
388 fprintf(stderr, "%s\n", SDL_GetError());
391 pixel = DT_GetPixel(s, x, y);
394 SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
395 pixel = SDL_MapRGBA(format, r, g, b, val);
396 SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
397 DT_PutPixel(s, x, y, pixel);
399 /* unlock surface again */
401 SDL_UnlockSurface(s);
409 /* Updates the console buffer */
410 void CON_UpdateConsole(void) {
414 grs_canvas *canv_save;
417 /* Due to the Blits, the update is not very fast: So only update if it's worth it */
421 Screenlines = console->ConsoleSurface->cv_h / (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h);
423 canv_save = grd_curcanv;
424 gr_set_current_canvas(console->ConsoleSurface);
427 SDL_FillRect(console->ConsoleSurface, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, console->ConsoleAlpha));
433 if(grd_curscreen->flags & SDL_OPENGLBLIT)
434 SDL_SetAlpha(console->ConsoleSurface, 0, SDL_ALPHA_OPAQUE);
437 /* draw the background image if there is one */
438 if(console->BackgroundImage)
439 gr_bitmap(0, 0, console->BackgroundImage);
441 /* Draw the text from the back buffers, calculate in the scrollback from the user
442 * this is a normal SDL software-mode blit, so we need to temporarily set the ColorKey
443 * for the font, and then clear it when we're done.
446 if((grd_curscreen->flags & SDL_OPENGLBLIT) && (grd_curscreen->format->BytesPerPixel > 2)) {
447 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
448 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
452 //now draw text from last but second line to top
453 for(loop = 0; loop < Screenlines-1 && loop < console->LineBuffer - console->ConsoleScrollBack; loop++) {
454 if(console->ConsoleScrollBack != 0 && loop == 0)
455 for(loop2 = 0; loop2 < (console->VChars / 5) + 1; loop2++)
457 orig_color = FG_COLOR;
458 gr_string(CON_CHAR_BORDER + (loop2*5*console->ConsoleSurface->cv_font->ft_w), (Screenlines - loop - 2) * (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h), CON_SCROLL_INDICATOR);
459 FG_COLOR = orig_color;
463 orig_color = FG_COLOR;
464 gr_string(CON_CHAR_BORDER, (Screenlines - loop - 2) * (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h), console->ConsoleLines[console->ConsoleScrollBack + loop]);
465 FG_COLOR = orig_color;
469 gr_set_current_canvas(canv_save);
472 if(grd_curscreen->flags & SDL_OPENGLBLIT)
473 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
477 void CON_UpdateOffset(void) {
478 switch(console->Visible) {
480 console->RaiseOffset -= CON_OPENCLOSE_SPEED;
481 if(console->RaiseOffset <= 0) {
482 console->RaiseOffset = 0;
483 console->Visible = CON_CLOSED;
487 console->RaiseOffset += CON_OPENCLOSE_SPEED;
488 if(console->RaiseOffset >= console->ConsoleSurface->cv_h) {
489 console->RaiseOffset = console->ConsoleSurface->cv_h;
490 console->Visible = CON_OPEN;
499 /* Draws the console buffer to the screen if the console is "visible" */
500 void CON_DrawConsole(void) {
501 grs_canvas *canv_save;
504 /* only draw if console is visible: here this means, that the console is not CON_CLOSED */
505 if(console->Visible == CON_CLOSED)
508 /* Update the scrolling offset */
511 /* Update the command line since it has a blinking cursor */
515 /* before drawing, make sure the alpha channel of the console surface is set
516 * properly. (sigh) I wish we didn't have to do this every frame... */
517 if(grd_curscreen->flags & SDL_OPENGLBLIT)
518 CON_AlphaGL(console->ConsoleSurface, console->ConsoleAlpha);
521 canv_save = grd_curcanv;
522 gr_set_current_canvas(&grd_curscreen->sc_canvas);
524 clip = gr_create_sub_bitmap(&console->ConsoleSurface->cv_bitmap, 0, console->ConsoleSurface->cv_h - console->RaiseOffset, console->ConsoleSurface->cv_w, console->RaiseOffset);
526 gr_bitmap(0, 0, clip);
527 gr_free_sub_bitmap(clip);
530 if(grd_curscreen->flags & SDL_OPENGLBLIT)
531 SDL_UpdateRects(grd_curscreen, 1, &DestRect);
534 gr_set_current_canvas(canv_save);
538 /* Initializes the console */
543 console->Visible = CON_CLOSED;
544 console->RaiseOffset = 0;
545 console->ConsoleLines = NULL;
546 console->CommandLines = NULL;
547 console->TotalConsoleLines = 0;
548 console->ConsoleScrollBack = 0;
549 console->TotalCommands = 0;
550 console->BackgroundImage = NULL;
552 console->ConsoleAlpha = SDL_ALPHA_OPAQUE;
555 console->InsMode = 1;
556 console->CursorPos = 0;
557 console->CommandScrollBack = 0;
558 console->Prompt = d_strdup(CON_DEFAULT_PROMPT);
559 console->HideKey = CON_DEFAULT_HIDEKEY;
561 /* load the console surface */
562 console->ConsoleSurface = NULL;
564 /* Load the dirty rectangle for user input */
565 console->InputBackground = NULL;
567 console->VChars = CON_CHARS_PER_LINE - 1;
568 console->LineBuffer = CON_NUM_LINES;
570 console->ConsoleLines = (char **)d_malloc(sizeof(char *) * console->LineBuffer);
571 console->CommandLines = (char **)d_malloc(sizeof(char *) * console->LineBuffer);
572 for(loop = 0; loop <= console->LineBuffer - 1; loop++) {
573 console->ConsoleLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
574 console->CommandLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
576 memset(console->Command, 0, CON_CHARS_PER_LINE);
577 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
578 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
579 memset(console->VCommand, 0, CON_CHARS_PER_LINE);
583 /* Initialise the cvars */
584 cvar_registervariable (&con_threshold);
592 void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline);
593 void CON_InitGFX(int w, int h)
599 if (console->ConsoleSurface) {
600 /* resize console surface */
601 gr_free_bitmap_data(&console->ConsoleSurface->cv_bitmap);
602 gr_init_bitmap_alloc(&console->ConsoleSurface->cv_bitmap, BM_LINEAR, 0, 0, w, h, w);
604 /* load the console surface */
605 console->ConsoleSurface = gr_create_canvas(w, h);
608 /* Load the consoles font */
609 CON_Font(SMALL_FONT, gr_find_closest_color(29,29,47), -1);
611 /* make sure that the size of the console is valid */
612 if(w > grd_curscreen->sc_w || w < console->ConsoleSurface->cv_font->ft_w * 32)
613 w = grd_curscreen->sc_w;
614 if(h > grd_curscreen->sc_h || h < console->ConsoleSurface->cv_font->ft_h)
615 h = grd_curscreen->sc_h;
617 /* Load the dirty rectangle for user input */
618 if (console->InputBackground)
619 gr_free_bitmap(console->InputBackground);
620 console->InputBackground = gr_create_bitmap(w, console->ConsoleSurface->cv_font->ft_h);
622 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
625 /* calculate the number of visible characters in the command line */
626 #if 0 // doesn't work because proportional font
627 console->VChars = (w - CON_CHAR_BORDER) / console->ConsoleSurface->cv_font->ft_w;
628 if(console->VChars >= CON_CHARS_PER_LINE)
629 console->VChars = CON_CHARS_PER_LINE - 1;
632 gr_init_bitmap_data(&bmp);
633 pcx_error = pcx_read_bitmap(CON_BG, &bmp, BM_LINEAR, pal);
634 Assert(pcx_error == PCX_ERROR_NONE);
635 gr_remap_bitmap_good(&bmp, pal, -1, -1);
636 CON_Background(&bmp);
637 gr_free_bitmap_data(&bmp);
641 /* Makes the console visible */
642 void CON_Show(void) {
643 console->Visible = CON_OPENING;
647 /* Hides the console (make it invisible) */
648 void CON_Hide(void) {
649 console->Visible = CON_CLOSING;
653 /* tells wether the console is visible or not */
654 int CON_isVisible(void) {
655 return((console->Visible == CON_OPEN) || (console->Visible == CON_OPENING));
658 /* Frees all the memory loaded by the console */
659 void CON_Free(void) {
662 for(i = 0; i <= console->LineBuffer - 1; i++) {
663 d_free(console->ConsoleLines[i]);
664 d_free(console->CommandLines[i]);
666 d_free(console->ConsoleLines);
667 d_free(console->CommandLines);
669 console->ConsoleLines = NULL;
670 console->CommandLines = NULL;
672 if (console->ConsoleSurface)
673 gr_free_canvas(console->ConsoleSurface);
674 console->ConsoleSurface = NULL;
676 if (console->BackgroundImage)
677 gr_free_bitmap(console->BackgroundImage);
678 console->BackgroundImage = NULL;
680 if (console->InputBackground)
681 gr_free_bitmap(console->InputBackground);
682 console->InputBackground = NULL;
684 d_free(console->Prompt);
690 /* Increments the console lines */
691 void CON_NewLineConsole(void) {
695 temp = console->ConsoleLines[console->LineBuffer - 1];
697 for(loop = console->LineBuffer - 1; loop > 0; loop--)
698 console->ConsoleLines[loop] = console->ConsoleLines[loop - 1];
700 console->ConsoleLines[0] = temp;
702 memset(console->ConsoleLines[0], 0, CON_CHARS_PER_LINE);
703 if(console->TotalConsoleLines < console->LineBuffer - 1)
704 console->TotalConsoleLines++;
706 //Now adjust the ConsoleScrollBack
707 //dont scroll if not at bottom
708 if(console->ConsoleScrollBack != 0)
709 console->ConsoleScrollBack++;
711 if(console->ConsoleScrollBack > console->LineBuffer-1)
712 console->ConsoleScrollBack = console->LineBuffer-1;
717 /* Increments the command lines */
718 void CON_NewLineCommand(void) {
722 temp = console->CommandLines[console->LineBuffer - 1];
725 for(loop = console->LineBuffer - 1; loop > 0; loop--)
726 console->CommandLines[loop] = console->CommandLines[loop - 1];
728 console->CommandLines[0] = temp;
730 memset(console->CommandLines[0], 0, CON_CHARS_PER_LINE);
731 if(console->TotalCommands < console->LineBuffer - 1)
732 console->TotalCommands++;
735 /* Draws the command line the user is typing in to the screen */
736 /* completely rewritten by C.Wacha */
737 void DrawCommandLine() {
741 grs_font* CurrentFont;
743 static unsigned int LastBlinkTime = 0; /* Last time the consoles cursor blinked */
744 static int LastCursorPos = 0; // Last Cursor Position
745 static int Blink = 0; /* Is the cursor currently blinking */
746 grs_canvas *canv_save;
749 commandbuffer = console->VChars - (int)strlen(console->Prompt) - 1; // -1 to make cursor visible
752 CurrentFont = console->ConsoleSurface->cv_font;
755 //Concatenate the left and right side to command
756 strcpy(console->Command, console->LCommand);
757 strncat(console->Command, console->RCommand, strlen(console->RCommand));
759 //calculate display offset from current cursor position
760 if(console->Offset < console->CursorPos - commandbuffer)
761 console->Offset = console->CursorPos - commandbuffer;
762 if(console->Offset > console->CursorPos)
763 console->Offset = console->CursorPos;
765 //first add prompt to visible part
766 strcpy(console->VCommand, console->Prompt);
768 //then add the visible part of the command
769 strncat(console->VCommand, &console->Command[console->Offset], strlen(&console->Command[console->Offset]));
771 //now display the result
774 //once again we're drawing text, so in OpenGL context we need to temporarily set up
775 //software-mode transparency.
776 if(grd_curscreen->flags & SDL_OPENGLBLIT) {
777 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
778 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
782 canv_save = grd_curcanv;
783 gr_set_current_canvas(console->ConsoleSurface);
785 //first of all restore InputBackground
786 gr_bitmap(0, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->InputBackground);
789 orig_color = FG_COLOR;
790 gr_string(CON_CHAR_BORDER, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->VCommand);
791 FG_COLOR = orig_color;
793 //at last add the cursor
794 //check if the blink period is over
795 if(get_msecs() > LastBlinkTime) {
796 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
803 //check if cursor has moved - if yes display cursor anyway
804 if(console->CursorPos != LastCursorPos) {
805 LastCursorPos = console->CursorPos;
806 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
811 int prompt_width, cmd_width, h, w;
813 gr_get_string_size(console->Prompt, &prompt_width, &h, &w);
814 gr_get_string_size(console->LCommand + console->Offset, &cmd_width, &h, &w);
815 x = CON_CHAR_BORDER + prompt_width + cmd_width;
816 orig_color = FG_COLOR;
818 gr_string(x, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, CON_INS_CURSOR);
820 gr_string(x, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, CON_OVR_CURSOR);
821 FG_COLOR = orig_color;
824 gr_set_current_canvas(canv_save);
828 if(grd_curscreen->flags & SDL_OPENGLBLIT) {
829 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
835 static inline int con_get_width(void)
837 if (!console->ConsoleSurface)
840 return console->ConsoleSurface->cv_bitmap.bm_w - CON_CHAR_BORDER;
844 static inline int con_get_string_width(char *string)
846 grs_canvas *canv_save;
849 if (!console->ConsoleSurface)
852 canv_save = grd_curcanv;
853 gr_set_current_canvas(console->ConsoleSurface);
854 gr_get_string_size(string, &w, &h, &aw);
855 gr_set_current_canvas(canv_save);
862 # define vsnprintf _vsnprintf
865 /* Outputs text to the console (in game), up to CON_CHARS_PER_LINE chars can be entered */
866 void CON_Out(const char *str, ...) {
868 //keep some space free for stuff like CON_Out("blablabla %s", console->Command);
869 char temp[CON_CHARS_PER_LINE + 128];
872 va_start(marker, str);
873 vsnprintf(temp, CON_CHARS_PER_LINE + 127, str, marker);
878 //temp now contains the complete string we want to output
879 // the only problem is that temp is maybe longer than the console
880 // width so we have to cut it into several pieces
882 if(console->ConsoleLines) {
888 CON_NewLineConsole();
889 strcat(console->ConsoleLines[0], ptemp);
891 } else if (p - ptemp > console->VChars - strlen(console->ConsoleLines[0]) ||
892 con_get_string_width(ptemp) > con_get_width()) {
893 CON_NewLineConsole();
894 strncat(console->ConsoleLines[0], ptemp, console->VChars - strlen(console->ConsoleLines[0]));
895 console->ConsoleLines[0][console->VChars] = '\0';
901 strncat(console->ConsoleLines[0], ptemp, console->VChars - strlen(console->ConsoleLines[0]));
902 console->ConsoleLines[0][console->VChars] = '\0';
910 /* Sets the alpha level of the console, 0 turns off alpha blending */
911 void CON_Alpha(unsigned char alpha) {
912 /* store alpha as state! */
913 console->ConsoleAlpha = alpha;
915 if((grd_curscreen->flags & SDL_OPENGLBLIT) == 0) {
917 SDL_SetAlpha(console->ConsoleSurface, 0, alpha);
919 SDL_SetAlpha(console->ConsoleSurface, SDL_SRCALPHA, alpha);
922 // CON_UpdateConsole();
927 /* Adds background image to the console, scaled to size of console*/
928 int CON_Background(grs_bitmap *image)
930 /* Free the background from the console */
932 if (console->BackgroundImage)
933 gr_free_bitmap(console->BackgroundImage);
934 console->BackgroundImage = NULL;
936 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
941 /* Load a new background */
942 if (console->BackgroundImage)
943 gr_free_bitmap(console->BackgroundImage);
944 console->BackgroundImage = gr_create_bitmap(console->ConsoleSurface->cv_w, console->ConsoleSurface->cv_h);
945 gr_bitmap_scale_to(image, console->BackgroundImage);
948 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
950 gr_bm_bitblt(console->BackgroundImage->bm_w, console->InputBackground->bm_h, 0, 0, 0, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->BackgroundImage, console->InputBackground);
955 /* Sets font info for the console */
956 void CON_Font(grs_font *font, int fg, int bg)
958 grs_canvas *canv_save;
960 canv_save = grd_curcanv;
961 gr_set_current_canvas(console->ConsoleSurface);
962 gr_set_curfont(font);
963 gr_set_fontcolor(fg, bg);
964 gr_set_current_canvas(canv_save);
968 /* resizes the console, has to reset alot of stuff
969 * returns 1 on error */
970 void CON_Resize(int w, int h)
972 /* make sure that the size of the console is valid */
973 if(w > grd_curscreen->sc_w || w < console->ConsoleSurface->cv_font->ft_w * 32)
974 w = grd_curscreen->sc_w;
975 if(h > grd_curscreen->sc_h || h < console->ConsoleSurface->cv_font->ft_h)
976 h = grd_curscreen->sc_h;
978 /* resize console surface */
979 gr_free_bitmap_data(&console->ConsoleSurface->cv_bitmap);
980 gr_init_bitmap_alloc(&console->ConsoleSurface->cv_bitmap, BM_LINEAR, 0, 0, w, h, w);
982 /* Load the dirty rectangle for user input */
983 gr_free_bitmap(console->InputBackground);
984 console->InputBackground = gr_create_bitmap(w, console->ConsoleSurface->cv_font->ft_h);
986 /* Now reset some stuff dependent on the previous size */
987 console->ConsoleScrollBack = 0;
989 /* Reload the background image (for the input text area) in the console */
990 if(console->BackgroundImage) {
992 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
994 gr_bm_bitblt(console->BackgroundImage->bm_w, console->InputBackground->bm_h, 0, 0, 0, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->BackgroundImage, console->InputBackground);
998 /* restore the alpha level */
999 CON_Alpha(console->ConsoleAlpha);
1003 /* Sets the Prompt for console */
1004 void CON_SetPrompt(char* newprompt) {
1005 //check length so we can still see at least 1 char :-)
1006 if(strlen(newprompt) < console->VChars) {
1007 d_free(console->Prompt);
1008 console->Prompt = d_strdup(newprompt);
1010 CON_Out("prompt too long. (max. %i chars)\n", console->VChars - 1);
1013 /* Sets the key that deactivates (hides) the console. */
1014 void CON_SetHideKey(int key) {
1015 console->HideKey = key;
1018 /* Executes the command entered */
1019 void CON_Execute(char* command) {
1020 cmd_append(command);
1023 void CON_TabCompletion(void) {
1027 command = cmd_complete(console->LCommand);
1030 return; //no tab completion took place so return silently
1032 j = (int)strlen(command);
1033 if(j > CON_CHARS_PER_LINE - 2)
1034 j = CON_CHARS_PER_LINE-1;
1036 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1037 console->CursorPos = 0;
1039 for(i = 0; i < j; i++) {
1040 console->CursorPos++;
1041 console->LCommand[i] = command[i];
1043 //add a trailing space
1044 console->CursorPos++;
1045 console->LCommand[j] = ' ';
1046 console->LCommand[j+1] = '\0';
1049 void Cursor_Left(void) {
1050 char temp[CON_CHARS_PER_LINE];
1052 if(console->CursorPos > 0) {
1053 console->CursorPos--;
1054 strcpy(temp, console->RCommand);
1055 strcpy(console->RCommand, &console->LCommand[strlen(console->LCommand)-1]);
1056 strcat(console->RCommand, temp);
1057 console->LCommand[strlen(console->LCommand)-1] = '\0';
1058 //CON_Out("L:%s, R:%s\n", console->LCommand, console->RCommand);
1062 void Cursor_Right(void) {
1063 char temp[CON_CHARS_PER_LINE];
1065 if(console->CursorPos < strlen(console->Command)) {
1066 console->CursorPos++;
1067 strncat(console->LCommand, console->RCommand, 1);
1068 strcpy(temp, console->RCommand);
1069 strcpy(console->RCommand, &temp[1]);
1070 //CON_Out("L:%s, R:%s\n", console->LCommand, console->RCommand);
1074 void Cursor_Home(void) {
1075 char temp[CON_CHARS_PER_LINE];
1077 console->CursorPos = 0;
1078 strcpy(temp, console->RCommand);
1079 strcpy(console->RCommand, console->LCommand);
1080 strncat(console->RCommand, temp, strlen(temp));
1081 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1084 void Cursor_End(void) {
1085 console->CursorPos = (int)strlen(console->Command);
1086 strncat(console->LCommand, console->RCommand, strlen(console->RCommand));
1087 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1090 void Cursor_Del(void) {
1091 char temp[CON_CHARS_PER_LINE];
1093 if(strlen(console->RCommand) > 0) {
1094 strcpy(temp, console->RCommand);
1095 strcpy(console->RCommand, &temp[1]);
1099 void Cursor_BSpace(void) {
1100 if(console->CursorPos > 0) {
1101 console->CursorPos--;
1103 if(console->Offset < 0)
1104 console->Offset = 0;
1105 console->LCommand[strlen(console->LCommand)-1] = '\0';
1109 void Cursor_Add(int event)
1111 if(strlen(console->Command) < CON_CHARS_PER_LINE - 1)
1113 console->CursorPos++;
1114 console->LCommand[strlen(console->LCommand)] = key_to_ascii(event);
1115 console->LCommand[strlen(console->LCommand)] = '\0';
1119 void Clear_Command(void) {
1120 console->CursorPos = 0;
1121 memset(console->VCommand, 0, CON_CHARS_PER_LINE);
1122 memset(console->Command, 0, CON_CHARS_PER_LINE);
1123 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1124 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1127 void Clear_History(void) {
1130 for(loop = 0; loop <= console->LineBuffer - 1; loop++)
1131 memset(console->ConsoleLines[loop], 0, CON_CHARS_PER_LINE);
1134 void Command_Up(void) {
1135 if(console->CommandScrollBack < console->TotalCommands - 1) {
1136 /* move back a line in the command strings and copy the command to the current input string */
1137 console->CommandScrollBack++;
1138 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1139 console->Offset = 0;
1140 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1141 console->CursorPos = (int)strlen(console->CommandLines[console->CommandScrollBack]);
1142 CON_UpdateConsole();
1146 void Command_Down(void) {
1147 if(console->CommandScrollBack > -1) {
1148 /* move forward a line in the command strings and copy the command to the current input string */
1149 console->CommandScrollBack--;
1150 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1151 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1152 console->Offset = 0;
1153 if(console->CommandScrollBack > -1)
1154 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1155 console->CursorPos = (int)strlen(console->LCommand);
1156 CON_UpdateConsole();
1160 /* convert to ansi rgb colors 17-231 */
1161 #define PAL2ANSI(x) ((36*gr_palette[(x)*3]/11) + (6*gr_palette[(x)*3+1]/11) + (gr_palette[(x)*3+2]/11) + 16)
1163 /* Print a message to the console */
1164 void con_printf(int priority, char *fmt, ...)
1169 if (priority <= (con_threshold.intval))
1171 va_start (arglist, fmt);
1172 vsprintf (buffer, fmt, arglist);
1175 if (con_initialized)
1178 if (!text_console_enabled)
1181 if (isatty(fileno(stdout))) {
1183 unsigned char color, spacing, underline;
1193 printf("\x1B[38;5;%dm", PAL2ANSI(color));
1200 //printf("<SPACING %d>", color);
1207 //printf("<UNDERLINE>");
1218 /* Produce a sanitised version and send it to the standard output */
1237 printf("%s", buffer);