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.
41 int text_console_enabled = 1;
44 #define text_console_enabled (!isvga())
48 /* Console specific cvars */
49 /* How discriminating we are about which messages are displayed */
50 cvar_t con_threshold = {"con_threshold", "0",};
52 /* Private console stuff */
53 #define CON_NUM_LINES 40
55 #define FG_COLOR grd_curcanv->cv_font_fg_color
56 #define get_msecs() approx_fsec_to_msec(timer_get_approx_seconds())
58 #define CON_BG_HIRES (cfexist("scoresb.pcx")?"scoresb.pcx":"scores.pcx")
59 #define CON_BG_LORES (cfexist("scores.pcx")?"scores.pcx":"scoresb.pcx") // Mac datafiles only have scoresb.pcx
60 #define CON_BG ((SWIDTH>=640)?CON_BG_HIRES:CON_BG_LORES)
62 //! Cut the buffer line if it becomes longer than this
63 #define CON_CHARS_PER_LINE 128
64 //! Cursor blink frequency in ms
65 #define CON_BLINK_RATE 500
66 //! Border in pixels from the most left to the first letter
67 #define CON_CHAR_BORDER 4
68 //! Spacing in pixels between lines
69 #define CON_LINE_SPACE 1
70 //! Default prompt used at the commandline
71 #define CON_DEFAULT_PROMPT "]"
72 //! Scroll this many lines at a time (when pressing PGUP or PGDOWN)
73 #define CON_LINE_SCROLL 2
74 //! Indicator showing that you scrolled up the history
75 #define CON_SCROLL_INDICATOR "^"
76 //! Cursor shown if we are in insert mode
77 #define CON_INS_CURSOR "_"
78 //! Cursor shown if we are in overwrite mode
79 #define CON_OVR_CURSOR "|"
80 //! Defines the default hide key (Hide() the console if pressed)
81 #define CON_DEFAULT_HIDEKEY KEY_ESC
82 //! Defines the opening/closing speed
83 #define CON_OPENCLOSE_SPEED 50
86 /*! This is a struct for the console's data */
87 typedef struct console_information_td {
88 int Visible; //! enum that tells which visible state we are in CON_HIDE, CON_SHOW, CON_RAISE, CON_LOWER
89 int RaiseOffset; //! Offset used when scrolling in the console
90 int HideKey; //! the key that can hide the console
91 char **ConsoleLines; //! List of all the past lines
92 char **CommandLines; //! List of all the past commands
93 int TotalConsoleLines; //! Total number of lines in the console
94 int ConsoleScrollBack; //! How much the user scrolled back in the console
95 int TotalCommands; //! Number of commands in the Back Commands
96 int LineBuffer; //! The number of visible lines in the console (autocalculated)
97 int VChars; //! The number of visible characters in one console line (autocalculated)
98 char* Prompt; //! Prompt displayed in command line
99 char Command[CON_CHARS_PER_LINE]; //! current command in command line = lcommand + rcommand
100 char RCommand[CON_CHARS_PER_LINE]; //! left hand side of cursor
101 char LCommand[CON_CHARS_PER_LINE]; //! right hand side of cursor
102 char VCommand[CON_CHARS_PER_LINE]; //! current visible command line
103 int CursorPos; //! Current cursor position in CurrentCommand
104 int Offset; //! CommandOffset (first visible char of command) - if command is too long to fit into console
105 int InsMode; //! Insert or Overwrite characters?
106 grs_canvas *ConsoleSurface; //! Canvas of the console
107 grs_bitmap *BackgroundImage; //! Background image for the console
108 grs_bitmap *InputBackground; //! Dirty rectangle to draw over behind the users background
110 unsigned char ConsoleAlpha; //! The consoles alpha level
112 int CommandScrollBack; //! How much the users scrolled back in the command lines
115 static ConsoleInformation Console;
116 #define console (&Console)
118 /* console is ready to be written to */
119 static int con_initialized;
123 void CON_UpdateOffset(void);
124 /*! Frees all the memory loaded by the console */
127 /*! Sets the alpha channel of an SDL_Surface to the specified value (0 - transparend,
128 255 - opaque). Use this function also for OpenGL. */
129 void CON_Alpha(unsigned char alpha);
130 /*! Internal: Sets the alpha channel of an SDL_Surface to the specified value.
131 Preconditions: the surface in question is RGBA. 0 <= a <= 255, where 0 is transparent and 255 opaque */
132 void CON_AlphaGL(SDL_Surface *s, int alpha);
133 /*! Sets a background image for the console */
135 int CON_Background(grs_bitmap *image);
136 /*! Sets font info for the console */
137 void CON_Font(grs_font *font, int fg, int bg);
138 /*! Modify the prompt of the console */
139 void CON_SetPrompt(char* newprompt);
140 /*! Set the key, that invokes a CON_Hide() after press. default is ESCAPE and you can always hide using
141 ESCAPE and the HideKey. compared against event->key.keysym.sym !! */
142 void CON_SetHideKey(int key);
143 /*! Internal: executes the command typed in at the console (called if you press ENTER)*/
144 void CON_Execute(char* command);
145 /*! Internal: Gets called when TAB was pressed */
146 void CON_TabCompletion(void);
147 /*! Internal: makes newline (same as printf("\n") or CON_Out("\n") ) */
148 void CON_NewLineConsole(void);
149 /*! Internal: shift command history (the one you can switch with the up/down keys) */
150 void CON_NewLineCommand(void);
151 /*! Internal: updates console after resize etc. */
152 void CON_UpdateConsole(void);
155 /*! Internal: draws the commandline the user is typing in to the screen. called by update? */
156 void DrawCommandLine();
158 /*! Internal: Gets called if you press the LEFT key (move cursor left) */
159 void Cursor_Left(void);
160 /*! Internal: Gets called if you press the RIGHT key (move cursor right) */
161 void Cursor_Right(void);
162 /*! Internal: Gets called if you press the HOME key (move cursor to the beginning
164 void Cursor_Home(void);
165 /*! Internal: Gets called if you press the END key (move cursor to the end of the line*/
166 void Cursor_End(void);
167 /*! Internal: Called if you press DELETE (deletes character under the cursor) */
168 void Cursor_Del(void);
169 /*! Internal: Called if you press BACKSPACE (deletes character left of cursor) */
170 void Cursor_BSpace(void);
171 /*! Internal: Called if you type in a character (add the char to the command) */
172 void Cursor_Add(int event);
174 /*! Internal: Called if you press Ctrl-C (deletes the commandline) */
175 void Clear_Command(void);
176 /*! Internal: Called if you press Ctrl-L (deletes the History) */
177 void Clear_History(void);
179 /*! Internal: Called if you press UP key (switches through recent typed in commands */
180 void Command_Up(void);
181 /*! Internal: Called if you press DOWN key (switches through recent typed in commands */
182 void Command_Down(void);
185 /* Takes keys from the keyboard and inputs them to the console
186 If the event was not handled (i.e. WM events or unknown ctrl-shift
187 sequences) the function returns the event for further processing. */
188 int CON_Events(int event)
193 if(event & KEY_CTRLED)
196 switch(event & ~KEY_CTRLED)
215 else if(event & KEY_ALTED)
217 //the console does not handle ALT combinations!
222 //first of all, check if the console hide key was pressed
223 if(event == console->HideKey)
228 switch (event & 0xff)
234 if(event & KEY_SHIFTED)
236 console->ConsoleScrollBack = console->LineBuffer-1;
243 if(event & KEY_SHIFTED)
245 console->ConsoleScrollBack = 0;
252 console->ConsoleScrollBack += CON_LINE_SCROLL;
253 if(console->ConsoleScrollBack > console->LineBuffer-1)
254 console->ConsoleScrollBack = console->LineBuffer-1;
259 console->ConsoleScrollBack -= CON_LINE_SCROLL;
260 if(console->ConsoleScrollBack < 0)
261 console->ConsoleScrollBack = 0;
283 console->InsMode = 1-console->InsMode;
289 if(strlen(console->Command) > 0) {
290 CON_NewLineCommand();
292 // copy the input into the past commands strings
293 strcpy(console->CommandLines[0], console->Command);
295 // display the command including the prompt
296 CON_Out("%s%s", console->Prompt, console->Command);
299 CON_Execute(console->Command);
302 console->CommandScrollBack = -1;
310 if (key_to_ascii(event) == 255)
324 /* CON_AlphaGL() -- sets the alpha channel of an SDL_Surface to the
325 * specified value. Preconditions: the surface in question is RGBA.
326 * 0 <= a <= 255, where 0 is transparent and 255 is opaque. */
327 void CON_AlphaGL(SDL_Surface *s, int alpha) {
332 SDL_PixelFormat *format;
333 static char errorPrinted = 0;
336 /* debugging assertions -- these slow you down, but hey, crashing sucks */
338 PRINT_ERROR("NULL Surface passed to CON_AlphaGL\n");
342 /* clamp alpha value to 0...255 */
343 if(alpha < SDL_ALPHA_TRANSPARENT)
344 val = SDL_ALPHA_TRANSPARENT;
345 else if(alpha > SDL_ALPHA_OPAQUE)
346 val = SDL_ALPHA_OPAQUE;
350 /* loop over alpha channels of each pixel, setting them appropriately. */
354 switch (format->BytesPerPixel) {
356 /* 16-bit surfaces don't seem to support alpha channels. */
359 PRINT_ERROR("16-bit SDL surfaces do not support alpha-blending under OpenGL.\n");
363 /* we can do this very quickly in 32-bit mode. 24-bit is more
364 * difficult. And since 24-bit mode is reall the same as 32-bit,
365 * so it usually ends up taking this route too. Win! Unroll loop
366 * and use pointer arithmetic for extra speed. */
367 int numpixels = h * (w << 2);
368 Uint8 *pix = (Uint8 *) (s->pixels);
369 Uint8 *last = pix + numpixels;
371 if((numpixels & 0x7) == 0)
372 for(pixel = pix + 3; pixel < last; pixel += 32)
373 *pixel = *(pixel + 4) = *(pixel + 8) = *(pixel + 12) = *(pixel + 16) = *(pixel + 20) = *(pixel + 24) = *(pixel + 28) = val;
375 for(pixel = pix + 3; pixel < last; pixel += 4)
380 /* we have no choice but to do this slowly. <sigh> */
381 for(y = 0; y < h; ++y)
382 for(x = 0; x < w; ++x) {
384 /* Lock the surface for direct access to the pixels */
385 if(SDL_MUSTLOCK(s) && SDL_LockSurface(s) < 0) {
386 PRINT_ERROR("Can't lock surface: ");
387 fprintf(stderr, "%s\n", SDL_GetError());
390 pixel = DT_GetPixel(s, x, y);
393 SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
394 pixel = SDL_MapRGBA(format, r, g, b, val);
395 SDL_GetRGBA(pixel, format, &r, &g, &b, &a);
396 DT_PutPixel(s, x, y, pixel);
398 /* unlock surface again */
400 SDL_UnlockSurface(s);
408 /* Updates the console buffer */
409 void CON_UpdateConsole(void) {
413 grs_canvas *canv_save;
416 /* Due to the Blits, the update is not very fast: So only update if it's worth it */
420 Screenlines = console->ConsoleSurface->cv_h / (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h);
422 canv_save = grd_curcanv;
423 gr_set_current_canvas(console->ConsoleSurface);
426 SDL_FillRect(console->ConsoleSurface, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, console->ConsoleAlpha));
432 if(grd_curscreen->flags & SDL_OPENGLBLIT)
433 SDL_SetAlpha(console->ConsoleSurface, 0, SDL_ALPHA_OPAQUE);
436 /* draw the background image if there is one */
437 if(console->BackgroundImage)
438 gr_bitmap(0, 0, console->BackgroundImage);
440 /* Draw the text from the back buffers, calculate in the scrollback from the user
441 * this is a normal SDL software-mode blit, so we need to temporarily set the ColorKey
442 * for the font, and then clear it when we're done.
445 if((grd_curscreen->flags & SDL_OPENGLBLIT) && (grd_curscreen->format->BytesPerPixel > 2)) {
446 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
447 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
451 //now draw text from last but second line to top
452 for(loop = 0; loop < Screenlines-1 && loop < console->LineBuffer - console->ConsoleScrollBack; loop++) {
453 if(console->ConsoleScrollBack != 0 && loop == 0)
454 for(loop2 = 0; loop2 < (console->VChars / 5) + 1; loop2++)
456 orig_color = FG_COLOR;
457 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);
458 FG_COLOR = orig_color;
462 orig_color = FG_COLOR;
463 gr_string(CON_CHAR_BORDER, (Screenlines - loop - 2) * (CON_LINE_SPACE + console->ConsoleSurface->cv_font->ft_h), console->ConsoleLines[console->ConsoleScrollBack + loop]);
464 FG_COLOR = orig_color;
468 gr_set_current_canvas(canv_save);
471 if(grd_curscreen->flags & SDL_OPENGLBLIT)
472 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
476 void CON_UpdateOffset(void) {
477 switch(console->Visible) {
479 console->RaiseOffset -= CON_OPENCLOSE_SPEED;
480 if(console->RaiseOffset <= 0) {
481 console->RaiseOffset = 0;
482 console->Visible = CON_CLOSED;
486 console->RaiseOffset += CON_OPENCLOSE_SPEED;
487 if(console->RaiseOffset >= console->ConsoleSurface->cv_h) {
488 console->RaiseOffset = console->ConsoleSurface->cv_h;
489 console->Visible = CON_OPEN;
498 /* Draws the console buffer to the screen if the console is "visible" */
499 void CON_DrawConsole(void) {
500 grs_canvas *canv_save;
503 /* only draw if console is visible: here this means, that the console is not CON_CLOSED */
504 if(console->Visible == CON_CLOSED)
507 /* Update the scrolling offset */
510 /* Update the command line since it has a blinking cursor */
514 /* before drawing, make sure the alpha channel of the console surface is set
515 * properly. (sigh) I wish we didn't have to do this every frame... */
516 if(grd_curscreen->flags & SDL_OPENGLBLIT)
517 CON_AlphaGL(console->ConsoleSurface, console->ConsoleAlpha);
520 canv_save = grd_curcanv;
521 gr_set_current_canvas(&grd_curscreen->sc_canvas);
523 clip = gr_create_sub_bitmap(&console->ConsoleSurface->cv_bitmap, 0, console->ConsoleSurface->cv_h - console->RaiseOffset, console->ConsoleSurface->cv_w, console->RaiseOffset);
525 gr_bitmap(0, 0, clip);
526 gr_free_sub_bitmap(clip);
529 if(grd_curscreen->flags & SDL_OPENGLBLIT)
530 SDL_UpdateRects(grd_curscreen, 1, &DestRect);
533 gr_set_current_canvas(canv_save);
537 /* Initializes the console */
542 console->Visible = CON_CLOSED;
543 console->RaiseOffset = 0;
544 console->ConsoleLines = NULL;
545 console->CommandLines = NULL;
546 console->TotalConsoleLines = 0;
547 console->ConsoleScrollBack = 0;
548 console->TotalCommands = 0;
549 console->BackgroundImage = NULL;
551 console->ConsoleAlpha = SDL_ALPHA_OPAQUE;
554 console->InsMode = 1;
555 console->CursorPos = 0;
556 console->CommandScrollBack = 0;
557 console->Prompt = CON_DEFAULT_PROMPT;
558 console->HideKey = CON_DEFAULT_HIDEKEY;
560 /* load the console surface */
561 console->ConsoleSurface = NULL;
563 /* Load the dirty rectangle for user input */
564 console->InputBackground = NULL;
566 console->VChars = CON_CHARS_PER_LINE - 1;
567 console->LineBuffer = CON_NUM_LINES;
569 console->ConsoleLines = (char **)d_malloc(sizeof(char *) * console->LineBuffer);
570 console->CommandLines = (char **)d_malloc(sizeof(char *) * console->LineBuffer);
571 for(loop = 0; loop <= console->LineBuffer - 1; loop++) {
572 console->ConsoleLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
573 console->CommandLines[loop] = (char *)d_calloc(CON_CHARS_PER_LINE, sizeof(char));
575 memset(console->Command, 0, CON_CHARS_PER_LINE);
576 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
577 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
578 memset(console->VCommand, 0, CON_CHARS_PER_LINE);
582 /* Initialise the cvars */
583 cvar_registervariable (&con_threshold);
591 void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline);
592 void CON_InitGFX(int w, int h)
598 if (console->ConsoleSurface) {
599 /* resize console surface */
600 gr_free_bitmap_data(&console->ConsoleSurface->cv_bitmap);
601 gr_init_bitmap_alloc(&console->ConsoleSurface->cv_bitmap, BM_LINEAR, 0, 0, w, h, w);
603 /* load the console surface */
604 console->ConsoleSurface = gr_create_canvas(w, h);
607 /* Load the consoles font */
608 CON_Font(SMALL_FONT, gr_getcolor(63,63,63), -1);
610 /* make sure that the size of the console is valid */
611 if(w > grd_curscreen->sc_w || w < console->ConsoleSurface->cv_font->ft_w * 32)
612 w = grd_curscreen->sc_w;
613 if(h > grd_curscreen->sc_h || h < console->ConsoleSurface->cv_font->ft_h)
614 h = grd_curscreen->sc_h;
616 /* Load the dirty rectangle for user input */
617 if (console->InputBackground)
618 gr_free_bitmap(console->InputBackground);
619 console->InputBackground = gr_create_bitmap(w, console->ConsoleSurface->cv_font->ft_h);
621 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
624 /* calculate the number of visible characters in the command line */
625 console->VChars = (w - CON_CHAR_BORDER) / console->ConsoleSurface->cv_font->ft_w;
626 if(console->VChars >= CON_CHARS_PER_LINE)
627 console->VChars = CON_CHARS_PER_LINE - 1;
629 gr_init_bitmap_data(&bmp);
630 pcx_error = pcx_read_bitmap(CON_BG, &bmp, BM_LINEAR, pal);
631 Assert(pcx_error == PCX_ERROR_NONE);
632 gr_remap_bitmap_good(&bmp, pal, -1, -1);
633 CON_Background(&bmp);
634 gr_free_bitmap_data(&bmp);
638 /* Makes the console visible */
639 void CON_Show(void) {
640 console->Visible = CON_OPENING;
644 /* Hides the console (make it invisible) */
645 void CON_Hide(void) {
646 console->Visible = CON_CLOSING;
649 /* tells wether the console is visible or not */
650 int CON_isVisible(void) {
651 return((console->Visible == CON_OPEN) || (console->Visible == CON_OPENING));
654 /* Frees all the memory loaded by the console */
655 void CON_Free(void) {
658 for(i = 0; i <= console->LineBuffer - 1; i++) {
659 d_free(console->ConsoleLines[i]);
660 d_free(console->CommandLines[i]);
662 d_free(console->ConsoleLines);
663 d_free(console->CommandLines);
665 console->ConsoleLines = NULL;
666 console->CommandLines = NULL;
668 gr_free_canvas(console->ConsoleSurface);
669 console->ConsoleSurface = NULL;
671 if (console->BackgroundImage)
672 gr_free_bitmap(console->BackgroundImage);
673 console->BackgroundImage = NULL;
675 gr_free_bitmap(console->InputBackground);
676 console->InputBackground = NULL;
682 /* Increments the console lines */
683 void CON_NewLineConsole(void) {
687 temp = console->ConsoleLines[console->LineBuffer - 1];
689 for(loop = console->LineBuffer - 1; loop > 0; loop--)
690 console->ConsoleLines[loop] = console->ConsoleLines[loop - 1];
692 console->ConsoleLines[0] = temp;
694 memset(console->ConsoleLines[0], 0, CON_CHARS_PER_LINE);
695 if(console->TotalConsoleLines < console->LineBuffer - 1)
696 console->TotalConsoleLines++;
698 //Now adjust the ConsoleScrollBack
699 //dont scroll if not at bottom
700 if(console->ConsoleScrollBack != 0)
701 console->ConsoleScrollBack++;
703 if(console->ConsoleScrollBack > console->LineBuffer-1)
704 console->ConsoleScrollBack = console->LineBuffer-1;
709 /* Increments the command lines */
710 void CON_NewLineCommand(void) {
714 temp = console->CommandLines[console->LineBuffer - 1];
717 for(loop = console->LineBuffer - 1; loop > 0; loop--)
718 console->CommandLines[loop] = console->CommandLines[loop - 1];
720 console->CommandLines[0] = temp;
722 memset(console->CommandLines[0], 0, CON_CHARS_PER_LINE);
723 if(console->TotalCommands < console->LineBuffer - 1)
724 console->TotalCommands++;
727 /* Draws the command line the user is typing in to the screen */
728 /* completely rewritten by C.Wacha */
729 void DrawCommandLine() {
733 grs_font* CurrentFont;
735 static unsigned int LastBlinkTime = 0; /* Last time the consoles cursor blinked */
736 static int LastCursorPos = 0; // Last Cursor Position
737 static int Blink = 0; /* Is the cursor currently blinking */
738 grs_canvas *canv_save;
741 commandbuffer = console->VChars - strlen(console->Prompt)-1; // -1 to make cursor visible
744 CurrentFont = console->ConsoleSurface->cv_font;
747 //Concatenate the left and right side to command
748 strcpy(console->Command, console->LCommand);
749 strncat(console->Command, console->RCommand, strlen(console->RCommand));
751 //calculate display offset from current cursor position
752 if(console->Offset < console->CursorPos - commandbuffer)
753 console->Offset = console->CursorPos - commandbuffer;
754 if(console->Offset > console->CursorPos)
755 console->Offset = console->CursorPos;
757 //first add prompt to visible part
758 strcpy(console->VCommand, console->Prompt);
760 //then add the visible part of the command
761 strncat(console->VCommand, &console->Command[console->Offset], strlen(&console->Command[console->Offset]));
763 //now display the result
766 //once again we're drawing text, so in OpenGL context we need to temporarily set up
767 //software-mode transparency.
768 if(grd_curscreen->flags & SDL_OPENGLBLIT) {
769 Uint32 *pix = (Uint32 *) (CurrentFont->FontSurface->pixels);
770 SDL_SetColorKey(CurrentFont->FontSurface, SDL_SRCCOLORKEY, *pix);
774 canv_save = grd_curcanv;
775 gr_set_current_canvas(console->ConsoleSurface);
777 //first of all restore InputBackground
778 gr_bitmap(0, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->InputBackground);
781 orig_color = FG_COLOR;
782 gr_string(CON_CHAR_BORDER, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, console->VCommand);
783 FG_COLOR = orig_color;
785 //at last add the cursor
786 //check if the blink period is over
787 if(get_msecs() > LastBlinkTime) {
788 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
795 //check if cursor has moved - if yes display cursor anyway
796 if(console->CursorPos != LastCursorPos) {
797 LastCursorPos = console->CursorPos;
798 LastBlinkTime = get_msecs() + CON_BLINK_RATE;
803 int prompt_width, cmd_width, h, w;
805 gr_get_string_size(console->Prompt, &prompt_width, &h, &w);
806 gr_get_string_size(console->LCommand + console->Offset, &cmd_width, &h, &w);
807 x = CON_CHAR_BORDER + prompt_width + cmd_width;
808 orig_color = FG_COLOR;
810 gr_string(x, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, CON_INS_CURSOR);
812 gr_string(x, console->ConsoleSurface->cv_h - console->ConsoleSurface->cv_font->ft_h, CON_OVR_CURSOR);
813 FG_COLOR = orig_color;
816 gr_set_current_canvas(canv_save);
820 if(grd_curscreen->flags & SDL_OPENGLBLIT) {
821 SDL_SetColorKey(CurrentFont->FontSurface, 0, 0);
827 # define vsnprintf _vsnprintf
830 /* Outputs text to the console (in game), up to CON_CHARS_PER_LINE chars can be entered */
831 void CON_Out(const char *str, ...) {
833 //keep some space free for stuff like CON_Out("blablabla %s", console->Command);
834 char temp[CON_CHARS_PER_LINE + 128];
837 va_start(marker, str);
838 vsnprintf(temp, CON_CHARS_PER_LINE + 127, str, marker);
843 //temp now contains the complete string we want to output
844 // the only problem is that temp is maybe longer than the console
845 // width so we have to cut it into several pieces
847 if(console->ConsoleLines) {
848 while(strlen(ptemp) > console->VChars) {
849 CON_NewLineConsole();
850 strncpy(console->ConsoleLines[0], ptemp, console->VChars);
851 console->ConsoleLines[0][console->VChars] = '\0';
852 ptemp = &ptemp[console->VChars];
854 CON_NewLineConsole();
855 strncpy(console->ConsoleLines[0], ptemp, console->VChars);
856 console->ConsoleLines[0][console->VChars] = '\0';
863 /* Sets the alpha level of the console, 0 turns off alpha blending */
864 void CON_Alpha(unsigned char alpha) {
865 /* store alpha as state! */
866 console->ConsoleAlpha = alpha;
868 if((grd_curscreen->flags & SDL_OPENGLBLIT) == 0) {
870 SDL_SetAlpha(console->ConsoleSurface, 0, alpha);
872 SDL_SetAlpha(console->ConsoleSurface, SDL_SRCALPHA, alpha);
875 // CON_UpdateConsole();
880 /* Adds background image to the console, scaled to size of console*/
881 int CON_Background(grs_bitmap *image)
883 /* Free the background from the console */
885 if (console->BackgroundImage)
886 gr_free_bitmap(console->BackgroundImage);
887 console->BackgroundImage = NULL;
889 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
894 /* Load a new background */
895 if (console->BackgroundImage)
896 gr_free_bitmap(console->BackgroundImage);
897 console->BackgroundImage = gr_create_bitmap(console->ConsoleSurface->cv_w, console->ConsoleSurface->cv_h);
898 gr_bitmap_scale_to(image, console->BackgroundImage);
901 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
903 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);
908 /* Sets font info for the console */
909 void CON_Font(grs_font *font, int fg, int bg)
911 grs_canvas *canv_save;
913 canv_save = grd_curcanv;
914 gr_set_current_canvas(console->ConsoleSurface);
915 gr_set_curfont(font);
916 gr_set_fontcolor(fg, bg);
917 gr_set_current_canvas(canv_save);
920 void gr_init_bitmap_alloc( grs_bitmap *bm, int mode, int x, int y, int w, int h, int bytesperline);
921 /* resizes the console, has to reset alot of stuff
922 * returns 1 on error */
923 void CON_Resize(int w, int h)
925 /* make sure that the size of the console is valid */
926 if(w > grd_curscreen->sc_w || w < console->ConsoleSurface->cv_font->ft_w * 32)
927 w = grd_curscreen->sc_w;
928 if(h > grd_curscreen->sc_h || h < console->ConsoleSurface->cv_font->ft_h)
929 h = grd_curscreen->sc_h;
931 /* resize console surface */
932 gr_free_bitmap_data(&console->ConsoleSurface->cv_bitmap);
933 gr_init_bitmap_alloc(&console->ConsoleSurface->cv_bitmap, BM_LINEAR, 0, 0, w, h, w);
935 /* Load the dirty rectangle for user input */
936 gr_free_bitmap(console->InputBackground);
937 console->InputBackground = gr_create_bitmap(w, console->ConsoleSurface->cv_font->ft_h);
939 /* Now reset some stuff dependent on the previous size */
940 console->ConsoleScrollBack = 0;
942 /* Reload the background image (for the input text area) in the console */
943 if(console->BackgroundImage) {
945 SDL_FillRect(console->InputBackground, NULL, SDL_MapRGBA(console->ConsoleSurface->format, 0, 0, 0, SDL_ALPHA_OPAQUE));
947 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);
951 /* restore the alpha level */
952 CON_Alpha(console->ConsoleAlpha);
956 /* Sets the Prompt for console */
957 void CON_SetPrompt(char* newprompt) {
958 //check length so we can still see at least 1 char :-)
959 if(strlen(newprompt) < console->VChars)
960 console->Prompt = d_strdup(newprompt);
962 CON_Out("prompt too long. (max. %i chars)", console->VChars - 1);
965 /* Sets the key that deactivates (hides) the console. */
966 void CON_SetHideKey(int key) {
967 console->HideKey = key;
970 /* Executes the command entered */
971 void CON_Execute(char* command) {
976 void CON_TabCompletion(void) {
980 command = d_strdup(console->LCommand);
981 command = cmd_complete(command);
984 return; //no tab completion took place so return silently
987 if(j > CON_CHARS_PER_LINE - 2)
988 j = CON_CHARS_PER_LINE-1;
990 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
991 console->CursorPos = 0;
993 for(i = 0; i < j; i++) {
994 console->CursorPos++;
995 console->LCommand[i] = command[i];
997 //add a trailing space
998 console->CursorPos++;
999 console->LCommand[j] = ' ';
1000 console->LCommand[j+1] = '\0';
1003 void Cursor_Left(void) {
1004 char temp[CON_CHARS_PER_LINE];
1006 if(console->CursorPos > 0) {
1007 console->CursorPos--;
1008 strcpy(temp, console->RCommand);
1009 strcpy(console->RCommand, &console->LCommand[strlen(console->LCommand)-1]);
1010 strcat(console->RCommand, temp);
1011 console->LCommand[strlen(console->LCommand)-1] = '\0';
1012 //CON_Out("L:%s, R:%s", console->LCommand, console->RCommand);
1016 void Cursor_Right(void) {
1017 char temp[CON_CHARS_PER_LINE];
1019 if(console->CursorPos < strlen(console->Command)) {
1020 console->CursorPos++;
1021 strncat(console->LCommand, console->RCommand, 1);
1022 strcpy(temp, console->RCommand);
1023 strcpy(console->RCommand, &temp[1]);
1024 //CON_Out("L:%s, R:%s", console->LCommand, console->RCommand);
1028 void Cursor_Home(void) {
1029 char temp[CON_CHARS_PER_LINE];
1031 console->CursorPos = 0;
1032 strcpy(temp, console->RCommand);
1033 strcpy(console->RCommand, console->LCommand);
1034 strncat(console->RCommand, temp, strlen(temp));
1035 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1038 void Cursor_End(void) {
1039 console->CursorPos = strlen(console->Command);
1040 strncat(console->LCommand, console->RCommand, strlen(console->RCommand));
1041 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1044 void Cursor_Del(void) {
1045 char temp[CON_CHARS_PER_LINE];
1047 if(strlen(console->RCommand) > 0) {
1048 strcpy(temp, console->RCommand);
1049 strcpy(console->RCommand, &temp[1]);
1053 void Cursor_BSpace(void) {
1054 if(console->CursorPos > 0) {
1055 console->CursorPos--;
1057 if(console->Offset < 0)
1058 console->Offset = 0;
1059 console->LCommand[strlen(console->LCommand)-1] = '\0';
1063 void Cursor_Add(int event)
1065 if(strlen(console->Command) < CON_CHARS_PER_LINE - 1)
1067 console->CursorPos++;
1068 console->LCommand[strlen(console->LCommand)] = key_to_ascii(event);
1069 console->LCommand[strlen(console->LCommand)] = '\0';
1073 void Clear_Command(void) {
1074 console->CursorPos = 0;
1075 memset(console->VCommand, 0, CON_CHARS_PER_LINE);
1076 memset(console->Command, 0, CON_CHARS_PER_LINE);
1077 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1078 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1081 void Clear_History(void) {
1084 for(loop = 0; loop <= console->LineBuffer - 1; loop++)
1085 memset(console->ConsoleLines[loop], 0, CON_CHARS_PER_LINE);
1088 void Command_Up(void) {
1089 if(console->CommandScrollBack < console->TotalCommands - 1) {
1090 /* move back a line in the command strings and copy the command to the current input string */
1091 console->CommandScrollBack++;
1092 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1093 console->Offset = 0;
1094 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1095 console->CursorPos = strlen(console->CommandLines[console->CommandScrollBack]);
1096 CON_UpdateConsole();
1100 void Command_Down(void) {
1101 if(console->CommandScrollBack > -1) {
1102 /* move forward a line in the command strings and copy the command to the current input string */
1103 console->CommandScrollBack--;
1104 memset(console->RCommand, 0, CON_CHARS_PER_LINE);
1105 memset(console->LCommand, 0, CON_CHARS_PER_LINE);
1106 console->Offset = 0;
1107 if(console->CommandScrollBack > -1)
1108 strcpy(console->LCommand, console->CommandLines[console->CommandScrollBack]);
1109 console->CursorPos = strlen(console->LCommand);
1110 CON_UpdateConsole();
1114 /* Print a message to the console */
1115 void con_printf(int priority, char *fmt, ...)
1120 if (priority <= ((int)con_threshold.value))
1122 va_start (arglist, fmt);
1123 vsprintf (buffer, fmt, arglist);
1126 if (con_initialized)
1129 if (text_console_enabled)
1131 /* Produce a sanitised version and send it to the standard output */
1150 printf("%s", buffer);